根据PANIC信息定位内核代码位置

首先Linux内核需要打开编译的调试选项CONFIG_DEBUG_INFO,如下:

Kernel hacking --->
    [*] Kernel debugging
    [*] Compile the kernel with debug info

这样,内核在编译之后的目标文件带有调试信息。检查内核的Makefile文件,打开CONFIG_DEBUG_INFO选项之后,内核为KBUILD_CFLAGS变量添加了-g的调试选项。

ifdef CONFIG_DEBUG_INFO
KBUILD_CFLAGS   += -g
KBUILD_AFLAGS   += -gdwarf-2
endif

比如有如下的panic信息,指令指针IP的绝对位置在ffffffff8196f70c,相对位置在函数ip_local_deliver_finish开始的位置偏移0x1c,另外0x100为此函数的结束位置。

[  266.469971] BUG: unable to handle kernel NULL pointer dereference at 00000000000004a0
[  266.470020] IP: [<ffffffff8196f70c>] ip_local_deliver_finish+0x1c/0x100
[  266.470020] PGD ad37a067 PUD ad37b067 PMD 0 
[  266.470020] Oops: 0000 [#1] SMP 
[  266.470020] CPU: 1 PID: 238 Comm: initXXXXXXXXXXX Not tainted 3.10.0 #1
[  266.470020] Hardware name: To Be Filled By O.E.M. To Be Filled By O.E.M./G6LD525 VER2, BIOS 080016  07/24/2015
[  266.470020] task: ffff88007f8b3b80 ti: ffff88009dae4000 task.ti: ffff88009dae4000
[  266.470020] RIP: 0010:[<ffffffff8196f70c>]  [<ffffffff8196f70c>] ip_local_deliver_finish+0x1c/0x100
[  266.470020] RSP: 0018:ffff88009dae7c98  EFLAGS: 00010206

查看内核代码可知,ip_local_deliver_finish函数位于文件net/ipv4/ip_input.c中。使用objdump工具反编译此文件的目标文件:

# objdump -DSl net/ipv4/ip_input.o

如下为反编译内容,此处使用panic信息中的相对位置定位出问题的代码位置:

ip_input.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <ip_local_deliver_finish>:
ip_local_deliver_finish():
/linux-3.10.0/net/ipv4/ip_input.c:198
   0:   e8 00 00 00 00          callq  5 <ip_local_deliver_finish+0x5>
   5:   55                      push   %rbp
   6:   48 89 e5                mov    %rsp,%rbp
   9:   41 55                   push   %r13
   b:   41 54                   push   %r12
   d:   49 89 f4                mov    %rsi,%r12
  10:   53                      push   %rbx
/linux-3.10.0/include/linux/netdevice.h:2058
  11:   48 8b 46 20             mov    0x20(%rsi),%rax
skb_network_header_len():
/linux-3.10.0/include/linux/skbuff.h:2095
  15:   0f b7 96 4e 01 00 00    movzwl 0x14e(%rsi),%edx
ip_local_deliver_finish():
/linux-3.10.0/include/linux/netdevice.h:2058
  1c:   4c 8b a8 a0 04 00 00    mov    0x4a0(%rax),%r13
skb_network_header_len():


  fd:   00 00 00

0000000000000100 <ip_rcv_finish>:

函数ip_local_deliver_finish的起始位置为0000000000000000,加上偏移0x1c,可知出错位置在文件include/linux/netdevice.h的2058行,而此netdevice.h中的函数有net/ipv4/ip_input.c的198行调用而来,看以下代码:

net/ipv4/ip_input.c:
196 static int ip_local_deliver_finish(struct sock *sk, struct sk_buff *skb)
197 {
198     struct net *net = dev_net(skb->dev);

include/linux/netdevice.h:
2055 static inline
2056 struct net *dev_net(const struct net_device *dev)
2057 {
2058     return read_pnet(&dev->nd_net);
2059 }

可知,问题出在dev_net函数中,读取的dev的成员nd_net为非法值
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

有一个问题时,以上objdump反汇编的代码没有插进去c代码。于是,写了一个hello world的测试程序,使用gcc -g编译后,再用objdump反汇编,还是可以看到插入的C代码的。内核只能看到行号,感觉应该是-O2优化的影响导致,还不确定。


# gcc -g main.c
# objdump -DSl a.out

结果如下:

 320 int main()
 321 {
 322   40052d:   55                      push   %rbp
 323   40052e:   48 89 e5                mov    %rsp,%rbp
 324 main.c:8
 325     printf("hello world!\n");
 326   400531:   bf d4 05 40 00          mov    $0x4005d4,%edi
 327   400536:   e8 d5 fe ff ff          callq  400410 <puts@plt>
 328 /home/kzhang/firewall_tc_2.0.0/root/1ksa0b/linux-3.10.0/main.c:10
 329 }

完。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值