codeview: Make md5sum calc read file in 'binary' mode
[nasm.git] / output / codeview.c
blob0a3826851be17dc80dae92b2df37ca92d8475ada
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 const 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 {
78 char *name;
79 unsigned char md5sum[MD5_HASHBYTES];
82 struct linepair {
83 uint32_t file_offset;
84 uint32_t linenumber;
87 enum symbol_type {
88 SYMTYPE_CODE,
89 SYMTYPE_PROC,
90 SYMTYPE_LDATA,
91 SYMTYPE_GDATA,
93 SYMTYPE_MAX
96 struct cv8_symbol {
97 enum symbol_type type;
98 char *name;
100 uint32_t secrel;
101 uint16_t section;
102 uint32_t size;
103 uint32_t typeindex;
105 enum symtype {
106 TYPE_UNREGISTERED = 0x0000, /* T_NOTYPE */
107 TYPE_BYTE = 0x0020,
108 TYPE_WORD = 0x0021,
109 TYPE_DWORD= 0x0022,
110 TYPE_QUAD = 0x0023,
112 TYPE_REAL32 = 0x0040,
113 TYPE_REAL64 = 0x0041,
114 TYPE_REAL80 = 0x0042,
115 TYPE_REAL128= 0x0043,
116 TYPE_REAL256= 0x0044,
117 TYPE_REAL512= 0x0045
118 } symtype;
121 struct cv8_state {
122 int symbol_sect;
123 int type_sect;
125 uint32_t text_offset;
127 struct source_file source_file;
129 struct SAA *lines;
130 uint32_t num_lines;
132 struct SAA *symbols;
133 struct cv8_symbol *last_sym;
134 unsigned num_syms[SYMTYPE_MAX];
135 unsigned symbol_lengths;
136 unsigned total_syms;
138 char *cwd;
140 struct cv8_state cv8_state;
142 static void cv8_init(void)
144 const uint32_t sect_flags = IMAGE_SCN_MEM_READ |
145 IMAGE_SCN_MEM_DISCARDABLE |
146 IMAGE_SCN_CNT_INITIALIZED_DATA |
147 IMAGE_SCN_ALIGN_1BYTES;
149 cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
150 cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
152 cv8_state.text_offset = 0;
154 cv8_state.lines = saa_init(sizeof(struct linepair));
155 cv8_state.num_lines = 0;
157 cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
158 cv8_state.last_sym = NULL;
160 cv8_state.cwd = nasm_realpath(".");
163 static void register_file(const char *filename);
164 static struct coff_Section *find_section(int32_t segto);
166 static void cv8_linenum(const char *filename, int32_t linenumber,
167 int32_t segto)
169 struct coff_Section *s;
170 struct linepair *li;
172 if (cv8_state.source_file.name == NULL)
173 register_file(filename);
175 s = find_section(segto);
176 if (s == NULL)
177 return;
179 if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
180 return;
182 li = saa_wstruct(cv8_state.lines);
183 li->file_offset = cv8_state.text_offset;
184 li->linenumber = linenumber;
186 cv8_state.num_lines++;
189 static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
190 int is_global, char *special)
192 struct cv8_symbol *sym;
193 struct coff_Section *s;
195 (void)special;
197 s = find_section(segment);
198 if (s == NULL)
199 return;
201 sym = saa_wstruct(cv8_state.symbols);
203 if (s->flags & IMAGE_SCN_MEM_EXECUTE)
204 sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
205 else
206 sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
207 cv8_state.num_syms[sym->type]++;
208 cv8_state.total_syms++;
210 sym->section = segment;
211 sym->secrel = offset;
212 sym->symtype = TYPE_UNREGISTERED;
213 sym->size = 0;
214 sym->typeindex = 0;
216 sym->name = nasm_strdup(name);
217 cv8_state.symbol_lengths += strlen(sym->name) + 1;
219 if (cv8_state.last_sym && cv8_state.last_sym->section == segment)
220 cv8_state.last_sym->size = offset - cv8_state.last_sym->secrel;
221 cv8_state.last_sym = sym;
224 static void cv8_typevalue(int32_t type)
226 if (!cv8_state.last_sym)
227 return;
228 if (cv8_state.last_sym->symtype != TYPE_UNREGISTERED)
229 return;
231 switch (TYM_TYPE(type)) {
232 case TY_BYTE:
233 cv8_state.last_sym->symtype = TYPE_BYTE;
234 break;
235 case TY_WORD:
236 cv8_state.last_sym->symtype = TYPE_WORD;
237 break;
238 case TY_DWORD:
239 cv8_state.last_sym->symtype = TYPE_DWORD;
240 break;
241 case TY_QWORD:
242 cv8_state.last_sym->symtype = TYPE_QUAD;
243 break;
244 case TY_FLOAT:
245 cv8_state.last_sym->symtype = TYPE_REAL32;
246 break;
247 case TY_TBYTE:
248 cv8_state.last_sym->symtype = TYPE_REAL80;
249 break;
250 case TY_OWORD:
251 cv8_state.last_sym->symtype = TYPE_REAL128;
252 break;
253 case TY_YWORD:
254 cv8_state.last_sym->symtype = TYPE_REAL256;
255 break;
256 case TY_UNKNOWN:
257 break;
258 case TY_LABEL:
259 break;
263 static void cv8_output(int type, void *param)
265 struct coff_DebugInfo *dinfo = param;
267 (void)type;
269 if (dinfo->section && dinfo->section->name &&
270 !strncmp(dinfo->section->name, ".text", 5))
271 cv8_state.text_offset += dinfo->size;
274 static void build_symbol_table(struct coff_Section *const sect);
275 static void build_type_table(struct coff_Section *const sect);
277 static void cv8_cleanup(void)
279 struct cv8_symbol *sym;
281 struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
282 struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
284 build_symbol_table(symbol_sect);
285 build_type_table(type_sect);
287 if (cv8_state.source_file.name != NULL)
288 free(cv8_state.source_file.name);
290 if (cv8_state.cwd != NULL)
291 free(cv8_state.cwd);
293 saa_free(cv8_state.lines);
295 saa_rewind(cv8_state.symbols);
296 while ((sym = saa_rstruct(cv8_state.symbols)))
297 free(sym->name);
298 saa_free(cv8_state.symbols);
301 /*******************************************************************************
302 * implementation
303 ******************************************************************************/
304 static void calc_md5(const char *const filename,
305 unsigned char sum[MD5_HASHBYTES])
307 int success = 0;
308 unsigned char *file_buf;
309 FILE *f;
310 MD5_CTX ctx;
312 f = pp_input_fopen(filename, "rb");
313 if (!f)
314 goto done;
316 file_buf = nasm_zalloc(BUFSIZ);
318 MD5Init(&ctx);
319 while (!feof(f)) {
320 size_t i = fread(file_buf, 1, BUFSIZ, f);
321 if (ferror(f))
322 goto done_0;
323 else if (i == 0)
324 break;
325 MD5Update(&ctx, file_buf, i);
327 MD5Final(sum, &ctx);
329 success = 1;
330 done_0:
331 nasm_free(file_buf);
332 fclose(f);
333 done:
334 if (!success) {
335 nasm_error(ERR_NONFATAL, "unable to hash file %s. "
336 "Debug information may be unavailable.\n",
337 filename);
339 return;
342 static void register_file(const char *filename)
344 cv8_state.source_file.name = nasm_realpath(filename);
345 memset(cv8_state.source_file.md5sum, 0, MD5_HASHBYTES);
346 calc_md5(filename, cv8_state.source_file.md5sum);
349 static struct coff_Section *find_section(int32_t segto)
351 int i;
353 for (i = 0; i < coff_nsects; i++) {
354 struct coff_Section *sec;
356 sec = coff_sects[i];
357 if (segto == sec->index)
358 return sec;
360 return NULL;
363 static void register_reloc(struct coff_Section *const sect,
364 char *sym, uint32_t addr, uint16_t type)
366 struct coff_Reloc *r;
367 struct coff_Section *sec;
369 r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
370 sect->tail = &r->next;
371 r->next = NULL;
372 sect->nrelocs++;
374 r->address = addr;
375 r->symbase = SECT_SYMBOLS;
376 r->type = type;
378 r->symbol = 0;
379 for (int i = 0; i < coff_nsects; i++) {
380 sec = coff_sects[i];
381 if (!strcmp(sym, sec->name)) {
382 return;
384 r->symbol += 2;
387 saa_rewind(coff_syms);
388 for (uint32_t i = 0; i < coff_nsyms; i++) {
389 struct coff_Symbol *s = saa_rstruct(coff_syms);
390 r->symbol++;
391 if (s->strpos == -1 && !strcmp(sym, s->name)) {
392 return;
393 } else if (s->strpos != -1) {
394 int res;
395 char *symname;
397 symname = nasm_malloc(s->namlen + 1);
398 saa_fread(coff_strs, s->strpos-4, symname, s->namlen);
399 symname[s->namlen] = '\0';
400 res = strcmp(sym, symname);
401 nasm_free(symname);
402 if (!res)
403 return;
406 nasm_panic(0, "codeview: relocation for unregistered symbol: %s", sym);
409 static inline void section_write32(struct coff_Section *sect, uint32_t val)
411 saa_write32(sect->data, val);
412 sect->len += 4;
415 static inline void section_write16(struct coff_Section *sect, uint16_t val)
417 saa_write16(sect->data, val);
418 sect->len += 2;
421 static inline void section_write8(struct coff_Section *sect, uint8_t val)
423 saa_write8(sect->data, val);
424 sect->len++;
427 static inline void section_wbytes(struct coff_Section *sect, const void *buf,
428 size_t len)
430 saa_wbytes(sect->data, buf, len);
431 sect->len += len;
434 static void write_filename_table(struct coff_Section *const sect)
436 uint32_t field_length = 0;
437 size_t filename_len = strlen(cv8_state.source_file.name);
439 field_length = 1 + filename_len + 1;
441 section_write32(sect, 0x000000F3);
442 section_write32(sect, field_length);
444 section_write8(sect, 0);
445 section_wbytes(sect, cv8_state.source_file.name, filename_len + 1);
448 static void write_sourcefile_table(struct coff_Section *const sect)
450 uint32_t field_length = 0;
452 field_length = 4 + 2 + MD5_HASHBYTES + 2;
454 section_write32(sect, 0x000000F4);
455 section_write32(sect, field_length);
457 section_write32(sect, 1); /* offset of filename in filename str table */
458 section_write16(sect, 0x0110);
459 section_wbytes(sect, cv8_state.source_file.md5sum, MD5_HASHBYTES);
460 section_write16(sect, 0);
463 static void write_linenumber_table(struct coff_Section *const sect)
465 int i;
466 uint32_t field_length = 0;
467 size_t field_base;
468 struct coff_Section *s;
469 struct linepair *li;
471 for (i = 0; i < coff_nsects; i++) {
472 if (!strncmp(coff_sects[i]->name, ".text", 5))
473 break;
476 if (i == coff_nsects)
477 return;
478 s = coff_sects[i];
480 field_length = 12 + 12 + (cv8_state.num_lines * 8);
482 section_write32(sect, 0x000000F2);
483 section_write32(sect, field_length);
485 field_base = sect->len;
486 section_write32(sect, 0); /* SECREL, updated by relocation */
487 section_write16(sect, 0); /* SECTION, updated by relocation*/
488 section_write16(sect, 0); /* pad */
489 section_write32(sect, s->len);
491 register_reloc(sect, ".text", field_base,
492 win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
494 register_reloc(sect, ".text", field_base + 4,
495 win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
497 /* 1 or more source mappings (we assume only 1) */
498 section_write32(sect, 0);
499 section_write32(sect, cv8_state.num_lines);
500 section_write32(sect, 12 + (cv8_state.num_lines * 8));
502 /* the pairs */
503 saa_rewind(cv8_state.lines);
504 while ((li = saa_rstruct(cv8_state.lines))) {
505 section_write32(sect, li->file_offset);
506 section_write32(sect, li->linenumber |= 0x80000000);
510 static uint16_t write_symbolinfo_obj(struct coff_Section *sect,
511 const char sep)
513 uint16_t obj_len;
515 obj_len = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1;
517 section_write16(sect, obj_len);
518 section_write16(sect, 0x1101);
519 section_write32(sect, 0); /* ASM language */
520 section_wbytes(sect, cv8_state.cwd, strlen(cv8_state.cwd));
521 section_write8(sect, sep);
522 section_wbytes(sect, coff_outfile, strlen(coff_outfile)+1);
524 return obj_len;
527 static uint16_t write_symbolinfo_properties(struct coff_Section *sect,
528 const char *const creator_str)
530 uint16_t creator_len;
532 creator_len = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2;
534 section_write16(sect, creator_len);
535 section_write16(sect, 0x1116);
536 section_write32(sect, 3); /* language */
537 if (win64)
538 section_write32(sect, 0x000000D0);
539 else if (win32)
540 section_write32(sect, 0x00000006);
541 else
542 nasm_assert(!"neither win32 nor win64 are set!");
543 section_write32(sect, 0); /* flags*/
544 section_write32(sect, 8); /* version */
545 section_wbytes(sect, creator_str, strlen(creator_str)+1);
547 * normally there would be key/value pairs here, but they aren't
548 * necessary. They are terminated by 2B
550 section_write16(sect, 0);
552 return creator_len;
555 static uint16_t write_symbolinfo_symbols(struct coff_Section *sect)
557 uint16_t len = 0, field_len;
558 uint32_t field_base;
559 struct cv8_symbol *sym;
561 saa_rewind(cv8_state.symbols);
562 while ((sym = saa_rstruct(cv8_state.symbols))) {
563 switch (sym->type) {
564 case SYMTYPE_LDATA:
565 case SYMTYPE_GDATA:
566 field_len = 12 + strlen(sym->name) + 1;
567 len += field_len - 2;
568 section_write16(sect, field_len);
569 if (sym->type == SYMTYPE_LDATA)
570 section_write16(sect, 0x110C);
571 else
572 section_write16(sect, 0x110D);
573 section_write32(sect, sym->symtype);
575 field_base = sect->len;
576 section_write32(sect, 0); /* SECREL */
577 section_write16(sect, 0); /* SECTION */
578 break;
579 case SYMTYPE_PROC:
580 case SYMTYPE_CODE:
581 field_len = 9 + strlen(sym->name) + 1;
582 len += field_len - 2;
583 section_write16(sect, field_len);
584 section_write16(sect, 0x1105);
586 field_base = sect->len;
587 section_write32(sect, 0); /* SECREL */
588 section_write16(sect, 0); /* SECTION */
589 section_write8(sect, 0); /* FLAG */
590 break;
591 default:
592 nasm_assert(!"unknown symbol type");
595 section_wbytes(sect, sym->name, strlen(sym->name) + 1);
597 register_reloc(sect, sym->name, field_base,
598 win64 ? IMAGE_REL_AMD64_SECREL :
599 IMAGE_REL_I386_SECREL);
600 register_reloc(sect, sym->name, field_base + 4,
601 win64 ? IMAGE_REL_AMD64_SECTION :
602 IMAGE_REL_I386_SECTION);
605 return len;
608 static void write_symbolinfo_table(struct coff_Section *const sect)
610 const char sep = '\\';
611 const char *creator_str = "The Netwide Assembler " NASM_VER;
614 uint16_t obj_length, creator_length, sym_length;
615 uint32_t field_length = 0, out_len;
617 /* signature, language, workingdir / coff_outfile NULL */
618 obj_length = 2 + 4 + strlen(cv8_state.cwd)+ 1 + strlen(coff_outfile) +1;
619 creator_length = 2 + 4 + 4 + 4 + 4 + strlen(creator_str)+1 + 2;
621 sym_length = ( cv8_state.num_syms[SYMTYPE_CODE] * 7) +
622 ( cv8_state.num_syms[SYMTYPE_PROC] * 7) +
623 ( cv8_state.num_syms[SYMTYPE_LDATA] * 10) +
624 ( cv8_state.num_syms[SYMTYPE_GDATA] * 10) +
625 cv8_state.symbol_lengths;
627 field_length = 2 + obj_length +
628 2 + creator_length +
629 (4 * cv8_state.total_syms) + sym_length;
631 section_write32(sect, 0x000000F1);
632 section_write32(sect, field_length);
634 /* for sub fields, length preceeds type */
636 out_len = write_symbolinfo_obj(sect, sep);
637 nasm_assert(out_len == obj_length);
639 out_len = write_symbolinfo_properties(sect, creator_str);
640 nasm_assert(out_len == creator_length);
642 out_len = write_symbolinfo_symbols(sect);
643 nasm_assert(out_len == sym_length);
646 static inline void align4_table(struct coff_Section *const sect)
648 unsigned diff;
649 uint32_t zero = 0;
650 struct SAA *data = sect->data;
652 if (data->wptr % 4 == 0)
653 return;
655 diff = 4 - (data->wptr % 4);
656 if (diff)
657 section_wbytes(sect, &zero, diff);
660 static void build_symbol_table(struct coff_Section *const sect)
662 section_write32(sect, 0x00000004);
664 write_filename_table(sect);
665 align4_table(sect);
666 write_sourcefile_table(sect);
667 align4_table(sect);
668 write_linenumber_table(sect);
669 align4_table(sect);
670 write_symbolinfo_table(sect);
671 align4_table(sect);
674 static void build_type_table(struct coff_Section *const sect)
676 uint16_t field_len;
677 struct cv8_symbol *sym;
679 section_write32(sect, 0x00000004);
681 saa_rewind(cv8_state.symbols);
682 while ((sym = saa_rstruct(cv8_state.symbols))) {
683 if (sym->type != SYMTYPE_PROC)
684 continue;
686 /* proc leaf */
688 field_len = 2 + 4 + 4 + 4 + 2;
689 section_write16(sect, field_len);
690 section_write16(sect, 0x1008); /* PROC type */
692 section_write32(sect, 0x00000003); /* return type */
693 section_write32(sect, 0); /* calling convention (default) */
694 section_write32(sect, sym->typeindex);
695 section_write16(sect, 0); /* # params */
697 /* arglist */
699 field_len = 2 + 4;
700 section_write16(sect, field_len);
701 section_write16(sect, 0x1201); /* ARGLIST */
702 section_write32(sect, 0); /*num params */