GDB调试Linux内核模块

关于GDB如何调试Linux内核,请参考我的另一篇文章:

Virtualbox环境通过GDB调试Linux内核_gdb能调试linux内核驱动吗-CSDN博客

调试内核模块与调试内核类似,一点区别是内核模块需要单独编译,编译时注意加入符号信息。在调试机进行远程调试时,需要载入这些符号信息,同时需要指定模块在内核中的地址。

1. 模块编译

下面是一个demo的模块示例 (demo_module.c),主要功能是当在命令行执行cat /proc/demo_proc 时,返回给用户空间一个消息:"Hello from the kernel!\n"

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#define PROCFS_NAME "demo_proc"

static struct proc_dir_entry *proc_file;

static ssize_t procfile_read(struct file *file, char __user *buffer, size_t len, loff_t *offset) {
    int ret;
    char *msg = "Hello from the kernel!\n";
    size_t msg_len = strlen(msg);

    if (*offset >= msg_len)
        return 0;

    if (*offset + len > msg_len)
        len = msg_len - *offset;

    ret = copy_to_user(buffer, msg + *offset, len);
    if (ret)
        return -EFAULT;

    *offset += len;
    return len;
}

static const struct proc_ops proc_file_ops = {
    .proc_read = procfile_read,
};

static int __init demo_module_init(void) {
    printk(KERN_INFO "Demo Module: Initialization\n");

    proc_file = proc_create(PROCFS_NAME, 0444, NULL, &proc_file_ops);
    if (!proc_file) {
        printk(KERN_ALERT "Demo Module: Error creating proc file\n");
        return -ENOMEM;
    }

    return 0;
}

static void __exit demo_module_exit(void) {
    proc_remove(proc_file);
    printk(KERN_INFO "Demo Module: Exit\n");
}

module_init(demo_module_init);
module_exit(demo_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("taoyuanforrest");
MODULE_DESCRIPTION("A simple example kernel module with a proc file");
MODULE_VERSION("1.0");

Makefile如下:

obj-m += demo_module.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules EXTRA_CFLAGS="-g"

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

其中,EXTRA_CFLAGS="-g" 的作用是编译时加入调试信息。

编译:

make

编译以后会在当前目录生成 demo_module.ko

2. 模块安装

sudo insmod demo_module.ko

查看是否成功:

[root@localhost linux]# lsmod | grep demo_module
demo_module            16384  0

3. 模块调试

首先,查看模块的加载地址:

[root@localhost linux]# cat /proc/modules | grep demo_module
demo_module 16384 0 - Live 0xffffffffa0000000 (O)

这里是0xffffffffa0000000

将编译好的含有调试信息内核模块传到调试机上。

在目标机上开启调试:

echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc

echo g > /proc/sysrq-trigger

在调试机上通过 gdb vmlinux启动gdb调试,然后通过 add-symbol-file 加载模块调试信息:

(gdb) add-symbol-file demo_module.ko 0xffffffffa0000000
add symbol table from file "demo_module.ko" at
        .text_addr = 0xffffffffa0000000
(y or n) y
Reading symbols from demo_module.ko...done.

 现在可以设置断点了,比如

(gdb) b demo_module.c:13
Breakpoint 1 at 0xffffffffa0000007: file /home/linux/demo_module.c, line 13.
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0xffffffffa0000007 in procfile_read at /home/linux/demo_module.c:13

连接到目标机:

(gdb) set serial baud 115200
(gdb)
(gdb) target remote /dev/ttyS0
Remote debugging using /dev/ttyS0
0xffffffff811276db in kgdb_breakpoint ()
(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0xffffffffa0000007 in procfile_read at /home/linux/demo_module.c:13
(gdb) c
Continuing.

 在目标机上执行 cat /proc/demo_proc, 此时调试机上会停在断点上。

4. 模块卸载

[root@localhost linux]# sudo rmmod demo_module
[root@localhost linux]# lsmod | grep demo_module
[root@localhost linux]#

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值