根据内核Oops 定位代码工具使用— addr2line 、gdb、objdump

(这三种工具都在out/host/linux-x86目录下)

内核开发时有时候出现Oops,例如一个野指针会导致内核崩溃,如运行时出现以下log:现在有三种方法可以找出具体出现野指针的地方

  1.    5.438972] bells bells:  wm5102-aif1 <-> samsung-i2s.0 mapping ok  
  2. [    5.443812] bells bells: Failed to add route OPCLK->Sub CLK_SYS  
  3. [    5.450499] Unable to handle kernel NULL pointer dereference at virtual address 00000010  
  4. [    5.457770] pgd = c0004000  
  5. [    5.460504] [00000010] *pgd=00000000  
  6. [    5.463959] Internal error: Oops: 5 [#1] PREEMPT SMP ARM  
  7. [    5.469249] CPU: 3    Not tainted  (3.4.5-g092c4c5 #75)  
  8. [    5.474457] PC is at snd_soc_dai_set_sysclk+0x10/0x84</span>  
  9. [    5.479481] LR is at bells_late_probe+0x60/0x198  
  10. [    5.484133]<span style="color:#FFCC33;"> pc : [<c040faa0>]</span>    lr : [<c0424030>]    psr: 60000013  
  11. [    5.484139] sp : d683bd58  ip : d683bd80  fp : d683bd7c  
  12. [    5.495579] r10: 00000000  r9 : c08a41f8  r8 : 00000000  
  13. [    5.500723] r7 : d62bf400  r6 : 00000000  r5 : d69ab800  r4 : 00000000  
  14. [    5.507284] r3 : 00000000  r2 : 00000000  r1 : 00000002  r0 : 00000000  
  15. [    5.513731] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel  
  16. [    5.521074] Control: 10c5387d  Table: 4000406a  DAC: 00000015  
  17. [    5.526799]   
  18. [    5.526802] PC: 0xc040fa20:  
   5.438972] bells bells:  wm5102-aif1 <-> samsung-i2s.0 mapping ok
[    5.443812] bells bells: Failed to add route OPCLK->Sub CLK_SYS
[    5.450499] Unable to handle kernel NULL pointer dereference at virtual address 00000010
[    5.457770] pgd = c0004000
[    5.460504] [00000010] *pgd=00000000
[    5.463959] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
[    5.469249] CPU: 3    Not tainted  (3.4.5-g092c4c5 #75)
[    5.474457] PC is at snd_soc_dai_set_sysclk+0x10/0x84
[    5.479481] LR is at bells_late_probe+0x60/0x198
[    5.484133] pc : [<c040faa0>]    lr : [<c0424030>]    psr: 60000013
[    5.484139] sp : d683bd58  ip : d683bd80  fp : d683bd7c
[    5.495579] r10: 00000000  r9 : c08a41f8  r8 : 00000000
[    5.500723] r7 : d62bf400  r6 : 00000000  r5 : d69ab800  r4 : 00000000
[    5.507284] r3 : 00000000  r2 : 00000000  r1 : 00000002  r0 : 00000000
[    5.513731] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
[    5.521074] Control: 10c5387d  Table: 4000406a  DAC: 00000015
[    5.526799] 
[    5.526802] PC: 0xc040fa20:
0 直接通过addr2line命令获取,例如:

$ arm-none-linux-gnueabi-addr2line -e vmlinux c040faa0   //跟上出错时pc指针位置

注:请确保CROSS_COMPILE跟你编译用的是一样的前缀,例如上面的arm-none-Linux-gnueabi-,你编译时也必须是这个,不然算出来的行号可能会偏差比较大。

addr2line 代码如下

  1. #!/bin/bash  
  2. #  
  3. # addr2line.sh -- Convert PC address to source code line, open the file and point to the line  
  4. #  
  5.   
  6. ADDR=$1  
  7. [ -z "$ADDR" ] && echo -e "Usage: Please specify the PC address\n    $0 PC_ADDR" && exit 1  
  8. [ -z "$CROSS_COMPILE" ] && CROSS_COMPILE=arm-none-linux-gnueabi-  
  9.   
  10. ADDR2LINE=${CROSS_COMPILE}addr2line  
  11. file_line=`$ADDR2LINE -e vmlinux $ADDR`  
  12. if [ "$file_line" == "??:0" ]; then  
  13.     echo "ERROR: Can not find the line for $ADDR"  
  14.     exit 2  
  15. else  
  16.     vim -c "set number" -c "set fdm=manual" $(echo $file_line | sed -e "s/:/ +/g")  
  17. fi  
#!/bin/bash
#
# addr2line.sh -- Convert PC address to source code line, open the file and point to the line
#

ADDR=$1
[ -z "$ADDR" ] && echo -e "Usage: Please specify the PC address\n    $0 PC_ADDR" && exit 1
[ -z "$CROSS_COMPILE" ] && CROSS_COMPILE=arm-none-linux-gnueabi-

ADDR2LINE=${CROSS_COMPILE}addr2line
file_line=`$ADDR2LINE -e vmlinux $ADDR`
if [ "$file_line" == "??:0" ]; then
	echo "ERROR: Can not find the line for $ADDR"
	exit 2
else
	vim -c "set number" -c "set fdm=manual" $(echo $file_line | sed -e "s/:/ +/g")
fi

1 通过gdb定位
1.1 首先运行gdb,不过需要使用出错内核的vmlinux
执行
 $ arm-linux-gnueabi-gdb vmlinux 


1.2 设置断点,即上面log信息中的用黄色重点标记的pc地址
执行 (gdb) b*0xc040faa0
Breakpoint 1 at 0xc040faa0: file sound/soc/soc-core.c, line 1070.
此时,我们知道了在 sound/soc/soc-core.c文件的1070行出错,这下我们就锁定了范围,具体解决了;
1.3 如果你不想再另打开一个窗口去看该函数,也可以直接在当前窗口查看该函数
(gdb) set listsize 50(设置显示50行的内容)
(gdb) list *0xc040faa0(查看显示的内容)
 
2 根据查询内核符号表和反汇编信息定位,它可以不依赖出错内核的vmlinux
2.1 根据上面红色标记的log信息,PC is at snd_soc_dai_set_sysclk+0x10/0x84
0x10:表示出错的偏移位置,0x84表示snd_soc_dai_set_sysclk函数的大小
2.2 现在就是找到snd_soc_dai_set_sysclk函数的位置,
$ arm-linux-gnueabi-nm vmlinux | grep snd_soc_dai_set_sysclk
c04116bc T snd_soc_dai_set_sysclk 


$ arm-linux-gnueabi-objdump -S vmlinux –start-address=0xc04116bc –stop-address=0xc04116bc > ~/temp/soc


 2.3 接下来就去查看vim ~/temp/soc文件, 找到0xc04116bc+0x10的位置即可
内核可以使用addr2line工具来进行调试。这个工具可以将地址转换为对应的源代码行号。当我们在内核中遇到崩溃或错误时,可以使用addr2line来找到代码中出问题的位置。 使用addr2line的步骤如下: 1. 首先,需要编译内核时打开CONFIG_DEBUG_INFO选项。这样编译出的内核会包含调试符号信息。 2. 在发生错误或崩溃的设备上,获取对应的内核转储文件(vmlinux)。如果没有vmlinux文件,可以使用相同版本的内核代码重新编译内核。 3. 在命令行中执行addr2line命令,将错误的地址作为参数传递给它。比如:addr2line -e vmlinux 0xaddress 这将会返回对应地址的源代码文件和行号信息。 通过这个方式,我们可以根据地址找到对应的源代码行号,从而更好地理解和调试内核中的问题。 [2 [3123 #### 引用[.reference_title] - *1* [Linux使用addr2line工具定位内核崩溃(oops)代码位置](https://blog.csdn.net/weixin_42262944/article/details/120235491)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *2* *3* [linux内核调试技巧之addr2line](https://blog.csdn.net/weixin_36300275/article/details/116649108)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值