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