Builtin Return Address

- - | Comments

在debug時, 若想知道是哪裡的code來call了某個API, 可以把__builtin_return_address(0)的value給印出來, 然後再透過addr2line查出line number.

下面的範例是追查哪裡的code去call了funcA().

ret.c
1
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  }

Terminal
1
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.

Terminal
1
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);
}

Comments