aboutsummaryrefslogtreecommitdiff
path: root/ld/emultempl
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2014-04-08 10:59:43 +0100
committerNick Clifton <nickc@redhat.com>2014-04-08 10:59:43 +0100
commit61e2488cd8497d158303a78563ad40f51f5c3f8e (patch)
tree096a515807bb59268398b4dd879929e93f78fec3 /ld/emultempl
parentae1d276159c3cfb29caacdf567aea01f433f78b0 (diff)
downloadgdb-61e2488cd8497d158303a78563ad40f51f5c3f8e.zip
gdb-61e2488cd8497d158303a78563ad40f51f5c3f8e.tar.gz
gdb-61e2488cd8497d158303a78563ad40f51f5c3f8e.tar.bz2
Add support for generating and inserting build IDs into COFF binaries.
* peXXigen.c (pe_print_debugdata): New function: Displays the contents of the debug directory and decodes codeview entries. (_bfd_XXi_swap_debugdir_in, _bfd_XXi_swap_debugdir_out) (_bfd_XXi_slurp_codeview_record, _bfd_XXi_write_codeview_record): Add functions for reading and writing debugdir and codeview records. * libpei.h (_bfd_XXi_swap_debugdir_in, _bfd_XXi_swap_debugdir_out) (_bfd_XXi_write_codeview_record): Add prototypes and macros. * libcoff-in.h (pe_tdata): Add build-id data. * libcoff.h: Regenerate. * coffcode.h (coff_write_object_contents): Run build_id after_write_object_contents hook. * pe.h (external_IMAGE_DEBUG_DIRECTORY, _CV_INFO_PDB70) (_CV_INFO_PDB20): Add structures and constants for debug directory and codeview records. * internal.h (internal_IMAGE_DEBUG_DIRECTORY, CODEVIEW_INFO): Add structures and constants for internal representation of debug directory and codeview records. * emultempl/elf32.em (id_note_section_size, read_hex, write_build_id): Move code for parsing build-id option and calculating the build-id to... * ldbuildid.c: New file. * ldbuildid.h: New file. * Makefile.am (CFILES, HFILES, OFILES, ld_new_SOURCES): Add new files. * Makefile.in: Regenerate. * ld.texinfo: Update --build-id description to mention COFF support. * NEWS: Mention support for COFF build ids. * emultempl/pe.em (gld${EMULATION_NAME}_handle_option): (pecoff_checksum_contents, write_build_id, setup_build_id) (gld_${EMULATION_NAME}_after_open): Handle and implement build-id option. * emultempl/pep.em: Likewise.
Diffstat (limited to 'ld/emultempl')
-rw-r--r--ld/emultempl/elf32.em96
-rw-r--r--ld/emultempl/pe.em233
-rw-r--r--ld/emultempl/pep.em234
3 files changed, 447 insertions, 116 deletions
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index de460a2..0173b66 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -39,10 +39,7 @@ fragment <<EOF
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
-#include "safe-ctype.h"
#include "getopt.h"
-#include "md5.h"
-#include "sha1.h"
#include <fcntl.h>
#include "bfdlink.h"
@@ -54,6 +51,7 @@ fragment <<EOF
#include "ldlang.h"
#include "ldfile.h"
#include "ldemul.h"
+#include "ldbuildid.h"
#include <ldgram.h>
#include "elf/common.h"
#include "elf-bfd.h"
@@ -895,53 +893,20 @@ id_note_section_size (bfd *abfd ATTRIBUTE_UNUSED)
{
const char *style = emit_note_gnu_build_id;
bfd_size_type size;
+ bfd_size_type build_id_size;
size = offsetof (Elf_External_Note, name[sizeof "GNU"]);
size = (size + 3) & -(bfd_size_type) 4;
- if (!strcmp (style, "md5") || !strcmp (style, "uuid"))
- size += 128 / 8;
- else if (!strcmp (style, "sha1"))
- size += 160 / 8;
- else if (!strncmp (style, "0x", 2))
- {
- /* ID is in string form (hex). Convert to bits. */
- const char *id = style + 2;
- do
- {
- if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
- {
- ++size;
- id += 2;
- }
- else if (*id == '-' || *id == ':')
- ++id;
- else
- {
- size = 0;
- break;
- }
- } while (*id != '\0');
- }
+ build_id_size = compute_build_id_size (style);
+ if (build_id_size)
+ size += build_id_size;
else
size = 0;
return size;
}
-static unsigned char
-read_hex (const char xdigit)
-{
- if (ISDIGIT (xdigit))
- return xdigit - '0';
- if (ISUPPER (xdigit))
- return xdigit - 'A' + 0xa;
- if (ISLOWER (xdigit))
- return xdigit - 'a' + 0xa;
- abort ();
- return 0;
-}
-
static bfd_boolean
write_build_id (bfd *abfd)
{
@@ -954,7 +919,6 @@ write_build_id (bfd *abfd)
bfd_size_type size;
file_ptr position;
Elf_External_Note *e_note;
- typedef void (*sum_fn) (const void *, size_t, void *);
style = t->o->build_id.style;
asec = t->o->build_id.sec;
@@ -986,55 +950,7 @@ write_build_id (bfd *abfd)
bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type);
memcpy (e_note->name, "GNU", sizeof "GNU");
- if (strcmp (style, "md5") == 0)
- {
- struct md5_ctx ctx;
-
- md5_init_ctx (&ctx);
- if (!bed->s->checksum_contents (abfd, (sum_fn) &md5_process_bytes, &ctx))
- return FALSE;
- md5_finish_ctx (&ctx, id_bits);
- }
- else if (strcmp (style, "sha1") == 0)
- {
- struct sha1_ctx ctx;
-
- sha1_init_ctx (&ctx);
- if (!bed->s->checksum_contents (abfd, (sum_fn) &sha1_process_bytes, &ctx))
- return FALSE;
- sha1_finish_ctx (&ctx, id_bits);
- }
- else if (strcmp (style, "uuid") == 0)
- {
- int n;
- int fd = open ("/dev/urandom", O_RDONLY);
- if (fd < 0)
- return FALSE;
- n = read (fd, id_bits, size);
- close (fd);
- if (n < (int) size)
- return FALSE;
- }
- else if (strncmp (style, "0x", 2) == 0)
- {
- /* ID is in string form (hex). Convert to bits. */
- const char *id = style + 2;
- size_t n = 0;
- do
- {
- if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
- {
- id_bits[n] = read_hex (*id++) << 4;
- id_bits[n++] |= read_hex (*id++);
- }
- else if (*id == '-' || *id == ':')
- ++id;
- else
- abort (); /* Should have been validated earlier. */
- } while (*id != '\0');
- }
- else
- abort (); /* Should have been validated earlier. */
+ generate_build_id (abfd, style, bed->s->checksum_contents, id_bits, size);
position = i_shdr->sh_offset + asec->output_offset;
size = asec->size;
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index c18cb26..ba51cc0 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -66,6 +66,7 @@ fragment <<EOF
#include "ldlex.h"
#include "ldmisc.h"
#include "ldctor.h"
+#include "ldbuildid.h"
#include "coff/internal.h"
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
@@ -73,9 +74,10 @@ fragment <<EOF
#include "coff/i386.h"
#include "coff/pe.h"
-/* FIXME: This is a BFD internal header file, and we should not be
+/* FIXME: These are BFD internal header files, and we should not be
using it here. */
#include "../bfd/libcoff.h"
+#include "../bfd/libpei.h"
#include "deffile.h"
#include "pe-dll.h"
@@ -131,6 +133,7 @@ static char * thumb_entry_symbol = NULL;
static lang_assignment_statement_type *image_base_statement = 0;
static unsigned short pe_dll_characteristics = 0;
static bfd_boolean insert_timestamp = FALSE;
+static const char *emit_build_id;
#ifdef DLL_SUPPORT
static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable. */
@@ -269,6 +272,7 @@ fragment <<EOF
#define OPTION_TERMINAL_SERVER_AWARE (OPTION_WDM_DRIVER + 1)
/* Determinism. */
#define OPTION_INSERT_TIMESTAMP (OPTION_TERMINAL_SERVER_AWARE + 1)
+#define OPTION_BUILD_ID (OPTION_INSERT_TIMESTAMP + 1)
static void
gld${EMULATION_NAME}_add_options
@@ -347,6 +351,7 @@ gld${EMULATION_NAME}_add_options
{"no-bind", no_argument, NULL, OPTION_NO_BIND},
{"wdmdriver", no_argument, NULL, OPTION_WDM_DRIVER},
{"tsaware", no_argument, NULL, OPTION_TERMINAL_SERVER_AWARE},
+ {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
{NULL, no_argument, NULL, 0}
};
@@ -386,7 +391,7 @@ typedef struct
#define U_SIZE(CSTR) \
(sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1))
-#define D(field,symbol,def,usc) {&pe.field,sizeof(pe.field), def, symbol, 0, usc}
+#define D(field,symbol,def,usc) {&pe.field, sizeof (pe.field), def, symbol, 0, usc}
static definfo init[] =
{
@@ -495,6 +500,7 @@ gld_${EMULATION_NAME}_list_options (FILE *file)
fprintf (file, _(" --no-bind Do not bind this image\n"));
fprintf (file, _(" --wdmdriver Driver uses the WDM model\n"));
fprintf (file, _(" --tsaware Image is Terminal Server aware\n"));
+ fprintf (file, _(" --build-id[=STYLE] Generate build ID\n"));
}
@@ -689,6 +695,7 @@ set_pe_stack_heap (char *resname, char *comname)
einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg);
}
+#define DEFAULT_BUILD_ID_STYLE "md5"
static bfd_boolean
gld${EMULATION_NAME}_handle_option (int optc)
@@ -807,7 +814,7 @@ gld${EMULATION_NAME}_handle_option (int optc)
if (optarg && *optarg)
{
char *end;
- pe_auto_image_base = strtoul(optarg, &end, 0);
+ pe_auto_image_base = strtoul (optarg, &end, 0);
/* XXX should check that we actually parsed something */
}
break;
@@ -880,6 +887,17 @@ gld${EMULATION_NAME}_handle_option (int optc)
case OPTION_TERMINAL_SERVER_AWARE:
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
break;
+ case OPTION_BUILD_ID:
+ if (emit_build_id != NULL)
+ {
+ free ((char *) emit_build_id);
+ emit_build_id = NULL;
+ }
+ if (optarg == NULL)
+ optarg = DEFAULT_BUILD_ID_STYLE;
+ if (strcmp (optarg, "none"))
+ emit_build_id = xstrdup (optarg);
+ break;
}
/* Set DLLCharacteristics bits */
@@ -1235,6 +1253,169 @@ debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj)
*found = 1;
}
+static bfd_boolean
+pecoff_checksum_contents (bfd *abfd,
+ void (*process) (const void *, size_t, void *),
+ void *arg)
+{
+ file_ptr filepos = (file_ptr) 0;
+
+ while (1)
+ {
+ unsigned char b;
+ int status;
+
+ if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
+ return 0;
+
+ status = bfd_bread (&b, (bfd_size_type) 1, abfd);
+ if (status < 1)
+ {
+ break;
+ }
+
+ (*process) (&b, 1, arg);
+ filepos += 1;
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+write_build_id (bfd *abfd)
+{
+ struct pe_tdata *t = pe_data (abfd);
+ asection *asec;
+ struct bfd_link_order *link_order = NULL;
+ unsigned char *contents;
+ bfd_size_type size;
+ bfd_size_type build_id_size;
+ unsigned char *build_id;
+
+ /* Find the section the .build-id output section has been merged info. */
+ for (asec = abfd->sections; asec != NULL; asec = asec->next)
+ {
+ struct bfd_link_order *l = NULL;
+ for (l = asec->map_head.link_order; l != NULL; l = l->next)
+ {
+ if ((l->type == bfd_indirect_link_order))
+ {
+ if (l->u.indirect.section == t->build_id.sec)
+ {
+ link_order = l;
+ break;
+ }
+ }
+ }
+
+ if (link_order)
+ break;
+ }
+
+ if (!link_order)
+ {
+ einfo (_("%P: warning: .build-id section discarded,"
+ " --build-id ignored.\n"));
+ return TRUE;
+ }
+
+ if (t->build_id.sec->contents == NULL)
+ t->build_id.sec->contents = (unsigned char *) xmalloc (t->build_id.sec->size);
+ contents = t->build_id.sec->contents;
+ size = t->build_id.sec->size;
+
+ build_id_size = compute_build_id_size (t->build_id.style);
+ build_id = xmalloc (build_id_size);
+ generate_build_id (abfd, t->build_id.style, pecoff_checksum_contents, build_id, build_id_size);
+
+ bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase;
+
+ /* Construct a debug directory entry which points to an immediately following CodeView record. */
+ struct internal_IMAGE_DEBUG_DIRECTORY idd;
+ idd.Characteristics = 0;
+ idd.TimeDateStamp = 0;
+ idd.MajorVersion = 0;
+ idd.MinorVersion = 0;
+ idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW;
+ idd.SizeOfData = sizeof (CV_INFO_PDB70) + 1;
+ idd.AddressOfRawData = asec->vma - ib + link_order->offset
+ + sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+ idd.PointerToRawData = asec->filepos + link_order->offset
+ + sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+
+ struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *)contents;
+ _bfd_XXi_swap_debugdir_out (abfd, &idd, ext);
+
+ /* Write the debug directory entry. */
+ if (bfd_seek (abfd, asec->filepos + link_order->offset, SEEK_SET) != 0)
+ return 0;
+
+ if ((bfd_bwrite (contents, size, abfd) != size))
+ return 0;
+
+ /* Construct the CodeView record. */
+ CODEVIEW_INFO cvinfo;
+ cvinfo.CVSignature = CVINFO_PDB70_CVSIGNATURE;
+ cvinfo.Age = 1;
+
+ /* Zero pad or truncate the generated build_id to fit in the CodeView record. */
+ memset (&(cvinfo.Signature), 0, CV_INFO_SIGNATURE_LENGTH);
+ memcpy (&(cvinfo.Signature), build_id, (build_id_size > CV_INFO_SIGNATURE_LENGTH)
+ ? CV_INFO_SIGNATURE_LENGTH : build_id_size);
+
+ free (build_id);
+
+ /* Write the codeview record. */
+ if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo) == 0)
+ return 0;
+
+ /* Record the location of the debug directory in the data directory. */
+ pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].VirtualAddress
+ = asec->vma - ib + link_order->offset;
+ pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size
+ = sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+
+ return TRUE;
+}
+
+/* Make .build-id section, and set up coff_tdata->build_id. */
+static bfd_boolean
+setup_build_id (bfd *ibfd)
+{
+ asection *s;
+ flagword flags;
+
+ if (!validate_build_id_style (emit_build_id))
+ {
+ einfo ("%P: warning: unrecognized --build-id style ignored.\n");
+ return FALSE;
+ }
+
+ flags = (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
+ s = bfd_make_section_anyway_with_flags (ibfd, ".build-id", flags);
+ if (s != NULL)
+ {
+ struct pe_tdata *t = pe_data (link_info.output_bfd);
+ t->build_id.after_write_object_contents = &write_build_id;
+ t->build_id.style = emit_build_id;
+ t->build_id.sec = s;
+
+ /* 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. */
+ s->size = sizeof (struct external_IMAGE_DEBUG_DIRECTORY)
+ + sizeof (CV_INFO_PDB70) + 1;
+
+ return TRUE;
+ }
+
+ einfo ("%P: warning: Cannot create .build-id section,"
+ " --build-id ignored.\n");
+ return FALSE;
+}
+
static void
gld_${EMULATION_NAME}_after_open (void)
{
@@ -1257,6 +1438,26 @@ gld_${EMULATION_NAME}_after_open (void)
}
#endif
+ if (emit_build_id != NULL)
+ {
+ bfd *abfd;
+
+ /* Find a COFF input. */
+ for (abfd = link_info.input_bfds;
+ abfd != (bfd *) NULL; abfd = abfd->link_next)
+ if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
+ break;
+
+ /* If there are no COFF input files do not try to
+ add a build-id section. */
+ if (abfd == NULL
+ || !setup_build_id (abfd))
+ {
+ free ((char *) emit_build_id);
+ emit_build_id = NULL;
+ }
+ }
+
/* Pass the wacky PE command line options into the output bfd.
FIXME: This should be done via a function, rather than by
including an internal BFD header. */
@@ -1279,17 +1480,23 @@ gld_${EMULATION_NAME}_after_open (void)
find it, so enable it in that case. */
if (pe_use_coff_long_section_names < 0 && link_info.strip == strip_none)
{
- /* Iterate over all sections of all input BFDs, checking
- for any that begin 'debug_' and are long names. */
- LANG_FOR_EACH_INPUT_STATEMENT (is)
+ if (link_info.relocatable)
+ pe_use_coff_long_section_names = 1;
+ else
{
- int found_debug = 0;
- bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
- if (found_debug)
- {
- pe_use_coff_long_section_names = 1;
- break;
- }
+ /* Iterate over all sections of all input BFDs, checking
+ for any that begin 'debug_' and are long names. */
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ int found_debug = 0;
+
+ bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
+ if (found_debug)
+ {
+ pe_use_coff_long_section_names = 1;
+ break;
+ }
+ }
}
}
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index dca36cc..d1575e2 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -64,6 +64,7 @@ fragment <<EOF
#include "ldlex.h"
#include "ldmisc.h"
#include "ldctor.h"
+#include "ldbuildid.h"
#include "coff/internal.h"
/* FIXME: See bfd/peXXigen.c for why we include an architecture specific
@@ -71,9 +72,10 @@ fragment <<EOF
#include "coff/x86_64.h"
#include "coff/pe.h"
-/* FIXME: This is a BFD internal header file, and we should not be
+/* FIXME: These are BFD internal header files, and we should not be
using it here. */
#include "../bfd/libcoff.h"
+#include "../bfd/libpei.h"
#undef AOUTSZ
#define AOUTSZ PEPAOUTSZ
@@ -146,6 +148,7 @@ static int support_old_code = 0;
static lang_assignment_statement_type *image_base_statement = 0;
static unsigned short pe_dll_characteristics = 0;
static bfd_boolean insert_timestamp = FALSE;
+static const char *emit_build_id;
#ifdef DLL_SUPPORT
static int pep_enable_stdcall_fixup = 1; /* 0=disable 1=enable (default). */
@@ -242,7 +245,8 @@ enum options
OPTION_NO_BIND,
OPTION_WDM_DRIVER,
OPTION_INSERT_TIMESTAMP,
- OPTION_TERMINAL_SERVER_AWARE
+ OPTION_TERMINAL_SERVER_AWARE,
+ OPTION_BUILD_ID
};
static void
@@ -318,6 +322,7 @@ gld${EMULATION_NAME}_add_options
{"wdmdriver", no_argument, NULL, OPTION_WDM_DRIVER},
{"tsaware", no_argument, NULL, OPTION_TERMINAL_SERVER_AWARE},
{"insert-timestamp", no_argument, NULL, OPTION_INSERT_TIMESTAMP},
+ {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
{NULL, no_argument, NULL, 0}
};
@@ -355,7 +360,7 @@ typedef struct
#define U_SIZE(CSTR) \
(sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1))
-#define D(field,symbol,def,usc) {&pep.field,sizeof(pep.field), def, symbol,0, usc}
+#define D(field,symbol,def,usc) {&pep.field, sizeof (pep.field), def, symbol, 0, usc}
static definfo init[] =
{
@@ -453,6 +458,7 @@ gld_${EMULATION_NAME}_list_options (FILE *file)
fprintf (file, _(" --no-bind Do not bind this image\n"));
fprintf (file, _(" --wdmdriver Driver uses the WDM model\n"));
fprintf (file, _(" --tsaware Image is Terminal Server aware\n"));
+ fprintf (file, _(" --build-id[=STYLE] Generate build ID\n"));
#endif
}
@@ -643,6 +649,7 @@ set_pep_stack_heap (char *resname, char *comname)
einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg);
}
+#define DEFAULT_BUILD_ID_STYLE "md5"
static bfd_boolean
gld${EMULATION_NAME}_handle_option (int optc)
@@ -816,6 +823,17 @@ gld${EMULATION_NAME}_handle_option (int optc)
case OPTION_TERMINAL_SERVER_AWARE:
pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
break;
+ case OPTION_BUILD_ID:
+ if (emit_build_id != NULL)
+ {
+ free ((char *) emit_build_id);
+ emit_build_id = NULL;
+ }
+ if (optarg == NULL)
+ optarg = DEFAULT_BUILD_ID_STYLE;
+ if (strcmp (optarg, "none"))
+ emit_build_id = xstrdup (optarg);
+ break;
}
/* Set DLLCharacteristics bits */
@@ -1187,10 +1205,174 @@ static void
debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj)
{
int *found = (int *) obj;
+
if (strncmp (".debug_", sect->name, sizeof (".debug_") - 1) == 0)
*found = 1;
}
+static bfd_boolean
+pecoff_checksum_contents (bfd *abfd,
+ void (*process) (const void *, size_t, void *),
+ void *arg)
+{
+ file_ptr filepos = (file_ptr) 0;
+
+ while (1)
+ {
+ unsigned char b;
+ int status;
+
+ if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
+ return 0;
+
+ status = bfd_bread (&b, (bfd_size_type) 1, abfd);
+ if (status < 1)
+ {
+ break;
+ }
+
+ (*process) (&b, 1, arg);
+ filepos += 1;
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+write_build_id (bfd *abfd)
+{
+ struct pe_tdata *t = pe_data (abfd);
+ asection *asec;
+ struct bfd_link_order *link_order = NULL;
+ unsigned char *contents;
+ bfd_size_type size;
+ bfd_size_type build_id_size;
+ unsigned char *build_id;
+
+ /* Find the section the .build-id output section has been merged info. */
+ for (asec = abfd->sections; asec != NULL; asec = asec->next)
+ {
+ struct bfd_link_order *l = NULL;
+ for (l = asec->map_head.link_order; l != NULL; l = l->next)
+ {
+ if ((l->type == bfd_indirect_link_order))
+ {
+ if (l->u.indirect.section == t->build_id.sec)
+ {
+ link_order = l;
+ break;
+ }
+ }
+ }
+
+ if (link_order)
+ break;
+ }
+
+ if (!link_order)
+ {
+ einfo (_("%P: warning: .build-id section discarded,"
+ " --build-id ignored.\n"));
+ return TRUE;
+ }
+
+ if (t->build_id.sec->contents == NULL)
+ t->build_id.sec->contents = (unsigned char *) xmalloc (t->build_id.sec->size);
+ contents = t->build_id.sec->contents;
+ size = t->build_id.sec->size;
+
+ build_id_size = compute_build_id_size (t->build_id.style);
+ build_id = xmalloc (build_id_size);
+ generate_build_id (abfd, t->build_id.style, pecoff_checksum_contents, build_id, build_id_size);
+
+ bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase;
+
+ /* Construct a debug directory entry which points to an immediately following CodeView record. */
+ struct internal_IMAGE_DEBUG_DIRECTORY idd;
+ idd.Characteristics = 0;
+ idd.TimeDateStamp = 0;
+ idd.MajorVersion = 0;
+ idd.MinorVersion = 0;
+ idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW;
+ idd.SizeOfData = sizeof (CV_INFO_PDB70) + 1;
+ idd.AddressOfRawData = asec->vma - ib + link_order->offset
+ + sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+ idd.PointerToRawData = asec->filepos + link_order->offset
+ + sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+
+ struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *)contents;
+ _bfd_XXi_swap_debugdir_out (abfd, &idd, ext);
+
+ /* Write the debug directory enttry */
+ if (bfd_seek (abfd, asec->filepos + link_order->offset, SEEK_SET) != 0)
+ return 0;
+
+ if ((bfd_bwrite (contents, size, abfd) != size))
+ return 0;
+
+ /* Construct the CodeView record. */
+ CODEVIEW_INFO cvinfo;
+ cvinfo.CVSignature = CVINFO_PDB70_CVSIGNATURE;
+ cvinfo.Age = 1;
+
+ /* Zero pad or truncate the generated build_id to fit in the CodeView record. */
+ memset (&(cvinfo.Signature), 0, CV_INFO_SIGNATURE_LENGTH);
+ memcpy (&(cvinfo.Signature), build_id, (build_id_size > CV_INFO_SIGNATURE_LENGTH)
+ ? CV_INFO_SIGNATURE_LENGTH : build_id_size);
+
+ free (build_id);
+
+ /* Write the codeview record. */
+ if (_bfd_XXi_write_codeview_record (abfd, idd.PointerToRawData, &cvinfo) == 0)
+ return 0;
+
+ /* Record the location of the debug directory in the data directory. */
+ pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].VirtualAddress
+ = asec->vma - ib + link_order->offset;
+ pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size
+ = sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+
+ return TRUE;
+}
+
+/* Make .build-id section, and set up coff_tdata->build_id. */
+static bfd_boolean
+setup_build_id (bfd *ibfd)
+{
+ asection *s;
+ flagword flags;
+
+ if (!validate_build_id_style (emit_build_id))
+ {
+ einfo ("%P: warning: unrecognized --build-id style ignored.\n");
+ return FALSE;
+ }
+
+ flags = (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
+ s = bfd_make_section_anyway_with_flags (ibfd, ".build-id", flags);
+ if (s != NULL)
+ {
+ struct pe_tdata *t = pe_data (link_info.output_bfd);
+ t->build_id.after_write_object_contents = &write_build_id;
+ t->build_id.style = emit_build_id;
+ t->build_id.sec = s;
+
+ /* 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. */
+ s->size = sizeof (struct external_IMAGE_DEBUG_DIRECTORY)
+ + sizeof (CV_INFO_PDB70) + 1;
+
+ return TRUE;
+ }
+
+ einfo ("%P: warning: Cannot create .build-id section,"
+ " --build-id ignored.\n");
+ return FALSE;
+}
+
static void
gld_${EMULATION_NAME}_after_open (void)
{
@@ -1214,6 +1396,26 @@ gld_${EMULATION_NAME}_after_open (void)
}
#endif
+ if (emit_build_id != NULL)
+ {
+ bfd *abfd;
+
+ /* Find a COFF input. */
+ for (abfd = link_info.input_bfds;
+ abfd != (bfd *) NULL; abfd = abfd->link_next)
+ if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
+ break;
+
+ /* If there are no COFF input files do not try to
+ add a build-id section. */
+ if (abfd == NULL
+ || !setup_build_id (abfd))
+ {
+ free ((char *) emit_build_id);
+ emit_build_id = NULL;
+ }
+ }
+
/* Pass the wacky PE command line options into the output bfd.
FIXME: This should be done via a function, rather than by
including an internal BFD header. */
@@ -1236,17 +1438,23 @@ gld_${EMULATION_NAME}_after_open (void)
find it, so enable it in that case. */
if (pep_use_coff_long_section_names < 0 && link_info.strip == strip_none)
{
- /* Iterate over all sections of all input BFDs, checking
- for any that begin 'debug_' and are long names. */
- LANG_FOR_EACH_INPUT_STATEMENT (is)
+ if (link_info.relocatable)
+ pep_use_coff_long_section_names = 1;
+ else
{
- int found_debug = 0;
- bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
- if (found_debug)
- {
- pep_use_coff_long_section_names = 1;
- break;
- }
+ /* Iterate over all sections of all input BFDs, checking
+ for any that begin 'debug_' and are long names. */
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ int found_debug = 0;
+
+ bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
+ if (found_debug)
+ {
+ pep_use_coff_long_section_names = 1;
+ break;
+ }
+ }
}
}