|  | //===-- 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); | 
|  | } |