| //===-- 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 <assert.h> |
| |
| #include <algorithm> |
| |
| #include "lldb/Core/Stream.h" |
| |
| #include "SymbolFileDWARF.h" |
| #include "DWARFDebugInfo.h" |
| #include "DWARFCompileUnit.h" |
| |
| using namespace lldb_private; |
| |
| //---------------------------------------------------------------------- |
| // Constructor |
| //---------------------------------------------------------------------- |
| DWARFDebugAranges::DWARFDebugAranges() : |
| m_aranges() |
| { |
| } |
| |
| |
| //---------------------------------------------------------------------- |
| // Compare function DWARFDebugAranges::Range structures |
| //---------------------------------------------------------------------- |
| static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2) |
| { |
| return range1.lo_pc < range2.lo_pc; |
| } |
| |
| //---------------------------------------------------------------------- |
| // CountArangeDescriptors |
| //---------------------------------------------------------------------- |
| class CountArangeDescriptors |
| { |
| public: |
| CountArangeDescriptors (uint32_t& count_ref) : count(count_ref) |
| { |
| // printf("constructor CountArangeDescriptors()\n"); |
| } |
| void operator() (const DWARFDebugArangeSet& set) |
| { |
| count += set.NumDescriptors(); |
| } |
| uint32_t& count; |
| }; |
| |
| //---------------------------------------------------------------------- |
| // AddArangeDescriptors |
| //---------------------------------------------------------------------- |
| class AddArangeDescriptors |
| { |
| public: |
| AddArangeDescriptors (DWARFDebugAranges::RangeColl& ranges) : range_collection(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.lo_pc = arange_desc_ptr->address; |
| range.hi_pc = arange_desc_ptr->address + arange_desc_ptr->length; |
| |
| // Insert each item in increasing address order so binary searching |
| // can later be done! |
| DWARFDebugAranges::RangeColl::iterator insert_pos = lower_bound(range_collection.begin(), range_collection.end(), range, RangeLessThan); |
| range_collection.insert(insert_pos, range); |
| } |
| } |
| DWARFDebugAranges::RangeColl& range_collection; |
| }; |
| |
| //---------------------------------------------------------------------- |
| // PrintRange |
| //---------------------------------------------------------------------- |
| static void PrintRange(const DWARFDebugAranges::Range& range) |
| { |
| // Cast the address values in case the address type is compiled as 32 bit |
| printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (long long)range.lo_pc, (long long)range.hi_pc); |
| } |
| |
| //---------------------------------------------------------------------- |
| // Extract |
| //---------------------------------------------------------------------- |
| bool |
| DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data) |
| { |
| if (debug_aranges_data.ValidOffset(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; |
| |
| for_each(sets.begin(), sets.end(), CountArangeDescriptors(count)); |
| |
| if (count > 0) |
| { |
| m_aranges.reserve(count); |
| AddArangeDescriptors range_adder(m_aranges); |
| for_each(sets.begin(), sets.end(), range_adder); |
| } |
| |
| // puts("\n\nDWARFDebugAranges list is:\n"); |
| // for_each(m_aranges.begin(), m_aranges.end(), PrintRange); |
| } |
| return false; |
| } |
| |
| //---------------------------------------------------------------------- |
| // Generate |
| //---------------------------------------------------------------------- |
| bool |
| DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data) |
| { |
| Clear(); |
| DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo(); |
| if (debug_info) |
| { |
| uint32_t cu_idx = 0; |
| const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits(); |
| for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) |
| { |
| DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx); |
| if (cu) |
| cu->DIE()->BuildAddressRangeTable(dwarf2Data, cu, this); |
| } |
| } |
| return !IsEmpty(); |
| } |
| |
| |
| void |
| DWARFDebugAranges::Print() const |
| { |
| puts("\n\nDWARFDebugAranges address range list is:\n"); |
| for_each(m_aranges.begin(), m_aranges.end(), PrintRange); |
| } |
| |
| |
| void |
| DWARFDebugAranges::Range::Dump(Stream *s) const |
| { |
| s->Printf("{0x%8.8x}: [0x%8.8llx - 0x%8.8llx)\n", offset, lo_pc, hi_pc); |
| } |
| |
| //---------------------------------------------------------------------- |
| // Dump |
| //---------------------------------------------------------------------- |
| //void |
| //DWARFDebugAranges::Dump(SymbolFileDWARF* dwarf2Data, Stream *s) |
| //{ |
| // const DataExtractor &debug_aranges_data = dwarf2Data->get_debug_aranges_data(); |
| // if (debug_aranges_data.ValidOffset(0)) |
| // { |
| // uint32_t offset = 0; |
| // |
| // DWARFDebugArangeSet set; |
| // while (set.Extract(debug_aranges_data, &offset)) |
| // set.Dump(s); |
| // } |
| // else |
| // s->PutCString("< EMPTY >\n"); |
| //} |
| // |
| |
| //---------------------------------------------------------------------- |
| // AppendDebugRanges |
| //---------------------------------------------------------------------- |
| //void |
| //DWARFDebugAranges::AppendDebugRanges(BinaryStreamBuf& debug_ranges, dw_addr_t cu_base_addr, uint32_t addr_size) const |
| //{ |
| // if (!m_aranges.empty()) |
| // { |
| // RangeCollIterator end = m_aranges.end(); |
| // RangeCollIterator pos; |
| // RangeCollIterator lo_pos = end; |
| // for (pos = m_aranges.begin(); pos != end; ++pos) |
| // { |
| // if (lo_pos == end) |
| // lo_pos = pos; |
| // |
| // RangeCollIterator next = pos + 1; |
| // if (next != end) |
| // { |
| // // Check to see if we can combine two consecutive ranges? |
| // if (pos->hi_pc == next->lo_pc) |
| // continue; // We can combine them! |
| // } |
| // |
| // if (cu_base_addr == 0 || cu_base_addr == DW_INVALID_ADDRESS) |
| // { |
| // debug_ranges.AppendMax64(lo_pos->lo_pc, addr_size); |
| // debug_ranges.AppendMax64(pos->hi_pc, addr_size); |
| // } |
| // else |
| // { |
| // assert(lo_pos->lo_pc >= cu_base_addr); |
| // assert(pos->hi_pc >= cu_base_addr); |
| // debug_ranges.AppendMax64(lo_pos->lo_pc - cu_base_addr, addr_size); |
| // debug_ranges.AppendMax64(pos->hi_pc - cu_base_addr, addr_size); |
| // } |
| // |
| // // Reset the low part of the next address range |
| // lo_pos = end; |
| // } |
| // } |
| // // Terminate the .debug_ranges with two zero addresses |
| // debug_ranges.AppendMax64(0, addr_size); |
| // debug_ranges.AppendMax64(0, addr_size); |
| // |
| //} |
| // |
| //---------------------------------------------------------------------- |
| // ArangeSetContainsAddress |
| //---------------------------------------------------------------------- |
| class ArangeSetContainsAddress |
| { |
| public: |
| ArangeSetContainsAddress (dw_addr_t the_address) : address(the_address), offset(DW_INVALID_OFFSET) {} |
| bool operator() (const DWARFDebugArangeSet& set) |
| { |
| offset = set.FindAddress(address); |
| return (offset != DW_INVALID_OFFSET); |
| } |
| const dw_addr_t address; |
| dw_offset_t offset; |
| }; |
| |
| |
| //---------------------------------------------------------------------- |
| // InsertRange |
| //---------------------------------------------------------------------- |
| void |
| DWARFDebugAranges::InsertRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) |
| { |
| // Insert each item in increasing address order so binary searching |
| // can later be done! |
| DWARFDebugAranges::Range range(low_pc, high_pc, offset); |
| InsertRange(range); |
| } |
| |
| //---------------------------------------------------------------------- |
| // InsertRange |
| //---------------------------------------------------------------------- |
| void |
| DWARFDebugAranges::InsertRange(const DWARFDebugAranges::Range& range) |
| { |
| // Insert each item in increasing address order so binary searching |
| // can later be done! |
| RangeColl::iterator insert_pos = lower_bound(m_aranges.begin(), m_aranges.end(), range, RangeLessThan); |
| m_aranges.insert(insert_pos, range); |
| } |
| |
| |
| void |
| DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc) |
| { |
| if (!m_aranges.empty()) |
| { |
| if (m_aranges.back().offset == offset && m_aranges.back().hi_pc == low_pc) |
| { |
| m_aranges.back().hi_pc = high_pc; |
| return; |
| } |
| } |
| m_aranges.push_back (DWARFDebugAranges::Range(low_pc, high_pc, offset)); |
| } |
| |
| void |
| DWARFDebugAranges::Sort() |
| { |
| // Sort our address range entries |
| std::stable_sort (m_aranges.begin(), m_aranges.end(), RangeLessThan); |
| |
| // Merge any entries that have the same offset and same start/end address |
| RangeColl::iterator pos = m_aranges.begin(); |
| RangeColl::iterator end = m_aranges.end(); |
| while (pos != end) |
| { |
| RangeColl::iterator next_pos = pos + 1; |
| if (next_pos != end && |
| pos->offset == next_pos->offset && |
| pos->hi_pc == next_pos->lo_pc) |
| { |
| // We have found an entry whose end address it he same as the |
| // next entry's start address and the offsets are the same so |
| // we can merge these two entries. |
| pos->hi_pc = next_pos->hi_pc; |
| // Erase the next entry that wasn't needed |
| pos = m_aranges.erase (next_pos); |
| // Now recompute the end of the collection |
| end = m_aranges.end(); |
| } |
| else |
| { |
| // Two entries have either different offsets or there are gaps |
| // in the address range, move along, nothing to see here. |
| pos = next_pos; |
| } |
| } |
| } |
| |
| //---------------------------------------------------------------------- |
| // FindAddress |
| //---------------------------------------------------------------------- |
| dw_offset_t |
| DWARFDebugAranges::FindAddress(dw_addr_t address) const |
| { |
| if ( !m_aranges.empty() ) |
| { |
| DWARFDebugAranges::Range range(address); |
| DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin(); |
| DWARFDebugAranges::RangeCollIterator end = m_aranges.end(); |
| DWARFDebugAranges::RangeCollIterator pos = lower_bound(begin, end, range, RangeLessThan); |
| |
| if ((pos != end) && (pos->lo_pc <= address && address < pos->hi_pc)) |
| { |
| // printf("FindAddress(1) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset); |
| return pos->offset; |
| } |
| else if (pos != begin) |
| { |
| --pos; |
| if ((pos->lo_pc <= address) && (address < pos->hi_pc)) |
| { |
| // printf("FindAddress(2) found 0x%8.8x in compile unit: 0x%8.8x\n", address, pos->offset); |
| return (*pos).offset; |
| } |
| } |
| } |
| return DW_INVALID_OFFSET; |
| } |
| |
| //---------------------------------------------------------------------- |
| // AllRangesAreContiguous |
| //---------------------------------------------------------------------- |
| bool |
| DWARFDebugAranges::AllRangesAreContiguous(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const |
| { |
| if (m_aranges.empty()) |
| return false; |
| |
| DWARFDebugAranges::RangeCollIterator begin = m_aranges.begin(); |
| DWARFDebugAranges::RangeCollIterator end = m_aranges.end(); |
| DWARFDebugAranges::RangeCollIterator pos; |
| dw_addr_t next_addr = 0; |
| |
| for (pos = begin; pos != end; ++pos) |
| { |
| if ((pos != begin) && (pos->lo_pc != next_addr)) |
| return false; |
| next_addr = pos->hi_pc; |
| } |
| lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid |
| hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid |
| return true; |
| } |
| |
| bool |
| DWARFDebugAranges::GetMaxRange(dw_addr_t& lo_pc, dw_addr_t& hi_pc) const |
| { |
| if (m_aranges.empty()) |
| return false; |
| |
| lo_pc = m_aranges.front().lo_pc; // We checked for empty at the start of function so front() will be valid |
| hi_pc = m_aranges.back().hi_pc; // We checked for empty at the start of function so back() will be valid |
| return true; |
| } |
| |