[DWARF parser] Make DWARF parser more robust against missing compile/type units.

DWARF standard claims that each compilation/type unit header in
.debug_info/.debug_types section must be followed by corresponding
compile/type unit DIE, possibly with its children. Two situations
are possible:

 * compile/type unit DIE is missing because DWARF producer failed to
   emit it.
 * DWARF parser failed to parse unit DIE correctly, for instance if it
   contains some unsupported attributes (see r237721, for instance).

In either of these cases, the library, and the tools that use it
(llvm-dwarfdump, llvm-symbolizer) should not crash. Insert appropriate
checks to protect against this.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237733 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Alexey Samsonov
2015-05-19 21:54:32 +00:00
parent b9b3fb261e
commit 05f725eb67
6 changed files with 33 additions and 27 deletions

View File

@ -195,9 +195,8 @@ public:
BaseAddr = base_addr; BaseAddr = base_addr;
} }
const DWARFDebugInfoEntryMinimal * const DWARFDebugInfoEntryMinimal *getUnitDIE(bool ExtractUnitDIEOnly = true) {
getCompileUnitDIE(bool extract_cu_die_only = true) { extractDIEsIfNeeded(ExtractUnitDIEOnly);
extractDIEsIfNeeded(extract_cu_die_only);
return DieArray.empty() ? nullptr : &DieArray[0]; return DieArray.empty() ? nullptr : &DieArray[0];
} }
@ -226,8 +225,7 @@ public:
/// It is illegal to call this method with a DIE that hasn't be /// It is illegal to call this method with a DIE that hasn't be
/// created by this unit. In other word, it's illegal to call this /// created by this unit. In other word, it's illegal to call this
/// method on a DIE that isn't accessible by following /// method on a DIE that isn't accessible by following
/// children/sibling links starting from this unit's /// children/sibling links starting from this unit's getUnitDIE().
/// getCompileUnitDIE().
uint32_t getDIEIndex(const DWARFDebugInfoEntryMinimal *DIE) { uint32_t getDIEIndex(const DWARFDebugInfoEntryMinimal *DIE) {
assert(!DieArray.empty() && DIE >= &DieArray[0] && assert(!DieArray.empty() && DIE >= &DieArray[0] &&
DIE < &DieArray[0] + DieArray.size()); DIE < &DieArray[0] + DieArray.size());

View File

@ -22,9 +22,10 @@ void DWARFCompileUnit::dump(raw_ostream &OS) {
<< " (next unit at " << format("0x%08x", getNextUnitOffset()) << " (next unit at " << format("0x%08x", getNextUnitOffset())
<< ")\n"; << ")\n";
const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false); if (const DWARFDebugInfoEntryMinimal *CU = getUnitDIE(false))
assert(CU && "Null Compile Unit?");
CU->dump(OS, this, -1U); CU->dump(OS, this, -1U);
else
OS << "<compile unit can't be parsed!>\n\n";
} }
// VTable anchor. // VTable anchor.

View File

@ -140,8 +140,10 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
OS << "\n.debug_line contents:\n"; OS << "\n.debug_line contents:\n";
for (const auto &CU : compile_units()) { for (const auto &CU : compile_units()) {
savedAddressByteSize = CU->getAddressByteSize(); savedAddressByteSize = CU->getAddressByteSize();
unsigned stmtOffset = const auto *CUDIE = CU->getUnitDIE();
CU->getCompileUnitDIE()->getAttributeValueAsSectionOffset( if (CUDIE == nullptr)
continue;
unsigned stmtOffset = CUDIE->getAttributeValueAsSectionOffset(
CU.get(), DW_AT_stmt_list, -1U); CU.get(), DW_AT_stmt_list, -1U);
if (stmtOffset != -1U) { if (stmtOffset != -1U) {
DataExtractor lineData(getLineSection().Data, isLittleEndian(), DataExtractor lineData(getLineSection().Data, isLittleEndian(),
@ -321,13 +323,14 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
} }
const DWARFLineTable * const DWARFLineTable *
DWARFContext::getLineTableForUnit(DWARFUnit *cu) { DWARFContext::getLineTableForUnit(DWARFUnit *U) {
if (!Line) if (!Line)
Line.reset(new DWARFDebugLine(&getLineSection().Relocs)); Line.reset(new DWARFDebugLine(&getLineSection().Relocs));
const auto *UnitDIE = U->getUnitDIE();
if (UnitDIE == nullptr)
return nullptr;
unsigned stmtOffset = unsigned stmtOffset =
cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset( UnitDIE->getAttributeValueAsSectionOffset(U, DW_AT_stmt_list, -1U);
cu, DW_AT_stmt_list, -1U);
if (stmtOffset == -1U) if (stmtOffset == -1U)
return nullptr; // No line table for this compile unit. return nullptr; // No line table for this compile unit.
@ -337,7 +340,7 @@ DWARFContext::getLineTableForUnit(DWARFUnit *cu) {
// We have to parse it first. // We have to parse it first.
DataExtractor lineData(getLineSection().Data, isLittleEndian(), DataExtractor lineData(getLineSection().Data, isLittleEndian(),
cu->getAddressByteSize()); U->getAddressByteSize());
return Line->getOrParseLineTable(lineData, stmtOffset); return Line->getOrParseLineTable(lineData, stmtOffset);
} }

View File

@ -33,7 +33,8 @@ void DWARFTypeUnit::dump(raw_ostream &OS) {
<< " (next unit at " << format("0x%08x", getNextUnitOffset()) << " (next unit at " << format("0x%08x", getNextUnitOffset())
<< ")\n"; << ")\n";
const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false); if (const DWARFDebugInfoEntryMinimal *TU = getUnitDIE(false))
assert(CU && "Null Compile Unit?"); TU->dump(OS, this, -1U);
CU->dump(OS, this, -1U); else
OS << "<type unit can't be parsed!>\n\n";
} }

View File

@ -310,8 +310,11 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
} }
void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
// First, check if CU DIE describes address ranges for the unit. const auto *U = getUnitDIE();
const auto &CUDIERanges = getCompileUnitDIE()->getAddressRanges(this); if (U == nullptr)
return;
// First, check if unit DIE describes address ranges for the whole unit.
const auto &CUDIERanges = U->getAddressRanges(this);
if (!CUDIERanges.empty()) { if (!CUDIERanges.empty()) {
CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end()); CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end());
return; return;

View File

@ -729,7 +729,7 @@ void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
const DWARFSection &InputSec = Dwarf.getLocSection(); const DWARFSection &InputSec = Dwarf.getLocSection();
DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize); DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
DWARFUnit &OrigUnit = Unit.getOrigUnit(); DWARFUnit &OrigUnit = Unit.getOrigUnit();
const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false); const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
int64_t UnitPcOffset = 0; int64_t UnitPcOffset = 0;
uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress( uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
&OrigUnit, dwarf::DW_AT_low_pc, -1ULL); &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
@ -2203,7 +2203,7 @@ void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit,
OrigDwarf.isLittleEndian(), AddressSize); OrigDwarf.isLittleEndian(), AddressSize);
auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange; auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
DWARFUnit &OrigUnit = Unit.getOrigUnit(); DWARFUnit &OrigUnit = Unit.getOrigUnit();
const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false); const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress( uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
&OrigUnit, dwarf::DW_AT_low_pc, -1ULL); &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
// Ranges addresses are based on the unit's low_pc. Compute the // Ranges addresses are based on the unit's low_pc. Compute the
@ -2287,7 +2287,7 @@ static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
DWARFContext &OrigDwarf) { DWARFContext &OrigDwarf) {
const DWARFDebugInfoEntryMinimal *CUDie = const DWARFDebugInfoEntryMinimal *CUDie =
Unit.getOrigUnit().getCompileUnitDIE(); Unit.getOrigUnit().getUnitDIE();
uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset( uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset(
&Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -1ULL); &Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -1ULL);
if (StmtList == -1ULL) if (StmtList == -1ULL)
@ -2461,7 +2461,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
// In a first phase, just read in the debug info and store the DIE // In a first phase, just read in the debug info and store the DIE
// parent links that we will use during the next phase. // parent links that we will use during the next phase.
for (const auto &CU : DwarfContext.compile_units()) { for (const auto &CU : DwarfContext.compile_units()) {
auto *CUDie = CU->getCompileUnitDIE(false); auto *CUDie = CU->getUnitDIE(false);
if (Options.Verbose) { if (Options.Verbose) {
outs() << "Input compilation unit:"; outs() << "Input compilation unit:";
CUDie->dump(outs(), CU.get(), 0); CUDie->dump(outs(), CU.get(), 0);
@ -2476,7 +2476,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
// references require the ParentIdx to be setup for every CU in // references require the ParentIdx to be setup for every CU in
// the object file before calling this. // the object file before calling this.
for (auto &CurrentUnit : Units) for (auto &CurrentUnit : Units)
lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *Obj, lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
CurrentUnit, 0); CurrentUnit, 0);
// The calls to applyValidRelocs inside cloneDIE will walk the // The calls to applyValidRelocs inside cloneDIE will walk the
@ -2489,7 +2489,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
// to clone/emit. // to clone/emit.
if (!ValidRelocs.empty()) if (!ValidRelocs.empty())
for (auto &CurrentUnit : Units) { for (auto &CurrentUnit : Units) {
const auto *InputDIE = CurrentUnit.getOrigUnit().getCompileUnitDIE(); const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
CurrentUnit.setStartOffset(OutputDebugInfoSize); CurrentUnit.setStartOffset(OutputDebugInfoSize);
DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */, DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */,
11 /* Unit Header size */); 11 /* Unit Header size */);