[lldb][NativePDB] Handle S_DEFRANGE_REGISTER_REL_INDIR (#190336)
Since #189401, LLVM and Clang generate `S_DEFRANGE_REGISTER_REL_INDIR` for indirect locations. This adds support in LLDB. The offset added after dereferencing is signed here - unlike in `S_REGREL32_INDIR` (at least that's the assumption). So I updated `MakeRegisterBasedIndirectLocationExpressionInternal` to handle the signedness. This is the reason the MSVC test was changed here. I didn't find a test case where LLVM emits the record with the `VFRAME` register. Other than that, the clang test is similar to the MSVC one except that the locations are slightly different.
This commit is contained in:
parent
fecf609998
commit
a2c9146da1
@ -166,8 +166,9 @@ static bool MakeRegisterBasedIndirectLocationExpressionInternal(
|
||||
return false;
|
||||
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_deref);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_plus_uconst);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_consts);
|
||||
stream.PutSLEB128(offset);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_plus);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -229,6 +230,31 @@ DWARFExpression lldb_private::npdb::MakeVFrameRelLocationExpression(
|
||||
});
|
||||
}
|
||||
|
||||
DWARFExpression lldb_private::npdb::MakeVFrameRelIndirLocationExpression(
|
||||
llvm::StringRef fpo_program, int32_t offset, int32_t offset_in_udt,
|
||||
lldb::ModuleSP module) {
|
||||
return MakeLocationExpressionInternal(
|
||||
module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool {
|
||||
const ArchSpec &architecture = module->GetArchitecture();
|
||||
|
||||
if (!EmitVFrameEvaluationDWARFExpression(
|
||||
fpo_program, architecture.GetMachine(), stream))
|
||||
return false;
|
||||
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_consts);
|
||||
stream.PutSLEB128(offset);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_plus);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_deref);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_consts);
|
||||
stream.PutSLEB128(offset_in_udt);
|
||||
stream.PutHex8(llvm::dwarf::DW_OP_plus);
|
||||
|
||||
register_kind = eRegisterKindLLDB;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
DWARFExpression lldb_private::npdb::MakeGlobalLocationExpression(
|
||||
uint16_t section, uint32_t offset, ModuleSP module) {
|
||||
assert(section > 0);
|
||||
|
||||
@ -47,6 +47,10 @@ MakeRegRelIndirLocationExpression(llvm::codeview::RegisterId reg,
|
||||
DWARFExpression MakeVFrameRelLocationExpression(llvm::StringRef fpo_program,
|
||||
int32_t offset,
|
||||
lldb::ModuleSP module);
|
||||
DWARFExpression
|
||||
MakeVFrameRelIndirLocationExpression(llvm::StringRef fpo_program,
|
||||
int32_t offset, int32_t offset_in_udt,
|
||||
lldb::ModuleSP module);
|
||||
DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
|
||||
lldb::ModuleSP module);
|
||||
llvm::Expected<DWARFExpression> MakeConstantLocationExpression(
|
||||
|
||||
@ -888,6 +888,37 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
|
||||
AddDwarfRange(location_map, expr, raw_ranges);
|
||||
break;
|
||||
}
|
||||
case S_DEFRANGE_REGISTER_REL_INDIR: {
|
||||
DefRangeRegisterRelIndirSym loc(
|
||||
SymbolRecordKind::DefRangeRegisterRelIndirSym);
|
||||
if (llvm::Error error =
|
||||
SymbolDeserializer::deserializeAs<DefRangeRegisterRelIndirSym>(
|
||||
loc_specifier_cvs, loc)) {
|
||||
llvm::consumeError(std::move(error));
|
||||
return result;
|
||||
}
|
||||
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 = MakeVFrameRelIndirLocationExpression(
|
||||
program, loc.Hdr.BasePointerOffset, loc.Hdr.OffsetInUdt,
|
||||
module);
|
||||
else {
|
||||
// invalid variable
|
||||
}
|
||||
} else {
|
||||
expr = MakeRegRelIndirLocationExpression(
|
||||
reg_id, loc.Hdr.BasePointerOffset, loc.Hdr.OffsetInUdt, module);
|
||||
}
|
||||
// FIXME: If it's UDT, we need to know the size of the value in byte.
|
||||
if (!loc.hasSpilledUDTMember())
|
||||
AddDwarfRange(location_map, expr, raw_ranges);
|
||||
break;
|
||||
}
|
||||
case S_DEFRANGE_SUBFIELD_REGISTER: {
|
||||
DefRangeSubfieldRegisterSym loc(
|
||||
SymbolRecordKind::DefRangeSubfieldRegisterSym);
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
# REQUIRES: lld, target-windows
|
||||
|
||||
# Test that LLDB can show variables introduced in C++ 17 structured bindings
|
||||
# when compiled with clang-cl.
|
||||
|
||||
# RUN: split-file %s %t
|
||||
|
||||
# RUN: %build --compiler=clang-cl --arch=64 --std=c++17 --nodefaultlib -o %t.exe -- %t/main.cpp
|
||||
# RUN: lldb-test symbols %t.exe | FileCheck %s --check-prefix=SYMBOLS
|
||||
# RUN: %lldb -f %t.exe -s %t/commands.input | FileCheck %s --check-prefix=LLDB
|
||||
|
||||
#--- main.cpp
|
||||
|
||||
struct Foo { int a; int b; };
|
||||
|
||||
int main() {
|
||||
Foo f{1, 2};
|
||||
|
||||
auto&[a, b] = f;
|
||||
return a + b; // break here
|
||||
}
|
||||
|
||||
#--- commands.input
|
||||
|
||||
br set -p "break here"
|
||||
r
|
||||
v f
|
||||
v a
|
||||
v b
|
||||
q
|
||||
|
||||
# SYMBOLS: Function{{.*}}, demangled = main, type =
|
||||
# SYMBOLS-NEXT: Block{{.*}}, ranges =
|
||||
# SYMBOLS-DAG: Variable{{.*}}, name = "f", type = {{.*}} (Foo), scope = local, location =
|
||||
# SYMBOLS-DAG: Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location = 0x00000000:
|
||||
# SYMBOLS-NEXT: [{{.*}}): DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts +0, DW_OP_plus
|
||||
# SYMBOLS-DAG: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location = 0x00000000:
|
||||
# SYMBOLS-NEXT: [{{.*}}): DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts {{[+-][0-9]+}}, DW_OP_plus
|
||||
|
||||
# LLDB: (lldb) v f
|
||||
# LLDB-NEXT: (Foo) f = (a = 1, b = 2)
|
||||
# LLDB-NEXT: (lldb) v a
|
||||
# LLDB-NEXT: (int) a = 1
|
||||
# LLDB-NEXT: (lldb) v b
|
||||
# LLDB-NEXT: (int) b = 2
|
||||
@ -32,8 +32,8 @@ q
|
||||
# SYMBOLS: Function{{.*}}, demangled = main, type =
|
||||
# SYMBOLS-NEXT: Block{{.*}}, ranges =
|
||||
# SYMBOLS-NEXT: Variable{{.*}}, name = "f", type = {{.*}} (Foo), scope = local, location =
|
||||
# SYMBOLS-NEXT: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_plus_uconst 0x{{[0-9]+}}
|
||||
# SYMBOLS-NEXT: Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_plus_uconst 0x0
|
||||
# SYMBOLS-NEXT: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts {{[+-][0-9]+}}, DW_OP_plus
|
||||
# SYMBOLS-NEXT: Variable{{.*}}, name = "a", type = {{.*}} (int), scope = local, location = DW_OP_breg{{.*}}, DW_OP_deref, DW_OP_consts +0, DW_OP_plus
|
||||
|
||||
# LLDB: (lldb) v f
|
||||
# LLDB-NEXT: (Foo) f = (a = 1, b = 2)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user