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 分析函数执行流程】
推荐阅读
- 推荐系统论文进阶|CTR预估 论文精读(十一)--Deep Interest Evolution Network(DIEN)
- Python专栏|数据分析的常规流程
- Python|Win10下 Python开发环境搭建(PyCharm + Anaconda) && 环境变量配置 && 常用工具安装配置