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 =
91         DWARFCompileUnit::extract(m_dwarf2Data, 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(uint32_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 DWARFUnit *DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset,
127                                                  uint32_t *idx_ptr) {
128   DWARFUnitSP cu_sp;
129   uint32_t cu_idx = DW_INVALID_INDEX;
130   if (cu_offset != DW_INVALID_OFFSET) {
131     ParseCompileUnitHeadersIfNeeded();
132 
133     // Watch out for single compile unit executable as they are pretty common
134     const size_t num_cus = m_compile_units.size();
135     if (num_cus == 1) {
136       if (m_compile_units[0]->GetOffset() == cu_offset) {
137         cu_sp = m_compile_units[0];
138         cu_idx = 0;
139       }
140     } else if (num_cus) {
141       CompileUnitColl::const_iterator end_pos = m_compile_units.end();
142       CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
143       CompileUnitColl::const_iterator pos = std::upper_bound(
144           begin_pos, end_pos, cu_offset, OffsetLessThanCompileUnitOffset);
145       if (pos != begin_pos) {
146         --pos;
147         if ((*pos)->GetOffset() == cu_offset) {
148           cu_sp = *pos;
149           cu_idx = std::distance(begin_pos, pos);
150         }
151       }
152     }
153   }
154   if (idx_ptr)
155     *idx_ptr = cu_idx;
156   return cu_sp.get();
157 }
158 
159 DWARFUnit *DWARFDebugInfo::GetCompileUnit(const DIERef &die_ref) {
160   if (die_ref.cu_offset == DW_INVALID_OFFSET)
161     return GetCompileUnitContainingDIEOffset(die_ref.die_offset);
162   else
163     return GetCompileUnit(die_ref.cu_offset);
164 }
165 
166 DWARFUnit *
167 DWARFDebugInfo::GetCompileUnitContainingDIEOffset(dw_offset_t die_offset) {
168   ParseCompileUnitHeadersIfNeeded();
169 
170   DWARFUnitSP cu_sp;
171 
172   // Watch out for single compile unit executable as they are pretty common
173   const size_t num_cus = m_compile_units.size();
174   if (num_cus == 1) {
175     if (m_compile_units[0]->ContainsDIEOffset(die_offset))
176       return m_compile_units[0].get();
177   } else if (num_cus) {
178     CompileUnitColl::const_iterator end_pos = m_compile_units.end();
179     CompileUnitColl::const_iterator begin_pos = m_compile_units.begin();
180     CompileUnitColl::const_iterator pos = std::upper_bound(
181         begin_pos, end_pos, die_offset, OffsetLessThanCompileUnitOffset);
182     if (pos != begin_pos) {
183       --pos;
184       if ((*pos)->ContainsDIEOffset(die_offset))
185         return (*pos).get();
186     }
187   }
188 
189   return nullptr;
190 }
191 
192 DWARFDIE
193 DWARFDebugInfo::GetDIEForDIEOffset(dw_offset_t die_offset) {
194   DWARFUnit *cu = GetCompileUnitContainingDIEOffset(die_offset);
195   if (cu)
196     return cu->GetDIE(die_offset);
197   return DWARFDIE();
198 }
199 
200 // GetDIE()
201 //
202 // Get the DIE (Debug Information Entry) with the specified offset.
203 DWARFDIE
204 DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
205   DWARFUnit *cu = GetCompileUnit(die_ref);
206   if (cu)
207     return cu->GetDIE(die_ref.die_offset);
208   return DWARFDIE(); // Not found
209 }
210 
211