linux中GDB详细使用手册

同步github地址 同步github地址: QQ: 564631192 因为执行脚本的时候会自动新启用一个子 bash因此在脚本中设置的ulimit -c unlimited 并不能产生核心转存储文件,需要执行可执行文件之前手动设置一下 ulimit -c unlimited DEBUG 是在linux下使用dbg的记录,一下的文件是在UBUNTU 16.04上验证通过的 1.通过gcc 的 -g 选项生成调试信息。 2.如果使用Makefile构建,一般要给CFLAGS中指定 -g 选项 3.如果使用configure脚本生成Makefile文件,可以这样使用。 启动 gdb 可执行文件名 可以在函数名和行号等上设置断点,程序运行后,达到断点就会自动暂停运行。此时可以查看时刻的变量值、显示栈帧、重新设置断点或重新运行等。断点命令(break),可以简写为b. ##格式: break 断点 (gdb) b main 断点可以通过函数名、当前文件内的行号来设置,也可以先指定文件名在指定行号,还可以指定与暂停位置的偏移量,或者地址来设置。 #格式说明: 例: ##运行 使用run命令开始运行,不加参数直接执行run 就会执行到设置断点的位置后暂停运行。可以简写为 r ##格式 ##显示栈帧 backtrace 命令可以在遇到断点而停止执行时显示栈帧。该命令简写为 bt 。此外,backtrace的别名还有 where 和 info stack(info s) ##格式: #显示变量 print命令可以显示变量。print可以简写为p ##格式; 单步执行的意思是根据源代码一行一行执行。 执行源代码中的一行的命令为next(简写为 n)。执行时如果遇到函数调用,可能想执行到函数内部,此时可以使用step(简写为p) 命令。 也就是说当有子函数调用的时候,使用n命令直接执行子函数获得返回值,但是 step命令会进入子函数中执行; next命令和step命令都是执行源代码中的一行,若果要逐条执行汇编指令,可以分别使用nexti命令和stepi命令 调试时,可以使用continue(简写为c)命令继续运行程序,程序会在遇到断点后再次暂停运行, 如果 没有遇到断点就会一直运行到结束。 大型软件或大量使用指针的程序中,很难男女感情变量在什么地方被改变。想要找到变量在何处被改变,可以使用watch命令(监视点,watchpoint)。 格式: watch <表达式> <表达式>发生变化时暂停运行。 此处表达式的意识是常量或变量等。 格式: awatch <表达式> <表达式>被访问,改变时暂停运行。 格式: rwatch <表达式> <表达式>被访问时暂停运行。 用delete(简写为 d)命令删除断点和监视点。 格式: 使用generate-core-file可将调试中的进程生成核心转存储文件 功能,将正在调试的文件生成核心转存储文件 有了内核转存储文件和调试对象,以后就能查看生成转存储文件时的运行历史(寄存器值,内存值等)。 例: 此外,gcore命令可以从命令行直接生成内核转存储文件。 确认行为之后,需要在gdb和进程分离时使用detach命令,这样调试中的进程就被从gdb的控制下释放出来,进程被detach后会继续运行 进程信息可以使用info proc命令显示 要调试守护进程(daemon process)等已经启动的进程,或者调试陷入死循环而无法返回的控制台进程时,可以使用attach命令 格式: 执行这一命令就可以attach到进程ID为pid的进程上。 下面使用sleep命令进行GDB调试 在特定条件下执行中断 格式: 这条命令将测试给定的条件,如果条件为真暂停运行。 例: 格式: 在指定的断点、监视点(watchpoint)或捕获点(catchpoint)忽略指定的次数。 continue命令与ignore命令一样,可以指定次数,达到指定次数前执行到断点时不暂停, 二者意义相同。 格式; 这些命分别执行指定次数的相应命令。 格式: finish 命令执行完当前函数后暂停,until命令执行完当前函数等代码块后暂停, 若果是循环,则执行完循环后暂停,常用于跳出循环。 用clear 命令删除已定义的断点,如果要保留定义,只想临时禁用断点的话,可以使用disable命令; 将禁用的断点重新启用,可以使用enable命令; 格式: 格式: 如果不指定断点编号,则禁用多有的断点,否则禁用指定断点 第3种命令禁用display命令定义的自动显示 第4中格式禁用mem命令定义的内存区域 可以省略breakpoints关键字 格式: 这些格式用于显示断点,once指定的断点只启用一次,也就是说,程序运行到该断点并暂停后,该断点即被禁用。 这与delete命令助攻的once不同,后者在运行暂停后删除断点 断点命令(commands)可以定义在断点中断后执行的命令 格式: 程序在执行到断点处暂停后,就会自动执行命令 与前面的条件断点组合使用,就可以在断点暂停时,执行复杂的显示动作等 info命令能够显示调试对象的各种各样的信息,另外show命令能够显示GDB内部的功能、变量和选项等。 通过print 命令显示过的值会记录在内部的值历史中,这些值可以在其他表达式中使用 用 show value 命令可以显示历史中的最后 10 个值 值历史的访问说明 可以随意的定义变量,变量以$ 开头,由英文字母和数字组成 可以将命令历史保存在文件中,保存命令历史后,就能在其它调试会话中重复利用这些命令(通过箭头键以查找以前的命令)、 十分方便,默认的历史文件位于 显示历史命令 格式: 可以使用csh风格的!字符 格式: 可将命令历史保存到文件中,可以通过环境变量GDBHISTFILE改变默认文件名 格式: 启用命令历史保存到文件和恢复的功能 格式: 设置保存到命令历史中的命令数量,默认值是256 星期六, 23. 二月 2019 12:20下午 linux环境下初始化文件为 .gdbinit。如果存在.gdbinit 文件,GDB就会在启动之前将其作为命令文件运行,初始化文件和命令文件的运行顺序如下: 1、$HOME/.gdbinit 2、运行命令选项 3、 4、通过 -x 选项给出的命令文件 初始化文件的语法和命令文件的语法相同,都由gdb命令组成 利用define命令可以定义命令,还可以使用document命令给自定义的命令添加说明,用help命令名,可以查看定义的命令名 格式: 格式: 格式: 例: 定义了一个 名为 li的命令,它能显示当前 $pc 所指的位置开始的10条指令。另外,用document命令给li命令定义了说明,使用help li可以查看说明; 除了使用初始化文件,还可以将各种设置文件写在文件中,,在运行调试器时读取这些文件 格式; 栈是程序存放数据的内存区域之一,其特征是LIFO(last in first out,后进先出)式数据结构,即后放进的数据先被取出,向栈中存储数据的操作称为PUSH(压入),从栈中取出数据称为POP(弹出),保存动态分配的自动变量时要使用栈,此外在函数调用时,栈还用于传递函数参数,以及用于保存返回地址和返回值。 调试选择栈帧,除了使用frame n 指定,还可以使用up down up是选择上一层栈帧,dowm是选择下一层栈帧 使用 info 命令的 frame 选项可以查看到更详细的栈帧信息,可以用帧编号作为该命令的选项 x/i $pc --> 以汇编的形式查看当前栈帧处的代码 (gdb) info proc mapping --> 查看该进程内存映射的命令 process 13193 Mapped address spaces: 说明: 可以使用info proc mapping 查看进程的内存映射,要保证占空间的栈顶端的值小于pc的值,程序才能正常运行,说明栈没有溢出 但是使用该命令时,GDB文件会打开/proc//maps,因此在分析coredump文件的时候无法使用,分析coredump文件的时候 可以使用下面的命令得到相同的信息。 (gdb)info files 或者 (gdb)info target 星期六, 23. 二月 2019 12:20下午 GDB等调试器的backtrace功能是通过搜索栈中的保存信息来实现的。 栈信息对于调试器来说非常重要,关于栈破坏可以看HACK#27 backtrace无法正确显示和 HACK#28 数组非法访问导致内存破坏 编译时使用GCC指定 -formit-frame-pointer选项,即可生成不使用栈指针的二进制文件即使这样使用GDB依然能够正确理解帧, 因为GDB是根据记录在调试信息中的栈使用量来计算帧的位置的 使用bt命令可以查栈的状态 使用frame可以查看现在选择的帧 调试没有调试信息的程序,使用 b *func 即函数前面加上 * 因为不使用 断点就不会设置到汇编语言层次的函数开头, 而是设置到地址偏后一点的源代码级别的开头,如果在break命令中不加 直接使用函数名,就无法用于参数确认。 Oops信息的解读方法Oops信息是内核发生致命错误时输出的内核信息 说明栈被破坏的就不嗯给你信任调试器生成的backtrace信息,极端一点说,新来backtrace只有在栈没有被破坏的前提下才成立 认为调试器的信息绝对正确是十分危险的 利用GDB进行调试,寄存器信息是绝对不能忽视的 调查栈破坏的方法有很多种,但是最显示的方法就是根据被破坏的数据内容,判断执行写入的位置,看看又没哟对栈空间(也就是自动变量空间)的引用、指针传递处理。 数组的错误操作 错误的操作数组导致典型的bug之一就是缓存区溢出,也就是说向已分配的内存空间写入数据,特别是如果这类bug发生在栈上的缓存区中,就可能引发安全漏洞 当使用-g编译选项之后利用GDB读入core并显示backtrace之后栈中的还是没有显示符号名,可以怀疑是缓冲区溢出的情况 这时使用 x/i +地址显示查看栈中地址的汇编语言,再根据程序在该架构中常放置的地址和共享内存常放置的地址判断是否是数组越界 魔法键=CTRL+PgUp键 之后按键 h p打印寄存器信息