常用的GDB调试小结

先来看下man手册关于gdb的一些说明

gdb的目的主要是让你知道程序内部正在运行什么代码,或者是当程序崩溃的时候正在执行什么代码。
GDB主要可以做四种事情来帮助你找到bug:
启动你的程序,指定任意可以影响程序行为的参数。
让你的程序在指定的条件停住.
测试你的程序停止的时候发生了什么。
改变程序内部的变量,来改正程序的错误继续执行。

你可以用gdb调试C/C++和modula-2程序。fortran的支持需要有Fortran编译器。
gdb使用shell命令gdb来调用,一旦开始,就从终端读取命令直接gdb退出,你可以通过help命令获取帮助信息。

可以不带任何参数或选项执行gdb命令,但是最常用的启动gdb的方式是带一个或者两个参数,指定一个可执行文件来作为参数:

  gdb program(gdb+可执行文件名称)

也可以再gdb文件后面指定可执行文件 和 core文件的名称:

  gdb program core(gdb + 可执行文件 +core文件)

  You can, instead, specify a process ID as a second argument, if you want to debug a running process:

也可以指定一个进程id作为第二个参数,如果你想调试一个正在运行的程序:

  gdb program 1234(gdb进程名+进程id)
  gdb -p 1234

将GDB附加到进程1234(除非您还有一个名为1234的文件;GDB首先检查核心文件)。使用选项-p可以省略程序文件名。

gdb调试命令:

  break [file:]function

        设置一个断点在函数中(在文件中)

  run [arglist]

         启动程序带上指定的参数

  bt    Backtrace: 

            显示堆栈

  print expr

            显示表达式的值

  c      

        继续执行你的程序(程序停住后,例如:在断点处停止)

  next  

            执行程序的下一行代码(程序停止以后);跨国任何当前行的函数调用。

  edit [file:]function

        查看当前程序停在哪。

  list [file:]function

           显示程序当前停住的代码行附近的代码

  step  单步调试

        执行程序的下一行(程序停住后),进入当前行的函数调用的内部

  help [name]

        显示gdb命令的相关信息。

  quit  

       退出gdb

需要详细的gdb说明,查看using gdb:一个gdb调试程序的指南,stallmain和roland写的,也有可用的在线文档作为gdb入口在gdb项目信息中。

选项:
除选项外的任何参数指定可执行文件和核心文件(或进程ID);也就是说,第一个没有关联选项标志的参数是等价的
到-se选项,第二个选项(如果有的话)相当于-c选项(如果它是文件的名称)。许多期权既有长期权也有短期权;两者都在这里显示。长
如果将表单截断,也可以识别它们,只要有足够多的选项是明确的。(如果你愿意,你可以用+而不是
-虽然我们演示了更常见的约定。
您提供的所有选项和命令行参数都是按顺序处理的。使用-x选项时,顺序会有所不同。

   -help
   -h  列出所有选项,并简要说明。

   -symbols=file
   -s file
       从文件中读取符号表。

   -write
       允许写入可执行文件和核心文件。

   -exec=file
   -e file
       在适当的时候使用file文件作为可执行文件执行,并与核心转储一起检查纯数据。

   -se=file
       从文件文件中读取符号表,并将其用作可执行文件。

   -core=file
   -c file
       使用file文件作为核心转储进行检查。

   -command=file
   -x file
       从文件中执行GDB命令。

   -ex command
       执行给定的GDB命令。

   -directory=directory
   -d directory
      将目录添加到搜索源文件的路径。

   -nh 不要从~/.gdbinit执行命令。

   -nx
   -n  不要从任何.gdbinit初始化文件执行命令。

   -quiet
   -q  "Quiet". 不要打印介绍性和版权信息。这些消息也在批处理模式下被抑制。
    -batch
       以批处理模式运行。处理完用-x指定的所有命令文件后(如果不禁止,则使用.gdbinit)以0状态退出。如果出现错误,则以非零状态退出在命令文件中执行GDB命令时发生。

      批处理模式对于作为过滤器运行GDB可能很有用,例如下载并在另一台计算机上运行一个程序;为了使这个消息更有用

              程序正常退出。

       (当在GDB控件下运行的程序终止时,通常会发出此命令)在批处理模式下运行时不会发出此命令。

   -cd=directory
      使用directory作为工作目录而不是当前目录运行GDB。

   -fullname
   -f  Emacs在将GDB作为子进程运行时设置此选项。它告诉GDB在每次堆栈时以标准的、可识别的方式输出完整的文件名和行号显示框架(包括每次程序停止时)。这种可识别的格式看起来像两个\032字符,后跟文件名、行号和字符的位置由冒号和换行符分隔。的源代码。Emacs-to-GDB接口程序使用两个\032字符作为信号来显示框架。

   -b bps
       设置GDB用于远程调试的任何串行接口的行速度(波特率或比特/秒)。

   -tty=device
       使用设备运行程序的标准输入和输出。

====================================================================
看下常用的GDB总结

1.启动调试

前置条件:编译生成执行码时带上 -g,如果使用Makefile,通过给CFLAGS指定-g选项,否则调试时没有符号信息。

gdb program最常用的用gdb启动程序,开始调试的方式
gdb program core用gdb查看core dump文件,跟踪程序core的原因
gdb program pid用gdb调试已经开始运行的程序,指定pid即可
gdb attach pid用gdb调试已经开始运行的程序,指定pid即可

2.调试命令
(1)执行命令模式

gdb -ex “set pagination 0” -ex “thread apply all bt” -batch -p $pid打印$pid进程所有线程的堆栈并退出。
gdb -ex “handle SIGUSR1 noprint nostop” --args program abc先执行引号内的命令,并带上参数abc,运行gdb

上面两个例子主要说明:
-ex 如何在启动gdb时,设置相应的命令(命令要用引号括住)。
–args 带参数启动

(2).交互模式

run(r)运行程序
continue(c)中断后继续运行到下一个断点
step (s)单步执行,进入函数
next (n)单步执行
return函数未执行完,忽略未执行的语句,返回
finish函数执行完毕返回
bt查看调用栈信息
bt N显示开头N个栈桢
bt -N显示最后N个栈桢
(frame)f N显示第N层栈桢
list显示源码
pwd当前的工作目录

(3)反复执行

continue N连续执行cointiue N次,一般用于避免频繁断点
step N连续执行step N次
next N连续执行next N次

3.断点

break 函数名设置断在某个函数
break 文件名:行号设置断在某一行。例如 break hello.c:28
info break查看设置的断点信息
break if condition条件断点
break 函数名 thread 线程号设置断点只断某个线程,通过info threads 查看线程号
delete 断点号 断点号…删除一个或多个断点
diable 断点号 断点号…禁止一个或多个断点
enable 断点号 断点号…打开一个或多个断点
command 断点号断点触发时,执行命令,一般用于打印变量

举个例子
(gdb) command 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just “end”.
print x
end
(gdb)

4.检测点

watch为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序
rwatch当表达式(变量)expr被读时,停住程序
awatch当表达式(变量)的值被读或被写时,停住程序
info watchpoints列出当前所设置了的所有观察点

技巧经验:观察某个变量是否变化,被读或者被写,由于变量只在某一个作用域,可以获取变量的地址,然后观察。
比如:观察examined_rows变量什么时候被修改
(1).p &examined_rows,得到地址
(2).watch *(ha_rows *) 0x7ffec8005e28,则可以观察这个变量的变化情况。

5.查看变量
(1)设置

set print elements N指定打印的长度,对长字符串特别有用
set print elements 0输出完整的字符串
set print pretty [off]设置或关闭设置。设置GDB打印结构的时候,每行一个成员,并且有相应的缩进。缺省是关闭的
print (p)变量/地址打印变量查看其值
info locals打印出当前函数中所有局部变量及其值
info args打印出当前函数的参数名及其值
display 变量自动打印变量
undisplay取消自动打印

注意:默认编译的时候,调试过程是看不见宏的值的,编译时候需要给选项。-g3

6.内存查看

格式: x /nfu x 是 examine 的缩写
a.n表示要显示的内存单元的个数
b.f表示显示方式, 可取如下值
(1).x 按十六进制格式显示变量。
(2).d 按十进制格式显示变量。
(3).u 按十进制格式显示无符号整型。
(4).o 按八进制格式显示变量。
(5).t 按二进制格式显示变量。
(6).a 按十六进制格式显示变量。
(7).i 指令地址格式
(8).c 按字符格式显示变量。
(9).f 按浮点数格式显示变量。
c.u表示一个地址单元的长度
(1).b表示单字节,
(2).h表示双字节,
(3).w表示四字节,
(4).g表示八字节

比如:x/3xh buf
表示从内存地址buf读取内容,3表示三个单位,x表示按十六进制显示,h表示以双字节为一个单位。

7.多线程调试

info threads查看线程
thread thread_no切换到线程号
thread apply all command所有线程都执行命令打印栈桢

比如:thread apply all bt //所有线程都打印栈桢

(1)线程锁
show scheduler-locking
set scheduler-locking on
set scheduler-locking off
默认是off,当程序继续运行的时候如果有断点,那么就把所有的线程都停下来,直到你指定某个线程继续执行(thread thread_no apply continue).
但是如果直接在当前线程执行continue的话,默认是会启动所有线程。这种模式有一种副作用,如果多个线程都断在同一个函数,这时候调试会出问题。
这个时候需要打开线程锁,但打开线程锁,意味着其它线程不能运行了。
(2)non-stop模式(7.0以后的版本支持)
set target-async 1
set pagination off
set non-stop on
gdb启动了不停模式,除了断点有关的线程会被停下来,其他线程会执行。

8.信号量

(1).singal 发送信号
假定你的程序已将一个专用的 SIGINT(键盘输入,或CTRL-C;信号2)信号处理程序设置成采取某个清理动作,
要想测试该信号处理程序,你可以设置一个断点并使用如下命令:
(gdb) signal 2
(2).handle 拦截信号
Handle命令可控制信号的处理,他有两个参数,一个是信号名,另一个是接受到信号时该作什么。几种可能的参数是:

  • nostop 接收到信号时,不要将它发送给程序,也不要停止程序。
  • stop 接受到信号时停止程序的执行,从而允许程序调试;显示一条表示已接受到信号的消息(禁止使用消息除外)
  • print 接受到信号时显示一条消息
  • noprint 接受到信号时不要显示消息(而且隐含着不停止程序运行)
  • pass 将信号发送给程序,从而允许你的程序去处理它、停止运行或采取别的动作。
  • nopass 停止程序运行,但不要将信号发送给程序。
    比如:
    handle SIGPIPE stop print //截获SIGPIPE信号,程序停止并打印信息
    handle SIGUSR1 nostop noprint //忽略SIGUSR1信号

9.生产环境使用GDB场景

内核转储(coredump)
(1).配置产生core文件
前置条件:确保系统配置的core file size足够,一般设置成unlimited
ulimit -c unlimited
配置corefile的参数:
echo 2 > /proc/sys/fs/suid_dumpable [程序中切换用户,也要产生corefile]
mkdir /tmp/corefiles
chmod 777 /tmp/corefiles
echo “/tmp/corefiles/core”>/proc/sys/kernel/core_pattern //配置core文件产生的目录为/tmp/corefiles
echo “1” > /proc/sys/kernel/core_uses_pid
kill -sigsegv pid //模拟异常内存访问信号
注意:
a.确保配置的目录有足够的磁盘空间,否则产生core文件可能不完整。
b.对于mysqld而言,要保证正确产生core-file,需要加上–core-file,默认这个参数是不打开的。
c.kill -9 pid 是不能产生core文件的,因为SIGKILL信号不能被捕获。
(2).使用core文件
gdb /usr/mysql/bin/mysqld core.24556
(3).dump已经运行进程的状态信息
gdb attach pid
(gdb) generate-core-file
调试完毕后,通过detach命令退出。
另外,通过gcore pid 命令也可以dump core文件,生成在当前目录下。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值