Linux Vmlinux反汇编操作和 oops stack 回朔分析

free-jdx 2020-11-13 14:17:48 10543
1. Linux Vmlinux反汇编操作和代码分析
1.1 对vmlinx反汇编

arm-linux-gnueabi-objdump -d vmlinux > debug.s

1.2 debug.s代码段分析
vmlinux:     file format elf32-littlearm
Disassembly of section .head.text:
内核地址      汇编对应的机器码   汇编指令        
c0008000 <stext>:   
//ARM在链接脚本里面,指定了内核的入口是stext
//在vmlinux.lds指定了ENTRY(stext) ,然后. = 0xC0000000 +0x00008000;
// .head.text :...,所以执行地址是内核地址0xc0008000
c0008000:       e10f9000        mrs r9, CPSR
c0008004:       e229901a        eor r9, r9, #26
c0008008:       e319001f        tst r9, #31
c000800c:       e3c9901f        bic r9, r9, #31
c0008010:       e38990d3        orr r9, r9, #211    ; 0xd3
c0008014:       1a000004        bne c000802c <stext+0x2c>
c0008018:       e3899c01        orr r9, r9, #256    ; 0x100
c000801c:       e28fe00c        add lr, pc, #12

下面这段是函数代码段,当我们把一个函数编译进内核(有系统)的时候,系统加载器会自动帮我们分配执行地址,如下面的c0008084,当内核调用这个函数的时候,根据函数名称就能找到对应的地址并执行

c0008084 <__create_page_tables>:
c0008084:   e2884901    add r4, r8, #16384  ; 0x4000
c0008088:   e1a00004    mov r0, r4
c000808c:   e3a03000    mov r3, #0
c0008090:   e2806901    add r6, r0, #16384  ; 0x4000
c0008094:   e4803004    str r3, [r0], #4
c0008098:   e4803004    str r3, [r0], #4
c000809c:   e4803004    str r3, [r0], #4

说明:那么我们得到这个反汇编的文件后有什么用处呢?下面结合oops栈回溯来介绍

2. oops 栈回朔分析
2.1 oops是什么?

这里,我们要理解一下oops是什么?oops语义上类似于惊讶,也类似于拟声词,像”哎呦”,所以对于程序来说,就如“哎呦,出错了!”,然后把出错的地址,各个寄存器的值等等打印出来。
首先,我们根据内核打印信息的段错误信息来分析,例子如下:

Unable to handle kernel paging request at virtual address 56000050
//内核使用56000050来访问时发生了错误
pgd = c3eb0000
[56000050] *pgd=00000000
Internal error: Oops: 5 [#1]    
//5表示错误代码,#1表示这个错误发生一次
Modules linked in: first_drv
// 在哪个模块出错
CPU: 0    Not tainted  (2.6.22.6 #1)
// 发生错误的CPU序号
   PC is at first_drv_open+0x18(该指令的偏移)/0x3c(该函数的总大小) [first_drv]
// 出错函函数,PC就是发生错误的指令的地址 
LR is at chrdev_open+0x14c/0x164
// LR寄存器的值,错误函数的栈返回地址
pc = 0xbf000018
// 出错时各个寄存器的值
pc : [<bf000018>]    lr : [<c008d888>]    psr: a0000013
sp : c3c7be88  ip : c3c7be98  fp : c3c7be94
r10: 00000000  r9 : c3c7a000  r8 : c049abc0
r7 : 00000000  r6 : 00000000  r5 : c3e740c0  r4 : c06d41e0
r3 : bf000000   r2 : 56000050  r1 : bf000964  r0 : 00000000
// 执行这条导致错误的指令时各个寄存器的值
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  Segment user
Control: c000717f  Table: 33eb0000  DAC: 00000015
Process firstdrvtest (pid: 777, stack limit = 0xc3c7a258)
//发生错误时当前进程的名称是firstdrvtest
栈
Stack: (0xc3c7be88 to 0xc3c7c000)
be80:            c3c7bebc c3c7be98 c008d888 bf000010 00000000 c049abc0
bea0:c3e740c0 c008d73c c0474e20 c3e766a8 c3c7bee4 c3c7bec0 c0089e48 c008d74c
bec0: c049abc0 c3c7bf04 00000003 ffffff9c c002c044 c3d10000 c3c7befc c3c7bee8
bee0: c0089f64 c0089d58 00000000 00000002 c3c7bf68 c3c7bf00 c0089fb8 c0089f40
bf00: c3c7bf04 c3e766a8 c0474e20 00000000 00000000 c3eb1000 00000101 00000001
bf20: 00000000 c3c7a000 c04a7468 c04a7460 ffffffe8 c3d10000 c3c7bf68 c3c7bf48
bf40: c008a16c c009fc70 00000003 00000000 c049abc0 00000002 bec1fee0 c3c7bf94
bf60: c3c7bf6c c008a2f4 c0089f88 00008520 bec1fed4 0000860c 00008670 00000005
bf80: c002c044 4013365c c3c7bfa4 c3c7bf98 c008a3a8 c008a2b0 00000000 c3c7bfa8
bfa0: c002bea0 c008a394 bec1fed4 0000860c 00008720 00000002 bec1fee0 00000001
bfc0: bec1fed4 0000860c 00008670 00000002 00008520 00000000 4013365c bec1fea8
bfe0: 00000000 bec1fe84 0000266c 400c98e0 60000010 00008720 00000000 00000000

Backtrace: (回溯)
// 在内核里面,选中FRAME_POINTER ,出错时才会打印出这些消息

[<bf000000>](first_drv_open+0x0/0x3c[first_drv])from[<c008d888>]    (chrdev_open+0x14c/0x164)
[<c008d73c>] (chrdev_open+0x0/0x164) from [<c0089e48>] (__dentry_open+0x100/0x1e8)
r8:c3e766a8 r7:c0474e20 r6:c008d73c r5:c3e740c0 r4:c049abc0
[<c0089d48>] (__dentry_open+0x0/0x1e8) from [<c0089f64>] (nameidata_to_filp+0x34/0x48)
[<c0089f30>] (nameidata_to_filp+0x0/0x48) from [<c0089fb8>] (do_filp_open+0x40/0x48)
r4:00000002
[<c0089f78>] (do_filp_open+0x0/0x48) from [<c008a2f4>] (do_sys_open+0x54/0xe4)
r5:bec1fee0 r4:00000002
[<c008a2a0>] (do_sys_open+0x0/0xe4) from [<c008a3a8>] (sys_open+0x24/0x28)
[<c008a384>] (sys_open+0x0/0x28) from [<c002bea0>] (ret_fast_syscall+0x0/0x2c)
Code: e24cb004 e59f1024 e3a00000 e5912000 (e5923000)
Segmentation fault  
2.2 oops调试步骤

根据上面的回朔信息,我们可以如下调试:
(1) 根据pc值,查看出错的地址是在内核还是在insmod 加载的驱动在内核里面,执行 cat System.map 查看内核的地址范围

(2) 查看内核函数,加载函数的地址
cat /proc/kallsyms > xx.text 这个xx.text里面,现在就有各个函数里面的地址根据pc值,找出一个相近的地址,这个地址<= pc值,找到 bf000000 t first_drv_open [first_drv] 出错的就是first_drv_open函数,t代是static函数

(3)反汇编

如果是在insmod加载的驱动的错误 arm-linux-objdump -D xxx.ko > xxx.dis
如果是在内核中的错误 arm-linux-objdump -D vmlinux > vmlinux.s

(4)在反汇编文件(.s)里面搜索first_drv_open

如果是内核,在内核的.dis里面查找pc值,例如

c014e6a8 <first_drv_open>:
c014e6a8:       e1a0c00d        mov     ip, sp 
c014e6ac:       e92dd800        stmdb   sp!, {fp, ip, lr, pc}
c014e6b0:       e24cb004        sub     fp, ip, #4      ; 0x4
c014e6b4:       e59f1024        ldr     r1, [pc, #36]   ;               c014e6e0 <.text+0x1276e0> 
c014e6b8:       e3a00000        mov     r0, #0  ; 0x0
c014e6bc:       e5912000        ldr     r2, [r1] 
c014e6c0:  e5923000   ldr  r3, [r2] // 在此出错 r2=56000050

如果是insmod加载的函数,找个first_drv_open,然后确定是哪个寄存器的值出错了。first_drv.s文件insmod后

00000000 <first_drv_open>:                 
bf000000 t first_drv_open     [first_drv]
00000018        
pc = bf000018

这里的00000018 就是.s出错的地址,后面有汇编代码,可以确定是哪个寄存器,根据上面寄存器的值,就可以得出哪里出错。

声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
free-jdx
红包 3114 52 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
free-jdx
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区