今天给各位分享个人引导网站源码分享下载的知识,其中也会对超简洁的个人引导页源码进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
GNU调试器是一个发现程序缺陷的强大工具。
如果你是一个程序员,想在你的软件增加某些功能,你首先考虑实现它的方法:例如写一个方法、定义一个类,或者创建新的数据类型。然后你用编译器或解释器可以理解的编程语言来实现这个功能。但是,如果你觉得你所有代码都正确,但是编译器或解释器依然无法理解你的指令怎么办?如果软件大多数情况下都运行良好,但是在某些环境下出现缺陷怎么办?这种情况下,你得知道如何正确使用调试器找到问题的根源。
GNU调试器GNUProjectDebugger(GDB)是一个发现项目缺陷的强大工具。它通过追踪程序运行过程中发生了什么来帮助你发现程序错误或崩溃的原因。(LCTT校注:GDB全程是“GNUProjectDebugger”,即“GNU项目调试器”,但是通常我们简称为“GNU调试器”)
本文是GDB基本用法的实践教程。请跟随示例,打开命令行并克隆此仓库:
gitclonehttps://github.com/hANSIc99/core_dump_example.git\n
快捷方式
GDB的每条命令都可以缩短。例如:显示设定的断点的infobreak命令可以被缩短为ibreak。你可能在其他地方看到过这种缩写,但在本文中,为了清晰展现使用的函数,我将所写出整个命令。
命令行参数
你可以将GDB附加到每个可执行文件。进入你克隆的仓库(core_dump_example),运行make进行编译。你现在能看到一个名为coredump的可执行文件。(更多信息,请参考我的文章《创建和调试Linux的转储文件》。)
要将GDB附加到这个可执行文件,请输入:gdbcoredump。
你的输出应如下所示:
返回结果显示没有找到调试符号。
调试信息是目标文件objectfile(可执行文件)的组成部分,调试信息包括数据类型、函数签名、源代码和操作码之间的关系。此时,你有两种选择:
继续调试汇编代码(参见下文“无符号调试”)使用调试信息进行编译,参见下一节内容
使用调试信息进行编译
为了在二进制文件中包含调试信息,你必须重新编译。打开Makefile,删除第9行的注释标签(-g\n
要重新编译程序,先运行makeclean,再运行make,最后启动GDB。该程序不再有任何调试符号来引导源代码的走向。
infofile命令显示二进制文件的内存区域和入口点:
.text区段始终从入口点开始,其中包含实际的操作码。要在入口点添加断点,输入break*0x401110然后输入run开始运行程序:
要在某个地址设置断点,使用取消引用运算符*来指定地址。
选择反汇编程序风格
在深入研究汇编之前,你可以选择要使用的汇编风格。GDB默认是AT&T,但我更喜欢Intel语法。变更风格如下:
setdisassembly-flavorintel\n
现在输入layoutasm调出汇编代码窗口,输入layoutreg调出寄存器窗口。你现在应该看到如下输出:
保存配置文件
尽管你已经输入了许多命令,但实际上还没有开始调试。如果你正在大量调试应用程序或尝试解决逆向工程的难题,则将GDB特定设置保存在文件中会很有用。
该项目的GitHub存储库中的gdbinit配置文件包含最近使用的命令:
setdisassembly-flavorintel\nsetwriteon\nbreak*0x401110\nrun-c2\nlayoutasm\nlayoutreg\n
setwriteon命令使你能够在程序运行期间修改二进制文件。
退出GDB并使用配置文件重新启动GDB:gdb-xgdbinitcoredump。
阅读指令
应用c2开关后,程序将崩溃。程序在入口函数处停止,因此你必须写入continue才能继续运行:
idiv指令进行整数除法运算:RAX寄存器中为被除数,指定参数为除数。商被加载到RAX寄存器中,余数被加载到RDX中。
从寄存器角度,你可以看到RAX包含5,因此你必须找出存储堆栈中位置为rbp-0x4的值。
读取内存
要读取原始内存内容,你必须指定比读取符号更多的参数。在汇编输出中向上滚动一点,可以看到堆栈的划分:
你最感兴趣的应该是rbp-0x4的值,因为它是idiv的存储参数。你可以从截图中看到rbp-0x8位置的下一个变量,所以rbp-0x4位置的变量是4字节宽。
在GDB中,你可以使用x命令查看任何内存内容:
x/n、f、u>addr>
可选参数:
n:单元大小的重复计数(默认值:1)f:格式说明符,如printfu:单元大小b:字节h:半字(2个字节)w:字(4个字节)(默认)g:双字(8个字节)
要打印rbp-0x4的值,请输入x/u$rbp-4:
如果你能记住这种模式,则可以直接查看内存。参见手册中的部分。
操作汇编
子程序zeroDivide发生运算异常。当你用向上箭头键向上滚动一点时,你会找到下面信息:
0x401211
这被称为函数前言:
调用函数的基指针(rbp)存放在栈上栈指针(rsp)的值被加载到基指针(rbp)
完全跳过这个子程序。你可以使用backtrace查看调用堆栈。在main函数之前只有一个堆栈帧,所以你可以用一次up回到main:
在你的main函数中,你会找到下面信息:
0x401431
子程序zeroDivide仅在jumpequal(je)为true时进入。你可以轻松地将其替换为jump-not-equal(jne)指令,该指令的操作码为0x75(假设你使用的是x86/64架构;其他架构上的操作码不同)。输入run重新启动程序。当程序在入口函数处停止时,设置操作码:
set*(unsignedchar*)0x401435=0x75\n
最后,输入continue。该程序将跳过子程序zeroDivide并且不会再崩溃。
总结
你会在许多集成开发环境(IDE)中发现GDB运行在后台,包括QtCreator和VSCodium的本地调试扩展。
了解如何充分利用GDB的功能很有用。一般情况下,并非所有GDB的功能都可以在IDE中使用,因此你可以从命令行使用GDB的经验中受益。
via:https://opensource.com/article/21/1/gnu-project-debugger
作者:StephanAvenwedde选题:lkxed译者:Maisie-x校对:wxy
本文由LCTT原创编译,Linux中国荣誉推出
如果你还想了解更多这方面的信息,记得收藏关注本站。
