1//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "DWARFDebugAranges.h"
11
12#include <assert.h>
13#include <stdio.h>
14
15#include <algorithm>
16
17#include "lldb/Core/Log.h"
18#include "lldb/Core/Stream.h"
19#include "lldb/Core/Timer.h"
20
21#include "LogChannelDWARF.h"
22#include "SymbolFileDWARF.h"
23#include "DWARFDebugInfo.h"
24#include "DWARFCompileUnit.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// Constructor
31//----------------------------------------------------------------------
32DWARFDebugAranges::DWARFDebugAranges() :
33    m_aranges()
34{
35}
36
37//----------------------------------------------------------------------
38// CountArangeDescriptors
39//----------------------------------------------------------------------
40class CountArangeDescriptors
41{
42public:
43    CountArangeDescriptors (uint32_t& count_ref) : count(count_ref)
44    {
45//      printf("constructor CountArangeDescriptors()\n");
46    }
47    void operator() (const DWARFDebugArangeSet& set)
48    {
49        count += set.NumDescriptors();
50    }
51    uint32_t& count;
52};
53
54
55//----------------------------------------------------------------------
56// Extract
57//----------------------------------------------------------------------
58bool
59DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
60{
61    if (debug_aranges_data.ValidOffset(0))
62    {
63        lldb::offset_t offset = 0;
64
65        DWARFDebugArangeSet set;
66        Range range;
67        while (set.Extract(debug_aranges_data, &offset))
68        {
69            const uint32_t num_descriptors = set.NumDescriptors();
70            if (num_descriptors > 0)
71            {
72                const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset();
73
74                for (uint32_t i=0; i<num_descriptors; ++i)
75                {
76                    const DWARFDebugArangeSet::Descriptor &descriptor = set.GetDescriptorRef(i);
77                    m_aranges.Append(RangeToDIE::Entry (descriptor.address, descriptor.length, cu_offset));
78                }
79            }
80            set.Clear();
81        }
82    }
83    return false;
84}
85
86//----------------------------------------------------------------------
87// Generate
88//----------------------------------------------------------------------
89bool
90DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
91{
92    Clear();
93    DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
94    if (debug_info)
95    {
96        const bool clear_dies_if_already_not_parsed = true;
97        uint32_t cu_idx = 0;
98        const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
99        for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
100        {
101            DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
102            if (cu)
103                cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed);
104        }
105    }
106    return !IsEmpty();
107}
108
109
110void
111DWARFDebugAranges::Dump (Log *log) const
112{
113    if (log == NULL)
114        return;
115
116    const size_t num_entries = m_aranges.GetSize();
117    for (size_t i=0; i<num_entries; ++i)
118    {
119        const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i);
120        if (entry)
121            log->Printf ("0x%8.8x: [0x%" PRIx64 " - 0x%" PRIx64 ")",
122                         entry->data,
123                         entry->GetRangeBase(),
124                         entry->GetRangeEnd());
125    }
126}
127
128void
129DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
130{
131    if (high_pc > low_pc)
132        m_aranges.Append(RangeToDIE::Entry (low_pc, high_pc - low_pc, offset));
133}
134
135void
136DWARFDebugAranges::Sort (bool minimize)
137{
138    Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
139                       __PRETTY_FUNCTION__, this);
140
141    Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
142    size_t orig_arange_size = 0;
143    if (log)
144    {
145        orig_arange_size = m_aranges.GetSize();
146        log->Printf ("DWARFDebugAranges::Sort(minimize = %u) with %" PRIu64 " entries", minimize, (uint64_t)orig_arange_size);
147    }
148
149    m_aranges.Sort();
150    m_aranges.CombineConsecutiveEntriesWithEqualData();
151
152    if (log)
153    {
154        if (minimize)
155        {
156            const size_t new_arange_size = m_aranges.GetSize();
157            const size_t delta = orig_arange_size - new_arange_size;
158            log->Printf ("DWARFDebugAranges::Sort() %" PRIu64 " entries after minimizing (%" PRIu64 " entries combined for %" PRIu64 " bytes saved)",
159                         (uint64_t)new_arange_size,
160                         (uint64_t)delta,
161                         (uint64_t)delta * sizeof(Range));
162        }
163        Dump (log);
164    }
165}
166
167//----------------------------------------------------------------------
168// FindAddress
169//----------------------------------------------------------------------
170dw_offset_t
171DWARFDebugAranges::FindAddress(dw_addr_t address) const
172{
173    const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address);
174    if (entry)
175        return entry->data;
176    return DW_INVALID_OFFSET;
177}
178