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