最近操统课需要用到bochs这个模拟器,我用的2.3.5. 但是实际出现了以个问题,就是gdb-stub这个功能不大正常,运行gdb后可以正常下断点,但是单步进可以,单步过却和单步进相同,这个问题不大比较恶心的是无法显示局部变量的值,总是显示0xffffffff
google了半天没看到一点有用的。。。。。唉,只好自己搞
参阅了gdb protocol后我修改了bochs的gdbstub.cc,让其显示出与gdb交互的内容,大致了解了内存这部分的步骤,主要是gdb给server(即bochs)发一个内存读取的请求,格式为m addr,length, 然后server返回十六进制的数据
在bochs的gdbstub.cc 558行为处理这个指令的,不难看懂,我修改了它,让它输出access_linear的返回值,然后再调试,查看局部变量,果然valid为0,进一步,到access_linear, 经过痛苦地多次调试,发现问题处在valid=BX_MEM(0)->dgb_fetch_mem...一行,最后进到或则个函数,在memory/misc_mem.cc 512行下看到了这部分,原来是bochs发现读取的地址越界,就用0xff填充,然后返回0, 我修改了0xff,然后用gdb调试时证实了这一点。
最后往上看,发现是addr比内存的长度还要大, 加入调试输出后发现gdb读的地址是0xf010
9fe0左右,而BX_MEM_THIS len仅有2000000,这显然会越界。
起初我考虑也许是那里关于内存大小的设置没有弄好,但没有找到具体位置,但后来发现其实那BX_MEM_THIS len 是在.bochsrc里有定义的,0x2000000=2^25=32k,而那个0xf0109fe0是内核做的虚拟内存,gdb只跟bochs打交道,而虚拟内存是内核弄的,虚拟机又管不着。因此好像没什么好办法。。。
之后我查了很多关于虚拟内存的资料,发现其实是cpu直接支持的,于是我看到了希望。仍是从bochs的源码开刀。
一开始我是把目光放在了gdt和ldt上,但是未果。最后又发现了它里面的CPU类有一个get_segment_base函数,几经尝试,找到了临时解决方法:
修改bochs的gdbstub.cc
将567行附近的
access_linear(addr,len,BX_READ,mem);
改成
access_linear((BX_CPU(0)->get_segment_base(BX_SEG_REG_CS))+addr,len,BX_READ,mem)
;
然后重新编译,记得是用gdb stub版本(./configure --enable-gdb-stub)
思路就是在gdb服务器端自动对虚拟内存作个映射。目前发现常用的关于断点,堆栈,数据,单步等相关命令都基本正常(不过好像有同学说w命令不好使,我没确认)。
不知道这个算不算bochs的一个bug, 跟它反映了一下,至今没有回应。
不过这还是第一次半系统地阅读了一个开源软件的代码,另外涉及到gdb协议,虚拟内存,cpu等知识,混在一起,最后还弄成功了,实在很过瘾。
google了半天没看到一点有用的。。。。。唉,只好自己搞
参阅了gdb protocol后我修改了bochs的gdbstub.cc,让其显示出与gdb交互的内容,大致了解了内存这部分的步骤,主要是gdb给server(即bochs)发一个内存读取的请求,格式为m addr,length, 然后server返回十六进制的数据
在bochs的gdbstub.cc 558行为处理这个指令的,不难看懂,我修改了它,让它输出access_linear的返回值,然后再调试,查看局部变量,果然valid为0,进一步,到access_linear, 经过痛苦地多次调试,发现问题处在valid=BX_MEM(0)->dgb_fetch_mem...一行,最后进到或则个函数,在memory/misc_mem.cc 512行下看到了这部分,原来是bochs发现读取的地址越界,就用0xff填充,然后返回0, 我修改了0xff,然后用gdb调试时证实了这一点。
最后往上看,发现是addr比内存的长度还要大, 加入调试输出后发现gdb读的地址是0xf010
9fe0左右,而BX_MEM_THIS len仅有2000000,这显然会越界。
起初我考虑也许是那里关于内存大小的设置没有弄好,但没有找到具体位置,但后来发现其实那BX_MEM_THIS len 是在.bochsrc里有定义的,0x2000000=2^25=32k,而那个0xf0109fe0是内核做的虚拟内存,gdb只跟bochs打交道,而虚拟内存是内核弄的,虚拟机又管不着。因此好像没什么好办法。。。
之后我查了很多关于虚拟内存的资料,发现其实是cpu直接支持的,于是我看到了希望。仍是从bochs的源码开刀。
一开始我是把目光放在了gdt和ldt上,但是未果。最后又发现了它里面的CPU类有一个get_segment_base函数,几经尝试,找到了临时解决方法:
修改bochs的gdbstub.cc
将567行附近的
access_linear(addr,len,BX_READ,mem);
改成
access_linear((BX_CPU(0)->get_segment_base(BX_SEG_REG_CS))+addr,len,BX_READ,mem)
;
然后重新编译,记得是用gdb stub版本(./configure --enable-gdb-stub)
思路就是在gdb服务器端自动对虚拟内存作个映射。目前发现常用的关于断点,堆栈,数据,单步等相关命令都基本正常(不过好像有同学说w命令不好使,我没确认)。
不知道这个算不算bochs的一个bug, 跟它反映了一下,至今没有回应。
不过这还是第一次半系统地阅读了一个开源软件的代码,另外涉及到gdb协议,虚拟内存,cpu等知识,混在一起,最后还弄成功了,实在很过瘾。
Comments