最近在做一个IDE,底层通过mi接口调用的gdb做调试。
因为要支持尽可能广的gdb版本,而gdb/mi接口偶有更新,最省事的处理方法无疑是调用旧版本有,新版本虽deprecated但也支持的接口。
事情就出在这了。
这个IDE需要新增一个查看内存的功能,gdb/mi提供了两种接口:
-data-read-memory [ -o byte-offset ] address word-format word-size nr-rows nr-cols [ aschar ]和
-data-read-memory-bytes [ -o byte-offset ] address count第一个接口提供了更多的功能,无需自己处理输出内容的格式,缺点是初始地址必须可读。这个接口已经被标志为deprecated 。
官方文档有个例子:
4-data-read-memory bytes+16 x 1 8 4 x 4^done,addr="0x000013a0",nr-bytes="32",total-bytes="32", next-row="0x000013c0",prev-row="0x0000139c", next-page="0x000013c0",prev-page="0x00001380",memory=[ {addr="0x000013a0",data=["0x10","0x11","0x12","0x13"],ascii="xxxx"}, {addr="0x000013a4",data=["0x14","0x15","0x16","0x17"],ascii="xxxx"}, {addr="0x000013a8",data=["0x18","0x19","0x1a","0x1b"],ascii="xxxx"}, {addr="0x000013ac",data=["0x1c","0x1d","0x1e","0x1f"],ascii="xxxx"}, {addr="0x000013b0",data=["0x20","0x21","0x22","0x23"],ascii=" !\"#"}, {addr="0x000013b4",data=["0x24","0x25","0x26","0x27"],ascii="$%&'"}, {addr="0x000013b8",data=["0x28","0x29","0x2a","0x2b"],ascii="()*+"}, {addr="0x000013bc",data=["0x2c","0x2d","0x2e","0x2f"],ascii=",-./"}] (gdb)几乎和IDE中要显示的方式一致了。
第二个接口则十分简单,优点是可以从请求范围内抽出需要读取的数据返回,只需初始地址或者结束地址可读。
官方文档中的例子:
-data-read-memory-bytes &a 10 ^done,memory=[{begin="0xbffff154",offset="0x00000000", end="0xbffff15e", contents="01000000020000000300"}] (gdb)无疑使用第一种方式做起来更简单,但我脑子当时缺了根弦,看到deprecated就弃用了第一个接口,给学长演示时,学长用的gdb 6.8,总是在提示没有此命令,才发现问题。
无奈只好再改了。
心里却不想把之前的工作注释掉,就想着判断下gdb版本,再分别做处理。
这就需要查第二种接口是哪版中出现的了。官方文档中没写明,官网上的news中也没提到这种小事,又不想一版一版地查NEWS文件,就二分法一个一个版本下载下来试试。这个接口应该是在7.3中第一次出现。
改好了代码,在各个gdb版本下试验,却出现了:
还以为是自己代码改出了毛病,却怎么想也想不出刚刚改的代码为什么会导致这样的问题,明明毛关系都没有。
看提示应该是target进程没启动,调试版的还会输出这样的调试信息:
觉得可能是dll调用出了问题。可target代码简单到不能再简单了,调用的dll应该都是不可能not found的。直接到目标目录下,双击执行target,提示
这才明白,原来是新一些的(具体多新就没查了)MinGW中的g++ 编译后的文件需要依赖一些库,这些库在旧的MinGW中没有,旧版的gdb也就无法进行调试了。换到旧版MinGW之后,只需先重新编译运行一遍,就可以避免“you can't do that without a process to debug"了。