qemu和gdb存在问题

3

我有一个设备驱动程序导致操作系统冻结,连鼠标都无法移动。我正试图调试此问题,我认为一个好的方法是使用我从未使用过的gdb和qemu。是否有更好的方法?

首先,我需要编译带有调试符号的内核,这个已经完成了。

现在,在与源代码相同的文件夹中生成了一个名为vmlinux的新文件。根据这个,似乎我还需要一个bzImage文件,以便我可以使用以下命令运行新编译的内核:

qemu-system-i386 -kernel bzImage 

或者在调试模式下

qemu-system-i386 -s -S -kernel bzImage

我找不到bzImage文件。在哪里可以找到它或者缺少什么?bzImage是指我使用qemu-img create创建的操作系统镜像吗?

另外,我不明白的是,现在内核已经被编译了(vmlinux),那么我该如何用qemu运行它呢?我的问题是,当我用qemu或调试器运行它时,内核是作为我的主OS中的应用程序运行的吗?

还有,我该如何安装我的设备驱动程序?我理解内核并不是Ubuntu,因此没有用户界面?

此外,我安装了qemu,但当我输入qemu时显示“command not found”。我猜我需要选择特定的处理器仿真器,例如qemu-system-i386、qemu-system-x86_64或qemu-x86_64?

qemu和kvm命令有什么相同点和不同点?

谢谢。


你可能在系统冻结后重新启动系统时查看了系统日志?那里有关于内核错误的任何消息吗?如果没有,我建议你这样做。有时候,从分析系统日志开始比按照你所描述的路线更容易。 - Eugene
如果系统日志中没有保存有关故障的信息,您可以尝试另一种方式来获取它。如果有问题的驱动程序可以在客户操作系统中运行(您似乎使用Ubuntu),则可以在引导时配置该操作系统将日志输出到串行端口,并从主机机器上检索它。如果驱动程序是针对虚拟机不支持的硬件,则QEMU也无法帮助。 - Eugene
关于QEMU和KVM,请参考它们的官方网站:QEMUKVM。简而言之,QEMU允许创建虚拟机,它模拟目标系统。当与KVM(一组特殊的内核模块等)一起使用时,QEMU获得了使用主机CPU的虚拟化支持而不是仿真的能力,从而实现在VM中运行的操作系统的更好性能。 - Eugene
没有任何内容在 kern.log 中。不确定是否有其他文件需要查看。我只是猜测,但我认为这是死锁而不是崩溃,这可能是为什么 kern.log 中没有任何内容的原因。 - user1253073
驱动程序并不是针对硬件的,它是一个跟踪工具,拦截文件系统调用并将其记录下来。然后驱动程序会进行较低级别的文件系统调用以执行实际操作。如果我能记录“文件系统”调用(在ext3-4级别),那么对我来说实际上更好。因此,如果有一种方法可以跟踪这些调用,那也可以解决我的问题。谢谢。 - user1253073
显示剩余2条评论
1个回答

3
所以,如果我正确理解问题,您有一个不需要特定硬件的内核模块。当您使用该模块时,系统会冻结,但内核日志中没有特殊信息。
以下内容可能有帮助。
获取日志
您描述的症状仍可能是内核 oops 或 panic 的结果。记录设施有时会在输出有关错误的信息到日志文件之前死亡。您可以尝试通过串行端口输出日志,这应该更可靠。
由于您的内核模块不需要任何特定的硬件,最简单的方法可能是将与您使用相同的 Linux 发行版安装到虚拟机中,并将该机器的虚拟串行端口(COM)连接到主机系统上的管道中。
这通常很容易做到。例如,如果主机操作系统和客户操作系统都是 Ubuntu 11.10,则 this blog post 包含详细说明。

VirtualBox 用于管理虚拟机。如果你更喜欢 QEMU,也可以使用它。我想使用 VirtualBox 更容易些,但这取决于个人偏好。

基本上,你需要执行以下步骤。

  • 创建一个虚拟机并安装您需要的Linux发行版作为其中的guest OS。
  • 在虚拟机的配置中启用串口(COM1,...)并将其配置为连接到主机上的特殊文件(“host pipe”),例如/tmp/vbox_serial
  • 启动guest OS并调整其引导选项:至少在引导加载程序菜单中添加console = ttyS0,115200或类似选项。
  • 在主机上启动minicomsocat或其他任何工具以从/tmp/vbox_serial读取。
  • 这就是全部。现在,通过/tmp/vbox_serial,您应该能够获得guest OS的内核日志,它会流向您的主机系统。如果客户系统崩溃,您仍然可以获取该日志,即使它未保存在guest系统的文件中。

为了使事情更容易,您可以在主机系统上使用socat而不是该博客文章作者建议的minicom。在这里,可能不需要使用minicom的强大功能。

这样,您可以使用socattee将日志保存到guest.log文件中,同时仍然将其输出到控制台:
socat /tmp/vbox_serial - | tee guest.log

如果发生内核oops或panic,日志中的回溯通常有助于找出问题所在。

检测死锁

如果您通过串行连接或其他方式获取了完整的日志,仍然没有发现任何可疑情况,并且您怀疑内核发生了死锁,则lockdep工具可能会有所帮助。它包含在内核中(但您可能需要重新构建内核并启用CONFIG_LOCKDEP_SUPPORT=y)。

Lockdep检测潜在的死锁并将结果输出到内核日志中。此演示文稿可以帮助您分析其输出。

跟踪工具

如果您需要跟踪内核中的某些事件以调试系统,则有一些有用的工具可供使用。

  • Kprobes - 一种可以在内核中几乎任意位置设置的断点。可用于跟踪函数调用等,对性能有适度影响。
  • SystemTap - 一个强大的系统,用于分析内核中正在发生的事情。其中一部分基于 Kprobes。
  • Ftrace - 一个包含在内核中的跟踪系统,如果需要,比 Kprobes 的开销更小。

谢谢。我有一个问题。串口会打印什么?我看到的是内核消息(kern.log)的一部分,而不是全部。奇怪的是,我的模块打印了一堆语句(每个文件调用大约50个),但只有几个被打印到串口上。然而,在kern.log中,所有的都在那里。即使是启动消息,也不是全部都在那里。实际上,有些在minicom中显示出来,但在kern.log中没有,反之亦然。那么我错过了什么?再次感谢。 - user1253073
没有看到你的代码很难猜测。也许与你用于打印这些消息的日志级别有关(例如,在printk()pr_*()包装器中使用的KERN_INFOKERN_ERR等)。它取决于内核设置,哪些消息被打印到控制台(包括串行控制台),哪些消息被打印到日志文件中。通常,具有KERN_CRIT或更高级别的消息会同时发送到控制台和日志文件,其余消息仅发送到日志文件中。你可以尝试在console=ttyS0之后,在启动时添加ignore_loglevel内核选项。 - Eugene
这样所有的消息都应该发送到串行控制台。至于在日志文件中缺失的消息-如我之前所建议的,日志守护程序并不总是成功地将消息保存在日志文件中,特别是如果内核或驱动程序发生了错误。通过串行连接输出更可靠。 - Eugene
如果你怀疑某处存在死锁,你可以像我之前建议的那样启用lockdep重新构建内核,并查看它报告了什么。此外,如果你可以在这里发布源代码或链接,那将非常有帮助。 - Eugene
实际上串口中没有打印任何调用跟踪或堆栈。上面格式化的唯一遗漏是缺少换行符。我再次运行它,现在不同的进程停滞了。这意味着我的模块正在占用其他进程的资源。我的下一步是按照您的建议检查死锁问题。该软件是tracefs,但我已将其移植到3.2内核,因此我怀疑我的某些更改导致了此问题。 - user1253073
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接