linux 内核开启调试选项

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

嵌入式 linux 经常要编译 linux 内核默认情况下编译出的内核镜像是不带调试信息的这样当内核 crash 打印 PC 指针和堆栈信息时我们需要反汇编来确认出错位置不直观。
如果内核开启了调试选项我们只需要一个 addr2line 命令就可以将 PC 指针定位到 C 程序的哪个文件的哪一行非常快捷高效。
下面我们就来介绍下如何开启内核调试选项。

-g

gcc 编译应用程序时使用 -g 选项编译出带有调试信息的可执行程序。编译内核也是同样的道理。所以我们先在顶层 Makefile 中搜索 -g 选项下面是 linux-4.1.15 例子

ifdef CONFIG_DEBUG_INFO
ifdef CONFIG_DEBUG_INFO_SPLIT
KBUILD_CFLAGS   += $(call cc-option, -gsplit-dwarf, -g)
else
KBUILD_CFLAGS	+= -g
endif
KBUILD_AFLAGS	+= -Wa,-gdwarf-2
endif
ifdef CONFIG_DEBUG_INFO_DWARF4
KBUILD_CFLAGS	+= $(call cc-option, -gdwarf-4,)
endif

要想使能 -g 选项就要使能 CONFIG_DEBUG_INFO 编译选项。
make menuconfig搜索 CONFIG_DEBUG_INFO

 .config - Linux/arm 4.1.15 Kernel Configuration
 → Search (CONFIG_DEBUG_INFO) ──────────────────────────────────────────────────────────
  ┌───────────────────────────────── Search Results ─────────────────────────────────┐
  │ Symbol: DEBUG_INFO [=n]                                                          │  
  │ Type  : boolean                                                                  │  
  │ Prompt: Compile the kernel with debug info                                       │  
  │   Location:                                                                      │  
  │     -> Kernel hacking                                                            │  
  │ (1)   -> Compile-time checks and compiler options                                │  
  │   Defined at lib/Kconfig.debug:120                                               │  
  │   Depends on: DEBUG_KERNEL [=y] && !COMPILE_TEST [=n]                            │  
  │                                                                                  │  
  │                                                                                  │  
  │ Symbol: DEBUG_INFO_DWARF4 [=n]                                                   │  
  │ Type  : boolean                                                                  │  
  │ Prompt: Generate dwarf4 debuginfo                                                │  
  │   Location:                                                                      │  
  │     -> Kernel hacking                                                            │  
  │       -> Compile-time checks and compiler options                                │  
  │ (2)     -> Compile the kernel with debug info (DEBUG_INFO [=y])                  │  
  │   Defined at lib/Kconfig.debug:161                                               │  
  │   Depends on: DEBUG_INFO [=y]                                                    │  
  │                                                                                  │  
  │                                                                                  │  
  │ Symbol: DEBUG_INFO_REDUCED [=n]                                                  │  
  │ Type  : boolean                                                                  │  
  ├──────────────────────────────────────────────────────────────────────────( 51%)──┤  
  │                                     < Exit >                                     │  
  └──────────────────────────────────────────────────────────────────────────────────┘  

vim .config

3244 # CONFIG_DEBUG_INFO is not set

修改为

3244 CONFIG_DEBUG_INFO=y

检查

 .config - Linux/arm 4.1.15 Kernel Configuration
 → Search (CONFIG_DEBUG_INFO) ──────────────────────────────────────────────────────────
  ┌───────────────────────────────── Search Results ─────────────────────────────────┐
  │ Symbol: DEBUG_INFO [=y]                                                          │  
  │ Type  : boolean                                                                  │  
  │ Prompt: Compile the kernel with debug info                                       │  
  │   Location:                                                                      │  
  │     -> Kernel hacking                                                            │  
  │ (1)   -> Compile-time checks and compiler options                                │  
  │   Defined at lib/Kconfig.debug:120                                               │  
  │   Depends on: DEBUG_KERNEL [=y] && !COMPILE_TEST [=n]                            │  
  │                                                                                  │  
  │                                                                                  │  
  │ Symbol: DEBUG_INFO_DWARF4 [=n]                                                   │  
  │ Type  : boolean                                                                  │  
  │ Prompt: Generate dwarf4 debuginfo                                                │  
  │   Location:                                                                      │  
  │     -> Kernel hacking                                                            │  
  │       -> Compile-time checks and compiler options                                │  
  │ (2)     -> Compile the kernel with debug info (DEBUG_INFO [=y])                  │  
  │   Defined at lib/Kconfig.debug:161                                               │  
  │   Depends on: DEBUG_INFO [=y]                                                    │  
  │                                                                                  │  
  │                                                                                  │  
  │ Symbol: DEBUG_INFO_REDUCED [=n]                                                  │  
  │ Type  : boolean                                                                  │  
  ├──────────────────────────────────────────────────────────────────────────( 51%)──┤  
  │                                     < Exit >                                     │  
  └──────────────────────────────────────────────────────────────────────────────────┘  



看到 Symbol: DEBUG_INFO [=y] 这样 -g 编译选项就开启了。
重新编译内核然后检查镜像文件

$ file vmlinux
vmlinux: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=bfb6aefe3b6955df44222bfefc9ee5b4955f9c81, with debug_info, not stripped

看到 with debug_info这样内核镜像就带有调试信息了。后面使用 openOCD 进行硬件调试或者根据 crash 信息定位出错代码位置都是很方便的。

实例

如下图在 do_mount_root 函数中添加一个调试 BUG。
在这里插入图片描述

板子运行后报错如下

ALSA device list:
  No soundcards found.
------------[ cut here ]------------
Kernel BUG at 809c70a8 [verbose debug info unavailable]
Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.1.15 #95
Hardware name: Freescale i.MX6 Ultralite (Device Tree)
task: 88048000 ti: 8804c000 task.ti: 8804c000
PC is at do_mount_root.part.3+0x38/0x44
LR is at mntput_no_expire+0x40/0x1ec
pc : [<809c70a8>]    lr : [<80115138>]    psr: 60000113
sp : 8804df00  ip : 00000000  fp : 8804df04
r10: 8086900c  r9 : 80869154  r8 : 000003e8
r7 : 80a90024  r6 : 00000006  r5 : 80a33888  r4 : 00000005
r3 : 0000000f  r2 : 80a90024  r1 : 0b10a000  r0 : 00000000
Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c5387d  Table: 8000406a  DAC: 00000015
Process swapper/0 (pid: 1, stack limit = 0x8804c210)
Stack: (0x8804df00 to 0x8804e000)
df00: 8804df3c 809c74d4 80a1bf6c 801067e0 80a1c474 80a1bf6c 88030040 80a1aac4
df20: 80a90024 80a90000 80a1aaa0 8094d744 80a90000 809c6620 8804df5c 809c76c4
df40: 80a1aaa0 8094d744 00000008 000000d2 80a90000 80a1aaa0 8804df9c 809c6ebc
df60: 00000007 00000007 809c6620 00000000 8804df7c 00000008 8804df9c 00000000
df80: 806d63c4 00000000 00000000 00000000 00000000 00000000 8804dfac 806d63d0
dfa0: 00000000 806d63c4 00000000 80010408 00000000 00000000 00000000 00000000
dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 5fedd77f e7ffbaae
[<809c70a8>] (do_mount_root.part.3) from [<809c74d4>] (mount_root+0x74/0x100)
[<809c74d4>] (mount_root) from [<809c76c4>] (prepare_namespace+0x164/0x1c8)
[<809c76c4>] (prepare_namespace) from [<809c6ebc>] (kernel_init_freeable+0x18c/0x1dc)
[<809c6ebc>] (kernel_init_freeable) from [<806d63d0>] (kernel_init+0xc/0xec)
[<806d63d0>] (kernel_init) from [<80010408>] (ret_from_fork+0x14/0x2c)
Code: e5933020 e593305c e5933008 e582300c (e7f001f2)
---[ end trace 48ec6f9402ae51bf ]---
Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b

random: nonblocking pool is initialized

开门见山地就提示我们 Kernel BUG at 809c70a8那我们就用 addr2line 来看看到底是哪行代码

$ addr2line -f -e vmlinux 0x809c70a8
do_mount_root
/home/liyongjun/project/board/IMX6ULL/linux/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek/init/do_mounts.c:373

do_mounts.c 文件的第 373 行
在这里插入图片描述
一下就定位到了出错位置这就是内核开启调试选项的好处。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux