|  | // Copyright (c) 2010 Google Inc. All Rights Reserved. | 
|  | // | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright | 
|  | // notice, this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above | 
|  | // copyright notice, this list of conditions and the following disclaimer | 
|  | // in the documentation and/or other materials provided with the | 
|  | // distribution. | 
|  | //     * Neither the name of Google Inc. nor the names of its | 
|  | // contributors may be used to endorse or promote products derived from | 
|  | // this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  |  | 
|  | // This is a client for the dwarf2reader to extract function and line | 
|  | // information from the debug info. | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <limits.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include <map> | 
|  | #include <queue> | 
|  | #include <vector> | 
|  | #include <memory> | 
|  |  | 
|  | #include "common/dwarf/functioninfo.h" | 
|  | #include "common/dwarf/bytereader.h" | 
|  | #include "common/using_std_string.h" | 
|  |  | 
|  | namespace dwarf2reader { | 
|  |  | 
|  | CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files, | 
|  | std::vector<string>* dirs, | 
|  | LineMap* linemap):linemap_(linemap), | 
|  | files_(files), | 
|  | dirs_(dirs) { | 
|  | // The dirs and files are 1 indexed, so just make sure we put | 
|  | // nothing in the 0 vector. | 
|  | assert(dirs->size() == 0); | 
|  | assert(files->size() == 0); | 
|  | dirs->push_back(""); | 
|  | SourceFileInfo s; | 
|  | s.name = ""; | 
|  | s.lowpc = ULLONG_MAX; | 
|  | files->push_back(s); | 
|  | } | 
|  |  | 
|  | void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) { | 
|  | // These should never come out of order, actually | 
|  | assert(dir_num == dirs_->size()); | 
|  | dirs_->push_back(name); | 
|  | } | 
|  |  | 
|  | void CULineInfoHandler::DefineFile(const string& name, | 
|  | int32 file_num, uint32 dir_num, | 
|  | uint64 mod_time, uint64 length) { | 
|  | assert(dir_num >= 0); | 
|  | assert(dir_num < dirs_->size()); | 
|  |  | 
|  | // These should never come out of order, actually. | 
|  | if (file_num == (int32)files_->size() || file_num == -1) { | 
|  | string dir = dirs_->at(dir_num); | 
|  |  | 
|  | SourceFileInfo s; | 
|  | s.lowpc = ULLONG_MAX; | 
|  |  | 
|  | if (dir == "") { | 
|  | s.name = name; | 
|  | } else { | 
|  | s.name = dir + "/" + name; | 
|  | } | 
|  |  | 
|  | files_->push_back(s); | 
|  | } else { | 
|  | fprintf(stderr, "error in DefineFile"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num, | 
|  | uint32 line_num, uint32 column_num) { | 
|  | if (file_num < files_->size()) { | 
|  | linemap_->insert( | 
|  | std::make_pair(address, | 
|  | std::make_pair(files_->at(file_num).name.c_str(), | 
|  | line_num))); | 
|  |  | 
|  | if(address < files_->at(file_num).lowpc) { | 
|  | files_->at(file_num).lowpc = address; | 
|  | } | 
|  | } else { | 
|  | fprintf(stderr,"error in AddLine"); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset, | 
|  | uint8 address_size, | 
|  | uint8 offset_size, | 
|  | uint64 cu_length, | 
|  | uint8 dwarf_version) { | 
|  | current_compilation_unit_offset_ = offset; | 
|  | return true; | 
|  | } | 
|  |  | 
|  |  | 
|  | // For function info, we only care about subprograms and inlined | 
|  | // subroutines. For line info, the DW_AT_stmt_list lives in the | 
|  | // compile unit tag. | 
|  |  | 
|  | bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag, | 
|  | const AttributeList& attrs) { | 
|  | switch (tag) { | 
|  | case DW_TAG_subprogram: | 
|  | case DW_TAG_inlined_subroutine: { | 
|  | current_function_info_ = new FunctionInfo; | 
|  | current_function_info_->lowpc = current_function_info_->highpc = 0; | 
|  | current_function_info_->name = ""; | 
|  | current_function_info_->line = 0; | 
|  | current_function_info_->file = ""; | 
|  | offset_to_funcinfo_->insert(std::make_pair(offset, | 
|  | current_function_info_)); | 
|  | }; | 
|  | // FALLTHROUGH | 
|  | case DW_TAG_compile_unit: | 
|  | return true; | 
|  | default: | 
|  | return false; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Only care about the name attribute for functions | 
|  |  | 
|  | void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset, | 
|  | enum DwarfAttribute attr, | 
|  | enum DwarfForm form, | 
|  | const string &data) { | 
|  | if (current_function_info_) { | 
|  | if (attr == DW_AT_name) | 
|  | current_function_info_->name = data; | 
|  | else if(attr == DW_AT_MIPS_linkage_name) | 
|  | current_function_info_->mangled_name = data; | 
|  | } | 
|  | } | 
|  |  | 
|  | void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, | 
|  | enum DwarfAttribute attr, | 
|  | enum DwarfForm form, | 
|  | uint64 data) { | 
|  | if (attr == DW_AT_stmt_list) { | 
|  | SectionMap::const_iterator iter = sections_.find("__debug_line"); | 
|  | assert(iter != sections_.end()); | 
|  |  | 
|  | // this should be a scoped_ptr but we dont' use boost :-( | 
|  | std::auto_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data, | 
|  | iter->second.second  - data, | 
|  | reader_, linehandler_)); | 
|  | lireader->Start(); | 
|  | } else if (current_function_info_) { | 
|  | switch (attr) { | 
|  | case DW_AT_low_pc: | 
|  | current_function_info_->lowpc = data; | 
|  | break; | 
|  | case DW_AT_high_pc: | 
|  | current_function_info_->highpc = data; | 
|  | break; | 
|  | case DW_AT_decl_line: | 
|  | current_function_info_->line = data; | 
|  | break; | 
|  | case DW_AT_decl_file: | 
|  | current_function_info_->file = files_->at(data).name; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset, | 
|  | enum DwarfAttribute attr, | 
|  | enum DwarfForm form, | 
|  | uint64 data) { | 
|  | if (current_function_info_) { | 
|  | switch (attr) { | 
|  | case DW_AT_specification: { | 
|  | // Some functions have a "specification" attribute | 
|  | // which means they were defined elsewhere. The name | 
|  | // attribute is not repeated, and must be taken from | 
|  | // the specification DIE. Here we'll assume that | 
|  | // any DIE referenced in this manner will already have | 
|  | // been seen, but that's not really required by the spec. | 
|  | FunctionMap::iterator iter = offset_to_funcinfo_->find(data); | 
|  | if (iter != offset_to_funcinfo_->end()) { | 
|  | current_function_info_->name = iter->second->name; | 
|  | current_function_info_->mangled_name = iter->second->mangled_name; | 
|  | } else { | 
|  | // If you hit this, this code probably needs to be rewritten. | 
|  | fprintf(stderr, "Error: DW_AT_specification was seen before the referenced DIE! (Looking for DIE at offset %08llx, in DIE at offset %08llx)\n", data, offset); | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void CUFunctionInfoHandler::EndDIE(uint64 offset) { | 
|  | if (current_function_info_ && current_function_info_->lowpc) | 
|  | address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc, | 
|  | current_function_info_)); | 
|  | } | 
|  |  | 
|  | }  // namespace dwarf2reader |