Skip to content

Commit 5e9c9b3

Browse files
committed
[LLDB][NativePDB] Add support for S_DEFRANGE_REGISTER and S_DEFRANGE_SUBFIELD_REGISTER
Differential Revision: https://reviews.llvm.org/D119508
1 parent 2f33f11 commit 5e9c9b3

File tree

12 files changed

+731
-20
lines changed

12 files changed

+731
-20
lines changed

lldb/include/lldb/Utility/RangeMap.h

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@ template <typename B, typename S> struct Range {
5959
return false;
6060
}
6161

62+
Range Intersect(const Range &rhs) const {
63+
const BaseType lhs_base = this->GetRangeBase();
64+
const BaseType rhs_base = rhs.GetRangeBase();
65+
const BaseType lhs_end = this->GetRangeEnd();
66+
const BaseType rhs_end = rhs.GetRangeEnd();
67+
Range range;
68+
range.SetRangeBase(std::max(lhs_base, rhs_base));
69+
range.SetRangeEnd(std::min(lhs_end, rhs_end));
70+
return range;
71+
}
72+
6273
BaseType GetRangeEnd() const { return base + size; }
6374

6475
void SetRangeEnd(BaseType end) {
@@ -99,12 +110,7 @@ template <typename B, typename S> struct Range {
99110

100111
// Returns true if the two ranges intersect
101112
bool DoesIntersect(const Range &rhs) const {
102-
const BaseType lhs_base = this->GetRangeBase();
103-
const BaseType rhs_base = rhs.GetRangeBase();
104-
const BaseType lhs_end = this->GetRangeEnd();
105-
const BaseType rhs_end = rhs.GetRangeEnd();
106-
bool result = (lhs_base < rhs_end) && (lhs_end > rhs_base);
107-
return result;
113+
return Intersect(rhs).IsValid();
108114
}
109115

110116
bool operator<(const Range &rhs) const {
@@ -133,6 +139,38 @@ template <typename B, typename S, unsigned N = 0> class RangeVector {
133139

134140
~RangeVector() = default;
135141

142+
static RangeVector GetOverlaps(const RangeVector &vec1,
143+
const RangeVector &vec2) {
144+
#ifdef ASSERT_RANGEMAP_ARE_SORTED
145+
assert(vec1.IsSorted() && vec2.IsSorted());
146+
#endif
147+
RangeVector result;
148+
auto pos1 = vec1.begin();
149+
auto end1 = vec1.end();
150+
auto pos2 = vec2.begin();
151+
auto end2 = vec2.end();
152+
while (pos1 != end1 && pos2 != end2) {
153+
Entry entry = pos1->Intersect(*pos2);
154+
if (entry.IsValid())
155+
result.Append(entry);
156+
if (pos1->GetRangeEnd() < pos2->GetRangeEnd())
157+
++pos1;
158+
else
159+
++pos2;
160+
}
161+
return result;
162+
}
163+
164+
bool operator==(const RangeVector &rhs) const {
165+
if (GetSize() != rhs.GetSize())
166+
return false;
167+
for (size_t i = 0; i < GetSize(); ++i) {
168+
if (GetEntryRef(i) != rhs.GetEntryRef(i))
169+
return false;
170+
}
171+
return true;
172+
}
173+
136174
void Append(const Entry &entry) { m_entries.push_back(entry); }
137175

138176
void Append(B base, S size) { m_entries.emplace_back(base, size); }

lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,29 @@ DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
250250
DWARFExpression result(nullptr, extractor, nullptr);
251251
return result;
252252
}
253+
254+
DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpressionForClass(
255+
llvm::ArrayRef<std::pair<RegisterId, uint32_t>> &members_info,
256+
lldb::ModuleSP module) {
257+
return MakeLocationExpressionInternal(
258+
module, [&](Stream &stream, RegisterKind &register_kind) -> bool {
259+
for (auto member_info : members_info) {
260+
if (member_info.first != llvm::codeview::RegisterId::NONE) {
261+
uint32_t reg_num =
262+
GetRegisterNumber(module->GetArchitecture().GetMachine(),
263+
member_info.first, register_kind);
264+
if (reg_num == LLDB_INVALID_REGNUM)
265+
return false;
266+
if (reg_num > 31) {
267+
stream.PutHex8(llvm::dwarf::DW_OP_regx);
268+
stream.PutULEB128(reg_num);
269+
} else {
270+
stream.PutHex8(llvm::dwarf::DW_OP_reg0 + reg_num);
271+
}
272+
}
273+
stream.PutHex8(llvm::dwarf::DW_OP_piece);
274+
stream.PutULEB128(member_info.second);
275+
}
276+
return true;
277+
});
278+
}

lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_NATIVEPDB_DWARFLOCATIONEXPRESSION_H
1111

1212
#include "lldb/lldb-forward.h"
13+
#include "llvm/ADT/ArrayRef.h"
1314
#include "llvm/DebugInfo/CodeView/CodeView.h"
1415

1516
namespace llvm {
@@ -39,6 +40,10 @@ DWARFExpression MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
3940
DWARFExpression MakeConstantLocationExpression(
4041
llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi,
4142
const llvm::APSInt &constant, lldb::ModuleSP module);
43+
DWARFExpression MakeEnregisteredLocationExpressionForClass(
44+
llvm::ArrayRef<std::pair<llvm::codeview::RegisterId, uint32_t>>
45+
&members_info,
46+
lldb::ModuleSP module);
4247
} // namespace npdb
4348
} // namespace lldb_private
4449

lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,8 @@ clang::Decl *PdbAstBuilder::GetOrCreateSymbolForId(PdbCompilandSymId id) {
497497
if (isLocalVariableType(cvs.kind())) {
498498
clang::DeclContext *scope = GetParentDeclContext(id);
499499
clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope);
500-
PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid);
500+
PdbCompilandSymId scope_id =
501+
PdbSymUid(m_decl_to_status[scope_decl].uid).asCompilandSym();
501502
return GetOrCreateVariableDecl(scope_id, id);
502503
}
503504

lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp

Lines changed: 94 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "PdbIndex.h"
1313
#include "PdbSymUid.h"
1414

15+
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
1516
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
1617
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
1718
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
@@ -20,6 +21,7 @@
2021
#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
2122
#include "lldb/Symbol/Block.h"
2223
#include "lldb/Utility/LLDBAssert.h"
24+
#include "lldb/Utility/LLDBLog.h"
2325
#include "lldb/lldb-enumerations.h"
2426

2527
using namespace lldb_private;
@@ -48,6 +50,22 @@ MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,
4850
return result;
4951
}
5052

53+
namespace {
54+
struct FindMembersSize : public TypeVisitorCallbacks {
55+
FindMembersSize(std::vector<std::pair<RegisterId, uint32_t>> &members_info,
56+
TpiStream &tpi)
57+
: members_info(members_info), tpi(tpi) {}
58+
std::vector<std::pair<RegisterId, uint32_t>> &members_info;
59+
TpiStream &tpi;
60+
llvm::Error visitKnownMember(CVMemberRecord &cvr,
61+
DataMemberRecord &member) override {
62+
members_info.emplace_back(llvm::codeview::RegisterId::NONE,
63+
GetSizeOfType(member.Type, tpi));
64+
return llvm::Error::success();
65+
}
66+
};
67+
} // namespace
68+
5169
CVTagRecord CVTagRecord::create(CVType type) {
5270
assert(IsTagRecord(type) && "type is not a tag record!");
5371
switch (type.kind()) {
@@ -477,6 +495,8 @@ VariableInfo lldb_private::npdb::GetVariableNameInfo(CVSymbol sym) {
477495
cantFail(SymbolDeserializer::deserializeAs<LocalSym>(sym, local));
478496
result.type = local.Type;
479497
result.name = local.Name;
498+
result.is_param =
499+
((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None);
480500
return result;
481501
}
482502

@@ -609,7 +629,8 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
609629
PdbCompilandSymId loc_specifier_id(var_id.modi,
610630
var_id.offset + sym.RecordData.size());
611631
CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);
612-
if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) {
632+
switch(loc_specifier_cvs.kind()) {
633+
case S_DEFRANGE_FRAMEPOINTER_REL: {
613634
DefRangeFramePointerRelSym loc(
614635
SymbolRecordKind::DefRangeFramePointerRelSym);
615636
cantFail(SymbolDeserializer::deserializeAs<DefRangeFramePointerRelSym>(
@@ -632,10 +653,8 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
632653
PdbCompilandSymId frame_proc_id(
633654
func_scope_id.modi, func_scope_id.offset + func_block_cvs.length());
634655

635-
bool is_parameter =
636-
((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None);
637656
RegisterId base_reg =
638-
GetBaseFrameRegister(index, frame_proc_id, is_parameter);
657+
GetBaseFrameRegister(index, frame_proc_id, result.is_param);
639658

640659
if (base_reg == RegisterId::VFRAME) {
641660
llvm::StringRef program;
@@ -651,7 +670,9 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
651670
MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module);
652671
result.ranges = std::move(ranges);
653672
}
654-
} else if (loc_specifier_cvs.kind() == S_DEFRANGE_REGISTER_REL) {
673+
break;
674+
}
675+
case S_DEFRANGE_REGISTER_REL: {
655676
DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym);
656677
cantFail(SymbolDeserializer::deserializeAs<DefRangeRegisterRelSym>(
657678
loc_specifier_cvs, loc));
@@ -674,9 +695,76 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
674695
base_reg, loc.Hdr.BasePointerOffset, module);
675696
result.ranges = std::move(ranges);
676697
}
698+
break;
677699
}
700+
case S_DEFRANGE_REGISTER: {
701+
DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym);
702+
cantFail(SymbolDeserializer::deserializeAs<DefRangeRegisterSym>(
703+
loc_specifier_cvs, loc));
678704

679-
// FIXME: Handle other kinds
705+
RegisterId base_reg = (RegisterId)(uint16_t)loc.Hdr.Register;
706+
result.ranges = MakeRangeList(index, loc.Range, loc.Gaps);
707+
result.location = MakeEnregisteredLocationExpression(base_reg, module);
708+
break;
709+
}
710+
case S_DEFRANGE_SUBFIELD_REGISTER: {
711+
CVType class_cvt = index.tpi().getType(result.type);
712+
ClassRecord class_record = CVTagRecord::create(class_cvt).asClass();
713+
CVType field_list = index.tpi().getType(class_record.FieldList);
714+
std::vector<std::pair<RegisterId, uint32_t>> members_info;
715+
FindMembersSize find_members_size(members_info, index.tpi());
716+
if (llvm::Error err =
717+
visitMemberRecordStream(field_list.data(), find_members_size))
718+
llvm::consumeError(std::move(err));
719+
720+
std::vector<Variable::RangeList> range_lists;
721+
uint32_t cur_offset = 0;
722+
size_t member_idx = 0;
723+
// Assuming S_DEFRANGE_SUBFIELD_REGISTER is followed only by
724+
// S_DEFRANGE_SUBFIELD_REGISTER, need to verify.
725+
while (loc_specifier_cvs.kind() == S_DEFRANGE_SUBFIELD_REGISTER &&
726+
member_idx < members_info.size()) {
727+
DefRangeSubfieldRegisterSym loc(
728+
SymbolRecordKind::DefRangeSubfieldRegisterSym);
729+
cantFail(SymbolDeserializer::deserializeAs<DefRangeSubfieldRegisterSym>(
730+
loc_specifier_cvs, loc));
731+
732+
if (result.ranges) {
733+
result.ranges = Variable::RangeList::GetOverlaps(
734+
*result.ranges, MakeRangeList(index, loc.Range, loc.Gaps));
735+
} else {
736+
result.ranges = MakeRangeList(index, loc.Range, loc.Gaps);
737+
result.ranges->Sort();
738+
}
739+
740+
// Some fields maybe optimized away and have no
741+
// S_DEFRANGE_SUBFIELD_REGISTER to describe them. Skip them.
742+
while (loc.Hdr.OffsetInParent != cur_offset) {
743+
cur_offset += members_info[member_idx].second;
744+
++member_idx;
745+
}
746+
if (member_idx < members_info.size()) {
747+
members_info[member_idx].first =
748+
(RegisterId)(uint16_t)loc.Hdr.Register;
749+
cur_offset += members_info[member_idx].second;
750+
++member_idx;
751+
}
752+
// Go to next S_DEFRANGE_SUBFIELD_REGISTER.
753+
loc_specifier_id = PdbCompilandSymId(
754+
loc_specifier_id.modi,
755+
loc_specifier_id.offset + loc_specifier_cvs.RecordData.size());
756+
loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id);
757+
}
758+
auto member_info_ref = llvm::makeArrayRef(members_info);
759+
result.location =
760+
MakeEnregisteredLocationExpressionForClass(member_info_ref, module);
761+
break;
762+
}
763+
default:
764+
// FIXME: Handle other kinds. LLVM only generates the 4 types of records
765+
// above.
766+
break;
767+
}
680768
return result;
681769
}
682770
llvm_unreachable("Symbol is not a local variable!");

lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ struct VariableInfo {
105105
llvm::codeview::TypeIndex type;
106106
llvm::Optional<DWARFExpression> location;
107107
llvm::Optional<Variable::RangeList> ranges;
108+
bool is_param;
108109
};
109110

110111
llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind);

lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,7 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
16651665
SymbolFileTypeSP sftype =
16661666
std::make_shared<SymbolFileType>(*this, type_sp->GetID());
16671667

1668+
is_param |= var_info.is_param;
16681669
ValueType var_scope =
16691670
is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal;
16701671
bool external = false;
@@ -1673,7 +1674,7 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
16731674
bool static_member = false;
16741675
VariableSP var_sp = std::make_shared<Variable>(
16751676
toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,
1676-
comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, external,
1677+
&block, *var_info.ranges, &decl, *var_info.location, external,
16771678
artificial, location_is_constant_data, static_member);
16781679

16791680
if (!is_param)

lldb/source/Symbol/Variable.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,14 @@ bool Variable::LocationIsValidForAddress(const Address &address) {
243243
// Be sure to resolve the address to section offset prior to calling this
244244
// function.
245245
if (address.IsSectionOffset()) {
246+
// We need to check if the address is valid for both scope range and value
247+
// range.
248+
// Empty scope range means block range.
249+
bool valid_in_scope_range =
250+
GetScopeRange().IsEmpty() || GetScopeRange().FindEntryThatContains(
251+
address.GetFileAddress()) != nullptr;
252+
if (!valid_in_scope_range)
253+
return false;
246254
SymbolContext sc;
247255
CalculateSymbolContext(&sc);
248256
if (sc.module_sp == address.GetModule()) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
image lookup -a 0x140001000 -v
2+
image lookup -a 0x140001003 -v
3+
image lookup -a 0x140001006 -v
4+
5+
image lookup -a 0x140001011 -v
6+
image lookup -a 0x140001017 -v
7+
image lookup -a 0x140001019 -v
8+
image lookup -a 0x14000101e -v
9+
image lookup -a 0x14000102c -v
10+
11+
exit

0 commit comments

Comments
 (0)