|  | //===-- 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; | 
|  |  | 
|  | // Compare function DWARFDebugAranges::Range structures | 
|  | static bool RangeLessThan(const DWARFDebugAranges::Range &range1, | 
|  | const DWARFDebugAranges::Range &range2) { | 
|  | return range1.LoPC < range2.LoPC; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | class CountArangeDescriptors { | 
|  | public: | 
|  | CountArangeDescriptors(uint32_t &count_ref) : Count(count_ref) {} | 
|  | void operator()(const DWARFDebugArangeSet &set) { | 
|  | Count += set.getNumDescriptors(); | 
|  | } | 
|  | uint32_t &Count; | 
|  | }; | 
|  |  | 
|  | class AddArangeDescriptors { | 
|  | public: | 
|  | AddArangeDescriptors(DWARFDebugAranges::RangeColl &ranges) | 
|  | : RangeCollection(ranges) {} | 
|  | void operator()(const DWARFDebugArangeSet& set) { | 
|  | const DWARFDebugArangeSet::Descriptor* arange_desc_ptr; | 
|  | DWARFDebugAranges::Range range; | 
|  | range.Offset = set.getCompileUnitDIEOffset(); | 
|  |  | 
|  | for (uint32_t i=0; (arange_desc_ptr = set.getDescriptor(i)) != NULL; ++i){ | 
|  | range.LoPC = arange_desc_ptr->Address; | 
|  | range.Length = arange_desc_ptr->Length; | 
|  |  | 
|  | // Insert each item in increasing address order so binary searching | 
|  | // can later be done! | 
|  | DWARFDebugAranges::RangeColl::iterator insert_pos = | 
|  | std::lower_bound(RangeCollection.begin(), RangeCollection.end(), | 
|  | range, RangeLessThan); | 
|  | RangeCollection.insert(insert_pos, range); | 
|  | } | 
|  | } | 
|  | DWARFDebugAranges::RangeColl& RangeCollection; | 
|  | }; | 
|  | } | 
|  |  | 
|  | bool DWARFDebugAranges::extract(DataExtractor debug_aranges_data) { | 
|  | if (debug_aranges_data.isValidOffset(0)) { | 
|  | uint32_t offset = 0; | 
|  |  | 
|  | typedef std::vector<DWARFDebugArangeSet> SetCollection; | 
|  | typedef SetCollection::const_iterator SetCollectionIter; | 
|  | SetCollection sets; | 
|  |  | 
|  | DWARFDebugArangeSet set; | 
|  | Range range; | 
|  | while (set.extract(debug_aranges_data, &offset)) | 
|  | sets.push_back(set); | 
|  |  | 
|  | uint32_t count = 0; | 
|  |  | 
|  | std::for_each(sets.begin(), sets.end(), CountArangeDescriptors(count)); | 
|  |  | 
|  | if (count > 0) { | 
|  | Aranges.reserve(count); | 
|  | AddArangeDescriptors range_adder(Aranges); | 
|  | std::for_each(sets.begin(), sets.end(), range_adder); | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool DWARFDebugAranges::generate(DWARFContext *ctx) { | 
|  | clear(); | 
|  | if (ctx) { | 
|  | const uint32_t num_compile_units = ctx->getNumCompileUnits(); | 
|  | for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { | 
|  | DWARFCompileUnit *cu = ctx->getCompileUnitAtIndex(cu_idx); | 
|  | if (cu) | 
|  | cu->buildAddressRangeTable(this, true); | 
|  | } | 
|  | } | 
|  | return !isEmpty(); | 
|  | } | 
|  |  | 
|  | void DWARFDebugAranges::dump(raw_ostream &OS) const { | 
|  | const uint32_t num_ranges = getNumRanges(); | 
|  | for (uint32_t i = 0; i < num_ranges; ++i) { | 
|  | const Range &range = Aranges[i]; | 
|  | OS << format("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.Offset, | 
|  | (uint64_t)range.LoPC, (uint64_t)range.HiPC()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void DWARFDebugAranges::Range::dump(raw_ostream &OS) const { | 
|  | OS << format("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", Offset, LoPC, HiPC()); | 
|  | } | 
|  |  | 
|  | void DWARFDebugAranges::appendRange(uint32_t offset, uint64_t low_pc, | 
|  | uint64_t high_pc) { | 
|  | if (!Aranges.empty()) { | 
|  | if (Aranges.back().Offset == offset && Aranges.back().HiPC() == low_pc) { | 
|  | Aranges.back().setHiPC(high_pc); | 
|  | return; | 
|  | } | 
|  | } | 
|  | Aranges.push_back(Range(low_pc, high_pc, offset)); | 
|  | } | 
|  |  | 
|  | void DWARFDebugAranges::sort(bool minimize, uint32_t n) { | 
|  | 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(), RangeLessThan); | 
|  |  | 
|  | if (!minimize) | 
|  | return; | 
|  |  | 
|  | // 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], n)) | 
|  | ++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], n)) { | 
|  | minimal_aranges[j].setHiPC (Aranges[i].HiPC()); | 
|  | } 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 = lower_bound(begin, end, range, RangeLessThan); | 
|  |  | 
|  | if (pos != end && pos->LoPC <= address && address < pos->HiPC()) { | 
|  | return pos->Offset; | 
|  | } else if (pos != begin) { | 
|  | --pos; | 
|  | if (pos->LoPC <= address && address < pos->HiPC()) | 
|  | return (*pos).Offset; | 
|  | } | 
|  | } | 
|  | return -1U; | 
|  | } | 
|  |  | 
|  | bool | 
|  | DWARFDebugAranges::allRangesAreContiguous(uint64_t &LoPC, uint64_t &HiPC) const{ | 
|  | if (Aranges.empty()) | 
|  | return false; | 
|  |  | 
|  | uint64_t next_addr = 0; | 
|  | RangeCollIterator begin = Aranges.begin(); | 
|  | for (RangeCollIterator pos = begin, end = Aranges.end(); pos != end; | 
|  | ++pos) { | 
|  | if (pos != begin && pos->LoPC != next_addr) | 
|  | return false; | 
|  | next_addr = pos->HiPC(); | 
|  | } | 
|  | // We checked for empty at the start of function so front() will be valid. | 
|  | LoPC = Aranges.front().LoPC; | 
|  | // We checked for empty at the start of function so back() will be valid. | 
|  | HiPC = Aranges.back().HiPC(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool DWARFDebugAranges::getMaxRange(uint64_t &LoPC, uint64_t &HiPC) const { | 
|  | if (Aranges.empty()) | 
|  | return false; | 
|  | // We checked for empty at the start of function so front() will be valid. | 
|  | LoPC = Aranges.front().LoPC; | 
|  | // We checked for empty at the start of function so back() will be valid. | 
|  | HiPC = Aranges.back().HiPC(); | 
|  | return true; | 
|  | } | 
|  |  |