【问题标题】:Debugging an Operating System调试操作系统
【发布时间】:2011-01-03 00:46:07
【问题描述】:

我正在浏览一些有关操作系统的一般性知识并提出了一个问题。开发人员在开发操作系统时将如何调试,即调试操作系统本身?有哪些工具可用于 OS 开发人员调试?

【问题讨论】:

  • +1,好问题!我不知道答案,但我所知道的是,你当然不能使用“普通”调试器,因为内核在它上面运行......
  • 认真思考!操作系统开发人员似乎有点反内核调试器 - 著名的 Linus Torvalds。
  • Linus Torbvalds 说只有傻瓜才需要内核调试器:P lwn.net/2000/0914/a/lt-debugger.php3
  • 套用 Bjarne Stroustroup 的话说,“新手总是比专家多。”调试器有时很有用。从调试器无法帮助您的经验中学习:也很有用。
  • Linus 还说 Emacs 是“邪恶的”(尽管其中编写了大量的 linux)。仅仅因为一名黑客可以在互联网上居高临下,就没有理由避免某些事情。除了他的强项之外,我不会把他的话当成福音:组织足够多的程序员以使 1960 年代的小型计算机操作系统半可用所需的社会工程学!

标签: debugging operating-system kernel


【解决方案1】:

调试内核困难,因为您可能无法依靠崩溃的机器来传达正在发生的事情。此外,错误的代码可能位于中断处理程序等可怕的地方。

据我所知,调试操作系统有四种主要方法:

  1. 完整性检查,以及屏幕输出。

    Linux 上的内核恐慌 (known as "Oops"es) 就是一个很好的例子。 Linux 人员编写了一个函数,可以打印出他们可以找到的内容(包括堆栈跟踪),然后停止一切

    即使是警告也是有用的。 Linux 为您可能不小心在中断处理程序中休眠的情况设置了防护措施。例如,mutex_lock 函数将检查(在might_sleep 中)您是否处于不安全的上下文中,如果是则打印堆栈跟踪。

  2. 调试器

    传统上,在调试过程中,计算机所做的一切都是通过串行线路输出到稳定的测试机器。随着虚拟机的出现,您现在可以将一个虚拟机的执行串行线连接到同一台物理机上的另一个程序,这非常方便。当然,这要求您的操作系统发布它正在执行的操作并等待调试器连接。 KGDB (Linux) 和 WinDBG (Windows) 就是一些这样的操作系统内调试器。 VMWaresupports this story explicitly.

    最近,VM 开发人员已经想出了如何在不使用串行线路或内核扩展的情况下调试内核。 VMWare has implemented this 在他们最近的资料中。

    在操作系统中调试的问题(在我看来)与Uncertainty principle 有关。中断(大多数硬错误肯定会出现)是异步的、频繁的和不确定的。如果您的错误与以特定方式重叠的两个中断有关,您将不会使用调试器公开它;该错误可能甚至不会发生。也就是说,它可能会,然后调试器可能会很有用。

  3. 确定性回放

    当您遇到似乎只在生产中出现的错误时,您希望可以记录发生的事情并重播,就像安全摄像头一样。感谢a professor I knew at Illinois,您现在可以在 VMWare 虚拟机中执行此操作。 VMWare 和相关人员describe it all 比我做得更好,他们提供的东西看起来像good documentation

    确定性回放在现场是全新的,所以到目前为止我还没有发现任何特别惯用的用法。他们说它也应该对安全漏洞特别有用。

  4. 将所有内容移至用户空间。

    最后,内核中的东西仍然更加脆弱,因此遵循 Nucleus(或微内核)设计具有巨大的开发优势,您可以将内核模式组件缩减到最低限度。对于其他一切,你可以使用无数的用户空间开发工具,你会更快乐。 FUSE 是用户空间文件系统扩展, 就是这方面的典型示例。

    我喜欢最后一个想法,因为它就像你编写的程序是可写的。循环,不是吗?

【讨论】:

  • 很好的答案,但在 2 中您错过了 VM 也可以在不使用模拟串行线路(甚至内核支持)的情况下提供到调试器的钩子。
  • QEMU(以及 KVM)提供了一个 GDB 存根,它比 VMWare 早很多年(至少是公开的)——只需使用 -s 运行即可。有时您可以将整个内核移至用户空间:Linux 有 UML,DragonFly BSD 有 vkernel,两者都允许更轻松的调试。
  • 写得很好,安德烈斯。我会在该列表中添加内存日志记录。为了调试多线程内核状态机,我使用了每处理器日志(不是字符串日志,而是数据日志)来调试问题。我也看到字符串日志记录在循环内核缓冲区中完成(没有打印出来/存储在文件中),用于调试。在我处理的文件系统中,我们记录从不同代码路径中释放的块的块号以及由谁释放,以调试由于软件错误导致的文件系统损坏。干杯。
  • VMWare 故事链接已损坏。
【解决方案2】:

在引导方案(从头开始的操作系统)中,您可能必须尽早在操作系统内核中引入远程调试功能(内存转储、日志记录等),并使用单独的机器。或者您可以使用虚拟机/管理程序。

Windows CE 有一个称为 KITL - 内核独立传输层的组件。我想标题不言自明。

【讨论】:

    【解决方案3】:

    您可以使用虚拟机:例如。 debug ring0 code with bochs/gdbDebugging NetBSD kernel with qemu

    或类似 KDB 的串行线路。

    【讨论】:

    • QEMU/KVM 也支持这一点,并且比 Bochs 更加现代和快速:-)
    【解决方案4】:

    printf 日志记录 附加到进程 严肃的单元测试 等等。

    【讨论】:

      【解决方案5】:

      使用内核调试器进行远程调试,也可以通过虚拟化来完成。

      【讨论】:

        【解决方案6】:

        调试操作系统不适合胆小的人。由于正在调试内核,因此您的选择将非常有限。大量的printf 语句是一种技巧,此外,它实际上取决于正在调试的“操作系统”,我们可以谈论

        • 文件系统
        • 驱动程序
        • 内存管理
        • 原始磁盘输入/输出
        • 屏幕输入/输出
        • 内核

        同样,如上所述,这是一项变化广泛的练习,它们都相互影响。更复杂的是,假设你要调试内核,如果运行时环境设置不正确,你会怎么做(我说的是内核负责加载二进制可执行文件)。

        有些内核可能(并非所有内核都有)包含一个简单的调试监视器,事实上,如果我没记错的话,在 Sams 出版的 Richard A Burgess 的名为“开发自己的 32 位操作系统”的书中,他合并了一个调试监视器,显示 CPU、寄存器等的各种状态。

        再次,考虑到二进制可执行文件需要某种加载机制,例如 gdb 等效项,如果没有设置加载二进制文件的环境,那么您的选择非常有限。

        通过使用大量的printf 语句将错误、日志等显示到单独的终端或文件是调试的最佳方式,这听起来确实是一场噩梦,但这样做是值得的。

        希望这会有所帮助, 最好的祝福, 汤姆。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-30
          • 2011-10-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多