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

    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()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章