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

 

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