Tutorial: Reverse debugging with GDB 7

Tutorial: Reverse debugging with GDB 7

by Jay Conrod
posted on 2009-12-01

GDB 7 came out a few weeks ago, and one of the major new features is reverse debugging. This allows you to record the execution of a process, then play it backward and forward. This is incredibly useful for fixing those mysterious bugs that are so common in C/C++ programs.

In this post, I'll give a motivating example of why reverse debugging is so useful, then I'll give a summary of the commands you need to know about. You might also want to look at the official tutorial on the GDB wiki, which is a good reference.

Here's a typical program we might have in C. It's very simple, but it contains a subtle bug that causes it to crash when we run it.

          #include <stdio.h>
#include <stdlib.h> void initialize(int *array, int size) {
for (int i = 0; i <= size; ++i)
array[i] = 0;
} int main(void) {
int *p = malloc(sizeof(int));
int values[10]; *p = 37;
initialize(values, 10);
printf("*p = %d\n", *p);
free(p); return 0;
}

This program is compiled with the following command:

          gcc -ggdb -std=c99 -O0 test.c -o test
        

When we run this program from the command line, we get a segmentation fault. What happened? We load it into gdb and enable recording:

          (gdb) break main
Breakpoint 1 at 0x8048449: file test.c, line 11.
(gdb) run
Starting program: /home/jay/Code/test/test Breakpoint 1, main () at test.c:11
(gdb) record
(gdb)

The record command turns on recording. It must be issued after the program has started running, so the beginning of main is a good place to use it. If you are debugging code that runs before main (such as C++ global constructors), you may want to set a breakpoint in _start, the actual entry point of the program.

Once recording is enabled, we run the program until the segmentation fault occurs:

          (gdb) continue
Continuing.
warning: Process record ignores the memory change of instruction at
address 0xdd45e1 because it can't get the value of the segment
register. Program received signal SIGSEGV, Segmentation fault.
0x0804847b in main () at test.c:15
(gdb)

After getting a weird warning (which appears to occur inside malloc), we find that the segmentation fault occurs at the call to printf. The only memory operation here is dereferencing p, so we print its value:

          (gdb) print p
$1 = (int *) 0x0
(gdb)

p should not be null! We set it at the beginning with malloc and never changed its value. We can find out where it was changed by setting a watchpoint and using the reverse-continue command. This works just like you would hope: the program runs backwards until the point at which p was changed. Note that we explicitly set a software watchpoint rather than a hardware watchpoint; GDB 7 seems to silently ignore hardware watchpoints when replaying the program.

          (gdb) set can-use-hw-watchpoints 0
(gdb) watch p
Watchpoint 2: p
(gdb) reverse-continue
Continuing.
Watchpoint 2: p Old value = (int *) 0x0
New value = (int *) 0x804b008
0x0804842c in initialize (array=0xbffff5c0, size=10) at test.c:6
(gdb)

GDB stops on line 6 in the initialize function. Upon closer examination of the loop, we notice the off-by-one error in the condition. Since the array we passed to initialize is adjacent to p on the stack, we overwrite p when we write off the end of the array.

This kind of error is an example of a buffer overflow, a common bug in C. More severe versions of this bug can create security vulnerabilities. Overflows are usually quite difficult to track down because a variable like p could change many times before taking on a "bad" value like it did here. If we had set a watchpoint at the beginning of a more complex program, the debugger might stop hundreds of times before we found something interesting. More generally, we frequently debug by sneaking up on a fault from the front; if we accidentally pass the fault, we usually have to start over. Reverse debugging allows us to approach a fault much more quickly from behind. We just let the program run normally until we reach a point shortly after a fault has occurred (for instance, when the SIGSEGV signal is received). We then run the program backward until we find what went wrong. The debugger can do pretty much the same things running backward as forward, including setting new watchpoints and breakpoints.

Before we wrap up, here's a quick summary of useful commands for reverse debugging:

  • record - enable recording mode. This command must be issued while the program is running, and you can only run the program back to the point where this command was issued. There is a performance penalty.
  • reverse-step, reverse-next, reverse-finish, reverse-continue - just like the normal versions of the commands, but in the opposite direction.set exec-direction reverse - switches the program execution direction to reverse. The step, next, finish, continue commands will work in the currect execution direction.
  • set can-use-hw-watchpoints 0 - disables hardware watch points. This is necessary if you want to use watchpoints while running the program in reverse.

Once again, you need GDB 7 in order to use reverse debugging. It is supplied as part of Ubuntu 9.10 (Karmic) and other newer Linux distributions. Since reverse debugging a fairly new feature, it's not as complete as one would hope, so there's an official wish list which contains bugs and feature requests.

Finally, I'd like to reference Sebastien Duquette's tutorial on reverse debugging, which is where I found out that you need to disable hardware watchpoints. If you're interested in how reverse debugging actually works, Michael Snyder (one of the GDB developers responsible for it) has a short post on StackOverflow about it.


Comment by Lakshmy m.a posted on Fri Mar 5 09:24:25 2010

sir, Am a student of model engineering college trikakkara of ernakulam district,kerala,India.we a group of 4 took this rgdb as our mini project.i would like to get some technical support from your side.can you please send me a mail as your respones, sir i couldnt get ur mail id...so that i can mail you we would like to get a tutorial of each reverse commands implementation + its logic we have downloaded the source code of the new version of gdb.7 but we couldnt understand the logic ,since its very lengthy, and we hav a short time to for our mini project section... It will be very helpful if we get the basic idea behind this.


http://www.jayconrod.com/posts/28/tutorial-reverse-debugging-with-gdb-7

Tutorial: Reverse debugging with GDB 7 (转载)的更多相关文章

  1. GDB 反向调试(Reverse Debugging)

    这个挺有意思 http://blog.csdn.net/CherylNatsu/article/details/6436570 使用调试器时最常用的功能就是step, next, continue,这 ...

  2. Debugging with GDB 用GDB调试多线程程序

    Debugging with GDB http://www.delorie.com/gnu/docs/gdb/gdb_25.html GDB调试多线程程序总结 一直对GDB多线程调试接触不多,最近因为 ...

  3. 【转载】GDB反向调试(Reverse Debugging)

    记得刚开始学C语言的时候,用vc的F10来调试程序,经常就是一阵狂按,然后一不小心按过了.结果又得从头再来,那时候我就问我的老师,能不能倒退回去几步.我的老师很遗憾地和我说,不行,开弓没有回头箭.这句 ...

  4. gdb调试4--回退

    加入你正在使用GDB7.0以上版本的调试器并且运行在支持反向调试的平台,你就可以用以下几条命令来调试程序: reverse-continue 反向运行程序知道遇到一个能使程序中断的事件(比如断点,观察 ...

  5. Debugging Under Unix: gdb Tutorial (https://www.cs.cmu.edu/~gilpin/tutorial/)

    //注释掉 #include <iostream.h> //替换为 #include <iostream> using namespace std; Contents Intr ...

  6. 27 Debugging Go Code with GDB 使用GDB调试go代码

    Debugging Go Code with GDB  使用GDB调试go代码 Introduction Common Operations Go Extensions Known Issues Tu ...

  7. [转]Debugging the Mac OS X kernel with VMware and GDB

    Source: http://ho.ax/posts/2012/02/debugging-the-mac-os-x-kernel-with-vmware-and-gdb/ Source: http:/ ...

  8. 使用gdb调试Python进程

    使用gdb调试Python进程 有时我们会想调试一个正在运行的Python进程,或者一个Python进程的coredump.例如现在遇到一个mod_wsgi的进程僵死了,不接受请求,想看看究竟是运行到 ...

  9. GDB的non-stop模式

    线程调试必杀技 - GDB的non-stop模式   作者:破砂锅 开源的GDB被广泛使用在Linux.OSX.Unix和各种嵌入式系统(例如手机),这次它又带给我们一个惊喜. 多线程调试之痛 调试器 ...

随机推荐

  1. SMBv3空指针引用dos漏洞复现

    0x01 前言 去年年底,当设置一个模拟器来定位SMB协议时,发现了一个如此简单而又非常有效的攻击大型企业的漏洞.TL; DR:一个拒绝服务错误允许BSOD协议向Windows 8.1和Windows ...

  2. 使用Ajax内容签名,减少流量浪费

    前端UI界面用Ajax获取数据内容的时候,一般是直接获取内容数据并填充,不管内容有无变化,不管数据量多大,都是直接重新加载数据,例如定时刷新公告等. 今天在浏览器控制台调试的时候,发现动态刷新内容,其 ...

  3. 框架----Web框架本质

    一.Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. #!/usr/bin/env python #coding:ut ...

  4. P1967 货车运输 树链剖分

    题目描述 AA国有nn座城市,编号从 11到nn,城市之间有 mm 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最 ...

  5. ubuntu如何杀死进程

    一.得到所有进程 先用命令查询出所有进程 ps -ef 二.杀死进程 我们使用ps -ef命令之后,就会得到一些列进程信息,有进程pid什么的,如果你要杀死莫个进程的话,直接使用命令   kill   ...

  6. [大数据可视化]-saiku的源码包Bulid常见问题和jar包

    最近在做kylin+mondrian+saiku的二次开发的时候,Bulid saiku的源码出现了很多问题,基本上一大部分问题jar找不到问题,很多jar国内网站都找不到.这时候只有手动下载然后注册 ...

  7. 跟我一起写Makefile(七)

    make 的运行—————— 一般来说,最简单的就是直接在命令行下输入make命令,make命令会找当前目录的makefile来执行,一切都是自动的.但也有时你也许只想让make重编译某些文件,而不是 ...

  8. uva 10288 Coupons (分数模板)

    https://vjudge.net/problem/UVA-10288 大街上到处在卖彩票,一元钱一张.购买撕开它上面的锡箔,你会看到一个漂亮的图案. 图案有n种,如果你收集到所有n(n≤33)种彩 ...

  9. Anniversary party(树形dp入门)

    Anniversary party Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  10. linux中execve函数的用法

    在父进程中fork一个子进程,在子进程中调用exec函数启动新的程序.exec函数一共有六个,其中execve为内核级系统调用,其他(execl,execle,execlp,execv,execvp) ...