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
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
49 #include "output/outlib.h"
50 #include "output/pecoff.h"
53 static void cv8_init(void);
54 static void cv8_linenum(const char *filename
, int32_t linenumber
,
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 */
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 /*******************************************************************************
76 ******************************************************************************/
83 struct source_file
*next
;
86 uint32_t sourcetbl_off
;
91 unsigned char md5sum
[MD5_HASHBYTES
];
109 enum symbol_type type
;
118 TYPE_UNREGISTERED
= 0x0000, /* T_NOTYPE */
124 TYPE_REAL32
= 0x0040,
125 TYPE_REAL64
= 0x0041,
126 TYPE_REAL80
= 0x0042,
127 TYPE_REAL128
= 0x0043,
128 TYPE_REAL256
= 0x0044,
137 uint32_t text_offset
;
139 struct source_file source_file
;
141 uint32_t total_filename_len
;
143 unsigned total_lines
;
146 struct cv8_symbol
*last_sym
;
147 unsigned num_syms
[SYMTYPE_MAX
];
148 unsigned symbol_lengths
;
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
,
187 struct coff_Section
*s
;
189 struct source_file
*file
;
191 s
= find_section(segto
);
195 if ((s
->flags
& IMAGE_SCN_MEM_EXECUTE
) == 0)
198 file
= register_file(filename
);
200 li
= saa_wstruct(file
->lines
);
201 li
->file_offset
= cv8_state
.text_offset
;
202 li
->linenumber
= linenumber
;
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
;
216 s
= find_section(segment
);
220 sym
= saa_wstruct(cv8_state
.symbols
);
222 if (s
->flags
& IMAGE_SCN_MEM_EXECUTE
)
223 sym
->type
= is_global
? SYMTYPE_PROC
: SYMTYPE_CODE
;
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
;
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
)
247 if (cv8_state
.last_sym
->symtype
!= TYPE_UNREGISTERED
)
250 switch (TYM_TYPE(type
)) {
252 cv8_state
.last_sym
->symtype
= TYPE_BYTE
;
255 cv8_state
.last_sym
->symtype
= TYPE_WORD
;
258 cv8_state
.last_sym
->symtype
= TYPE_DWORD
;
261 cv8_state
.last_sym
->symtype
= TYPE_QUAD
;
264 cv8_state
.last_sym
->symtype
= TYPE_REAL32
;
267 cv8_state
.last_sym
->symtype
= TYPE_REAL80
;
270 cv8_state
.last_sym
->symtype
= TYPE_REAL128
;
273 cv8_state
.last_sym
->symtype
= TYPE_REAL256
;
282 static void cv8_output(int type
, void *param
)
284 struct coff_DebugInfo
*dinfo
= param
;
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
);
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 /*******************************************************************************
331 ******************************************************************************/
332 static void calc_md5(const char *const filename
,
333 unsigned char sum
[MD5_HASHBYTES
])
336 unsigned char *file_buf
;
340 f
= pp_input_fopen(filename
, "rb");
344 file_buf
= nasm_zalloc(BUFSIZ
);
348 size_t i
= fread(file_buf
, 1, BUFSIZ
, f
);
353 MD5Update(&ctx
, file_buf
, i
);
363 nasm_error(ERR_NONFATAL
, "unable to hash file %s. "
364 "Debug information may be unavailable.\n",
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
)) {
383 if (cv8_state
.source_file
.name
== NULL
) {
384 file
= &cv8_state
.source_file
;
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
) {}
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
));
398 calc_md5(fullpath
, file
->md5sum
);
400 cv8_state
.num_files
++;
401 cv8_state
.total_filename_len
+= file
->namelen
+ 1;
406 static struct coff_Section
*find_section(int32_t segto
)
410 for (i
= 0; i
< coff_nsects
; i
++) {
411 struct coff_Section
*sec
;
414 if (segto
== sec
->index
)
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
;
432 r
->symbase
= SECT_SYMBOLS
;
436 for (int i
= 0; i
< coff_nsects
; i
++) {
438 if (!strcmp(sym
, sec
->name
)) {
444 saa_rewind(coff_syms
);
445 for (uint32_t i
= 0; i
< coff_nsyms
; i
++) {
446 struct coff_Symbol
*s
= saa_rstruct(coff_syms
);
448 if (s
->strpos
== -1 && !strcmp(sym
, s
->name
)) {
450 } else if (s
->strpos
!= -1) {
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
);
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
);
472 static inline void section_write16(struct coff_Section
*sect
, uint16_t val
)
474 saa_write16(sect
->data
, val
);
478 static inline void section_write8(struct coff_Section
*sect
, uint8_t val
)
480 saa_write8(sect
->data
, val
);
484 static inline void section_wbytes(struct coff_Section
*sect
, const void *buf
,
487 saa_wbytes(sect
->data
, buf
, 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;
546 uint32_t field_length
= 0;
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))
556 if (i
== coff_nsects
)
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
) {
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
));
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
,
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);
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 */
624 section_write32(sect
, 0x000000D0);
626 section_write32(sect
, 0x00000006);
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);
641 static uint16_t write_symbolinfo_symbols(struct coff_Section
*sect
)
643 uint16_t len
= 0, field_len
;
645 struct cv8_symbol
*sym
;
647 saa_rewind(cv8_state
.symbols
);
648 while ((sym
= saa_rstruct(cv8_state
.symbols
))) {
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);
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 */
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 */
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
);
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
+
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
)
736 struct SAA
*data
= sect
->data
;
738 if (data
->wptr
% 4 == 0)
741 diff
= 4 - (data
->wptr
% 4);
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
);
752 write_sourcefile_table(sect
);
754 write_linenumber_table(sect
);
756 write_symbolinfo_table(sect
);
760 static void build_type_table(struct coff_Section
*const sect
)
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
)
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 */
786 section_write16(sect
, field_len
);
787 section_write16(sect
, 0x1201); /* ARGLIST */
788 section_write32(sect
, 0); /*num params */