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 //----------------------------------------------------------------------
31 // Constructor
32 //----------------------------------------------------------------------
33 DWARFDebugInfo::DWARFDebugInfo(lldb_private::DWARFContext &context)
34     : m_dwarf2Data(NULL), m_context(context), m_compile_units(),
35       m_cu_aranges_up() {}
36 
37 //----------------------------------------------------------------------
38 // SetDwarfData
39 //----------------------------------------------------------------------
40 void DWARFDebugInfo::SetDwarfData(SymbolFileDWARF *dwarf2Data) {
41   m_dwarf2Data = dwarf2Data;
42   m_compile_units.clear();
43 }
44 
45 llvm::Expected<DWARFDebugAranges &> DWARFDebugInfo::GetCompileUnitAranges() {
46   if (m_cu_aranges_up)
47     return *m_cu_aranges_up;
48 
49   assert(m_dwarf2Data);
50 
51   m_cu_aranges_up = llvm::make_unique<DWARFDebugAranges>();
52   const DWARFDataExtractor *debug_aranges_data =
53       m_context.getOrLoadArangesData();
54   if (debug_aranges_data) {
55     llvm::Error error = m_cu_aranges_up->extract(*debug_aranges_data);
56     if (error)
57       return std::move(error);
58   }
59 
60   // Make a list of all CUs represented by the arange data in the file.
61   std::set<dw_offset_t> cus_with_data;
62   for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) {
63     dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n);
64     if (offset != DW_INVALID_OFFSET)
65       cus_with_data.insert(offset);
66   }
67 
68   // Manually build arange data for everything that wasn't in the
69   // .debug_aranges table.
70   const size_t num_compile_units = GetNumCompileUnits();
71   for (size_t idx = 0; idx < num_compile_units; ++idx) {
72     DWARFUnit *cu = GetCompileUnitAtIndex(idx);
73 
74     dw_offset_t offset = cu->GetOffset();
75     if (cus_with_data.find(offset) == cus_with_data.end())
76       cu->BuildAddressRangeTable(m_dwarf2Data, m_cu_aranges_up.get());
77   }
78 
79   const bool minimize = true;
80   m_cu_aranges_up->Sort(minimize);
81   return *m_cu_aranges_up;
82 }
83 
84 void DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded() {
85   if (!m_compile_units.empty())
86     return;
87   if (!m_dwarf2Data)
88     return;
89 
90   lldb::offset_t offset = 0;
91   const auto &debug_info_data = m_dwarf2Data->get_debug_info_data();
92 
93   while (debug_info_data.ValidOffset(offset)) {
94     llvm::Expected<DWARFUnitSP> cu_sp =
95         DWARFCompileUnit::extract(m_dwarf2Data, debug_info_data, &offset);
96 
97     if (!cu_sp) {
98       // FIXME: Propagate this error up.
99       llvm::consumeError(cu_sp.takeError());
100       return;
101     }
102 
103     // If it didn't return an error, then it should be returning a valid
104     // CompileUnit.
105     assert(*cu_sp);
106 
107     m_compile_units.push_back(*cu_sp);
108 
109     offset = (*cu_sp)->GetNextCompileUnitOffset();
110   }
111 }
112 
113 size_t DWARFDebugInfo::GetNumCompileUnits() {
114   ParseCompileUnitHeadersIfNeeded();
115   return m_compile_units.size();
116 }
117 
118 DWARFUnit *DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx) {
119   DWARFUnit *cu = NULL;
120   if (idx < GetNumCompileUnits())
121     cu = m_compile_units[idx].get();
122   return cu;
123 }
124 
125 bool DWARFDebugInfo::OffsetLessThanCompileUnitOffset(
126     dw_offset_t offset, const DWARFUnitSP &cu_sp) {
127   return offset < cu_sp->GetOffset();
128 }
129 
130 DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset,
131                                                  uint32_t *idx_ptr) {
132   DWARFUnitSP cu_sp;
133   uint32_t cu_idx = DW_INVALID_INDEX;
134   if (cu_offset != DW_INVALID_OFFSET) {
135     ParseCompileUnitHeadersIfNeeded();
136 
137     // Watch out for single compile unit executable as they are pretty common
138     const size_t num_cus = m_compile_units.size();
139     if (num_cus == 1) {
140       if (m_compile_units[0]->GetOffset() == cu_offset) {
141         cu_sp = m_compile_units[0];
142         cu_idx = 0;
143       }
144     } else if (num_cus) {
145       CompileUnitColl::const_iterator end_pos = m_compile_units.end();
146       CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
147       CompileUnitColl::const_iterator pos = std::upper_bound(
148           begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset);
149       if (pos != begin_pos) {
150         --pos;
151         if ((*pos)->GetOffset() == cu_offset) {
152           cu_sp = *pos;
153           cu_idx = std::distance(begin_pos, pos);
154         }
155       }
156     }
157   }
158   if (idx_ptr)
159     *idx_ptr = cu_idx;
160   return cu_sp.get();
161 }
162 
163 DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) {
164   if (die_ref.cu_offset == DW_INVALID_OFFSET)
165     return GetCompileUnitContainingDIEOffset(die_ref.die_offset);
166   else
167     return GetCompileUnit(die_ref.cu_offset);
168 }
169 
170 DWARFUnit *
171 DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
172   ParseCompileUnitHeadersIfNeeded();
173 
174   DWARFUnitSP cu_sp;
175 
176   // Watch out for single compile unit executable as they are pretty common
177   const size_t num_cus = m_compile_units.size();
178   if (num_cus == 1) {
179     if (m_compile_units[0]->ContainsDIEOffset(die_offset))
180       return m_compile_units[0].get();
181   } else if (num_cus) {
182     CompileUnitColl::const_iterator end_pos = m_compile_units.end();
183     CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
184     CompileUnitColl::const_iterator pos = std::upper_bound(
185         begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset);
186     if (pos != begin_pos) {
187       --pos;
188       if ((*pos)->ContainsDIEOffset(die_offset))
189         return (*pos).get();
190     }
191   }
192 
193   return nullptr;
194 }
195 
196 DWARFDIE
197 DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) {
198   DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset);
199   if (cu)
200     return cu->GetDIE(die_offset);
201   return DWARFDIE();
202 }
203 
204 //----------------------------------------------------------------------
205 // GetDIE()
206 //
207 // Get the DIE (Debug Information Entry) with the specified offset.
208 //----------------------------------------------------------------------
209 DWARFDIE
210 DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
211   DWARFUnit *cu = GetCompileUnit(die_ref);
212   if (cu)
213     return cu->GetDIE(die_ref.die_offset);
214   return DWARFDIE(); // Not found
215 }
216 
217