4. 堆栈

查看调用堆栈(call stack)无疑是调试过程中非常重要的事情。

(gdb) where # 查看调用堆栈 (相同作用的命令还有 info s 和 bt)

#0 test (a=4096, b=8192) at hello.c:5
#1 0x0804843b in main () at hello.c:13

(gdb) frame # 查看当前堆栈帧,还可显示当前代码

#0 test (a=4096, b=8192) at hello.c:5
5 int c = a + b;

(gdb) info frame # 获取当前堆栈帧更详细的信息

可以用 frame 修改当前堆栈帧,然后查看其详细信息。

(gdb) frame 1

#1 0x0804843b in main () at hello.c:13
13 int c = test(a, b);

(gdb) info frame

 5. 变量和参数

(gdb) info locals # 显示局部变量

c = 0

(gdb) info args # 显示函数参数(自变量)

8. 进程

查看进程相关信息,尤其是 maps 内存数据是非常有用的。

(gdb) help info proc stat

Show /proc process information about any running process.
Specify any process id, or use the program being debugged by default.
Specify any of the following keywords for detailed info:

mappings – list of mapped memory regions.
stat – list a bunch of random process info.
status – list a different bunch of random process info.
all – list all available /proc info.

(gdb) info proc mappings # 相当于 cat /proc/{pid}/maps

 

process 22561
cmdline = ‘/home/yuhen/Learn.c/hello’
cwd = ‘/home/yuhen/Learn.c’
exe = ‘/home/yuhen/Learn.c/hello’
Mapped address spaces:

Start Addr   End Addr       Size     Offset objfile
0x8048000 0x8049000 0x1000 0 /home/yuhen/Learn.c/hello
0x8049000 0x804a000 0x1000 0 /home/yuhen/Learn.c/hello
0x804a000 0x804b000 0x1000 0x1000 /home/yuhen/Learn.c/hello
0x8a33000 0x8a54000 0x21000 0x8a33000 [heap]
0xb7565000 0xb7f67000 0xa02000 0xb7565000
0xb7f67000 0xb80c3000 0x15c000 0 /lib/tls/i686/cmov/libc-2.9.so
0xb80c3000 0xb80c4000 0x1000 0x15c000 /lib/tls/i686/cmov/libc-2.9.so
0xb80c4000 0xb80c6000 0x2000 0x15c000 /lib/tls/i686/cmov/libc-2.9.so
0xb80c6000 0xb80c7000 0x1000 0x15e000 /lib/tls/i686/cmov/libc-2.9.so
0xb80c7000 0xb80ca000 0x3000 0xb80c7000
0xb80d7000 0xb80d9000 0x2000 0xb80d7000
0xb80d9000 0xb80da000 0x1000 0xb80d9000 [vdso]
0xb80da000 0xb80f6000 0x1c000 0 /lib/ld-2.9.so
0xb80f6000 0xb80f7000 0x1000 0x1b000 /lib/ld-2.9.so
0xb80f7000 0xb80f8000 0x1000 0x1c000 /lib/ld-2.9.so
0xbfee2000 0xbfef7000 0x15000 0xbffeb000 [stack]</pre>

9. 线程

可以在 pthread_create 处设置断点,当线程创建时会生成提示信息。

(gdb) c

Continuing.
[New Thread 0xb7e78b70 (LWP 2933)]

(gdb) info threads # 查看所有线程列表

 

  • 2 Thread 0xb7e78b70 (LWP 2933) test (arg=0x804b008) at main.c:24
    1 Thread 0xb7e796c0 (LWP 2932) 0xb7fe2430 in __kernel_vsyscall ()
(gdb) where # 显示当前线程调用堆栈

#0 test (arg=0x804b008) at main.c:24
#1 0xb7fc580e in start_thread (arg=0xb7e78b70) at pthread_create.c:300
#2 0xb7f478de in clone () at …/sysdeps/unix/sysv/linux/i386/clone.S:130

(gdb) thread 1 # 切换线程

 

[Switching to thread 1 (Thread 0xb7e796c0 (LWP 2932))]#0 0xb7fe2430 in __kernel_vsyscall ()

(gdb) where # 查看切换后线程调用堆栈

 

#0 0xb7fe2430 in __kernel_vsyscall ()
#1 0xb7fc694d in pthread_join (threadid=3085405040, thread_return=0xbffff744) at pthread_join.c:89
#2 0x08048828 in main (argc=1, argv=0xbffff804) at main.c:36

10. 其他

调试子进程。

(gdb) set follow-fork-mode child

临时进入 Shell 执行命令,Exit 返回。

(gdb) shell

调试时直接调用函数。

(gdb) call test("abc")

使用 "--tui" 参数,可以在终端窗口上部显示一个源代码查看窗。

$ gdb --tui hello

查看命令帮助。

(gdb) help b

最后就是退出命令。

(gdb) q

和 Linux Base Shell 习惯一样,对于记不住的命令,可以在输入前几个字母后按 Tab 补全。

----------- 分隔线 ---------------

GDB 还有很多指令,功能也异常强大。不过对于熟悉了 VS 那种豪华 IDE 的人来说,这种命令行调试是种巨大的痛苦。尽管我个人建议多用 GDB,但也不反对用 GUI 调试器来加快调试进程。​​​Nemiver​​ 就不错,推荐一下。