codeview.c: Add support for multiple source files
[nasm.git] / output / codeview.c
blobd490fa4b260138b97ae1f60698fbd5be171221fc
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 "preproc.h"
48 #include "saa.h"
49 #include "output/outlib.h"
50 #include "output/pecoff.h"
51 #include "md5.h"
53 static void cv8_init(void);
54 static void cv8_linenum(const char *filename, int32_t linenumber,
55 int32_t segto);
56 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
57 int is_global, char *special);
58 static void cv8_typevalue(int32_t type);
59 static void cv8_output(int type, void *param);
60 static void cv8_cleanup(void);
62 struct dfmt df_cv8 = {
63 "Codeview 8", /* .fullname */
64 "cv8", /* .shortname */
65 cv8_init, /* .init */
66 cv8_linenum, /* .linenum */
67 cv8_deflabel, /* .debug_deflabel */
68 null_debug_directive, /* .debug_directive */
69 cv8_typevalue, /* .debug_typevalue */
70 cv8_output, /* .debug_output */
71 cv8_cleanup, /* .cleanup */
74 /*******************************************************************************
75 * dfmt callbacks
76 ******************************************************************************/
77 struct source_file;
79 struct source_file {
80 char *name;
81 uint32_t namelen;
83 struct source_file *next;
85 uint32_t filetbl_off;
86 uint32_t sourcetbl_off;
88 struct SAA *lines;
89 uint32_t num_lines;
91 unsigned char md5sum[MD5_HASHBYTES];
94 struct linepair {
95 uint32_t file_offset;
96 uint32_t linenumber;
99 enum symbol_type {
100 SYMTYPE_CODE,
101 SYMTYPE_PROC,
102 SYMTYPE_LDATA,
103 SYMTYPE_GDATA,
105 SYMTYPE_MAX
108 struct cv8_symbol {
109 enum symbol_type type;
110 char *name;
112 uint32_t secrel;
113 uint16_t section;
114 uint32_t size;
115 uint32_t typeindex;
117 enum symtype {
118 TYPE_UNREGISTERED = 0x0000, /* T_NOTYPE */
119 TYPE_BYTE = 0x0020,
120 TYPE_WORD = 0x0021,
121 TYPE_DWORD= 0x0022,
122 TYPE_QUAD = 0x0023,
124 TYPE_REAL32 = 0x0040,
125 TYPE_REAL64 = 0x0041,
126 TYPE_REAL80 = 0x0042,
127 TYPE_REAL128= 0x0043,
128 TYPE_REAL256= 0x0044,
129 TYPE_REAL512= 0x0045
130 } symtype;
133 struct cv8_state {
134 int symbol_sect;
135 int type_sect;
137 uint32_t text_offset;
139 struct source_file source_file;
140 unsigned num_files;
141 uint32_t total_filename_len;
143 unsigned total_lines;
145 struct SAA *symbols;
146 struct cv8_symbol *last_sym;
147 unsigned num_syms[SYMTYPE_MAX];
148 unsigned symbol_lengths;
149 unsigned total_syms;
151 char *cwd;
153 struct cv8_state cv8_state;
155 static void cv8_init(void)
157 const uint32_t sect_flags = IMAGE_SCN_MEM_READ |
158 IMAGE_SCN_MEM_DISCARDABLE |
159 IMAGE_SCN_CNT_INITIALIZED_DATA |
160 IMAGE_SCN_ALIGN_1BYTES;
162 cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
163 cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
165 cv8_state.text_offset = 0;
167 cv8_state.source_file.name = NULL;
168 cv8_state.source_file.next = NULL;
170 cv8_state.num_files = 0;
171 cv8_state.total_filename_len = 0;
173 cv8_state.total_lines = 0;
175 cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
176 cv8_state.last_sym = NULL;
178 cv8_state.cwd = nasm_realpath(".");
181 static struct source_file *register_file(const char *filename);
182 static struct coff_Section *find_section(int32_t segto);
184 static void cv8_linenum(const char *filename, int32_t linenumber,
185 int32_t segto)
187 struct coff_Section *s;
188 struct linepair *li;
189 struct source_file *file;
191 s = find_section(segto);
192 if (s == NULL)
193 return;
195 if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
196 return;
198 file = register_file(filename);
200 li = saa_wstruct(file->lines);
201 li->file_offset = cv8_state.text_offset;
202 li->linenumber = linenumber;
204 file->num_lines++;
205 cv8_state.total_lines++;
208 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
209 int is_global, char *special)
211 struct cv8_symbol *sym;
212 struct coff_Section *s;
214 (void)special;
216 s = find_section(segment);
217 if (s == NULL)
218 return;
220 sym = saa_wstruct(cv8_state.symbols);
222 if (s->flags & IMAGE_SCN_MEM_EXECUTE)
223 sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
224 else
225 sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
226 cv8_state.num_syms[sym->type]++;
227 cv8_state.total_syms++;
229 sym->section = segment;
230 sym->secrel = offset;
231 sym->symtype = TYPE_UNREGISTERED;
232 sym->size = 0;
233 sym->typeindex = 0;
235 sym->name = nasm_strdup(name);
236 cv8_state.symbol_lengths += strlen(sym->name) + 1;
238 if (cv8_state.last_sym && cv8_state.last_sym->section == segment)
239 cv8_state.last_sym->size = offset - cv8_state.last_sym->secrel;
240 cv8_state.last_sym = sym;
243 static void cv8_typevalue(int32_t type)
245 if (!cv8_state.last_sym)
246 return;
247 if (cv8_state.last_sym->symtype != TYPE_UNREGISTERED)
248 return;
250 switch (TYM_TYPE(type)) {
251 case TY_BYTE:
252 cv8_state.last_sym->symtype = TYPE_BYTE;
253 break;
254 case TY_WORD:
255 cv8_state.last_sym->symtype = TYPE_WORD;
256 break;
257 case TY_DWORD:
258 cv8_state.last_sym->symtype = TYPE_DWORD;
259 break;
260 case TY_QWORD:
261 cv8_state.last_sym->symtype = TYPE_QUAD;
262 break;
263 case TY_FLOAT:
264 cv8_state.last_sym->symtype = TYPE_REAL32;
265 break;
266 case TY_TBYTE:
267 cv8_state.last_sym->symtype = TYPE_REAL80;
268 break;
269 case TY_OWORD:
270 cv8_state.last_sym->symtype = TYPE_REAL128;
271 break;
272 case TY_YWORD:
273 cv8_state.last_sym->symtype = TYPE_REAL256;
274 break;
275 case TY_UNKNOWN:
276 break;
277 case TY_LABEL:
278 break;
282 static void cv8_output(int type, void *param)
284 struct coff_DebugInfo *dinfo = param;
286 (void)type;
288 if (dinfo->section && dinfo->section->name &&
289 !strncmp(dinfo->section->name, ".text", 5))
290 cv8_state.text_offset += dinfo->size;
293 static void build_symbol_table(struct coff_Section *const sect);
294 static void build_type_table(struct coff_Section *const sect);
296 static void cv8_cleanup(void)
298 struct cv8_symbol *sym;
299 struct source_file *file;
301 struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
302 struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
304 build_symbol_table(symbol_sect);
305 build_type_table(type_sect);
307 if (cv8_state.source_file.name) {
308 nasm_free(cv8_state.source_file.name);
309 saa_free(cv8_state.source_file.lines);
312 list_for_each(file, cv8_state.source_file.next) {
313 nasm_free(file->name);
314 saa_free(file->lines);
315 free(file);
318 if (cv8_state.cwd != NULL)
319 nasm_free(cv8_state.cwd);
321 saa_free(cv8_state.lines);
323 saa_rewind(cv8_state.symbols);
324 while ((sym = saa_rstruct(cv8_state.symbols)))
325 nasm_free(sym->name);
326 saa_free(cv8_state.symbols);
329 /*******************************************************************************
330 * implementation
331 ******************************************************************************/
332 static void calc_md5(const char *const filename,
333 unsigned char sum[MD5_HASHBYTES])
335 int success = 0;
336 unsigned char *file_buf;
337 FILE *f;
338 MD5_CTX ctx;
340 f = pp_input_fopen(filename, "rb");
341 if (!f)
342 goto done;
344 file_buf = nasm_zalloc(BUFSIZ);
346 MD5Init(&ctx);
347 while (!feof(f)) {
348 size_t i = fread(file_buf, 1, BUFSIZ, f);
349 if (ferror(f))
350 goto done_0;
351 else if (i == 0)
352 break;
353 MD5Update(&ctx, file_buf, i);
355 MD5Final(sum, &ctx);
357 success = 1;
358 done_0:
359 nasm_free(file_buf);
360 fclose(f);
361 done:
362 if (!success) {
363 nasm_error(ERR_NONFATAL, "unable to hash file %s. "
364 "Debug information may be unavailable.\n",
365 filename);
367 return;
370 static struct source_file *register_file(const char *filename)
372 struct source_file *file;
374 char *fullpath = nasm_realpath(filename);
376 for (file = &cv8_state.source_file; file != NULL; file = file->next) {
377 if (file->name != NULL && !strcmp(file->name, fullpath)) {
378 free(fullpath);
379 return file;
383 if (cv8_state.source_file.name == NULL) {
384 file = &cv8_state.source_file;
385 } else {
386 struct source_file *next;
387 file = nasm_malloc(sizeof(struct source_file));
388 for (next = &cv8_state.source_file; next->next != NULL; next = next->next) {}
389 next->next = file;
392 memset(file, 0, sizeof(struct source_file));
394 file->name = fullpath;
395 file->namelen = strlen(fullpath);
396 file->lines = saa_init(sizeof(struct linepair));
397 file->next = NULL;
398 calc_md5(fullpath, file->md5sum);
400 cv8_state.num_files++;
401 cv8_state.total_filename_len += file->namelen + 1;
403 return file;
406 static struct coff_Section *find_section(int32_t segto)
408 int i;
410 for (i = 0; i < coff_nsects; i++) {
411 struct coff_Section *sec;
413 sec = coff_sects[i];
414 if (segto == sec->index)
415 return sec;
417 return NULL;
420 static void register_reloc(struct coff_Section *const sect,
421 char *sym, uint32_t addr, uint16_t type)
423 struct coff_Reloc *r;
424 struct coff_Section *sec;
426 r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
427 sect->tail = &r->next;
428 r->next = NULL;
429 sect->nrelocs++;
431 r->address = addr;
432 r->symbase = SECT_SYMBOLS;
433 r->type = type;
435 r->symbol = 0;
436 for (int i = 0; i < coff_nsects; i++) {
437 sec = coff_sects[i];
438 if (!strcmp(sym, sec->name)) {
439 return;
441 r->symbol += 2;
444 saa_rewind(coff_syms);
445 for (uint32_t i = 0; i < coff_nsyms; i++) {
446 struct coff_Symbol *s = saa_rstruct(coff_syms);
447 r->symbol++;
448 if (s->strpos == -1 && !strcmp(sym, s->name)) {
449 return;
450 } else if (s->strpos != -1) {
451 int res;
452 char *symname;
454 symname = nasm_malloc(s->namlen + 1);
455 saa_fread(coff_strs, s->strpos-4, symname, s->namlen);
456 symname[s->namlen] = '\0';
457 res = strcmp(sym, symname);
458 nasm_free(symname);
459 if (!res)
460 return;
463 nasm_panic(0, "codeview: relocation for unregistered symbol: %s", sym);
466 static inline void section_write32(struct coff_Section *sect, uint32_t val)
468 saa_write32(sect->data, val);
469 sect->len += 4;
472 static inline void section_write16(struct coff_Section *sect, uint16_t val)
474 saa_write16(sect->data, val);
475 sect->len += 2;
478 static inline void section_write8(struct coff_Section *sect, uint8_t val)
480 saa_write8(sect->data, val);
481 sect->len++;
484 static inline void section_wbytes(struct coff_Section *sect, const void *buf,
485 size_t len)
487 saa_wbytes(sect->data, buf, len);
488 sect->len += len;
491 static void write_filename_table(struct coff_Section *const sect)
493 uint32_t field_length;
494 uint32_t tbl_off = 1; /* offset starts at 1 to skip NULL entry */
495 struct source_file *file;
497 nasm_assert(cv8_state.source_file.name != NULL);
498 nasm_assert(cv8_state.num_files > 0);
499 nasm_assert(cv8_state.total_filename_len > 0);
501 field_length = 1 + cv8_state.total_filename_len;
503 section_write32(sect, 0x000000F3);
504 section_write32(sect, field_length);
506 section_write8(sect, 0);
508 for (file = &cv8_state.source_file; file != NULL; file = file->next) {
509 section_wbytes(sect, file->name, file->namelen + 1);
510 file->filetbl_off = tbl_off;
511 tbl_off += file->namelen + 1;
515 static void write_sourcefile_table(struct coff_Section *const sect)
517 const uint32_t entry_size = 4 + 2 + MD5_HASHBYTES + 2;
519 uint32_t field_length = 0;
520 uint32_t tbl_off = 0;
521 struct source_file *file;
523 field_length = entry_size * cv8_state.num_files;
525 section_write32(sect, 0x000000F4);
526 section_write32(sect, field_length);
528 for (file = &cv8_state.source_file; file != NULL; file = file->next) {
529 nasm_assert(file->filetbl_off > 0);
530 section_write32(sect, file->filetbl_off);
531 section_write16(sect, 0x0110);
532 section_wbytes(sect, file->md5sum, MD5_HASHBYTES);
533 section_write16(sect, 0);
535 file->sourcetbl_off = tbl_off;
536 tbl_off += entry_size;
540 static void write_linenumber_table(struct coff_Section *const sect)
542 const uint32_t file_field_len = 12;
543 const uint32_t line_field_len = 8;
545 int i;
546 uint32_t field_length = 0;
547 size_t field_base;
548 struct source_file *file;
549 struct coff_Section *s;
551 for (i = 0; i < coff_nsects; i++) {
552 if (!strncmp(coff_sects[i]->name, ".text", 5))
553 break;
556 if (i == coff_nsects)
557 return;
558 s = coff_sects[i];
560 field_length = 12;
561 field_length += (cv8_state.num_files * file_field_len);
562 field_length += (cv8_state.total_lines * line_field_len);
564 section_write32(sect, 0x000000F2);
565 section_write32(sect, field_length);
567 field_base = sect->len;
568 section_write32(sect, 0); /* SECREL, updated by relocation */
569 section_write16(sect, 0); /* SECTION, updated by relocation*/
570 section_write16(sect, 0); /* pad */
571 section_write32(sect, s->len);
573 register_reloc(sect, ".text", field_base,
574 win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
576 register_reloc(sect, ".text", field_base + 4,
577 win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
579 for (file = &cv8_state.source_file; file != NULL; file = file->next) {
580 struct linepair *li;
582 /* source mapping */
583 section_write32(sect, file->sourcetbl_off);
584 section_write32(sect, file->num_lines);
585 section_write32(sect, file_field_len + (file->num_lines * line_field_len));
587 /* the pairs */
588 saa_rewind(file->lines);
589 while ((li = saa_rstruct(file->lines))) {
590 section_write32(sect, li->file_offset);
591 section_write32(sect, li->linenumber |= 0x80000000);
596 static uint16_t write_symbolinfo_obj(struct coff_Section *sect,
597 const char sep)
599 uint16_t obj_len;
601 obj_len = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1;
603 section_write16(sect, obj_len);
604 section_write16(sect, 0x1101);
605 section_write32(sect, 0); /* ASM language */
606 section_wbytes(sect, cv8_state.cwd, strlen(cv8_state.cwd));
607 section_write8(sect, sep);
608 section_wbytes(sect, coff_outfile, strlen(coff_outfile)+1);
610 return obj_len;
613 static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
614 const char *const creator_str)
616 uint16_t creator_len;
618 creator_len = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2;
620 section_write16(sect, creator_len);
621 section_write16(sect, 0x1116);
622 section_write32(sect, 3); /* language */
623 if (win64)
624 section_write32(sect, 0x000000D0);
625 else if (win32)
626 section_write32(sect, 0x00000006);
627 else
628 nasm_assert(!"neither win32 nor win64 are set!");
629 section_write32(sect, 0); /* flags*/
630 section_write32(sect, 8); /* version */
631 section_wbytes(sect, creator_str, strlen(creator_str)+1);
633 * normally there would be key/value pairs here, but they aren't
634 * necessary. They are terminated by 2B
636 section_write16(sect, 0);
638 return creator_len;
641 static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
643 uint16_t len = 0, field_len;
644 uint32_t field_base;
645 struct cv8_symbol *sym;
647 saa_rewind(cv8_state.symbols);
648 while ((sym = saa_rstruct(cv8_state.symbols))) {
649 switch (sym->type) {
650 case SYMTYPE_LDATA:
651 case SYMTYPE_GDATA:
652 field_len = 12 + strlen(sym->name) + 1;
653 len += field_len - 2;
654 section_write16(sect, field_len);
655 if (sym->type == SYMTYPE_LDATA)
656 section_write16(sect, 0x110C);
657 else
658 section_write16(sect, 0x110D);
659 section_write32(sect, sym->symtype);
661 field_base = sect->len;
662 section_write32(sect, 0); /* SECREL */
663 section_write16(sect, 0); /* SECTION */
664 break;
665 case SYMTYPE_PROC:
666 case SYMTYPE_CODE:
667 field_len = 9 + strlen(sym->name) + 1;
668 len += field_len - 2;
669 section_write16(sect, field_len);
670 section_write16(sect, 0x1105);
672 field_base = sect->len;
673 section_write32(sect, 0); /* SECREL */
674 section_write16(sect, 0); /* SECTION */
675 section_write8(sect, 0); /* FLAG */
676 break;
677 default:
678 nasm_assert(!"unknown symbol type");
681 section_wbytes(sect, sym->name, strlen(sym->name) + 1);
683 register_reloc(sect, sym->name, field_base,
684 win64 ? IMAGE_REL_AMD64_SECREL :
685 IMAGE_REL_I386_SECREL);
686 register_reloc(sect, sym->name, field_base + 4,
687 win64 ? IMAGE_REL_AMD64_SECTION :
688 IMAGE_REL_I386_SECTION);
691 return len;
694 static void write_symbolinfo_table(struct coff_Section *const sect)
696 const char sep = '\\';
697 const char *creator_str = "The Netwide Assembler " NASM_VER;
700 uint16_t obj_length, creator_length, sym_length;
701 uint32_t field_length = 0, out_len;
703 /* signature, language, workingdir / coff_outfile NULL */
704 obj_length = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1;
705 creator_length = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2;
707 sym_length = ( cv8_state.num_syms[SYMTYPE_CODE] * 7) +
708 ( cv8_state.num_syms[SYMTYPE_PROC] * 7) +
709 ( cv8_state.num_syms[SYMTYPE_LDATA] * 10) +
710 ( cv8_state.num_syms[SYMTYPE_GDATA] * 10) +
711 cv8_state.symbol_lengths;
713 field_length = 2 + obj_length +
714 2 + creator_length +
715 (4 * cv8_state.total_syms) + sym_length;
717 section_write32(sect, 0x000000F1);
718 section_write32(sect, field_length);
720 /* for sub fields, length preceeds type */
722 out_len = write_symbolinfo_obj(sect, sep);
723 nasm_assert(out_len == obj_length);
725 out_len = write_symbolinfo_properties(sect, creator_str);
726 nasm_assert(out_len == creator_length);
728 out_len = write_symbolinfo_symbols(sect);
729 nasm_assert(out_len == sym_length);
732 static inline void align4_table(struct coff_Section *const sect)
734 unsigned diff;
735 uint32_t zero = 0;
736 struct SAA *data = sect->data;
738 if (data->wptr % 4 == 0)
739 return;
741 diff = 4 - (data->wptr % 4);
742 if (diff)
743 section_wbytes(sect, &zero, diff);
746 static void build_symbol_table(struct coff_Section *const sect)
748 section_write32(sect, 0x00000004);
750 write_filename_table(sect);
751 align4_table(sect);
752 write_sourcefile_table(sect);
753 align4_table(sect);
754 write_linenumber_table(sect);
755 align4_table(sect);
756 write_symbolinfo_table(sect);
757 align4_table(sect);
760 static void build_type_table(struct coff_Section *const sect)
762 uint16_t field_len;
763 struct cv8_symbol *sym;
765 section_write32(sect, 0x00000004);
767 saa_rewind(cv8_state.symbols);
768 while ((sym = saa_rstruct(cv8_state.symbols))) {
769 if (sym->type != SYMTYPE_PROC)
770 continue;
772 /* proc leaf */
774 field_len = 2 + 4 + 4 + 4 + 2;
775 section_write16(sect, field_len);
776 section_write16(sect, 0x1008); /* PROC type */
778 section_write32(sect, 0x00000003); /* return type */
779 section_write32(sect, 0); /* calling convention (default) */
780 section_write32(sect, sym->typeindex);
781 section_write16(sect, 0); /* # params */
783 /* arglist */
785 field_len = 2 + 4;
786 section_write16(sect, field_len);
787 section_write16(sect, 0x1201); /* ARGLIST */
788 section_write32(sect, 0); /*num params */