Index: lit/SymbolFile/NativePDB/Inputs/local-variables.lldbinit =================================================================== --- lit/SymbolFile/NativePDB/Inputs/local-variables.lldbinit +++ lit/SymbolFile/NativePDB/Inputs/local-variables.lldbinit @@ -0,0 +1,32 @@ +break set -n main +run a b c d e f g +p argc +step +p SomeLocal +step +p Param1 +p Param2 +step +p Param1 +p Param2 +p Local1 +step +p Param1 +p Param2 +p Local1 +p Local2 +step +p Param1 +p Param2 +p Local1 +p Local2 +step +p Param1 +p Param2 +p Local1 +p Local2 +continue + +target modules dump ast + +quit Index: lit/SymbolFile/NativePDB/local-variables.cpp =================================================================== --- lit/SymbolFile/NativePDB/local-variables.cpp +++ lit/SymbolFile/NativePDB/local-variables.cpp @@ -0,0 +1,161 @@ +// clang-format off + +// REQUIRES: system-windows +// RUN: %build -o %t.exe -- %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \ +// RUN: %p/Inputs/local-variables.lldbinit 2>&1 | FileCheck %s + +int Function(int Param1, char Param2) { + unsigned Local1 = Param1 + 1; + char Local2 = Param2 + 1; + ++Local1; + ++Local2; + return Local1; +} + +int main(int argc, char **argv) { + int SomeLocal = argc * 2; + return Function(SomeLocal, 'a'); +} + +// CHECK: (lldb) target create "{{.*}}local-variables.cpp.tmp.exe" +// CHECK-NEXT: Current executable set to '{{.*}}local-variables.cpp.tmp.exe' +// CHECK-NEXT: (lldb) command source -s 0 '{{.*}}local-variables.lldbinit' +// CHECK-NEXT: Executing commands in '{{.*}}local-variables.lldbinit'. +// CHECK-NEXT: (lldb) break set -n main +// CHECK-NEXT: Breakpoint 1: where = local-variables.cpp.tmp.exe`main + {{.*}} at local-variables.cpp:{{.*}}, address = {{.*}} +// CHECK-NEXT: (lldb) run a b c d e f g +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1 +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`main(argc=8, argv={{.*}}) at local-variables.cpp:{{.*}} +// CHECK-NEXT: 14 } +// CHECK-NEXT: 15 +// CHECK-NEXT: 16 int main(int argc, char **argv) { +// CHECK-NEXT: -> 17 int SomeLocal = argc * 2; +// CHECK-NEXT: 18 return Function(SomeLocal, 'a'); +// CHECK-NEXT: 19 } +// CHECK-NEXT: 20 + +// CHECK: Process {{.*}} launched: '{{.*}}local-variables.cpp.tmp.exe' +// CHECK-NEXT: (lldb) p argc +// CHECK-NEXT: (int) $0 = 8 +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`main(argc=8, argv={{.*}}) at local-variables.cpp:{{.*}} +// CHECK-NEXT: 15 +// CHECK-NEXT: 16 int main(int argc, char **argv) { +// CHECK-NEXT: 17 int SomeLocal = argc * 2; +// CHECK-NEXT: -> 18 return Function(SomeLocal, 'a'); +// CHECK-NEXT: 19 } +// CHECK-NEXT: 20 + +// CHECK: (lldb) p SomeLocal +// CHECK-NEXT: (int) $1 = 16 +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} +// CHECK-NEXT: 6 +// CHECK-NEXT: 7 +// CHECK-NEXT: 8 int Function(int Param1, char Param2) { +// CHECK-NEXT: -> 9 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: 10 char Local2 = Param2 + 1; +// CHECK-NEXT: 11 ++Local1; +// CHECK-NEXT: 12 ++Local2; + +// CHECK: (lldb) p Param1 +// CHECK-NEXT: (int) $2 = 16 +// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (char) $3 = 'a' +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} +// CHECK-NEXT: 7 +// CHECK-NEXT: 8 int Function(int Param1, char Param2) { +// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: -> 10 char Local2 = Param2 + 1; +// CHECK-NEXT: 11 ++Local1; +// CHECK-NEXT: 12 ++Local2; +// CHECK-NEXT: 13 return Local1; + +// CHECK: (lldb) p Param1 +// CHECK-NEXT: (int) $4 = 16 +// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (char) $5 = 'a' +// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (unsigned int) $6 = 17 +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} +// CHECK-NEXT: 8 int Function(int Param1, char Param2) { +// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: 10 char Local2 = Param2 + 1; +// CHECK-NEXT: -> 11 ++Local1; +// CHECK-NEXT: 12 ++Local2; +// CHECK-NEXT: 13 return Local1; +// CHECK-NEXT: 14 } + +// CHECK: (lldb) p Param1 +// CHECK-NEXT: (int) $7 = 16 +// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (char) $8 = 'a' +// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (unsigned int) $9 = 17 +// CHECK-NEXT: (lldb) p Local2 +// CHECK-NEXT: (char) $10 = 'b' +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} +// CHECK-NEXT: 9 unsigned Local1 = Param1 + 1; +// CHECK-NEXT: 10 char Local2 = Param2 + 1; +// CHECK-NEXT: 11 ++Local1; +// CHECK-NEXT: -> 12 ++Local2; +// CHECK-NEXT: 13 return Local1; +// CHECK-NEXT: 14 } +// CHECK-NEXT: 15 + +// CHECK: (lldb) p Param1 +// CHECK-NEXT: (int) $11 = 16 +// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (char) $12 = 'a' +// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (unsigned int) $13 = 18 +// CHECK-NEXT: (lldb) p Local2 +// CHECK-NEXT: (char) $14 = 'b' +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables.cpp.tmp.exe`Function(Param1=16, Param2='a') at local-variables.cpp:{{.*}} +// CHECK-NEXT: 10 char Local2 = Param2 + 1; +// CHECK-NEXT: 11 ++Local1; +// CHECK-NEXT: 12 ++Local2; +// CHECK-NEXT: -> 13 return Local1; +// CHECK-NEXT: 14 } +// CHECK-NEXT: 15 +// CHECK-NEXT: 16 int main(int argc, char **argv) { + +// CHECK: (lldb) p Param1 +// CHECK-NEXT: (int) $15 = 16 +// CHECK-NEXT: (lldb) p Param2 +// CHECK-NEXT: (char) $16 = 'a' +// CHECK-NEXT: (lldb) p Local1 +// CHECK-NEXT: (unsigned int) $17 = 18 +// CHECK-NEXT: (lldb) p Local2 +// CHECK-NEXT: (char) $18 = 'c' +// CHECK-NEXT: (lldb) continue +// CHECK-NEXT: Process {{.*}} resuming +// CHECK-NEXT: Process {{.*}} exited with status = 18 (0x00000012) + +// CHECK: (lldb) target modules dump ast +// CHECK-NEXT: Dumping clang ast for 7 modules. +// CHECK-NEXT: TranslationUnitDecl +// CHECK-NEXT: |-FunctionDecl {{.*}} main 'int (int, char **)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} argc 'int' +// CHECK-NEXT: | `-ParmVarDecl {{.*}} argv 'char **' +// CHECK-NEXT: |-FunctionDecl {{.*}} Function 'int (int, char)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} Param1 'int' +// CHECK-NEXT: | `-ParmVarDecl {{.*}} Param2 'char' Index: source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h =================================================================== --- source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h +++ source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h @@ -11,6 +11,7 @@ #define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H #include "lldb/lldb-forward.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" namespace llvm { class APSInt; @@ -23,6 +24,13 @@ } // namespace llvm namespace lldb_private { namespace npdb { +DWARFExpression +MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg, + lldb::ModuleSP module); + +DWARFExpression MakeRegRelLocationExpression(llvm::codeview::RegisterId reg, + int32_t offset, + lldb::ModuleSP module); DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset, lldb::ModuleSP module); DWARFExpression MakeConstantLocationExpression( Index: source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp =================================================================== --- source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp +++ source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp @@ -9,12 +9,14 @@ #include "DWARFLocationExpression.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamBuffer.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/DataBufferHeap.h" + #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" @@ -29,6 +31,467 @@ using namespace llvm::codeview; using namespace llvm::pdb; +static const uint32_t g_code_view_to_lldb_registers_x86[] = { + LLDB_INVALID_REGNUM, // NONE + lldb_al_i386, // AL + lldb_cl_i386, // CL + lldb_dl_i386, // DL + lldb_bl_i386, // BL + lldb_ah_i386, // AH + lldb_ch_i386, // CH + lldb_dh_i386, // DH + lldb_bh_i386, // BH + lldb_ax_i386, // AX + lldb_cx_i386, // CX + lldb_dx_i386, // DX + lldb_bx_i386, // BX + lldb_sp_i386, // SP + lldb_bp_i386, // BP + lldb_si_i386, // SI + lldb_di_i386, // DI + lldb_eax_i386, // EAX + lldb_ecx_i386, // ECX + lldb_edx_i386, // EDX + lldb_ebx_i386, // EBX + lldb_esp_i386, // ESP + lldb_ebp_i386, // EBP + lldb_esi_i386, // ESI + lldb_edi_i386, // EDI + lldb_es_i386, // ES + lldb_cs_i386, // CS + lldb_ss_i386, // SS + lldb_ds_i386, // DS + lldb_fs_i386, // FS + lldb_gs_i386, // GS + LLDB_INVALID_REGNUM, // IP + LLDB_INVALID_REGNUM, // FLAGS + lldb_eip_i386, // EIP + lldb_eflags_i386, // EFLAGS + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // TEMP + LLDB_INVALID_REGNUM, // TEMPH + LLDB_INVALID_REGNUM, // QUOTE + LLDB_INVALID_REGNUM, // PCDR3 + LLDB_INVALID_REGNUM, // PCDR4 + LLDB_INVALID_REGNUM, // PCDR5 + LLDB_INVALID_REGNUM, // PCDR6 + LLDB_INVALID_REGNUM, // PCDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CR0 + LLDB_INVALID_REGNUM, // CR1 + LLDB_INVALID_REGNUM, // CR2 + LLDB_INVALID_REGNUM, // CR3 + LLDB_INVALID_REGNUM, // CR4 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_dr0_i386, // DR0 + lldb_dr1_i386, // DR1 + lldb_dr2_i386, // DR2 + lldb_dr3_i386, // DR3 + lldb_dr4_i386, // DR4 + lldb_dr5_i386, // DR5 + lldb_dr6_i386, // DR6 + lldb_dr7_i386, // DR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // GDTR + LLDB_INVALID_REGNUM, // GDTL + LLDB_INVALID_REGNUM, // IDTR + LLDB_INVALID_REGNUM, // IDTL + LLDB_INVALID_REGNUM, // LDTR + LLDB_INVALID_REGNUM, // TR + LLDB_INVALID_REGNUM, // PSEUDO1 + LLDB_INVALID_REGNUM, // PSEUDO2 + LLDB_INVALID_REGNUM, // PSEUDO3 + LLDB_INVALID_REGNUM, // PSEUDO4 + LLDB_INVALID_REGNUM, // PSEUDO5 + LLDB_INVALID_REGNUM, // PSEUDO6 + LLDB_INVALID_REGNUM, // PSEUDO7 + LLDB_INVALID_REGNUM, // PSEUDO8 + LLDB_INVALID_REGNUM, // PSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_i386, // ST0 + lldb_st1_i386, // ST1 + lldb_st2_i386, // ST2 + lldb_st3_i386, // ST3 + lldb_st4_i386, // ST4 + lldb_st5_i386, // ST5 + lldb_st6_i386, // ST6 + lldb_st7_i386, // ST7 + LLDB_INVALID_REGNUM, // CTRL + LLDB_INVALID_REGNUM, // STAT + LLDB_INVALID_REGNUM, // TAG + LLDB_INVALID_REGNUM, // FPIP + LLDB_INVALID_REGNUM, // FPCS + LLDB_INVALID_REGNUM, // FPDO + LLDB_INVALID_REGNUM, // FPDS + LLDB_INVALID_REGNUM, // ISEM + LLDB_INVALID_REGNUM, // FPEIP + LLDB_INVALID_REGNUM, // FPEDO + lldb_mm0_i386, // MM0 + lldb_mm1_i386, // MM1 + lldb_mm2_i386, // MM2 + lldb_mm3_i386, // MM3 + lldb_mm4_i386, // MM4 + lldb_mm5_i386, // MM5 + lldb_mm6_i386, // MM6 + lldb_mm7_i386, // MM7 + lldb_xmm0_i386, // XMM0 + lldb_xmm1_i386, // XMM1 + lldb_xmm2_i386, // XMM2 + lldb_xmm3_i386, // XMM3 + lldb_xmm4_i386, // XMM4 + lldb_xmm5_i386, // XMM5 + lldb_xmm6_i386, // XMM6 + lldb_xmm7_i386 // XMM7 +}; + +static const uint32_t g_code_view_to_lldb_registers_x86_64[] = { + LLDB_INVALID_REGNUM, // NONE + lldb_al_x86_64, // AL + lldb_cl_x86_64, // CL + lldb_dl_x86_64, // DL + lldb_bl_x86_64, // BL + lldb_ah_x86_64, // AH + lldb_ch_x86_64, // CH + lldb_dh_x86_64, // DH + lldb_bh_x86_64, // BH + lldb_ax_x86_64, // AX + lldb_cx_x86_64, // CX + lldb_dx_x86_64, // DX + lldb_bx_x86_64, // BX + lldb_sp_x86_64, // SP + lldb_bp_x86_64, // BP + lldb_si_x86_64, // SI + lldb_di_x86_64, // DI + lldb_eax_x86_64, // EAX + lldb_ecx_x86_64, // ECX + lldb_edx_x86_64, // EDX + lldb_ebx_x86_64, // EBX + lldb_esp_x86_64, // ESP + lldb_ebp_x86_64, // EBP + lldb_esi_x86_64, // ESI + lldb_edi_x86_64, // EDI + lldb_es_x86_64, // ES + lldb_cs_x86_64, // CS + lldb_ss_x86_64, // SS + lldb_ds_x86_64, // DS + lldb_fs_x86_64, // FS + lldb_gs_x86_64, // GS + LLDB_INVALID_REGNUM, // IP + LLDB_INVALID_REGNUM, // FLAGS + LLDB_INVALID_REGNUM, // EIP + LLDB_INVALID_REGNUM, // EFLAGS + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // TEMP + LLDB_INVALID_REGNUM, // TEMPH + LLDB_INVALID_REGNUM, // QUOTE + LLDB_INVALID_REGNUM, // PCDR3 + LLDB_INVALID_REGNUM, // PCDR4 + LLDB_INVALID_REGNUM, // PCDR5 + LLDB_INVALID_REGNUM, // PCDR6 + LLDB_INVALID_REGNUM, // PCDR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // CR0 + LLDB_INVALID_REGNUM, // CR1 + LLDB_INVALID_REGNUM, // CR2 + LLDB_INVALID_REGNUM, // CR3 + LLDB_INVALID_REGNUM, // CR4 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_dr0_x86_64, // DR0 + lldb_dr1_x86_64, // DR1 + lldb_dr2_x86_64, // DR2 + lldb_dr3_x86_64, // DR3 + lldb_dr4_x86_64, // DR4 + lldb_dr5_x86_64, // DR5 + lldb_dr6_x86_64, // DR6 + lldb_dr7_x86_64, // DR7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // GDTR + LLDB_INVALID_REGNUM, // GDTL + LLDB_INVALID_REGNUM, // IDTR + LLDB_INVALID_REGNUM, // IDTL + LLDB_INVALID_REGNUM, // LDTR + LLDB_INVALID_REGNUM, // TR + LLDB_INVALID_REGNUM, // PSEUDO1 + LLDB_INVALID_REGNUM, // PSEUDO2 + LLDB_INVALID_REGNUM, // PSEUDO3 + LLDB_INVALID_REGNUM, // PSEUDO4 + LLDB_INVALID_REGNUM, // PSEUDO5 + LLDB_INVALID_REGNUM, // PSEUDO6 + LLDB_INVALID_REGNUM, // PSEUDO7 + LLDB_INVALID_REGNUM, // PSEUDO8 + LLDB_INVALID_REGNUM, // PSEUDO9 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_st0_x86_64, // ST0 + lldb_st1_x86_64, // ST1 + lldb_st2_x86_64, // ST2 + lldb_st3_x86_64, // ST3 + lldb_st4_x86_64, // ST4 + lldb_st5_x86_64, // ST5 + lldb_st6_x86_64, // ST6 + lldb_st7_x86_64, // ST7 + LLDB_INVALID_REGNUM, // CTRL + LLDB_INVALID_REGNUM, // STAT + LLDB_INVALID_REGNUM, // TAG + LLDB_INVALID_REGNUM, // FPIP + LLDB_INVALID_REGNUM, // FPCS + LLDB_INVALID_REGNUM, // FPDO + LLDB_INVALID_REGNUM, // FPDS + LLDB_INVALID_REGNUM, // ISEM + LLDB_INVALID_REGNUM, // FPEIP + LLDB_INVALID_REGNUM, // FPEDO + lldb_mm0_x86_64, // MM0 + lldb_mm1_x86_64, // MM1 + lldb_mm2_x86_64, // MM2 + lldb_mm3_x86_64, // MM3 + lldb_mm4_x86_64, // MM4 + lldb_mm5_x86_64, // MM5 + lldb_mm6_x86_64, // MM6 + lldb_mm7_x86_64, // MM7 + lldb_xmm0_x86_64, // XMM0 + lldb_xmm1_x86_64, // XMM1 + lldb_xmm2_x86_64, // XMM2 + lldb_xmm3_x86_64, // XMM3 + lldb_xmm4_x86_64, // XMM4 + lldb_xmm5_x86_64, // XMM5 + lldb_xmm6_x86_64, // XMM6 + lldb_xmm7_x86_64, // XMM7 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + lldb_mxcsr_x86_64, // MXCSR + LLDB_INVALID_REGNUM, // EDXEAX + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, // EMM0L + LLDB_INVALID_REGNUM, // EMM1L + LLDB_INVALID_REGNUM, // EMM2L + LLDB_INVALID_REGNUM, // EMM3L + LLDB_INVALID_REGNUM, // EMM4L + LLDB_INVALID_REGNUM, // EMM5L + LLDB_INVALID_REGNUM, // EMM6L + LLDB_INVALID_REGNUM, // EMM7L + LLDB_INVALID_REGNUM, // EMM0H + LLDB_INVALID_REGNUM, // EMM1H + LLDB_INVALID_REGNUM, // EMM2H + LLDB_INVALID_REGNUM, // EMM3H + LLDB_INVALID_REGNUM, // EMM4H + LLDB_INVALID_REGNUM, // EMM5H + LLDB_INVALID_REGNUM, // EMM6H + LLDB_INVALID_REGNUM, // EMM7H + LLDB_INVALID_REGNUM, // MM00 + LLDB_INVALID_REGNUM, // MM01 + LLDB_INVALID_REGNUM, // MM10 + LLDB_INVALID_REGNUM, // MM11 + LLDB_INVALID_REGNUM, // MM20 + LLDB_INVALID_REGNUM, // MM21 + LLDB_INVALID_REGNUM, // MM30 + LLDB_INVALID_REGNUM, // MM31 + LLDB_INVALID_REGNUM, // MM40 + LLDB_INVALID_REGNUM, // MM41 + LLDB_INVALID_REGNUM, // MM50 + LLDB_INVALID_REGNUM, // MM51 + LLDB_INVALID_REGNUM, // MM60 + LLDB_INVALID_REGNUM, // MM61 + LLDB_INVALID_REGNUM, // MM70 + LLDB_INVALID_REGNUM, // MM71 + lldb_xmm8_x86_64, // XMM8 + lldb_xmm9_x86_64, // XMM9 + lldb_xmm10_x86_64, // XMM10 + lldb_xmm11_x86_64, // XMM11 + lldb_xmm12_x86_64, // XMM12 + lldb_xmm13_x86_64, // XMM13 + lldb_xmm14_x86_64, // XMM14 + lldb_xmm15_x86_64, // XMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + lldb_sil_x86_64, // SIL + lldb_dil_x86_64, // DIL + lldb_bpl_x86_64, // BPL + lldb_spl_x86_64, // SPL + lldb_rax_x86_64, // RAX + lldb_rbx_x86_64, // RBX + lldb_rcx_x86_64, // RCX + lldb_rdx_x86_64, // RDX + lldb_rsi_x86_64, // RSI + lldb_rdi_x86_64, // RDI + lldb_rbp_x86_64, // RBP + lldb_rsp_x86_64, // RSP + lldb_r8_x86_64, // R8 + lldb_r9_x86_64, // R9 + lldb_r10_x86_64, // R10 + lldb_r11_x86_64, // R11 + lldb_r12_x86_64, // R12 + lldb_r13_x86_64, // R13 + lldb_r14_x86_64, // R14 + lldb_r15_x86_64, // R15 + lldb_r8l_x86_64, // R8B + lldb_r9l_x86_64, // R9B + lldb_r10l_x86_64, // R10B + lldb_r11l_x86_64, // R11B + lldb_r12l_x86_64, // R12B + lldb_r13l_x86_64, // R13B + lldb_r14l_x86_64, // R14B + lldb_r15l_x86_64, // R15B + lldb_r8w_x86_64, // R8W + lldb_r9w_x86_64, // R9W + lldb_r10w_x86_64, // R10W + lldb_r11w_x86_64, // R11W + lldb_r12w_x86_64, // R12W + lldb_r13w_x86_64, // R13W + lldb_r14w_x86_64, // R14W + lldb_r15w_x86_64, // R15W + lldb_r8d_x86_64, // R8D + lldb_r9d_x86_64, // R9D + lldb_r10d_x86_64, // R10D + lldb_r11d_x86_64, // R11D + lldb_r12d_x86_64, // R12D + lldb_r13d_x86_64, // R13D + lldb_r14d_x86_64, // R14D + lldb_r15d_x86_64, // R15D + lldb_ymm0_x86_64, // AMD64_YMM0 + lldb_ymm1_x86_64, // AMD64_YMM1 + lldb_ymm2_x86_64, // AMD64_YMM2 + lldb_ymm3_x86_64, // AMD64_YMM3 + lldb_ymm4_x86_64, // AMD64_YMM4 + lldb_ymm5_x86_64, // AMD64_YMM5 + lldb_ymm6_x86_64, // AMD64_YMM6 + lldb_ymm7_x86_64, // AMD64_YMM7 + lldb_ymm8_x86_64, // AMD64_YMM8 + lldb_ymm9_x86_64, // AMD64_YMM9 + lldb_ymm10_x86_64, // AMD64_YMM10 + lldb_ymm11_x86_64, // AMD64_YMM11 + lldb_ymm12_x86_64, // AMD64_YMM12 + lldb_ymm13_x86_64, // AMD64_YMM13 + lldb_ymm14_x86_64, // AMD64_YMM14 + lldb_ymm15_x86_64, // AMD64_YMM15 + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, + lldb_bnd0_x86_64, // BND0 + lldb_bnd1_x86_64, // BND1 + lldb_bnd2_x86_64 // BND2 +}; + +uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type, + llvm::codeview::RegisterId register_id) { + switch (arch_type) { + case llvm::Triple::x86: + if (static_cast(register_id) < + sizeof(g_code_view_to_lldb_registers_x86) / + sizeof(g_code_view_to_lldb_registers_x86[0])) + return g_code_view_to_lldb_registers_x86[static_cast( + register_id)]; + + switch (register_id) { + case llvm::codeview::RegisterId::MXCSR: + return lldb_mxcsr_i386; + case llvm::codeview::RegisterId::BND0: + return lldb_bnd0_i386; + case llvm::codeview::RegisterId::BND1: + return lldb_bnd1_i386; + case llvm::codeview::RegisterId::BND2: + return lldb_bnd2_i386; + default: + return LLDB_INVALID_REGNUM; + } + case llvm::Triple::x86_64: + if (static_cast(register_id) < + sizeof(g_code_view_to_lldb_registers_x86_64) / + sizeof(g_code_view_to_lldb_registers_x86_64[0])) + return g_code_view_to_lldb_registers_x86_64[static_cast( + register_id)]; + + return LLDB_INVALID_REGNUM; + default: + return LLDB_INVALID_REGNUM; + } +} + +uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) { + if (register_id == llvm::codeview::RegisterId::VFRAME) + return LLDB_REGNUM_GENERIC_FP; + + return LLDB_INVALID_REGNUM; +} + +static uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type, + llvm::codeview::RegisterId register_id, + RegisterKind ®ister_kind) { + register_kind = eRegisterKindLLDB; + uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id); + if (reg_num != LLDB_INVALID_REGNUM) + return reg_num; + + register_kind = eRegisterKindGeneric; + return GetGenericRegisterNumber(register_id); +} + static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) { switch (kind) { case SimpleTypeKind::Int128: @@ -107,6 +570,46 @@ return result; } +static DWARFExpression MakeRegisterBasedLocationExpressionInternal( + llvm::codeview::RegisterId reg, llvm::Optional relative_offset, + lldb::ModuleSP module) { + return MakeLocationExpressionInternal( + module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { + uint32_t reg_num = GetRegisterNumber( + module->GetArchitecture().GetMachine(), reg, register_kind); + if (reg_num == LLDB_INVALID_REGNUM) + return false; + + if (reg_num > 31) { + llvm::dwarf::LocationAtom base = relative_offset + ? llvm::dwarf::DW_OP_bregx + : llvm::dwarf::DW_OP_regx; + stream.PutHex8(base); + stream.PutULEB128(reg_num); + } else { + llvm::dwarf::LocationAtom base = relative_offset + ? llvm::dwarf::DW_OP_breg0 + : llvm::dwarf::DW_OP_reg0; + stream.PutHex8(base + reg_num); + } + + if (relative_offset) + stream.PutSLEB128(*relative_offset); + + return true; + }); +} + +DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpression( + llvm::codeview::RegisterId reg, lldb::ModuleSP module) { + return MakeRegisterBasedLocationExpressionInternal(reg, llvm::None, module); +} + +DWARFExpression lldb_private::npdb::MakeRegRelLocationExpression( + llvm::codeview::RegisterId reg, int32_t offset, lldb::ModuleSP module) { + return MakeRegisterBasedLocationExpressionInternal(reg, offset, module); +} + DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression( uint16_t section, uint32_t offset, ModuleSP module) { assert(section > 0); Index: source/Plugins/SymbolFile/NativePDB/PdbSymUid.h =================================================================== --- source/Plugins/SymbolFile/NativePDB/PdbSymUid.h +++ source/Plugins/SymbolFile/NativePDB/PdbSymUid.h @@ -93,6 +93,7 @@ uint64_t m_repr = 0; public: + PdbSymUid() = default; PdbSymUid(uint64_t repr) : m_repr(repr) {} PdbSymUid(const PdbCompilandId &cid); PdbSymUid(const PdbCompilandSymId &csid); Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -109,10 +109,10 @@ VariableList &variables) override; size_t ParseTypes(const SymbolContext &sc) override; - size_t ParseVariablesForContext(const SymbolContext &sc) override { - return 0; - } + size_t ParseVariablesForContext(const SymbolContext &sc) override; + CompilerDecl GetDeclForUID(lldb::user_id_t uid) override; + CompilerDeclContext GetDeclContextForUID(lldb::user_id_t uid) override; CompilerDeclContext GetDeclContextContainingUID(lldb::user_id_t uid) override; Type *ResolveTypeUID(lldb::user_id_t type_uid) override; llvm::Optional GetDynamicArrayInfoForUID( @@ -194,20 +194,30 @@ clang::MSInheritanceAttr::Spelling inheritance); lldb::FunctionSP GetOrCreateFunction(PdbCompilandSymId func_id, - const SymbolContext &sc); + CompileUnit &comp_unit); lldb::CompUnitSP GetOrCreateCompileUnit(const CompilandIndexItem &cci); lldb::TypeSP GetOrCreateType(PdbTypeSymId type_id); lldb::TypeSP GetOrCreateType(llvm::codeview::TypeIndex ti); lldb::VariableSP GetOrCreateGlobalVariable(PdbGlobalSymId var_id); + Block &GetOrCreateBlock(PdbCompilandSymId block_id); + lldb::VariableSP GetOrCreateLocalVariable(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id, + bool is_param); lldb::FunctionSP CreateFunction(PdbCompilandSymId func_id, - const SymbolContext &sc); + CompileUnit &comp_unit); + Block &CreateBlock(PdbCompilandSymId block_id); + lldb::VariableSP CreateLocalVariable(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id, bool is_param); lldb::CompUnitSP CreateCompileUnit(const CompilandIndexItem &cci); lldb::TypeSP CreateType(PdbTypeSymId type_id); lldb::TypeSP CreateAndCacheType(PdbTypeSymId type_id); lldb::VariableSP CreateGlobalVariable(PdbGlobalSymId var_id); lldb::VariableSP CreateConstantSymbol(PdbGlobalSymId var_id, const llvm::codeview::CVSymbol &cvs); + size_t ParseVariablesForCompileUnit(CompileUnit &comp_unit, + VariableList &variables); + size_t ParseVariablesForBlock(PdbCompilandSymId block_id); llvm::BumpPtrAllocator m_allocator; @@ -224,6 +234,8 @@ m_parent_types; llvm::DenseMap m_global_vars; + llvm::DenseMap m_local_variables; + llvm::DenseMap m_blocks; llvm::DenseMap m_functions; llvm::DenseMap m_compilands; llvm::DenseMap m_types; Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -66,6 +66,15 @@ using namespace llvm::codeview; using namespace llvm::pdb; +namespace { +struct VariableInfo { + llvm::StringRef name; + TypeIndex type; + llvm::Optional location; + llvm::Optional ranges; +}; +} // namespace + static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { switch (lang) { case PDB_Lang::Cpp: @@ -314,6 +323,94 @@ } } +static Variable::RangeList +MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range, + llvm::ArrayRef gaps) { + lldb::addr_t start = + index.MakeVirtualAddress(range.ISectStart, range.OffsetStart); + lldb::addr_t end = start + range.Range; + + Variable::RangeList result; + while (!gaps.empty()) { + const LocalVariableAddrGap &gap = gaps.front(); + + lldb::addr_t size = gap.GapStartOffset - start; + result.Append(start, size); + start += gap.Range; + gaps = gaps.drop_front(); + } + + result.Append(start, end); + return result; +} + +static VariableInfo GetVariableInformation(PdbIndex &index, + PdbCompilandSymId var_id, + ModuleSP module, + bool get_location_info) { + VariableInfo result; + CVSymbol sym = index.ReadSymbolRecord(var_id); + + if (sym.kind() == S_REGREL32) { + RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); + cantFail(SymbolDeserializer::deserializeAs(sym, reg)); + result.type = reg.Type; + result.name = reg.Name; + if (get_location_info) { + result.location = + MakeRegRelLocationExpression(reg.Register, reg.Offset, module); + result.ranges.emplace(); + } + return result; + } + + if (sym.kind() == S_REGISTER) { + RegisterSym reg(SymbolRecordKind::RegisterSym); + cantFail(SymbolDeserializer::deserializeAs(sym, reg)); + result.type = reg.Index; + result.name = reg.Name; + if (get_location_info) { + result.location = + MakeEnregisteredLocationExpression(reg.Register, module); + result.ranges.emplace(); + } + return result; + } + + if (sym.kind() == S_LOCAL) { + LocalSym local(SymbolRecordKind::LocalSym); + cantFail(SymbolDeserializer::deserializeAs(sym, local)); + result.type = local.Type; + result.name = local.Name; + + if (!get_location_info) + return result; + + PdbCompilandSymId loc_specifier_id(var_id.modi, + var_id.offset + sym.RecordData.size()); + CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); + if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) { + DefRangeFramePointerRelSym loc( + SymbolRecordKind::DefRangeFramePointerRelSym); + cantFail(SymbolDeserializer::deserializeAs( + loc_specifier_cvs, loc)); + // FIXME: The register needs to come from the S_FRAMEPROC symbol. + result.location = + MakeRegRelLocationExpression(RegisterId::RSP, loc.Offset, module); + result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); + } else { + // FIXME: Handle other kinds + llvm::APSInt value; + value = 42; + result.location = MakeConstantLocationExpression( + TypeIndex::Int32(), index.tpi(), value, module); + } + return result; + } + llvm_unreachable("Symbol is not a local variable!"); + return result; +} + void SymbolFileNativePDB::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, @@ -520,8 +617,45 @@ return count; } +Block &SymbolFileNativePDB::CreateBlock(PdbCompilandSymId block_id) { + CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi); + CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset); + clang::DeclContext *parent_decl_ctx = m_clang->GetTranslationUnitDecl(); + + if (sym.kind() == S_GPROC32 || sym.kind() == S_LPROC32) { + // This is a function. It must be global. Creating the Function entry for + // it automatically creates a block for it. + CompUnitSP comp_unit = GetOrCreateCompileUnit(*cii); + return GetOrCreateFunction(block_id, *comp_unit)->GetBlock(false); + } + + lldbassert(sym.kind() == S_BLOCK32); + + // This is a block. Its parent is either a function or another block. In + // either case, its parent can be viewed as a block (e.g. a function contains + // 1 big block. So just get the parent block and add this block to it. + BlockSym block(static_cast(sym.kind())); + cantFail(SymbolDeserializer::deserializeAs(sym, block)); + lldbassert(block.Parent != 0); + PdbCompilandSymId parent_id(block_id.modi, block.Parent); + Block &parent_block = GetOrCreateBlock(parent_id); + + lldb::user_id_t opaque_block_uid = toOpaqueUid(block_id); + BlockSP child_block = std::make_shared(opaque_block_uid); + parent_block.AddChild(child_block); + CompilerDeclContext cdc = GetDeclContextForUID(parent_block.GetID()); + parent_decl_ctx = + static_cast(cdc.GetOpaqueDeclContext()); + clang::BlockDecl *block_decl = + m_clang->CreateBlockDeclaration(parent_decl_ctx); + + m_blocks.insert({opaque_block_uid, child_block}); + m_uid_to_decl.insert({opaque_block_uid, block_decl}); + return *child_block; +} + lldb::FunctionSP SymbolFileNativePDB::CreateFunction(PdbCompilandSymId func_id, - const SymbolContext &sc) { + CompileUnit &comp_unit) { const CompilandIndexItem *cci = m_index->compilands().GetCompiland(func_id.modi); lldbassert(cci); @@ -535,7 +669,7 @@ return nullptr; AddressRange func_range(file_vm_addr, sol.length, - sc.module_sp->GetSectionList()); + comp_unit.GetModule()->GetSectionList()); if (!func_range.GetBaseAddress().IsValid()) return nullptr; @@ -546,27 +680,22 @@ PdbTypeSymId sig_id(proc.FunctionType, false); Mangled mangled(proc.Name); FunctionSP func_sp = std::make_shared( - sc.comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled, + &comp_unit, toOpaqueUid(func_id), toOpaqueUid(sig_id), mangled, func_type.get(), func_range); - sc.comp_unit->AddFunction(func_sp); + comp_unit.AddFunction(func_sp); + + user_id_t opaque_func_uid = toOpaqueUid(func_id); clang::StorageClass storage = clang::SC_None; if (sym_record.kind() == S_LPROC32) storage = clang::SC_Static; - // There are two ways we could retrieve the parameter list. The first is by - // iterating the arguments on the function signature type, however that would - // only tell us the types of the arguments and not the names. The second is - // to iterate the CVSymbol records that follow the S_GPROC32 / S_LPROC32 until - // we have the correct number of arguments as stated by the function - // signature. The latter has more potential to go wrong in the face of - // improper debug info simply because we're assuming more about the layout of - // the records, but it is the only way to get argument names. + // The function signature only tells us the number of types of arguments, but + // not the names. So we need to iterate the symbol stream looking for the + // corresponding symbol records to properly construct the AST. CVType sig_cvt; - CVType arg_list_cvt; ProcedureRecord sig_record; - ArgListRecord arg_list_record; sig_cvt = m_index->tpi().getType(proc.FunctionType); if (sig_cvt.kind() != LF_PROCEDURE) @@ -574,8 +703,7 @@ cantFail( TypeDeserializer::deserializeAs(sig_cvt, sig_record)); - CompilerDeclContext context = - GetDeclContextContainingUID(toOpaqueUid(func_id)); + CompilerDeclContext context = GetDeclContextContainingUID(opaque_func_uid); clang::DeclContext *decl_context = static_cast(context.GetOpaqueDeclContext()); @@ -583,8 +711,9 @@ decl_context, proc.Name.str().c_str(), func_type->GetForwardCompilerType(), storage, false); - lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); - m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; + lldbassert(m_uid_to_decl.count(opaque_func_uid) == 0); + m_uid_to_decl[opaque_func_uid] = function_decl; + CVSymbolArray scope = limitSymbolArrayToScope( cci->m_debug_stream.getSymbolArray(), func_id.offset); @@ -593,57 +722,34 @@ auto end = scope.end(); std::vector params; while (begin != end && params_remaining > 0) { - uint32_t record_offset = begin.offset(); - CVSymbol sym = *begin++; - - TypeIndex param_type; - llvm::StringRef param_name; + CVSymbol sym = *begin; switch (sym.kind()) { - case S_REGREL32: { - RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); - cantFail(SymbolDeserializer::deserializeAs(sym, reg)); - param_type = reg.Type; - param_name = reg.Name; + case S_REGREL32: + case S_REGISTER: + case S_LOCAL: break; - } - case S_REGISTER: { - RegisterSym reg(SymbolRecordKind::RegisterSym); - cantFail(SymbolDeserializer::deserializeAs(sym, reg)); - param_type = reg.Index; - param_name = reg.Name; - break; - } - case S_LOCAL: { - LocalSym local(SymbolRecordKind::LocalSym); - cantFail(SymbolDeserializer::deserializeAs(sym, local)); - if ((local.Flags & LocalSymFlags::IsParameter) == LocalSymFlags::None) - continue; - param_type = local.Type; - param_name = local.Name; - break; - } case S_BLOCK32: - // All parameters should come before the first block. If that isn't the - // case, then perhaps this is bad debug info that doesn't contain - // information about all parameters. params_remaining = 0; continue; default: + ++begin; continue; } + PdbCompilandSymId param_uid(func_id.modi, begin.offset()); + VariableInfo var_info = GetVariableInformation( + *m_index, param_uid, GetObjectFile()->GetModule(), false); - PdbCompilandSymId param_uid(func_id.modi, record_offset); - TypeSP type_sp = GetOrCreateType(param_type); + TypeSP type_sp = GetOrCreateType(var_info.type); clang::ParmVarDecl *param = m_clang->CreateParameterDeclaration( - function_decl, param_name.str().c_str(), + function_decl, var_info.name.str().c_str(), type_sp->GetForwardCompilerType(), clang::SC_None); lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); m_uid_to_decl[toOpaqueUid(param_uid)] = param; params.push_back(param); --params_remaining; + ++begin; } - if (!params.empty()) m_clang->SetFunctionParameters(function_decl, params.data(), params.size()); @@ -1243,10 +1349,10 @@ } FunctionSP SymbolFileNativePDB::GetOrCreateFunction(PdbCompilandSymId func_id, - const SymbolContext &sc) { + CompileUnit &comp_unit) { auto emplace_result = m_functions.try_emplace(toOpaqueUid(func_id), nullptr); if (emplace_result.second) - emplace_result.first->second = CreateFunction(func_id, sc); + emplace_result.first->second = CreateFunction(func_id, comp_unit); lldbassert(emplace_result.first->second); return emplace_result.first->second; @@ -1264,6 +1370,14 @@ return emplace_result.first->second; } +Block &SymbolFileNativePDB::GetOrCreateBlock(PdbCompilandSymId block_id) { + auto iter = m_blocks.find(toOpaqueUid(block_id)); + if (iter != m_blocks.end()) + return *iter->second; + + return CreateBlock(block_id); +} + lldb::CompUnitSP SymbolFileNativePDB::ParseCompileUnitAtIndex(uint32_t index) { if (index >= GetNumCompileUnits()) return CompUnitSP(); @@ -1326,19 +1440,35 @@ resolved_flags |= eSymbolContextCompUnit; } - if (resolve_scope & eSymbolContextFunction) { + if (resolve_scope & eSymbolContextFunction || + resolve_scope & eSymbolContextBlock) { lldbassert(sc.comp_unit); std::vector matches = m_index->FindSymbolsByVa(file_addr); - for (const auto &match : matches) { + // Search the matches in reverse. This way if there are multiple matches + // (for example we are 3 levels deep in a nested scope) it will find the + // innermost one first. + for (const auto &match : llvm::reverse(matches)) { if (match.uid.kind() != PdbSymUidKind::CompilandSym) continue; + PdbCompilandSymId csid = match.uid.asCompilandSym(); CVSymbol cvs = m_index->ReadSymbolRecord(csid); - if (CVSymToPDBSym(cvs.kind()) != PDB_SymType::Function) + PDB_SymType type = CVSymToPDBSym(cvs.kind()); + if (type != PDB_SymType::Function && type != PDB_SymType::Block) continue; - sc.function = GetOrCreateFunction(csid, sc).get(); - } + if (type == PDB_SymType::Function) { + sc.function = GetOrCreateFunction(csid, *sc.comp_unit).get(); + sc.block = sc.GetFunctionBlock(); + } + + if (type == PDB_SymType::Block) { + sc.block = &GetOrCreateBlock(csid); + sc.function = sc.block->CalculateSymbolContextFunction(); + } resolved_flags |= eSymbolContextFunction; + resolved_flags |= eSymbolContextBlock; + break; + } } if (resolve_scope & eSymbolContextLineEntry) { @@ -1496,7 +1626,9 @@ size_t SymbolFileNativePDB::ParseFunctionBlocks(const SymbolContext &sc) { lldbassert(sc.comp_unit && sc.function); - return 0; + GetOrCreateBlock(PdbSymUid(sc.function->GetID()).asCompilandSym()); + // FIXME: Parse child blocks + return 1; } void SymbolFileNativePDB::DumpClangAST(Stream &s) { @@ -1558,9 +1690,8 @@ SymbolContext sc; sc.comp_unit = GetOrCreateCompileUnit(cci).get(); - sc.module_sp = sc.comp_unit->GetModule(); PdbCompilandSymId func_id(proc.modi(), proc.SymOffset); - sc.function = GetOrCreateFunction(func_id, sc).get(); + sc.function = GetOrCreateFunction(func_id, *sc.comp_unit).get(); sc_list.Append(sc); } @@ -1621,6 +1752,188 @@ size_t SymbolFileNativePDB::ParseTypes(const SymbolContext &sc) { return 0; } +size_t +SymbolFileNativePDB::ParseVariablesForCompileUnit(CompileUnit &comp_unit, + VariableList &variables) { + PdbSymUid sym_uid(comp_unit.GetID()); + lldbassert(sym_uid.kind() == PdbSymUidKind::Compiland); + return 0; +} + +VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, + PdbCompilandSymId var_id, + bool is_param) { + ModuleSP module = GetObjectFile()->GetModule(); + VariableInfo var_info = + GetVariableInformation(*m_index, var_id, module, true); + + CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi); + CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii); + TypeSP type_sp = GetOrCreateType(var_info.type); + std::string name = var_info.name.str(); + Declaration decl; + SymbolFileTypeSP sftype = + std::make_shared(*this, type_sp->GetID()); + + ValueType var_scope = + is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal; + VariableSP var_sp = std::make_shared( + toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, + comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false, + false, false); + + CompilerDeclContext cdc = GetDeclContextForUID(toOpaqueUid(scope_id)); + clang::DeclContext *decl_ctx = + static_cast(cdc.GetOpaqueDeclContext()); + + // Parameter info should have already been added to the AST. + if (!is_param) { + clang::QualType qt = + ClangUtil::GetCanonicalQualType(type_sp->GetForwardCompilerType()); + + clang::VarDecl *var_decl = + m_clang->CreateVariableDeclaration(decl_ctx, name.c_str(), qt); + lldbassert(m_uid_to_decl.count(toOpaqueUid(var_id)) == 0); + m_uid_to_decl[toOpaqueUid(var_id)] = var_decl; + } + + m_local_variables[toOpaqueUid(var_id)] = var_sp; + return var_sp; +} + +VariableSP SymbolFileNativePDB::GetOrCreateLocalVariable( + PdbCompilandSymId scope_id, PdbCompilandSymId var_id, bool is_param) { + auto iter = m_local_variables.find(toOpaqueUid(var_id)); + if (iter != m_local_variables.end()) + return iter->second; + + return CreateLocalVariable(scope_id, var_id, is_param); +} + +size_t SymbolFileNativePDB::ParseVariablesForBlock(PdbCompilandSymId block_id) { + Block &block = GetOrCreateBlock(block_id); + + size_t count = 0; + + CompilandIndexItem *cii = m_index->compilands().GetCompiland(block_id.modi); + CVSymbol sym = cii->m_debug_stream.readSymbolAtOffset(block_id.offset); + uint32_t params_remaining = 0; + switch (sym.kind()) { + case S_GPROC32: + case S_LPROC32: { + ProcSym proc(static_cast(sym.kind())); + cantFail(SymbolDeserializer::deserializeAs(sym, proc)); + CVType signature = m_index->tpi().getType(proc.FunctionType); + ProcedureRecord sig; + cantFail(TypeDeserializer::deserializeAs(signature, sig)); + params_remaining = sig.getParameterCount(); + break; + } + case S_BLOCK32: + break; + default: + lldbassert(false && "Symbol is not a block!"); + return 0; + } + + VariableListSP variables = block.GetBlockVariableList(false); + if (!variables) { + variables = std::make_shared(); + block.SetVariableList(variables); + } + + CVSymbolArray syms = limitSymbolArrayToScope( + cii->m_debug_stream.getSymbolArray(), block_id.offset); + + // Skip the first record since it's a PROC32 or BLOCK32, and there's + // no point examining it since we know it's not a local variable. + syms.drop_front(); + auto iter = syms.begin(); + auto end = syms.end(); + + while (iter != end) { + uint32_t record_offset = iter.offset(); + CVSymbol variable_cvs = *iter; + PdbCompilandSymId child_sym_id(block_id.modi, record_offset); + ++iter; + + // If this is a block, recurse into its children and then skip it. + if (variable_cvs.kind() == S_BLOCK32) { + uint32_t block_end = getScopeEndOffset(variable_cvs); + count += ParseVariablesForBlock(child_sym_id); + iter = syms.at(block_end); + continue; + } + + bool is_param = params_remaining > 0; + VariableSP variable; + switch (variable_cvs.kind()) { + case S_REGREL32: + case S_REGISTER: + case S_LOCAL: + variable = GetOrCreateLocalVariable(block_id, child_sym_id, is_param); + if (is_param) + --params_remaining; + variables->AddVariableIfUnique(variable); + break; + default: + break; + } + } + + // Pass false for set_children, since we call this recursively so that the + // children will call this for themselves. + block.SetDidParseVariables(true, false); + + return count; +} + +size_t SymbolFileNativePDB::ParseVariablesForContext(const SymbolContext &sc) { + lldbassert(sc.function || sc.comp_unit); + + VariableListSP variables; + PdbSymUid sym_uid; + if (sc.block) { + PdbSymUid block_id(sc.block->GetID()); + + size_t count = ParseVariablesForBlock(block_id.asCompilandSym()); + return count; + } + + if (sc.function) { + PdbSymUid block_id(sc.function->GetID()); + + size_t count = ParseVariablesForBlock(block_id.asCompilandSym()); + return count; + } + + if (sc.comp_unit) { + variables = sc.comp_unit->GetVariableList(false); + if (!variables) { + variables = std::make_shared(); + sc.comp_unit->SetVariableList(variables); + } + return ParseVariablesForCompileUnit(*sc.comp_unit, *variables); + } + + llvm_unreachable("Unreachable!"); +} + +CompilerDecl SymbolFileNativePDB::GetDeclForUID(lldb::user_id_t uid) { + auto iter = m_uid_to_decl.find(uid); + if (iter == m_uid_to_decl.end()) + return CompilerDecl(); + + return {m_clang, iter->second}; +} + +CompilerDeclContext +SymbolFileNativePDB::GetDeclContextForUID(lldb::user_id_t uid) { + CompilerDecl compiler_decl = GetDeclForUID(uid); + clang::Decl *decl = static_cast(compiler_decl.GetOpaqueDecl()); + return {m_clang, clang::Decl::castToDeclContext(decl)}; +} + CompilerDeclContext SymbolFileNativePDB::GetDeclContextContainingUID(lldb::user_id_t uid) { // FIXME: This should look up the uid, decide if it's a symbol or a type, and Index: source/Symbol/ClangASTContext.cpp =================================================================== --- source/Symbol/ClangASTContext.cpp +++ source/Symbol/ClangASTContext.cpp @@ -2218,10 +2218,13 @@ const CompilerType ¶m_type, int storage) { ASTContext *ast = getASTContext(); assert(ast != nullptr); - return ParmVarDecl::Create(*ast, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast->Idents.get(name) : nullptr, - ClangUtil::GetQualType(param_type), nullptr, - (clang::StorageClass)storage, nullptr); + auto *decl = + ParmVarDecl::Create(*ast, decl_ctx, SourceLocation(), SourceLocation(), + name && name[0] ? &ast->Idents.get(name) : nullptr, + ClangUtil::GetQualType(param_type), nullptr, + (clang::StorageClass)storage, nullptr); + decl_ctx->addDecl(decl); + return decl; } void ClangASTContext::SetFunctionParameters(FunctionDecl *function_decl,