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
48 #include "output/outlib.h"
49 #include "output/pecoff.h"
52 static void cv8_init(void);
53 static void cv8_linenum(const char *filename
, int32_t linenumber
,
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 "Codeview 8", /* .fullname */
63 "cv8", /* .shortname */
65 cv8_linenum
, /* .linenum */
66 cv8_deflabel
, /* .debug_deflabel */
67 null_debug_directive
, /* .debug_directive */
68 cv8_typevalue
, /* .debug_typevalue */
69 cv8_output
, /* .debug_output */
70 cv8_cleanup
, /* .cleanup */
73 /*******************************************************************************
75 ******************************************************************************/
78 unsigned char md5sum
[MD5_HASHBYTES
];
96 enum symbol_type type
;
105 TYPE_UNREGISTERED
= 0x0000, /* T_NOTYPE */
111 TYPE_REAL32
= 0x0040,
112 TYPE_REAL64
= 0x0041,
113 TYPE_REAL80
= 0x0042,
114 TYPE_REAL128
= 0x0043,
115 TYPE_REAL256
= 0x0044,
124 uint32_t text_offset
;
126 struct source_file source_file
;
132 struct cv8_symbol
*last_sym
;
133 unsigned num_syms
[SYMTYPE_MAX
];
134 unsigned symbol_lengths
;
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
,
168 struct coff_Section
*s
;
171 if (cv8_state
.source_file
.name
== NULL
)
172 register_file(filename
);
174 s
= find_section(segto
);
178 if ((s
->flags
& IMAGE_SCN_MEM_EXECUTE
) == 0)
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
)
193 struct cv8_symbol
*sym
;
194 struct coff_Section
*s
;
198 s
= find_section(segment
);
202 sym
= saa_wstruct(cv8_state
.symbols
);
204 if (s
->flags
& IMAGE_SCN_MEM_EXECUTE
)
205 sym
->type
= is_global
? SYMTYPE_PROC
: SYMTYPE_CODE
;
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
;
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
);
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
)
242 if (cv8_state
.last_sym
->symtype
!= TYPE_UNREGISTERED
)
245 switch (TYM_TYPE(type
)) {
247 cv8_state
.last_sym
->symtype
= TYPE_BYTE
;
250 cv8_state
.last_sym
->symtype
= TYPE_WORD
;
253 cv8_state
.last_sym
->symtype
= TYPE_DWORD
;
256 cv8_state
.last_sym
->symtype
= TYPE_QUAD
;
259 cv8_state
.last_sym
->symtype
= TYPE_REAL32
;
262 cv8_state
.last_sym
->symtype
= TYPE_REAL80
;
265 cv8_state
.last_sym
->symtype
= TYPE_REAL128
;
268 cv8_state
.last_sym
->symtype
= TYPE_REAL256
;
277 static void cv8_output(int type
, void *param
)
279 struct coff_DebugInfo
*dinfo
= param
;
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
)
307 saa_free(cv8_state
.lines
);
309 saa_rewind(cv8_state
.symbols
);
310 while ((sym
= saa_rstruct(cv8_state
.symbols
)))
312 saa_free(cv8_state
.symbols
);
315 /*******************************************************************************
317 ******************************************************************************/
318 static void calc_md5(const char *const filename
,
319 unsigned char sum
[MD5_HASHBYTES
])
322 unsigned char *file_buf
;
326 f
= fopen(filename
, "r");
330 file_buf
= nasm_zalloc(BUFSIZ
);
334 size_t i
= fread(file_buf
, 1, BUFSIZ
, f
);
339 MD5Update(&ctx
, file_buf
, i
);
349 nasm_error(ERR_NONFATAL
, "unable to hash file %s. "
350 "Debug information may be unavailable.\n",
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
)
367 for (i
= 0; i
< coff_nsects
; i
++) {
368 struct coff_Section
*sec
;
371 if (segto
== sec
->index
)
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
;
389 r
->symbase
= SECT_SYMBOLS
;
393 for (int i
= 0; i
< coff_nsects
; i
++) {
395 if (!strcmp(sym
, sec
->name
)) {
401 saa_rewind(coff_syms
);
402 for (uint32_t i
= 0; i
< coff_nsyms
; i
++) {
403 struct coff_Symbol
*s
= saa_rstruct(coff_syms
);
405 if (s
->strpos
== -1 && !strcmp(sym
, s
->name
)) {
407 } else if (s
->strpos
!= -1) {
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
);
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
);
429 static inline void section_write16(struct coff_Section
*sect
, uint16_t val
)
431 saa_write16(sect
->data
, val
);
435 static inline void section_write8(struct coff_Section
*sect
, uint8_t val
)
437 saa_write8(sect
->data
, val
);
441 static inline void section_wbytes(struct coff_Section
*sect
, const void *buf
,
444 saa_wbytes(sect
->data
, buf
, 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
)
480 uint32_t field_length
= 0;
482 struct coff_Section
*s
;
485 for (i
= 0; i
< coff_nsects
; i
++) {
486 if (!strncmp(coff_sects
[i
]->name
, ".text", 5))
490 if (i
== coff_nsects
)
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));
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
,
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);
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 */
552 section_write32(sect
, 0x000000D0);
554 section_write32(sect
, 0x00000006);
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);
569 static uint16_t write_symbolinfo_symbols(struct coff_Section
*sect
)
571 uint16_t len
= 0, field_len
;
573 struct cv8_symbol
*sym
;
575 saa_rewind(cv8_state
.symbols
);
576 while ((sym
= saa_rstruct(cv8_state
.symbols
))) {
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);
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 */
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 */
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
);
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
+
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
)
664 struct SAA
*data
= sect
->data
;
666 if (data
->wptr
% 4 == 0)
669 diff
= 4 - (data
->wptr
% 4);
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
);
680 write_sourcefile_table(sect
);
682 write_linenumber_table(sect
);
684 write_symbolinfo_table(sect
);
688 static void build_type_table(struct coff_Section
*const sect
)
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
)
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 */
714 section_write16(sect
, field_len
);
715 section_write16(sect
, 0x1201); /* ARGLIST */
716 section_write32(sect
, 0); /*num params */