gdb调试命令

# 重要说明

(1)  使用GCC进行编译时,需在编译选项中加入"-g"参数

       cc -g main.c -o main
       g++ -g main.cpp -o main

(2)  使用GCC进行编译时,为了能使指令与源代码对应上,编译选项中不要加入启用优化的"-O"参数

(3)  使用gdb调试前,要先进入待调试模块所在目录(使得能正确关联到源代码文件)

(4)  进入gdb调试状态,直接回车表示"重复上一次命令"

(5)  按上下方向键可以浏览和选择以前输入过的命令

(6)  gdb中,输入命令时,可以不用打全命令,只用打命令的前几个字符就可以了,当然,命令的前几个字符应该要标志着一个唯一的命令。

      在Linux下,你可以敲击两次TAB键来补齐命令的全称,如果有重复的,那么gdb会把其列出来

(7)  可从这儿下载最新的gdb [http://www.gnu.org/software/gdb/download/

# 调试进程

gdb test         // 调试当前目录下的名为test的可执行程序    输入r,运行程序

gdb -p PID     // 勾住目标进程进行调试  PID为目标进程ID,可通过ps -ux来查看当前运行的进程

attach 2146   // 附加到PID为2146的进程上

detach 2146  // 释放对PID为2146进程的调试

q                 // 结束gdb调试 [quit]

# 启动额外参数

-se symbolfile    // 从指定文件中读取符号表信息,并用在可执行文件中

-c corefile      // 调试core dump的core文件

如:gdb gamesvrd.0 -c /data/corefile/core_gamesvrd.0_11833_1358767740  // 需要进入gamesvrd.0的目录

-d directory    // 加入一个源文件的搜索路径   默认搜索路径是环境变量中PATH所定义的路径

若当前调试进程的可执行文件目录中有名为.gdbinit文件,在启动调试时会执行该脚本(下面为一个文件内容示例)

--------------
b YXSCubeData.cpp : 2653
c
--------------

# 调试

0. 程序参数

set args -b -x  // 修改发送给程序的参数,将-b和-x参数发送给程序

show args       // 显示程序当前的参数

1. 设置断点  [break]

b worker.cpp : 45   // 在worker.cpp文件的45行处设置一个断点

b 45   // 在当前文件的45行处设置一个断点

b worker.cpp : CWorker::DoWork  // 在worker.cpp文件的DoWork函数起始处设置一个断点

------------------

若有命名空间,还应带上命名空间  b worker.cpp : MYPRJ::CWorker::DoWork

若函数被重载,还应带上参数类型  b worker.cpp : CWorker::DoWork(bool)

------------------

b +5  // 在距离当前位置的后5行处设置一个断点

b -6  // 在距离当前位置的前6行处设置一个断点

b ... if <条件>  // 条件断点

例:b worker.cpp : 45 if workerNum==5 

例:b worker.cpp : CWorker::DoWork if workerNum==5

2. 查看断点   [info breakpoints]

i b    // 查看当前所有断点(每个断点都有一个编号)

3. 禁用/启用断点

disable 1  // 禁用编号为1的断点

enable 1   // 启用编号为1的断点

disable     // 禁用所有断点

enable      // 启用所有断点

4. 删除断点  [delete breakpoints]

d 1   // 删除编号为1的断点

d      // 删除所有断点

5. 调试执行控制

r  // 调试启动进程 [run]

k  // 结束当前调试的进程 [kill]

c  // 继续运行 [continue]   相当于vc中的F5

ctrl+c  // 暂停程序运行

n  // 单步执行 [next] 相当于vc中的F10

n 2  // 2为步进数目

s  // step into到函数内部 相当于vc中的F11

finish/fin  // step out出函数 相当于vc中的shift+F11

u   // 当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体  [until]

u 145  //执行至145行代码停下 

6. 查看变量  [print]

p nSum   // 打印nSum变量的值 

p /fmt nSum  // 按指定格式打印nSum变量的值

------------------

fmt为以下值
x 十六进制  d 十进制
u 无符号数  o 八进制
t 二进制     a 十六进制打印【地址】
c 字符格式  f 浮点数   s 字符串

------------------

p h@10  // 查看数组h的前10个值

p *bar  // 查看指针bar所指对象内容

whatis nSum  // 查看变量nSum的类型

ptype foo   // 查看foo的类型定义

w exp  // 查看表达式exp的值 [watch]

7. 修改变量

p x=4    // 将x的值修改为4

8. 查看内存

x/<n/f/u> <addr>

n、f、u是可选的参数。
n 是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址的内容。
f 表示显示的格式,参见【6.查看变量fmt的说明】。如果地址所指的是字符串,那么格式可以是s,如果地址是指令地址,那么格式可以是i。
u 表示从当前地址往后请求的字节数,如果不指定的话,GDB默认是4个bytes。
u参数可以用下面的字符来代替,b表示单字节,h表示双字节,w表示四字节,g表示八字节
当我们指定了字节长度后,GDB会从指内存定的内存地址开始,读写指定字节,并把其当作一个值取出来。

如:x/3uh 0x54320EED

// 从内存地址0x54320EED读取内容,h表示以双字节为一个单位,3表示三个单位,u表示按十六进制显示。

9. 其他调试信息查看

bt  // 查看堆栈调用 [backtrace]

-------------------------------------------------

有时我们通过bt命令,看到的堆栈信息是错乱的(一堆的???),如下:

针对这种情况,可以采用以下方法来查看堆栈:
(1) 从ebp获取函数调用堆栈的head指针

(2) 显示堆栈的heard指针内存块的内容

(3) 对当前函数返回地址执行info symbol命令,打印出当前函数栈帧信息(含函数名)

## 完整的例子:

-------------------------------------------------

frame 3  // 跳转到函数堆栈中索引为3的函数上下文

i reg // 显示寄存器信息 [info]

i func  // 显示所有的函数名

i local  // 显示当前函数的所有局部变量的信息

i prog  // 显示调试程序的执行状态

10. 代码载入  [程序必须被断点断住]

Ctrl+ x  Ctrl + a  // 将代码载入到命令行中进行调试

l  // 载入当前代码行的前后各4行代码 [list]

l 45  // 显示当前文件按第45行的周围代码

l worker.cpp : 70 // 显示work.cpp第70行的周围代码

l worker.cpp : sum // 显示work.cpp中sum函数的周围代码

l CWorker::DoWork(bool)  // 显示函数名为CWorker::DoWork(bool)的函数的代码

l 0xabcd1234  //  查看地址为0xabcd1234的周围的代码

11. 多线程

i threads  // 显示线程信息

thread 2   // 切换到线程表中索引为2的线程

b foo 2  // 在函数foo设置断点,并且只在索引为2的线程中命中

12. 强制操作

call A(1,2)  // 强制调用函数A,并输出其返回值

return   // 使用return命令取消当前函数的执行,并立即返回

return exp  // 如果指定了exp,那么该表达式的值会被认作函数的返回值

 

更详细请参考:用GDB调试程序(一)   用GDB调试程序(二)   用GDB调试程序(三)

                   用GDB调试程序(四)    用GDB调试程序(五)   用GDB调试程序(六)  用GDB调试程序(七)

原文地址:https://www.cnblogs.com/kekec/p/2693548.html