ld: Copy other symbols into PDB file
authorMark Harmstone <mark@harmstone.com>
Fri, 9 Dec 2022 01:52:39 +0000 (01:52 +0000)
committerAlan Modra <amodra@gmail.com>
Fri, 23 Dec 2022 10:32:21 +0000 (21:02 +1030)
ld/pdb.c
ld/pdb.h
ld/testsuite/ld-pe/pdb-syms2-symbols1.d [new file with mode: 0644]
ld/testsuite/ld-pe/pdb-syms2.s [new file with mode: 0644]
ld/testsuite/ld-pe/pdb.exp

index 375ff35d04b5e2487d2f94401905c5725442856a..5bcf0566cae3750753c284a4c544373c7ed0f19a 100644 (file)
--- a/ld/pdb.c
+++ b/ld/pdb.c
@@ -908,11 +908,15 @@ find_end_of_scope (uint8_t *data, uint32_t size)
        {
        case S_GPROC32:
        case S_LPROC32:
+       case S_BLOCK32:
+       case S_INLINESITE:
+       case S_THUNK32:
          scope_level++;
          break;
 
        case S_END:
        case S_PROC_ID_END:
+       case S_INLINESITE_END:
          scope_level--;
 
          if (scope_level == 0)
@@ -961,6 +965,7 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf,
 {
   uint8_t *orig_buf = *buf;
   unsigned int scope_level = 0;
+  uint8_t *scope = NULL;
 
   while (size >= sizeof (uint16_t))
     {
@@ -1206,6 +1211,8 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf,
 
            free (ref);
 
+           scope = *buf;
+
            memcpy (*buf, proc, len);
            *buf += len;
 
@@ -1321,16 +1328,343 @@ parse_symbols (uint8_t *data, uint32_t size, uint8_t **buf,
          }
 
        case S_END:
+       case S_INLINESITE_END:
        case S_PROC_ID_END:
          memcpy (*buf, data, len);
 
          if (type == S_PROC_ID_END) /* transform to S_END */
            bfd_putl16 (S_END, *buf + sizeof (uint16_t));
 
+         /* Reset scope variable back to the address of the previous
+            scope start.  */
+         if (scope)
+           {
+             uint32_t parent;
+             uint16_t scope_start_type =
+               bfd_getl16 (scope + sizeof (uint16_t));
+
+             switch (scope_start_type)
+               {
+               case S_GPROC32:
+               case S_LPROC32:
+                 parent = bfd_getl32 (scope + offsetof (struct procsym,
+                                                        parent));
+                 break;
+
+               case S_BLOCK32:
+                 parent = bfd_getl32 (scope + offsetof (struct blocksym,
+                                                        parent));
+                 break;
+
+               case S_INLINESITE:
+                 parent = bfd_getl32 (scope + offsetof (struct inline_site,
+                                                        parent));
+                 break;
+
+               case S_THUNK32:
+                 parent = bfd_getl32 (scope + offsetof (struct thunk,
+                                                        parent));
+                 break;
+
+               default:
+                 einfo (_("%P: warning: unexpected CodeView scope start"
+                          " record %v\n"), scope_start_type);
+                 bfd_set_error (bfd_error_bad_value);
+                 return false;
+               }
+
+             if (parent == 0)
+               scope = NULL;
+             else
+               scope = orig_buf + parent - sizeof (uint32_t);
+           }
+
          *buf += len;
          scope_level--;
          break;
 
+       case S_BUILDINFO:
+         {
+           struct buildinfosym *bi = (struct buildinfosym *) data;
+
+           if (len < sizeof (struct buildinfosym))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_BUILDINFO\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           if (!remap_symbol_type (&bi->type, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           break;
+         }
+
+       case S_BLOCK32:
+         {
+           struct blocksym *bl = (struct blocksym *) data;
+           uint8_t *endptr;
+           uint32_t end;
+
+           if (len < offsetof (struct blocksym, name))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_BLOCK32\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &bl->parent);
+
+           endptr = find_end_of_scope (data, size);
+
+           if (!endptr)
+             {
+               einfo (_("%P: warning: could not find end of"
+                        " S_BLOCK32 record\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           end = *buf - orig_buf + sizeof (uint32_t) + endptr - data;
+           bfd_putl32 (end, &bl->end);
+
+           scope = *buf;
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           scope_level++;
+
+           break;
+         }
+
+       case S_BPREL32:
+         {
+           struct bprelsym *bp = (struct bprelsym *) data;
+
+           if (len < offsetof (struct bprelsym, name))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_BPREL32\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           if (!remap_symbol_type (&bp->type, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           break;
+         }
+
+       case S_REGISTER:
+         {
+           struct regsym *reg = (struct regsym *) data;
+
+           if (len < offsetof (struct regsym, name))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_REGISTER\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           if (!remap_symbol_type (&reg->type, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           break;
+         }
+
+       case S_REGREL32:
+         {
+           struct regrel *rr = (struct regrel *) data;
+
+           if (len < offsetof (struct regrel, name))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_REGREL32\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           if (!remap_symbol_type (&rr->type, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           break;
+         }
+
+       case S_LOCAL:
+         {
+           struct localsym *l = (struct localsym *) data;
+
+           if (len < offsetof (struct localsym, name))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_LOCAL\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           if (!remap_symbol_type (&l->type, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           break;
+         }
+
+       case S_INLINESITE:
+         {
+           struct inline_site *is = (struct inline_site *) data;
+           uint8_t *endptr;
+           uint32_t end;
+
+           if (len < offsetof (struct inline_site, binary_annotations))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_INLINESITE\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &is->parent);
+
+           endptr = find_end_of_scope (data, size);
+
+           if (!endptr)
+             {
+               einfo (_("%P: warning: could not find end of"
+                        " S_INLINESITE record\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           end = *buf - orig_buf + sizeof (uint32_t) + endptr - data;
+           bfd_putl32 (end, &is->end);
+
+           if (!remap_symbol_type (&is->inlinee, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           scope = *buf;
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           scope_level++;
+
+           break;
+         }
+
+       case S_THUNK32:
+         {
+           struct thunk *th = (struct thunk *) data;
+           uint8_t *endptr;
+           uint32_t end;
+
+           if (len < offsetof (struct thunk, name))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_THUNK32\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           bfd_putl32 (scope - orig_buf + sizeof (uint32_t), &th->parent);
+
+           endptr = find_end_of_scope (data, size);
+
+           if (!endptr)
+             {
+               einfo (_("%P: warning: could not find end of"
+                        " S_THUNK32 record\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           end = *buf - orig_buf + sizeof (uint32_t) + endptr - data;
+           bfd_putl32 (end, &th->end);
+
+           scope = *buf;
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           scope_level++;
+
+           break;
+         }
+
+       case S_HEAPALLOCSITE:
+         {
+           struct heap_alloc_site *has = (struct heap_alloc_site *) data;
+
+           if (len < sizeof (struct heap_alloc_site))
+             {
+               einfo (_("%P: warning: truncated CodeView record"
+                        " S_HEAPALLOCSITE\n"));
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           if (!remap_symbol_type (&has->type, map, num_types))
+             {
+               bfd_set_error (bfd_error_bad_value);
+               return false;
+             }
+
+           memcpy (*buf, data, len);
+           *buf += len;
+
+           break;
+         }
+
+       case S_OBJNAME: /* just copy */
+       case S_COMPILE3:
+       case S_UNAMESPACE:
+       case S_FRAMEPROC:
+       case S_FRAMECOOKIE:
+       case S_LABEL32:
+       case S_DEFRANGE_REGISTER_REL:
+       case S_DEFRANGE_FRAMEPOINTER_REL:
+       case S_DEFRANGE_SUBFIELD_REGISTER:
+       case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+       case S_DEFRANGE_REGISTER:
+         memcpy (*buf, data, len);
+         *buf += len;
+         break;
+
        default:
          einfo (_("%P: warning: unrecognized CodeView record %v\n"), type);
          bfd_set_error (bfd_error_bad_value);
@@ -1441,12 +1775,40 @@ calculate_symbols_size (uint8_t *data, uint32_t size, uint32_t *sym_size)
            *sym_size += len;
          break;
 
+       case S_BLOCK32: /* always copied */
+       case S_INLINESITE:
+       case S_THUNK32:
+         *sym_size += len;
+         scope_level++;
+         break;
+
        case S_END: /* always copied */
        case S_PROC_ID_END:
+       case S_INLINESITE_END:
          *sym_size += len;
          scope_level--;
          break;
 
+       case S_OBJNAME: /* always copied */
+       case S_COMPILE3:
+       case S_UNAMESPACE:
+       case S_FRAMEPROC:
+       case S_FRAMECOOKIE:
+       case S_LABEL32:
+       case S_BUILDINFO:
+       case S_BPREL32:
+       case S_REGISTER:
+       case S_REGREL32:
+       case S_LOCAL:
+       case S_DEFRANGE_REGISTER_REL:
+       case S_DEFRANGE_FRAMEPOINTER_REL:
+       case S_DEFRANGE_SUBFIELD_REGISTER:
+       case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+       case S_DEFRANGE_REGISTER:
+       case S_HEAPALLOCSITE:
+         *sym_size += len;
+         break;
+
        default:
          einfo (_("%P: warning: unrecognized CodeView record %v\n"), type);
          return false;
index 9048b5fa37c905d8831bc56e132f356a8c97b6a2..ddb9b86ce85630419832c062a156e8a63b13dcd5 100644 (file)
--- a/ld/pdb.h
+++ b/ld/pdb.h
 #define LF_UQUADWORD                   0x800a
 
 #define S_END                          0x0006
+#define S_FRAMEPROC                    0x1012
+#define S_OBJNAME                      0x1101
+#define S_THUNK32                      0x1102
+#define S_BLOCK32                      0x1103
+#define S_LABEL32                      0x1105
+#define S_REGISTER                     0x1106
 #define S_CONSTANT                     0x1107
 #define S_UDT                          0x1108
+#define S_BPREL32                      0x110b
 #define S_LDATA32                      0x110c
 #define S_GDATA32                      0x110d
 #define S_PUB32                                0x110e
 #define S_LPROC32                      0x110f
 #define S_GPROC32                      0x1110
+#define S_REGREL32                     0x1111
 #define S_LTHREAD32                    0x1112
 #define S_GTHREAD32                    0x1113
+#define S_UNAMESPACE                   0x1124
 #define S_PROCREF                      0x1125
 #define S_LPROCREF                     0x1127
+#define S_FRAMECOOKIE                  0x113a
+#define S_COMPILE3                     0x113c
+#define S_LOCAL                                0x113e
+#define S_DEFRANGE_REGISTER            0x1141
+#define S_DEFRANGE_FRAMEPOINTER_REL    0x1142
+#define S_DEFRANGE_SUBFIELD_REGISTER   0x1143
+#define S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE 0x1144
+#define S_DEFRANGE_REGISTER_REL                0x1145
 #define S_LPROC32_ID                   0x1146
 #define S_GPROC32_ID                   0x1147
+#define S_BUILDINFO                    0x114c
+#define S_INLINESITE                   0x114d
+#define S_INLINESITE_END               0x114e
 #define S_PROC_ID_END                  0x114f
+#define S_HEAPALLOCSITE                        0x115e
 
 /* PDBStream70 in pdb1.h */
 struct pdb_stream_70
@@ -617,6 +638,164 @@ struct constsym
   char name[];
 } ATTRIBUTE_PACKED;
 
+/* BUILDINFOSYM in cvinfo.h */
+struct buildinfosym
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t type;
+} ATTRIBUTE_PACKED;
+
+/* BLOCKSYM32 in cvinfo.h */
+struct blocksym
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t parent;
+  uint32_t end;
+  uint32_t len;
+  uint32_t offset;
+  uint16_t section;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* BPRELSYM32 in cvinfo.h */
+struct bprelsym
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t bp_offset;
+  uint32_t type;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* REGSYM in cvinfo.h */
+struct regsym
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t type;
+  uint16_t reg;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* REGREL32 in cvinfo.h */
+struct regrel
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t offset;
+  uint32_t type;
+  uint16_t reg;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* LOCALSYM in cvinfo.h */
+struct localsym
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t type;
+  uint16_t flags;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* CV_LVAR_ADDR_RANGE in cvinfo.h */
+struct lvar_addr_range
+{
+  uint32_t offset;
+  uint16_t section;
+  uint16_t length;
+} ATTRIBUTE_PACKED;
+
+/* CV_LVAR_ADDR_GAP in cvinfo.h */
+struct lvar_addr_gap {
+  uint16_t offset;
+  uint16_t length;
+} ATTRIBUTE_PACKED;
+
+/* DEFRANGESYMREGISTERREL in cvinfo.h */
+struct defrange_register_rel
+{
+  uint16_t size;
+  uint16_t kind;
+  uint16_t reg;
+  uint16_t offset_parent;
+  uint32_t offset_register;
+  struct lvar_addr_range range;
+  struct lvar_addr_gap gaps[];
+} ATTRIBUTE_PACKED;
+
+/* DEFRANGESYMFRAMEPOINTERREL in cvinfo.h */
+struct defrange_framepointer_rel
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t offset;
+  struct lvar_addr_range range;
+  struct lvar_addr_gap gaps[];
+} ATTRIBUTE_PACKED;
+
+/* DEFRANGESYMSUBFIELDREGISTER in cvinfo.h */
+struct defrange_subfield_register
+{
+  uint16_t size;
+  uint16_t kind;
+  uint16_t reg;
+  uint16_t attributes;
+  uint32_t offset_parent;
+  struct lvar_addr_range range;
+  struct lvar_addr_gap gaps[];
+} ATTRIBUTE_PACKED;
+
+/* DEFRANGESYMREGISTER in cvinfo.h */
+struct defrange_register
+{
+  uint16_t size;
+  uint16_t kind;
+  uint16_t reg;
+  uint16_t attributes;
+  struct lvar_addr_range range;
+  struct lvar_addr_gap gaps[];
+} ATTRIBUTE_PACKED;
+
+/* INLINESITESYM in cvinfo.h */
+struct inline_site
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t parent;
+  uint32_t end;
+  uint32_t inlinee;
+  uint8_t binary_annotations[];
+} ATTRIBUTE_PACKED;
+
+/* THUNKSYM32 in cvinfo.h */
+struct thunk
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t parent;
+  uint32_t end;
+  uint32_t next;
+  uint32_t offset;
+  uint16_t section;
+  uint16_t length;
+  uint8_t thunk_type;
+  char name[];
+} ATTRIBUTE_PACKED;
+
+/* HEAPALLOCSITE in cvinfo.h */
+struct heap_alloc_site
+{
+  uint16_t size;
+  uint16_t kind;
+  uint32_t offset;
+  uint16_t section;
+  uint16_t length;
+  uint32_t type;
+} ATTRIBUTE_PACKED;
+
 extern bool create_pdb_file (bfd *, const char *, const unsigned char *);
 
 #endif
diff --git a/ld/testsuite/ld-pe/pdb-syms2-symbols1.d b/ld/testsuite/ld-pe/pdb-syms2-symbols1.d
new file mode 100644 (file)
index 0000000..34132d1
--- /dev/null
@@ -0,0 +1,38 @@
+
+*:     file format binary
+
+Contents of section .data:
+ 0000 04000000 0e000111 00000000 73796d73  ............syms
+ 0010 332e6f00 22003c11 00000000 d0000000  3.o.".<.........
+ 0020 00000000 00000000 00000000 0000474e  ..............GN
+ 0030 55204153 00f3f2f1 06002411 73746400  U AS......$.std.
+ 0040 06004c11 05100000 2e001011 00000000  ..L.............
+ 0050 18020000 00000000 06000000 00000000  ................
+ 0060 00000000 01100000 00000000 01000070  ...............p
+ 0070 726f6331 00f3f2f1 1e001210 00000000  roc1............
+ 0080 00000000 00000000 00000000 00000000  ................
+ 0090 00000000 0000f2f1 0e003a11 08000000  ..........:.....
+ 00a0 48010000 000000f1 0e000b11 04000000  H...............
+ 00b0 02100000 666f6f00 0e000611 02100000  ....foo.........
+ 00c0 48016261 7200f2f1 12001111 04000000  H.bar...........
+ 00d0 02100000 48016261 7a00f2f1 12003e11  ....H.baz.....>.
+ 00e0 02100000 00006c6f 63616c31 00f3f2f1  ......local1....
+ 00f0 16004511 48010000 00000000 01000000  ..E.H...........
+ 0100 01000400 02000100 12003e11 02100000  ..........>.....
+ 0110 00006c6f 63616c32 00f3f2f1 12004211  ..local2......B.
+ 0120 04000000 01000000 01000400 02000100  ................
+ 0130 12003e11 02100000 00006c6f 63616c33  ..>.......local3
+ 0140 00f3f2f1 16004311 48010000 04000000  ......C.H.......
+ 0150 01000000 01000400 02000100 12003e11  ..............>.
+ 0160 02100000 00006c6f 63616c34 00f3f2f1  ......local4....
+ 0170 06004411 04000000 12003e11 02100000  ..D.......>.....
+ 0180 00006c6f 63616c35 00f3f2f1 12004111  ..local5......A.
+ 0190 48010000 01000000 01000400 02000100  H...............
+ 01a0 0e004d11 48000000 b0010000 06100000  ..M.H...........
+ 01b0 02004e11 16000311 48000000 e0010000  ..N.....H.......
+ 01c0 04000000 01000000 010000f1 12000511  ................
+ 01d0 02000000 0100006c 6162656c 00f3f2f1  .......label....
+ 01e0 02000600 1e000211 48000000 04020000  ........H.......
+ 01f0 00000000 06000000 01000100 00746875  .............thu
+ 0200 6e6b00f1 02000600 0e005e11 04000000  nk........^.....
+ 0210 01000100 02100000 02000600 00000000  ................
\ No newline at end of file
diff --git a/ld/testsuite/ld-pe/pdb-syms2.s b/ld/testsuite/ld-pe/pdb-syms2.s
new file mode 100644 (file)
index 0000000..ec677ea
--- /dev/null
@@ -0,0 +1,430 @@
+.equ CV_SIGNATURE_C13, 4
+.equ DEBUG_S_SYMBOLS, 0xf1
+
+.equ T_VOID, 0x0003
+.equ T_UINT4, 0x0075
+
+.equ LF_MODIFIER, 0x1001
+.equ LF_PROCEDURE, 0x1008
+.equ LF_ARGLIST, 0x1201
+.equ LF_FUNC_ID, 0x1601
+.equ LF_BUILDINFO, 0x1603
+.equ LF_STRING_ID, 0x1605
+
+.equ S_END, 0x0006
+.equ S_FRAMEPROC, 0x1012
+.equ S_OBJNAME, 0x1101
+.equ S_THUNK32, 0x1102
+.equ S_BLOCK32, 0x1103
+.equ S_LABEL32, 0x1105
+.equ S_REGISTER, 0x1106
+.equ S_BPREL32, 0x110b
+.equ S_GPROC32, 0x1110
+.equ S_REGREL32, 0x1111
+.equ S_UNAMESPACE, 0x1124
+.equ S_FRAMECOOKIE, 0x113a
+.equ S_COMPILE3, 0x113c
+.equ S_LOCAL, 0x113e
+.equ S_DEFRANGE_REGISTER, 0x1141
+.equ S_DEFRANGE_FRAMEPOINTER_REL, 0x1142
+.equ S_DEFRANGE_SUBFIELD_REGISTER, 0x1143
+.equ S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144
+.equ S_DEFRANGE_REGISTER_REL, 0x1145
+.equ S_BUILDINFO, 0x114c
+.equ S_INLINESITE, 0x114d
+.equ S_INLINESITE_END, 0x114e
+.equ S_HEAPALLOCSITE, 0x115e
+
+.equ CV_AMD64_RAX, 328
+.equ CV_CFL_AMD64, 0xd0
+
+.section ".debug$S", "rn"
+
+.long CV_SIGNATURE_C13
+
+.long DEBUG_S_SYMBOLS
+.long .syms_end - .syms_start
+
+.syms_start:
+
+.objname1:
+.short .compile1 - .objname1 - 2
+.short S_OBJNAME
+.long 0 # signature
+.asciz "syms3.o"
+
+.compile1:
+.short .unamespace1 - .compile1 - 2
+.short S_COMPILE3
+.long 0 # flags
+.short CV_CFL_AMD64 # target processor
+.short 0 # frontend major
+.short 0 # frontend minor
+.short 0 # frontend build
+.short 0 # frontend qfe
+.short 0 # backend major
+.short 0 # backend minor
+.short 0 # backend build
+.short 0 # backend qfe
+.asciz "GNU AS"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.unamespace1:
+.short .sbuildinfo1 - .unamespace1 - 2
+.short S_UNAMESPACE
+.asciz "std"
+
+.sbuildinfo1:
+.short .gproc1 - .sbuildinfo1 - 2
+.short S_BUILDINFO
+.long 0x1007 # type
+
+.gproc1:
+.short .frameproc1 - .gproc1 - 2
+.short S_GPROC32
+.long 0 # parent
+.long 0 # end
+.long 0 # next symbol
+.long .proc1_end - proc1 # length
+.long 0 # debug start offset
+.long 0 # debug end offset
+.long 0x1001 # type
+.secrel32 proc1
+.secidx proc1
+.byte 0 # flags
+.asciz "proc1"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.frameproc1:
+.short .framecookie1 - .frameproc1 - 2
+.short S_FRAMEPROC
+.long 0 # frame size
+.long 0 # frame padding
+.long 0 # padding offset
+.long 0 # size of callee-save registers
+.long 0 # offset of exception handler
+.short 0 # section of exception handler
+.long 0 # flags
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.framecookie1:
+.short .bprel1 - .framecookie1 - 2
+.short S_FRAMECOOKIE
+.long 8 # frame-relative offset
+.short CV_AMD64_RAX # register
+.long 0 # cookie type (CV_COOKIETYPE_COPY)
+.byte 0 # flags
+.byte 0xf1 # padding
+
+.bprel1:
+.short .reg1 - .bprel1 - 2
+.short S_BPREL32
+.long 4 # BP-relative offset
+.long 0x1008 # type
+.asciz "foo"
+
+.reg1:
+.short .regrel1 - .reg1 - 2
+.short S_REGISTER
+.long 0x1008 # type
+.short CV_AMD64_RAX
+.asciz "bar"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.regrel1:
+.short .local1 - .regrel1 - 2
+.short S_REGREL32
+.long 4 # offset
+.long 0x1008 # type
+.short CV_AMD64_RAX
+.asciz "baz"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.local1:
+.short .defrange1 - .local1 - 2
+.short S_LOCAL
+.long 0x1008 # type
+.short 0 # flags
+.asciz "local1"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.defrange1:
+.short .local2 - .defrange1 - 2
+.short S_DEFRANGE_REGISTER_REL
+.short CV_AMD64_RAX
+.short 0 # offset parent
+.long 0 # offset register
+.secrel32 .block1 # offset
+.secidx .block1 # section
+.short .block1_end - .block1 # length
+.short .gap1 - .block1 # gap 1 offset
+.short .gap1_end - .gap1 # gap 1 length
+
+.local2:
+.short .defrange2 - .local2 - 2
+.short S_LOCAL
+.long 0x1008 # type
+.short 0 # flags
+.asciz "local2"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.defrange2:
+.short .local3 - .defrange2 - 2
+.short S_DEFRANGE_FRAMEPOINTER_REL
+.long 4 # frame pointer offset
+.secrel32 .block1 # offset
+.secidx .block1 # section
+.short .block1_end - .block1 # length
+.short .gap1 - .block1 # gap 1 offset
+.short .gap1_end - .gap1 # gap 1 length
+
+.local3:
+.short .defrange3 - .local3 - 2
+.short S_LOCAL
+.long 0x1008 # type
+.short 0 # flags
+.asciz "local3"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.defrange3:
+.short .local4 - .defrange3 - 2
+.short S_DEFRANGE_SUBFIELD_REGISTER
+.short CV_AMD64_RAX
+.short 0 # attributes
+.long 4 # offset in parent variable
+.secrel32 .block1 # offset
+.secidx .block1 # section
+.short .block1_end - .block1 # length
+.short .gap1 - .block1 # gap 1 offset
+.short .gap1_end - .gap1 # gap 1 length
+
+.local4:
+.short .defrange4 - .local4 - 2
+.short S_LOCAL
+.long 0x1008 # type
+.short 0 # flags
+.asciz "local4"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.defrange4:
+.short .local5 - .defrange4 - 2
+.short S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE
+.long 4 # frame pointer offset
+
+.local5:
+.short .defrange5 - .local5 - 2
+.short S_LOCAL
+.long 0x1008 # type
+.short 0 # flags
+.asciz "local5"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.defrange5:
+.short .inlinesite1 - .defrange5 - 2
+.short S_DEFRANGE_REGISTER
+.short CV_AMD64_RAX
+.short 0 # attributes
+.secrel32 .block1 # offset
+.secidx .block1 # section
+.short .block1_end - .block1 # length
+.short .gap1 - .block1 # gap 1 offset
+.short .gap1_end - .gap1 # gap 1 length
+
+.inlinesite1:
+.short .inlinesite1end - .inlinesite1 - 2
+.short S_INLINESITE
+.long 0 # parent
+.long 0 # end
+.long 0x1009 # inlinee (inline_func)
+
+.inlinesite1end:
+.short .sblock1 - .inlinesite1end - 2
+.short S_INLINESITE_END
+
+.sblock1:
+.short .label1 - .sblock1 - 2
+.short S_BLOCK32
+.long 0 # parent (filled in by linker)
+.long 0 # end (filled in by linker)
+.long .block1_end - .block1 # length
+.secrel32 .block1
+.secidx .block1
+.byte 0 # name
+.byte 0xf1 # padding
+
+.label1:
+.short .sblock1_end - .label1 - 2
+.short S_LABEL32
+.secrel32 label
+.secidx label
+.byte 0 # flags
+.asciz "label"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+.sblock1_end:
+.short .thunk1 - .sblock1_end - 2
+.short S_END
+
+.thunk1:
+.short .thunk1_end - .thunk1 - 2
+.short S_THUNK32
+.long 0 # parent
+.long 0 # end
+.long 0 # next
+.secrel32 thunk
+.secidx thunk
+.short .thunk_end - thunk
+.byte 0 # THUNK_ORDINAL value
+.asciz "thunk"
+.byte 0xf1 # padding
+
+.thunk1_end:
+.short .heapallocsite1 - .thunk1_end - 2
+.short S_END
+
+.heapallocsite1:
+.short .gproc1_end - .heapallocsite1 - 2
+.short S_HEAPALLOCSITE
+.secrel32 .gap1_end
+.secidx .gap1_end
+.short .block1_end - .gap1_end
+.long 0x1008 # type
+
+.gproc1_end:
+.short .syms_end - .gproc1_end - 2
+.short S_END
+
+.syms_end:
+
+.section ".debug$T", "rn"
+
+.long CV_SIGNATURE_C13
+
+# Type 1000, arglist (uint32_t)
+.arglist1:
+.short .proctype1 - .arglist1 - 2
+.short LF_ARGLIST
+.long 1 # no. entries
+.long T_UINT4
+
+# Type 1001, procedure (return type T_VOID, arglist 1000)
+.proctype1:
+.short .string1 - .proctype1 - 2
+.short LF_PROCEDURE
+.long T_VOID
+.byte 0 # calling convention
+.byte 0 # attributes
+.short 1 # no. parameters
+.long 0x1000
+
+# Type 1002, string "/tmp" (build directory)
+.string1:
+.short .string2 - .string1 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "/tmp"
+.byte 0xf3 # padding
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1003, string "gcc" (compiler)
+.string2:
+.short .string3 - .string2 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "gcc"
+
+# Type 1004, string "tmp.c" (source file)
+.string3:
+.short .string4 - .string3 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "tmp.c"
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1005, string "tmp.pdb" (PDB file)
+.string4:
+.short .string5 - .string4 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "tmp.pdb"
+
+# Type 1006, string "-gcodeview" (command arguments)
+.string5:
+.short .buildinfo1 - .string5 - 2
+.short LF_STRING_ID
+.long 0 # sub-string
+.asciz "-gcodeview"
+.byte 0xf1 # padding
+
+# Type 1007, build info
+.buildinfo1:
+.short .mod1 - .buildinfo1 - 2
+.short LF_BUILDINFO
+.short 5 # count
+.long 0x1002 # build directory
+.long 0x1003 # compiler
+.long 0x1004 # source file
+.long 0x1005 # PDB file
+.long 0x1006 # command arguments
+.byte 0xf2 # padding
+.byte 0xf1 # padding
+
+# Type 1008, const uint32_t
+.mod1:
+.short .funcid1 - .mod1 - 2
+.short LF_MODIFIER
+.long T_UINT4
+.short 1 # const
+.p2align 2
+
+# Type 1009, func ID for inline_func
+.funcid1:
+.short .types_end - .funcid1 - 2
+.short LF_FUNC_ID
+.long 0 # parent scope
+.long 0x1001 # type
+.asciz "inline_func"
+
+.types_end:
+
+.text
+
+.global proc1
+proc1:
+  nop
+.block1:
+  nop
+label:
+  nop
+.gap1:
+  nop
+.gap1_end:
+  nop
+.block1_end:
+  nop
+.proc1_end:
+
+thunk:
+  nop
+.thunk_end:
index 34eafc142a74b93fe4b6f9cb52d01eb78f3eb43d..5df1583c2474cc6307cf06a2bc468952e67d6bf4 100644 (file)
@@ -1614,6 +1614,72 @@ proc test8 { } {
     }
 }
 
+proc test9 { } {
+    global as
+    global ar
+    global ld
+    global objdump
+    global srcdir
+    global subdir
+
+    if ![ld_assemble $as $srcdir/$subdir/pdb-syms2.s tmpdir/pdb-syms2.o] {
+       unsupported "Build pdb-syms2.o"
+       return
+    }
+
+    if ![ld_link $ld "tmpdir/pdb-syms2.exe" "--pdb=tmpdir/pdb-syms2.pdb tmpdir/pdb-syms2.o"] {
+       unsupported "Create PE image with PDB file"
+       return
+    }
+
+    # get index of module stream
+
+    set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.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
+    set data [read $fi 4]
+    binary scan $data i mod_info_size
+
+    seek $fi 36 current
+    set mod_info [read $fi $mod_info_size]
+
+    close $fi
+
+    binary scan [string range $mod_info 34 35] s module_index
+
+    # check module records
+
+    set index_str [format "%04x" $module_index]
+
+    set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb $index_str"]
+
+    if ![string match "" $exec_output] {
+       fail "Could not extract module symbols"
+       return
+    } else {
+       pass "Extracted module symbols"
+    }
+
+    set exp [file_contents "$srcdir/$subdir/pdb-syms2-symbols1.d"]
+    set got [run_host_cmd "$objdump" "-s --target=binary tmpdir/$index_str"]
+
+    if [string match $exp $got] {
+       pass "Correct symbols in module stream"
+    } else {
+       fail "Incorrect symbols in module stream"
+    }
+}
+
 test1
 test2
 test3
@@ -1622,3 +1688,4 @@ test5
 test6
 test7
 test8
+test9