您好,登录后才能下订单哦!
小编给大家分享一下Linux系统中GDB是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
GDB调试是C/C++程序员必须掌握的技能。
GDB 可以做四种主要的事情(以及支持这些事情的其他事情)来帮助你捕获行为中的错误:
启动你的程序,并指定可能影响其行为的所有内容。
使程序在指定条件下停止。
检查程序停止时发生的情况。
更改程序中的内容,以便你可以尝试纠正一个错误的影响,然后继续学习另一个错误。
这些程序可能与GDB(本机)在同一台计算机上执行,在另一台计算机(远程)上或在模拟器上执行。GDB可以在大多数流行的UNIX和Microsoft Windows变体以及Mac OS X上运行。
  通过 gcc 的 -g 选项,将调试信息加到可执行文件中。
$ gcc -g hello.c -o hello1
  如果使用 Makefile 构建,一般要在 CFLAGS 中指定 -g 选项。
CFLAGS := -Wall -O2 -g1
  注意,给 GCC 编译器加上优化选项后,实际的执行顺序可能由于优化而与源代码顺序不同,因此利用调试器跟踪运行时,有时会执行到莫名奇妙的地方,从而造成混乱。
  使用命令 gdb 程序名启动。
  可以在函数名和行号等上设置断点。程序到达断点就会自动暂停运行。此时可以查看该时刻的变量值,显示栈帧、重新设置断点或重新运行等。断点命令 break 可以简写为 b,命令为 break 。      断点可以通过函数名、当前文件内的行号来设置,也可以先指定文件名再指定行号,还可以指定与暂停位置的偏移量,或者用地址来设置。格式:
格式 | 说明 |
---|---|
break | 对当前正在执行的文件中的指定函数设置断点 |
break | 对当前正在执行的文件中的特定行设置断点 |
break 文件名:行号 | 对指定文件的指定行设置断点,最常用的设置断点方式 |
break 文件名:函数名 | 对指定文件的指定函数设置断点 |
break | 当前指令行+/-偏移量出设置断点 |
break | 指定地址处设置断点 |
     设置好的断点可以通过 info break 确认。
  使用 run 参数 命令开始运行,其中参数为可执行程序的参数。如果设置了断点,会执行到设置了断点的位置后暂停运行。可以简写为 r。
  backtrace 命令可以在遇到断点或异常而暂停执行时显示栈帧,该命令简写为 bt。此外,backtrace 的别名还有 where 和 info stack。
格式 | 说明 |
---|---|
bt | 显示所有栈帧 |
bt | 只显示开头 N 个栈帧 |
bt | 只显示最后 N 个栈帧 |
bt full | 不仅显示 backtrace,还要显示局部变量 |
bt full |
     显示栈帧之后,就可以看出程序在何处停止,以及程序的调用路径。
  print 命令可以显示变量,可以简写为 p。      格式:print 变量。
  info registers 可以显示寄存器,简写为 info reg。      在寄存器名之前添加 $,显示寄存器的内容,例如 p $eax。   p/格式 $寄存器 可以指定寄存器的显示格式,例如 p/c $eax。可使用的格式如下:
格式 | 说明 |
---|---|
x | 显示为十六进制数 |
d | 显示为十进制数 |
u | 显示为无符号十进制数 |
o | 显示为八进制数 |
t | 显示为二进制数 |
a | 地址 |
c | 显示为字符(ASCII) |
f | 浮点小数 |
s | 显示为字符串 |
i | 显示为机器语言,仅在显示内存的 x 命令中可用 |
显示详细信息
     程序指针可以写为 ,也可以写为eip,使用 p $pc 显示程序指针内容。程序指针指向当前程序的运行点的地址。      x 命令可以显示内存的内容,格式:x/ 。例如 x/i $ps,显示汇编指令。      一般使用 x 命令时,格式为 x/
单位 | 说明 |
---|---|
b | 字节 |
h | 半字(2 字节) |
w | 字(4 字节)(默认值) |
g | 双字(8 字节) |
  例如命令 x\10i $pc 显示从 pc 所指地址开始的 10 条指令。      反汇编命令 disassemble,简写为 disas。格式:
disassemble。反汇编当前整个函数。
disassemble 程序计数器。反汇编程序计数器所在函数的整个函数。
disassemble 开始地址 结束地址。反汇编从开始地址到结束地址之间的部分。
  单步执行的意思时根据源代码一行一行地执行。执行源代码中一行的命令为 next ,简写为 n。执行时如果遇到函数调用,想执行到函数内部,使用 step 命令,简写为 p。   如果要逐条执行汇编指令,可以分别使用 nexti 和 stepi 命令。
  使用 continue 命令继续运行程序,简写为 c。程序会在遇到断点后再次暂停运行。使用 continue 命令指定忽略断点的次数。
  大型软件或大量使用指针的程序中,很难弄清变量在什么地方被改变,要想找到变量在何处被改变,可以使用 watch 命令(监视点,watchpoint)。格式如下:
watch 。表达式发生变化时暂停运行。
awatch 。表达式被访问、改变时暂停运行。
rwatch 。表达式被访问时暂停运行。
  需要注意,设置监视点可能会降低运行速度。
  delete 命令删除断点和监视点,简写为 d。格式为 delete ,表示删除编号指示的断点或监视点,编号可以用命令 info b 查看。   clear 命令删除已定义的断点。可用命令包括:     clear     clear     clear 文件名:行号     clear 文件名:函数名      disable 命令禁用断点。命令格式如下:     disable:禁用所有断点。     disable :禁用指定断点。     disable display :禁用 display 命令定义的自动显示。     disable mem :禁用 mem 命令定义的内存区域。      enable 命令用于启用断点。命令格式如下:     enable     enable     enable once :使指定的断点只启用一次。     enable delete     enable display     enable mem
  硬件断点(hbreak),适用于 ROM 空间等无法修改的内存区域中的程序,在有些架构中无法使用。      临时断点(tbreak)和临时硬件断点(thbreak),在运行到该处时暂停,此时断点会被删除,在只需要停止一次时用起来方便。
  格式:set variable 。例如命令 set variable options = 0,将变量 options 的值改成了 0。
  使用 generate-core-file 可将调试中的进程生成内核转储文件。通过内核转储文件和调试对象,查看生成转储文件时的运行历史。      gcore 命令可以从命令行直接生成内核转储文件。在命令行使用 gcore pid,其中 pid 为进程号。该命令无须停止正在运行的程序以获得内核转储文件,当需要在其他机器上单独分析问题原因,或是分析客户现场发生的问题时十分有用。
  内核转储(core dump)的最大好处是,它能保存问题发生时的状态。只要有问题发生时程序的可执行文件和内核转储,就可以知道进程当前的状态。
  大多数 Linux 发行版默认关闭了内核转储功能,使用 ulimit 命令可以查看当前的内核转储功能是否有效。
$ ulimit -c 012
  -c 选项表示内核转储文件的大小限制,0 表示内核转储无效。开启内核转储执行命令:
$ ulimit -c unlimited or $ ulimit -c 上限123
  unlimited 意思是不限制内核转储文件的大小,发生问题时进程的内存就可以全部转储到内核转储文件中。或者设置内核转储文件的上限,在参数中指定上限大小,单位为 Kb。      程序发生异常时会在当前目录下生成内核转储文件。例如程序 a.out 生成转储文件 core,使用以下方式启动 GDB:
$ gdb -c core ./a.out1
     使用 GDB 的 list 命令可以查看附近的源代码。命令使用方法
格式 | 说明 |
---|---|
list | 显示程序第 linenum 行周围的源代码 |
list | 显示函数名为 function 的函数的源代码 |
list | 显示当前行后面的源代码 |
list – | 显示当前行前面的源代码 |
set listsize | 设置一次显示源代码的行数 |
show listsize | 查看当前 listsize 的设置 |
list | 显示从 first 行到 last 行之间的源代码 |
list , | 显示从当前行到 last 行之间的源代码 |
list + | 往后显示源代码 |
  转储保存位置的完整路径可以通过 sysctl 变量 kernel.core_pattern 设置。在文件 /etc/sysctl.conf 中设置如下:
$ cat /etc/sysctl.conf kernel.core_pattern = /var/core/%t-%e-%p-%c.core kernel.core_uses_pid = 0 $ sysctl -p1234
     此外,还可以在 /proc/sys/kernel 下修改设置。   /proc/sys/kernel/core_uses_pid 可以控制产生的 core 文件的文件名中是否添加 pid 作为扩展 ,如果添加则文件内容为 1 ,否则为 0。   proc/sys/kernel/core_pattern 可以设置格式化的 core 文件保存位置或文件名 ,可以这样修改 :
$ echo "/corefile/core-%e-%p-%t" > core_pattern1
     kernel.core_pattern 中可以设置的格式符如下:
格式符 | 说明 |
---|---|
%% | % 字符本身 |
%p | 被转储进程的进程 ID(PID) |
%u | 被转储进程的真实用户 ID(real UID) |
%g | 被转储进程的真实组 ID(real GID) |
%s | 引发转储的信号编号 |
%t | 转储时刻(从 1970/1/1 0:00 开始的秒数) |
%h | 主机名(同 uname(2) 返回的 nodename) |
%e | 可执行文件名 |
%c | 转储文件的大小上限(内核版本 2.6.24 后可用) |
  修改 /etc/sysctl.conf中 的 kernel.core_pattern 变量来设置。
$ cat /etc/sysctl.conf kernel.core_pattern= | usr/local/sbin/core_helper %t %e %p %c kernel.core_uses_pid= 0 $ sysctl -p1234
  core_helper 的内容:
$cat usr/local/sbin/core_helper #!/bin/sh execgzip ->/var/core/$1-$2-$3-$4.core.gz1234
  这样,发生内核转储时就会在 /var/core 下生成压缩的内核转储文件。
  /etc/profile 文件中可以设置开启所有用户的内核转储功能,默认情况下禁止内核转储:
ulimit -S -c 0 > /dev/null 2>&11
  将其修改为
ulimit -S -c unlimited > /dev/null 2>&11
     接下来要让通过 init 脚本启动的守护进程的内核转储功能有效。在 /etc/sysconfig/init 文件中添加一行命令。
DAEMON_COREFILE_LIMIT='unlimited'1
     最后在 /etc/sysctl.conf 中加入以下设置。
fs.suid_dumpable=11
  这个设置使得被 SUID 的程序也能内核转储。重新启动启动,就可以启用整个系统的内核转储。      在我使用的Ubuntu、Debian和移植的嵌入式Linux系统中,没有找到 /etc/sysconfig 文件夹。修改了文件 /etc/security/limits.conf,按照文件的内容提示修改,使 unlimited 永久生效。
  多进程程序如果使用庞大的共享内存,内核转储时所有进程的共享内存全部转储,会对磁盘造成巨大的压力,转储过程也会加重系统的负载。由于共享内存的内容是相同的,只需要在某个进程中转储共享内存。      通过 /proc/
比特掩码 | 内存类型 |
---|---|
比特 0 | 匿名专用内存 |
比特 1 | 匿名共享内存 |
比特 2 | file-backed 专用内从 |
比特 3 | file-backed 共享内存 |
比特 4 | ELF 文件映射(内核版本 2.6.24 后可用) |
  要跳过所有的共享内存区段,应将值改位 1。
  要调试已经启动的进程,或是调试陷入死循环而无法返回控制台的进程时,可以使用 attach 命令。格式:attach
  break if ,这条命令将测试给定的条件,如果为帧则暂停运行。      如果断点已经存在,condition 命令给断点添加触发条件,condition 命令删除指定编号断点的触发条件。
  ignore :在编号指定的断点、监视点或捕获点忽略指定的次数。   continue : 达到指定次数前,执行到断电时不暂停。   s/stepi/n/nexti :执行指定次数的相应命令。   finish:执行完当前函数后暂停。   until:执行完当前函数等代码块后暂停,如果是循环,则在执行完循环后暂停,常用于跳出循环。   until :执行到指定地址停止。
  commands 命令可以定义在断点终端后自动执行的命令。格式如下:
(gdb) commands ... end1234
  通过 print 命令显示过的值会记录在内部的值历史中。这些值通过 $ 进行引用,使用 show value 命令可以显示历史中的最后 10 个值。
变量 | 说明 |
---|---|
$ | 值历史的最后一个值 |
$n | 值历史的第 n 个值 |
$$ | 值历史的倒数第 2 个值 |
$$n | 值历史的倒数第 n 个值 |
$_ | x 命令显示过的最后的地址 |
$__ | x 命令显示过的最后的地址的值 |
$_eexitcode | 调试过程中的程序的返回代码 |
$bpnum | 最后设置的断点编号 |
     还可以随意定义变量,变量以 $ 开头,由英文字母和数字组成。例如:
(gdb) set $i=0 (gdb) p $i $i = 0123
  show history 将命令历史保存到文件中,默认命令历史文件位于 ./.gdb_history。
  set history expansion   show history expansion
  可以使用 csh 风格的 ! 字符。
  set history filename   show history filename
  将命令历史保存到文件中。可以通过环境变量 GDBHISTFILE 改变默认文件名。
  set history save   show history save
  启用命令历史保存到文件和恢复的功能。
  set history size   show history size
  可设置保存到命令历史中的命令数量。默认值为 256。
  Linux 环境下的初始化文件为 .gdbinit。如果存在 .gdbinit 文件,GDB 会在启动之前将其作为命令文件运行。初始化文件和命令文件的运行顺序如下。
1、$HOME/.gdbinit。
2、运行命令行选项。
3、./.gdbinit。
4、通过 -x 选项给出的命令文件。
  初始化文件和命令文件的语法相同。利用 define 命令可以自定义命令,document 命令给自定义命令添加说明,GDB 运行时使用 help 可以查看定义的命令。示例如下:
define li x/10i $pc end document li list machine instruction end123456
     除了初始化文件,还可以把设置写在文件中,在运行 GDB 时读取这些文件。命令为 source ,例如:
(gdb) source gdbcalc (gdb) p $log10(10000.0) $1 = 4123
  其中 gdbcalc 文件内容如下:
#!/usr/bin/gdb -x file /usr/bin/gdb start set $e = 2.7182818284590452354 set $pi = 3.14159265358979323846 set $fabs = (double (*)(double)) fabs set $sqrt = (double (*)(double)) sqrt set $cbrt = (double (*)(double)) cbrt set $exp = (double (*)(double)) exp set $exp2 = (double (*)(double)) exp2 set $exp10 = (double (*)(double)) exp10 set $log = (double (*)(double)) log set $log2 = (double (*)(double)) log2 set $log10 = (double (*)(double)) log10 set $pow = (double (*)(double, double)) pow set $sin = (double (*)(double)) sin set $cos = (double (*)(double)) cos set $tan = (double (*)(double)) tan set $asin = (double (*)(double)) asin set $acos = (double (*)(double)) acos set $atan = (double (*)(double)) atan set $atan2 = (double (*)(double, double)) atan set $sinh = (double (*)(double)) sinh set $cosh = (double (*)(double)) cosh set $tanh = (double (*)(double)) tanh set $asinh = (double (*)(double)) asinh set $acosh = (double (*)(double)) acosh set $atanh = (double (*)(double)) atanh22345678910111213141516171819202122232425262728
  GDB 常用命令及缩略形式如下表:
命令 | 简写形式 | 说明 |
---|---|---|
backtrace | bt、where | 显示 backtrace |
break | 设置断点 | |
continue | c、cont | 继续运行 |
delete | d | 删除断点 |
finish | 运行到函数结束 | |
info breakpoints | 显示断点信息 | |
next | n | 执行下一行 |
p | 显示表达式 | |
run | r | 运行程序 |
step | s | 一次执行一行,包括函数内部 |
x | 显示内存内容 | |
until | u | 执行到指定行 |
directory | dir | 插入目录 |
disable | dis | 禁用断点 |
down | do | 在当前调用的栈帧中选择要显示的栈帧 |
edit | e | 编辑文件或函数 |
frame | f | 选择要显示的栈帧 |
forward-search | fo | 向前搜索 |
generate-core-file | gcore | 生成内核转储 |
help | h | 显示帮助一览 |
info | i | 显示信息 |
list | l | 显示函数或行 |
nexti | ni | 执行下一行(以汇编代码为单位) |
print-object | po | 显示目标信息 |
sharedlibrary | share | 加载共享库的符号 |
setpi | si | 执行下一行 |
显示详细信息
以上是“Linux系统中GDB是什么”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。