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