public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Mark Harmstone <mark@harmstone.com>
To: binutils@sourceware.org
Cc: Mark Harmstone <mark@harmstone.com>
Subject: [PATCH] ld: Write DEBUG_S_FILECHKSMS entries in PDBs
Date: Fri, 25 Nov 2022 02:54:33 +0000	[thread overview]
Message-ID: <20221125025433.26818-1-mark@harmstone.com> (raw)
In-Reply-To: <20221125025334.26665-1-mark@harmstone.com>

Here we parse the DEBUG_S_FILECHKSMS subsections of the .debug$S input
sections, which contain the names and checksums of the input source
files.

Copies are stored in the "C13" substream of the symbol stream for each
module. We also populate the source info substream of the DBI stream,
which contains a deduplicated list of all source files.

---
 ld/pdb.c                              | 433 +++++++++++++++++++++++++-
 ld/pdb.h                              |   9 +
 ld/testsuite/ld-pe/pdb.exp            | 154 +++++++++
 ld/testsuite/ld-pe/pdb3-c13-info1.d   |   8 +
 ld/testsuite/ld-pe/pdb3-c13-info2.d   |   8 +
 ld/testsuite/ld-pe/pdb3-source-info.d |   7 +
 ld/testsuite/ld-pe/pdb3a.s            |  52 ++++
 ld/testsuite/ld-pe/pdb3b.s            |  52 ++++
 8 files changed, 711 insertions(+), 12 deletions(-)
 create mode 100644 ld/testsuite/ld-pe/pdb3-c13-info1.d
 create mode 100644 ld/testsuite/ld-pe/pdb3-c13-info2.d
 create mode 100644 ld/testsuite/ld-pe/pdb3-source-info.d
 create mode 100644 ld/testsuite/ld-pe/pdb3a.s
 create mode 100644 ld/testsuite/ld-pe/pdb3b.s

diff --git a/ld/pdb.c b/ld/pdb.c
index dc008bc38bb..d133b3e1aaa 100644
--- a/ld/pdb.c
+++ b/ld/pdb.c
@@ -46,6 +46,7 @@ struct string
   struct string *next;
   uint32_t hash;
   uint32_t offset;
+  uint32_t source_file_offset;
   size_t len;
   char s[];
 };
@@ -58,6 +59,18 @@ struct string_table
   htab_t hashmap;
 };
 
+struct mod_source_files
+{
+  uint16_t files_count;
+  struct string **files;
+};
+
+struct source_files_info
+{
+  uint16_t mod_count;
+  struct mod_source_files *mods;
+};
+
 /* Add a new stream to the PDB archive, and return its BFD.  */
 static bfd *
 add_stream (bfd *pdb, const char *name, uint16_t *stream_num)
@@ -400,6 +413,134 @@ get_arch_number (bfd *abfd)
   return IMAGE_FILE_MACHINE_I386;
 }
 
+/* Validate the DEBUG_S_FILECHKSMS entry within a module's .debug$S
+   section, and copy it to the module's symbol stream.  */
+static bool
+copy_filechksms (uint8_t *data, uint32_t size, char *string_table,
+		 struct string_table *strings, uint8_t *out,
+		 struct mod_source_files *mod_source)
+{
+  uint8_t *orig_data = data;
+  uint32_t orig_size = size;
+  uint16_t num_files = 0;
+  struct string **strptr;
+
+  bfd_putl32 (DEBUG_S_FILECHKSMS, out);
+  out += sizeof (uint32_t);
+
+  bfd_putl32 (size, out);
+  out += sizeof (uint32_t);
+
+  /* Calculate the number of files, and check for any overflows.  */
+
+  while (size > 0)
+    {
+      struct file_checksum *fc = (struct file_checksum *) data;
+      uint8_t padding;
+      size_t len;
+
+      if (size < sizeof (struct file_checksum))
+	{
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+
+      len = sizeof (struct file_checksum) + fc->checksum_length;
+
+      if (size < len)
+	{
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+
+      data += len;
+      size -= len;
+
+      if (len % sizeof (uint32_t))
+	padding = sizeof (uint32_t) - (len % sizeof (uint32_t));
+      else
+	padding = 0;
+
+      if (size < padding)
+	{
+	  bfd_set_error (bfd_error_bad_value);
+	  return false;
+	}
+
+      num_files++;
+
+      data += padding;
+      size -= padding;
+    }
+
+  /* Add the files to mod_source, so that they'll appear in the source
+     info substream.  */
+
+  if (num_files > 0)
+    {
+      uint16_t new_count = num_files + mod_source->files_count;
+
+      mod_source->files = xrealloc (mod_source->files,
+				    sizeof (struct string *) * new_count);
+
+      strptr = mod_source->files + mod_source->files_count;
+
+      mod_source->files_count += num_files;
+    }
+
+  /* Actually copy the data.  */
+
+  data = orig_data;
+  size = orig_size;
+
+  while (size > 0)
+    {
+      struct file_checksum *fc = (struct file_checksum *) data;
+      uint32_t string_off;
+      uint8_t padding;
+      size_t len;
+      struct string *str = NULL;
+
+      string_off = bfd_getl32 (&fc->file_id);
+      len = sizeof (struct file_checksum) + fc->checksum_length;
+
+      if (len % sizeof (uint32_t))
+	padding = sizeof (uint32_t) - (len % sizeof (uint32_t));
+      else
+	padding = 0;
+
+      /* Remap the "file ID", i.e. the offset in the module's string table,
+         so it points to the right place in the main string table.  */
+
+      if (string_table)
+	{
+	  char *fn = string_table + string_off;
+	  size_t fn_len = strlen (fn);
+	  uint32_t hash = calc_hash (fn, fn_len);
+	  void **slot;
+
+	  slot = htab_find_slot_with_hash (strings->hashmap, fn, hash,
+					   NO_INSERT);
+
+	  if (slot)
+	    str = (struct string *) *slot;
+	}
+
+      *strptr = str;
+      strptr++;
+
+      bfd_putl32 (str ? str->offset : 0, &fc->file_id);
+
+      memcpy (out, data, len + padding);
+
+      data += len + padding;
+      size -= len + padding;
+      out += len + padding;
+    }
+
+  return true;
+}
+
 /* Add a string to the strings table, if it's not already there.  */
 static void
 add_string (char *str, size_t len, struct string_table *strings)
@@ -420,6 +561,7 @@ add_string (char *str, size_t len, struct string_table *strings)
       s->next = NULL;
       s->hash = hash;
       s->offset = strings->strings_len;
+      s->source_file_offset = 0xffffffff;
       s->len = len;
       memcpy (s->s, str, len);
 
@@ -479,10 +621,15 @@ parse_string_table (bfd_byte *data, size_t size,
 
 /* Parse the .debug$S section within an object file.  */
 static bool
-handle_debugs_section (asection *s, bfd *mod, struct string_table *strings)
+handle_debugs_section (asection *s, bfd *mod, struct string_table *strings,
+		       uint8_t **dataptr, uint32_t *sizeptr,
+		       struct mod_source_files *mod_source)
 {
   bfd_byte *data = NULL;
   size_t off;
+  uint32_t c13_size = 0;
+  char *string_table = NULL;
+  uint8_t *buf, *bufptr;
 
   if (!bfd_get_full_section_contents (mod, s, &data))
     return false;
@@ -498,6 +645,8 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings)
 
   off = sizeof (uint32_t);
 
+  /* calculate size */
+
   while (off + sizeof (uint32_t) <= s->size)
     {
       uint32_t type, size;
@@ -526,9 +675,64 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings)
 
       switch (type)
 	{
+	case DEBUG_S_FILECHKSMS:
+	  c13_size += sizeof (uint32_t) + sizeof (uint32_t) + size;
+
+	  if (c13_size % sizeof (uint32_t))
+	    c13_size += sizeof (uint32_t) - (c13_size % sizeof (uint32_t));
+
+	  break;
+
 	case DEBUG_S_STRINGTABLE:
 	  parse_string_table (data + off, size, strings);
 
+	  string_table = (char *) data + off;
+
+	  break;
+	}
+
+      off += size;
+
+      if (off % sizeof (uint32_t))
+	off += sizeof (uint32_t) - (off % sizeof (uint32_t));
+    }
+
+  if (c13_size == 0)
+    {
+      free (data);
+      return true;
+    }
+
+  /* copy data */
+
+  buf = xmalloc (c13_size);
+  bufptr = buf;
+
+  off = sizeof (uint32_t);
+
+  while (off + sizeof (uint32_t) <= s->size)
+    {
+      uint32_t type, size;
+
+      type = bfd_getl32 (data + off);
+      off += sizeof (uint32_t);
+
+      size = bfd_getl32 (data + off);
+      off += sizeof (uint32_t);
+
+      switch (type)
+	{
+	case DEBUG_S_FILECHKSMS:
+	  if (!copy_filechksms (data + off, size, string_table,
+				strings, bufptr,
+				mod_source))
+	    {
+	      free (data);
+	      return false;
+	    }
+
+	  bufptr += sizeof (uint32_t) + sizeof (uint32_t) + size;
+
 	  break;
 	}
 
@@ -540,6 +744,23 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings)
 
   free (data);
 
+  if (*dataptr)
+    {
+      /* Append the C13 info to what's already there, if the module has
+	 multiple .debug$S sections.  */
+
+      *dataptr = xrealloc (*dataptr, *sizeptr + c13_size);
+      memcpy (*dataptr + *sizeptr, buf, c13_size);
+
+      free (buf);
+    }
+  else
+    {
+      *dataptr = buf;
+    }
+
+  *sizeptr += c13_size;
+
   return true;
 }
 
@@ -547,11 +768,15 @@ handle_debugs_section (asection *s, bfd *mod, struct string_table *strings)
    data for each object file.  */
 static bool
 populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
-			struct string_table *strings)
+			struct string_table *strings,
+			uint32_t *c13_info_size,
+			struct mod_source_files *mod_source)
 {
   uint8_t int_buf[sizeof (uint32_t)];
+  uint8_t *c13_info = NULL;
 
   *sym_byte_size = sizeof (uint32_t);
+  *c13_info_size = 0;
 
   /* Process .debug$S section(s).  */
 
@@ -559,8 +784,13 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
     {
       if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t))
 	{
-	  if (!handle_debugs_section (s, mod, strings))
+	  if (!handle_debugs_section (s, mod, strings, &c13_info,
+				      c13_info_size, mod_source))
+	    {
+	      free (c13_info);
+	      free (mod_source->files);
 	      return false;
+	    }
 	}
     }
 
@@ -569,7 +799,22 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
   bfd_putl32 (CV_SIGNATURE_C13, int_buf);
 
   if (bfd_bwrite (int_buf, sizeof (uint32_t), stream) != sizeof (uint32_t))
-    return false;
+    {
+      free (c13_info);
+      return false;
+    }
+
+  if (c13_info)
+    {
+      if (bfd_bwrite (c13_info, *c13_info_size, stream)
+	  != *c13_info_size)
+	{
+	  free (c13_info);
+	  return false;
+	}
+
+      free (c13_info);
+    }
 
   /* Write the global refs size.  */
 
@@ -584,9 +829,11 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
 /* Create the module info substream within the DBI.  */
 static bool
 create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
-			      uint32_t *size, struct string_table *strings)
+			      uint32_t *size, struct string_table *strings,
+			      struct source_files_info *source)
 {
   uint8_t *ptr;
+  unsigned int mod_num;
 
   static const char linker_fn[] = "* Linker *";
 
@@ -631,32 +878,54 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
 	len += 4 - (len % 4);
 
       *size += len;
+
+      source->mod_count++;
     }
 
   *data = xmalloc (*size);
 
   ptr = *data;
 
+  source->mods = xmalloc (source->mod_count
+			  * sizeof (struct mod_source_files));
+  memset (source->mods, 0,
+	  source->mod_count * sizeof (struct mod_source_files));
+
+  mod_num = 0;
+
   for (bfd *in = coff_data (abfd)->link_info->input_bfds; in;
        in = in->link.next)
     {
       struct module_info *mod = (struct module_info *) ptr;
       uint16_t stream_num;
       bfd *stream;
-      uint32_t sym_byte_size;
+      uint32_t sym_byte_size, c13_info_size;
       uint8_t *start = ptr;
 
       stream = add_stream (pdb, NULL, &stream_num);
 
       if (!stream)
 	{
+	  for (unsigned int i = 0; i < source->mod_count; i++)
+	    {
+	      free (source->mods[i].files);
+	    }
+
+	  free (source->mods);
 	  free (*data);
 	  return false;
 	}
 
       if (!populate_module_stream (stream, in, &sym_byte_size,
-				   strings))
+				   strings, &c13_info_size,
+				   &source->mods[mod_num]))
 	{
+	  for (unsigned int i = 0; i < source->mod_count; i++)
+	    {
+	      free (source->mods[i].files);
+	    }
+
+	  free (source->mods);
 	  free (*data);
 	  return false;
 	}
@@ -679,7 +948,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
       bfd_putl16 (stream_num, &mod->module_sym_stream);
       bfd_putl32 (sym_byte_size, &mod->sym_byte_size);
       bfd_putl32 (0, &mod->c11_byte_size);
-      bfd_putl32 (0, &mod->c13_byte_size);
+      bfd_putl32 (c13_info_size, &mod->c13_byte_size);
       bfd_putl16 (0, &mod->source_file_count);
       bfd_putl16 (0, &mod->padding);
       bfd_putl32 (0, &mod->unused2);
@@ -741,6 +1010,8 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
 	  memset (ptr, 0, 4 - ((ptr - start) % 4));
 	  ptr += 4 - ((ptr - start) % 4);
 	}
+
+      mod_num++;
     }
 
   return true;
@@ -855,6 +1126,114 @@ create_section_contrib_substream (bfd *abfd, void **data, uint32_t *size)
   return true;
 }
 
+/* The source info substream lives within the DBI stream, and lists the
+   source files for each object file (i.e. it's derived from the
+   DEBUG_S_FILECHKSMS parts of the .debug$S sections).  This is a bit
+   superfluous, as the filenames are also available in the C13 parts of
+   the module streams, but MSVC relies on it to work properly.  */
+static void
+create_source_info_substream (void **data, uint32_t *size,
+			      struct source_files_info *source)
+{
+  uint16_t dedupe_source_files_count = 0;
+  uint16_t source_files_count = 0;
+  uint32_t strings_len = 0;
+  uint8_t *ptr;
+
+  /* Loop through the source files, marking unique filenames.  The pointers
+     here are for entries in the main string table, and so have already
+     been deduplicated.  */
+
+  for (uint16_t i = 0; i < source->mod_count; i++)
+    {
+      for (uint16_t j = 0; j < source->mods[i].files_count; j++)
+	{
+	  if (source->mods[i].files[j])
+	    {
+	      if (source->mods[i].files[j]->source_file_offset == 0xffffffff)
+		{
+		  source->mods[i].files[j]->source_file_offset = strings_len;
+		  strings_len += source->mods[i].files[j]->len + 1;
+		  dedupe_source_files_count++;
+		}
+
+	      source_files_count++;
+	    }
+	}
+    }
+
+  *size = sizeof (uint16_t) + sizeof (uint16_t);
+  *size += (sizeof (uint16_t) + sizeof (uint16_t)) * source->mod_count;
+  *size += sizeof (uint32_t) * source_files_count;
+  *size += strings_len;
+
+  *data = xmalloc (*size);
+
+  ptr = (uint8_t *) *data;
+
+  /* Write header (module count and source file count).  */
+
+  bfd_putl16 (source->mod_count, ptr);
+  ptr += sizeof (uint16_t);
+
+  bfd_putl16 (dedupe_source_files_count, ptr);
+  ptr += sizeof (uint16_t);
+
+  /* Write "ModIndices".  As the LLVM documentation puts it, "this array is
+     present, but does not appear to be useful".  */
+
+  for (uint16_t i = 0; i < source->mod_count; i++)
+    {
+      bfd_putl16 (i, ptr);
+      ptr += sizeof (uint16_t);
+    }
+
+  /* Write source file count for each module.  */
+
+  for (uint16_t i = 0; i < source->mod_count; i++)
+    {
+      bfd_putl16 (source->mods[i].files_count, ptr);
+      ptr += sizeof (uint16_t);
+    }
+
+  /* For each module, write the offsets within the string table
+     for each source file.  */
+
+  for (uint16_t i = 0; i < source->mod_count; i++)
+    {
+      for (uint16_t j = 0; j < source->mods[i].files_count; j++)
+	{
+	  if (source->mods[i].files[j])
+	    {
+	      bfd_putl32 (source->mods[i].files[j]->source_file_offset, ptr);
+	      ptr += sizeof (uint32_t);
+	    }
+	}
+    }
+
+  /* Write the string table.  We set source_file_offset to a dummy value for
+     each entry we write, so we don't write duplicate filenames.  */
+
+  for (uint16_t i = 0; i < source->mod_count; i++)
+    {
+      for (uint16_t j = 0; j < source->mods[i].files_count; j++)
+	{
+	  if (source->mods[i].files[j]
+	      && source->mods[i].files[j]->source_file_offset != 0xffffffff)
+	    {
+	      memcpy (ptr, source->mods[i].files[j]->s,
+		      source->mods[i].files[j]->len);
+	      ptr += source->mods[i].files[j]->len;
+
+	      *ptr = 0;
+	      ptr++;
+
+	      source->mods[i].files[j]->source_file_offset = 0xffffffff;
+	    }
+	}
+    }
+}
+
 /* Stream 4 is the debug information (DBI) stream.  */
 static bool
 populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
@@ -865,19 +1244,38 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
 {
   struct pdb_dbi_stream_header h;
   struct optional_dbg_header opt;
-  void *mod_info, *sc;
-  uint32_t mod_info_size, sc_size;
+  void *mod_info, *sc, *source_info;
+  uint32_t mod_info_size, sc_size, source_info_size;
+  struct source_files_info source;
+
+  source.mod_count = 0;
+  source.mods = NULL;
 
   if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size,
-				     strings))
+				     strings, &source))
     return false;
 
   if (!create_section_contrib_substream (abfd, &sc, &sc_size))
     {
+      for (unsigned int i = 0; i < source.mod_count; i++)
+	{
+	  free (source.mods[i].files);
+	}
+      free (source.mods);
+
       free (mod_info);
       return false;
     }
 
+  create_source_info_substream (&source_info, &source_info_size,
+				&source);
+
+  for (unsigned int i = 0; i < source.mod_count; i++)
+    {
+      free (source.mods[i].files);
+    }
+  free (source.mods);
+
   bfd_putl32 (0xffffffff, &h.version_signature);
   bfd_putl32 (DBI_STREAM_VERSION_70, &h.version_header);
   bfd_putl32 (1, &h.age);
@@ -890,7 +1288,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
   bfd_putl32 (mod_info_size, &h.mod_info_size);
   bfd_putl32 (sc_size, &h.section_contribution_size);
   bfd_putl32 (0, &h.section_map_size);
-  bfd_putl32 (0, &h.source_info_size);
+  bfd_putl32 (source_info_size, &h.source_info_size);
   bfd_putl32 (0, &h.type_server_map_size);
   bfd_putl32 (0, &h.mfc_type_server_index);
   bfd_putl32 (sizeof (opt), &h.optional_dbg_header_size);
@@ -901,6 +1299,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
 
   if (bfd_bwrite (&h, sizeof (h), stream) != sizeof (h))
     {
+      free (source_info);
       free (sc);
       free (mod_info);
       return false;
@@ -908,6 +1307,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
 
   if (bfd_bwrite (mod_info, mod_info_size, stream) != mod_info_size)
     {
+      free (source_info);
       free (sc);
       free (mod_info);
       return false;
@@ -917,12 +1317,21 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
 
   if (bfd_bwrite (sc, sc_size, stream) != sc_size)
     {
+      free (source_info);
       free (sc);
       return false;
     }
 
   free (sc);
 
+  if (bfd_bwrite (source_info, source_info_size, stream) != source_info_size)
+    {
+      free (source_info);
+      return false;
+    }
+
+  free (source_info);
+
   bfd_putl16 (0xffff, &opt.fpo_stream);
   bfd_putl16 (0xffff, &opt.exception_stream);
   bfd_putl16 (0xffff, &opt.fixup_stream);
diff --git a/ld/pdb.h b/ld/pdb.h
index 611f71041c0..e8f673c24a0 100644
--- a/ld/pdb.h
+++ b/ld/pdb.h
@@ -156,6 +156,7 @@ struct optional_dbg_header
 #define CV_SIGNATURE_C13		4
 
 #define DEBUG_S_STRINGTABLE		0xf3
+#define DEBUG_S_FILECHKSMS		0xf4
 
 #define STRING_TABLE_SIGNATURE		0xeffeeffe
 #define STRING_TABLE_VERSION		1
@@ -200,6 +201,14 @@ struct module_info
   uint32_t pdb_file_path_name_index;
 };
 
+/* filedata in dumpsym7.cpp */
+struct file_checksum
+{
+  uint32_t file_id;
+  uint8_t checksum_length;
+  uint8_t checksum_type;
+} ATTRIBUTE_PACKED;
+
 extern bool create_pdb_file (bfd *, const char *, const unsigned char *);
 
 #endif
diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp
index 09e9b4a8809..9dab41110ac 100644
--- a/ld/testsuite/ld-pe/pdb.exp
+++ b/ld/testsuite/ld-pe/pdb.exp
@@ -824,6 +824,160 @@ proc test3 { } {
     }
 }
 
+proc extract_c13_info { pdb mod_info } {
+    global ar
+
+    binary scan [string range $mod_info 34 35] s module_sym_stream
+    binary scan [string range $mod_info 36 39] i sym_byte_size
+    binary scan [string range $mod_info 40 43] i c11_byte_size
+    binary scan [string range $mod_info 44 47] i c13_byte_size
+
+    set index_str [format "%04x" $module_sym_stream]
+
+    set exec_output [run_host_cmd "$ar" "x --output tmpdir $pdb $index_str"]
+
+    if ![string match "" $exec_output] {
+	return ""
+    }
+
+    set fi [open tmpdir/$index_str]
+    fconfigure $fi -translation binary
+
+    seek $fi [expr $sym_byte_size + $c11_byte_size]
+
+    set data [read $fi $c13_byte_size]
+
+    close $fi
+
+    return $data
+}
+
+proc test4 { } {
+    global as
+    global ar
+    global ld
+    global objdump
+    global srcdir
+    global subdir
+
+    if ![ld_assemble $as $srcdir/$subdir/pdb3a.s tmpdir/pdb3a.o] {
+	unsupported "Build pdb3a.o"
+	return
+    }
+
+    if ![ld_assemble $as $srcdir/$subdir/pdb3b.s tmpdir/pdb3b.o] {
+	unsupported "Build pdb3b.o"
+	return
+    }
+
+    if ![ld_link $ld "tmpdir/pdb3.exe" "--pdb=tmpdir/pdb3.pdb tmpdir/pdb3a.o tmpdir/pdb3b.o"] {
+	unsupported "Create PE image with PDB file"
+	return
+    }
+
+    # read relevant bits from DBI stream
+
+    set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb3.pdb 0003"]
+
+    if ![string match "" $exec_output] {
+	fail "Could not extract DBI stream"
+	return
+    } else {
+	pass "Extracted DBI stream"
+    }
+
+    set fi [open tmpdir/0003]
+    fconfigure $fi -translation binary
+
+    seek $fi 24
+
+    # read substream sizes
+
+    set data [read $fi 4]
+    binary scan $data i mod_info_size
+
+    set data [read $fi 4]
+    binary scan $data i section_contribution_size
+
+    set data [read $fi 4]
+    binary scan $data i section_map_size
+
+    set data [read $fi 4]
+    binary scan $data i source_info_size
+
+    seek $fi 24 current
+
+    set mod_info [read $fi $mod_info_size]
+
+    seek $fi [expr $section_contribution_size + $section_map_size] current
+
+    set source_info [read $fi $source_info_size]
+
+    close $fi
+
+    # check source info substream
+
+    set fi [open tmpdir/pdb3-source-info w]
+    fconfigure $fi -translation binary
+    puts -nonewline $fi $source_info
+    close $fi
+
+    set exp [file_contents "$srcdir/$subdir/pdb3-source-info.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-source-info"]
+
+    if [string match $exp $got] {
+	pass "Correct source info substream"
+    } else {
+	fail "Incorrect source info substream"
+    }
+
+    # check C13 info in first module
+
+    set c13_info [extract_c13_info "tmpdir/pdb3.pdb" [string range $mod_info 0 63]]
+
+    set fi [open tmpdir/pdb3-c13-info1 w]
+    fconfigure $fi -translation binary
+    puts -nonewline $fi $c13_info
+    close $fi
+
+    set exp [file_contents "$srcdir/$subdir/pdb3-c13-info1.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-c13-info1"]
+
+    if [string match $exp $got] {
+	pass "Correct C13 info for first module"
+    } else {
+	fail "Incorrect C13 info for first module"
+    }
+
+    # check C13 info in second module
+
+    set fn1_end [string first \000 $mod_info 64]
+    set fn2_end [string first \000 $mod_info [expr $fn1_end + 1]]
+
+    set off [expr $fn2_end + 1]
+
+    if { [expr $off % 4] != 0 } {
+	set off [expr $off + 4 - ($off % 4)]
+    }
+
+    set c13_info [extract_c13_info "tmpdir/pdb3.pdb" [string range $mod_info $off [expr $off + 63]]]
+
+    set fi [open tmpdir/pdb3-c13-info2 w]
+    fconfigure $fi -translation binary
+    puts -nonewline $fi $c13_info
+    close $fi
+
+    set exp [file_contents "$srcdir/$subdir/pdb3-c13-info2.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb3-c13-info2"]
+
+    if [string match $exp $got] {
+	pass "Correct C13 info for second module"
+    } else {
+	fail "Incorrect C13 info for second module"
+    }
+}
+
 test1
 test2
 test3
+test4
diff --git a/ld/testsuite/ld-pe/pdb3-c13-info1.d b/ld/testsuite/ld-pe/pdb3-c13-info1.d
new file mode 100644
index 00000000000..f92062ba4e5
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb3-c13-info1.d
@@ -0,0 +1,8 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 f4000000 30000000 02000000 10016745  ....0.........gE
+ 0010 2301efcd ab8998ba dcfe1023 45670000  #..........#Eg..
+ 0020 06000000 100198ba dcfe1023 45676745  ...........#EggE
+ 0030 2301efcd ab890000                    #.......        
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb3-c13-info2.d b/ld/testsuite/ld-pe/pdb3-c13-info2.d
new file mode 100644
index 00000000000..1c33ce1e798
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb3-c13-info2.d
@@ -0,0 +1,8 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 f4000000 30000000 06000000 100198ba  ....0...........
+ 0010 dcfe1023 45676745 2301efcd ab890000  ...#EggE#.......
+ 0020 0a000000 10013b2a 19087f6e 5d4c4c5d  ......;*...n]LL]
+ 0030 6e7f0819 2a3b0000                    n...*;..        
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb3-source-info.d b/ld/testsuite/ld-pe/pdb3-source-info.d
new file mode 100644
index 00000000000..5b7d58cfa0c
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb3-source-info.d
@@ -0,0 +1,7 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 03000300 00000100 02000200 02000000  ................
+ 0010 00000000 04000000 04000000 08000000  ................
+ 0020 666f6f00 62617200 62617a00           foo.bar.baz.    
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb3a.s b/ld/testsuite/ld-pe/pdb3a.s
new file mode 100644
index 00000000000..71795b53a66
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb3a.s
@@ -0,0 +1,52 @@
+.equ CV_SIGNATURE_C13, 4
+.equ DEBUG_S_STRINGTABLE, 0xf3
+.equ DEBUG_S_FILECHKSMS, 0xf4
+.equ CHKSUM_TYPE_MD5, 1
+
+.equ NUM_MD5_BYTES, 16
+
+.section ".debug$S", "rn"
+.long CV_SIGNATURE_C13
+.long DEBUG_S_STRINGTABLE
+.long .strings_end - .strings_start
+
+.strings_start:
+
+.asciz ""
+
+.src1:
+.asciz "foo"
+
+.src2:
+.asciz "bar"
+
+.strings_end:
+
+.balign 4
+
+.long DEBUG_S_FILECHKSMS
+.long .chksms_end - .chksms_start
+
+.chksms_start:
+
+.long .src1 - .strings_start
+.byte NUM_MD5_BYTES
+.byte CHKSUM_TYPE_MD5
+.long 0x01234567
+.long 0x89abcdef
+.long 0xfedcba98
+.long 0x67452310
+.short 0 # padding
+
+.long .src2 - .strings_start
+.byte NUM_MD5_BYTES
+.byte CHKSUM_TYPE_MD5
+.long 0xfedcba98
+.long 0x67452310
+.long 0x01234567
+.long 0x89abcdef
+.short 0 # padding
+
+.chksms_end:
+
+.balign 4
diff --git a/ld/testsuite/ld-pe/pdb3b.s b/ld/testsuite/ld-pe/pdb3b.s
new file mode 100644
index 00000000000..fffb1150c88
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb3b.s
@@ -0,0 +1,52 @@
+.equ CV_SIGNATURE_C13, 4
+.equ DEBUG_S_STRINGTABLE, 0xf3
+.equ DEBUG_S_FILECHKSMS, 0xf4
+.equ CHKSUM_TYPE_MD5, 1
+
+.equ NUM_MD5_BYTES, 16
+
+.section ".debug$S", "rn"
+.long CV_SIGNATURE_C13
+.long DEBUG_S_STRINGTABLE
+.long .strings_end - .strings_start
+
+.strings_start:
+
+.asciz ""
+
+.src1:
+.asciz "bar"
+
+.src2:
+.asciz "baz"
+
+.strings_end:
+
+.balign 4
+
+.long DEBUG_S_FILECHKSMS
+.long .chksms_end - .chksms_start
+
+.chksms_start:
+
+.long .src1 - .strings_start
+.byte NUM_MD5_BYTES
+.byte CHKSUM_TYPE_MD5
+.long 0xfedcba98
+.long 0x67452310
+.long 0x01234567
+.long 0x89abcdef
+.short 0 # padding
+
+.long .src2 - .strings_start
+.byte NUM_MD5_BYTES
+.byte CHKSUM_TYPE_MD5
+.long 0x08192a3b
+.long 0x4c5d6e7f
+.long 0x7f6e5d4c
+.long 0x3b2a1908
+.short 0 # padding
+
+.chksms_end:
+
+.balign 4
-- 
2.37.4


  reply	other threads:[~2022-11-25  2:54 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-25  2:53 [PATCH v2] ld: Generate PDB string table Mark Harmstone
2022-11-25  2:54 ` Mark Harmstone [this message]
2022-11-27  2:38   ` [PATCH] ld: Fix segfault in populate_publics_stream Mark Harmstone
2022-11-27  2:38     ` [PATCH] ld: Write DEBUG_S_LINES entries in PDB file Mark Harmstone
2022-11-29  0:10       ` [PATCH] ld: Write types into TPI stream of PDB Mark Harmstone
2022-11-29  0:10         ` [PATCH] ld: Write types into IPI " Mark Harmstone
2022-11-29  0:10         ` [PATCH] ld: Parse LF_UDT_SRC_LINE records when creating PDB file Mark Harmstone
2022-12-05  1:53           ` [PATCH] ld: Write globals stream in PDB Mark Harmstone
2022-12-05  1:53             ` [PATCH] ld: Copy other symbols into PDB file Mark Harmstone
2022-12-05  1:53             ` [PATCH] ld: Write linker symbols in PDB Mark Harmstone
2022-12-06 17:07             ` [PATCH] ld: Write globals stream " Nick Clifton
2022-12-06 17:52               ` Mark Harmstone
2022-12-08 11:00                 ` Nick Clifton
2022-12-09  1:11               ` Mark Harmstone
2022-11-28 14:54     ` [PATCH] ld: Fix segfault in populate_publics_stream Jan Beulich
2022-11-28 17:53       ` Mark Harmstone
2022-11-29  9:00         ` Jan Beulich
2022-11-29 17:47           ` Mark Harmstone
2022-11-30  7:00             ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221125025433.26818-1-mark@harmstone.com \
    --to=mark@harmstone.com \
    --cc=binutils@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).