From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by sourceware.org (Postfix) with ESMTPS id EDE453858D32 for ; Mon, 3 Oct 2022 01:43:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EDE453858D32 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=harmstone.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wr1-x432.google.com with SMTP id bv17so5684097wrb.10 for ; Sun, 02 Oct 2022 18:43:34 -0700 (PDT) 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; bh=vrP4kJLoFnpQP68kRq4r6B/6m3SbLqVluMzZevTobsM=; b=OiBG37UpuGrspEWpmiCaraTA7y6AoKd31FJAwMPJdiZo+wcgscu4CzOzZmNhSbulir In2JBOnJ8g2Zcry9/S3qqbbJ3GB6yDaFAVSuFP3/2E2SE6koEkTKHB+mKphCmXXNTcs6 6e5SPHBAH7Dr/du3OJjRyTOG0YUsBCC+KpLI9s8oNhTqfWH4e0Yn9riBzk2/ScMjDlrf DjdfO7bZEgrrJfkkWyhbRBnQA3Ee12grmbGcONG8FrfvJsybyLsIf6yraFLd+8Zh50xr Jgedc8EA/m6sToTq7CS5oLZPs6ty5ShBlyIreV3Wa2zotaMrFkDTX/c9YBCA/llnphnJ s+sQ== 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; bh=vrP4kJLoFnpQP68kRq4r6B/6m3SbLqVluMzZevTobsM=; b=u372MyWP/Q4w3Nh8VDcuiAn4l8d4+tXoZGKVsOac0DbjhipeEPO2ZJEcMDliJZQxZs 4GsqYbhkxueJtfk2z+W3NV9Ne08tr4XnpF4XWGamU9EcmTNv0KBTE141Ymj0ly2ZRzoF JF9sGoxmP9QHBW0K1QF3GUFpJaY7g3ouplqnKHPM284G90fMCGUVZSp6oK/RyJM4oXTH DPP//yXc2GUTBC9w89Tu1m+3v2GMq5pJtT3AZctCnSRNmxuYgqCVOy34gO9C0h8Vzb1v kQ/K601SjXIU3jRG0cVCC24V/3hHhU50l0xFMtMXNmtEGSAO5hb/HiTgMkkSRkw160Nm jSxA== X-Gm-Message-State: ACrzQf35MbHWGlgEv0s5f7Q1UrOxpO0mSOBYQdmBSBTg+1J02p0ayGwv FOPO0BgCghirDuDYnuhQyXAYkO22Byc= X-Google-Smtp-Source: AMsMyM48U5WE0IRwUs5TwrzLzzfz6qujdt5Szi8UnXrtXUYsUcLh/gKNR25u+oWcTEDbqMBXubBkag== X-Received: by 2002:a05:6000:15c8:b0:22a:59f8:ad18 with SMTP id y8-20020a05600015c800b0022a59f8ad18mr11128405wry.631.1664761413282; Sun, 02 Oct 2022 18:43:33 -0700 (PDT) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id bx10-20020a5d5b0a000000b00228fa832b7asm8656846wrb.52.2022.10.02.18.43.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 02 Oct 2022 18:43:32 -0700 (PDT) Sender: Mark Harmstone From: Mark Harmstone To: binutils@sourceware.org Cc: Mark Harmstone Subject: [PATCH 1/2] ld: Add --pdb option Date: Mon, 3 Oct 2022 02:43:12 +0100 Message-Id: <20221003014313.28766-1-mark@harmstone.com> X-Mailer: git-send-email 2.35.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: This patch adds the --pdb option to ld when linking PE files, which augments the existing CodeView record used for build IDs by adding a PDB filename. If no filename is provided, this defaults to the image name with the extension replaced by "pdb". --- bfd/libpei.h | 6 +++-- bfd/peXXigen.c | 30 ++++++++++++++++----- bfd/peicode.h | 2 +- ld/emultempl/pe.em | 49 +++++++++++++++++++++++++++++++---- ld/emultempl/pep.em | 47 ++++++++++++++++++++++++++++++--- ld/testsuite/ld-pe/pdb.exp | 53 ++++++++++++++++++++++++++++++++++++++ ld/testsuite/ld-pe/pdb1.s | 5 ++++ 7 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 ld/testsuite/ld-pe/pdb.exp create mode 100644 ld/testsuite/ld-pe/pdb1.s diff --git a/bfd/libpei.h b/bfd/libpei.h index 4aca024192c..8b53bd90e84 100644 --- a/bfd/libpei.h +++ b/bfd/libpei.h @@ -388,9 +388,11 @@ void _bfd_XX_get_symbol_info (bfd *, asymbol *, symbol_info *); bool _bfd_XXi_final_link_postscript (bfd *, struct coff_final_link_info *); void _bfd_XXi_swap_debugdir_in (bfd *, void *, void *); unsigned _bfd_XXi_swap_debugdir_out (bfd *, void *, void *); -unsigned _bfd_XXi_write_codeview_record (bfd *, file_ptr, CODEVIEW_INFO *); +unsigned _bfd_XXi_write_codeview_record + (bfd *, file_ptr, CODEVIEW_INFO *, const char *); CODEVIEW_INFO *_bfd_XXi_slurp_codeview_record - (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo); + (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo, + char **pdb); /* The following are needed only for ONE of pe or pei, but don't otherwise vary; peicode.h fixes up ifdefs but we provide the diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c index 5ab09387e72..8db188ce036 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -1134,7 +1134,8 @@ _bfd_XXi_swap_debugdir_out (bfd * abfd, void * inp, void * extp) } CODEVIEW_INFO * -_bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo) +_bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo, + char **pdb) { char buffer[256+1]; bfd_size_type nread; @@ -1174,6 +1175,9 @@ _bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length cvinfo->SignatureLength = CV_INFO_SIGNATURE_LENGTH; /* cvinfo->PdbFileName = cvinfo70->PdbFileName; */ + if (pdb) + *pdb = xstrdup (cvinfo70->PdbFileName); + return cvinfo; } else if ((cvinfo->CVSignature == CVINFO_PDB20_CVSIGNATURE) @@ -1185,6 +1189,9 @@ _bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length cvinfo->SignatureLength = 4; /* cvinfo->PdbFileName = cvinfo20->PdbFileName; */ + if (pdb) + *pdb = xstrdup (cvinfo20->PdbFileName); + return cvinfo; } @@ -1192,9 +1199,11 @@ _bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length } unsigned int -_bfd_XXi_write_codeview_record (bfd * abfd, file_ptr where, CODEVIEW_INFO *cvinfo) +_bfd_XXi_write_codeview_record (bfd * abfd, file_ptr where, CODEVIEW_INFO *cvinfo, + const char *pdb) { - const bfd_size_type size = sizeof (CV_INFO_PDB70) + 1; + size_t pdb_len = pdb ? strlen (pdb) : 0; + const bfd_size_type size = sizeof (CV_INFO_PDB70) + pdb_len + 1; bfd_size_type written; CV_INFO_PDB70 *cvinfo70; char * buffer; @@ -1217,7 +1226,11 @@ _bfd_XXi_write_codeview_record (bfd * abfd, file_ptr where, CODEVIEW_INFO *cvinf memcpy (&(cvinfo70->Signature[8]), &(cvinfo->Signature[8]), 8); H_PUT_32 (abfd, cvinfo->Age, cvinfo70->Age); - cvinfo70->PdbFileName[0] = '\0'; + + if (pdb == NULL) + cvinfo70->PdbFileName[0] = '\0'; + else + memcpy (cvinfo70->PdbFileName, pdb, pdb_len + 1); written = bfd_bwrite (buffer, size, abfd); @@ -2615,22 +2628,25 @@ pe_print_debugdata (bfd * abfd, void * vfile) We need to use a 32-bit aligned buffer to safely read in a codeview record. */ char buffer[256 + 1] ATTRIBUTE_ALIGNED_ALIGNOF (CODEVIEW_INFO); + char *pdb; CODEVIEW_INFO *cvinfo = (CODEVIEW_INFO *) buffer; /* The debug entry doesn't have to have to be in a section, in which case AddressOfRawData is 0, so always use PointerToRawData. */ if (!_bfd_XXi_slurp_codeview_record (abfd, (file_ptr) idd.PointerToRawData, - idd.SizeOfData, cvinfo)) + idd.SizeOfData, cvinfo, &pdb)) continue; for (j = 0; j < cvinfo->SignatureLength; j++) sprintf (&signature[j*2], "%02x", cvinfo->Signature[j] & 0xff); /* xgettext:c-format */ - fprintf (file, _("(format %c%c%c%c signature %s age %ld)\n"), + fprintf (file, _("(format %c%c%c%c signature %s age %ld pdb %s)\n"), buffer[0], buffer[1], buffer[2], buffer[3], - signature, cvinfo->Age); + signature, cvinfo->Age, pdb[0] ? pdb : "(none)"); + + free (pdb); } } diff --git a/bfd/peicode.h b/bfd/peicode.h index 02573c84694..326e9f9a8ca 100644 --- a/bfd/peicode.h +++ b/bfd/peicode.h @@ -1383,7 +1383,7 @@ pe_bfd_read_buildid (bfd *abfd) */ if (_bfd_XXi_slurp_codeview_record (abfd, (file_ptr) idd.PointerToRawData, - idd.SizeOfData, cvinfo)) + idd.SizeOfData, cvinfo, NULL)) { struct bfd_build_id* build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) + cvinfo->SignatureLength); diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em index 892bf70b7a6..ef15d9ee4ca 100644 --- a/ld/emultempl/pe.em +++ b/ld/emultempl/pe.em @@ -146,6 +146,8 @@ static lang_assignment_statement_type *image_base_statement = 0; static unsigned short pe_dll_characteristics = DEFAULT_DLL_CHARACTERISTICS; static bool insert_timestamp = true; static const char *emit_build_id; +static int pdb; +static char *pdb_name; #ifdef DLL_SUPPORT static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable. */ @@ -284,7 +286,8 @@ fragment <sections; asec != NULL; asec = asec->next) @@ -1295,6 +1308,9 @@ write_build_id (bfd *abfd) bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase; + if (pdb_name) + pdb_base_name = lbasename (pdb_name); + /* Construct a debug directory entry which points to an immediately following CodeView record. */ struct internal_IMAGE_DEBUG_DIRECTORY idd; idd.Characteristics = 0; @@ -1302,7 +1318,7 @@ write_build_id (bfd *abfd) idd.MajorVersion = 0; idd.MinorVersion = 0; idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW; - idd.SizeOfData = sizeof (CV_INFO_PDB70) + 1; + idd.SizeOfData = sizeof (CV_INFO_PDB70) + (pdb_base_name ? strlen (pdb_base_name) : 0) + 1; idd.AddressOfRawData = asec->vma - ib + link_order->offset + sizeof (struct external_IMAGE_DEBUG_DIRECTORY); idd.PointerToRawData = asec->filepos + link_order->offset @@ -1331,7 +1347,8 @@ write_build_id (bfd *abfd) free (build_id); /* Write the codeview record. */ - if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo) == 0) + if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo, + pdb_base_name) == 0) return 0; /* Record the location of the debug directory in the data directory. */ @@ -1368,11 +1385,14 @@ setup_build_id (bfd *ibfd) /* Section is a fixed size: One IMAGE_DEBUG_DIRECTORY entry, of type IMAGE_DEBUG_TYPE_CODEVIEW, - pointing at a CV_INFO_PDB70 record containing the build-id, with a - null byte for PdbFileName. */ + pointing at a CV_INFO_PDB70 record containing the build-id, followed by + PdbFileName if relevant. */ s->size = sizeof (struct external_IMAGE_DEBUG_DIRECTORY) + sizeof (CV_INFO_PDB70) + 1; + if (pdb_name) + s->size += strlen (pdb_name); + return true; } @@ -1403,6 +1423,25 @@ gld${EMULATION_NAME}_after_open (void) } #endif + if (pdb && !pdb_name) + { + const char *base = lbasename (bfd_get_filename (link_info.output_bfd)); + size_t len = strlen (base); + static const char suffix[] = ".pdb"; + + while (len > 0 && base[len] != '.') + { + len--; + } + + if (len == 0) + len = strlen (base); + + pdb_name = xmalloc (len + sizeof (suffix)); + memcpy (pdb_name, base, len); + memcpy (pdb_name + len, suffix, sizeof (suffix)); + } + if (emit_build_id != NULL) { bfd *abfd; diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em index e68d1e69f17..78b36de49e7 100644 --- a/ld/emultempl/pep.em +++ b/ld/emultempl/pep.em @@ -157,6 +157,8 @@ static lang_assignment_statement_type *image_base_statement = 0; static unsigned short pe_dll_characteristics = DEFAULT_DLL_CHARACTERISTICS; static bool insert_timestamp = true; static const char *emit_build_id; +static int pdb; +static char *pdb_name; #ifdef DLL_SUPPORT static int pep_enable_stdcall_fixup = 1; /* 0=disable 1=enable (default). */ @@ -255,6 +257,7 @@ enum options OPTION_NO_INSERT_TIMESTAMP, OPTION_TERMINAL_SERVER_AWARE, OPTION_BUILD_ID, + OPTION_PDB, OPTION_ENABLE_RELOC_SECTION, OPTION_DISABLE_RELOC_SECTION, OPTION_DISABLE_HIGH_ENTROPY_VA, @@ -343,6 +346,7 @@ gld${EMULATION_NAME}_add_options {"insert-timestamp", no_argument, NULL, OPTION_INSERT_TIMESTAMP}, {"no-insert-timestamp", no_argument, NULL, OPTION_NO_INSERT_TIMESTAMP}, {"build-id", optional_argument, NULL, OPTION_BUILD_ID}, + {"pdb", optional_argument, NULL, OPTION_PDB}, {"enable-reloc-section", no_argument, NULL, OPTION_ENABLE_RELOC_SECTION}, {"disable-reloc-section", no_argument, NULL, OPTION_DISABLE_RELOC_SECTION}, {"disable-high-entropy-va", no_argument, NULL, OPTION_DISABLE_HIGH_ENTROPY_VA}, @@ -490,6 +494,7 @@ gld${EMULATION_NAME}_list_options (FILE *file) fprintf (file, _(" --[disable-]wdmdriver Driver uses the WDM model\n")); fprintf (file, _(" --[disable-]tsaware Image is Terminal Server aware\n")); fprintf (file, _(" --build-id[=STYLE] Generate build ID\n")); + fprintf (file, _(" --pdb[=FILENAME] Generate PDB file\n")); #endif } @@ -898,6 +903,13 @@ gld${EMULATION_NAME}_handle_option (int optc) if (strcmp (optarg, "none")) emit_build_id = xstrdup (optarg); break; + case OPTION_PDB: + if (emit_build_id == NULL) + emit_build_id = xstrdup (DEFAULT_BUILD_ID_STYLE); + pdb = 1; + if (optarg) + pdb_name = xstrdup (optarg); + break; } /* Set DLLCharacteristics bits */ @@ -1240,6 +1252,7 @@ write_build_id (bfd *abfd) bfd_size_type size; bfd_size_type build_id_size; unsigned char *build_id; + const char *pdb_base_name = NULL; /* Find the section the .buildid output section has been merged info. */ for (asec = abfd->sections; asec != NULL; asec = asec->next) @@ -1279,6 +1292,9 @@ write_build_id (bfd *abfd) bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase; + if (pdb_name) + pdb_base_name = lbasename (pdb_name); + /* Construct a debug directory entry which points to an immediately following CodeView record. */ struct internal_IMAGE_DEBUG_DIRECTORY idd; idd.Characteristics = 0; @@ -1286,7 +1302,7 @@ write_build_id (bfd *abfd) idd.MajorVersion = 0; idd.MinorVersion = 0; idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW; - idd.SizeOfData = sizeof (CV_INFO_PDB70) + 1; + idd.SizeOfData = sizeof (CV_INFO_PDB70) + (pdb_base_name ? strlen (pdb_base_name) : 0) + 1; idd.AddressOfRawData = asec->vma - ib + link_order->offset + sizeof (struct external_IMAGE_DEBUG_DIRECTORY); idd.PointerToRawData = asec->filepos + link_order->offset @@ -1315,7 +1331,8 @@ write_build_id (bfd *abfd) free (build_id); /* Write the codeview record. */ - if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo) == 0) + if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo, + pdb_base_name) == 0) return 0; /* Record the location of the debug directory in the data directory. */ @@ -1352,11 +1369,14 @@ setup_build_id (bfd *ibfd) /* Section is a fixed size: One IMAGE_DEBUG_DIRECTORY entry, of type IMAGE_DEBUG_TYPE_CODEVIEW, - pointing at a CV_INFO_PDB70 record containing the build-id, with a - null byte for PdbFileName. */ + pointing at a CV_INFO_PDB70 record containing the build-id, followed by + PdbFileName if relevant. */ s->size = sizeof (struct external_IMAGE_DEBUG_DIRECTORY) + sizeof (CV_INFO_PDB70) + 1; + if (pdb_name) + s->size += strlen (pdb_name); + return true; } @@ -1388,6 +1408,25 @@ gld${EMULATION_NAME}_after_open (void) } #endif + if (pdb && !pdb_name) + { + const char *base = lbasename (bfd_get_filename (link_info.output_bfd)); + size_t len = strlen (base); + static const char suffix[] = ".pdb"; + + while (len > 0 && base[len] != '.') + { + len--; + } + + if (len == 0) + len = strlen (base); + + pdb_name = xmalloc (len + sizeof (suffix)); + memcpy (pdb_name, base, len); + memcpy (pdb_name + len, suffix, sizeof (suffix)); + } + if (emit_build_id != NULL) { bfd *abfd; diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp new file mode 100644 index 00000000000..1560241cdb8 --- /dev/null +++ b/ld/testsuite/ld-pe/pdb.exp @@ -0,0 +1,53 @@ +# Expect script for creating PDB files when linking. +# Copyright (C) 2022 Free Software Foundation, Inc. +# +# This file is part of the GNU Binutils. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + +if {![istarget i*86-*-mingw*] + && ![istarget x86_64-*-mingw*]} { + return +} + +proc get_pdb_name { pe } { + global OBJDUMP + + set exec_output [run_host_cmd "$OBJDUMP" "-p $pe"] + + if ![regexp -line "^\\(format RSDS signature (\[0-9a-fA-F\]{32}) age 1 pdb (.*)\\)$" $exec_output full sig pdb] { + return "" + } + + return $pdb +} + +if ![ld_assemble $as $srcdir/$subdir/pdb1.s tmpdir/pdb1.o] { + unsupported "Build pdb1.o" + return +} + +if ![ld_link $ld "tmpdir/pdb1.exe" "--pdb=tmpdir/pdb1.pdb tmpdir/pdb1.o"] { + fail "Could not create a PE image with a PDB file" + return +} + +if ![string equal [get_pdb_name "tmpdir/pdb1.exe"] "pdb1.pdb"] { + fail "PDB filename not found in CodeView debug info" + return +} + +pass "PDB filename present in CodeView debug info" diff --git a/ld/testsuite/ld-pe/pdb1.s b/ld/testsuite/ld-pe/pdb1.s new file mode 100644 index 00000000000..30a8cfcca2c --- /dev/null +++ b/ld/testsuite/ld-pe/pdb1.s @@ -0,0 +1,5 @@ +.text + +.global foo +foo: + .long 0x12345678 -- 2.35.1