GDB Remote Serial Protocol —— RSP协议解析
简介
这篇文章翻译看看也是不错的
https://tatsuo.medium.com/implement-gdb-remote-debug-protocol-stub-from-scratch-3-e87a697ca48c
GDB Remote Serial Protocol——GDB的标准远程通信协议。
当你已经熟悉你的处理器是如何处理断点和其他异常时,再了解一点基本的远程穿行通信协议的知识,你就可以在你的嵌入式平台上实现与主机GDB的通信。(即远程调试)
协议定义
GDB RemoteSerial Protocol(RSP)是一种简单的,通过串口线、网络等至少支持半双工通信的媒介进行ASCII消息传输的协议。
RSP包以$符号作为数据包的开始,后跟一个或多个用于组成要发送的消息的ASCII字节,并以#作为数据包的结束。再#后,还有两个16进制的ASCII字符作为要发送的消息的校验和。一个完整的RSP协议数据包如下:
$m4015bc,2#5a
消息的接收方会立即返回‘+’表示正确接收数据,或‘-’表示没有正确接收数据。当返回‘-’时,GDB会将错误码返回给用户,并无条件挂起GDB进程。
目标机按接收到的指令次序,依次将信息输出在GDB的console中。除非GDB进程中有其他的命令正在执行,否则来自目标机的信息将会在任意时刻输出在console中。
RSP必须实现的命令
根据功能划分,可将GDB发送来的信息,分成三种命令:寄存器相关(register-)、内存相关(memory-based)和程序控制命令。
寄存器相关
主要是对寄存器进行读、写操作。
读寄存器组:(“g”)
eg:$g#67
当GDB想获取当前目标机的寄存器信息时,就会像目标机发送(“g”)命令,目标机会返回如下信息:
+$123456789abcdef0…#xx
(Register 0 的值为0x12345678,1 的值为0xabcdef0….等等)
目标机根据平台的大小端返回相应的字节流,关于大小端的定义,可以在目标平台的gdb宏文件中找到,eg:gdb/config/<arch>tm-<arch>.h (不同版本可能不一样,我就没找到)
写寄存器组:(“G”)
eg:$G123456789abcdef0…#xx
(设置register0 的值为0x12345678,1 为 0xabcdef0…等等)
使用这个命令,GDB会在程序恢复运行前,按照平台的字节序将数据存储在相应的寄存器中。同时目标平台也会回应给GDB反馈信息,如成功返回+$OK#9a。
写寄存器:(“P”)
eg:$p10=0040149c#b3
(设置16号寄存器的值为0x40149c)
当GDB仅仅想设置一个或二个寄存器时,GDB会发送这条指令(代替(“G”)命令)给目标机。寄存器的号与读写寄存器组的号是一样的。同时,若成功,目标机会返回+$OK#9a。
内存相关
读内存:(“m”)
eg: $4015bc,2#5a
(从0x4015bc这个地址开始读2个字节的数据)
GDB发送的读命令会确定局部变量和全局变量的值,并用断点指令替代opcode,及其他用户需要的信息。GDB是知道目标平台的大小端的,因此目标机只需返回字符流即可,GDB会适当的对它们进行重组。
目标机的调试桩根据目标机的数据宽度对读写内存指令进行了优化,例如日立SH-2处理器的外设配置寄存器只能通过16位/32位进行读写。因此,在任何时刻,调试桩都只用16位/32位进行访问。目标机会返回如下信息:
+$2f86#-06
写内存:(“M”)
eg:M4015cc,2:c320#6d
(向地址0x4015cc写入数据0xc320)
如果正确,目标机返回+$OK#9a。
程序控制命令
程序控制命令是GDB用来控制被调试程序行为的命令。相对寄存器相关命令和内存相关命令,控制命令的实现难度大些。
获取最后的信号(“?”)
eg:$?#3f
这个命令用来确定目标是如何达到当前的状态的。接收到的响应同最后的信号(“last signal”),后面会介绍。
单步命令(“s”)
eg:$s#73
当GDB想让目标精确的执行一条汇编指令时,GDB会向目标机发送这条命令。(用户在GDB的console中输入step和stepi),接收到的响应见continue。
继续命令(“c”)
eg:$C#63
当用户在console下执行continue命令时,GDB回向目标机发送此命令。目标机成功解析此命令后,GDB会释放控制权,使被调试目标机全速运行。
调试桩除了返回“+”消息包,表示正确收到信息外,不会立即响应step和continue命令。相反,只有当下一个断点到达时,被请求的指令已经执行完(ste,p时的情况),一个异常发生,或者程序退出时,桩才进行响应。
有两种方式响应这些命令:一种是简单的(“last signal”),另一种是多用途的(“expedited response”)。
Last Signal 响应(“S”)
eg:+$050#b8
这是最简单的响应lastsignal(“?”)step和continue命令。“05”可以用作使用POSIX标准的signal函数的任意信号值的响应。“5”是断点异常,“10”是总线错误,等等。
快速响应(Expeditedresponse (“T”))
eg:$T0510:1238;F:FFE0…#xx
这条信息将最后的信号响应(例子是“05”)和一些GDB可能立刻会读取的寄存器进行结合。为了在代码单步执行时,提高GDB调试性能,这条信息使GDB直接获取该寄存器的值(通常是PC和状态寄存器),避免发出读寄存器的命令。
寄存器号的格式与读写寄存器命令相同。在这个例子中,寄存器16(hex 10)的值是0x1238,寄存器15(F hex)的值为0xffe0。
其他命令:
Console 输出(“O“)——可自定义的
eg:$0x48656c6cf2c20776f726c64210a#55
(在GDB console中输出“Hello, world!\n“)
这个命令允许调试桩向GDBconsole发送文本信息。文本会被按照16进制显示在console中,并且GDB会一直输出信息,直到它遇到(‘\n’, 0xa)字符。
这个信息通常是由目标机发起,GDB绝不会发送一个console output信息给目标机。
空响应(““)
当目标机调试桩遇见一个它不支持或不理解的命令时,它将返回空响应。这允许GDB选择一个替代命令如果另一个命令是有效的。
eg:<an unrecognized command>
目标机响应:+$#00
错误响应(“E“)
当目标机调试桩在执行命令时遇到一个错误时,它将会给GDB返回错误信息。例如总线错误或进行非法地址访问时,会生成这样的错误。
eg:<a command that produces an error>
目标机响应:+$E01##
在GDB中没有任何预定义的错误码,因此当GDB接收到错误信息时,会将错误信息输出在console中,并且挂起当前进程。
java新手自学群 626070845
java/springboot/hadoop/JVM 群 4915800
Hadoop/mongodb(搭建/开发/运维)Q群481975850
GOLang Q1群:6848027
GOLang Q2群:450509103
GOLang Q3群:436173132
GOLang Q4群:141984758
GOLang Q5群:215535604
C/C++/QT群 1414577
单片机嵌入式/电子电路入门群群 306312845
MUD/LIB/交流群 391486684
Electron/koa/Nodejs/express 214737701
大前端群vue/js/ts 165150391
操作系统研发群:15375777
汇编/辅助/破解新手群:755783453
大数据 elasticsearch 群 481975850
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。