Tuesday, July 21, 2009

[Linux]GDB笔记

本文参考了如下资源
GDB quick reference: 一个很不错的cheatsheet
RMS的gdb tutorial
中文的gdb教程

1 最基本用法

最基本的gdb用法可以帮助你找到程序里哪里出现segment fault。首先你要在gcc编译的时候加上-ggdb选项。假定你的程序名叫foo,你可以用如下命令进入gdb开始program进行debug:
$ gdb foo
gdb会在你出现段错误的地方停下来,你会看到是哪个程序哪行语句出了问题.
2 Core Dump

发现了segment fault的话,还可以使用core dump。这样不但可以很方便的找到出问题的代码. 还可以多次重现这个错误。 首先使用以下的命令允许系统生成core文件.
$ ulimit -c unlimited
然后运行你的代码,比如叫foo, 等到segment fault发生并异常退出以后, 你会发现在foo的同一个文件夹下多了一个名字类似core.1234这样的文件。这时候运行如下命令就可以重现案发现场了
$ gdb foo core.1234

3 普通用法

r [arglist]: (重新)运行程序
b [file:]line, b [file:]function: 设置断点在line或者function
c, continue: 继续运行程序
s, step: 单步执行, 进入函数
n, next: 单步执行, 不进入函数
finish: 执行完当前frame
kill: 终止当前程序
q, Ctrl-d: 退出gdb
p [expr]: 显示表达式expr. 比如var表示变量var的内容而 &var表示变量var的内存地址
bt: 显示当前调用栈(call stack)
set args [arglist]: 设置命令行参数,从而可以直接用r(run)来执行

4 断点(breakpoit)/观察点(watchpoint)设置与管理

b [file:]line, b [file:]function: 设置断点在line或者function
watch [expr]: 设置观察点,一旦表达式expr有变化就停下来. expr通常为一个变量或者内存地址
rwatch [expr]: 设置观察点,一旦被读就停下程序
awatch [expr]: 设置观察点,一旦被读或者被写都停下程序
比如你可以使用awatch *(long*)addr来监视内存地址addr是否被读或者被写
info breakpoints/watchpoints: 查看当前设置了的断点和观察点, info watchpoints是info breakpoints的alias
enable/disable/delete [n]: 激活/禁用/删除 编号为[n]的断点/观察点

5 程序栈

bt, backtrace: 显示当前调用栈(call stack),比如
(gdb) bt
#0  0x000000010005ea07 in init (ctx=0x100622070, opts=@0x10060d078) at Utils.cpp:1678
#1  0x00000001000149ad in main (argc=3, argv=0x7fff5fbffb30) at main.cpp:591
frame: 改变frame,比如
(gdb) frame 1
#2  0x8048414 in main (argc=1, argv=0xbffffaf4) at test.c:19
19        x = func1(x);
info frame: 查看当前frame的信息
(gdb) info frame
Stack level 2, frame at 0xbffffa8c:
eip = 0x8048414 in main (test.c:19); saved eip 0x40037f5c
called by frame at 0xbffffac8, caller of frame at 0xbffffa5c 
source language c.
Arglist at 0xbffffa8c, args: argc=1, argv=0xbffffaf4
Locals at 0xbffffa8c, Previous frame's sp is 0x0
Saved registers:
ebp at 0xbffffa8c, eip at 0xbffffa90
info locals: 查看当前frame里的局部变量
(gdb) info locals
x = 30
s = 0x8048484 "Hello World!\n"
info args: 查看当前frame的调用参数
(gdb) info args
argc = 1
argv = (char **) 0xbffffaf4


6 查看变量/函数, 改变变量值

如果有一个指针变量it指向一个struct item, 查看这个struct item的内存地址:
(gdb) p it
$1 = (item *) 0x100700060
查看这个struct的内容
(gdb) p *it
$2 = {
  next = 0x100700000, 
  prev = 0x0
}
如果你有如下数组
int *array = (int *) malloc (len * sizeof (int));
你可以这样来查看你的数组
p *array@len
有时候你知道一段二进制代码所属的函数和偏移, 查这段对应的源代码:
list *myfunc+0x16

改变一个变量a的值为10
set variable a=10

7 查看内存

用命令"x /nfu <addr>"
n表示要显示的内存单元的个数
f表示显示方式, 可取如下值
x 按十六进制格式显示变量。
d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。
o 按八进制格式显示变量。
t 按二进制格式显示变量。
a 按十六进制格式显示变量。
i 指令地址格式
c 按字符格式显示变量。
f 按浮点数格式显示变量。
u表示一个地址单元的长度
b表示单字节,
h表示双字节,
w表示四字节,
g表示八字节

8 其他


info source: 查看当前frame对应的源文件信息

(gdb) info source
Current source file is shared_ptr.hpp
Compilation directory is /usr/local/include/boost/smart_ptr
Located in /usr/local/include/boost/smart_ptr/shared_ptr.hpp
Contains 712 lines.
Source language is c++.
Compiled with unknown debugging format.
Does not include preprocessor macro info.
info threads: 查看当前线程数目以及状态

(gdb) info threads
       Id   Target Id         Frame
       3    process 35 thread 27  0x34e5 in sigpause ()
       2    process 35 thread 23  0x34e5 in sigpause ()
     * 1    process 35 thread 13  main (argc=1, argv=0x7ffffff8)
         at threadtest.c:68

No comments: