http://wiki.ubuntu.org.cn/index.php?title=%E7%94%A8GDB%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F&variant=zh-hans
http://simohayha.iteye.com/blog/493091
gdbtui
call 函数(参数):调用程序中可见的函数,并传递“参数”,如:call gdb_test(55)
- print gdb_test(22):将以整数22作为参数调用 gdb_test() 函数
- print gdb_test(a):将以变量 a 作为参数调用 gdb_test() 函数
- 扩展info locals: 显示当前堆栈页的所有变量
-
分割窗口
- layout:用于分割窗口,可以一边查看代码,一边测试:
- layout src:显示源代码窗口
- layout asm:显示反汇编窗口
- layout regs:显示源代码/反汇编和CPU寄存器窗口
- layout split:显示源代码和反汇编窗口
- Ctrl + L:刷新窗口
-
1.3. 更强大的工具
cgdb
cgdb可以看作gdb的界面增强版,用来替代gdb的 gdb -tui。cgdb主要功能是在调试时进行代码的同步显示,这无疑增加了调试的方便性,提高了调试效率。界面类似vi,符合unix/linux下开发人 员习惯;如果熟悉gdb和vi,几乎可以立即使用cgdb。
ctrl+x+a 进入/退出图形化
info win //查看focus的窗口
fs src //focus源码
fs cmd
1 info 用来描述你的程序的状态,比如info b就是显示出当前的程序的所有断点.
2 set 用来设置一些环境变量的值,比如set prompt $.
3 show用来描述gdb自己的状态.
常用命令全写到一个文件中,启动时加载
gdb -x gdbOptionFile
(3)edit [file:]function
简写:e,编辑当前所在的行,也可以编辑某个函数的源码。
编译要用-g选项. -g3包括宏信息
然后用gdb +程序名,或者直接gdb后,用file + 文件名加载程序.
1 run/r 运行程序.
2 set args 设置程序的参数.
3 path directory 加一个目录到环境变量path
4 set directory 设置gdb的工作目录
5 pwd 当前的工作目录
6 attch process-id 调试 运行的进程
dettach 当调试进程完毕,release 掉gdb的控制.
调试多线程.
1 thread threadno 选择当前的线程.
2 info thread 查看当前程序的线程.
debug多进程:
If you are running your program in an execution environment that supports processes, run creates an inferior process and makes that process run your program。
默认情况下,当fork一个子进程之后,gdb会继续debug父进程,而子进程会运行下去.不过我们能够改变这个.
set follow-fork-mode mode 这里mode可以为parent或者child. parent是默认值,而child的话就是gdb继续debug子进程,而父进程会运行下去.
如果你想要同时debug父子进程,也可以设置:
set detach-on-fork mode 默认是on,也就是只能debug一个进程,如果改为off则可以同时debug父子进程.
缺省gdb是调试主进程的,可是现在采用daemon模式工作的程序那么多,主进程通常很快就结束了,子进程才是真正干活的。怎么跟踪调试子进程呢?
在gdb里面执行:
set follow-fork-mode child
则gdb就可以调试子进程了。
保存一个书签稍后返回.
checkpoint 保存当前的程序的状态.
restart checkpoint-id 返回到checkpoint-id那个点.这个值可以用info checkpoint来查看
breakpoint,watchpoint以及catchpoint
breakpoint 就是断点.
watchpoint 就是用来检测变量的改变,他可以看做是特殊的断点,也就是当变量改变时停止程序.
catchpoint 是另外一种特殊的断点,用来监测某一事件的发生,有点类似其它语言中的异常.
1 设置Breakpoint
break location 设置断点.location可以为行号,函数名或者指令地址.
break 设置断点,不过这个断点为当前栈帧的下一条指令.
break location if condition 当condition为真时,程序到达这个断点才起作用.
tbreaks args, 一次性的断点.
rbreaks regex 设置断点在所有与regex匹配的函数.这个正则表达式的语义与grep的相同.
2 设置watchpoint
watch expr[thread threadno] 设置检测变量expr,后面可以跟着改变这个变量的线程.如果跟着线程号,则说明只有当这个线程改变变量时,程序才会stop.
rwatch expr[thread threadno] 上面是监测变量改变,而这个命令是监测程序读取变量.
awatch expr[thread threadno] 当expr要么被读,要么被写时,程序直接break.
3 设置catchpoint
catch event 当event发生的时候程序停止.
event可以是下面的几种类型: throw ,catch,exception,exception unhandled,assert,exec,fork,vfork.
tcatch event 一次性的监测事件.
删除断点
clear 删除在当前的栈帧的将要被执行的下一条指令断点.
clear location 删除location位置的断点.其实更有用的是下面几个命令:
clear function,clear filename:function ,clear linenum,clear filename:linenum.
delete [breakpoints][range...] 其实也就是删除多个断点,如果没有range,咋就是删除全部断点.
关闭断点
一个断点(包括 watchpoint和catchpoint)可以有下面四种状态.
打开,关闭,enabled once,enabled for deletion
disable [breakpoints][range..] 关闭指定的断点或者全部断点(如果没有range)
enable [breakpoints][range..] 打开指定的断点或者全部断点(如果没有range)
enable [breakpoints] once range 临时打开指定的断点(也就是说是一次性的,.
enable [breakpoints] delete range 临时打开指定的断点并只工作一次,也就是一次之后这个断点将会被删除.
break condition
contidition bnum expression 当expression为真的时候,程序到达这个断点才会停止.
contidition bnum 从断点bnum删除掉一个condition.
ignore bnum count 设置一个断点bnum的忽略次数为count.也就是只有count次数后,这个断点才会起作用.
断点命令列表
这个主要是用来当到达这个断点,程序停止后,你想要执行一连串的命令.格式为:
- command [bnum]
- ... command-list ..
- end
指定一堆命令给断点bnum.如果想删除命令的话就把command-list置为空就行了.
如果没有bnum,则这个command指的是最后设置的一个断点.
这里有个例子:
- break 403
- commands
- ///不输出任何东西
- silent
- ///改变x的值
- set x = y + 4
- ///然后continue
- cont
- end
接下来来看continue和step
continue表示让程序继续执行,直到下一个断点或者执行完毕。
step表示让程序执行一行代码或者说一条机器指令(依赖于你选择的命令)。
下面来看命令:
- continue [ignore-count]
- c [ignore-count]
- fg [ignore-count]
这几个命令都是resume一个程序,然后参数ignore-count表示忽略当前这个断点的次数。
step [count]
继续运行程序直到抵达一个新的代码行(它会跟入函数).这里要记住step只会停止在source line的第一条指令。
如果加上count参数则表示它会step count次。如果遇到断点则会停止。
next [count]
和step很类似,区别就是不会跟进函数。
- set step-mode
- set step-mode on
- set step-mode off
on就可以使step停止在没有debug信息的函数的第一条指令上。off则是直接执行完这个函数。
这里要注意上面的命令都只是跳一行代码。而不是一条指令。
util 继续运行直到source line通过了当前的行。这个命令主要是针对循环语句中的step。比如你在循环结尾设置util,则只有当循环退出时才会在这个断点停止。而不是每次都停止。
util location 继续运行直到指定的location,或者当前的栈帧返回。
advance location 继续运行直到给定的location,这个相比与上面的命令,它就象全局的。
stepi [arg]
执行一条机器指令。 arg表示次数。
nexti [arg]
和next类似只不过执行的是一条机器指令。
下来来看信号。
gdb可以监测在你的程序中的任何信号。
来看命令。
handle signal [keywords...]
这个命令用来改变信号signal(名字或者数字)在gdb中的行为。
其中关键就是keywords.在这里keywords可以为下面几种类型:
1 nostop gdb接收到信号不会停止程序,而只是打印出一段message
2 stop 和上面类似只不过会停止程序。
3 print 当信号发生必须打印一条消息通知。
4 noprint 信号发生,gdb将不会打印任何东西。
5 pass和noignore 这两个是同义的。表示信号对你的程序是可见的。
6 nopass和ignore 这两个也是同义的。和上面相反。。
在gdb中,当你的程序由于一个信号而停止后,直到你继续执行,否则信号对你的程序是不可见得。也就是说当gdb捕捉到信号,我们可以用nopass或者ignore来使信号对我们的程序为不可见。
最后来看下多线程程序的调试。
首先来看多线程调试的几种模式。
1 all-stop模式。
在这种模式中,当你的程序在gdb由于任何原因而停止,此时所有的线程都会停止。而不仅仅是当前的线程。一般来说gdb不能单步所有的线程。因为线程调度gdb是无法控制的。无论什么时候当gdb停止你的程序,它都会自动切换到触发断点的那个线程。
在一些os中我们可以通过lock线程调度器,从而达到只有一个线程在运行。
set scheduler-locking mode
设置模式,如果mode是off,则表示没有lock,则任何线程在任何时候都有可能在运行。当mode为on的时候,锁定其他的线程,也就是只有当前线程在执行。也就是你单步的时候其他线程是不会运行的。这个对我们只关注本线程比较重要。
set scheduler-locking off|on|step 估计是实际使用过多线程调试的人都可以发现,在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,怎么只让被调试 程序执行呢?通过这个命令就可以实现这个需求。off 不锁定任何线程,也就是所有线程都执行,这是默认值。 on 只有当前被调试程序会执行。 step 在单步的时候,除了next过一个函数的情况(熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,只有当前线程会执行。
默认情况下,当你键入step或者next命令时,gdb只允许当前进程的线程运行。我们可以通过命令来修改这个默认值。
set schedule-multiple mode
当mode为on则所有进程的所有线程都匀许运行。否则只有当前的进程的线程能够resume。
2 none-stop模式。
顾名思义,当程序在gdb中停止,只有当前的线程会被停止,而其他的线程将会继续运行。
这个时候step,next这些命令就只对当前的线程起作用。
我们要打开这个模式需要这样操作:
- # Enable the async interface.
- set target-async 1
- # If using the CLI, pagination breaks non-stop.
- set pagination off
- # Finally, turn it on!
- set non-stop on
这里要注意打开这个模式必须得在你attach或运行这个程序或者进程之前才能进行。 并用detach来取消挂接的进程。
Background Execution
gdb执行命令有两种类型:前台的(同步)和后台(异步)的。
区别很简单,前台的话,gdb在输出提示符之前会等待程序report一些线程已经终止的信息。而异步的则是直接返回。
我们需要显式打开异步模式。
set target-async on
下面就是支持异步的命令:
- run
- attach
- step
- stepi
- next
- nexti
- continue
- finish
- until
通过上面我们可以看到异步模式主要用在none-stop模式中。
如果你想停止后台运行的程序,那么使用interrupt
在all-stop模式中interrupt将会停止所有的线程。而在none-stop中只会停止当前线程。interrupt -a此时就能停止所有线程。’
当你有多个线程,你此时只想给某个线程设置断点,这个时候可以用这个命令:
break linespec thread threadno
break linespec thread threadno if ...
linespec为源码行号,threadno为线程id。
最后来看下多线程调试中可能会遇到的一个问题:
如果一个线程在一个断点,或者由于其他什么原因停止,此时另外的线程阻塞在一个系统调用。这个时候这个系统调用就有可能会过早的返回。因此我们在调用系统调用,最好都要检测它的返回值。
举个例子:
sleep (10);
这个我们应该改成这样:
- int unslept = 10;
- while (unslept > 0)
- unslept = sleep (unslept);
通常在gdb调试时要打印出一些字符串的内容,通过
结果不能够完全输出,而进行了省略,通过命令set print elements 0就可以了
gdb宏展开 (编译时需加上-gdwarf-2 -g3)
(gdb) macro expand MACRO_NAME
The ‘start’ command does the equivalent of setting a temporary breakpoint at the beginning of the main procedure and then invoking the ‘run’ command.
whatis
ptype
set args -x some-other-options
set print thread-events
thread apply [threadno | all] command
set follow-fork-mode parent/child //通过fork或vfork创建新进程时,继续调试哪个进程
On Linux, if you want to debug both the parent and child processes, use the command set detach-on-fork.
set detach-on-fork off //Both processes will be held under the control of gdb. One process (child or parent, depending on the value of follow-fork-mode) is debugged as usual, while the other is held suspended.
If you choose to set ‘detach-on-fork’ mode off, then gdb will retain control of all forked processes (including nested forks). You can list the forked processes under the control of gdb by using the info inferiors command, and switch from one fork to another by using the inferior command (see Debugging Multiple Inferiors and Programs).
To quit debugging one of the forked processes, you can either detach from it by using the detach inferiors command (allowing it to run independently), or kill it using the kill inferiors command. See Debugging Multiple Inferiors and Programs.
gdb represents the state of each program execution with an object called an inferior.
You can get multiple executables into a debugging session via the add-inferior and clone-inferior commands. On some systems gdb can add inferiors to the debug session automatically by following calls to fork and exec.
set print inferior-events on
- checkpoint
零时执行再返回checkpoint,好像什么都没发生过。牛b的特性
Thus, if you're stepping thru a program and you think you're getting close to the point where things go wrong, you can save a checkpoint. Then, if you accidentally go too far and miss the critical statement, instead of having to restart your program from the beginning, you can just go back to the checkpoint and start again from there.
相关命令:
checkpoint
info checkpoint
restart checkpoint-id
delete checkpoint checkpoint-id
https://sourceware.org/gdb/download/onlinedocs/gdb/Forks.html#Forks
- watchpoint
watch/rwatch/awatch [-l|-location] expr [thread threadnum] [mask maskvalue]
info watchpoints
- catchpoint
catch fork
catch syscall chmod
catch signal [signal... | ‘all’]
info break to list the current catchpoints
A watchpoint is a special breakpoint that stops your program when the value of an expression changes.
4.11 Debugging Forks
On most systems, gdb has no special support for debugging programs which create additional processes using the fork function. When a program forks, gdb will continue to debug the parent process and the child process will run unimpeded. If you have set a breakpoint in any code which the child then executes, the child will get a SIGTRAP signal which (unless it catches the signal) will cause it to terminate.
However, if you want to debug the child process there is a workaround which isn't too painful. Put a call to sleep in the code which the child process executes after the fork. It may be useful to sleep only if a certain environment variable is set, or a certain file exists, so that the delay need not occur when you don't want to run gdb on the child. While the child is sleeping, use the ps program to get its process ID. Then tell gdb (a new invocation of gdb if you are also debugging the parent process) to attach to the child process (see Attach). From that point on you can debug the child process just like any other process which you attached to.
save breakpoints [filename]
source [filename]
skip function
info skip
skip delete/enable/disable
info handle
info signals
handle signal stop/print/pass
线程
gdb supports debugging programs with multiple threads (see Debugging Programs with Multiple Threads). There are two modes of controlling execution of your program within the debugger. In the default mode, referred to as all-stop mode, when any thread in your program stops (for example, at a breakpoint or while being stepped), all other threads in the program are also stopped by gdb. On some targets, gdb also supports non-stop mode, in which other threads can continue to run freely while you examine the stopped thread in the debugger.
You might even find your program stopped in another thread after continuing or even single-stepping. This happens whenever some other thread runs into a breakpoint, a signal, or an exception before the first thread completes whatever you requested.
Whenever gdb stops your program, due to a breakpoint or a signal, it automatically selects the thread where that breakpoint or signal happened. gdb alerts you to the context switch with a message such as ‘[Switching to Thread n]’ to identify the thread.
set scheduler-locking mode
Set the scheduler locking mode. If it is off, then there is no locking and any thread may run at any time. If on, then only the current thread may run when the inferior is resumed. The step mode optimizes for single-stepping; it prevents other threads from preempting the current thread while you are stepping, so that the focus of debugging does not change unexpectedly. Other threads only rarely (or never) get a chance to run when you step. They are more likely to run when you ‘next’ over a function call, and they are completely free to run when you use commands like ‘continue’, ‘until’, or ‘finish’.
set schedule-multiple
Set the mode for allowing threads of multiple processes to be resumed when an execution command is issued. When on, all threads of all processes are allowed to run. When off, only the threads of the current process are resumed. The default is off. The scheduler-locking mode takes precedence when set to on, or while you are stepping and set to step.
To enter non-stop mode, use this sequence of commands before you run or attach to your program:
# Enable the async interface.
set target-async 1
# If using the CLI, pagination breaks non-stop.
set pagination off
# Finally, turn it on!
set non-stop on
In non-stop mode, all execution commands apply only to the current thread by default. That is, continue only continues one thread. To continue all threads, issue continue -a or c -a.
浙公网安备 33010602011771号