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 types into IPI stream of PDB
Date: Tue, 29 Nov 2022 00:10:14 +0000	[thread overview]
Message-ID: <20221129001015.21775-2-mark@harmstone.com> (raw)
In-Reply-To: <20221129001015.21775-1-mark@harmstone.com>

This covers the other types, that are instead written to the ID
information stream.

---
 ld/pdb.c                                 | 204 +++++++++++++++++++--
 ld/pdb.h                                 |  45 ++++-
 ld/testsuite/ld-pe/pdb-types2-hashlist.d |   8 +
 ld/testsuite/ld-pe/pdb-types2-skiplist.d |   5 +
 ld/testsuite/ld-pe/pdb-types2-typelist.d |  20 ++
 ld/testsuite/ld-pe/pdb-types2a.s         |  42 +++++
 ld/testsuite/ld-pe/pdb-types2b.s         | 221 +++++++++++++++++++++++
 ld/testsuite/ld-pe/pdb.exp               | 172 ++++++++++++++++++
 8 files changed, 699 insertions(+), 18 deletions(-)
 create mode 100644 ld/testsuite/ld-pe/pdb-types2-hashlist.d
 create mode 100644 ld/testsuite/ld-pe/pdb-types2-skiplist.d
 create mode 100644 ld/testsuite/ld-pe/pdb-types2-typelist.d
 create mode 100644 ld/testsuite/ld-pe/pdb-types2a.s
 create mode 100644 ld/testsuite/ld-pe/pdb-types2b.s

diff --git a/ld/pdb.c b/ld/pdb.c
index 979ea126aa5..6584ccd9911 100644
--- a/ld/pdb.c
+++ b/ld/pdb.c
@@ -1097,13 +1097,16 @@ is_name_anonymous (char *name, size_t len)
    already seen add it to types (for TPI types) or ids (for IPI types).  */
 static bool
 handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
-	     uint32_t num_types, struct types *types)
+	     uint32_t num_types, struct types *types,
+	     struct types *ids)
 {
   uint16_t size, type;
   void **slot;
   hashval_t hash;
   bool other_hash = false;
   uint32_t cv_hash;
+  struct types *t;
+  bool ipi = false;
 
   size = bfd_getl16 (data) + sizeof (uint16_t);
   type = bfd_getl16 (data + sizeof (uint16_t));
@@ -1904,6 +1907,168 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
       /* Does not reference any types, nothing to be done.  */
       break;
 
+    case LF_STRING_ID:
+      {
+	struct lf_string_id *str = (struct lf_string_id *) data;
+	size_t string_len;
+
+	if (size < offsetof (struct lf_string_id, string))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_STRING_ID\n"));
+	    return false;
+	  }
+
+	if (!remap_type (&str->substring, map, type_num, num_types))
+	  return false;
+
+	string_len = strnlen (str->string,
+			      size - offsetof (struct lf_string_id, string));
+
+	if (string_len == size - offsetof (struct lf_string_id, string))
+	  {
+	    einfo (_("%P: warning: string for LF_STRING_ID has no"
+		     " terminating zero\n"));
+	    return false;
+	  }
+
+	ipi = true;
+
+	break;
+      }
+
+    case LF_SUBSTR_LIST:
+      {
+	uint32_t num_entries;
+	struct lf_arglist *ssl = (struct lf_arglist *) data;
+
+	if (size < offsetof (struct lf_arglist, args))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_SUBSTR_LIST\n"));
+	    return false;
+	  }
+
+	num_entries = bfd_getl32 (&ssl->num_entries);
+
+	if (size < offsetof (struct lf_arglist, args)
+		   + (num_entries * sizeof (uint32_t)))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_SUBSTR_LIST\n"));
+	    return false;
+	  }
+
+	for (uint32_t i = 0; i < num_entries; i++)
+	  {
+	    if (!remap_type (&ssl->args[i], map, type_num, num_types))
+	      return false;
+	  }
+
+	ipi = true;
+
+	break;
+      }
+
+    case LF_BUILDINFO:
+      {
+	uint16_t num_entries;
+	struct lf_build_info *bi = (struct lf_build_info *) data;
+
+	if (size < offsetof (struct lf_build_info, strings))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_BUILDINFO\n"));
+	    return false;
+	  }
+
+	num_entries = bfd_getl16 (&bi->count);
+
+	if (size < offsetof (struct lf_build_info, strings)
+		   + (num_entries * sizeof (uint32_t)))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_BUILDINFO\n"));
+	    return false;
+	  }
+
+	for (uint32_t i = 0; i < num_entries; i++)
+	  {
+	    if (!remap_type (&bi->strings[i], map, type_num, num_types))
+	      return false;
+	  }
+
+	ipi = true;
+
+	break;
+      }
+
+    case LF_FUNC_ID:
+      {
+	struct lf_func_id *func = (struct lf_func_id *) data;
+	size_t name_len;
+
+	if (size < offsetof (struct lf_func_id, name))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_FUNC_ID\n"));
+	    return false;
+	  }
+
+	if (!remap_type (&func->parent_scope, map, type_num, num_types))
+	  return false;
+
+	if (!remap_type (&func->function_type, map, type_num, num_types))
+	  return false;
+
+	name_len = strnlen (func->name,
+			    size - offsetof (struct lf_func_id, name));
+
+	if (name_len == size - offsetof (struct lf_func_id, name))
+	  {
+	    einfo (_("%P: warning: string for LF_FUNC_ID has no"
+		     " terminating zero\n"));
+	    return false;
+	  }
+
+	ipi = true;
+
+	break;
+      }
+
+    case LF_MFUNC_ID:
+      {
+	struct lf_mfunc_id *mfunc = (struct lf_mfunc_id *) data;
+	size_t name_len;
+
+	if (size < offsetof (struct lf_mfunc_id, name))
+	  {
+	    einfo (_("%P: warning: truncated CodeView type record"
+		     " LF_MFUNC_ID\n"));
+	    return false;
+	  }
+
+	if (!remap_type (&mfunc->parent_type, map, type_num, num_types))
+	  return false;
+
+	if (!remap_type (&mfunc->function_type, map, type_num, num_types))
+	  return false;
+
+	name_len = strnlen (mfunc->name,
+			    size - offsetof (struct lf_mfunc_id, name));
+
+	if (name_len == size - offsetof (struct lf_mfunc_id, name))
+	  {
+	    einfo (_("%P: warning: string for LF_MFUNC_ID has no"
+		     " terminating zero\n"));
+	    return false;
+	  }
+
+	ipi = true;
+
+	break;
+      }
+
     default:
       einfo (_("%P: warning: unrecognized CodeView type %v\n"), type);
       return false;
@@ -1911,7 +2076,9 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
 
   hash = iterative_hash (data, size, 0);
 
-  slot = htab_find_slot_with_hash (types->hashmap, data, hash, INSERT);
+  t = ipi ? ids : types;
+
+  slot = htab_find_slot_with_hash (t->hashmap, data, hash, INSERT);
   if (!slot)
     return false;
 
@@ -1924,7 +2091,7 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
       e = (struct type_entry *) *slot;
 
       e->next = NULL;
-      e->index = types->num_types;
+      e->index = t->num_types;
 
       if (other_hash)
 	e->cv_hash = cv_hash;
@@ -1933,16 +2100,16 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
 
       memcpy (e->data, data, size);
 
-      if (types->last)
-	types->last->next = e;
+      if (t->last)
+	t->last->next = e;
       else
-	types->first = e;
+	t->first = e;
 
-      types->last = e;
+      t->last = e;
 
       map[type_num] = e;
 
-      types->num_types++;
+      t->num_types++;
     }
   else /* duplicate */
     {
@@ -1955,7 +2122,8 @@ handle_type (uint8_t *data, struct type_entry **map, uint32_t type_num,
 /* Parse the .debug$T section of a module, and pass any type definitions
    found to handle_type.  */
 static bool
-handle_debugt_section (asection *s, bfd *mod, struct types *types)
+handle_debugt_section (asection *s, bfd *mod, struct types *types,
+		       struct types *ids)
 {
   bfd_byte *data = NULL;
   size_t off;
@@ -2012,7 +2180,7 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types)
 
       size = bfd_getl16 (data + off);
 
-      if (!handle_type (data + off, map, type_num, num_types, types))
+      if (!handle_type (data + off, map, type_num, num_types, types, ids))
 	{
 	  free (data);
 	  free (map);
@@ -2037,7 +2205,8 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
 			struct string_table *strings,
 			uint32_t *c13_info_size,
 			struct mod_source_files *mod_source,
-			bfd *abfd, struct types *types)
+			bfd *abfd, struct types *types,
+			struct types *ids)
 {
   uint8_t int_buf[sizeof (uint32_t)];
   uint8_t *c13_info = NULL;
@@ -2061,7 +2230,7 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size,
 	}
       else if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t))
 	{
-	  if (!handle_debugt_section (s, mod, types))
+	  if (!handle_debugt_section (s, mod, types, ids))
 	    {
 	      free (c13_info);
 	      free (mod_source->files);
@@ -2107,7 +2276,7 @@ static bool
 create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
 			      uint32_t *size, struct string_table *strings,
 			      struct source_files_info *source,
-			      struct types *types)
+			      struct types *types, struct types *ids)
 {
   uint8_t *ptr;
   unsigned int mod_num;
@@ -2196,7 +2365,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data,
       if (!populate_module_stream (stream, in, &sym_byte_size,
 				   strings, &c13_info_size,
 				   &source->mods[mod_num], abfd,
-				   types))
+				   types, ids))
 	{
 	  for (unsigned int i = 0; i < source->mod_count; i++)
 	    {
@@ -2519,7 +2688,8 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
 		     uint16_t sym_rec_stream_num,
 		     uint16_t publics_stream_num,
 		     struct string_table *strings,
-		     struct types *types)
+		     struct types *types,
+		     struct types *ids)
 {
   struct pdb_dbi_stream_header h;
   struct optional_dbg_header opt;
@@ -2531,7 +2701,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb,
   source.mods = NULL;
 
   if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size,
-				     strings, &source, types))
+				     strings, &source, types, ids))
     return false;
 
   if (!create_section_contrib_substream (abfd, &sc, &sc_size))
@@ -3206,7 +3376,7 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid)
 
   if (!populate_dbi_stream (dbi_stream, abfd, pdb, section_header_stream_num,
 			    sym_rec_stream_num, publics_stream_num,
-			    &strings, &types))
+			    &strings, &types, &ids))
     {
       einfo (_("%P: warning: cannot populate DBI stream "
 	       "in PDB file: %E\n"));
diff --git a/ld/pdb.h b/ld/pdb.h
index ecc26c1c87a..7d87a3fef07 100644
--- a/ld/pdb.h
+++ b/ld/pdb.h
@@ -54,6 +54,11 @@
 #define LF_METHOD			0x150f
 #define LF_NESTTYPE			0x1510
 #define LF_ONEMETHOD			0x1511
+#define LF_FUNC_ID			0x1601
+#define LF_MFUNC_ID			0x1602
+#define LF_BUILDINFO			0x1603
+#define LF_SUBSTR_LIST			0x1604
+#define LF_STRING_ID			0x1605
 
 #define LF_CHAR				0x8000
 #define LF_SHORT			0x8001
@@ -265,7 +270,7 @@ struct lf_pointer
   uint32_t attributes;
 } ATTRIBUTE_PACKED;
 
-/* lfArgList in cvinfo.h */
+/* lfArgList in cvinfo.h (used for both LF_ARGLIST and LF_SUBSTR_LIST) */
 struct lf_arglist
 {
   uint16_t size;
@@ -474,6 +479,44 @@ struct lf_nest_type
   char name[];
 } ATTRIBUTE_PACKED;
 
+/* lfStringId in cvinfo.h */
+struct lf_string_id
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t substring;
+  char string[];
+} ATTRIBUTE_PACKED;
+
+/* lfBuildInfo in cvinfo.h */
+struct lf_build_info
+{
+  uint16_t size;
+  uint16_t kind;
+  uint16_t count;
+  uint32_t strings[];
+} ATTRIBUTE_PACKED;
+
+/* lfFuncId in cvinfo.h */
+struct lf_func_id
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t parent_scope;
+  uint32_t function_type;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* lfMFuncId in cvinfo.h */
+struct lf_mfunc_id
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t parent_type;
+  uint32_t function_type;
+  char name[];
+} ATTRIBUTE_PACKED;
+
 extern bool create_pdb_file (bfd *, const char *, const unsigned char *);
 
 #endif
diff --git a/ld/testsuite/ld-pe/pdb-types2-hashlist.d b/ld/testsuite/ld-pe/pdb-types2-hashlist.d
new file mode 100644
index 00000000000..71d9045fbbd
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb-types2-hashlist.d
@@ -0,0 +1,8 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 75cf0100 8d660300 f2a20300 aea00000  *
+ 0010 ef990300 223d0000 d6b60000 24070100  *
+ 0020 7f220100 f6d10200 16100200 010a0300  *
+ 0030 0b4f0300 12690300 a56d0300           *
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb-types2-skiplist.d b/ld/testsuite/ld-pe/pdb-types2-skiplist.d
new file mode 100644
index 00000000000..52c10fa501d
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb-types2-skiplist.d
@@ -0,0 +1,5 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 00100000 00000000                    *
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb-types2-typelist.d b/ld/testsuite/ld-pe/pdb-types2-typelist.d
new file mode 100644
index 00000000000..d0fd26e0fa4
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb-types2-typelist.d
@@ -0,0 +1,20 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 0e000516 00000000 74657374 00f3f2f1  ........test....
+ 0010 0a000516 00000000 666f6f00 0a000516  ........foo.....
+ 0020 00000000 62617200 0e000416 02000000  ....bar.........
+ 0030 01100000 02100000 0a000516 03100000  ................
+ 0040 62617a00 0e000516 00000000 2f746d70  baz........./tmp
+ 0050 00f3f2f1 0a000516 00000000 67636300  ............gcc.
+ 0060 0e000516 00000000 746d702e 6300f2f1  ........tmp.c...
+ 0070 0e000516 00000000 746d702e 70646200  ........tmp.pdb.
+ 0080 12000516 00000000 2d67636f 64657669  ........-gcodevi
+ 0090 657700f1 1a000316 05000510 00000610  ew..............
+ 00a0 00000710 00000810 00000910 0000f2f1  ................
+ 00b0 12000516 00000000 6e616d65 73706163  ........namespac
+ 00c0 6500f2f1 12000116 00000000 01100000  e...............
+ 00d0 66756e63 3100f2f1 12000116 0b100000  func1...........
+ 00e0 01100000 66756e63 3200f2f1 12000216  ....func2.......
+ 00f0 02100000 04100000 6d657468 6f6400f1  ........method..
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb-types2a.s b/ld/testsuite/ld-pe/pdb-types2a.s
new file mode 100644
index 00000000000..e11843ae575
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb-types2a.s
@@ -0,0 +1,42 @@
+.equ CV_SIGNATURE_C13, 4
+
+.equ T_VOID, 0x0003
+.equ T_INT4, 0x0074
+
+.equ LF_PROCEDURE, 0x1008
+.equ LF_MFUNCTION, 0x1009
+.equ LF_POINTER, 0x1002
+.equ LF_ARGLIST, 0x1201
+.equ LF_FIELDLIST, 0x1203
+.equ LF_CLASS, 0x1504
+.equ LF_ONEMETHOD, 0x1511
+.equ LF_FUNC_ID, 0x1601
+.equ LF_MFUNC_ID, 0x1602
+.equ LF_BUILDINFO, 0x1603
+.equ LF_SUBSTR_LIST, 0x1604
+.equ LF_STRING_ID, 0x1605
+
+.equ CV_PTR_64, 0xc
+
+.section ".debug$T", "rn"
+
+.long CV_SIGNATURE_C13
+
+# Type 1000, string "test"
+.string1:
+.short .string2 - .string1 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "test"
+.byte 0xf3
+.byte 0xf2
+.byte 0xf1
+
+# Type 1001, string "foo"
+.string2:
+.short .types_end - .string2 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "foo"
+
+.types_end:
diff --git a/ld/testsuite/ld-pe/pdb-types2b.s b/ld/testsuite/ld-pe/pdb-types2b.s
new file mode 100644
index 00000000000..33541729f63
--- /dev/null
+++ b/ld/testsuite/ld-pe/pdb-types2b.s
@@ -0,0 +1,221 @@
+.equ CV_SIGNATURE_C13, 4
+
+.equ T_VOID, 0x0003
+.equ T_INT4, 0x0074
+
+.equ LF_PROCEDURE, 0x1008
+.equ LF_MFUNCTION, 0x1009
+.equ LF_POINTER, 0x1002
+.equ LF_ARGLIST, 0x1201
+.equ LF_FIELDLIST, 0x1203
+.equ LF_CLASS, 0x1504
+.equ LF_ONEMETHOD, 0x1511
+.equ LF_FUNC_ID, 0x1601
+.equ LF_MFUNC_ID, 0x1602
+.equ LF_BUILDINFO, 0x1603
+.equ LF_SUBSTR_LIST, 0x1604
+.equ LF_STRING_ID, 0x1605
+
+.equ CV_PTR_64, 0xc
+
+.section ".debug$T", "rn"
+
+.long CV_SIGNATURE_C13
+
+# Type 1000, string "foo"
+.string1:
+.short .string2 - .string1 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "foo"
+
+# Type 1001, string "bar"
+.string2:
+.short .substrlist1 - .string2 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "bar"
+
+# Type 1002, substr list of "foo" and "bar"
+.substrlist1:
+.short .string3 - .substrlist1 - 2
+.short LF_SUBSTR_LIST
+.long 2 # count
+.long 0x1000
+.long 0x1001
+
+# Type 1003, string "baz" referencing substr list 1002
+.string3:
+.short .string4 - .string3 - 2
+.short LF_STRING_ID
+.long 0x1002
+.asciz "baz"
+
+# Type 1004, string "/tmp" (build directory)
+.string4:
+.short .string5 - .string4 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "/tmp"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1005, string "gcc" (compiler)
+.string5:
+.short .string6 - .string5 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "gcc"
+
+# Type 1006, string "tmp.c" (source file)
+.string6:
+.short .string7 - .string6 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "tmp.c"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1007, string "tmp.pdb" (PDB file)
+.string7:
+.short .string8 - .string7 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "tmp.pdb"
+
+# Type 1008, string "-gcodeview" (command arguments)
+.string8:
+.short .buildinfo1 - .string8 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "-gcodeview"
+.byte 0xf1 # padding
+
+# The 1009, build info
+.buildinfo1:
+.short .string9 - .buildinfo1 - 2
+.short LF_BUILDINFO
+.short 5 # count
+.long 0x1004 # build directory
+.long 0x1005 # compiler
+.long 0x1006 # source file
+.long 0x1007 # PDB file
+.long 0x1008 # command arguments
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 100a, string "namespace"
+.string9:
+.short .arglist1 - .string9 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "namespace"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 100b, arg list of type T_INT4
+.arglist1:
+.short .proc1 - .arglist1 - 2
+.short LF_ARGLIST
+.long 1 # no. entries
+.long T_INT4
+
+# Type 100c, procedure, return type T_VOID, arg list 100b
+.proc1:
+.short .func1 - .proc1 - 2
+.short LF_PROCEDURE
+.long T_VOID
+.byte 0 # calling convention
+.byte 0 # attributes
+.short 1 # no. parameters
+.long 0x100b
+
+# Type 100d, function "func1"
+.func1:
+.short .func2 - .func1 - 2
+.short LF_FUNC_ID
+.long 0 # parent scope
+.long 0x100c # type
+.asciz "func1"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 100e, function "func2" within scope "namespace"
+.func2:
+.short .class1 - .func2 - 2
+.short LF_FUNC_ID
+.long 0x100a # parent scope
+.long 0x100c # type
+.asciz "func2"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 100f, forward declaration of class foo
+.class1:
+.short .ptr1 - .class1 - 2
+.short LF_CLASS
+.short 0 # no. members
+.short 0x80 # property (has unique name, forward declaration)
+.long 0 # field list
+.long 0 # type derived from
+.long 0 # type of vshape table
+.short 0 # size
+.asciz "foo" # name
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1010, pointer to 100f
+.ptr1:
+.short .mfunction1 - .ptr1 - 2
+.short LF_POINTER
+.long 0x100f
+.long (8 << 13) | CV_PTR_64
+
+# Type 1011, member function of 100f, return type void, arg list 100b
+.mfunction1:
+.short .fieldlist1 - .mfunction1 - 2
+.short LF_MFUNCTION
+.long T_VOID
+.long 0x100f
+.long 0x1010 # type of "this" pointer
+.byte 0 # calling convention
+.byte 0 # attributes
+.short 1 # no. parameters
+.long 0x100b # arg list
+.long 0 # "this" adjustment
+
+# Type 1012, field list for class foo
+.fieldlist1:
+.short .class2 - .fieldlist1 - 2
+.short LF_FIELDLIST
+.short LF_ONEMETHOD
+.short 0 # method attribute
+.long 0x1010 # method type
+.asciz "method"
+.byte 0xf1
+
+# Type 1013, actual declaration of class foo
+.class2:
+.short .mfunc1 - .class2 - 2
+.short LF_CLASS
+.short 0 # no. members
+.short 0 # property
+.long 0x1012 # field list
+.long 0 # type derived from
+.long 0 # type of vshape table
+.short 0 # size
+.asciz "foo" # name
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1014, function "method" within class "foo"
+.mfunc1:
+.short .types_end - .mfunc1 - 2
+.short LF_MFUNC_ID
+.long 0x100f # parent class
+.long 0x1011 # function type
+.asciz "method"
+.byte 0xf1 # padding
+
+.types_end:
diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp
index 5661438c9e9..9753216f544 100644
--- a/ld/testsuite/ld-pe/pdb.exp
+++ b/ld/testsuite/ld-pe/pdb.exp
@@ -1148,8 +1148,180 @@ proc test5 { } {
     }
 }
 
+proc test6 { } {
+    global as
+    global ar
+    global ld
+    global objdump
+    global srcdir
+    global subdir
+
+    if ![ld_assemble $as $srcdir/$subdir/pdb-types2a.s tmpdir/pdb-types2a.o] {
+	unsupported "Build pdb-types2a.o"
+	return
+    }
+
+    if ![ld_assemble $as $srcdir/$subdir/pdb-types2b.s tmpdir/pdb-types2b.o] {
+	unsupported "Build pdb-types2b.o"
+	return
+    }
+
+    if ![ld_link $ld "tmpdir/pdb-types2.exe" "--pdb=tmpdir/pdb-types2.pdb tmpdir/pdb-types2a.o tmpdir/pdb-types2b.o"] {
+	unsupported "Create PE image with PDB file"
+	return
+    }
+
+    set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb 0004"]
+
+    if ![string match "" $exec_output] {
+	fail "Could not extract IPI stream"
+	return
+    } else {
+	pass "Extracted IPI stream"
+    }
+
+    # check values in IPI header, and save anything interesting
+
+    set fi [open tmpdir/0004]
+    fconfigure $fi -translation binary
+
+    seek $fi 8 current
+
+    set data [read $fi 4]
+    binary scan $data i first_type
+
+    if { $first_type != 0x1000 } {
+	fail "Incorrect first type value in IPI stream."
+    } else {
+	pass "Correct first type value in IPI stream."
+    }
+
+    set data [read $fi 4]
+    binary scan $data i end_type
+
+    # end_type is one greater than the last type in the stream
+    if { $end_type != 0x100f } {
+	fail "Incorrect end type value in IPI stream."
+    } else {
+	pass "Correct end type value in IPI stream."
+    }
+
+    set data [read $fi 4]
+    binary scan $data i type_list_size
+
+    set data [read $fi 2]
+    binary scan $data s hash_stream_index
+
+    seek $fi 2 current
+
+    set data [read $fi 4]
+    binary scan $data i hash_size
+
+    if { $hash_size != 4 } {
+	fail "Incorrect hash size in IPI stream."
+    } else {
+	pass "Correct hash size in IPI stream."
+    }
+
+    set data [read $fi 4]
+    binary scan $data i num_buckets
+
+    if { $num_buckets != 0x3ffff } {
+	fail "Incorrect number of buckets in IPI stream."
+    } else {
+	pass "Correct number of buckets in IPI stream."
+    }
+
+    set data [read $fi 4]
+    binary scan $data i hash_list_offset
+
+    set data [read $fi 4]
+    binary scan $data i hash_list_size
+
+    set data [read $fi 4]
+    binary scan $data i skip_list_offset
+
+    set data [read $fi 4]
+    binary scan $data i skip_list_size
+
+    seek $fi 8 current
+
+    set type_list [read $fi $type_list_size]
+
+    close $fi
+
+    set fi [open tmpdir/pdb-types2-typelist w]
+    fconfigure $fi -translation binary
+    puts -nonewline $fi $type_list
+    close $fi
+
+    # check type list
+
+    set exp [file_contents "$srcdir/$subdir/pdb-types2-typelist.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-typelist"]
+    if ![string match $exp $got] {
+	fail "Incorrect type list in IPI stream."
+    } else {
+	pass "Correct type list in IPI stream."
+    }
+
+    # extract hash list and skip list
+
+    set index_str [format "%04x" $hash_stream_index]
+
+    set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-types2.pdb $index_str"]
+
+    if ![string match "" $exec_output] {
+	fail "Could not extract IPI hash stream."
+    } else {
+	pass "Extracted IPI hash stream."
+    }
+
+    set fi [open tmpdir/$index_str]
+    fconfigure $fi -translation binary
+
+    seek $fi $hash_list_offset
+    set hash_list [read $fi $hash_list_size]
+
+    seek $fi $skip_list_offset
+    set skip_list [read $fi $skip_list_size]
+
+    close $fi
+
+    # check hash list
+
+    set fi [open tmpdir/pdb-types2-hashlist w]
+    fconfigure $fi -translation binary
+    puts -nonewline $fi $hash_list
+    close $fi
+
+    set exp [file_contents "$srcdir/$subdir/pdb-types2-hashlist.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-hashlist"]
+    if ![string match $exp $got] {
+	fail "Incorrect hash list in IPI stream."
+    } else {
+	pass "Correct hash list in IPI stream."
+    }
+
+    # check skip list
+
+    set fi [open tmpdir/pdb-types2-skiplist w]
+    fconfigure $fi -translation binary
+    puts -nonewline $fi $skip_list
+    close $fi
+
+    set exp [file_contents "$srcdir/$subdir/pdb-types2-skiplist.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/pdb-types2-skiplist"]
+    if ![string match $exp $got] {
+	fail "Incorrect skip list in IPI stream."
+    } else {
+	pass "Correct skip list in IPI stream."
+    }
+}
+
 test1
 test2
 test3
 test4
 test5
+test6
-- 
2.37.4


  reply	other threads:[~2022-11-29  0:10 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 ` [PATCH] ld: Write DEBUG_S_FILECHKSMS entries in PDBs Mark Harmstone
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         ` Mark Harmstone [this message]
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=20221129001015.21775-2-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).