如何编译出带有调试信息的内核模块

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何编译出带有调试信息的内核模块相关的知识,希望对你有一定的参考价值。

示例

led_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>

#define GPIO_CLR_REG ((__u32)0x3f200028)
#define GPIO_SET_REG ((__u32)0x3f20001C)
static volatile __u32 *gpio_led_reg;

static int led_init(void)

	printk("led on\\n");

	gpio_led_reg = (__u32 *)ioremap(GPIO_CLR_REG, 4);
	writel(0x7F, gpio_led_reg);

	return 0;


static void led_exit(void)

	printk("led off\\n");
	gpio_led_reg = (__u32 *)ioremap(GPIO_SET_REG, 4);
	writel(0x7F, gpio_led_reg);


module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("Dual BSD/GPL");

Makefile

obj-m = led_drv.o

KDIR = /home/liyongjun/project/board/buildroot/RPi3/build/linux-custom
CROSS_COMPILE = /home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-gnueabihf-

all:
	make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
	make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) clean

编译

$ make
make -C /home/liyongjun/project/board/buildroot/RPi3/build/linux-custom M=/home/liyongjun/project/board/buildroot/override/led_drv ARCH=arm CROSS_COMPILE=/home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-gnueabihf- modules
make[1]: 进入目录“/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom”
  CC [M]  /home/liyongjun/project/board/buildroot/override/led_drv/led_drv.o
  MODPOST /home/liyongjun/project/board/buildroot/override/led_drv/Module.symvers
  CC [M]  /home/liyongjun/project/board/buildroot/override/led_drv/led_drv.mod.o
  LD [M]  /home/liyongjun/project/board/buildroot/override/led_drv/led_drv.ko
make[1]: 离开目录“/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom”

使用 file 命令查看 ko 是否带有 debug 信息,不带

$ file led_drv.ko 
led_drv.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), BuildID[sha1]=3aa652128eede4a93a7a8f31dbcc12a6ca49508c, not stripped

使用 gdb 查看 ko 是否带有 debug 符号信息,不带

(gdb) file led_drv.ko 
Reading symbols from led_drv.ko...
(No debugging symbols found in led_drv.ko)

使用 objdump 查看 ko 是否带有 debug 符号信息,不带

$ /home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-gnueabihf-objdump -d -l led_drv.ko 

led_drv.ko:     file format elf32-littlearm


Disassembly of section .text.unlikely:

00000000 <init_module>:
led_init():
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    fp, ip, lr, pc
   8:   e24cb004        sub     fp, ip, #4
   c:   e52de004        push    lr            ; (str lr, [sp, #-4]!)
  10:   ebfffffe        bl      0 <__gnu_mcount_nc>
  14:   e3000000        movw    r0, #0
  18:   e3400000        movt    r0, #0
  1c:   ebfffffe        bl      0 <printk>
  20:   e3a01004        mov     r1, #4
  24:   e3a00028        mov     r0, #40 ; 0x28
  28:   e3430f20        movt    r0, #16160      ; 0x3f20
  2c:   ebfffffe        bl      0 <ioremap>
  30:   e3003000        movw    r3, #0
  34:   e3403000        movt    r3, #0
  38:   e5830000        str     r0, [r3]
  3c:   f57ff04e        dsb     st
  40:   e3a0207f        mov     r2, #127        ; 0x7f
  44:   e5933000        ldr     r3, [r3]
  48:   e5832000        str     r2, [r3]
  4c:   e3a00000        mov     r0, #0
  50:   e89da800        ldm     sp, fp, sp, pc

00000054 <cleanup_module>:
led_exit():
  54:   e1a0c00d        mov     ip, sp
  58:   e92dd800        push    fp, ip, lr, pc
  5c:   e24cb004        sub     fp, ip, #4
  60:   e52de004        push    lr            ; (str lr, [sp, #-4]!)
  64:   ebfffffe        bl      0 <__gnu_mcount_nc>
  68:   e3000000        movw    r0, #0
  6c:   e3400000        movt    r0, #0
  70:   ebfffffe        bl      0 <printk>
  74:   e3a01004        mov     r1, #4
  78:   e3a0001c        mov     r0, #28
  7c:   e3430f20        movt    r0, #16160      ; 0x3f20
  80:   ebfffffe        bl      0 <ioremap>
  84:   e3003000        movw    r3, #0
  88:   e3403000        movt    r3, #0
  8c:   e5830000        str     r0, [r3]
  90:   f57ff04e        dsb     st
  94:   e3a0207f        mov     r2, #127        ; 0x7f
  98:   e5933000        ldr     r3, [r3]
  9c:   e5832000        str     r2, [r3]
  a0:   e89da800        ldm     sp, fp, sp, pc

Disassembly of section .plt:

000000a4 <.plt>:
        ...

如何给 ko 添加调试信息呢?

使用 EXTRA_CFLAGS = -g 选项
因为编译内核模块不像编译一个 app,Makefile 中没有 gcc 命令,无法添加 -g 选项。
Makefile

obj-m = led_drv.o

KDIR = /home/liyongjun/project/board/buildroot/RPi3/build/linux-custom
CROSS_COMPILE = /home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-gnueabihf-

EXTRA_CFLAGS = -g

all:
	make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
	make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) clean

使用 EXTRA_CFLAGS 选项,就是向下级 Makefile 传递 CFLAGS 参数,通常,下级 Makefile 中都会隐式使用 CFLAGS 参数。

编译后再次查看 ko 信息

使用 file 命令查看 ko 是否带有 debug 信息,

$ file led_drv.ko 
led_drv.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), BuildID[sha1]=00f91fef955b4980fbec6f39e8a0b994d6c56b6c, with debug_info, not stripped

使用 gdb 查看 ko 是否带有 debug 符号信息,

(gdb) file led_drv.ko 
Reading symbols from led_drv.ko...

使用 objdump 查看 ko 是否带有 debug 符号信息,

$ /home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-gnueabihf-objdump -d -l led_drv.ko 

led_drv.ko:     file format elf32-littlearm


Disassembly of section .text.unlikely:

00000000 <init_module>:
led_init():
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:12
   0:   e1a0c00d        mov     ip, sp
   4:   e92dd800        push    fp, ip, lr, pc
   8:   e24cb004        sub     fp, ip, #4
   c:   e52de004        push    lr            ; (str lr, [sp, #-4]!)
  10:   ebfffffe        bl      0 <__gnu_mcount_nc>
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:13
  14:   e3000000        movw    r0, #0
  18:   e3400000        movt    r0, #0
  1c:   ebfffffe        bl      0 <printk>
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:15
  20:   e3a01004        mov     r1, #4
  24:   e3a00028        mov     r0, #40 ; 0x28
  28:   e3430f20        movt    r0, #16160      ; 0x3f20
  2c:   ebfffffe        bl      0 <ioremap>
  30:   e3003000        movw    r3, #0
  34:   e3403000        movt    r3, #0
  38:   e5830000        str     r0, [r3]
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:16
  3c:   f57ff04e        dsb     st
__raw_writel():
/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom/./arch/arm/include/asm/io.h:95
  40:   e3a0207f        mov     r2, #127        ; 0x7f
led_init():
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:16
  44:   e5933000        ldr     r3, [r3]
__raw_writel():
/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom/./arch/arm/include/asm/io.h:95
  48:   e5832000        str     r2, [r3]
led_init():
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:19
  4c:   e3a00000        mov     r0, #0
  50:   e89da800        ldm     sp, fp, sp, pc

00000054 <cleanup_module>:
led_exit():
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:22
  54:   e1a0c00d        mov     ip, sp
  58:   e92dd800        push    fp, ip, lr, pc
  5c:   e24cb004        sub     fp, ip, #4
  60:   e52de004        push    lr            ; (str lr, [sp, #-4]!)
  64:   ebfffffe        bl      0 <__gnu_mcount_nc>
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:23
  68:   e3000000        movw    r0, #0
  6c:   e3400000        movt    r0, #0
  70:   ebfffffe        bl      0 <printk>
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:24
  74:   e3a01004        mov     r1, #4
  78:   e3a0001c        mov     r0, #28
  7c:   e3430f20        movt    r0, #16160      ; 0x3f20
  80:   ebfffffe        bl      0 <ioremap>
  84:   e3003000        movw    r3, #0
  88:   e3403000        movt    r3, #0
  8c:   e5830000        str     r0, [r3]
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:25
  90:   f57ff04e        dsb     st
__raw_writel():
/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom/./arch/arm/include/asm/io.h:95
  94:   e3a0207f        mov     r2, #127        ; 0x7f
led_exit():
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:25
  98:   e5933000        ldr     r3, [r3]
__raw_writel():
/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom/./arch/arm/include/asm/io.h:95
  9c:   e5832000        str     r2, [r3]
led_exit():
/home/liyongjun/project/board/buildroot/override/led_drv/led_drv.c:26
  a0:   e89da800        ldm     sp, fp, sp, pc

Disassembly of section .plt:

000000a4 <.plt>:
        ...

方法二

之所以编译的内核模块不带调试信息,是因为依赖的内核没有开启调试选项(-g),可以编译内核时打开调试选项,这样使用该内核编译出的内核模块也带有调试信息。

以上是关于如何编译出带有调试信息的内核模块的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 内核模块中找到合适的 DWARF 符号作为地址?

如何编译一个linux下的驱动模块

1-18 编译安装内核支持ntfs文件系统

如何使用crash工具分析Linux内核崩溃转储文件

JLinkGDBServer调试ARM linux内核

JLinkGDBServer调试ARM linux内核