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