OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> | |
31 | |
32 // Implement the DwarfCUToModule class; see dwarf_cu_to_module.h. | |
33 | |
34 #include <algorithm> | |
35 #include <cassert> | |
36 | |
37 #include "common/dwarf_cu_to_module.h" | |
38 #include "common/dwarf_line_to_module.h" | |
39 | |
40 | |
41 namespace google_breakpad { | |
42 | |
43 using std::map; | |
44 using std::vector; | |
45 | |
46 // Data provided by a DWARF specification DIE. | |
47 // | |
48 // In DWARF, the DIE for a definition may contain a DW_AT_specification | |
49 // attribute giving the offset of the corresponding declaration DIE, and | |
50 // the definition DIE may omit information given in the declaration. For | |
51 // example, it's common for a function's address range to appear only in | |
52 // its definition DIE, but its name to appear only in its declaration | |
53 // DIE. | |
54 // | |
55 // The dumper needs to be able to follow DW_AT_specification links to | |
56 // bring all this information together in a FUNC record. Conveniently, | |
57 // DIEs that are the target of such links have a DW_AT_declaration flag | |
58 // set, so we can identify them when we first see them, and record their | |
59 // contents for later reference. | |
60 // | |
61 // A Specification holds information gathered from a declaration DIE that | |
62 // we may need if we find a DW_AT_specification link pointing to it. | |
63 struct DwarfCUToModule::Specification { | |
64 // The name of the enclosing scope, or the empty string if there is none. | |
65 string enclosing_name; | |
66 | |
67 // The name for the specification DIE itself, without any enclosing | |
68 // name components. | |
69 string unqualified_name; | |
70 }; | |
71 | |
72 // An abstract origin -- base definition of an inline function. | |
73 struct AbstractOrigin { | |
74 AbstractOrigin() : name() {} | |
75 AbstractOrigin(const string& name) : name(name) {} | |
76 | |
77 string name; | |
78 }; | |
79 | |
80 typedef map<uint64, AbstractOrigin> AbstractOriginByOffset; | |
81 | |
82 // Data global to the DWARF-bearing file that is private to the | |
83 // DWARF-to-Module process. | |
84 struct DwarfCUToModule::FilePrivate { | |
85 // A map from offsets of DIEs within the .debug_info section to | |
86 // Specifications describing those DIEs. Specification references can | |
87 // cross compilation unit boundaries. | |
88 SpecificationByOffset specifications; | |
89 | |
90 AbstractOriginByOffset origins; | |
91 }; | |
92 | |
93 DwarfCUToModule::FileContext::FileContext(const string &filename_arg, | |
94 Module *module_arg) | |
95 : filename(filename_arg), module(module_arg) { | |
96 file_private = new DwarfCUToModule::FilePrivate(); | |
97 } | |
98 | |
99 DwarfCUToModule::FileContext::~FileContext() { | |
100 delete file_private; | |
101 } | |
102 | |
103 // Information global to the particular compilation unit we're | |
104 // parsing. This is for data shared across the CU's entire DIE tree, | |
105 // and parameters from the code invoking the CU parser. | |
106 struct DwarfCUToModule::CUContext { | |
107 CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg) | |
108 : file_context(file_context_arg), | |
109 reporter(reporter_arg), | |
110 language(Language::CPlusPlus) { } | |
111 ~CUContext() { | |
112 for (vector<Module::Function *>::iterator it = functions.begin(); | |
113 it != functions.end(); it++) | |
114 delete *it; | |
115 }; | |
116 | |
117 // The DWARF-bearing file into which this CU was incorporated. | |
118 FileContext *file_context; | |
119 | |
120 // For printing error messages. | |
121 WarningReporter *reporter; | |
122 | |
123 // The source language of this compilation unit. | |
124 const Language *language; | |
125 | |
126 // The functions defined in this compilation unit. We accumulate | |
127 // them here during parsing. Then, in DwarfCUToModule::Finish, we | |
128 // assign them lines and add them to file_context->module. | |
129 // | |
130 // Destroying this destroys all the functions this vector points to. | |
131 vector<Module::Function *> functions; | |
132 }; | |
133 | |
134 // Information about the context of a particular DIE. This is for | |
135 // information that changes as we descend the tree towards the leaves: | |
136 // the containing classes/namespaces, etc. | |
137 struct DwarfCUToModule::DIEContext { | |
138 // The fully-qualified name of the context. For example, for a | |
139 // tree like: | |
140 // | |
141 // DW_TAG_namespace Foo | |
142 // DW_TAG_class Bar | |
143 // DW_TAG_subprogram Baz | |
144 // | |
145 // in a C++ compilation unit, the DIEContext's name for the | |
146 // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's | |
147 // name for the DW_TAG_namespace DIE would be "". | |
148 string name; | |
149 }; | |
150 | |
151 // An abstract base class for all the dumper's DIE handlers. | |
152 class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { | |
153 public: | |
154 // Create a handler for the DIE at OFFSET whose compilation unit is | |
155 // described by CU_CONTEXT, and whose immediate context is described | |
156 // by PARENT_CONTEXT. | |
157 GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, | |
158 uint64 offset) | |
159 : cu_context_(cu_context), | |
160 parent_context_(parent_context), | |
161 offset_(offset), | |
162 declaration_(false), | |
163 specification_(NULL) { } | |
164 | |
165 // Derived classes' ProcessAttributeUnsigned can defer to this to | |
166 // handle DW_AT_declaration, or simply not override it. | |
167 void ProcessAttributeUnsigned(enum DwarfAttribute attr, | |
168 enum DwarfForm form, | |
169 uint64 data); | |
170 | |
171 // Derived classes' ProcessAttributeReference can defer to this to | |
172 // handle DW_AT_specification, or simply not override it. | |
173 void ProcessAttributeReference(enum DwarfAttribute attr, | |
174 enum DwarfForm form, | |
175 uint64 data); | |
176 | |
177 // Derived classes' ProcessAttributeReference can defer to this to | |
178 // handle DW_AT_specification, or simply not override it. | |
179 void ProcessAttributeString(enum DwarfAttribute attr, | |
180 enum DwarfForm form, | |
181 const string &data); | |
182 | |
183 protected: | |
184 // Compute and return the fully-qualified name of the DIE. If this | |
185 // DIE is a declaration DIE, to be cited by other DIEs' | |
186 // DW_AT_specification attributes, record its enclosing name and | |
187 // unqualified name in the specification table. | |
188 // | |
189 // Use this from EndAttributes member functions, not ProcessAttribute* | |
190 // functions; only the former can be sure that all the DIE's attributes | |
191 // have been seen. | |
192 string ComputeQualifiedName(); | |
193 | |
194 CUContext *cu_context_; | |
195 DIEContext *parent_context_; | |
196 uint64 offset_; | |
197 | |
198 // If this DIE has a DW_AT_declaration attribute, this is its value. | |
199 // It is false on DIEs with no DW_AT_declaration attribute. | |
200 bool declaration_; | |
201 | |
202 // If this DIE has a DW_AT_specification attribute, this is the | |
203 // Specification structure for the DIE the attribute refers to. | |
204 // Otherwise, this is NULL. | |
205 Specification *specification_; | |
206 | |
207 // The value of the DW_AT_name attribute, or the empty string if the | |
208 // DIE has no such attribute. | |
209 string name_attribute_; | |
210 }; | |
211 | |
212 void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( | |
213 enum DwarfAttribute attr, | |
214 enum DwarfForm form, | |
215 uint64 data) { | |
216 switch (attr) { | |
217 case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; | |
218 default: break; | |
219 } | |
220 } | |
221 | |
222 void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( | |
223 enum DwarfAttribute attr, | |
224 enum DwarfForm form, | |
225 uint64 data) { | |
226 switch (attr) { | |
227 case dwarf2reader::DW_AT_specification: { | |
228 // Find the Specification to which this attribute refers, and | |
229 // set specification_ appropriately. We could do more processing | |
230 // here, but it's better to leave the real work to our | |
231 // EndAttribute member function, at which point we know we have | |
232 // seen all the DIE's attributes. | |
233 FileContext *file_context = cu_context_->file_context; | |
234 SpecificationByOffset *specifications | |
235 = &file_context->file_private->specifications; | |
236 SpecificationByOffset::iterator spec = specifications->find(data); | |
237 if (spec != specifications->end()) { | |
238 specification_ = &spec->second; | |
239 } else { | |
240 // Technically, there's no reason a DW_AT_specification | |
241 // couldn't be a forward reference, but supporting that would | |
242 // be a lot of work (changing to a two-pass structure), and I | |
243 // don't think any producers we care about ever emit such | |
244 // things. | |
245 cu_context_->reporter->UnknownSpecification(offset_, data); | |
246 } | |
247 break; | |
248 } | |
249 default: break; | |
250 } | |
251 } | |
252 | |
253 void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( | |
254 enum DwarfAttribute attr, | |
255 enum DwarfForm form, | |
256 const string &data) { | |
257 switch (attr) { | |
258 case dwarf2reader::DW_AT_name: name_attribute_ = data; break; | |
259 default: break; | |
260 } | |
261 } | |
262 | |
263 string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { | |
264 // Find our unqualified name. If the DIE has its own DW_AT_name | |
265 // attribute, then use that; otherwise, check our specification. | |
266 const string *unqualified_name; | |
267 if (name_attribute_.empty() && specification_) | |
268 unqualified_name = &specification_->unqualified_name; | |
269 else | |
270 unqualified_name = &name_attribute_; | |
271 | |
272 // Find the name of our enclosing context. If we have a | |
273 // specification, it's the specification's enclosing context that | |
274 // counts; otherwise, use this DIE's context. | |
275 const string *enclosing_name; | |
276 if (specification_) | |
277 enclosing_name = &specification_->enclosing_name; | |
278 else | |
279 enclosing_name = &parent_context_->name; | |
280 | |
281 // If this DIE was marked as a declaration, record its names in the | |
282 // specification table. | |
283 if (declaration_) { | |
284 FileContext *file_context = cu_context_->file_context; | |
285 Specification spec; | |
286 spec.enclosing_name = *enclosing_name; | |
287 spec.unqualified_name = *unqualified_name; | |
288 file_context->file_private->specifications[offset_] = spec; | |
289 } | |
290 | |
291 // Combine the enclosing name and unqualified name to produce our | |
292 // own fully-qualified name. | |
293 return cu_context_->language->MakeQualifiedName(*enclosing_name, | |
294 *unqualified_name); | |
295 } | |
296 | |
297 // A handler class for DW_TAG_subprogram DIEs. | |
298 class DwarfCUToModule::FuncHandler: public GenericDIEHandler { | |
299 public: | |
300 FuncHandler(CUContext *cu_context, DIEContext *parent_context, | |
301 uint64 offset) | |
302 : GenericDIEHandler(cu_context, parent_context, offset), | |
303 low_pc_(0), high_pc_(0), abstract_origin_(NULL), inline_(false) { } | |
304 void ProcessAttributeUnsigned(enum DwarfAttribute attr, | |
305 enum DwarfForm form, | |
306 uint64 data); | |
307 void ProcessAttributeSigned(enum DwarfAttribute attr, | |
308 enum DwarfForm form, | |
309 int64 data); | |
310 void ProcessAttributeReference(enum DwarfAttribute attr, | |
311 enum DwarfForm form, | |
312 uint64 data); | |
313 | |
314 bool EndAttributes(); | |
315 void Finish(); | |
316 | |
317 private: | |
318 // The fully-qualified name, as derived from name_attribute_, | |
319 // specification_, parent_context_. Computed in EndAttributes. | |
320 string name_; | |
321 uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc | |
322 const AbstractOrigin* abstract_origin_; | |
323 bool inline_; | |
324 }; | |
325 | |
326 void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( | |
327 enum DwarfAttribute attr, | |
328 enum DwarfForm form, | |
329 uint64 data) { | |
330 switch (attr) { | |
331 // If this attribute is present at all --- even if its value is | |
332 // DW_INL_not_inlined --- then GCC may cite it as someone else's | |
333 // DW_AT_abstract_origin attribute. | |
334 case dwarf2reader::DW_AT_inline: inline_ = true; break; | |
335 | |
336 case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; | |
337 case dwarf2reader::DW_AT_high_pc: high_pc_ = data; break; | |
338 default: | |
339 GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); | |
340 break; | |
341 } | |
342 } | |
343 | |
344 void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( | |
345 enum DwarfAttribute attr, | |
346 enum DwarfForm form, | |
347 int64 data) { | |
348 switch (attr) { | |
349 // If this attribute is present at all --- even if its value is | |
350 // DW_INL_not_inlined --- then GCC may cite it as someone else's | |
351 // DW_AT_abstract_origin attribute. | |
352 case dwarf2reader::DW_AT_inline: inline_ = true; break; | |
353 | |
354 default: | |
355 break; | |
356 } | |
357 } | |
358 | |
359 void DwarfCUToModule::FuncHandler::ProcessAttributeReference( | |
360 enum DwarfAttribute attr, | |
361 enum DwarfForm form, | |
362 uint64 data) { | |
363 switch(attr) { | |
364 case dwarf2reader::DW_AT_abstract_origin: { | |
365 const AbstractOriginByOffset& origins = | |
366 cu_context_->file_context->file_private->origins; | |
367 AbstractOriginByOffset::const_iterator origin = origins.find(data); | |
368 if (origin != origins.end()) { | |
369 abstract_origin_ = &(origin->second); | |
370 } else { | |
371 cu_context_->reporter->UnknownAbstractOrigin(offset_, data); | |
372 } | |
373 break; | |
374 } | |
375 default: | |
376 GenericDIEHandler::ProcessAttributeReference(attr, form, data); | |
377 break; | |
378 } | |
379 } | |
380 | |
381 bool DwarfCUToModule::FuncHandler::EndAttributes() { | |
382 // Compute our name, and record a specification, if appropriate. | |
383 name_ = ComputeQualifiedName(); | |
384 if (name_.empty() && abstract_origin_) { | |
385 name_ = abstract_origin_->name; | |
386 } | |
387 return true; | |
388 } | |
389 | |
390 void DwarfCUToModule::FuncHandler::Finish() { | |
391 // Did we collect the information we need? Not all DWARF function | |
392 // entries have low and high addresses (for example, inlined | |
393 // functions that were never used), but all the ones we're | |
394 // interested in cover a non-empty range of bytes. | |
395 if (low_pc_ < high_pc_) { | |
396 // Create a Module::Function based on the data we've gathered, and | |
397 // add it to the functions_ list. | |
398 Module::Function *func = new Module::Function; | |
399 func->name = name_; | |
400 func->address = low_pc_; | |
401 func->size = high_pc_ - low_pc_; | |
402 func->parameter_size = 0; | |
403 cu_context_->functions.push_back(func); | |
404 } else if (inline_) { | |
405 AbstractOrigin origin(name_); | |
406 cu_context_->file_context->file_private->origins[offset_] = origin; | |
407 } | |
408 } | |
409 | |
410 // A handler for DIEs that contain functions and contribute a | |
411 // component to their names: namespaces, classes, etc. | |
412 class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { | |
413 public: | |
414 NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, | |
415 uint64 offset) | |
416 : GenericDIEHandler(cu_context, parent_context, offset) { } | |
417 bool EndAttributes(); | |
418 DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag, | |
419 const AttributeList &attrs); | |
420 | |
421 private: | |
422 DIEContext child_context_; // A context for our children. | |
423 }; | |
424 | |
425 bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { | |
426 child_context_.name = ComputeQualifiedName(); | |
427 return true; | |
428 } | |
429 | |
430 dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( | |
431 uint64 offset, | |
432 enum DwarfTag tag, | |
433 const AttributeList &attrs) { | |
434 switch (tag) { | |
435 case dwarf2reader::DW_TAG_subprogram: | |
436 return new FuncHandler(cu_context_, &child_context_, offset); | |
437 case dwarf2reader::DW_TAG_namespace: | |
438 case dwarf2reader::DW_TAG_class_type: | |
439 case dwarf2reader::DW_TAG_structure_type: | |
440 case dwarf2reader::DW_TAG_union_type: | |
441 return new NamedScopeHandler(cu_context_, &child_context_, offset); | |
442 default: | |
443 return NULL; | |
444 } | |
445 }; | |
446 | |
447 void DwarfCUToModule::WarningReporter::CUHeading() { | |
448 if (printed_cu_header_) | |
449 return; | |
450 fprintf(stderr, "%s: in compilation unit '%s' (offset 0x%llx):\n", | |
451 filename_.c_str(), cu_name_.c_str(), cu_offset_); | |
452 printed_cu_header_ = true; | |
453 } | |
454 | |
455 void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, | |
456 uint64 target) { | |
457 CUHeading(); | |
458 fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_specification" | |
459 " attribute referring to the die at offset 0x%llx, which either" | |
460 " was not marked as a declaration, or comes later in the file\n", | |
461 filename_.c_str(), offset, target); | |
462 } | |
463 | |
464 void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64 offset, | |
465 uint64 target) { | |
466 CUHeading(); | |
467 fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_abstract_origin" | |
468 " attribute referring to the die at offset 0x%llx, which either" | |
469 " was not marked as an inline, or comes later in the file\n", | |
470 filename_.c_str(), offset, target); | |
471 } | |
472 | |
473 void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { | |
474 CUHeading(); | |
475 fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", | |
476 filename_.c_str(), name.c_str()); | |
477 } | |
478 | |
479 void DwarfCUToModule::WarningReporter::BadLineInfoOffset(uint64 offset) { | |
480 CUHeading(); | |
481 fprintf(stderr, "%s: warning: line number data offset beyond end" | |
482 " of '.debug_line' section\n", | |
483 filename_.c_str()); | |
484 } | |
485 | |
486 void DwarfCUToModule::WarningReporter::UncoveredHeading() { | |
487 if (printed_unpaired_header_) | |
488 return; | |
489 CUHeading(); | |
490 fprintf(stderr, "%s: warning: skipping unpaired lines/functions:\n", | |
491 filename_.c_str()); | |
492 printed_unpaired_header_ = true; | |
493 } | |
494 | |
495 void DwarfCUToModule::WarningReporter::UncoveredFunction( | |
496 const Module::Function &function) { | |
497 if (!uncovered_warnings_enabled_) | |
498 return; | |
499 UncoveredHeading(); | |
500 fprintf(stderr, " function%s: %s\n", | |
501 function.size == 0 ? " (zero-length)" : "", | |
502 function.name.c_str()); | |
503 } | |
504 | |
505 void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { | |
506 if (!uncovered_warnings_enabled_) | |
507 return; | |
508 UncoveredHeading(); | |
509 fprintf(stderr, " line%s: %s:%d at 0x%llx\n", | |
510 (line.size == 0 ? " (zero-length)" : ""), | |
511 line.file->name.c_str(), line.number, line.address); | |
512 } | |
513 | |
514 DwarfCUToModule::DwarfCUToModule(FileContext *file_context, | |
515 LineToModuleFunctor *line_reader, | |
516 WarningReporter *reporter) | |
517 : line_reader_(line_reader), has_source_line_info_(false) { | |
518 cu_context_ = new CUContext(file_context, reporter); | |
519 child_context_ = new DIEContext(); | |
520 } | |
521 | |
522 DwarfCUToModule::~DwarfCUToModule() { | |
523 delete cu_context_; | |
524 delete child_context_; | |
525 } | |
526 | |
527 void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, | |
528 enum DwarfForm form, | |
529 int64 data) { | |
530 switch (attr) { | |
531 case dwarf2reader::DW_AT_language: // source language of this CU | |
532 SetLanguage(static_cast<DwarfLanguage>(data)); | |
533 break; | |
534 default: | |
535 break; | |
536 } | |
537 } | |
538 | |
539 void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, | |
540 enum DwarfForm form, | |
541 uint64 data) { | |
542 switch (attr) { | |
543 case dwarf2reader::DW_AT_stmt_list: // Line number information. | |
544 has_source_line_info_ = true; | |
545 source_line_offset_ = data; | |
546 break; | |
547 case dwarf2reader::DW_AT_language: // source language of this CU | |
548 SetLanguage(static_cast<DwarfLanguage>(data)); | |
549 break; | |
550 default: | |
551 break; | |
552 } | |
553 } | |
554 | |
555 void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, | |
556 enum DwarfForm form, | |
557 const string &data) { | |
558 if (attr == dwarf2reader::DW_AT_name) | |
559 cu_context_->reporter->SetCUName(data); | |
560 } | |
561 | |
562 bool DwarfCUToModule::EndAttributes() { | |
563 return true; | |
564 } | |
565 | |
566 dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( | |
567 uint64 offset, | |
568 enum DwarfTag tag, | |
569 const AttributeList &attrs) { | |
570 switch (tag) { | |
571 case dwarf2reader::DW_TAG_subprogram: | |
572 return new FuncHandler(cu_context_, child_context_, offset); | |
573 case dwarf2reader::DW_TAG_namespace: | |
574 case dwarf2reader::DW_TAG_class_type: | |
575 case dwarf2reader::DW_TAG_structure_type: | |
576 case dwarf2reader::DW_TAG_union_type: | |
577 return new NamedScopeHandler(cu_context_, child_context_, offset); | |
578 default: | |
579 return NULL; | |
580 } | |
581 } | |
582 | |
583 void DwarfCUToModule::SetLanguage(DwarfLanguage language) { | |
584 switch (language) { | |
585 case dwarf2reader::DW_LANG_Java: | |
586 cu_context_->language = Language::Java; | |
587 break; | |
588 | |
589 // DWARF has no generic language code for assembly language; this is | |
590 // what the GNU toolchain uses. | |
591 case dwarf2reader::DW_LANG_Mips_Assembler: | |
592 cu_context_->language = Language::Assembler; | |
593 break; | |
594 | |
595 // C++ covers so many cases that it probably has some way to cope | |
596 // with whatever the other languages throw at us. So make it the | |
597 // default. | |
598 // | |
599 // Objective C and Objective C++ seem to create entries for | |
600 // methods whose DW_AT_name values are already fully-qualified: | |
601 // "-[Classname method:]". These appear at the top level. | |
602 // | |
603 // DWARF data for C should never include namespaces or functions | |
604 // nested in struct types, but if it ever does, then C++'s | |
605 // notation is probably not a bad choice for that. | |
606 default: | |
607 case dwarf2reader::DW_LANG_ObjC: | |
608 case dwarf2reader::DW_LANG_ObjC_plus_plus: | |
609 case dwarf2reader::DW_LANG_C: | |
610 case dwarf2reader::DW_LANG_C89: | |
611 case dwarf2reader::DW_LANG_C99: | |
612 case dwarf2reader::DW_LANG_C_plus_plus: | |
613 cu_context_->language = Language::CPlusPlus; | |
614 break; | |
615 } | |
616 } | |
617 | |
618 void DwarfCUToModule::ReadSourceLines(uint64 offset) { | |
619 const dwarf2reader::SectionMap §ion_map | |
620 = cu_context_->file_context->section_map; | |
621 dwarf2reader::SectionMap::const_iterator map_entry | |
622 = section_map.find(".debug_line"); | |
623 if (map_entry == section_map.end()) { | |
624 cu_context_->reporter->MissingSection(".debug_line"); | |
625 return; | |
626 } | |
627 const char *section_start = map_entry->second.first; | |
628 uint64 section_length = map_entry->second.second; | |
629 if (offset >= section_length) { | |
630 cu_context_->reporter->BadLineInfoOffset(offset); | |
631 return; | |
632 } | |
633 (*line_reader_)(section_start + offset, section_length - offset, | |
634 cu_context_->file_context->module, &lines_); | |
635 } | |
636 | |
637 namespace { | |
638 // Return true if ADDRESS falls within the range of ITEM. | |
639 template <class T> | |
640 inline bool within(const T &item, Module::Address address) { | |
641 // Because Module::Address is unsigned, and unsigned arithmetic | |
642 // wraps around, this will be false if ADDRESS falls before the | |
643 // start of ITEM, or if it falls after ITEM's end. | |
644 return address - item.address < item.size; | |
645 } | |
646 } | |
647 | |
648 void DwarfCUToModule::AssignLinesToFunctions() { | |
649 vector<Module::Function *> *functions = &cu_context_->functions; | |
650 WarningReporter *reporter = cu_context_->reporter; | |
651 | |
652 // This would be simpler if we assumed that source line entries | |
653 // don't cross function boundaries. However, there's no real reason | |
654 // to assume that (say) a series of function definitions on the same | |
655 // line wouldn't get coalesced into one line number entry. The | |
656 // DWARF spec certainly makes no such promises. | |
657 // | |
658 // So treat the functions and lines as peers, and take the trouble | |
659 // to compute their ranges' intersections precisely. In any case, | |
660 // the hair here is a constant factor for performance; the | |
661 // complexity from here on out is linear. | |
662 | |
663 // Put both our functions and lines in order by address. | |
664 sort(functions->begin(), functions->end(), | |
665 Module::Function::CompareByAddress); | |
666 sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress); | |
667 | |
668 // The last line that we used any piece of. We use this only for | |
669 // generating warnings. | |
670 const Module::Line *last_line_used = NULL; | |
671 | |
672 // The last function and line we warned about --- so we can avoid | |
673 // doing so more than once. | |
674 const Module::Function *last_function_cited = NULL; | |
675 const Module::Line *last_line_cited = NULL; | |
676 | |
677 // Make a single pass through both vectors from lower to higher | |
678 // addresses, populating each Function's lines vector with lines | |
679 // from our lines_ vector that fall within the function's address | |
680 // range. | |
681 vector<Module::Function *>::iterator func_it = functions->begin(); | |
682 vector<Module::Line>::const_iterator line_it = lines_.begin(); | |
683 | |
684 Module::Address current; | |
685 | |
686 // Pointers to the referents of func_it and line_it, or NULL if the | |
687 // iterator is at the end of the sequence. | |
688 Module::Function *func; | |
689 const Module::Line *line; | |
690 | |
691 // Start current at the beginning of the first line or function, | |
692 // whichever is earlier. | |
693 if (func_it != functions->end() && line_it != lines_.end()) { | |
694 func = *func_it; | |
695 line = &*line_it; | |
696 current = std::min(func->address, line->address); | |
697 } else if (line_it != lines_.end()) { | |
698 func = NULL; | |
699 line = &*line_it; | |
700 current = line->address; | |
701 } else if (func_it != functions->end()) { | |
702 func = *func_it; | |
703 line = NULL; | |
704 current = (*func_it)->address; | |
705 } else { | |
706 return; | |
707 } | |
708 | |
709 while (func || line) { | |
710 // This loop has two invariants that hold at the top. | |
711 // | |
712 // First, at least one of the iterators is not at the end of its | |
713 // sequence, and those that are not refer to the earliest | |
714 // function or line that contains or starts after CURRENT. | |
715 // | |
716 // Note that every byte is in one of four states: it is covered | |
717 // or not covered by a function, and, independently, it is | |
718 // covered or not covered by a line. | |
719 // | |
720 // The second invariant is that CURRENT refers to a byte whose | |
721 // state is different from its predecessor, or it refers to the | |
722 // first byte in the address space. In other words, CURRENT is | |
723 // always the address of a transition. | |
724 // | |
725 // Note that, although each iteration advances CURRENT from one | |
726 // transition address to the next in each iteration, it might | |
727 // not advance the iterators. Suppose we have a function that | |
728 // starts with a line, has a gap, and then a second line, and | |
729 // suppose that we enter an iteration with CURRENT at the end of | |
730 // the first line. The next transition address is the start of | |
731 // the second line, after the gap, so the iteration should | |
732 // advance CURRENT to that point. At the head of that iteration, | |
733 // the invariants require that the line iterator be pointing at | |
734 // the second line. But this is also true at the head of the | |
735 // next. And clearly, the iteration must not change the function | |
736 // iterator. So neither iterator moves. | |
737 | |
738 // Assert the first invariant (see above). | |
739 assert(!func || current < func->address || within(*func, current)); | |
740 assert(!line || current < line->address || within(*line, current)); | |
741 | |
742 // The next transition after CURRENT. | |
743 Module::Address next_transition; | |
744 | |
745 // Figure out which state we're in, add lines or warn, and compute | |
746 // the next transition address. | |
747 if (func && current >= func->address) { | |
748 if (line && current >= line->address) { | |
749 // Covered by both a line and a function. | |
750 Module::Address func_left = func->size - (current - func->address); | |
751 Module::Address line_left = line->size - (current - line->address); | |
752 // This may overflow, but things work out. | |
753 next_transition = current + std::min(func_left, line_left); | |
754 Module::Line l = *line; | |
755 l.address = current; | |
756 l.size = next_transition - current; | |
757 func->lines.push_back(l); | |
758 last_line_used = line; | |
759 } else { | |
760 // Covered by a function, but no line. | |
761 if (func != last_function_cited) { | |
762 reporter->UncoveredFunction(*func); | |
763 last_function_cited = func; | |
764 } | |
765 if (line && within(*func, line->address)) | |
766 next_transition = line->address; | |
767 else | |
768 // If this overflows, we'll catch it below. | |
769 next_transition = func->address + func->size; | |
770 } | |
771 } else { | |
772 if (line && current >= line->address) { | |
773 // Covered by a line, but no function. | |
774 // | |
775 // If GCC emits padding after one function to align the start | |
776 // of the next, then it will attribute the padding | |
777 // instructions to the last source line of function (to reduce | |
778 // the size of the line number info), but omit it from the | |
779 // DW_AT_{low,high}_pc range given in .debug_info (since it | |
780 // costs nothing to be precise there). If we did use at least | |
781 // some of the line we're about to skip, and it ends at the | |
782 // start of the next function, then assume this is what | |
783 // happened, and don't warn. | |
784 if (line != last_line_cited | |
785 && !(func | |
786 && line == last_line_used | |
787 && func->address - line->address == line->size)) { | |
788 reporter->UncoveredLine(*line); | |
789 last_line_cited = line; | |
790 } | |
791 if (func && within(*line, func->address)) | |
792 next_transition = func->address; | |
793 else | |
794 // If this overflows, we'll catch it below. | |
795 next_transition = line->address + line->size; | |
796 } else { | |
797 // Covered by neither a function nor a line. By the invariant, | |
798 // both func and line begin after CURRENT. The next transition | |
799 // is the start of the next function or next line, whichever | |
800 // is earliest. | |
801 assert (func || line); | |
802 if (func && line) | |
803 next_transition = std::min(func->address, line->address); | |
804 else if (func) | |
805 next_transition = func->address; | |
806 else | |
807 next_transition = line->address; | |
808 } | |
809 } | |
810 | |
811 // If a function or line abuts the end of the address space, then | |
812 // next_transition may end up being zero, in which case we've completed | |
813 // our pass. Handle that here, instead of trying to deal with it in | |
814 // each place we compute next_transition. | |
815 if (!next_transition) | |
816 break; | |
817 | |
818 // Advance iterators as needed. If lines overlap or functions overlap, | |
819 // then we could go around more than once. We don't worry too much | |
820 // about what result we produce in that case, just as long as we don't | |
821 // hang or crash. | |
822 while (func_it != functions->end() | |
823 && current >= (*func_it)->address | |
824 && !within(**func_it, next_transition)) | |
825 func_it++; | |
826 func = (func_it != functions->end()) ? *func_it : NULL; | |
827 while (line_it != lines_.end() | |
828 && current >= line_it->address | |
829 && !within(*line_it, next_transition)) | |
830 line_it++; | |
831 line = (line_it != lines_.end()) ? &*line_it : NULL; | |
832 | |
833 // We must make progress. | |
834 assert(next_transition > current); | |
835 current = next_transition; | |
836 } | |
837 } | |
838 | |
839 void DwarfCUToModule::Finish() { | |
840 // Assembly language files have no function data, and that gives us | |
841 // no place to store our line numbers (even though the GNU toolchain | |
842 // will happily produce source line info for assembly language | |
843 // files). To avoid spurious warnings about lines we can't assign | |
844 // to functions, skip CUs in languages that lack functions. | |
845 if (!cu_context_->language->HasFunctions()) | |
846 return; | |
847 | |
848 // Read source line info, if we have any. | |
849 if (has_source_line_info_) | |
850 ReadSourceLines(source_line_offset_); | |
851 | |
852 vector<Module::Function *> *functions = &cu_context_->functions; | |
853 | |
854 // Dole out lines to the appropriate functions. | |
855 AssignLinesToFunctions(); | |
856 | |
857 // Add our functions, which now have source lines assigned to them, | |
858 // to module_. | |
859 cu_context_->file_context->module->AddFunctions(functions->begin(), | |
860 functions->end()); | |
861 | |
862 // Ownership of the function objects has shifted from cu_context to | |
863 // the Module. | |
864 functions->clear(); | |
865 } | |
866 | |
867 bool DwarfCUToModule::StartCompilationUnit(uint64 offset, | |
868 uint8 address_size, | |
869 uint8 offset_size, | |
870 uint64 cu_length, | |
871 uint8 dwarf_version) { | |
872 return dwarf_version >= 2; | |
873 } | |
874 | |
875 bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag, | |
876 const AttributeList& attrs) { | |
877 // We don't deal with partial compilation units (the only other tag | |
878 // likely to be used for root DIE). | |
879 return tag == dwarf2reader::DW_TAG_compile_unit; | |
880 } | |
881 | |
882 } // namespace google_breakpad | |
OLD | NEW |