zequanwu updated this revision to Diff 450408. zequanwu added a comment. - Recurse into parent classes when filling the offset to size map. - Previously the range parsed earlier is preferred, now it's the range parsed later is preferred, since it makes the code cleaner and it doesn't really matter as long as it's consistent. Although overlapping ranges are allowed in RangeDataVector, I'm still trying to keep the RangeMap contains non-overlapping ranges, since only whole value ranges are allowed to overlap with each other, and subfield ranges should not overlap with each other or whole value ranges. It's easier just to keep all ranges non-overlapping.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D130796/new/ https://reviews.llvm.org/D130796 Files: lldb/include/lldb/Utility/RangeMap.h lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables-registers.lldbinit lldb/test/Shell/SymbolFile/NativePDB/inline_sites.test lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s lldb/test/Shell/SymbolFile/NativePDB/subfield_register_simple_type.s
Index: lldb/test/Shell/SymbolFile/NativePDB/subfield_register_simple_type.s =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/subfield_register_simple_type.s +++ /dev/null @@ -1,433 +0,0 @@ -# clang-format off -# REQUIRES: lld, x86 - -# RUN: %clang_cl --target=i386-windows-msvc -c /Fo%t.obj -- %s -# RUN: lld-link /debug:full /nodefaultlib /entry:main %t.obj /out:%t.exe /base:0x400000 -# RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \ -# RUN: %p/Inputs/subfield_register_simple_type.lldbinit 2>&1 | FileCheck %s - -# This file is compiled from following source file: -# clang-cl --target=i386-windows-msvc /Z7 /O1 -c /Fa a.cpp -# __int64 __attribute__((optnone)) bar(__int64 x) { return x; }; -# __int64 foo(__int64 x) { -# return bar(x); -# } -# -# int main(int argc, char** argv) { -# foo(argc); -# return 0; -# } - -# FIXME: The following variable location have wrong register numbers due to -# https://github.com/llvm/llvm-project/issues/53575. Fix them after resolving -# the issue. - -# CHECK: (lldb) image lookup -a 0x40102f -v -# CHECK: LineEntry: [0x00401026-0x00401039): C:\src\a.cpp:3 -# CHECK-NEXT: Variable: id = {{.*}}, name = "x", type = "int64_t", valid ranges = [0x0040102f-0x00401036), location = DW_OP_reg0 EAX, DW_OP_piece 0x4, DW_OP_reg2 EDX, DW_OP_piece 0x4, decl = - - .text - .def @feat.00; - .scl 3; - .type 0; - .endef - .globl @feat.00 -.set @feat.00, 1 - .intel_syntax noprefix - .file "a.cpp" - .def "?bar@@YA_J_J@Z"; - .scl 2; - .type 32; - .endef - .section .text,"xr",one_only,"?bar@@YA_J_J@Z" - .globl "?bar@@YA_J_J@Z" # -- Begin function ?bar@@YA_J_J@Z - .p2align 4, 0x90 -"?bar@@YA_J_J@Z": # @"?bar@@YA_J_J@Z" -Lfunc_begin0: - .cv_func_id 0 - .cv_file 1 "C:\\src\\a.cpp" "CB99424BC3DD1AB059A2DBC6841147F2" 1 - .cv_loc 0 1 1 0 # a.cpp:1:0 - .cv_fpo_proc "?bar@@YA_J_J@Z" 8 -# %bb.0: # %entry - push ebp - .cv_fpo_pushreg ebp - mov ebp, esp - .cv_fpo_setframe ebp - and esp, -8 - .cv_fpo_stackalign 8 - sub esp, 8 - .cv_fpo_stackalloc 8 - .cv_fpo_endprologue - mov eax, dword ptr [ebp + 8] - mov ecx, dword ptr [ebp + 12] - mov dword ptr [esp], eax - mov dword ptr [esp + 4], ecx -Ltmp0: - mov eax, dword ptr [esp] - mov edx, dword ptr [esp + 4] - mov esp, ebp - pop ebp - ret -Ltmp1: - .cv_fpo_endproc -Lfunc_end0: - # -- End function - .def "?foo@@YA_J_J@Z"; - .scl 2; - .type 32; - .endef - .section .text,"xr",one_only,"?foo@@YA_J_J@Z" - .globl "?foo@@YA_J_J@Z" # -- Begin function ?foo@@YA_J_J@Z -"?foo@@YA_J_J@Z": # @"?foo@@YA_J_J@Z" -Lfunc_begin1: - .cv_func_id 1 - .cv_fpo_proc "?foo@@YA_J_J@Z" 8 -# %bb.0: # %entry - #DEBUG_VALUE: foo:x <- [DW_OP_plus_uconst 4] [$esp+0] - .cv_loc 1 1 3 0 # a.cpp:3:0 - jmp "?bar@@YA_J_J@Z" # TAILCALL -Ltmp2: - .cv_fpo_endproc -Lfunc_end1: - # -- End function - .def _main; - .scl 2; - .type 32; - .endef - .section .text,"xr",one_only,_main - .globl _main # -- Begin function main -_main: # @main -Lfunc_begin2: - .cv_func_id 2 - .cv_loc 2 1 6 0 # a.cpp:6:0 - .cv_fpo_proc _main 8 -# %bb.0: # %entry - #DEBUG_VALUE: main:argv <- [DW_OP_plus_uconst 8] [$esp+0] - #DEBUG_VALUE: main:argc <- [DW_OP_plus_uconst 4] [$esp+0] - .cv_inline_site_id 3 within 2 inlined_at 1 7 0 - .cv_loc 3 1 3 0 # a.cpp:3:0 - mov eax, dword ptr [esp + 4] - mov ecx, eax - sar ecx, 31 -Ltmp3: - #DEBUG_VALUE: foo:x <- [DW_OP_LLVM_fragment 0 32] $eax - #DEBUG_VALUE: foo:x <- [DW_OP_LLVM_fragment 32 32] $ecx - push ecx -Ltmp4: - push eax - call "?bar@@YA_J_J@Z" -Ltmp5: - add esp, 8 -Ltmp6: - .cv_loc 2 1 8 0 # a.cpp:8:0 - xor eax, eax - ret -Ltmp7: - .cv_fpo_endproc -Lfunc_end2: - # -- End function - .section .drectve,"yn" - .ascii " /DEFAULTLIB:libcmt.lib" - .ascii " /DEFAULTLIB:oldnames.lib" - .section .debug$S,"dr" - .p2align 2 - .long 4 # Debug section magic - .long 241 - .long Ltmp9-Ltmp8 # Subsection size -Ltmp8: - .short Ltmp11-Ltmp10 # Record length -Ltmp10: - .short 4353 # Record kind: S_OBJNAME - .long 0 # Signature - .asciz "C:\\src\\a.obj" # Object name - .p2align 2 -Ltmp11: - .short Ltmp13-Ltmp12 # Record length -Ltmp12: - .short 4412 # Record kind: S_COMPILE3 - .long 1 # Flags and language - .short 7 # CPUType - .short 15 # Frontend version - .short 0 - .short 0 - .short 0 - .short 15000 # Backend version - .short 0 - .short 0 - .short 0 - .asciz "clang version 15.0.0" # Null-terminated compiler version string - .p2align 2 -Ltmp13: -Ltmp9: - .p2align 2 - .long 246 # Inlinee lines subsection - .long Ltmp15-Ltmp14 # Subsection size -Ltmp14: - .long 0 # Inlinee lines signature - - # Inlined function foo starts at a.cpp:2 - .long 4098 # Type index of inlined function - .cv_filechecksumoffset 1 # Offset into filechecksum table - .long 2 # Starting line number -Ltmp15: - .p2align 2 - .section .debug$S,"dr",associative,"?bar@@YA_J_J@Z" - .p2align 2 - .long 4 # Debug section magic - .cv_fpo_data "?bar@@YA_J_J@Z" - .long 241 # Symbol subsection for bar - .long Ltmp17-Ltmp16 # Subsection size -Ltmp16: - .short Ltmp19-Ltmp18 # Record length -Ltmp18: - .short 4423 # Record kind: S_GPROC32_ID - .long 0 # PtrParent - .long 0 # PtrEnd - .long 0 # PtrNext - .long Lfunc_end0-"?bar@@YA_J_J@Z" # Code size - .long 0 # Offset after prologue - .long 0 # Offset before epilogue - .long 4099 # Function type index - .secrel32 "?bar@@YA_J_J@Z" # Function section relative address - .secidx "?bar@@YA_J_J@Z" # Function section index - .byte 0 # Flags - .asciz "bar" # Function name - .p2align 2 -Ltmp19: - .short Ltmp21-Ltmp20 # Record length -Ltmp20: - .short 4114 # Record kind: S_FRAMEPROC - .long 12 # FrameSize - .long 0 # Padding - .long 0 # Offset of padding - .long 0 # Bytes of callee saved registers - .long 0 # Exception handler offset - .short 0 # Exception handler section - .long 147456 # Flags (defines frame register) - .p2align 2 -Ltmp21: - .short Ltmp23-Ltmp22 # Record length -Ltmp22: - .short 4414 # Record kind: S_LOCAL - .long 19 # TypeIndex - .short 1 # Flags - .asciz "x" - .p2align 2 -Ltmp23: - .cv_def_range Ltmp0 Ltmp1, reg_rel, 30006, 0, -8 - .short 2 # Record length - .short 4431 # Record kind: S_PROC_ID_END -Ltmp17: - .p2align 2 - .cv_linetable 0, "?bar@@YA_J_J@Z", Lfunc_end0 - .section .debug$S,"dr",associative,"?foo@@YA_J_J@Z" - .p2align 2 - .long 4 # Debug section magic - .cv_fpo_data "?foo@@YA_J_J@Z" - .long 241 # Symbol subsection for foo - .long Ltmp25-Ltmp24 # Subsection size -Ltmp24: - .short Ltmp27-Ltmp26 # Record length -Ltmp26: - .short 4423 # Record kind: S_GPROC32_ID - .long 0 # PtrParent - .long 0 # PtrEnd - .long 0 # PtrNext - .long Lfunc_end1-"?foo@@YA_J_J@Z" # Code size - .long 0 # Offset after prologue - .long 0 # Offset before epilogue - .long 4098 # Function type index - .secrel32 "?foo@@YA_J_J@Z" # Function section relative address - .secidx "?foo@@YA_J_J@Z" # Function section index - .byte 0 # Flags - .asciz "foo" # Function name - .p2align 2 -Ltmp27: - .short Ltmp29-Ltmp28 # Record length -Ltmp28: - .short 4114 # Record kind: S_FRAMEPROC - .long 0 # FrameSize - .long 0 # Padding - .long 0 # Offset of padding - .long 0 # Bytes of callee saved registers - .long 0 # Exception handler offset - .short 0 # Exception handler section - .long 0 # Flags (defines frame register) - .p2align 2 -Ltmp29: - .short Ltmp31-Ltmp30 # Record length -Ltmp30: - .short 4414 # Record kind: S_LOCAL - .long 19 # TypeIndex - .short 1 # Flags - .asciz "x" - .p2align 2 -Ltmp31: - .cv_def_range Lfunc_begin1 Lfunc_end1, reg_rel, 30006, 0, 4 - .short 2 # Record length - .short 4431 # Record kind: S_PROC_ID_END -Ltmp25: - .p2align 2 - .cv_linetable 1, "?foo@@YA_J_J@Z", Lfunc_end1 - .section .debug$S,"dr",associative,_main - .p2align 2 - .long 4 # Debug section magic - .cv_fpo_data _main - .long 241 # Symbol subsection for main - .long Ltmp33-Ltmp32 # Subsection size -Ltmp32: - .short Ltmp35-Ltmp34 # Record length -Ltmp34: - .short 4423 # Record kind: S_GPROC32_ID - .long 0 # PtrParent - .long 0 # PtrEnd - .long 0 # PtrNext - .long Lfunc_end2-_main # Code size - .long 0 # Offset after prologue - .long 0 # Offset before epilogue - .long 4103 # Function type index - .secrel32 _main # Function section relative address - .secidx _main # Function section index - .byte 0 # Flags - .asciz "main" # Function name - .p2align 2 -Ltmp35: - .short Ltmp37-Ltmp36 # Record length -Ltmp36: - .short 4114 # Record kind: S_FRAMEPROC - .long 0 # FrameSize - .long 0 # Padding - .long 0 # Offset of padding - .long 0 # Bytes of callee saved registers - .long 0 # Exception handler offset - .short 0 # Exception handler section - .long 0 # Flags (defines frame register) - .p2align 2 -Ltmp37: - .short Ltmp39-Ltmp38 # Record length -Ltmp38: - .short 4414 # Record kind: S_LOCAL - .long 116 # TypeIndex - .short 1 # Flags - .asciz "argc" - .p2align 2 -Ltmp39: - .cv_def_range Lfunc_begin2 Ltmp4, reg_rel, 30006, 0, 4 - .short Ltmp41-Ltmp40 # Record length -Ltmp40: - .short 4414 # Record kind: S_LOCAL - .long 4100 # TypeIndex - .short 1 # Flags - .asciz "argv" - .p2align 2 -Ltmp41: - .cv_def_range Lfunc_begin2 Ltmp4, reg_rel, 30006, 0, 8 - .short Ltmp43-Ltmp42 # Record length -Ltmp42: - .short 4429 # Record kind: S_INLINESITE - .long 0 # PtrParent - .long 0 # PtrEnd - .long 4098 # Inlinee type index - .cv_inline_linetable 3 1 2 Lfunc_begin2 Lfunc_end2 - .p2align 2 -Ltmp43: - .short Ltmp45-Ltmp44 # Record length -Ltmp44: - .short 4414 # Record kind: S_LOCAL - .long 19 # TypeIndex - .short 1 # Flags - .asciz "x" - .p2align 2 -Ltmp45: - .cv_def_range Ltmp3 Ltmp5, subfield_reg, 17, 0 - .cv_def_range Ltmp3 Ltmp5, subfield_reg, 18, 4 - .short 2 # Record length - .short 4430 # Record kind: S_INLINESITE_END - .short 2 # Record length - .short 4431 # Record kind: S_PROC_ID_END -Ltmp33: - .p2align 2 - .cv_linetable 2, _main, Lfunc_end2 - .section .debug$S,"dr" - .cv_filechecksums # File index to string table offset subsection - .cv_stringtable # String table - .long 241 - .long Ltmp47-Ltmp46 # Subsection size -Ltmp46: - .short Ltmp49-Ltmp48 # Record length -Ltmp48: - .short 4428 # Record kind: S_BUILDINFO - .long 4109 # LF_BUILDINFO index - .p2align 2 -Ltmp49: -Ltmp47: - .p2align 2 - .section .debug$T,"dr" - .p2align 2 - .long 4 # Debug section magic - # ArgList (0x1000) - .short 0xa # Record length - .short 0x1201 # Record kind: LF_ARGLIST - .long 0x1 # NumArgs - .long 0x13 # Argument: __int64 - # Procedure (0x1001) - .short 0xe # Record length - .short 0x1008 # Record kind: LF_PROCEDURE - .long 0x13 # ReturnType: __int64 - .byte 0x0 # CallingConvention: NearC - .byte 0x0 # FunctionOptions - .short 0x1 # NumParameters - .long 0x1000 # ArgListType: (__int64) - # FuncId (0x1002) - .short 0xe # Record length - .short 0x1601 # Record kind: LF_FUNC_ID - .long 0x0 # ParentScope - .long 0x1001 # FunctionType: __int64 (__int64) - .asciz "foo" # Name - # FuncId (0x1003) - .short 0xe # Record length - .short 0x1601 # Record kind: LF_FUNC_ID - .long 0x0 # ParentScope - .long 0x1001 # FunctionType: __int64 (__int64) - .asciz "bar" # Name - # Pointer (0x1004) - .short 0xa # Record length - .short 0x1002 # Record kind: LF_POINTER - .long 0x470 # PointeeType: char* - .long 0x800a # Attrs: [ Type: Near32, Mode: Pointer, SizeOf: 4 ] - # ArgList (0x1005) - .short 0xe # Record length - .short 0x1201 # Record kind: LF_ARGLIST - .long 0x2 # NumArgs - .long 0x74 # Argument: int - .long 0x1004 # Argument: char** - # Procedure (0x1006) - .short 0xe # Record length - .short 0x1008 # Record kind: LF_PROCEDURE - .long 0x74 # ReturnType: int - .byte 0x0 # CallingConvention: NearC - .byte 0x0 # FunctionOptions - .short 0x2 # NumParameters - .long 0x1005 # ArgListType: (int, char**) - # FuncId (0x1007) - .short 0x12 # Record length - .short 0x1601 # Record kind: LF_FUNC_ID - .long 0x0 # ParentScope - .long 0x1006 # FunctionType: int (int, char**) - .asciz "main" # Name - .byte 243 - .byte 242 - .byte 241 - # StringId (0x1008) - .short 0xe # Record length - .short 0x1605 # Record kind: LF_STRING_ID - .long 0x0 # Id - .asciz "C:\\src" # StringData - .byte 241 - # StringId (0x1009) - .short 0xe # Record length - .short 0x1605 # Record kind: LF_STRING_ID - .long 0x0 # Id - .asciz "a.cpp" # StringData - .byte 242 - .byte 241 Index: lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s +++ lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.s @@ -34,39 +34,38 @@ # CHECK: (lldb) image lookup -a 0x140001000 -v # CHECK: LineEntry: [0x0000000140001000-0x0000000140001003): C:\src\test\a.cpp:10 -# CHECK-NEXT: Variable: id = {{.*}}, name = "p1", type = "int", valid ranges = [0x0000000140001000-0x0000000140001003), location = DW_OP_reg26 XMM9 -# CHECK-NEXT: Variable: id = {{.*}}, name = "p2", type = "char", valid ranges = [0x0000000140001000-0x0000000140001006), location = DW_OP_regx 0x3f +# CHECK-NEXT: Variable: id = {{.*}}, name = "p1", type = "int", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001003) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "p2", type = "char", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001006) -> DW_OP_regx 0x3f # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x140001003 -v # CHECK: LineEntry: [0x0000000140001003-0x0000000140001006): C:\src\test\a.cpp:11 -# CHECK-NEXT: Variable: id = {{.*}}, name = "p2", type = "char", valid ranges = [0x0000000140001000-0x0000000140001006), location = DW_OP_regx 0x3f +# CHECK-NEXT: Variable: id = {{.*}}, name = "p2", type = "char", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001006) -> DW_OP_regx 0x3f +# CHECK-NEXT: Variable: id = {{.*}}, name = "s", type = "S", valid ranges = <block>, location = [0x0000000140001003, 0x0000000140001006) -> DW_OP_piece 0x4, DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x3 # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x140001006 -v # CHECK: LineEntry: [0x0000000140001006-0x0000000140001011): C:\src\test\a.cpp:12 -# CHECK-NEXT: Variable: id = {{.*}}, name = "s", type = "S", valid ranges = [0x0000000140001006-0x0000000140001011), location = DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_regx 0x3f, DW_OP_piece 0x1 +# CHECK-NEXT: Variable: id = {{.*}}, name = "s", type = "S", valid ranges = <block>, location = [0x0000000140001006, 0x0000000140001011) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x3 # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x140001011 -v # CHECK: LineEntry: [0x0000000140001011-0x0000000140001015): C:\src\test\a.cpp:15 -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001011-0x0000000140001017), location = DW_OP_reg26 XMM9 -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001011-0x0000000140001019), location = DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001011, 0x0000000140001017) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001011, 0x0000000140001019) -> DW_OP_reg3 RBX # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x140001017 -v # CHECK: LineEntry: [0x0000000140001017-0x000000014000101e): C:\src\test\a.cpp:17 -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001011-0x0000000140001019), location = DW_OP_reg3 RBX -# CHECK-NEXT: Variable: id = {{.*}}, name = "local", type = "int", valid ranges = [0x0000000140001017-0x000000014000101e), location = DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001011, 0x0000000140001019) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "local", type = "int", valid ranges = <block>, location = [0x0000000140001017, 0x000000014000101e) -> DW_OP_reg26 XMM9 # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x140001019 -v # CHECK: LineEntry: [0x0000000140001017-0x000000014000101e): C:\src\test\a.cpp:17 -# CHECK-NEXT: Variable: id = {{.*}}, name = "local", type = "int", valid ranges = [0x0000000140001017-0x000000014000101e), location = DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "local", type = "int", valid ranges = <block>, location = [0x0000000140001017, 0x000000014000101e) -> DW_OP_reg26 XMM9 # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x14000101e -v # CHECK: LineEntry: [0x000000014000101e-0x0000000140001031): C:\src\test\a.cpp:18 -# CHECK-NEXT: Variable: id = {{.*}}, name = "s", type = "S", valid ranges = [0x000000014000101e-0x000000014000102c), location = DW_OP_reg24 XMM7, DW_OP_piece 0x4, DW_OP_piece 0x1 +# CHECK-NEXT: Variable: id = {{.*}}, name = "s", type = "S", valid ranges = <block>, location = [0x000000014000101e, 0x000000014000102c) -> DW_OP_reg24 XMM7, DW_OP_piece 0x4, DW_OP_piece 0x4 # CHECK-EMPTY: # CHECK: (lldb) image lookup -a 0x14000102c -v # CHECK: LineEntry: [0x000000014000101e-0x0000000140001031): C:\src\test\a.cpp:18 -# CHECK-EMPTY: - .text .def @feat.00; @@ -153,6 +152,72 @@ .Ltmp7: add rsp, 40 ret +# Manually created for testing purpose. +.L31: + .cv_loc 1 1 1000 0 # a.cpp:1000:0 + ret +.L32: + ret +.L33: + ret +.L34: + .cv_loc 1 1 1001 0 # a.cpp:1001:0 + ret +.L35: + ret +.L36: + ret +.L37: + ret +.L38: + ret +.L39: + ret +.L3a: + ret +.L3b: + .cv_loc 1 1 1002 0 # a.cpp:1002:0 + ret +.L3c: + ret +.L3d: + ret +.L3e: + ret +.L3f: + ret +.L40: + ret +.L41: + ret +.L42: + ret +.L43: + ret +.L44: + ret +.L45: + .cv_loc 1 1 1003 0 # a.cpp:1003:0 + ret +.L46: + ret +.L47: + ret +.L48: + ret +.L49: + ret +.L4a: + ret +.L4b: + ret +.L4c: + ret +.L4d: + ret +.L4e: + ret +.Lend: .Ltmp8: .Lfunc_end1: .seh_endproc @@ -322,8 +387,152 @@ .p2align 2 .Ltmp38: .cv_def_range .Ltmp6 .Ltmp7, subfield_reg, 17, 0 - .short 2 # Record length - .short 4431 # Record kind: S_PROC_ID_END + .short .Ltmp101-.Ltmp100 +# Manually created debug info for testing purpose. +# 1. Test non-overlapped ranges. +.Ltmp100: + .short 4414 # Record kind: S_LOCAL + .long 4109 # TypeIndex + .short 0 # Flags + .asciz "non_overlapped_ranges" + .p2align 2 +.Ltmp101: + .cv_def_range .L31 .L32, reg, 331 + .cv_def_range .L32 .L33, reg, 330 + .cv_def_range .L33 .L34, reg, 336 + .short .Ltmp103-.Ltmp102 +# CHECK: (lldb) image lookup -a 0x140001031 -v +# CHECK: LineEntry: [0x0000000140001031-0x0000000140001034): C:\src\test\a.cpp:1000 +# CHECK-NEXT: Variable: id = {{.*}}, name = "non_overlapped_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001031, 0x0000000140001032) -> DW_OP_reg3 RBX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001032 -v +# CHECK: LineEntry: [0x0000000140001031-0x0000000140001034): C:\src\test\a.cpp:1000 +# CHECK-NEXT: Variable: id = {{.*}}, name = "non_overlapped_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001032, 0x0000000140001033) -> DW_OP_reg2 RCX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001033 -v +# CHECK: LineEntry: [0x0000000140001031-0x0000000140001034): C:\src\test\a.cpp:1000 +# CHECK-NEXT: Variable: id = {{.*}}, name = "non_overlapped_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001033, 0x0000000140001034) -> DW_OP_reg8 R8 +# CHECK-EMPTY: + +# 2. Test overlapped subfield/reg_rel ranges at different offsets. +.Ltmp102: + .short 4414 # Record kind: S_LOCAL + .long 4109 # TypeIndex + .short 0 # Flags + .asciz "overlapped_subfield_ranges" + .p2align 2 +.Ltmp103: + .cv_def_range .L34 .L36, subfield_reg, 3, 0 + .cv_def_range .L35 .L37, subfield_reg, 17, 4 + .cv_def_range .L37 .L39, reg_rel, 1, 1, 4 + .short .Ltmp105-.Ltmp104 +# CHECK: (lldb) image lookup -a 0x140001034 -v +# CHECK: LineEntry: [0x0000000140001034-0x000000014000103b): C:\src\test\a.cpp:1001 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_subfield_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001034, 0x0000000140001035) -> DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x7 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001035 -v +# CHECK: LineEntry: [0x0000000140001034-0x000000014000103b): C:\src\test\a.cpp:1001 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_subfield_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001035, 0x0000000140001036) -> DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x3, DW_OP_reg24 XMM7, DW_OP_piece 0x4 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001036 -v +# CHECK: LineEntry: [0x0000000140001034-0x000000014000103b): C:\src\test\a.cpp:1001 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_subfield_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001036, 0x0000000140001037) -> DW_OP_piece 0x4, DW_OP_reg24 XMM7, DW_OP_piece 0x4 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001037 -v +# CHECK: LineEntry: [0x0000000140001034-0x000000014000103b): C:\src\test\a.cpp:1001 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_subfield_ranges", type = "S1", valid ranges = <block>, location = [0x0000000140001037, 0x0000000140001039) -> DW_OP_bregx 0x3c +4, DW_OP_piece 0x1, DW_OP_piece 0x7 +# CHECK-EMPTY: + +# 3. Test overlapped ranges for the whole value. +.Ltmp104: + .short 4414 # Record kind: S_LOCAL + .long 4109 # TypeIndex + .short 0 # Flags + .asciz "overlapped_ranges_2" + .p2align 2 +.Ltmp105: + .cv_def_range .L3b .L3d, reg, 331 + .cv_def_range .L3c .L3e, reg, 330 + .cv_def_range .L3f .L44, reg, 339 + .cv_def_range .L41 .L43, reg, 328 + .short .Ltmp107-.Ltmp106 +# CHECK: (lldb) image lookup -a 0x14000103b -v +# CHECK: LineEntry: [0x000000014000103b-0x0000000140001045): C:\src\test\a.cpp:1002 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_2", type = "S1", valid ranges = <block>, location = [0x000000014000103b, 0x000000014000103c) -> DW_OP_reg3 RBX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x14000103d -v +# CHECK: LineEntry: [0x000000014000103b-0x0000000140001045): C:\src\test\a.cpp:1002 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_2", type = "S1", valid ranges = <block>, location = [0x000000014000103c, 0x000000014000103e) -> DW_OP_reg2 RCX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x14000103f -v +# CHECK: LineEntry: [0x000000014000103b-0x0000000140001045): C:\src\test\a.cpp:1002 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_2", type = "S1", valid ranges = <block>, location = [0x000000014000103f, 0x0000000140001041) -> DW_OP_reg11 R11 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001041 -v +# CHECK: LineEntry: [0x000000014000103b-0x0000000140001045): C:\src\test\a.cpp:1002 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_2", type = "S1", valid ranges = <block>, location = [0x0000000140001041, 0x0000000140001043) -> DW_OP_reg0 RAX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001043 -v +# CHECK: LineEntry: [0x000000014000103b-0x0000000140001045): C:\src\test\a.cpp:1002 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_2", type = "S1", valid ranges = <block>, location = [0x0000000140001043, 0x0000000140001044) -> DW_OP_reg11 R11 +# CHECK-EMPTY: + +# 4. Test overlapped ranges for both subfield and whole value. +.Ltmp106: + .short 4414 # Record kind: S_LOCAL + .long 4109 # TypeIndex + .short 0 # Flags + .asciz "overlapped_ranges_3" + .p2align 2 +.Ltmp107: + # The following two lines result: + # [.L45, .L46) -> value at offset 0 is at reg 3. + # [.L46, .L49) -> value at offset 0 is at reg 3 and value at offset 4 is at reg 17. + # [.L49, .L4a) -> value at offset 4 is at reg 17. + .cv_def_range .L46 .L4a, subfield_reg, 17, 4 + .cv_def_range .L45 .L49, subfield_reg, 3, 0 + # The following overwrites range [.L47, .L48) and [.L49 .L4a) because whole + # value location is preferred over composited value locations. + .cv_def_range .L47 .L48, reg, 331 + .cv_def_range .L49 .L4a, reg, 328 + # For the same reason, reg 330 wins in following example. + .cv_def_range .L4b .L4e, reg, 330 + .cv_def_range .L4b .L4d, subfield_reg, 17, 4 + .cv_def_range .L4c .L4e, subfield_reg, 3, 0 + .short 2 + .short 4431 # Record kind: S_PROC_ID_END +# CHECK: (lldb) image lookup -a 0x140001045 -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x0000000140001045, 0x0000000140001046) -> DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x7 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001046 -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x0000000140001046, 0x0000000140001047) -> DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x3, DW_OP_reg24 XMM7, DW_OP_piece 0x4 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001047 -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x0000000140001047, 0x0000000140001048) -> DW_OP_reg3 RBX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001048 -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x0000000140001048, 0x0000000140001049) -> DW_OP_regx 0x3f, DW_OP_piece 0x1, DW_OP_piece 0x3, DW_OP_reg24 XMM7, DW_OP_piece 0x4 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x140001049 -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x0000000140001049, 0x000000014000104a) -> DW_OP_reg0 RAX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x14000104a -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x14000104b -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x000000014000104b, 0x000000014000104e) -> DW_OP_reg2 RCX +# CHECK-EMPTY: +# CHECK: (lldb) image lookup -a 0x14000104c -v +# CHECK: LineEntry: [0x0000000140001045-0x000000014000104f): C:\src\test\a.cpp:1003 +# CHECK-NEXT: Variable: id = {{.*}}, name = "overlapped_ranges_3", type = "S1", valid ranges = <block>, location = [0x000000014000104b, 0x000000014000104e) -> DW_OP_reg2 RCX +# CHECK-EMPTY: + .Ltmp26: .p2align 2 .cv_linetable 1, main, .Lfunc_end1 @@ -452,25 +661,38 @@ .byte 243 .byte 242 .byte 241 - # StringId (0x100C) - .short 0x12 # Record length - .short 0x1605 # Record kind: LF_STRING_ID - .long 0x0 # Id - .asciz "C:\\src\\test" # StringData - # StringId (0x100D) - .short 0xe # Record length - .short 0x1605 # Record kind: LF_STRING_ID - .long 0x0 # Id - .asciz "a.cpp" # StringData - .byte 242 - .byte 241 + # Manually created debug info for testing purpose, FieldList (0x100C) and Struct (0x100D) + # FieldList (0x100C) + .short 0x1a # Record length + .short 0x1203 # Record kind: LF_FIELDLIST + .short 0x150d # Member kind: DataMember ( LF_MEMBER ) + .short 0x3 # Attrs: Public + .long 0x70 # Type: char + .short 0x0 # FieldOffset + .asciz "c" # Name + .short 0x150d # Member kind: DataMember ( LF_MEMBER ) + .short 0x3 # Attrs: Public + .long 0x74 # Type: int + .short 0x4 # FieldOffset + .asciz "i" # Name + # Struct (0x100D) + .short 0x20 # Record length + .short 0x1505 # Record kind: LF_STRUCTURE + .short 0x2 # MemberCount + .short 0x200 # Properties ( HasUniqueName (0x200) ) + .long 0x100c # FieldList: <field list> + .long 0x0 # DerivedFrom + .long 0x0 # VShape + .short 0x8 # SizeOf + .asciz "S1" # Name + .asciz ".?AUS1@@" # LinkageName # BuildInfo (0x100E) .short 0x1a # Record length .short 0x1603 # Record kind: LF_BUILDINFO - .short 0x5 # NumArgs - .long 0x100c # Argument: C:\src\test + .short 0x1 # NumArgs + .long 0x0 # Argument + .long 0x0 # Argument .long 0x0 # Argument - .long 0x100d # Argument: a.cpp .long 0x0 # Argument .long 0x0 # Argument .byte 242 Index: lldb/test/Shell/SymbolFile/NativePDB/inline_sites.test =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/inline_sites.test +++ lldb/test/Shell/SymbolFile/NativePDB/inline_sites.test @@ -52,13 +52,17 @@ #CHECK: (lldb) b a.cpp:4 #CHECK: Breakpoint 13: where = {{.*}}`main + 61 at a.cpp:4, address = 0x000000014000103d +# FIXME: The following variable location have wrong register numbers due to +# https://github.com/llvm/llvm-project/issues/53575. Fix them after resolving +# the issue. + # CEHCK-LABEL: (lldb) image lookup -a 0x140001003 -v # CHECK: Summary: {{.*}}`main + 3 at a.cpp:2 # CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x0000000140001046) # CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x140001046) # CHECK: LineEntry: [0x0000000140001000-0x0000000140001004): /tmp/a.cpp:2 -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001000-0x000000014000102d) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001000, 0x000000014000102d) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX # CEHCK-LABEL: (lldb) image lookup -a 0x140001004 -v # CHECK: Summary: {{.*}}`main + 4 [inlined] Namespace1::foo at a.h:5 @@ -67,10 +71,10 @@ # CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x140001046) # CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001039)[0x14000103f-0x140001046), name = "Namespace1::foo", decl = a.h:4 # CHECK: LineEntry: [0x0000000140001004-0x000000014000100c): /tmp/a.h:5 -# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001000-0x000000014000102d) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001046) +# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001039) -> DW_OP_breg7 RSP+44 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001000, 0x000000014000102d) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001046) -> DW_OP_breg7 RSP+48 # CEHCK-LABEL: (lldb) image lookup -a 0x140001010 -v # CHECK: Summary: {{.*}}`main + 16 [inlined] Namespace1::foo + 12 at a.h:7 @@ -79,10 +83,10 @@ # CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x140001046) # CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001039)[0x14000103f-0x140001046), name = "Namespace1::foo", decl = a.h:4 # CHECK: LineEntry: [0x0000000140001010-0x0000000140001018): /tmp/a.h:7 -# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001000-0x000000014000102d) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001046) +# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001039) -> DW_OP_breg7 RSP+44 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001000, 0x000000014000102d) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001046) -> DW_OP_breg7 RSP+48 # CEHCK-LABEL: (lldb) image lookup -a 0x14000101c -v # CHECK: Summary: {{.*}}`main + 28 [inlined] Class1::bar at b.h:5 @@ -93,12 +97,12 @@ # CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001039)[0x14000103f-0x140001046), name = "Namespace1::foo", decl = a.h:4 # CHECK-NEXT: id = {{.*}}, range = [0x14000101c-0x140001039), name = "Class1::bar", decl = b.h:4 # CHECK: LineEntry: [0x000000014000101c-0x0000000140001022): /tmp/b.h:5 -# CHECK-NEXT: Variable: id = {{.*}}, name = "x", type = "int", valid ranges = [0x000000014000101c-0x000000014000101e) -# CHECK-NEXT: Variable: id = {{.*}}, name = "bar_local", type = "int", valid ranges = [0x000000014000101c-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001000-0x000000014000102d) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001046) +# CHECK-NEXT: Variable: id = {{.*}}, name = "x", type = "int", valid ranges = <block>, location = [0x000000014000101c, 0x000000014000101e) -> DW_OP_reg24 XMM7 +# CHECK-NEXT: Variable: id = {{.*}}, name = "bar_local", type = "int", valid ranges = <block>, location = [0x000000014000101c, 0x0000000140001039) -> DW_OP_breg7 RSP+52 +# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001039) -> DW_OP_breg7 RSP+44 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001000, 0x000000014000102d) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001046) -> DW_OP_breg7 RSP+48 # CEHCK-LABEL: (lldb) image lookup -a 0x14000102a -v # CHECK: Summary: {{.*}}`main + 42 [inlined] Namespace2::Class2::func at c.h:5 @@ -111,21 +115,21 @@ # CHECK-NEXT: id = {{.*}}, range = [0x14000101c-0x140001039), name = "Class1::bar", decl = b.h:4 # CHECK-NEXT: id = {{.*}}, range = [0x14000102a-0x140001039), name = "Namespace2::Class2::func", decl = c.h:4 # CHECK: LineEntry: [0x000000014000102a-0x0000000140001031): /tmp/c.h:5 -# CHECK-NEXT: Variable: id = {{.*}}, name = "x", type = "int", valid ranges = [0x000000014000102a-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "func_local", type = "int", valid ranges = [0x000000014000102a-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "bar_local", type = "int", valid ranges = [0x000000014000101c-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001039) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001000-0x000000014000102d) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001046) +# CHECK-NEXT: Variable: id = {{.*}}, name = "x", type = "int", valid ranges = <block>, location = [0x000000014000102a, 0x0000000140001039) -> DW_OP_reg24 XMM7 +# CHECK-NEXT: Variable: id = {{.*}}, name = "func_local", type = "int", valid ranges = <block>, location = [0x000000014000102a, 0x0000000140001039) -> DW_OP_breg7 RSP+48 +# CHECK-NEXT: Variable: id = {{.*}}, name = "bar_local", type = "int", valid ranges = <block>, location = [0x000000014000101c, 0x0000000140001039) -> DW_OP_breg7 RSP+52 +# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001039) -> DW_OP_breg7 RSP+44 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001000, 0x000000014000102d) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001046) -> DW_OP_breg7 RSP+48 # CEHCK-LABEL: (lldb) image lookup -a 0x140001039 -v # CHECK: Summary: {{.*}}`main + 57 at a.cpp:3 # CHECK: Function: id = {{.*}}, name = "main", range = [0x0000000140001000-0x0000000140001046) # CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x140001046) # CHECK: LineEntry: [0x0000000140001039-0x000000014000103d): /tmp/a.cpp:3 -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001046) +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001046) -> DW_OP_breg7 RSP+48 # CEHCK-LABEL: (lldb) image lookup -a 0x140001044 -v # CHECK: Summary: {{.*}}`main + 68 [inlined] Namespace1::foo + 5 at a.h:8 @@ -134,10 +138,10 @@ # CHECK: Blocks: id = {{.*}}, range = [0x140001000-0x140001046) # CHECK-NEXT: id = {{.*}}, ranges = [0x140001004-0x140001039)[0x14000103f-0x140001046), name = "Namespace1::foo", decl = a.h:4 # CHECK: LineEntry: [0x0000000140001044-0x0000000140001046): /tmp/a.h:8 -# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = [0x0000000140001044-0x0000000140001046) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = [0x0000000140001044-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = [0x0000000140001000-0x0000000140001045) -# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = [0x0000000140001004-0x0000000140001046) +# CHECK-NEXT: Variable: id = {{.*}}, name = "foo_local", type = "int", valid ranges = <block>, location = [0x0000000140001044, 0x0000000140001046) -> DW_OP_breg7 RSP+44 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argc", type = "int", valid ranges = <block>, location = [0x0000000140001044, 0x0000000140001045) -> DW_OP_reg26 XMM9 +# CHECK-NEXT: Variable: id = {{.*}}, name = "argv", type = "char **", valid ranges = <block>, location = [0x0000000140001000, 0x0000000140001045) -> DW_OP_reg3 RBX +# CHECK-NEXT: Variable: id = {{.*}}, name = "main_local", type = "int", valid ranges = <block>, location = [0x0000000140001004, 0x0000000140001046) -> DW_OP_breg7 RSP+48 # CHECK-LABEL: (lldb) target modules dump ast # CHECK-NEXT: Dumping clang ast for 1 modules. Index: lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables-registers.lldbinit =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables-registers.lldbinit +++ lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables-registers.lldbinit @@ -8,4 +8,24 @@ image lookup -a 0x14000101e -v image lookup -a 0x14000102c -v +image lookup -a 0x140001031 -v +image lookup -a 0x140001032 -v +image lookup -a 0x140001033 -v +image lookup -a 0x140001034 -v +image lookup -a 0x140001035 -v +image lookup -a 0x140001036 -v +image lookup -a 0x140001037 -v +image lookup -a 0x14000103b -v +image lookup -a 0x14000103d -v +image lookup -a 0x14000103f -v +image lookup -a 0x140001041 -v +image lookup -a 0x140001043 -v +image lookup -a 0x140001045 -v +image lookup -a 0x140001046 -v +image lookup -a 0x140001047 -v +image lookup -a 0x140001048 -v +image lookup -a 0x140001049 -v +image lookup -a 0x14000104a -v +image lookup -a 0x14000104b -v +image lookup -a 0x14000104c -v exit Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -1702,9 +1702,13 @@ func_block->GetStartAddress(addr); VariableInfo var_info = GetVariableLocationInfo(*m_index, var_id, *func_block, module); - if (!var_info.location || !var_info.ranges) + if (!var_info.location || var_info.location->GetSize() == 0) return nullptr; - + Function *func = func_block->CalculateSymbolContextFunction(); + if (!func) + return VariableSP(); + var_info.location->SetFuncFileAddress( + func->GetAddressRange().GetBaseAddress().GetFileAddress()); CompilandIndexItem *cii = m_index->compilands().GetCompiland(var_id.modi); CompUnitSP comp_unit_sp = GetOrCreateCompileUnit(*cii); TypeSP type_sp = GetOrCreateType(var_info.type); @@ -1720,11 +1724,10 @@ bool artificial = false; bool location_is_constant_data = false; bool static_member = false; - DWARFExpressionList locaiton_list = DWARFExpressionList( - module, *var_info.location, nullptr); + Variable::RangeList scope_ranges; VariableSP var_sp = std::make_shared<Variable>( toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, - &block, *var_info.ranges, &decl, locaiton_list, external, artificial, + &block, scope_ranges, &decl, *var_info.location, external, artificial, location_is_constant_data, static_member); if (!is_param) m_ast->GetOrCreateVariableDecl(scope_id, var_id); Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -103,8 +103,7 @@ struct VariableInfo { llvm::StringRef name; llvm::codeview::TypeIndex type; - llvm::Optional<DWARFExpression> location; - llvm::Optional<Variable::RangeList> ranges; + llvm::Optional<DWARFExpressionList> location; bool is_param; }; Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -29,6 +29,8 @@ using namespace llvm::codeview; using namespace llvm::pdb; +// The returned range list is guaranteed to be sorted and no overlaps between +// adjacent ranges because fields in LocalVariableAddrGap are unsigned integers. static Variable::RangeList MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range, llvm::ArrayRef<LocalVariableAddrGap> gaps) { @@ -53,20 +55,216 @@ namespace { struct FindMembersSize : public TypeVisitorCallbacks { - FindMembersSize( - std::map<uint64_t, std::pair<RegisterId, uint32_t>> &members_info, - TpiStream &tpi) - : members_info(members_info), tpi(tpi) {} - std::map<uint64_t, std::pair<RegisterId, uint32_t>> &members_info; + FindMembersSize(uint64_t base_offset, + std::map<uint64_t, size_t> &offset_to_size, TpiStream &tpi) + : base_offset(base_offset), offset_to_size(offset_to_size), tpi(tpi) {} + uint64_t base_offset; + std::map<uint64_t, size_t> &offset_to_size; TpiStream &tpi; + + static bool GetMemberSizesForUdt(TypeIndex index, llvm::pdb::TpiStream &tpi, + uint64_t base_offset, + std::map<uint64_t, size_t> &offset_to_size) { + if (index.isSimple()) + return true; + if (IsForwardRefUdt(index, tpi)) { + auto expected_full_ti = tpi.findFullDeclForForwardRef(index); + if (!expected_full_ti) { + llvm::consumeError(expected_full_ti.takeError()); + return false; + } + index = *expected_full_ti; + } + CVType cvt = tpi.getType(index); + switch (cvt.kind()) { + case LF_MODIFIER: + return GetMemberSizesForUdt({LookThroughModifierRecord(cvt)}, tpi, + base_offset, offset_to_size); + case LF_ENUM: + case LF_CLASS: + case LF_STRUCTURE: + case LF_INTERFACE: + case LF_UNION: { + TagRecord tag_record = CVTagRecord::create(cvt).asTag(); + CVType field_list_cvt = tpi.getType(tag_record.FieldList); + FieldListRecord field_list; + if (llvm::Error error = TypeDeserializer::deserializeAs<FieldListRecord>( + field_list_cvt, field_list)) { + llvm::consumeError(std::move(error)); + return false; + } + FindMembersSize find_members_size(base_offset, offset_to_size, tpi); + if (llvm::Error err = + visitMemberRecordStream(field_list.Data, find_members_size)) { + llvm::consumeError(std::move(err)); + return false; + } + return true; + } + default: + return true; + } + } + llvm::Error visitKnownMember(CVMemberRecord &cvr, DataMemberRecord &member) override { - members_info.insert( - {member.getFieldOffset(), - {llvm::codeview::RegisterId::NONE, GetSizeOfType(member.Type, tpi)}}); + uint64_t offset = base_offset + member.getFieldOffset(); + size_t size = GetSizeOfType(member.Type, tpi); + // In the case of union, use the largest size. + if (offset_to_size[offset] < size) + offset_to_size[offset] = size; + return llvm::Error::success(); + } + llvm::Error visitKnownMember(CVMemberRecord &cvr, + BaseClassRecord &base) override { + GetMemberSizesForUdt(base.getBaseType(), tpi, base.getBaseOffset(), + offset_to_size); + return llvm::Error::success(); + } + llvm::Error visitKnownMember(CVMemberRecord &cvr, + VirtualBaseClassRecord &base) override { + GetMemberSizesForUdt(base.getBaseType(), tpi, base.getVBPtrOffset(), + offset_to_size); return llvm::Error::success(); } }; + +struct MemberLocations { + std::map<uint64_t, MemberValLocation> offset_to_location; + DWARFExpression expr; + bool is_dwarf = false; + + MemberLocations() = default; + MemberLocations(const DWARFExpression &expr) : expr(expr), is_dwarf(true) {} + MemberLocations(uint64_t offset, const MemberValLocation &member_loc) { + insert(offset, member_loc); + } + + void insert(uint64_t offset, const MemberValLocation &member_loc) { + offset_to_location[offset] = member_loc; + } + + struct Comparator { + public: + bool operator()(const MemberLocations &, const MemberLocations &) const { + return false; + } + }; +}; + +// A range map with address ranges to a map of pair of offset and locaitons. +typedef RangeDataVector<lldb::addr_t, lldb::addr_t, MemberLocations, 0, + MemberLocations::Comparator> + RangeMap; + +void AddMemberLocationRanges(RangeMap &location_map, uint64_t offset, + MemberValLocation member_loc, + const Variable::RangeList &ranges) { + RangeMap new_location_map; + auto add_overlap_region = [&](lldb::addr_t base, lldb::addr_t end, + RangeMap::Entry *entry) { + RangeMap::Entry overlap_region = {base, end - base, entry->data}; + overlap_region.data.insert(offset, member_loc); + new_location_map.Append(overlap_region); + }; + + for (const auto &range : ranges) { + lldb::addr_t base = range.GetRangeBase(); + lldb::addr_t end = range.GetRangeEnd(); + uint32_t base_idx = location_map.FindEntryIndexThatContainsOrFollows(base); + while (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) { + if (base >= end || entry->base >= end) + break; + if (entry->data.is_dwarf) + base = entry->GetRangeEnd(); + else { + lldb::addr_t entry_end = entry->GetRangeEnd(); + if (base > entry->base) { + add_overlap_region(base, end < entry_end ? end : entry_end, entry); + entry->SetRangeEnd(base); + } else if (base < entry->base) { + new_location_map.Append( + {base, entry->base - base, {offset, member_loc}}); + if (entry_end == end) + entry->data.insert(offset, member_loc); + else { + add_overlap_region(entry->base, end, entry); + entry->ShrinkFront(end - entry->base); + } + } else { + if (end < entry_end) { + new_location_map.Append({end, entry_end, entry->data}); + entry->SetRangeEnd(end); + } + entry->data.insert(offset, member_loc); + } + base = entry_end; + } + ++base_idx; + } + if (base >= end) + continue; + new_location_map.Append({base, end - base, {offset, member_loc}}); + } + for (const auto &entry : new_location_map) + location_map.Append(entry); + if (!new_location_map.IsEmpty()) + location_map.Sort(); +} + +void AddDwarfRange(RangeMap &location_map, const DWARFExpression &expr, + const Variable::RangeList &ranges) { + if (!expr.IsValid()) + return; + RangeMap new_location_map; + for (const auto &range : ranges) { + lldb::addr_t base = range.GetRangeBase(); + lldb::addr_t end = range.GetRangeEnd(); + uint32_t base_idx = location_map.FindEntryIndexThatContains(base); + uint32_t end_idx = location_map.FindEntryIndexThatContains(end - 1); + // range is within an entry. + if (base_idx == end_idx && base_idx != UINT32_MAX) { + auto *entry = location_map.GetMutableEntryAtIndex(base_idx); + if (base > entry->base) { + new_location_map.Append({entry->base, base - entry->base, entry->data}); + entry->ShrinkFront(base - entry->base); + } + if (end == entry->GetRangeEnd()) + entry->data = expr; + else { + entry->ShrinkFront(end - base); + new_location_map.Append({base, end - base, expr}); + } + continue; + } + base_idx = location_map.FindEntryIndexThatContainsOrFollows(base); + if (auto *entry = location_map.GetMutableEntryAtIndex(base_idx)) { + if (entry->Contains(base) && entry->base != base) { + entry->SetRangeEnd(base); + ++base_idx; + } + } + end_idx = location_map.FindEntryIndexThatContainsOrFollows(end - 1); + if (auto *entry = location_map.GetMutableEntryAtIndex(end_idx)) { + if (entry->Contains(end - 1)) { + if (entry->GetRangeEnd() == end) + ++end_idx; + else + entry->ShrinkFront(end - entry->base); + } + } + + if (end_idx == UINT32_MAX) + end_idx = location_map.GetSize(); + // Erase existing ranges covered by new range. + location_map.Erase(base_idx, end_idx); + new_location_map.Append({base, end - base, expr}); + } + + for (const auto &entry : new_location_map) + location_map.Append(entry); + location_map.Sort(); +} } // namespace CVTagRecord CVTagRecord::create(CVType type) { @@ -612,207 +810,182 @@ if (sym.kind() == S_REGREL32) { RegRelativeSym reg(SymbolRecordKind::RegRelativeSym); cantFail(SymbolDeserializer::deserializeAs<RegRelativeSym>(sym, reg)); - result.location = - MakeRegRelLocationExpression(reg.Register, reg.Offset, module); - result.ranges.emplace(); + result.location = DWARFExpressionList( + module, MakeRegRelLocationExpression(reg.Register, reg.Offset, module), + nullptr); return result; } if (sym.kind() == S_REGISTER) { RegisterSym reg(SymbolRecordKind::RegisterSym); cantFail(SymbolDeserializer::deserializeAs<RegisterSym>(sym, reg)); - result.location = MakeEnregisteredLocationExpression(reg.Register, module); - result.ranges.emplace(); + result.location = DWARFExpressionList( + module, MakeEnregisteredLocationExpression(reg.Register, module), + nullptr); return result; } if (sym.kind() == S_LOCAL) { LocalSym local(SymbolRecordKind::LocalSym); - cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local)); + if (llvm::Error error = + SymbolDeserializer::deserializeAs<LocalSym>(sym, local)) { + llvm::consumeError(std::move(error)); + return result; + } PdbCompilandSymId loc_specifier_id(var_id.modi, var_id.offset + sym.RecordData.size()); - CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); - switch(loc_specifier_cvs.kind()) { - case S_DEFRANGE_FRAMEPOINTER_REL: { - DefRangeFramePointerRelSym loc( - SymbolRecordKind::DefRangeFramePointerRelSym); - cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>( - loc_specifier_cvs, loc)); - - Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps); - - PdbCompilandSymId func_scope_id = - PdbSymUid(func_block.GetID()).asCompilandSym(); - CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id); - lldbassert(func_block_cvs.kind() == S_GPROC32 || - func_block_cvs.kind() == S_LPROC32); - - PdbCompilandSymId frame_proc_id( - func_scope_id.modi, func_scope_id.offset + func_block_cvs.length()); - - RegisterId base_reg = - GetBaseFrameRegister(index, frame_proc_id, result.is_param); - if (base_reg == RegisterId::NONE) - break; - if (base_reg == RegisterId::VFRAME) { - llvm::StringRef program; - if (GetFrameDataProgram(index, ranges, program)) { - result.location = - MakeVFrameRelLocationExpression(program, loc.Hdr.Offset, module); - result.ranges = std::move(ranges); - } else { - // invalid variable + CVSymbol loc_specifier_cvs; + // Only used for S_DEFRANGE_FRAMEPOINTER_REL. + RegisterId base_reg = RegisterId::NONE; + size_t type_size = GetSizeOfType(result.type, index.tpi()); + // A map from offset of a field in parent to size of the field. + std::map<uint64_t, size_t> offset_to_size; + // Get the size of each fields if it's udt. + if (!FindMembersSize::GetMemberSizesForUdt(result.type, index.tpi(), 0, + offset_to_size)) + return result; + + // When overlaps happens, always prefer the one that doesn't split the value + // into multiple locations and the location parsed first is perfered. + RangeMap location_map; + + // Iterate through all location records after S_LOCAL. They describe the + // value of this variable at different locations. + bool finished = false; + while (!finished) { + loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); + switch (loc_specifier_cvs.kind()) { + case S_DEFRANGE_FRAMEPOINTER_REL: { + DefRangeFramePointerRelSym loc( + SymbolRecordKind::DefRangeFramePointerRelSym); + if (llvm::Error error = + SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>( + loc_specifier_cvs, loc)) { + llvm::consumeError(std::move(error)); + return result; } - } else { - result.location = - MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module); - result.ranges = std::move(ranges); + Variable::RangeList raw_ranges = + MakeRangeList(index, loc.Range, loc.Gaps); + if (base_reg == RegisterId::NONE) { + PdbCompilandSymId func_scope_id = + PdbSymUid(func_block.GetID()).asCompilandSym(); + CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id); + lldbassert(func_block_cvs.kind() == S_GPROC32 || + func_block_cvs.kind() == S_LPROC32); + PdbCompilandSymId frame_proc_id(func_scope_id.modi, + func_scope_id.offset + + func_block_cvs.length()); + base_reg = + GetBaseFrameRegister(index, frame_proc_id, result.is_param); + if (base_reg == RegisterId::NONE) + break; + } + DWARFExpression expr; + if (base_reg == RegisterId::VFRAME) { + llvm::StringRef program; + if (GetFrameDataProgram(index, raw_ranges, program)) + expr = MakeVFrameRelLocationExpression(program, loc.Hdr.Offset, + module); + else { + // invalid variable + } + } else + expr = MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module); + AddDwarfRange(location_map, expr, raw_ranges); + break; } - break; - } - case S_DEFRANGE_REGISTER_REL: { - DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym); - cantFail(SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>( - loc_specifier_cvs, loc)); - - Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps); - - RegisterId base_reg = (RegisterId)(uint16_t)loc.Hdr.Register; - - if (base_reg == RegisterId::VFRAME) { - llvm::StringRef program; - if (GetFrameDataProgram(index, ranges, program)) { - result.location = MakeVFrameRelLocationExpression( - program, loc.Hdr.BasePointerOffset, module); - result.ranges = std::move(ranges); - } else { - // invalid variable + case S_DEFRANGE_REGISTER: { + DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym); + if (llvm::Error error = + SymbolDeserializer::deserializeAs<DefRangeRegisterSym>( + loc_specifier_cvs, loc)) { + llvm::consumeError(std::move(error)); + return result; } - } else { - result.location = MakeRegRelLocationExpression( - base_reg, loc.Hdr.BasePointerOffset, module); - result.ranges = std::move(ranges); + RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register; + Variable::RangeList raw_ranges = + MakeRangeList(index, loc.Range, loc.Gaps); + DWARFExpression expr = + MakeEnregisteredLocationExpression(reg_id, module); + AddDwarfRange(location_map, expr, raw_ranges); + break; } - break; - } - case S_DEFRANGE_REGISTER: { - DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym); - cantFail(SymbolDeserializer::deserializeAs<DefRangeRegisterSym>( - loc_specifier_cvs, loc)); - - RegisterId base_reg = (RegisterId)(uint16_t)loc.Hdr.Register; - result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); - result.location = MakeEnregisteredLocationExpression(base_reg, module); - break; - } - case S_DEFRANGE_SUBFIELD_REGISTER: { - // A map from offset in parent to pair of register id and size. If the - // variable is a simple type, then we don't know the number of subfields. - // Otherwise, the size of the map should be greater than or equal to the - // number of sub field record. - std::map<uint64_t, std::pair<RegisterId, uint32_t>> members_info; - bool is_simple_type = result.type.isSimple(); - if (!is_simple_type) { - CVType class_cvt = index.tpi().getType(result.type); - TypeIndex class_id = result.type; - if (class_cvt.kind() == LF_MODIFIER) - class_id = LookThroughModifierRecord(class_cvt); - if (IsForwardRefUdt(class_id, index.tpi())) { - auto expected_full_ti = - index.tpi().findFullDeclForForwardRef(class_id); - if (!expected_full_ti) { - llvm::consumeError(expected_full_ti.takeError()); - break; - } - class_cvt = index.tpi().getType(*expected_full_ti); + case S_DEFRANGE_REGISTER_REL: { + DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym); + if (llvm::Error error = + SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>( + loc_specifier_cvs, loc)) { + llvm::consumeError(std::move(error)); + return result; } - if (IsTagRecord(class_cvt)) { - TagRecord tag_record = CVTagRecord::create(class_cvt).asTag(); - CVType field_list_cvt = index.tpi().getType(tag_record.FieldList); - FieldListRecord field_list; - if (llvm::Error error = - TypeDeserializer::deserializeAs<FieldListRecord>( - field_list_cvt, field_list)) - llvm::consumeError(std::move(error)); - FindMembersSize find_members_size(members_info, index.tpi()); - if (llvm::Error err = visitMemberRecordStream(field_list.Data, - find_members_size)) { - llvm::consumeError(std::move(err)); - break; + Variable::RangeList raw_ranges = + MakeRangeList(index, loc.Range, loc.Gaps); + RegisterId reg_id = (RegisterId)(uint16_t)loc.Hdr.Register; + DWARFExpression expr; + if (reg_id == RegisterId::VFRAME) { + llvm::StringRef program; + if (GetFrameDataProgram(index, raw_ranges, program)) + expr = MakeVFrameRelLocationExpression( + program, loc.Hdr.BasePointerOffset, module); + else { + // invalid variable } } else { - // TODO: Handle poiner type. - break; + expr = MakeRegRelLocationExpression(reg_id, loc.Hdr.BasePointerOffset, + module); + } + if (expr.IsValid()) { + if (loc.hasSpilledUDTMember()) { + uint64_t offset = loc.offsetInParent(); + AddMemberLocationRanges( + location_map, offset, + {(uint16_t)reg_id, (uint16_t)loc.Hdr.BasePointerOffset, false}, + raw_ranges); + } else + AddDwarfRange(location_map, expr, raw_ranges); } + break; } - - size_t member_idx = 0; - // Assuming S_DEFRANGE_SUBFIELD_REGISTER is followed only by - // S_DEFRANGE_SUBFIELD_REGISTER, need to verify. - while (loc_specifier_cvs.kind() == S_DEFRANGE_SUBFIELD_REGISTER) { - if (!is_simple_type && member_idx >= members_info.size()) - break; - + case S_DEFRANGE_SUBFIELD_REGISTER: { DefRangeSubfieldRegisterSym loc( SymbolRecordKind::DefRangeSubfieldRegisterSym); - cantFail(SymbolDeserializer::deserializeAs<DefRangeSubfieldRegisterSym>( - loc_specifier_cvs, loc)); - - if (result.ranges) { - result.ranges = Variable::RangeList::GetOverlaps( - *result.ranges, MakeRangeList(index, loc.Range, loc.Gaps)); - } else { - result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); - result.ranges->Sort(); + if (llvm::Error error = + SymbolDeserializer::deserializeAs<DefRangeSubfieldRegisterSym>( + loc_specifier_cvs, loc)) { + llvm::consumeError(std::move(error)); + return result; } - if (is_simple_type) { - if (members_info.count(loc.Hdr.OffsetInParent)) { - // Malformed record. - result.ranges->Clear(); - return result; - } - members_info[loc.Hdr.OffsetInParent] = { - (RegisterId)(uint16_t)loc.Hdr.Register, 0}; - } else { - if (!members_info.count(loc.Hdr.OffsetInParent)) { - // Malformed record. - result.ranges->Clear(); - return result; - } - members_info[loc.Hdr.OffsetInParent].first = - (RegisterId)(uint16_t)loc.Hdr.Register; - } - // Go to next S_DEFRANGE_SUBFIELD_REGISTER. - loc_specifier_id = PdbCompilandSymId( - loc_specifier_id.modi, - loc_specifier_id.offset + loc_specifier_cvs.RecordData.size()); - loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); + Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps); + AddMemberLocationRanges(location_map, loc.Hdr.OffsetInParent, + {loc.Hdr.Register, 0, true}, ranges); + break; } - // Fix size for simple type. - if (is_simple_type) { - auto cur = members_info.begin(); - auto end = members_info.end(); - auto next = cur; - ++next; - uint32_t size = 0; - while (next != end) { - cur->second.second = next->first - cur->first; - size += cur->second.second; - cur = next++; - } - cur->second.second = - GetTypeSizeForSimpleKind(result.type.getSimpleKind()) - size; + // FIXME: Handle other kinds. LLVM only generates the 4 types of records + // above. MSVC generates other location types. + case S_DEFRANGE: + case S_DEFRANGE_SUBFIELD: + case S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: + break; + default: + finished = true; + break; } - result.location = - MakeEnregisteredLocationExpressionForClass(members_info, module); - break; + loc_specifier_id = PdbCompilandSymId( + loc_specifier_id.modi, + loc_specifier_id.offset + loc_specifier_cvs.RecordData.size()); } - default: - // FIXME: Handle other kinds. LLVM only generates the 4 types of records - // above. - break; + result.location = DWARFExpressionList(); + for (const auto &entry : location_map) { + DWARFExpression dwarf_expr = + entry.data.is_dwarf ? entry.data.expr + : MakeEnregisteredLocationExpressionForComposite( + entry.data.offset_to_location, + offset_to_size, type_size, module); + + result.location->AddExpression(entry.GetRangeBase(), entry.GetRangeEnd(), + dwarf_expr); } return result; } Index: lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h +++ lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h @@ -26,6 +26,12 @@ } // namespace llvm namespace lldb_private { namespace npdb { +struct MemberValLocation { + uint16_t reg_id; + uint16_t reg_offset; + bool is_at_reg = true; +}; + DWARFExpression MakeEnregisteredLocationExpression(llvm::codeview::RegisterId reg, lldb::ModuleSP module); @@ -41,9 +47,9 @@ DWARFExpression MakeConstantLocationExpression( llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi, const llvm::APSInt &constant, lldb::ModuleSP module); -DWARFExpression MakeEnregisteredLocationExpressionForClass( - std::map<uint64_t, std::pair<llvm::codeview::RegisterId, uint32_t>> - &members_info, +DWARFExpression MakeEnregisteredLocationExpressionForComposite( + const std::map<uint64_t, MemberValLocation> &offset_to_location, + std::map<uint64_t, size_t> &offset_to_size, size_t total_size, lldb::ModuleSP module); } // namespace npdb } // namespace lldb_private Index: lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp @@ -128,33 +128,38 @@ return result; } +static bool MakeRegisterBasedLocationExpressionInternal( + Stream &stream, llvm::codeview::RegisterId reg, RegisterKind register_kind, + llvm::Optional<int32_t> relative_offset, lldb::ModuleSP module) { + 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; +} + static DWARFExpression MakeRegisterBasedLocationExpressionInternal( llvm::codeview::RegisterId reg, llvm::Optional<int32_t> 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; + return MakeRegisterBasedLocationExpressionInternal( + stream, reg, register_kind, relative_offset, module); }); } @@ -251,28 +256,43 @@ return result; } -DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpressionForClass( - std::map<uint64_t, std::pair<RegisterId, uint32_t>> &members_info, +DWARFExpression +lldb_private::npdb::MakeEnregisteredLocationExpressionForComposite( + const std::map<uint64_t, MemberValLocation> &offset_to_location, + std::map<uint64_t, size_t> &offset_to_size, size_t total_size, lldb::ModuleSP module) { return MakeLocationExpressionInternal( module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { - for (auto pair : members_info) { - std::pair<RegisterId, uint32_t> member_info = pair.second; - if (member_info.first != llvm::codeview::RegisterId::NONE) { - uint32_t reg_num = - GetRegisterNumber(module->GetArchitecture().GetMachine(), - member_info.first, register_kind); - if (reg_num == LLDB_INVALID_REGNUM) - return false; - if (reg_num > 31) { - stream.PutHex8(llvm::dwarf::DW_OP_regx); - stream.PutULEB128(reg_num); - } else { - stream.PutHex8(llvm::dwarf::DW_OP_reg0 + reg_num); - } + size_t cur_offset = 0; + bool is_simple_type = offset_to_size.empty(); + // Iterate through offset_to_location because offset_to_size might be + // empty if the variable is a simple type. + for (const auto &offset_loc : offset_to_location) { + if (cur_offset < offset_loc.first) { + stream.PutHex8(llvm::dwarf::DW_OP_piece); + stream.PutULEB128(offset_loc.first - cur_offset); + cur_offset = offset_loc.first; } + MemberValLocation loc = offset_loc.second; + llvm::Optional<int32_t> offset = + loc.is_at_reg ? llvm::None + : llvm::Optional<int32_t>(loc.reg_offset); + if (!MakeRegisterBasedLocationExpressionInternal( + stream, (RegisterId)loc.reg_id, register_kind, offset, + module)) + return false; + if (!is_simple_type) { + stream.PutHex8(llvm::dwarf::DW_OP_piece); + stream.PutULEB128(offset_to_size[offset_loc.first]); + cur_offset = offset_loc.first + offset_to_size[offset_loc.first]; + } + } + // For simple type, it specifies the byte size of the value described by + // the previous dwarf expr. For udt, it's the remaining byte size at end + // of a struct. + if (total_size > cur_offset) { stream.PutHex8(llvm::dwarf::DW_OP_piece); - stream.PutULEB128(member_info.second); + stream.PutULEB128(total_size - cur_offset); } return true; }); Index: lldb/include/lldb/Utility/RangeMap.h =================================================================== --- lldb/include/lldb/Utility/RangeMap.h +++ lldb/include/lldb/Utility/RangeMap.h @@ -49,6 +49,11 @@ void Slide(BaseType slide) { base += slide; } + void ShrinkFront(S s) { + base += s; + size -= size > s ? s : size; + } + bool Union(const Range &rhs) { if (DoesAdjoinOrIntersect(rhs)) { auto new_end = std::max<BaseType>(GetRangeEnd(), rhs.GetRangeEnd()); @@ -445,6 +450,13 @@ void Append(const Entry &entry) { m_entries.emplace_back(entry); } + bool Erase(uint32_t start, uint32_t end) { + if (start >= end || end > m_entries.size()) + return false; + m_entries.erase(begin() + start, begin() + end); + return true; + } + void Sort() { if (m_entries.size() > 1) std::stable_sort(m_entries.begin(), m_entries.end(), @@ -621,6 +633,17 @@ return nullptr; } + uint32_t FindEntryIndexThatContainsOrFollows(B addr) const { +#ifdef ASSERT_RANGEMAP_ARE_SORTED + assert(IsSorted()); +#endif + const AugmentedEntry *entry = static_cast<const AugmentedEntry *>( + FindEntryThatContainsOrFollows(addr)); + if (entry) + return std::distance(m_entries.begin(), entry); + return UINT32_MAX; + } + Entry *Back() { return (m_entries.empty() ? nullptr : &m_entries.back()); } const Entry *Back() const {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits