diff --git a/include/dwarfstack.h b/include/dwarfstack.h index 01fbbcf..0565ce2 100644 --- a/include/dwarfstack.h +++ b/include/dwarfstack.h @@ -44,6 +44,9 @@ extern "C" { // funcname: function name // context: user-provided pointer (callbackContext) // columnno: column number +// For an address inside inlined code, the callback is called once per +// inlined function (innermost first) and finally for the containing +// function; addr is 0 for all but the first of these calls. typedef void dwstCallback( uint64_t addr,const char *filename,int lineno,const char *funcname, void *context,int columnno ); @@ -75,6 +78,19 @@ typedef void dwstCallbackW( // filename: executable location #define DWST_NOT_FOUND -3 +// DWST_LINE_ADDR: start address of the source line (only dwstOfModule()) +// addr: line address +// (0 for the outer frames of inlined code) +// filename: NULL +// funcname: function name +#define DWST_LINE_ADDR -4 + +// DWST_FUNC_ADDR: start address of the function (only dwstOfModule()) +// addr: function address +// filename: NULL +// funcname: function name +#define DWST_FUNC_ADDR -5 + // dwstOfFile(): stack information of file // name: executable location @@ -95,6 +111,42 @@ EXPORT int dwstOfFileW( dwstCallbackW *callbackFunc,void *callbackContext ); +typedef struct dwst_module dwst_module; + +// dwstModuleOpen(): prepare debug information for repeated lookups +// dbg: Dwarf_Debug of the executable +// (has to stay valid until dwstModuleClose()) +// imageBase_dbg: preferred image base address of the executable +EXPORT dwst_module *dwstModuleOpen( + void *dbg,uint64_t imageBase_dbg ); + +// dwstModuleClose(): free module created by dwstModuleOpen() +// (dbg itself is not freed) +// module: module handle +EXPORT void dwstModuleClose( + dwst_module *module ); + +// dwstOfModule(): stack information of module +// (like dwstOfFile(), but additionally reports DWST_FUNC_ADDR and +// DWST_LINE_ADDR before each resolved frame) +// module: module handle from dwstModuleOpen() +// name: executable location +// imageBase: used image base address +// addr: stack addresses +// count: number of addresses +// callbackFunc: callback function +// callbackContext: user-provided pointer (context) +EXPORT int dwstOfModule( + dwst_module *module,const char *name,uint64_t imageBase, + uint64_t *addr,int count, + dwstCallback *callbackFunc,void *callbackContext ); + +EXPORT int dwstOfModuleW( + dwst_module *module,const wchar_t *name,uint64_t imageBase, + uint64_t *addr,int count, + dwstCallbackW *callbackFunc,void *callbackContext ); + + // dwstOfProcess(): stack information of current process // addr: stack addresses // count: number of addresses diff --git a/src/dwst-file.c b/src/dwst-file.c index 76d3f3c..c70792a 100644 --- a/src/dwst-file.c +++ b/src/dwst-file.c @@ -267,8 +267,29 @@ typedef struct inline_info uint64_t ptrOrig; int fileno,lineno,columnno; int fileno_offs; + Dwarf_Addr lineaddr; + uint64_t baseOffs; + int reportAddrs; } inline_info; +// report start addresses of function and source line +static void dwarf_callback_addrs( inline_info *cuInfo, + Dwarf_Addr low,const char *funcname ) +{ + if( !cuInfo->reportAddrs ) return; + + if( low ) + dwarf_callback( cuInfo->callbackFunc,cuInfo->callbackFuncW, + low - cuInfo->baseOffs,NULL,NULL, + DWST_FUNC_ADDR,funcname,cuInfo->callbackContext,cuInfo->columnno ); + + // lineaddr is 0 for the outer frames of inlined code, DWARF doesn't + // store where the code of the call line starts + dwarf_callback( cuInfo->callbackFunc,cuInfo->callbackFuncW, + cuInfo->lineaddr ? cuInfo->lineaddr - cuInfo->baseOffs : 0,NULL,NULL, + DWST_LINE_ADDR,funcname,cuInfo->callbackContext,cuInfo->columnno ); +} + // find the calling-location of inlined functions static int findInlined( Dwarf_Debug dbg,Dwarf_Die die,inline_info *cuInfo ) { @@ -353,6 +374,7 @@ static int findInlined( Dwarf_Debug dbg,Dwarf_Die die,inline_info *cuInfo ) if( cuInfo->ptrptr>=highpc ) continue; + low = lowpc; break; } @@ -366,6 +388,8 @@ static int findInlined( Dwarf_Debug dbg,Dwarf_Die die,inline_info *cuInfo ) { char *funcname = dwarf_name_of_func_linked( dbg,die ); + dwarf_callback_addrs( cuInfo,low,funcname ); + dwarf_callback( cuInfo->callbackFunc,cuInfo->callbackFuncW, cuInfo->ptrOrig,cuInfo->files[cuInfo->fileno],NULL, cuInfo->lineno,funcname,cuInfo->callbackContext,cuInfo->columnno ); @@ -394,6 +418,8 @@ static int findInlined( Dwarf_Debug dbg,Dwarf_Die die,inline_info *cuInfo ) { char *funcname = dwarf_name_of_func_linked( dbg,die ); + dwarf_callback_addrs( cuInfo,low,funcname ); + dwarf_callback( cuInfo->callbackFunc,cuInfo->callbackFuncW, cuInfo->ptrOrig,cuInfo->files[cuInfo->fileno],NULL, cuInfo->lineno,funcname,cuInfo->callbackContext,cuInfo->columnno ); @@ -402,6 +428,7 @@ static int findInlined( Dwarf_Debug dbg,Dwarf_Die die,inline_info *cuInfo ) cuInfo->lineno = lineno; cuInfo->columnno = 0; cuInfo->ptrOrig = 0; + cuInfo->lineaddr = 0; Dwarf_Attribute callcolumn; if( dwarf_attr(die,DW_AT_call_column,&callcolumn,NULL)==DW_DLV_OK ) @@ -444,30 +471,21 @@ typedef struct cu_info int rangeCount; } cu_info; -int dwstOfFileExt( - const char *name,const wchar_t *nameW,uint64_t imageBase, - uint64_t *addr,int count, - dwstCallback *callbackFunc,dwstCallbackW *callbackFuncW, - void *callbackContext ) +struct dwst_module { - if( !nameW || !addr || !count || (!callbackFunc && !callbackFuncW) ) - return( 0 ); - - if( imageBase ) - dwarf_callback( callbackFunc,callbackFuncW,imageBase,name,nameW, - DWST_BASE_ADDR,NULL,callbackContext,0 ); - - Dwarf_Addr imageBase_dbg; Dwarf_Debug dbg; - if( dwarf_pe_init(nameW,&imageBase_dbg,0,0,&dbg,NULL)!=DW_DLV_OK ) - { - int i; - for( i=0; idbg = dbg; + module->imageBase_dbg = imageBase_dbg; + module->cuArr = cuArr; + module->cuQty = cuQty; + + return( module ); +} + +static int dwstOfModuleExt( + dwst_module *module,const char *name,const wchar_t *nameW, + uint64_t imageBase,uint64_t *addr,int count, + dwstCallback *callbackFunc,dwstCallbackW *callbackFuncW, + void *callbackContext,int reportAddrs ) +{ + if( !module || !addr || !count || (!callbackFunc && !callbackFuncW) ) + return( 0 ); + + Dwarf_Debug dbg = module->dbg; + Dwarf_Addr imageBase_dbg = module->imageBase_dbg; + cu_info *cuArr = module->cuArr; + int cuQty = module->cuQty; + uint64_t baseOffs = 0; if( imageBase ) { @@ -664,6 +704,7 @@ int dwstOfFileExt( Dwarf_Unsigned srcfileno = 0; Dwarf_Unsigned lineno = 0; Dwarf_Unsigned columnno = 0; + Dwarf_Addr lineaddr = 0; if( lines ) { int c; @@ -686,6 +727,7 @@ int dwstOfFileExt( continue; } + dwarf_lineaddr( lines[c-1],&lineaddr,NULL ); dwarf_line_srcfileno( lines[c-1],&srcfileno,NULL ); dwarf_lineno( lines[c-1],&lineno,NULL ); dwarf_lineoff_b( lines[c-1],&columnno,NULL ); @@ -715,7 +757,7 @@ int dwstOfFileExt( inline_info ii = { ptr,cuInfo->base, files,fileCount,callbackFunc,callbackFuncW,callbackContext, ptrOrig,(int)srcfileno+cuInfo->fileno_offs,lineno,columnno, - cuInfo->fileno_offs }; + cuInfo->fileno_offs,lineaddr,baseOffs,reportAddrs }; walkChildren( dbg,die,(ChildWalker*)findInlined,&ii ); } else @@ -734,6 +776,18 @@ int dwstOfFileExt( DWST_NOT_FOUND,NULL,callbackContext,0 ); } + return( i ); +} + +void dwstModuleClose( + dwst_module *module ) +{ + if( !module ) return; + + Dwarf_Debug dbg = module->dbg; + cu_info *cuArr = module->cuArr; + int cuQty = module->cuQty; + int j; for( j=0; j