| //===-- DWARFCompileUnit.cpp ----------------------------------------------===// | 
 | // | 
 | //                     The LLVM Compiler Infrastructure | 
 | // | 
 | // This file is distributed under the University of Illinois Open Source | 
 | // License. See LICENSE.TXT for details. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "DWARFCompileUnit.h" | 
 | #include "DWARFContext.h" | 
 | #include "DWARFFormValue.h" | 
 | #include "llvm/Support/Dwarf.h" | 
 | #include "llvm/Support/Format.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | using namespace llvm; | 
 | using namespace dwarf; | 
 |  | 
 | DataExtractor DWARFCompileUnit::getDebugInfoExtractor() const { | 
 |   return DataExtractor(Context.getInfoSection(), | 
 |                        Context.isLittleEndian(), getAddressByteSize()); | 
 | } | 
 |  | 
 | bool DWARFCompileUnit::extract(DataExtractor debug_info, uint32_t *offset_ptr) { | 
 |   clear(); | 
 |  | 
 |   Offset = *offset_ptr; | 
 |  | 
 |   if (debug_info.isValidOffset(*offset_ptr)) { | 
 |     uint64_t abbrOffset; | 
 |     const DWARFDebugAbbrev *abbr = Context.getDebugAbbrev(); | 
 |     Length = debug_info.getU32(offset_ptr); | 
 |     Version = debug_info.getU16(offset_ptr); | 
 |     abbrOffset = debug_info.getU32(offset_ptr); | 
 |     AddrSize = debug_info.getU8(offset_ptr); | 
 |  | 
 |     bool lengthOK = debug_info.isValidOffset(getNextCompileUnitOffset()-1); | 
 |     bool versionOK = DWARFContext::isSupportedVersion(Version); | 
 |     bool abbrOffsetOK = Context.getAbbrevSection().size() > abbrOffset; | 
 |     bool addrSizeOK = AddrSize == 4 || AddrSize == 8; | 
 |  | 
 |     if (lengthOK && versionOK && addrSizeOK && abbrOffsetOK && abbr != NULL) { | 
 |       Abbrevs = abbr->getAbbreviationDeclarationSet(abbrOffset); | 
 |       return true; | 
 |     } | 
 |  | 
 |     // reset the offset to where we tried to parse from if anything went wrong | 
 |     *offset_ptr = Offset; | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | uint32_t | 
 | DWARFCompileUnit::extract(uint32_t offset, DataExtractor debug_info_data, | 
 |                           const DWARFAbbreviationDeclarationSet *abbrevs) { | 
 |   clear(); | 
 |  | 
 |   Offset = offset; | 
 |  | 
 |   if (debug_info_data.isValidOffset(offset)) { | 
 |     Length = debug_info_data.getU32(&offset); | 
 |     Version = debug_info_data.getU16(&offset); | 
 |     bool abbrevsOK = debug_info_data.getU32(&offset) == abbrevs->getOffset(); | 
 |     Abbrevs = abbrevs; | 
 |     AddrSize = debug_info_data.getU8 (&offset); | 
 |  | 
 |     bool versionOK = DWARFContext::isSupportedVersion(Version); | 
 |     bool addrSizeOK = AddrSize == 4 || AddrSize == 8; | 
 |  | 
 |     if (versionOK && addrSizeOK && abbrevsOK && | 
 |         debug_info_data.isValidOffset(offset)) | 
 |       return offset; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | void DWARFCompileUnit::clear() { | 
 |   Offset = 0; | 
 |   Length = 0; | 
 |   Version = 0; | 
 |   Abbrevs = 0; | 
 |   AddrSize = 0; | 
 |   BaseAddr = 0; | 
 |   DieArray.clear(); | 
 | } | 
 |  | 
 | void DWARFCompileUnit::dump(raw_ostream &OS) { | 
 |   OS << format("0x%08x", Offset) << ": Compile Unit:" | 
 |      << " length = " << format("0x%08x", Length) | 
 |      << " version = " << format("0x%04x", Version) | 
 |      << " abbr_offset = " << format("0x%04x", Abbrevs->getOffset()) | 
 |      << " addr_size = " << format("0x%02x", AddrSize) | 
 |      << " (next CU at " << format("0x%08x", getNextCompileUnitOffset()) | 
 |      << ")\n"; | 
 |  | 
 |   getCompileUnitDIE(false)->dump(OS, this, -1U); | 
 | } | 
 |  | 
 | void DWARFCompileUnit::setDIERelations() { | 
 |   if (DieArray.empty()) | 
 |     return; | 
 |   DWARFDebugInfoEntryMinimal *die_array_begin = &DieArray.front(); | 
 |   DWARFDebugInfoEntryMinimal *die_array_end = &DieArray.back(); | 
 |   DWARFDebugInfoEntryMinimal *curr_die; | 
 |   // We purposely are skipping the last element in the array in the loop below | 
 |   // so that we can always have a valid next item | 
 |   for (curr_die = die_array_begin; curr_die < die_array_end; ++curr_die) { | 
 |     // Since our loop doesn't include the last element, we can always | 
 |     // safely access the next die in the array. | 
 |     DWARFDebugInfoEntryMinimal *next_die = curr_die + 1; | 
 |  | 
 |     const DWARFAbbreviationDeclaration *curr_die_abbrev = | 
 |       curr_die->getAbbreviationDeclarationPtr(); | 
 |  | 
 |     if (curr_die_abbrev) { | 
 |       // Normal DIE | 
 |       if (curr_die_abbrev->hasChildren()) | 
 |         next_die->setParent(curr_die); | 
 |       else | 
 |         curr_die->setSibling(next_die); | 
 |     } else { | 
 |       // NULL DIE that terminates a sibling chain | 
 |       DWARFDebugInfoEntryMinimal *parent = curr_die->getParent(); | 
 |       if (parent) | 
 |         parent->setSibling(next_die); | 
 |     } | 
 |   } | 
 |  | 
 |   // Since we skipped the last element, we need to fix it up! | 
 |   if (die_array_begin < die_array_end) | 
 |     curr_die->setParent(die_array_begin); | 
 | } | 
 |  | 
 | size_t DWARFCompileUnit::extractDIEsIfNeeded(bool cu_die_only) { | 
 |   const size_t initial_die_array_size = DieArray.size(); | 
 |   if ((cu_die_only && initial_die_array_size > 0) || | 
 |       initial_die_array_size > 1) | 
 |     return 0; // Already parsed | 
 |  | 
 |   // Set the offset to that of the first DIE and calculate the start of the | 
 |   // next compilation unit header. | 
 |   uint32_t offset = getFirstDIEOffset(); | 
 |   uint32_t next_cu_offset = getNextCompileUnitOffset(); | 
 |  | 
 |   DWARFDebugInfoEntryMinimal die; | 
 |   // Keep a flat array of the DIE for binary lookup by DIE offset | 
 |   uint32_t depth = 0; | 
 |   // We are in our compile unit, parse starting at the offset | 
 |   // we were told to parse | 
 |  | 
 |   const uint8_t *fixed_form_sizes = | 
 |     DWARFFormValue::getFixedFormSizesForAddressSize(getAddressByteSize()); | 
 |  | 
 |   while (offset < next_cu_offset && | 
 |          die.extractFast(this, fixed_form_sizes, &offset)) { | 
 |  | 
 |     if (depth == 0) { | 
 |       uint64_t base_addr = | 
 |         die.getAttributeValueAsUnsigned(this, DW_AT_low_pc, -1U); | 
 |       if (base_addr == -1U) | 
 |         base_addr = die.getAttributeValueAsUnsigned(this, DW_AT_entry_pc, 0); | 
 |       setBaseAddress(base_addr); | 
 |     } | 
 |  | 
 |     if (cu_die_only) { | 
 |       addDIE(die); | 
 |       return 1; | 
 |     } | 
 |     else if (depth == 0 && initial_die_array_size == 1) { | 
 |       // Don't append the CU die as we already did that | 
 |     } else { | 
 |       addDIE (die); | 
 |     } | 
 |  | 
 |     const DWARFAbbreviationDeclaration *abbrDecl = | 
 |       die.getAbbreviationDeclarationPtr(); | 
 |     if (abbrDecl) { | 
 |       // Normal DIE | 
 |       if (abbrDecl->hasChildren()) | 
 |         ++depth; | 
 |     } else { | 
 |       // NULL DIE. | 
 |       if (depth > 0) | 
 |         --depth; | 
 |       if (depth == 0) | 
 |         break;  // We are done with this compile unit! | 
 |     } | 
 |  | 
 |   } | 
 |  | 
 |   // Give a little bit of info if we encounter corrupt DWARF (our offset | 
 |   // should always terminate at or before the start of the next compilation | 
 |   // unit header). | 
 |   if (offset > next_cu_offset) { | 
 |     fprintf (stderr, "warning: DWARF compile unit extends beyond its bounds cu 0x%8.8x at 0x%8.8x'\n", getOffset(), offset); | 
 |   } | 
 |  | 
 |   setDIERelations(); | 
 |   return DieArray.size(); | 
 | } | 
 |  | 
 | void DWARFCompileUnit::clearDIEs(bool keep_compile_unit_die) { | 
 |   if (DieArray.size() > 1) { | 
 |     // std::vectors never get any smaller when resized to a smaller size, | 
 |     // or when clear() or erase() are called, the size will report that it | 
 |     // is smaller, but the memory allocated remains intact (call capacity() | 
 |     // to see this). So we need to create a temporary vector and swap the | 
 |     // contents which will cause just the internal pointers to be swapped | 
 |     // so that when "tmp_array" goes out of scope, it will destroy the | 
 |     // contents. | 
 |  | 
 |     // Save at least the compile unit DIE | 
 |     std::vector<DWARFDebugInfoEntryMinimal> tmpArray; | 
 |     DieArray.swap(tmpArray); | 
 |     if (keep_compile_unit_die) | 
 |       DieArray.push_back(tmpArray.front()); | 
 |   } | 
 | } | 
 |  | 
 | void | 
 | DWARFCompileUnit::buildAddressRangeTable(DWARFDebugAranges *debug_aranges, | 
 |                                          bool clear_dies_if_already_not_parsed){ | 
 |   // This function is usually called if there in no .debug_aranges section | 
 |   // in order to produce a compile unit level set of address ranges that | 
 |   // is accurate. If the DIEs weren't parsed, then we don't want all dies for | 
 |   // all compile units to stay loaded when they weren't needed. So we can end | 
 |   // up parsing the DWARF and then throwing them all away to keep memory usage | 
 |   // down. | 
 |   const bool clear_dies = extractDIEsIfNeeded(false) > 1; | 
 |  | 
 |   DieArray[0].buildAddressRangeTable(this, debug_aranges); | 
 |  | 
 |   // Keep memory down by clearing DIEs if this generate function | 
 |   // caused them to be parsed. | 
 |   if (clear_dies) | 
 |     clearDIEs(true); | 
 | } |