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