GDB的工作原理及skyeye远程调试
目录
01.GDB简介
02.Ptrace简介
03.GDB三种调试方式
04.GDB调试的基础—信号
05.SkyEye支持GDB远程调试
01.GDB简介
GDB:GNU debugger 是UNIX及UNIX-like下强大的命令行调试工具。
▲GDB调试整体架构
可以发现GDB调试不管是本地调试还是远程调试,都是基于ptrace系统调用来实现的。
02.Ptrace简介
Ptrace系统调用的原型:
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request,pid_t pid, void *addr, void *data);
说明:Ptrace系统调用提供了一种方法来让父进程可以观察和控制其它进程的执行,检查和改变其核心映像以及寄存器。主要用来实现断点调试和系统调用跟踪。
(且先不去管内核中是怎么实现Ptrace的)。GDB就是通过调用这个系统调用,然后通过一些参数来控制其他进程的执行的。
下面我们来看Ptrace函数中Request参数的一些主要选项:
Request参数的主要选项:
PTRACE_TRACEME:由子进程调用,表示本进程将被其父进程跟踪,交付给这个进程的所有信号,即使信号是忽略处理的(除SIGKILL之外),都将使其停止,父进程将通过wait()获知这一情况。
这是什么意思呢?我们可以结合到GDB上来看。如果在GDB中run一个程序,首先GDB会创建一个子进程,然后该子进程调用Ptrace系统调用,参数就是PTRACE_TRACEME,然后调用一个exec执行程序。基本过程是这样,细节上可能会有出入。需要注意的是,这个选项PTRACE_TRACEME是由子进程调用的而不是父进程!
PTRACE_ATTACH:attach到一个指定的进程,使其成为当前进程跟踪的子进程,而子进程的行为等同于它进行了一次PTRACE_TRACEME操作。但是,需要注意的是,虽然当前进程成为被跟踪进程的父进程,但是子进程使用getppid()的到的仍将是其原始父进程的pid。
当你在GDB中使用attach命令来跟踪一个指定进程/线程的时候,GDB就自动成为该进程的父进程,而被跟踪的进程则使用了一次PTRACE_TRACEME,GDB也就顺理成章的接管了这个进程。
PTRACE_CONT:继续运行之前停止的子进程。可同时向子进程交付指定的信号。
需要注意的另一点是,使用GDB调试过多线程/进程的人应该都知道,当子进程遇到一个信号的时候,GDB就会截获这个信号,并将子进程暂停下来。这是为什么呢?
实际上,在使用参数为PTRACE_TRACEME或PTRACE_ATTACH的ptrace系统调用建立调试关系之后,交付给目标程序的任何信号(除 SIGKILL之外)都将被GDB先行截获,或在远程调试中被GDBserver截获并通知GDB。GDB因此有机会对信号进行相应处理,并根据信号的属性决定在继续目标程序运行时是否将之前截获的信号实际交付给目标程序。
03.GDB三种调试方式
3.1. attach并调试一个已经运行的进程
确定需要进行调试的进程id
运行GDB,输入attch pid,如:GDB 12345。GDB将对指定进行执行如下操作:ptrace (PTRACE_ATTACH,pid,0,0)
3.2. 运行并调试一个新的进程
运行GDB,通过命令行参数或file指定目标调试程序如GDB ./test
输入run命令,GDB执行下述操作:
通过fork()系统调用创建一个新进程
在新创建的子进程中调用ptrace(PTRACE_TRACEME,0,0,0)
在子进程中通过execv()系统调用加载用户指定的可执行文件。
3.3. 远程调试目标主机上新创建的进程
GDB运行在调试机,GDBserver运行在目标机,两者之间的通信数据格式由GDB远程串行协议(Remote Serial Proctocl)定义。
GDBsever的启动方式相当于运行并调试一个新创建的进程。
04.GDB调试的基础—信号
GDB调试的实现都是建立在信号的基础上的,在使用参数为PTRACE_TRACEME或PTRACE_ATTACH的ptrace系统调用建立调试关系后,交付给目标程序的任何信号首先都会被GDB截获。
因此GDB可以先行对信号进行相应处理,并根据信号的属性决定是否要将信号交付给目标程序。
单步调试
Next指令可以实现单步调试,即每次只执行一行语句。一行语句可能对应多条及其指令,当执行next指令时,分析其实现机制首先需要理解step range以及step_range_start和step_range_end的概念。执行next命令时,GDB会计算当前停止语句对应的第一条指令的地址作为step_range_start,然后计算当前停止位置下一行的c语句的第一条指令的地址作为step_range_end,随后控制目标程序,从当前停止位置开始走指令集单步,直至pc超出step range为止。
Next命令的结束条件:
pc<step_range_startllpc>=step_range_end
▲图 4.1 next命令实现示意图
之所以不能简单的判断pc是否达到step_range_end,是因为step_range_end仅仅是c源代码意义上的下一行第一条指令的地址,目标程序实际运行未必就会到达那里,因此,next命令的结束条件可以理解为只要pc离开当前源代码即可。
Next命令跨越函数调用的过程:
从当前停止位置开始走指令级单步
走到子函数第一条指令时发现是函数调用,就在函数返回地址插入一个临时断点
让目标程序继续运行,通过子函数体,直至遇到之前插入的临时断点
继续走指令集单步,直至满足next命令的结束条件为止
▲图 4.2 next跨越函数实现示意图
Step命令和next命令完全一样,也是实现c源代码级的单步,对于简单的语句,step完全等同于next。唯一不同的是,若单步过程中遇到函数调用,step命令将停止在子函数的起始处,而不是将其跨越(无调试信息的子函数除外)。
Nexti命令实现指令集单步,和next命令类似,nexti命令单步过程中不会进入子函数调用。
Stepi命令实现指令集单步,而且是严格的指令集单步,每次直接走一条指令后立即停止,不在区分是否存在函数调用。
设置断点:
断点功能的实现就是在指定位置插入断点指令,使目标程序运行至该处时产生SIGTRAP信号,该信号被GDB捕获,通过断点地址的匹配确定是否命中断点。
断点命中的判断:目标程序遇到断点,并不一定就需要停下来,该停就停,不该停的还是要继续跑。只要真正需要停止运行的情况才认为是断点命中。是否命中断点的判断因素主要有以下这些:
导致目标程序本次停止运行的信号是不是SIGTRAP
在GDB维护的断点链表中是否存在一个断点的地址与目标程序本次停止位置匹配
若断点存在条件,此时条件是否满足
断点的忽略次数此时是否为0
若断点只针对某个线程有效,那么遇到该断点的线程是否就是断点所设定的线程。
若前两个条件之一不满足,则认为目标程序停止是因随机信号而停止。
若后三个条件之一不满足,则认为目标程序本次没有命中断点,GDB会让其继续运行。
GDB将断点实际插入目标程序的时机:
当用户通过break命令设置一个断点时,这个断点不会立即生效,因为此时GDB只是在内部的断点链表中为这个断点新创建了一个节点而已。GDB会在用户下次继续发出目标程序运行的指令时,将所有断点插入目标程序中。与此相呼应,当目标程序停止时,GDB会将所有断点暂时从目标程序中清除。
断点命中失败的情况下,跨越断点继续运行的过程:
清除断点
单步到断点的下一条指令
恢复断点
继续目标程序运行
05.SkyEye支持GDB远程调试
5.1 SkyEye基本介绍
SkyEye是一款支持 ARM、TI DSP、PowerPC、X86、SPARC,龙芯,飞腾等多种处理器体系架构的指令级别仿真平台。
SkyEye便是通过3.3的方式进行远程调试。
▲图 4.3 next跨越函数实现示意图
同时提供了SkyEye 命令行工具和SkyEye界面两种形式进行调试。
5.2 启动SkyEye命令行对源代码进行调试
1. 使用SkyEye命令行工具与GDB以及工程建立连接
2. 在main函数前进行断点
3. 执行至断点处
4. 进行「step」单步操作
5. 进行「next」单步操作
6. 进行「continue」继续执行
▲图 5.1 命令行调试示意图
5.3 启动SkyEye界面对源代码进行调试
1. 执行单步跳入(step)
2. 进行断点(breakpoint)
3. 单步跳过(next)
4. 继续运行(continue)
▲图 5.2 SkyEye界面调试图
5.4 提供查看变量、寄存器等功能
▲图 5.3 SkyEye界面调试查看变量寄存器图
5.5 同时可以切换至指令集调试
▲图 5.4 SkyEye界面指令集调试图
5.6 具体信息展现在控制台处
▲图 5.5 SkyEye界面调试输出信息图
GDB的工作原理及skyeye远程调试相关推荐
- 【GDB】gdbserver的使用,远程调试开发板
0.将gdbserver拷贝到目标板子上 注:gdbserver在交叉编译工具目录/debug-root/usr/bin下 可用file命令查看 --------------------------- ...
- gdb工作原理(一)
#include <sys/ptrace.h>long ptrace(enum __ptrace_request request, pid_t pid,void *addr, void * ...
- gdb工作原理(二)
一.组成架构 二.ptrace系统调用 ptrace系统调用对原型 long ptrace(enum __ptrace_request request, pid_t pid,void *addr, v ...
- chrome android远程调试工作原理
注意⚠️:本文为个人学习原理所翻译的文章,文中介绍的方法还未实践验证,不保证有效可用.目前仅进行了原理学习,后续会补充实际操作过程中遇到的问题. chrome android远程调试工作原理 Chro ...
- 调试器原理_调试器的工作原理
调试器原理 调试器是大多数(如果不是每种)开发人员在软件工程生涯中至少使用一次的软件之一,但是你们当中有多少人知道它们的实际工作原理? 在悉尼举行的linux.conf.au 2018上的演讲中,我将 ...
- 利用GDB进行远程调试
在进行嵌入式系统开发中,受到嵌入式系统资源的限制,调试环境和通用桌面系统的调试环境有差别,引入了远程调试技术.这时,调试器运行于通过桌面系统,被调试的程序则运行于基于特定硬件平台的嵌入式系统(目标系统 ...
- 【嵌入式】Linux开发工具gdb及远程调试
gdb及远程调试 gdb gdb安装 gdb调试命令 gdb 调试步骤 嵌入式远程调试 在开发板上运行 gdbserver 在PC端执行 其他Liunx开发工具 交叉反汇编器 arm-linux-ob ...
- 转载 调试器工作原理
调试器工作原理--基础篇 本文是一系列探究调试器工作原理的文章的第一篇.我还不确定这个系列需要包括多少篇文章以及它们所涵盖的主题,但我打算从基础知识开始说起. 关于本文 我打算在这篇文章中介绍关于Li ...
- 网络摄像头工作原理_好,更好,最好以预算创建最终的远程工作者网络摄像头设置
网络摄像头工作原理 I've been a remote worker and an occasional YouTuber for well over a decade. I'm always lo ...
最新文章
- [elixir! #0043] 精确到 1bit 的字符串处理
- github开源项目分享
- Android应用中如何保护JAVA代码
- HDU 3625 Examining the Rooms【第一类斯特灵数】
- 读书笔记:《思考的乐趣:Matrix67数学笔记》第4章 统计数据的陷阱
- C# WebRequest 基础连接已关闭 连接意外关闭
- Oracle 9 - redo和undo
- RDS最佳实践(三)—如何制定相关的流程来规范RDS的使用
- FusionChart完全入门手册 -2
- JZOJ4742 单峰
- 汇编语言实模式到保护模式的思考
- JBoss下载与JBoss安装
- hh-suite使用教程
- java.lang.IllegalStateException: Only fullscreen activities can request orientation
- 【Python 基础篇】Python代码 之 三目表达式总结
- VAR(向量自回归)模型的stata操作——关于期货现货价格联动关系的案例
- 山东理工大学oj打字速度测试
- 题目 1548: 盾神与砝码称重
- 【C++】整型溢出问题
- Flutter iOS问题记录 - Fastlane打包的ipa包上传fir后不显示应用版本名称
热门文章
- 分析原因型思维模型框架_分析营销型网站优化效果不佳的主要原因
- oracle sql切换模式,Oracle SQL 模式下命令回退
- 函数上下文this和参数列表arguments介绍
- Starlink的20ms延迟怎么计算得到的?
- 矩阵的Cholesky分解
- android一格一格向上的进度条,如何 使用 ProgressBar 进度条
- java 排队实现_实验排队功能实现(JAVA)
- python opencv旋转图片_opencv3+python3进行图片旋转处理
- mac win10 mysql_Mac装双系统Win10,安装MySQL遇到的问题
- java sort 效率_性能对比:collections.sort vs treeSet sort vs java8 stream.sorted