Example #1
0
void DwarfVariableFinder::getInfo(const DWARFDie &die) {
  auto tagString = TagString(die.getTag());
  if (tagString.empty()) {
    outs() << format("DW_TAG_Unknown_%x", die.getTag());
  }
  auto formVal = die.find(dwarf::DW_AT_name);
  formVal->dump(outs());
}
Example #2
0
unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
                                        DieRangeInfo &ParentRI) {
  unsigned NumErrors = 0;

  if (!Die.isValid())
    return NumErrors;

  DWARFAddressRangesVector Ranges = Die.getAddressRanges();

  // Build RI for this DIE and check that ranges within this DIE do not
  // overlap.
  DieRangeInfo RI(Die);
  for (auto Range : Ranges) {
    if (!Range.valid()) {
      ++NumErrors;
      error() << "Invalid address range " << Range << "\n";
      continue;
    }

    // Verify that ranges don't intersect.
    const auto IntersectingRange = RI.insert(Range);
    if (IntersectingRange != RI.Ranges.end()) {
      ++NumErrors;
      error() << "DIE has overlapping address ranges: " << Range << " and "
              << *IntersectingRange << "\n";
      break;
    }
  }

  // Verify that children don't intersect.
  const auto IntersectingChild = ParentRI.insert(RI);
  if (IntersectingChild != ParentRI.Children.end()) {
    ++NumErrors;
    error() << "DIEs have overlapping address ranges:";
    Die.dump(OS, 0);
    IntersectingChild->Die.dump(OS, 0);
    OS << "\n";
  }

  // Verify that ranges are contained within their parent.
  bool ShouldBeContained = !Ranges.empty() && !ParentRI.Ranges.empty() &&
                           !(Die.getTag() == DW_TAG_subprogram &&
                             ParentRI.Die.getTag() == DW_TAG_subprogram);
  if (ShouldBeContained && !ParentRI.contains(RI)) {
    ++NumErrors;
    error() << "DIE address ranges are not "
               "contained in its parent's ranges:";
    Die.dump(OS, 0);
    ParentRI.Die.dump(OS, 0);
    OS << "\n";
  }

  // Recursively check children.
  for (DWARFDie Child : Die)
    NumErrors += verifyDieRanges(Child, RI);

  return NumErrors;
}
Example #3
0
bool DWARFVerifier::verifyUnitContents(DWARFUnit Unit, uint8_t UnitType) {
  uint32_t NumUnitErrors = 0;
  unsigned NumDies = Unit.getNumDIEs();
  for (unsigned I = 0; I < NumDies; ++I) {
    auto Die = Unit.getDIEAtIndex(I);
    if (Die.getTag() == DW_TAG_null)
      continue;
    for (auto AttrValue : Die.attributes()) {
      NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
      NumUnitErrors += verifyDebugInfoForm(Die, AttrValue);
    }
  }

  DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
  if (!Die) {
    error() << "Compilation unit without DIE.\n";
    NumUnitErrors++;
    return NumUnitErrors == 0;
  }

  if (!dwarf::isUnitType(Die.getTag())) {
    error() << "Compilation unit root DIE is not a unit DIE: "
            << dwarf::TagString(Die.getTag()) << ".\n";
    NumUnitErrors++;
  }

  if (UnitType != 0 &&
      !DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
    error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
            << ") and root DIE (" << dwarf::TagString(Die.getTag())
            << ") do not match.\n";
    NumUnitErrors++;
  }

  DieRangeInfo RI;
  NumUnitErrors += verifyDieRanges(Die, RI);

  return NumUnitErrors == 0;
}
Example #4
0
/// Recursively dump the DIE type name when applicable.
static void dumpTypeName(raw_ostream &OS, const DWARFDie &Die) {
  DWARFDie D = Die.getAttributeValueAsReferencedDie(DW_AT_type);

  if (!D.isValid())
    return;

  if (const char *Name = D.getName(DINameKind::LinkageName)) {
    OS << Name;
    return;
  }

  // FIXME: We should have pretty printers per language. Currently we print
  // everything as if it was C++ and fall back to the TAG type name.
  const dwarf::Tag T = D.getTag();
  switch (T) {
  case DW_TAG_array_type:
  case DW_TAG_pointer_type:
  case DW_TAG_ptr_to_member_type:
  case DW_TAG_reference_type:
  case DW_TAG_rvalue_reference_type:
    break;
  default:
    dumpTypeTagName(OS, T);
  }

  // Follow the DW_AT_type if possible.
  dumpTypeName(OS, D);

  switch (T) {
  case DW_TAG_array_type:
    OS << "[]";
    break;
  case DW_TAG_pointer_type:
    OS << '*';
    break;
  case DW_TAG_ptr_to_member_type:
    OS << '*';
    break;
  case DW_TAG_reference_type:
    OS << '&';
    break;
  case DW_TAG_rvalue_reference_type:
    OS << "&&";
    break;
  default:
    break;
  }
}
Example #5
0
static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE,
                                          bool IncludeLinkageName = true) {
  SmallVector<StringRef, 2> Result;
  if (const char *Str = DIE.getName(DINameKind::ShortName))
    Result.emplace_back(Str);
  else if (DIE.getTag() == dwarf::DW_TAG_namespace)
    Result.emplace_back("(anonymous namespace)");

  if (IncludeLinkageName) {
    if (const char *Str = DIE.getName(DINameKind::LinkageName)) {
      if (Result.empty() || Result[0] != Str)
        Result.emplace_back(Str);
    }
  }

  return Result;
}
Example #6
0
void
DWARFUnit::getInlinedChainForAddress(uint64_t Address,
                                     SmallVectorImpl<DWARFDie> &InlinedChain) {
  assert(InlinedChain.empty());
  // Try to look for subprogram DIEs in the DWO file.
  parseDWO();
  // First, find the subroutine that contains the given address (the leaf
  // of inlined chain).
  DWARFDie SubroutineDIE =
      (DWO ? DWO.get() : this)->getSubroutineForAddress(Address);

  if (!SubroutineDIE)
    return;

  while (!SubroutineDIE.isSubprogramDIE()) {
    if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine)
      InlinedChain.push_back(SubroutineDIE);
    SubroutineDIE  = SubroutineDIE.getParent();
  }
  InlinedChain.push_back(SubroutineDIE);
}
Example #7
0
std::shared_ptr<TypeInfo> DwarfVariableFinder::makeType(const DWARFDie &die) {

  if (!die.isValid()) {
    return std::make_shared<TypeInfo>("", ~0u);
  }
  auto opSize = die.find(dwarf::DW_AT_byte_size);
  unsigned size = 1;
  if(opSize.hasValue()) {
    size = opSize.getValue().getAsUnsignedConstant().getValue();  
  }

  std::string type_encoding = "";
  raw_string_ostream SS(type_encoding);

  switch (die.getTag()) {
    case dwarf::DW_TAG_base_type: {  
                                    auto opForm = die.find(dwarf::DW_AT_encoding);
                                    auto opEnc = opForm->getAsUnsignedConstant();
                                    assert(opEnc < HANDLE_DW_ATE_SIZE);
                                    SS << HANDLE_DW_ATE[*opEnc];
                                    opForm = die.find(dwarf::DW_AT_name);
                                    opForm->dump(SS);
                                    return std::make_shared<TypeInfo>(SS.str(), size);
                                  }
    case dwarf::DW_TAG_reference_type:
    case dwarf::DW_TAG_rvalue_reference_type:
    case dwarf::DW_TAG_pointer_type: {
                                       auto baseType = getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type));
                                       SS <<  "*" << baseType->getName();
                                       return std::make_shared<TypeInfo>(SS.str(), size);
                                     }
    case dwarf::DW_TAG_array_type: {
                                     auto baseType = getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type));
                                     SS << baseType->getName();
                                     size *= baseType->getSize();

                                     for (auto childDie = die.getFirstChild(); childDie && childDie.getTag(); 
                                         childDie = childDie.getSibling()) {
                                       std::shared_ptr<TypeInfo> rangeInfo = makeType(childDie);
                                       SS << "[";
                                       SS <<  rangeInfo->getName();
                                       SS << "]";
                                       size *= rangeInfo->getSize();
                                     }
                                     return std::make_shared<TypeInfo>(SS.str(), size);
                                   }
    case dwarf::DW_TAG_subrange_type: {
                                        uint64_t count = 0;
                                        auto opCount = die.find(dwarf::DW_AT_count);
                                        if(opCount.hasValue()) {
                                          count = opCount.getValue().getAsUnsignedConstant().getValue();
                                        } else {
                                          opCount = die.find(dwarf::DW_AT_upper_bound);
                                          assert(opCount.hasValue());
                                          count = opCount.getValue().getAsUnsignedConstant().getValue()  +1;
                                        }
                                        return std::make_shared<TypeInfo>(std::to_string(count), count);
                                      }
    case dwarf::DW_TAG_typedef: {
                                  return getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type));
                                }

    case dwarf::DW_TAG_structure_type:
    case dwarf::DW_TAG_class_type:
    case dwarf::DW_TAG_union_type: {
                                     SS << "struct" << dwarf::toString(die.find(dwarf::DW_AT_name), "None");
                                     auto structType = std::make_shared<TypeInfo>(SS.str(), size);

                                     // Add subentries for various pieces of the struct.
                                     for (auto childDie = die.getFirstChild(); childDie && childDie.getTag(); childDie = childDie.getSibling()) {
                                       if (childDie.getTag() != dwarf::DW_TAG_inheritance &&
                                           childDie.getTag() != dwarf::DW_TAG_member) {
                                         continue;
                                       }
                                       uint64_t dataMemOffset = dwarf::toUnsigned(childDie.find(dwarf::DW_AT_data_member_location), ~0U);
                                       structType->getFields().emplace_back(makeType(childDie), dataMemOffset);
                                     }
                                     return structType;
                                   }

    case dwarf::DW_TAG_inheritance:
    case dwarf::DW_TAG_member: {
                                 return getType(die.getAttributeValueAsReferencedDie(dwarf::DW_AT_type));
                               }        

    default: {
               auto tagString = TagString(die.getTag());
               if (tagString.empty()) {
                 llvm::errs() << format("DW_TAG_Unknown_%x", die.getTag());
               }
               die.dump(llvm::errs(), 10);
               return std::make_shared<TypeInfo>("", ~0u);
             }
  }
}
Example #8
0
/// Recursively dump the DIE type name when applicable.
static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) {
  if (!D.isValid())
    return;

  if (const char *Name = D.getName(DINameKind::LinkageName)) {
    OS << Name;
    return;
  }

  // FIXME: We should have pretty printers per language. Currently we print
  // everything as if it was C++ and fall back to the TAG type name.
  const dwarf::Tag T = D.getTag();
  switch (T) {
  case DW_TAG_array_type:
  case DW_TAG_pointer_type:
  case DW_TAG_ptr_to_member_type:
  case DW_TAG_reference_type:
  case DW_TAG_rvalue_reference_type:
  case DW_TAG_subroutine_type:
    break;
  default:
    dumpTypeTagName(OS, T);
  }

  // Follow the DW_AT_type if possible.
  DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type);
  dumpTypeName(OS, TypeDie);

  switch (T) {
  case DW_TAG_subroutine_type: {
    if (!TypeDie)
      OS << "void";
    OS << '(';
    bool First = true;
    for (const DWARFDie &C : D.children()) {
      if (C.getTag() == DW_TAG_formal_parameter) {
        if (!First)
          OS << ", ";
        First = false;
        dumpTypeName(OS, C.getAttributeValueAsReferencedDie(DW_AT_type));
      }
    }
    OS << ')';
    break;
  }
  case DW_TAG_array_type: {
    dumpArrayType(OS, D);
    break;
  }
  case DW_TAG_pointer_type:
    OS << '*';
    break;
  case DW_TAG_ptr_to_member_type:
    if (DWARFDie Cont =
            D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) {
      dumpTypeName(OS << ' ', Cont);
      OS << "::";
    }
    OS << '*';
    break;
  case DW_TAG_reference_type:
    OS << '&';
    break;
  case DW_TAG_rvalue_reference_type:
    OS << "&&";
    break;
  default:
    break;
  }
}
Example #9
0
unsigned DWARFVerifier::verifyNameIndexCompleteness(
    const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) {

  // First check, if the Die should be indexed. The code follows the DWARF v5
  // wording as closely as possible.

  // "All non-defining declarations (that is, debugging information entries
  // with a DW_AT_declaration attribute) are excluded."
  if (Die.find(DW_AT_declaration))
    return 0;

  // "DW_TAG_namespace debugging information entries without a DW_AT_name
  // attribute are included with the name “(anonymous namespace)”.
  // All other debugging information entries without a DW_AT_name attribute
  // are excluded."
  // "If a subprogram or inlined subroutine is included, and has a
  // DW_AT_linkage_name attribute, there will be an additional index entry for
  // the linkage name."
  auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram ||
                            Die.getTag() == DW_TAG_inlined_subroutine;
  auto EntryNames = getNames(Die, IncludeLinkageName);
  if (EntryNames.empty())
    return 0;

  // We deviate from the specification here, which says:
  // "The name index must contain an entry for each debugging information entry
  // that defines a named subprogram, label, variable, type, or namespace,
  // subject to ..."
  // Instead whitelisting all TAGs representing a "type" or a "subprogram", to
  // make sure we catch any missing items, we instead blacklist all TAGs that we
  // know shouldn't be indexed.
  switch (Die.getTag()) {
  // Compile units and modules have names but shouldn't be indexed.
  case DW_TAG_compile_unit:
  case DW_TAG_module:
    return 0;

  // Function and template parameters are not globally visible, so we shouldn't
  // index them.
  case DW_TAG_formal_parameter:
  case DW_TAG_template_value_parameter:
  case DW_TAG_template_type_parameter:
  case DW_TAG_GNU_template_parameter_pack:
  case DW_TAG_GNU_template_template_param:
    return 0;

  // Object members aren't globally visible.
  case DW_TAG_member:
    return 0;

  // According to a strict reading of the specification, enumerators should not
  // be indexed (and LLVM currently does not do that). However, this causes
  // problems for the debuggers, so we may need to reconsider this.
  case DW_TAG_enumerator:
    return 0;

  // Imported declarations should not be indexed according to the specification
  // and LLVM currently does not do that.
  case DW_TAG_imported_declaration:
    return 0;

  // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging
  // information entries without an address attribute (DW_AT_low_pc,
  // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded."
  case DW_TAG_subprogram:
  case DW_TAG_inlined_subroutine:
  case DW_TAG_label:
    if (Die.findRecursively(
            {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
      break;
    return 0;

  // "DW_TAG_variable debugging information entries with a DW_AT_location
  // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are
  // included; otherwise, they are excluded."
  //
  // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list.
  case DW_TAG_variable:
    if (isVariableIndexable(Die, DCtx))
      break;
    return 0;

  default:
    break;
  }

  // Now we know that our Die should be present in the Index. Let's check if
  // that's the case.
  unsigned NumErrors = 0;
  uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset();
  for (StringRef Name : EntryNames) {
    if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) {
          return E.getDIEUnitOffset() == DieUnitOffset;
        })) {
      error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
                         "name {3} missing.\n",
                         NI.getUnitOffset(), Die.getOffset(), Die.getTag(),
                         Name);
      ++NumErrors;
    }
  }
  return NumErrors;
}
Example #10
0
unsigned DWARFVerifier::verifyNameIndexEntries(
    const DWARFDebugNames::NameIndex &NI,
    const DWARFDebugNames::NameTableEntry &NTE) {
  // Verifying type unit indexes not supported.
  if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0)
    return 0;

  const char *CStr = NTE.getString();
  if (!CStr) {
    error() << formatv(
        "Name Index @ {0:x}: Unable to get string associated with name {1}.\n",
        NI.getUnitOffset(), NTE.getIndex());
    return 1;
  }
  StringRef Str(CStr);

  unsigned NumErrors = 0;
  unsigned NumEntries = 0;
  uint32_t EntryID = NTE.getEntryOffset();
  uint32_t NextEntryID = EntryID;
  Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID);
  for (; EntryOr; ++NumEntries, EntryID = NextEntryID,
                                EntryOr = NI.getEntry(&NextEntryID)) {
    uint32_t CUIndex = *EntryOr->getCUIndex();
    if (CUIndex > NI.getCUCount()) {
      error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
                         "invalid CU index ({2}).\n",
                         NI.getUnitOffset(), EntryID, CUIndex);
      ++NumErrors;
      continue;
    }
    uint32_t CUOffset = NI.getCUOffset(CUIndex);
    uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset();
    DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset);
    if (!DIE) {
      error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
                         "non-existing DIE @ {2:x}.\n",
                         NI.getUnitOffset(), EntryID, DIEOffset);
      ++NumErrors;
      continue;
    }
    if (DIE.getDwarfUnit()->getOffset() != CUOffset) {
      error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
                         "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
                         NI.getUnitOffset(), EntryID, DIEOffset, CUOffset,
                         DIE.getDwarfUnit()->getOffset());
      ++NumErrors;
    }
    if (DIE.getTag() != EntryOr->tag()) {
      error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
                         "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
                         NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(),
                         DIE.getTag());
      ++NumErrors;
    }

    auto EntryNames = getNames(DIE);
    if (!is_contained(EntryNames, Str)) {
      error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
                         "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
                         NI.getUnitOffset(), EntryID, DIEOffset, Str,
                         make_range(EntryNames.begin(), EntryNames.end()));
      ++NumErrors;
    }
  }
  handleAllErrors(EntryOr.takeError(),
                  [&](const DWARFDebugNames::SentinelError &) {
                    if (NumEntries > 0)
                      return;
                    error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is "
                                       "not associated with any entries.\n",
                                       NI.getUnitOffset(), NTE.getIndex(), Str);
                    ++NumErrors;
                  },
                  [&](const ErrorInfoBase &Info) {
                    error()
                        << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n",
                                   NI.getUnitOffset(), NTE.getIndex(), Str,
                                   Info.message());
                    ++NumErrors;
                  });
  return NumErrors;
}