aboutsummaryrefslogtreecommitdiff
path: root/bfd
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 /bfd
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 'bfd')
-rw-r--r--bfd/ChangeLog15
-rw-r--r--bfd/coffcode.h13
-rw-r--r--bfd/libcoff-in.h8
-rw-r--r--bfd/libcoff.h8
-rw-r--r--bfd/libpei.h12
-rw-r--r--bfd/peXXigen.c218
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)