Python|armclang 使用 instrument function 分析函数执行流程

1、添加编译选项 armcc 编译选项添加 --gnu_instrument(比如 CFLAGS += --gnu_instrument)
armclang 编译选项添加 -finstrument-functions (比如 CFLAGS +=-finstrument-functions)

2、申明 instrument 函数 void __cyg_profile_func_enter(void *this, void *callsite)__attribute__((no_instrument_function));
void __cyg_profile_func_exit(void *this, void *callsite)__attribute__((no_instrument_function));

3、定义 instrument 函数 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);
}
这里输出当前函数的地址(instrument 函数: __cyg_profile_func_enter 和 __cyg_profile_func_exit会分别在使用 -finstrument-functions 或--gnu_instrument 编译过的模块函数进入和退出时自动调用, 这两个函数的第一个参数是当前函数的函数地址,第二参数是调用该函数的函数地址).

4、分析maps 文件 编译器生成的maps 文件,其中生成的函数段格式如下:

function10x882f29a9Thumb Code28module.o(.text) function20x882f2861Thumb Code28module.o(.text)

假设 maps 文件名为 arm.map

5、运行程序得到 instrument 函数输出的函数地址 运行使用 instrument 函数重新编译过的模块,假设 fp 的文件名是 addr.txt, 运行程序后addr.txt 的内容如下
E0x882f29a9 E0x882f2861 X0x882f2861 X0x882f29a9

6、将输出的函数地址转换为函数名 原理很简单,就是到 map 文件中通过函数地址,找到对应的函数名称,这个过程我们使用 Pyhon 脚步完成
$ python3 addr2name.py arm.map addr.txt
Start address to name
function1
function2


addr2name.py 源码如下:
import sysdef find_name(fmap_name, addr): result="" with open(fmap_name, 'r') as fmap: for line in fmap: if line.find(addr) == -1: continue if line.split()[1] == addr: result = line[:] break return resultdef main(): print('Start address to name') fmap_name = sys.argv[1] faddr_name = sys.argv[2]with open(faddr_name, 'r') as faddr: for addr in faddr: #print(repr(addr)) addr = addr.strip() if not addr.startswith("E"): continue line = find_name(fmap_name, addr[1:]) print(line.split()[0]); if __name__ == '__main__': main()

【Python|armclang 使用 instrument function 分析函数执行流程】

    推荐阅读