diff options
Diffstat (limited to 'contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp')
-rw-r--r-- | contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp b/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp new file mode 100644 index 0000000..591d4bd --- /dev/null +++ b/contrib/llvm/lib/DebugInfo/DWARFDebugAranges.cpp @@ -0,0 +1,152 @@ +//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFDebugAranges.h" +#include "DWARFCompileUnit.h" +#include "DWARFContext.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +using namespace llvm; + +void DWARFDebugAranges::extract(DataExtractor DebugArangesData) { + if (!DebugArangesData.isValidOffset(0)) + return; + uint32_t Offset = 0; + typedef std::vector<DWARFDebugArangeSet> RangeSetColl; + RangeSetColl Sets; + DWARFDebugArangeSet Set; + uint32_t TotalRanges = 0; + + while (Set.extract(DebugArangesData, &Offset)) { + Sets.push_back(Set); + TotalRanges += Set.getNumDescriptors(); + } + if (TotalRanges == 0) + return; + + Aranges.reserve(TotalRanges); + for (RangeSetColl::const_iterator I = Sets.begin(), E = Sets.end(); I != E; + ++I) { + uint32_t CUOffset = I->getCompileUnitDIEOffset(); + + for (uint32_t i = 0, n = I->getNumDescriptors(); i < n; ++i) { + const DWARFDebugArangeSet::Descriptor *ArangeDescPtr = + I->getDescriptor(i); + uint64_t LowPC = ArangeDescPtr->Address; + uint64_t HighPC = LowPC + ArangeDescPtr->Length; + appendRange(CUOffset, LowPC, HighPC); + } + } +} + +void DWARFDebugAranges::generate(DWARFContext *CTX) { + clear(); + if (!CTX) + return; + + // Extract aranges from .debug_aranges section. + DataExtractor ArangesData(CTX->getARangeSection(), CTX->isLittleEndian(), 0); + extract(ArangesData); + + // Generate aranges from DIEs: even if .debug_aranges section is present, + // it may describe only a small subset of compilation units, so we need to + // manually build aranges for the rest of them. + for (uint32_t i = 0, n = CTX->getNumCompileUnits(); i < n; ++i) { + if (DWARFCompileUnit *CU = CTX->getCompileUnitAtIndex(i)) { + uint32_t CUOffset = CU->getOffset(); + if (ParsedCUOffsets.insert(CUOffset).second) + CU->buildAddressRangeTable(this, true, CUOffset); + } + } + + sortAndMinimize(); +} + +void DWARFDebugAranges::appendRange(uint32_t CUOffset, uint64_t LowPC, + uint64_t HighPC) { + if (!Aranges.empty()) { + if (Aranges.back().CUOffset == CUOffset && + Aranges.back().HighPC() == LowPC) { + Aranges.back().setHighPC(HighPC); + return; + } + } + Aranges.push_back(Range(LowPC, HighPC, CUOffset)); +} + +void DWARFDebugAranges::sortAndMinimize() { + const size_t orig_arange_size = Aranges.size(); + // Size of one? If so, no sorting is needed + if (orig_arange_size <= 1) + return; + // Sort our address range entries + std::stable_sort(Aranges.begin(), Aranges.end()); + + // Most address ranges are contiguous from function to function + // so our new ranges will likely be smaller. We calculate the size + // of the new ranges since although std::vector objects can be resized, + // the will never reduce their allocated block size and free any excesss + // memory, so we might as well start a brand new collection so it is as + // small as possible. + + // First calculate the size of the new minimal arange vector + // so we don't have to do a bunch of re-allocations as we + // copy the new minimal stuff over to the new collection. + size_t minimal_size = 1; + for (size_t i = 1; i < orig_arange_size; ++i) { + if (!Range::SortedOverlapCheck(Aranges[i-1], Aranges[i])) + ++minimal_size; + } + + // If the sizes are the same, then no consecutive aranges can be + // combined, we are done. + if (minimal_size == orig_arange_size) + return; + + // Else, make a new RangeColl that _only_ contains what we need. + RangeColl minimal_aranges; + minimal_aranges.resize(minimal_size); + uint32_t j = 0; + minimal_aranges[j] = Aranges[0]; + for (size_t i = 1; i < orig_arange_size; ++i) { + if (Range::SortedOverlapCheck(minimal_aranges[j], Aranges[i])) { + minimal_aranges[j].setHighPC(Aranges[i].HighPC()); + } else { + // Only increment j if we aren't merging + minimal_aranges[++j] = Aranges[i]; + } + } + assert(j+1 == minimal_size); + + // Now swap our new minimal aranges into place. The local + // minimal_aranges will then contian the old big collection + // which will get freed. + minimal_aranges.swap(Aranges); +} + +uint32_t DWARFDebugAranges::findAddress(uint64_t Address) const { + if (!Aranges.empty()) { + Range range(Address); + RangeCollIterator begin = Aranges.begin(); + RangeCollIterator end = Aranges.end(); + RangeCollIterator pos = + std::lower_bound(begin, end, range); + + if (pos != end && pos->containsAddress(Address)) { + return pos->CUOffset; + } else if (pos != begin) { + --pos; + if (pos->containsAddress(Address)) + return pos->CUOffset; + } + } + return -1U; +} |