From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by sourceware.org (Postfix) with ESMTPS id 54B8A3858417 for ; Tue, 29 Nov 2022 00:10:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 54B8A3858417 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=harmstone.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wr1-x42a.google.com with SMTP id h11so12304358wrw.13 for ; Mon, 28 Nov 2022 16:10:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date :message-id:reply-to; bh=TvnUncDnQPut9dAXd2a5NKlEODo018R85D/7QWJhZrM=; b=XQ+EKKATGcSN1SNlc19Tg2P46ub5kyXzOFA8j7axs98xARiqKYyTM4yITA1L9W4jQ3 7wZkXJKfa2AHkjw+0eqUEoHg3MdtVrIyziJUquN3WG/uNyFXqdxgbnsEytzAVkoqZ2t2 8tZQSpyCN+N0ESTXf3mcUGbP+NvwvOuAv/9OsTC7PVca490aPDXUhgEVMDdXSjTeN04y lJMOGaJH8nr7rJZ0wNrfRNv8JaSPeFx4MzNDuW0U6ctNzoNmxIE25ssiXsHpEM0wXqPA hdOb9dFf4KOMWCkTrjxF/rHBBIB8WghAyZPdbFWK9XHcpC1uYU3ikOyPq/vtLa9QfTAn EEjw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=TvnUncDnQPut9dAXd2a5NKlEODo018R85D/7QWJhZrM=; b=WYm6nkTykBCVd+tCotgOzwEo/RFUh6Dh9wjZcNf+3cb/zqNdTHBTCoXdGvBcwHGzEF F0/3Ub2hQf5M2n+Ubw+s5MEjU1lCa7Qhp7wMxhiHg9mZYEIHJ6vZklZ3alwjJu87aGYJ X9zYQ1SkCSk82n9nOvg/ERns8Fn2VqxZRweFdieGAYWw2DR6clBFMFpIFYGIeTYZkSvc bMjVgaHfoPloWEh6xuKpsCoDmmvdHOBdUFpmqBofiON2tNliQIbDDMx/UQ4KlUSpMO4E f7OOOQ0Z0MpCqbsZeSyiE5CwmIqHXwRdY43mc8vxbhlUFglLB9A8xB7Me6ViGlO5nJ5L U1Ow== X-Gm-Message-State: ANoB5pk2T6Rh2R/IU/etQ+WOytk8buohsz3FOUok5lnGsDCtlSWEOAV8 vqY08UTBYa4gwt6NiDV0KEjAz4aehF0= X-Google-Smtp-Source: AA0mqf6efusOsuKy4yIMZGiqL+XaFV0/JxCpIHLMq8YM+ZlqyAMeq3YaUr9cS+afv4KgKWTDCkM35Q== X-Received: by 2002:a5d:55c3:0:b0:236:c12b:6e29 with SMTP id i3-20020a5d55c3000000b00236c12b6e29mr32576788wrw.98.1669680622624; Mon, 28 Nov 2022 16:10:22 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id r11-20020a05600c35cb00b003a84375d0d1sm57570wmq.44.2022.11.28.16.10.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Nov 2022 16:10:22 -0800 (PST) Sender: Mark Harmstone From: Mark Harmstone To: binutils@sourceware.org Cc: Mark Harmstone Subject: [PATCH] ld: Write types into IPI stream of PDB Date: Tue, 29 Nov 2022 00:10:14 +0000 Message-Id: <20221129001015.21775-2-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221129001015.21775-1-mark@harmstone.com> References: <20221127023840.32080-2-mark@harmstone.com> <20221129001015.21775-1-mark@harmstone.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.3 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: This covers the other types, that are instead written to the ID information stream. --- ld/pdb.c | 204 +++++++++++++++++++-- ld/pdb.h | 45 ++++- ld/testsuite/ld-pe/pdb-types2-hashlist.d | 8 + ld/testsuite/ld-pe/pdb-types2-skiplist.d | 5 + ld/testsuite/ld-pe/pdb-types2-typelist.d | 20 ++ ld/testsuite/ld-pe/pdb-types2a.s | 42 +++++ ld/testsuite/ld-pe/pdb-types2b.s | 221 +++++++++++++++++++++++ ld/testsuite/ld-pe/pdb.exp | 172 ++++++++++++++++++ 8 files changed, 699 insertions(+), 18 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb-types2-hashlist.d create mode 100644 ld/testsuite/ld-pe/pdb-types2-skiplist.d create mode 100644 ld/testsuite/ld-pe/pdb-types2-typelist.d create mode 100644 ld/testsuite/ld-pe/pdb-types2a.s create mode 100644 ld/testsuite/ld-pe/pdb-types2b.s diff --git a/ld/pdb.c b/ld/pdb.c index 979ea126aa5..6584ccd9911 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -1097,13 +1097,16 @@ is_name_anonymous (char *name, size_t len) already seen add it to types (for TPI types) or ids (for IPI types). */ static bool handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, - uint32_t num_types, struct types *types) + uint32_t num_types, struct types *types, + struct types *ids) { uint16_t size, type; void **slot; hashval_t hash; bool other_hash = false; uint32_t cv_hash; + struct types *t; + bool ipi = false; size = bfd_getl16 (data) + sizeof (uint16_t); type = bfd_getl16 (data + sizeof (uint16_t)); @@ -1904,6 +1907,168 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, /* Does not reference any types, nothing to be done. */ break; + case LF_STRING_ID: + { + struct lf_string_id *str = (struct lf_string_id *) data; + size_t string_len; + + if (size < offsetof (struct lf_string_id, string)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_STRING_ID\n")); + return false; + } + + if (!remap_type (&str->substring, map, type_num, num_types)) + return false; + + string_len = strnlen (str->string, + size - offsetof (struct lf_string_id, string)); + + if (string_len == size - offsetof (struct lf_string_id, string)) + { + einfo (_("%P: warning: string for LF_STRING_ID has no" + " terminating zero\n")); + return false; + } + + ipi = true; + + break; + } + + case LF_SUBSTR_LIST: + { + uint32_t num_entries; + struct lf_arglist *ssl = (struct lf_arglist *) data; + + if (size < offsetof (struct lf_arglist, args)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_SUBSTR_LIST\n")); + return false; + } + + num_entries = bfd_getl32 (&ssl->num_entries); + + if (size < offsetof (struct lf_arglist, args) + + (num_entries * sizeof (uint32_t))) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_SUBSTR_LIST\n")); + return false; + } + + for (uint32_t i = 0; i < num_entries; i++) + { + if (!remap_type (&ssl->args[i], map, type_num, num_types)) + return false; + } + + ipi = true; + + break; + } + + case LF_BUILDINFO: + { + uint16_t num_entries; + struct lf_build_info *bi = (struct lf_build_info *) data; + + if (size < offsetof (struct lf_build_info, strings)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_BUILDINFO\n")); + return false; + } + + num_entries = bfd_getl16 (&bi->count); + + if (size < offsetof (struct lf_build_info, strings) + + (num_entries * sizeof (uint32_t))) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_BUILDINFO\n")); + return false; + } + + for (uint32_t i = 0; i < num_entries; i++) + { + if (!remap_type (&bi->strings[i], map, type_num, num_types)) + return false; + } + + ipi = true; + + break; + } + + case LF_FUNC_ID: + { + struct lf_func_id *func = (struct lf_func_id *) data; + size_t name_len; + + if (size < offsetof (struct lf_func_id, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FUNC_ID\n")); + return false; + } + + if (!remap_type (&func->parent_scope, map, type_num, num_types)) + return false; + + if (!remap_type (&func->function_type, map, type_num, num_types)) + return false; + + name_len = strnlen (func->name, + size - offsetof (struct lf_func_id, name)); + + if (name_len == size - offsetof (struct lf_func_id, name)) + { + einfo (_("%P: warning: string for LF_FUNC_ID has no" + " terminating zero\n")); + return false; + } + + ipi = true; + + break; + } + + case LF_MFUNC_ID: + { + struct lf_mfunc_id *mfunc = (struct lf_mfunc_id *) data; + size_t name_len; + + if (size < offsetof (struct lf_mfunc_id, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_MFUNC_ID\n")); + return false; + } + + if (!remap_type (&mfunc->parent_type, map, type_num, num_types)) + return false; + + if (!remap_type (&mfunc->function_type, map, type_num, num_types)) + return false; + + name_len = strnlen (mfunc->name, + size - offsetof (struct lf_mfunc_id, name)); + + if (name_len == size - offsetof (struct lf_mfunc_id, name)) + { + einfo (_("%P: warning: string for LF_MFUNC_ID has no" + " terminating zero\n")); + return false; + } + + ipi = true; + + break; + } + default: einfo (_("%P: warning: unrecognized CodeView type %v\n"), type); return false; @@ -1911,7 +2076,9 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, hash = iterative_hash (data, size, 0); - slot = htab_find_slot_with_hash (types->hashmap, data, hash, INSERT); + t = ipi ? ids : types; + + slot = htab_find_slot_with_hash (t->hashmap, data, hash, INSERT); if (!slot) return false; @@ -1924,7 +2091,7 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, e = (struct type_entry *) *slot; e->next = NULL; - e->index = types->num_types; + e->index = t->num_types; if (other_hash) e->cv_hash = cv_hash; @@ -1933,16 +2100,16 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, memcpy (e->data, data, size); - if (types->last) - types->last->next = e; + if (t->last) + t->last->next = e; else - types->first = e; + t->first = e; - types->last = e; + t->last = e; map[type_num] = e; - types->num_types++; + t->num_types++; } else /* duplicate */ { @@ -1955,7 +2122,8 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, /* Parse the .debug$T section of a module, and pass any type definitions found to handle_type. */ static bool -handle_debugt_section (asection *s, bfd *mod, struct types *types) +handle_debugt_section (asection *s, bfd *mod, struct types *types, + struct types *ids) { bfd_byte *data = NULL; size_t off; @@ -2012,7 +2180,7 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types) size = bfd_getl16 (data + off); - if (!handle_type (data + off, map, type_num, num_types, types)) + if (!handle_type (data + off, map, type_num, num_types, types, ids)) { free (data); free (map); @@ -2037,7 +2205,8 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, struct string_table *strings, uint32_t *c13_info_size, struct mod_source_files *mod_source, - bfd *abfd, struct types *types) + bfd *abfd, struct types *types, + struct types *ids) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; @@ -2061,7 +2230,7 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, } else if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) { - if (!handle_debugt_section (s, mod, types)) + if (!handle_debugt_section (s, mod, types, ids)) { free (c13_info); free (mod_source->files); @@ -2107,7 +2276,7 @@ static bool create_module_info_substream (bfd *abfd, bfd *pdb, void **data, uint32_t *size, struct string_table *strings, struct source_files_info *source, - struct types *types) + struct types *types, struct types *ids) { uint8_t *ptr; unsigned int mod_num; @@ -2196,7 +2365,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, if (!populate_module_stream (stream, in, &sym_byte_size, strings, &c13_info_size, &source->mods[mod_num], abfd, - types)) + types, ids)) { for (unsigned int i = 0; i < source->mod_count; i++) { @@ -2519,7 +2688,8 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, uint16_t sym_rec_stream_num, uint16_t publics_stream_num, struct string_table *strings, - struct types *types) + struct types *types, + struct types *ids) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; @@ -2531,7 +2701,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, source.mods = NULL; if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, - strings, &source, types)) + strings, &source, types, ids)) return false; if (!create_section_contrib_substream (abfd, &sc, &sc_size)) @@ -3206,7 +3376,7 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) if (!populate_dbi_stream (dbi_stream, abfd, pdb, section_header_stream_num, sym_rec_stream_num, publics_stream_num, - &strings, &types)) + &strings, &types, &ids)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); diff --git a/ld/pdb.h b/ld/pdb.h index ecc26c1c87a..7d87a3fef07 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -54,6 +54,11 @@ #define LF_METHOD 0x150f #define LF_NESTTYPE 0x1510 #define LF_ONEMETHOD 0x1511 +#define LF_FUNC_ID 0x1601 +#define LF_MFUNC_ID 0x1602 +#define LF_BUILDINFO 0x1603 +#define LF_SUBSTR_LIST 0x1604 +#define LF_STRING_ID 0x1605 #define LF_CHAR 0x8000 #define LF_SHORT 0x8001 @@ -265,7 +270,7 @@ struct lf_pointer uint32_t attributes; } ATTRIBUTE_PACKED; -/* lfArgList in cvinfo.h */ +/* lfArgList in cvinfo.h (used for both LF_ARGLIST and LF_SUBSTR_LIST) */ struct lf_arglist { uint16_t size; @@ -474,6 +479,44 @@ struct lf_nest_type char name[]; } ATTRIBUTE_PACKED; +/* lfStringId in cvinfo.h */ +struct lf_string_id +{ + uint16_t size; + uint16_t kind; + uint32_t substring; + char string[]; +} ATTRIBUTE_PACKED; + +/* lfBuildInfo in cvinfo.h */ +struct lf_build_info +{ + uint16_t size; + uint16_t kind; + uint16_t count; + uint32_t strings[]; +} ATTRIBUTE_PACKED; + +/* lfFuncId in cvinfo.h */ +struct lf_func_id +{ + uint16_t size; + uint16_t kind; + uint32_t parent_scope; + uint32_t function_type; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfMFuncId in cvinfo.h */ +struct lf_mfunc_id +{ + uint16_t size; + uint16_t kind; + uint32_t parent_type; + uint32_t function_type; + char name[]; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb-types2-hashlist.d b/ld/testsuite/ld-pe/pdb-types2-hashlist.d new file mode 100644 index 00000000000..71d9045fbbd --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types2-hashlist.d @@ -0,0 +1,8 @@ + +*: file format binary + +Contents of section .data: + 0000 75cf0100 8d660300 f2a20300 aea00000 * + 0010 ef990300 223d0000 d6b60000 24070100 * + 0020 7f220100 f6d10200 16100200 010a0300 * + 0030 0b4f0300 12690300 a56d0300 * \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types2-skiplist.d b/ld/testsuite/ld-pe/pdb-types2-skiplist.d new file mode 100644 index 00000000000..52c10fa501d --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types2-skiplist.d @@ -0,0 +1,5 @@ + +*: file format binary + +Contents of section .data: + 0000 00100000 00000000 * \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types2-typelist.d b/ld/testsuite/ld-pe/pdb-types2-typelist.d new file mode 100644 index 00000000000..d0fd26e0fa4 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types2-typelist.d @@ -0,0 +1,20 @@ + +*: file format binary + +Contents of section .data: + 0000 0e000516 00000000 74657374 00f3f2f1 ........test.... + 0010 0a000516 00000000 666f6f00 0a000516 ........foo..... + 0020 00000000 62617200 0e000416 02000000 ....bar......... + 0030 01100000 02100000 0a000516 03100000 ................ + 0040 62617a00 0e000516 00000000 2f746d70 baz........./tmp + 0050 00f3f2f1 0a000516 00000000 67636300 ............gcc. + 0060 0e000516 00000000 746d702e 6300f2f1 ........tmp.c... + 0070 0e000516 00000000 746d702e 70646200 ........tmp.pdb. + 0080 12000516 00000000 2d67636f 64657669 ........-gcodevi + 0090 657700f1 1a000316 05000510 00000610 ew.............. + 00a0 00000710 00000810 00000910 0000f2f1 ................ + 00b0 12000516 00000000 6e616d65 73706163 ........namespac + 00c0 6500f2f1 12000116 00000000 01100000 e............... + 00d0 66756e63 3100f2f1 12000116 0b100000 func1........... + 00e0 01100000 66756e63 3200f2f1 12000216 ....func2....... + 00f0 02100000 04100000 6d657468 6f6400f1 ........method.. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types2a.s b/ld/testsuite/ld-pe/pdb-types2a.s new file mode 100644 index 00000000000..e11843ae575 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types2a.s @@ -0,0 +1,42 @@ +.equ CV_SIGNATURE_C13, 4 + +.equ T_VOID, 0x0003 +.equ T_INT4, 0x0074 + +.equ LF_PROCEDURE, 0x1008 +.equ LF_MFUNCTION, 0x1009 +.equ LF_POINTER, 0x1002 +.equ LF_ARGLIST, 0x1201 +.equ LF_FIELDLIST, 0x1203 +.equ LF_CLASS, 0x1504 +.equ LF_ONEMETHOD, 0x1511 +.equ LF_FUNC_ID, 0x1601 +.equ LF_MFUNC_ID, 0x1602 +.equ LF_BUILDINFO, 0x1603 +.equ LF_SUBSTR_LIST, 0x1604 +.equ LF_STRING_ID, 0x1605 + +.equ CV_PTR_64, 0xc + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, string "test" +.string1: +.short .string2 - .string1 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "test" +.byte 0xf3 +.byte 0xf2 +.byte 0xf1 + +# Type 1001, string "foo" +.string2: +.short .types_end - .string2 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "foo" + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb-types2b.s b/ld/testsuite/ld-pe/pdb-types2b.s new file mode 100644 index 00000000000..33541729f63 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types2b.s @@ -0,0 +1,221 @@ +.equ CV_SIGNATURE_C13, 4 + +.equ T_VOID, 0x0003 +.equ T_INT4, 0x0074 + +.equ LF_PROCEDURE, 0x1008 +.equ LF_MFUNCTION, 0x1009 +.equ LF_POINTER, 0x1002 +.equ LF_ARGLIST, 0x1201 +.equ LF_FIELDLIST, 0x1203 +.equ LF_CLASS, 0x1504 +.equ LF_ONEMETHOD, 0x1511 +.equ LF_FUNC_ID, 0x1601 +.equ LF_MFUNC_ID, 0x1602 +.equ LF_BUILDINFO, 0x1603 +.equ LF_SUBSTR_LIST, 0x1604 +.equ LF_STRING_ID, 0x1605 + +.equ CV_PTR_64, 0xc + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, string "foo" +.string1: +.short .string2 - .string1 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "foo" + +# Type 1001, string "bar" +.string2: +.short .substrlist1 - .string2 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "bar" + +# Type 1002, substr list of "foo" and "bar" +.substrlist1: +.short .string3 - .substrlist1 - 2 +.short LF_SUBSTR_LIST +.long 2 # count +.long 0x1000 +.long 0x1001 + +# Type 1003, string "baz" referencing substr list 1002 +.string3: +.short .string4 - .string3 - 2 +.short LF_STRING_ID +.long 0x1002 +.asciz "baz" + +# Type 1004, string "/tmp" (build directory) +.string4: +.short .string5 - .string4 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "/tmp" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1005, string "gcc" (compiler) +.string5: +.short .string6 - .string5 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "gcc" + +# Type 1006, string "tmp.c" (source file) +.string6: +.short .string7 - .string6 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "tmp.c" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1007, string "tmp.pdb" (PDB file) +.string7: +.short .string8 - .string7 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "tmp.pdb" + +# Type 1008, string "-gcodeview" (command arguments) +.string8: +.short .buildinfo1 - .string8 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "-gcodeview" +.byte 0xf1 # padding + +# The 1009, build info +.buildinfo1: +.short .string9 - .buildinfo1 - 2 +.short LF_BUILDINFO +.short 5 # count +.long 0x1004 # build directory +.long 0x1005 # compiler +.long 0x1006 # source file +.long 0x1007 # PDB file +.long 0x1008 # command arguments +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100a, string "namespace" +.string9: +.short .arglist1 - .string9 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "namespace" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100b, arg list of type T_INT4 +.arglist1: +.short .proc1 - .arglist1 - 2 +.short LF_ARGLIST +.long 1 # no. entries +.long T_INT4 + +# Type 100c, procedure, return type T_VOID, arg list 100b +.proc1: +.short .func1 - .proc1 - 2 +.short LF_PROCEDURE +.long T_VOID +.byte 0 # calling convention +.byte 0 # attributes +.short 1 # no. parameters +.long 0x100b + +# Type 100d, function "func1" +.func1: +.short .func2 - .func1 - 2 +.short LF_FUNC_ID +.long 0 # parent scope +.long 0x100c # type +.asciz "func1" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100e, function "func2" within scope "namespace" +.func2: +.short .class1 - .func2 - 2 +.short LF_FUNC_ID +.long 0x100a # parent scope +.long 0x100c # type +.asciz "func2" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100f, forward declaration of class foo +.class1: +.short .ptr1 - .class1 - 2 +.short LF_CLASS +.short 0 # no. members +.short 0x80 # property (has unique name, forward declaration) +.long 0 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 0 # size +.asciz "foo" # name +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1010, pointer to 100f +.ptr1: +.short .mfunction1 - .ptr1 - 2 +.short LF_POINTER +.long 0x100f +.long (8 << 13) | CV_PTR_64 + +# Type 1011, member function of 100f, return type void, arg list 100b +.mfunction1: +.short .fieldlist1 - .mfunction1 - 2 +.short LF_MFUNCTION +.long T_VOID +.long 0x100f +.long 0x1010 # type of "this" pointer +.byte 0 # calling convention +.byte 0 # attributes +.short 1 # no. parameters +.long 0x100b # arg list +.long 0 # "this" adjustment + +# Type 1012, field list for class foo +.fieldlist1: +.short .class2 - .fieldlist1 - 2 +.short LF_FIELDLIST +.short LF_ONEMETHOD +.short 0 # method attribute +.long 0x1010 # method type +.asciz "method" +.byte 0xf1 + +# Type 1013, actual declaration of class foo +.class2: +.short .mfunc1 - .class2 - 2 +.short LF_CLASS +.short 0 # no. members +.short 0 # property +.long 0x1012 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 0 # size +.asciz "foo" # name +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1014, function "method" within class "foo" +.mfunc1: +.short .types_end - .mfunc1 - 2 +.short LF_MFUNC_ID +.long 0x100f # parent class +.long 0x1011 # function type +.asciz "method" +.byte 0xf1 # padding + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 5661438c9e9..9753216f544 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1148,8 +1148,180 @@ proc test5 { } { } } +proc test6 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb-types2a.s tmpdir/pdb-types2a.o] { + unsupported "Build pdb-types2a.o" + return + } + + if ![ld_assemble $as $srcdir/$subdir/pdb-types2b.s tmpdir/pdb-types2b.o] { + unsupported "Build pdb-types2b.o" + return + } + + if ![ld_link $ld "tmpdir/pdb-types2.exe" "--pdb=tmpdir/pdb-types2.pdb tmpdir/pdb-types2a.o tmpdir/pdb-types2b.o"] { + unsupported "Create PE image with PDB file" + return + } + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb 0004"] + + if ![string match "" $exec_output] { + fail "Could not extract IPI stream" + return + } else { + pass "Extracted IPI stream" + } + + # check values in IPI header, and save anything interesting + + set fi [open tmpdir/0004] + fconfigure $fi -translation binary + + seek $fi 8 current + + set data [read $fi 4] + binary scan $data i first_type + + if { $first_type != 0x1000 } { + fail "Incorrect first type value in IPI stream." + } else { + pass "Correct first type value in IPI stream." + } + + set data [read $fi 4] + binary scan $data i end_type + + # end_type is one greater than the last type in the stream + if { $end_type != 0x100f } { + fail "Incorrect end type value in IPI stream." + } else { + pass "Correct end type value in IPI stream." + } + + set data [read $fi 4] + binary scan $data i type_list_size + + set data [read $fi 2] + binary scan $data s hash_stream_index + + seek $fi 2 current + + set data [read $fi 4] + binary scan $data i hash_size + + if { $hash_size != 4 } { + fail "Incorrect hash size in IPI stream." + } else { + pass "Correct hash size in IPI stream." + } + + set data [read $fi 4] + binary scan $data i num_buckets + + if { $num_buckets != 0x3ffff } { + fail "Incorrect number of buckets in IPI stream." + } else { + pass "Correct number of buckets in IPI stream." + } + + set data [read $fi 4] + binary scan $data i hash_list_offset + + set data [read $fi 4] + binary scan $data i hash_list_size + + set data [read $fi 4] + binary scan $data i skip_list_offset + + set data [read $fi 4] + binary scan $data i skip_list_size + + seek $fi 8 current + + set type_list [read $fi $type_list_size] + + close $fi + + set fi [open tmpdir/pdb-types2-typelist w] + fconfigure $fi -translation binary + puts -nonewline $fi $type_list + close $fi + + # check type list + + set exp [file_contents "$srcdir/$subdir/pdb-types2-typelist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-typelist"] + if ![string match $exp $got] { + fail "Incorrect type list in IPI stream." + } else { + pass "Correct type list in IPI stream." + } + + # extract hash list and skip list + + set index_str [format "%04x" $hash_stream_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract IPI hash stream." + } else { + pass "Extracted IPI hash stream." + } + + set fi [open tmpdir/$index_str] + fconfigure $fi -translation binary + + seek $fi $hash_list_offset + set hash_list [read $fi $hash_list_size] + + seek $fi $skip_list_offset + set skip_list [read $fi $skip_list_size] + + close $fi + + # check hash list + + set fi [open tmpdir/pdb-types2-hashlist w] + fconfigure $fi -translation binary + puts -nonewline $fi $hash_list + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb-types2-hashlist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-hashlist"] + if ![string match $exp $got] { + fail "Incorrect hash list in IPI stream." + } else { + pass "Correct hash list in IPI stream." + } + + # check skip list + + set fi [open tmpdir/pdb-types2-skiplist w] + fconfigure $fi -translation binary + puts -nonewline $fi $skip_list + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb-types2-skiplist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-skiplist"] + if ![string match $exp $got] { + fail "Incorrect skip list in IPI stream." + } else { + pass "Correct skip list in IPI stream." + } +} + test1 test2 test3 test4 test5 +test6 -- 2.37.4