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: // This is a client for the dwarf2reader to extract function and line michael@0: // information from the debug info. michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "common/dwarf/functioninfo.h" michael@0: #include "common/dwarf/bytereader.h" michael@0: #include "common/using_std_string.h" michael@0: michael@0: namespace dwarf2reader { michael@0: michael@0: CULineInfoHandler::CULineInfoHandler(std::vector* files, michael@0: std::vector* dirs, michael@0: LineMap* linemap):linemap_(linemap), michael@0: files_(files), michael@0: dirs_(dirs) { michael@0: // The dirs and files are 1 indexed, so just make sure we put michael@0: // nothing in the 0 vector. michael@0: assert(dirs->size() == 0); michael@0: assert(files->size() == 0); michael@0: dirs->push_back(""); michael@0: SourceFileInfo s; michael@0: s.name = ""; michael@0: s.lowpc = ULLONG_MAX; michael@0: files->push_back(s); michael@0: } michael@0: michael@0: void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) { michael@0: // These should never come out of order, actually michael@0: assert(dir_num == dirs_->size()); michael@0: dirs_->push_back(name); michael@0: } michael@0: michael@0: void CULineInfoHandler::DefineFile(const string& name, michael@0: int32 file_num, uint32 dir_num, michael@0: uint64 mod_time, uint64 length) { michael@0: assert(dir_num >= 0); michael@0: assert(dir_num < dirs_->size()); michael@0: michael@0: // These should never come out of order, actually. michael@0: if (file_num == (int32)files_->size() || file_num == -1) { michael@0: string dir = dirs_->at(dir_num); michael@0: michael@0: SourceFileInfo s; michael@0: s.lowpc = ULLONG_MAX; michael@0: michael@0: if (dir == "") { michael@0: s.name = name; michael@0: } else { michael@0: s.name = dir + "/" + name; michael@0: } michael@0: michael@0: files_->push_back(s); michael@0: } else { michael@0: fprintf(stderr, "error in DefineFile"); michael@0: } michael@0: } michael@0: michael@0: void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num, michael@0: uint32 line_num, uint32 column_num) { michael@0: if (file_num < files_->size()) { michael@0: linemap_->insert( michael@0: std::make_pair(address, michael@0: std::make_pair(files_->at(file_num).name.c_str(), michael@0: line_num))); michael@0: michael@0: if(address < files_->at(file_num).lowpc) { michael@0: files_->at(file_num).lowpc = address; michael@0: } michael@0: } else { michael@0: fprintf(stderr,"error in AddLine"); michael@0: } michael@0: } michael@0: michael@0: bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset, michael@0: uint8 address_size, michael@0: uint8 offset_size, michael@0: uint64 cu_length, michael@0: uint8 dwarf_version) { michael@0: current_compilation_unit_offset_ = offset; michael@0: return true; michael@0: } michael@0: michael@0: michael@0: // For function info, we only care about subprograms and inlined michael@0: // subroutines. For line info, the DW_AT_stmt_list lives in the michael@0: // compile unit tag. michael@0: michael@0: bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) { michael@0: switch (tag) { michael@0: case DW_TAG_subprogram: michael@0: case DW_TAG_inlined_subroutine: { michael@0: current_function_info_ = new FunctionInfo; michael@0: current_function_info_->lowpc = current_function_info_->highpc = 0; michael@0: current_function_info_->name = ""; michael@0: current_function_info_->line = 0; michael@0: current_function_info_->file = ""; michael@0: offset_to_funcinfo_->insert(std::make_pair(offset, michael@0: current_function_info_)); michael@0: }; michael@0: // FALLTHROUGH michael@0: case DW_TAG_compile_unit: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: // Only care about the name attribute for functions michael@0: michael@0: void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: const string &data) { michael@0: if (current_function_info_) { michael@0: if (attr == DW_AT_name) michael@0: current_function_info_->name = data; michael@0: else if(attr == DW_AT_MIPS_linkage_name) michael@0: current_function_info_->mangled_name = data; michael@0: } michael@0: } michael@0: michael@0: void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: uint64 data) { michael@0: if (attr == DW_AT_stmt_list) { michael@0: SectionMap::const_iterator iter = sections_.find("__debug_line"); michael@0: assert(iter != sections_.end()); michael@0: michael@0: // this should be a scoped_ptr but we dont' use boost :-( michael@0: std::auto_ptr lireader(new LineInfo(iter->second.first + data, michael@0: iter->second.second - data, michael@0: reader_, linehandler_)); michael@0: lireader->Start(); michael@0: } else if (current_function_info_) { michael@0: switch (attr) { michael@0: case DW_AT_low_pc: michael@0: current_function_info_->lowpc = data; michael@0: break; michael@0: case DW_AT_high_pc: michael@0: current_function_info_->highpc = data; michael@0: break; michael@0: case DW_AT_decl_line: michael@0: current_function_info_->line = data; michael@0: break; michael@0: case DW_AT_decl_file: michael@0: current_function_info_->file = files_->at(data).name; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset, michael@0: enum DwarfAttribute attr, michael@0: enum DwarfForm form, michael@0: uint64 data) { michael@0: if (current_function_info_) { michael@0: switch (attr) { michael@0: case DW_AT_specification: { michael@0: // Some functions have a "specification" attribute michael@0: // which means they were defined elsewhere. The name michael@0: // attribute is not repeated, and must be taken from michael@0: // the specification DIE. Here we'll assume that michael@0: // any DIE referenced in this manner will already have michael@0: // been seen, but that's not really required by the spec. michael@0: FunctionMap::iterator iter = offset_to_funcinfo_->find(data); michael@0: if (iter != offset_to_funcinfo_->end()) { michael@0: current_function_info_->name = iter->second->name; michael@0: current_function_info_->mangled_name = iter->second->mangled_name; michael@0: } else { michael@0: // If you hit this, this code probably needs to be rewritten. michael@0: 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); michael@0: } michael@0: break; michael@0: } michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void CUFunctionInfoHandler::EndDIE(uint64 offset) { michael@0: if (current_function_info_ && current_function_info_->lowpc) michael@0: address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc, michael@0: current_function_info_)); michael@0: } michael@0: michael@0: } // namespace dwarf2reader