//===-- 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 <stdio.h>
#include <algorithm>
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/Timer.h"
#include "LogChannelDWARF.h"
#include "SymbolFileDWARF.h"
#include "DWARFDebugInfo.h"
#include "DWARFCompileUnit.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------
DWARFDebugAranges::DWARFDebugAranges() :
m_aranges()
{
}
//----------------------------------------------------------------------
// 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;
};
//----------------------------------------------------------------------
// Extract
//----------------------------------------------------------------------
bool
DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
{
if (debug_aranges_data.ValidOffset(0))
{
lldb::offset_t offset = 0;
DWARFDebugArangeSet set;
Range range;
while (set.Extract(debug_aranges_data, &offset))
{
const uint32_t num_descriptors = set.NumDescriptors();
if (num_descriptors > 0)
{
const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset();
for (uint32_t i=0; i<num_descriptors; ++i)
{
const DWARFDebugArangeSet::Descriptor &descriptor = set.GetDescriptorRef(i);
m_aranges.Append(RangeToDIE::Entry (descriptor.address, descriptor.length, cu_offset));
}
}
set.Clear();
}
}
return false;
}
//----------------------------------------------------------------------
// Generate
//----------------------------------------------------------------------
bool
DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
{
Clear();
DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
if (debug_info)
{
const bool clear_dies_if_already_not_parsed = true;
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->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed);
}
}
return !IsEmpty();
}
void
DWARFDebugAranges::Dump (Log *log) const
{
if (log == NULL)
return;
const size_t num_entries = m_aranges.GetSize();
for (size_t i=0; i<num_entries; ++i)
{
const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i);
if (entry)
log->Printf ("0x%8.8x: [0x%" PRIx64 " - 0x%" PRIx64 ")",
entry->data,
entry->GetRangeBase(),
entry->GetRangeEnd());
}
}
void
DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
{
if (high_pc > low_pc)
m_aranges.Append(RangeToDIE::Entry (low_pc, high_pc - low_pc, offset));
}
void
DWARFDebugAranges::Sort (bool minimize)
{
Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
__PRETTY_FUNCTION__, this);
Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
size_t orig_arange_size = 0;
if (log)
{
orig_arange_size = m_aranges.GetSize();
log->Printf ("DWARFDebugAranges::Sort(minimize = %u) with %" PRIu64 " entries", minimize, (uint64_t)orig_arange_size);
}
m_aranges.Sort();
m_aranges.CombineConsecutiveEntriesWithEqualData();
if (log)
{
if (minimize)
{
const size_t new_arange_size = m_aranges.GetSize();
const size_t delta = orig_arange_size - new_arange_size;
log->Printf ("DWARFDebugAranges::Sort() %" PRIu64 " entries after minimizing (%" PRIu64 " entries combined for %" PRIu64 " bytes saved)",
(uint64_t)new_arange_size,
(uint64_t)delta,
(uint64_t)delta * sizeof(Range));
}
Dump (log);
}
}
//----------------------------------------------------------------------
// FindAddress
//----------------------------------------------------------------------
dw_offset_t
DWARFDebugAranges::FindAddress(dw_addr_t address) const
{
const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address);
if (entry)
return entry->data;
return DW_INVALID_OFFSET;
}