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

    技术2022-07-12  70

    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 文件,其中生成的函数段格式如下:

    function1 0x882f29a9 Thumb Code 28 module.o(.text) function2 0x882f2861 Thumb Code 28 module.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 sys def 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 result def 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()

     

    Processed: 0.016, SQL: 9