[DWARF parser] Make DWARF parser more robust against missing compile/type units.
authorAlexey Samsonov <vonosmas@gmail.com>
Tue, 19 May 2015 21:54:32 +0000 (21:54 +0000)
committerAlexey Samsonov <vonosmas@gmail.com>
Tue, 19 May 2015 21:54:32 +0000 (21:54 +0000)
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

include/llvm/DebugInfo/DWARF/DWARFUnit.h
lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
lib/DebugInfo/DWARF/DWARFContext.cpp
lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
lib/DebugInfo/DWARF/DWARFUnit.cpp
tools/dsymutil/DwarfLinker.cpp

index 2b377a9ad2fb73d7191e6287b35886eaa9bb7d25..5604b93f220587cb1b40bbfcbc4de6debd889332 100644 (file)
@@ -195,9 +195,8 @@ public:
     BaseAddr = base_addr;
   }
 
-  const DWARFDebugInfoEntryMinimal *
-  getCompileUnitDIE(bool extract_cu_die_only = true) {
-    extractDIEsIfNeeded(extract_cu_die_only);
+  const DWARFDebugInfoEntryMinimal *getUnitDIE(bool ExtractUnitDIEOnly = true) {
+    extractDIEsIfNeeded(ExtractUnitDIEOnly);
     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
   /// created by this unit. In other word, it's illegal to call this
   /// method on a DIE that isn't accessible by following
-  /// children/sibling links starting from this unit's
-  /// getCompileUnitDIE().
+  /// children/sibling links starting from this unit's getUnitDIE().
   uint32_t getDIEIndex(const DWARFDebugInfoEntryMinimal *DIE) {
     assert(!DieArray.empty() && DIE >= &DieArray[0] &&
            DIE < &DieArray[0] + DieArray.size());
index 01e724799ab25152e0971685c613a9fc9e7a6281..39a7c772dc76f4d65c9d2499f230ab44c4814ad5 100644 (file)
@@ -22,9 +22,10 @@ void DWARFCompileUnit::dump(raw_ostream &OS) {
      << " (next unit at " << format("0x%08x", getNextUnitOffset())
      << ")\n";
 
-  const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false);
-  assert(CU && "Null Compile Unit?");
-  CU->dump(OS, this, -1U);
+  if (const DWARFDebugInfoEntryMinimal *CU = getUnitDIE(false))
+    CU->dump(OS, this, -1U);
+  else
+    OS << "<compile unit can't be parsed!>\n\n";
 }
 
 // VTable anchor.
index 3b427007e59e839c8cfcc289322fd606d8d2aa60..1faa2ba5921d562005b70b9b0f4493cba4d12faa 100644 (file)
@@ -140,9 +140,11 @@ void DWARFContext::dump(raw_ostream &OS, DIDumpType DumpType) {
     OS << "\n.debug_line contents:\n";
     for (const auto &CU : compile_units()) {
       savedAddressByteSize = CU->getAddressByteSize();
-      unsigned stmtOffset =
-          CU->getCompileUnitDIE()->getAttributeValueAsSectionOffset(
-              CU.get(), DW_AT_stmt_list, -1U);
+      const auto *CUDIE = CU->getUnitDIE();
+      if (CUDIE == nullptr)
+        continue;
+      unsigned stmtOffset = CUDIE->getAttributeValueAsSectionOffset(
+          CU.get(), DW_AT_stmt_list, -1U);
       if (stmtOffset != -1U) {
         DataExtractor lineData(getLineSection().Data, isLittleEndian(),
                                savedAddressByteSize);
@@ -321,13 +323,14 @@ const DWARFDebugFrame *DWARFContext::getDebugFrame() {
 }
 
 const DWARFLineTable *
-DWARFContext::getLineTableForUnit(DWARFUnit *cu) {
+DWARFContext::getLineTableForUnit(DWARFUnit *U) {
   if (!Line)
     Line.reset(new DWARFDebugLine(&getLineSection().Relocs));
-
+  const auto *UnitDIE = U->getUnitDIE();
+  if (UnitDIE == nullptr)
+    return nullptr;
   unsigned stmtOffset =
-      cu->getCompileUnitDIE()->getAttributeValueAsSectionOffset(
-          cu, DW_AT_stmt_list, -1U);
+      UnitDIE->getAttributeValueAsSectionOffset(U, DW_AT_stmt_list, -1U);
   if (stmtOffset == -1U)
     return nullptr; // No line table for this compile unit.
 
@@ -337,7 +340,7 @@ DWARFContext::getLineTableForUnit(DWARFUnit *cu) {
 
   // We have to parse it first.
   DataExtractor lineData(getLineSection().Data, isLittleEndian(),
-                         cu->getAddressByteSize());
+                         U->getAddressByteSize());
   return Line->getOrParseLineTable(lineData, stmtOffset);
 }
 
index 65c7bff0990de70e7050671e6665988430e1e83e..766e8ac16f0ccdfb41b639cd457dd09acf2c3fb4 100644 (file)
@@ -33,7 +33,8 @@ void DWARFTypeUnit::dump(raw_ostream &OS) {
      << " (next unit at " << format("0x%08x", getNextUnitOffset())
      << ")\n";
 
-  const DWARFDebugInfoEntryMinimal *CU = getCompileUnitDIE(false);
-  assert(CU && "Null Compile Unit?");
-  CU->dump(OS, this, -1U);
+  if (const DWARFDebugInfoEntryMinimal *TU = getUnitDIE(false))
+    TU->dump(OS, this, -1U);
+  else
+    OS << "<type unit can't be parsed!>\n\n";
 }
index 406915a9e4c722333245568c8144bb1eee127f25..63a9985555140a132abf16c22fd8b5282292aaef 100644 (file)
@@ -310,8 +310,11 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
 }
 
 void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
-  // First, check if CU DIE describes address ranges for the unit.
-  const auto &CUDIERanges = getCompileUnitDIE()->getAddressRanges(this);
+  const auto *U = getUnitDIE();
+  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()) {
     CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end());
     return;
index e4046e7e720ff5c391556b432372297ac3e4abae..33f8606509e2294d99dbe07ecbfb45972537a8d6 100644 (file)
@@ -729,7 +729,7 @@ void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
   const DWARFSection &InputSec = Dwarf.getLocSection();
   DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
   DWARFUnit &OrigUnit = Unit.getOrigUnit();
-  const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false);
+  const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
   int64_t UnitPcOffset = 0;
   uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
       &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
@@ -2203,7 +2203,7 @@ void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit,
                                OrigDwarf.isLittleEndian(), AddressSize);
   auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
   DWARFUnit &OrigUnit = Unit.getOrigUnit();
-  const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false);
+  const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
   uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
       &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
   // 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,
                                         DWARFContext &OrigDwarf) {
   const DWARFDebugInfoEntryMinimal *CUDie =
-      Unit.getOrigUnit().getCompileUnitDIE();
+      Unit.getOrigUnit().getUnitDIE();
   uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset(
       &Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -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
     // parent links that we will use during the next phase.
     for (const auto &CU : DwarfContext.compile_units()) {
-      auto *CUDie = CU->getCompileUnitDIE(false);
+      auto *CUDie = CU->getUnitDIE(false);
       if (Options.Verbose) {
         outs() << "Input compilation unit:";
         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
     // the object file before calling this.
     for (auto &CurrentUnit : Units)
-      lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *Obj,
+      lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
                         CurrentUnit, 0);
 
     // The calls to applyValidRelocs inside cloneDIE will walk the
@@ -2489,7 +2489,7 @@ bool DwarfLinker::link(const DebugMap &Map) {
     // to clone/emit.
     if (!ValidRelocs.empty())
       for (auto &CurrentUnit : Units) {
-        const auto *InputDIE = CurrentUnit.getOrigUnit().getCompileUnitDIE();
+        const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
         CurrentUnit.setStartOffset(OutputDebugInfoSize);
         DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */,
                                   11 /* Unit Header size */);