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