// Copyright 2006 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 #include #include #include "common/mac/dwarf/functioninfo.h" #include "common/mac/dwarf/bytereader.h" namespace dwarf2reader { // Given an offset value, its form, and the base offset of the // compilation unit containing this value, return an absolute offset // within the .debug_info section. uint64 GetAbsoluteOffset(uint64 offset, enum DwarfForm form, uint64 compilation_unit_base) { switch (form) { case DW_FORM_ref1: case DW_FORM_ref2: case DW_FORM_ref4: case DW_FORM_ref8: case DW_FORM_ref_udata: return offset + compilation_unit_base; case DW_FORM_ref_addr: default: return offset; } } CULineInfoHandler::CULineInfoHandler(vector* files, vector* 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, uint32 file_num, uint32 line_num, uint32 column_num) { if (file_num < files_->size()) { linemap_->insert(make_pair(address, 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(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 :-( auto_ptr 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; 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. uint64 abs_offset = GetAbsoluteOffset(data, form, current_compilation_unit_offset_); FunctionMap::iterator iter = offset_to_funcinfo_->find(abs_offset); 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", abs_offset, offset); } break; } default: break; } } } void CUFunctionInfoHandler::EndDIE(uint64 offset) { if (current_function_info_ && current_function_info_->lowpc) address_to_funcinfo_->insert(make_pair(current_function_info_->lowpc, current_function_info_)); } } // namespace dwarf2reader