1 //===-- DWARFDebugInfo.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 "SymbolFileDWARF.h"
10 
11 #include <algorithm>
12 #include <set>
13 
14 #include "lldb/Host/PosixApi.h"
15 #include "lldb/Symbol/ObjectFile.h"
16 #include "lldb/Utility/RegularExpression.h"
17 #include "lldb/Utility/Stream.h"
18 
19 #include "DWARFCompileUnit.h"
20 #include "DWARFContext.h"
21 #include "DWARFDebugAranges.h"
22 #include "DWARFDebugInfo.h"
23 #include "DWARFDebugInfoEntry.h"
24 #include "DWARFFormValue.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace std;
29 
30 // Constructor
31 DWARFDebugInfo::DWARFDebugInfo(lldb_private::DWARFContext &context)
32     : m_dwarf2Data(NULL), m_context(context), m_compile_units(),
33       m_cu_aranges_up() {}
34 
35 // SetDwarfData
36 void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) {
37   m_dwarf2Data = dwarf2Data;
38   m_compile_units.clear();
39 }
40 
41 llvm::Expected<DWARFDebugAranges &> DWARFDebugInfo::GetCompileUnitAranges() {
42   if (m_cu_aranges_up)
43     return *m_cu_aranges_up;
44 
45   assert(m_dwarf2Data);
46 
47   m_cu_aranges_up = llvm::make_unique<DWARFDebugAranges>();
48   const DWARFDataExtractor *debug_aranges_data =
49       m_context.getOrLoadArangesData();
50   if (debug_aranges_data) {
51     llvm::Error error = m_cu_aranges_up->extract(*debug_aranges_data);
52     if (error)
53       return std::move(error);
54   }
55 
56   // Make a list of all CUs represented by the arange data in the file.
57   std::set<dw_offset_t> cus_with_data;
58   for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) {
59     dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n);
60     if (offset != DW_INVALID_OFFSET)
61       cus_with_data.insert(offset);
62   }
63 
64   // Manually build arange data for everything that wasn't in the
65   // .debug_aranges table.
66   const size_t num_compile_units = GetNumCompileUnits();
67   for (size_t idx = 0; idx < num_compile_units; ++idx) {
68     DWARFUnit *cu = GetCompileUnitAtIndex(idx);
69 
70     dw_offset_t offset = cu->GetOffset();
71     if (cus_with_data.find(offset) == cus_with_data.end())
72       cu->BuildAddressRangeTable(m_dwarf2Data, m_cu_aranges_up.get());
73   }
74 
75   const bool minimize = true;
76   m_cu_aranges_up->Sort(minimize);
77   return *m_cu_aranges_up;
78 }
79 
80 void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() {
81   if (!m_compile_units.empty())
82     return;
83   if (!m_dwarf2Data)
84     return;
85 
86   lldb::offset_t offset = 0;
87   const auto &debug_info_data = m_dwarf2Data->get_debug_info_data();
88 
89   while (debug_info_data.ValidOffset(offset)) {
90     llvm::Expected<DWARFUnitSP> cu_sp = DWARFCompileUnit::extract(
91         m_dwarf2Data, m_compile_units.size(), debug_info_data, &offset);
92 
93     if (!cu_sp) {
94       // FIXME: Propagate this error up.
95       llvm::consumeError(cu_sp.takeError());
96       return;
97     }
98 
99     // If it didn't return an error, then it should be returning a valid
100     // CompileUnit.
101     assert(*cu_sp);
102 
103     m_compile_units.push_back(*cu_sp);
104 
105     offset = (*cu_sp)->GetNextCompileUnitOffset();
106   }
107 }
108 
109 size_t DWARFDebugInfo::GetNumCompileUnits() {
110   ParseCompileUnitHeadersIfNeeded();
111   return m_compile_units.size();
112 }
113 
114 DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(user_id_t idx) {
115   DWARFUnit *cu = NULL;
116   if (idx < GetNumCompileUnits())
117     cu = m_compile_units[idx].get();
118   return cu;
119 }
120 
121 bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset(
122     dw_offset_t offset, const DWARFUnitSP &cu_sp) {
123   return offset < cu_sp->GetOffset();
124 }
125 
126 uint32_t DWARFDebugInfo::FindCompileUnitIndex(dw_offset_t offset) {
127   ParseCompileUnitHeadersIfNeeded();
128 
129   // llvm::lower_bound is not used as for DIE offsets it would still return
130   // index +1 and GetOffset() returning index itself would be a special case.
131   auto pos = llvm::upper_bound(m_compile_units, offset,
132                                OffsetLessThanCompileUnitOffset);
133   uint32_t idx = std::distance(m_compile_units.begin(), pos);
134   if (idx == 0)
135     return DW_INVALID_OFFSET;
136   return idx - 1;
137 }
138 
139 DWARFUnit *DWARFDebugInfo::GetCompileUnitAtOffset(dw_offset_t cu_offset,
140                                                   uint32_t *idx_ptr) {
141   uint32_t idx = FindCompileUnitIndex(cu_offset);
142   DWARFUnit *result = GetCompileUnitAtIndex(idx);
143   if (result && result->GetOffset() != cu_offset) {
144     result = nullptr;
145     idx = DW_INVALID_INDEX;
146   }
147   if (idx_ptr)
148     *idx_ptr = idx;
149   return result;
150 }
151 
152 DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) {
153   if (die_ref.cu_offset == DW_INVALID_OFFSET)
154     return GetCompileUnitContainingDIEOffset(die_ref.die_offset);
155   else
156     return GetCompileUnitAtOffset(die_ref.cu_offset);
157 }
158 
159 DWARFUnit *
160 DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
161   uint32_t idx = FindCompileUnitIndex(die_offset);
162   DWARFUnit *result = GetCompileUnitAtIndex(idx);
163   if (result && !result->ContainsDIEOffset(die_offset))
164     return nullptr;
165   return result;
166 }
167 
168 DWARFDIE
169 DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) {
170   DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset);
171   if (cu)
172     return cu->GetDIE(die_offset);
173   return DWARFDIE();
174 }
175 
176 // GetDIE()
177 //
178 // Get the DIE (Debug Information Entry) with the specified offset.
179 DWARFDIE
180 DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
181   DWARFUnit *cu = GetCompileUnit(die_ref);
182   if (cu)
183     return cu->GetDIE(die_ref.die_offset);
184   return DWARFDIE(); // Not found
185 }
186 
187