我有時候對於程式呼叫不明顯的時候,看程式很費勁,這時候我們希望把程式呼叫鏈列印出來。
對於庫函式提供了執行緒介面。backtrace()、backtrace_symbols()、backtrace_symbols_fd()
其實網上的教程都是結合這個示例寫的。我的也不例外。
直接上核心部分,如果你想看func_1的上級呼叫是誰,可以把這個介面放到這個函式裡。
void print_stack(void)
for(j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);
}
#include#include#include#includevoid print_stack(void)
for(j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);}
/* "static" means don't export the symbol... */
//static void myfunc2(void)
void myfunc2(void)
void myfunc1()
int main(int argc,char *ar**)
注意,在生成可執行檔案的編譯選項裡加上-rdynamic ,否則你看到的只是呼叫棧位址。
#makeile
main:main.o
gcc -rdynamic main.o -o main
main.o:main.c
gcc -c -g -wall main.c -o main.o
.phony:clean
clean:
rm -rf *.o main
可以看到函式呼叫鏈是main->myfunc1->myfunc2->print_stack
backtrace() returned 6 addresses
./main(print_stack+0x2e) [0x400a54]
./main(myfunc2+0x9) [0x400b22]
./main(myfunc1+0x9) [0x400b2e]
./main(main+0x19) [0x400b4a]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f34f6502840]
./main(_start+0x29) [0x400959]
如果makefile中不加-rdynamic選項,執行的結果如下:
可以看到,只有呼叫棧位址資訊,沒有函式名。但是可以借助符號表檢視呼叫棧位址表示什麼函式。
./main() [0x400784]
./main() [0x400852]
./main() [0x40085e]
./main() [0x40087a]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0) [0x7f301a281840]
./main() [0x400689]
需要先生成.out檔案,
gcc main.c main.out
然後借助.out檔案檢視符號表。
nm -n main.out
列印的符號表如下:
0000000000400756 t print_stack -> ./main() [0x400784]
0000000000400849 t myfunc2 -> ./main.out() [0x400852]
0000000000400855 t myfunc1 -> ./main.out() [0x40085e]
0000000000400861 t main -> ./main.out() [0x40087a]
符號表:
u backtrace@@glibc_2.2.5
u backtrace_symbols@@glibc_2.2.5
u exit@@glibc_2.2.5
u free@@glibc_2.2.5
w __gmon_start__
w _itm_deregistertmclonetable
w _itm_registertmclonetable
w _jv_registerclasses
u __libc_start_main@@glibc_2.2.5
u perror@@glibc_2.2.5
u printf@@glibc_2.2.5
u puts@@glibc_2.2.5
u __stack_chk_fail@@glibc_2.4
0000000000400588 t _init
0000000000400660 t _start
0000000000400690 t deregister_tm_clones
00000000004006d0 t register_tm_clones
0000000000400710 t __do_global_dtors_aux
0000000000400730 t frame_dummy
0000000000400756 t print_stack
0000000000400849 t myfunc2
0000000000400855 t myfunc1
0000000000400861 t main
0000000000400890 t __libc_csu_init
0000000000400900 t __libc_csu_fini
0000000000400904 t _fini
0000000000400910 r _io_stdin_used
0000000000400950 r __gnu_eh_frame_hdr
0000000000400af0 r __frame_end__
0000000000600e10 t __frame_dummy_init_array_entry
0000000000600e10 t __init_array_start
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000600e18 t __init_array_end
0000000000600e20 d __jcr_end__
0000000000600e20 d __jcr_list__
0000000000600e28 d _dynamic
0000000000601000 d _global_offset_table_
0000000000601060 d __data_start
0000000000601060 w data_start
0000000000601068 d __dso_handle
0000000000601070 b __bss_start
0000000000601070 b completed.7594
0000000000601070 d _edata
0000000000601070 d __tmc_end__
0000000000601078 b _end
#include#include#include#includevoid myfunc3(void)
for(j = 0; j < nptrs; j++)
printf("%s\n", strings[j]);
free(strings);}
/* "static" means don't export the symbol... */
//void myfunc2(void)
static void myfunc2(void)
void myfunc(int ncalls)
int main(int argc,char *ar**)
myfunc(atoi(ar**[1]));
exit(exit_success);
}
man backtrace linux下列印呼叫棧
include include include include stacktrace.h 列印呼叫棧的最大深度 define dump stack depth max 16 列印呼叫棧函式 void dump trace char stack strings null int stack depth...
函式呼叫棧
當程式進行函式呼叫的時候,系統會用到下面三種暫存器 3.ebp ebp暫存器裡儲存的是棧基址,是在函式呼叫之前,由esp賦值給ebp的。棧底方向,高位位址 call fun arg1,arg2,arg3 修改esp,棧向下增長,引數入棧,返回位址入棧 arg3 arg2 arg1 返回位址 上一層e...
棧 函式呼叫
編譯以下程式,分析此程式以得出棧的精髓 1 主函式被上層呼叫者呼叫後,執行push ebp,esp 4 因為ebp入棧 ebp值沒有改變,值得注意的是剛開始分配站的時候,第乙個入棧的是return,主函式的返回位址,然後是ebp 2 然後是mov ebp,esp,將esp的值賦給ebp,該語句未執行...