Index: lldb/include/lldb/Utility/RangeMap.h =================================================================== --- lldb/include/lldb/Utility/RangeMap.h +++ lldb/include/lldb/Utility/RangeMap.h @@ -128,6 +128,8 @@ typedef S SizeType; typedef Range Entry; typedef llvm::SmallVector Collection; + using const_iterator = typename Collection::const_iterator; + using iterator = typename Collection::iterator; RangeVector() = default; @@ -171,6 +173,10 @@ return false; } + const_iterator RemoveEntry(const_iterator it) { return m_entries.erase(it); } + + iterator RemoveEntry(iterator it) { return m_entries.erase(it); } + void Sort() { if (m_entries.size() > 1) std::stable_sort(m_entries.begin(), m_entries.end()); @@ -337,9 +343,10 @@ return nullptr; } - using const_iterator = typename Collection::const_iterator; const_iterator begin() const { return m_entries.begin(); } const_iterator end() const { return m_entries.end(); } + iterator begin() { return m_entries.begin(); } + iterator end() { return m_entries.end(); } protected: void CombinePrevAndNext(typename Collection::iterator pos) { Index: lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h +++ lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.h @@ -11,6 +11,7 @@ #include "lldb/lldb-forward.h" #include "llvm/DebugInfo/CodeView/CodeView.h" +#include namespace llvm { class APSInt; @@ -39,6 +40,10 @@ DWARFExpression MakeConstantLocationExpression( llvm::codeview::TypeIndex underlying_ti, llvm::pdb::TpiStream &tpi, const llvm::APSInt &constant, lldb::ModuleSP module); +DWARFExpression MakeEnregisteredLocationExpressionForClass( + const std::vector> + &members_info, + lldb::ModuleSP module); } // namespace npdb } // namespace lldb_private Index: lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp @@ -250,3 +250,29 @@ DWARFExpression result(nullptr, extractor, nullptr); return result; } + +DWARFExpression lldb_private::npdb::MakeEnregisteredLocationExpressionForClass( + const std::vector> &members_info, + lldb::ModuleSP module) { + return MakeLocationExpressionInternal( + module, [&](Stream &stream, RegisterKind ®ister_kind) -> bool { + for (auto member_info : members_info) { + 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); + } + } + stream.PutHex8(llvm::dwarf::DW_OP_piece); + stream.PutULEB128(member_info.second); + } + return true; + }); +} Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -497,7 +497,8 @@ if (isLocalVariableType(cvs.kind())) { clang::DeclContext *scope = GetParentDeclContext(id); clang::Decl *scope_decl = clang::Decl::castFromDeclContext(scope); - PdbCompilandSymId scope_id(id.modi, m_decl_to_status[scope_decl].uid); + PdbCompilandSymId scope_id = + PdbSymUid(m_decl_to_status[scope_decl].uid).asCompilandSym(); return GetOrCreateVariableDecl(scope_id, id); } Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h @@ -105,6 +105,7 @@ llvm::codeview::TypeIndex type; llvm::Optional location; llvm::Optional ranges; + bool is_param; }; llvm::pdb::PDB_SymType CVSymToPDBSym(llvm::codeview::SymbolKind kind); Index: lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -12,6 +12,7 @@ #include "PdbIndex.h" #include "PdbSymUid.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" @@ -20,6 +21,7 @@ #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" #include "lldb/Symbol/Block.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/lldb-enumerations.h" using namespace lldb_private; @@ -48,6 +50,22 @@ return result; } +namespace { +struct FindMembersSize : public TypeVisitorCallbacks { + FindMembersSize(std::vector> &members_info, + TpiStream &tpi) + : members_info(members_info), tpi(tpi) {} + std::vector> &members_info; + TpiStream &tpi; + llvm::Error visitKnownMember(CVMemberRecord &cvr, + DataMemberRecord &member) override { + members_info.emplace_back(llvm::codeview::RegisterId::NONE, + GetSizeOfType(member.Type, tpi)); + return llvm::Error::success(); + } +}; +} // namespace + CVTagRecord CVTagRecord::create(CVType type) { assert(IsTagRecord(type) && "type is not a tag record!"); switch (type.kind()) { @@ -477,6 +495,8 @@ cantFail(SymbolDeserializer::deserializeAs(sym, local)); result.type = local.Type; result.name = local.Name; + result.is_param = + ((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None); return result; } @@ -609,7 +629,8 @@ PdbCompilandSymId loc_specifier_id(var_id.modi, var_id.offset + sym.RecordData.size()); CVSymbol loc_specifier_cvs = index.ReadSymbolRecord(loc_specifier_id); - if (loc_specifier_cvs.kind() == S_DEFRANGE_FRAMEPOINTER_REL) { + switch(loc_specifier_cvs.kind()) { + case S_DEFRANGE_FRAMEPOINTER_REL: { DefRangeFramePointerRelSym loc( SymbolRecordKind::DefRangeFramePointerRelSym); cantFail(SymbolDeserializer::deserializeAs( @@ -632,10 +653,8 @@ PdbCompilandSymId frame_proc_id( func_scope_id.modi, func_scope_id.offset + func_block_cvs.length()); - bool is_parameter = - ((local.Flags & LocalSymFlags::IsParameter) != LocalSymFlags::None); RegisterId base_reg = - GetBaseFrameRegister(index, frame_proc_id, is_parameter); + GetBaseFrameRegister(index, frame_proc_id, result.is_param); if (base_reg == RegisterId::VFRAME) { llvm::StringRef program; @@ -651,7 +670,9 @@ MakeRegRelLocationExpression(base_reg, loc.Hdr.Offset, module); result.ranges = std::move(ranges); } - } else if (loc_specifier_cvs.kind() == S_DEFRANGE_REGISTER_REL) { + break; + } + case S_DEFRANGE_REGISTER_REL: { DefRangeRegisterRelSym loc(SymbolRecordKind::DefRangeRegisterRelSym); cantFail(SymbolDeserializer::deserializeAs( loc_specifier_cvs, loc)); @@ -674,9 +695,110 @@ base_reg, loc.Hdr.BasePointerOffset, module); result.ranges = std::move(ranges); } + break; } + case S_DEFRANGE_REGISTER: { + DefRangeRegisterSym loc(SymbolRecordKind::DefRangeRegisterSym); + cantFail(SymbolDeserializer::deserializeAs( + loc_specifier_cvs, loc)); - // FIXME: Handle other kinds + 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: { + CVType class_cvt = index.tpi().getType(result.type); + ClassRecord class_record = CVTagRecord::create(class_cvt).asClass(); + CVType field_list = index.tpi().getType(class_record.FieldList); + std::vector> members_info; + FindMembersSize find_members_size(members_info, index.tpi()); + if (llvm::Error err = + visitMemberRecordStream(field_list.data(), find_members_size)) + llvm::consumeError(std::move(err)); + + std::vector range_lists; + uint32_t cur_offset = 0; + 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 && + member_idx < members_info.size()) { + DefRangeSubfieldRegisterSym loc( + SymbolRecordKind::DefRangeSubfieldRegisterSym); + cantFail(SymbolDeserializer::deserializeAs( + loc_specifier_cvs, loc)); + + if (result.ranges) { + // Modify the result.ranges so that the ranges inside it is covered by + // all range_lists. + Variable::RangeList range_list = + MakeRangeList(index, loc.Range, loc.Gaps); + Variable::RangeList temp_range_list; + for (Variable::RangeList::iterator begin = result.ranges->begin(), + end = result.ranges->end(); + begin != end;) { + uint32_t start_idx = + range_list.FindEntryIndexThatContains(begin->GetRangeBase()); + uint32_t end_idx = + range_list.FindEntryIndexThatContains(begin->GetRangeEnd() - 1); + if (start_idx == UINT32_MAX && end_idx == UINT32_MAX) { + begin = result.ranges->RemoveEntry(begin); + } else { + if (start_idx == UINT32_MAX) { + begin->SetRangeBase( + range_list.GetEntryAtIndex(end_idx)->GetRangeBase()); + } else if (end_idx == UINT32_MAX) { + begin->SetRangeEnd( + range_list.GetEntryAtIndex(start_idx)->GetRangeEnd()); + } else if (start_idx != end_idx) { + // Split the range into two parts by setting end of existing + // range and inserting new range into temp list. + begin->SetRangeEnd( + range_list.GetEntryAtIndex(start_idx)->GetRangeEnd()); + temp_range_list.Append( + {range_list.GetEntryAtIndex(end_idx)->GetRangeBase(), + begin->GetRangeEnd()}); + } + ++begin; + } + } + for (auto range : temp_range_list) { + result.ranges->Append(range); + } + result.ranges->Sort(); + } else { + result.ranges = MakeRangeList(index, loc.Range, loc.Gaps); + result.ranges->Sort(); + } + + // Some fields maybe optimized away and have no + // S_DEFRANGE_SUBFIELD_REGISTER to describe them. Skip them. + while (loc.Hdr.OffsetInParent != cur_offset) { + cur_offset += members_info[member_idx].second; + ++member_idx; + } + if (member_idx < members_info.size()) { + members_info[member_idx].first = + (RegisterId)(uint16_t)loc.Hdr.Register; + cur_offset += members_info[member_idx].second; + ++member_idx; + } + // 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); + } + result.location = + MakeEnregisteredLocationExpressionForClass(members_info, module); + break; + } + default: + // FIXME: Handle other kinds. LLVM only generates the 4 types of records + // above. + break; + } return result; } llvm_unreachable("Symbol is not a local variable!"); Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -1661,6 +1661,7 @@ SymbolFileTypeSP sftype = std::make_shared(*this, type_sp->GetID()); + is_param |= var_info.is_param; ValueType var_scope = is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal; bool external = false; @@ -1669,7 +1670,7 @@ bool static_member = false; VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, - comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, external, + &block, *var_info.ranges, &decl, *var_info.location, external, artificial, location_is_constant_data, static_member); if (!is_param) Index: lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables-registers.lldbinit =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/NativePDB/Inputs/local-variables-registers.lldbinit @@ -0,0 +1,15 @@ +b main +r a b c d +p argc +step +p local +step +p p2 +step +p s +p s.x +p s.y +finish +p s.x +c +exit Index: lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.cpp =================================================================== --- /dev/null +++ lldb/test/Shell/SymbolFile/NativePDB/local-variables-registers.cpp @@ -0,0 +1,102 @@ +// clang-format off +// REQUIRES: system-windows + +// RUN: %build --opt basic -o %t.exe -- %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -s \ +// RUN: %p/Inputs/local-variables-registers.lldbinit 2>&1 | FileCheck %s + +struct S { + int x; + char y; +}; +__attribute__((noinline)) S CreateS(int p1, char p2) { + S s; + s.x = p1 + 1; + s.y = p2 + 2; + ++s.x; + ++s.y; + return s; +} +int main(int argc, char** argv) { + int local = argc * 2; + S s = CreateS(local, 'a'); + return s.x + s.y; +} + +// CHECK: (lldb) b main +// CHECK-NEXT: Breakpoint 1 +// CHECK-NEXT: (lldb) r a b c d +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1 +// CHECK-NEXT: frame #0: {{.*}} local-variables-registers.cpp.tmp.exe`main(argc=5, argv={{.*}}) at local-variables-registers.cpp:21 +// CHECK-NEXT: 18 return s; +// CHECK-NEXT: 19 } +// CHECK-NEXT: 20 int main(int argc, char** argv) { +// CHECK-NEXT: -> 21 int local = argc * 2; +// CHECK-NEXT: 22 S s = CreateS(local, 'a'); +// CHECK-NEXT: 23 return s.x + s.y; +// CHECK-NEXT: 24 } +// CHECK-NEXT: Process {{.*}} launched: +// CHECK-NEXT: (lldb) p argc +// CHECK-NEXT: (int) $0 = 5 +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables-registers.cpp.tmp.exe`main(argc=, argv={{.*}}) at local-variables-registers.cpp:22 +// CHECK-NEXT: 19 } +// CHECK-NEXT: 20 int main(int argc, char** argv) { +// CHECK-NEXT: 21 int local = argc * 2; +// CHECK-NEXT: -> 22 S s = CreateS(local, 'a'); +// CHECK-NEXT: 23 return s.x + s.y; +// CHECK-NEXT: 24 } +// CHECK-NEXT: 25 +// CHECK-NEXT: (lldb) p local +// CHECK-NEXT: (int) $1 = 10 +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables-registers.cpp.tmp.exe`CreateS(p1=10, p2='a') at local-variables-registers.cpp:17 +// CHECK-NEXT: 14 s.x = p1 + 1; +// CHECK-NEXT: 15 s.y = p2 + 2; +// CHECK-NEXT: 16 ++s.x; +// CHECK-NEXT: -> 17 ++s.y; +// CHECK-NEXT: 18 return s; +// CHECK-NEXT: 19 } +// CHECK-NEXT: 20 int main(int argc, char** argv) { +// CHECK-NEXT: (lldb) p p2 +// CHECK-NEXT: (char) $2 = 'a' +// CHECK-NEXT: (lldb) step +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step in +// CHECK-NEXT: frame #0: {{.*}} local-variables-registers.cpp.tmp.exe`CreateS(p1=10, p2=) at local-variables-registers.cpp:18 +// CHECK-NEXT: 15 s.y = p2 + 2; +// CHECK-NEXT: 16 ++s.x; +// CHECK-NEXT: 17 ++s.y; +// CHECK-NEXT: -> 18 return s; +// CHECK-NEXT: 19 } +// CHECK-NEXT: 20 int main(int argc, char** argv) { +// CHECK-NEXT: 21 int local = argc * 2; +// CHECK-NEXT: (lldb) p s +// CHECK-NEXT: (S) $3 = (x = 12, y = 'd') +// CHECK-NEXT: (lldb) p s.x +// CHECK-NEXT: (int) $4 = 12 +// CHECK-NEXT: (lldb) p s.y +// CHECK-NEXT: (char) $5 = 'd' +// CHECK-NEXT: (lldb) finish +// CHECK-NEXT: Process {{.*}} stopped +// CHECK-NEXT: * thread #1, stop reason = step out +// CHECK-NEXT: Return value: (S) $6 = (x = 12, y = 'd') +// CHECK-EMPTY: +// CHECK-NEXT: frame #0: {{.*}} local-variables-registers.cpp.tmp.exe`main(argc=, argv=) at local-variables-registers.cpp:23 +// CHECK-NEXT: 20 int main(int argc, char** argv) { +// CHECK-NEXT: 21 int local = argc * 2; +// CHECK-NEXT: 22 S s = CreateS(local, 'a'); +// CHECK-NEXT: -> 23 return s.x + s.y; +// CHECK-NEXT: 24 } +// CHECK-NEXT: 25 +// CHECK-NEXT: 26 // CHECK: (lldb) b main +// CHECK-NEXT: (lldb) p s.x +// CHECK-NEXT: (int) $7 = 12 +// CHECK-NEXT: (lldb) c +// CHECK-NEXT: Process {{.*}} resuming +// CHECK-NEXT: Process {{.*}} exited with status = 112 \ No newline at end of file Index: lldb/test/Shell/SymbolFile/NativePDB/stack_unwinding01.cpp =================================================================== --- lldb/test/Shell/SymbolFile/NativePDB/stack_unwinding01.cpp +++ lldb/test/Shell/SymbolFile/NativePDB/stack_unwinding01.cpp @@ -24,19 +24,19 @@ // CHECK: (lldb) thread backtrace // CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1 -// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method at stack_unwinding01.cpp:12 +// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12 // CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20 // CHECK: (lldb) thread backtrace // CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1 -// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method at stack_unwinding01.cpp:12 -// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method at stack_unwinding01.cpp:12 +// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12 +// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12 // CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20 // CHECK: (lldb) thread backtrace // CHECK-NEXT: * thread #1, stop reason = breakpoint 1.1 -// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method at stack_unwinding01.cpp:12 -// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method at stack_unwinding01.cpp:12 -// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method at stack_unwinding01.cpp:12 +// CHECK-NEXT: * frame #0: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=4, b=2) at stack_unwinding01.cpp:12 +// CHECK-NEXT: frame #1: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=3, b=2) at stack_unwinding01.cpp:12 +// CHECK-NEXT: frame #2: {{.*}} stack_unwinding01.cpp.tmp.exe`Struct::simple_method(this={{.*}}, a=2, b=2) at stack_unwinding01.cpp:12 // CHECK-NEXT: frame #3: {{.*}} stack_unwinding01.cpp.tmp.exe`main(argc={{.*}}, argv={{.*}}) at stack_unwinding01.cpp:20