在debug時, 若想知道是哪裡的code來call了某個API,
可以把__builtin_return_address(0)的value給印出來,
然後再透過addr2line查出line number.
下面的範例是追查哪裡的code去call了funcA().
ret.c1
2
3
4
5
6
7
8
9
10
11
12
| 1 #include <stdio.h>
2
3 void funcA(void)
4 {
5 printf("ret:0x%08x\n",__builtin_return_address(0));
6 }
7
8 int main(void)
9 {
10 funcA();
11 return 0 ;
12 }
|
Terminal1
2
3
4
5
6
7
| bramante@matrix:~/test$ gcc -g -o ret ret.c
bramante@matrix:~/test$ ./ret
ret:0x0040051f
bramante@matrix:~/test$ addr2line -Cfe ./ret 40051f
main
/home/bramante/test/ret.c:11
bramante@matrix:~/test$
|
addr2line查到的line number是執行完該API後的下一行,
如果想得到call API的那行的line number,
可以把address減1之後再查line number.
例如, 0x40051f - 1 = 0x40051e, 然後查0x40051e的line number.
Terminal1
2
3
4
| bramante@matrix:~/test$ addr2line -Cfe ./ret 40051e
main
/home/bramante/test/ret.c:10
bramante@matrix:~/test$
|
x86對 __builtin_return_address(n)的支援相當完整,
幾乎可以當成backtrace()來用,
MIPS和ARM對 __builtin_return_address()的支援則相當有限,
只支援了 __builtin_return_address(0),
而且還必需在API內的第一行就取值,
不然有可能會出錯.
在MIPS或ARM上, __builtin_return_address(0)要放在funcA()開頭的第一行,
才能確保得到的return address的value是正確的.
funcA()1
2
3
4
5
6
| void funcA(void)
{
unsigned int ret = (unsigned int) __builtin_return_address(0) ;//必須在API開頭的第一行就取值
....
printf("ret:0x%08x\n",ret);
}
|