【转】定位oops的具体代码行

最近在学写linux驱动,按照宋宝华的《linux设备驱动开发详解》上的例子一步步来写。编译运行以后出现oops,不知道怎么调试,上网搜了一下,看到这篇文章,感觉不错转载到这里。
来自Linus Torvalds的讨论:
https://groups.google.com/group/linux.kernel/browse_thread/thread/b70bffe9015a8c41/ed9c0a0cfcd31111
例如这样的一个Oops:
Oops: 0000 [#1] PREEMPT SMP  
                Modules linked in: capidrv kernelcapi isdn slhc ipv6 loop dm_multipath snd_ens1371 gameport snd_rawmidi snd_ac97_codec ac97_bus s nd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd parport_pc floppy parport pcnet32 soundcore mii pcspkr snd_page_alloc ac i2c_piix4 i2c_core button power_supply sr_mod sg cdrom ata_piix libata dm_snapshot dm_zero dm_mirror dm_mod BusLogic sd_mod scsi_mod ext3 jbd mbcache uhci_hcd ohci_hcd ehci_hcd
Pid: 1726, comm: kstopmachine Not tainted (2.6.24-rc3-module #2)
                EIP: 0060:[<c04e53d6>] EFLAGS: 00010092 CPU: 0
                EIP is at list_del+0xa/0x61
                EAX: e0c3cc04 EBX: 00000020 ECX: 0000000e EDX: dec62000
                ESI: df6e8f08 EDI: 000006bf EBP: dec62fb4 ESP: dec62fa4
                 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 
                Process kstopmachine (pid: 1726, ti=dec62000 task=df8d2d40 task.ti=dec62000)
                Stack: 000006bf dec62fb4 c04276c7 00000020 dec62fbc c044ab4c dec62fd0 c045336c 
                       df6e8f08 c04532b4 00000000 dec62fe0 c043deb0 c043de75 00000000 00000000 
                       c0405cdf df6e8eb4 00000000 00000000 00000000 00000000 00000000 
                Call Trace:
                 [<c0406081>] show_trace_log_lvl+0x1a/0x2f
                 [<c0406131>] show_stack_log_lvl+0x9b/0xa3
                 [<c04061dc>] show_registers+0xa3/0x1df
                 [<c0406437>] die+0x11f/0x200
                 [<c0613cba>] do_page_fault+0x533/0x61a
                 [<c06123ea>] error_code+0x72/0x78
                 [<c044ab4c>] __unlink_module+0xb/0xf
                 [<c045336c>] do_stop+0xb8/0x108
                 [<c043deb0>] kthread+0x3b/0x63
                 [<c0405cdf>] kernel_thread_helper+0x7/0x10
                 =======================
                Code: 6b c0 e8 2e 7e f6 ff e8 d1 16 f2 ff b8 01 00 00 00 e8 aa 1c f4 ff 89 d8 83 c4 10 5b 5d c3 90 90 90 55 89 e5 53 83 ec 0c 8b 48 04 <8b> 11 39 c2 74 18 89 54 24 08 89 44 24 04 c7 04 24 be 32 6b c0  
                EIP: [<c04e53d6>] list_del+0xa/0x61 SS:ESP 0068:dec62fa4
                note: kstopmachine[1726] exited with preempt_count 1

1, 有自己编译的vmlinux: 使用gdb
 编译时打开complie with debug info选项。 
注意这行: 
EIP is at list_del+0xa/0x61
 这告诉我们,list_del函数有0x61这么大,而Oops发生在0xa处。 那么我们先看一下list_del从哪里开始:                
          # grep list_del /boot/System.map-2.6.24-rc3-module
                c10e5234 T plist_del
                c10e53cc T list_del
                c120feb6 T klist_del
                c12d6d34 r __ksymtab_list_del
                c12dadfc r __ksymtab_klist_del
                c12e1abd r __kstrtab_list_del
                c12e9d03 r __kstrtab_klist_del
 于是我们知道,发生Oops时的EIP值是:
       c10e53cc + 0xa  == c10e53d6
           然后用gdb查看:
           # gdb /home/arc/build/linux-2.6/vmlinux
                (gdb) b *0xc10e53d6
                Breakpoint 1 at 0xc10e53d6: file /usr/src/linux-2.6.24-rc3/lib/list_debug.c, line 64.
           看,gdb直接就告诉你在哪个文件、哪一行了。
           gdb中还可以这样:
                # gdb Sources/linux-2.6.24/vmlinux
                (gdb) l *do_fork+0x1f
                0xc102b7ac is in do_fork (kernel/fork.c:1385).
                1380
                1381    static int fork_traceflag(unsigned clone_flags)
                1382    {
                1383            if (clone_flags & CLONE_UNTRACED)
                1384                    return 0;
                1385            else if (clone_flags & CLONE_VFORK) {
                1386                    if (current->ptrace & PT_TRACE_VFORK)
                1387                            return PTRACE_EVENT_VFORK;
                1388            } else if ((clone_flags & CSIGNAL) != SIGCHLD) {
                1389                    if (current->ptrace & PT_TRACE_CLONE)
                (gdb)
            也可以直接知道line number。
            或者:
                (gdb) l *(0xffffffff8023eaf0 + 0xff)  /* 出错函数的地址加上偏移 */
2, 没有自己编译的vmlinux: TIPS
           如果在lkml或bugzilla上看到一个Oops,而自己不能重现,那就只能反汇编以"Code:"开始的行。 这样可以尝试定位到
           源代码中。

           注意,Oops中的Code:行,会把导致Oops的第一条指令,也就是EIP的值的第一个字节, 用尖括号<>括起来。 但是,有些
           体系结构(例如常见的x86)指令是不等长的(不一样的指令可能有不一样的长度),所以要不断的尝试(trial-and-error)。

           Linus通常使用一个小程序,类似这样:

                const char array[] = "\xnn\xnn\xnn...";
                int main(int argc, char *argv[])
                {
                        printf("%p\n", array);
                        *(int *)0 = 0;
                }

e.g. /*{{{*/ /* 注意, array一共有从array[0]到array[64]这65个元素, 其中出错的那个操作码<8b> == arry[43] */
#include <stdio.h>
#include <stdlib.h>


const char array[] ="\x6b\xc0\xe8\x2e\x7e\xf6\xff\xe8\xd1\x16\xf2\xff\xb8\x01\x00\x00\x00\xe8\xaa\x1c\xf4\xff\x89\xd8\x83\xc4\x10\x5b\x5d\xc3\x90\x90\x90\x55\x89\xe5\x53\x83\xec\x0c\x8b\x48\x04\x8b\x11\x39\xc2\x74\x18\x89\x54\x24\x08\x89\x44\x24\x04\xc7\x04\x24\xbe\x32\x6b\xc0";
int main(int argc, char *argv[])
{
        printf("%p\n", array);
        *(int *)0 = 0;
}
/*}}}*/



           用gcc -g编译,在gdb里运行它:

                [arc@dhcp-cbjs05-218-251 ~]$ gdb hello
                GNU gdb Fedora (6.8-1.fc9)
                Copyright (C) 2008 Free Software Foundation, Inc.
                License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
                This is free software: you are free to change and redistribute it.
                There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
                and "show warranty" for details.
                This GDB was configured as "x86_64-redhat-linux-gnu"...
                (no debugging symbols found)
                (gdb) r
                Starting program: /home/arc/hello
                0x80484e0

                Program received signal SIGSEGV, Segmentation fault.

           注意,这时候就可以反汇编0x80484e0这个地址:

                (gdb) disassemble 0x80484e0
                Dump of assembler code for function array:
                0x080484e0 <array+0>:   imul   $0xffffffe8,%eax,%eax
                0x080484e3 <array+3>:   jle,pn 0x80484dc <__dso_handle+20>
                0x080484e6 <array+6>:   ljmp   *<internal disassembler error>
                0x080484e8 <array+8>:   rcll   (%esi)
                0x080484ea <array+10>:  repnz (bad)
                0x080484ec <array+12>:  mov    $0x1,%eax
                0x080484f1 <array+17>:  call   0x7f8a1a0
                0x080484f6 <array+22>:  mov    %ebx,%eax
                0x080484f8 <array+24>:  add    $0x10,%esp
                0x080484fb <array+27>:  pop    %ebx
                0x080484fc <array+28>:  pop    %ebp
                0x080484fd <array+29>:  ret
                0x080484fe <array+30>:  nop
                0x080484ff <array+31>:  nop
                0x08048500 <array+32>:  nop
                0x08048501 <array+33>:  push   %ebp
                0x08048502 <array+34>:  mov    %esp,%ebp
                0x08048504 <array+36>:  push   %ebx
                0x08048505 <array+37>:  sub    $0xc,%esp
                0x08048508 <array+40>:  mov    0x4(%eax),%ecx
                0x0804850b <array+43>:  mov    (%ecx),%edx
                0x0804850d <array+45>:  cmp    %eax,%edx
                0x0804850f <array+47>:  je     0x8048529
                0x08048511 <array+49>:  mov    %edx,0x8(%esp)
                0x08048515 <array+53>:  mov    %eax,0x4(%esp)
                0x08048519 <array+57>:  movl   $0xc06b32be,(%esp)
                0x08048520 <array+64>:  add    %ah,0xa70
                End of assembler dump.
                (gdb)

          OK, 现在你知道出错的那条指令是array[43],也就是mov    (%ecx),%edx,也就是说,(%ecx)指向了一个错误内存地址。

补充:

为了使汇编代码和C代码更好的对应起来, Linux内核的Kbuild子系统提供了这样一个功能: 任何一个C文件都可以单独编译成汇编文件,例如:

make path/to/the/sourcefile.s

例如我想把kernel/sched.c编译成汇编,那么:

make kernel/sched.s V=1

或者:

make kernel/sched.lst V=1

         编译出*.s文件
           
           有时侯需要对*.s文件进行分析,以确定BUG所在的位置。 对任何一个内核build目录下的*.c文件,都可以
           直接编译出*.s文件。

                   # make drivers/net/e100.s V=1
           
           而对于自己写的module,就需要在Makefile中有一个灵活的target写法:
                   
                # cat Makefile
                obj-m := usb-skel.o
                KDIR := /lib/modules/`uname -r`/build
                traget := modules

                default:
                        make -C $(KDIR) M=$(shell pwd) $(target)
                clean:
                        rm -f *.o *.ko .*.cmd *.symvers *.mod.c
                        rm -rf .tmp_versions


                # make target=usb-skel.s V=1
           
           这样,kbuild系统才知道你要make的目标不是modules,而是usb-skel.s。




另外, 内核源代码目录的./scripts/decodecode文件是用来解码Oops的:

./scripts/decodecode < Oops.txt
(我没用过,就只提一下。)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/297852.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Dapr牵手.NET学习笔记:用docker-compose部署服务

上一篇聊到用两个物理机&#xff08;一个win,一个mac&#xff09;来部署dapr和服务 &#xff0c;实现order调用pay的负载均衡。本篇说一下在windows上的docker部署这三个服务&#xff0c;达到与上一篇的效果。三个服务的部署架构是这样的首先要把OrderSystem(服务端口80)项目do…

Java并发编程实战_真香!阿里P8耗时半年著作660页Java高并发与网络编程实战总结...

随着软件行业的飞速发展&#xff0c;互联网公司对开发者的技能要求也越来越高。而高并发、网络编程、微服务、海量数据的处理等技能&#xff0c;是每一个开发者进阶时的必学知识。为了帮助初级开发者快速掌握这些实用技术&#xff0c;本书以“理论&#xff0b;范例”的形式对各…

oracle如何往dg加盘_oracle 在物理机上添加磁盘操作

物理机上添加磁盘操作注意&#xff1a;1)物理机上添加磁盘操作&#xff0c;不涉及到start_udev的动作。2)磁盘分区的操作&#xff0c;需要谨慎进行&#xff0c;核准无误后再操作。(1)查看磁盘名称命名# su - grid$ sqlplus / as sysasmset linesize 180col name format a20col …

【译】在Asp.Net中操作PDF – iTextSharp - 使用表格

使用Asp.Net生成PDF最常用的元素应该是表格&#xff0c;表格可以帮助比如订单或者发票类型的文档更加格式化和美观。本篇文章并不会深入探讨表格&#xff0c;仅仅是提供一个使用iTextSharp生成表格的方法介绍&#xff0c;本文需要阅读我之前iTextSharp系列文章作为基础&#xf…

linux docker导入镜像,Docker镜像的导入和导出

相关阅读&#xff1a;场景描述&#xff1a;需要在客户现场快速部署应用&#xff0c;东西多&#xff0c;时间短场景分析&#xff1a;为了节省时间&#xff0c;使用docker进行快速部署&#xff0c;由于不是内部环境&#xff0c;无法使用内部私有库&#xff0c;于是构建镜像&#…

有些图,只要看错一眼就再也回不去了!

全世界只有3.14 % 的人关注了爆炸吧知识平时在网络上逛&#xff0c;你会发现有种图片&#xff0c;一旦看茬&#xff0c;就再也回不去了&#xff01;今天就来集体复习一下&#xff1a;首先是这张著名的图&#xff0c;很可爱的小盆友但如果告诉你&#xff1a;那两个大黑点是鼻孔&…

2015年网页设计最佳颜色搭配的9种选择

2019独角兽企业重金招聘Python工程师标准>>> 2015年网页设计最佳颜色搭配的9种选择 还在为你的网站选用哪种色调发愁&#xff0c;难易选择吗&#xff1f;本篇为你总结了2015年国外网友设计最佳颜色搭配的9个方案&#xff0c;供你参考... 详细解读 和小伙伴们一起来吐…

CryEngine

最近CryEngine3已经发布了&#xff08;实际上已经到3.1了&#xff09;&#xff0c;看到很多朋友都想要拿到最新的版本&#xff0c;在这里附上具体的申请方法。楼主看到了&#xff0c;麻烦看看能不能置个顶。 CryEngine对于教育机构是有免费授权的。实际上授权也十分宽松&#x…

EF Core的一个紧急bug,我这样修改

1背景今日在生产环境碰到如下错误ASP.NET MVC项目 Repository层中&#xff0c;Delete总是失败another entity of the same type already has the same primary key value具体错误提示&#xff1a;Attaching an entity of type ResearchManager.Models.BigTracker_UI.Product_Tr…

电脑home键在哪_如何灵活使用电脑键盘上的各个键

电脑上的键有很多但是你真的了解它们的用法么&#xff0c;今天笔者给大家分享一下电脑键盘上各个键的作用。区域一&#xff1a;共有13个按键&#xff0c;ESC&#xff0c;F1-F2。F1&#xff1a;帮助信息。F2&#xff1a;选定一个文件或文件夹。按下F2可以重命名。F3&#xff1a;…

svn强制注释 linux,svn强制要求提交注释

看了N多资料&#xff0c;不知道为什么我总是不成功。现在终于测试成功了&#xff0c;下面是实际操作过程~~使用bitnami一键安装了subversion&#xff0c;在使用中&#xff0c;希望开发人员提交时必须输入日志内容&#xff0c;可通过以下方法实现。首先转到相应的库的hook目录中…

jquery easyui datagrid getSelections用法

1.datagrid、 数据绑定 $(#tt).datagrid({ url: GetDataJosn, title: DataGrid, width: 800, height: 300, pageSize: 10, idField: productid, fitColumns: true,…

XCode5 真机调试及发布应用

一、XCODE 真机测试 Xcode5已经很智能&#xff0c;只需生成一个开发证书&#xff0c;安装后&#xff0c;插入设备会自动添加&#xff0c;注意&#xff0c;当Mac系统升级后&#xff0c;证书需要重新生成。证书生成步骤&#xff1a;1、生成 CertificateSigningRequest.certSignin…

身家4400亿美元的他,吃低于3美元的早餐,和2个老婆同居28年!

全世界只有3.14 % 的人关注了爆炸吧知识1930年8月30日&#xff0c;巴菲特出生在美国内布拉斯加州的奥马哈市。当时的美国还笼罩在经济大萧条的阴影中&#xff0c;还好父亲是位出色的股票掮客&#xff0c;这也让小巴菲特的童年过得顺顺利利。但小巴同学从小就不合群&#xff0c;…

怎么才能把项目做烂?!

上一篇聊聊《为什么被用户牵着鼻子走&#xff1f;刚参加工作做项目常说的一句话&#xff1a;没有困难&#xff0c;制造困难也得上。到不是真闲得蛋疼制造困难&#xff0c;而是表达解决困难的决心。2009年在某煤炭集团做了一个动态监测煤质煤量的实时系统&#xff0c;当时一般为…

电脑重新分区扩大c盘_两种方法,给电脑C盘增加10G的容量,电脑焕然一新

在我们日常的生活工作中&#xff0c;手机电脑已经成为了不可或缺的存在。然而当我们的手机电脑经过长年累月的使用之后&#xff0c;手机电脑都会变得很卡&#xff0c;在电脑上最直观的显示就是电脑C盘分区显示为红色&#xff0c;可用空间已经不够用了。我们知道&#xff0c;电脑…

python wx提示框字体_使用wxStyledTextCtrl实现代码提示

wxStyledTextCtrl是wxPython对流行的Scintilla的包装&#xff0c;Scintilla的网站(http://www.scintilla.org/)&#xff0c;wxStyledTextCtrl是一个功能强大的富文本编辑控件&#xff0c;常见的编辑器功能都能找到&#xff0c;包括代码高亮&#xff0c;搜索替换&#xff0c;拷贝…

PHP5中PDO的简单使用

PDO(PHP Data Object) 是PHP 5新出来的东西&#xff0c;在PHP 6都要出来的时候&#xff0c;PHP 6只默认使用PDO来处理数据库&#xff0c;将把所有的数据库扩展移到了PECL&#xff0c;那么默认就是没有了我们喜爱的php_mysql.dll之类的了&#xff0c;那怎么办捏&#xff0c;我们…

redis在linux搭建集群,Linux/Centos 7 redis4 集群搭建

背景说明&#xff1a;项目初期使用AWS的ElastiCache Redis作为系统的数据缓存&#xff0c;近期由于数据量和QPS加大&#xff0c;导致Redis存在压力&#xff0c;进行了两次的单点垂直升级&#xff0c;缓解了目前的压力。项目组进行了数据和费用的评估&#xff0c;考虑到日后升级…

远程控制

我和舍友共用ADSL&#xff0c;我的电脑接在宽带路由器上面。为了能远程控制家里的电脑&#xff0c;我是煞费苦心&#xff0c;最后终于OK了&#xff0c;把一些经验心得写出来。 首先想要远程登录的机器最好是WinXP或者Win2003(据说Win2003更好一些&#xff0c;可以多用户同时登…