1 //===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "DWARFDebugPubnames.h"
11
12 #include "lldb/Core/Stream.h"
13 #include "lldb/Core/Timer.h"
14
15 #include "DWARFDebugInfo.h"
16 #include "DWARFDIECollection.h"
17 #include "DWARFFormValue.h"
18 #include "DWARFCompileUnit.h"
19 #include "LogChannelDWARF.h"
20 #include "SymbolFileDWARF.h"
21
22
23 using namespace lldb;
24 using namespace lldb_private;
25
DWARFDebugPubnames()26 DWARFDebugPubnames::DWARFDebugPubnames() :
27 m_sets()
28 {
29 }
30
31 bool
Extract(const DWARFDataExtractor & data)32 DWARFDebugPubnames::Extract(const DWARFDataExtractor& data)
33 {
34 Timer scoped_timer (__PRETTY_FUNCTION__,
35 "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")",
36 (uint64_t)data.GetByteSize());
37 Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
38 if (log)
39 log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", (uint64_t)data.GetByteSize());
40
41 if (data.ValidOffset(0))
42 {
43 lldb::offset_t offset = 0;
44
45 DWARFDebugPubnamesSet set;
46 while (data.ValidOffset(offset))
47 {
48 if (set.Extract(data, &offset))
49 {
50 m_sets.push_back(set);
51 offset = set.GetOffsetOfNextEntry();
52 }
53 else
54 break;
55 }
56 if (log)
57 Dump (log);
58 return true;
59 }
60 return false;
61 }
62
63
64 bool
GeneratePubnames(SymbolFileDWARF * dwarf2Data)65 DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
66 {
67 Timer scoped_timer (__PRETTY_FUNCTION__,
68 "DWARFDebugPubnames::GeneratePubnames (data = %p)",
69 static_cast<void*>(dwarf2Data));
70
71 Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
72 if (log)
73 log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)",
74 static_cast<void*>(dwarf2Data));
75
76 m_sets.clear();
77 DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
78 if (debug_info)
79 {
80
81 const DWARFDataExtractor* debug_str = &dwarf2Data->get_debug_str_data();
82
83 uint32_t cu_idx = 0;
84 const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
85 for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
86 {
87
88 DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
89
90 const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize(), cu->IsDWARF64());
91
92 bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
93
94 DWARFDIECollection dies;
95 const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) +
96 cu->AppendDIEsWithTag (DW_TAG_variable, dies);
97
98 dw_offset_t cu_offset = cu->GetOffset();
99 DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
100
101 size_t die_idx;
102 for (die_idx = 0; die_idx < die_count; ++die_idx)
103 {
104 const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
105 DWARFDebugInfoEntry::Attributes attributes;
106 const char *name = NULL;
107 const char *mangled = NULL;
108 bool add_die = false;
109 const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes);
110 if (num_attributes > 0)
111 {
112 uint32_t i;
113
114 dw_tag_t tag = die->Tag();
115
116 for (i=0; i<num_attributes; ++i)
117 {
118 dw_attr_t attr = attributes.AttributeAtIndex(i);
119 DWARFFormValue form_value;
120 switch (attr)
121 {
122 case DW_AT_name:
123 if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
124 name = form_value.AsCString(debug_str);
125 break;
126
127 case DW_AT_MIPS_linkage_name:
128 case DW_AT_linkage_name:
129 if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
130 mangled = form_value.AsCString(debug_str);
131 break;
132
133 case DW_AT_low_pc:
134 case DW_AT_ranges:
135 case DW_AT_entry_pc:
136 if (tag == DW_TAG_subprogram)
137 add_die = true;
138 break;
139
140 case DW_AT_location:
141 if (tag == DW_TAG_variable)
142 {
143 const DWARFDebugInfoEntry* parent_die = die->GetParent();
144 while ( parent_die != NULL )
145 {
146 switch (parent_die->Tag())
147 {
148 case DW_TAG_subprogram:
149 case DW_TAG_lexical_block:
150 case DW_TAG_inlined_subroutine:
151 // Even if this is a function level static, we don't add it. We could theoretically
152 // add these if we wanted to by introspecting into the DW_AT_location and seeing
153 // if the location describes a hard coded address, but we don't want the performance
154 // penalty of that right now.
155 add_die = false;
156 // if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
157 // {
158 // // If we have valid block data, then we have location expression bytes
159 // // that are fixed (not a location list).
160 // const uint8_t *block_data = form_value.BlockData();
161 // if (block_data)
162 // {
163 // uint32_t block_length = form_value.Unsigned();
164 // if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
165 // {
166 // if (block_data[0] == DW_OP_addr)
167 // add_die = true;
168 // }
169 // }
170 // }
171 parent_die = NULL; // Terminate the while loop.
172 break;
173
174 case DW_TAG_compile_unit:
175 add_die = true;
176 parent_die = NULL; // Terminate the while loop.
177 break;
178
179 default:
180 parent_die = parent_die->GetParent(); // Keep going in the while loop.
181 break;
182 }
183 }
184 }
185 break;
186 }
187 }
188 }
189
190 if (add_die && (name || mangled))
191 {
192 pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name);
193 }
194 }
195
196 if (pubnames_set.NumDescriptors() > 0)
197 {
198 m_sets.push_back(pubnames_set);
199 }
200
201 // Keep memory down by clearing DIEs if this generate function
202 // caused them to be parsed
203 if (clear_dies)
204 cu->ClearDIEs (true);
205 }
206 }
207 if (m_sets.empty())
208 return false;
209 if (log)
210 Dump (log);
211 return true;
212 }
213
214 bool
GeneratePubBaseTypes(SymbolFileDWARF * dwarf2Data)215 DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data)
216 {
217 m_sets.clear();
218 DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
219 if (debug_info)
220 {
221 uint32_t cu_idx = 0;
222 const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
223 for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
224 {
225 DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
226 DWARFDIECollection dies;
227 const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies);
228 dw_offset_t cu_offset = cu->GetOffset();
229 DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
230
231 size_t die_idx;
232 for (die_idx = 0; die_idx < die_count; ++die_idx)
233 {
234 const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
235 const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL);
236
237 if (name)
238 {
239 pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name);
240 }
241 }
242
243 if (pubnames_set.NumDescriptors() > 0)
244 {
245 m_sets.push_back(pubnames_set);
246 }
247 }
248 }
249 return !m_sets.empty();
250 }
251
252 void
Dump(Log * s) const253 DWARFDebugPubnames::Dump(Log *s) const
254 {
255 if (m_sets.empty())
256 s->PutCString("< EMPTY >\n");
257 else
258 {
259 const_iterator pos;
260 const_iterator end = m_sets.end();
261
262 for (pos = m_sets.begin(); pos != end; ++pos)
263 (*pos).Dump(s);
264 }
265 }
266
267 bool
Find(const char * name,bool ignore_case,std::vector<dw_offset_t> & die_offsets) const268 DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const
269 {
270 const_iterator pos;
271 const_iterator end = m_sets.end();
272
273 die_offsets.clear();
274
275 for (pos = m_sets.begin(); pos != end; ++pos)
276 {
277 (*pos).Find(name, ignore_case, die_offsets);
278 }
279
280 return !die_offsets.empty();
281 }
282
283 bool
Find(const RegularExpression & regex,std::vector<dw_offset_t> & die_offsets) const284 DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const
285 {
286 const_iterator pos;
287 const_iterator end = m_sets.end();
288
289 die_offsets.clear();
290
291 for (pos = m_sets.begin(); pos != end; ++pos)
292 {
293 (*pos).Find(regex, die_offsets);
294 }
295
296 return !die_offsets.empty();
297 }
298