[LLDB][NativePDB] Switch to use DWARFLocationList.

Before, NativePDB uses scoped range as a workaround for value range, that causes
problems (e.g. a variable's value can only have one range, but usually a
variable's value is located at different address ranges, each at different
locations, in optimized build).
This patch let NativePDB switch to DWARFLocationList so a variable's value can
be described at multiple non-overlapped address ranges and each range maps to a
location.
Because overlapping ranges exists, here's peference when choosing ranges:
1. Always prefer whole value locations. Suppose a variable size is 8 bytes, one record is that for range [1, 5) first 4 bytes is at ecx, and another record is that for range [2, 8) the 8 bytes value is at rdx. This results: [1, 2) has first 4 bytes at ecx, [2, 8) has the whole value at rdx.
2. Always prefer the locations parsed later. Suppose first record is that for range [1, 5) value is at ecx, second record is that for range [2, 6) value is at eax. This results: [1, 2) -> ecx, [2, 6) -> eax.

Differential Revision: https://reviews.llvm.org/D130796
This commit is contained in:
Zequan Wu
2022-07-29 12:35:22 -07:00
parent 7f72a0f5bb
commit 71d778f33e
12 changed files with 806 additions and 722 deletions

View File

@@ -49,6 +49,11 @@ template <typename B, typename S> struct Range {
void Slide(BaseType slide) { base += slide; }
void ShrinkFront(S s) {
base += s;
size -= std::min(s, size);
}
bool Union(const Range &rhs) {
if (DoesAdjoinOrIntersect(rhs)) {
auto new_end = std::max<BaseType>(GetRangeEnd(), rhs.GetRangeEnd());
@@ -445,6 +450,13 @@ public:
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 @@ public:
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 {

View File

@@ -649,3 +649,100 @@ uint32_t lldb_private::npdb::GetLLDBRegisterNumber(
return LLDB_INVALID_REGNUM;
}
}
uint32_t
lldb_private::npdb::GetRegisterSize(llvm::codeview::RegisterId register_id) {
switch(register_id) {
case llvm::codeview::RegisterId::AL:
case llvm::codeview::RegisterId::BL:
case llvm::codeview::RegisterId::CL:
case llvm::codeview::RegisterId::DL:
case llvm::codeview::RegisterId::AH:
case llvm::codeview::RegisterId::BH:
case llvm::codeview::RegisterId::CH:
case llvm::codeview::RegisterId::DH:
case llvm::codeview::RegisterId::SIL:
case llvm::codeview::RegisterId::DIL:
case llvm::codeview::RegisterId::BPL:
case llvm::codeview::RegisterId::SPL:
case llvm::codeview::RegisterId::R8B:
case llvm::codeview::RegisterId::R9B:
case llvm::codeview::RegisterId::R10B:
case llvm::codeview::RegisterId::R11B:
case llvm::codeview::RegisterId::R12B:
case llvm::codeview::RegisterId::R13B:
case llvm::codeview::RegisterId::R14B:
case llvm::codeview::RegisterId::R15B:
return 1;
case llvm::codeview::RegisterId::AX:
case llvm::codeview::RegisterId::BX:
case llvm::codeview::RegisterId::CX:
case llvm::codeview::RegisterId::DX:
case llvm::codeview::RegisterId::SP:
case llvm::codeview::RegisterId::BP:
case llvm::codeview::RegisterId::SI:
case llvm::codeview::RegisterId::DI:
case llvm::codeview::RegisterId::R8W:
case llvm::codeview::RegisterId::R9W:
case llvm::codeview::RegisterId::R10W:
case llvm::codeview::RegisterId::R11W:
case llvm::codeview::RegisterId::R12W:
case llvm::codeview::RegisterId::R13W:
case llvm::codeview::RegisterId::R14W:
case llvm::codeview::RegisterId::R15W:
return 2;
case llvm::codeview::RegisterId::EAX:
case llvm::codeview::RegisterId::EBX:
case llvm::codeview::RegisterId::ECX:
case llvm::codeview::RegisterId::EDX:
case llvm::codeview::RegisterId::ESP:
case llvm::codeview::RegisterId::EBP:
case llvm::codeview::RegisterId::ESI:
case llvm::codeview::RegisterId::EDI:
case llvm::codeview::RegisterId::R8D:
case llvm::codeview::RegisterId::R9D:
case llvm::codeview::RegisterId::R10D:
case llvm::codeview::RegisterId::R11D:
case llvm::codeview::RegisterId::R12D:
case llvm::codeview::RegisterId::R13D:
case llvm::codeview::RegisterId::R14D:
case llvm::codeview::RegisterId::R15D:
return 4;
case llvm::codeview::RegisterId::RAX:
case llvm::codeview::RegisterId::RBX:
case llvm::codeview::RegisterId::RCX:
case llvm::codeview::RegisterId::RDX:
case llvm::codeview::RegisterId::RSI:
case llvm::codeview::RegisterId::RDI:
case llvm::codeview::RegisterId::RBP:
case llvm::codeview::RegisterId::RSP:
case llvm::codeview::RegisterId::R8:
case llvm::codeview::RegisterId::R9:
case llvm::codeview::RegisterId::R10:
case llvm::codeview::RegisterId::R11:
case llvm::codeview::RegisterId::R12:
case llvm::codeview::RegisterId::R13:
case llvm::codeview::RegisterId::R14:
case llvm::codeview::RegisterId::R15:
return 8;
case llvm::codeview::RegisterId::XMM0:
case llvm::codeview::RegisterId::XMM1:
case llvm::codeview::RegisterId::XMM2:
case llvm::codeview::RegisterId::XMM3:
case llvm::codeview::RegisterId::XMM4:
case llvm::codeview::RegisterId::XMM5:
case llvm::codeview::RegisterId::XMM6:
case llvm::codeview::RegisterId::XMM7:
case llvm::codeview::RegisterId::XMM8:
case llvm::codeview::RegisterId::XMM9:
case llvm::codeview::RegisterId::XMM10:
case llvm::codeview::RegisterId::XMM11:
case llvm::codeview::RegisterId::XMM12:
case llvm::codeview::RegisterId::XMM13:
case llvm::codeview::RegisterId::XMM14:
case llvm::codeview::RegisterId::XMM15:
return 16;
default:
return 0;
}
}

View File

@@ -17,6 +17,7 @@ namespace npdb {
uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
llvm::codeview::RegisterId register_id);
uint32_t GetRegisterSize(llvm::codeview::RegisterId register_id);
} // namespace npdb
} // namespace lldb_private

View File

@@ -128,33 +128,38 @@ static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
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 &register_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 @@ DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
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 &register_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;
});

View File

@@ -26,6 +26,12 @@ class TpiStream;
} // 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 MakeGlobalLocationExpression(uint16_t section, uint32_t offset,
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

View File

@@ -19,6 +19,7 @@
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h"
#include "Plugins/SymbolFile/NativePDB/CodeViewRegisterMapping.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
@@ -29,6 +30,8 @@ using namespace lldb_private::npdb;
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) {
@@ -52,21 +55,144 @@ MakeRangeList(const PdbIndex &index, const LocalVariableAddrRange &range,
}
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;
TpiStream &tpi;
llvm::Error visitKnownMember(CVMemberRecord &cvr,
DataMemberRecord &member) override {
members_info.insert(
{member.getFieldOffset(),
{llvm::codeview::RegisterId::NONE, GetSizeOfType(member.Type, tpi)}});
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) {
if (end < entry_end)
new_location_map.Append({end, entry_end - end, entry->data});
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 +738,176 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
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));
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;
Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps);
// 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;
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)
// 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;
}
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;
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
}
} else {
result.location =
MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module);
result.ranges = std::move(ranges);
}
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);
}
// 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;
}
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);
uint32_t reg_size =
GetRegisterSize((RegisterId)(uint16_t)loc.Hdr.Register);
if (reg_size == 0)
break;
offset_to_size[loc.Hdr.OffsetInParent] = reg_size;
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;
}
result.location =
MakeEnregisteredLocationExpressionForClass(members_info, module);
break;
}
default:
// FIXME: Handle other kinds. LLVM only generates the 4 types of records
// above.
break;
// 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;
}
loc_specifier_id = PdbCompilandSymId(
loc_specifier_id.modi,
loc_specifier_id.offset + loc_specifier_cvs.RecordData.size());
}
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;
}

View File

@@ -103,8 +103,7 @@ struct SegmentOffsetLength {
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;
};

View File

@@ -1712,9 +1712,13 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
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);
@@ -1732,11 +1736,10 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
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);

View File

@@ -8,4 +8,28 @@ image lookup -a 0x140001019 -v
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
image lookup -a 0x14000104e -v
image lookup -a 0x14000104f -v
image lookup -a 0x140001050 -v
image lookup -a 0x140001051 -v
exit

View File

@@ -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.

View File

@@ -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,75 @@ main: # @main
.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:
.cv_loc 1 1 1004 0 # a.cpp:1004:0
ret
.L4f:
ret
.L50:
.Ltmp8:
.Lfunc_end1:
.seh_endproc
@@ -322,8 +390,172 @@ main: # @main
.p2align 2
.Ltmp38:
.cv_def_range .Ltmp6 .Ltmp7, subfield_reg, 17, 0
.short 2 # Record length
.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 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, subfield_reg, 18, 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_piece 0x4, DW_OP_reg26 XMM9, DW_OP_piece 0x4
# 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 .Ltmp109-.Ltmp108
# CHECK: (lldb) image lookup -a 0x140001045 -v
# CHECK: LineEntry: [0x0000000140001045-0x000000014000104e): 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-0x000000014000104e): 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-0x000000014000104e): 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-0x000000014000104e): 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-0x000000014000104e): 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-0x000000014000104e): C:\src\test\a.cpp:1003
# CHECK-EMPTY:
# CHECK: (lldb) image lookup -a 0x14000104b -v
# CHECK: LineEntry: [0x0000000140001045-0x000000014000104e): 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-0x000000014000104e): 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:
# 5. Simple type with subfield.
.Ltmp108:
.short 4414 # Record kind: S_LOCAL
.long 19 # TypeIndex
.short 0 # Flags
.asciz "simple_type1"
.p2align 2
.Ltmp109:
.cv_def_range .L4e .L4f, subfield_reg, 17, 4
.cv_def_range .L4e .L50, subfield_reg, 18, 0
.short 2
.short 4431 # Record kind: S_PROC_ID_END
# CHECK: (lldb) image lookup -a 0x14000104e -v
# CHECK: LineEntry: [0x000000014000104e-0x0000000140001050): C:\src\test\a.cpp:1004
# CHECK-NEXT: Variable: id = {{.*}}, name = "simple_type1", type = "int64_t", valid ranges = <block>, location = [0x000000014000104e, 0x000000014000104f) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_reg24 XMM7, DW_OP_piece 0x4
# CHECK-EMPTY:
# CHECK: (lldb) image lookup -a 0x14000104f -v
# CHECK: LineEntry: [0x000000014000104e-0x0000000140001050): C:\src\test\a.cpp:1004
# CHECK-NEXT: Variable: id = {{.*}}, name = "simple_type1", type = "int64_t", valid ranges = <block>, location = [0x000000014000104f, 0x0000000140001050) -> DW_OP_reg26 XMM9, DW_OP_piece 0x4, DW_OP_piece 0x4
# CHECK-EMPTY:
.Ltmp26:
.p2align 2
.cv_linetable 1, main, .Lfunc_end1
@@ -452,25 +684,38 @@ main: # @main
.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

View File

@@ -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