我想将系统启动时调用的函数地址或名称存储到系统崩溃中。在程序执行期间调用时,有没有办法从任何硬件寄存器中检索这些函数地址?
答案 0 :(得分:2)
生成用于进入和退出函数的检测调用。在函数输入之后和函数退出之前,使用当前函数的地址及其调用站点调用以下分析函数。 (在某些平台上,__ builtin_return_address不能在当前函数之外工作,否则调用站点信息可能无法用于分析功能。)
void __cyg_profile_func_enter (void *this_fn, void *call_site); void __cyg_profile_func_exit (void *this_fn, void *call_site);
示例:
#include <stdio.h>
void __cyg_profile_func_enter(void * this_fn, void * call_site)
{
fprintf(stderr, "enter: %p %p\n", this_fn, call_site);
}
void __cyg_profile_func_exit(void * this_fn, void * call_site)
{
fprintf(stderr, " exit: %p %p\n", this_fn, call_site);
}
void foo(void);
void bar(void);
void foo(void)
{
bar();
return;
}
void bar(void)
{
return;
}
int main(void)
{
bar();
foo();
return 0;
}
使用以下方法编译和链接:
gcc -finstrument-functions -finstrument-functions-exclude-function-list=__cyg_profile_func_enter,__cyg_profile_func_exit -Wall -g -o main main.c
预期输出看起来与此相似:
enter: 0x400665 0x7fcfedaf6c8d
enter: 0x400643 0x400681
exit: 0x400643 0x400681
enter: 0x40061c 0x400686
enter: 0x400643 0x400633
exit: 0x400643 0x400633
exit: 0x40061c 0x400686
exit: 0x400665 0x7fcfedaf6c8d
答案 1 :(得分:1)
答案 2 :(得分:0)
您无法在函数本身中保存函数地址,并且在执行期间无法访问函数名称,但可以在调用函数之前保存它:
savefptr(myfunction);
savefname("myfunction");
myfunction(a,b,c);
使用savefptr()
和savefname()
的适当定义。
如果这样做是为了跟踪/调试(例如,您希望生成一个日志以了解代码中发生了什么),那么使用__FILE__
跟踪文件名和代码行可能会很好。 __LINE__
宏:
fprintf (stderr, "I'm in:'%s' line %d.",
__FILE__, __LINE__);
如果可以避免使用编译器或操作系统细节,我会建议。
答案 3 :(得分:0)
我只在* nix系统下做了类似的工作,因此我根据* nix为你提供了我的解决方案。
我假设您使用gcc
作为默认编译器,然后您最好在makefile中启用-finstrument-functions
和-fdump-rtl-expand
,例如:
CFLAGS += -Wall -O -ggdb -Wstrict-prototypes -Wno-pointer-sign -finstrument-functions -fdump-rtl-expand
在此之后,您可以实现跟踪功能,例如,your_trace.c:
#include <stdio.h>
#include <stdlib.h>
/* Function prototypes with attributes */
void main_constructor( void )
__attribute__ ((no_instrument_function, constructor));
void main_destructor( void )
__attribute__ ((no_instrument_function, destructor));
void __cyg_profile_func_enter( void *, void * )
__attribute__ ((no_instrument_function));
void __cyg_profile_func_exit( void *, void * )
__attribute__ ((no_instrument_function));
static FILE *fp;
void main_constructor( void )
{
fp = fopen( "trace.txt", "w" );
if (fp == NULL) exit(-1);
}
void main_deconstructor( void )
{
fclose( fp );
}
void __cyg_profile_func_enter( void *this, void *callsite )
{
fprintf(fp, "E%p\n", (int *)this);
}
void __cyg_profile_func_exit( void *this, void *callsite )
{
fprintf(fp, "X%p\n", (int *)this);
}
在这些之后,在编译代码之后,您将看到一个* .map文件,其中包含函数信息。也用trace.c编译,如果只是在编译后运行输出文件,它会生成函数调用信息,即trace.txt
文件,它有函数地址,你可以使用add2line
查看每个其中或者您可以使用pvtrace
工具来获取trace.txt
的函数调用,例如,我编译的程序名为DEMO
,然后:
-> pvtrace ./DEMO
您将获得graph.dot
并记录您的运行时函数调用。
OR
只需启用-ggdb
并使用调试工具查看每个功能地址,例如DDD
或GDB
。