Add support for generating and inserting build IDs into COFF binaries.
authorJon TURNEY <jon.turney@dronecode.org.uk>
Tue, 8 Apr 2014 09:59:43 +0000 (10:59 +0100)
committerNick Clifton <nickc@redhat.com>
Tue, 8 Apr 2014 09:59:43 +0000 (10:59 +0100)
* 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.

25 files changed:
bfd/ChangeLog
bfd/coffcode.h
bfd/libcoff-in.h
bfd/libcoff.h
bfd/libpei.h
bfd/peXXigen.c
include/coff/ChangeLog
include/coff/internal.h
include/coff/pe.h
ld/ChangeLog
ld/Makefile.am
ld/Makefile.in
ld/NEWS
ld/emultempl/elf32.em
ld/emultempl/pe.em
ld/emultempl/pep.em
ld/ld.texinfo
ld/ldbuildid.c [new file with mode: 0644]
ld/ldbuildid.h [new file with mode: 0644]
ld/ldmain.c
ld/testsuite/ld-pe/longsecn-3.d
ld/testsuite/ld-pe/longsecn-4.d
ld/testsuite/ld-pe/longsecn-5.d
ld/testsuite/ld-pe/non-c-lang-syms.s
ld/testsuite/ld-pe/orphana_nu.s

index 6ad175fd0448daedc18902aad62de24627d9ef35..70d23c50b154284def99f8d9e028546526b5ccf1 100644 (file)
@@ -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
index d6fe39f1572184f470a7a823a5c017494f2fb542..4994fb3afe3164104df6a243ecfff952bcd31cdf 100644 (file)
@@ -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;
 
index a556edcfcee25dc535ab48470f426db993963daa..cc1e52b04f2fc41fb1c995870ee015eec13e1184 100644 (file)
@@ -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)
index 36c9829bde1ebfc3bc7d47c69319a2eedc31d8c3..6cb387ceb831884bc6e18bbcead90193ac4c2e92 100644 (file)
@@ -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)
index 0fdafb0a132cc905edd37720f8f9d01ab01504ad..ffcafded780c9f9b3a33ed688180e1c5a80f9968 100644 (file)
 #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
 
 #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 */
 
 #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
index e78edaacd1514351f14205af77df1a28aa97b83b..ea7846f496957e06903d9044b34b8fdf0356829f 100644 (file)
@@ -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)
index 2ee6361f82827977472949f61aa615c164df6c76..769e9ead7eac3f89abac433512d9bf1860421134 100644 (file)
@@ -1,3 +1,12 @@
+2014-04-08  Jon TURNEY  <jon.turney@dronecode.org.uk>
+
+       * 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.
+
 2014-03-13  Tristan Gingold  <gingold@adacore.com>
 
        * pe.h (struct external_ANON_OBJECT_HEADER_BIGOBJ): Declare.
index b34e5c6c348455192025b236082b14eed29789fd..47e85d9fecfaeb181cc4096b8546b91226108132 100644 (file)
@@ -1,18 +1,18 @@
 /* Internal format of COFF object file data structures, for GNU BFD.
    This file is part of BFD, the Binary File Descriptor library.
-   
+
    Copyright (C) 1999-2014 Free Software Foundation, Inc.
 
    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,
@@ -55,7 +55,7 @@ struct internal_extra_pe_filehdr
   unsigned short e_res2[10];   /* Reserved words, all 0x0 */
   bfd_vma  e_lfanew;           /* File address of new exe header, 0x80 */
   unsigned long dos_message[16]; /* text which always follows dos header */
-  bfd_vma  nt_signature;       /* required NT signature, 0x4550 */ 
+  bfd_vma  nt_signature;       /* required NT signature, 0x4550 */
 };
 
 #define GO32_STUBSIZE 2048
@@ -66,7 +66,7 @@ struct internal_filehdr
 
   /* coff-stgo32 EXE stub header before BFD tdata has been allocated.
      Its data is kept in INTERNAL_FILEHDR.GO32STUB afterwards.
-     
+
      F_GO32STUB is set iff go32stub contains a valid data.  Artifical headers
      created in BFD have no pre-set go32stub.  */
   char go32stub[GO32_STUBSIZE];
@@ -109,7 +109,7 @@ struct internal_filehdr
 #define F_GO32STUB      (0x4000)
 
 /* Extra structure which is used in the optional header.  */
-typedef struct _IMAGE_DATA_DIRECTORY 
+typedef struct _IMAGE_DATA_DIRECTORY
 {
   bfd_vma VirtualAddress;
   long    Size;
@@ -132,6 +132,44 @@ typedef struct _IMAGE_DATA_DIRECTORY
 /* DataDirectory[15] is currently reserved, so no define. */
 #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES  16
 
+/* Extra structure used in debug directory.  */
+struct internal_IMAGE_DEBUG_DIRECTORY
+{
+  unsigned long  Characteristics;
+  unsigned long  TimeDateStamp;
+  unsigned short MajorVersion;
+  unsigned short MinorVersion;
+  unsigned long  Type;
+  unsigned long  SizeOfData;
+  unsigned long  AddressOfRawData;
+  unsigned long  PointerToRawData;
+};
+
+#define PE_IMAGE_DEBUG_TYPE_UNKNOWN          0
+#define PE_IMAGE_DEBUG_TYPE_COFF             1
+#define PE_IMAGE_DEBUG_TYPE_CODEVIEW         2
+#define PE_IMAGE_DEBUG_TYPE_FPO              3
+#define PE_IMAGE_DEBUG_TYPE_MISC             4
+#define PE_IMAGE_DEBUG_TYPE_EXCEPTION        5
+#define PE_IMAGE_DEBUG_TYPE_FIXUP            6
+#define PE_IMAGE_DEBUG_TYPE_OMAP_TO_SRC      7
+#define PE_IMAGE_DEBUG_TYPE_OMAP_FROM_SRC    8
+#define PE_IMAGE_DEBUG_TYPE_BORLAND          9
+#define PE_IMAGE_DEBUG_TYPE_RESERVED10       10
+#define PE_IMAGE_DEBUG_TYPE_CLSID            11
+
+/* Extra structure for a codeview debug record */
+#define CV_INFO_SIGNATURE_LENGTH 16
+
+typedef struct _CODEVIEW_INFO
+{
+  unsigned long CVSignature;
+  char          Signature[CV_INFO_SIGNATURE_LENGTH];
+  unsigned int  SignatureLength;
+  unsigned long Age;
+  // char PdbFileName[];
+} CODEVIEW_INFO;
+
 /* Default image base for NT.  */
 #define NT_EXE_IMAGE_BASE 0x400000
 #define NT_DLL_IMAGE_BASE 0x10000000
@@ -147,22 +185,22 @@ typedef struct _IMAGE_DATA_DIRECTORY
 # define PE_DEF_FILE_ALIGNMENT 0x200
 #endif
 
-struct internal_extra_pe_aouthdr 
+struct internal_extra_pe_aouthdr
 {
   /* FIXME: The following entries are in AOUTHDR.  But they aren't
      available internally in bfd.  We add them here so that objdump
      can dump them.  */
-  /* The state of the image file  */
+  /* The state of the image file.  */
   short Magic;
-  /* Linker major version number */
+  /* Linker major version number */
   char MajorLinkerVersion;
-  /* Linker minor version number  */
+  /* Linker minor version number.  */
   char MinorLinkerVersion;     
-  /* Total size of all code sections  */
+  /* Total size of all code sections.  */
   long SizeOfCode;
-  /* Total size of all initialized data sections  */
+  /* Total size of all initialized data sections.  */
   long SizeOfInitializedData;
-  /* Total size of all uninitialized data sections  */
+  /* Total size of all uninitialized data sections.  */
   long SizeOfUninitializedData;
   /* Address of entry point relative to image base.  */
   bfd_vma AddressOfEntryPoint;
@@ -170,40 +208,40 @@ struct internal_extra_pe_aouthdr
   bfd_vma BaseOfCode;
   /* Address of the first data section relative to image base.  */
   bfd_vma BaseOfData;
+
   /* PE stuff  */
-  bfd_vma ImageBase;           /* address of specific location in memory that
-                                  file is located, NT default 0x10000 */
-
-  bfd_vma SectionAlignment;    /* section alignment default 0x1000 */
-  bfd_vma FileAlignment;       /* file alignment default 0x200 */
-  short   MajorOperatingSystemVersion; /* minimum version of the operating */
-  short   MinorOperatingSystemVersion; /* system req'd for exe, default to 1*/
-  short   MajorImageVersion;   /* user defineable field to store version of */
-  short   MinorImageVersion;   /* exe or dll being created, default to 0 */ 
-  short   MajorSubsystemVersion; /* minimum subsystem version required to */
-  short   MinorSubsystemVersion; /* run exe; default to 3.1 */
-  long    Reserved1;           /* seems to be 0 */
-  long    SizeOfImage;         /* size of memory to allocate for prog */
-  long    SizeOfHeaders;       /* size of PE header and section table */
-  long    CheckSum;            /* set to 0 */
+  bfd_vma ImageBase;           /* Address of specific location in memory that
+                                   file is located, NT default 0x10000.  */
+
+  bfd_vma SectionAlignment;    /* Section alignment default 0x1000.  */
+  bfd_vma FileAlignment;       /* File alignment default 0x200.  */
+  short   MajorOperatingSystemVersion; /* Minimum version of the operating.  */
+  short   MinorOperatingSystemVersion; /* System req'd for exe, default to 1.  */
+  short   MajorImageVersion;   /* User defineable field to store version of */
+  short   MinorImageVersion;   /*  exe or dll being created, default to 0.  */ 
+  short   MajorSubsystemVersion; /* Minimum subsystem version required to */
+  short   MinorSubsystemVersion; /*  run exe; default to 3.1.  */
+  long    Reserved1;           /* Seems to be 0.  */
+  long    SizeOfImage;         /* Size of memory to allocate for prog.  */
+  long    SizeOfHeaders;       /* Size of PE header and section table.  */
+  long    CheckSum;            /* Set to 0.  */
   short   Subsystem;   
 
-  /* type of subsystem exe uses for user interface,
+  /* Type of subsystem exe uses for user interface,
      possible values:
      1 - NATIVE   Doesn't require a subsystem
      2 - WINDOWS_GUI runs in Windows GUI subsystem
      3 - WINDOWS_CUI runs in Windows char sub. (console app)
      5 - OS2_CUI runs in OS/2 character subsystem
-     7 - POSIX_CUI runs in Posix character subsystem */
-  unsigned short DllCharacteristics; /* flags for DLL init  */
-  bfd_vma SizeOfStackReserve;  /* amount of memory to reserve  */
-  bfd_vma SizeOfStackCommit;   /* amount of memory initially committed for 
-                                  initial thread's stack, default is 0x1000 */
-  bfd_vma SizeOfHeapReserve;   /* amount of virtual memory to reserve and */
-  bfd_vma SizeOfHeapCommit;    /* commit, don't know what to defaut it to */
-  long    LoaderFlags;         /* can probably set to 0 */
-  long    NumberOfRvaAndSizes; /* number of entries in next entry, 16 */
+     7 - POSIX_CUI runs in Posix character subsystem */
+  unsigned short DllCharacteristics; /* flags for DLL init.  */
+  bfd_vma SizeOfStackReserve;  /* Amount of memory to reserve.  */
+  bfd_vma SizeOfStackCommit;   /* Amount of memory initially committed for
+                                   initial thread's stack, default is 0x1000.  */
+  bfd_vma SizeOfHeapReserve;   /* Amount of virtual memory to reserve and */
+  bfd_vma SizeOfHeapCommit;    /*  commit, don't know what to defaut it to.  */
+  long    LoaderFlags;         /* Can probably set to 0.  */
+  long    NumberOfRvaAndSizes; /* Number of entries in next entry, 16.  */
   IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
 };
 
index 3166531097f76b8278497e408833e3bcde501e9b..0ed9dde3b290cb934f6739f5e0a86685507c9fc6 100644 (file)
@@ -1,4 +1,4 @@
-/* pe.h  -  PE COFF header information 
+/* pe.h  -  PE COFF header information
 
    Copyright (C) 1999-2014 Free Software Foundation, Inc.
 
 #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER     12
 #define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER     13
 #define IMAGE_SUBSYSTEM_XBOX                   14
-  
+
 /* Magic values that are true for all dos/nt implementations.  */
-#define DOSMAGIC       0x5a4d  
+#define DOSMAGIC       0x5a4d
 #define NT_SIGNATURE   0x00004550
 
 /* NT allows long filenames, we want to accommodate this.
@@ -264,7 +264,7 @@ struct external_PEI_filehdr
 
 /* 32-bit PE a.out header: */
 
-typedef struct 
+typedef struct
 {
   AOUTHDR standard;
 
@@ -300,7 +300,7 @@ typedef struct
 /* Like PEAOUTHDR, except that the "standard" member has no BaseOfData
    (aka data_start) member and that some of the members are 8 instead
    of just 4 bytes long.  */
-typedef struct 
+typedef struct
 {
 #ifdef AOUTHDRSZ64
   AOUTHDR64 standard;
@@ -338,7 +338,7 @@ typedef struct
 #else
 #define PEPAOUTSZ      240
 #endif
-  
+
 #undef  E_FILNMLEN
 #define E_FILNMLEN     18      /* # characters in a file name.  */
 
@@ -584,4 +584,41 @@ struct external_pex64_scope_entry
   (PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
    PEX64_SCOPE_ENTRY_SIZE * (IDX))
 
+/* Extra structure used in debug directory */
+struct external_IMAGE_DEBUG_DIRECTORY {
+  char Characteristics[4];
+  char TimeDateStamp[4];
+  char MajorVersion[2];
+  char MinorVersion[2];
+  char Type[4];
+  char SizeOfData[4];
+  char AddressOfRawData[4];
+  char PointerToRawData[4];
+};
+
+/* Extra structures used in codeview debug record */
+/* This is not part of the PE specification */
+
+#define CVINFO_PDB70_CVSIGNATURE 0x53445352 // "RSDS"
+#define CVINFO_PDB20_CVSIGNATURE 0x3031424e // "NB10"
+#define CVINFO_CV50_CVSIGNATURE  0x3131424e // "NB11"
+#define CVINFO_CV41_CVSIGNATURE  0x3930424e // Ã¢NB09"
+
+typedef struct _CV_INFO_PDB70
+{
+  char CvSignature[4];
+  char Signature[16];
+  char Age[4];
+  char PdbFileName[];
+} CV_INFO_PDB70;
+
+typedef struct _CV_INFO_PDB20
+{
+  char CvHeader[4];
+  char Offset[4];
+  char Signature[4];
+  char Age[4];
+  char PdbFileName[];
+} CV_INFO_PDB20;
+
 #endif /* _PE_H */
index 0a02f900a781985a5c37c1e0ef15c952d3c4e518..cdba250b17e11d7cf103a04b9db37c27a76255c8 100644 (file)
@@ -1,3 +1,21 @@
+2014-04-08  Jon TURNEY  <jon.turney@dronecode.org.uk>
+
+       * 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.
+
 2014-04-04  Cary Coutant  <ccoutant@google.com>
 
        PR gold/16804
index 795663f740a6f1bb42b9a2ad4f6277c334b27527..3e2dc1af64b0f67f6e6297c61743359926ad852c 100644 (file)
@@ -496,12 +496,12 @@ ALL_EMUL_EXTRA_BINARIES =
 CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \
        ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \
        mri.c ldcref.c pe-dll.c pep-dll.c ldlex-wrapper.c \
-       $(PLUGIN_C)
+       $(PLUGIN_C) ldbuildid.c
 
 HFILES = ld.h ldctor.h ldemul.h ldexp.h ldfile.h \
        ldlang.h ldlex.h ldmain.h ldmisc.h ldver.h \
        ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h \
-       elf-hints-local.h $(PLUGIN_H)
+       elf-hints-local.h $(PLUGIN_H) ldbuildid.h
 
 GENERATED_CFILES = ldgram.c ldlex.c deffilep.c
 GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h
@@ -513,7 +513,8 @@ BUILT_SOURCES = $(GENERATED_HFILES)
 OFILES = ldgram.@OBJEXT@ ldlex-wrapper.@OBJEXT@ lexsup.@OBJEXT@ ldlang.@OBJEXT@ \
        mri.@OBJEXT@ ldctor.@OBJEXT@ ldmain.@OBJEXT@ $(PLUGIN_OBJECT) \
        ldwrite.@OBJEXT@ ldexp.@OBJEXT@  ldemul.@OBJEXT@ ldver.@OBJEXT@ ldmisc.@OBJEXT@ \
-       ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES}
+       ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES} \
+       ldbuildid.@OBJEXT@
 
 STAGESTUFF = *.@OBJEXT@ ldscripts/* e*.c
 
@@ -1935,7 +1936,8 @@ EXTRA_ld_new_SOURCES = deffilep.y ldlex.l
 EXTRA_ld_new_SOURCES += pep-dll.c pe-dll.c
 
 ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmain.c \
-       ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C)
+       ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C) \
+       ldbuildid.c
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(EMUL_EXTRA_BINARIES) \
                      $(BFDLIB) $(LIBIBERTY) $(LIBINTL_DEP)
 ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
index 3c9f8f4b1d049176fd3f6c51689be56864caf4de..4f54c26cdce586e070ad932ec330e9501eda5b81 100644 (file)
@@ -109,7 +109,7 @@ am_ld_new_OBJECTS = ldgram.$(OBJEXT) ldlex-wrapper.$(OBJEXT) \
        ldctor.$(OBJEXT) ldmain.$(OBJEXT) ldwrite.$(OBJEXT) \
        ldexp.$(OBJEXT) ldemul.$(OBJEXT) ldver.$(OBJEXT) \
        ldmisc.$(OBJEXT) ldfile.$(OBJEXT) ldcref.$(OBJEXT) \
-       $(am__objects_1)
+       $(am__objects_1) ldbuildid.$(OBJEXT)
 ld_new_OBJECTS = $(am_ld_new_OBJECTS)
 am__DEPENDENCIES_1 =
 DEFAULT_INCLUDES = -I.@am__isrc@
@@ -800,12 +800,12 @@ ALL_EMUL_EXTRA_BINARIES =
 CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \
        ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \
        mri.c ldcref.c pe-dll.c pep-dll.c ldlex-wrapper.c \
-       $(PLUGIN_C)
+       $(PLUGIN_C) ldbuildid.c
 
 HFILES = ld.h ldctor.h ldemul.h ldexp.h ldfile.h \
        ldlang.h ldlex.h ldmain.h ldmisc.h ldver.h \
        ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h \
-       elf-hints-local.h $(PLUGIN_H)
+       elf-hints-local.h $(PLUGIN_H) ldbuildid.h
 
 GENERATED_CFILES = ldgram.c ldlex.c deffilep.c
 GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h
@@ -816,7 +816,8 @@ BUILT_SOURCES = $(GENERATED_HFILES)
 OFILES = ldgram.@OBJEXT@ ldlex-wrapper.@OBJEXT@ lexsup.@OBJEXT@ ldlang.@OBJEXT@ \
        mri.@OBJEXT@ ldctor.@OBJEXT@ ldmain.@OBJEXT@ $(PLUGIN_OBJECT) \
        ldwrite.@OBJEXT@ ldexp.@OBJEXT@  ldemul.@OBJEXT@ ldver.@OBJEXT@ ldmisc.@OBJEXT@ \
-       ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES}
+       ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES} \
+       ldbuildid.@OBJEXT@
 
 STAGESTUFF = *.@OBJEXT@ ldscripts/* e*.c
 
@@ -838,7 +839,8 @@ ELF_GEN_DEPS = $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/elf-generic.em
 EXTRA_ld_new_SOURCES = deffilep.y ldlex.l pep-dll.c pe-dll.c \
        $(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
 ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmain.c \
-       ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C)
+       ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C) \
+       ldbuildid.c
 
 ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(EMUL_EXTRA_BINARIES) \
                      $(BFDLIB) $(LIBIBERTY) $(LIBINTL_DEP)
@@ -1365,6 +1367,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ez80.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ez8001.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ez8002.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldbuildid.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldcref.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldctor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldemul.Po@am__quote@
diff --git a/ld/NEWS b/ld/NEWS
index 94d086e93c61142bf9319073ef6fed134e18bad4..a9124b6d1434517c6af179ae59f1f0f0b77500e8 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,9 @@
 -*- text -*-
 
+* Add support for the --build-id command line option to COFF based targets.
+
+* x86/x86_64 pe-coff now supports the --build-id option.
+
 * Add support for the Andes NDS32.
 
 Changes in 2.24:
index de460a274f2e262d25970aff8d21420d216a2669..0173b66d7b14cb7ed31f052419e5cffb94a167a6 100644 (file)
@@ -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;
index c18cb266beb23d14108044571382e0c7f4dbedb3..ba51cc0488c369dcb1e4197df51503ac2b1048fc 100644 (file)
@@ -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;
+             }
+         }
        }
     }
 
index dca36cc341aabfa2ec9db139b8ec94690165201a..d1575e2673d50c65fb81cf31bcd24e55993cecce 100644 (file)
@@ -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;
+             }
+         }
        }
     }
 
index 62d8aa75632aab8efdcaf509abe75bd0d6f9e67e..7d2de3b0eb9dce8b671868593ee470076c09cd6b 100644 (file)
@@ -2160,16 +2160,16 @@ enable other tradeoffs in future versions of the linker.
 @kindex --build-id=@var{style}
 @item --build-id
 @itemx --build-id=@var{style}
-Request creation of @code{.note.gnu.build-id} ELF note section.
-The contents of the note are unique bits identifying this linked
-file.  @var{style} can be @code{uuid} to use 128 random bits,
-@code{sha1} to use a 160-bit @sc{SHA1} hash on the normative
-parts of the output contents, @code{md5} to use a 128-bit
-@sc{MD5} hash on the normative parts of the output contents, or
-@code{0x@var{hexstring}} to use a chosen bit string specified as
-an even number of hexadecimal digits (@code{-} and @code{:}
-characters between digit pairs are ignored).  If @var{style} is
-omitted, @code{sha1} is used.
+Request the creation of a @code{.note.gnu.build-id} ELF note section
+or a @code{.build-id} COFF section.  The contents of the note are
+unique bits identifying this linked file.  @var{style} can be
+@code{uuid} to use 128 random bits, @code{sha1} to use a 160-bit
+@sc{SHA1} hash on the normative parts of the output contents,
+@code{md5} to use a 128-bit @sc{MD5} hash on the normative parts of
+the output contents, or @code{0x@var{hexstring}} to use a chosen bit
+string specified as an even number of hexadecimal digits (@code{-} and
+@code{:} characters between digit pairs are ignored).  If @var{style}
+is omitted, @code{sha1} is used.
 
 The @code{md5} and @code{sha1} styles produces an identifier
 that is always the same in an identical output file, but will be
diff --git a/ld/ldbuildid.c b/ld/ldbuildid.c
new file mode 100644 (file)
index 0000000..1214789
--- /dev/null
@@ -0,0 +1,158 @@
+/* ldbuildid.c - Build Id support routines
+   Copyright 2013, 2014 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.  */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "md5.h"
+#include "sha1.h"
+#include "ldbuildid.h"
+
+#define streq(a,b)     strcmp ((a), (b)) == 0
+#define strneq(a,b,n)  strncmp ((a), (b), (n)) == 0
+
+bfd_boolean
+validate_build_id_style (const char *style)
+{
+ if ((streq (style, "md5")) || (streq (style, "sha1"))
+#ifndef __MINGW32__
+     || (streq (style, "uuid"))
+#endif
+     || (strneq (style, "0x", 2)))
+   return TRUE;
+
+ return FALSE;
+}
+
+bfd_size_type
+compute_build_id_size (const char *style)
+{
+  if (streq (style, "md5") || streq (style, "uuid"))
+    return  128 / 8;
+
+  if (streq (style, "sha1"))
+    return  160 / 8;
+
+  if (strneq (style, "0x", 2))
+    {
+      bfd_size_type size = 0;
+      /* ID is in string form (hex).  Count the bytes.  */
+      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');
+      return size;
+    }
+
+  return 0;
+}
+
+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;
+}
+
+bfd_boolean
+generate_build_id (bfd *abfd,
+                  const char *style,
+                  checksum_fn checksum_contents,
+                  unsigned char *id_bits,
+                  int size)
+{
+  if (streq (style, "md5"))
+    {
+      struct md5_ctx ctx;
+
+      md5_init_ctx (&ctx);
+      if (!(*checksum_contents) (abfd, (sum_fn) &md5_process_bytes, &ctx))
+       return FALSE;
+      md5_finish_ctx (&ctx, id_bits);
+    }
+  else if (streq (style, "sha1"))
+    {
+      struct sha1_ctx ctx;
+
+      sha1_init_ctx (&ctx);
+      if (!(*checksum_contents) (abfd, (sum_fn) &sha1_process_bytes, &ctx))
+       return FALSE;
+      sha1_finish_ctx (&ctx, id_bits);
+    }
+#ifndef __MINGW32__
+  else if (streq (style, "uuid"))
+    {
+      int n;
+      int fd = open ("/dev/urandom", O_RDONLY);
+
+      if (fd < 0)
+       return FALSE;
+      n = read (fd, id_bits, size);
+      close (fd);
+      if (n < size)
+       return FALSE;
+    }
+#endif
+  else if (strneq (style, "0x", 2))
+    {
+      /* 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.  */
+
+  return TRUE;
+}
diff --git a/ld/ldbuildid.h b/ld/ldbuildid.h
new file mode 100644 (file)
index 0000000..a91ac1a
--- /dev/null
@@ -0,0 +1,39 @@
+/* ldbuildid.h -
+   Copyright 2013, 2014 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.  */
+
+#ifndef LDBUILDID_H
+#define LDBUILDID_H
+
+extern bfd_boolean
+validate_build_id_style (const char *);
+
+extern bfd_size_type
+compute_build_id_size (const char *);
+
+typedef void (*sum_fn) (const void *, size_t, void *);
+
+typedef bfd_boolean (*checksum_fn) (bfd *,
+                                   void (*) (const void *, size_t, void *),
+                                   void *);
+
+extern bfd_boolean
+generate_build_id (bfd *, const char *, checksum_fn, unsigned char *, int);
+
+#endif /* LDBUILDID_H */
index 14253a6f0c2a8a4f393a9360116b51d447f43aa1..b132dae62dfd0e60d855836b5f81abdca4962650 100644 (file)
@@ -378,6 +378,13 @@ main (int argc, char **argv)
 
   lang_final ();
 
+  /* If the only command line argument has been -v or --version or --verbose
+     then ignore any input files provided by linker scripts and exit now.
+     We do not want to create an output file when the linker is just invoked
+     to provide version information.  */
+  if (argc == 2 && version_printed)
+    xexit (0);
+
   if (!lang_has_input_file)
     {
       if (version_printed || command_line.print_output_format)
index 0317be3084a39428c5b1451b07586c25d2e21053..c86a828db95393d102cdd0479747af0b1b97c3ea 100644 (file)
@@ -37,5 +37,4 @@ Idx Name          Size      VMA +LMA +File off  Algn
                   CONTENTS, ALLOC, LOAD, DATA
  14 \.rodata\.very\.long\.section\$1234 [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  2\*\*[0-9]
                   CONTENTS, ALLOC, LOAD, DATA
- 15 \.(bss |text)         [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  2\*\*[0-9]
-                  (ALLOC|CONTENTS, ALLOC, LOAD, (READONLY, )?CODE)
+#...
index 565ef38100b29efec4af80a79925de9d0da48615..e326d98e80758e12f60ef21372b58af969ebbe10 100644 (file)
@@ -37,5 +37,4 @@ Idx Name          Size      VMA +LMA +File off  Algn
                   CONTENTS, ALLOC, LOAD, DATA
  14 \.rodata\.      [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  2\*\*[0-9]
                   CONTENTS, ALLOC, LOAD, DATA
- 15 \.(bss |text)         [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  2\*\*[0-9]
-                  (ALLOC|CONTENTS, ALLOC, LOAD, (READONLY, )?CODE)
+#...
index 82d94b8ab2799b9acdea59aaabaf9753450b71cb..f3ef22bd9a478cd19e6e33f946bd59a01cbe4140 100644 (file)
@@ -37,5 +37,4 @@ Idx Name          Size      VMA +LMA +File off  Algn
                   CONTENTS, ALLOC, LOAD, DATA
  14 \.rodata\.very\.long\.section\$1234 [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  2\*\*[0-9]
                   CONTENTS, ALLOC, LOAD, DATA
- 15 \.(bss |text)         [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  [0-9a-fA-F]+  2\*\*[0-9]
-                  (ALLOC|CONTENTS, ALLOC, LOAD, (READONLY, )?CODE)
+#...
index e849d9e16871f0e87b3c9f55af996618c5c70857..28006a1bf6ce11cbb61f75aa1426818b73237648 100644 (file)
@@ -1,4 +1,3 @@
-
 main:
 _main:
        nop
index d3c564f3f4a24fa5a61b3124a0e98ed14cc8fdb8..618789c8ddef8e08744553fea58bc283962bb569 100644 (file)
@@ -1,6 +1,8 @@
+ .globl _mainCRTStartup
  .globl mainCRTStartup
  .globl start
  .text
+_mainCRTStartup:
 mainCRTStartup:
 start:
 
This page took 0.054567 seconds and 4 git commands to generate.