From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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-Google-Smtp-Source: AA0mqf5kZ63zjrbZ+kLcyjKkpteUJ/sJHlUKCCwZS4PGfBaO2HJsPlOESNKh0e805D9xnfvKAzl76Q== 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) Sender: Mark Harmstone 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 Content-Transfer-Encoding: 8bit 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 List-Id: --- 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 -- 2.37.4