免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 7686 | 回复: 17
打印 上一主题 下一主题

使用GDB与QEMU调试内核时的问题分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-02-19 13:42 |只看该作者 |倒序浏览
使用QEMU+GDB能够实现源代码级的内核调试,但是,存在一个问
题──当内核允许中断时,单步命令(n与s)会进入时钟中断。通过
浏览QEMU的源代码,大体把原因找了出来。 单步命令(n与s)在
gdb远程调试通讯协议中是s(参看info gdb),qemu的gdb stub
在受到s命令后将虚拟CPU进入单步状态,但是在接收到s命令前,
qemu的虚拟CPU是停止的(在等待gdb的命令),注意,这个时
候,虚拟时钟计时并没有停止,所以,很可能在qemu的虚拟CPU还
没开始的时候就需要触发时钟中断了,但是虚拟CPU还在停止状态,
中断无法触发。接收到s命令后,虚拟CPU开始执行指令。这时,如
果内核允许中断,虚拟时钟就将触发中断,所以s命令执行一条指令
后停止在时钟中断处理程序的开始处,而不是希望的函数中下一条指
令处。

  现在看一下问题的解决方法。在我看来,需要修改gdb远程调试内核
时单步命令的语义。有两个方向。
1.在gdb上修改。在处理用户的n与s命令时不是发送协议中的s命令,
而是分两步。首先确定下一条指令的开始位置(或者下一行源程序对应
的指令的开始位置)。对于有些RISC机器机器指令固定为某个长度,那
么确定这个位置比较简单,但是对于像x86这样的变长指令的体系结构
就需要稍微麻烦一点(需要确定当前指令的长度等)。然后假如第一步
确定的地址是naddr。现在像处理用户的tbreak *naddr一样处理就可
以了,接着发送继续运行命令c就可以了。
2.在qemu的gdb stub上修改协议命令s的处理方法。接收到s命令后
不是让虚拟CPU进入单步执行状态,而是确定在没有中断的情况下,下
一条指令的位置(注意对于当前是跳转指令的情况处理比较复杂),然
后在这个位置设置临时断点,在虚拟CPU到达这个断点进入gdb stub
后立即将其取消。

这两种处理方法中,我认为1比较好,实现起来清晰明了,但是需要对
gdb的代码比较熟悉。2方法比较复杂,尤其是在当前指令是跳转指令
时,不太容易确定临时断点的位置。

另外作为暂时的权宜之计,我们可以只使用tbreak +offset来代替n
与s命令。

原来的patch在Linux下没有作用,我因为最近才调试Linux内核才发现。
下面的patch已经完全可以用了。调试Linux kernel不会再进入中断了。

[ 本帖最后由 mingyanguo 于 2006-4-17 15:08 编辑 ]

qemupatch.tar.gz

1.55 KB, 下载次数: 139

论坛徽章:
0
2 [报告]
发表于 2006-02-19 15:22 |只看该作者
兄弟, 这个确实有价值研究一下, xfocus的watercloud和alert7都在使用qemu时遭遇这个问题, 最后向邮件列表发送了BUG Report了事…我则是干脆放弃qemu了……

论坛徽章:
0
3 [报告]
发表于 2006-02-19 16:09 |只看该作者
原帖由 albcamus 于 2006-2-19 15:22 发表
兄弟, 这个确实有价值研究一下, xfocus的watercloud和alert7都在使用qemu时遭遇这个问题, 最后向邮件列表发送了BUG Report了事…我则是干脆放弃qemu了……

以我现在的理解,感觉不是qemu的问题,而且在qemu的gdb stub中
修改的话,感觉不怎么优雅而且麻烦。等等先看看gdb的代码吧,如果
能修改一下的话,改改试试。

论坛徽章:
0
4 [报告]
发表于 2006-02-20 13:07 |只看该作者
mingyanguo兄, 仔细看了文章, 觉得还是在qemu上修改比较好; qemu最大的优点之一是提供了一个gdb server, 倘使改动gdb的话, 一则gdb太过复杂(不知道跟qemu比起来如何), 二则好象也是破坏了这个特性。
这个问题我也很感兴趣,你能留个MSN或者Email,我们联系一下吗?

论坛徽章:
0
5 [报告]
发表于 2006-02-20 14:32 |只看该作者
非常感谢!!!

有个好的调试工具太重要了。

论坛徽章:
0
6 [报告]
发表于 2006-02-20 14:44 |只看该作者
原帖由 guotie 于 2006-2-20 14:32 发表
非常感谢!!!

有个好的调试工具太重要了。

汗~期望值太高容易失望的! 我们也不是高手, 只是往里钻钻看而已呀

论坛徽章:
0
7 [报告]
发表于 2006-02-20 15:30 |只看该作者
原帖由 albcamus 于 2006-2-20 13:07 发表
mingyanguo兄, 仔细看了文章, 觉得还是在qemu上修改比较好; qemu最大的优点之一是提供了一个gdb server, 倘使改动gdb的话, 一则gdb太过复杂(不知道跟qemu比起来如何), 二则好象也是破坏了这个特性。
这个 ...

不要那么客气,我没你大,应该我称呼你兄才是。

我得mail guomingyan At gmail.com
MSN也不稳定,经常没法用。

GDB确实太大了,现在还没找到头绪那。其实,在GDB上改的话,可以新加个命令,保留原来的n,s。
QEMU规模要比GDB小吧(浏览了一点,感觉而已)。
QEMU上改的话,我又想了个思路就是在虚拟CPU因为debug停止的时候让虚拟时钟也停止计数,这样虚拟CPU再次运行的时候,虚拟时钟中断就不会立即触发了。

论坛徽章:
0
8 [报告]
发表于 2006-02-22 21:26 |只看该作者

一个简单的解决方法

通过对qemu的源代码进行简单的修改,找到了一个绝大部分时候可行的解决方法(我实验时很少跟进中断)──在gdb单步执行的时候禁止所有的虚拟中断。

修改的地方很少,我是对qemu-snapshot-2005-07-17_23版本在打了FreeBSD ports的补丁的基础上修改的。0.8的版本应该差不多。
可是说修改很无关大局。
下面是修改

XXX============================XXXXXXX


--- /home/prime/gdbstub.c       Wed Feb 22 21:15:05 2006
+++ gdbstub.c   Sun Jul  3 04:59:33 2005
@@ -45,7 +45,7 @@
};
/* XXX: This is not thread safe.  Do we care?  */
static int gdbserver_fd = -1;
-int    gdbstep;
+
typedef struct GDBState {
     enum RSState state; /* parsing state */
     int fd;
@@ -444,7 +444,6 @@
#ifdef DEBUG_GDB
     printf("command='%s'\n", line_buf);
#endif
-    gdbstep = 1;
     p = line_buf;
     ch = *p++;
     switch(ch) {
@@ -470,7 +469,6 @@
#else
         vm_start();
#endif
-       gdbstep = 0;
        return RS_IDLE;
     case 's':
         if (*p != '\0') {
@@ -721,7 +719,6 @@
         qemu_del_fd_read_handler(s->fd);
         qemu_free(s);
         vm_start();
-       gdbstep = 0;
     } else {
         for(i = 0; i < size; i++)
             gdb_read_byte(s, cpu_single_env, buf[i]);

XXXXX=============================================XXXXXXX
--- /home/prime/gdbstub.h       Wed Feb 22 21:15:05 2006
+++ gdbstub.h   Wed Apr 27 04:42:36 2005
@@ -8,5 +8,5 @@
void gdb_exit(CPUState *, int);
#endif
int gdbserver_start(int);
-extern int     gdbstep;
+
#endif
XXXX================================================XXXXXX
--- vl.c        Wed Feb 22 21:14:14 2006
+++ /home/prime/vl.c    Wed Feb 22 21:19:52 2006
@@ -871,9 +871,12 @@
         last_clock = ti;
     }
#endif
-    if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
-                           qemu_get_clock(vm_clock)) ||
-        qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
+    if ((qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+                           qemu_get_clock(vm_clock))
+#ifdef CONFIG_GDBSTUB
+                           &&(gdbstep == 0)
+#endif
+       )||qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
                            qemu_get_clock(rt_clock))) {
         /* stop the cpu because a timer occured */
         cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
@@ -2818,6 +2821,9 @@
#endif

         if (vm_running) {
+#ifdef CONFIG_GDBSTUB
+               if(gdbstep == 0)
+#endif
             qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
                             qemu_get_clock(vm_clock));
             /* run dma transfers, if any */

论坛徽章:
0
9 [报告]
发表于 2006-02-23 09:22 |只看该作者
我没有FreeBSD环境, 你加入qemu的mailing list了吗? CLF有几个人一直在用qemu也许可以讨论下。
这么强的贴子, 先加为精华

论坛徽章:
0
10 [报告]
发表于 2006-02-23 12:11 |只看该作者
原帖由 albcamus 于 2006-2-23 09:22 发表
我没有FreeBSD环境, 你加入qemu的mailing list了吗? CLF有几个人一直在用qemu也许可以讨论下。
这么强的贴子, 先加为精华

mailing list的链接前几天我打不开
正在试着加入呢。
其实这个改动很小,与FreeBSD的ports的补丁不相干。

[ 本帖最后由 mingyanguo 于 2006-2-23 12:25 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP