[PDB] Emit S_UDT records in LLD.
authorZachary Turner <zturner@google.com>
Tue, 4 Dec 2018 21:48:46 +0000 (21:48 +0000)
committerZachary Turner <zturner@google.com>
Tue, 4 Dec 2018 21:48:46 +0000 (21:48 +0000)
Previously these were dropped.  We now understand them sufficiently
well to start emitting them.  From the debugger's perspective, this
now enables us to have debug info about typedefs (both global and
function-locally scoped)

Differential Revision: https://reviews.llvm.org/D55228

llvm-svn: 348306

lld/COFF/PDB.cpp
lld/test/COFF/pdb-globals.test
lld/test/COFF/pdb-symbol-types.yaml
lld/test/COFF/pdb-type-server-simple.test
lld/test/COFF/s_udt.s [new file with mode: 0644]
llvm/include/llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h
llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp

index 1c425f1..faf32a2 100644 (file)
@@ -959,11 +959,10 @@ static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack,
   S.OpeningRecord->PtrEnd = CurOffset;
 }
 
-static bool symbolGoesInModuleStream(const CVSymbol &Sym) {
+static bool symbolGoesInModuleStream(const CVSymbol &Sym, bool IsGlobalScope) {
   switch (Sym.kind()) {
   case SymbolKind::S_GDATA32:
   case SymbolKind::S_CONSTANT:
-  case SymbolKind::S_UDT:
   // We really should not be seeing S_PROCREF and S_LPROCREF in the first place
   // since they are synthesized by the linker in response to S_GPROC32 and
   // S_LPROC32, but if we do see them, don't put them in the module stream I
@@ -971,6 +970,9 @@ static bool symbolGoesInModuleStream(const CVSymbol &Sym) {
   case SymbolKind::S_PROCREF:
   case SymbolKind::S_LPROCREF:
     return false;
+  // S_UDT records go in the module stream if it is not a global S_UDT.
+  case SymbolKind::S_UDT:
+    return !IsGlobalScope;
   // S_GDATA32 does not go in the module stream, but S_LDATA32 does.
   case SymbolKind::S_LDATA32:
   default:
@@ -978,7 +980,7 @@ static bool symbolGoesInModuleStream(const CVSymbol &Sym) {
   }
 }
 
-static bool symbolGoesInGlobalsStream(const CVSymbol &Sym) {
+static bool symbolGoesInGlobalsStream(const CVSymbol &Sym, bool IsGlobalScope) {
   switch (Sym.kind()) {
   case SymbolKind::S_CONSTANT:
   case SymbolKind::S_GDATA32:
@@ -992,13 +994,9 @@ static bool symbolGoesInGlobalsStream(const CVSymbol &Sym) {
   case SymbolKind::S_PROCREF:
   case SymbolKind::S_LPROCREF:
     return true;
-  // FIXME: For now, we drop all S_UDT symbols (i.e. they don't go in the
-  // globals stream or the modules stream).  These have special handling which
-  // needs more investigation before we can get right, but by putting them all
-  // into the globals stream WinDbg fails to display local variables of class
-  // types saying that it cannot find the type Foo *.  So as a stopgap just to
-  // keep things working, we drop them.
+  // S_UDT records go in the globals stream if it is a global S_UDT.
   case SymbolKind::S_UDT:
+    return IsGlobalScope;
   default:
     return false;
   }
@@ -1121,11 +1119,11 @@ void PDBLinker::mergeSymbolRecords(ObjFile *File, const CVIndexMap &IndexMap,
         // adding the symbol to the module since we may need to get the next
         // symbol offset, and writing to the module's symbol stream will update
         // that offset.
-        if (symbolGoesInGlobalsStream(Sym))
+        if (symbolGoesInGlobalsStream(Sym, Scopes.empty()))
           addGlobalSymbol(Builder.getGsiBuilder(),
                           File->ModuleDBI->getModuleIndex(), CurSymOffset, Sym);
 
-        if (symbolGoesInModuleStream(Sym)) {
+        if (symbolGoesInModuleStream(Sym, Scopes.empty())) {
           // Add symbols to the module in bulk. If this symbol is contiguous
           // with the previous run of symbols to add, combine the ranges. If
           // not, close the previous range of symbols and start a new one.
index db0d3f6..ee9c0ef 100644 (file)
@@ -15,6 +15,8 @@ RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s
 CHECK-LABEL:                        Global Symbols
 CHECK-NEXT:  ============================================================
 CHECK-NEXT:   Records
+CHECK-NEXT:      340 | S_UDT [size = 20] `HelloPoint`
+CHECK-NEXT:            original type = 0x1007
 CHECK-NEXT:      208 | S_LPROCREF [size = 24] `LocalFunc`
 CHECK-NEXT:            module = 1, sum name = 0, offset = 292
 CHECK-NEXT:      160 | S_PROCREF [size = 28] `GlobalFunc`
@@ -25,9 +27,11 @@ CHECK-NEXT:      232 | S_GDATA32 [size = 28] `__purecall`
 CHECK-NEXT:            type = 0x0403 (void*), addr = 0003:0004
 CHECK-NEXT:      260 | S_GDATA32 [size = 24] `GlobalVar`
 CHECK-NEXT:            type = 0x100B (const int*), addr = 0003:0000
+CHECK-NEXT:      312 | S_UDT [size = 28] `HelloPointTypedef`
+CHECK-NEXT:            original type = 0x1005
 CHECK-NEXT:      284 | S_LDATA32 [size = 28] `ConstantVar`
 CHECK-NEXT:            type = 0x100A (const int), addr = 0002:0000
-CHECK-NEXT:      312 | S_PROCREF [size = 40] `HelloPoint::HelloPoint`
+CHECK-NEXT:      360 | S_PROCREF [size = 40] `HelloPoint::HelloPoint`
 CHECK-NEXT:            module = 1, sum name = 0, offset = 376
 
 CHECK-LABEL:                           Symbols
index 0ed1215..d8741af 100644 (file)
 # CHECK-NEXT:  ============================================================
 # CHECK-NEXT:   Records
 # CHECK-NEXT:       48 | S_PROCREF [size = 20] `main`
-# CHECK-NEXT:             module = 1, sum name = 0, offset = 116
+# CHECK-NEXT:            module = 1, sum name = 0, offset = 116
+# CHECK-NEXT:       96 | S_UDT [size = 16] `UDT_Foo`
+# CHECK-NEXT:            original type = 0x1004
+# CHECK-NEXT:      112 | S_UDT [size = 12] `Foo`
+# CHECK-NEXT:            original type = 0x1004
 # CHECK-NEXT:       68 | S_GDATA32 [size = 28] `global_foo`
-# CHECK-NEXT:             type = 0x1004 (Foo), addr = 0003:0000
+# CHECK-NEXT:            type = 0x1004 (Foo), addr = 0003:0000
 
 # CHECK:                           Symbols
 # CHECK: ============================================================
index cae32af..f69a34a 100644 (file)
@@ -62,10 +62,12 @@ CHECK:            {{.*}}: `b.c`
 CHECK-LABEL:                       Global Symbols
 CHECK:       ============================================================
 CHECK-NEXT:    Records
-CHECK-NEXT:        36 | S_PROCREF [size = 20] `main`
-CHECK-NEXT:             module = 1, sum name = 0, offset = 104
-CHECK-NEXT:        56 | S_PROCREF [size = 16] `g`
-CHECK-NEXT:             module = 2, sum name = 0, offset = 104
+CHECK-NEXT:       36 | S_PROCREF [size = 20] `main`
+CHECK-NEXT:            module = 1, sum name = 0, offset = 104
+CHECK-NEXT:       68 | S_PROCREF [size = 16] `g`
+CHECK-NEXT:            module = 2, sum name = 0, offset = 104
+CHECK-NEXT:       56 | S_UDT [size = 12] `Foo`
+CHECK-NEXT:            original type = 0x1006
 
 CHECK-LABEL:                           Symbols
 CHECK: ============================================================
diff --git a/lld/test/COFF/s_udt.s b/lld/test/COFF/s_udt.s
new file mode 100644 (file)
index 0000000..e7d253f
--- /dev/null
@@ -0,0 +1,475 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-windows-msvc < %s > %t.obj
+# RUN: lld-link /DEBUG:FULL /nodefaultlib /entry:main %t.obj /PDB:%t.pdb /OUT:%t.exe
+# RUN: llvm-pdbutil dump -types -globals -symbols -modi=0 %t.pdb | FileCheck %s
+
+# CHECK:                               Types (TPI Stream)
+# CHECK-NEXT: ============================================================
+# CHECK:      0x1003 | LF_STRUCTURE [size = 44] `Struct`
+# CHECK-NEXT:          unique name: `.?AUStruct@@`
+# CHECK-NEXT:          vtable: <no type>, base list: <no type>, field list: <no type>
+# CHECK-NEXT:          options: forward ref (-> 0x1006) | has unique name, sizeof 0
+# CHECK-NEXT: 0x1004 | LF_POINTER [size = 12]
+# CHECK-NEXT:          referent = 0x1003, mode = pointer, opts = None, kind = ptr64
+# CHECK:      0x1006 | LF_STRUCTURE [size = 44] `Struct`
+# CHECK-NEXT:          unique name: `.?AUStruct@@`
+# CHECK-NEXT:          vtable: <no type>, base list: <no type>, field list: 0x1005
+# CHECK-NEXT:          options: has unique name, sizeof 4
+# CHECK:                               Global Symbols
+# CHECK-NEXT: ============================================================
+# CHECK:      {{.*}} | S_UDT [size = 24] `StructTypedef`
+# CHECK:               original type = 0x1003
+# CHECK:      {{.*}} | S_UDT [size = 16] `Struct`
+# CHECK:               original type = 0x1006
+# CHECK:      {{.*}} | S_UDT [size = 20] `IntTypedef`
+# CHECK:               original type = 0x0074 (int)
+# CHECK:                               Symbols
+# CHECK-NEXT: ============================================================
+# CHECK:      {{.*}} | S_GPROC32 [size = 44] `main`
+# CHECK-NEXT:          parent = 0, end = 252, addr = 0001:0000, code size = 52
+# CHECK-NEXT:          type = `0x1002 (int (int, char**))`, debug start = 0, debug end = 0, flags = none\r
+# CHECK-NOT:  {{.*}} | S_END
+# CHECK:      {{.*}} | S_UDT [size = 28] `main::LocalTypedef`
+# CHECK-NEXT:          original type = 0x1004
+# CHECK:      {{.*}} | S_END [size = 4]\r
+\r
+# source code to re-generate:\r
+# clang-cl /Z7 /GS- /GR- /c foo.cpp\r
+#\r
+# struct Struct {\r
+#   int x;\r
+# };\r
+# \r
+# using IntTypedef = int;\r
+# using StructTypedef = Struct;\r
+# Struct S;\r
+# StructTypedef SS;\r
+# IntTypedef I;\r
+# \r
+# int main(int argc, char **argv) {\r
+#   using LocalTypedef = Struct*;\r
+#   LocalTypedef SPtr;\r
+#   return I + S.x + SS.x + SPtr->x;\r
+# }
+
+       .text\r
+       .def     @feat.00;\r
+       .scl    3;\r
+       .type   0;\r
+       .endef\r
+       .globl  @feat.00\r
+.set @feat.00, 0\r
+       .intel_syntax noprefix\r
+       .def     main;\r
+       .scl    2;\r
+       .type   32;\r
+       .endef\r
+       .globl  main                    # -- Begin function main\r
+       .p2align        4, 0x90\r
+main:                                   # @main\r
+.Lfunc_begin0:\r
+       .cv_func_id 0\r
+       .cv_file        1 "D:\\src\\llvmbuild\\cl\\Debug\\x64\\foo.cpp" "2B62298EE3EEF94E1D81FDFE18BD46A6" 1\r
+       .cv_loc 0 1 12 0                # foo.cpp:12:0\r
+.seh_proc main\r
+# %bb.0:                                # %entry\r
+       sub     rsp, 32\r
+       .seh_stackalloc 32\r
+       .seh_endprologue\r
+       mov     dword ptr [rsp + 28], 0\r
+       mov     qword ptr [rsp + 16], rdx\r
+       mov     dword ptr [rsp + 12], ecx\r
+.Ltmp0:\r
+       .cv_loc 0 1 15 0                # foo.cpp:15:0\r
+       mov     ecx, dword ptr [rip + "?I@@3HA"]\r
+       add     ecx, dword ptr [rip + "?S@@3UStruct@@A"]\r
+       add     ecx, dword ptr [rip + "?SS@@3UStruct@@A"]\r
+       mov     rdx, qword ptr [rsp]\r
+       add     ecx, dword ptr [rdx]\r
+       mov     eax, ecx\r
+       add     rsp, 32\r
+       ret\r
+.Ltmp1:\r
+.Lfunc_end0:\r
+       .seh_handlerdata\r
+       .text\r
+       .seh_endproc\r
+                                        # -- End function\r
+       .bss\r
+       .globl  "?S@@3UStruct@@A"       # @"?S@@3UStruct@@A"\r
+       .p2align        2\r
+"?S@@3UStruct@@A":\r
+       .zero   4\r
+\r
+       .globl  "?SS@@3UStruct@@A"      # @"?SS@@3UStruct@@A"\r
+       .p2align        2\r
+"?SS@@3UStruct@@A":\r
+       .zero   4\r
+\r
+       .globl  "?I@@3HA"               # @"?I@@3HA"\r
+       .p2align        2\r
+"?I@@3HA":\r
+       .long   0                       # 0x0\r
+\r
+       .section        .drectve,"yn"\r
+       .ascii  " /DEFAULTLIB:libcmt.lib"\r
+       .ascii  " /DEFAULTLIB:oldnames.lib"\r
+       .section        .debug$S,"dr"\r
+       .p2align        2\r
+       .long   4                       # Debug section magic\r
+       .long   241\r
+       .long   .Ltmp3-.Ltmp2           # Subsection size\r
+.Ltmp2:\r
+       .short  .Ltmp5-.Ltmp4           # Record length\r
+.Ltmp4:\r
+       .short  4412                    # Record kind: S_COMPILE3\r
+       .long   1                       # Flags and language\r
+       .short  208                     # CPUType\r
+       .short  8                       # Frontend version\r
+       .short  0\r
+       .short  0\r
+       .short  0\r
+       .short  8000                    # Backend version\r
+       .short  0\r
+       .short  0\r
+       .short  0\r
+       .asciz  "clang version 8.0.0 "  # Null-terminated compiler version string\r
+.Ltmp5:\r
+.Ltmp3:\r
+       .p2align        2\r
+       .long   241                     # Symbol subsection for main\r
+       .long   .Ltmp7-.Ltmp6           # Subsection size\r
+.Ltmp6:\r
+       .short  .Ltmp9-.Ltmp8           # Record length\r
+.Ltmp8:\r
+       .short  4423                    # Record kind: S_GPROC32_ID\r
+       .long   0                       # PtrParent\r
+       .long   0                       # PtrEnd\r
+       .long   0                       # PtrNext\r
+       .long   .Lfunc_end0-main        # Code size\r
+       .long   0                       # Offset after prologue\r
+       .long   0                       # Offset before epilogue\r
+       .long   4099                    # Function type index\r
+       .secrel32       main            # Function section relative address\r
+       .secidx main                    # Function section index\r
+       .byte   0                       # Flags\r
+       .asciz  "main"                  # Function name\r
+.Ltmp9:\r
+       .short  .Ltmp11-.Ltmp10         # Record length\r
+.Ltmp10:\r
+       .short  4114                    # Record kind: S_FRAMEPROC\r
+       .long   32                      # FrameSize\r
+       .long   0                       # Padding\r
+       .long   0                       # Offset of padding\r
+       .long   0                       # Bytes of callee saved registers\r
+       .long   0                       # Exception handler offset\r
+       .short  0                       # Exception handler section\r
+       .long   81920                   # Flags (defines frame register)\r
+.Ltmp11:\r
+       .short  .Ltmp13-.Ltmp12         # Record length\r
+.Ltmp12:\r
+       .short  4414                    # Record kind: S_LOCAL\r
+       .long   116                     # TypeIndex\r
+       .short  1                       # Flags\r
+       .asciz  "argc"\r
+.Ltmp13:\r
+       .cv_def_range    .Ltmp0 .Ltmp1, "B\021\f\000\000\000"\r
+       .short  .Ltmp15-.Ltmp14         # Record length\r
+.Ltmp14:\r
+       .short  4414                    # Record kind: S_LOCAL\r
+       .long   4096                    # TypeIndex\r
+       .short  1                       # Flags\r
+       .asciz  "argv"\r
+.Ltmp15:\r
+       .cv_def_range    .Ltmp0 .Ltmp1, "B\021\020\000\000\000"\r
+       .short  .Ltmp17-.Ltmp16         # Record length\r
+.Ltmp16:\r
+       .short  4414                    # Record kind: S_LOCAL\r
+       .long   4101                    # TypeIndex\r
+       .short  0                       # Flags\r
+       .asciz  "SPtr"\r
+.Ltmp17:\r
+       .cv_def_range    .Ltmp0 .Ltmp1, "B\021\000\000\000\000"\r
+       .short  .Ltmp19-.Ltmp18         # Record length\r
+.Ltmp18:\r
+       .short  4360                    # Record kind: S_UDT\r
+       .long   4101                    # Type\r
+       .asciz  "main::LocalTypedef"\r
+.Ltmp19:\r
+       .short  2                       # Record length\r
+       .short  4431                    # Record kind: S_PROC_ID_END\r
+.Ltmp7:\r
+       .p2align        2\r
+       .cv_linetable   0, main, .Lfunc_end0\r
+       .long   241                     # Symbol subsection for globals\r
+       .long   .Ltmp21-.Ltmp20         # Subsection size\r
+.Ltmp20:\r
+       .short  .Ltmp23-.Ltmp22         # Record length\r
+.Ltmp22:\r
+       .short  4365                    # Record kind: S_GDATA32\r
+       .long   4103                    # Type\r
+       .secrel32       "?S@@3UStruct@@A" # DataOffset\r
+       .secidx "?S@@3UStruct@@A"       # Segment\r
+       .asciz  "S"                     # Name\r
+.Ltmp23:\r
+       .short  .Ltmp25-.Ltmp24         # Record length\r
+.Ltmp24:\r
+       .short  4365                    # Record kind: S_GDATA32\r
+       .long   4100                    # Type\r
+       .secrel32       "?SS@@3UStruct@@A" # DataOffset\r
+       .secidx "?SS@@3UStruct@@A"      # Segment\r
+       .asciz  "SS"                    # Name\r
+.Ltmp25:\r
+       .short  .Ltmp27-.Ltmp26         # Record length\r
+.Ltmp26:\r
+       .short  4365                    # Record kind: S_GDATA32\r
+       .long   116                     # Type\r
+       .secrel32       "?I@@3HA"       # DataOffset\r
+       .secidx "?I@@3HA"               # Segment\r
+       .asciz  "I"                     # Name\r
+.Ltmp27:\r
+.Ltmp21:\r
+       .p2align        2\r
+       .long   241\r
+       .long   .Ltmp29-.Ltmp28         # Subsection size\r
+.Ltmp28:\r
+       .short  .Ltmp31-.Ltmp30         # Record length\r
+.Ltmp30:\r
+       .short  4360                    # Record kind: S_UDT\r
+       .long   4103                    # Type\r
+       .asciz  "Struct"\r
+.Ltmp31:\r
+       .short  .Ltmp33-.Ltmp32         # Record length\r
+.Ltmp32:\r
+       .short  4360                    # Record kind: S_UDT\r
+       .long   4100                    # Type\r
+       .asciz  "StructTypedef"\r
+.Ltmp33:\r
+       .short  .Ltmp35-.Ltmp34         # Record length\r
+.Ltmp34:\r
+       .short  4360                    # Record kind: S_UDT\r
+       .long   116                     # Type\r
+       .asciz  "IntTypedef"\r
+.Ltmp35:\r
+.Ltmp29:\r
+       .p2align        2\r
+       .cv_filechecksums               # File index to string table offset subsection\r
+       .cv_stringtable                 # String table\r
+       .long   241\r
+       .long   .Ltmp37-.Ltmp36         # Subsection size\r
+.Ltmp36:\r
+       .short  6                       # Record length\r
+       .short  4428                    # Record kind: S_BUILDINFO\r
+       .long   4108                    # LF_BUILDINFO index\r
+.Ltmp37:\r
+       .p2align        2\r
+       .section        .debug$T,"dr"\r
+       .p2align        2\r
+       .long   4                       # Debug section magic\r
+       # Pointer (0x1000) {\r
+       #   TypeLeafKind: LF_POINTER (0x1002)\r
+       #   PointeeType: char* (0x670)\r
+       #   PtrType: Near64 (0xC)\r
+       #   PtrMode: Pointer (0x0)\r
+       #   IsFlat: 0\r
+       #   IsConst: 0\r
+       #   IsVolatile: 0\r
+       #   IsUnaligned: 0\r
+       #   IsRestrict: 0\r
+       #   IsThisPtr&: 0\r
+       #   IsThisPtr&&: 0\r
+       #   SizeOf: 8\r
+       # }\r
+       .byte   0x0a, 0x00, 0x02, 0x10\r
+       .byte   0x70, 0x06, 0x00, 0x00\r
+       .byte   0x0c, 0x00, 0x01, 0x00\r
+       # ArgList (0x1001) {\r
+       #   TypeLeafKind: LF_ARGLIST (0x1201)\r
+       #   NumArgs: 2\r
+       #   Arguments [\r
+       #     ArgType: int (0x74)\r
+       #     ArgType: char** (0x1000)\r
+       #   ]\r
+       # }\r
+       .byte   0x0e, 0x00, 0x01, 0x12\r
+       .byte   0x02, 0x00, 0x00, 0x00\r
+       .byte   0x74, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x10, 0x00, 0x00\r
+       # Procedure (0x1002) {\r
+       #   TypeLeafKind: LF_PROCEDURE (0x1008)\r
+       #   ReturnType: int (0x74)\r
+       #   CallingConvention: NearC (0x0)\r
+       #   FunctionOptions [ (0x0)\r
+       #   ]\r
+       #   NumParameters: 2\r
+       #   ArgListType: (int, char**) (0x1001)\r
+       # }\r
+       .byte   0x0e, 0x00, 0x08, 0x10\r
+       .byte   0x74, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x02, 0x00\r
+       .byte   0x01, 0x10, 0x00, 0x00\r
+       # FuncId (0x1003) {\r
+       #   TypeLeafKind: LF_FUNC_ID (0x1601)\r
+       #   ParentScope: 0x0\r
+       #   FunctionType: int (int, char**) (0x1002)\r
+       #   Name: main\r
+       # }\r
+       .byte   0x12, 0x00, 0x01, 0x16\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x02, 0x10, 0x00, 0x00\r
+       .byte   0x6d, 0x61, 0x69, 0x6e\r
+       .byte   0x00, 0xf3, 0xf2, 0xf1\r
+       # Struct (0x1004) {\r
+       #   TypeLeafKind: LF_STRUCTURE (0x1505)\r
+       #   MemberCount: 0\r
+       #   Properties [ (0x280)\r
+       #     ForwardReference (0x80)\r
+       #     HasUniqueName (0x200)\r
+       #   ]\r
+       #   FieldList: 0x0\r
+       #   DerivedFrom: 0x0\r
+       #   VShape: 0x0\r
+       #   SizeOf: 0\r
+       #   Name: Struct\r
+       #   LinkageName: .?AUStruct@@\r
+       # }\r
+       .byte   0x2a, 0x00, 0x05, 0x15\r
+       .byte   0x00, 0x00, 0x80, 0x02\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x53, 0x74\r
+       .byte   0x72, 0x75, 0x63, 0x74\r
+       .byte   0x00, 0x2e, 0x3f, 0x41\r
+       .byte   0x55, 0x53, 0x74, 0x72\r
+       .byte   0x75, 0x63, 0x74, 0x40\r
+       .byte   0x40, 0x00, 0xf2, 0xf1\r
+       # Pointer (0x1005) {\r
+       #   TypeLeafKind: LF_POINTER (0x1002)\r
+       #   PointeeType: Struct (0x1004)\r
+       #   PtrType: Near64 (0xC)\r
+       #   PtrMode: Pointer (0x0)\r
+       #   IsFlat: 0\r
+       #   IsConst: 0\r
+       #   IsVolatile: 0\r
+       #   IsUnaligned: 0\r
+       #   IsRestrict: 0\r
+       #   IsThisPtr&: 0\r
+       #   IsThisPtr&&: 0\r
+       #   SizeOf: 8\r
+       # }\r
+       .byte   0x0a, 0x00, 0x02, 0x10\r
+       .byte   0x04, 0x10, 0x00, 0x00\r
+       .byte   0x0c, 0x00, 0x01, 0x00\r
+       # FieldList (0x1006) {\r
+       #   TypeLeafKind: LF_FIELDLIST (0x1203)\r
+       #   DataMember {\r
+       #     TypeLeafKind: LF_MEMBER (0x150D)\r
+       #     AccessSpecifier: Public (0x3)\r
+       #     Type: int (0x74)\r
+       #     FieldOffset: 0x0\r
+       #     Name: x\r
+       #   }\r
+       # }\r
+       .byte   0x0e, 0x00, 0x03, 0x12\r
+       .byte   0x0d, 0x15, 0x03, 0x00\r
+       .byte   0x74, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x78, 0x00\r
+       # Struct (0x1007) {\r
+       #   TypeLeafKind: LF_STRUCTURE (0x1505)\r
+       #   MemberCount: 1\r
+       #   Properties [ (0x200)\r
+       #     HasUniqueName (0x200)\r
+       #   ]\r
+       #   FieldList: <field list> (0x1006)\r
+       #   DerivedFrom: 0x0\r
+       #   VShape: 0x0\r
+       #   SizeOf: 4\r
+       #   Name: Struct\r
+       #   LinkageName: .?AUStruct@@\r
+       # }\r
+       .byte   0x2a, 0x00, 0x05, 0x15\r
+       .byte   0x01, 0x00, 0x00, 0x02\r
+       .byte   0x06, 0x10, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x04, 0x00, 0x53, 0x74\r
+       .byte   0x72, 0x75, 0x63, 0x74\r
+       .byte   0x00, 0x2e, 0x3f, 0x41\r
+       .byte   0x55, 0x53, 0x74, 0x72\r
+       .byte   0x75, 0x63, 0x74, 0x40\r
+       .byte   0x40, 0x00, 0xf2, 0xf1\r
+       # StringId (0x1008) {\r
+       #   TypeLeafKind: LF_STRING_ID (0x1605)\r
+       #   Id: 0x0\r
+       #   StringData: D:\src\llvmbuild\cl\Debug\x64\foo.cpp\r
+       # }\r
+       .byte   0x2e, 0x00, 0x05, 0x16\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x44, 0x3a, 0x5c, 0x73\r
+       .byte   0x72, 0x63, 0x5c, 0x6c\r
+       .byte   0x6c, 0x76, 0x6d, 0x62\r
+       .byte   0x75, 0x69, 0x6c, 0x64\r
+       .byte   0x5c, 0x63, 0x6c, 0x5c\r
+       .byte   0x44, 0x65, 0x62, 0x75\r
+       .byte   0x67, 0x5c, 0x78, 0x36\r
+       .byte   0x34, 0x5c, 0x66, 0x6f\r
+       .byte   0x6f, 0x2e, 0x63, 0x70\r
+       .byte   0x70, 0x00, 0xf2, 0xf1\r
+       # UdtSourceLine (0x1009) {\r
+       #   TypeLeafKind: LF_UDT_SRC_LINE (0x1606)\r
+       #   UDT: Struct (0x1007)\r
+       #   SourceFile: D:\src\llvmbuild\cl\Debug\x64\foo.cpp (0x1008)\r
+       #   LineNumber: 1\r
+       # }\r
+       .byte   0x0e, 0x00, 0x06, 0x16\r
+       .byte   0x07, 0x10, 0x00, 0x00\r
+       .byte   0x08, 0x10, 0x00, 0x00\r
+       .byte   0x01, 0x00, 0x00, 0x00\r
+       # StringId (0x100A) {\r
+       #   TypeLeafKind: LF_STRING_ID (0x1605)\r
+       #   Id: 0x0\r
+       #   StringData: D:\\src\\llvmbuild\\cl\\Debug\\x64\r
+       # }\r
+       .byte   0x2a, 0x00, 0x05, 0x16\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x44, 0x3a, 0x5c, 0x5c\r
+       .byte   0x73, 0x72, 0x63, 0x5c\r
+       .byte   0x5c, 0x6c, 0x6c, 0x76\r
+       .byte   0x6d, 0x62, 0x75, 0x69\r
+       .byte   0x6c, 0x64, 0x5c, 0x5c\r
+       .byte   0x63, 0x6c, 0x5c, 0x5c\r
+       .byte   0x44, 0x65, 0x62, 0x75\r
+       .byte   0x67, 0x5c, 0x5c, 0x78\r
+       .byte   0x36, 0x34, 0x00, 0xf1\r
+       # StringId (0x100B) {\r
+       #   TypeLeafKind: LF_STRING_ID (0x1605)\r
+       #   Id: 0x0\r
+       #   StringData: foo.cpp\r
+       # }\r
+       .byte   0x0e, 0x00, 0x05, 0x16\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x66, 0x6f, 0x6f, 0x2e\r
+       .byte   0x63, 0x70, 0x70, 0x00\r
+       # BuildInfo (0x100C) {\r
+       #   TypeLeafKind: LF_BUILDINFO (0x1603)\r
+       #   NumArgs: 5\r
+       #   Arguments [\r
+       #     ArgType: D:\\src\\llvmbuild\\cl\\Debug\\x64 (0x100A)\r
+       #     ArgType: 0x0\r
+       #     ArgType: foo.cpp (0x100B)\r
+       #     ArgType: 0x0\r
+       #     ArgType: 0x0\r
+       #   ]\r
+       # }\r
+       .byte   0x1a, 0x00, 0x03, 0x16\r
+       .byte   0x05, 0x00, 0x0a, 0x10\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x0b, 0x10\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0x00, 0x00\r
+       .byte   0x00, 0x00, 0xf2, 0xf1\r
+\r
+       .addrsig\r
+       .addrsig_sym "?S@@3UStruct@@A"\r
+       .addrsig_sym "?SS@@3UStruct@@A"\r
+       .addrsig_sym "?I@@3HA"\r
index 1a4f89d..4c39ca7 100644 (file)
@@ -61,7 +61,6 @@ public:
   void addGlobalSymbol(const codeview::ProcRefSym &Sym);
   void addGlobalSymbol(const codeview::DataSym &Sym);
   void addGlobalSymbol(const codeview::ConstantSym &Sym);
-  void addGlobalSymbol(const codeview::UDTSym &Sym);
   void addGlobalSymbol(const codeview::CVSymbol &Sym);
 
 private:
index b40ae8e..57da700 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
 
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/DebugInfo/CodeView/RecordName.h"
 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
@@ -20,6 +21,7 @@
 #include "llvm/DebugInfo/PDB/Native/Hash.h"
 #include "llvm/Support/BinaryItemStream.h"
 #include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/xxhash.h"
 #include <algorithm>
 #include <vector>
 
@@ -29,8 +31,27 @@ using namespace llvm::pdb;
 using namespace llvm::codeview;
 
 struct llvm::pdb::GSIHashStreamBuilder {
+  struct UdtDenseMapInfo {
+    static inline CVSymbol getEmptyKey() {
+      static CVSymbol Empty;
+      return Empty;
+    }
+    static inline CVSymbol getTombstoneKey() {
+      static CVSymbol Tombstone(static_cast<SymbolKind>(-1),
+                                ArrayRef<uint8_t>());
+      return Tombstone;
+    }
+    static unsigned getHashValue(const CVSymbol &Val) {
+      return xxHash64(Val.RecordData);
+    }
+    static bool isEqual(const CVSymbol &LHS, const CVSymbol &RHS) {
+      return LHS.RecordData == RHS.RecordData;
+    }
+  };
+
   std::vector<CVSymbol> Records;
   uint32_t StreamIndex;
+  llvm::DenseSet<CVSymbol, UdtDenseMapInfo> UdtHashes;
   std::vector<PSHashRecord> HashRecords;
   std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap;
   std::vector<support::ulittle32_t> HashBuckets;
@@ -42,10 +63,18 @@ struct llvm::pdb::GSIHashStreamBuilder {
 
   template <typename T> void addSymbol(const T &Symbol, MSFBuilder &Msf) {
     T Copy(Symbol);
-    Records.push_back(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(),
-                                                       CodeViewContainer::Pdb));
+    addSymbol(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(),
+                                               CodeViewContainer::Pdb));
+  }
+  void addSymbol(const CVSymbol &Symbol) {
+    if (Symbol.kind() == S_UDT) {
+      auto Iter = UdtHashes.insert(Symbol);
+      if (!Iter.second)
+        return;
+    }
+
+    Records.push_back(Symbol);
   }
-  void addSymbol(const CVSymbol &Symbol) { Records.push_back(Symbol); }
 };
 
 uint32_t GSIHashStreamBuilder::calculateSerializedLength() const {
@@ -272,10 +301,6 @@ void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) {
   GSH->addSymbol(Sym, Msf);
 }
 
-void GSIStreamBuilder::addGlobalSymbol(const UDTSym &Sym) {
-  GSH->addSymbol(Sym, Msf);
-}
-
 void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Sym) {
   GSH->addSymbol(Sym);
 }