michael@0: // Copyright (c) 2010 Google Inc. All Rights Reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. michael@0: // See dwarf2diehandler.h for details. michael@0: michael@0: #include michael@0: michael@0: #include michael@0: michael@0: #include "common/dwarf/dwarf2diehandler.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: namespace dwarf2reader { michael@0: michael@0: DIEDispatcher::~DIEDispatcher() { michael@0: while (!die_handlers_.empty()) { michael@0: HandlerStack &entry = die_handlers_.top(); michael@0: if (entry.handler_ != root_handler_) michael@0: delete entry.handler_; michael@0: die_handlers_.pop(); michael@0: } michael@0: } michael@0: michael@0: bool DIEDispatcher::StartCompilationUnit(uint64 offset, uint8 address_size, michael@0: uint8 offset_size, uint64 cu_length, michael@0: uint8 dwarf_version) { michael@0: return root_handler_->StartCompilationUnit(offset, address_size, michael@0: offset_size, cu_length, michael@0: dwarf_version); michael@0: } michael@0: michael@0: bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag) { michael@0: // The stack entry for the parent of this DIE, if there is one. michael@0: HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); michael@0: michael@0: // Does this call indicate that we're done receiving the parent's michael@0: // attributes' values? If so, call its EndAttributes member function. michael@0: if (parent && parent->handler_ && !parent->reported_attributes_end_) { michael@0: parent->reported_attributes_end_ = true; michael@0: if (!parent->handler_->EndAttributes()) { michael@0: // Finish off this handler now. and edit *PARENT to indicate that michael@0: // we don't want to visit any of the children. michael@0: parent->handler_->Finish(); michael@0: if (parent->handler_ != root_handler_) michael@0: delete parent->handler_; michael@0: parent->handler_ = NULL; michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: // Find a handler for this DIE. michael@0: DIEHandler *handler; michael@0: if (parent) { michael@0: if (parent->handler_) michael@0: // Ask the parent to find a handler. michael@0: handler = parent->handler_->FindChildHandler(offset, tag); michael@0: else michael@0: // No parent handler means we're not interested in any of our michael@0: // children. michael@0: handler = NULL; michael@0: } else { michael@0: // This is the root DIE. For a non-root DIE, the parent's handler michael@0: // decides whether to visit it, but the root DIE has no parent michael@0: // handler, so we have a special method on the root DIE handler michael@0: // itself to decide. michael@0: if (root_handler_->StartRootDIE(offset, tag)) michael@0: handler = root_handler_; michael@0: else michael@0: handler = NULL; michael@0: } michael@0: michael@0: // Push a handler stack entry for this new handler. As an michael@0: // optimization, we don't push NULL-handler entries on top of other michael@0: // NULL-handler entries; we just let the oldest such entry stand for michael@0: // the whole subtree. michael@0: if (handler || !parent || parent->handler_) { michael@0: HandlerStack entry; michael@0: entry.offset_ = offset; michael@0: entry.handler_ = handler; michael@0: entry.reported_attributes_end_ = false; michael@0: die_handlers_.push(entry); michael@0: } michael@0: michael@0: return handler != NULL; michael@0: } michael@0: michael@0: void DIEDispatcher::EndDIE(uint64 offset) { michael@0: assert(!die_handlers_.empty()); michael@0: HandlerStack *entry = &die_handlers_.top(); michael@0: if (entry->handler_) { michael@0: // This entry had better be the handler for this DIE. michael@0: assert(entry->offset_ == offset); michael@0: // If a DIE has no children, this EndDIE call indicates that we're michael@0: // done receiving its attributes' values. michael@0: if (!entry->reported_attributes_end_) michael@0: entry->handler_->EndAttributes(); // Ignore return value: no children. michael@0: entry->handler_->Finish(); michael@0: if (entry->handler_ != root_handler_) michael@0: delete entry->handler_; michael@0: } else { michael@0: // If this DIE is within a tree we're ignoring, then don't pop the michael@0: // handler stack: that entry stands for the whole tree. michael@0: if (entry->offset_ != offset) michael@0: return; michael@0: } michael@0: die_handlers_.pop(); michael@0: } michael@0: michael@0: void DIEDispatcher::ProcessAttributeUnsigned(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: uint64 data) { michael@0: HandlerStack ¤t = die_handlers_.top(); michael@0: // This had better be an attribute of the DIE we were meant to handle. michael@0: assert(offset == current.offset_); michael@0: current.handler_->ProcessAttributeUnsigned(attr, form, data); michael@0: } michael@0: michael@0: void DIEDispatcher::ProcessAttributeSigned(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: int64 data) { michael@0: HandlerStack ¤t = die_handlers_.top(); michael@0: // This had better be an attribute of the DIE we were meant to handle. michael@0: assert(offset == current.offset_); michael@0: current.handler_->ProcessAttributeSigned(attr, form, data); michael@0: } michael@0: michael@0: void DIEDispatcher::ProcessAttributeReference(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: uint64 data) { michael@0: HandlerStack ¤t = die_handlers_.top(); michael@0: // This had better be an attribute of the DIE we were meant to handle. michael@0: assert(offset == current.offset_); michael@0: current.handler_->ProcessAttributeReference(attr, form, data); michael@0: } michael@0: michael@0: void DIEDispatcher::ProcessAttributeBuffer(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: const char* data, michael@0: uint64 len) { michael@0: HandlerStack ¤t = die_handlers_.top(); michael@0: // This had better be an attribute of the DIE we were meant to handle. michael@0: assert(offset == current.offset_); michael@0: current.handler_->ProcessAttributeBuffer(attr, form, data, len); michael@0: } michael@0: michael@0: void DIEDispatcher::ProcessAttributeString(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: const string& data) { michael@0: HandlerStack ¤t = die_handlers_.top(); michael@0: // This had better be an attribute of the DIE we were meant to handle. michael@0: assert(offset == current.offset_); michael@0: current.handler_->ProcessAttributeString(attr, form, data); michael@0: } michael@0: michael@0: void DIEDispatcher::ProcessAttributeSignature(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: uint64 signature) { michael@0: HandlerStack ¤t = die_handlers_.top(); michael@0: // This had better be an attribute of the DIE we were meant to handle. michael@0: assert(offset == current.offset_); michael@0: current.handler_->ProcessAttributeSignature(attr, form, signature); michael@0: } michael@0: michael@0: } // namespace dwarf2reader