toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial