gdbでスタックフレームを見てみる
最近Linuxプログラミングインターフェースの輪読をおこなっているので、その復習のため、ちょっと見てみました。
こんなソースを実行。 allocaはおまけです。
1 #include <stdio.h> 2 #include <alloca.h> 3 4 void test1(int *); 5 void test2(int *); 6 void test3(int *); 7 8 int main(int argc, char *argv) { 9 int a = 111; 10 test1(&a); 11 return 0; 12 } 13 14 void test1(int *a){ 15 printf("test1 : %d\n",*a); 16 printf("test1 address : %p\n",test1); 17 test2(a); 18 } 19 20 void test2(int *a){ 21 *a = 222; 22 void *x; 23 printf("test2 : %d\n",*a); 24 printf("test2 address : %p\n",test2); 25 x = alloca(4); 26 printf("alloca : %p\n",x); 27 test3(a); 28 } 29 30 void test3(int *a){ 31 *a = 333; 32 printf("test3 : %d\n",*a); 33 printf("test3 address : %p\n",test3); 34 }
gdbでdebugしてみる。 break pointの設定 && 実行
(gdb) break 34 Breakpoint 1 at 0x400678: file ./stack_test.c, line 34. (gdb) run Starting program: /home/foxtrot/stack_test/./a.out test1 : 111 test1 address : 0x400559 test2 : 222 test2 address : 0x40059e alloca : 0x7fffffffe510 test3 : 333 test3 address : 0x400637 Breakpoint 1, test3 (a=0x7fffffffe59c) at ./stack_test.c:34 34 } (gdb)
backtrace! 先頭からプログラムカウンタの値、関数名、引数、コードの実行箇所みたいです。
(gdb) backtrace #0 test3 (a=0x7fffffffe59c) at ./stack_test.c:34 #1 0x0000000000400635 in test2 (a=0x7fffffffe59c) at ./stack_test.c:27 #2 0x000000000040059c in test1 (a=0x7fffffffe59c) at ./stack_test.c:17 #3 0x0000000000400552 in main (argc=1, argv=0x7fffffffe688 "\253\350\377\377\377\177") at ./stack_test.c:10
frame 数字 を指定することで、実行しているソースコードの場所も見れます。 このときlistを実行することで、さらにその周りのソースコードも見れるとか。
(gdb) frame 1 #1 0x0000000000400635 in test2 (a=0x7fffffffe59c) at ./stack_test.c:27 27 test3(a); (gdb) list 22 void *x; 23 printf("test2 : %d\n",*a); 24 printf("test2 address : %p\n",test2); 25 x = alloca(4); 26 printf("alloca : %p\n",x); 27 test3(a); 28 } 29 30 void test3(int *a){ 31 *a = 333;
info localsでローカル変数。info argsで引数
(gdb) info args a = 0x7fffffffe59c (gdb) info locals x = 0x7fffffffe510
info frame 数字 でより詳しい情報がみれます。 呼び出し元とか呼び出し先とかプログラムカウンタの値とか。
(gdb) info frame 0 Stack frame at 0x7fffffffe510: rip = 0x400678 in test3 (./stack_test.c:34); saved rip 0x400635 called by frame at 0x7fffffffe560 source language c. Arglist at 0x7fffffffe500, args: a=0x7fffffffe59c Locals at 0x7fffffffe500, Previous frame's sp is 0x7fffffffe510 Saved registers: rbp at 0x7fffffffe500, rip at 0x7fffffffe508 (gdb) info frame 1 Stack frame at 0x7fffffffe560: rip = 0x400635 in test2 (./stack_test.c:27); saved rip 0x40059c called by frame at 0x7fffffffe580, caller of frame at 0x7fffffffe510 source language c. Arglist at 0x7fffffffe550, args: a=0x7fffffffe59c Locals at 0x7fffffffe550, Previous frame's sp is 0x7fffffffe560 Saved registers: rbp at 0x7fffffffe550, rip at 0x7fffffffe558 (gdb) info frame 2 Stack frame at 0x7fffffffe580: rip = 0x40059c in test1 (./stack_test.c:17); saved rip 0x400552 called by frame at 0x7fffffffe5b0, caller of frame at 0x7fffffffe560 source language c. Arglist at 0x7fffffffe570, args: a=0x7fffffffe59c Locals at 0x7fffffffe570, Previous frame's sp is 0x7fffffffe580 Saved registers: rbp at 0x7fffffffe570, rip at 0x7fffffffe578 (gdb) info frame 3 Stack frame at 0x7fffffffe5b0: rip = 0x400552 in main (./stack_test.c:10); saved rip 0x7ffff7a3bb15 caller of frame at 0x7fffffffe580 source language c. Arglist at 0x7fffffffe5a0, args: argc=1, argv=0x7fffffffe688 "\253\350\377\377\377\177" Locals at 0x7fffffffe5a0, Previous frame's sp is 0x7fffffffe5b0 Saved registers: rbp at 0x7fffffffe5a0, rip at 0x7fffffffe5a8
Stack frame at xxxxの箇所が、Stackのメモリアドレスなのかな。 試しにallocaに大きな値を入れてみた。
25 x = alloca(64);
これでgdbで再度見てみると確かに値が変わっている! 前回はframe 0の値が「Stack frame at 0x7fffffffe510:」だったけれども、今回は「Stack frame at 0x7fffffffe4e0:」になっている。
(gdb) info frame 0 Stack frame at 0x7fffffffe4e0: rip = 0x4006c2 in test3 (./stack_test.c:37); saved rip 0x400635 called by frame at 0x7fffffffe560 source language c. Arglist at 0x7fffffffe4d0, args: a=0x7fffffffe59c Locals at 0x7fffffffe4d0, Previous frame's sp is 0x7fffffffe4e0 Saved registers: rbp at 0x7fffffffe4d0, rip at 0x7fffffffe4d8 (gdb) info frame 1 Stack frame at 0x7fffffffe560: rip = 0x400635 in test2 (./stack_test.c:27); saved rip 0x40059c called by frame at 0x7fffffffe580, caller of frame at 0x7fffffffe4e0 source language c. Arglist at 0x7fffffffe550, args: a=0x7fffffffe59c Locals at 0x7fffffffe550, Previous frame's sp is 0x7fffffffe560 Saved registers: rbp at 0x7fffffffe550, rip at 0x7fffffffe558
ripとかは退避したプログラムカウンタの値?ripはeipの64bit版なんですかね。。 なんか調べると奥が深そうだから、また今度!