DWARFDebugAranges.cpp [plain text]
#include "DWARFDebugAranges.h"
#include <assert.h>
#include <stdio.h>
#include <algorithm>
#include "lldb/Core/Stream.h"
#include "lldb/Core/Timer.h"
#include "SymbolFileDWARF.h"
#include "DWARFDebugInfo.h"
#include "DWARFCompileUnit.h"
using namespace lldb_private;
DWARFDebugAranges::DWARFDebugAranges() :
m_aranges()
{
}
static bool RangeLessThan (const DWARFDebugAranges::Range& range1, const DWARFDebugAranges::Range& range2)
{
return range1.lo_pc < range2.lo_pc;
}
class CountArangeDescriptors
{
public:
CountArangeDescriptors (uint32_t& count_ref) : count(count_ref)
{
}
void operator() (const DWARFDebugArangeSet& set)
{
count += set.NumDescriptors();
}
uint32_t& count;
};
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;
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;
};
static void PrintRange(const DWARFDebugAranges::Range& range)
{
printf("0x%8.8x: [0x%8.8llx - 0x%8.8llx)\n", range.offset, (long long)range.lo_pc, (long long)range.hi_pc);
}
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);
}
}
return false;
}
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);
}
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;
};
void
DWARFDebugAranges::InsertRange(dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
{
DWARFDebugAranges::Range range(low_pc, high_pc, offset);
InsertRange(range);
}
void
DWARFDebugAranges::InsertRange(const DWARFDebugAranges::Range& range)
{
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()
{
Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
__PRETTY_FUNCTION__, this);
std::stable_sort (m_aranges.begin(), m_aranges.end(), RangeLessThan);
const size_t old_size = m_aranges.size();
std::vector<size_t> merged;
for (size_t merge, cursor = 1; cursor < old_size; ++cursor)
{
merge = cursor - 1;
Range &r1 = m_aranges[merge];
Range &r2 = m_aranges[cursor];
if (r1.hi_pc == r2.lo_pc && r1.offset == r2.offset)
{
r2.lo_pc = r1.lo_pc;
merged.push_back(merge);
}
}
if (merged.empty())
return;
const size_t new_size = old_size - merged.size();
for (size_t i = 0, src = 0, dst = 0; dst < new_size; ++src, ++dst)
{
while (src == merged[i]) {
++src;
++i;
}
if (src == dst)
continue;
m_aranges[dst] = m_aranges[src];
}
m_aranges.resize(new_size);
}
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))
{
return pos->offset;
}
else if (pos != begin)
{
--pos;
if ((pos->lo_pc <= address) && (address < pos->hi_pc))
{
return (*pos).offset;
}
}
}
return DW_INVALID_OFFSET;
}
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; hi_pc = m_aranges.back().hi_pc; 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; hi_pc = m_aranges.back().hi_pc; return true;
}