百科生活 投稿
关于【gdb操作汇总解析】,今天小编给您分享一下,如果对您有所帮助别忘了关注本站哦。
- 内容导航:
- 1、gdb操作汇总解析:gdb还不会吗?看这篇
- 2、gdb操作汇总解析,GDT基础知识简介与应用
1、gdb操作汇总解析:gdb还不会吗?看这篇
"title":"总览","content"
本文为GDB调试指南,参考GDB调试手册,但加入了很多实例,目前已有的篇目:
- 启动调试
- 断点设置
- 变量查看
- 单步调试
- 源码查看
每个篇目都加入了示例,可操作性强。
"title":"启动调试","content"前言
GDB(GNU Debugger)是UNIX及UNIX-like下的强大调试工具,可以调试ada, c, c++, asm, minimal, d, fortran, objective-c, go, java,pascal等语言。本文以C程序为例,介绍GDB启动调试的多种方式。
哪类程序可被调试
对于C程序来说,需要在编译时加上-g参数,保留调试信息,否则不能使用GDB进行调试。
但如果不是自己编译的程序,并不知道是否带有-g参数,如何判断一个文件是否带有调试信息呢?
gdb 文件
例如:
$ gdb helloworldReading symbols from helloWorld...(no debugging symbols found)...done.
如果没有调试信息,会提示no debugging symbols found。
如果是下面的提示:
Reading symbols from helloWorld...done.
则可以进行调试。
readelf查看段信息
例如:
$ readelf -S helloWorld|grep debug [28] .debug_aranges PROGBITS 0000000000000000 0000106d [29] .debug_info PROGBITS 0000000000000000 0000109d [30] .debug_abbrev PROGBITS 0000000000000000 0000115b [31] .debug_line PROGBITS 0000000000000000 000011b9 [32] .debug_str PROGBITS 0000000000000000 000011fc
helloWorld为文件名,如果没有任何debug信息,则不能被调试。
file查看strip状况
下面的情况也是不可调试的:
file helloWorldhelloWorld: (省略前面内容) stripped
如果最后是stripped,则说明该文件的符号表信息和调试信息已被去除,不能使用gdb调试。但是not stripped的情况并不能说明能够被调试。
调试方式运行程序
程序还未启动时,可有多种方式启动调试。
调试启动无参程序
例如:
$ gdb helloWorld(gdb)
输入run命令,即可运行程序
调试启动带参程序
假设有以下程序,启动时需要带参数:
//来源:公众号【编程珠玑】 地址:https://www.yanbinghu.com#include 编译: gcc -g -o hello hello.c 这种情况如何启动调试呢?需要设置参数: $ gdb hello(gdb)run 编程珠玑Starting program: /home/shouwang/workspaces/c/hello 编程珠玑Hello World 编程珠玑 只需要run的时候带上参数即可。 或者使用set args,然后在用run启动: gdb hello(gdb) set args 编程珠玑(gdb) runStarting program: /home/hyb/workspaces/c/hello 编程珠玑Hello World 编程珠玑 调试core文件 当程序core dump时,可能会产生core文件,它能够很大程序帮助我们定位问题。但前提是系统没有限制core文件的产生。可以使用命令limit -c查看: $ ulimit -c0 如果结果是0,那么恭喜你,即便程序core dump了也不会有core文件留下。我们需要让core文件能够产生: ulimit -c unlimied #表示不限制core文件大小ulimit -c 10 #设置最大大小,单位为块,一块默认为512字节 上面两种方式可选其一。第一种无限制,第二种指定最大产生的大小。 调试core文件也很简单: gdb 程序文件名 core文件名 通常输入bt查看调用栈。 调试已运行程序 如果程序已经运行了怎么办呢? 首先使用ps命令找到进程id: ps -ef|grep 进程名 attach方式 假设获取到进程id为20829,则可用下面的方式调试进程: $ gdb(gdb) attach 20829 接下来就可以继续你的调试啦。 可能会有下面的错误提示: Could not attach to process. If your uid matches the uid of the targetprocess, check the setting of /proc/sys/kernel/yama/ptrace_scope, or tryagain as the root user. For more details, see /etc/sysctl.d/10-ptrace.confptrace: Operation not permitted. 解决方法,切换到root用户: 将/etc/sysctl.d/10-ptrace.conf中的 kernel.yama.ptrace_scope = 1 修改为 kernel.yama.ptrace_scope = 0 直接调试相关id进程 还可以是用这样的方式gdb program pid,例如: gdb hello 20829 或者: gdb hello --pid 20829 已运行程序没有调试信息 为了节省磁盘空间,已经运行的程序通常没有调试信息。但如果又不能停止当前程序重新启动调试,那怎么办呢?还有办法,那就是同样的代码,再编译出一个带调试信息的版本。然后使用和前面提到的方式操作。对于attach方式,在attach之前,使用file命令即可: $ gdb(gdb) file helloReading symbols from hello...done.(gdb)attach 20829 小结 本小结主要介绍了两种类型的GDB启动调试方式,分别是调试未运行的程序和已经运行的程序。对于什么样的程序能够进行调试也进行了简单说明。 前言 上节我们讲到了GDB启动调试的多种方式,分别应用于多种场景。今天我们来介绍一下断点设置的多种方式。 为何要设置断点 在介绍之前,我们首先需要了解,为什么需要设置断点。我们在指定位置设置断点之后,程序运行到该位置将会“暂停”,这个时候我们就可以对程序进行更多的操作,比如查看变量内容,堆栈情况等等,以帮助我们调试程序。 查看已设置的断点 在学习断点设置之前,我们可以使用info breakpoints查看已设置断点: info breakpointsNum Type Disp Enb Address What1 breakpoint keep y 0x00000000004005fc in printNum2 at test.c:17 breakpoint already hit 1 time2 hw watchpoint keep y a breakpoint already hit 1 time ignore next 3 hits 它将会列出所有已设置的断点,每一个断点都有一个标号,用来代表这个断点。例如,第2个断点设置是一个观察点,并且会忽略三次。 断点设置 断点设置有多种方式,分别应用于不同的场景。借助示例程序进行一一介绍: //来源:公众号【编程珠玑】 地址:https://www.yanbinghu.com//test.c#include 编译: gcc -g -o test test.c 注意,编译时需要带上-g参数,否则不会有调试信息。 根据行号设置断点 b 9 #break 可简写为b 或者 b test.c:9 程序运行到第9行的时候会断住。 根据函数名设置断点 同样可以将断点设置在函数处: b printNum 程序在调用到printNum函数的时候会断住。 根据条件设置断点 假设程序某处发生崩溃,而崩溃的原因怀疑是某个地方出现了非期望的值,那么你就可以在这里断点观察,当出现该非法值时,程序断住。这个时候我们可以借助gdb来设置条件断点,例如: break test.c:23 if b==0 当在b等于0时,程序将会在第23行断住。 它和condition有着类似的作用,假设上面的断点号为1,那么: condition 1 b==0 会使得b等于0时,产生断点1。而实际上可以很方便地用来改变断点产生的条件,例如,之前设置b==0时产生该断点,那么使用condition可以修改断点产生的条件。 根据规则设置断点 例如需要对所有调用printNum函数都设置断点,可以使用下面的方式: rbreak printNum* 所有以printNum开头的函数都设置了断点。而下面是对所有函数设置断点: #用法:rbreak file:regexrbreak . rbreak test.c:. #对test.c中的所有函数设置断点rbreak test.c:^print #对以print开头的函数设置断点 设置临时断点 假设某处的断点只想生效一次,那么可以设置临时断点,这样断点后面就不复存在了: tbreak test.c:l0 #在第10行设置临时断点 跳过多次设置断点 假如有某个地方,我们知道可能出错,但是前面30次都没有问题,虽然在该处设置了断点,但是想跳过前面30次,可以使用下面的方式: ignore 1 30 其中,1是你要忽略的断点号,可以通过前面的方式查找到,30是需要跳过的次数。这样设置之后,会跳过前面30次。再次通过info breakpoints可以看到: Num Type Disp Enb Address What1 breakpoint keep y 0x00000000004005e8 in printNum2 at test.c:16 ignore next 30 hits 根据表达式值变化产生断点 有时候我们需要观察某个值或表达式,知道它什么时候发生变化了,这个时候我们可以借助watch命令。例如: watch a 这个时候,让程序继续运行,如果a的值发生变化,则会打印相关内容,如: Hardware watchpoint 2: aOld value = http://www.029ztxx.com/tg/12New value = 11 但是这里要特别注意的是,程序必须运行起来,否则会出现: No symbol "a" in current context. 因为程序没有运行,当前上下文也就没有相关变量信息。 rwatch和awatch同样可以设置观察点前者是当变量值被读时断住,后者是被读或者被改写时断住。 禁用或启动断点 有些断点暂时不想使用,但又不想删除,可以暂时禁用或启用。例如: disable #禁用所有断点disable bnum #禁用标号为bnum的断点enable #启用所有断点enable bnum #启用标号为bnum的断点enable delete bnum #启动标号为bnum的断点,并且在此之后删除该断点 断点清除 断点清除主要用到clear和delete命令。常见使用如下: clear #删除当前行所有breakpointsclear function #删除函数名为function处的断点clear filename:function #删除文件filename中函数function处的断点clear lineNum #删除行号为lineNum处的断点clear f:lename:lineNum #删除文件filename中行号为lineNum处的断点delete #删除所有breakpoints,watchpoints和catchpointsdelete bnum #删除断点号为bnum的断点 小结 本小结介绍了常见的断点设置方法,断点设置之后,可以便于我们后期观察变量,堆栈等信息,为进一步的定位与调试做准备。 前言 在启动调试以及设置断点之后,就到了我们非常关键的一步-查看变量。GDB调试最大的目的之一就是走查代码,查看运行结果是否符合预期。既然如此,我们就不得不了解一些查看各种类型变量的方法,以帮助我们进一步定位问题。 准备工作 在查看变量之前,需要先启动调试并设置断点,这个在前面两小节中已经降到。后面的内容都基于在某个位置已经断住。 本文辅助说明程序如下: testGdb.c //来源:公众号【编程珠玑】 地址:https://www.yanbinghu.com//testGdb.c#include testGdb.h int a = 11; 编译: $ gcc -g -o testGdb testGdb.o 普通变量查看 打印基本类型变量,数组,字符数组 最常见的使用便是使用print(可简写为p)打印变量内容。 例如,打印基本类型,数组,字符数组等直接使用p 变量名即可: (gdb) p a$1 = 10(gdb) p b$2 = {1, 2, 3, 5}(gdb) p c$3 = "hello,yanbinghu"(gdb) 当然有时候,多个函数或者多个文件会有同一个变量名,这个时候可以在前面加上函数名或者文件名来区分: (gdb) p 'testGdb.h'::a$1 = 11(gdb) p 'main'::b$2 = {1, 2, 3, 5}(gdb) 这里所打印的a值是我们定义在testGdb.h文件里的,而b值是main函数中的b。 打印指针指向内容 如果还是使用上面的方式打印指针指向的内容,那么打印出来的只是指针地址而已,例如: (gdb) p d$1 = (int *) 0x602010(gdb) 而如果想要打印指针指向的内容,需要解引用: (gdb) p *d$2 = 0(gdb) p *d@10$3 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}(gdb) 从上面可以看到,仅仅使用*只能打印第一个值,如果要打印多个值,后面跟上@并加上要打印的长度。 或者@后面跟上变量值: (gdb) p *d@a$2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}(gdb) 由于a的值为10,并且是作为整型指针数据长度,因此后面可以直接跟着a,也可以打印出所有内容。 另外值得一提的是,$可表示上一个变量,而假设此时有一个链表linkNode,它有next成员代表下一个节点,则可使用下面方式不断打印链表内容: (gdb) p *linkNode(这里显示linkNode节点内容)(gdb) p *$.next(这里显示linkNode节点下一个节点的内容) 如果想要查看前面数组的内容,你可以将下标一个一个累加,还可以定义一个类似UNIX环境变量,例如: (gdb) set $index=0(gdb) p b[$index++]$11 = 1(gdb) p b[$index++]$12 = 2(gdb) p b[$index++]$13 = 3 这样就不需要每次修改下标去打印啦。 按照特定格式打印变量 对于简单的数据,print默认的打印方式已经足够了,它会根据变量类型的格式打印出来,但是有时候这还不够,我们需要更多的格式控制。常见格式控制字符如下: 还是以辅助程序来说明,正常方式打印字符数组c: (gdb) p c$18 = "hello,yanbinghu" 但是如果我们要查看它的十六进制格式打印呢? (gdb) p/x c$19 = {0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x79, 0x61, 0x6e, 0x62, 0x69, 0x6e, 0x67, 0x68, 0x75, 0x0}(gdb) 但是如果我们想用这种方式查看浮点数的二进制格式是怎样的是不行的,因为直接打印它首先会被转换成整型,因此最终会得到8: (gdb) p e$1 = 8.5(gdb) p/t e$2 = 1000(gdb) 那么就需要另外一种查看方式了。 查看内存内容 examine(简写为x)可以用来查看内存地址中的值。语法如下: x/[n][f][u] addr 其中: 单元类型常见有如下: 我们通过一个实例来看,假如我们要把float变量e按照二进制方式打印,并且打印单位是一字节: (gdb) x/4tb &e0x7fffffffdbd4: 00000000 00000000 00001000 01000001(gdb) 可以看到,变量e的四个字节都以二进制的方式打印出来了。 自动显示变量内容 假设我们希望程序断住时,就显示某个变量的值,可以使用display命令。 (gdb) display e1: e = 8.5 那么每次程序断住时,就会打印e的值。要查看哪些变量被设置了display,可以使用: (gdb)into displayAuto-display expressions now in effect:Num Enb Expression1: y b2: y e 如果想要清除可以使用 delete display num #num为前面变量前的编号,不带num时清除所有。 或者去使能: disable display num #num为前面变量前的编号,不带num时去使能所有 查看寄存器内容 (gdb)info registersrax 0x0 0rbx 0x0 0rcx 0x7ffff7dd1b00 140737351850752rdx 0x0 0rsi 0x7ffff7dd1b30 140737351850800rdi 0xffffffff 4294967295rbp 0x7fffffffdc10 0x7fffffffdc10(内容过多未显示完全) 小结 通过不同方式查看变量值或者内存值能够极大的帮助我们判断程序的运行是否符合我们的预期,如果发现观察的值不是我们预期的时候,就需要检查我们的代码了。 前言 我们已经了解了GDB基本的启动,设置断点,查看变量等,如果这些内容你还不知道,建议先回顾一下前面的内容。在启动调试设置断点观察之后,没有我们想要的信息怎么办呢?这个时候,就需要单步执行或者跳过当前断点继续执行等等。而本文所说的单步调试并非仅仅指单步执行,而是指在你的控制之下,按要求执行语句。 准备 老规矩,先准备一个示例程序如下: //来源:公众号【编程珠玑】 地址:https://www.yanbinghu.com#include 编译: gcc -g -o gdbStep gdbStep.c 程序的功能比较简单,这里不多做解释。 特别简单说明一条命令,list(可简写为l),它可以将源码列出来,例如: (gdb) list1 #include 单步执行-next next命令(可简写为n)用于在程序断住后,继续执行下一条语句,假设已经启动调试,并在第12行停住,如果要继续执行,则使用n执行下一条语句,如果后面跟上数字num,则表示执行该命令num次,就达到继续执行n行的效果了: $ gdb gdbStep #启动调试(gdb)b 25 #将断点设置在12行(gdb)run #运行程序Breakpoint 1, main () at gdbStep.c:2525 int b = 7;(gdb) n #单步执行26 printf("it will calc a + b");(gdb) n 2 #执行两次it will calc a + b28 printf("%d + %d = %d",a,b,c);(gdb) 从上面的执行结果可以看到,我们在25行处断住,执行n之后,运行到26行,运行n 2之后,运行到28行,但是有没有发现一个问题,为什么不会进入到add函数内部呢?那就需要用到另外一个命令啦。 单步进入-step 对于上面的情况,如果我们想跟踪add函数内部的情况,可以使用step命令(可简写为s),它可以单步跟踪到函数内部,但前提是该函数有调试信息并且有源码信息。 $ gdb gdbStep #启动调试(gdb) b 25 #在12行设置断点Breakpoint 1 at 0x4005d3: file gdbStep.c, line 25.(gdb) run #运行程序Breakpoint 1, main () at gdbStep.c:2525 int b = 7;(gdb) s 26 printf("it will calc a + b");(gdb) s #单步进入,但是并没有该函数的源文件信息_IO_puts (str=0x4006b8 "it will calc a + b") at ioputs.c:3333 ioputs.c: No such file or directory.(gdb) finish #继续完成该函数调用Run till exit from #0 _IO_puts (str=0x4006b8 "it will calc a + b") at ioputs.c:33it will calc a + bmain () at gdbStep.c:2727 int c = add(a,b);Value returned is $1 = 19(gdb) s #单步进入,现在已经进入到了add函数内部add (a=13, b=57) at gdbStep.c:66 int c = a + b; 从上面的过程可以看到,s命令会尝试进入函数,但是如果没有该函数源码,需要跳过该函数执行,可使用finish命令,继续后面的执行。如果没有函数调用,s的作用与n的作用并无差别,仅仅是继续执行下一行。它后面也可以跟数字,表明要执行的次数。 当然它还有一个选项,用来设置当遇到没有调试信息的函数,s命令是否跳过该函数,而执行后面的。默认情况下,它是会跳过的,即step-mode值是off: (gdb) show step-mode Mode of the step operation is off.(gdb) set step-mode alt="gdb操作汇总解析,gdb还不会吗?看这篇" src="http://p3.toutiaoimg.com/large/tos-cn-i-qvj2lq49k0/62f7099cfbd342028de3f88bbc297a0c" /> GD&T的应用 为了理解 GD&T 在生产环境中的定性应用,必须了解设计模型。设计模型由一组几何形状组成,称为特征。在完成的设计中,必须定义特征的几何形状,并且必须约束其几何属性(例如,位置、方向、大小和形状)的偏差。有两种常用的方法来约束设计模型中特征的几何的偏差。GD&T 可以根据零件的功能或零件的制造方式应用于每个特征。它通常被认为是基于零件功能的 GD&T 应用的最佳实践。 第一步:使用已建立的基准参考应用GD&T 将 GD&T 应用于设计模型的第一步是建立基准参考框架 (DRF)。建立的第一个基准坐标系称为主导基准坐标系。在 GD&T 的功能方法中,在其装配中定向和定位零件的表面通常用作用于建立主要 DRF 的基准特征。基准特征选择还有其他注意事项: 第二步:应用GD&T约束特征属性 一旦建立了主要的 DRF,您就可以使用 GD&T 约束模型中每个特征的几何属性相对于基于函数的 DRF。在复杂的零件中,可能需要建立多个 DRF,但最终零件中的所有特征都必须直接或间接地约束到主要的 DRF。 Sigmetrix 的GD&T Advisor软件提供了方便的工具,用于在您的零件上定义特征,将 GD&T 应用于这些特征,然后评估每个特征和在特征上应用的条件 GD&T 以确定特征的所有几何属性是否都受到完全约束。 下表显示了用于指定 ASMEY14.5M-1994 标准中特征的几何偏差限制的几何特征符号。 几何特征符号与公差值、修改符号和基准参考框架一起组合在一个特征控制框架中,如下所示。 特征控制框架,有时称为 GD&T 标注,定义基于特征功能和设计意图的允许特征偏差。 考虑此处显示的锁爪零件。该零件是座椅锁定机构中的一个部件。大平面与另一个零件上的平面齐平安装,并标记为基准特征 A。大孔是爪的中心旋转孔,代表重要的功能特征,标记为基准特征 B。小平面爪尖上的位置是爪与撞杆接触的位置,以确保座椅固定在车架上,并标记为基准特征 C。还有其他几个功能特征。这些特征应参照安装特征 A、B 和 C 进行控制。该部件的所有其余特征都不太重要,并通过可在注释中找到的一般轮廓公差进行控制。 虽然有多种方法可以计算产生零件本身允许的差异所需的所有数据,但与使用集成的容差分析软件(例如CETOL 6 Sigma或 Sigmetrix 的GD&T Advisor)相比,其他方法可能既耗时又不准确。在您的环境中使用的解决方案将影响您的整体生产成本和质量。通过选择与您的团队已经使用的 CAD 系统集成的软件(CREO、SOLIDWORKS、CATIA)——在产品设计和工程阶段的早期就实现了时间和准确性。 GD&T ADVISOR软件 作为设计过程的必要功能,几何尺寸和公差(GD&T)通常被认为是一项繁琐的手动练习,其中手动绘制规格并作为单独的步骤应用于 CAD 图纸。 进入GD&TAdvisor - 首选的 GD&T 软件解决方案,它使设计师能够在 CAD 环境中传达真实世界制造零件中允许的缺陷水平。 GD&TAdvisor 是一种交互式软件工具,可为正确应用 GD&T 提供专家指导。它指导用户在 CAD 环境中应用 GD&T,确保符合标准,同时大大提高生产力。 使用 GD&T Advisor,提高生产力、改进设计质量和降低成本成为现实。在将GD&T 应用于模型设计时,GD&TAdvisor 极大地提高了生产力,将鼠标点击次数和所需时间减少了多达 75%。GD&T Advisor 通过在应用程序的每个步骤中提供现成的指导,简化了对复杂 GD&T 标准的理解。节省设计检查的宝贵时间并加快设计过程,同时减少通常与尺寸和公差错误相关的废品和工程变更 (ECN)。 节省质量检查的宝贵时间并加快设计流程,同时减少制造阶段常见的废料和工程变更单——每年可节省数千至数万美元。 使用GD&TAdvisor,提高生产力、提高制造精度和降低成本成为现实。能够以显着减少的点击次数执行标准化的 GD&T 分析,从而大大缩短了分析时间。 质量检查成为一种快速而轻松的做法——节省宝贵的时间并加速设计过程,同时减少制造阶段通常熟悉的废料和工程变更单——每年节省数千甚至数万美元。 GD&T Advisor解决了 GD&T 应用程序的三个关键方面: •创建– 在 3D 模型环境中高效、智能地、语法上正确的应用 GD&T •验证– GD&T 的可视化和面向功能的评估 •使用– 智能、CAD 原生注释可用于下游流程,例如绘图制作、公差分析、计算机辅助检查和其他设计活动 本文关键词:gdb 操作,gdb常用指令,gdb 使用,gdb 常用命令,gdb分析coredump。这就是关于《gdb操作汇总解析,gdb还不会吗?看这篇》的所有内容,希望对您能有所帮助!
将GD&T应用于设计模型的一般方法
为什么选择 GD&T ADVISOR ?
好处
GD&T软件功能和控制
- 上一篇: 新年的古诗词,新年有画意
- 下一篇: 采样是什么意思,为什么环球音乐、索尼音乐都在抢
- 最近发表