diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -53,28 +53,21 @@ } if (debug_aranges->GetNumRanges() == num_debug_aranges) { - // We got nothing from the debug info, maybe we have a line tables only - // situation. Check the line tables and build the arange table from this. + // We got nothing from the debug info, try to build the arange table from + // the debug map OSO aranges. SymbolContext sc; sc.comp_unit = m_dwarf.GetCompUnitForDWARFCompUnit(*this); if (sc.comp_unit) { SymbolFileDWARFDebugMap *debug_map_sym_file = m_dwarf.GetDebugMapSymfile(); - if (debug_map_sym_file == nullptr) { - if (LineTable *line_table = sc.comp_unit->GetLineTable()) { - LineTable::FileAddressRanges file_ranges; - const bool append = true; - const size_t num_ranges = - line_table->GetContiguousFileAddressRanges(file_ranges, append); - for (uint32_t idx = 0; idx < num_ranges; ++idx) { - const LineTable::FileAddressRanges::Entry &range = - file_ranges.GetEntryRef(idx); - debug_aranges->AppendRange(cu_offset, range.GetRangeBase(), - range.GetRangeEnd()); - } - } - } else - debug_map_sym_file->AddOSOARanges(&m_dwarf, debug_aranges); + if (debug_map_sym_file) { + auto *cu_info = + debug_map_sym_file->GetCompileUnitInfo(&GetSymbolFileDWARF()); + // If there are extra compile units the OSO entries aren't a reliable + // source of information. + if (cu_info->compile_units_sps.empty()) + debug_map_sym_file->AddOSOARanges(&m_dwarf, debug_aranges); + } } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -702,9 +702,9 @@ // We already parsed this compile unit, had out a shared pointer to it cu_sp = comp_unit->shared_from_this(); } else { - if (dwarf_cu.GetOffset() == 0 && GetDebugMapSymfile()) { + if (GetDebugMapSymfile()) { // Let the debug map create the compile unit - cu_sp = m_debug_map_symfile->GetCompileUnit(this); + cu_sp = m_debug_map_symfile->GetCompileUnit(this, dwarf_cu); dwarf_cu.SetUserData(cu_sp.get()); } else { ModuleSP module_sp(m_objfile_sp->GetModule()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -19,6 +19,7 @@ #include "UniqueDWARFASTType.h" class SymbolFileDWARF; +class DWARFCompileUnit; class DWARFDebugAranges; class DWARFDeclContext; @@ -174,7 +175,10 @@ llvm::sys::TimePoint<> oso_mod_time; lldb_private::Status oso_load_error; OSOInfoSP oso_sp; - lldb::CompUnitSP compile_unit_sp; + /// The compile units that an object file contains. + llvm::SmallVector compile_units_sps; + /// A map from the compile unit ID to its index in the vector. + llvm::SmallDenseMap id_to_index_map; uint32_t first_symbol_index = UINT32_MAX; uint32_t last_symbol_index = UINT32_MAX; uint32_t first_symbol_id = UINT32_MAX; @@ -182,10 +186,7 @@ FileRangeMap file_range_map; bool file_range_map_valid = false; - CompileUnitInfo() - : so_file(), oso_path(), oso_mod_time(), oso_sp(), compile_unit_sp(), - - file_range_map() {} + CompileUnitInfo() = default; const FileRangeMap &GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile); }; @@ -193,7 +194,17 @@ // Protected Member Functions void InitOSO(); + /// This function actually returns the number of object files, which may be + /// less than the actual number of compile units, since an object file may + /// contain more than one compile unit. SymbolFileDWARFDebugMap looks up the + /// number of compile units by reading the nlist symbol table, which + /// currently, on macOS, only reports one compile unit per object file, and + /// there's no efficient way to calculate the actual number of compile units + /// upfront. uint32_t CalculateNumCompileUnits() override; + + /// This function actually returns the first compile unit the object file at + /// the given index contains. lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) override; static uint32_t GetOSOIndexFromUserID(lldb::user_id_t uid) { @@ -263,7 +274,11 @@ void SetCompileUnit(SymbolFileDWARF *oso_dwarf, const lldb::CompUnitSP &cu_sp); - lldb::CompUnitSP GetCompileUnit(SymbolFileDWARF *oso_dwarf); + /// Returns the compile unit associated with the dwarf compile unit. This may + /// be one of the extra compile units an object file contains which isn't + /// reachable by ParseCompileUnitAtIndex(uint32_t). + lldb::CompUnitSP GetCompileUnit(SymbolFileDWARF *oso_dwarf, + DWARFCompileUnit &dwarf_cu); CompileUnitInfo *GetCompileUnitInfo(SymbolFileDWARF *oso_dwarf); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "SymbolFileDWARFDebugMap.h" +#include "DWARFCompileUnit.h" #include "DWARFDebugAranges.h" +#include "DWARFDebugInfo.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" @@ -17,6 +19,7 @@ #include "lldb/Utility/RangeMap.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Timer.h" +#include "lldb/Utility/StreamString.h" //#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT #if defined(DEBUG_OSO_DMAP) @@ -586,25 +589,42 @@ const uint32_t cu_count = GetNumCompileUnits(); if (cu_idx < cu_count) { - Module *oso_module = GetModuleByCompUnitInfo(&m_compile_unit_infos[cu_idx]); + auto &cu_info = m_compile_unit_infos[cu_idx]; + Module *oso_module = GetModuleByCompUnitInfo(&cu_info); if (oso_module) { FileSpec so_file_spec; if (GetFileSpecForSO(cu_idx, so_file_spec)) { // User zero as the ID to match the compile unit at offset zero in each - // .o file since each .o file can only have one compile unit for now. + // .o file. lldb::user_id_t cu_id = 0; - m_compile_unit_infos[cu_idx].compile_unit_sp = + cu_info.compile_units_sps.push_back( std::make_shared( m_objfile_sp->GetModule(), nullptr, so_file_spec, cu_id, - eLanguageTypeUnknown, eLazyBoolCalculate); - - if (m_compile_unit_infos[cu_idx].compile_unit_sp) { - SetCompileUnitAtIndex(cu_idx, - m_compile_unit_infos[cu_idx].compile_unit_sp); + eLanguageTypeUnknown, eLazyBoolCalculate)); + cu_info.id_to_index_map.insert({0, 0}); + SetCompileUnitAtIndex(cu_idx, cu_info.compile_units_sps[0]); + // If there's a symbol file also register all the extra compile units. + if (SymbolFileDWARF *oso_symfile = + GetSymbolFileByCompUnitInfo(&cu_info)) { + auto num_dwarf_units = oso_symfile->DebugInfo().GetNumUnits(); + for (size_t i = 0; i < num_dwarf_units; ++i) { + auto *dwarf_unit = oso_symfile->DebugInfo().GetUnitAtIndex(i); + if (auto *dwarf_cu = llvm::dyn_cast(dwarf_unit)) { + // The "main" one was already registered. + if (dwarf_cu->GetID() == 0) + continue; + cu_info.compile_units_sps.push_back(std::make_shared( + m_objfile_sp->GetModule(), nullptr, so_file_spec, + dwarf_cu->GetID(), eLanguageTypeUnknown, eLazyBoolCalculate)); + cu_info.id_to_index_map.insert( + {dwarf_cu->GetID(), cu_info.compile_units_sps.size() - 1}); + } + } } } } - comp_unit_sp = m_compile_unit_infos[cu_idx].compile_unit_sp; + if (!cu_info.compile_units_sps.empty()) + comp_unit_sp = cu_info.compile_units_sps[0]; } return comp_unit_sp; @@ -619,7 +639,12 @@ SymbolFileDWARFDebugMap::GetCompUnitInfo(const CompileUnit &comp_unit) { const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t i = 0; i < cu_count; ++i) { - if (&comp_unit == m_compile_unit_infos[i].compile_unit_sp.get()) + auto &id_to_index_map = m_compile_unit_infos[i].id_to_index_map; + + auto it = id_to_index_map.find(comp_unit.GetID()); + if (it != id_to_index_map.end() && + &comp_unit == + m_compile_unit_infos[i].compile_units_sps[it->getSecond()].get()) return &m_compile_unit_infos[i]; } return nullptr; @@ -1239,18 +1264,21 @@ } lldb::CompUnitSP -SymbolFileDWARFDebugMap::GetCompileUnit(SymbolFileDWARF *oso_dwarf) { +SymbolFileDWARFDebugMap::GetCompileUnit(SymbolFileDWARF *oso_dwarf, DWARFCompileUnit &dwarf_cu) { if (oso_dwarf) { const uint32_t cu_count = GetNumCompileUnits(); for (uint32_t cu_idx = 0; cu_idx < cu_count; ++cu_idx) { SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[cu_idx]); if (oso_symfile == oso_dwarf) { - if (!m_compile_unit_infos[cu_idx].compile_unit_sp) - m_compile_unit_infos[cu_idx].compile_unit_sp = - ParseCompileUnitAtIndex(cu_idx); - - return m_compile_unit_infos[cu_idx].compile_unit_sp; + if (m_compile_unit_infos[cu_idx].compile_units_sps.empty()) + ParseCompileUnitAtIndex(cu_idx); + + auto &id_to_index_map = m_compile_unit_infos[cu_idx].id_to_index_map; + auto it = id_to_index_map.find(dwarf_cu.GetID()); + if (it != id_to_index_map.end()) + return m_compile_unit_infos[cu_idx] + .compile_units_sps[it->getSecond()]; } } } @@ -1280,11 +1308,17 @@ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo(&m_compile_unit_infos[cu_idx]); if (oso_symfile == oso_dwarf) { - if (m_compile_unit_infos[cu_idx].compile_unit_sp) { - assert(m_compile_unit_infos[cu_idx].compile_unit_sp.get() == + if (!m_compile_unit_infos[cu_idx].compile_units_sps.empty()) { + assert(m_compile_unit_infos[cu_idx].compile_units_sps[0].get() == cu_sp.get()); } else { - m_compile_unit_infos[cu_idx].compile_unit_sp = cu_sp; + assert(cu_sp->GetID() == 0 && + "Setting first compile unit but with id different than 0!"); + auto &compile_units_sps = m_compile_unit_infos[cu_idx].compile_units_sps; + compile_units_sps.push_back(cu_sp); + m_compile_unit_infos[cu_idx].id_to_index_map.insert( + {cu_sp->GetID(), compile_units_sps.size() - 1}); + SetCompileUnitAtIndex(cu_idx, cu_sp); } } diff --git a/lldb/test/API/lang/c/full_lto_stepping/Makefile b/lldb/test/API/lang/c/full_lto_stepping/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/c/full_lto_stepping/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c foo.c +CFLAGS_EXTRAS = -flto=full -Wl,-object_path_lto -Wl,$(BUILDDIR)/lto.o + +include Makefile.rules \ No newline at end of file diff --git a/lldb/test/API/lang/c/full_lto_stepping/TestFullLtoStepping.py b/lldb/test/API/lang/c/full_lto_stepping/TestFullLtoStepping.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/c/full_lto_stepping/TestFullLtoStepping.py @@ -0,0 +1,29 @@ +"""Test that stepping in object files with multiple compile units works.""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestFullLtoStepping(TestBase): + + @skipIf(compiler=no_match("clang")) + @skipUnlessDarwin + def test(self): + self.build() + target = self.createTestTarget() + + breakpoint = target.BreakpointCreateByName("main") + self.assertTrue( + breakpoint and breakpoint.IsValid(), + "Breakpoint is valid") + + _, _, thread, _ = lldbutil.run_to_breakpoint_do_run(self, target, breakpoint) + name = thread.frames[0].GetFunctionName() + # Check that we start out in main. + self.assertEqual(name, 'main') + thread.StepInto() + name = thread.frames[0].GetFunctionName() + # Check that we stepped into f. + self.assertEqual(name, 'f') diff --git a/lldb/test/API/lang/c/full_lto_stepping/foo.h b/lldb/test/API/lang/c/full_lto_stepping/foo.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/c/full_lto_stepping/foo.h @@ -0,0 +1 @@ +int f(void); diff --git a/lldb/test/API/lang/c/full_lto_stepping/foo.c b/lldb/test/API/lang/c/full_lto_stepping/foo.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/c/full_lto_stepping/foo.c @@ -0,0 +1,3 @@ +int f() { + return 42; +} diff --git a/lldb/test/API/lang/c/full_lto_stepping/main.c b/lldb/test/API/lang/c/full_lto_stepping/main.c new file mode 100644 --- /dev/null +++ b/lldb/test/API/lang/c/full_lto_stepping/main.c @@ -0,0 +1,6 @@ +#include "foo.h" + +int main(void) { + int i = f(); + return 0; +}