⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 (ldd) ch04-调试技术(转载).htm

📁 html格式
💻 HTM
📖 第 1 页 / 共 4 页
字号:
      color=#ffffff size=3>
      <P><BR>(代码)<BR>&nbsp;<BR>由于read从它的小缓冲区(faulty_buf)复制数据到用户空间,我们希望读一小块文件<BR>能够工作。然而,每次读出多于1KB的数据会跨越页面边界,如果访问了非法页面read就<BR>会失败。事实上,前面给出的oops是在请求一个4KB大小的read时发生的,这条消息在/v<BR>ar/log/messages(syslogd默认存放内核消息的文件)的oops消息前给出了:<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>同样的cat命令却不能在Alpha上产生oops,这是因为从faulty_buf读取4KB字节没有超出<BR>页边界(Alpha上的页面大小是8KB,缓冲区正好在页面的起始位置附近)。如果在你的<BR>系统上读取faulty没有产生oops,试试wc,或者给dd显式地指定块大小。<BR>&nbsp;<BR>使用ksymoops<BR>oops消息的最大问题就是十六进制数值对于程序员来说没什么意义;需要将它们解析为<BR>符号。<BR>&nbsp;<BR>内核源码通过其所包含的ksymoops工具帮助开发人员――但是注意,版本1.2的源码中没<BR>有这个程序。该工具将oops消息中的数值地址解析为内核符号,但只限于PC机产生的oop<BR>s消息。由于消息本身就是处理器相关的,每一体系结构都有其自身的消息格式。<BR>&nbsp;<BR>ksymoops从标准输入获得oops消息,并从命令行内核符号表的名字。符号表通常就是/us<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>ksymoops从标准输入获得oops消息,并从命令行内核符号表的名字。符号表通常就是/us<BR>r/src/linux/System.map。程序以更可读的方式打印调用轨迹和程序代码,而不是最原<BR>始的oops消息。下面的片断就是用上一节的oops消息得出的结果:<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>由ksymoops反汇编出的代码给出了失效的指令和其后的指令。很明显――对于那些知道<BR>一点汇编的人――repz&nbsp;movsl指令(REPeat&nbsp;till&nbsp;cx&nbsp;is&nbsp;Zero,&nbsp;MOVe&nbsp;a&nbsp;String&nbsp;of<BR>Longs)用源索引(esi,是0x202e000)访问了一个未映射页面。用来获得模块信息的ks<BR>ymoops&nbsp;-m命令给出,模块映射到一个在0x0202dxxx的页面上,这也确认乐esi确实超出<BR>了范围。<BR>&nbsp;<BR>由于faulty模块所占用的内存不在系统表中,被解码的调用轨迹还给出了两个数值地址<BR>。这些值可以手动补充,或是通过ksyms命令的输出,或是在/proc/ksyms中查询模块的<BR>名字。<BR>&nbsp;<BR>然而对于这个失效,这两个地址并不对应与代码地址。如果你看了arch/i386/kernel/tr<BR>aps.c,你就发现,调用轨迹是从整个堆栈并利用一些启发式方法区分数据值(本地变量<BR>和函数参数)和返回地址获得的。调用轨迹中只给出了引用内核代码的地址和引用模块<BR>的地址。由于模块所占页面既有代码也有数据,错综复杂的栈可能会漏掉启发式信息,<BR>这就是上面两个0x202xxxx地址的情况。<BR>&nbsp;<BR>如果你不愿手动查看模块地址,下面这组管道可以用来创建一个既有内核又有模块符号<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>如果你不愿手动查看模块地址,下面这组管道可以用来创建一个既有内核又有模块符号<BR>的符号表。无论何时你加载模块,你都必须重新创建这个符号表。<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>这个管道将完整的系统表与/proc/ksyms中的公开内核符号混合在一起,后者除了内核符<BR>号外,还包括了当前内核里的模块符号。这些地址在insmod重定位代码后就出现在/proc<BR>/ksyms中。由于这两个文件的格式不同,使用了sed和awk将所有的文本行转换为一种合<BR>适的格式。然后对这张表排序,去除重复部分,这样ksymoops就可以用了。<BR>&nbsp;<BR>如果我们重新运行ksymoops,它从新的符号表中截取出如下信息:<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>正如你所见到的,当跟踪与模块有关的oops消息时,创建一个修订的系统表是很有助益<BR>的:现在ksymoops能够对指令指针解码并完成整个调用轨迹了。还要注意,显式反汇编<BR>码的格式和objdump所使用的格式一样。objdump也是一个功能强大的工具;如果你需要<BR>查看失败前的指令,你调用命令objdump&nbsp;–d&nbsp;faulty.o。<BR>&nbsp;<BR>在文件的汇编列表中,字串faulty_read+45/60标记为失效行。有关objdump的更多的信<BR>息和它的命令行选项可以参见该命令的手册。<BR>&nbsp;<BR>即便你构建了你自己的修订版符号表,上面提到的有关调用轨迹的问题仍然存在:虽然0<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>即便你构建了你自己的修订版符号表,上面提到的有关调用轨迹的问题仍然存在:虽然0<BR>x202xxxx指针被解码了,但仍然是假的。<BR>&nbsp;<BR>学会解码oops消息需要一定的经验,但是确实值得一做。用来学习的时间很快就会有所<BR>回报。不过由于机器指令的Unix语法与Intel语法不同,唯一的问题在于从哪获得有关汇<BR>编语言的文档;尽管你了解PC汇编语言,但你的经验都是用Intel语法的编程获得的。在<BR>参考书目中,我给一些有所补益的书籍。<BR>&nbsp;<BR>使用oops<BR>使用ksymoops有些繁琐。你需要C++编译器编译它,你还要构建你自己的符号表来充分发<BR>挥程序的能力,你还要将原始消息和ksymoops输出合在一起组成可用的信息。<BR>&nbsp;<BR>如果你不想找这么多麻烦,你可以使用oops程序。oops在本书的O’Reilly&nbsp;FTP站点给出<BR>的源码中。它源自最初的ksymoops工具,现在它的作者已经不维护这个工具了。oops是<BR>用C语言写成的,而且直接查看/proc/ksyms而无需用户每次加载模块后构建新的符号表<BR>。<BR>&nbsp;<BR>该程序试图解码所有的处理器寄存器并&nbsp;颜&nbsp;轨迹解析为符号值。它的缺点是,它要比ksy<BR>moops罗嗦些,但通常你所有的信息越多,你发现错误也就越快。oops的另一个优点是,<BR>它可以解析x86,Alpha和Sparc的oops消息。与内核源码相同,这个程序也按GPL发行。<BR>&nbsp;<BR>oops产生的输出与ksymoops的类似,但是更完全。这里给出前一个oops输出的开始部分<BR>—由于在这个oops消息中堆栈没保存什么有用的东西,我不认为应该显示整个&nbsp;颜&nbsp;轨迹<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>—由于在这个oops消息中堆栈没保存什么有用的东西,我不认为应该显示整个&nbsp;颜&nbsp;轨迹<BR>:<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>当你调试“真正的”模块(faulty太短了,没有什么意义)时,将寄存器和堆栈解码是<BR>非常有益的,而且如果被调试的所有模块符号都开放出来时更有帮助。在失效时,处理<BR>器寄存器一般不会指向模块的符号,只有当符号表开放给/proc/ksyms时,你才能输出中<BR>标别它们。<BR>&nbsp;<BR>我们可以用一下步骤制作一张更完整的符号表。首先,我们不应在模块中声明静态变量<BR>,否则我们就无法用insmod开放它们了。第二,如下面的截取自scull的init_module函<BR>数的代码所示,我们可以用#ifdef&nbsp;SCULL_DEBUG或类似的宏屏蔽register_symtab调用。<BR>&nbsp;<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>我们在第2章“编写和运行模块”的“注册符号表”一节中已经看到了类似内容,那里说<BR>,如果模块不注册符号表,所有的全局符号就都开放。尽管这一功能仅在SCULL_DEBUG被<BR>激活时才有效,为了避免内核中的名字空间污染,所有的全局符号有合适的前缀(参见<BR>第2章的“模块与应用程序”一节)。<BR>&nbsp;<BR>使用klogd<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>使用klogd<BR>klogd守护进程的近期版本可以在oops存放到记录文件前对oops消息解码。解码过程只由<BR>版本1.3或更新版本的守护进程完成,而且只有将-k&nbsp;/usr/src/linux/System.map做为参<BR>数传递给守护进程时才解码。(你可以用其他符号表文件代替System.map)<BR>&nbsp;<BR>有新的klogd给出的faulty的oops如下所示,它写到了系统记录中:<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>我想能解码的klogd对于调试一般的Linux安装的核心来说是很好的工具。由klogd解码的<BR>消息包括大部分ksymoops的功能,而且也要求用户编译额外的工具,或是,当系统出现<BR>故障时,为了给出完整的错误报告而合并两个输出。当oops发生在内核时,守护进程还<BR>会正确地解码指令指针。它并不反汇编代码,但这不是问题,当错误报告给出消息时,<BR>二进制数据仍然存在,可以离线反汇编代码。<BR>&nbsp;<BR>守护进程的另一个功能就是,如果符号表版本与当前内核不匹配,它会拒绝解析符号。<BR>如果在系统记录中解析出了符号,你可以确信它是正确的解码。<BR>&nbsp;<BR>然而,尽管它对Linux用户很有帮助,这个工具在调试模块时没有什么帮助。我个人没有<BR>在开放软件的电脑里使用解码选项。klogd的问题是它不解析模块中的符号;因为守护进<BR>程在程序员加载模块前就已经运行了,即使读了/proc/ksyms也不会有什么帮助。记录文<BR>件中存在解析后的符号会使oops和ksymoops混淆,造成进一步解析的困难。<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>如果你需要使用klogd调试你的模块,最新版本的守护进程需要加入一些新的特殊支持,<BR>我期待它的完成,只要给内核打一个小补丁就可以了。<BR>&nbsp;<BR>系统挂起<BR>尽管内核代码中的大多数错误仅会导致一个oops消息,有时它们困难完全将系统挂起。<BR>如果系统挂起了,没有消息能够打印出来。例如,如果代码遇到一个死循环,内核停止<BR>了调度过程,系统不会再响应任何动作,包括魔法键Ctrl-Alt-Del组合。<BR>&nbsp;<BR>处理系统挂起有两个选择――一个是防范与未然,另一个就是亡羊补牢,在发生挂起后<BR>调试代码。<BR>&nbsp;<BR>通过在策略点上插入schedule调用可以防止死循环。schedule调用(正如你所猜想到的<BR>)调用调度器,因此允许其他进程偷取当然进程的CPU时间。如果进程因你的驱动程序中<BR>的错误而在内核空间循环,你可以在跟踪到这种情况后杀掉这个进程。<BR>&nbsp;<BR>在驱动程序代码中插入schedule调用会给程序员带来新的“问题”:函数,,以及调用轨<BR>迹中的所有函数,必须是可重入的。在正常环境下,由于不同的进程可能并发地访问设<BR>备,驱动程序做为整体是可重入的,但由于Linux内核是不可抢占的,不必每个函数都是<BR>可重入的。但如果驱动程序函数允许调度器中断当前进程,另一个不同的进程可能会进<BR>入同一个函数。如果schedule调用仅在调试期间打开,如果你不允许,你可以避免两个<BR>并发进程访问驱动程序,所以并发性倒不是什么非常重要的问题。在介绍阻塞型操作时<BR>(第5章的“写可重入代码”)我们再详细介绍并发性问题。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>(第5章的“写可重入代码”)我们再详细介绍并发性问题。<BR>&nbsp;<BR>如果要调试死循环,你可以利用Linux键盘的特殊键。默认情况下,如果和修饰键一起按<BR>了PrScr键(键码是70),系统会向当前控制台打印有关机器状态的有用信息。这一功能<BR>在x86和Alpha系统都有。Linux的Sparc移植也有同样的功能,但它使用了标记为“Break<BR>/Scroll&nbsp;Lock”的键(键码是30)。<BR>&nbsp;<BR>每一个特殊函数都有一个名字,并如下面所示都有一个按键事件与之对应。组合键之后<BR>的括号里是函数名。<BR>&nbsp;<BR>Shift-PrScr(Show_Memory)<BR>&nbsp;<BR>打印若干行关于内存使用的信息,尤其是有关缓冲区高速缓存的使用情况。<BR>&nbsp;<BR>Control-PrScr(Show_State)<BR>&nbsp;<BR>针对系统里的每一个处理器打印一行信息,同时还打印内部进程树。对当前进程进行标<BR>记。<BR>&nbsp;<BR>RightAlt-PrScr(Show_Registers)<BR>&nbsp;<BR>由于它可以打印按键时的处理器寄存器内容,它是系统挂起时最重要的一个键了。如果<BR>有当前内核的系统表的话,查看指令计数器以及它如何随时间变化,对了解代码在何处<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>有当前内核的系统表的话,查看指令计数器以及它如何随时间变化,对了解代码在何处<BR>循环非常有帮助。<BR>&nbsp;<BR>如果想将这些函数映射到不同的键上,每一个函数名都可以做为参数传递给loadkeys。<BR>键盘映射表可以任意修改(这是“策略无关的”)。<BR>&nbsp;<BR>如果console_loglevel足够到的话,这些函数打印的消息会出现在控制台上。如果不是<BR>你运行了一个旧klogd和一个新内核的话,默认记录级应该足够了。如果没有出现消息,<BR>你可以象以前说的那样提升记录级。“足够高”的具体值与你使用的内核版本有关。对<BR>于Linux&nbsp;2.0或更新的版本来说是5。<BR>&nbsp;<BR>即便当系统挂起时,消息也会打印到控制台上,确认记录级足够高是非常重要的。消息<BR>是在产生中断时生成的,因此即便有错的进程不释放CPU也可以运行――当然,除非中断<BR>被屏蔽了,不过如果发生这种情况既不太可能也非常不幸。<BR>&nbsp;<BR>有时系统看起来象是挂起了,但其实不是。例如,如果键盘因某种奇怪的原因被锁住了<BR>就会发生这种情况。这种假挂起可以通过查看你为探明此种情况而运行的程序输出来判<BR>断。我有一个程序会不断地更新LED显示器上的时钟,我发现这个对于验证调度器尚在运<BR>行非常有用。你可以不必依赖外部设备就可以检查调度器,你可以实现一个程序让键盘L<BR>ED闪烁,或是不断地打开关闭软盘马达,或是不断触动扬声器――不过我个人认为,通<BR>常的蜂鸣声很烦人,应该尽量避免。看看ioctl命令KDMKTONE。O’Reilly&nbsp;FTP站点上的<BR>例子程序(misc-progs/heartbeat.c)中有一个是让键盘LED不断闪烁的。<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>如果键盘不接收输入了,最佳的处理手段是从网络登录在系统中,杀掉任何违例的进程<BR>,或是重新设置键盘(用kdb_mode&nbsp;-a)。然而,如果你没有网络可用来恢复的话,发现<BR>系统挂起是由键盘锁死造成的一点儿用也没有。如果情况确实是这样,你应该配置一种<BR>替代输入设备,至少可以保证正常地重启系统。对于你的计算机来说,关闭系统或重启<BR>比起所谓的按“大红钮”要更方便一些,至少它可以免去长时间地fsck扫描磁盘。<BR>&nbsp;<BR>这种替代输入设备可以是游戏杆或是鼠标。在sunsite.edu.cn上有一个游戏杆重启守护<BR>进程,gpm-1.10或更新的鼠标服务器可以通过命令行选项支持类似的功能。如果键盘没<BR>有锁死,但是却误入“原始”模式,你可以看看kdb包中文档介绍的一些小技巧。我建议<BR>最好在问题出现以前就看看这些文档,否则就太晚了。另一种可能是配置gpm-root菜单<BR>,增添一个“reboot”或“reset&nbsp;keyboard”菜单项;gpm-root一个响应控制鼠标事件<BR>的守护进程,它用来在屏幕上显示菜单和执行所配置的动作。<BR>&nbsp;<BR>最好,你会可以按“留意安全键”(SAK),一个用于将系统恢复为可用状态的特殊键。<BR>由于不是所有的实现都能用,当前Linux版本的默认键盘表中没有为此键特设一项。不过<BR>你还是可以用loadkeys将你的键盘上的一个键映射为SAK。你应该看看drivers/char目录<BR>中的SAK实现。代码中的注释解释了为什么这个键在Linux&nbsp;2.0中不是总能工作,这里我<BR>就不多说了。<BR>&nbsp;<BR>不过,如果你运行版本2.1.9或是更新的版本,你就可以使用非常可靠地留意安全键了。<BR>此外,2.1.43及后续版本内核还有一个编译选项选择是否打开“SysRq魔法键”;我建议<BR>你看一看drivers/char/sysrq.c中的代码并使用这项新技术。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>你看一看drivers/char/sysrq.c中的代码并使用这项新技术。<BR>&nbsp;<BR>如果你的驱动程序真的将系统挂起了,而且你有不知道在哪插入schedule调用,最佳的<BR>处理方法就是加一些打印消息,并将它们打印到控制台上(通过修改console_loglevel<BR>变量值)。在重演挂起过程时,最好将所有的磁盘都以只读方式安装在系统上。如果磁<BR>盘是只读的或没有安装,就不会存在破坏文件系统或使其进入不一致状态的危险。至少<BR>你可以避免在复位系统后运行fsck。另一中方法就是使用NFS根计算机来测试模块。在这<BR>种情况下,由于NFS服务器管理文件系统的一致性,而它又不会受你的驱动程序的影响,<BR>你可以避免任何的文件系统崩溃。<BR>&nbsp;<BR>使用调试器<BR>最后一种调试模块的方法就是使用调试器来一步步地跟踪代码,查看变量和机器寄存器<BR>的值。这种方法非常耗时,应该尽可能地避免。不过,某些情况下通过调试器对代码进<BR>行细粒度的分析是非常有益的。在这里,我们所说的被调试的代码运行在内核空间――<BR>除非你远程控制内核,否则不可能一步步跟踪内核,这会使很多事情变得更加困难。由<BR>于远程控制很少用到,我们最后介绍这项技术。所幸的是,在当前版本的内核中可以查<BR>看和修改变量。<BR>&nbsp;<BR>在这一级上熟练地使用调试器需要精通gdb命令,对汇编码有一定了解,并且有能够将源<BR>码与优化后的汇编码对应起来的能力。<BR>&nbsp;<BR>不幸的是,gdb更适合与调试核心而不是模块,调试模块化的代码需要更多的技术。这更<BR>多的技术就是kdebug包,它利用gdb的“远程调试”接口控制本地内核。我将在介绍普通<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>多的技术就是kdebug包,它利用gdb的“远程调试”接口控制本地内核。我将在介绍普通<BR>调试器后介绍kdebug。<BR>&nbsp;<BR>使用gdb<BR>gdb在探究系统内部行为时非常有用。启动调试器时必须假想内核就是一个应用程序。除<BR>了指定内核文件名外,你还应该在命令行中提供内存镜象文件的名字。典型的gdb调用如<BR>下所示:<BR>&nbsp;<BR>(代码)<BR>&nbsp;<BR>第一个参数是未经压缩的内核可执行文件(在你编译完内核后,这个文件在/usr/src/li<BR>nux目录中)的名字。只有x86体系结构有zImage文件(有时称为vmlinuz),它是一种解<BR>决Intel处理器实模式下只有640KB限制的一种技巧;而无论在哪个平台上,vmlinux都是<BR>你所编译的未经压缩的内核。<BR>&nbsp;<BR>gdb命令行的第二个参数是是内存镜象文件的名字。与其他在/proc下的文件类似,/proc<BR>/kcore也是在被读取时产生的。当read系统调用在/proc文件系统执行时,它映射到一个<BR>用于数据生成而不是数据读取的函数上;我们已在“使用/proc文件系统”一节中介绍了<BR>这个功能。系统用kcore来表示按内存镜象文件格式存储的内核“可执行文件”;由于它<BR>要表示整个内核地址空间,它是一个非常巨大的文件,对应所有的物理内存。利用gdb,<BR>你可以通过标准gdb命令查看内核标量。例如,p&nbsp;jiffies可以打印从系统启动到当前时<BR>刻的时钟滴答数。<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>当你从gdb打印数据时,内核还在运行,不同数据项会在不同时刻有不同的数值;然而,<BR>gdb为了优化对内存镜象文件的访问会将已经读到的数据缓存起来。如果你再次查看jiff<BR>ies变量,你会得到和以前相同的值。缓存变量值防止额外的磁盘操作对普通内存镜象文<BR>件来说是对的,但对“动态”内存镜象文件来说就不是很方便了。解决方法是在你想刷<BR>新gdb缓存的时候执行core-file&nbsp;/proc/kcore命令;调试器将使用新的内存镜象文件并<BR>废弃旧信息。但是,读新数据时你并不总是需要执行core-file命令;gdb以1KB的尺度读<BR>取内存镜象文件,仅仅缓存它所引用的若干块。<BR>&nbsp;<BR>你不能用普通gdb做的是修改内核数据;由于调试器需要在访问内存镜象前运行被调试程<BR>序,它是不会去修改内存镜象文件的。当调试内核镜象时,执行run命令会导致在执行若<BR>干指令后导致段违例。出于这个原因,/proc/kcore都没有实现write方法。<BR>&nbsp;<BR>如果你用调试选项(-g)编译了内核,结果产生的vmlinux比没有用-g选项的更适合于gd<BR>b。不过要注意,用-g选项编译内核需要大量的磁盘空间――支持网络和很少几个设备和<BR>文件系统的2.0内核在PC上需要11KB。不过不管怎样,你都可以生成zImage文件并用它来<BR>其他系统:在生成可启动镜象时由于选项-g而加入的调试信息最终都被去掉了。如果我<BR>有足够的磁盘空间,我会一致打开-g选项的。<BR>&nbsp;<BR>在非PC计算机上则有不同的方法。在Alpha上,make&nbsp;boot会在生成可启动镜象前将调试<BR>信息去掉,所以你最终会获得vmlinux和vmlinux.gz两个文件。gdb可以使用前者,但你<BR>只能用后者启动。在Sparc上,默认情况下内核(至少是2.0内核)不会被去掉调试信息<BR>,所以你需要在将其传递给silo(Sparc的内核加载器)前将调试信息去掉,这样才能启<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>,所以你需要在将其传递给silo(Sparc的内核加载器)前将调试信息去掉,这样才能启<BR>动。由于尺寸的问题,无论milo(Alpha的内核加载器)还是silo都不能启动未去掉调试<BR>信息的内核。<BR>&nbsp;<BR>当你用-g选项编译内核并且用vmlinux和/proc/kcore一起使用调试器,gdb可以返回很多<BR>有关内核内部结构的信息。例如,你可以使用类似于这样的命令,p&nbsp;*module_list,p<BR>*module_list-&gt;next和p&nbsp;*chrdevs[4]-&gt;fops等显示这些结构的内容。如果你手头有内核<BR>映射表和源码的话,这些探测命令是非常有用的。<BR>&nbsp;<BR>另一个gdb可以在当前内核上执行的有用任务是,通过disassemble命令(它可以缩写)<BR>或是“检查指令”(x/i)命令反汇编函数。disassemble命令的参数可以是函数名或是<BR>内存区范围,而x/i则使用一个内存地址做为参数,也可以用符号名。例如,你可以用x/<BR>20i反汇编20条指令。注意,你不能反汇编一个模块的函数,这是因为调试器处理vmlinu<BR>x,它并不知道你的模块的信息。如果你试图用模块的地址反汇编代码,gdb很有可能会<BR>报告“不能访问xxxx处的内存(Cannot&nbsp;access&nbsp;memory&nbsp;at&nbsp;xxxx)”。基于同样的原因<BR>,你不查看属于模块的数据项。如果你知道你的变量的地址,你可以从/dev/mem中读出<BR>它的值,但很难弄明白从系统内存中分解出的数据是什么含义。<BR>&nbsp;<BR>如果你需要反汇编模块函数,你最好对用objdump工具处理你的模块文件。很不幸,该工<BR>具只能对磁盘上的文件进行处理,而不能对运行中的模块进行处理;因此,objdump中给<BR>出的地址都是未经重定位的地<BR>--<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>或是“检查指令”(x/i)命令反汇编函数。disassemble命令的参数可以是函数名或是<BR>内存区范围,而x/i则使用一个内存地址做为参数,也可以用符号名。例如,你可以用x/<BR>20i反汇编20条指令。注意,你不能反汇编一个模块的函数,这是因为调试器处理vmlinu<BR>x,它并不知道你的模块的信息。如果你试图用模块的地址反汇编代码,gdb很有可能会<BR>报告“不能访问xxxx处的内存(Cannot&nbsp;access&nbsp;memory&nbsp;at&nbsp;xxxx)”。基于同样的原因<BR>,你不查看属于模块的数据项。如果你知道你的变量的地址,你可以从/dev/mem中读出<BR>它的值,但很难弄明白从系统内存中分解出的数据是什么含义。<BR>&nbsp;<BR>如果你需要反汇编模块函数,你最好对用objdump工具处理你的模块文件。很不幸,该工<BR>具只能对磁盘上的文件进行处理,而不能对运行中的模块进行处理;因此,objdump中给<BR>出的地址都是未经重定位的地<BR>--<BR><FONT 
      color=#00ff00>※&nbsp;来源:.华南网木棉站&nbsp;bbs.gznet.edu.cn.[FROM:&nbsp;202.38.196.234]</FONT><BR>--<BR><FONT 
      color=#00ffff>※&nbsp;转寄:.华南网木棉站&nbsp;bbs.gznet.edu.cn.[FROM:&nbsp;211.80.41.106]</FONT><BR>--<BR><FONT 
      color=#0000ff>※&nbsp;转寄:.华南网木棉站&nbsp;bbs.gznet.edu.cn.[FROM:&nbsp;211.80.41.106]</FONT><BR>--<BR><FONT 
      color=#ffff00>※&nbsp;转载:.南京大学小百合站&nbsp;bbs.nju.edu.cn.[FROM:&nbsp;211.80.41.106]</FONT><BR>--<BR><FONT 
      color=#ff0000>※&nbsp;转载:·饮水思源&nbsp;bbs.sjtu.edu.cn·[FROM:&nbsp;211.80.41.106]</FONT><BR></P></FONT>
      <P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT 
      color=#ffffff size=2>目录页</FONT></A> | <A 
      href="http://joyfire.net/lsdp/5.htm"><FONT color=#ffffff 
      size=2>上一页</FONT></A> | <A href="http://joyfire.net/lsdp/7.htm"><FONT 
      color=#ffffff size=2>下一页</FONT></A></P></SPAN></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>
  <TBODY>
  <TR>
    <TD colSpan=3 height=2>
      <TABLE cellSpacing=0 cellPadding=0 width="100%" bgColor=#666666 
        border=0><TBODY>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -