From patchwork Fri Dec 9 01:52:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31571 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp528347wrr; Thu, 8 Dec 2022 17:53:02 -0800 (PST) X-Google-Smtp-Source: AA0mqf7G8adJSRyu/jQNmdpDMBes03D1h1vZ/dq8QpN0d2Bd7klYQyIoBSj1nQgAXFzymlacPPBx X-Received: by 2002:a17:906:1914:b0:7c1:311f:352f with SMTP id a20-20020a170906191400b007c1311f352fmr2174934eje.48.1670550781825; Thu, 08 Dec 2022 17:53:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550781; cv=none; d=google.com; s=arc-20160816; b=tcDhhfGvgPRlm7asYOoMk6xVAtqgu6Zeo2Jxqi9xegDO/E7NtBvkCw9KEoMKxrv7uZ RSO+iOm1ZjWHDsfyHs4aHhWJ/J0xQf1sA4CtDj9DQlZdyJ+5tFgIhrYHlHKWNaeCU00t WlgtihGevKUjP35igwPF659yDJy3m8TrpboGTlmSgLKCl4fFsQjKRZWfvVV6YLs4eIoI BD+wHL38GmmH85JRCvLlEA92ymjZRs4xTaLpCehS5Efwd0ET4Ws+gcIANxeGijtkTO7p YeMgs8Hi7rOIAAW0+I+W+TLeuQ5Exdl12270xuf/Z3DkTDeryiTC6u3fJQ+8z9Cvnc6M /mIw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:message-id:date:subject:cc:to:from:dkim-signature :dmarc-filter:delivered-to; bh=aOl/+FtBOxyMdCUqsfeOvaPA8dF4HuzR4welSGcFBO0=; b=t2Z1wcoh4mImfX5a3G0cPvuf8kHTljenuRD/BxDNLdXUfx38V7+MoAPLcuW9BqOujO MCnibDMYMYaoHkrttFdjCQu0ByxAyVlcHwNtyJb8BnSMuCi3q1E7DK6V7sNJIuxwnecg 1uVdtd6r1Re2Ykb/JW4ONSKJ/QrA3dIhCHLW/4Fp1cOP89/VsbqatB8uNAK+n8C/flVr klwIF+5kTX5PRbR60ImQwphNLZTz6f6WR9HmtH5KJW1ArQIdT6ODPVrl8skPwQ39knme Pd/oLJ4bKLV+7yBGNSjkblWYOBQ6xaWf9dhe2IiUXE3SBfi5D4Pm4LjJXy6bvWLapZdY /7Hg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=BkCTIIpU; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id xg12-20020a170907320c00b007836ec6999dsi3221ejb.904.2022.12.08.17.53.01 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:53:01 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=BkCTIIpU; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 533953889045 for ; Fri, 9 Dec 2022 01:52:56 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by sourceware.org (Postfix) with ESMTPS id D7A23384F728 for ; Fri, 9 Dec 2022 01:52:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D7A23384F728 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-wm1-x32c.google.com with SMTP id j5-20020a05600c410500b003cfa9c0ea76so2409764wmi.3 for ; Thu, 08 Dec 2022 17:52:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:sender:from:to:cc:subject:date:message-id:reply-to; bh=aOl/+FtBOxyMdCUqsfeOvaPA8dF4HuzR4welSGcFBO0=; b=BkCTIIpU//hfROxVoWcoJnIk76tjxn1NEDMM8SHLG+kfoodNqdXxjDO9fYcmOfUPp0 YVyCoTL8essup847aSja2nszuSlGgRjxPZygNe4QCN06y1SYw9KVhoS879QBuJJiQ/3o 3h20nlOVnZwyKdDAinaxtO8eYVWtNo8ZinLc7FnGWXbaFBNyEGnquELxqnKyCrvhREMd C2y30aqBTm0O9aNJ0/HBF1XvNTnSCpK5qc5YoFRB4V5ZaK1ufI52B1tdctuV2djoYIDg Cc3T2Ayv0FwmYnlmqy3RDsqQeI3I64nlzmz/ZsINTfuoIF6tyj6nzOIlbS4lvwsGspWp UNCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:sender:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=aOl/+FtBOxyMdCUqsfeOvaPA8dF4HuzR4welSGcFBO0=; b=C3VGtvAQiw/XugT8VTOy5HlhEI2u37CYS4mW8Ej9xq+zliusgBit9C5m28XVczfPYC ty1gdeqRP0lfResoYGC1X1VVwQdQWIly/AfyE6tIvoUbHZxZTDnhlOvstrPD42f1aWyF ah/PsIF2HBPl1tBstCC50bD2tKBvw/IDv6xdk8WxpwIY/cX4zN81hPstgagn3V2FuxMQ AMXDpK95lAVNJ3VAxcWAJG8DIjifQtU7UHB9Lq9c+zPxpMXsM9kqNWyduRgF0VEDPVVR lx6gZZ5Hoohz4BihZOxeRHHT4BSX83ZjVx38+HEyzC/khpUudxztsgJrEZh2UH3b6lpi s8Fg== X-Gm-Message-State: ANoB5pljfWXrSmfwG6J7qfaQxySDhWr3kMN7EXmYlHTfecgYB5oYnL1i bI0XHSWSM91sfQwA7NR2mPVtYkJ8zBs= X-Received: by 2002:a05:600c:3c95:b0:3cf:e7c8:494 with SMTP id bg21-20020a05600c3c9500b003cfe7c80494mr3400337wmb.29.1670550764209; Thu, 08 Dec 2022 17:52:44 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:43 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 01/10] ld: Generate PDB string table Date: Fri, 9 Dec 2022 01:52:31 +0000 Message-Id: <20221209015240.6348-1-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699456598492811?= X-GMAIL-MSGID: =?utf-8?q?1751699456598492811?= Resubmitted patch set as per Nick's request. --- ld/pdb.c | 296 +++++++++++++++++++++++++++++- ld/pdb.h | 12 ++ ld/testsuite/ld-pe/pdb-strings.d | 10 + ld/testsuite/ld-pe/pdb-strings1.s | 19 ++ ld/testsuite/ld-pe/pdb-strings2.s | 19 ++ ld/testsuite/ld-pe/pdb.exp | 122 ++++++++++++ 6 files changed, 472 insertions(+), 6 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb-strings.d create mode 100644 ld/testsuite/ld-pe/pdb-strings1.s create mode 100644 ld/testsuite/ld-pe/pdb-strings2.s diff --git a/ld/pdb.c b/ld/pdb.c index 6f69574289d..98663a1f9ae 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -41,6 +41,23 @@ struct public uint32_t address; }; +struct string +{ + struct string *next; + uint32_t hash; + uint32_t offset; + size_t len; + char s[]; +}; + +struct string_table +{ + struct string *strings_head; + struct string *strings_tail; + uint32_t strings_len; + htab_t hashmap; +}; + /* Add a new stream to the PDB archive, and return its BFD. */ static bfd * add_stream (bfd *pdb, const char *name, uint16_t *stream_num) @@ -383,15 +400,170 @@ get_arch_number (bfd *abfd) return IMAGE_FILE_MACHINE_I386; } +/* Add a string to the strings table, if it's not already there. */ +static void +add_string (char *str, size_t len, struct string_table *strings) +{ + uint32_t hash = calc_hash (str, len); + void **slot; + + slot = htab_find_slot_with_hash (strings->hashmap, str, hash, INSERT); + + if (!*slot) + { + struct string *s; + + *slot = xmalloc (offsetof (struct string, s) + len); + + s = (struct string *) *slot; + + s->next = NULL; + s->hash = hash; + s->offset = strings->strings_len; + s->len = len; + memcpy (s->s, str, len); + + if (strings->strings_tail) + strings->strings_tail->next = s; + else + strings->strings_head = s; + + strings->strings_tail = s; + + strings->strings_len += len + 1; + } +} + +/* Return the hash of an entry in the string table. */ +static hashval_t +hash_string_table_entry (const void *p) +{ + const struct string *s = (const struct string *) p; + + return s->hash; +} + +/* Compare an entry in the string table with a string. */ +static int +eq_string_table_entry (const void *a, const void *b) +{ + const struct string *s1 = (const struct string *) a; + const char *s2 = (const char *) b; + size_t s2_len = strlen (s2); + + if (s2_len != s1->len) + return 0; + + return memcmp (s1->s, s2, s2_len) == 0; +} + +/* Parse the string table within the .debug$S section. */ +static void +parse_string_table (bfd_byte *data, size_t size, + struct string_table *strings) +{ + while (true) + { + size_t len = strnlen ((char *) data, size); + + add_string ((char *) data, len, strings); + + data += len + 1; + + if (size <= len + 1) + break; + + size -= len + 1; + } +} + +/* Parse the .debug$S section within an object file. */ +static bool +handle_debugs_section (asection *s, bfd *mod, struct string_table *strings) +{ + bfd_byte *data = NULL; + size_t off; + + if (!bfd_get_full_section_contents (mod, s, &data)) + return false; + + if (!data) + return false; + + if (bfd_getl32 (data) != CV_SIGNATURE_C13) + { + free (data); + return true; + } + + off = sizeof (uint32_t); + + while (off + sizeof (uint32_t) <= s->size) + { + uint32_t type, size; + + type = bfd_getl32 (data + off); + + off += sizeof (uint32_t); + + if (off + sizeof (uint32_t) > s->size) + { + free (data); + bfd_set_error (bfd_error_bad_value); + return false; + } + + size = bfd_getl32 (data + off); + + off += sizeof (uint32_t); + + if (off + size > s->size) + { + free (data); + bfd_set_error (bfd_error_bad_value); + return false; + } + + switch (type) + { + case DEBUG_S_STRINGTABLE: + parse_string_table (data + off, size, strings); + + break; + } + + off += size; + + if (off % sizeof (uint32_t)) + off += sizeof (uint32_t) - (off % sizeof (uint32_t)); + } + + free (data); + + return true; +} + /* Populate the module stream, which consists of the transformed .debug$S data for each object file. */ static bool -populate_module_stream (bfd *stream, uint32_t *sym_byte_size) +populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, + struct string_table *strings) { uint8_t int_buf[sizeof (uint32_t)]; *sym_byte_size = sizeof (uint32_t); + /* Process .debug$S section(s). */ + + for (asection *s = mod->sections; s; s = s->next) + { + if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) + { + if (!handle_debugs_section (s, mod, strings)) + return false; + } + } + /* Write the signature. */ bfd_putl32 (CV_SIGNATURE_C13, int_buf); @@ -412,7 +584,7 @@ populate_module_stream (bfd *stream, uint32_t *sym_byte_size) /* Create the module info substream within the DBI. */ static bool create_module_info_substream (bfd *abfd, bfd *pdb, void **data, - uint32_t *size) + uint32_t *size, struct string_table *strings) { uint8_t *ptr; @@ -482,7 +654,8 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, return false; } - if (!populate_module_stream (stream, &sym_byte_size)) + if (!populate_module_stream (stream, in, &sym_byte_size, + strings)) { free (*data); return false; @@ -687,14 +860,16 @@ static bool populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, uint16_t section_header_stream_num, uint16_t sym_rec_stream_num, - uint16_t publics_stream_num) + uint16_t publics_stream_num, + struct string_table *strings) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; void *mod_info, *sc; uint32_t mod_info_size, sc_size; - if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size)) + if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, + strings)) return false; if (!create_section_contrib_substream (abfd, &sc, &sc_size)) @@ -1107,6 +1282,95 @@ create_section_header_stream (bfd *pdb, bfd *abfd, uint16_t *num) return true; } +/* Populate the "/names" named stream, which contains the string table. */ +static bool +populate_names_stream (bfd *stream, struct string_table *strings) +{ + char int_buf[sizeof (uint32_t)]; + struct string_table_header h; + uint32_t num_strings = 0, num_buckets; + struct string **buckets; + + bfd_putl32 (STRING_TABLE_SIGNATURE, &h.signature); + bfd_putl32 (STRING_TABLE_VERSION, &h.version); + + if (bfd_bwrite (&h, sizeof (h), stream) != sizeof (h)) + return false; + + bfd_putl32 (strings->strings_len, int_buf); + + if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) + return false; + + int_buf[0] = 0; + + if (bfd_bwrite (int_buf, 1, stream) != 1) + return false; + + for (struct string *s = strings->strings_head; s; s = s->next) + { + if (bfd_bwrite (s->s, s->len, stream) != s->len) + return false; + + if (bfd_bwrite (int_buf, 1, stream) != 1) + return false; + + num_strings++; + } + + num_buckets = num_strings * 2; + + buckets = xmalloc (sizeof (struct string *) * num_buckets); + memset (buckets, 0, sizeof (struct string *) * num_buckets); + + for (struct string *s = strings->strings_head; s; s = s->next) + { + uint32_t bucket_num = s->hash % num_buckets; + + while (buckets[bucket_num]) + { + bucket_num++; + + if (bucket_num == num_buckets) + bucket_num = 0; + } + + buckets[bucket_num] = s; + } + + bfd_putl32 (num_buckets, int_buf); + + if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) + { + free (buckets); + return false; + } + + for (unsigned int i = 0; i < num_buckets; i++) + { + if (buckets[i]) + bfd_putl32 (buckets[i]->offset, int_buf); + else + bfd_putl32 (0, int_buf); + + if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != + sizeof (uint32_t)) + { + free (buckets); + return false; + } + } + + free (buckets); + + bfd_putl32 (num_strings, int_buf); + + if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) + return false; + + return true; +} + /* Create a PDB debugging file for the PE image file abfd with the build ID guid, stored at pdb_name. */ bool @@ -1117,6 +1381,7 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) bfd *info_stream, *dbi_stream, *names_stream, *sym_rec_stream, *publics_stream; uint16_t section_header_stream_num, sym_rec_stream_num, publics_stream_num; + struct string_table strings; pdb = bfd_openw (pdb_name, "pdb"); if (!pdb) @@ -1125,6 +1390,13 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) return false; } + strings.strings_head = NULL; + strings.strings_tail = NULL; + strings.strings_len = 1; + strings.hashmap = htab_create_alloc (0, hash_string_table_entry, + eq_string_table_entry, free, + xcalloc, free); + bfd_set_format (pdb, bfd_archive); if (!create_old_directory_stream (pdb)) @@ -1201,13 +1473,23 @@ 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)) + sym_rec_stream_num, publics_stream_num, + &strings)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); goto end; } + add_string ("", 0, &strings); + + if (!populate_names_stream (names_stream, &strings)) + { + einfo (_("%P: warning: cannot populate names stream " + "in PDB file: %E\n")); + goto end; + } + if (!populate_publics_stream (publics_stream, abfd, sym_rec_stream)) { einfo (_("%P: warning: cannot populate publics stream " @@ -1227,5 +1509,7 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) end: bfd_close (pdb); + htab_delete (strings.hashmap); + return ret; } diff --git a/ld/pdb.h b/ld/pdb.h index e22dea18eca..611f71041c0 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -155,6 +155,18 @@ struct optional_dbg_header #define CV_SIGNATURE_C13 4 +#define DEBUG_S_STRINGTABLE 0xf3 + +#define STRING_TABLE_SIGNATURE 0xeffeeffe +#define STRING_TABLE_VERSION 1 + +/* VHdr in nmt.h */ +struct string_table_header +{ + uint32_t signature; + uint32_t version; +}; + #define SECTION_CONTRIB_VERSION_60 0xf12eba2d /* SC in dbicommon.h */ diff --git a/ld/testsuite/ld-pe/pdb-strings.d b/ld/testsuite/ld-pe/pdb-strings.d new file mode 100644 index 00000000000..8be853efb72 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-strings.d @@ -0,0 +1,10 @@ + +*: file format binary + +Contents of section .data: + 0000 feeffeef 01000000 17000000 0000666f ..............fo + 0010 6f006261 72006261 7a007175 78007175 o.bar.baz.qux.qu + 0020 7578000c 00000001 0000000a 00000000 ux.............. + 0030 00000000 00000000 00000012 00000000 ................ + 0040 00000000 00000002 00000006 00000000 ................ + 0050 0000000e 00000006 000000 ........... \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-strings1.s b/ld/testsuite/ld-pe/pdb-strings1.s new file mode 100644 index 00000000000..09eedd93fb3 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-strings1.s @@ -0,0 +1,19 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_STRINGTABLE, 0xf3 + +.section ".debug$S", "rn" +.long CV_SIGNATURE_C13 +.long DEBUG_S_STRINGTABLE +.long .strings_end - .strings_start + +.strings_start: + +.asciz "" +.asciz "foo" +.asciz "bar" +.asciz "baz" +.asciz "qux" + +.strings_end: + +.balign 4 diff --git a/ld/testsuite/ld-pe/pdb-strings2.s b/ld/testsuite/ld-pe/pdb-strings2.s new file mode 100644 index 00000000000..33d9215e4c8 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-strings2.s @@ -0,0 +1,19 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_STRINGTABLE, 0xf3 + +.section ".debug$S", "rn" +.long CV_SIGNATURE_C13 +.long DEBUG_S_STRINGTABLE +.long .strings_end - .strings_start + +.strings_start: + +.asciz "" +.asciz "bar" +.asciz "baz" +.asciz "qux" +.asciz "quux" + +.strings_end: + +.balign 4 diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 0be65e22fb6..09e9b4a8809 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -703,5 +703,127 @@ proc test2 { } { test_section_contrib $section_contrib } +proc find_named_stream { pdb name } { + global ar + + set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb 0001"] + + if ![string match "" $exec_output] { + return 0 + } + + set fi [open tmpdir/0001] + fconfigure $fi -translation binary + + seek $fi 0x1c + + set data [read $fi 4] + binary scan $data i string_len + + set strings [read $fi $string_len] + + set string_off 0 + + while {[string first \000 $strings $string_off] != -1 } { + set str [string range $strings $string_off [expr [string first \000 $strings $string_off] - 1]] + + if { $str eq $name } { + break + } + + incr string_off [expr [string length $str] + 1] + } + + if { [string length $strings] == $string_off } { # string not found + close $fi + return 0 + } + + set data [read $fi 4] + binary scan $data i num_entries + + seek $fi 4 current + + set data [read $fi 4] + binary scan $data i present_bitmap_len + + seek $fi [expr $present_bitmap_len * 4] current + + set data [read $fi 4] + binary scan $data i deleted_bitmap_len + + seek $fi [expr $deleted_bitmap_len * 4] current + + for {set i 0} {$i < $num_entries} {incr i} { + set data [read $fi 4] + binary scan $data i offset + + if { $offset == $string_off } { + set data [read $fi 4] + binary scan $data i value + close $fi + + return $value + } + + seek $fi 4 current + } + + close $fi + + return 0 +} + +proc test3 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb-strings1.s tmpdir/pdb-strings1.o] { + unsupported "Build pdb-strings1.o" + return + } + + if ![ld_assemble $as $srcdir/$subdir/pdb-strings2.s tmpdir/pdb-strings2.o] { + unsupported "Build pdb-strings2.o" + return + } + + if ![ld_link $ld "tmpdir/pdb-strings.exe" "--pdb=tmpdir/pdb-strings.pdb tmpdir/pdb-strings1.o tmpdir/pdb-strings2.o"] { + unsupported "Create PE image with PDB file" + return + } + + set index [find_named_stream "tmpdir/pdb-strings.pdb" "/names"] + + if { $index == 0 } { + fail "Could not find /names stream" + return + } else { + pass "Found /names stream" + } + + set index_str [format "%04x" $index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-strings.pdb $index_str"] + + if ![string match "" $exec_output] { + return 0 + } + + set exp [file_contents "$srcdir/$subdir/pdb-strings.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"] + + if ![string match $exp $got] { + fail "Strings table was not as expected" + } else { + pass "Strings table was as expected" + } +} + test1 test2 +test3 From patchwork Fri Dec 9 01:52:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31572 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp528421wrr; Thu, 8 Dec 2022 17:53:13 -0800 (PST) X-Google-Smtp-Source: AA0mqf7XzDgKA+seUrdKhcWBEbOT7aEdBBHtTFFcDDN9IkeMASAu+BsgmpPjB553jnYmSKkTg3uF X-Received: by 2002:a05:6402:5307:b0:45c:835c:1ebb with SMTP id eo7-20020a056402530700b0045c835c1ebbmr3746738edb.9.1670550793240; Thu, 08 Dec 2022 17:53:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550793; cv=none; d=google.com; s=arc-20160816; b=Oalc4T+x4e6WdPXrbUieheCudcMRpkd4bnUHVCYC/UEp5kLp4iEFthGX4w7Oiit6lv azvThPvT8XhmhFiB/Z+41uCMdWuQGhCU/gA1zgSPeePc71lAifv0D5pfzZoShKwgRbwz iZQWMh1gyeVacZrpGw6pFIzBqeLvqrkuZsz1a3U2QsYl33hm+PniipXJiUZZQGT0lipU vEgIZ1z1QRF8SEtua3CKfaQW5Lvgl96yEV7EvPnw4TGMTJMJkJVgB9JYJlegZQd5iTqu 8/O4xaaZOjDeLevS6Zzu5NibNzYzKdolP18WP6hL2UXkYczl9TS/g4CtJ07rsTQxE1/z YAPQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=IuaKNWdCs2jWT93wqAyx19hyjUwnqToZwq2OI/5DitQ=; b=Qt3rf8x9rs8AJxHyeZy2xxxB3KJqwJy7coxT9LQSwhJ0f6kZZTB9ReBKbjBDy/cx04 26gvw1JqwyNNtGtvCjpV+t7YI20HgV9Hj3NVBblDaA3kaPEsGD3NYOC7bJc0aDZWzmln qNboogrzCV9+02Yripse1/8bXcrd84qfJ3pa5+MpETgc2lOt4sMmx/OZ5dxaBwZbI9Wk bTYVpiSIgzwfwAoPWT0n008Sz4jA/++JDau8f36ShWBPNHAZtu31D45mlO38N6by842n xAwHrz0FzXT/S15DYlso6AuHyWnB6tWyu+Geq8u9J+v/p/Cc1HJuMorx+0xyxwTDBQ8Y HaQQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=HdXz1h6l; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id t23-20020a508d57000000b0046270f01409si209438edt.40.2022.12.08.17.53.12 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:53:13 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=HdXz1h6l; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B0FED38923C5 for ; Fri, 9 Dec 2022 01:53:01 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by sourceware.org (Postfix) with ESMTPS id D59403871FAE for ; Fri, 9 Dec 2022 01:52:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D59403871FAE 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-wm1-x336.google.com with SMTP id f13-20020a1cc90d000000b003d08c4cf679so2401129wmb.5 for ; Thu, 08 Dec 2022 17:52:46 -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=IuaKNWdCs2jWT93wqAyx19hyjUwnqToZwq2OI/5DitQ=; b=HdXz1h6luGPRVvw+XONtkppLB9tcCUL6/K8Kc3VqzpGKlTcRmLshLeO2NPB429HrUd atlLcPTSfuLa2n6GqZGMJ2ll3LuV3j68eOPkrkWaz4SW5m0FZo+9qghf6I6sVBuDJJd5 YmzrKmqlxsUiGh4EoEkfrnFxhR+eeVogc2hpxkS5m73EmQtJC75etLhONdEpuHrIsw7K vBh9YEiFIRuLZdun2OO7jRgZeohJBAmmhd28pK71ecFqC2rAgZgU5ZAxr0mQZu1lCAlV VALXBg909heWI175HIATpZtN9hw5oI6h12B8uSgenLVaolNiyAcf4aUmkUHSN05f6UUj BTMQ== 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=IuaKNWdCs2jWT93wqAyx19hyjUwnqToZwq2OI/5DitQ=; b=w91qw4FEauE4MO3SB9DmfSv2XbMurhJJUbaV/09ayeRIOJ6ivCzTOpiX59Ozz7Dc+f GbTDXZDvintlfoA9+2Zi9dPM1ThcqoTX4a9shi4Ny4/2hyNkbwkROapRd70KOHsgdjB7 fDWa57hvrgUDl+MHr4tk+yqqAQ9UjM7WHlxn5c6Qdis6P6dUnsSKkTWEQrRLCAizpVl0 ne+WuZXVOzKzXRoXo1biuZKEEj/5jdPeWDVE+RwKROmkayVYiu/RhrBd8twcZ9Ud/GNh ARcOKWlViccUtJcA1hNZe1CEIVIKmJCkHwxINL96R0U5n2gddBbaf9VLBSM5vsqPWTAk L7nw== X-Gm-Message-State: ANoB5pkQX9NbqEziVRyQJ35DLGIujEH1wsF50NWA8FQjkbCMZnaQEW3Y bPhvsg96hp84xiKknwODHtomQpCfjVU= X-Received: by 2002:a1c:cc1a:0:b0:3cf:5e42:de64 with SMTP id h26-20020a1ccc1a000000b003cf5e42de64mr3393842wmb.39.1670550765068; Thu, 08 Dec 2022 17:52:45 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:44 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 02/10] ld: Write DEBUG_S_FILECHKSMS entries in PDBs Date: Fri, 9 Dec 2022 01:52:32 +0000 Message-Id: <20221209015240.6348-2-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699469047973588?= X-GMAIL-MSGID: =?utf-8?q?1751699469047973588?= --- ld/pdb.c | 430 +++++++++++++++++++++++++- ld/pdb.h | 9 + ld/testsuite/ld-pe/pdb.exp | 154 +++++++++ ld/testsuite/ld-pe/pdb3-c13-info1.d | 8 + ld/testsuite/ld-pe/pdb3-c13-info2.d | 8 + ld/testsuite/ld-pe/pdb3-source-info.d | 7 + ld/testsuite/ld-pe/pdb3a.s | 52 ++++ ld/testsuite/ld-pe/pdb3b.s | 52 ++++ 8 files changed, 708 insertions(+), 12 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb3-c13-info1.d create mode 100644 ld/testsuite/ld-pe/pdb3-c13-info2.d create mode 100644 ld/testsuite/ld-pe/pdb3-source-info.d create mode 100644 ld/testsuite/ld-pe/pdb3a.s create mode 100644 ld/testsuite/ld-pe/pdb3b.s diff --git a/ld/pdb.c b/ld/pdb.c index 98663a1f9ae..b37a5a0ebfd 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -46,6 +46,7 @@ struct string struct string *next; uint32_t hash; uint32_t offset; + uint32_t source_file_offset; size_t len; char s[]; }; @@ -58,6 +59,18 @@ struct string_table htab_t hashmap; }; +struct mod_source_files +{ + uint16_t files_count; + struct string **files; +}; + +struct source_files_info +{ + uint16_t mod_count; + struct mod_source_files *mods; +}; + /* Add a new stream to the PDB archive, and return its BFD. */ static bfd * add_stream (bfd *pdb, const char *name, uint16_t *stream_num) @@ -400,6 +413,134 @@ get_arch_number (bfd *abfd) return IMAGE_FILE_MACHINE_I386; } +/* Validate the DEBUG_S_FILECHKSMS entry within a module's .debug$S + section, and copy it to the module's symbol stream. */ +static bool +copy_filechksms (uint8_t *data, uint32_t size, char *string_table, + struct string_table *strings, uint8_t *out, + struct mod_source_files *mod_source) +{ + uint8_t *orig_data = data; + uint32_t orig_size = size; + uint16_t num_files = 0; + struct string **strptr; + + bfd_putl32 (DEBUG_S_FILECHKSMS, out); + out += sizeof (uint32_t); + + bfd_putl32 (size, out); + out += sizeof (uint32_t); + + /* Calculate the number of files, and check for any overflows. */ + + while (size > 0) + { + struct file_checksum *fc = (struct file_checksum *) data; + uint8_t padding; + size_t len; + + if (size < sizeof (struct file_checksum)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + len = sizeof (struct file_checksum) + fc->checksum_length; + + if (size < len) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + data += len; + size -= len; + + if (len % sizeof (uint32_t)) + padding = sizeof (uint32_t) - (len % sizeof (uint32_t)); + else + padding = 0; + + if (size < padding) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + num_files++; + + data += padding; + size -= padding; + } + + /* Add the files to mod_source, so that they'll appear in the source + info substream. */ + + if (num_files > 0) + { + uint16_t new_count = num_files + mod_source->files_count; + + mod_source->files = xrealloc (mod_source->files, + sizeof (struct string *) * new_count); + + strptr = mod_source->files + mod_source->files_count; + + mod_source->files_count += num_files; + } + + /* Actually copy the data. */ + + data = orig_data; + size = orig_size; + + while (size > 0) + { + struct file_checksum *fc = (struct file_checksum *) data; + uint32_t string_off; + uint8_t padding; + size_t len; + struct string *str = NULL; + + string_off = bfd_getl32 (&fc->file_id); + len = sizeof (struct file_checksum) + fc->checksum_length; + + if (len % sizeof (uint32_t)) + padding = sizeof (uint32_t) - (len % sizeof (uint32_t)); + else + padding = 0; + + /* Remap the "file ID", i.e. the offset in the module's string table, + so it points to the right place in the main string table. */ + + if (string_table) + { + char *fn = string_table + string_off; + size_t fn_len = strlen (fn); + uint32_t hash = calc_hash (fn, fn_len); + void **slot; + + slot = htab_find_slot_with_hash (strings->hashmap, fn, hash, + NO_INSERT); + + if (slot) + str = (struct string *) *slot; + } + + *strptr = str; + strptr++; + + bfd_putl32 (str ? str->offset : 0, &fc->file_id); + + memcpy (out, data, len + padding); + + data += len + padding; + size -= len + padding; + out += len + padding; + } + + return true; +} + /* Add a string to the strings table, if it's not already there. */ static void add_string (char *str, size_t len, struct string_table *strings) @@ -420,6 +561,7 @@ add_string (char *str, size_t len, struct string_table *strings) s->next = NULL; s->hash = hash; s->offset = strings->strings_len; + s->source_file_offset = 0xffffffff; s->len = len; memcpy (s->s, str, len); @@ -479,10 +621,15 @@ parse_string_table (bfd_byte *data, size_t size, /* Parse the .debug$S section within an object file. */ static bool -handle_debugs_section (asection *s, bfd *mod, struct string_table *strings) +handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, + uint8_t **dataptr, uint32_t *sizeptr, + struct mod_source_files *mod_source) { bfd_byte *data = NULL; size_t off; + uint32_t c13_size = 0; + char *string_table = NULL; + uint8_t *buf, *bufptr; if (!bfd_get_full_section_contents (mod, s, &data)) return false; @@ -498,6 +645,8 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings) off = sizeof (uint32_t); + /* calculate size */ + while (off + sizeof (uint32_t) <= s->size) { uint32_t type, size; @@ -526,9 +675,63 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings) switch (type) { + case DEBUG_S_FILECHKSMS: + c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size; + + if (c13_size % sizeof (uint32_t)) + c13_size += sizeof (uint32_t) - (c13_size % sizeof (uint32_t)); + + break; + case DEBUG_S_STRINGTABLE: parse_string_table (data + off, size, strings); + string_table = (char *) data + off; + + break; + } + + off += size; + + if (off % sizeof (uint32_t)) + off += sizeof (uint32_t) - (off % sizeof (uint32_t)); + } + + if (c13_size == 0) + { + free (data); + return true; + } + + /* copy data */ + + buf = xmalloc (c13_size); + bufptr = buf; + + off = sizeof (uint32_t); + + while (off + sizeof (uint32_t) <= s->size) + { + uint32_t type, size; + + type = bfd_getl32 (data + off); + off += sizeof (uint32_t); + + size = bfd_getl32 (data + off); + off += sizeof (uint32_t); + + switch (type) + { + case DEBUG_S_FILECHKSMS: + if (!copy_filechksms (data + off, size, string_table, + strings, bufptr, mod_source)) + { + free (data); + return false; + } + + bufptr += sizeof (uint32_t) + sizeof (uint32_t) + size; + break; } @@ -540,6 +743,23 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings) free (data); + if (*dataptr) + { + /* Append the C13 info to what's already there, if the module has + multiple .debug$S sections. */ + + *dataptr = xrealloc (*dataptr, *sizeptr + c13_size); + memcpy (*dataptr + *sizeptr, buf, c13_size); + + free (buf); + } + else + { + *dataptr = buf; + } + + *sizeptr += c13_size; + return true; } @@ -547,11 +767,15 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings) data for each object file. */ static bool populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, - struct string_table *strings) + struct string_table *strings, + uint32_t *c13_info_size, + struct mod_source_files *mod_source) { uint8_t int_buf[sizeof (uint32_t)]; + uint8_t *c13_info = NULL; *sym_byte_size = sizeof (uint32_t); + *c13_info_size = 0; /* Process .debug$S section(s). */ @@ -559,8 +783,13 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, { if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) { - if (!handle_debugs_section (s, mod, strings)) + if (!handle_debugs_section (s, mod, strings, &c13_info, + c13_info_size, mod_source)) + { + free (c13_info); + free (mod_source->files); return false; + } } } @@ -569,7 +798,21 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, bfd_putl32 (CV_SIGNATURE_C13, int_buf); if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) - return false; + { + free (c13_info); + return false; + } + + if (c13_info) + { + if (bfd_bwrite (c13_info, *c13_info_size, stream) != *c13_info_size) + { + free (c13_info); + return false; + } + + free (c13_info); + } /* Write the global refs size. */ @@ -584,9 +827,11 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, /* Create the module info substream within the DBI. */ static bool create_module_info_substream (bfd *abfd, bfd *pdb, void **data, - uint32_t *size, struct string_table *strings) + uint32_t *size, struct string_table *strings, + struct source_files_info *source) { uint8_t *ptr; + unsigned int mod_num; static const char linker_fn[] = "* Linker *"; @@ -631,32 +876,54 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, len += 4 - (len % 4); *size += len; + + source->mod_count++; } *data = xmalloc (*size); ptr = *data; + source->mods = xmalloc (source->mod_count + * sizeof (struct mod_source_files)); + memset (source->mods, 0, + source->mod_count * sizeof (struct mod_source_files)); + + mod_num = 0; + for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; in = in->link.next) { struct module_info *mod = (struct module_info *) ptr; uint16_t stream_num; bfd *stream; - uint32_t sym_byte_size; + uint32_t sym_byte_size, c13_info_size; uint8_t *start = ptr; stream = add_stream (pdb, NULL, &stream_num); if (!stream) { + for (unsigned int i = 0; i < source->mod_count; i++) + { + free (source->mods[i].files); + } + + free (source->mods); free (*data); return false; } if (!populate_module_stream (stream, in, &sym_byte_size, - strings)) + strings, &c13_info_size, + &source->mods[mod_num])) { + for (unsigned int i = 0; i < source->mod_count; i++) + { + free (source->mods[i].files); + } + + free (source->mods); free (*data); return false; } @@ -679,7 +946,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, bfd_putl16 (stream_num, &mod->module_sym_stream); bfd_putl32 (sym_byte_size, &mod->sym_byte_size); bfd_putl32 (0, &mod->c11_byte_size); - bfd_putl32 (0, &mod->c13_byte_size); + bfd_putl32 (c13_info_size, &mod->c13_byte_size); bfd_putl16 (0, &mod->source_file_count); bfd_putl16 (0, &mod->padding); bfd_putl32 (0, &mod->unused2); @@ -741,6 +1008,8 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, memset (ptr, 0, 4 - ((ptr - start) % 4)); ptr += 4 - ((ptr - start) % 4); } + + mod_num++; } return true; @@ -855,6 +1124,114 @@ create_section_contrib_substream (bfd *abfd, void **data, uint32_t *size) return true; } +/* The source info substream lives within the DBI stream, and lists the + source files for each object file (i.e. it's derived from the + DEBUG_S_FILECHKSMS parts of the .debug$S sections). This is a bit + superfluous, as the filenames are also available in the C13 parts of + the module streams, but MSVC relies on it to work properly. */ +static void +create_source_info_substream (void **data, uint32_t *size, + struct source_files_info *source) +{ + uint16_t dedupe_source_files_count = 0; + uint16_t source_files_count = 0; + uint32_t strings_len = 0; + uint8_t *ptr; + + /* Loop through the source files, marking unique filenames. The pointers + here are for entries in the main string table, and so have already + been deduplicated. */ + + for (uint16_t i = 0; i < source->mod_count; i++) + { + for (uint16_t j = 0; j < source->mods[i].files_count; j++) + { + if (source->mods[i].files[j]) + { + if (source->mods[i].files[j]->source_file_offset == 0xffffffff) + { + source->mods[i].files[j]->source_file_offset = strings_len; + strings_len += source->mods[i].files[j]->len + 1; + dedupe_source_files_count++; + } + + source_files_count++; + } + } + } + + *size = sizeof (uint16_t) + sizeof (uint16_t); + *size += (sizeof (uint16_t) + sizeof (uint16_t)) * source->mod_count; + *size += sizeof (uint32_t) * source_files_count; + *size += strings_len; + + *data = xmalloc (*size); + + ptr = (uint8_t *) *data; + + /* Write header (module count and source file count). */ + + bfd_putl16 (source->mod_count, ptr); + ptr += sizeof (uint16_t); + + bfd_putl16 (dedupe_source_files_count, ptr); + ptr += sizeof (uint16_t); + + /* Write "ModIndices". As the LLVM documentation puts it, "this array is + present, but does not appear to be useful". */ + + for (uint16_t i = 0; i < source->mod_count; i++) + { + bfd_putl16 (i, ptr); + ptr += sizeof (uint16_t); + } + + /* Write source file count for each module. */ + + for (uint16_t i = 0; i < source->mod_count; i++) + { + bfd_putl16 (source->mods[i].files_count, ptr); + ptr += sizeof (uint16_t); + } + + /* For each module, write the offsets within the string table + for each source file. */ + + for (uint16_t i = 0; i < source->mod_count; i++) + { + for (uint16_t j = 0; j < source->mods[i].files_count; j++) + { + if (source->mods[i].files[j]) + { + bfd_putl32 (source->mods[i].files[j]->source_file_offset, ptr); + ptr += sizeof (uint32_t); + } + } + } + + /* Write the string table. We set source_file_offset to a dummy value for + each entry we write, so we don't write duplicate filenames. */ + + for (uint16_t i = 0; i < source->mod_count; i++) + { + for (uint16_t j = 0; j < source->mods[i].files_count; j++) + { + if (source->mods[i].files[j] + && source->mods[i].files[j]->source_file_offset != 0xffffffff) + { + memcpy (ptr, source->mods[i].files[j]->s, + source->mods[i].files[j]->len); + ptr += source->mods[i].files[j]->len; + + *ptr = 0; + ptr++; + + source->mods[i].files[j]->source_file_offset = 0xffffffff; + } + } + } +} + /* Stream 4 is the debug information (DBI) stream. */ static bool populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, @@ -865,19 +1242,37 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; - void *mod_info, *sc; - uint32_t mod_info_size, sc_size; + void *mod_info, *sc, *source_info; + uint32_t mod_info_size, sc_size, source_info_size; + struct source_files_info source; + + source.mod_count = 0; + source.mods = NULL; if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, - strings)) + strings, &source)) return false; if (!create_section_contrib_substream (abfd, &sc, &sc_size)) { + for (unsigned int i = 0; i < source.mod_count; i++) + { + free (source.mods[i].files); + } + free (source.mods); + free (mod_info); return false; } + create_source_info_substream (&source_info, &source_info_size, &source); + + for (unsigned int i = 0; i < source.mod_count; i++) + { + free (source.mods[i].files); + } + free (source.mods); + bfd_putl32 (0xffffffff, &h.version_signature); bfd_putl32 (DBI_STREAM_VERSION_70, &h.version_header); bfd_putl32 (1, &h.age); @@ -890,7 +1285,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, bfd_putl32 (mod_info_size, &h.mod_info_size); bfd_putl32 (sc_size, &h.section_contribution_size); bfd_putl32 (0, &h.section_map_size); - bfd_putl32 (0, &h.source_info_size); + bfd_putl32 (source_info_size, &h.source_info_size); bfd_putl32 (0, &h.type_server_map_size); bfd_putl32 (0, &h.mfc_type_server_index); bfd_putl32 (sizeof (opt), &h.optional_dbg_header_size); @@ -901,6 +1296,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, if (bfd_bwrite (&h, sizeof (h), stream) != sizeof (h)) { + free (source_info); free (sc); free (mod_info); return false; @@ -908,6 +1304,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, if (bfd_bwrite (mod_info, mod_info_size, stream) != mod_info_size) { + free (source_info); free (sc); free (mod_info); return false; @@ -917,12 +1314,21 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, if (bfd_bwrite (sc, sc_size, stream) != sc_size) { + free (source_info); free (sc); return false; } free (sc); + if (bfd_bwrite (source_info, source_info_size, stream) != source_info_size) + { + free (source_info); + return false; + } + + free (source_info); + bfd_putl16 (0xffff, &opt.fpo_stream); bfd_putl16 (0xffff, &opt.exception_stream); bfd_putl16 (0xffff, &opt.fixup_stream); diff --git a/ld/pdb.h b/ld/pdb.h index 611f71041c0..e8f673c24a0 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -156,6 +156,7 @@ struct optional_dbg_header #define CV_SIGNATURE_C13 4 #define DEBUG_S_STRINGTABLE 0xf3 +#define DEBUG_S_FILECHKSMS 0xf4 #define STRING_TABLE_SIGNATURE 0xeffeeffe #define STRING_TABLE_VERSION 1 @@ -200,6 +201,14 @@ struct module_info uint32_t pdb_file_path_name_index; }; +/* filedata in dumpsym7.cpp */ +struct file_checksum +{ + uint32_t file_id; + uint8_t checksum_length; + uint8_t checksum_type; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 09e9b4a8809..9dab41110ac 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -824,6 +824,160 @@ proc test3 { } { } } +proc extract_c13_info { pdb mod_info } { + global ar + + binary scan [string range $mod_info 34 35] s module_sym_stream + binary scan [string range $mod_info 36 39] i sym_byte_size + binary scan [string range $mod_info 40 43] i c11_byte_size + binary scan [string range $mod_info 44 47] i c13_byte_size + + set index_str [format "%04x" $module_sym_stream] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"] + + if ![string match "" $exec_output] { + return "" + } + + set fi [open tmpdir/$index_str] + fconfigure $fi -translation binary + + seek $fi [expr $sym_byte_size + $c11_byte_size] + + set data [read $fi $c13_byte_size] + + close $fi + + return $data +} + +proc test4 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb3a.s tmpdir/pdb3a.o] { + unsupported "Build pdb3a.o" + return + } + + if ![ld_assemble $as $srcdir/$subdir/pdb3b.s tmpdir/pdb3b.o] { + unsupported "Build pdb3b.o" + return + } + + if ![ld_link $ld "tmpdir/pdb3.exe" "--pdb=tmpdir/pdb3.pdb tmpdir/pdb3a.o tmpdir/pdb3b.o"] { + unsupported "Create PE image with PDB file" + return + } + + # read relevant bits from DBI stream + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb3.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 + + # read substream sizes + + set data [read $fi 4] + binary scan $data i mod_info_size + + set data [read $fi 4] + binary scan $data i section_contribution_size + + set data [read $fi 4] + binary scan $data i section_map_size + + set data [read $fi 4] + binary scan $data i source_info_size + + seek $fi 24 current + + set mod_info [read $fi $mod_info_size] + + seek $fi [expr $section_contribution_size + $section_map_size] current + + set source_info [read $fi $source_info_size] + + close $fi + + # check source info substream + + set fi [open tmpdir/pdb3-source-info w] + fconfigure $fi -translation binary + puts -nonewline $fi $source_info + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb3-source-info.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-source-info"] + + if [string match $exp $got] { + pass "Correct source info substream" + } else { + fail "Incorrect source info substream" + } + + # check C13 info in first module + + set c13_info [extract_c13_info "tmpdir/pdb3.pdb" [string range $mod_info 0 63]] + + set fi [open tmpdir/pdb3-c13-info1 w] + fconfigure $fi -translation binary + puts -nonewline $fi $c13_info + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb3-c13-info1.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-c13-info1"] + + if [string match $exp $got] { + pass "Correct C13 info for first module" + } else { + fail "Incorrect C13 info for first module" + } + + # check C13 info in second module + + set fn1_end [string first \000 $mod_info 64] + set fn2_end [string first \000 $mod_info [expr $fn1_end + 1]] + + set off [expr $fn2_end + 1] + + if { [expr $off % 4] != 0 } { + set off [expr $off + 4 - ($off % 4)] + } + + set c13_info [extract_c13_info "tmpdir/pdb3.pdb" [string range $mod_info $off [expr $off + 63]]] + + set fi [open tmpdir/pdb3-c13-info2 w] + fconfigure $fi -translation binary + puts -nonewline $fi $c13_info + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb3-c13-info2.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-c13-info2"] + + if [string match $exp $got] { + pass "Correct C13 info for second module" + } else { + fail "Incorrect C13 info for second module" + } +} + test1 test2 test3 +test4 diff --git a/ld/testsuite/ld-pe/pdb3-c13-info1.d b/ld/testsuite/ld-pe/pdb3-c13-info1.d new file mode 100644 index 00000000000..f92062ba4e5 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb3-c13-info1.d @@ -0,0 +1,8 @@ + +*: file format binary + +Contents of section .data: + 0000 f4000000 30000000 02000000 10016745 ....0.........gE + 0010 2301efcd ab8998ba dcfe1023 45670000 #..........#Eg.. + 0020 06000000 100198ba dcfe1023 45676745 ...........#EggE + 0030 2301efcd ab890000 #....... \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb3-c13-info2.d b/ld/testsuite/ld-pe/pdb3-c13-info2.d new file mode 100644 index 00000000000..1c33ce1e798 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb3-c13-info2.d @@ -0,0 +1,8 @@ + +*: file format binary + +Contents of section .data: + 0000 f4000000 30000000 06000000 100198ba ....0........... + 0010 dcfe1023 45676745 2301efcd ab890000 ...#EggE#....... + 0020 0a000000 10013b2a 19087f6e 5d4c4c5d ......;*...n]LL] + 0030 6e7f0819 2a3b0000 n...*;.. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb3-source-info.d b/ld/testsuite/ld-pe/pdb3-source-info.d new file mode 100644 index 00000000000..5b7d58cfa0c --- /dev/null +++ b/ld/testsuite/ld-pe/pdb3-source-info.d @@ -0,0 +1,7 @@ + +*: file format binary + +Contents of section .data: + 0000 03000300 00000100 02000200 02000000 ................ + 0010 00000000 04000000 04000000 08000000 ................ + 0020 666f6f00 62617200 62617a00 foo.bar.baz. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb3a.s b/ld/testsuite/ld-pe/pdb3a.s new file mode 100644 index 00000000000..71795b53a66 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb3a.s @@ -0,0 +1,52 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_STRINGTABLE, 0xf3 +.equ DEBUG_S_FILECHKSMS, 0xf4 +.equ CHKSUM_TYPE_MD5, 1 + +.equ NUM_MD5_BYTES, 16 + +.section ".debug$S", "rn" +.long CV_SIGNATURE_C13 +.long DEBUG_S_STRINGTABLE +.long .strings_end - .strings_start + +.strings_start: + +.asciz "" + +.src1: +.asciz "foo" + +.src2: +.asciz "bar" + +.strings_end: + +.balign 4 + +.long DEBUG_S_FILECHKSMS +.long .chksms_end - .chksms_start + +.chksms_start: + +.long .src1 - .strings_start +.byte NUM_MD5_BYTES +.byte CHKSUM_TYPE_MD5 +.long 0x01234567 +.long 0x89abcdef +.long 0xfedcba98 +.long 0x67452310 +.short 0 # padding + +.long .src2 - .strings_start +.byte NUM_MD5_BYTES +.byte CHKSUM_TYPE_MD5 +.long 0xfedcba98 +.long 0x67452310 +.long 0x01234567 +.long 0x89abcdef +.short 0 # padding + +.chksms_end: + +.balign 4 diff --git a/ld/testsuite/ld-pe/pdb3b.s b/ld/testsuite/ld-pe/pdb3b.s new file mode 100644 index 00000000000..fffb1150c88 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb3b.s @@ -0,0 +1,52 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_STRINGTABLE, 0xf3 +.equ DEBUG_S_FILECHKSMS, 0xf4 +.equ CHKSUM_TYPE_MD5, 1 + +.equ NUM_MD5_BYTES, 16 + +.section ".debug$S", "rn" +.long CV_SIGNATURE_C13 +.long DEBUG_S_STRINGTABLE +.long .strings_end - .strings_start + +.strings_start: + +.asciz "" + +.src1: +.asciz "bar" + +.src2: +.asciz "baz" + +.strings_end: + +.balign 4 + +.long DEBUG_S_FILECHKSMS +.long .chksms_end - .chksms_start + +.chksms_start: + +.long .src1 - .strings_start +.byte NUM_MD5_BYTES +.byte CHKSUM_TYPE_MD5 +.long 0xfedcba98 +.long 0x67452310 +.long 0x01234567 +.long 0x89abcdef +.short 0 # padding + +.long .src2 - .strings_start +.byte NUM_MD5_BYTES +.byte CHKSUM_TYPE_MD5 +.long 0x08192a3b +.long 0x4c5d6e7f +.long 0x7f6e5d4c +.long 0x3b2a1908 +.short 0 # padding + +.chksms_end: + +.balign 4 From patchwork Fri Dec 9 01:52:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31570 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp528320wrr; Thu, 8 Dec 2022 17:52:57 -0800 (PST) X-Google-Smtp-Source: AA0mqf4IthM+aHsKhJqPYO3Co8XOKE1lT0brOVeDw+HQMBHbG42bw+gouIllljt7ArxiMSJhcQmP X-Received: by 2002:a17:907:8c8e:b0:78d:f457:1063 with SMTP id td14-20020a1709078c8e00b0078df4571063mr4272506ejc.32.1670550777073; Thu, 08 Dec 2022 17:52:57 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550777; cv=none; d=google.com; s=arc-20160816; b=VjxJCW+iIjZJBHUAujHSvt9eaUvk5mppQu70i5YfxLw/Phjx2O6uZjsJpUE25iYV09 0xKcl5bA7PJqeB8XKKH6zifG6zgvoN4pELfCTomUPAmUoInIi4Y4Ok4Eep1v2zZKhg1F hqOZjcUz0kYILJzTOR5cHNIWHBzziurjI7r+C8oAd1/FJyCOjaxp/vTMSC3CKdfm3xqt jLJsnO74ofCyvaf1Nk4HY5mmYZlP+7y2iadrSwk9huATBe3Z8vrVlK+CzJw/wwoghCUX catKhWbLqx6EMSw9bI4IoUoYUUpdKCu/mmFMthQdnaHftuMaPG/J6jmBVTo7vmjcaulz 8wgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=xs6f9Fl+fCvfMD9EKWlNPkbPozQ5JFHLBNSwUpQJ8es=; b=igiQrXF9km1MgJmjg4bE7zg3URyZHGoGJMaKHcmuwPA4FRGSz3AnhvaMsNqXXv+MUw xdkrJzNZVwg5cHu1WXDROIh/HGH79uq4tpZeUKfHy+245rB41ZBIkR5eIT6GT1PXEGhE ye9cAr7kcfzylcBSyKT45ugPb2ZVtLtzr08ZYB/J8mg1bkdK+dC2uRujkJWSKD+AKOxE sMOnEAYmmzpTCxexzgqcvdojyKMQmwF4L6mspmP3Ev0fjMi5IB7pTq0XZnx+0oL7myIf 9d+5TJAMa599rDEv7uaILsYrW25vkWKQxeb+/9g5z+ric5V/0VoT3hMcQdRHVw+WOZli RBmw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=MnvAZVFL; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id cs16-20020a170906dc9000b007add0e1a187si38926ejc.594.2022.12.08.17.52.56 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:57 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=MnvAZVFL; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 70E6C382E18F for ; Fri, 9 Dec 2022 01:52:54 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by sourceware.org (Postfix) with ESMTPS id 94837387723A for ; Fri, 9 Dec 2022 01:52:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 94837387723A 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-wm1-x32c.google.com with SMTP id ay40so2567523wmb.2 for ; Thu, 08 Dec 2022 17:52:47 -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=xs6f9Fl+fCvfMD9EKWlNPkbPozQ5JFHLBNSwUpQJ8es=; b=MnvAZVFLeIUgYUSlmVK3/LmdC6tKHFNNMPYbn9mNcoRhXor5LbPwk1782kE59Dd6nq iSHrgdx33fHNr/XTSLDSAcpzQxh3CutUAr+EdR50axDFF9/i9VqCayYJmDkg5SXNBaQu UkFgokyQ3mBiok3VcxbHPuQXDEdLi/VC9Tg7oNDCc1RcANGNUS/BM/Vbf7gPJwh91vi2 cVGPMh9K/CfYB7YjMzyXUvjzf27y1NDGq+EFQhX7n1x2fXbwZvg07XPnpu2tiQsJv2KG GHG/l1HU+NMaqxgcGE/Wkmm2ajljzEIb4v70Y/qN/s1AfvUOlKamO/rdQAYM5x09lqMp 8E3A== 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=xs6f9Fl+fCvfMD9EKWlNPkbPozQ5JFHLBNSwUpQJ8es=; b=Xyqt+QSRtAjqn4MHnKru1VoTPRJe00iX2bbEuETDz3jsCGdf2GIHZFZGvWNSJuyfIS 7pd7sF7nv2KlQEVX2Bbg9crDtV54RnHevPIq4c+1e2V5m1R+4Ut2pwKjK8d29dlpso3A Md/TBw7sr44fMGUcmjN0Ndu7o8giFwPCmDQxztXaB+A3h3Uw4aOsHu+NkuabTqVVUUXC U3IZhZEBG/AbcSqraFdecuS0uuGuHcPUwQMbnZ/Xwt9kia17nRHedPGyeqBiVilVUDDF KBG3597lotxp2VO9VwVfNMbY9dHKFzvl9hIRZkXGpEHUu5SfymUwysl680muZO6WGK+V wZSA== X-Gm-Message-State: ANoB5pk+lWr7n2DojKfZkDJcZk5kzXv56DlkuTCKaNiXP7hDgOK2qnxo XevlxXInPcaTKxKB223qpPoam7gmcag= X-Received: by 2002:a1c:6a04:0:b0:3c6:e63d:fce2 with SMTP id f4-20020a1c6a04000000b003c6e63dfce2mr3299239wmc.9.1670550766077; Thu, 08 Dec 2022 17:52:46 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:45 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 03/10] ld: Fix segfault in populate_publics_stream Date: Fri, 9 Dec 2022 01:52:33 +0000 Message-Id: <20221209015240.6348-3-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699451853323201?= X-GMAIL-MSGID: =?utf-8?q?1751699451853323201?= --- ld/pdb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ld/pdb.c b/ld/pdb.c index b37a5a0ebfd..3edeab25332 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -1410,6 +1410,9 @@ populate_publics_stream (bfd *stream, bfd *abfd, bfd *sym_rec_stream) for (bfd *in = coff_data (abfd)->link_info->input_bfds; in; in = in->link.next) { + if (!in->outsymbols) + continue; + for (unsigned int i = 0; i < in->symcount; i++) { struct bfd_symbol *sym = in->outsymbols[i]; From patchwork Fri Dec 9 01:52:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31573 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp528426wrr; Thu, 8 Dec 2022 17:53:14 -0800 (PST) X-Google-Smtp-Source: AA0mqf4FSl77axCd5Artf2NQnaYP3Tb0bCGy8u2ZwEi5d5xvWVpY9uhOZcW6Fn9tQMNQv22ZTW9D X-Received: by 2002:a17:906:f0d5:b0:7c1:1c6:faea with SMTP id dk21-20020a170906f0d500b007c101c6faeamr4357006ejb.75.1670550794607; Thu, 08 Dec 2022 17:53:14 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550794; cv=none; d=google.com; s=arc-20160816; b=A94mAWJMX6+BhPAjw4/h3fxUzaBWWxMK5x0KKiVesRYCGhdD2dh2zr60RLhjLbZnmX cDkIC6R8gBdKHTZGROdQFyE8u1EDuEP4MSl2k5xkxu8qHrWwZ56+ZcfOS82Jq36JB0KH G4PKUG/gMW/mTad+eG2gxv0eNeKdohdFdfhN0LInr+R5n3visswSmQXLX9OQGxwPdWTw CK0ZfJFbQMpdTvxgxaK1N0wYUINPmdlEURAsD4O1sRajJd0dUOtteGNIJ6iCpibRbMtz en7PGWfLTZBsmcA9KiZJxDp9uEVd04YEjMNuCSPCo7O2upJkV0mytCp4DaasDP1WMcrc GlgQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=eK3s9gyPJGoCIB3cn8RWhonluPbzDyvsVWN1Hj/aPyo=; b=pL927kfkFQZryTxtgUm2a8Stxc8k8XafUx/sL2SiO3hLxGjFVbwnT0C/Wqp5B/DT3T Z6WIAigG7X1NvZ4jx2hWgnTHieSHL4ZTe6G2dhbQqjnqbsuojiYhx8rFrJs9Hvnamia5 4W2hogBpcBx3gKSTPihX79P9ijRJuNJKpIvOKpdzZkFDBdyUjVgWqfmviVBnPjYwUjlo rQhq8ObpNJknZfIqFO5w9h1RosNqSmDy3KdvoqaG2/01hOb3HAt0UEdGKs2s7AxUSaWM sOvIMxdgoAZlCsBYl+HoulmYGbv27tIBQTsRyJYONOHnCZ6vFE2faCuDICSUpXjVCKVM mg9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b="SxRQEf/d"; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id hv16-20020a17090760d000b007c0b52d0df1si34999ejc.660.2022.12.08.17.53.14 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:53:14 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b="SxRQEf/d"; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3B7A33892B90 for ; Fri, 9 Dec 2022 01:53:02 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by sourceware.org (Postfix) with ESMTPS id E47A73835579 for ; Fri, 9 Dec 2022 01:52:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E47A73835579 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-wm1-x331.google.com with SMTP id v124-20020a1cac82000000b003cf7a4ea2caso4775277wme.5 for ; Thu, 08 Dec 2022 17:52:48 -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=eK3s9gyPJGoCIB3cn8RWhonluPbzDyvsVWN1Hj/aPyo=; b=SxRQEf/dyw6apSL9Bom0vSVC5n6rGNMMpTatacoCjLR2e8qdMB5RwsEipxp2uYL8NY nDzcEkbHzvcUkDhaia71TkdLGk3tE0jJTkCbrr7KQS7mfB6cS9x+trekTTImdvWvdWG/ SNpED3Icqaojfi68xnjKw1QbQL7rAj4kN9GtqS31LTm15EIZCjuJLMs+w515bSH1KI9W HQLewsHbx9c8rCHRlAt8GMnez+TZGvUq2luJalhtQjtm7uxsL4+1HPJpw8zWyMUHMIaD LgXdN+l20hrT0xkA93vvl8v+LLF/dfvrifpiNN+TDA7k33SgYe8lqyFInK41pAs4i/0D CqmQ== 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=eK3s9gyPJGoCIB3cn8RWhonluPbzDyvsVWN1Hj/aPyo=; b=NFnaEmC1SR/2WgJm1rVegbQ4JVD2eSnx4N5b0E+fZTAAeVGtWt23hrT5zHlCLrOl96 ZaI8+e3A/7qxtI7aBEHoJ5qpzFIbkFZGM80m8ZZLg/qe6+L/mfvsa5BK5Brk9brgEOZE MkXM//d+/yTcBc+9tYSeMi8NefdpsQFG0oMoXOC+Y6m5O9t5VCZhfRsR7aZeE0mbNJD0 hFLFdDgbiUBB61ZTGRDevrqLmrSYMommWPg9sUM7QGsoTMljROZTXIDID2CTkZLPEcmI gp5TI4fODE2KIR5rTexpMt616JXgG7RdrsS0G1lklurqq3swgEzgRTHJmS8SKTo6XW14 enpg== X-Gm-Message-State: ANoB5plZPHS1ZizyUZgxPWt+q7ijE4a2Qx7pAKDDKnpXuzYwDYVRZvr1 h+FmaiIZV5rJt+hZZWzRFACjaVQWrdE= X-Received: by 2002:a05:600c:4909:b0:3d1:f3eb:c718 with SMTP id f9-20020a05600c490900b003d1f3ebc718mr3694996wmp.19.1670550767414; Thu, 08 Dec 2022 17:52:47 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:46 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 04/10] ld: Write DEBUG_S_LINES entries in PDB file Date: Fri, 9 Dec 2022 01:52:34 +0000 Message-Id: <20221209015240.6348-4-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699469777269825?= X-GMAIL-MSGID: =?utf-8?q?1751699469777269825?= --- ld/pdb.c | 111 +++++++++++++++++++++++++++- ld/pdb.h | 1 + ld/testsuite/ld-pe/pdb.exp | 2 +- ld/testsuite/ld-pe/pdb3-c13-info1.d | 8 +- ld/testsuite/ld-pe/pdb3a.s | 88 ++++++++++++++++++++++ 5 files changed, 204 insertions(+), 6 deletions(-) diff --git a/ld/pdb.c b/ld/pdb.c index 3edeab25332..a2f78c4c348 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -623,7 +623,8 @@ parse_string_table (bfd_byte *data, size_t size, static bool handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, uint8_t **dataptr, uint32_t *sizeptr, - struct mod_source_files *mod_source) + struct mod_source_files *mod_source, + bfd *abfd) { bfd_byte *data = NULL; size_t off; @@ -637,6 +638,59 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, if (!data) return false; + /* Resolve relocations. Addresses are stored within the .debug$S section as + a .secidx, .secrel32 pair. */ + + if (s->flags & SEC_RELOC) + { + struct internal_reloc *relocs; + struct internal_syment *symbols; + asection **sectlist; + unsigned int syment_count; + int sect_num; + struct external_syment *ext; + + syment_count = obj_raw_syment_count (mod); + + relocs = + _bfd_coff_read_internal_relocs (mod, s, false, NULL, true, NULL); + + symbols = xmalloc (sizeof (struct internal_syment) * syment_count); + sectlist = xmalloc (sizeof (asection *) * syment_count); + + ext = (struct external_syment *) (coff_data (mod)->external_syms); + + for (unsigned int i = 0; i < syment_count; i++) + { + bfd_coff_swap_sym_in (mod, &ext[i], &symbols[i]); + } + + sect_num = 1; + + for (asection *sect = mod->sections; sect; sect = sect->next) + { + for (unsigned int i = 0; i < syment_count; i++) + { + if (symbols[i].n_scnum == sect_num) + sectlist[i] = sect; + } + + sect_num++; + } + + if (!bfd_coff_relocate_section (abfd, coff_data (abfd)->link_info, mod, + s, data, relocs, symbols, sectlist)) + { + free (sectlist); + free (symbols); + free (data); + return false; + } + + free (sectlist); + free (symbols); + } + if (bfd_getl32 (data) != CV_SIGNATURE_C13) { free (data); @@ -689,6 +743,32 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, string_table = (char *) data + off; break; + + case DEBUG_S_LINES: + { + uint16_t sect; + + if (size < sizeof (uint32_t) + sizeof (uint16_t)) + { + free (data); + bfd_set_error (bfd_error_bad_value); + return false; + } + + sect = bfd_getl16 (data + off + sizeof (uint32_t)); + + /* Skip GC'd symbols. */ + if (sect != 0) + { + c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size; + + if (c13_size % sizeof (uint32_t)) + c13_size += + sizeof (uint32_t) - (c13_size % sizeof (uint32_t)); + } + + break; + } } off += size; @@ -733,6 +813,28 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, bufptr += sizeof (uint32_t) + sizeof (uint32_t) + size; break; + + case DEBUG_S_LINES: + { + uint16_t sect; + + sect = bfd_getl16 (data + off + sizeof (uint32_t)); + + /* Skip if GC'd. */ + if (sect != 0) + { + bfd_putl32 (type, bufptr); + bufptr += sizeof (uint32_t); + + bfd_putl32 (size, bufptr); + bufptr += sizeof (uint32_t); + + memcpy (bufptr, data + off, size); + bufptr += size; + } + + break; + } } off += size; @@ -769,7 +871,8 @@ static bool 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) + struct mod_source_files *mod_source, + bfd *abfd) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; @@ -784,7 +887,7 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) { if (!handle_debugs_section (s, mod, strings, &c13_info, - c13_info_size, mod_source)) + c13_info_size, mod_source, abfd)) { free (c13_info); free (mod_source->files); @@ -916,7 +1019,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])) + &source->mods[mod_num], abfd)) { for (unsigned int i = 0; i < source->mod_count; i++) { diff --git a/ld/pdb.h b/ld/pdb.h index e8f673c24a0..bbb106043c4 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -155,6 +155,7 @@ struct optional_dbg_header #define CV_SIGNATURE_C13 4 +#define DEBUG_S_LINES 0xf2 #define DEBUG_S_STRINGTABLE 0xf3 #define DEBUG_S_FILECHKSMS 0xf4 diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 9dab41110ac..2e5f83477aa 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -870,7 +870,7 @@ proc test4 { } { return } - if ![ld_link $ld "tmpdir/pdb3.exe" "--pdb=tmpdir/pdb3.pdb tmpdir/pdb3a.o tmpdir/pdb3b.o"] { + if ![ld_link $ld "tmpdir/pdb3.exe" "--pdb=tmpdir/pdb3.pdb --gc-sections -e main tmpdir/pdb3a.o tmpdir/pdb3b.o"] { unsupported "Create PE image with PDB file" return } diff --git a/ld/testsuite/ld-pe/pdb3-c13-info1.d b/ld/testsuite/ld-pe/pdb3-c13-info1.d index f92062ba4e5..5a4f94861c7 100644 --- a/ld/testsuite/ld-pe/pdb3-c13-info1.d +++ b/ld/testsuite/ld-pe/pdb3-c13-info1.d @@ -5,4 +5,10 @@ Contents of section .data: 0000 f4000000 30000000 02000000 10016745 ....0.........gE 0010 2301efcd ab8998ba dcfe1023 45670000 #..........#Eg.. 0020 06000000 100198ba dcfe1023 45676745 ...........#EggE - 0030 2301efcd ab890000 #....... \ No newline at end of file + 0030 2301efcd ab890000 f2000000 58000000 #...........X... + 0040 00000000 01000000 14000000 00000000 ................ + 0050 02000000 1c000000 00000000 01000080 ................ + 0060 04000000 02000080 18000000 02000000 ................ + 0070 1c000000 08000000 03000080 0c000000 ................ + 0080 04000080 00000000 01000000 14000000 ................ + 0090 10000000 05000080 ........ \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb3a.s b/ld/testsuite/ld-pe/pdb3a.s index 71795b53a66..1df84a344f6 100644 --- a/ld/testsuite/ld-pe/pdb3a.s +++ b/ld/testsuite/ld-pe/pdb3a.s @@ -1,4 +1,5 @@ .equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_LINES, 0xf2 .equ DEBUG_S_STRINGTABLE, 0xf3 .equ DEBUG_S_FILECHKSMS, 0xf4 .equ CHKSUM_TYPE_MD5, 1 @@ -50,3 +51,90 @@ .chksms_end: .balign 4 + +.long DEBUG_S_LINES +.long .lines_end - .lines_start + +.lines_start: + +.secrel32 main +.secidx main +.short 0 # flags +.long .main_end - main # length of region + +.lines_block1: + +.long 0 # file ID 0 (foo) +.long 2 # no. lines +.long .lines_block2 - .lines_block1 # length + +.long .line1 - main +.long 0x80000001 # line 1 +.long .line2 - main +.long 0x80000002 # line 2 + +.lines_block2: + +.long 0x18 # file ID 18 (bar) +.long 2 # no. lines +.long .lines_block3 - .lines_block2 # length + +.long .line3 - main +.long 0x80000003 # line 3 +.long .line4 - main +.long 0x80000004 # line 4 + +.lines_block3: + +.long 0 # file ID 0 (foo) +.long 1 # no. lines +.long .lines_end - .lines_block3 # length + +.long .line5 - main +.long 0x80000005 # line 5 + +.lines_end: + +.long DEBUG_S_LINES +.long .lines_end2 - .lines_start2 + +.lines_start2: + +.secrel32 gcfunc +.secidx gcfunc +.short 0 # flags +.long .gcfunc_end - gcfunc # length of region + +.lines_block4: + +.long 0 # file ID 0 (foo) +.long 1 # no. lines +.long .lines_end2 - .lines_block4 # length + +.long .line6 - gcfunc +.long 0x80000006 # line 6 + +.lines_end2: + +.text + +.global main +main: +.line1: + .long 0x12345678 +.line2: + .long 0x12345678 +.line3: + .long 0x12345678 +.line4: + .long 0x12345678 +.line5: + .long 0x12345678 +.main_end: + +.section "gcsect" + +gcfunc: +.line6: + .long 0x12345678 +.gcfunc_end: From patchwork Fri Dec 9 01:52:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31584 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp529389wrr; Thu, 8 Dec 2022 17:56:28 -0800 (PST) X-Google-Smtp-Source: AA0mqf6fuT0B2wWvsYHMcmPgTRSGvoTcfcjOxq8r0I7i5emNkR1NTIAgPEnrYzBiF1lPNRX4H33g X-Received: by 2002:a17:907:8a22:b0:7b2:739d:a08e with SMTP id sc34-20020a1709078a2200b007b2739da08emr3780343ejc.45.1670550988392; Thu, 08 Dec 2022 17:56:28 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550988; cv=none; d=google.com; s=arc-20160816; b=Wnm+shkJUZDE2LmBsK+YBOaFc7fOmID9c13vttFMa/bWmgG3rBLV4bMwSwaw8znz9Q +iZsmzr4GnrpdPR7KznpRA6gg56zPdzGamsubpunll/ZqTEp2NMj1pJ12bTTPvTFtzwi +IhF7fJUu9E2kIGwWZNvMw2k7vBEpbINaRGBQ2Px3U+9vGwuE1OuHa9OnAnaxI+dmi/R JLaoxUhS6LSBndFMTNJ82jE4FaijzX4pjiKhlB1PFX8gKBSX7Qd6kZzNyV8OAzRg5t1z axKoTk4QWXJRzMfX2H3/wHasA8Fic2DPOdr86X2l2lvjI4iGC5fXUeSEGtRXlAI0nIYs cbBA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=7kH6eHRIHKonqwZCv6OQmFpr2oDOO69WN9jEYJMwgGc=; b=jJCBAG/PhTy6++Cgm9EVNcVRp/1AINhWnE+DN1yrkyRPjsMNWEJW3N+EFiEVFlnhdL Q8CAqHas2E6GcuXewuHJz3SjTOWHOcqLsySUxUdLkhcQLzNCI8FFwKpLF4CxvDqkR08R 2BVwtW1T7zElbu6W9PehgzRQHSVku+0rvGv4POdGPoFOo2OfncdISiZ2fAx/kNgz6HDy 9Yod5eDIDvesCkonkS7QHaLmp4cevxzFH8RuBZuFXuGnrm9HABY0fpgiEbK2nsP9iI8m eEPSKKBVspyQdla4BO11oPP9y7bk5zkypqJU/q081MRxjlQLSue0RrPrxjEoHV2Tgo5i l+sA== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=Ju1qoF1K; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id xb4-20020a170907070400b007ba49ec6d3bsi66247ejb.390.2022.12.08.17.56.28 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:56:28 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=Ju1qoF1K; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A3CEB39385BD for ; Fri, 9 Dec 2022 01:54:30 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by sourceware.org (Postfix) with ESMTPS id F121A382A20F for ; Fri, 9 Dec 2022 01:52:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F121A382A20F 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-wm1-x32c.google.com with SMTP id f13-20020a1cc90d000000b003d08c4cf679so2401198wmb.5 for ; Thu, 08 Dec 2022 17:52:50 -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=7kH6eHRIHKonqwZCv6OQmFpr2oDOO69WN9jEYJMwgGc=; b=Ju1qoF1KnaEX1XoW3lKLNFRH+0UGXwOEEYJnmndGFW2VSx060Njb+/V9dYdcsLUkXS 60I6xn4430SYaCZ/vV6yY+3xcvZ15G25GF9yzESmacin7l2tWLWKi/KaiZdUQGjf+wCF DaXtBOVwAIR6XVNRHSDSRRSnO6ogGOwPGOq/Z9+NwPFM/E9ZEZGZD8i6Z7qt/R4q1uk3 e6zkaxkJW2l+BPlmaSsGiFuwze54veXlqIniAG7IriBVkoBDNWJ3W4AjmHz7akVYuv/g dd6TuVwp3qk3rAKyKops7T9NbVzdZRAlJ89bNXMQ3oxSxrqCOdSIGD4IfYQfaz9KIxf3 J5yA== 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=7kH6eHRIHKonqwZCv6OQmFpr2oDOO69WN9jEYJMwgGc=; b=3N6htYroXhYlBqBOSI387Trn+CVBIX3AN7RisjoGlGTU9kZeJw4SagJXsB7Ks8L7jk 1JktvjewSS1gC+d+r2qUzV0WbrFhadTgLIINGzSD/k41uT0F6XxY2kisRH57V4Z+l+h5 paNTo7DBuOD7uykGFcF5Tb/d8uh0UTFETOy/OcACMcPYcvuZ917hsHTI/OcGYVS87nK4 U19eCPATpWKSglM9JOdk9JAW+GGrH4G4xZtmP4oHSe7hkZMh+GhzKkNrwvXbyCRXKrwk RR6+JZXeFaeDq70lU5Xx3r9sUnTV1OSdc8PyHOlezfFWpCBOuJA8WZHgJwXty/PoaTWC dX8Q== X-Gm-Message-State: ANoB5pltbrbup0be5ocS3u6X8IQkpTQCRFcHGfc6kjz7x+ErnF4doHjs nSWfKM7YFx/1kTZbygJSvVtsy+1XIKY= X-Received: by 2002:a1c:f216:0:b0:3c6:e60f:3f6f with SMTP id s22-20020a1cf216000000b003c6e60f3f6fmr3279883wmc.38.1670550768297; Thu, 08 Dec 2022 17:52:48 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:47 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 05/10] ld: Write types into TPI stream of PDB Date: Fri, 9 Dec 2022 01:52:35 +0000 Message-Id: <20221209015240.6348-5-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699673368776763?= X-GMAIL-MSGID: =?utf-8?q?1751699673368776763?= --- ld/pdb.c | 1290 +++++++++++++++++++++- ld/pdb.h | 264 +++++ ld/testsuite/ld-pe/pdb-types1-hashlist.d | 13 + ld/testsuite/ld-pe/pdb-types1-skiplist.d | 5 + ld/testsuite/ld-pe/pdb-types1-typelist.d | 60 + ld/testsuite/ld-pe/pdb-types1a.s | 27 + ld/testsuite/ld-pe/pdb-types1b.s | 461 ++++++++ ld/testsuite/ld-pe/pdb.exp | 172 +++ 8 files changed, 2270 insertions(+), 22 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb-types1-hashlist.d create mode 100644 ld/testsuite/ld-pe/pdb-types1-skiplist.d create mode 100644 ld/testsuite/ld-pe/pdb-types1-typelist.d create mode 100644 ld/testsuite/ld-pe/pdb-types1a.s create mode 100644 ld/testsuite/ld-pe/pdb-types1b.s diff --git a/ld/pdb.c b/ld/pdb.c index a2f78c4c348..4bb19420f95 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -71,6 +71,69 @@ struct source_files_info struct mod_source_files *mods; }; +struct type_entry +{ + struct type_entry *next; + uint32_t index; + uint32_t cv_hash; + uint8_t data[]; +}; + +struct types +{ + htab_t hashmap; + uint32_t num_types; + struct type_entry *first; + struct type_entry *last; +}; + +static const uint32_t crc_table[] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + /* Add a new stream to the PDB archive, and return its BFD. */ static bfd * add_stream (bfd *pdb, const char *name, uint16_t *stream_num) @@ -365,38 +428,142 @@ end: return ret; } +/* Calculate the CRC32 used for type hashes. */ +static uint32_t +crc32 (const uint8_t *data, size_t len) +{ + uint32_t crc = 0; + + while (len > 0) + { + crc = (crc >> 8) ^ crc_table[(crc & 0xff) ^ *data]; + + data++; + len--; + } + + return crc; +} + /* Stream 2 is the type information (TPI) stream, and stream 4 is the ID information (IPI) stream. They differ only in which records go in which stream. */ static bool -create_type_stream (bfd *pdb) +populate_type_stream (bfd *pdb, bfd *stream, struct types *types) { - bfd *stream; struct pdb_tpi_stream_header h; + struct type_entry *e; + uint32_t len = 0, index_offset_len, off; + struct bfd *hash_stream = NULL; + uint16_t hash_stream_index; - stream = add_stream (pdb, NULL, NULL); - if (!stream) + static const uint32_t index_skip = 0x2000; + + e = types->first; + + index_offset_len = 0; + + while (e) + { + uint32_t old_len = len; + + len += sizeof (uint16_t) + bfd_getl16 (e->data); + + if (old_len == 0 || old_len / index_skip != len / index_skip) + index_offset_len += sizeof (uint32_t) * 2; + + e = e->next; + } + + /* Each type stream also has a stream which holds the hash value for each + type, along with a skip list to speed up searching. */ + + hash_stream = add_stream (pdb, "", &hash_stream_index); + + if (!hash_stream) return false; bfd_putl32 (TPI_STREAM_VERSION_80, &h.version); bfd_putl32 (sizeof (h), &h.header_size); bfd_putl32 (TPI_FIRST_INDEX, &h.type_index_begin); - bfd_putl32 (TPI_FIRST_INDEX, &h.type_index_end); - bfd_putl32 (0, &h.type_record_bytes); - bfd_putl16 (0xffff, &h.hash_stream_index); + bfd_putl32 (TPI_FIRST_INDEX + types->num_types, &h.type_index_end); + bfd_putl32 (len, &h.type_record_bytes); + bfd_putl16 (hash_stream_index, &h.hash_stream_index); bfd_putl16 (0xffff, &h.hash_aux_stream_index); - bfd_putl32 (4, &h.hash_key_size); - bfd_putl32 (0x3ffff, &h.num_hash_buckets); + bfd_putl32 (sizeof (uint32_t), &h.hash_key_size); + bfd_putl32 (NUM_TPI_HASH_BUCKETS, &h.num_hash_buckets); bfd_putl32 (0, &h.hash_value_buffer_offset); - bfd_putl32 (0, &h.hash_value_buffer_length); - bfd_putl32 (0, &h.index_offset_buffer_offset); - bfd_putl32 (0, &h.index_offset_buffer_length); - bfd_putl32 (0, &h.hash_adj_buffer_offset); + bfd_putl32 (types->num_types * sizeof (uint32_t), + &h.hash_value_buffer_length); + bfd_putl32 (types->num_types * sizeof (uint32_t), + &h.index_offset_buffer_offset); + bfd_putl32 (index_offset_len, &h.index_offset_buffer_length); + bfd_putl32 ((types->num_types * sizeof (uint32_t)) + index_offset_len, + &h.hash_adj_buffer_offset); bfd_putl32 (0, &h.hash_adj_buffer_length); if (bfd_bwrite (&h, sizeof (h), stream) != sizeof (h)) return false; + /* Write the type definitions into the main stream, and the hashes + into the hash stream. The hashes have already been calculated + in handle_type. */ + + e = types->first; + + while (e) + { + uint8_t buf[sizeof (uint32_t)]; + uint16_t size; + + size = bfd_getl16 (e->data); + + if (bfd_bwrite (e->data, size + sizeof (uint16_t), stream) + != size + sizeof (uint16_t)) + return false; + + bfd_putl32 (e->cv_hash % NUM_TPI_HASH_BUCKETS, buf); + + if (bfd_bwrite (buf, sizeof (uint32_t), hash_stream) + != sizeof (uint32_t)) + return false; + + e = e->next; + } + + /* Write the index offsets, i.e. the skip list, into the hash stream. We + copy MSVC here by writing a new entry for every 8192 bytes. */ + + e = types->first; + off = 0; + + while (e) + { + uint32_t old_off = off; + uint16_t size = bfd_getl16 (e->data); + + off += size + sizeof (uint16_t); + + if (old_off == 0 || old_off / index_skip != len / index_skip) + { + uint8_t buf[sizeof (uint32_t)]; + + bfd_putl32 (TPI_FIRST_INDEX + e->index, buf); + + if (bfd_bwrite (buf, sizeof (uint32_t), hash_stream) + != sizeof (uint32_t)) + return false; + + bfd_putl32 (old_off, buf); + + if (bfd_bwrite (buf, sizeof (uint32_t), hash_stream) + != sizeof (uint32_t)) + return false; + } + + e = e->next; + } + return true; } @@ -619,6 +786,32 @@ parse_string_table (bfd_byte *data, size_t size, } } +/* Return the size of an extended value parameter, as used in + LF_ENUMERATE etc. */ +static unsigned int +extended_value_len (uint16_t type) +{ + switch (type) + { + case LF_CHAR: + return 1; + + case LF_SHORT: + case LF_USHORT: + return 2; + + case LF_LONG: + case LF_ULONG: + return 4; + + case LF_QUADWORD: + case LF_UQUADWORD: + return 8; + } + + return 0; +} + /* Parse the .debug$S section within an object file. */ static bool handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, @@ -865,6 +1058,984 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, return true; } +/* Remap the type number stored in data from the per-module numbering to + that of the deduplicated output list. */ +static bool +remap_type (void *data, struct type_entry **map, + uint32_t type_num, uint32_t num_types) +{ + uint32_t type = bfd_getl32 (data); + + /* Ignore builtin types (those with IDs below 0x1000). */ + if (type < TPI_FIRST_INDEX) + return true; + + if (type >= TPI_FIRST_INDEX + type_num) + { + einfo (_("%P: CodeView type %v references other type %v not yet " + "declared\n"), TPI_FIRST_INDEX + type_num, type); + return false; + } + + if (type >= TPI_FIRST_INDEX + num_types) + { + einfo (_("%P: CodeView type %v references out of range type %v\n"), + TPI_FIRST_INDEX + type_num, type); + return false; + } + + type = TPI_FIRST_INDEX + map[type - TPI_FIRST_INDEX]->index; + bfd_putl32 (type, data); + + return true; +} + +/* Determines whether the name of a struct, class, or union counts as + "anonymous". Non-anonymous types have a hash based on just the name, + rather than the whole structure. */ +static bool +is_name_anonymous (char *name, size_t len) +{ + static const char tag1[] = ""; + static const char tag2[] = "__unnamed"; + static const char tag3[] = "::"; + static const char tag4[] = "::__unnamed"; + + if (len == sizeof (tag1) - 1 && !memcmp (name, tag1, sizeof (tag1) - 1)) + return true; + + if (len == sizeof (tag2) - 1 && !memcmp (name, tag2, sizeof (tag2) - 1)) + return true; + + if (len >= sizeof (tag3) - 1 + && !memcmp (name + len - sizeof (tag3) + 1, tag3, sizeof (tag3) - 1)) + return true; + + if (len >= sizeof (tag4) - 1 + && !memcmp (name + len - sizeof (tag4) + 1, tag4, sizeof (tag4) - 1)) + return true; + + return false; +} + +/* Parse a type definition in the .debug$T section. We remap the numbers + of any referenced types, and if the type is not a duplicate of one + 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) +{ + uint16_t size, type; + void **slot; + hashval_t hash; + bool other_hash = false; + uint32_t cv_hash; + + size = bfd_getl16 (data) + sizeof (uint16_t); + type = bfd_getl16 (data + sizeof (uint16_t)); + + switch (type) + { + case LF_MODIFIER: + { + struct lf_modifier *mod = (struct lf_modifier *) data; + + if (size < offsetof (struct lf_modifier, modifier)) + { + einfo (_("%P: warning: truncated CodeView type record " + "LF_MODIFIER\n")); + return false; + } + + if (!remap_type (&mod->base_type, map, type_num, num_types)) + return false; + + break; + } + + case LF_POINTER: + { + struct lf_pointer *ptr = (struct lf_pointer *) data; + + if (size < offsetof (struct lf_pointer, attributes)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_POINTER\n")); + return false; + } + + if (!remap_type (&ptr->base_type, map, type_num, num_types)) + return false; + + break; + } + + case LF_PROCEDURE: + { + struct lf_procedure *proc = (struct lf_procedure *) data; + + if (size < sizeof (struct lf_procedure)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_PROCEDURE\n")); + return false; + } + + if (!remap_type (&proc->return_type, map, type_num, num_types)) + return false; + + if (!remap_type (&proc->arglist, map, type_num, num_types)) + return false; + + break; + } + + case LF_MFUNCTION: + { + struct lf_mfunction *func = (struct lf_mfunction *) data; + + if (size < sizeof (struct lf_procedure)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_MFUNCTION\n")); + return false; + } + + if (!remap_type (&func->return_type, map, type_num, num_types)) + return false; + + if (!remap_type (&func->containing_class_type, map, type_num, + num_types)) + return false; + + if (!remap_type (&func->this_type, map, type_num, num_types)) + return false; + + if (!remap_type (&func->arglist, map, type_num, num_types)) + return false; + + break; + } + + case LF_ARGLIST: + { + uint32_t num_entries; + struct lf_arglist *al = (struct lf_arglist *) data; + + if (size < offsetof (struct lf_arglist, args)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ARGLIST\n")); + return false; + } + + num_entries = bfd_getl32 (&al->num_entries); + + if (size < offsetof (struct lf_arglist, args) + + (num_entries * sizeof (uint32_t))) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ARGLIST\n")); + return false; + } + + for (uint32_t i = 0; i < num_entries; i++) + { + if (!remap_type (&al->args[i], map, type_num, num_types)) + return false; + } + + break; + } + + case LF_FIELDLIST: + { + uint16_t left = size - sizeof (uint16_t) - sizeof (uint16_t); + uint8_t *ptr = data + sizeof (uint16_t) + sizeof (uint16_t); + + while (left > 0) + { + uint16_t subtype; + + if (left < sizeof (uint16_t)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FIELDLIST\n")); + return false; + } + + subtype = bfd_getl16 (ptr); + + switch (subtype) + { + case LF_MEMBER: + { + struct lf_member *mem = (struct lf_member *) ptr; + size_t name_len, subtype_len; + + if (left < offsetof (struct lf_member, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_MEMBER\n")); + return false; + } + + if (!remap_type (&mem->type, map, type_num, num_types)) + return false; + + name_len = + strnlen (mem->name, + left - offsetof (struct lf_member, name)); + + if (name_len == left - offsetof (struct lf_member, name)) + { + einfo (_("%P: warning: name for LF_MEMBER has no" + " terminating zero\n")); + return false; + } + + name_len++; + + subtype_len = offsetof (struct lf_member, name) + name_len; + + if (subtype_len % 4 != 0) + subtype_len += 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FIELDLIST\n")); + return false; + } + + ptr += subtype_len; + left -= subtype_len; + + break; + } + + case LF_ENUMERATE: + { + struct lf_enumerate *en = (struct lf_enumerate *) ptr; + size_t name_len, subtype_len; + uint16_t val; + + if (left < offsetof (struct lf_enumerate, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ENUMERATE\n")); + return false; + } + + subtype_len = offsetof (struct lf_enumerate, name); + + val = bfd_getl16 (&en->value); + + /* If val >= 0x8000, the actual value immediately follows. */ + if (val >= 0x8000) + { + unsigned int param_len = extended_value_len (val); + + if (param_len == 0) + { + einfo (_("%P: warning: unhandled type %v within" + " LF_ENUMERATE\n"), val); + return false; + } + + if (left < subtype_len + param_len) + { + einfo (_("%P: warning: truncated CodeView type" + " record LF_ENUMERATE\n")); + return false; + } + + subtype_len += param_len; + } + + name_len = strnlen ((char *) ptr + subtype_len, + left - subtype_len); + + if (name_len == left - offsetof (struct lf_enumerate, name)) + { + einfo (_("%P: warning: name for LF_ENUMERATE has no" + " terminating zero\n")); + return false; + } + + name_len++; + + subtype_len += name_len; + + if (subtype_len % 4 != 0) + subtype_len += 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ENUMERATE\n")); + return false; + } + + ptr += subtype_len; + left -= subtype_len; + + break; + } + + case LF_INDEX: + { + struct lf_index *ind = (struct lf_index *) ptr; + + if (left < sizeof (struct lf_index)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_INDEX\n")); + return false; + } + + if (!remap_type (&ind->index, map, type_num, num_types)) + return false; + + ptr += sizeof (struct lf_index); + left -= sizeof (struct lf_index); + + break; + } + + case LF_ONEMETHOD: + { + struct lf_onemethod *meth = (struct lf_onemethod *) ptr; + size_t name_len, subtype_len; + + if (left < offsetof (struct lf_onemethod, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ONEMETHOD\n")); + return false; + } + + if (!remap_type (&meth->method_type, map, type_num, + num_types)) + return false; + + name_len = + strnlen (meth->name, + left - offsetof (struct lf_onemethod, name)); + + if (name_len == left - offsetof (struct lf_onemethod, name)) + { + einfo (_("%P: warning: name for LF_ONEMETHOD has no" + " terminating zero\n")); + return false; + } + + name_len++; + + subtype_len = offsetof (struct lf_onemethod, name) + + name_len; + + if (subtype_len % 4 != 0) + subtype_len += 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FIELDLIST\n")); + return false; + } + + ptr += subtype_len; + left -= subtype_len; + + break; + } + + case LF_METHOD: + { + struct lf_method *meth = (struct lf_method *) ptr; + size_t name_len, subtype_len; + + if (left < offsetof (struct lf_method, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_METHOD\n")); + return false; + } + + if (!remap_type (&meth->method_list, map, type_num, + num_types)) + return false; + + name_len = + strnlen (meth->name, + left - offsetof (struct lf_method, name)); + + if (name_len == left - offsetof (struct lf_method, name)) + { + einfo (_("%P: warning: name for LF_METHOD has no" + " terminating zero\n")); + return false; + } + + name_len++; + + subtype_len = offsetof (struct lf_method, name) + name_len; + + if (subtype_len % 4 != 0) + subtype_len += 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FIELDLIST\n")); + return false; + } + + ptr += subtype_len; + left -= subtype_len; + + break; + } + + case LF_BCLASS: + { + struct lf_bclass *bc = (struct lf_bclass *) ptr; + + if (left < sizeof (struct lf_bclass)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_BCLASS\n")); + return false; + } + + if (!remap_type (&bc->base_class_type, map, type_num, + num_types)) + return false; + + ptr += sizeof (struct lf_bclass); + left -= sizeof (struct lf_bclass); + + break; + } + + case LF_VFUNCTAB: + { + struct lf_vfunctab *vft = (struct lf_vfunctab *) ptr; + + if (left < sizeof (struct lf_vfunctab)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_VFUNCTAB\n")); + return false; + } + + if (!remap_type (&vft->type, map, type_num, num_types)) + return false; + + ptr += sizeof (struct lf_vfunctab); + left -= sizeof (struct lf_vfunctab); + + break; + } + + case LF_VBCLASS: + case LF_IVBCLASS: + { + struct lf_vbclass *vbc = (struct lf_vbclass *) ptr; + + if (left < sizeof (struct lf_vbclass)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_VBCLASS/LF_IVBCLASS\n")); + return false; + } + + if (!remap_type (&vbc->base_class_type, map, type_num, + num_types)) + return false; + + if (!remap_type (&vbc->virtual_base_pointer_type, map, + type_num, num_types)) + return false; + + ptr += sizeof (struct lf_vbclass); + left -= sizeof (struct lf_vbclass); + + break; + } + + case LF_STMEMBER: + { + struct lf_static_member *st = + (struct lf_static_member *) ptr; + size_t name_len, subtype_len; + + if (left < offsetof (struct lf_static_member, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_STMEMBER\n")); + return false; + } + + if (!remap_type (&st->type, map, type_num, num_types)) + return false; + + name_len = + strnlen (st->name, + left - offsetof (struct lf_static_member, name)); + + if (name_len == left + - offsetof (struct lf_static_member, name)) + { + einfo (_("%P: warning: name for LF_STMEMBER has no" + " terminating zero\n")); + return false; + } + + name_len++; + + subtype_len = offsetof (struct lf_static_member, name) + + name_len; + + if (subtype_len % 4 != 0) + subtype_len += 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FIELDLIST\n")); + return false; + } + + ptr += subtype_len; + left -= subtype_len; + + break; + } + + case LF_NESTTYPE: + { + struct lf_nest_type *nest = (struct lf_nest_type *) ptr; + size_t name_len, subtype_len; + + if (left < offsetof (struct lf_nest_type, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_NESTTYPE\n")); + return false; + } + + if (!remap_type (&nest->type, map, type_num, num_types)) + return false; + + name_len = + strnlen (nest->name, + left - offsetof (struct lf_nest_type, name)); + + if (name_len == left - offsetof (struct lf_nest_type, name)) + { + einfo (_("%P: warning: name for LF_NESTTYPE has no" + " terminating zero\n")); + return false; + } + + name_len++; + + subtype_len = offsetof (struct lf_nest_type, name) + + name_len; + + if (subtype_len % 4 != 0) + subtype_len += 4 - (subtype_len % 4); + + if (left < subtype_len) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_FIELDLIST\n")); + return false; + } + + ptr += subtype_len; + left -= subtype_len; + + break; + } + + default: + einfo (_("%P: warning: unrecognized CodeView subtype %v\n"), + subtype); + return false; + } + } + + break; + } + + case LF_BITFIELD: + { + struct lf_bitfield *bf = (struct lf_bitfield *) data; + + if (size < offsetof (struct lf_bitfield, length)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_BITFIELD\n")); + return false; + } + + if (!remap_type (&bf->base_type, map, type_num, num_types)) + return false; + + break; + } + + case LF_METHODLIST: + { + struct lf_methodlist *ml = (struct lf_methodlist *) data; + unsigned int num_entries; + + if (size < offsetof (struct lf_methodlist, entries)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_METHODLIST\n")); + return false; + } + + if ((size - offsetof (struct lf_methodlist, entries)) + % sizeof (struct lf_methodlist_entry)) + { + einfo (_("%P: warning: malformed CodeView type record" + " LF_METHODLIST\n")); + return false; + } + + num_entries = (size - offsetof (struct lf_methodlist, entries)) + / sizeof (struct lf_methodlist_entry); + + for (unsigned int i = 0; i < num_entries; i++) + { + if (!remap_type (&ml->entries[i].method_type, map, + type_num, num_types)) + return false; + } + + break; + } + + case LF_ARRAY: + { + struct lf_array *arr = (struct lf_array *) data; + + if (size < offsetof (struct lf_array, length_in_bytes)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ARRAY\n")); + return false; + } + + if (!remap_type (&arr->element_type, map, type_num, num_types)) + return false; + + if (!remap_type (&arr->index_type, map, type_num, num_types)) + return false; + + break; + } + + case LF_CLASS: + case LF_STRUCTURE: + { + struct lf_class *cl = (struct lf_class *) data; + uint16_t prop; + size_t name_len; + + if (size < offsetof (struct lf_class, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_CLASS/LF_STRUCTURE\n")); + return false; + } + + if (!remap_type (&cl->field_list, map, type_num, num_types)) + return false; + + if (!remap_type (&cl->derived_from, map, type_num, num_types)) + return false; + + if (!remap_type (&cl->vshape, map, type_num, num_types)) + return false; + + name_len = strnlen (cl->name, size - offsetof (struct lf_class, name)); + + if (name_len == size - offsetof (struct lf_class, name)) + { + einfo (_("%P: warning: name for LF_CLASS/LF_STRUCTURE has no" + " terminating zero\n")); + return false; + } + + prop = bfd_getl16 (&cl->properties); + + if (prop & CV_PROP_HAS_UNIQUE_NAME) + { + /* Structure has another name following first one. */ + + size_t len = offsetof (struct lf_class, name) + name_len + 1; + size_t unique_name_len; + + unique_name_len = strnlen (cl->name + name_len + 1, size - len); + + if (unique_name_len == size - len) + { + einfo (_("%P: warning: unique name for LF_CLASS/LF_STRUCTURE" + " has no terminating zero\n")); + return false; + } + } + + if (!(prop & (CV_PROP_FORWARD_REF | CV_PROP_SCOPED)) + && !is_name_anonymous (cl->name, name_len)) + { + other_hash = true; + cv_hash = crc32 ((uint8_t *) cl->name, name_len); + } + + break; + } + + case LF_UNION: + { + struct lf_union *un = (struct lf_union *) data; + uint16_t prop; + size_t name_len; + + if (size < offsetof (struct lf_union, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_UNION\n")); + return false; + } + + if (!remap_type (&un->field_list, map, type_num, num_types)) + return false; + + name_len = strnlen (un->name, size - offsetof (struct lf_union, name)); + + if (name_len == size - offsetof (struct lf_union, name)) + { + einfo (_("%P: warning: name for LF_UNION has no" + " terminating zero\n")); + return false; + } + + prop = bfd_getl16 (&un->properties); + + if (prop & CV_PROP_HAS_UNIQUE_NAME) + { + /* Structure has another name following first one. */ + + size_t len = offsetof (struct lf_union, name) + name_len + 1; + size_t unique_name_len; + + unique_name_len = strnlen (un->name + name_len + 1, size - len); + + if (unique_name_len == size - len) + { + einfo (_("%P: warning: unique name for LF_UNION has" + " no terminating zero\n")); + return false; + } + } + + if (!(prop & (CV_PROP_FORWARD_REF | CV_PROP_SCOPED)) + && !is_name_anonymous (un->name, name_len)) + { + other_hash = true; + cv_hash = crc32 ((uint8_t *) un->name, name_len); + } + + break; + } + + case LF_ENUM: + { + struct lf_enum *en = (struct lf_enum *) data; + uint16_t prop; + size_t name_len; + + if (size < offsetof (struct lf_enum, name)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_ENUM\n")); + return false; + } + + if (!remap_type (&en->underlying_type, map, type_num, num_types)) + return false; + + if (!remap_type (&en->field_list, map, type_num, num_types)) + return false; + + name_len = strnlen (en->name, size - offsetof (struct lf_enum, name)); + + if (name_len == size - offsetof (struct lf_enum, name)) + { + einfo (_("%P: warning: name for LF_ENUM has no" + " terminating zero\n")); + return false; + } + + prop = bfd_getl16 (&en->properties); + + if (prop & CV_PROP_HAS_UNIQUE_NAME) + { + /* Structure has another name following first one. */ + + size_t len = offsetof (struct lf_enum, name) + name_len + 1; + size_t unique_name_len; + + unique_name_len = strnlen (en->name + name_len + 1, size - len); + + if (unique_name_len == size - len) + { + einfo (_("%P: warning: unique name for LF_ENUM has" + " no terminating zero\n")); + return false; + } + } + + break; + } + + case LF_VTSHAPE: + /* Does not reference any types, nothing to be done. */ + break; + + default: + einfo (_("%P: warning: unrecognized CodeView type %v\n"), type); + return false; + } + + hash = iterative_hash (data, size, 0); + + slot = htab_find_slot_with_hash (types->hashmap, data, hash, INSERT); + if (!slot) + return false; + + if (!*slot) /* new entry */ + { + struct type_entry *e; + + *slot = xmalloc (offsetof (struct type_entry, data) + size); + + e = (struct type_entry *) *slot; + + e->next = NULL; + e->index = types->num_types; + + if (other_hash) + e->cv_hash = cv_hash; + else + e->cv_hash = crc32 (data, size); + + memcpy (e->data, data, size); + + if (types->last) + types->last->next = e; + else + types->first = e; + + types->last = e; + + map[type_num] = e; + + types->num_types++; + } + else /* duplicate */ + { + map[type_num] = (struct type_entry *) *slot; + } + + return true; +} + +/* 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) +{ + bfd_byte *data = NULL; + size_t off; + unsigned int num_types = 0; + struct type_entry **map; + uint32_t type_num; + + if (!bfd_get_full_section_contents (mod, s, &data)) + return false; + + if (!data) + return false; + + if (bfd_getl32 (data) != CV_SIGNATURE_C13) + { + free (data); + return true; + } + + off = sizeof (uint32_t); + + while (off + sizeof (uint16_t) <= s->size) + { + uint16_t size; + + size = bfd_getl16 (data + off); + off += sizeof (uint16_t); + + if (size + off > s->size || size <= sizeof (uint16_t)) + { + free (data); + bfd_set_error (bfd_error_bad_value); + return false; + } + + num_types++; + off += size; + } + + if (num_types == 0) + { + free (data); + return true; + } + + map = xcalloc (num_types, sizeof (struct type_entry *)); + + off = sizeof (uint32_t); + type_num = 0; + + while (off + sizeof (uint16_t) <= s->size) + { + uint16_t size; + + size = bfd_getl16 (data + off); + + if (!handle_type (data + off, map, type_num, num_types, types)) + { + free (data); + free (map); + bfd_set_error (bfd_error_bad_value); + return false; + } + + off += sizeof (uint16_t) + size; + type_num++; + } + + free (data); + free (map); + + return true; +} + /* Populate the module stream, which consists of the transformed .debug$S data for each object file. */ static bool @@ -872,7 +2043,7 @@ 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) + bfd *abfd, struct types *types) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; @@ -894,6 +2065,15 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, return false; } } + else if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) + { + if (!handle_debugt_section (s, mod, types)) + { + free (c13_info); + free (mod_source->files); + return false; + } + } } /* Write the signature. */ @@ -931,7 +2111,8 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, 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 source_files_info *source, + struct types *types) { uint8_t *ptr; unsigned int mod_num; @@ -1019,7 +2200,8 @@ 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)) + &source->mods[mod_num], abfd, + types)) { for (unsigned int i = 0; i < source->mod_count; i++) { @@ -1341,7 +2523,8 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, uint16_t section_header_stream_num, uint16_t sym_rec_stream_num, uint16_t publics_stream_num, - struct string_table *strings) + struct string_table *strings, + struct types *types) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; @@ -1353,7 +2536,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)) + strings, &source, types)) return false; if (!create_section_contrib_substream (abfd, &sc, &sc_size)) @@ -1883,6 +3066,31 @@ populate_names_stream (bfd *stream, struct string_table *strings) return true; } +/* Calculate the hash of a type_entry. */ +static hashval_t +hash_type_entry (const void *p) +{ + const struct type_entry *e = (const struct type_entry *) p; + uint16_t size = bfd_getl16 (e->data) + sizeof (uint16_t); + + return iterative_hash (e->data, size, 0); +} + +/* Compare a type_entry with a type. */ +static int +eq_type_entry (const void *a, const void *b) +{ + const struct type_entry *e = (const struct type_entry *) a; + uint16_t size_a = bfd_getl16 (e->data); + uint16_t size_b = bfd_getl16 (b); + + if (size_a != size_b) + return 0; + + return memcmp (e->data + sizeof (uint16_t), + (const uint8_t *) b + sizeof (uint16_t), size_a) == 0; +} + /* Create a PDB debugging file for the PE image file abfd with the build ID guid, stored at pdb_name. */ bool @@ -1891,9 +3099,10 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) bfd *pdb; bool ret = false; bfd *info_stream, *dbi_stream, *names_stream, *sym_rec_stream, - *publics_stream; + *publics_stream, *tpi_stream, *ipi_stream; uint16_t section_header_stream_num, sym_rec_stream_num, publics_stream_num; struct string_table strings; + struct types types, ids; pdb = bfd_openw (pdb_name, "pdb"); if (!pdb) @@ -1927,7 +3136,9 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) goto end; } - if (!create_type_stream (pdb)) + tpi_stream = add_stream (pdb, NULL, NULL); + + if (!tpi_stream) { einfo (_("%P: warning: cannot create TPI stream " "in PDB file: %E\n")); @@ -1943,7 +3154,9 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) goto end; } - if (!create_type_stream (pdb)) + ipi_stream = add_stream (pdb, NULL, NULL); + + if (!ipi_stream) { einfo (_("%P: warning: cannot create IPI stream " "in PDB file: %E\n")); @@ -1984,15 +3197,48 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) goto end; } + types.num_types = 0; + types.hashmap = htab_create_alloc (0, hash_type_entry, eq_type_entry, + free, xcalloc, free); + types.first = types.last = NULL; + + ids.num_types = 0; + ids.hashmap = htab_create_alloc (0, hash_type_entry, eq_type_entry, + free, xcalloc, free); + ids.first = ids.last = NULL; + if (!populate_dbi_stream (dbi_stream, abfd, pdb, section_header_stream_num, sym_rec_stream_num, publics_stream_num, - &strings)) + &strings, &types)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); + htab_delete (types.hashmap); + htab_delete (ids.hashmap); + goto end; + } + + if (!populate_type_stream (pdb, tpi_stream, &types)) + { + einfo (_("%P: warning: cannot populate TPI stream " + "in PDB file: %E\n")); + htab_delete (types.hashmap); + htab_delete (ids.hashmap); goto end; } + htab_delete (types.hashmap); + + if (!populate_type_stream (pdb, ipi_stream, &ids)) + { + einfo (_("%P: warning: cannot populate IPI stream " + "in PDB file: %E\n")); + htab_delete (ids.hashmap); + goto end; + } + + htab_delete (ids.hashmap); + add_string ("", 0, &strings); if (!populate_names_stream (names_stream, &strings)) diff --git a/ld/pdb.h b/ld/pdb.h index bbb106043c4..ecc26c1c87a 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -27,6 +27,41 @@ #include "sysdep.h" #include "bfd.h" #include +#include + +#define LF_VTSHAPE 0x000a +#define LF_MODIFIER 0x1001 +#define LF_POINTER 0x1002 +#define LF_PROCEDURE 0x1008 +#define LF_MFUNCTION 0x1009 +#define LF_ARGLIST 0x1201 +#define LF_FIELDLIST 0x1203 +#define LF_BITFIELD 0x1205 +#define LF_METHODLIST 0x1206 +#define LF_BCLASS 0x1400 +#define LF_VBCLASS 0x1401 +#define LF_IVBCLASS 0x1402 +#define LF_INDEX 0x1404 +#define LF_VFUNCTAB 0x1409 +#define LF_ENUMERATE 0x1502 +#define LF_ARRAY 0x1503 +#define LF_CLASS 0x1504 +#define LF_STRUCTURE 0x1505 +#define LF_UNION 0x1506 +#define LF_ENUM 0x1507 +#define LF_MEMBER 0x150d +#define LF_STMEMBER 0x150e +#define LF_METHOD 0x150f +#define LF_NESTTYPE 0x1510 +#define LF_ONEMETHOD 0x1511 + +#define LF_CHAR 0x8000 +#define LF_SHORT 0x8001 +#define LF_USHORT 0x8002 +#define LF_LONG 0x8003 +#define LF_ULONG 0x8004 +#define LF_QUADWORD 0x8009 +#define LF_UQUADWORD 0x800a #define S_PUB32 0x110e @@ -65,6 +100,7 @@ struct pdb_tpi_stream_header #define TPI_STREAM_VERSION_80 20040203 #define TPI_FIRST_INDEX 0x1000 +#define NUM_TPI_HASH_BUCKETS 0x3ffff /* NewDBIHdr in dbi.h */ struct pdb_dbi_stream_header @@ -210,6 +246,234 @@ struct file_checksum uint8_t checksum_type; } ATTRIBUTE_PACKED; +/* lfModifier in cvinfo.h */ +struct lf_modifier +{ + uint16_t size; + uint16_t kind; + uint32_t base_type; + uint16_t modifier; + uint16_t padding; +} ATTRIBUTE_PACKED; + +/* lfPointer in cvinfo.h */ +struct lf_pointer +{ + uint16_t size; + uint16_t kind; + uint32_t base_type; + uint32_t attributes; +} ATTRIBUTE_PACKED; + +/* lfArgList in cvinfo.h */ +struct lf_arglist +{ + uint16_t size; + uint16_t kind; + uint32_t num_entries; + uint32_t args[]; +} ATTRIBUTE_PACKED; + +/* lfProc in cvinfo.h */ +struct lf_procedure +{ + uint16_t size; + uint16_t kind; + uint32_t return_type; + uint8_t calling_convention; + uint8_t attributes; + uint16_t num_parameters; + uint32_t arglist; +} ATTRIBUTE_PACKED; + +/* lfMFunc in cvinfo.h */ +struct lf_mfunction +{ + uint16_t size; + uint16_t kind; + uint32_t return_type; + uint32_t containing_class_type; + uint32_t this_type; + uint8_t calling_convention; + uint8_t attributes; + uint16_t num_parameters; + uint32_t arglist; + int32_t this_adjustment; +} ATTRIBUTE_PACKED; + +/* lfArray in cvinfo.h */ +struct lf_array +{ + uint16_t size; + uint16_t kind; + uint32_t element_type; + uint32_t index_type; + uint16_t length_in_bytes; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfBitfield in cvinfo.h */ +struct lf_bitfield +{ + uint16_t size; + uint16_t kind; + uint32_t base_type; + uint8_t length; + uint8_t position; +} ATTRIBUTE_PACKED; + +/* lfMember in cvinfo.h */ +struct lf_member +{ + uint16_t kind; + uint16_t attributes; + uint32_t type; + uint16_t offset; + char name[]; +} ATTRIBUTE_PACKED; + +/* from bitfield structure CV_prop_t in cvinfo.h */ +#define CV_PROP_FORWARD_REF 0x80 +#define CV_PROP_SCOPED 0x100 +#define CV_PROP_HAS_UNIQUE_NAME 0x200 + +/* lfClass in cvinfo.h */ +struct lf_class +{ + uint16_t size; + uint16_t kind; + uint16_t num_members; + uint16_t properties; + uint32_t field_list; + uint32_t derived_from; + uint32_t vshape; + uint16_t length; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfUnion in cvinfo.h */ +struct lf_union +{ + uint16_t size; + uint16_t kind; + uint16_t num_members; + uint16_t properties; + uint32_t field_list; + uint16_t length; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfEnumerate in cvinfo.h */ +struct lf_enumerate +{ + uint16_t kind; + uint16_t attributes; + uint16_t value; + /* then actual value if value >= 0x8000 */ + char name[]; +} ATTRIBUTE_PACKED; + +/* lfEnum in cvinfo.h */ +struct lf_enum +{ + uint16_t size; + uint16_t kind; + uint16_t num_elements; + uint16_t properties; + uint32_t underlying_type; + uint32_t field_list; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfIndex in cvinfo.h */ +struct lf_index +{ + uint16_t kind; + uint16_t padding; + uint32_t index; +} ATTRIBUTE_PACKED; + +/* lfOneMethod in cvinfo.h */ +struct lf_onemethod +{ + uint16_t kind; + uint16_t method_attribute; + uint32_t method_type; + char name[]; +} ATTRIBUTE_PACKED; + +/* mlMethod in cvinfo.h */ +struct lf_methodlist_entry +{ + uint16_t method_attribute; + uint16_t padding; + uint32_t method_type; +} ATTRIBUTE_PACKED; + +/* lfMethodList in cvinfo.h */ +struct lf_methodlist +{ + uint16_t size; + uint16_t kind; + struct lf_methodlist_entry entries[]; +} ATTRIBUTE_PACKED; + +/* lfMethod in cvinfo.h */ +struct lf_method +{ + uint16_t kind; + uint16_t count; + uint32_t method_list; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfBClass in cvinfo.h */ +struct lf_bclass +{ + uint16_t kind; + uint16_t attributes; + uint32_t base_class_type; + uint16_t offset; + uint16_t padding; +} ATTRIBUTE_PACKED; + +/* lfVFuncTab in cvinfo.h */ +struct lf_vfunctab +{ + uint16_t kind; + uint16_t padding; + uint32_t type; +} ATTRIBUTE_PACKED; + +/* lfVBClass in cvinfo.h */ +struct lf_vbclass +{ + uint16_t kind; + uint16_t attributes; + uint32_t base_class_type; + uint32_t virtual_base_pointer_type; + uint16_t virtual_base_pointer_offset; + uint16_t virtual_base_vbtable_offset; +} ATTRIBUTE_PACKED; + +/* lfSTMember in cvinfo.h */ +struct lf_static_member +{ + uint16_t kind; + uint16_t attributes; + uint32_t type; + char name[]; +} ATTRIBUTE_PACKED; + +/* lfNestType in cvinfo.h */ +struct lf_nest_type +{ + uint16_t kind; + uint16_t padding; + uint32_t 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-types1-hashlist.d b/ld/testsuite/ld-pe/pdb-types1-hashlist.d new file mode 100644 index 00000000000..b75f08c1de7 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types1-hashlist.d @@ -0,0 +1,13 @@ + +*: file format binary + +Contents of section .data: + 0000 5b4f0200 e29b0300 a99a0300 90160300 * + 0010 32970300 d6540100 fad50000 c3b00000 * + 0020 6a270200 7b000100 31de0000 2bf50200 * + 0030 b59b0300 73cf0300 10b90000 84240300 * + 0040 64150100 2e8a0000 88fe0000 c0660000 * + 0050 ffd80200 b0260100 7c060200 e3240200 * + 0060 63ff0100 fb6b0300 0ad90100 523c0200 * + 0070 4d5e0200 8a940200 4b710300 6aa90300 * + 0080 0a2c0300 67e10300 4a3d0300 * \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types1-skiplist.d b/ld/testsuite/ld-pe/pdb-types1-skiplist.d new file mode 100644 index 00000000000..52c10fa501d --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types1-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-types1-typelist.d b/ld/testsuite/ld-pe/pdb-types1-typelist.d new file mode 100644 index 00000000000..ff2d91c311e --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types1-typelist.d @@ -0,0 +1,60 @@ + +*: file format binary + +Contents of section .data: + 0000 0a000110 12000000 02000000 0a000110 ................ + 0010 12000000 01000000 0a000110 22000000 ............"... + 0020 02000000 0a000110 74000000 03000000 ........t....... + 0030 0a000210 01100000 0c000100 0a000210 ................ + 0040 02100000 0a800000 12000112 03000000 ................ + 0050 01100000 02100000 03100000 0e000810 ................ + 0060 02100000 00000300 06100000 0e000315 ................ + 0070 04100000 74000000 180000f1 0a000512 ....t........... + 0080 75000000 0100f2f1 0a000512 75000000 u...........u... + 0090 1f01f2f1 22000312 0d150300 09100000 ...."........... + 00a0 00006e75 6d3100f1 0d150300 0a100000 ..num1.......... + 00b0 00006e75 6d3200f1 22000515 02000000 ..num2.."....... + 00c0 0b100000 00000000 00000000 04003c75 ................... + 00e0 00008002 00000000 00000000 00000000 ................ + 00f0 0000666f 6f006261 7200f2f1 0a000210 ..foo.bar....... + 0100 0d100000 0c000100 06000112 00000000 ................ + 0110 1a000910 02100000 0d100000 0e100000 ................ + 0120 00000000 0f100000 00000000 1a000910 ................ + 0130 02100000 0d100000 0e100000 00000300 ................ + 0140 06100000 00000000 12000612 00000000 ................ + 0150 10100000 00000000 11100000 32000312 ............2... + 0160 0d150300 75000000 00006e75 6d00f2f1 ....u.....num... + 0170 11150000 10100000 6d657468 6f6400f1 ........method.. + 0180 0f150200 12100000 6d657468 6f643200 ........method2. + 0190 1e000515 02000002 13100000 00000000 ................ + 01a0 00000000 0400666f 6f006261 7200f2f1 ......foo.bar... + 01b0 22000312 0d150300 75000000 00006e75 ".......u.....nu + 01c0 6d3100f1 0d150300 10000000 00006e75 m1............nu + 01d0 6d3200f1 1a000615 02000000 15100000 m2.............. + 01e0 04003c75 6e6e616d 65642d74 61673e00 ... + 01f0 16000615 00008002 00000000 00006261 ..............ba + 0200 7a007175 7800f2f1 16000615 02000002 z.qux........... + 0210 15100000 04006261 7a007175 7800f2f1 ......baz.qux... + 0220 52000312 02150300 00007265 6400f2f1 R.........red... + 0230 02150300 01006772 65656e00 02150300 ......green..... + 0240 0380ffff ffff626c 756500f1 02150300 ......blue...... + 0250 02800080 79656c6c 6f7700f1 02150300 ....yellow...... + 0260 0a800000 00000100 00007075 72706c65 ..........purple + 0270 00f3f2f1 1e000715 00008002 23000000 ............#... + 0280 00000000 636f6c6f 75720063 6f6c6f75 ....colour.colou + 0290 723200f1 1e000715 05000002 23000000 r2..........#... + 02a0 19100000 636f6c6f 75720063 6f6c6f75 ....colour.colou + 02b0 723200f1 0a000312 04140000 19100000 r2.............. + 02c0 06000a00 010000f1 0a000210 1d100000 ................ + 02d0 0c000100 0a000312 02150300 00006100 ..............a. + 02e0 22000715 01000800 75000000 1f100000 ".......u....... + 02f0 71757578 3a3a6e65 73746564 5f656e75 quux::nested_enu + 0300 6d00f2f1 52000312 00140000 14100000 m...R........... + 0310 0400f2f1 09140000 1e100000 01140000 ................ + 0320 14100000 1e100000 00000000 0e150000 ................ + 0330 02100000 73746174 69635f6d 656d6265 ....static_membe + 0340 7200f2f1 10150000 20100000 6e657374 r....... ...nest + 0350 65645f65 6e756d00 1a000515 01000000 ed_enum......... + 0360 21100000 00000000 00000000 04007175 !.............qu + 0370 757800f1 ux.. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types1a.s b/ld/testsuite/ld-pe/pdb-types1a.s new file mode 100644 index 00000000000..a2ee9a9972f --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types1a.s @@ -0,0 +1,27 @@ +.equ CV_SIGNATURE_C13, 4 + +.equ T_LONG, 0x0012 + +.equ LF_MODIFIER, 0x1001 + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, volatile long +.mod1: +.short .mod2 - .mod1 - 2 +.short LF_MODIFIER +.long T_LONG +.short 2 # volatile +.p2align 2 + +# Type 1001, const long +.mod2: +.short .types_end - .mod2 - 2 +.short LF_MODIFIER +.long T_LONG +.short 1 # const +.p2align 2 + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb-types1b.s b/ld/testsuite/ld-pe/pdb-types1b.s new file mode 100644 index 00000000000..89ee6e3840f --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types1b.s @@ -0,0 +1,461 @@ +.equ CV_SIGNATURE_C13, 4 + +.equ T_CHAR, 0x0010 +.equ T_LONG, 0x0012 +.equ T_ULONG, 0x0022 +.equ T_INT4, 0x0074 +.equ T_UINT4, 0x0075 +.equ T_UQUAD, 0x0023 + +.equ LF_VTSHAPE, 0x000a +.equ LF_MODIFIER, 0x1001 +.equ LF_POINTER, 0x1002 +.equ LF_PROCEDURE, 0x1008 +.equ LF_MFUNCTION, 0x1009 +.equ LF_ARGLIST, 0x1201 +.equ LF_FIELDLIST, 0x1203 +.equ LF_BITFIELD, 0x1205 +.equ LF_METHODLIST, 0x1206 +.equ LF_BCLASS, 0x1400 +.equ LF_VBCLASS, 0x1401 +.equ LF_INDEX, 0x1404 +.equ LF_VFUNCTAB, 0x1409 +.equ LF_ENUMERATE, 0x1502 +.equ LF_ARRAY, 0x1503 +.equ LF_STRUCTURE, 0x1505 +.equ LF_UNION, 0x1506 +.equ LF_ENUM, 0x1507 +.equ LF_MEMBER, 0x150d +.equ LF_STMEMBER, 0x150e +.equ LF_METHOD, 0x150f +.equ LF_NESTTYPE, 0x1510 +.equ LF_ONEMETHOD, 0x1511 + +.equ LF_USHORT, 0x8002 +.equ LF_LONG, 0x8003 +.equ LF_UQUADWORD, 0x800a + +.equ CV_PTR_NEAR32, 0xa +.equ CV_PTR_64, 0xc + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, const long +.mod1: +.short .mod2 - .mod1 - 2 +.short LF_MODIFIER +.long T_LONG +.short 1 # const +.p2align 2 + +# Type 1001, volatile unsigned long +.mod2: +.short .mod3 - .mod2 - 2 +.short LF_MODIFIER +.long T_ULONG +.short 2 # volatile +.p2align 2 + +# Type 1002, const volatile int +.mod3: +.short .ptr1 - .mod3 - 2 +.short LF_MODIFIER +.long T_INT4 +.short 3 # const volatile +.p2align 2 + +# Type 1003, const long * (64-bit pointer) +.ptr1: +.short .ptr2 - .ptr1 - 2 +.short LF_POINTER +.long 0x1000 +.long (8 << 13) | CV_PTR_64 + +# Type 1004, volatile unsigned long * (32-bit pointer) +.ptr2: +.short .arglist1 - .ptr2 - 2 +.short LF_POINTER +.long 0x1001 +.long (4 << 13) | CV_PTR_NEAR32 + +# Type 1005, arg list of types 1000, 1001, 1002 +.arglist1: +.short .proc1 - .arglist1 - 2 +.short LF_ARGLIST +.long 3 # no. entries +.long 0x1000 +.long 0x1001 +.long 0x1002 + +# Type 1006, procedure, return type 1001, arg list 1005 +.proc1: +.short .arr1 - .proc1 - 2 +.short LF_PROCEDURE +.long 0x1001 +.byte 0 # calling convention +.byte 0 # attributes +.short 3 # no. parameters +.long 0x1005 + +# Type 1007, array[3] of const long * +.arr1: +.short .bitfield1 - .arr1 - 2 +.short LF_ARRAY +.long 0x1003 # element type +.long T_INT4 # index type +.short 24 # length in bytes +.byte 0 # name +.byte 0xf1 # padding + +# Type 1008, bitfield of uint32_t, position 0, length 1 +.bitfield1: +.short .bitfield2 - .bitfield1 - 2 +.short LF_BITFIELD +.long T_UINT4 +.byte 1 +.byte 0 +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1009, bitfield of uint32_t, position 1, length 31 +.bitfield2: +.short .fieldlist1 - .bitfield2 - 2 +.short LF_BITFIELD +.long T_UINT4 +.byte 31 +.byte 1 +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100a, field list (1008 as num1, 1009 as num2) +.fieldlist1: +.short .struct1 - .fieldlist1 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long 0x1008 +.short 0 # offset +.asciz "num1" +.byte 0xf1 # padding +.short LF_MEMBER +.short 3 # public +.long 0x1009 +.short 0 # offset +.asciz "num2" +.byte 0xf1 # padding + +# Type 100b, anonymous struct, field list 100a +.struct1: +.short .struct2 - .struct1 - 2 +.short LF_STRUCTURE +.short 2 # no. members +.short 0 # property +.long 0x100a # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "" + +# Type 100c, forward declaration of struct foo +.struct2: +.short .ptr3 - .struct2 - 2 +.short LF_STRUCTURE +.short 0 # no. members +.short 0x280 # 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 +.asciz "bar" # unique name +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100d, pointer to 100c +.ptr3: +.short .arglist2 - .ptr3 - 2 +.short LF_POINTER +.long 0x100c +.long (8 << 13) | CV_PTR_64 + +# Type 100e, empty arg list +.arglist2: +.short .mfunc1 - .arglist2 - 2 +.short LF_ARGLIST +.long 0 # no. entries + +# Type 100f, member function of 100c, return type 1001 +.mfunc1: +.short .mfunc2 - .mfunc1 - 2 +.short LF_MFUNCTION +.long 0x1001 +.long 0x100c +.long 0x100d # type of "this" pointer +.byte 0 # calling convention +.byte 0 # attributes +.short 0 # no. parameters +.long 0x100e # arg list +.long 0 # "this" adjustment + +# Type 1010, member function of 100c, return type 1001, arg list 1005 +.mfunc2: +.short .methodlist1 - .mfunc2 - 2 +.short LF_MFUNCTION +.long 0x1001 +.long 0x100c +.long 0x100d # type of "this" pointer +.byte 0 # calling convention +.byte 0 # attributes +.short 3 # no. parameters +.long 0x1005 # arg list +.long 0 # "this" adjustment + +# Type 1011, method list for both member functions 100f and 1010 +.methodlist1: +.short .fieldlist2 - .methodlist1 - 2 +.short LF_METHODLIST +.short 0 # attributes +.short 0 # padding +.long 0x100f +.short 0 # attributes +.short 0 # padding +.long 0x1010 + +# Type 1012, field list (uint32_t as num1) +.fieldlist2: +.short .struct3 - .fieldlist2 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long T_UINT4 +.short 0 # offset +.asciz "num" +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_ONEMETHOD +.short 0 # method attribute +.long 0x100f # method type +.asciz "method" +.byte 0xf1 +.short LF_METHOD +.short 2 # no. overloads +.long 0x1011 # method list +.asciz "method2" + +# Type 1013, struct foo, field list 1012 +.struct3: +.short .fieldlist3 - .struct3 - 2 +.short LF_STRUCTURE +.short 2 # no. members +.short 0x200 # property (has unique name) +.long 0x1012 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "foo" # name +.asciz "bar" # unique name +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1014, field list (uint32_t as num1, char as num2) +.fieldlist3: +.short .union1 - .fieldlist3 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long T_UINT4 +.short 0 # offset +.asciz "num1" +.byte 0xf1 # padding +.short LF_MEMBER +.short 3 # public +.long T_CHAR +.short 0 # offset +.asciz "num2" +.byte 0xf1 # padding + +# Type 1015, anonymous union (field list 1014) +.union1: +.short .union2 - .union1 - 2 +.short LF_UNION +.short 2 # no. members +.short 0 # property +.long 0x1014 +.short 4 # size +.asciz "" + +# Type 1016, forward declaration of union baz +.union2: +.short .union3 - .union2 - 2 +.short LF_UNION +.short 0 # no. members +.short 0x280 # property (has unique name, forward declaration) +.long 0 # field list +.short 0 # size +.asciz "baz" +.asciz "qux" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1017, union baz (field list 1014) +.union3: +.short .fieldlist4 - .union3 - 2 +.short LF_UNION +.short 2 # no. members +.short 0x200 # property (has unique name, forward declaration) +.long 0x1014 # field list +.short 4 # size +.asciz "baz" +.asciz "qux" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1018, field list for enum (red = 0, green = 1, blue = -1, yellow = 0x8000, purple = 0x100000000) +.fieldlist4: +.short .enum1 - .fieldlist4 - 2 +.short LF_FIELDLIST +.short LF_ENUMERATE +.short 3 # public +.short 0 # value +.asciz "red" +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_ENUMERATE +.short 3 # public +.short 1 # value +.asciz "green" +.short LF_ENUMERATE +.short 3 # public +.short LF_LONG +.long 0xffffffff # value +.asciz "blue" +.byte 0xf1 # padding +.short LF_ENUMERATE +.short 3 # public +.short LF_USHORT +.short 0x8000 # value +.asciz "yellow" +.byte 0xf1 # padding +.short LF_ENUMERATE +.short 3 # public +.short LF_UQUADWORD +.quad 0x100000000 # value +.asciz "purple" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1019, forward reference to enum +.enum1: +.short .enum2 - .enum1 - 2 +.short LF_ENUM +.short 0 # no. elements +.short 0x280 # property (has unique name, forward ref) +.long T_UQUAD # underlying type +.long 0 # field list +.asciz "colour" +.asciz "colour2" +.byte 0xf1 # padding + +# Type 101a, enum (field list 1018) +.enum2: +.short .fieldlist5 - .enum2 - 2 +.short LF_ENUM +.short 5 # no. elements +.short 0x200 # property (has unique name) +.long T_UQUAD # underlying type +.long 0x1018 # field list +.asciz "colour" +.asciz "colour2" +.byte 0xf1 # padding + +# Type 101b, field list referencing other field list 1018 +.fieldlist5: +.short .vtshape1 - .fieldlist5 - 2 +.short LF_FIELDLIST +.short LF_INDEX +.short 0 # padding +.long 0x1018 + +# Type 101c, virtual function table shape +.vtshape1: +.short .ptr4 - .vtshape1 - 2 +.short LF_VTSHAPE +.short 1 # no. descriptors +.byte 0 # descriptor (CV_VTS_near) +.byte 0xf1 # padding + +# Type 101d, pointer to 101c +.ptr4: +.short .fieldlist6 - .ptr4 - 2 +.short LF_POINTER +.long 0x101c +.long (8 << 13) | CV_PTR_64 + +# Type 101e, fieldlist for enum +.fieldlist6: +.short .enum3 - .fieldlist6 - 2 +.short LF_FIELDLIST +.short LF_ENUMERATE +.short 3 # public +.short 0 # value +.asciz "a" + +# Type 101f, nested enum +.enum3: +.short .fieldlist7 - .enum3 - 2 +.short LF_ENUM +.short 1 # no. elements +.short 0x8 # property (is nested) +.long T_UINT4 # underlying type +.long 0x101e # field list +.asciz "quux::nested_enum" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1020, field list for struct quux +.fieldlist7: +.short .struct4 - .fieldlist7 - 2 +.short LF_FIELDLIST +.short LF_BCLASS +.short 0 # attributes +.long 0x1013 # base class +.short 4 # offset within class +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_VFUNCTAB +.short 0 # padding +.long 0x101d # pointer to vtshape +.short LF_VBCLASS +.short 0 # attribute +.long 0x1013 # type index of direct virtual base class +.long 0x101d # type index of virtual base pointer +.short 0 # virtual base pointer offset +.short 0 # virtual base offset from vbtable +.short LF_STMEMBER +.short 0 # attribute +.long 0x1001 # volatile unsigned long +.asciz "static_member" +.byte 0xf2 # padding +.byte 0xf1 # padding +.short LF_NESTTYPE +.short 0 # padding +.long 0x101f # enum type +.asciz "nested_enum" + +# Type 1021, struct quux, field list 1020 +.struct4: +.short .types_end - .struct4 - 2 +.short LF_STRUCTURE +.short 1 # no. members +.short 0 # property +.long 0x1020 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "quux" # name +.byte 0xf1 # padding + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 2e5f83477aa..5661438c9e9 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -977,7 +977,179 @@ proc test4 { } { } } +proc test5 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb-types1a.s tmpdir/pdb-types1a.o] { + unsupported "Build pdb-types1a.o" + return + } + + if ![ld_assemble $as $srcdir/$subdir/pdb-types1b.s tmpdir/pdb-types1b.o] { + unsupported "Build pdb-types1b.o" + return + } + + if ![ld_link $ld "tmpdir/pdb-types1.exe" "--pdb=tmpdir/pdb-types1.pdb tmpdir/pdb-types1a.o tmpdir/pdb-types1b.o"] { + unsupported "Create PE image with PDB file" + return + } + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types1.pdb 0002"] + + if ![string match "" $exec_output] { + fail "Could not extract TPI stream" + return + } else { + pass "Extracted TPI stream" + } + + # check values in TPI header, and save anything interesting + + set fi [open tmpdir/0002] + 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 TPI stream." + } else { + pass "Correct first type value in TPI 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 != 0x1023 } { + fail "Incorrect end type value in TPI stream." + } else { + pass "Correct end type value in TPI 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 TPI stream." + } else { + pass "Correct hash size in TPI stream." + } + + set data [read $fi 4] + binary scan $data i num_buckets + + if { $num_buckets != 0x3ffff } { + fail "Incorrect number of buckets in TPI stream." + } else { + pass "Correct number of buckets in TPI 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-types1-typelist w] + fconfigure $fi -translation binary + puts -nonewline $fi $type_list + close $fi + + # check type list + + set exp [file_contents "$srcdir/$subdir/pdb-types1-typelist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types1-typelist"] + if ![string match $exp $got] { + fail "Incorrect type list in TPI stream." + } else { + pass "Correct type list in TPI 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-types1.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract TPI hash stream." + } else { + pass "Extracted TPI 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-types1-hashlist w] + fconfigure $fi -translation binary + puts -nonewline $fi $hash_list + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb-types1-hashlist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types1-hashlist"] + if ![string match $exp $got] { + fail "Incorrect hash list in TPI stream." + } else { + pass "Correct hash list in TPI stream." + } + + # check skip list + + set fi [open tmpdir/pdb-types1-skiplist w] + fconfigure $fi -translation binary + puts -nonewline $fi $skip_list + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb-types1-skiplist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types1-skiplist"] + if ![string match $exp $got] { + fail "Incorrect skip list in TPI stream." + } else { + pass "Correct skip list in TPI stream." + } +} + test1 test2 test3 test4 +test5 From patchwork Fri Dec 9 01:52:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31580 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp529277wrr; Thu, 8 Dec 2022 17:56:10 -0800 (PST) X-Google-Smtp-Source: AA0mqf74UZfD8QA8307qWAECiTAMUi3nPCbodYSnXH1wCAkwCR875lMqFrM3ZXXPfjbi68haOoBZ X-Received: by 2002:aa7:d5ce:0:b0:46b:aedf:f32b with SMTP id d14-20020aa7d5ce000000b0046baedff32bmr5336836eds.4.1670550970453; Thu, 08 Dec 2022 17:56:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550970; cv=none; d=google.com; s=arc-20160816; b=BuupGSJ4+qNkAbmeVzZMQUs+S9QbKnTJ9UzaSYxS0yWGe+wtQImB2/n3u3ycqZRN4V tW2KYOemyjatn3tQJnbjEm3fE0aSSnEs7PtyxP0JmdMXOWIG6x8vABRNrL7tIhxWA3mQ OfRO9zZy9aJVSETeb6wIVgorqjATYnN9OvoMG5bjuV+gslGF8qUGlnem+B7RnK9FW3CE 1lSonGpAV8pvhnUv2/eZg/6Ne7BsEHZ6Jmk3mKS/LngcnAKSsf+bthinqgNFWLMtgrzD LRCxfR5eoqa2byI7n6eWAFEpyzoBcY+pr0ADdqekzrZHBImY0RI6EdPxkJ6UfMXnM2hP 4jsg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=/rRacCe5lrPn470JU4Rt+ew+LafgpZ1MY+8uNotWYtk=; b=bLrD2TCUOiXsWDEmw4HbDkHlv7VJklLyhSmKHc5qZmZ5RbyEGVcOgvdlJ5WNVIIgG6 24Ppi/XeNjUANYJfcJEWZfTxMWdVSetxBcKBVY3q/DL9EEYD0Pmp6krqIGpHUyrldCWs R2VCfmo5DpK6FqulnfXqznGV7oloUWM/sd78xZmq4ZNxspvnmKXQP/OsnPLVgDiudBG6 t/Dr227PtSPGbHuZEk6D2u+fnZempRh2kEN6uDRtr1HxDzH70ocA9v98lW4IDI3mNOeh 5j0ivs/5k+oYCW/e6a0y62Ouun8krCQF+xnQ72HzRdyoIGZxrXhjfBMAkPSayFxWleW7 z2Nw== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=KXkGZMXJ; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id n8-20020a05640205c800b00469b3fcafe8si271055edx.432.2022.12.08.17.56.10 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:56:10 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=KXkGZMXJ; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 961BF38C265B for ; Fri, 9 Dec 2022 01:54:24 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by sourceware.org (Postfix) with ESMTPS id DB88B382BEA3 for ; Fri, 9 Dec 2022 01:52:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DB88B382BEA3 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-wm1-x32b.google.com with SMTP id o15so2224594wmr.4 for ; Thu, 08 Dec 2022 17:52:50 -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=/rRacCe5lrPn470JU4Rt+ew+LafgpZ1MY+8uNotWYtk=; b=KXkGZMXJng51vYjqprBCo98nAHyMvO9E4KSICZB5VAa950S3TzQraRGPW421r4SSDH 19aqnlwh3wHcmy+fdqTp1UxXtGfjc+kIjyd6j1pX100vbi0ghQ+guMu+Qg+GXIeHgREj 8aWzUjHWU+4lHPqLyJhp7aGfSz7Ry0t180BIg3AN8haosmvmR+ctDAv4kW5KLSpPvAxS zrHZ/CEvNWkYoHL2mjqo1AFkqRoQV58YWhiowNsTgU7bkhjKltFXRxPH/WfQMwRBwTaq ZEDDd9GmPFZOT+sVJnrmmsKnw9freiOufBYVYKiDiX8laBRCWE2CXMNFqTrFSoUBcGNK 19fA== 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=/rRacCe5lrPn470JU4Rt+ew+LafgpZ1MY+8uNotWYtk=; b=8Lh209BzVycgsX9WKSQHBfOcZufVKrALtm1BTPGNK5ZqpiI4VAtkB0O+/X+xYfCT9q N8DlXVsdYlVUEYcv3prm3k0cF4v8IcuhcbCCcYpLIImM5lAieMHLUb9rhi4VTbnzwWZ9 Xl6W6L2tQlXsNFvpSoG02ycr5JFop4HgnGV1SehUGmAThqQLmobJXEdI8zPeaKaneKqv uWMDcQroya15SAzl+HG7PedA0HTDPwmLMDyHkv+c/T3/5oxxIALjN8KuhDt6Hs12PkdH yMG6tYxcp4cWc00zeFKbJbWP6LOgCvHzfjuqNULbPGGaT/WyEwE8cJsAl+nY/riScN8o itpw== X-Gm-Message-State: ANoB5plPZ+AWuEznv/3m7I7OimXpmM3UjZjju4CM3P9SznTsIlOfnoN3 6NWnO2jMbXHcg3+mmRBaC3QRpSFeeG0= X-Received: by 2002:a05:600c:3549:b0:3c6:e61e:ae8c with SMTP id i9-20020a05600c354900b003c6e61eae8cmr4043337wmq.28.1670550769160; Thu, 08 Dec 2022 17:52:49 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:48 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 06/10] ld: Write types into IPI stream of PDB Date: Fri, 9 Dec 2022 01:52:36 +0000 Message-Id: <20221209015240.6348-6-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699654328188752?= X-GMAIL-MSGID: =?utf-8?q?1751699654328188752?= --- 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 4bb19420f95..69fade50814 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -1123,13 +1123,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)); @@ -1910,6 +1913,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; @@ -1917,7 +2082,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; @@ -1930,7 +2097,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; @@ -1939,16 +2106,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 */ { @@ -1961,7 +2128,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; @@ -2018,7 +2186,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); @@ -2043,7 +2211,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; @@ -2067,7 +2236,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); @@ -2112,7 +2281,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; @@ -2201,7 +2370,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++) { @@ -2524,7 +2693,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; @@ -2536,7 +2706,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)) @@ -3209,7 +3379,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 From patchwork Fri Dec 9 01:52:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31579 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp529270wrr; Thu, 8 Dec 2022 17:56:09 -0800 (PST) X-Google-Smtp-Source: AA0mqf7qaJ299Nv8I623vU4QlCwBfZzZ71VnB3fO+xbIcr9w448QSPQFAE27PfqEFkmMcmNiRoOb X-Received: by 2002:a05:6402:5303:b0:462:8a68:1398 with SMTP id eo3-20020a056402530300b004628a681398mr5158697edb.1.1670550969125; Thu, 08 Dec 2022 17:56:09 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550969; cv=none; d=google.com; s=arc-20160816; b=cdsDAyE9UuWOVixQQ1DXPycNrtKZDiBB0WJAsK/5x23qDbVVQdvhqIHMxp5xy4nsZF 3+tRtKm/L1GDb/Q5BDh2X1eY7yKK/vUqtwsiHTzeypWnrRqhLEr3+OtwrJPTw2VtUzZ4 Q3OdBchF5IV756cOOOnLj4xYAeuPYYQ3P2O4EBD02ZdoCDHvm2+UWig47280sFutuqAr W2Yq7+W7vOWyJ8q0o324KQaYrZ6e56B5XT7PTpfYn6YQo6nt47qNjqpq628BG5LdJ2dx Ql/Bn4fMEg7IJGC9SeBBmpY7NgfXKlzVNDC8P7PYCf1Z3wuQq+z2stlN2lNeNLDmk/cK 0v3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=pRAAuMLAiugJDkqr7ANyM1yL/z1eD+nWA/B5ZMAoAJA=; b=LK5QNChA20UJxtPq5uf4G6yPtFbX0Hq7MmZMbNcPa+geeEPzLb+kvxX22CcjX8Cx1B whQoUsY7qJ5aeLxZhwb6smS63Rn0ybSVBxQo6RoIC0CSTjVycbiAIbG5aNTHLKMXJWiF 3eu2uhjFUFD793D5mUUn8EUHy9+79vMdvZmzHcIInw4lRhSt8nBJm4wJZwLnh3L/Khub qrlP3jHX/Ccsr/R1sFa4FUTV4QcckZp43O1oJDNFMk1ZGQ1Zsi2jAdZ+rlgNsyZkQ+xQ VjT/DYbJTZ/Kj0ZWcxsrFdeODmKzekdjAhw+4fN0GOYT21ReWGFVcOXGxVCHWu+nNonM AyRg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=liFsFV6S; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id h17-20020a056402281100b0046b999e8862si339670ede.20.2022.12.08.17.56.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:56:09 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=liFsFV6S; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id EED4D3810ACE for ; Fri, 9 Dec 2022 01:54:23 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by sourceware.org (Postfix) with ESMTPS id 0036C3830FC3 for ; Fri, 9 Dec 2022 01:52:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0036C3830FC3 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-wm1-x32a.google.com with SMTP id h8-20020a1c2108000000b003d1efd60b65so4807057wmh.0 for ; Thu, 08 Dec 2022 17:52:51 -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=pRAAuMLAiugJDkqr7ANyM1yL/z1eD+nWA/B5ZMAoAJA=; b=liFsFV6SzhWLzxLaXqnJz/w5fIr44LzAk5WZCQfPVPjF1CdMWY6fOqZHlEdJCrKLeZ PVSVUXYjBATq7spTqjmaMrTowyg+esvhoanst/GYs2EoKaeA9DHToDVQo0Zok2IUAgyC 2netHHkIAIPQsA0RfdpZnZlSRhovk/fuZsXSlSZlUZXohlQ2blbfFtiUGaeeXXUGc4bw +OPWMNKc2VaWRPtRqK63Q/0vTdosufnYnCw2JcHdk5/AI7S36p+IHIMJhICGP6ctFLXX GAPLgmO0ae+eptI57YIo8gUIPWWe1i0KOOIfiUxvrfHFt7nrHgCxx8zD4gXEcvzMpLD1 Ip+w== 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=pRAAuMLAiugJDkqr7ANyM1yL/z1eD+nWA/B5ZMAoAJA=; b=z0BbiZEPwq5AQHsA5hNnlNtT8I0sDruHTvYVRb1fHzi1R6UPxUoznyFEB5mKlG+EoJ BIIeOgjjn6SJyqVYpv4jc4iNfxYxXAHC8uKHbxenIdIcr2wsELMp/EMCPLsCq79AZWIw YeXcS33FvkvSxk5m/zpzWvuTVW/EAUWVLVjgU9rSp+FtNKIMkgFb8yhXzgD3L1YGKedm JIHhdGFk0wdxsC9j8i6kxpAbtfMQbryHYJGWM7jCtW5kAutqwLN1LPYgt2jo9M9KnDZW 3XBJ0FTeb/qAbt1wpIw4ZdytQ8ibX43MDhpzR8tjHCQpZhSE9DFBDTUQXf61oyoByLPn R7GQ== X-Gm-Message-State: ANoB5pmXIZasQbgHSofxftuKjAIH7R+Fk/M5gjNWT2w2cZNtBUWYwYia 47T98G4YXniDorMDXWbfRnxa82UWOXg= X-Received: by 2002:a05:600c:3b9c:b0:3d1:e710:98ec with SMTP id n28-20020a05600c3b9c00b003d1e71098ecmr3859467wms.21.1670550770281; Thu, 08 Dec 2022 17:52:50 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:49 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 07/10] ld: Parse LF_UDT_SRC_LINE records when creating PDB file Date: Fri, 9 Dec 2022 01:52:37 +0000 Message-Id: <20221209015240.6348-7-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699652739887102?= X-GMAIL-MSGID: =?utf-8?q?1751699652739887102?= --- ld/pdb.c | 171 +++++++++++++++++++++-- ld/pdb.h | 23 +++ ld/testsuite/ld-pe/pdb-types3-hashlist.d | 5 + ld/testsuite/ld-pe/pdb-types3-skiplist.d | 5 + ld/testsuite/ld-pe/pdb-types3-typelist.d | 7 + ld/testsuite/ld-pe/pdb-types3a.s | 57 ++++++++ ld/testsuite/ld-pe/pdb-types3b.s | 68 +++++++++ ld/testsuite/ld-pe/pdb.exp | 133 ++++++++++++++++++ 8 files changed, 459 insertions(+), 10 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb-types3-hashlist.d create mode 100644 ld/testsuite/ld-pe/pdb-types3-skiplist.d create mode 100644 ld/testsuite/ld-pe/pdb-types3-typelist.d create mode 100644 ld/testsuite/ld-pe/pdb-types3a.s create mode 100644 ld/testsuite/ld-pe/pdb-types3b.s diff --git a/ld/pdb.c b/ld/pdb.c index 69fade50814..53a83fb8d6b 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -76,6 +76,7 @@ struct type_entry struct type_entry *next; uint32_t index; uint32_t cv_hash; + bool has_udt_src_line; uint8_t data[]; }; @@ -708,19 +709,19 @@ copy_filechksms (uint8_t *data, uint32_t size, char *string_table, return true; } -/* Add a string to the strings table, if it's not already there. */ -static void +/* Add a string to the strings table, if it's not already there. Returns its + offset within the string table. */ +static uint32_t add_string (char *str, size_t len, struct string_table *strings) { uint32_t hash = calc_hash (str, len); + struct string *s; void **slot; slot = htab_find_slot_with_hash (strings->hashmap, str, hash, INSERT); if (!*slot) { - struct string *s; - *slot = xmalloc (offsetof (struct string, s) + len); s = (struct string *) *slot; @@ -741,6 +742,12 @@ add_string (char *str, size_t len, struct string_table *strings) strings->strings_len += len + 1; } + else + { + s = (struct string *) *slot; + } + + return s->offset; } /* Return the hash of an entry in the string table. */ @@ -1118,13 +1125,149 @@ is_name_anonymous (char *name, size_t len) return false; } +/* Handle LF_UDT_SRC_LINE type entries, which are a special case. These + give the source file and line number for each user-defined type that is + declared. We parse these and emit instead an LF_UDT_MOD_SRC_LINE entry, + which also includes the module number. */ +static bool +handle_udt_src_line (uint8_t *data, uint16_t size, struct type_entry **map, + uint32_t type_num, uint32_t num_types, + struct types *ids, uint16_t mod_num, + struct string_table *strings) +{ + struct lf_udt_src_line *usl = (struct lf_udt_src_line *) data; + uint32_t orig_type, source_file_type; + void **slot; + hashval_t hash; + struct type_entry *e, *type_e, *str_e; + struct lf_udt_mod_src_line *umsl; + struct lf_string_id *str; + uint32_t source_file_offset; + + if (size < sizeof (struct lf_udt_src_line)) + { + einfo (_("%P: warning: truncated CodeView type record" + " LF_UDT_SRC_LINE\n")); + return false; + } + + /* Check if LF_UDT_MOD_SRC_LINE already present for type, and return. */ + + orig_type = bfd_getl32 (&usl->type); + + if (orig_type < TPI_FIRST_INDEX || + orig_type >= TPI_FIRST_INDEX + num_types || + !map[orig_type - TPI_FIRST_INDEX]) + { + einfo (_("%P: warning: CodeView type record LF_UDT_SRC_LINE" + " referred to unknown type %v\n"), orig_type); + return false; + } + + type_e = map[orig_type - TPI_FIRST_INDEX]; + + /* Skip if type already declared in other module. */ + if (type_e->has_udt_src_line) + return true; + + if (!remap_type (&usl->type, map, type_num, num_types)) + return false; + + /* Extract string from source_file_type. */ + + source_file_type = bfd_getl32 (&usl->source_file_type); + + if (source_file_type < TPI_FIRST_INDEX || + source_file_type >= TPI_FIRST_INDEX + num_types || + !map[source_file_type - TPI_FIRST_INDEX]) + { + einfo (_("%P: warning: CodeView type record LF_UDT_SRC_LINE" + " referred to unknown string %v\n"), source_file_type); + return false; + } + + str_e = map[source_file_type - TPI_FIRST_INDEX]; + + if (bfd_getl16 (str_e->data + sizeof (uint16_t)) != LF_STRING_ID) + { + einfo (_("%P: warning: CodeView type record LF_UDT_SRC_LINE" + " pointed to unexpected record type\n")); + return false; + } + + str = (struct lf_string_id *) str_e->data; + + /* Add string to string table. */ + + source_file_offset = add_string (str->string, strlen (str->string), + strings); + + /* Add LF_UDT_MOD_SRC_LINE entry. */ + + size = sizeof (struct lf_udt_mod_src_line); + + e = xmalloc (offsetof (struct type_entry, data) + size); + + e->next = NULL; + e->index = ids->num_types; + e->has_udt_src_line = false; + + /* LF_UDT_MOD_SRC_LINE use calc_hash on the type number, rather than + the crc32 used for type hashes elsewhere. */ + e->cv_hash = calc_hash ((char *) &usl->type, sizeof (uint32_t)); + + type_e->has_udt_src_line = true; + + umsl = (struct lf_udt_mod_src_line *) e->data; + + bfd_putl16 (size - sizeof (uint16_t), &umsl->size); + bfd_putl16 (LF_UDT_MOD_SRC_LINE, &umsl->kind); + memcpy (&umsl->type, &usl->type, sizeof (uint32_t)); + bfd_putl32 (source_file_offset, &umsl->source_file_string); + memcpy (&umsl->line_no, &usl->line_no, sizeof (uint16_t)); + bfd_putl16 (mod_num + 1, &umsl->module_no); + + hash = iterative_hash (e->data, size, 0); + + slot = htab_find_slot_with_hash (ids->hashmap, data, hash, INSERT); + if (!slot) + { + free (e); + return false; + } + + if (*slot) + { + free (e); + einfo (_("%P: warning: duplicate CodeView type record " + "LF_UDT_MOD_SRC_LINE\n")); + return false; + } + + *slot = e; + + if (ids->last) + ids->last->next = e; + else + ids->first = e; + + ids->last = e; + + map[type_num] = e; + + ids->num_types++; + + return true; +} + /* Parse a type definition in the .debug$T section. We remap the numbers of any referenced types, and if the type is not a duplicate of one 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, - struct types *ids) + struct types *ids, uint16_t mod_num, + struct string_table *strings) { uint16_t size, type; void **slot; @@ -2075,6 +2218,10 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, break; } + case LF_UDT_SRC_LINE: + return handle_udt_src_line (data, size, map, type_num, num_types, + ids, mod_num, strings); + default: einfo (_("%P: warning: unrecognized CodeView type %v\n"), type); return false; @@ -2104,6 +2251,8 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, else e->cv_hash = crc32 (data, size); + e->has_udt_src_line = false; + memcpy (e->data, data, size); if (t->last) @@ -2129,7 +2278,8 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, found to handle_type. */ static bool handle_debugt_section (asection *s, bfd *mod, struct types *types, - struct types *ids) + struct types *ids, uint16_t mod_num, + struct string_table *strings) { bfd_byte *data = NULL; size_t off; @@ -2186,7 +2336,8 @@ 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, ids)) + if (!handle_type (data + off, map, type_num, num_types, types, ids, + mod_num, strings)) { free (data); free (map); @@ -2212,7 +2363,7 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, uint32_t *c13_info_size, struct mod_source_files *mod_source, bfd *abfd, struct types *types, - struct types *ids) + struct types *ids, uint16_t mod_num) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; @@ -2236,7 +2387,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, ids)) + if (!handle_debugt_section (s, mod, types, ids, mod_num, strings)) { free (c13_info); free (mod_source->files); @@ -2370,7 +2521,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, ids)) + types, ids, mod_num)) { for (unsigned int i = 0; i < source->mod_count; i++) { diff --git a/ld/pdb.h b/ld/pdb.h index 7d87a3fef07..668f3e168fd 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -59,6 +59,8 @@ #define LF_BUILDINFO 0x1603 #define LF_SUBSTR_LIST 0x1604 #define LF_STRING_ID 0x1605 +#define LF_UDT_SRC_LINE 0x1606 +#define LF_UDT_MOD_SRC_LINE 0x1607 #define LF_CHAR 0x8000 #define LF_SHORT 0x8001 @@ -517,6 +519,27 @@ struct lf_mfunc_id char name[]; } ATTRIBUTE_PACKED; +/* lfUdtSrcLine in cvinfo.h */ +struct lf_udt_src_line +{ + uint16_t size; + uint16_t kind; + uint32_t type; + uint32_t source_file_type; + uint32_t line_no; +} ATTRIBUTE_PACKED; + +/* lfUdtModSrcLine in cvinfo.h */ +struct lf_udt_mod_src_line +{ + uint16_t size; + uint16_t kind; + uint32_t type; + uint32_t source_file_string; + uint32_t line_no; + uint16_t module_no; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb-types3-hashlist.d b/ld/testsuite/ld-pe/pdb-types3-hashlist.d new file mode 100644 index 00000000000..4a3775be42a --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types3-hashlist.d @@ -0,0 +1,5 @@ + +*: file format binary + +Contents of section .data: + 0000 d4d90000 0c1c0000 * \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types3-skiplist.d b/ld/testsuite/ld-pe/pdb-types3-skiplist.d new file mode 100644 index 00000000000..52c10fa501d --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types3-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-types3-typelist.d b/ld/testsuite/ld-pe/pdb-types3-typelist.d new file mode 100644 index 00000000000..d6ffaadb246 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types3-typelist.d @@ -0,0 +1,7 @@ + +*: file format binary + +Contents of section .data: + 0000 0e000516 00000000 666f6f2e 6800f2f1 ........foo.h... + 0010 10000716 01100000 01000000 2a000000 ............*... + 0020 0100 .. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-types3a.s b/ld/testsuite/ld-pe/pdb-types3a.s new file mode 100644 index 00000000000..def001e52f7 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types3a.s @@ -0,0 +1,57 @@ +.equ CV_SIGNATURE_C13, 4 +.equ T_INT4, 0x0074 + +.equ LF_FIELDLIST, 0x1203 +.equ LF_STRUCTURE, 0x1505 +.equ LF_MEMBER, 0x150d +.equ LF_STRING_ID, 0x1605 +.equ LF_UDT_SRC_LINE, 0x1606 + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, fieldlist for struct foo +.fieldlist1: +.short .struct1 - .fieldlist1 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long T_INT4 +.short 0 # offset +.asciz "num" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1001, struct foo +.struct1: +.short .string1 - .struct1 - 2 +.short LF_STRUCTURE +.short 1 # no. members +.short 0 # property +.long 0x1000 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "foo" # name +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1002, string "foo" +.string1: +.short .udtsrcline1 - .string1 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "foo.h" +.byte 0xf2 +.byte 0xf1 + +# Type 1003, UDT source line for type 1001 +.udtsrcline1: +.short .types_end - .udtsrcline1 - 2 +.short LF_UDT_SRC_LINE +.long 0x1001 +.long 0x1002 # source file string +.long 42 # line no. + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb-types3b.s b/ld/testsuite/ld-pe/pdb-types3b.s new file mode 100644 index 00000000000..a22234e221f --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-types3b.s @@ -0,0 +1,68 @@ +.equ CV_SIGNATURE_C13, 4 + +.equ T_LONG, 0x0012 +.equ T_INT4, 0x0074 + +.equ LF_MODIFIER, 0x1001 +.equ LF_FIELDLIST, 0x1203 +.equ LF_STRUCTURE, 0x1505 +.equ LF_MEMBER, 0x150d +.equ LF_STRING_ID, 0x1605 +.equ LF_UDT_SRC_LINE, 0x1606 + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, const long +.mod1: +.short .fieldlist1 - .mod1 - 2 +.short LF_MODIFIER +.long T_LONG +.short 1 # const +.short 0 # padding + +# Type 1001, fieldlist for struct foo +.fieldlist1: +.short .struct1 - .fieldlist1 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long T_INT4 +.short 0 # offset +.asciz "num" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1002, struct foo +.struct1: +.short .string1 - .struct1 - 2 +.short LF_STRUCTURE +.short 1 # no. members +.short 0 # property +.long 0x1001 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "foo" # name +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1003, string "foo" +.string1: +.short .udtsrcline1 - .string1 - 2 +.short LF_STRING_ID +.long 0 # sub-string +.asciz "foo.h" +.byte 0xf2 +.byte 0xf1 + +# Type 1004, UDT source line for type 1002 +.udtsrcline1: +.short .types_end - .udtsrcline1 - 2 +.short LF_UDT_SRC_LINE +.long 0x1002 +.long 0x1003 # source file string +.long 42 # line no. + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 9753216f544..1a5416890d1 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1319,9 +1319,142 @@ proc test6 { } { } } +proc test7 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb-types3a.s tmpdir/pdb-types3a.o] { + unsupported "Build pdb-types3a.o" + return + } + + if ![ld_assemble $as $srcdir/$subdir/pdb-types3b.s tmpdir/pdb-types3b.o] { + unsupported "Build pdb-types3b.o" + return + } + + if ![ld_link $ld "tmpdir/pdb-types3.exe" "--pdb=tmpdir/pdb-types3.pdb tmpdir/pdb-types3a.o tmpdir/pdb-types3b.o"] { + unsupported "Create PE image with PDB file" + return + } + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types3.pdb 0004"] + + if ![string match "" $exec_output] { + fail "Could not extract IPI stream" + return + } else { + pass "Extracted IPI stream" + } + + set fi [open tmpdir/0004] + fconfigure $fi -translation binary + + seek $fi 16 current + + 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 10 current + + 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-types3-typelist w] + fconfigure $fi -translation binary + puts -nonewline $fi $type_list + close $fi + + # check type list + + set exp [file_contents "$srcdir/$subdir/pdb-types3-typelist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types3-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-types3.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-types3-hashlist w] + fconfigure $fi -translation binary + puts -nonewline $fi $hash_list + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb-types3-hashlist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types3-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-types3-skiplist w] + fconfigure $fi -translation binary + puts -nonewline $fi $skip_list + close $fi + + set exp [file_contents "$srcdir/$subdir/pdb-types3-skiplist.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types3-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 +test7 From patchwork Fri Dec 9 01:52:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31591 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp530081wrr; Thu, 8 Dec 2022 17:58:54 -0800 (PST) X-Google-Smtp-Source: AA0mqf5FndV36xnvA+iWSz7aNWMOh2Axvx+1eL8m1MlaadScO6uwp7Qa774MYZWhIGy2C1IPh/O5 X-Received: by 2002:a17:906:351b:b0:7c0:a6a9:64e9 with SMTP id r27-20020a170906351b00b007c0a6a964e9mr4565809eja.36.1670551134227; Thu, 08 Dec 2022 17:58:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670551134; cv=none; d=google.com; s=arc-20160816; b=dYEZkg9cqOsVT2ZnhpoKumbyjXDzrSOKhXifnEJ9KqG5h84as+fnKBNSZy0ZFI1vdD xmrtEhYMhZt9NG/vLrLywIMvjLOn/AODcuMvmjfMQ7Xnn7sTvnhxtw1+hsxm4D87ll08 oE7Zd7dyN8fz64e8X87dIFW3xRID9rn7wLxSFo81MM80hLBycDInwRRE2eQt0RHsFAlC RN0RmWKkWjXIFU+eBEoQ42M5EFfi3MkF38PgoHsjhRKne0hobpJRkHbiO1vJyXngSFj6 EP/MRddKszHgyWdjxI9h8jer+w9+3WXSgK/8dyezK6Jufh5H7QQatj9LAjQULMbCUSGt dx/Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=xsW2HFmEFhPUkVXF4vv+zqfAKQvwFOKv0/i0GTD45zM=; b=iOyD9W1cN9jV6BwbUSDT/ZhbMwUb370/tZbvtFU+rP67eR362aHEMJrKeij21Qz8vw y3nA4c7izygzYAaW6OD6kwjQWCRhVQUGOAoHivM5EHL12wk7D0heDRszNikfODQUOGN6 XATf3lcgUlTR/2LPChg7GDw0Tgb5+MpyuslK5id2bCLnf73jRtWvib/J0ICPmZYe1pdx ZGRmRKmGlLmCJ/HLBiWBitCHQhQnXlhFVuGD2DB9woJU47GMwF0/wti7skmLpn9rVHJn MbTt0Ih5eguJ+Z9f7XvoHx7ZXZ9qMnqFmOzkKLL65u/I9oumfpU1vX4RCclhqJdHhFYx uSjg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=JdWeODaL; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id be8-20020a1709070a4800b007af039d0bcasi66707ejc.429.2022.12.08.17.58.53 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:58:54 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=JdWeODaL; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1A89338CCDC0 for ; Fri, 9 Dec 2022 01:55:06 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by sourceware.org (Postfix) with ESMTPS id A96B038319E0 for ; Fri, 9 Dec 2022 01:52:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A96B038319E0 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-wm1-x331.google.com with SMTP id c65-20020a1c3544000000b003cfffd00fc0so4794068wma.1 for ; Thu, 08 Dec 2022 17:52:53 -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=xsW2HFmEFhPUkVXF4vv+zqfAKQvwFOKv0/i0GTD45zM=; b=JdWeODaLTqhOUgy3gjd6MXY36qw7AKxlHMHgPmIXJjeabruFwt5pqQeGVV/cQYxO7q hJ4Lafzk/jBfCKqnm4z7NZPSlQDyEbnLQMcMHrBYROMEpKHCsFjngt6tGLhYy4VP/yJu vvVbEPHDW895MeA8JZloXGOKaaH2mNi6yUzkwaJGbtEM2kB+703lGSZQVkY96ZC3xldJ HaiRVEAuY53T5WscpH54dD8Jld3LY5TGHG8hvwOJvsKHabUTzjTMWPupozqTO1Vm9P9c WVfz6wPwdmMdhFXIdIbZ2mSR6JnUM3VzRrUuNNgdbIFSXVMWnetQO9sk/5X/WsBfyV5a SfGw== 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=xsW2HFmEFhPUkVXF4vv+zqfAKQvwFOKv0/i0GTD45zM=; b=yft9M2ScbVMog9Sa2h5C98dhtSRGDoDuYkb/xCUTl16O39sXv/ehUI04nee3CD9AT7 gAItUjjExJ3WOowcoGwJyr5lvdM/tXcmVRt8PqPAan6Lg8TaCGmcITLJ5rEVIYQR1FwL kvyygaz1rOn+WgSEddGW32IuOpHcg9aXGWSIi8lMsQevzmiu5FE3nR6EapHUeIRKNwTB nJMRggkZwa3GVRjsDPcjvGeV2UlDRknXEJa4n85k1EHtjTe7gwpFM17TYyq3Ny1BMN7y nW04NHTg/csJzJc4OV0295RON7xdgLEx+pzm1IJ+4eai0b47R7LdU9aE3+k5zd62ZfxU ZIsg== X-Gm-Message-State: ANoB5ple0pUkYMHgvmvSPC9972kRVtWt6HF80ipu54uazfoFXs7eAmIw Vr+EPaVveUqAei1Z4D1dskzipr7Nr5Y= X-Received: by 2002:a05:600c:3c9a:b0:3c6:c6c9:d75e with SMTP id bg26-20020a05600c3c9a00b003c6c6c9d75emr4215291wmb.0.1670550771261; Thu, 08 Dec 2022 17:52:51 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:50 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 08/10] ld: Write globals stream in PDB Date: Fri, 9 Dec 2022 01:52:38 +0000 Message-Id: <20221209015240.6348-8-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699825958285026?= X-GMAIL-MSGID: =?utf-8?q?1751699825958285026?= --- ld/pdb.c | 1088 +++++++++++++++++++++-- ld/pdb.h | 77 ++ ld/testsuite/ld-pe/pdb-syms1-globals.d | 57 ++ ld/testsuite/ld-pe/pdb-syms1-records.d | 61 ++ ld/testsuite/ld-pe/pdb-syms1-symbols1.d | 8 + ld/testsuite/ld-pe/pdb-syms1-symbols2.d | 56 ++ ld/testsuite/ld-pe/pdb-syms1a.s | 110 +++ ld/testsuite/ld-pe/pdb-syms1b.s | 737 +++++++++++++++ ld/testsuite/ld-pe/pdb.exp | 164 ++++ 9 files changed, 2279 insertions(+), 79 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb-syms1-globals.d create mode 100644 ld/testsuite/ld-pe/pdb-syms1-records.d create mode 100644 ld/testsuite/ld-pe/pdb-syms1-symbols1.d create mode 100644 ld/testsuite/ld-pe/pdb-syms1-symbols2.d create mode 100644 ld/testsuite/ld-pe/pdb-syms1a.s create mode 100644 ld/testsuite/ld-pe/pdb-syms1b.s diff --git a/ld/pdb.c b/ld/pdb.c index 53a83fb8d6b..5257cda2e25 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -88,6 +88,24 @@ struct types struct type_entry *last; }; +struct global +{ + struct global *next; + uint32_t offset; + uint32_t hash; + uint32_t refcount; + unsigned int index; + uint8_t data[]; +}; + +struct globals +{ + uint32_t num_entries; + struct global *first; + struct global *last; + htab_t hashmap; +}; + static const uint32_t crc_table[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, @@ -767,56 +785,677 @@ eq_string_table_entry (const void *a, const void *b) const char *s2 = (const char *) b; size_t s2_len = strlen (s2); - if (s2_len != s1->len) - return 0; + if (s2_len != s1->len) + return 0; + + return memcmp (s1->s, s2, s2_len) == 0; +} + +/* Parse the string table within the .debug$S section. */ +static void +parse_string_table (bfd_byte *data, size_t size, + struct string_table *strings) +{ + while (true) + { + size_t len = strnlen ((char *) data, size); + + add_string ((char *) data, len, strings); + + data += len + 1; + + if (size <= len + 1) + break; + + size -= len + 1; + } +} + +/* Remap a type reference within a CodeView symbol. */ +static bool +remap_symbol_type (void *data, struct type_entry **map, uint32_t num_types) +{ + uint32_t type = bfd_getl32 (data); + + /* Ignore builtin types (those with IDs below 0x1000). */ + if (type < TPI_FIRST_INDEX) + return true; + + if (type >= TPI_FIRST_INDEX + num_types) + { + einfo (_("%P: CodeView symbol references out of range type %v\n"), + type); + return false; + } + + type = TPI_FIRST_INDEX + map[type - TPI_FIRST_INDEX]->index; + bfd_putl32 (type, data); + + return true; +} + +/* Add an entry into the globals stream. If it already exists, increase + the refcount. */ +static bool +add_globals_ref (struct globals *glob, bfd *sym_rec_stream, const char *name, + size_t name_len, uint8_t *data, size_t len) +{ + void **slot; + uint32_t hash; + struct global *g; + + slot = htab_find_slot_with_hash (glob->hashmap, data, + iterative_hash (data, len, 0), INSERT); + + if (*slot) + { + g = *slot; + g->refcount++; + return true; + } + + *slot = xmalloc (offsetof (struct global, data) + len); + + hash = crc32 ((const uint8_t *) name, name_len); + hash %= NUM_GLOBALS_HASH_BUCKETS; + + g = *slot; + g->next = NULL; + g->offset = bfd_tell (sym_rec_stream); + g->hash = hash; + g->refcount = 1; + memcpy (g->data, data, len + 1); + + glob->num_entries++; + + if (glob->last) + glob->last->next = g; + else + glob->first = g; + + glob->last = g; + + return bfd_bwrite (data, len, sym_rec_stream) == len; +} + +/* Find the end of the current scope within symbols data. */ +static uint8_t * +find_end_of_scope (uint8_t *data, uint32_t size) +{ + unsigned int scope_level = 1; + uint16_t len; + + len = bfd_getl16 (data) + sizeof (uint16_t); + + data += len; + size -= len; + + while (true) + { + uint16_t type; + + if (size < sizeof (uint32_t)) + return NULL; + + len = bfd_getl16 (data) + sizeof (uint16_t); + type = bfd_getl16 (data + sizeof (uint16_t)); + + if (size < len) + return NULL; + + switch (type) + { + case S_GPROC32: + case S_LPROC32: + scope_level++; + break; + + case S_END: + case S_PROC_ID_END: + scope_level--; + + if (scope_level == 0) + return data; + + break; + } + + data += len; + size -= len; + } +} + +/* Return the size of an extended value parameter, as used in + LF_ENUMERATE etc. */ +static unsigned int +extended_value_len (uint16_t type) +{ + switch (type) + { + case LF_CHAR: + return 1; + + case LF_SHORT: + case LF_USHORT: + return 2; + + case LF_LONG: + case LF_ULONG: + return 4; + + case LF_QUADWORD: + case LF_UQUADWORD: + return 8; + } + + return 0; +} + +/* Parse the symbols in a .debug$S section, and copy them to the module's + symbol stream. */ +static bool +parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf, + struct type_entry **map, uint32_t num_types, + bfd *sym_rec_stream, struct globals *glob, uint16_t mod_num) +{ + uint8_t *orig_buf = *buf; + unsigned int scope_level = 0; + + while (size >= sizeof (uint16_t)) + { + uint16_t len, type; + + len = bfd_getl16 (data) + sizeof (uint16_t); + + if (len > size) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + type = bfd_getl16 (data + sizeof (uint16_t)); + + switch (type) + { + case S_LDATA32: + case S_GDATA32: + case S_LTHREAD32: + case S_GTHREAD32: + { + struct datasym *d = (struct datasym *) data; + size_t name_len; + + if (len < offsetof (struct datasym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_LDATA32/S_GDATA32/S_LTHREAD32/S_GTHREAD32\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (scope_level == 0) + { + uint16_t section = bfd_getl16 (&d->section); + + if (section == 0) /* GC'd, ignore */ + break; + } + + name_len = + strnlen (d->name, len - offsetof (struct datasym, name)); + + if (name_len == len - offsetof (struct datasym, name)) + { + einfo (_("%P: warning: name for S_LDATA32/S_GDATA32/" + "S_LTHREAD32/S_GTHREAD32 has no terminating" + " zero\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&d->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* If S_LDATA32 or S_LTHREAD32, copy into module symbols. */ + + if (type == S_LDATA32 || type == S_LTHREAD32) + { + memcpy (*buf, d, len); + *buf += len; + } + + /* S_LDATA32 and S_LTHREAD32 only go in globals if + not in function scope. */ + if (type == S_GDATA32 || type == S_GTHREAD32 || scope_level == 0) + { + if (!add_globals_ref (glob, sym_rec_stream, d->name, + name_len, data, len)) + return false; + } + + break; + } + + case S_GPROC32: + case S_LPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + { + struct procsym *proc = (struct procsym *) data; + size_t name_len; + uint16_t section; + uint32_t end; + uint8_t *endptr; + size_t ref_size, padding; + struct refsym *ref; + + if (len < offsetof (struct procsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_GPROC32/S_LPROC32\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + section = bfd_getl16 (&proc->section); + + endptr = find_end_of_scope (data, size); + + if (!endptr) + { + einfo (_("%P: warning: could not find end of" + " S_GPROC32/S_LPROC32 record\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (section == 0) /* skip if GC'd */ + { + /* Skip to after S_END. */ + + size -= endptr - data; + data = endptr; + + len = bfd_getl16 (data) + sizeof (uint16_t); + + data += len; + size -= len; + + continue; + } + + name_len = + strnlen (proc->name, len - offsetof (struct procsym, name)); + + if (name_len == len - offsetof (struct procsym, name)) + { + einfo (_("%P: warning: name for S_GPROC32/S_LPROC32 has no" + " terminating zero\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (type == S_GPROC32_ID || type == S_LPROC32_ID) + { + /* Transform into S_GPROC32 / S_LPROC32. */ + + uint32_t t_idx = bfd_getl32 (&proc->type); + struct type_entry *t; + uint16_t t_type; + + if (t_idx < TPI_FIRST_INDEX + || t_idx >= TPI_FIRST_INDEX + num_types) + { + einfo (_("%P: CodeView symbol references out of range" + " type %v\n"), type); + bfd_set_error (bfd_error_bad_value); + return false; + } + + t = map[t_idx - TPI_FIRST_INDEX]; + + t_type = bfd_getl16 (t->data + sizeof (uint16_t)); + + switch (t_type) + { + case LF_FUNC_ID: + { + struct lf_func_id *t_data = + (struct lf_func_id *) t->data; + + /* Replace proc->type with function type. */ + + memcpy (&proc->type, &t_data->function_type, + sizeof (uint32_t)); + + break; + } + + case LF_MFUNC_ID: + { + struct lf_mfunc_id *t_data = + (struct lf_mfunc_id *) t->data; + + /* Replace proc->type with function type. */ + + memcpy (&proc->type, &t_data->function_type, + sizeof (uint32_t)); + + break; + } + + default: + einfo (_("%P: CodeView S_GPROC32_ID/S_LPROC32_ID symbol" + " referenced unknown type as ID\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Change record type. */ + + if (type == S_GPROC32_ID) + bfd_putl32 (S_GPROC32, &proc->kind); + else + bfd_putl32 (S_LPROC32, &proc->kind); + } + else + { + if (!remap_symbol_type (&proc->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + } + + end = *buf - orig_buf + sizeof (uint32_t) + endptr - data; + bfd_putl32 (end, &proc->end); + + /* Add S_PROCREF / S_LPROCREF to globals stream. */ + + ref_size = offsetof (struct refsym, name) + name_len + 1; + + if (ref_size % sizeof (uint32_t)) + padding = sizeof (uint32_t) - (ref_size % sizeof (uint32_t)); + else + padding = 0; + + ref = xmalloc (ref_size + padding); + + bfd_putl16 (ref_size + padding - sizeof (uint16_t), &ref->size); + bfd_putl16 (type == S_GPROC32 || type == S_GPROC32_ID ? + S_PROCREF : S_LPROCREF, &ref->kind); + bfd_putl32 (0, &ref->sum_name); + bfd_putl32 (*buf - orig_buf + sizeof (uint32_t), + &ref->symbol_offset); + bfd_putl16 (mod_num + 1, &ref->mod); + + memcpy (ref->name, proc->name, name_len + 1); + + memset (ref->name + name_len + 1, 0, padding); + + if (!add_globals_ref (glob, sym_rec_stream, proc->name, name_len, + (uint8_t *) ref, ref_size + padding)) + { + free (ref); + return false; + } + + free (ref); + + memcpy (*buf, proc, len); + *buf += len; + + scope_level++; + + break; + } + + case S_UDT: + { + struct udtsym *udt = (struct udtsym *) data; + size_t name_len; + + if (len < offsetof (struct udtsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_UDT\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + name_len = + strnlen (udt->name, len - offsetof (struct udtsym, name)); + + if (name_len == len - offsetof (struct udtsym, name)) + { + einfo (_("%P: warning: name for S_UDT has no" + " terminating zero\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&udt->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* S_UDT goes in the symbols stream if within a procedure, + otherwise it goes in the globals stream. */ + if (scope_level == 0) + { + if (!add_globals_ref (glob, sym_rec_stream, udt->name, + name_len, data, len)) + return false; + } + else + { + memcpy (*buf, udt, len); + *buf += len; + } + + break; + } + + case S_CONSTANT: + { + struct constsym *c = (struct constsym *) data; + size_t name_len, rec_size; + uint16_t val; + + if (len < offsetof (struct constsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_CONSTANT\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + rec_size = offsetof (struct constsym, name); + + val = bfd_getl16 (&c->value); + + /* If val >= 0x8000, actual value follows. */ + if (val >= 0x8000) + { + unsigned int param_len = extended_value_len (val); + + if (param_len == 0) + { + einfo (_("%P: warning: unhandled type %v within" + " S_CONSTANT\n"), val); + bfd_set_error (bfd_error_bad_value); + return false; + } + + rec_size += param_len; + } + + name_len = + strnlen ((const char *) data + rec_size, len - rec_size); + + if (name_len == len - rec_size) + { + einfo (_("%P: warning: name for S_CONSTANT has no" + " terminating zero\n")); + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!remap_symbol_type (&c->type, map, num_types)) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + + if (!add_globals_ref (glob, sym_rec_stream, + (const char *) data + rec_size, name_len, + data, len)) + return false; + + break; + } + + case S_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)); + + *buf += len; + scope_level--; + break; + + default: + einfo (_("%P: warning: unrecognized CodeView record %v\n"), type); + bfd_set_error (bfd_error_bad_value); + return false; + } + + data += len; + size -= len; + } + + return true; +} + +/* For a given symbol subsection, work out how much space to allocate in the + result module stream. This is different because we don't copy certain + symbols, such as S_CONSTANT, and we skip over any procedures or data that + have been GC'd out. */ +static bool +calculate_symbols_size (uint8_t *data, uint32_t size, uint32_t *sym_size) +{ + unsigned int scope_level = 0; + + while (size >= sizeof (uint32_t)) + { + uint16_t len = bfd_getl16 (data) + sizeof (uint16_t); + uint16_t type = bfd_getl16 (data + sizeof (uint16_t)); + + switch (type) + { + case S_LDATA32: + case S_LTHREAD32: + { + struct datasym *d = (struct datasym *) data; + uint16_t section; + + if (len < offsetof (struct datasym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_LDATA32/S_LTHREAD32\n")); + return false; + } + + section = bfd_getl16 (&d->section); + + /* copy if not GC'd or within function */ + if (scope_level != 0 || section != 0) + *sym_size += len; + } + + case S_GDATA32: + case S_GTHREAD32: + case S_CONSTANT: + /* Not copied into symbols stream. */ + break; + + case S_GPROC32: + case S_LPROC32: + case S_GPROC32_ID: + case S_LPROC32_ID: + { + struct procsym *proc = (struct procsym *) data; + uint16_t section; + + if (len < offsetof (struct procsym, name)) + { + einfo (_("%P: warning: truncated CodeView record" + " S_GPROC32/S_LPROC32\n")); + return false; + } + + section = bfd_getl16 (&proc->section); + + if (section != 0) + { + *sym_size += len; + } + else + { + uint8_t *endptr = find_end_of_scope (data, size); + + if (!endptr) + { + einfo (_("%P: warning: could not find end of" + " S_GPROC32/S_LPROC32 record\n")); + return false; + } - return memcmp (s1->s, s2, s2_len) == 0; -} + /* Skip to after S_END. */ -/* Parse the string table within the .debug$S section. */ -static void -parse_string_table (bfd_byte *data, size_t size, - struct string_table *strings) -{ - while (true) - { - size_t len = strnlen ((char *) data, size); + size -= endptr - data; + data = endptr; - add_string ((char *) data, len, strings); + len = bfd_getl16 (data) + sizeof (uint16_t); - data += len + 1; + data += len; + size -= len; - if (size <= len + 1) - break; + continue; + } - size -= len + 1; - } -} + scope_level++; -/* Return the size of an extended value parameter, as used in - LF_ENUMERATE etc. */ -static unsigned int -extended_value_len (uint16_t type) -{ - switch (type) - { - case LF_CHAR: - return 1; + break; + } - case LF_SHORT: - case LF_USHORT: - return 2; + case S_UDT: + if (scope_level != 0) /* only goes in symbols if local */ + *sym_size += len; + break; - case LF_LONG: - case LF_ULONG: - return 4; + case S_END: /* always copied */ + case S_PROC_ID_END: + *sym_size += len; + scope_level--; + break; - case LF_QUADWORD: - case LF_UQUADWORD: - return 8; + default: + einfo (_("%P: warning: unrecognized CodeView record %v\n"), type); + return false; + } + + data += len; + size -= len; } - return 0; + return true; } /* Parse the .debug$S section within an object file. */ @@ -824,13 +1463,17 @@ static bool handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, uint8_t **dataptr, uint32_t *sizeptr, struct mod_source_files *mod_source, - bfd *abfd) + bfd *abfd, uint8_t **syms, uint32_t *sym_byte_size, + struct type_entry **map, uint32_t num_types, + bfd *sym_rec_stream, struct globals *glob, + uint16_t mod_num) { bfd_byte *data = NULL; size_t off; uint32_t c13_size = 0; char *string_table = NULL; - uint8_t *buf, *bufptr; + uint8_t *buf, *bufptr, *symbuf, *symbufptr; + uint32_t sym_size = 0; if (!bfd_get_full_section_contents (mod, s, &data)) return false; @@ -969,6 +1612,16 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, break; } + + case DEBUG_S_SYMBOLS: + if (!calculate_symbols_size (data + off, size, &sym_size)) + { + free (data); + bfd_set_error (bfd_error_bad_value); + return false; + } + + break; } off += size; @@ -977,7 +1630,10 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, off += sizeof (uint32_t) - (off % sizeof (uint32_t)); } - if (c13_size == 0) + if (sym_size % sizeof (uint32_t)) + sym_size += sizeof (uint32_t) - (sym_size % sizeof (uint32_t)); + + if (c13_size == 0 && sym_size == 0) { free (data); return true; @@ -985,8 +1641,25 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, /* copy data */ - buf = xmalloc (c13_size); - bufptr = buf; + if (c13_size != 0) + { + buf = xmalloc (c13_size); + bufptr = buf; + } + else + { + buf = NULL; + } + + if (sym_size != 0) + { + symbuf = xmalloc (sym_size); + symbufptr = symbuf; + } + else + { + symbuf = NULL; + } off = sizeof (uint32_t); @@ -1007,6 +1680,7 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, strings, bufptr, mod_source)) { free (data); + free (symbuf); return false; } @@ -1035,6 +1709,17 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, break; } + + case DEBUG_S_SYMBOLS: + if (!parse_symbols (data + off, size, &symbufptr, map, num_types, + sym_rec_stream, glob, mod_num)) + { + free (data); + free (symbuf); + return false; + } + + break; } off += size; @@ -1045,22 +1730,42 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings, free (data); - if (*dataptr) + if (buf) { - /* Append the C13 info to what's already there, if the module has - multiple .debug$S sections. */ + if (*dataptr) + { + /* Append the C13 info to what's already there, if the module has + multiple .debug$S sections. */ - *dataptr = xrealloc (*dataptr, *sizeptr + c13_size); - memcpy (*dataptr + *sizeptr, buf, c13_size); + *dataptr = xrealloc (*dataptr, *sizeptr + c13_size); + memcpy (*dataptr + *sizeptr, buf, c13_size); - free (buf); + free (buf); + } + else + { + *dataptr = buf; + } + + *sizeptr += c13_size; } - else + + if (symbuf) { - *dataptr = buf; - } + if (*syms) + { + *syms = xrealloc (*syms, *sym_byte_size + sym_size); + memcpy (*syms + *sym_byte_size, symbuf, sym_size); + + free (symbuf); + } + else + { + *syms = symbuf; + } - *sizeptr += c13_size; + *sym_byte_size += sym_size; + } return true; } @@ -2279,12 +2984,11 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num, static bool handle_debugt_section (asection *s, bfd *mod, struct types *types, struct types *ids, uint16_t mod_num, - struct string_table *strings) + struct string_table *strings, + struct type_entry ***map, uint32_t *num_types) { bfd_byte *data = NULL; size_t off; - unsigned int num_types = 0; - struct type_entry **map; uint32_t type_num; if (!bfd_get_full_section_contents (mod, s, &data)) @@ -2315,17 +3019,17 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types, return false; } - num_types++; + (*num_types)++; off += size; } - if (num_types == 0) + if (*num_types == 0) { free (data); return true; } - map = xcalloc (num_types, sizeof (struct type_entry *)); + *map = xcalloc (*num_types, sizeof (struct type_entry *)); off = sizeof (uint32_t); type_num = 0; @@ -2336,11 +3040,11 @@ 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, ids, + if (!handle_type (data + off, *map, type_num, *num_types, types, ids, mod_num, strings)) { free (data); - free (map); + free (*map); bfd_set_error (bfd_error_bad_value); return false; } @@ -2350,7 +3054,6 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types, } free (data); - free (map); return true; } @@ -2363,39 +3066,57 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, uint32_t *c13_info_size, struct mod_source_files *mod_source, bfd *abfd, struct types *types, - struct types *ids, uint16_t mod_num) + struct types *ids, uint16_t mod_num, + bfd *sym_rec_stream, struct globals *glob) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; + uint8_t *syms = NULL; + struct type_entry **map = NULL; + uint32_t num_types = 0; - *sym_byte_size = sizeof (uint32_t); + *sym_byte_size = 0; *c13_info_size = 0; - /* Process .debug$S section(s). */ + /* Process .debug$T section. */ for (asection *s = mod->sections; s; s = s->next) { - if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) + if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) { - if (!handle_debugs_section (s, mod, strings, &c13_info, - c13_info_size, mod_source, abfd)) + if (!handle_debugt_section (s, mod, types, ids, mod_num, strings, + &map, &num_types)) { - free (c13_info); free (mod_source->files); return false; } + + break; } - else if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) + } + + /* Process .debug$S section(s). */ + + for (asection *s = mod->sections; s; s = s->next) + { + if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) { - if (!handle_debugt_section (s, mod, types, ids, mod_num, strings)) + if (!handle_debugs_section (s, mod, strings, &c13_info, + c13_info_size, mod_source, abfd, + &syms, sym_byte_size, map, num_types, + sym_rec_stream, glob, mod_num)) { free (c13_info); + free (syms); free (mod_source->files); + free (map); return false; } } } + free (map); + /* Write the signature. */ bfd_putl32 (CV_SIGNATURE_C13, int_buf); @@ -2403,9 +3124,22 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) { free (c13_info); + free (syms); return false; } + if (syms) + { + if (bfd_bwrite (syms, *sym_byte_size, stream) != *sym_byte_size) + { + free (c13_info); + free (syms); + return false; + } + + free (syms); + } + if (c13_info) { if (bfd_bwrite (c13_info, *c13_info_size, stream) != *c13_info_size) @@ -2432,7 +3166,8 @@ 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 *ids) + struct types *types, struct types *ids, + bfd *sym_rec_stream, struct globals *glob) { uint8_t *ptr; unsigned int mod_num; @@ -2521,7 +3256,8 @@ 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, ids, mod_num)) + types, ids, mod_num, + sym_rec_stream, glob)) { for (unsigned int i = 0; i < source->mod_count; i++) { @@ -2549,7 +3285,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, bfd_putl16 (0, &mod->flags); bfd_putl16 (stream_num, &mod->module_sym_stream); - bfd_putl32 (sym_byte_size, &mod->sym_byte_size); + bfd_putl32 (sizeof (uint32_t) + sym_byte_size, &mod->sym_byte_size); bfd_putl32 (0, &mod->c11_byte_size); bfd_putl32 (c13_info_size, &mod->c13_byte_size); bfd_putl16 (0, &mod->source_file_count); @@ -2837,6 +3573,170 @@ create_source_info_substream (void **data, uint32_t *size, } } +/* Used as parameter to qsort, to sort globals by hash. */ +static int +global_compare_hash (const void *s1, const void *s2) +{ + const struct global *g1 = *(const struct global **) s1; + const struct global *g2 = *(const struct global **) s2; + + if (g1->hash < g2->hash) + return -1; + if (g1->hash > g2->hash) + return 1; + + return 0; +} + +/* Create the globals stream, which contains the unmangled symbol names. */ +static bool +create_globals_stream (bfd *pdb, struct globals *glob, uint16_t *stream_num) +{ + bfd *stream; + struct globals_hash_header h; + uint32_t buckets_size, filled_buckets = 0; + struct global **sorted = NULL; + bool ret = false; + struct global *buckets[NUM_GLOBALS_HASH_BUCKETS]; + char int_buf[sizeof (uint32_t)]; + + stream = add_stream (pdb, NULL, stream_num); + if (!stream) + return false; + + memset (buckets, 0, sizeof (buckets)); + + if (glob->num_entries > 0) + { + struct global *g; + + /* Create an array of pointers, sorted by hash value. */ + + sorted = xmalloc (sizeof (struct global *) * glob->num_entries); + + g = glob->first; + for (unsigned int i = 0; i < glob->num_entries; i++) + { + sorted[i] = g; + g = g->next; + } + + qsort (sorted, glob->num_entries, sizeof (struct global *), + global_compare_hash); + + /* Populate the buckets. */ + + for (unsigned int i = 0; i < glob->num_entries; i++) + { + if (!buckets[sorted[i]->hash]) + { + buckets[sorted[i]->hash] = sorted[i]; + filled_buckets++; + } + + sorted[i]->index = i; + } + } + + buckets_size = NUM_GLOBALS_HASH_BUCKETS / 8; + buckets_size += sizeof (uint32_t); + buckets_size += filled_buckets * sizeof (uint32_t); + + bfd_putl32 (GLOBALS_HASH_SIGNATURE, &h.signature); + bfd_putl32 (GLOBALS_HASH_VERSION_70, &h.version); + bfd_putl32 (glob->num_entries * sizeof (struct hash_record), + &h.entries_size); + bfd_putl32 (buckets_size, &h.buckets_size); + + if (bfd_bwrite (&h, sizeof (h), stream) != sizeof (h)) + return false; + + /* Write hash entries, sorted by hash. */ + + for (unsigned int i = 0; i < glob->num_entries; i++) + { + struct hash_record hr; + + bfd_putl32 (sorted[i]->offset + 1, &hr.offset); + bfd_putl32 (sorted[i]->refcount, &hr.reference); + + if (bfd_bwrite (&hr, sizeof (hr), stream) != sizeof (hr)) + goto end; + } + + /* Write the bitmap for filled and unfilled buckets. */ + + for (unsigned int i = 0; i < NUM_GLOBALS_HASH_BUCKETS; i += 8) + { + uint8_t v = 0; + + for (unsigned int j = 0; j < 8; j++) + { + if (buckets[i + j]) + v |= 1 << j; + } + + if (bfd_bwrite (&v, sizeof (v), stream) != sizeof (v)) + goto end; + } + + /* Add a 4-byte gap. */ + + bfd_putl32 (0, int_buf); + + if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t)) + goto end; + + /* Write the bucket offsets. */ + + for (unsigned int i = 0; i < NUM_GLOBALS_HASH_BUCKETS; i++) + { + if (buckets[i]) + { + /* 0xc is size of internal hash_record structure in + Microsoft's parser. */ + bfd_putl32 (buckets[i]->index * 0xc, int_buf); + + if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != + sizeof (uint32_t)) + goto end; + } + } + + ret = true; + +end: + free (sorted); + + return ret; +} + +/* Hash an entry in the globals list. */ +static hashval_t +hash_global_entry (const void *p) +{ + const struct global *g = (const struct global *) p; + uint16_t len = bfd_getl16 (g->data); + + return iterative_hash (g->data, len, 0); +} + +/* Compare an entry in the globals list with a symbol. */ +static int +eq_global_entry (const void *a, const void *b) +{ + const struct global *g = (const struct global *) a; + uint16_t len1, len2; + + len1 = bfd_getl16 (g->data) + sizeof (uint16_t); + len2 = bfd_getl16 (b) + sizeof (uint16_t); + + if (len1 != len2) + return 0; + + return !memcmp (g->data, b, len1); +} + /* Stream 4 is the debug information (DBI) stream. */ static bool populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, @@ -2845,20 +3745,50 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, uint16_t publics_stream_num, struct string_table *strings, struct types *types, - struct types *ids) + struct types *ids, + bfd *sym_rec_stream) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; void *mod_info, *sc, *source_info; uint32_t mod_info_size, sc_size, source_info_size; struct source_files_info source; + struct globals glob; + uint16_t globals_stream_num; source.mod_count = 0; source.mods = NULL; + glob.num_entries = 0; + glob.first = NULL; + glob.last = NULL; + + glob.hashmap = htab_create_alloc (0, hash_global_entry, + eq_global_entry, free, xcalloc, free); + if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, - strings, &source, types, ids)) - return false; + strings, &source, types, ids, + sym_rec_stream, &glob)) + { + htab_delete (glob.hashmap); + return false; + } + + if (!create_globals_stream (pdb, &glob, &globals_stream_num)) + { + htab_delete (glob.hashmap); + + for (unsigned int i = 0; i < source.mod_count; i++) + { + free (source.mods[i].files); + } + free (source.mods); + + free (mod_info); + return false; + } + + htab_delete (glob.hashmap); if (!create_section_contrib_substream (abfd, &sc, &sc_size)) { @@ -2883,7 +3813,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, bfd_putl32 (0xffffffff, &h.version_signature); bfd_putl32 (DBI_STREAM_VERSION_70, &h.version_header); bfd_putl32 (1, &h.age); - bfd_putl16 (0xffff, &h.global_stream_index); + bfd_putl16 (globals_stream_num, &h.global_stream_index); bfd_putl16 (0x8e1d, &h.build_number); // MSVC 14.29 bfd_putl16 (publics_stream_num, &h.public_stream_index); bfd_putl16 (0, &h.pdb_dll_version); @@ -3530,7 +4460,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, &ids)) + &strings, &types, &ids, sym_rec_stream)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); diff --git a/ld/pdb.h b/ld/pdb.h index 668f3e168fd..9048b5fa37c 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -70,7 +70,21 @@ #define LF_QUADWORD 0x8009 #define LF_UQUADWORD 0x800a +#define S_END 0x0006 +#define S_CONSTANT 0x1107 +#define S_UDT 0x1108 +#define S_LDATA32 0x110c +#define S_GDATA32 0x110d #define S_PUB32 0x110e +#define S_LPROC32 0x110f +#define S_GPROC32 0x1110 +#define S_LTHREAD32 0x1112 +#define S_GTHREAD32 0x1113 +#define S_PROCREF 0x1125 +#define S_LPROCREF 0x1127 +#define S_LPROC32_ID 0x1146 +#define S_GPROC32_ID 0x1147 +#define S_PROC_ID_END 0x114f /* PDBStream70 in pdb1.h */ struct pdb_stream_70 @@ -109,6 +123,8 @@ struct pdb_tpi_stream_header #define TPI_FIRST_INDEX 0x1000 #define NUM_TPI_HASH_BUCKETS 0x3ffff +#define NUM_GLOBALS_HASH_BUCKETS 4096 + /* NewDBIHdr in dbi.h */ struct pdb_dbi_stream_header { @@ -198,6 +214,7 @@ struct optional_dbg_header #define CV_SIGNATURE_C13 4 +#define DEBUG_S_SYMBOLS 0xf1 #define DEBUG_S_LINES 0xf2 #define DEBUG_S_STRINGTABLE 0xf3 #define DEBUG_S_FILECHKSMS 0xf4 @@ -540,6 +557,66 @@ struct lf_udt_mod_src_line uint16_t module_no; } ATTRIBUTE_PACKED; +/* DATASYM32 in cvinfo.h */ +struct datasym +{ + uint16_t size; + uint16_t kind; + uint32_t type; + uint32_t offset; + uint16_t section; + char name[]; +} ATTRIBUTE_PACKED; + +/* PROCSYM32 in cvinfo.h */ +struct procsym +{ + uint16_t size; + uint16_t kind; + uint32_t parent; + uint32_t end; + uint32_t next; + uint32_t proc_len; + uint32_t debug_start; + uint32_t debug_end; + uint32_t type; + uint32_t offset; + uint16_t section; + uint8_t flags; + char name[]; +} ATTRIBUTE_PACKED; + +/* REFSYM2 in cvinfo.h */ +struct refsym +{ + uint16_t size; + uint16_t kind; + uint32_t sum_name; + uint32_t symbol_offset; + uint16_t mod; + char name[]; +} ATTRIBUTE_PACKED; + +/* UDTSYM in cvinfo.h */ +struct udtsym +{ + uint16_t size; + uint16_t kind; + uint32_t type; + char name[]; +} ATTRIBUTE_PACKED; + +/* CONSTSYM in cvinfo.h */ +struct constsym +{ + uint16_t size; + uint16_t kind; + uint32_t type; + uint16_t value; + /* then actual value if value >= 0x8000 */ + char name[]; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb-syms1-globals.d b/ld/testsuite/ld-pe/pdb-syms1-globals.d new file mode 100644 index 00000000000..356c5de22a3 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms1-globals.d @@ -0,0 +1,57 @@ + +*: file format binary + +Contents of section .data: + 0000 ffffffff 1a092ff1 d0000000 64020000 ....../.....d... + 0010 fd000000 01000000 35010000 01000000 ........5....... + 0020 15000000 01000000 19010000 01000000 ................ + 0030 c1000000 01000000 b9010000 01000000 ................ + 0040 d5000000 01000000 61010000 01000000 ........a....... + 0050 e9000000 01000000 11020000 01000000 ................ + 0060 e9010000 01000000 d5010000 01000000 ................ + 0070 49010000 01000000 a5010000 01000000 I............... + 0080 99010000 01000000 85000000 01000000 ................ + 0090 01000000 01000000 99000000 01000000 ................ + 00a0 7d010000 01000000 ad000000 01000000 }............... + 00b0 5d000000 01000000 49000000 01000000 ].......I....... + 00c0 21000000 02000000 35000000 01000000 !.......5....... + 00d0 fd010000 01000000 71000000 01000000 ........q....... + 00e0 00000000 00000000 00000000 00000000 ................ + 00f0 00000000 00000000 00000000 00000000 ................ + 0100 00000000 00000000 00000000 00000000 ................ + 0110 00000000 00000000 00000000 00000000 ................ + 0120 00000000 00000000 00000000 00000000 ................ + 0130 00000000 00000000 00000000 00000000 ................ + 0140 00000000 00000000 00000000 00000000 ................ + 0150 00000002 00000000 00000000 00000000 ................ + 0160 00000000 00000000 00000000 00000000 ................ + 0170 00000000 00020000 00000000 00000000 ................ + 0180 00000000 00000000 00000000 00000000 ................ + 0190 00000000 00000001 00000000 00000000 ................ + 01a0 00000000 00000000 00000000 00000000 ................ + 01b0 00000000 00000000 00000000 00000000 ................ + 01c0 00000000 00000000 00000000 00000000 ................ + 01d0 00000000 00000000 00000000 00000000 ................ + 01e0 08001000 00000000 00000000 00000040 ...............@ + 01f0 04002000 00000000 00000000 00000000 .. ............. + 0200 00000000 00000001 00000000 00000000 ................ + 0210 00000000 00000000 00000000 00000000 ................ + 0220 00000000 00000000 00000000 00000000 ................ + 0230 00000000 00000000 00080000 00004000 ..............@. + 0240 00000000 00000000 00100010 00000000 ................ + 0250 40000000 00000000 00000000 00000000 @............... + 0260 00000000 00000800 00000000 00000000 ................ + 0270 00000008 00000000 00000000 00000000 ................ + 0280 00000000 02004000 00000000 00000000 ......@......... + 0290 00000000 00008000 00000000 00000000 ................ + 02a0 00000000 00000000 10000000 00000000 ................ + 02b0 00000000 00000000 00000000 00800000 ................ + 02c0 00000000 00000000 00002000 00010000 .......... ..... + 02d0 00000000 00000000 00000000 00000040 ...............@ + 02e0 00000000 00000000 0c000000 18000000 ................ + 02f0 24000000 30000000 3c000000 48000000 $...0...<...H... + 0300 54000000 60000000 6c000000 78000000 T...`...l...x... + 0310 84000000 90000000 9c000000 a8000000 ................ + 0320 b4000000 c0000000 d8000000 e4000000 ................ + 0330 f0000000 fc000000 08010000 20010000 ............ ... + 0340 2c010000 ,... \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-syms1-records.d b/ld/testsuite/ld-pe/pdb-syms1-records.d new file mode 100644 index 00000000000..bbf6d7f158e --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms1-records.d @@ -0,0 +1,61 @@ + +*: file format binary + +Contents of section .data: + 0000 12002511 00000000 04000000 01007072 ..%...........pr + 0010 6f633200 0a000811 04100000 62617200 oc2.........bar. + 0020 12000c11 00100000 08000000 02006c76 ..............lv + 0030 61723100 12000c11 00100000 0c000000 ar1............. + 0040 02006c76 61723100 12000c11 00100000 ..lvar1......... + 0050 00000000 03006c76 61723200 12000d11 ......lvar2..... + 0060 00100000 18000000 02006776 61723100 ..........gvar1. + 0070 12000d11 00100000 04000000 03006776 ..............gv + 0080 61723200 12002511 00000000 54000000 ar2...%.....T... + 0090 02007072 6f633100 12002511 00000000 ..proc1...%..... + 00a0 88000000 02007072 6f633200 12002711 ......proc2...'. + 00b0 00000000 f0000000 02007072 6f633300 ..........proc3. + 00c0 12002711 00000000 24010000 02007072 ..'.....$.....pr + 00d0 6f633400 12002511 00000000 58010000 oc4...%.....X... + 00e0 02007072 6f633500 12002511 00000000 ..proc5...%..... + 00f0 8c010000 02007072 6f633600 1a002511 ......proc6...%. + 0100 00000000 c0010000 0200666f 6f3a3a6d ..........foo::m + 0110 6574686f 64000000 1a002511 00000000 ethod.....%..... + 0120 f8010000 0200666f 6f3a3a6d 6574686f ......foo::metho + 0130 64320000 12002711 00000000 30020000 d2....'.....0... + 0140 02007072 6f633900 16002511 00000000 ..proc9...%..... + 0150 64020000 02007072 6f633130 00000000 d.....proc10.... + 0160 1a002711 00000000 98020000 0200666f ..'...........fo + 0170 6f3a3a6d 6574686f 64330000 1a002711 o::method3....'. + 0180 00000000 d0020000 0200666f 6f3a3a6d ..........foo::m + 0190 6574686f 64340000 0a000811 0a100000 ethod4.......... + 01a0 666f6f00 12000711 75000000 2a00616e foo.....u...*.an + 01b0 73776572 00f3f2f1 1a000711 23000000 swer........#... + 01c0 0a80efcd ab896745 2301616e 73776572 ......gE#.answer + 01d0 3200f2f1 12001211 00100000 20000000 2........... ... + 01e0 02006c76 61723500 12001211 00100000 ..lvar5......... + 01f0 12000000 03006c76 61723600 12001311 ......lvar6..... + 0200 00100000 1c000000 02006776 61723300 ..........gvar3. + 0210 12001311 00100000 08000000 03006776 ..............gv + 0220 61723400 12000e11 00000000 18000000 ar4............. + 0230 02006776 61723100 12000e11 00000000 ..gvar1......... + 0240 04000000 03006776 61723200 12000e11 ......gvar2..... + 0250 00000000 0c000000 03007072 6f633100 ..........proc1. + 0260 12000e11 02000000 06000000 01007072 ..............pr + 0270 6f633200 12000e11 00000000 0d000000 oc2............. + 0280 03007072 6f633300 12000e11 02000000 ..proc3......... + 0290 07000000 01007072 6f633400 12000e11 ......proc4..... + 02a0 00000000 0e000000 03007072 6f633500 ..........proc5. + 02b0 12000e11 02000000 08000000 01007072 ..............pr + 02c0 6f633600 12000e11 00000000 0f000000 oc6............. + 02d0 03007072 6f633700 12000e11 02000000 ..proc7......... + 02e0 09000000 01007072 6f633800 12000e11 ......proc8..... + 02f0 00000000 10000000 03007072 6f633900 ..........proc9. + 0300 16000e11 02000000 0a000000 01007072 ..............pr + 0310 6f633130 00000000 16000e11 00000000 oc10............ + 0320 11000000 03007072 6f633131 00000000 ......proc11.... + 0330 16000e11 02000000 0b000000 01007072 ..............pr + 0340 6f633132 00000000 12000e11 00000000 oc12............ + 0350 1c000000 02006776 61723300 12000e11 ......gvar3..... + 0360 00000000 08000000 03006776 61723400 ..........gvar4. + 0370 12000e11 02000000 00000000 01006d61 ..............ma + 0380 696e0000 in.. \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-syms1-symbols1.d b/ld/testsuite/ld-pe/pdb-syms1-symbols1.d new file mode 100644 index 00000000000..4de22acbd08 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms1-symbols1.d @@ -0,0 +1,8 @@ + +*: file format binary + +Contents of section .data: + 0000 04000000 2e001011 00000000 34000000 ............4... + 0010 00000000 01000000 00000000 00000000 ................ + 0020 02100000 06000000 01000070 726f6332 ...........proc2 + 0030 00f3f2f1 02000600 00000000 ............ \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-syms1-symbols2.d b/ld/testsuite/ld-pe/pdb-syms1-symbols2.d new file mode 100644 index 00000000000..f134637a744 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms1-symbols2.d @@ -0,0 +1,56 @@ + +*: file format binary + +Contents of section .data: + 0000 04000000 12000c11 00100000 08000000 ................ + 0010 02006c76 61723100 12000c11 00100000 ..lvar1......... + 0020 08000000 02006c76 61723100 12000c11 ......lvar1..... + 0030 00100000 0c000000 02006c76 61723100 ..........lvar1. + 0040 12000c11 00100000 00000000 03006c76 ..............lv + 0050 61723200 2e001011 00000000 84000000 ar2............. + 0060 00000000 01000000 00000000 00000000 ................ + 0070 05100000 0c000000 03000070 726f6331 ...........proc1 + 0080 00f3f2f1 02000600 2e001011 00000000 ................ + 0090 ec000000 00000000 01000000 00000000 ................ + 00a0 00000000 05100000 06000000 01000070 ...............p + 00b0 726f6332 00f3f2f1 0a000811 04100000 roc2............ + 00c0 62617200 12000c11 00100000 10000000 bar............. + 00d0 02006c76 61723300 12001211 00100000 ..lvar3......... + 00e0 14000000 02006c76 61723400 02000600 ......lvar4..... + 00f0 2e000f11 00000000 20010000 00000000 ........ ....... + 0100 01000000 00000000 00000000 05100000 ................ + 0110 0d000000 03000070 726f6333 00f3f2f1 .......proc3.... + 0120 02000600 2e000f11 00000000 54010000 ............T... + 0130 00000000 01000000 00000000 00000000 ................ + 0140 05100000 07000000 01000070 726f6334 ...........proc4 + 0150 00f3f2f1 02000600 2e001011 00000000 ................ + 0160 88010000 00000000 01000000 00000000 ................ + 0170 00000000 05100000 0e000000 03000070 ...............p + 0180 726f6335 00f3f2f1 02000600 2e001011 roc5............ + 0190 00000000 bc010000 00000000 01000000 ................ + 01a0 00000000 00000000 05100000 08000000 ................ + 01b0 01000070 726f6336 00f3f2f1 02000600 ...proc6........ + 01c0 32001011 00000000 f4010000 00000000 2............... + 01d0 01000000 00000000 00000000 05100000 ................ + 01e0 0f000000 03000066 6f6f3a3a 6d657468 .......foo::meth + 01f0 6f6400f1 02000600 32001011 00000000 od......2....... + 0200 2c020000 00000000 01000000 00000000 ,............... + 0210 00000000 05100000 09000000 01000066 ...............f + 0220 6f6f3a3a 6d657468 6f643200 02000600 oo::method2..... + 0230 2e000f11 00000000 60020000 00000000 ........`....... + 0240 01000000 00000000 00000000 05100000 ................ + 0250 10000000 03000070 726f6339 00f3f2f1 .......proc9.... + 0260 02000600 2e001011 00000000 94020000 ................ + 0270 00000000 01000000 00000000 00000000 ................ + 0280 05100000 0a000000 01000070 726f6331 ...........proc1 + 0290 3000f2f1 02000600 32000f11 00000000 0.......2....... + 02a0 cc020000 00000000 01000000 00000000 ................ + 02b0 00000000 05100000 11000000 03000066 ...............f + 02c0 6f6f3a3a 6d657468 6f643300 02000600 oo::method3..... + 02d0 32000f11 00000000 04030000 00000000 2............... + 02e0 01000000 00000000 00000000 05100000 ................ + 02f0 0b000000 01000066 6f6f3a3a 6d657468 .......foo::meth + 0300 6f643400 02000600 12001211 00100000 od4............. + 0310 20000000 02006c76 61723500 12001211 .....lvar5..... + 0320 00100000 12000000 03006c76 61723600 ..........lvar6. + 0330 00000000 .... \ No newline at end of file diff --git a/ld/testsuite/ld-pe/pdb-syms1a.s b/ld/testsuite/ld-pe/pdb-syms1a.s new file mode 100644 index 00000000000..c1929c3ec85 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms1a.s @@ -0,0 +1,110 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_SYMBOLS, 0xf1 + +.equ T_UINT4, 0x0075 + +.equ LF_MODIFIER, 0x1001 +.equ LF_PROCEDURE, 0x1008 +.equ LF_ARGLIST, 0x1201 +.equ LF_FIELDLIST, 0x1203 +.equ LF_STRUCTURE, 0x1505 +.equ LF_MEMBER, 0x150d + +.equ S_END, 0x0006 +.equ S_UDT, 0x1108 +.equ S_GPROC32, 0x1110 + +.section ".debug$S", "rn" + +.long CV_SIGNATURE_C13 + +.long DEBUG_S_SYMBOLS +.long .syms_end - .syms_start + +.syms_start: + +.gproc2: +.short .gproc2_end - .gproc2 - 2 +.short S_GPROC32 +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long 1 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1002 # type +.secrel32 proc2 +.secidx proc2 +.byte 0 # flags +.asciz "proc2" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc2_end: +.short .udt1 - .gproc2_end - 2 +.short S_END + +.udt1: +.short .syms_end - .udt1 - 2 +.short S_UDT +.long 0x1004 # struct bar +.asciz "bar" + +.syms_end: + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, const uint32_t +.mod1: +.short .arglist1 - .mod1 - 2 +.short LF_MODIFIER +.long T_UINT4 +.short 1 # const +.p2align 2 + +# Type 1001, arglist (uint32_t) +.arglist1: +.short .proctype1 - .arglist1 - 2 +.short LF_ARGLIST +.long 1 # no. entries +.long T_UINT4 + +# Type 1002, procedure (return type T_VOID, arglist 1001) +.proctype1: +.short .fieldlist1 - .proctype1 - 2 +.short LF_PROCEDURE +.long T_VOID +.byte 0 # calling convention +.byte 0 # attributes +.short 1 # no. parameters +.long 0x1001 + +# Type 1003, field list for struct bar +.fieldlist1: +.short .struct1 - .fieldlist1 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long T_UINT4 +.short 0 # offset +.asciz "num1" +.byte 0xf1 # padding + +# Type 1004, declaration of struct bar +.struct1: +.short .types_end - .struct1 - 2 +.short LF_STRUCTURE +.short 1 # no. members +.short 0 # property +.long 0x1003 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "bar" # name +.byte 0xf2 # padding +.byte 0xf1 # padding + +.types_end: diff --git a/ld/testsuite/ld-pe/pdb-syms1b.s b/ld/testsuite/ld-pe/pdb-syms1b.s new file mode 100644 index 00000000000..ddc471104b5 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb-syms1b.s @@ -0,0 +1,737 @@ +.equ CV_SIGNATURE_C13, 4 +.equ DEBUG_S_SYMBOLS, 0xf1 + +.equ T_VOID, 0x0003 +.equ T_UQUAD, 0x0023 +.equ T_UINT4, 0x0075 + +.equ LF_MODIFIER, 0x1001 +.equ LF_POINTER, 0x1002 +.equ LF_PROCEDURE, 0x1008 +.equ LF_MFUNCTION, 0x1009 +.equ LF_ARGLIST, 0x1201 +.equ LF_FIELDLIST, 0x1203 +.equ LF_CLASS, 0x1504 +.equ LF_STRUCTURE, 0x1505 +.equ LF_MEMBER, 0x150d +.equ LF_ONEMETHOD, 0x1511 +.equ LF_FUNC_ID, 0x1601 +.equ LF_MFUNC_ID, 0x1602 + +.equ LF_UQUADWORD, 0x800a + +.equ S_END, 0x0006 +.equ S_CONSTANT, 0x1107 +.equ S_UDT, 0x1108 +.equ S_LDATA32, 0x110c +.equ S_GDATA32, 0x110d +.equ S_LPROC32, 0x110f +.equ S_GPROC32, 0x1110 +.equ S_LTHREAD32, 0x1112 +.equ S_GTHREAD32, 0x1113 +.equ S_LPROC32_ID, 0x1146 +.equ S_GPROC32_ID, 0x1147 +.equ S_PROC_ID_END, 0x114f + +.equ CV_PTR_64, 0xc + +.section ".debug$S", "rn" + +.long CV_SIGNATURE_C13 + +.long DEBUG_S_SYMBOLS +.long .syms_end - .syms_start + +.syms_start: + +.ldata1: +.short .ldata1a - .ldata1 - 2 +.short S_LDATA32 +.long 0x1000 # const uint32_t +.secrel32 lvar1 +.secidx lvar1 +.asciz "lvar1" + +.ldata1a: # duplicate with same address +.short .ldata1b - .ldata1a - 2 +.short S_LDATA32 +.long 0x1000 # const uint32_t +.secrel32 lvar1 +.secidx lvar1 +.asciz "lvar1" + +.ldata1b: # duplicate with different address +.short .ldata2 - .ldata1b - 2 +.short S_LDATA32 +.long 0x1000 # const uint32_t +.secrel32 lvar1a +.secidx lvar1a +.asciz "lvar1" + +.ldata2: +.short .gdata1 - .ldata2 - 2 +.short S_LDATA32 +.long 0x1000 # const uint32_t +.secrel32 lvar2 +.secidx lvar2 +.asciz "lvar2" + +.gdata1: +.short .gdata2 - .gdata1 - 2 +.short S_GDATA32 +.long 0x1000 # const uint32_t +.secrel32 gvar1 +.secidx gvar1 +.asciz "gvar1" + +.gdata2: +.short .gproc1 - .gdata2 - 2 +.short S_GDATA32 +.long 0x1000 # const uint32_t +.secrel32 gvar2 +.secidx gvar2 +.asciz "gvar2" + +.gproc1: +.short .gproc1_end - .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 0x1002 # type +.secrel32 proc1 +.secidx proc1 +.byte 0 # flags +.asciz "proc1" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc1_end: +.short .gproc2 - .gproc1_end - 2 +.short S_END + +.gproc2: +.short .udt1 - .gproc2 - 2 +.short S_GPROC32 +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc2_end - proc2 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1002 # type +.secrel32 proc2 +.secidx proc2 +.byte 0 # flags +.asciz "proc2" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.udt1: +.short .ldata3 - .udt1 - 2 +.short S_UDT +.long 0x1011 # struct bar +.asciz "bar" + +.ldata3: +.short .lthread1 - .ldata3 - 2 +.short S_LDATA32 +.long 0x1000 # const uint32_t +.secrel32 lvar3 +.secidx lvar3 +.asciz "lvar3" + +.lthread1: +.short .gproc2_end - .lthread1 - 2 +.short S_LTHREAD32 +.long 0x1000 # const uint32_t +.secrel32 lvar4 +.secidx lvar4 +.asciz "lvar4" + +.gproc2_end: +.short .gproc3 - .gproc2_end - 2 +.short S_END + +.gproc3: +.short .gproc3_end - .gproc3 - 2 +.short S_LPROC32 +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc3_end - proc3 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1002 # type +.secrel32 proc3 +.secidx proc3 +.byte 0 # flags +.asciz "proc3" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc3_end: +.short .gproc4 - .gproc3_end - 2 +.short S_END + +.gproc4: +.short .gproc4_end - .gproc4 - 2 +.short S_LPROC32 +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc4_end - proc4 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1002 # type +.secrel32 proc4 +.secidx proc4 +.byte 0 # flags +.asciz "proc4" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc4_end: +.short .gproc5 - .gproc4_end - 2 +.short S_END + +.gproc5: +.short .gproc5_end - .gproc5 - 2 +.short S_GPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc5_end - proc5 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1003 # func ID +.secrel32 proc5 +.secidx proc5 +.byte 0 # flags +.asciz "proc5" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc5_end: +.short .gproc6 - .gproc5_end - 2 +.short S_PROC_ID_END + +.gproc6: +.short .gproc6_end - .gproc6 - 2 +.short S_GPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc6_end - proc6 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x1004 # func ID +.secrel32 proc6 +.secidx proc6 +.byte 0 # flags +.asciz "proc6" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc6_end: +.short .gproc7 - .gproc6_end - 2 +.short S_PROC_ID_END + +.gproc7: +.short .gproc7_end - .gproc7 - 2 +.short S_GPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc7_end - proc7 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x100a # func ID +.secrel32 proc7 +.secidx proc7 +.byte 0 # flags +.asciz "foo::method" +.byte 0xf1 # padding + +.gproc7_end: +.short .gproc8 - .gproc7_end - 2 +.short S_PROC_ID_END + +.gproc8: +.short .gproc8_end - .gproc8 - 2 +.short S_GPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc8_end - proc8 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x100b # func ID +.secrel32 proc8 +.secidx proc8 +.byte 0 # flags +.asciz "foo::method2" + +.gproc8_end: +.short .gproc9 - .gproc8_end - 2 +.short S_PROC_ID_END + +.gproc9: +.short .gproc9_end - .gproc9 - 2 +.short S_LPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc9_end - proc9 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x100c # func ID +.secrel32 proc9 +.secidx proc9 +.byte 0 # flags +.asciz "proc9" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc9_end: +.short .gproc10 - .gproc9_end - 2 +.short S_PROC_ID_END + +.gproc10: +.short .gproc10_end - .gproc10 - 2 +.short S_GPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc10_end - proc10 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x100d # func ID +.secrel32 proc10 +.secidx proc10 +.byte 0 # flags +.asciz "proc10" +.byte 0xf2 # padding +.byte 0xf1 # padding + +.gproc10_end: +.short .gproc11 - .gproc10_end - 2 +.short S_PROC_ID_END + +.gproc11: +.short .gproc11_end - .gproc11 - 2 +.short S_LPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc11_end - proc11 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x100e # func ID +.secrel32 proc11 +.secidx proc11 +.byte 0 # flags +.asciz "foo::method3" + +.gproc11_end: +.short .gproc12 - .gproc11_end - 2 +.short S_PROC_ID_END + +.gproc12: +.short .gproc12_end - .gproc12 - 2 +.short S_LPROC32_ID +.long 0 # parent +.long 0 # end +.long 0 # next symbol +.long .proc12_end - proc12 # length +.long 0 # debug start offset +.long 0 # debug end offset +.long 0x100f # func ID +.secrel32 proc12 +.secidx proc12 +.byte 0 # flags +.asciz "foo::method4" + +.gproc12_end: +.short .udt2 - .gproc12_end - 2 +.short S_PROC_ID_END + +.udt2: +.short .constant1 - .udt2 - 2 +.short S_UDT +.long 0x1009 # class foo +.asciz "foo" + +.constant1: +.short .constant2 - .constant1 - 2 +.short S_CONSTANT +.long T_UINT4 +.short 42 +.asciz "answer" +.byte 0xf3 # padding +.byte 0xf2 # padding +.byte 0xf1 # padding + +.constant2: +.short .lthread2 - .constant2 - 2 +.short S_CONSTANT +.long T_UQUAD +.short LF_UQUADWORD +.quad 0x0123456789abcdef +.asciz "answer2" +.byte 0xf2 # padding +.byte 0xf1 # padding + +.lthread2: +.short .lthread3 - .lthread2 - 2 +.short S_LTHREAD32 +.long 0x1000 # const uint32_t +.secrel32 lvar5 +.secidx lvar5 +.asciz "lvar5" + +.lthread3: +.short .gthread1 - .lthread3 - 2 +.short S_LTHREAD32 +.long 0x1000 # const uint32_t +.secrel32 lvar6 +.secidx lvar6 +.asciz "lvar6" + +.gthread1: +.short .gthread2 - .gthread1 - 2 +.short S_GTHREAD32 +.long 0x1000 # const uint32_t +.secrel32 gvar3 +.secidx gvar3 +.asciz "gvar3" + +.gthread2: +.short .syms_end - .gthread2 - 2 +.short S_GTHREAD32 +.long 0x1000 # const uint32_t +.secrel32 gvar4 +.secidx gvar4 +.asciz "gvar4" + +.p2align 2 +.syms_end: + +.section ".debug$T", "rn" + +.long CV_SIGNATURE_C13 + +# Type 1000, const uint32_t +.mod1: +.short .arglist1 - .mod1 - 2 +.short LF_MODIFIER +.long T_UINT4 +.short 1 # const +.p2align 2 + +# Type 1001, arglist (uint32_t) +.arglist1: +.short .proctype1 - .arglist1 - 2 +.short LF_ARGLIST +.long 1 # no. entries +.long T_UINT4 + +# Type 1002, procedure (return type T_VOID, arglist 1001) +.proctype1: +.short .funcid1 - .proctype1 - 2 +.short LF_PROCEDURE +.long T_VOID +.byte 0 # calling convention +.byte 0 # attributes +.short 1 # no. parameters +.long 0x1001 + +# Type 1003, func ID for proc5 +.funcid1: +.short .funcid2 - .funcid1 - 2 +.short LF_FUNC_ID +.long 0 # parent scope +.long 0x1002 # type +.asciz "proc5" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1004, func ID for proc6 +.funcid2: +.short .class1 - .funcid2 - 2 +.short LF_FUNC_ID +.long 0 # parent scope +.long 0x1002 # type +.asciz "proc6" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 1005, forward declaration of class foo +.class1: +.short .ptr1 - .class1 - 2 +.short LF_CLASS +.short 0 # no. members +.short 0x80 # property (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 1006, pointer to 1005 +.ptr1: +.short .mfunction1 - .ptr1 - 2 +.short LF_POINTER +.long 0x1005 +.long (8 << 13) | CV_PTR_64 + +# Type 1007, member function of 1005, return type void, arg list 1001 +.mfunction1: +.short .fieldlist1 - .mfunction1 - 2 +.short LF_MFUNCTION +.long T_VOID +.long 0x1005 +.long 0x1006 # type of "this" pointer +.byte 0 # calling convention +.byte 0 # attributes +.short 1 # no. parameters +.long 0x1001 # arg list +.long 0 # "this" adjustment + +# Type 1008, field list for class foo +.fieldlist1: +.short .class2 - .fieldlist1 - 2 +.short LF_FIELDLIST +.short LF_ONEMETHOD +.short 0 # method attribute +.long 0x1007 # method type +.asciz "method" +.byte 0xf1 # padding +.short LF_ONEMETHOD +.short 0 # method attribute +.long 0x1007 # method type +.asciz "method2" +.short LF_ONEMETHOD +.short 0 # method attribute +.long 0x1007 # method type +.asciz "method3" +.short LF_ONEMETHOD +.short 0 # method attribute +.long 0x1007 # method type +.asciz "method4" + +# Type 1009, actual declaration of class foo +.class2: +.short .mfunc1 - .class2 - 2 +.short LF_CLASS +.short 0 # no. members +.short 0 # property +.long 0x1008 # 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 100a, function "method" within class "foo" +.mfunc1: +.short .mfunc2 - .mfunc1 - 2 +.short LF_MFUNC_ID +.long 0x1009 # parent class +.long 0x1002 # function type +.asciz "method" +.byte 0xf1 # padding + +# Type 100b, function "method2" within class "foo" +.mfunc2: +.short .funcid3 - .mfunc2 - 2 +.short LF_MFUNC_ID +.long 0x1009 # parent class +.long 0x1002 # function type +.asciz "method2" + +# Type 100c, func ID for proc9 +.funcid3: +.short .funcid4 - .funcid3 - 2 +.short LF_FUNC_ID +.long 0 # parent scope +.long 0x1002 # type +.asciz "proc9" +.byte 0xf2 # padding +.byte 0xf1 # padding + +# Type 100d, func ID for proc10 +.funcid4: +.short .mfunc3 - .funcid4 - 2 +.short LF_FUNC_ID +.long 0 # parent scope +.long 0x1002 # type +.asciz "proc10" +.byte 0xf1 # padding + +# Type 100e, function "method3" within class "foo" +.mfunc3: +.short .mfunc4 - .mfunc3 - 2 +.short LF_MFUNC_ID +.long 0x1009 # parent class +.long 0x1002 # function type +.asciz "method3" + +# Type 100f, function "method4" within class "foo" +.mfunc4: +.short .fieldlist2 - .mfunc4 - 2 +.short LF_MFUNC_ID +.long 0x1009 # parent class +.long 0x1002 # function type +.asciz "method4" + +# Type 1010, field list for struct bar +.fieldlist2: +.short .struct1 - .fieldlist2 - 2 +.short LF_FIELDLIST +.short LF_MEMBER +.short 3 # public +.long T_UINT4 +.short 0 # offset +.asciz "num1" +.byte 0xf1 # padding + +# Type 1011, declaration of struct bar +.struct1: +.short .types_end - .struct1 - 2 +.short LF_STRUCTURE +.short 1 # no. members +.short 0 # property +.long 0x1010 # field list +.long 0 # type derived from +.long 0 # type of vshape table +.short 4 # size +.asciz "bar" # name +.byte 0xf2 # padding +.byte 0xf1 # padding + +.types_end: + +.data + +.long 0x12345678 +.long 0x12345678 + +lvar1: +.long 42 + +lvar1a: +.long 0x12345678 + +lvar3: +.long 84 + +lvar4: +.long 85 + +.global gvar1 +gvar1: +.long 43 + +.global gvar3 +gvar3: +.long 41 + +lvar5: +.long 86 + +.text + +.global main +main: + jmp main + .secrel32 .data + +.global proc2 +proc2: + nop +.proc2_end: + +.global proc4 +proc4: + nop +.proc4_end: + +.global proc6 +proc6: + nop +.proc6_end: + +.global proc8 +proc8: + nop +.proc8_end: + +.global proc10 +proc10: + nop +.proc10_end: + +.global proc12 +proc12: + nop +.proc12_end: + +.section "gcsect" + +lvar2: +.long 84 + +.global gvar2 +gvar2: +.long 85 + +.global gvar4 +gvar4: +.long 86 + +.global proc1 +proc1: + nop +.proc1_end: + +.global proc3 +proc3: + nop +.proc3_end: + +.global proc5 +proc5: + nop +.proc5_end: + +.global proc7 +proc7: + nop +.proc7_end: + +.global proc9 +proc9: + nop +.proc9_end: + +.global proc11 +proc11: + nop +.proc11_end: + +lvar6: +.long 86 diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 1a5416890d1..34eafc142a7 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1451,6 +1451,169 @@ proc test7 { } { } } +proc test8 { } { + global as + global ar + global ld + global objdump + global srcdir + global subdir + + if ![ld_assemble $as $srcdir/$subdir/pdb-syms1a.s tmpdir/pdb-syms1a.o] { + unsupported "Build pdb-syms1a.o" + return + } + + if ![ld_assemble $as $srcdir/$subdir/pdb-syms1b.s tmpdir/pdb-syms1b.o] { + unsupported "Build pdb-syms1b.o" + return + } + + if ![ld_link $ld "tmpdir/pdb-syms1.exe" "--pdb=tmpdir/pdb-syms1.pdb tmpdir/pdb-syms1a.o tmpdir/pdb-syms1b.o"] { + unsupported "Create PE image with PDB file" + return + } + + # get index of globals stream and records stream + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.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 12 + set data [read $fi 2] + binary scan $data s globals_index + + seek $fi 6 current + set data [read $fi 2] + binary scan $data s records_index + + seek $fi 2 current + 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 + + # get index of first and second module streams + + binary scan [string range $mod_info 34 35] s mod1_index + + set off 64 + + set obj1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]] + incr off [expr [string length $obj1] + 1] + + set ar1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]] + incr off [expr [string length $ar1] + 1] + + if { [expr $off % 4] != 0 } { + set off [expr $off + 4 - ($off % 4)] + } + + incr off 34 + + binary scan [string range $mod_info $off [expr $off + 1]] s mod2_index + + # check globals stream + + set index_str [format "%04x" $globals_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract globals stream" + return + } else { + pass "Extracted globals stream" + } + + set exp [file_contents "$srcdir/$subdir/pdb-syms1-globals.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"] + + if [string match $exp $got] { + pass "Correct globals stream" + } else { + fail "Incorrect globals stream" + } + + # check records stream + + set index_str [format "%04x" $records_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract records stream" + return + } else { + pass "Extracted records stream" + } + + set exp [file_contents "$srcdir/$subdir/pdb-syms1-records.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"] + + if [string match $exp $got] { + pass "Correct records stream" + } else { + fail "Incorrect records stream" + } + + # check symbols in first module + + set index_str [format "%04x" $mod1_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract first module's symbols" + return + } else { + pass "Extracted first module's symbols" + } + + set exp [file_contents "$srcdir/$subdir/pdb-syms1-symbols1.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"] + + if [string match $exp $got] { + pass "Correct symbols in first module's stream" + } else { + fail "Incorrect symbols in first module's stream" + } + + # check symbols in second module + + set index_str [format "%04x" $mod2_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms1.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract second module's symbols" + return + } else { + pass "Extracted second module's symbols" + } + + set exp [file_contents "$srcdir/$subdir/pdb-syms1-symbols2.d"] + set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"] + + if [string match $exp $got] { + pass "Correct symbols in second module's stream" + } else { + fail "Incorrect symbols in second module's stream" + } +} + test1 test2 test3 @@ -1458,3 +1621,4 @@ test4 test5 test6 test7 +test8 From patchwork Fri Dec 9 01:52:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31582 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp529343wrr; Thu, 8 Dec 2022 17:56:20 -0800 (PST) X-Google-Smtp-Source: AA0mqf5VKkUc5j8kVznhjTMIigK3/wqVpQWXIXnzHwo5zFzJWYArTLrAbBGpwnGDCPikEWWAv7jR X-Received: by 2002:a17:906:3008:b0:7b5:73aa:9984 with SMTP id 8-20020a170906300800b007b573aa9984mr3427585ejz.14.1670550980119; Thu, 08 Dec 2022 17:56:20 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670550980; cv=none; d=google.com; s=arc-20160816; b=0JCrpkEuCpb3hMN1xNiLxnph0qSwTtdvvLHl1+RrhEmnPq3JKeXtz5gSU6cPKHor9i qLQqZsZd8rBmSWfsqB5RL47C6fjZVGkWw8WMHqRSrbpbH/MeO2WgTjxRi2pqdohn7Jxm O9j6a12ZSp/pLpFnuwyiYvRaJQeoU1qiGlI+LT2X+8hDuesbMZPtyDfloSy8C2qOaVI7 /6MWNS2ic4sUE6aGekD2zRPf1Qu+H3atf6QMrf5cAlRu07DHbh6lUcR/U64lNUXspFPD SPu+mQDsiCP8cVABwOqBXNNyh2QMPWn3xxd4P+GP9rCKmyFMD/wC2W/Hu/+IUzQ3HLl5 kfoA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=bPbNgrbAqJnaThsadarWksORuR/KhWX30n5A+DWoMu4=; b=j9RXmUsWWgp7e4ioaBET4RMsUN7xW7ilMUG+vs3usBw5Lq9OY1bl59TpLqnrtI4lo4 YiNc5Qzw+7Of/20WWi2/6ztoWgQ7OsRVzkSmrBKoJ+C4H+Hti2xtGaasP7lmJQqOhJrn wVrkdkZnuwcAk1xcBhUHIq7lkLQvXqOydSd66BSM9Lk03veIUttWD9NZV5ZoHvciE0mZ zZYkhiKpUbPQNpkJxywC8lThz6m7uLw5iR/3866HK2e0I32A6PkQWFYzFjLfFSN/8CWd qXMr1Y552P+qEsF2h6wcNBq/ZfunKJQ1bd9twltbALGG9cHDW27KNFRMoWq/fqYq7W8l hL1w== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=i+dUk8Fg; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id ho36-20020a1709070ea400b007ae5ccae236si141545ejc.90.2022.12.08.17.56.19 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:56:20 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=i+dUk8Fg; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ED759389C03C for ; Fri, 9 Dec 2022 01:54:28 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by sourceware.org (Postfix) with ESMTPS id 4D4F03886C40 for ; Fri, 9 Dec 2022 01:52:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4D4F03886C40 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-wm1-x336.google.com with SMTP id f13-20020a1cc90d000000b003d08c4cf679so2401234wmb.5 for ; Thu, 08 Dec 2022 17:52:53 -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=bPbNgrbAqJnaThsadarWksORuR/KhWX30n5A+DWoMu4=; b=i+dUk8FgWcdyEbo3BMeN50/HpNvORGdrsg3DU0E8gMus/kjMdOjIabCCuPOzLSqpus CbDr64ermeBNTxFXIu97/Ex5ODkpo7OOGo0QaA1zx38vY2cwktCw/1ApMdF1jeoprAaP EqYHWvB9pzz6Ee70rPzvaTel2JHOBQO95Zp4/8GBEESiU+pvTrtUYwfHxeDv5OOK4T/9 WeqcZSks0AITXkUaMkQiahVSdtwj5QR7JjD2PTARji+GnlVvXfGj9vTjaqgfzooqi9o/ pIH5gNR2xGwgDxnaKQw2WMGN05+FLph52K5JBqzoIyVQka4mEJUuwsuO5GTM1Qso0utJ Zblg== 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=bPbNgrbAqJnaThsadarWksORuR/KhWX30n5A+DWoMu4=; b=v2AqUaNbCfIq105iYc3JTmfUSmYIaWm7piK5KzNO2nWMp1HGstXjw7CCCbgunLjZV1 QfB+MQEGFxjO8OHZp3ANQnzjT9dj6ueqVNAGHejLXUi0WWs9kLL76QUp2wix48xUmfYi UmVq/BtoIQTi5WmTuqqxfoCkeNEos9GA9CSk5spmpIXb3WkXC+zISrWL1YWsmEdlfkGR 1v6cXcSeuV2alhgyt6mRK24wB6bKk3lMdMYR4dqAI+KtYGpDcUzLWG5l/SzUuGX2Vldo iB3YbS4oJwPtGbfu5vXZzZFPzfl2WTqThcf7/3kn63Er++ura4p4JNP8pZ4GNw0O6C9p k3Iw== X-Gm-Message-State: ANoB5pnp02pyRbgvJhHZdQowIwJ4MAI5jcFEzhi8KrVTOj3m4TO75XVV z7NFaXeSfnkuHT+YgeoyVDIdbPELirA= X-Received: by 2002:a05:600c:4f93:b0:3cf:6e85:eda7 with SMTP id n19-20020a05600c4f9300b003cf6e85eda7mr3326351wmq.14.1670550772225; Thu, 08 Dec 2022 17:52:52 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:51 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 09/10] ld: Copy other symbols into PDB file Date: Fri, 9 Dec 2022 01:52:39 +0000 Message-Id: <20221209015240.6348-9-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.2 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, UNWANTED_LANGUAGE_BODY autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699664671145590?= X-GMAIL-MSGID: =?utf-8?q?1751699664671145590?= --- 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 5257cda2e25..09377a02e52 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -907,11 +907,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) @@ -960,6 +964,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)) { @@ -1205,6 +1210,8 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf, free (ref); + scope = *buf; + memcpy (*buf, proc, len); *buf += len; @@ -1320,16 +1327,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); @@ -1440,12 +1774,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 From patchwork Fri Dec 9 01:52:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 31592 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp530216wrr; Thu, 8 Dec 2022 17:59:21 -0800 (PST) X-Google-Smtp-Source: AA0mqf6YEC7Zd8SsESf4yfUP9z6LqHVJyLch6WK4/vZQpk6cJWmas3M58V/7wt16bY1gv7FM7AwC X-Received: by 2002:a17:906:fb13:b0:7c1:ed:171c with SMTP id lz19-20020a170906fb1300b007c100ed171cmr3343663ejb.26.1670551161348; Thu, 08 Dec 2022 17:59:21 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670551161; cv=none; d=google.com; s=arc-20160816; b=TqCYjtceFRN7AkfWNnI8Q0ZgvMHow5rKBWhmktl9t4vZ36ktcAa4HijFQo/gym2Yz/ 4+z6aPLN4Af7Oy5q/6NIVFUnmZOG5dYufI4lDmKeB5J7DtHoy0fB4KIP3ekV1Xj3BbP6 VERyRS6z1qBNHBd6X1EctEm4nciu3+rmyHwKAMZeADDTTVUSbws3egcd0+8RyATvTqy5 jVb7K2E2P/C2XT2bYcH3B7CkCs4TPepKqpT1ZczWq9Qqp2nXvJbC8CfSj3ChbKZCGPdn ilkiTrR16q25UBwRonQ+6sPF+qQef+d7ttm8RaTXRleaS9cPO9unV28FxB6TLEl91pd9 xkIA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=6bLTlEnzoBB6Y2IxVoFyaTNZ1FQt835ExMAmY7MwfX0=; b=S9nSabq5Bx8seVwe7OVNpGAn/1/LLoj+LFRuL5oGHw3+hLAjgDmW0LatGpIwMr/Y2y 4UdCOc5TKFUI7GPDeaPprPeirCT/i91Qr7XrzvBZY00MaOmCsVslEv2H642QnajyjHWs l2VjlekyiAMaK3+nYSPXIhZWHdv2PdLUtLcqrEsHsbMygOgcbZooCPmJzuTEtc25kc5L oqd0mHCaeUrnQnaN3gIQjipsUGFcYOwtflNrQLidklgmuEeaJlLbvSNsf21FHXHs4Y4V H9XE3KEziI31HJ9++9wkHGB9o36WYbUwVjMCR4LHiPrRcTpn49BZaqbL3By8sui3IdvN /T5w== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=lXiFvO+5; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id oq19-20020a170906cc9300b007c0d428795dsi77219ejb.191.2022.12.08.17.59.21 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:59:21 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=lXiFvO+5; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4B9C73AA901F for ; Fri, 9 Dec 2022 01:55:17 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by sourceware.org (Postfix) with ESMTPS id 273C1388C5D6 for ; Fri, 9 Dec 2022 01:52:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 273C1388C5D6 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-wm1-x32c.google.com with SMTP id ay40so2567651wmb.2 for ; Thu, 08 Dec 2022 17:52:54 -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=6bLTlEnzoBB6Y2IxVoFyaTNZ1FQt835ExMAmY7MwfX0=; b=lXiFvO+5bG/wtiWiwkkUQw3zadi+Pc0IqQP2cvRQYW+d8PGY0V1VuTatr10ZTMoR3C jOoWp21OFrn5vPsAB7AZWTo9wVzzqvJMNO1YZm6wCM5HDwCXdHiZOjqZCvrCkmvV0ELy QV7vVCqCpjkd+aTf+SBlvsvgmWGcFraM8VobfecB/mahk9ijlIEAM6SN2FIBuHTcbpun 7dSvPO76emCbkarXTIpJR22GiKPn5uOOu2GxUeLD1BMOalANIC73VoVCJxfqQ32kmZqk oCSFaXAOuQ6JfPSIXo0q+jESjNoM+p2egM7UXQj6a0NQl/O1c6dGgHcBDWJUTaqpQ8pM uNWw== 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=6bLTlEnzoBB6Y2IxVoFyaTNZ1FQt835ExMAmY7MwfX0=; b=yzeLmLLem6D9hnqO5hCIiW0Al9l+U9uwUrFzOcdp+QMmS3fSYAKl6k//ww26w/QVMo PILWmcQmuH1hQ21RzKKeOpW+nnbgn+zuAALsrguGQCcNbo1HQrvjxL5D07YOqt5ywOQ1 epdRLFL3RoPGe3vhNp2lM4WM+jIpDd5ORBy8O8YxBGt+uObgmkrSGIcyF4tcjL/x3yuT TQZKMynS53gSGS7FygTlS0r/tKePxktkcibz8XP4LJ16/cOkRLRjNv9X+YugnG2M3DPa hgLrGwhu5HTul7qJqce0mZU0vAlqTaeRmlS7l3zgjfC/paIniBFwf102HYZpN+93eGGN 4yrQ== X-Gm-Message-State: ANoB5pmLVZWOsCvJutD0SgxBuswSzeiW2+b/EvKoGmO+3zJ7P1D54+dG mmNDsEz9c7Rx75k+EqCfrXf4w8zwIvA= X-Received: by 2002:a05:600c:1c91:b0:3d2:640:c4e5 with SMTP id k17-20020a05600c1c9100b003d20640c4e5mr1690417wms.8.1670550773436; Thu, 08 Dec 2022 17:52:53 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id fc18-20020a05600c525200b003d04e4ed873sm7473139wmb.22.2022.12.08.17.52.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 17:52:52 -0800 (PST) From: Mark Harmstone To: binutils@sourceware.org, nickc@redhat.com Cc: Mark Harmstone Subject: [PATCH 10/10] ld: Write linker symbols in PDB Date: Fri, 9 Dec 2022 01:52:40 +0000 Message-Id: <20221209015240.6348-10-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221209015240.6348-1-mark@harmstone.com> References: <20221209015240.6348-1-mark@harmstone.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751699854166554485?= X-GMAIL-MSGID: =?utf-8?q?1751699854166554485?= --- ld/pdb.c | 242 +++++++++++++++++++++++++++++++------ ld/pdb.h | 42 +++++++ ld/testsuite/ld-pe/pdb.exp | 77 ++++++++++++ 3 files changed, 327 insertions(+), 34 deletions(-) diff --git a/ld/pdb.c b/ld/pdb.c index 09377a02e52..0346ccb388c 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -21,6 +21,7 @@ #include "pdb.h" #include "bfdlink.h" #include "ld.h" +#include "ldmain.h" #include "ldmisc.h" #include "libbfd.h" #include "libiberty.h" @@ -3420,6 +3421,168 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types, return true; } +/* Return the CodeView constant for the selected architecture. */ +static uint16_t +target_processor (bfd *abfd) +{ + if (abfd->arch_info->arch != bfd_arch_i386) + return 0; + + if (abfd->arch_info->mach & bfd_mach_x86_64) + return CV_CFL_X64; + else + return CV_CFL_80386; +} + +/* Create the symbols that go in "* Linker *", the dummy module created + for the linker itself. */ +static bool +create_linker_symbols (bfd *abfd, uint8_t **syms, uint32_t *sym_byte_size, + const char *pdb_name) +{ + uint8_t *ptr; + struct objname *name; + struct compile3 *comp; + struct envblock *env; + size_t padding1, padding2, env_size; + char *cwdval, *exeval, *pdbval; + + /* extra NUL for padding */ + static const char linker_fn[] = "* Linker *\0"; + static const char linker_name[] = "GNU LD " VERSION; + + static const char cwd[] = "cwd"; + static const char exe[] = "exe"; + static const char pdb[] = "pdb"; + + cwdval = getcwd (NULL, 0); + if (!cwdval) + { + einfo (_("%P: warning: unable to get working directory\n")); + return false; + } + + exeval = lrealpath (program_name); + + if (!exeval) + { + einfo (_("%P: warning: unable to get program name\n")); + free (cwdval); + return false; + } + + pdbval = lrealpath (pdb_name); + + if (!pdbval) + { + einfo (_("%P: warning: unable to get full path to PDB\n")); + free (exeval); + free (cwdval); + return false; + } + + *sym_byte_size += offsetof (struct objname, name) + sizeof (linker_fn); + *sym_byte_size += offsetof (struct compile3, compiler) + sizeof (linker_name); + + if (*sym_byte_size % 4) + padding1 = 4 - (*sym_byte_size % 4); + else + padding1 = 0; + + *sym_byte_size += padding1; + + env_size = offsetof (struct envblock, strings); + env_size += sizeof (cwd); + env_size += strlen (cwdval) + 1; + env_size += sizeof (exe); + env_size += strlen (exeval) + 1; + env_size += sizeof (pdb); + env_size += strlen (pdbval) + 1; + + if (env_size % 4) + padding2 = 4 - (env_size % 4); + else + padding2 = 0; + + env_size += padding2; + + *sym_byte_size += env_size; + + *syms = xmalloc (*sym_byte_size); + ptr = *syms; + + /* Write S_OBJNAME */ + + name = (struct objname *) ptr; + bfd_putl16 (offsetof (struct objname, name) + + sizeof (linker_fn) - sizeof (uint16_t), &name->size); + bfd_putl16 (S_OBJNAME, &name->kind); + bfd_putl32 (0, &name->signature); + memcpy (name->name, linker_fn, sizeof (linker_fn)); + + ptr += offsetof (struct objname, name) + sizeof (linker_fn); + + /* Write S_COMPILE3 */ + + comp = (struct compile3 *) ptr; + + bfd_putl16 (offsetof (struct compile3, compiler) + sizeof (linker_name) + + padding1 - sizeof (uint16_t), &comp->size); + bfd_putl16 (S_COMPILE3, &comp->kind); + bfd_putl32 (CV_CFL_LINK, &comp->flags); + bfd_putl16 (target_processor (abfd), &comp->machine); + bfd_putl16 (0, &comp->frontend_major); + bfd_putl16 (0, &comp->frontend_minor); + bfd_putl16 (0, &comp->frontend_build); + bfd_putl16 (0, &comp->frontend_qfe); + bfd_putl16 (0, &comp->backend_major); + bfd_putl16 (0, &comp->backend_minor); + bfd_putl16 (0, &comp->backend_build); + bfd_putl16 (0, &comp->backend_qfe); + memcpy (comp->compiler, linker_name, sizeof (linker_name)); + + memset (comp->compiler + sizeof (linker_name), 0, padding1); + + ptr += offsetof (struct compile3, compiler) + sizeof (linker_name) + padding1; + + /* Write S_ENVBLOCK */ + + env = (struct envblock *) ptr; + + bfd_putl16 (env_size - sizeof (uint16_t), &env->size); + bfd_putl16 (S_ENVBLOCK, &env->kind); + env->flags = 0; + + ptr += offsetof (struct envblock, strings); + + memcpy (ptr, cwd, sizeof (cwd)); + ptr += sizeof (cwd); + memcpy (ptr, cwdval, strlen (cwdval) + 1); + ptr += strlen (cwdval) + 1; + + memcpy (ptr, exe, sizeof (exe)); + ptr += sizeof (exe); + memcpy (ptr, exeval, strlen (exeval) + 1); + ptr += strlen (exeval) + 1; + + memcpy (ptr, pdb, sizeof (pdb)); + ptr += sizeof (pdb); + memcpy (ptr, pdbval, strlen (pdbval) + 1); + ptr += strlen (pdbval) + 1; + + /* Microsoft's LINK also includes "cmd", the command-line options passed + to the linker, but unfortunately we don't have access to argc and argv + at this stage. */ + + memset (ptr, 0, padding2); + + free (pdbval); + free (exeval); + free (cwdval); + + return true; +} + /* Populate the module stream, which consists of the transformed .debug$S data for each object file. */ static bool @@ -3429,55 +3592,65 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, struct mod_source_files *mod_source, bfd *abfd, struct types *types, struct types *ids, uint16_t mod_num, - bfd *sym_rec_stream, struct globals *glob) + bfd *sym_rec_stream, struct globals *glob, + const char *pdb_name) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; uint8_t *syms = NULL; - struct type_entry **map = NULL; - uint32_t num_types = 0; *sym_byte_size = 0; *c13_info_size = 0; - /* Process .debug$T section. */ - - for (asection *s = mod->sections; s; s = s->next) + if (!strcmp (bfd_get_filename (mod), "dll stuff")) { - if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) + if (!create_linker_symbols (mod, &syms, sym_byte_size, pdb_name)) + return false; + } + else + { + struct type_entry **map = NULL; + uint32_t num_types = 0; + + /* Process .debug$T section. */ + + for (asection *s = mod->sections; s; s = s->next) { - if (!handle_debugt_section (s, mod, types, ids, mod_num, strings, - &map, &num_types)) + if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) { - free (mod_source->files); - return false; - } + if (!handle_debugt_section (s, mod, types, ids, mod_num, strings, + &map, &num_types)) + { + free (mod_source->files); + return false; + } - break; + break; + } } - } - /* Process .debug$S section(s). */ + /* Process .debug$S section(s). */ - for (asection *s = mod->sections; s; s = s->next) - { - if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) + for (asection *s = mod->sections; s; s = s->next) { - if (!handle_debugs_section (s, mod, strings, &c13_info, - c13_info_size, mod_source, abfd, - &syms, sym_byte_size, map, num_types, - sym_rec_stream, glob, mod_num)) + if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) { - free (c13_info); - free (syms); - free (mod_source->files); - free (map); - return false; + if (!handle_debugs_section (s, mod, strings, &c13_info, + c13_info_size, mod_source, abfd, + &syms, sym_byte_size, map, num_types, + sym_rec_stream, glob, mod_num)) + { + free (c13_info); + free (syms); + free (mod_source->files); + free (map); + return false; + } } } - } - free (map); + free (map); + } /* Write the signature. */ @@ -3529,7 +3702,8 @@ 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 *ids, - bfd *sym_rec_stream, struct globals *glob) + bfd *sym_rec_stream, struct globals *glob, + const char *pdb_name) { uint8_t *ptr; unsigned int mod_num; @@ -3619,7 +3793,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, strings, &c13_info_size, &source->mods[mod_num], abfd, types, ids, mod_num, - sym_rec_stream, glob)) + sym_rec_stream, glob, pdb_name)) { for (unsigned int i = 0; i < source->mod_count; i++) { @@ -4108,7 +4282,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, struct string_table *strings, struct types *types, struct types *ids, - bfd *sym_rec_stream) + bfd *sym_rec_stream, const char *pdb_name) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; @@ -4130,7 +4304,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, strings, &source, types, ids, - sym_rec_stream, &glob)) + sym_rec_stream, &glob, pdb_name)) { htab_delete (glob.hashmap); return false; @@ -4822,7 +4996,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, &ids, sym_rec_stream)) + &strings, &types, &ids, sym_rec_stream, pdb_name)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); diff --git a/ld/pdb.h b/ld/pdb.h index ddb9b86ce85..749a60249df 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -93,6 +93,7 @@ #define S_LPROCREF 0x1127 #define S_FRAMECOOKIE 0x113a #define S_COMPILE3 0x113c +#define S_ENVBLOCK 0x113d #define S_LOCAL 0x113e #define S_DEFRANGE_REGISTER 0x1141 #define S_DEFRANGE_FRAMEPOINTER_REL 0x1142 @@ -796,6 +797,47 @@ struct heap_alloc_site uint32_t type; } ATTRIBUTE_PACKED; +/* OBJNAMESYM in cvinfo.h */ +struct objname +{ + uint16_t size; + uint16_t kind; + uint32_t signature; + char name[]; +} ATTRIBUTE_PACKED; + +#define CV_CFL_80386 0x03 +#define CV_CFL_X64 0xD0 + +#define CV_CFL_LINK 0x07 + +/* COMPILESYM3 in cvinfo.h */ +struct compile3 +{ + uint16_t size; + uint16_t kind; + uint32_t flags; + uint16_t machine; + uint16_t frontend_major; + uint16_t frontend_minor; + uint16_t frontend_build; + uint16_t frontend_qfe; + uint16_t backend_major; + uint16_t backend_minor; + uint16_t backend_build; + uint16_t backend_qfe; + char compiler[]; +} ATTRIBUTE_PACKED; + +/* ENVBLOCKSYM in cvinfo.h */ +struct envblock +{ + uint16_t size; + uint16_t kind; + uint8_t flags; + char strings[]; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 5df1583c247..bd50b2fb076 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1678,6 +1678,83 @@ proc test9 { } { } else { fail "Incorrect symbols in module stream" } + + # check linker symbols + + set off 64 + + set obj1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]] + incr off [expr [string length $obj1] + 1] + + set ar1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]] + incr off [expr [string length $ar1] + 1] + + if { [expr $off % 4] != 0 } { + set off [expr $off + 4 - ($off % 4)] + } + + incr off 34 + + binary scan [string range $mod_info $off [expr $off + 1]] s linker_syms_index + + set index_str [format "%04x" $linker_syms_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 linker symbols" + return + } else { + pass "Extracted linker symbols" + } + + set syms [file_contents "tmpdir/$index_str"] + + # check S_OBJNAME + + set off 4 + binary scan [string range $syms $off [expr $off + 1]] s sym_len + binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type + + if { $sym_type != 0x1101 } { + fail "First linker symbol was not S_OBJNAME" + } else { + pass "First linker symbol was S_OBJNAME" + + set linker_fn [string range $syms [expr $off + 8] [expr [string first \000 $syms [expr $off + 8]] - 1]] + + if ![string equal $linker_fn "* Linker *"] { + fail "Incorrect linker object name" + } else { + pass "Correct linker object name" + } + } + + incr off [expr $sym_len + 2] + + # check S_COMPILE3 + + binary scan [string range $syms $off [expr $off + 1]] s sym_len + binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type + + if { $sym_type != 0x113c } { + fail "Second linker symbol was not S_COMPILE3" + } else { + pass "Second linker symbol was S_COMPILE3" + } + + incr off [expr $sym_len + 2] + + # check S_ENVBLOCK + + binary scan [string range $syms $off [expr $off + 1]] s sym_len + binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type + + if { $sym_type != 0x113d } { + fail "Third linker symbol was not S_ENVBLOCK" + } else { + pass "Third linker symbol was S_ENVBLOCK" + } } test1