ktap代码分析笔记 (1) —— ktap.c

ktap.c源码如下(省去版权信息):

#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
#error "Currently ktap don't support kernel older than 3.1"
#endif

#if !CONFIG_EVENT_TRACING
#error "Please enable CONFIG_EVENT_TRACING before compile ktap"
#endif

#if !CONFIG_PERF_EVENTS
#error "Please enable CONFIG_PERF_EVENTS before compile ktap"
#endif

#include <linux/module.h>
#include <linux/errno.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include "../include/ktap_types.h"
#include "ktap.h"
#include "kp_bcread.h"
#include "kp_vm.h"

/* common helper function */
long gettimeofday_ns(void)
{
    struct timespec now;

    getnstimeofday(&now);
    return now.tv_sec * NSEC_PER_SEC + now.tv_nsec;
}

static int load_trunk(ktap_option_t *parm, unsigned long **buff)
{
    int ret;
    unsigned long *vmstart;

    vmstart = vmalloc(parm->trunk_len);
    if (!vmstart)
        return -ENOMEM;

    ret = copy_from_user(vmstart, (void __user *)parm->trunk,
                 parm->trunk_len);
    if (ret < 0) {
        vfree(vmstart);
        return -EFAULT;
    }

    *buff = vmstart;
    return 0;
}

static struct dentry *kp_dir_dentry;

/* Ktap Main Entry */
static int ktap_main(struct file *file, ktap_option_t *parm)
{
    unsigned long *buff = NULL;
    ktap_state_t *ks;
    ktap_proto_t *pt;
    long start_time, delta_time;
    int ret;

    start_time = gettimeofday_ns();

    ks = kp_vm_new_state(parm, kp_dir_dentry);
    if (unlikely(!ks))
        return -ENOEXEC;

    file->private_data = ks;

    ret = load_trunk(parm, &buff);
    if (ret) {
        kp_error(ks, "cannot load file\n");
        goto out;
    }

    pt = kp_bcread(ks, (unsigned char *)buff, parm->trunk_len);

    vfree(buff);

    if (pt) {
        /* validate byte code */
        if (kp_vm_validate_code(ks, pt, ks->stack))
            goto out;

        delta_time = (gettimeofday_ns() - start_time) / NSEC_PER_USEC;
        kp_verbose_printf(ks, "booting time: %d (us)\n", delta_time);

        /* enter vm */
        kp_vm_call_proto(ks, pt);
    }

 out:
    kp_vm_exit(ks);
    return ret;
}


static void print_version(void)
{
}

static long ktap_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    ktap_option_t parm;
    int ret;

    switch (cmd) {
    case KTAP_CMD_IOC_VERSION:
        print_version();
        return 0;
    case KTAP_CMD_IOC_RUN:
        /*
         * must be root to run ktap script (at least for now)
         *
         * TODO: check perf_paranoid sysctl and allow non-root user
         * to use ktap for tracing process(like uprobe) ?
         */
        if (!capable(CAP_SYS_ADMIN))
            return -EACCES;

        ret = copy_from_user(&parm, (void __user *)arg,
                     sizeof(ktap_option_t));
        if (ret < 0)
            return -EFAULT;

        return ktap_main(file, &parm);
    default:
        return -EINVAL;
    };

        return 0;
}

static const struct file_operations ktap_fops = {
    .llseek                 = no_llseek,
    .unlocked_ioctl         = ktap_ioctl,
};

static long ktapvm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int new_fd, err;
    struct file *new_file;

    new_fd = get_unused_fd_flags(0);
    if (new_fd < 0)
        return new_fd;

    new_file = anon_inode_getfile("[ktap]", &ktap_fops, NULL, O_RDWR);
    if (IS_ERR(new_file)) {
        err = PTR_ERR(new_file);
        put_unused_fd(new_fd);
        return err;
    }

    file->private_data = NULL;
    fd_install(new_fd, new_file);
    return new_fd;
}

static const struct file_operations ktapvm_fops = {
    .owner  = THIS_MODULE,
    .unlocked_ioctl         = ktapvm_ioctl,
};

int (*kp_ftrace_profile_set_filter)(struct perf_event *event, int event_id,
                    const char *filter_str);

struct syscall_metadata **syscalls_metadata;

/*TODO: kill this function in future */
static int __init init_dummy_kernel_functions(void)
{
    unsigned long *addr;

    /*
     * ktap need symbol ftrace_profile_set_filter to set event filter, 
     * export it in future. 
     */
#ifdef CONFIG_PPC64
    kp_ftrace_profile_set_filter =
        (void *)kallsyms_lookup_name(".ftrace_profile_set_filter");
#else
    kp_ftrace_profile_set_filter =
        (void *)kallsyms_lookup_name("ftrace_profile_set_filter");
#endif
    if (!kp_ftrace_profile_set_filter) {
        pr_err("ktap: cannot lookup ftrace_profile_set_filter "
            "in kallsyms\n");
        return -1;
    }

    /* use syscalls_metadata for syscall event handling */
    addr = (void *)kallsyms_lookup_name("syscalls_metadata");
    if (!addr) {
        pr_err("ktap: cannot lookup syscalls_metadata in kallsyms\n");
        return -1;
    }

    syscalls_metadata = (struct syscall_metadata **)*addr;
    return 0;
}

static int __init init_ktap(void)
{
    struct dentry *ktapvm_dentry;

    if (init_dummy_kernel_functions())
        return -1;

    kp_dir_dentry = debugfs_create_dir("ktap", NULL);
    if (!kp_dir_dentry) {
        pr_err("ktap: debugfs_create_dir failed\n");
        return -1;
    }

    ktapvm_dentry = debugfs_create_file("ktapvm", 0444, kp_dir_dentry, NULL,
                        &ktapvm_fops);

    if (!ktapvm_dentry) {
        pr_err("ktapvm: cannot create ktapvm file\n");
        debugfs_remove_recursive(kp_dir_dentry);
        return -1;
    }

    return 0;
}

static void __exit exit_ktap(void)
{
    debugfs_remove_recursive(kp_dir_dentry);
}

module_init(init_ktap);
module_exit(exit_ktap);

MODULE_AUTHOR("Jovi Zhangwei <jovi.zhangwei@gmail.com>");
MODULE_DESCRIPTION("ktap");
MODULE_LICENSE("GPL");

int kp_max_loop_count = 100000;
module_param_named(max_loop_count, kp_max_loop_count, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_loop_count, "max loop execution count"); 

(1)

#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0)
#error "Currently ktap don't support kernel older than 3.1"
#endif

#if !CONFIG_EVENT_TRACING
#error "Please enable CONFIG_EVENT_TRACING before compile ktap"
#endif

#if !CONFIG_PERF_EVENTS
#error "Please enable CONFIG_PERF_EVENTS before compile ktap"
#endif

ktap目前只能在3.1.0以上的kernel版本上运行,并且要有perf的支持。

(2)

module_init(init_ktap);
module_exit(exit_ktap);

MODULE_AUTHOR("Jovi Zhangwei <jovi.zhangwei@gmail.com>");
MODULE_DESCRIPTION("ktap");
MODULE_LICENSE("GPL");

int kp_max_loop_count = 100000;
module_param_named(max_loop_count, kp_max_loop_count, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_loop_count, "max loop execution count"); 

以上定义了一些ktapvm.ko这个内核模块的一些信息。

(3)

static int __init init_dummy_kernel_functions(void)
{
    unsigned long *addr;

    /*
     * ktap need symbol ftrace_profile_set_filter to set event filter, 
     * export it in future. 
     */
#ifdef CONFIG_PPC64
    kp_ftrace_profile_set_filter =
        (void *)kallsyms_lookup_name(".ftrace_profile_set_filter");
#else
    kp_ftrace_profile_set_filter =
        (void *)kallsyms_lookup_name("ftrace_profile_set_filter");
#endif
    if (!kp_ftrace_profile_set_filter) {
        pr_err("ktap: cannot lookup ftrace_profile_set_filter "
            "in kallsyms\n");
        return -1;
    }

    /* use syscalls_metadata for syscall event handling */
    addr = (void *)kallsyms_lookup_name("syscalls_metadata");
    if (!addr) {
        pr_err("ktap: cannot lookup syscalls_metadata in kallsyms\n");
        return -1;
    }

    syscalls_metadata = (struct syscall_metadata **)*addr;
    return 0;
}

static int __init init_ktap(void)
{
    struct dentry *ktapvm_dentry;

    if (init_dummy_kernel_functions())
        return -1;

    kp_dir_dentry = debugfs_create_dir("ktap", NULL);
    if (!kp_dir_dentry) {
        pr_err("ktap: debugfs_create_dir failed\n");
        return -1;
    }

    ktapvm_dentry = debugfs_create_file("ktapvm", 0444, kp_dir_dentry, NULL,
                        &ktapvm_fops);

    if (!ktapvm_dentry) {
        pr_err("ktapvm: cannot create ktapvm file\n");
        debugfs_remove_recursive(kp_dir_dentry);
        return -1;
    }

    return 0;
}

static void __exit exit_ktap(void)
{
    debugfs_remove_recursive(kp_dir_dentry);
}

module_init(init_ktap);
module_exit(exit_ktap);

ktapvm.ko的加载函数init_ktap会创建/sys/kernel/debug/ktap/这个文件夹,并在下面创建ktapvm文件。kallsyms_lookup_name函数则用来查找指定symbol的内存地址,而syscalls_metadata在目前代码中并没有使用。卸载模块函数exit_ktap则会删除/sys/kernel/debug/ktap/这个文件夹以及文件夹下的所有文件。

(4)

static const struct file_operations ktapvm_fops = {
    .owner  = THIS_MODULE,
    .unlocked_ioctl         = ktapvm_ioctl,
};

以上代码定义了ktapvm.ko的核心函数:ktapvm_ioctl,对这个模块的所有的操作都是通过ktapvm_ioctl函数完成。

(5)

static long ktapvm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int new_fd, err;
    struct file *new_file;

    new_fd = get_unused_fd_flags(0);
    if (new_fd < 0)
        return new_fd;

    new_file = anon_inode_getfile("[ktap]", &ktap_fops, NULL, O_RDWR);
    if (IS_ERR(new_file)) {
        err = PTR_ERR(new_file);
        put_unused_fd(new_fd);
        return err;
    }

    file->private_data = NULL;
    fd_install(new_fd, new_file);
    return new_fd;
}

ktapvm模块只提供了一个ioctl函数:ktapvm_ioctl,而这个函数的作用就是生成一个[ktap]的文件描述符。

(6)

static long ktap_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    ktap_option_t parm;
    int ret;

    switch (cmd) {
    case KTAP_CMD_IOC_VERSION:
        print_version();
        return 0;
    case KTAP_CMD_IOC_RUN:
        /*
         * must be root to run ktap script (at least for now)
         *
         * TODO: check perf_paranoid sysctl and allow non-root user
         * to use ktap for tracing process(like uprobe) ?
         */
        if (!capable(CAP_SYS_ADMIN))
            return -EACCES;

        ret = copy_from_user(&parm, (void __user *)arg,
                     sizeof(ktap_option_t));
        if (ret < 0)
            return -EFAULT;

        return ktap_main(file, &parm);
    default:
        return -EINVAL;
    };

        return 0;
}

static const struct file_operations ktap_fops = {
    .llseek                 = no_llseek,
    .unlocked_ioctl         = ktap_ioctl,
};

[ktap]文件的ioctl操作函数是ktap_ioctl,它的核心功能就是从user-space空间拷贝ktap_option_t,然后调用ktap_main函数执行ktap命令。

(7)

/* common helper function */
long gettimeofday_ns(void)
{
    struct timespec now;

    getnstimeofday(&now);
    return now.tv_sec * NSEC_PER_SEC + now.tv_nsec;
}

static int load_trunk(ktap_option_t *parm, unsigned long **buff)
{
    int ret;
    unsigned long *vmstart;

    vmstart = vmalloc(parm->trunk_len);
    if (!vmstart)
        return -ENOMEM;

    ret = copy_from_user(vmstart, (void __user *)parm->trunk,
                 parm->trunk_len);
    if (ret < 0) {
        vfree(vmstart);
        return -EFAULT;
    }

    *buff = vmstart;
    return 0;
}

gettimeofday_ns返回当前的纳秒值,而load_trunk则从user-space空间拷贝ktap命令。

(8)

static struct dentry *kp_dir_dentry;

/* Ktap Main Entry */
static int ktap_main(struct file *file, ktap_option_t *parm)
{
    unsigned long *buff = NULL;
    ktap_state_t *ks;
    ktap_proto_t *pt;
    long start_time, delta_time;
    int ret;

    start_time = gettimeofday_ns();

    ks = kp_vm_new_state(parm, kp_dir_dentry);
    if (unlikely(!ks))
        return -ENOEXEC;

    file->private_data = ks;

    ret = load_trunk(parm, &buff);
    if (ret) {
        kp_error(ks, "cannot load file\n");
        goto out;
    }

    pt = kp_bcread(ks, (unsigned char *)buff, parm->trunk_len);

    vfree(buff);

    if (pt) {
        /* validate byte code */
        if (kp_vm_validate_code(ks, pt, ks->stack))
            goto out;

        delta_time = (gettimeofday_ns() - start_time) / NSEC_PER_USEC;
        kp_verbose_printf(ks, "booting time: %d (us)\n", delta_time);

        /* enter vm */
        kp_vm_call_proto(ks, pt);
    }

 out:
    kp_vm_exit(ks);
    return ret;
}

ktap_main是运行ktap命令的函数,关于其中调用其它函数的细节,会在其它部分讨论,此处不再赘述。

 

Linux kernel 笔记 (37)——”system.map”和“/proc/kallsyms”

system.map包含kernel image的符号表。/proc/kallsyms则包含kernel image和所有动态加载模块的符号表。如果一个函数被编译器内联(inline)或者优化掉了,则它在/proc/kallsyms有可能找不到。

此外,如果不是root用户,则显示/proc/kallsyms中的地址都是0

$ cat /proc/kallsyms | more
0000000000000000 A irq_stack_union
0000000000000000 A __per_cpu_start
0000000000000000 A cpu_debug_store
0000000000000000 A cpu_tss_rw
......

$ sudo cat /proc/kallsyms | more
[sudo] password for xiaonan:
0000000000000000 A irq_stack_union
0000000000000000 A __per_cpu_start
0000000000004000 A cpu_debug_store
0000000000005000 A cpu_tss_rw
0000000000008000 A gdt_page
0000000000009000 A exception_stacks
......

看起来kallsyms_lookup_name需要CONFIG_KALLSYMS_ALL设置为Y(参考CONFIG_KALLSYMS_ALL)。

Module.symvers包含了kernel所有exportsymbols(参考What is the purpose of “Module.symvers” in Linux?)。这个链接讲了/proc/kallsyms,可以和Module.symvers对比。

参考资料:

Reading kallsyms in user-mode ;
Does kallsyms have all the symbol of kernel functions?
System.map file and /proc/kallsyms
system.map

 

Linux kernel 笔记 (36)——”procfs”简介

Procfs是一个RAM-based虚拟文件系统,挂载在proc目录下。proc就像系统的一面镜子,通过它可以得到运行系统的很多信息。 /proc中的文件是在访问时由kernel动态生成的。

dl980-5:/proc # ls
1     1166  1234  1452  170   198   243   287   308   3334  372   416   46    503  550   5989  640   756   911  960        execdomains
10    1167  1236  1453  1702  199   244   2872  3087  334   373   4163  460   504  551   599   641   7591  912  961        fb
100   1168  1237  146   1703  2     245   2873  309   3342  374   417   461   505  552   6     642   76    913  962        filesystems
1003  1169  124   147   1704  20    246   2876  3093  3344  375   418   462   506  553   60    643   764   914  963        fs
1007  117   1240  1478  1706  200   247   2877  31    335   376   419   4627  507  554   600   645   77    915  964        interrupts
1008  1170  1241  1479  171   201   248   288   310   3352  377   42    463   508  555   601   646   78    916  965        iomem
1009  1171  1242  148   172   2018  249   2881  311   3358  378   420   464   509  556   602   647   7818  917  966        ioports
101   1172  1243  149   1721  202   25    2884  312   336   379   421   4646  51   557   603   648   8     918  967        ipmi
1010  1173  1244  15    1729  203   250   289   313   3360  38    422   465   510  558   604   649   80    919  968        irq
1011  1174  1245  150   173   204   251   2890  3137  3361  380   423   466   511  56    605   65    81    92   969        kallsyms
1012  1175  1246  151   1736  205   252   29    3139  337   381   424   467   512  560   6052  650   82    920  97         kcore
1013  1176  1247  152   1737  206   253   290   314   338   382   425   468   513  561   6058  651   83    921  970        key-users
1015  1177  1248  1520  174   2060  254   2908  315   3389  3827  426   469   514  562   606   652   84    922  971        kmsg
1016  1178  1249  1522  175   207   255   291   3155  339   383   427   47    515  563   607   653   8461  923  972        kpagecount
1017  1179  125   1529  1751  208   256   2911  3156  34    384   428   470   516  564   608   654   85    924  973        kpageflags
1018  118   1250  153   1755  209   257   2912  3158  340   385   429   471   517  565   6086  655   86    925  974        latency_stats
1019  1180  1251  154   176   21    258   2915  316   341   386   43    472   518  566   609   656   87    926  975        loadavg
102   1181  1252  155   177   210   259   292   3161  342   387   430   473   519  567   61    657   874   927  976        locks
1025  1182  1253  156   178   211   26    2921  3163  3426  388   431   475   52   568   610   658   876   928  977        meminfo
103   1183  1254  157   1787  212   260   2927  3166  343   389   432   476   520  57    611   659   877   929  978        misc
1042  1186  1255  158   1788  213   261   293   317   344   390   433   477   521  570   612   66    879   93   98         modules
1044  1187  1259  16    179   215   262   2932  318   345   391   434   4777  522  5708  613   660   88    930  980        mounts
1045  1188  126   160   1790  216   263   2939  3183  346   392   435   478   523  571   614   661   880   931  981        mtrr
....

数字代表的是进程号,也是一个目录,通过/proc/pid就可以得到这个进程的信息。其它像kmsgmeminfo等则提供了系统的其它信息。

参考资料:
EXPLORING LINUX PROCFS VIA SHELL SCRIPTS

 

Linux kernel 笔记 (35)——”linux/version.h”文件

<linux/version.h>是由顶级目录下的Makefile生成的:

......
define filechk_version.h
    (echo \#define LINUX_VERSION_CODE $(shell                         \
    expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
    echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef

$(version_h): $(srctree)/Makefile FORCE
    $(call filechk,version.h)
    $(Q)rm -f $(old_version_h)
......

它包含了LINUX_VERSION_CODEKERNEL_VERSION这两个macro定义。以下面这个版本为例:

......
#define LINUX_VERSION_CODE 199680
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
......

199680对应3.12.0版本。

参考资料:
How the “<linux/version.h>” file is generated?

 

Linux kernel 笔记 (34)——模块参数

module_parammodule_param_named定义在<linux/moduleparam.h>文件:

/**
 * module_param - typesafe helper for a module/cmdline parameter
 * @value: the variable to alter, and exposed parameter name.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
 * ".") the kernel commandline parameter.  Note that - is changed to _, so
 * the user can use "foo-bar=1" even for variable "foo_bar".
 *
 * @perm is 0 if the the variable is not to appear in sysfs, or 0444
 * for world-readable, 0644 for root-writable, etc.  Note that if it
 * is writable, you may need to use kparam_block_sysfs_write() around
 * accesses (esp. charp, which can be kfreed when it changes).
 *
 * The @type is simply pasted to refer to a param_ops_##type and a
 * param_check_##type: for convenience many standard types are provided but
 * you can create your own by defining those variables.
 *
 * Standard types are:
 *  byte, short, ushort, int, uint, long, ulong
 *  charp: a character pointer
 *  bool: a bool, values 0/1, y/n, Y/N.
 *  invbool: the above, only sense-reversed (N = true).
 */
#define module_param(name, type, perm)              \
    module_param_named(name, name, type, perm)

/**
 * module_param_named - typesafe helper for a renamed module/cmdline parameter
 * @name: a valid C identifier which is the parameter name.
 * @value: the actual lvalue to alter.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * Usually it's a good idea to have variable names and user-exposed names the
 * same, but that's harder if the variable must be non-static or is inside a
 * structure.  This allows exposure under a different name.
 */
#define module_param_named(name, value, type, perm)            \
    param_check_##type(name, &(value));                \
    module_param_cb(name, &param_ops_##type, &value, perm);        \
    __MODULE_PARM_TYPE(name, #type)

module_param用来定义一个模块参数,type指定类型(intbool等等),perm指定用户访问权限,取值如下(<linux/stat.h>):

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

#define S_IRWXUGO   (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO   (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO     (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO     (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO     (S_IXUSR|S_IXGRP|S_IXOTH)

module_param_named则是为变量取一个可读性更好的名字。

ktap源码为例:

int kp_max_loop_count = 100000;
module_param_named(max_loop_count, kp_max_loop_count, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_loop_count, "max loop execution count");

加载ktapvm模块,读取kp_max_loop_count的值:

[root@Linux ~]# cat /sys/module/ktapvm/parameters/max_loop_count
100000
[root@Linux ~]# ls -lt /sys/module/ktapvm/parameters/max_loop_count
-rw-r--r--. 1 root root 4096 Oct 22 22:51 /sys/module/ktapvm/parameters/max_loop_count

可以看到kp_max_loop_count变量在/sys/module/ktapvm/parameters文件夹下的名字是max_loop_count,值是100000,只有root用户拥有写权限。可以通过修改这个文件达到改变kp_max_loop_count变量的目的:

[root@Linux ~]# echo 200000 > /sys/module/ktapvm/parameters/max_loop_count
[root@Linux ~]# cat /sys/module/ktapvm/parameters/max_loop_count
200000

MODULE_PARM_DESC用来定义参数的描述信息,使用modinfo命令可以查看:

[root@Linux ~]# modinfo ktapvm.ko
.....
parm:           max_loop_count:max loop execution count (int)

参考资料:
Everything You Wanted to Know About Module Parameters

Linux kernel 笔记 (33)——“debugfs“简介

以下摘自维基百科

debugfs is a simple to use RAM-based file system specially designed for debugging purposes. It exists as a simple way for kernel developers to make information available to user space. Unlike /proc, which is only meant for information about a process, or sysfs, which has strict one-value-per-file rules, debugfs has no rules at all. Developers can put any information they want there.

debugfs是一个用于调试目的,简单的,基于内存的文件系统。kernel的信息可以输出到debugfs中,这样方便user space程序查看和使用。

为了使用debugfs功能,编译kernel时需要把CONFIG_DEBUG_FS置成yes

典型的挂载debugfs文件系统命令:

mount -t debugfs none /sys/kernel/debug

由于没有具体设备,所以设备的位置使用了none(参考这个帖子

 

Linux kernel 笔记 (32)——“make“和”make modules“

以下摘自LKD:

After the kernel configuration is set—however you do it—you can build it with a single command:
$ make
Unlike kernels before 2.6, you no longer need to run make dep before building the kernel—the dependency tree is maintained automatically.You also do not need to specify a specific build type, such as bzImage, or build modules separately, as you did in old versions.The default Makefile rule will handle everything.

也就是在2.6版本以后的Linux kernel中,执行makemake all命令即包含了make modules。也可参加这个帖子

 

Linux kernel 笔记 (31)——“make help”命令

make help命令列出编译kernel时的选项帮助信息:

linux-4cy8:/usr/src/linux/build # make help
make -C /usr/src/linux-3.0.101-63 O=/usr/src/linux-3.0.101-63/build/. help
Cleaning targets:
  clean           - Remove most generated files but keep the config and
                    enough build support to build external modules
  mrproper        - Remove all generated files + config + various backup files
  distclean       - mrproper + remove editor backup and patch files

Configuration targets:
  config          - Update current config utilising a line-oriented program
  nconfig         - Update current config utilising a ncurses menu based program
  menuconfig      - Update current config utilising a menu based program
  xconfig         - Update current config utilising a QT based front-end
  gconfig         - Update current config utilising a GTK based front-end
  oldconfig       - Update current config utilising a provided .config as base
  localmodconfig  - Update current config disabling modules not loaded
  localyesconfig  - Update current config converting local mods to core
  silentoldconfig - Same as oldconfig, but quietly, additionally update deps
  defconfig       - New config with default from ARCH supplied defconfig
  savedefconfig   - Save current config as ./defconfig (minimal config)
  allnoconfig     - New config where all options are answered with no
  allyesconfig    - New config where all options are accepted with yes
  allmodconfig    - New config selecting modules when possible
  alldefconfig    - New config with all symbols set to default
  randconfig      - New config with random answer to all options
  listnewconfig   - List new options
  oldnoconfig     - Same as silentoldconfig but set new symbols to n (unset)

Other generic targets:
  all             - Build all targets marked with [*]
* vmlinux         - Build the bare kernel
* modules         - Build all modules
  modules_install - Install all modules to INSTALL_MOD_PATH (default: /)
  firmware_install- Install all firmware to INSTALL_FW_PATH
                    (default: $(INSTALL_MOD_PATH)/lib/firmware)
  dir/            - Build all files in dir and below
  dir/file.[oisS] - Build specified target only
  dir/file.lst    - Build specified mixed source/assembly target only
                    (requires a recent binutils and recent build (System.map))
  dir/file.ko     - Build module including final link
  modules_prepare - Set up for building external modules
  tags/TAGS       - Generate tags file for editors
  cscope          - Generate cscope index
  gtags           - Generate GNU GLOBAL index
  kernelrelease   - Output the release version string
  kernelversion   - Output the version stored in Makefile
  headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH
                    (default: /usr/src/linux-3.0.101-63/build/usr)

Static analysers
  checkstack      - Generate a list of stack hogs
  namespacecheck  - Name space analysis on compiled kernel
  versioncheck    - Sanity check on version.h usage
  includecheck    - Check for duplicate included header files
  export_report   - List the usages of all exported symbols
  headers_check   - Sanity check on exported headers
  headerdep       - Detect inclusion cycles in headers
  coccicheck      - Check with Coccinelle.

Kernel packaging:
  rpm-pkg             - Build both source and binary RPM kernel packages
  binrpm-pkg          - Build only the binary kernel package
  deb-pkg             - Build the kernel as an deb package
  tar-pkg             - Build the kernel as an uncompressed tarball
  targz-pkg           - Build the kernel as a gzip compressed tarball
  tarbz2-pkg          - Build the kernel as a bzip2 compressed tarball
  tarxz-pkg           - Build the kernel as a xz compressed tarball
  perf-tar-src-pkg    - Build perf-3.0.101.tar source tarball
  perf-targz-src-pkg  - Build perf-3.0.101.tar.gz source tarball
  perf-tarbz2-src-pkg - Build perf-3.0.101.tar.bz2 source tarball
  perf-tarxz-src-pkg  - Build perf-3.0.101.tar.xz source tarball

Documentation targets:
 Linux kernel internal documentation in different formats:
  htmldocs        - HTML
  pdfdocs         - PDF
  psdocs          - Postscript
  xmldocs         - XML DocBook
  mandocs         - man pages
  installmandocs  - install man pages generated by mandocs
  cleandocs       - clean all generated DocBook files

Architecture specific targets (x86):
* bzImage      - Compressed kernel image (arch/x86/boot/bzImage)
  install      - Install kernel using
                  (your) ~/bin/installkernel or
                  (distribution) /sbin/installkernel or
                  install to $(INSTALL_PATH) and run lilo
  fdimage      - Create 1.4MB boot floppy image (arch/x86/boot/fdimage)
  fdimage144   - Create 1.4MB boot floppy image (arch/x86/boot/fdimage)
  fdimage288   - Create 2.8MB boot floppy image (arch/x86/boot/fdimage)
  isoimage     - Create a boot CD-ROM image (arch/x86/boot/image.iso)
                  bzdisk/fdimage*/isoimage also accept:
                  FDARGS="..."  arguments for the booted kernel
                  FDINITRD=file initrd for the booted kernel

  i386_defconfig           - Build for i386
  x86_64_defconfig         - Build for x86_64

  make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build
  make V=2   [targets] 2 => give reason for rebuild of target
  make O=dir [targets] Locate all output files in "dir", including .config
  make C=1   [targets] Check all c source with $CHECK (sparse by default)
  make C=2   [targets] Force check of all c source with $CHECK
  make W=n   [targets] Enable extra gcc checks, n=1,2,3 where
                1: warnings which may be relevant and do not occur too often
                2: warnings which occur quite often but may still be relevant
                3: more obscure warnings, can most likely be ignored
                Multiple levels can be combined with W=12 or W=123
  make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections

Execute "make" or "make all" to build all targets marked with [*]
For further info see the ./README file

很有用!!

 

Linux kernel 笔记 (30)——“.ko”和“.o”文件区别

原帖参见这里

假设你编写的模块文件是mod.c,编译会生成mod.o文件。kernel编译系统还会自动生成一个mod_kmod.c文件(包含需要的kernel数据结构),编译这个文件生成另一个object文件。把mod_kmod.c所新生成的object文件和之前的mod.o文件链接生成最后的mod.ko文件。也就是可以被kernel加载运行的模块文件。