📄 ch04s06.html
字号:
[0]kdb> go</pre><p>bp 命令告诉 kdb 在下一次内核进入 scull_read 时停止. 你接着键入 go 来继续执行. 在将一些东西放入一个 scull 设备后, 我们可以试着通过在另一个终端的外壳下运行 cat 命令来读取它, 产生下面:</p><pre class="screen">Instruction(i) breakpoint #0 at 0xd087c5dc (adjusted)0xd087c5dc scull_read: int3Entering kdb (current=0xcf09f890, pid 1575) on processor 0 due toBreakpoint @ 0xd087c5dc[0]kdb></pre><p>我们现在位于 scull_read 的开始. 为看到我们任何到那里的, 我们可以获得一个堆栈回溯:</p><pre class="screen">[0]kdb> bt ESP EIP Function (args)0xcdbddf74 0xd087c5dc [scull]scull_read0xcdbddf78 0xc0150718 vfs_read+0xb80xcdbddfa4 0xc01509c2 sys_read+0x420xcdbddfc4 0xc0103fcf syscall_call+0x7[0]kdb></pre><p>kdb 试图打印出调用回溯中每个函数的参数. 然而, 它被编译器的优化技巧搞糊涂了. 因此, 它无法打印 scull_read 的参数.</p><p>到时候查看一些数据了. mds 命令操作数据; 我们可以查询 schull_devices 指针的值, 使用这样一个命令:</p><pre class="screen">[0]kdb> mds scull_devices 1 0xd0880de8 cf36ac00 ....</pre><p>这里我们要求一个(4字节)字, 起始于 scull_devices 的位置; 答案告诉我们的设备数组在地址 0xd0880de8; 第一个设备结构自己在 0xcf36ac00. 为查看那个设备结构, 我们需要使用这个地址:</p><pre class="screen">[0]kdb> mds cf36ac000xcf36ac00 ce137dbc ....0xcf36ac04 00000fa0 ....0xcf36ac08 000003e8 ....0xcf36ac0c 0000009b ....0xcf36ac10 00000000 ....0xcf36ac14 00000001 ....0xcf36ac18 00000000 ....0xcf36ac1c 00000001 ....</pre><p>这里的 8 行对应于 scull_dev 结构的开始部分. 因此, 我们看到第一个设备的内存位于 0xce137dbc, quantum 是 4000 (16进制 fa0), 量子集大小是 1000 (16进制 3e8 ), 当前有 155( 16进制 9b) 字节存于设备中.</p><p>kdb 也可以改变数据. 假想我们要截短一些数据从设备中:</p><pre class="screen">[0]kdb> mm cf26ac0c 0x500xcf26ac0c = 0x50</pre><p>在设备上一个后续的 cat 会返回比之前少的数据.</p><p>kdb 有不少其他功能, 包括单步(指令, 不是 C 源码的一行), 在数据存取上设置断点, 反汇编代码, 步入链表, 存取寄存器数据, 还有更多. 在你应用了 kdb 补丁后, 一个完整的手册页集能够在你的源码树的 documentation/kdb 下发现.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="ThekgdbPatches.sect"></a>4.6.3. kgdb 补丁</h3></div></div></div><p>目前为止我们看到的 2 个交互式调试方法( 使用 gdb 于 /proc/kcore 和 kdb) 都缺乏应用程序开发者已经熟悉的那种环境. 如果有一个真正的内核调试器支持改变变量, 断点等特色, 不是很好?</p><p>确实, 有这样一个解决方案. 在本书编写时, 2 个分开的补丁在流通中, 它允许 gdb, 具备完全功能, 针对内核运行. 这 2 个补丁都称为 kgdb. 它们通过分开运行测试内核的系统和运行调试器的系统来工作; 这 2 个系统典型地是通过一个串口线连接起来. 因此, 开发者可以在稳定地桌面系统上运行 gdb, 而操作一个运行在专门测试的盒子中的内核. 这种方式建立 gdb 开始需要一些时间, 但是很快会得到回报,当一个难问题出现时.</p><p>这些补丁目前处于健壮的状态, 在某些点上可能被合并, 因此我们避免说太多, 除了它们在哪里以及它们的基本特色. 鼓励感兴趣的读者去看这些的当前状态.</p><p>第一个 kgdb 补丁当前在 -mm 内核树里 -- 补丁进入 2.6 主线的集结场. 补丁的这个版本支持 x86, SuperH, ia64, x86_64, 和 32位 PPC 体系. 除了通过串口操作的常用模式, 这个版本的 kgdb 可以通过一个局域网通讯. 使能以太网模式并且使用 kgdboe参数指定发出调试命令的 IP 地址来启动内核. 在 Documentation/i386/kgdb 下的文档描述了如何建立.<sup>[<a name="id423580" href="#ftn.id423580">16</a>]</sup></p><p>作为一个选择, 你可使用位于 http://kgdb.sf.net 的kgdb补丁. 这个调试器的版本不支持网络通讯模式(尽管据说在开发中), 但是它确实有内嵌的使用可加载模块的支持. 它支持 x86, x86_64, PowerPC, 和 S/390 体系.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="TheUserModeLinuxPort.sect"></a>4.6.4. 用户模式 Linux 移植</h3></div></div></div><p>用户模式 Linux (UML) 是一个有趣的概念. 它被构建为一个分开的 Linux 内核移植, 有它自己的 arch/um 子目录. 它不在一个新的硬件类型上运行, 但是; 相反, 它运行在一个由 Linux 系统调用接口实现的虚拟机上. 如此, UML 使用 Linux 内核来运行, 作为一个Linux 系统上的独立的用户模式进程.</p><p>有一个作为用户进程运行的内核拷贝有几个优点. 因为它们运行在一个受限的虚拟的处理器上, 一个错误的内核不能破坏"真实的"系统. 可以在同一台盒子轻易的尝试不同的硬件和软件配置. 并且, 也许对内核开发者而言, 用户模式内核可容易地使用 gdb 和 其他调试器操作.</p><p>毕竟, 它只是一个进程. UML 显然有加快内核开发的潜力.</p><p>然而, UML 有个大的缺点,从驱动编写者的角度看: 用户模式内核无法存取主机系统的硬件. 因此, 虽然它对于调试大部分本书的例子驱动是有用的, UML 对于不得不处理真实硬件的驱动的调试还是没有用处.</p><p>看 http://user-mode-linux.sf.net/ 关于 UML 的更多信息.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="TheLinuxTraceToolkit.sect"></a>4.6.5. Linux 追踪工具</h3></div></div></div><p>Linux Trace Toolkit (LTT) 是一个内核补丁以及一套相关工具, 允许追踪内核中的事件. 这个追踪包括时间信息, 可以创建一个给定时间段内发生事情的合理的完整图像. 因此, 它不仅用来调试也可以追踪性能问题.</p><p>LTT, 同广泛的文档一起, 可以在 <a href="http://www.opersys.com/LTT" target="_top">http://www.opersys.com/LTT</a> 找到.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="DynamicProbes.sect"></a>4.6.6. 动态探针</h3></div></div></div><p>Dynamic Probes ( DProbes ) 是由 IBM 发行的(在 GPL 之下)为 IA-32 体系的 Linux 的调试工具. 它允许安放一个"探针"在几乎系统中任何地方, 用户空间和内核空间都可以. 探针由一些代码组成( 有一个特殊的,面向堆栈的语言写成), 当控制命中给定的点时执行. 这个代码可以报告信息给用户空间, 改变寄存器, 或者做其他很多事情. DProbes 的有用特性是, 一旦这个能力建立到内核中, 探针可以在任何地方插入在一个运行中的系统中, 不用内核建立或者重启. DProbes 可以和 LTT 一起来插入一个新的跟踪事件在任意位置.</p><p>DProbes 工具可以从 IBM 的开放源码网站:<a href="http://oss.sof-ware.ibm.com" target="_top">http://oss.sof-ware.ibm.com</a> 下载.</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id423580" href="#id423580">16</a>] </sup>确实是忽略了指出, 你应当使你的网络适配卡建立在内核中, 然而, 否则调试器在启动时找不到它会关掉它自己.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04s05.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="ch04.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="ch05.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">4.5. 调试系统故障 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 第 5 章 并发和竞争情况</td></tr></table></div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -