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 /bfd | |
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 'bfd')
-rw-r--r-- | bfd/ChangeLog | 15 | ||||
-rw-r--r-- | bfd/coffcode.h | 13 | ||||
-rw-r--r-- | bfd/libcoff-in.h | 8 | ||||
-rw-r--r-- | bfd/libcoff.h | 8 | ||||
-rw-r--r-- | bfd/libpei.h | 12 | ||||
-rw-r--r-- | bfd/peXXigen.c | 218 |
6 files changed, 270 insertions, 4 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 6ad175f..70d23c5 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,18 @@ +2014-04-08 Jon TURNEY <jon.turney@dronecode.org.uk> + + * 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. + 2014-04-05 Alan Modra <amodra@gmail.com> * elflink.c (_bfd_elf_add_default_symbol): Pass poldbfd when diff --git a/bfd/coffcode.h b/bfd/coffcode.h index d6fe39f..4994fb3 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -4329,7 +4329,18 @@ coff_write_object_contents (bfd * abfd) } #endif - /* Now write them. */ +#ifdef COFF_WITH_PE + { + /* After object contents are finalized so we can compute a reasonable hash, + but before header is written so we can update it to point to debug directory. */ + struct pe_tdata *pe = pe_data (abfd); + + if (pe->build_id.after_write_object_contents != NULL) + (*pe->build_id.after_write_object_contents) (abfd); + } +#endif + + /* Now write header. */ if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) return FALSE; diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h index a556edc..cc1e52b 100644 --- a/bfd/libcoff-in.h +++ b/bfd/libcoff-in.h @@ -119,6 +119,14 @@ typedef struct pe_tdata bfd_boolean insert_timestamp; bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *); flagword real_flags; + + /* Build-id info. */ + struct + { + bfd_boolean (*after_write_object_contents) (bfd *); + const char *style; + asection *sec; + } build_id; } pe_data_type; #define pe_data(bfd) ((bfd)->tdata.pe_obj_data) diff --git a/bfd/libcoff.h b/bfd/libcoff.h index 36c9829..6cb387c 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -123,6 +123,14 @@ typedef struct pe_tdata bfd_boolean insert_timestamp; bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *); flagword real_flags; + + /* build-id info. */ + struct + { + bfd_boolean (*after_write_object_contents) (bfd *); + const char *style; + asection *sec; + } build_id; } pe_data_type; #define pe_data(bfd) ((bfd)->tdata.pe_obj_data) diff --git a/bfd/libpei.h b/bfd/libpei.h index 0fdafb0..ffcafde 100644 --- a/bfd/libpei.h +++ b/bfd/libpei.h @@ -235,6 +235,9 @@ #define _bfd_XXi_swap_scnhdr_out _bfd_pex64i_swap_scnhdr_out #define _bfd_XXi_swap_sym_in _bfd_pex64i_swap_sym_in #define _bfd_XXi_swap_sym_out _bfd_pex64i_swap_sym_out +#define _bfd_XXi_swap_debugdir_in _bfd_pex64i_swap_debugdir_in +#define _bfd_XXi_swap_debugdir_out _bfd_pex64i_swap_debugdir_out +#define _bfd_XXi_write_codeview_record _bfd_pex64i_write_codeview_record #elif defined COFF_WITH_pep @@ -266,6 +269,9 @@ #define _bfd_XXi_swap_scnhdr_out _bfd_pepi_swap_scnhdr_out #define _bfd_XXi_swap_sym_in _bfd_pepi_swap_sym_in #define _bfd_XXi_swap_sym_out _bfd_pepi_swap_sym_out +#define _bfd_XXi_swap_debugdir_in _bfd_pepi_swap_debugdir_in +#define _bfd_XXi_swap_debugdir_out _bfd_pepi_swap_debugdir_out +#define _bfd_XXi_write_codeview_record _bfd_pepi_write_codeview_record #else /* !COFF_WITH_pep */ @@ -297,6 +303,9 @@ #define _bfd_XXi_swap_scnhdr_out _bfd_pei_swap_scnhdr_out #define _bfd_XXi_swap_sym_in _bfd_pei_swap_sym_in #define _bfd_XXi_swap_sym_out _bfd_pei_swap_sym_out +#define _bfd_XXi_swap_debugdir_in _bfd_pei_swap_debugdir_in +#define _bfd_XXi_swap_debugdir_out _bfd_pei_swap_debugdir_out +#define _bfd_XXi_write_codeview_record _bfd_pei_write_codeview_record #endif /* !COFF_WITH_pep */ @@ -339,6 +348,9 @@ bfd_boolean _bfd_XX_print_private_bfd_data_common (bfd *, void *); bfd_boolean _bfd_XX_bfd_copy_private_bfd_data_common (bfd *, bfd *); void _bfd_XX_get_symbol_info (bfd *, asymbol *, symbol_info *); bfd_boolean _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 *); /* 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 e78edaa..ea7846f 100644 --- a/bfd/peXXigen.c +++ b/bfd/peXXigen.c @@ -802,7 +802,7 @@ _bfd_XXi_only_swap_filehdr_out (bfd * abfd, void * in, void * out) /* Only use a real timestamp if the option was chosen. */ if ((pe_data (abfd)->insert_timestamp)) - H_PUT_32 (abfd, time(0), filehdr_out->f_timdat); + H_PUT_32 (abfd, time (0), filehdr_out->f_timdat); PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr, filehdr_out->f_symptr); @@ -1031,6 +1031,106 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out) return ret; } +void +_bfd_XXi_swap_debugdir_in (bfd * abfd, void * ext1, void * in1) +{ + struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *) ext1; + struct internal_IMAGE_DEBUG_DIRECTORY *in = (struct internal_IMAGE_DEBUG_DIRECTORY *) in1; + + in->Characteristics = H_GET_32(abfd, ext->Characteristics); + in->TimeDateStamp = H_GET_32(abfd, ext->TimeDateStamp); + in->MajorVersion = H_GET_16(abfd, ext->MajorVersion); + in->MinorVersion = H_GET_16(abfd, ext->MinorVersion); + in->Type = H_GET_32(abfd, ext->Type); + in->SizeOfData = H_GET_32(abfd, ext->SizeOfData); + in->AddressOfRawData = H_GET_32(abfd, ext->AddressOfRawData); + in->PointerToRawData = H_GET_32(abfd, ext->PointerToRawData); +} + +unsigned int +_bfd_XXi_swap_debugdir_out (bfd * abfd, void * inp, void * extp) +{ + struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *) extp; + struct internal_IMAGE_DEBUG_DIRECTORY *in = (struct internal_IMAGE_DEBUG_DIRECTORY *) inp; + + H_PUT_32(abfd, in->Characteristics, ext->Characteristics); + H_PUT_32(abfd, in->TimeDateStamp, ext->TimeDateStamp); + H_PUT_16(abfd, in->MajorVersion, ext->MajorVersion); + H_PUT_16(abfd, in->MinorVersion, ext->MinorVersion); + H_PUT_32(abfd, in->Type, ext->Type); + H_PUT_32(abfd, in->SizeOfData, ext->SizeOfData); + H_PUT_32(abfd, in->AddressOfRawData, ext->AddressOfRawData); + H_PUT_32(abfd, in->PointerToRawData, ext->PointerToRawData); + + return sizeof (struct external_IMAGE_DEBUG_DIRECTORY); +} + +static CODEVIEW_INFO * +_bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo) +{ + char buffer[256+1]; + + if (bfd_seek (abfd, where, SEEK_SET) != 0) + return NULL; + + if (bfd_bread (buffer, 256, abfd) < 4) + return NULL; + + /* ensure null termination of filename */ + buffer[256] = '\0'; + + cvinfo->CVSignature = H_GET_32(abfd, buffer); + cvinfo->Age = 0; + + if ((cvinfo->CVSignature == CVINFO_PDB70_CVSIGNATURE) + && (length > sizeof (CV_INFO_PDB70))) + { + CV_INFO_PDB70 *cvinfo70 = (CV_INFO_PDB70 *)(buffer); + + cvinfo->Age = H_GET_32(abfd, cvinfo70->Age); + memcpy (cvinfo->Signature, cvinfo70->Signature, CV_INFO_SIGNATURE_LENGTH); + cvinfo->SignatureLength = CV_INFO_SIGNATURE_LENGTH; + // cvinfo->PdbFileName = cvinfo70->PdbFileName; + + return cvinfo; + } + else if ((cvinfo->CVSignature == CVINFO_PDB20_CVSIGNATURE) + && (length > sizeof (CV_INFO_PDB20))) + { + CV_INFO_PDB20 *cvinfo20 = (CV_INFO_PDB20 *)(buffer); + cvinfo->Age = H_GET_32(abfd, cvinfo20->Age); + memcpy (cvinfo->Signature, cvinfo20->Signature, 4); + cvinfo->SignatureLength = 4; + // cvinfo->PdbFileName = cvinfo20->PdbFileName; + + return cvinfo; + } + + return NULL; +} + +unsigned int +_bfd_XXi_write_codeview_record (bfd * abfd, file_ptr where, CODEVIEW_INFO *cvinfo) +{ + unsigned int size = sizeof (CV_INFO_PDB70) + 1; + CV_INFO_PDB70 *cvinfo70; + char buffer[size]; + + if (bfd_seek (abfd, where, SEEK_SET) != 0) + return 0; + + cvinfo70 = (CV_INFO_PDB70 *) buffer; + H_PUT_32 (abfd, CVINFO_PDB70_CVSIGNATURE, cvinfo70->CvSignature); + memcpy (&(cvinfo70->Signature), cvinfo->Signature, CV_INFO_SIGNATURE_LENGTH); + H_PUT_32 (abfd, cvinfo->Age, cvinfo70->Age); + cvinfo70->PdbFileName[0] = '\0'; + + if (bfd_bwrite (buffer, size, abfd) != size) + return 0; + + return size; +} + static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] = { N_("Export Directory [.edata (or where ever we found it)]"), @@ -2240,6 +2340,117 @@ rsrc_print_section (bfd * abfd, void * vfile) return TRUE; } +#define IMAGE_NUMBEROF_DEBUG_TYPES 12 + +static char * debug_type_names[IMAGE_NUMBEROF_DEBUG_TYPES] = +{ + "Unknown", + "COFF", + "CodeView", + "FPO", + "Misc", + "Exception", + "Fixup", + "OMAP-to-SRC", + "OMAP-from-SRC", + "Borland", + "Reserved", + "CLSID", +}; + +static bfd_boolean +pe_print_debugdata (bfd * abfd, void * vfile) +{ + FILE *file = (FILE *) vfile; + pe_data_type *pe = pe_data (abfd); + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + asection *section; + bfd_byte *data = 0; + bfd_size_type dataoff; + unsigned int i; + + bfd_vma addr = extra->DataDirectory[PE_DEBUG_DATA].VirtualAddress; + bfd_size_type size = extra->DataDirectory[PE_DEBUG_DATA].Size; + + if (size == 0) + return TRUE; + + addr += extra->ImageBase; + for (section = abfd->sections; section != NULL; section = section->next) + { + if ((addr >= section->vma) && (addr < (section->vma + section->size))) + break; + } + + if (section == NULL) + { + fprintf (file, + _("\nThere is a debug directory, but the section containing it could not be found\n")); + return TRUE; + } + + fprintf (file, _("\nThere is a debug directory in %s at 0x%lx\n\n"), + section->name, (unsigned long) addr); + + dataoff = addr - section->vma; + + fprintf (file, + _("Type Size Rva Offset\n")); + + /* Read the whole section. */ + if (!bfd_malloc_and_get_section (abfd, section, &data)) + { + if (data != NULL) + free (data); + return FALSE; + } + + for (i = 0; i < size / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++) + { + const char *type_name; + struct external_IMAGE_DEBUG_DIRECTORY *ext + = &((struct external_IMAGE_DEBUG_DIRECTORY *)(data + dataoff))[i]; + struct internal_IMAGE_DEBUG_DIRECTORY idd; + + _bfd_XXi_swap_debugdir_in (abfd, ext, &idd); + + if ((idd.Type) > IMAGE_NUMBEROF_DEBUG_TYPES) + type_name = debug_type_names[0]; + else + type_name = debug_type_names[idd.Type]; + + fprintf (file, " %2ld %14s %08lx %08lx %08lx\n", + idd.Type, type_name, idd.SizeOfData, + idd.AddressOfRawData, idd.PointerToRawData); + + if (idd.Type == PE_IMAGE_DEBUG_TYPE_CODEVIEW) + { + char signature[CV_INFO_SIGNATURE_LENGTH * 2 + 1]; + char buffer[256 + 1]; + 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)) + continue; + + for (i = 0; i < cvinfo->SignatureLength; i++) + sprintf (&signature[i*2], "%02x", cvinfo->Signature[i] & 0xff); + + fprintf (file, "(format %c%c%c%c signature %s age %ld)\n", + buffer[0], buffer[1], buffer[2], buffer[3], + signature, cvinfo->Age); + } + } + + if (size % sizeof (struct external_IMAGE_DEBUG_DIRECTORY) != 0) + fprintf (file, + _("The debug directory size is not a multiple of the debug directory entry size\n")); + + return TRUE; +} + /* Print out the program headers. */ bfd_boolean @@ -2413,6 +2624,7 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile) else pe_print_pdata (abfd, vfile); pe_print_reloc (abfd, vfile); + pe_print_debugdata (abfd, file); rsrc_print_section (abfd, vfile); @@ -3576,7 +3788,7 @@ rsrc_process_section (bfd * abfd, if (num_input_rsrc < 2) goto end; - + /* Step one: Walk the section, computing the size of the tables, leaves and data and decide if we need to do anything. */ dataend = data + size; @@ -3841,7 +4053,7 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) } h1 = coff_link_hash_lookup (coff_hash_table (info), - (bfd_get_symbol_leading_char(abfd) != 0 + (bfd_get_symbol_leading_char (abfd) != 0 ? "__tls_used" : "_tls_used"), FALSE, FALSE, TRUE); if (h1 != NULL) |