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