doc: update documentation for a version 2.12 release
[nasm.git] / output / codeview.c
blob2f5bb690fb0cd529ddfb5c0a8c9b7f208a27ed16
1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2016 The NASM Authors - All Rights Reserved
4 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * ----------------------------------------------------------------------- */
35 * codeview.c Codeview Debug Format support for COFF
38 #include "version.h"
39 #include "compiler.h"
41 #include <stdio.h>
42 #include <stddef.h>
43 #include <stdlib.h>
45 #include "nasm.h"
46 #include "nasmlib.h"
47 #include "saa.h"
48 #include "output/outlib.h"
49 #include "output/pecoff.h"
50 #include "md5.h"
52 static void cv8_init(void);
53 static void cv8_linenum(const char *filename, int32_t linenumber,
54 int32_t segto);
55 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
56 int is_global, char *special);
57 static void cv8_typevalue(int32_t type);
58 static void cv8_output(int type, void *param);
59 static void cv8_cleanup(void);
61 struct dfmt df_cv8 = {
62 .fullname = "Codeview 8",
63 .shortname = "cv8",
64 .init = cv8_init,
65 .linenum = cv8_linenum,
66 .debug_deflabel = cv8_deflabel,
67 .debug_directive = null_debug_directive,
68 .debug_typevalue = cv8_typevalue,
69 .debug_output = cv8_output,
70 .cleanup = cv8_cleanup,
73 /*******************************************************************************
74 * dfmt callbacks
75 ******************************************************************************/
76 struct source_file {
77 char *name;
78 unsigned char md5sum[MD5_HASHBYTES];
81 struct linepair {
82 uint32_t file_offset;
83 uint32_t linenumber;
86 enum symbol_type {
87 SYMTYPE_CODE,
88 SYMTYPE_PROC,
89 SYMTYPE_LDATA,
90 SYMTYPE_GDATA,
92 SYMTYPE_MAX,
95 struct cv8_symbol {
96 enum symbol_type type;
97 char *name;
99 uint32_t secrel;
100 uint16_t section;
101 uint32_t size;
102 uint32_t typeindex;
104 enum symtype {
105 TYPE_UNREGISTERED = 0x0000, /* T_NOTYPE */
106 TYPE_BYTE = 0x0020,
107 TYPE_WORD = 0x0021,
108 TYPE_DWORD= 0x0022,
109 TYPE_QUAD = 0x0023,
111 TYPE_REAL32 = 0x0040,
112 TYPE_REAL64 = 0x0041,
113 TYPE_REAL80 = 0x0042,
114 TYPE_REAL128= 0x0043,
115 TYPE_REAL256= 0x0044,
116 TYPE_REAL512= 0x0045,
117 } symtype;
120 struct cv8_state {
121 int symbol_sect;
122 int type_sect;
124 uint32_t text_offset;
126 struct source_file source_file;
128 struct SAA *lines;
129 uint32_t num_lines;
131 struct SAA *symbols;
132 struct cv8_symbol *last_sym;
133 unsigned num_syms[SYMTYPE_MAX];
134 unsigned symbol_lengths;
135 unsigned total_syms;
137 char *cwd;
139 struct cv8_state cv8_state;
141 static void cv8_init(void)
143 const uint32_t sect_flags = IMAGE_SCN_MEM_READ |
144 IMAGE_SCN_MEM_DISCARDABLE |
145 IMAGE_SCN_CNT_INITIALIZED_DATA |
146 IMAGE_SCN_ALIGN_1BYTES;
148 cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
149 cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
151 cv8_state.text_offset = 0;
153 cv8_state.lines = saa_init(sizeof(struct linepair));
154 cv8_state.num_lines = 0;
156 cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
157 cv8_state.last_sym = NULL;
159 cv8_state.cwd = nasm_realpath(".");
162 static void register_file(const char *filename);
163 static struct coff_Section *find_section(int32_t segto);
165 static void cv8_linenum(const char *filename, int32_t linenumber,
166 int32_t segto)
168 struct coff_Section *s;
169 struct linepair *li;
171 if (cv8_state.source_file.name == NULL)
172 register_file(filename);
174 s = find_section(segto);
175 if (s == NULL)
176 return;
178 if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
179 return;
181 li = saa_wstruct(cv8_state.lines);
182 li->file_offset = cv8_state.text_offset;
183 li->linenumber = linenumber;
185 cv8_state.num_lines++;
188 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
189 int is_global, char *special)
191 int ret;
192 size_t len;
193 struct cv8_symbol *sym;
194 struct coff_Section *s;
196 (void)special;
198 s = find_section(segment);
199 if (s == NULL)
200 return;
202 sym = saa_wstruct(cv8_state.symbols);
204 if (s->flags & IMAGE_SCN_MEM_EXECUTE)
205 sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
206 else
207 sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
208 cv8_state.num_syms[sym->type]++;
209 cv8_state.total_syms++;
211 sym->section = segment;
212 sym->secrel = offset;
213 sym->symtype = TYPE_UNREGISTERED;
214 sym->size = 0;
215 sym->typeindex = 0;
217 /* handle local labels */
218 if (name[0] == '.' && cv8_state.last_sym != NULL) {
219 len = strlen(cv8_state.last_sym->name) + strlen(name);
220 sym->name = nasm_malloc(len + 1);
221 ret = snprintf(sym->name, len + 1, "%s%s",
222 cv8_state.last_sym->name, name);
223 nasm_assert(ret > 0 && (size_t)ret == len);
224 } else {
225 len = strlen(name);
226 sym->name = nasm_malloc(len + 1);
227 ret = snprintf(sym->name, len + 1, "%s", name);
228 nasm_assert(ret > 0 && (size_t)ret == len);
231 cv8_state.symbol_lengths += len + 1;
233 if (cv8_state.last_sym && cv8_state.last_sym->section == segment)
234 cv8_state.last_sym->size = offset - cv8_state.last_sym->secrel;
235 cv8_state.last_sym = sym;
238 static void cv8_typevalue(int32_t type)
240 if (!cv8_state.last_sym)
241 return;
242 if (cv8_state.last_sym->symtype != TYPE_UNREGISTERED)
243 return;
245 switch (TYM_TYPE(type)) {
246 case TY_BYTE:
247 cv8_state.last_sym->symtype = TYPE_BYTE;
248 break;
249 case TY_WORD:
250 cv8_state.last_sym->symtype = TYPE_WORD;
251 break;
252 case TY_DWORD:
253 cv8_state.last_sym->symtype = TYPE_DWORD;
254 break;
255 case TY_QWORD:
256 cv8_state.last_sym->symtype = TYPE_QUAD;
257 break;
258 case TY_FLOAT:
259 cv8_state.last_sym->symtype = TYPE_REAL32;
260 break;
261 case TY_TBYTE:
262 cv8_state.last_sym->symtype = TYPE_REAL80;
263 break;
264 case TY_OWORD:
265 cv8_state.last_sym->symtype = TYPE_REAL128;
266 break;
267 case TY_YWORD:
268 cv8_state.last_sym->symtype = TYPE_REAL256;
269 break;
270 case TY_UNKNOWN:
271 break;
272 case TY_LABEL:
273 break;
277 static void cv8_output(int type, void *param)
279 struct coff_DebugInfo *dinfo = param;
281 (void)type;
283 if (dinfo->section && dinfo->section->name &&
284 !strncmp(dinfo->section->name, ".text", 5))
285 cv8_state.text_offset += dinfo->size;
288 static void build_symbol_table(struct coff_Section *const sect);
289 static void build_type_table(struct coff_Section *const sect);
291 static void cv8_cleanup(void)
293 struct cv8_symbol *sym;
295 struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
296 struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
298 build_symbol_table(symbol_sect);
299 build_type_table(type_sect);
301 if (cv8_state.source_file.name != NULL)
302 free(cv8_state.source_file.name);
304 if (cv8_state.cwd != NULL)
305 free(cv8_state.cwd);
307 saa_free(cv8_state.lines);
309 saa_rewind(cv8_state.symbols);
310 while ((sym = saa_rstruct(cv8_state.symbols)))
311 free(sym->name);
312 saa_free(cv8_state.symbols);
315 /*******************************************************************************
316 * implementation
317 ******************************************************************************/
318 static void calc_md5(const char *const filename,
319 unsigned char sum[MD5_HASHBYTES])
321 int success = 0;
322 unsigned char *file_buf;
323 FILE *f;
324 MD5_CTX ctx;
326 f = fopen(filename, "r");
327 if (!f)
328 goto done;
330 file_buf = nasm_zalloc(BUFSIZ);
332 MD5Init(&ctx);
333 while (!feof(f)) {
334 size_t i = fread(file_buf, 1, BUFSIZ, f);
335 if (ferror(f))
336 goto done_0;
337 else if (i == 0)
338 break;
339 MD5Update(&ctx, file_buf, i);
341 MD5Final(sum, &ctx);
343 success = 1;
344 done_0:
345 nasm_free(file_buf);
346 fclose(f);
347 done:
348 if (!success) {
349 nasm_error(ERR_NONFATAL, "unable to hash file %s. "
350 "Debug information may be unavailable.\n",
351 filename);
353 return;
356 static void register_file(const char *filename)
358 cv8_state.source_file.name = nasm_realpath(filename);
359 memset(cv8_state.source_file.md5sum, 0, MD5_HASHBYTES);
360 calc_md5(filename, cv8_state.source_file.md5sum);
363 static struct coff_Section *find_section(int32_t segto)
365 int i;
367 for (i = 0; i < coff_nsects; i++) {
368 struct coff_Section *sec;
370 sec = coff_sects[i];
371 if (segto == sec->index)
372 return sec;
374 return NULL;
377 static void register_reloc(struct coff_Section *const sect,
378 char *sym, uint32_t addr, uint16_t type)
380 struct coff_Reloc *r;
381 struct coff_Section *sec;
383 r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
384 sect->tail = &r->next;
385 r->next = NULL;
386 sect->nrelocs++;
388 r->address = addr;
389 r->symbase = SECT_SYMBOLS;
390 r->type = type;
392 r->symbol = 0;
393 for (int i = 0; i < coff_nsects; i++) {
394 sec = coff_sects[i];
395 if (!strcmp(sym, sec->name)) {
396 return;
398 r->symbol += 2;
401 saa_rewind(coff_syms);
402 for (uint32_t i = 0; i < coff_nsyms; i++) {
403 struct coff_Symbol *s = saa_rstruct(coff_syms);
404 r->symbol++;
405 if (s->strpos == -1 && !strcmp(sym, s->name)) {
406 return;
407 } else if (s->strpos != -1) {
408 int res;
409 char *symname;
411 symname = nasm_malloc(s->namlen + 1);
412 saa_fread(coff_strs, s->strpos-4, symname, s->namlen);
413 symname[s->namlen] = '\0';
414 res = strcmp(sym, symname);
415 nasm_free(symname);
416 if (!res)
417 return;
420 nasm_assert(!"relocation for unregistered symbol");
423 static inline void section_write32(struct coff_Section *sect, uint32_t val)
425 saa_write32(sect->data, val);
426 sect->len += 4;
429 static inline void section_write16(struct coff_Section *sect, uint16_t val)
431 saa_write16(sect->data, val);
432 sect->len += 2;
435 static inline void section_write8(struct coff_Section *sect, uint8_t val)
437 saa_write8(sect->data, val);
438 sect->len++;
441 static inline void section_wbytes(struct coff_Section *sect, const void *buf,
442 size_t len)
444 saa_wbytes(sect->data, buf, len);
445 sect->len += len;
448 static void write_filename_table(struct coff_Section *const sect)
450 uint32_t field_length = 0;
451 size_t filename_len = strlen(cv8_state.source_file.name);
453 field_length = 1 + filename_len + 1;
455 section_write32(sect, 0x000000F3);
456 section_write32(sect, field_length);
458 section_write8(sect, 0);
459 section_wbytes(sect, cv8_state.source_file.name, filename_len + 1);
462 static void write_sourcefile_table(struct coff_Section *const sect)
464 uint32_t field_length = 0;
466 field_length = 4 + 2 + MD5_HASHBYTES + 2;
468 section_write32(sect, 0x000000F4);
469 section_write32(sect, field_length);
471 section_write32(sect, 1); /* offset of filename in filename str table */
472 section_write16(sect, 0x0110);
473 section_wbytes(sect, cv8_state.source_file.md5sum, MD5_HASHBYTES);
474 section_write16(sect, 0);
477 static void write_linenumber_table(struct coff_Section *const sect)
479 int i;
480 uint32_t field_length = 0;
481 size_t field_base;
482 struct coff_Section *s;
483 struct linepair *li;
485 for (i = 0; i < coff_nsects; i++) {
486 if (!strncmp(coff_sects[i]->name, ".text", 5))
487 break;
490 if (i == coff_nsects)
491 return;
492 s = coff_sects[i];
494 field_length = 12 + 12 + (cv8_state.num_lines * 8);
496 section_write32(sect, 0x000000F2);
497 section_write32(sect, field_length);
499 field_base = sect->len;
500 section_write32(sect, 0); /* SECREL, updated by relocation */
501 section_write16(sect, 0); /* SECTION, updated by relocation*/
502 section_write16(sect, 0); /* pad */
503 section_write32(sect, s->len);
505 register_reloc(sect, ".text", field_base,
506 win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
508 register_reloc(sect, ".text", field_base + 4,
509 win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
511 /* 1 or more source mappings (we assume only 1) */
512 section_write32(sect, 0);
513 section_write32(sect, cv8_state.num_lines);
514 section_write32(sect, 12 + (cv8_state.num_lines * 8));
516 /* the pairs */
517 saa_rewind(cv8_state.lines);
518 while ((li = saa_rstruct(cv8_state.lines))) {
519 section_write32(sect, li->file_offset);
520 section_write32(sect, li->linenumber |= 0x80000000);
524 static uint16_t write_symbolinfo_obj(struct coff_Section *sect,
525 const char sep)
527 uint16_t obj_len;
529 obj_len = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1;
531 section_write16(sect, obj_len);
532 section_write16(sect, 0x1101);
533 section_write32(sect, 0); /* ASM language */
534 section_wbytes(sect, cv8_state.cwd, strlen(cv8_state.cwd));
535 section_write8(sect, sep);
536 section_wbytes(sect, coff_outfile, strlen(coff_outfile)+1);
538 return obj_len;
541 static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
542 const char *const creator_str)
544 uint16_t creator_len;
546 creator_len = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2;
548 section_write16(sect, creator_len);
549 section_write16(sect, 0x1116);
550 section_write32(sect, 3); /* language */
551 if (win64)
552 section_write32(sect, 0x000000D0);
553 else if (win32)
554 section_write32(sect, 0x00000006);
555 else
556 nasm_assert(!"neither win32 nor win64 are set!");
557 section_write32(sect, 0); /* flags*/
558 section_write32(sect, 8); /* version */
559 section_wbytes(sect, creator_str, strlen(creator_str)+1);
561 * normally there would be key/value pairs here, but they aren't
562 * necessary. They are terminated by 2B
564 section_write16(sect, 0);
566 return creator_len;
569 static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
571 uint16_t len = 0, field_len;
572 uint32_t field_base;
573 struct cv8_symbol *sym;
575 saa_rewind(cv8_state.symbols);
576 while ((sym = saa_rstruct(cv8_state.symbols))) {
577 switch (sym->type) {
578 case SYMTYPE_LDATA:
579 case SYMTYPE_GDATA:
580 field_len = 12 + strlen(sym->name) + 1;
581 len += field_len - 2;
582 section_write16(sect, field_len);
583 if (sym->type == SYMTYPE_LDATA)
584 section_write16(sect, 0x110C);
585 else
586 section_write16(sect, 0x110D);
587 section_write32(sect, sym->symtype);
589 field_base = sect->len;
590 section_write32(sect, 0); /* SECREL */
591 section_write16(sect, 0); /* SECTION */
592 break;
593 case SYMTYPE_PROC:
594 case SYMTYPE_CODE:
595 field_len = 9 + strlen(sym->name) + 1;
596 len += field_len - 2;
597 section_write16(sect, field_len);
598 section_write16(sect, 0x1105);
600 field_base = sect->len;
601 section_write32(sect, 0); /* SECREL */
602 section_write16(sect, 0); /* SECTION */
603 section_write8(sect, 0); /* FLAG */
604 break;
605 default:
606 nasm_assert(!"unknown symbol type");
609 section_wbytes(sect, sym->name, strlen(sym->name) + 1);
611 register_reloc(sect, sym->name, field_base,
612 win64 ? IMAGE_REL_AMD64_SECREL :
613 IMAGE_REL_I386_SECREL);
614 register_reloc(sect, sym->name, field_base + 4,
615 win64 ? IMAGE_REL_AMD64_SECTION :
616 IMAGE_REL_I386_SECTION);
619 return len;
622 static void write_symbolinfo_table(struct coff_Section *const sect)
624 const char sep = '\\';
625 const char *creator_str = "The Netwide Assembler " NASM_VER;
628 uint16_t obj_length, creator_length, sym_length;
629 uint32_t field_length = 0, out_len;
631 /* signature, language, workingdir / coff_outfile NULL */
632 obj_length = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1;
633 creator_length = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2;
635 sym_length = ( cv8_state.num_syms[SYMTYPE_CODE] * 7) +
636 ( cv8_state.num_syms[SYMTYPE_PROC] * 7) +
637 ( cv8_state.num_syms[SYMTYPE_LDATA] * 10) +
638 ( cv8_state.num_syms[SYMTYPE_GDATA] * 10) +
639 cv8_state.symbol_lengths;
641 field_length = 2 + obj_length +
642 2 + creator_length +
643 (4 * cv8_state.total_syms) + sym_length;
645 section_write32(sect, 0x000000F1);
646 section_write32(sect, field_length);
648 /* for sub fields, length preceeds type */
650 out_len = write_symbolinfo_obj(sect, sep);
651 nasm_assert(out_len == obj_length);
653 out_len = write_symbolinfo_properties(sect, creator_str);
654 nasm_assert(out_len == creator_length);
656 out_len = write_symbolinfo_symbols(sect);
657 nasm_assert(out_len == sym_length);
660 static inline void align4_table(struct coff_Section *const sect)
662 unsigned diff;
663 uint32_t zero = 0;
664 struct SAA *data = sect->data;
666 if (data->wptr % 4 == 0)
667 return;
669 diff = 4 - (data->wptr % 4);
670 if (diff)
671 section_wbytes(sect, &zero, diff);
674 static void build_symbol_table(struct coff_Section *const sect)
676 section_write32(sect, 0x00000004);
678 write_filename_table(sect);
679 align4_table(sect);
680 write_sourcefile_table(sect);
681 align4_table(sect);
682 write_linenumber_table(sect);
683 align4_table(sect);
684 write_symbolinfo_table(sect);
685 align4_table(sect);
688 static void build_type_table(struct coff_Section *const sect)
690 uint16_t field_len;
691 struct cv8_symbol *sym;
693 section_write32(sect, 0x00000004);
695 saa_rewind(cv8_state.symbols);
696 while ((sym = saa_rstruct(cv8_state.symbols))) {
697 if (sym->type != SYMTYPE_PROC)
698 continue;
700 /* proc leaf */
702 field_len = 2 + 4 + 4 + 4 + 2;
703 section_write16(sect, field_len);
704 section_write16(sect, 0x1008); /* PROC type */
706 section_write32(sect, 0x00000003); /* return type */
707 section_write32(sect, 0); /* calling convention (default) */
708 section_write32(sect, sym->typeindex);
709 section_write16(sect, 0); /* # params */
711 /* arglist */
713 field_len = 2 + 4;
714 section_write16(sect, field_len);
715 section_write16(sect, 0x1201); /* ARGLIST */
716 section_write32(sect, 0); /*num params */