From 5d9c033689ad1ef19ed2d2fd7f30bfd0bc473d9d Mon Sep 17 00:00:00 2001 From: Mark Harmstone Date: Fri, 9 Dec 2022 01:52:39 +0000 Subject: [PATCH] ld: Copy other symbols into PDB file --- ld/pdb.c | 362 ++++++++++++++++++++ ld/pdb.h | 179 ++++++++++ ld/testsuite/ld-pe/pdb-syms2-symbols1.d | 38 +++ ld/testsuite/ld-pe/pdb-syms2.s | 430 ++++++++++++++++++++++++ ld/testsuite/ld-pe/pdb.exp | 67 ++++ 5 files changed, 1076 insertions(+) create mode 100644 ld/testsuite/ld-pe/pdb-syms2-symbols1.d create mode 100644 ld/testsuite/ld-pe/pdb-syms2.s diff --git a/ld/pdb.c b/ld/pdb.c index 375ff35d04b..5bcf0566cae 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -908,11 +908,15 @@ find_end_of_scope (uint8_t *data, uint32_t size) { case S_GPROC32: case S_LPROC32: + case S_BLOCK32: + case S_INLINESITE: + case S_THUNK32: scope_level++; break; case S_END: case S_PROC_ID_END: + case S_INLINESITE_END: scope_level--; if (scope_level == 0) @@ -961,6 +965,7 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf, { uint8_t *orig_buf = *buf; unsigned int scope_level = 0; + uint8_t *scope = NULL; while (size >= sizeof (uint16_t)) { @@ -1206,6 +1211,8 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf, free (ref); + scope = *buf; + memcpy (*buf, proc, len); *buf += len; @@ -1321,16 +1328,343 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf, } case S_END: + case S_INLINESITE_END: case S_PROC_ID_END: memcpy (*buf, data, len); if (type == S_PROC_ID_END) /* transform to S_END */ bfd_putl16 (S_END, *buf + sizeof (uint16_t)); + /* Reset scope variable back to the address of the previous + scope start. */ + if (scope) + { + uint32_t parent; + uint16_t scope_start_type = + bfd_getl16 (scope + sizeof (uint16_t)); + + switch (scope_start_type) + { + case S_GPROC32: + case S_LPROC32: + parent = bfd_getl32 (scope + offsetof (struct procsym, + parent)); + break; + + case S_BLOCK32: + parent = bfd_getl32 (scope + offsetof (struct blocksym, + parent)); + break; + + case S_INLINESITE: + parent = bfd_getl32 (scope + offsetof (struct inline_site, + parent)); + break; + + case S_THUNK32: + parent = bfd_getl32 (scope + offsetof (struct thunk, + parent)); + break; + + default: + einfo (_("%P: warning: unexpected CodeView scope start" + " record %v\n"), scope_start_type); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (parent == 0) + scope = NULL; + else + scope = orig_buf + parent - sizeof (uint32_t); + } + *buf += len; scope_level--; break; + case S_BUILDINFO: + { + struct buildinfosym *bi = (struct buildinfosym *) data; + + if (len < sizeof (struct buildinfosym)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_BUILDINFO\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&bi->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + memcpy (*buf, data, len); + *buf += len; + + break; + } + + case S_BLOCK32: + { + struct blocksym *bl = (struct blocksym *) data; + uint8_t *endptr; + uint32_t end; + + if (len < offsetof (struct blocksym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_BLOCK32\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &bl->parent); + + endptr = find_end_of_scope (data, size); + + if (!endptr) + { + einfo (_("%P: warning: could not find end of" + " S_BLOCK32 record\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; + bfd_putl32 (end, &bl->end); + + scope = *buf; + + memcpy (*buf, data, len); + *buf += len; + + scope_level++; + + break; + } + + case S_BPREL32: + { + struct bprelsym *bp = (struct bprelsym *) data; + + if (len < offsetof (struct bprelsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_BPREL32\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&bp->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + memcpy (*buf, data, len); + *buf += len; + + break; + } + + case S_REGISTER: + { + struct regsym *reg = (struct regsym *) data; + + if (len < offsetof (struct regsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_REGISTER\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (®->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + memcpy (*buf, data, len); + *buf += len; + + break; + } + + case S_REGREL32: + { + struct regrel *rr = (struct regrel *) data; + + if (len < offsetof (struct regrel, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_REGREL32\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&rr->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + memcpy (*buf, data, len); + *buf += len; + + break; + } + + case S_LOCAL: + { + struct localsym *l = (struct localsym *) data; + + if (len < offsetof (struct localsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_LOCAL\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&l->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + memcpy (*buf, data, len); + *buf += len; + + break; + } + + case S_INLINESITE: + { + struct inline_site *is = (struct inline_site *) data; + uint8_t *endptr; + uint32_t end; + + if (len < offsetof (struct inline_site, binary_annotations)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_INLINESITE\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &is->parent); + + endptr = find_end_of_scope (data, size); + + if (!endptr) + { + einfo (_("%P: warning: could not find end of" + " S_INLINESITE record\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; + bfd_putl32 (end, &is->end); + + if (!remap_symbol_type (&is->inlinee, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + scope = *buf; + + memcpy (*buf, data, len); + *buf += len; + + scope_level++; + + break; + } + + case S_THUNK32: + { + struct thunk *th = (struct thunk *) data; + uint8_t *endptr; + uint32_t end; + + if (len < offsetof (struct thunk, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_THUNK32\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &th->parent); + + endptr = find_end_of_scope (data, size); + + if (!endptr) + { + einfo (_("%P: warning: could not find end of" + " S_THUNK32 record\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; + bfd_putl32 (end, &th->end); + + scope = *buf; + + memcpy (*buf, data, len); + *buf += len; + + scope_level++; + + break; + } + + case S_HEAPALLOCSITE: + { + struct heap_alloc_site *has = (struct heap_alloc_site *) data; + + if (len < sizeof (struct heap_alloc_site)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_HEAPALLOCSITE\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&has->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + memcpy (*buf, data, len); + *buf += len; + + break; + } + + case S_OBJNAME: /* just copy */ + case S_COMPILE3: + case S_UNAMESPACE: + case S_FRAMEPROC: + case S_FRAMECOOKIE: + case S_LABEL32: + case S_DEFRANGE_REGISTER_REL: + case S_DEFRANGE_FRAMEPOINTER_REL: + case S_DEFRANGE_SUBFIELD_REGISTER: + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + case S_DEFRANGE_REGISTER: + memcpy (*buf, data, len); + *buf += len; + break; + default: einfo (_("%P: warning: unrecognized CodeView record %v\n"), type); bfd_set_error (bfd_error_bad_value); @@ -1441,12 +1775,40 @@ calculate_symbols_size (uint8_t *data, uint32_t size, uint32_t *sym_size) *sym_size += len; break; + case S_BLOCK32: /* always copied */ + case S_INLINESITE: + case S_THUNK32: + *sym_size += len; + scope_level++; + break; + case S_END: /* always copied */ case S_PROC_ID_END: + case S_INLINESITE_END: *sym_size += len; scope_level--; break; + case S_OBJNAME: /* always copied */ + case S_COMPILE3: + case S_UNAMESPACE: + case S_FRAMEPROC: + case S_FRAMECOOKIE: + case S_LABEL32: + case S_BUILDINFO: + case S_BPREL32: + case S_REGISTER: + case S_REGREL32: + case S_LOCAL: + case S_DEFRANGE_REGISTER_REL: + case S_DEFRANGE_FRAMEPOINTER_REL: + case S_DEFRANGE_SUBFIELD_REGISTER: + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + case S_DEFRANGE_REGISTER: + case S_HEAPALLOCSITE: + *sym_size += len; + break; + default: einfo (_("%P: warning: unrecognized CodeView record %v\n"), type); return false; diff --git a/ld/pdb.h b/ld/pdb.h index 9048b5fa37c..ddb9b86ce85 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -71,20 +71,41 @@ #define LF_UQUADWORD 0x800a #define S_END 0x0006 +#define S_FRAMEPROC 0x1012 +#define S_OBJNAME 0x1101 +#define S_THUNK32 0x1102 +#define S_BLOCK32 0x1103 +#define S_LABEL32 0x1105 +#define S_REGISTER 0x1106 #define S_CONSTANT 0x1107 #define S_UDT 0x1108 +#define S_BPREL32 0x110b #define S_LDATA32 0x110c #define S_GDATA32 0x110d #define S_PUB32 0x110e #define S_LPROC32 0x110f #define S_GPROC32 0x1110 +#define S_REGREL32 0x1111 #define S_LTHREAD32 0x1112 #define S_GTHREAD32 0x1113 +#define S_UNAMESPACE 0x1124 #define S_PROCREF 0x1125 #define S_LPROCREF 0x1127 +#define S_FRAMECOOKIE 0x113a +#define S_COMPILE3 0x113c +#define S_LOCAL 0x113e +#define S_DEFRANGE_REGISTER 0x1141 +#define S_DEFRANGE_FRAMEPOINTER_REL 0x1142 +#define S_DEFRANGE_SUBFIELD_REGISTER 0x1143 +#define S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE 0x1144 +#define S_DEFRANGE_REGISTER_REL 0x1145 #define S_LPROC32_ID 0x1146 #define S_GPROC32_ID 0x1147 +#define S_BUILDINFO 0x114c +#define S_INLINESITE 0x114d +#define S_INLINESITE_END 0x114e #define S_PROC_ID_END 0x114f +#define S_HEAPALLOCSITE 0x115e /* PDBStream70 in pdb1.h */ struct pdb_stream_70 @@ -617,6 +638,164 @@ struct constsym char name[]; } ATTRIBUTE_PACKED; +/* BUILDINFOSYM in cvinfo.h */ +struct buildinfosym +{ + uint16_t size; + uint16_t kind; + uint32_t type; +} ATTRIBUTE_PACKED; + +/* BLOCKSYM32 in cvinfo.h */ +struct blocksym +{ + uint16_t size; + uint16_t kind; + uint32_t parent; + uint32_t end; + uint32_t len; + uint32_t offset; + uint16_t section; + char name[]; +} ATTRIBUTE_PACKED; + +/* BPRELSYM32 in cvinfo.h */ +struct bprelsym +{ + uint16_t size; + uint16_t kind; + uint32_t bp_offset; + uint32_t type; + char name[]; +} ATTRIBUTE_PACKED; + +/* REGSYM in cvinfo.h */ +struct regsym +{ + uint16_t size; + uint16_t kind; + uint32_t type; + uint16_t reg; + char name[]; +} ATTRIBUTE_PACKED; + +/* REGREL32 in cvinfo.h */ +struct regrel +{ + uint16_t size; + uint16_t kind; + uint32_t offset; + uint32_t type; + uint16_t reg; + char name[]; +} ATTRIBUTE_PACKED; + +/* LOCALSYM in cvinfo.h */ +struct localsym +{ + uint16_t size; + uint16_t kind; + uint32_t type; + uint16_t flags; + char name[]; +} ATTRIBUTE_PACKED; + +/* CV_LVAR_ADDR_RANGE in cvinfo.h */ +struct lvar_addr_range +{ + uint32_t offset; + uint16_t section; + uint16_t length; +} ATTRIBUTE_PACKED; + +/* CV_LVAR_ADDR_GAP in cvinfo.h */ +struct lvar_addr_gap { + uint16_t offset; + uint16_t length; +} ATTRIBUTE_PACKED; + +/* DEFRANGESYMREGISTERREL in cvinfo.h */ +struct defrange_register_rel +{ + uint16_t size; + uint16_t kind; + uint16_t reg; + uint16_t offset_parent; + uint32_t offset_register; + struct lvar_addr_range range; + struct lvar_addr_gap gaps[]; +} ATTRIBUTE_PACKED; + +/* DEFRANGESYMFRAMEPOINTERREL in cvinfo.h */ +struct defrange_framepointer_rel +{ + uint16_t size; + uint16_t kind; + uint32_t offset; + struct lvar_addr_range range; + struct lvar_addr_gap gaps[]; +} ATTRIBUTE_PACKED; + +/* DEFRANGESYMSUBFIELDREGISTER in cvinfo.h */ +struct defrange_subfield_register +{ + uint16_t size; + uint16_t kind; + uint16_t reg; + uint16_t attributes; + uint32_t offset_parent; + struct lvar_addr_range range; + struct lvar_addr_gap gaps[]; +} ATTRIBUTE_PACKED; + +/* DEFRANGESYMREGISTER in cvinfo.h */ +struct defrange_register +{ + uint16_t size; + uint16_t kind; + uint16_t reg; + uint16_t attributes; + struct lvar_addr_range range; + struct lvar_addr_gap gaps[]; +} ATTRIBUTE_PACKED; + +/* INLINESITESYM in cvinfo.h */ +struct inline_site +{ + uint16_t size; + uint16_t kind; + uint32_t parent; + uint32_t end; + uint32_t inlinee; + uint8_t binary_annotations[]; +} ATTRIBUTE_PACKED; + +/* THUNKSYM32 in cvinfo.h */ +struct thunk +{ + uint16_t size; + uint16_t kind; + uint32_t parent; + uint32_t end; + uint32_t next; + uint32_t offset; + uint16_t section; + uint16_t length; + uint8_t thunk_type; + char name[]; +} ATTRIBUTE_PACKED; + +/* HEAPALLOCSITE in cvinfo.h */ +struct heap_alloc_site +{ + uint16_t size; + uint16_t kind; + uint32_t offset; + uint16_t section; + uint16_t length; + uint32_t type; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb-syms2-symbols1.d b/ld/testsuite/ld-pe/pdb-syms2-symbols1.d new file mode 100644 index 00000000000..34132d1264e --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms2-symbols1.d @@ -0,0 +1,38 @@ + +*: file format binary + +Contents of section .data: + 0000 04000000 0e000111 00000000 73796d73 ............syms + 0010 332e6f00 22003c11 00000000 d0000000 3.o.".<......... + 0020 00000000 00000000 00000000 0000474e ..............GN + 0030 55204153 00f3f2f1 06002411 73746400 U AS......$.std. + 0040 06004c11 05100000 2e001011 00000000 ..L............. + 0050 18020000 00000000 06000000 00000000 ................ + 0060 00000000 01100000 00000000 01000070 ...............p + 0070 726f6331 00f3f2f1 1e001210 00000000 roc1............ + 0080 00000000 00000000 00000000 00000000 ................ + 0090 00000000 0000f2f1 0e003a11 08000000 ..........:..... + 00a0 48010000 000000f1 0e000b11 04000000 H............... + 00b0 02100000 666f6f00 0e000611 02100000 ....foo......... + 00c0 48016261 7200f2f1 12001111 04000000 H.bar........... + 00d0 02100000 48016261 7a00f2f1 12003e11 ....H.baz.....>. + 00e0 02100000 00006c6f 63616c31 00f3f2f1 ......local1.... + 00f0 16004511 48010000 00000000 01000000 ..E.H........... + 0100 01000400 02000100 12003e11 02100000 ..........>..... + 0110 00006c6f 63616c32 00f3f2f1 12004211 ..local2......B. + 0120 04000000 01000000 01000400 02000100 ................ + 0130 12003e11 02100000 00006c6f 63616c33 ..>.......local3 + 0140 00f3f2f1 16004311 48010000 04000000 ......C.H....... + 0150 01000000 01000400 02000100 12003e11 ..............>. + 0160 02100000 00006c6f 63616c34 00f3f2f1 ......local4.... + 0170 06004411 04000000 12003e11 02100000 ..D.......>..... + 0180 00006c6f 63616c35 00f3f2f1 12004111 ..local5......A. + 0190 48010000 01000000 01000400 02000100 H............... + 01a0 0e004d11 48000000 b0010000 06100000 ..M.H........... + 01b0 02004e11 16000311 48000000 e0010000 ..N.....H....... + 01c0 04000000 01000000 010000f1 12000511 ................ + 01d0 02000000 0100006c 6162656c 00f3f2f1 .......label.... + 01e0 02000600 1e000211 48000000 04020000 ........H....... + 01f0 00000000 06000000 01000100 00746875 .............thu + 0200 6e6b00f1 02000600 0e005e11 04000000 nk........^..... + 0210 01000100 02100000 02000600 00000000 ................ \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-syms2.s b/ld/testsuite/ld-pe/pdb-syms2.s new file mode 100644 index 00000000000..ec677eaee43 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms2.s @@ -0,0 +1,430 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_SYMBOLS, 0xf1 + +.equ T_VOID, 0x0003 +.equ T_UINT4, 0x0075 + +.equ LF_MODIFIER, 0x1001 +.equ LF_PROCEDURE, 0x1008 +.equ LF_ARGLIST, 0x1201 +.equ LF_FUNC_ID, 0x1601 +.equ LF_BUILDINFO, 0x1603 +.equ LF_STRING_ID, 0x1605 + +.equ S_END, 0x0006 +.equ S_FRAMEPROC, 0x1012 +.equ S_OBJNAME, 0x1101 +.equ S_THUNK32, 0x1102 +.equ S_BLOCK32, 0x1103 +.equ S_LABEL32, 0x1105 +.equ S_REGISTER, 0x1106 +.equ S_BPREL32, 0x110b +.equ S_GPROC32, 0x1110 +.equ S_REGREL32, 0x1111 +.equ S_UNAMESPACE, 0x1124 +.equ S_FRAMECOOKIE, 0x113a +.equ S_COMPILE3, 0x113c +.equ S_LOCAL, 0x113e +.equ S_DEFRANGE_REGISTER, 0x1141 +.equ S_DEFRANGE_FRAMEPOINTER_REL, 0x1142 +.equ S_DEFRANGE_SUBFIELD_REGISTER, 0x1143 +.equ S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144 +.equ S_DEFRANGE_REGISTER_REL, 0x1145 +.equ S_BUILDINFO, 0x114c +.equ S_INLINESITE, 0x114d +.equ S_INLINESITE_END, 0x114e +.equ S_HEAPALLOCSITE, 0x115e + +.equ CV_AMD64_RAX, 328 +.equ CV_CFL_AMD64, 0xd0 + +.section ".debug$S", "rn" + +.long CV_SIGNATURE_C13 + +.long DEBUG_S_SYMBOLS +.long .syms_end - .syms_start + +.syms_start: + +.objname1: +.short .compile1 - .objname1 - 2 +.short S_OBJNAME +.long 0 # signature +.asciz "syms3.o" + +.compile1: +.short .unamespace1 - .compile1 - 2 +.short S_COMPILE3 +.long 0 # flags +.short CV_CFL_AMD64 # target processor +.short 0 # frontend major +.short 0 # frontend minor +.short 0 # frontend build +.short 0 # frontend qfe +.short 0 # backend major +.short 0 # backend minor +.short 0 # backend build +.short 0 # backend qfe +.asciz "GNU AS" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.unamespace1: +.short .sbuildinfo1 - .unamespace1 - 2 +.short S_UNAMESPACE +.asciz "std" + +.sbuildinfo1: +.short .gproc1 - .sbuildinfo1 - 2 +.short S_BUILDINFO +.long 0x1007 # type + +.gproc1: +.short .frameproc1 - .gproc1 - 2 +.short S_GPROC32 +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc1_end - proc1 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1001 # type +.secrel32 proc1 +.secidx proc1 +.byte 0 # flags +.asciz "proc1" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.frameproc1: +.short .framecookie1 - .frameproc1 - 2 +.short S_FRAMEPROC +.long 0 # frame size +.long 0 # frame padding +.long 0 # padding offset +.long 0 # size of callee-save registers +.long 0 # offset of exception handler +.short 0 # section of exception handler +.long 0 # flags +.byte 0xf2 # padding +.byte 0xf1 # padding + +.framecookie1: +.short .bprel1 - .framecookie1 - 2 +.short S_FRAMECOOKIE +.long 8 # frame-relative offset +.short CV_AMD64_RAX # register +.long 0 # cookie type (CV_COOKIETYPE_COPY) +.byte 0 # flags +.byte 0xf1 # padding + +.bprel1: +.short .reg1 - .bprel1 - 2 +.short S_BPREL32 +.long 4 # BP-relative offset +.long 0x1008 # type +.asciz "foo" + +.reg1: +.short .regrel1 - .reg1 - 2 +.short S_REGISTER +.long 0x1008 # type +.short CV_AMD64_RAX +.asciz "bar" +.byte 0xf2 # padding +.byte 0xf1 # padding + +.regrel1: +.short .local1 - .regrel1 - 2 +.short S_REGREL32 +.long 4 # offset +.long 0x1008 # type +.short CV_AMD64_RAX +.asciz "baz" +.byte 0xf2 # padding +.byte 0xf1 # padding + +.local1: +.short .defrange1 - .local1 - 2 +.short S_LOCAL +.long 0x1008 # type +.short 0 # flags +.asciz "local1" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.defrange1: +.short .local2 - .defrange1 - 2 +.short S_DEFRANGE_REGISTER_REL +.short CV_AMD64_RAX +.short 0 # offset parent +.long 0 # offset register +.secrel32 .block1 # offset +.secidx .block1 # section +.short .block1_end - .block1 # length +.short .gap1 - .block1 # gap 1 offset +.short .gap1_end - .gap1 # gap 1 length + +.local2: +.short .defrange2 - .local2 - 2 +.short S_LOCAL +.long 0x1008 # type +.short 0 # flags +.asciz "local2" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.defrange2: +.short .local3 - .defrange2 - 2 +.short S_DEFRANGE_FRAMEPOINTER_REL +.long 4 # frame pointer offset +.secrel32 .block1 # offset +.secidx .block1 # section +.short .block1_end - .block1 # length +.short .gap1 - .block1 # gap 1 offset +.short .gap1_end - .gap1 # gap 1 length + +.local3: +.short .defrange3 - .local3 - 2 +.short S_LOCAL +.long 0x1008 # type +.short 0 # flags +.asciz "local3" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.defrange3: +.short .local4 - .defrange3 - 2 +.short S_DEFRANGE_SUBFIELD_REGISTER +.short CV_AMD64_RAX +.short 0 # attributes +.long 4 # offset in parent variable +.secrel32 .block1 # offset +.secidx .block1 # section +.short .block1_end - .block1 # length +.short .gap1 - .block1 # gap 1 offset +.short .gap1_end - .gap1 # gap 1 length + +.local4: +.short .defrange4 - .local4 - 2 +.short S_LOCAL +.long 0x1008 # type +.short 0 # flags +.asciz "local4" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.defrange4: +.short .local5 - .defrange4 - 2 +.short S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE +.long 4 # frame pointer offset + +.local5: +.short .defrange5 - .local5 - 2 +.short S_LOCAL +.long 0x1008 # type +.short 0 # flags +.asciz "local5" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.defrange5: +.short .inlinesite1 - .defrange5 - 2 +.short S_DEFRANGE_REGISTER +.short CV_AMD64_RAX +.short 0 # attributes +.secrel32 .block1 # offset +.secidx .block1 # section +.short .block1_end - .block1 # length +.short .gap1 - .block1 # gap 1 offset +.short .gap1_end - .gap1 # gap 1 length + +.inlinesite1: +.short .inlinesite1end - .inlinesite1 - 2 +.short S_INLINESITE +.long 0 # parent +.long 0 # end +.long 0x1009 # inlinee (inline_func) + +.inlinesite1end: +.short .sblock1 - .inlinesite1end - 2 +.short S_INLINESITE_END + +.sblock1: +.short .label1 - .sblock1 - 2 +.short S_BLOCK32 +.long 0 # parent (filled in by linker) +.long 0 # end (filled in by linker) +.long .block1_end - .block1 # length +.secrel32 .block1 +.secidx .block1 +.byte 0 # name +.byte 0xf1 # padding + +.label1: +.short .sblock1_end - .label1 - 2 +.short S_LABEL32 +.secrel32 label +.secidx label +.byte 0 # flags +.asciz "label" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.sblock1_end: +.short .thunk1 - .sblock1_end - 2 +.short S_END + +.thunk1: +.short .thunk1_end - .thunk1 - 2 +.short S_THUNK32 +.long 0 # parent +.long 0 # end +.long 0 # next +.secrel32 thunk +.secidx thunk +.short .thunk_end - thunk +.byte 0 # THUNK_ORDINAL value +.asciz "thunk" +.byte 0xf1 # padding + +.thunk1_end: +.short .heapallocsite1 - .thunk1_end - 2 +.short S_END + +.heapallocsite1: +.short .gproc1_end - .heapallocsite1 - 2 +.short S_HEAPALLOCSITE +.secrel32 .gap1_end +.secidx .gap1_end +.short .block1_end - .gap1_end +.long 0x1008 # type + +.gproc1_end: +.short .syms_end - .gproc1_end - 2 +.short S_END + +.syms_end: + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, arglist (uint32_t) +.arglist1: +.short .proctype1 - .arglist1 - 2 +.short LF_ARGLIST +.long 1 # no. entries +.long T_UINT4 + +# Type 1001, procedure (return type T_VOID, arglist 1000) +.proctype1: +.short .string1 - .proctype1 - 2 +.short LF_PROCEDURE +.long T_VOID +.byte 0 # calling convention +.byte 0 # attributes +.short 1 # no. parameters +.long 0x1000 + +# Type 1002, string "/tmp" (build directory) +.string1: +.short .string2 - .string1 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "/tmp" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1003, string "gcc" (compiler) +.string2: +.short .string3 - .string2 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "gcc" + +# Type 1004, string "tmp.c" (source file) +.string3: +.short .string4 - .string3 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "tmp.c" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1005, string "tmp.pdb" (PDB file) +.string4: +.short .string5 - .string4 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "tmp.pdb" + +# Type 1006, string "-gcodeview" (command arguments) +.string5: +.short .buildinfo1 - .string5 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "-gcodeview" +.byte 0xf1 # padding + +# Type 1007, build info +.buildinfo1: +.short .mod1 - .buildinfo1 - 2 +.short LF_BUILDINFO +.short 5 # count +.long 0x1002 # build directory +.long 0x1003 # compiler +.long 0x1004 # source file +.long 0x1005 # PDB file +.long 0x1006 # command arguments +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1008, const uint32_t +.mod1: +.short .funcid1 - .mod1 - 2 +.short LF_MODIFIER +.long T_UINT4 +.short 1 # const +.p2align 2 + +# Type 1009, func ID for inline_func +.funcid1: +.short .types_end - .funcid1 - 2 +.short LF_FUNC_ID +.long 0 # parent scope +.long 0x1001 # type +.asciz "inline_func" + +.types_end: + +.text + +.global proc1 +proc1: + nop +.block1: + nop +label: + nop +.gap1: + nop +.gap1_end: + nop +.block1_end: + nop +.proc1_end: + +thunk: + nop +.thunk_end: diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 34eafc142a7..5df1583c247 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1614,6 +1614,72 @@ proc test8 { } { } } +proc test9 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb-syms2.s tmpdir/pdb-syms2.o] { + unsupported "Build pdb-syms2.o" + return + } + + if ![ld_link $ld "tmpdir/pdb-syms2.exe" "--pdb=tmpdir/pdb-syms2.pdb tmpdir/pdb-syms2.o"] { + unsupported "Create PE image with PDB file" + return + } + + # get index of module stream + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb 0003"] + + if ![string match "" $exec_output] { + fail "Could not extract DBI stream" + return + } else { + pass "Extracted DBI stream" + } + + set fi [open tmpdir/0003] + fconfigure $fi -translation binary + + seek $fi 24 + set data [read $fi 4] + binary scan $data i mod_info_size + + seek $fi 36 current + set mod_info [read $fi $mod_info_size] + + close $fi + + binary scan [string range $mod_info 34 35] s module_index + + # check module records + + set index_str [format "%04x" $module_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract module symbols" + return + } else { + pass "Extracted module symbols" + } + + set exp [file_contents "$srcdir/$subdir/pdb-syms2-symbols1.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"] + + if [string match $exp $got] { + pass "Correct symbols in module stream" + } else { + fail "Incorrect symbols in module stream" + } +} + test1 test2 test3 @@ -1622,3 +1688,4 @@ test5 test6 test7 test8 +test9 -- 2.30.2