Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(996)

Side by Side Diff: obsolete/breakpad/common/dwarf_cu_to_module.cc

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 &section_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
OLDNEW
« no previous file with comments | « obsolete/breakpad/common/dwarf_cu_to_module.h ('k') | obsolete/breakpad/common/dwarf_cu_to_module_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698