从零开始搭建环境编写操作系统 AT&T GCC (七)GDB调试和-monitor

来源:互联网 发布:mac os x 10.12 beta5 编辑:程序博客网 时间:2024/06/14 00:00

  一直有个小教程没有写给大家,那就是使用GDB调试和-monitor调试,借这次代码整理,跟大家说一下怎么用。这里我使用到了objdump工具,gdb调试工具,这些工具都可以直接apt-get获得。当然我还用到了qemu的自带调试功能-monitor
  这一节就是把system文件夹下lds文件的. = 0x8200;删掉,这是个历史遗留问题哈哈,刚开始写的时候加上了这行代码,导致了后来写程序众多不便,于是决定删掉他,这一节不感兴趣的可以直接跳过了。
一、修改system文件夹
  1、打开lds文件,删掉 . = 0x8200; 这个历史遗留问题
  2、打开system.s 进行如下修改,我们看看程序还能不能正常运行。

########################################start 32############set GDT    movl    gdt_base+0x8200,    %eax################修改############0# empty GDT    movl    $0x00000000,   0(%eax)    movl    $0x00000000,   4(%eax)############1# code GDT    movl    $0x8200ffff,   8(%eax)    movl    $0x00409a00,   12(%eax)############2# data GDT    movl    $0x0000ffff,   16(%eax)    movl    $0x00cf9200,   20(%eax)############3# stack GDT    movl    $0x00007a00,   24(%eax)    movl    $0x00409600,   28(%eax)#close interrupt    cli     lgdt    gdt_size+0x8200 #configuration  ################修改

  保存,运行,哎呦?还不错,至少没有大错误,鼠标和我们的文字没有了,怎么回事?我也不知道,debug!
  这里写图片描述

二、debug过程记录
  其实我是不太想写这个的,因为想要把完整的debug过程记录下来还是需要费点时间,但是为了体现一下怎么用qemu和dbg调试系统内核,而且这部分的教程真是少之又少,所以还是狠狠心写下来吧。当然,具体DBG的所有命令解释,-monitor的所有命令解释,objdump的所有命令解释我就不赘述了,这些资料网上还是有很多的,我只是记录我的debug过程,给大家一个大体的概念。
  1、首先我注意到了鼠标和字符同时没有了,显示这两个的函数是我在另外的.c文件中定义的,所以问题应该是出在寻址上。
  2、进入系统代码文件夹,执行命令:objdump -D bin/system.elf ,反汇编.elf文件。找到SysMain函数,阅读汇编源码,看看问题是不是出在这里。似乎问题不大。没有找到问题。

 151:   e8 bb 03 00 00          call   511 <PutString> 156:   83 c4 10                add    $0x10,%esp 159:   83 ec 04                sub    $0x4,%esp 15c:   6a 00                   push   $0x0 15e:   6a 32                   push   $0x32 160:   6a 32                   push   $0x32

  3、执行objdump -D -b binary -m i386 bin/system.bin 命令反汇编我们的raw binary文件,额,好长,而且没有条理,疯了,那也得看。在2、中我们看到SysMain在0xf6处,所以直奔0xf6,找到push 0xfffffff传参就找到我们函数调用位置了。传完参数,最后call了0x511,似乎也没有问题。完了,咋回事儿?
  4、不能就这样放弃啊,该放大招了,打开loader文件夹Makefile,修改如下,意思是启动虚拟机的时候stop
  

    qemu-system-i386 -fda $(BIN_DIR)/loader.img -boot a -gdb tcp::1234 -S -monitor stdio #   qemu-system-i386 -fda $(BIN_DIR)/loader.img -boot a -gdb tcp::1234 -monitor stdio 

  5、make,啊哈,虚拟机停住了,再打开一个控制台,启动gdb,执行target remote localhost:1234 连接虚拟机,成功
  6、设置断点 break *0x8200 ,因为我们把system加载到了这个位置运行的嘛,所以启动system的一瞬间,我们停住它,然后在dbg中输入命令c,continue的简写,让它执行起来,然后中断在0x8200处,完成
  7、停住了,这个时候我们启动反汇编模式,layout asm,ip上下的代码就清晰可见了,注意layout asm在启动保护模式分段之后就不能用了,因为它无视CS寄存器……
  8、用鼠标往下翻汇编源码,找到ljmp,我们要在这里再停下来,break *0x8274 再插入一个断点,continue
  9、又停住了,下边我们就不能再用layout asm了,所以我们先关掉它,ctrl+x 然后按a,关掉了。执行命令si,这个是执行一步汇编的意思,我们看它跳到哪里了。
  10、我的跳到了0x79处,但是我们有段选择子,偏移是0x8200,所以现在执行的指令应该位于0x8279处,我们再打开一个发控制台,objdump -D -b binary -m i386 bin/system.bin,看着我们的反汇编代码。这个时候0x79就应该与我们的代码一一对应了,看看0x79处是什么,可能是混乱的,没关系
  11、再在gdb中回车一下,看看执行到哪里了,我的是0x7d
     7d: 8e d8 mov %eax,%ds
  12、最上面的指令因为对齐的原因,翻译的不准确,就不看了,0x7d这才是我们的汇编代码
  13、第一个call 到了0xf6,再打开一个控制台,objdump -D bin/system.elf,看看0xf6是什么,main函数,没问题
  14、在gdb不停的回车执行si,直接回车表示执行上一条命令,现在进入了main函数依然没有发现问题
  15、找到call 0x511,这条指令在0x151位置,因为我们知道0x511是输出字符的函数,我们这设置一个断点break *0x8351
  16、continue,停了下来,输入si单步调试,看看到哪里去了,停住了!问题来了,为啥停住了??
  17、再检查寄存器,擦,IDT为0x1140,又犯傻了,我们把偏移0x8200去掉后,数据段也不正确了
  
  18、把system.s进行修改,改成如下,暂时可以用了。

############2# data GDT    movl    $0x8200ffff,   16(%eax)    movl    $0x00cf9200,   20(%eax)

  19、背景变成这样子了,那是因为数据段修改后显存存放位置不正确,把所有显存写入的地址都减去0x8200,当然这也只是权宜之计,我们先这样做
  这里写图片描述
  20、好了,显存恢复了正常,中断还是不能使用,去InitIDT把 DefaultIntCallBack的-0x8200去掉,还是不能用,频繁重启,去查看一下IDT寄存器的基址,居然还是0x1140,写程序就是在慢慢犯傻的过程中改进,因为LIDT需要的是绝对地址嘛,也是佩服自己的智商,直接去void InitIDT()中,给idt+0x8200/8就好了嘛!注意是0x8200/8,因为指针每加1,是以自身大小为单位+1,我们要地址加0x8200,所以要除以自身单位。修改后的InitIDT()
  

    for (i=1;i<0x30;i++)    {        idt[i].offset1 = (short)((int)(void*)(DefaultIntCallBack));        idt[i].selector = 0x0008;        idt[i].no_use = 0x8e00;        idt[i].offset2 = (short)(((int)(void*)(DefaultIntCallBack))>>16);       }    FunctionLidt(0x30*8-1,idt+0x8200/8);

  这次make一下,成功!我们看到中断函数被调用了,虽然不断重启,原因是中断结束后需要iret,我们没有做这个工作(偷懒的方法是在中断最后加一个while(1)),所以我们是成功的!
  21、这次调试就记录到这里了,当然如果自己会调试内核最好了,有问题尽管问!

阅读全文
1 0
原创粉丝点击