GDB Remote Serial Protocol —— RSP协议解析

简介

      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中,并且挂起当前进程。

 

你可能感兴趣的:(protocol)