1 /* ----------------------------------------------------------------------- *
3 * Copyright 1996-2017 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
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
55 static void cv8_init(void);
56 static void cv8_linenum(const char *filename
, int32_t linenumber
,
58 static void cv8_deflabel(char *name
, int32_t segment
, int64_t offset
,
59 int is_global
, char *special
);
60 static void cv8_typevalue(int32_t type
);
61 static void cv8_output(int type
, void *param
);
62 static void cv8_cleanup(void);
64 const struct dfmt df_cv8
= {
65 "Codeview 8", /* .fullname */
66 "cv8", /* .shortname */
68 cv8_linenum
, /* .linenum */
69 cv8_deflabel
, /* .debug_deflabel */
70 null_debug_directive
, /* .debug_directive */
71 cv8_typevalue
, /* .debug_typevalue */
72 cv8_output
, /* .debug_output */
73 cv8_cleanup
, /* .cleanup */
74 NULL
/* pragma list */
77 /*******************************************************************************
79 ******************************************************************************/
87 struct source_file
*next
;
90 uint32_t sourcetbl_off
;
95 unsigned char md5sum
[MD5_HASHBYTES
];
113 enum symbol_type type
;
122 TYPE_UNREGISTERED
= 0x0000, /* T_NOTYPE */
128 TYPE_REAL32
= 0x0040,
129 TYPE_REAL64
= 0x0041,
130 TYPE_REAL80
= 0x0042,
131 TYPE_REAL128
= 0x0043,
132 TYPE_REAL256
= 0x0044,
141 uint32_t text_offset
;
143 struct source_file
*source_files
, **source_files_tail
;
144 const char *last_filename
;
145 struct source_file
*last_source_file
;
146 struct hash_table file_hash
;
148 uint32_t total_filename_len
;
151 unsigned total_lines
;
154 struct cv8_symbol
*last_sym
;
155 unsigned num_syms
[SYMTYPE_MAX
];
156 unsigned symbol_lengths
;
164 struct cv8_state cv8_state
;
166 static void cv8_init(void)
168 const uint32_t sect_flags
= IMAGE_SCN_MEM_READ
|
169 IMAGE_SCN_MEM_DISCARDABLE
|
170 IMAGE_SCN_CNT_INITIALIZED_DATA
|
171 IMAGE_SCN_ALIGN_1BYTES
;
173 cv8_state
.symbol_sect
= coff_make_section(".debug$S", sect_flags
);
174 cv8_state
.type_sect
= coff_make_section(".debug$T", sect_flags
);
176 cv8_state
.text_offset
= 0;
178 cv8_state
.source_files
= NULL
;
179 cv8_state
.source_files_tail
= &cv8_state
.source_files
;
180 hash_init(&cv8_state
.file_hash
, HASH_MEDIUM
);
182 cv8_state
.num_files
= 0;
183 cv8_state
.total_filename_len
= 0;
185 cv8_state
.total_lines
= 0;
187 cv8_state
.symbols
= saa_init(sizeof(struct cv8_symbol
));
188 cv8_state
.last_sym
= NULL
;
191 static struct source_file
*register_file(const char *filename
);
192 static struct coff_Section
*find_section(int32_t segto
);
194 static void cv8_linenum(const char *filename
, int32_t linenumber
,
197 struct coff_Section
*s
;
199 struct source_file
*file
;
201 file
= register_file(filename
);
203 s
= find_section(segto
);
207 if ((s
->flags
& IMAGE_SCN_MEM_EXECUTE
) == 0)
210 li
= saa_wstruct(file
->lines
);
211 li
->file_offset
= cv8_state
.text_offset
;
212 li
->linenumber
= linenumber
;
215 cv8_state
.total_lines
++;
218 static void cv8_deflabel(char *name
, int32_t segment
, int64_t offset
,
219 int is_global
, char *special
)
221 struct cv8_symbol
*sym
;
222 struct coff_Section
*s
;
226 s
= find_section(segment
);
230 sym
= saa_wstruct(cv8_state
.symbols
);
232 if (s
->flags
& IMAGE_SCN_MEM_EXECUTE
)
233 sym
->type
= is_global
? SYMTYPE_PROC
: SYMTYPE_CODE
;
235 sym
->type
= is_global
? SYMTYPE_GDATA
: SYMTYPE_LDATA
;
236 cv8_state
.num_syms
[sym
->type
]++;
237 cv8_state
.total_syms
++;
239 sym
->section
= segment
;
240 sym
->secrel
= offset
;
241 sym
->symtype
= TYPE_UNREGISTERED
;
245 sym
->name
= nasm_strdup(name
);
246 cv8_state
.symbol_lengths
+= strlen(sym
->name
) + 1;
248 if (cv8_state
.last_sym
&& cv8_state
.last_sym
->section
== segment
)
249 cv8_state
.last_sym
->size
= offset
- cv8_state
.last_sym
->secrel
;
250 cv8_state
.last_sym
= sym
;
253 static void cv8_typevalue(int32_t type
)
255 if (!cv8_state
.last_sym
)
257 if (cv8_state
.last_sym
->symtype
!= TYPE_UNREGISTERED
)
260 switch (TYM_TYPE(type
)) {
262 cv8_state
.last_sym
->symtype
= TYPE_BYTE
;
265 cv8_state
.last_sym
->symtype
= TYPE_WORD
;
268 cv8_state
.last_sym
->symtype
= TYPE_DWORD
;
271 cv8_state
.last_sym
->symtype
= TYPE_QUAD
;
274 cv8_state
.last_sym
->symtype
= TYPE_REAL32
;
277 cv8_state
.last_sym
->symtype
= TYPE_REAL80
;
280 cv8_state
.last_sym
->symtype
= TYPE_REAL128
;
283 cv8_state
.last_sym
->symtype
= TYPE_REAL256
;
286 cv8_state
.last_sym
->symtype
= TYPE_REAL512
;
295 static void cv8_output(int type
, void *param
)
297 struct coff_DebugInfo
*dinfo
= param
;
301 if (dinfo
->section
&& dinfo
->section
->name
&&
302 !strncmp(dinfo
->section
->name
, ".text", 5))
303 cv8_state
.text_offset
+= dinfo
->size
;
306 static void build_symbol_table(struct coff_Section
*const sect
);
307 static void build_type_table(struct coff_Section
*const sect
);
309 static void cv8_cleanup(void)
311 struct cv8_symbol
*sym
;
312 struct source_file
*file
;
314 struct coff_Section
*symbol_sect
= coff_sects
[cv8_state
.symbol_sect
];
315 struct coff_Section
*type_sect
= coff_sects
[cv8_state
.type_sect
];
317 cv8_state
.outfile
.name
= nasm_realpath(outname
);
318 cv8_state
.outfile
.namebytes
= strlen(cv8_state
.outfile
.name
) + 1;
320 build_symbol_table(symbol_sect
);
321 build_type_table(type_sect
);
323 list_for_each(file
, cv8_state
.source_files
) {
324 nasm_free(file
->fullname
);
325 saa_free(file
->lines
);
328 hash_free(&cv8_state
.file_hash
);
330 saa_rewind(cv8_state
.symbols
);
331 while ((sym
= saa_rstruct(cv8_state
.symbols
)))
332 nasm_free(sym
->name
);
333 saa_free(cv8_state
.symbols
);
335 nasm_free(cv8_state
.outfile
.name
);
338 /*******************************************************************************
340 ******************************************************************************/
341 static void calc_md5(const char *const filename
,
342 unsigned char sum
[MD5_HASHBYTES
])
345 unsigned char *file_buf
;
349 f
= pp_input_fopen(filename
, NF_BINARY
);
353 file_buf
= nasm_zalloc(BUFSIZ
);
357 size_t i
= fread(file_buf
, 1, BUFSIZ
, f
);
362 MD5Update(&ctx
, file_buf
, i
);
372 nasm_error(ERR_NONFATAL
, "unable to hash file %s. "
373 "Debug information may be unavailable.\n",
379 static struct source_file
*register_file(const char *filename
)
381 struct source_file
*file
;
384 struct hash_insert hi
;
387 * The common case is that we are invoked with the same filename
388 * as we were last time. Make this a pointer comparison: this is
389 * safe because the NASM core code allocates each filename once
390 * and never frees it.
392 if (likely(cv8_state
.last_filename
== filename
))
393 return cv8_state
.last_source_file
;
395 cv8_state
.last_filename
= filename
;
397 filep
= hash_find(&cv8_state
.file_hash
, filename
, &hi
);
401 /* New filename encounter */
403 fullpath
= nasm_realpath(filename
);
405 file
= nasm_zalloc(sizeof(*file
));
407 file
->filename
= filename
;
408 file
->fullname
= fullpath
;
409 file
->fullnamelen
= strlen(fullpath
);
410 file
->lines
= saa_init(sizeof(struct linepair
));
411 *cv8_state
.source_files_tail
= file
;
412 cv8_state
.source_files_tail
= &file
->next
;
413 calc_md5(fullpath
, file
->md5sum
);
415 hash_add(&hi
, filename
, file
);
417 cv8_state
.num_files
++;
418 cv8_state
.total_filename_len
+= file
->fullnamelen
+ 1;
421 cv8_state
.last_source_file
= file
;
425 static struct coff_Section
*find_section(int32_t segto
)
429 for (i
= 0; i
< coff_nsects
; i
++) {
430 struct coff_Section
*sec
;
433 if (segto
== sec
->index
)
439 static void register_reloc(struct coff_Section
*const sect
,
440 char *sym
, uint32_t addr
, uint16_t type
)
442 struct coff_Reloc
*r
;
443 struct coff_Section
*sec
;
446 r
= *sect
->tail
= nasm_malloc(sizeof(struct coff_Reloc
));
447 sect
->tail
= &r
->next
;
452 r
->symbase
= SECT_SYMBOLS
;
456 for (i
= 0; i
< (uint32_t)coff_nsects
; i
++) {
458 if (!strcmp(sym
, sec
->name
)) {
464 saa_rewind(coff_syms
);
465 for (i
= 0; i
< coff_nsyms
; i
++) {
466 struct coff_Symbol
*s
= saa_rstruct(coff_syms
);
468 if (s
->strpos
== -1 && !strcmp(sym
, s
->name
)) {
470 } else if (s
->strpos
!= -1) {
474 symname
= nasm_malloc(s
->namlen
+ 1);
475 saa_fread(coff_strs
, s
->strpos
-4, symname
, s
->namlen
);
476 symname
[s
->namlen
] = '\0';
477 res
= strcmp(sym
, symname
);
483 nasm_panic("codeview: relocation for unregistered symbol: %s", sym
);
486 static inline void section_write32(struct coff_Section
*sect
, uint32_t val
)
488 saa_write32(sect
->data
, val
);
492 static inline void section_write16(struct coff_Section
*sect
, uint16_t val
)
494 saa_write16(sect
->data
, val
);
498 static inline void section_write8(struct coff_Section
*sect
, uint8_t val
)
500 saa_write8(sect
->data
, val
);
504 static inline void section_wbytes(struct coff_Section
*sect
, const void *buf
,
507 saa_wbytes(sect
->data
, buf
, len
);
511 static void write_filename_table(struct coff_Section
*const sect
)
513 uint32_t field_length
;
514 uint32_t tbl_off
= 1; /* offset starts at 1 to skip NULL entry */
515 struct source_file
*file
;
517 nasm_assert(cv8_state
.source_files
!= NULL
);
518 nasm_assert(cv8_state
.num_files
> 0);
519 nasm_assert(cv8_state
.total_filename_len
> 0);
521 field_length
= 1 + cv8_state
.total_filename_len
;
523 section_write32(sect
, 0x000000F3);
524 section_write32(sect
, field_length
);
526 section_write8(sect
, 0);
528 list_for_each(file
, cv8_state
.source_files
) {
529 section_wbytes(sect
, file
->fullname
, file
->fullnamelen
+ 1);
530 file
->filetbl_off
= tbl_off
;
531 tbl_off
+= file
->fullnamelen
+ 1;
535 static void write_sourcefile_table(struct coff_Section
*const sect
)
537 const uint32_t entry_size
= 4 + 2 + MD5_HASHBYTES
+ 2;
539 uint32_t field_length
= 0;
540 uint32_t tbl_off
= 0;
541 struct source_file
*file
;
543 field_length
= entry_size
* cv8_state
.num_files
;
545 section_write32(sect
, 0x000000F4);
546 section_write32(sect
, field_length
);
548 list_for_each(file
, cv8_state
.source_files
) {
549 nasm_assert(file
->filetbl_off
> 0);
550 section_write32(sect
, file
->filetbl_off
);
551 section_write16(sect
, 0x0110);
552 section_wbytes(sect
, file
->md5sum
, MD5_HASHBYTES
);
553 section_write16(sect
, 0);
555 file
->sourcetbl_off
= tbl_off
;
556 tbl_off
+= entry_size
;
560 static void write_linenumber_table(struct coff_Section
*const sect
)
562 const uint32_t file_field_len
= 12;
563 const uint32_t line_field_len
= 8;
566 uint32_t field_length
= 0;
568 struct source_file
*file
;
569 struct coff_Section
*s
;
571 for (i
= 0; i
< coff_nsects
; i
++) {
572 if (!strncmp(coff_sects
[i
]->name
, ".text", 5))
576 if (i
== coff_nsects
)
581 field_length
+= (cv8_state
.num_files
* file_field_len
);
582 field_length
+= (cv8_state
.total_lines
* line_field_len
);
584 section_write32(sect
, 0x000000F2);
585 section_write32(sect
, field_length
);
587 field_base
= sect
->len
;
588 section_write32(sect
, 0); /* SECREL, updated by relocation */
589 section_write16(sect
, 0); /* SECTION, updated by relocation*/
590 section_write16(sect
, 0); /* pad */
591 section_write32(sect
, s
->len
);
593 register_reloc(sect
, ".text", field_base
,
594 win64
? IMAGE_REL_AMD64_SECREL
: IMAGE_REL_I386_SECREL
);
596 register_reloc(sect
, ".text", field_base
+ 4,
597 win64
? IMAGE_REL_AMD64_SECTION
: IMAGE_REL_I386_SECTION
);
599 list_for_each(file
, cv8_state
.source_files
) {
603 section_write32(sect
, file
->sourcetbl_off
);
604 section_write32(sect
, file
->num_lines
);
605 section_write32(sect
, file_field_len
+ (file
->num_lines
* line_field_len
));
608 saa_rewind(file
->lines
);
609 while ((li
= saa_rstruct(file
->lines
))) {
610 section_write32(sect
, li
->file_offset
);
611 section_write32(sect
, li
->linenumber
|= 0x80000000);
616 static uint16_t write_symbolinfo_obj(struct coff_Section
*sect
)
620 obj_len
= 2 + 4 + cv8_state
.outfile
.namebytes
;
622 section_write16(sect
, obj_len
);
623 section_write16(sect
, 0x1101);
624 section_write32(sect
, 0); /* ASM language */
625 section_wbytes(sect
, cv8_state
.outfile
.name
, cv8_state
.outfile
.namebytes
);
630 static uint16_t write_symbolinfo_properties(struct coff_Section
*sect
,
631 const char *const creator_str
)
633 /* https://github.com/Microsoft/microsoft-pdb/blob/1d60e041/include/cvinfo.h#L3313 */
634 uint16_t creator_len
;
636 creator_len
= 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str
)+1 + 2;
639 * We used to use a language ID of 3 for "MASM", since it's closest of the
640 * options available; however, BinScope from WACK (the Windows Application
641 * Certification Kit) tests for specific minimum MASM versions and trying to
642 * match an increasing sequence of random MASM version/build numbers seems
643 * like a fool's errand.
645 * Instead, use a different language ID (NASM is, after all, not MASM
646 * syntax) and just write the actual NASM version number. BinScope appears
647 * to be happy with that.
650 section_write16(sect
, creator_len
);
651 section_write16(sect
, 0x1116);
652 section_write32(sect
, 'N'); /* language: 'N' (0x4e) for "NASM"; flags are 0 */
654 section_write16(sect
, 0x00D0); /* machine */
656 section_write16(sect
, 0x0006); /* machine */
658 nasm_assert(!"neither win32 nor win64 are set!");
659 section_write16(sect
, 0); /* verFEMajor */
660 section_write16(sect
, 0); /* verFEMinor */
661 section_write16(sect
, 0); /* verFEBuild */
663 /* BinScope/WACK insist on version >= 8.0.50727 */
664 section_write16(sect
, NASM_MAJOR_VER
); /* verMajor */
665 section_write16(sect
, NASM_MINOR_VER
); /* verMinor */
666 section_write16(sect
, NASM_SUBMINOR_VER
*100 + NASM_PATCHLEVEL_VER
); /* verBuild */
668 section_wbytes(sect
, creator_str
, strlen(creator_str
)+1); /* verSt */
670 * normally there would be key/value pairs here, but they aren't
671 * necessary. They are terminated by 2B
673 section_write16(sect
, 0);
678 static uint16_t write_symbolinfo_symbols(struct coff_Section
*sect
)
680 uint16_t len
= 0, field_len
;
682 struct cv8_symbol
*sym
;
684 saa_rewind(cv8_state
.symbols
);
685 while ((sym
= saa_rstruct(cv8_state
.symbols
))) {
689 field_len
= 12 + strlen(sym
->name
) + 1;
690 len
+= field_len
- 2;
691 section_write16(sect
, field_len
);
692 if (sym
->type
== SYMTYPE_LDATA
)
693 section_write16(sect
, 0x110C);
695 section_write16(sect
, 0x110D);
696 section_write32(sect
, sym
->symtype
);
698 field_base
= sect
->len
;
699 section_write32(sect
, 0); /* SECREL */
700 section_write16(sect
, 0); /* SECTION */
704 field_len
= 9 + strlen(sym
->name
) + 1;
705 len
+= field_len
- 2;
706 section_write16(sect
, field_len
);
707 section_write16(sect
, 0x1105);
709 field_base
= sect
->len
;
710 section_write32(sect
, 0); /* SECREL */
711 section_write16(sect
, 0); /* SECTION */
712 section_write8(sect
, 0); /* FLAG */
715 nasm_assert(!"unknown symbol type");
718 section_wbytes(sect
, sym
->name
, strlen(sym
->name
) + 1);
720 register_reloc(sect
, sym
->name
, field_base
,
721 win64
? IMAGE_REL_AMD64_SECREL
:
722 IMAGE_REL_I386_SECREL
);
723 register_reloc(sect
, sym
->name
, field_base
+ 4,
724 win64
? IMAGE_REL_AMD64_SECTION
:
725 IMAGE_REL_I386_SECTION
);
731 static void write_symbolinfo_table(struct coff_Section
*const sect
)
733 static const char creator_str
[] = "The Netwide Assembler " NASM_VER
;
734 uint16_t obj_length
, creator_length
, sym_length
;
735 uint32_t field_length
= 0, out_len
;
737 nasm_assert(cv8_state
.outfile
.namebytes
);
739 /* signature, language, outfile NULL */
740 obj_length
= 2 + 4 + cv8_state
.outfile
.namebytes
;
741 creator_length
= 2 + 4 + 2 + 3*2 + 3*2 + strlen(creator_str
)+1 + 2;
743 sym_length
= ( cv8_state
.num_syms
[SYMTYPE_CODE
] * 7) +
744 ( cv8_state
.num_syms
[SYMTYPE_PROC
] * 7) +
745 ( cv8_state
.num_syms
[SYMTYPE_LDATA
] * 10) +
746 ( cv8_state
.num_syms
[SYMTYPE_GDATA
] * 10) +
747 cv8_state
.symbol_lengths
;
749 field_length
= 2 + obj_length
+
751 (4 * cv8_state
.total_syms
) + sym_length
;
753 section_write32(sect
, 0x000000F1);
754 section_write32(sect
, field_length
);
756 /* for sub fields, length preceeds type */
758 out_len
= write_symbolinfo_obj(sect
);
759 nasm_assert(out_len
== obj_length
);
761 out_len
= write_symbolinfo_properties(sect
, creator_str
);
762 nasm_assert(out_len
== creator_length
);
764 out_len
= write_symbolinfo_symbols(sect
);
765 nasm_assert(out_len
== sym_length
);
768 static inline void align4_table(struct coff_Section
*const sect
)
772 struct SAA
*data
= sect
->data
;
774 if (data
->wptr
% 4 == 0)
777 diff
= 4 - (data
->wptr
% 4);
779 section_wbytes(sect
, &zero
, diff
);
782 static void build_symbol_table(struct coff_Section
*const sect
)
784 section_write32(sect
, 0x00000004);
786 write_filename_table(sect
);
788 write_sourcefile_table(sect
);
790 write_linenumber_table(sect
);
792 write_symbolinfo_table(sect
);
796 static void build_type_table(struct coff_Section
*const sect
)
799 struct cv8_symbol
*sym
;
801 section_write32(sect
, 0x00000004);
803 saa_rewind(cv8_state
.symbols
);
804 while ((sym
= saa_rstruct(cv8_state
.symbols
))) {
805 if (sym
->type
!= SYMTYPE_PROC
)
810 field_len
= 2 + 4 + 4 + 4 + 2;
811 section_write16(sect
, field_len
);
812 section_write16(sect
, 0x1008); /* PROC type */
814 section_write32(sect
, 0x00000003); /* return type */
815 section_write32(sect
, 0); /* calling convention (default) */
816 section_write32(sect
, sym
->typeindex
);
817 section_write16(sect
, 0); /* # params */
822 section_write16(sect
, field_len
);
823 section_write16(sect
, 0x1201); /* ARGLIST */
824 section_write32(sect
, 0); /*num params */