2010-01-23 00:30:36 +01:00
// Copyright 2010 Google Inc. All Rights Reserved.
2008-10-09 01:56:02 +02:00
//
// 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.
2009-10-06 20:16:36 +02:00
# include <assert.h>
2008-10-09 01:56:02 +02:00
# include <map>
# include <queue>
# include <vector>
2009-12-15 18:06:21 +01:00
# include "common/dwarf/functioninfo.h"
2008-10-09 01:56:02 +02:00
2009-12-15 18:06:21 +01:00
# include "common/dwarf/bytereader.h"
2008-10-09 01:56:02 +02:00
namespace dwarf2reader {
CULineInfoHandler : : CULineInfoHandler ( vector < SourceFileInfo > * files ,
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 " ) ;
}
}
2010-01-23 00:30:36 +01:00
void CULineInfoHandler : : AddLine ( uint64 address , uint64 length , uint32 file_num ,
2008-10-09 01:56:02 +02:00
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 ) {
2008-12-08 14:12:45 +01:00
current_compilation_unit_offset_ = offset ;
2008-10-09 01:56:02 +02:00
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 ) {
2008-12-08 14:00:29 +01:00
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 ;
}
2008-10-09 01:56:02 +02:00
}
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 < 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 ;
2010-01-12 17:53:02 +01:00
default :
break ;
}
}
}
void CUFunctionInfoHandler : : ProcessAttributeReference ( uint64 offset ,
enum DwarfAttribute attr ,
enum DwarfForm form ,
uint64 data ) {
if ( current_function_info_ ) {
switch ( attr ) {
2008-12-08 14:12:45 +01:00
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.
2010-01-12 17:53:02 +01:00
FunctionMap : : iterator iter = offset_to_funcinfo_ - > find ( data ) ;
2008-12-08 14:12:45 +01:00
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.
2010-01-12 17:53:02 +01:00
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 ) ;
2008-12-08 14:12:45 +01:00
}
break ;
}
2008-10-09 01:56:02 +02:00
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