-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lldb] Fix a crash when using .dwp files and make type lookup reliable with the index cache #79544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ | |
#include "DWARFDebugInfoEntry.h" | ||
#include "DWARFFormValue.h" | ||
#include "DWARFTypeUnit.h" | ||
#include "LogChannelDWARF.h" | ||
|
||
using namespace lldb; | ||
using namespace lldb_private; | ||
|
@@ -81,27 +82,90 @@ void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { | |
: m_context.getOrLoadDebugInfoData(); | ||
lldb::offset_t offset = 0; | ||
while (data.ValidOffset(offset)) { | ||
llvm::Expected<DWARFUnitSP> unit_sp = DWARFUnit::extract( | ||
m_dwarf, m_units.size(), data, section, &offset); | ||
const lldb::offset_t unit_header_offset = offset; | ||
llvm::Expected<DWARFUnitSP> expected_unit_sp = | ||
DWARFUnit::extract(m_dwarf, m_units.size(), data, section, &offset); | ||
|
||
if (!unit_sp) { | ||
// FIXME: Propagate this error up. | ||
llvm::consumeError(unit_sp.takeError()); | ||
if (!expected_unit_sp) { | ||
Log *log = GetLog(DWARFLog::DebugInfo); | ||
LLDB_LOG(log, "Unable to extract DWARFUnitHeader at {0:x}: {1}", | ||
unit_header_offset, llvm::toString(expected_unit_sp.takeError())); | ||
return; | ||
} | ||
|
||
DWARFUnitSP unit_sp = *expected_unit_sp; | ||
|
||
// If it didn't return an error, then it should be returning a valid Unit. | ||
assert(*unit_sp); | ||
m_units.push_back(*unit_sp); | ||
offset = (*unit_sp)->GetNextUnitOffset(); | ||
assert((bool)unit_sp); | ||
|
||
// Keep a map of DWO ID back to the skeleton units. Sometimes accelerator | ||
// table lookups can cause the DWO files to be accessed before the skeleton | ||
// compile unit is parsed, so we keep a map to allow us to match up the DWO | ||
// file to the back to the skeleton compile units. | ||
if (unit_sp->GetUnitType() == lldb_private::dwarf::DW_UT_skeleton) { | ||
if (std::optional<uint64_t> unit_dwo_id = unit_sp->GetHeaderDWOId()) | ||
m_dwarf5_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit_sp.get(); | ||
} | ||
|
||
if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp->get())) { | ||
m_units.push_back(unit_sp); | ||
offset = unit_sp->GetNextUnitOffset(); | ||
|
||
if (auto *type_unit = llvm::dyn_cast<DWARFTypeUnit>(unit_sp.get())) { | ||
m_type_hash_to_unit_index.emplace_back(type_unit->GetTypeHash(), | ||
unit_sp.get()->GetID()); | ||
unit_sp->GetID()); | ||
} | ||
} | ||
} | ||
|
||
DWARFUnit *DWARFDebugInfo::GetSkeletonUnit(DWARFUnit *dwo_unit) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe return a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A NULL pointer already means it isn't availble. Not sure what making it optional would benefit? |
||
// If this isn't a DWO unit, don't try and find the skeleton unit. | ||
if (!dwo_unit->IsDWOUnit()) | ||
return nullptr; | ||
|
||
auto dwo_id = dwo_unit->GetDWOId(); | ||
if (!dwo_id.has_value()) | ||
return nullptr; | ||
|
||
// Parse the unit headers so that m_dwarf5_dwo_id_to_skeleton_unit is filled | ||
// in with all of the DWARF5 skeleton compile units DWO IDs since it is easy | ||
// to access the DWO IDs in the DWARFUnitHeader for each DWARFUnit. | ||
ParseUnitHeadersIfNeeded(); | ||
|
||
// Find the value in our cache and return it we we find it. This cache may | ||
// only contain DWARF5 units. | ||
auto iter = m_dwarf5_dwo_id_to_skeleton_unit.find(*dwo_id); | ||
if (iter != m_dwarf5_dwo_id_to_skeleton_unit.end()) | ||
return iter->second; | ||
|
||
// DWARF5 unit headers have the DWO ID and should have already been in the map | ||
// so if it wasn't found in the above find() call, then we didn't find it and | ||
// don't need to do the more expensive DWARF4 search. | ||
if (dwo_unit->GetVersion() >= 5) | ||
return nullptr; | ||
|
||
// Parse all DWO IDs from all DWARF4 and earlier compile units that have DWO | ||
// IDs. It is more expensive to get the DWO IDs from DWARF4 compile units as | ||
// we need to parse the unit DIE and extract the DW_AT_dwo_id or | ||
// DW_AT_GNU_dwo_id attribute values, so do this only if we didn't find our | ||
// match above search and only for DWARF4 and earlier compile units. | ||
llvm::call_once(m_dwarf4_dwo_id_to_skeleton_unit_once_flag, [this]() { | ||
for (uint32_t i = 0, num = GetNumUnits(); i < num; ++i) { | ||
if (DWARFUnit *unit = GetUnitAtIndex(i)) { | ||
if (unit->GetVersion() < 5) { | ||
if (std::optional<uint64_t> unit_dwo_id = unit->GetDWOId()) | ||
m_dwarf4_dwo_id_to_skeleton_unit[*unit_dwo_id] = unit; | ||
} | ||
} | ||
} | ||
}); | ||
|
||
// Search the DWARF4 DWO results that we parsed lazily. | ||
iter = m_dwarf4_dwo_id_to_skeleton_unit.find(*dwo_id); | ||
if (iter != m_dwarf4_dwo_id_to_skeleton_unit.end()) | ||
return iter->second; | ||
return nullptr; | ||
} | ||
|
||
void DWARFDebugInfo::ParseUnitHeadersIfNeeded() { | ||
llvm::call_once(m_units_once_flag, [&] { | ||
ParseUnitsFor(DIERef::Section::DebugInfo); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -722,8 +722,8 @@ DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) { | |
|
||
// The compile unit ID is the index of the DWARF unit. | ||
DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID()); | ||
if (dwarf_cu && dwarf_cu->GetUserData() == nullptr) | ||
dwarf_cu->SetUserData(comp_unit); | ||
if (dwarf_cu && dwarf_cu->GetLLDBCompUnit() == nullptr) | ||
dwarf_cu->SetLLDBCompUnit(comp_unit); | ||
|
||
// It must be DWARFCompileUnit when it created a CompileUnit. | ||
return llvm::cast_or_null<DWARFCompileUnit>(dwarf_cu); | ||
|
@@ -771,15 +771,15 @@ static const char *GetDWOName(DWARFCompileUnit &dwarf_cu, | |
|
||
lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { | ||
CompUnitSP cu_sp; | ||
CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); | ||
CompileUnit *comp_unit = dwarf_cu.GetLLDBCompUnit(); | ||
if (comp_unit) { | ||
// We already parsed this compile unit, had out a shared pointer to it | ||
cu_sp = comp_unit->shared_from_this(); | ||
} else { | ||
if (GetDebugMapSymfile()) { | ||
// Let the debug map create the compile unit | ||
cu_sp = m_debug_map_symfile->GetCompileUnit(this, dwarf_cu); | ||
dwarf_cu.SetUserData(cu_sp.get()); | ||
dwarf_cu.SetLLDBCompUnit(cu_sp.get()); | ||
} else { | ||
ModuleSP module_sp(m_objfile_sp->GetModule()); | ||
if (module_sp) { | ||
|
@@ -792,7 +792,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { | |
*GetDWARFUnitIndex(dwarf_cu.GetID()), cu_language, | ||
eLazyBoolCalculate, std::move(support_files)); | ||
|
||
dwarf_cu.SetUserData(cu_sp.get()); | ||
dwarf_cu.SetLLDBCompUnit(cu_sp.get()); | ||
|
||
SetCompileUnitAtIndex(dwarf_cu.GetID(), cu_sp); | ||
}; | ||
|
@@ -1675,20 +1675,20 @@ Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die, | |
|
||
CompileUnit * | ||
SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit &dwarf_cu) { | ||
|
||
if (dwarf_cu.IsDWOUnit()) { | ||
DWARFCompileUnit *non_dwo_cu = | ||
static_cast<DWARFCompileUnit *>(dwarf_cu.GetUserData()); | ||
DWARFCompileUnit *non_dwo_cu = dwarf_cu.GetSkeletonUnit(); | ||
assert(non_dwo_cu); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment explain why this assertion can hold - why |
||
return non_dwo_cu->GetSymbolFileDWARF().GetCompUnitForDWARFCompUnit( | ||
*non_dwo_cu); | ||
} | ||
// Check if the symbol vendor already knows about this compile unit? | ||
if (dwarf_cu.GetUserData() == nullptr) { | ||
// The symbol vendor doesn't know about this compile unit, we need to parse | ||
// and add it to the symbol vendor object. | ||
return ParseCompileUnit(dwarf_cu).get(); | ||
} | ||
return static_cast<CompileUnit *>(dwarf_cu.GetUserData()); | ||
CompileUnit *lldb_cu = dwarf_cu.GetLLDBCompUnit(); | ||
if (lldb_cu) | ||
return lldb_cu; | ||
// The symbol vendor doesn't know about this compile unit, we need to parse | ||
// and add it to the symbol vendor object. | ||
return ParseCompileUnit(dwarf_cu).get(); | ||
} | ||
|
||
void SymbolFileDWARF::GetObjCMethods( | ||
|
@@ -1750,7 +1750,7 @@ SymbolFileDWARF::GetDIE(const DIERef &die_ref) { | |
} | ||
|
||
if (*file_index == DIERef::k_file_index_mask) | ||
symbol_file = m_dwp_symfile.get(); // DWP case | ||
symbol_file = GetDwpSymbolFile().get(); // DWP case | ||
else | ||
symbol_file = this->DebugInfo() | ||
.GetUnitAtIndex(*die_ref.file_index()) | ||
|
@@ -1785,6 +1785,10 @@ std::optional<uint64_t> SymbolFileDWARF::GetDWOId() { | |
return {}; | ||
} | ||
|
||
DWARFUnit *SymbolFileDWARF::GetSkeletonUnit(DWARFUnit *dwo_unit) { | ||
return DebugInfo().GetSkeletonUnit(dwo_unit); | ||
} | ||
|
||
std::shared_ptr<SymbolFileDWARFDwo> | ||
SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( | ||
DWARFUnit &unit, const DWARFDebugInfoEntry &cu_die) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could at least LLDB_LOG the error into the dwarf channel?