linux gdb调试应用程序常用方式

一、调试命令
主要发生在一些调试环境中,文件的编译我们可以认为比较麻烦,或者说我们并不像真正的修改源代码,因为测试的代码修改之后还要改回来;麻烦不说,如果修改之后测试代码没有改回来,那么问题就更加严重了,所以我们尽量希望通过gdb工具来环保的修改程序的行为,这样我们就可能使用到下面的一些方法和指令。

在gdb调试状态下的常用指令:

c : 继续执行

ctrl+c :立即中断

b : 设置断点 可以支持表达式(如cpp命名空间::类::函数)、地址(各类可访问的地址,如应用程序空间的地址)、变量(ret)

d : 删除断点

i b : 显示所有断点

i r : 显示所有寄存器(如rax rbi)

p [xxx]: 打印变量或者地址 *可以解引用

x /format [xxx]:输出变量 支持格式化(如 /32i 打印32个长度的反汇编 /32c 打印32个字符 *可以解引用

disas : 输出当前断点的汇编代码。

u  [x]: 单步跳出执行 (如u 1 如果有符号表代码一行,没有则是汇编代码一行)

n [x]: 单步执行

s [x]: 单步进入执行

二、进入调试状态,调试进程
常用两种方式:

1 gdb启动调试:通过gdb 启动,设置 file xxxxx,之后args $1,$2,$3 ……

2 gdb挂载调试:ps 或者 xprop 找到目标进程pid,通过sudo gdb ,然后设置 attach pid

三、跳过一些代码

我们希望跳过一些函数或者代码段的执行,此时就可以使用jump指令来完成该功能。
gdb的jump指令是对汇编语言中的jump指令的模拟,或者说是对C语言中goto语言的模拟。在被调试任务刚开始运行的时候,就可以通过jump指令来动态的修改被调试任务的PC指针,这个做法简单粗暴,但是比较有效。
gdb中代码
jump_command
resolve_sal_pc (&sal);    /* May error out */
……
addr = sal.pc;
……
proceed (addr, TARGET_SIGNAL_0, 0);

关键的proceed函数中对于这个解析出来的地址的处理为
void
proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
if (addr == (CORE_ADDR) -1)
{
……
}
else
{
write_pc (addr);直接修改了被调试任务的PC指针,所以被调试任务开始运行之后直接从pc地址直接继续运行。
}

四、修改函数返回值。
有些调用者并没有保存调用函数的返回值,而是直接把函数调用作为一个判断语句,例如
if (func())
{}
else
{}
此时我们如何修改这个函数func的返回,从而让程序执行和返回值相反的操作。
此时其实是通过体系结构相关的一些指令来完成,但是对于特定的处理器,这个指令却是可以确定的。因为386下函数的返回值都是通过eax保存的,所以我们可以直接修改这个寄存器的值即可,而修改的指令同样还是set,即
set $eax=10
五、一个测试的例子
[root@Harry changereturn]# cat func.cpp
#include <stdio.h>
int test()
{
printf(“In test function\n”);
return true;
}
int main()
{
if (test())
{
printf(“return is true\n”);
}
else
{
printf(“Return is false\n”);
}
}
[root@Harry changereturn]# g++ func.cpp -g -o func.c.exe
[root@Harry changereturn]# gdb func.c.exe
GNU gdb (GDB) Fedora (7.0-3.fc12)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type “show copying”
and “show warranty” for details.
This GDB was configured as “i686-redhat-linux-gnu”.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>…
Reading symbols from /home/tsecer/CodeTest/changereturn/func.c.exe…done.
(gdb) b main
Breakpoint 1 at 0x8048496: file func.cpp, line 9.
(gdb) r
Starting program: /home/tsecer/CodeTest/changereturn/func.c.exe

Breakpoint 1, main () at func.cpp:9
9        if (test())
Missing separate debuginfos, use: debuginfo-install glibc-2.11.2-3.i686 libgcc-4.4.2-7.fc12.i686 libstdc++-4.4.2-7.fc12.i686
(gdb) s
test () at func.cpp:4
4        printf(“In test function\n”);
(gdb) jump 5  通过jump5直接设置地址到源代码第5行,可以看到接下来的输出中没有打印”In test function\n”
Continuing at 0x8048486.
return is true

Program exited normally.
(gdb) r
Starting program: /home/tsecer/CodeTest/changereturn/func.c.exe

Breakpoint 1, main () at func.cpp:9
9        if (test())
(gdb) s
test () at func.cpp:4
4        printf(“In test function\n”);
(gdb) finish
Run till exit from #0  test () at func.cpp:4
In test function
0x0804849b in main () at func.cpp:9
9        if (test())
Value returned is $1 = 1
(gdb) set $eax=0 修改test函数返回值,此时主函数执行流程被修改。
(gdb) c
Continuing.
Return is false

Program exited normally.
(gdb)2