精华内容
下载资源
问答
  • 使用kgdb调试linux内核内核模块

    千次阅读 2008-03-12 16:10:00
    使用kgdb调试linux内核内核模块创建时间:2005-09-09文章属性:原创文章提交:xcspy (xcspy.com_at_gmail.com)作者:xcspy成员 ladybug E-mail:xcspy.com@gmail.com 主页:www.xcspy.com 1. 几种内核调试工具...

    使用kgdb调试linux内核及内核模块


    创建时间:2005-09-09
    文章属性:原创
    文章提交:xcspy (xcspy.com_at_gmail.com)

    作者:xcspy成员 ladybug
    E-mail:xcspy.com@gmail.com
    主页:www.xcspy.com

    1. 几种内核调试工具比较

    kdb:只能在汇编代码级进行调试;
         优点是不需要两台机器进行调试。

    gdb:在调试模块时缺少一些至关重要的功能,它可用来查看内核的运行情况,包括反汇编内核函数。

    kgdb:能很方便的在源码级对内核进行调试,缺点是kgdb只能进行远程调试,它需要一根串口线及两台机器来调试内核(也可以是在同一台主机上用vmware软件运行两个操作系统来调试)

    使用kdb和gdb调试内核的方法相对比较简单,这里只描述如何使用kgdb来调试内核。

    2.软硬件准备

    环境:
    一台开发机developer(192.168.16.5 com1),一台测试机target(192.168.16.30 com2),都预装redhat 9;一根串口线

    下载以下软件包:
    linux内核2.4.23         linux-2.4.23.tar.bz2
    kgdb内核补丁1.9版       linux-2.4.23-kgdb-1.9.patch
    可调试内核模块的gdb     gdbmod-1.9.bz2

    3.ok,开始

    3.1 测试串口线
    物理连接好串口线后,使用一下命令进行测试,stty可以对串口参数进行设置

    在developer上执行:
    stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
    echo hello > /dev/ttyS0
    在target上执行:
    stty ispeed 115200 ospeed 115200 -F /dev/ttyS1
    cat /dev/ttyS1

    串口线没问题的话在target的屏幕上显示hello

    3.2 安装与配置

    3.2.1 安装

    下载linux-2.4.23.tar.bz2,linux-2.4.23-kgdb-1.9.patch,gdbmod-1.9.bz2到developer的/home/liangjian目录

    *在developer机器上

    #cd /home/liangjian
    #bunzip2 linux-2.4.23.tar.bz2
    #tar -xvf linux-2.4.23.tar
    #bunzip2 gdbmod-1.9.bz2
    #cp gdbmod-1.9 /usr/local/bin
    #cd linux-2.4.23
    #patch -p1 < ../linux-2.4.23-kgdb-1.9.patch
    #make menuconfig

    在Kernel hacking配置项中将以下三项编译进内核
    KGDB: Remote (serial) kernel debugging with gdb
    KGDB: Thread analysis
    KGDB: Console messages through gdb

    注意在编译内核的时候需要加上-g选项
    #make dep;make bzImage

    使用scp进行将相关文件拷贝到target上(当然也可以使用其它的网络工具)
    #scp arch/i386/boot/bzImage root@192.168.16.30:/boot/vmlinuz-2.4.23-kgdb
    #scp System.map root@192.168.16.30:/boot/System.map-2.4.23-kgdb
    #scp arch/i386/kernel/gdbstart  root@192.168.16.30:/sbin
    gdbstart为kgdb提供的一个工具,用于激活内核钩子,使内核处于调试状态

    3.2.2 配置

    *在developer机器上

    在内核源码目录下编辑一文件.gdbinit(该文件用以对gdb进行初始化),内容如下:
    #vi .gdbinit
    define rmt
    set remotebaud 115200
    target remote /dev/ttyS0
    end
    #
    以上在.gdbinit中定义了一个宏rmt,该宏主要是设置使用的串口号和速率

    *在target机器上

    编辑/etc/grub.conf文件,加入以下行:
    #vi /etc/grub.conf
    title Red Hat Linux (2.4.23-kgdb)
        root (hd0,0)
        kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1
    #

    在root目录下建立一个脚本文件debugkernel,内容如下:
    #vi debug
    #!/bin/bash
    gdbstart -s 115200 -t /dev/ttyS1 <<EOF

    EOF
    #chmod +x debugkernel
    这个脚本主要是调用gdbstart程序设置target机上使用的串口及其速率,并使内核处于调试状态

    3.3 开始调试

    target上的内核或内核模块处于调试状态时,可以查看其变量、设置断点、查看堆栈等,并且是源码级的调试,和用gdb调试用户程序一样

    3.3.1 内核启动后调试

    *在target机器上

    重启系统,选择以 2.4.23-kgdb内核启动,启动完成后运行debugkenel,
    这时内核将停止运行,在控制台屏幕上显示信息,并等待来自developer的
    串口连接

    #./debug
    About to activate GDB stub in the kernel on /dev/ttyS1
    Waiting for connection from remote gdb...

    *在developer机器上

    #cd /home/liangjian/linux-2.4.23
    # gdb vmlinux
    GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
    Copyright 2003 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i386-redhat-linux-gnu"...

    执行rmt宏
    (gdb) rmt
    breakpoint () at kgdbstub.c:1005
    1005                    atomic_set(&kgdb_setting_breakpoint, 0);

    这时target上的内核处于调试状态,可以查看其变量、设置断点、查看堆栈等,和用gdb调试用户程序一样

    查看堆栈
    (gdb) bt
    #0  breakpoint () at kgdbstub.c:1005
    #1  0xc0387f48 in init_task_union ()
    #2  0xc01bc867 in gdb_interrupt (irq=3, dev_id=0x0, regs=0xc0387f98) at
    gdbserial.c:158
    #3  0xc010937b in handle_IRQ_event (irq=3, regs=0xc0387f98, action=0xce5a9860)
    at irq.c:452
    #4  0xc0109597 in do_IRQ (regs=
          {ebx = -1072671776, ecx = -1, edx = -1070047232, esi = -1070047232, edi
    = -1070047232, ebp = -1070039092, eax = 0, xds
    = -1070071784, xes = -1070071784, orig_eax = -253, eip = -1072671729, xcs =
    16, eflags = 582, esp = -1070039072, xss = -1072671582}) at irq.c:639
    #5  0xc010c0e8 in call_do_IRQ ()

    查看jiffies变量的值
    (gdb) p jiffies
    $1 = 76153

    如果想让target上的内核继续运行,执行continue命令
    (gdb) continue
    Continuing.

    3.3.2 内核在引导时调试

    kgdb可以在内核引导时就对其进行调试,但并不是所有引导过程都是可调试的,如在kgdb 1.9版中,它在init/main.c的start_kernel()函数中插入以下代码:
    start_kernel()
    {
        ......
            smp_init();
    #ifdef CONFIG_KGDB
            if (gdb_enter) {
                    gdb_hook();             /* right at boot time */
            }
    #endif
        ......
    }

    所以在smp_init()之前的初始化引导过程是不能调试的。

    另外要想让target的内核在引导时就处于调试状态,需要修改其/etc/grub.conf文件为如下形式:
    title Red Hat Linux (2.4.23-kgdb)
        root (hd0,0)
        kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1 gdb gdbttyS=1 gdbbaud=115200

    *在target机器上

    引导2.4.23-kgdb内核,内核将在短暂的运行后暂停并进入调试状态,打印如下信息:
    Waiting for connection from remote gdb...

    *在developer机器上

    #cd /home/liangjian/linux-2.4.23
    # gdb vmlinux
    GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
    Copyright 2003 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i386-redhat-linux-gnu"...

    执行rmt宏
    (gdb) rmt
    breakpoint () at kgdbstub.c:1005
    1005                    atomic_set(&kgdb_setting_breakpoint, 0);

    查看当前堆栈
    (gdb) bt
    #0  breakpoint () at kgdbstub.c:1005
    #1  0xc0387fe0 in init_task_union ()
    #2  0xc01bc984 in gdb_hook () at gdbserial.c:250
    #3  0xc0388898 in start_kernel () at init/main.c:443

    在do_basic_setup函数处设置断点,并让内核恢复运行
    (gdb) b do_basic_setup
    Breakpoint 1 at 0xc0388913: file current.h, line 9.
    (gdb) continue
    Continuing.
    [New Thread 1]
    [Switching to Thread 1]

    Breakpoint 1, do_basic_setup () at current.h:9
    9               __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));

    内核在do_basic_setup断点处停止运行后查看当前堆栈
    (gdb) bt
    #0  do_basic_setup () at current.h:9
    (gdb)

    3.3.3 内核模块调试调试

    要想调试内核模块,需要相应的gdb支持,kgdb的主页上提供了一个工具gdbmod,它修正了gdb 6.0在解析模块地址时的错误,可以用来正确的调试内核模块

    *在developer机器上

    写了个测试用的内核模块orig,如下:
    void xcspy_func()
    {
        printk("<1>xcspy_func/n");
        printk("<1>aaaaaaaaaaa/n");
    }

    int xcspy_init()
    {
        printk("<1>xcspy_init_module/n");
            
        return 0;
    }

    void xcspy_exit()
    {
        printk("<1>xcspy_cleanup_module/n");
    }

    module_init(xcspy_init);
    module_exit(xcspy_exit);

    编译该模块:
    #cd /home/liangjian/lkm
    #gcc -D__KERNEL__ -DMODULE -I/home/liangjian/linux-2.4.23/include -O -Wall -g -c -o orig.o orig.c
    #scp orig.o root@192.168.16.30:/root

    开始调试:
    # gdbmod vmlinux
    GNU gdb 6.0
    Copyright 2003 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i686-pc-linux-gnu"...

    设置符号文件的搜索路径
    (gdb) set solib-search-path /home/liangjian/lkm

    执行rmt宏
    (gdb) rmt
    breakpoint () at kgdbstub.c:1005
    1005                    atomic_set(&kgdb_setting_breakpoint, 0);

    设置断点使得可以调试内核模块的init函数,查内核源码可知,内核是通过module.c文件的第566行(sys_init_module函数中)mod->init来调用模块的init函数的
    (gdb) b module.c:566
    Breakpoint 1 at 0xc011cd83: file module.c, line 566.
    (gdb) c
    Continuing.
    [New Thread 1352]
    [Switching to Thread 1352]

    这时在target机器上执行insmod orig.o,developer则相应的在断点处被暂停,如下
                                                                                                                              
    Breakpoint 1, sys_init_module (name_user=0xc03401bc "/001",
    mod_user=0x80904d8) at module.c:566
    566             if (mod->init && (error = mod->init()) != 0) {

    使用step命令进入模块的init函数
    (gdb) step
    xcspy_init () at orig.c:12
    12              printk("<1>xcspy_init_module/n");
    (gdb) n
    15      }
    (gdb)

    说明:
    调试内核模块的非init函数相对比较简单,只要先在target上执行insmod orig.o,这时由于模块的符号被加载,可以直接在developer的gdb中对想调试的模块函数设置断点,如bt xcspy_func,后面当xcspy_func被调用时就进入了调试状态。
    如果想调试内核模块的init函数,由于在执行insmod之前模块的符号还没有被加载,不能直接对模块的init函数设置断点,所以相对来说要困难一 些。可以采用两种变通的方法:1,采用上面介绍的在内核调用模块的init函数被调用之前的某处插入断点,如bt sys_init_module()或bt module.c:566;2,在developer上让内核处于运行状态,在target上先执行一遍insmod orig.o,这时orig.o的符号已经被加载到内存中,可以直接在developer的gdb中对模块的init函数设置断点,如bt xcspy_init,然后在target上rmmod orig.o,当下次在target上重新加载orig.o时就进入了调试状态,developer在xcspy_init处被暂停。
     
    展开全文
  • 1. 内核简单模块的编写 通过命令date可以获取当前系统时间,如下面示例。 下面我们通过编写一个简单的内核模块直接获取当前系统时间。 1.1模块源码编写 在Linux内核源码中,定义了一个struct timeval结构体,...

    1. 内核简单模块的编写

    通过命令date可以获取当前系统时间,如下面示例。

    下面我们通过编写一个简单的内核模块直接获取当前系统时间。

    1.1模块源码编写

    在Linux内核源码中,定义了一个struct timeval结构体,结构体中有两个成员变量tv_sec,tv_usec,分别保存当前系统时间的秒和毫秒,time_t和suseconds_t类型变量在x86架构中,均为long型,变量类型定义在文件include/linux/time.h中。

    00018: struct timeval {

    00019time_t tv_sec/ * seconds */

    00020suseconds_t tv_usec; / * microseconds */

    00021: };

    00022:

     

    模块源码如下:

    00001:

    00002: #include <linux/ module.h>

    00003: #include <linux/ time.h>

    00004:

    00005: static char modname[] = "time";

    00006:

    00007: extern struct timespec xtime;

    00008:

    00009: int init_module( void )

    00010: {

    00011struct timeval tv;

    00012printk( "Installing %s module.", modname );

    00013do_gettimeofday(&tv);

    00014printk("\njiffies:%lu, tv.tv_sec:%lu, tv.tv_nsec:%lu ", jiffies, tv.tv_sec, tv.tv_usec);

    00015:

    00016return 0;

    00017: }

    00018:

    00019:

    00020: void cleanup_module( void )

    00021: {

    00022printk( "\nRemoving %s module.", modname );

    00023: }

    00024:

    00025: MODULE_LICENSE("GPL");

    00026:

     

    1.2Makefile

    创建一个Makefile,执行make,即可编译生成内核模块,生成后缀名为.ko的文件。

    Makefile内容:

    注意:在default:后面的$(MAKE) … … 和rm –r … …两行前面必须是Tab键,不能为空格或其他字符,否则执行make时,会报告“Makefile:10: *** missing separator. Stop.”错误。

    1.3模块加载

    执行make,编译生成模块.ko文件后,就可以通过insmod命令来加载模块。

    通过lsmod命令可以查看驱动是否成功加载到内核中。

    通过insmod命令加载刚编译成功的time.ko模块后,似乎系统没有反应,也没看到打印信息。而事实上,内核模块的打印信息一般不会打印在终端上。驱动的打印都在内核日志中,我们可以使用dmesg命令查看内核日志信息。

    内核模块time.ko获取到的当前系统时间为1289489871秒,与执行date ‘+%s’命令获取到的值一致。

    2内核模块版本与符号表

    在编写和使用内核模块过程中,会发现在某个内核版本上编译的模块只能在当前内核版本中使用。若模块版本号与当前内核版本号不匹配导致就会无法加载,提示“insmod: error inserting 'time.ko': -1 Invalid module format”,内核会打印类似信息“time: version magic '2.6.32.12-0.7-default SMP mod_unload modversions ' should be '2.6.18-92.el5 SMP mod_unload gcc-4.1'”。

    2.1内核模块版本号

    查看内核模块版本信息的命令为modinfo,如查看刚才我们编写的time.ko。

    模块的版本号在“vermagic“一项,当前系统中使用的模块版本号都是相同的。

    模块版本号是哪里决定的?我们是否可以更改?我们是否可以在当前系统中,编译其他内核版本的模块?

    2.1.1模块版本号的确定

    在make编译模块时,通过-C参数制定内核源码头文件位置。前面我们编译time模块内核源码头文件位置为/lib/modules/2.6.32.12-0.7-default/build。

    make -C /lib/modules/2.6.32.12-0.7-default/build SUBDIRS=/root/programming modules

    我们来分析模块版本号的确定

    vermagic: 2.6.32.12-0.7-default SMP mod_unload modversions

    在RHEL5系统中,模块版本号vermagic由include/linux/vermagic.h和include/linux/utsrelease.h两个文件的内容来决定,即vermagic就为VERMAGIC_STRING

    文件include/linux/utsrelease.h的内容如下:

    文件include/linux/vermagic.h的内容如下:

    而在SLES11.1内核2.6.32.12-0.7-default的模块版本号VERMAGIC_STRING由scripts/mod/modpost可执行文件确定。

    2.1.2模块版本号的修改

    前面分析了模块版本号由VERMAGIC_STRING确定产生,若我们需要修改模块版本号或希望在当前内核版本中编译其他内核的模块(注意gcc大版本和CPU架构i686/x86_64保持一致),只需要修改控制模块的VERMAGIC_STRING值即可。

    如我们将示例中的time模块在RHEL5.2内核中编译RHEL5.3内核模块,然后在RHEL5.3系统上可以加载。

    2.1.3编译非当前内核版本模块

    在模块版本号的修改介绍的方法中,仅适合内核版本(OS发行版本)差别不大的情况下,可以方便修改某块版本。本小节介绍如何编译非当前内核版本模块。

    步骤:

    1. 将待编译特定内核源码开发包拷贝到当前系统中某个目录下

    如我们打算在SLES11.1 x86_64系统中编译RHEL5.5 x86_64内核模块,应先将RHEL5.5 x86_64内核开发包拷贝到SLES11.1系统中。

    1. 修改Makefile,将KDIR指向待编译内核开发包目录

    在Makefile中,设置KDIR变量为指定内核源码目录位置。

    3、执行make编译模块

    执行后,生成内核模块。可以使用modinfo命令来查看新生成模块的版本号。如

    #modinfo /root/programming/time.ko

     

    编译非当前内核版本模块后,加载再次提示“Invalid module format”时,通过dmesg命令查看加载失败原因。

    如上面的提示,我们直接include/linux/vermagic.h文件即可,将gcc版本信息值改为固定值gcc-4.1即可。

    2.2内核符号表及使用

    加载模块时,insmod使用公共内核符号表解析模块中未定义的符号。公共符号表中包含了所有的全局内核项(即函数和变量)的地址,内核符号表的内容全部在文件/proc/kallsyms中,可以通过cat等命令查看。内核和模块将函数、变量导出后,就成为内核符号表的一部分。

    在我们编写的内核模块中,可以使用内核或其他模块定义的函数和变量,如本章示例的获取时间模块中,就调用了内核函数do_gettimeofday()。

     

    内核中有两个宏用来导出函数和变量:

    EXPORT_SYMBOL(symbolname)

    将函数或变量导出到所有模块

    EXPORT_SYMBOL_GPL(symbolname)

    将函数或变量仅导出到GPL模块

    我们也可以在自己的模块中导出部分函数或变量,这样其他模块就可以访问这部分函数、变量。C语言用户态程序编程中,我们常会使用在其他C文件或lib库中定位的函数和变量,内核符号表和这有相似之处。

    系统中所有内核和模块导出的变量和函数,就成了内核符号表,在/proc/kallsyms文件中。

    内核符号表中,第一列为函数或变量的在内核中的地址,第二列为符号的类型,第三列为符号名,第四列为符号所属的模块。若第四列为空,则表示该符号属于内核代码。

    内核符号属性

    符号属性

    含义

    b

    符号在未初始化数据区(BSS)

    c

    普通符号,是未初始化区域

    d

    符号在初始化数据区

    g

    符号针对小object,在初始化数据区

    i

    非直接引用其他符号的符号

    n

    调试符号

    r

    符号在只读数据区

    s

    符号针对小object,在未初始化数据区

    t

    符号在代码段

    u

    符号未定义

     

    若符号在内核中是全局性的,则属性为大写字母,如T、U等。其他符号属性含义,请参考命令nm的帮助信息。

    00273: / * Only label it "global" if it is exported. */

    00274: static void upcase_if_global(struct kallsym_iter *iter)

    00275: {

    00276if (is_exported(iter- >name, iter- >owner))

    00277iter- >type += 'A' - 'a';

    00278: }

    00279:

     

    若打算使用内核中的符号,在模块中增加函数或变量说明即可。如:

    00091: extern struct timespec xtime;

     

    3模块版本控制

    Linux内核版本在不变升级,内核提供的API或符号可能也随之变化。这对内核模块开发来说,是一个比较麻烦的问题,通常要适应不同的内核版本,或者只针对具体某些内核版本开发。

    内核为了确保模块的函数接口与内核借口一致,采用了模块版本控制。版本控制最简单的办法就是为了内核和模块都设置一个常量,该常量会随着接口变化而不断增加。加载模块时,内核会检查模块提供的常量是否和内核版本常量相等,若不相等则拒绝加载。

    采用常量的办法进行版本控制,方法简单,但不够灵活。如内核部分接口变化后,版本常量就会增加。但若某模块使用的这些接口并没有变化,也会导致驱动无法加载。基于这个原因,最恰当的方法是将单个内核API的变化考虑进去。实际的模块和内核实现无关,模块和内核关系密切的是API接口。

    3.1checksum方法

    CRC checksum原理是使用函数的参数来计算校验码,若校验码不相等,加载模块失败。

    我们来看一下内核执行模块加载的函数load_module()(文件kernel/module.c)。1767行会调用check_modstruct_version()函数来检查struct_module符号的CRC校验码。若校验码不相等,则提示“disagrees about version of symbol struct_module”。如

    hwinc_kernel_driver: disagrees about version of symbol struct_module

    Found checksum B6AF205C vs module F3D5F8AF

     

    01600: static struct module *load_module(void __user *umod,

    01601unsigned long len,

    01602const char __user *uargs)

    01603: {

    01604Elf_Ehdr *hdr;

    01605Elf_Shdr *sechdrs;

    … …

    01766/ * Check module struct version now, before we try to use module. */

    01767if (! check_modstruct_version(sechdrs, versindex, mod)) {

    01768err = - ENOEXEC;

    01769goto free_hdr;

    01770}

    01771:

    01772modmagic = get_modinfo(sechdrs, infoindex, "vermagic");

    01773/ * This is allowed: modprobe - - force will invalidate it. */

    01774if (! modmagic) {

    01775add_taint_module(mod,TAINT_FORCED_MODULE);

    01776printk(KERN_WARNING "%s: no version magic, tainting

    kernel.\n",

    01777mod- >name);

    01778else if (! same_magic(modmagic, vermagic )) {

    01779printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",

    01780mod- >name, modmagic, vermagic );

    01781err = - ENOEXEC;

    01782goto free_hdr;

    01783}

     

    在编译内核模块时,会生成*.mod.c文件,该文件中包含了模块中各个符号的校验码。校验码的生成,由scripts/genksyms/genksyms计算生成。

    注意:scripts/genksyms/genksyms文件是在内核源码目录或内核开发包目录中,如/usr/src/linux-2.6.32.12-0.7-obj/x86_64/default/scripts/genksyms/genksyms

    3.2vermagic

    查看内核版本模块信息时,会看到vermagic一项。模块在装载时,load_module()函数会比较(如前面代码的1772行)当前运行内核的vermagic和当前要加载的模块的vermagic比较,如果不同,则禁止加载模块。

    Vermagic的的确定请参考章节2.1.1。

    3.3内核模块版本控制使能与关闭

    我们常遇到内核提示“disagrees about version of symbol struct_module”,而导致模块无法加载的情况。

    3.3.1内核中关闭/使能

    若选择关闭内核的模块版本控制功能,则会避免出现这种情况。模块版本控制选项在内核源码配置文件.config中,注释掉CONFIG_MODVERSIONS就取消了模块版本控制。

    CONFIG_MODVERSIONS=y

    重新编译内核,重启即可。

    3.3.2模块中关闭/使能版本控制

    如下面的实例。虽然模块的vermagic和内核一致,但struct_module的版本号不一致。我们可以不修改当前内核,重新编译模块即可解决问题。

    若去掉模块版本控制后,加载驱动导致系统死机。建议解决办法:使用待运行内核的.config配置文件覆盖模块编译指向的内核开发包(源码).config文件。

    .config配置文件的获取:(1)可以拷贝/proc/config.gz,然后解压缩,拷贝为.config;(2)若/proc/config.gz不存在,可以使用/boot/目录下对应的内核配置文件;(3)或向内核提供者获取.config配置文件。

    此时我们可以修改内核开发包中的模块版本控制选项,修改文件.config(在内核源码或开发包根目录下),注释掉或删除CONFIG_MODVERSIONS选项,重新编译模块即可去除模块的版本控制。

    CONFIG_MODULES=y

    CONFIG_OBSOLETE_MODPARM=y

    #CONFIG_MODVERSIONS=y

    CONFIG_MODULE_SIG=y

    4内核模块参数

    在用户执行系统命令或其他程序时,可以使用参数。内核模块也可以使用参数。

    参数必须使用宏module_param()声明,该宏定义在include/linux/moduleparam.h文件中。module_param()需要三个参数:参数名称、类型、sysfs文件系统入口项的访问权限掩码。

    模块参数的定义必须放在任何函数之外。如本章获取系统时间的模块示例,我们增加province和population两个参数(参数仅作示范,和系统时间无任何关系)。

    00001: #include <linux/ module.h>

    00002: #include <linux/ time.h>

    00003: #include <linux/ moduleparam.h>

    00004:

    00005: static char modname[] = "time";

    00006:

    00007: static char *province = "Guangdong";

    00008: module_param(provincecharp0);

    00009: static int population = 10000;

    00010: module_param(populationint0);

    00011:

    00012: int init_module( void )

    00013: {

    00014struct timeval tv;

    00015printk( "Installing %s module.", modname );

    00016do_gettimeofday(&tv);

    00017printk("\njiffies:%lu, tv.tv_sec:%lu, tv.tv_nsec:%lu ",

    00018jiffies, tv.tv_sec, tv.tv_usec);

    00019:

    00020printk("\nProvince:%s, Population:%d \n", province , population );

    00021:

    00022return 0;

    00023: }

    00024:

    00025:

    00026: void cleanup_module( void )

    00027: {

    00028printk( "\nRemoving %s module.", modname );

    00029: }

    00030:

    00031: MODULE_LICENSE("GPL");

    00032:

     

    加载模块time后,内核打印信息:

    内核模块支持的参数类型如下:

    bool

    invbool

    charp:字符串指针。内核会为用户提供的字符串自动分配内存。

    int

    long

    short

    uint:unsigned int

    ulong:unsigned long

    ushort:unsigned short

    5模块入口/出口函数及其他

    每个内核模块都要有初始化(入口)函数和清除(出口)函数,清除函数负责在模块被移除前注销接口并向系统返回所有资源。

    在本章time模块的示例中,并没有像用户态C程序一样有main()入口函数。time模块入口函数为init_module(),而出口函数为cleanup_module()。

    在复杂的模块中,我们可以指定模块的入口/出口函数名称。通过module_init()和module_exit()函数分别指定。如LSISAS1068E驱动mptsas中的入口/出口函数:

    04828: module_init(mptsas_init);

    04829: module_exit(mptsas_exit);

    在模块中,我们还可以添加作者信息、模块描述、模块版本等信息。

    MODULE_AUTHOR():模块作者信息

    MODULE_DESCRIPTION():模块描述

    MODULE_LICENSE():模块协议

    MODULE_VERSION():模块版本

    如:

    00070: #define my_NAME "Fusion MPT SCSI Host driver"

    00071: #define my_VERSION MPT_LINUX_VERSION_COMMON

    00072: #define MYNAM "mptscsih"

    00073:

    00074: MODULE_AUTHOR(MODULEAUTHOR);

    00075: MODULE_DESCRIPTION(my_NAME);

    00076: MODULE_LICENSE("GPL");

    00077: MODULE_VERSION(my_VERSION);

     

    6内核模块与用户程序区别

    6.1用户空间与内核空间

    内核空间具有最高权限,可以访问所有CPU寄存器和其他所有资源。

    • 内核空间可以访问所有的CPU指令和所有的内存空间、I/O空间。

    • 用户空间只能访问有限的资源,若需要特殊权限,可以通过系统调用获取相应的资源。

    • 用户空间允许页面中断,而内核空间则不允许。

    • 用户空间是0-3G的地址范围,内核空间是3G-4G的地址范围。

    • 内核空间和用户空间是针对线性地址空间的。

    • 所有内核进(线)程共用一个地址空间,而用户进程都有各自的地址空间。

    ​​​​​​​                                                               Linux 32位系统用户空间与内核空间

    6.2内核模块与应用程序的对比

    • 内核模块具有独立的地址空间

    模块运行在内核空间中。应用程序运行在用户空间中。系统软件受到保护,不允许用户程序访问。内核空间和用户空间有各自独立的内存地址空间。

    • 内核模块具有更高的执行特权

    运行在内核空间中的代码要比运行在用户空间中的代码具有更大的特权。

    • 内核模块不按顺序执行

    用户程序通常按顺序执行并且从头到尾地执行单独的任务。内核模块并不按顺序执行,它注册自己是为了服务将来的请求。

    • 内核模块可以被中断

    在同一时刻,可能有许多进程同时向驱动程序发出请求。中断程序可以在驱动程序正在响应系统调用时,向驱动程序发出请求。在对称多处理器(SMP)系统中,驱动程序可能在多个 CPU 上并发地执行。

    • 内核模块必须是可抢占的

    • 内核模块能够共享数据

    一个应用程序的不同线程常常不会共享数据。与之相对应的是,组成驱动程序的数据结构和例程被所有使用驱动程序的线程所共享。驱动程序必须能够处理由多个请求导致的竞争问题。

    • 错误处理

    应用程序的错误导致Segmentation Fault,而内核模块的错误影响整个系统,甚至使内核

    7常见问题处理

    1、头文件引用

    在用户程序和内核模块时,可能都会使用头文件 #include <linux/time.h>,但两者文件所在的位置是不同的。

    用户态用户程序使用的time.h,在gcc库文件中,一般位置是/usr/include/linux/time.h或/usr/include/sys/time.h。

    内核模块使用的time.h,在内核源码头文件中,一般位置是<内核版本>/include/linux/time.h,如/usr/src/kernels/2.6.18-128.el5-x86_64/include/linux/time.h。

     

    2、提示内核build目录不存在

    在编写好内核模块后,执行make时,有的系统会提示类似“make: *** /lib/modules/2.6.18-128.el5xen/build: No such file or directory. Stop.”错误信息。原因在于内核源码开发包没有安装。

    解决办法:安装当前内核版本的源码开发包。

    3、模块加载提示Invalid Module Format”

    解决步骤:

    1. 执行dmesg命令,查看模块提示Invalid Module Format的详细原因

    2. 根据提示信息,结合本章提到内核模块版本号与修改一些,修复相应的错误。

    4、模块加载提示“Symbol not found”

    解决步骤:

    1. 执行dmesg命令,查看模块哪些符号在当前系统中不存在。

    2. 执行modinfo命令,查看当前模块依赖关系,并检查依赖的模块是否已加载到系统中。

    4、模块加载提示“disagrees about version of symbol struct_module

    请参考“模块版本控制”一节。

    5、是否有办法将模块加载到非当前内核版本中,而不重新编译模块?

    在内核版本相近和CPU架构相同的情况下,如2.6.18-92.e15 i686和2.6.18-194.e15 i686内核,可以直接二进制编辑模块,修改模块的版本信息,这样就可以加载到非当前内核版本中了。

     

    展开全文
  • 内核模块添加sysfs属性

    千次阅读 2010-05-05 00:07:00
    内核区的内存复制,虚拟字符设备上常见的 __user 属性在这里并不需要,因而也不需要多一次 copy_from_user/copy_to_user, 在 show/store 函数参数上的 buf/count 参数已经是内核区的地址,可以直接操作 。 ...

    1. 添加 sysfs 支持

    如果你正在开发的设备驱动程序中需要与用户层的接口,一般可选的方法有:

    1.注册虚拟的字符设备文件,以这个虚拟设备上的 read/write/ioctl 等接口与用户交互;但 read/write 一般只能做一件事情, ioctl 可以根据 cmd 参数做多个功能,但其缺点是很明显的: ioctl 接口无法直接在 Shell 脚本中使用,为了使用 ioctl 的功能,还必须编写配套的 C语言的虚拟设备操作程序, ioctl 的二进制数据接口也是造成大小端问题 (big endianlittle endian)32/64位不可移植问题的根源;

    2.注册 proc 接口,接受用户的 read/write/ioctl 操作;同样的,一个 proc 项通常使用其 read/write/ioctl 接口,它所存在的问题与上面的虚拟字符设备的的问题相似;

    3.注册 sysfs 属性;

    最重要的是,添加虚拟字符设备支持和注册 proc 接口支持这两者所需要增加的代码量都并不少,最好的方法还是使用 sysfs 属性支持,一切在用户层是可见的透明,且增加的代码量是最少的,可维护性也最好;方法就是使用 <include/linux/device.h> 头文件提供的这四个宏,分别应用于总线/类别/驱动/设备四种内核数据结构对象上:

    #define BUS_ATTR(_name, _mode, _show, _store)   /

    struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store)

     

    #define CLASS_ATTR(_name, _mode, _show, _store)                 /

    struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store)

     

    #define DRIVER_ATTR(_name, _mode, _show, _store)        /

    struct driver_attribute driver_attr_##_name =           /

            __ATTR(_name, _mode, _show, _store)

     

    #define DEVICE_ATTR(_name, _mode, _show, _store) /

    struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

     

    总线(BUS)和类别(CLASS)属性一般用于新设计的总线和新设计的类别,这两者一般是不用的;因为你的设备一般是以PCI等成熟的常规方式连接到主机,而不会去新发明一种类型;使用驱动属性和设备属性的区别就在于:看你的 sysfs 属性设计是针对整个驱动有效的还是针对这份驱动所可能支持的每个设备分别有效。

    从头文件中还可以找到 show/store 函数的原型,注意到它和虚拟字符设备或 proc 项的 read/write 的作用很类似,但有一点不同是 show/store 函数上的 buf/count 参数是在 sysfs 层已作了用户区/内核区的内存复制,虚拟字符设备上常见的 __user 属性在这里并不需要,因而也不需要多一次 copy_from_user/copy_to_user, show/store 函数参数上的 buf/count 参数已经是内核区的地址,可以直接操作

     

    2. 案例文件

    2.1. 功能分析

    1.demo.ko按一定的时间间隔不断的产生各种级别的日志

     

    2.我们新增了attr.hattr.c源文件,并且基本不修改demo.cdemo.h的情况下让demo.ko支持sysfs

    所作修改是:在demo的初始化函数中调用demo_attr_install,在demo的退出函数中调用demo_attr_uninstall

     

    3.从函数demo_attr_show到各个属性自定义的show函数其实就是面向对象中的多态

     

    4.添加sysfs支持后的好处就是可以在用户态下直接跟demo.ko交互,比如

    修改打印日志的级别,

    echo 101 > /sys/demo/loglevel

    修改打印时间间隔,

    echo 3000 > /sys/demo/interval

     

    5.attr.c / attr.h中的框架可重用

    添加一个新的属性,只需要

    使用DEMO_ATTR宏定义一个属性

    如果该属性支持读,则添加实现ssize_t (*show)(char *buf);

    如果该属性支持写,则添加实现ssize_t (*store)(const char *buf, size_t count);

     

    其余的代码都不需要改动,都是公共代码。

    2.2. attr.h文件

     

    2.3. demo.h文件

     

    2.4. demo.c文件

     

    2.5. attr.c文件

     

    3. 参考资料

    /Documentation/kobject.txt

    /Documentation/filesystems/sysfs.txt

    展开全文
  • 使用kgdb调试linux内核内核模块创建时间:2005-09-09文章属性:原创文章提交:xcspy (xcspy.com_at_gmail.com)作者:xcspy成员 ladybugE-mail:xcspy.com@gmail.com主页:www.xcspy.com1. 几种内核调试工具比较kdb...

    使用kgdb调试linux内核及内核模块

    创建时间:2005-09-09
    文章属性:原创
    文章提交:xcspy (xcspy.com_at_gmail.com)

    作者:xcspy成员 ladybug
    E-mail:xcspy.com@gmail.com
    主页:www.xcspy.com

    1. 几种内核调试工具比较

    kdb:只能在汇编代码级进行调试;
         优点是不需要两台机器进行调试。

    gdb:在调试模块时缺少一些至关重要的功能,它可用来查看内核的运行情况,包括反汇编内
    核函数。

    kgdb:能很方便的在源码级对内核进行调试,缺点是kgdb只能进行远程调试,它需要一根串
    口线及两台机器来调试内核(也可以是在同一台主机上用vmware软件运行两个操作系统来调试
    )

    使用kdb和gdb调试内核的方法相对比较简单,这里只描述如何使用kgdb来调试内核。

    2.软硬件准备

    环境:
    一台开发机developer(192.168.16.5 com1),一台测试机target(192.168.16.30 com2),都
    预装redhat 9;一根串口线

    下载以下软件包:
    linux内核2.4.23         linux-2.4.23.tar.bz2
    kgdb内核补丁1.9版       linux-2.4.23-kgdb-1.9.patch
    可调试内核模块的gdb     gdbmod-1.9.bz2

    3.ok,开始

    3.1 测试串口线
    物理连接好串口线后,使用一下命令进行测试,stty可以对串口参数进行设置

    在developer上执行:
    stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
    echo hello > /dev/ttyS0
    在target上执行:
    stty ispeed 115200 ospeed 115200 -F /dev/ttyS1
    cat /dev/ttyS1

    串口线没问题的话在target的屏幕上显示hello

    3.2 安装与配置

    3.2.1 安装

    下载linux-2.4.23.tar.bz2,linux-2.4.23-kgdb-1.9.patch,gdbmod-1.9.bz2到developer
    的/home/liangjian目录

    *在developer机器上

    #cd /home/liangjian
    #bunzip2 linux-2.4.23.tar.bz2
    #tar -xvf linux-2.4.23.tar
    #bunzip2 gdbmod-1.9.bz2
    #cp gdbmod-1.9 /usr/local/bin
    #cd linux-2.4.23
    #patch -p1 < ../linux-2.4.23-kgdb-1.9.patch
    #make menuconfig

    在Kernel hacking配置项中将以下三项编译进内核
    KGDB: Remote (serial) kernel debugging with gdb
    KGDB: Thread analysis
    KGDB: Console messages through gdb

    注意在编译内核的时候需要加上-g选项
    #make dep;make bzImage

    使用scp进行将相关文件拷贝到target上(当然也可以使用其它的网络工具)
    #scp arch/i386/boot/bzImage root@192.168.16.30:/boot/vmlinuz-2.4.23-kgdb
    #scp System.map root@192.168.16.30:/boot/System.map-2.4.23-kgdb
    #scp arch/i386/kernel/gdbstart  root@192.168.16.30:/sbin
    gdbstart为kgdb提供的一个工具,用于激活内核钩子,使内核处于调试状态

    3.2.2 配置

    *在developer机器上

    在内核源码目录下编辑一文件.gdbinit(该文件用以对gdb进行初始化),内容如下:
    #vi .gdbinit
    define rmt
    set remotebaud 115200
    target remote /dev/ttyS0
    end
    #
    以上在.gdbinit中定义了一个宏rmt,该宏主要是设置使用的串口号和速率

    *在target机器上

    编辑/etc/grub.conf文件,加入以下行:
    #vi /etc/grub.conf
    title Red Hat Linux (2.4.23-kgdb)
        root (hd0,0)
        kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1
    #

    在root目录下建立一个脚本文件debugkernel,内容如下:
    #vi debug
    #!/bin/bash
    gdbstart -s 115200 -t /dev/ttyS1 <<EOF

    EOF
    #chmod +x debugkernel
    这个脚本主要是调用gdbstart程序设置target机上使用的串口及其速率,并使内核处于调试
    状态

    3.3 开始调试

    target上的内核或内核模块处于调试状态时,可以查看其变量、设置断点、查看堆栈等,并
    且是源码级的调试,和用gdb调试用户程序一样

    3.3.1 内核启动后调试

    *在target机器上

    重启系统,选择以 2.4.23-kgdb内核启动,启动完成后运行debugkenel,
    这时内核将停止运行,在控制台屏幕上显示信息,并等待来自developer的
    串口连接

    #./debug
    About to activate GDB stub in the kernel on /dev/ttyS1
    Waiting for connection from remote gdb...

    *在developer机器上

    #cd /home/liangjian/linux-2.4.23
    # gdb vmlinux
    GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
    Copyright 2003 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i386-redhat-linux-gnu"...

    执行rmt宏
    (gdb) rmt
    breakpoint () at kgdbstub.c:1005
    1005                    atomic_set(&kgdb_setting_breakpoint, 0);

    这时target上的内核处于调试状态,可以查看其变量、设置断点、查看堆栈等,和用gdb调试
    用户程序一样

    查看堆栈
    (gdb) bt
    #0  breakpoint () at kgdbstub.c:1005
    #1  0xc0387f48 in init_task_union ()
    #2  0xc01bc867 in gdb_interrupt (irq=3, dev_id=0x0, regs=0xc0387f98) at
    gdbserial.c:158
    #3  0xc010937b in handle_IRQ_event (irq=3, regs=0xc0387f98, action=0xce5a9860)
    at irq.c:452
    #4  0xc0109597 in do_IRQ (regs=
          {ebx = -1072671776, ecx = -1, edx = -1070047232, esi = -1070047232, edi
    = -1070047232, ebp = -1070039092, eax = 0, xds
    = -1070071784, xes = -1070071784, orig_eax = -253, eip = -1072671729, xcs =
    16, eflags = 582, esp = -1070039072, xss = -1072671582}) at irq.c:639
    #5  0xc010c0e8 in call_do_IRQ ()

    查看jiffies变量的值
    (gdb) p jiffies
    $1 = 76153

    如果想让target上的内核继续运行,执行continue命令
    (gdb) continue
    Continuing.

    3.3.2 内核在引导时调试

    kgdb可以在内核引导时就对其进行调试,但并不是所有引导过程都是可调试的,如在kgdb 1
    .9版中,它在init/main.c的start_kernel()函数中插入以下代码:
    start_kernel()
    {
        ......
            smp_init();
    #ifdef CONFIG_KGDB
            if (gdb_enter) {
                    gdb_hook();             /* right at boot time */
            }
    #endif
        ......
    }

    所以在smp_init()之前的初始化引导过程是不能调试的。

    另外要想让target的内核在引导时就处于调试状态,需要修改其/etc/grub.conf文件为如下
    形式:
    title Red Hat Linux (2.4.23-kgdb)
        root (hd0,0)
        kernel /boot/vmlinuz-2.4.23-kgdb ro root=/dev/hda1 gdb gdbttyS=1 gdbbaud=115
    200

    *在target机器上

    引导2.4.23-kgdb内核,内核将在短暂的运行后暂停并进入调试状态,打印如下信息:
    Waiting for connection from remote gdb...

    *在developer机器上

    #cd /home/liangjian/linux-2.4.23
    # gdb vmlinux
    GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
    Copyright 2003 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i386-redhat-linux-gnu"...

    执行rmt宏
    (gdb) rmt
    breakpoint () at kgdbstub.c:1005
    1005                    atomic_set(&kgdb_setting_breakpoint, 0);

    查看当前堆栈
    (gdb) bt
    #0  breakpoint () at kgdbstub.c:1005
    #1  0xc0387fe0 in init_task_union ()
    #2  0xc01bc984 in gdb_hook () at gdbserial.c:250
    #3  0xc0388898 in start_kernel () at init/main.c:443

    在do_basic_setup函数处设置断点,并让内核恢复运行
    (gdb) b do_basic_setup
    Breakpoint 1 at 0xc0388913: file current.h, line 9.
    (gdb) continue
    Continuing.
    [New Thread 1]
    [Switching to Thread 1]

    Breakpoint 1, do_basic_setup () at current.h:9
    9               __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));

    内核在do_basic_setup断点处停止运行后查看当前堆栈
    (gdb) bt
    #0  do_basic_setup () at current.h:9
    (gdb)

    3.3.3 内核模块调试调试

    要想调试内核模块,需要相应的gdb支持,kgdb的主页上提供了一个工具gdbmod,它修正了g
    db 6.0在解析模块地址时的错误,可以用来正确的调试内核模块

    *在developer机器上

    写了个测试用的内核模块orig,如下:
    void xcspy_func()
    {
        printk("<1>xcspy_func/n");
        printk("<1>aaaaaaaaaaa/n");
    }

    int xcspy_init()
    {
        printk("<1>xcspy_init_module/n");
           
        return 0;
    }

    void xcspy_exit()
    {
        printk("<1>xcspy_cleanup_module/n");
    }

    module_init(xcspy_init);
    module_exit(xcspy_exit);

    编译该模块:
    #cd /home/liangjian/lkm
    #gcc -D__KERNEL__ -DMODULE -I/home/liangjian/linux-2.4.23/include -O -Wall -g -c
     -o orig.o orig.c
    #scp orig.o root@192.168.16.30:/root

    开始调试:
    # gdbmod vmlinux
    GNU gdb 6.0
    Copyright 2003 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i686-pc-linux-gnu"...

    设置符号文件的搜索路径
    (gdb) set solib-search-path /home/liangjian/lkm

    执行rmt宏
    (gdb) rmt
    breakpoint () at kgdbstub.c:1005
    1005                    atomic_set(&kgdb_setting_breakpoint, 0);

    设置断点使得可以调试内核模块的init函数,查内核源码可知,内核是通过module.c文件的
    第566行(sys_init_module函数中)mod->init来调用模块的init函数的
    (gdb) b module.c:566
    Breakpoint 1 at 0xc011cd83: file module.c, line 566.
    (gdb) c
    Continuing.
    [New Thread 1352]
    [Switching to Thread 1352]

    这时在target机器上执行insmod orig.o,developer则相应的在断点处被暂停,如下
                                                                                   
                                             
    Breakpoint 1, sys_init_module (name_user=0xc03401bc "/001",
    mod_user=0x80904d8) at module.c:566
    566             if (mod->init && (error = mod->init()) != 0) {

    使用step命令进入模块的init函数
    (gdb) step
    xcspy_init () at orig.c:12
    12              printk("<1>xcspy_init_module/n");
    (gdb) n
    15      }
    (gdb)

    说明:
    调试内核模块的非init函数相对比较简单,只要先在target上执行insmod orig.o,这时由于
    模块的符号被加载,可以直接在developer的gdb中对想调试的模块函数设置断点,如bt xcs
    py_func,后面当xcspy_func被调用时就进入了调试状态。
    如果想调试内核模块的init函数,由于在执行insmod之前模块的符号还没有被加载,不能直
    接对模块的init函数设置断点,所以相对来说要困难一些。可以采用两种变通的方法:1,采
    用上面介绍的在内核调用模块的init函数被调用之前的某处插入断点,如bt sys_init_modu
    le()或bt module.c:566;2,在developer上让内核处于运行状态,在target上先执行一遍in
    smod orig.o,这时orig.o的符号已经被加载到内存中,可以直接在developer的gdb中对模块
    的init函数设置断点,如bt xcspy_init,然后在target上rmmod orig.o,当下次在target上
    重新加载orig.o时就进入了调试状态,developer在xcspy_init处被暂停。 

    展开全文
  • 使用kgdb调试linux内核内核模块创建时间:2005-09-09文章属性:原创文章提交:xcspy (xcspy.com_at_gmail.com)作者:xcspy成员 ladybugE-mail:xcspy.com@gmail.com主页:www.xcspy.com1. 几种内核调试工具比较kdb...
  • 使用kgdb调试linux内核内核模块创建时间:2005-09-09文章属性:原创文章提交:xcspy (xcspy.com_at_gmail.com)作者:xcspy成员 ladybugE-mail:xcspy.com@gmail.com主页:www.xcspy.com1. 几种内核调试工具比较kdb...
  • Linux内核模块详解

    万次阅读 多人点赞 2019-08-26 09:22:36
    内核模块 实验目的 内核模块是Linux操作系统中一个比较独特的机制。通过这一章学习,希望能够理解Linux提出内核模块这个机制的意义;理解并掌握Linux实现内核模块机制的基本技术路线;运用Linux提供的工具和命令,...
  • linux内核模块笔记

    千次阅读 2014-12-21 20:58:43
    linux内核介绍 3. 内核的编译和安装(x86) 4. 第一个模块 5. 模块的相关工具 6. 模块的符号导出 7. 模块的参数 作业: 1.看linux/module.h。以后每天看课程中接触到的头文件 这个文件所在的位置:/home/zshh/...
  • 简介: 为保持 Linux 内核的稳定与可持续发展...内核可装载模块就是可在内核运行时加载到内核的一组代码。通常 , 我们会在两个版本不同的内核上装载同一模块失败,即使是在两个相邻的补丁级(Patch Level)版本上。
  • 内核模块的加载

    千次阅读 2015-04-27 17:49:46
    一般linux中有两个程序可以添加内核模块,modprobe和insmod,前者考虑到了各个模块之间可能出现的依赖关系,被依赖的模块会被自动载入,而insmod只是简单的尝试载入当前的模块。二者最终都是通过linux系统调用sys_...
  • Linux内核模块简介

    千次阅读 2016-08-27 10:22:12
    Linux内核模块简介
  • 调试linux内核模块

    千次阅读 2012-10-01 14:42:50
     最近几天学习Linux-2.6平台上的设备驱动,所以要建立内核内核模块的调试平台.虽然网上有很多相关教程,但多是基于2.6.26以前的通过补丁安装的,过程非常复杂,而且问题比较多.linux从 2.6.26开始已经集成了kgdb,只...
  • Linux内核模块设计

    千次阅读 2010-11-06 12:53:00
    UNIT 1 Linux内核模块设计             1. 单体内核 VS 微内核 2. Hello,kernel模块实例 3. 内核模块的Makefile 4. 模块的加载与测试 5. 内核...
  • 通过在系统运行期间,加载内核模块来动态的扩展系统该功能而无需重启系统,更无须为这新增添的功能重新编译一个新的系统内核映像。 1. ELF文件格式解析 内核模块采用ELF(Executableand Linkable Format )格式作为...
  • linux内核模块的参数传递

    千次阅读 2019-06-26 22:33:02
    模块安装时候可以给模块中的变量传递数值,安装后,模块中变量的值就是安装时所传入的值 ,没有传递的变量,则使用代码中默认值。 带参数的模块安装后会生成目录: /sys/module/模块名/parameters/ 示例:如果安装 ...
  • 使用内核模块的方式添加系统调用 ...在内核模块中实现系统调用函数,修改映射在内存中的系统调用表,把一个空闲的系统调用表项指向自己写的模块中的函数。具体步骤如下: a. 找系统调用表在内存中的位置;
  • Linux内核模块分析(module_init宏)

    千次阅读 2016-05-17 03:25:13
    我们在学习Linux驱动开发时,首先需要了解Linux的模块化机制(module),但是module并不仅仅用于支撑驱动的加载和卸载。一个最简单的模块例子如下:// filename: HelloWorld.c#include #include <linux/init.h>...
  • 密钥在内核代码中称为key,因为key是由用户态进程创建,由内核管理,其实体存储在内核申请的内存中,所以密钥管理需要实施配额管理。密钥有对称密钥和非对称密钥两大类,每类密钥又有很多种。密钥种类不同,payload...
  • Linux内核模块基础

    2013-07-06 19:28:07
    Linux内核模块基础 1内核简单模块的编写 通过命令date可以获取当前系统时间,如下面示例。 下面我们通过编写一个简单的内核模块直接获取当前系统时间。 1.1模块源码编写 在Linux内核源码中,...
  • Linux2.6允许用户insmod的时候往内核模块里面传递参数,它主要使用module_param宏定义来实现这一功能。module_param的定义可以在include/linux/moduleparam.h文件里面查看到,它的原型为:module_param(name, type, ...
  • linux内核模块传参

    千次阅读 2011-09-28 14:34:53
    module_param()理解 ------------------------------------------- 在用户态下编程可以通过main()的来传递命令行参数,而编写一个内核模块则通过module_param() module_param()宏是Linux
  • Linux内核模块编程-系统调用拦截

    千次阅读 2015-11-16 22:15:48
    系统调用拦截本文实验基于Centos6.5 内核...通过学习系统调用的内核实现我们发现其实系统调用的地址是放在sys_call_table中通过系统调用号定位到具体的系统调用地址,然后开始调用,那么通过编写内核模块修改sys_c
  • 内核里使用内存 内存使用,无非就是申请、复制、设置、释放。在 C 语言里,它们对应的函数是:malloc、memcpy、memset、free;在内核编程里,他们分别对应 ExAllocatePool、RtlMoveMemory、 RtlFillMemory、...
  • 内存寻址 、硬件中的分段与分页 、Linux内存管理 页与内存管理区 、kmalloc()和vmalloc()
  • 模块是Linux高效利用微内核,同时不会降低系统性能与优点的一种方法。几乎Linux内核的每个高层组件 --- 文件系统、设备驱动、网络,都可以作为模块进行编译。Linux的发布版,充分使用模块方式全面地支持多种品牌...
  • 内核添加自己的模块

    千次阅读 2012-06-17 20:35:48
    内核添加自己的模块 http://www.cnblogs.com/timkyle/archive/2012/04/13/2444975.html 说明: 我开发板的内核启动参数环境变量bootargs内容为root=/dev/nfs nfsroot=192.168.1.10:/nfsroot ip=192....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 40,729
精华内容 16,291
关键字:

修改内核内存属性模块