diff options
author | Jon TURNEY <jon.turney@dronecode.org.uk> | 2014-04-08 10:59:43 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2014-04-08 10:59:43 +0100 |
commit | 61e2488cd8497d158303a78563ad40f51f5c3f8e (patch) | |
tree | 096a515807bb59268398b4dd879929e93f78fec3 /ld/emultempl | |
parent | ae1d276159c3cfb29caacdf567aea01f433f78b0 (diff) | |
download | gdb-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.em | 96 | ||||
-rw-r--r-- | ld/emultempl/pe.em | 233 | ||||
-rw-r--r-- | ld/emultempl/pep.em | 234 |
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; + } + } } } |