五。内核代码调试方法——proc文件系统、seqfile文件系统
2013-11-05 22:32
281 查看
如有错误大家一定告诉我,一起学习了;
############## proc 文件系统 ##################
1、 mount -t proc none /proc
ps ---> /proc/(每个结构体(每个进程)在这创建一个目录。以pid名字命名,进程的状态,关系等属性都是内核写在相应的目录下)
内核:找的是proc文件系统,我们只是通过上面的命令挂载到/proc下,找的不是proc目录,但是用户态的ps命令只会在proc目录下找,所以习惯放在proc目录
task_struct(每个进程都对应这么一个结构体) ---> task_struct的list(链表) --->
创建一个新的进程内核会自动分配一个这样的结构体(task_struct),再分配一个pid,然后把父进程的页表拷贝过来,所以父子进程共享前半段,当子进程进行不同的操作时会重新写页表
这些创建都是在磁盘上创建,proc文件系统上的文件在硬盘是不存在的,是存在于内存的;所以/proc里的文件只有内核代码能够创建,我们需要写模块来执行这些操作
不能这么创建,在/proc 下进行下列操作是错误的
mkdir /proc/test X(错)
touch /proc/test/hello X(错)
2、功能:
1>.调试:
a.printk
b.创建/proc/test/hello 打印到这个文件中。代替printk
2>.给内核传数据:
echo abc > /proc/test/hello
hello文件不能容纳数据,只是一个标识,是内核接口;abc的内容是传到内核的。
3、proc文件系统的头文件,包含各种函数的实现
<linux>/include/linux/proc_fs.h
struct proc_dir_entry{ //proc目录每个文件都对应这么一个结构体
void *data;
//这个值是写驱动的人提前写好的,内核不会操作这个值;在调用函数时会把这个值传给读写函数,无用就是NULL
//这是一个指针
read_proc_t *read_proc; //proc下文件的读函数指针
write_proc_t *write_proc; //proc下文件的写函数指针
loff_t size;//偏移
const struct inode_operations *proc_iops;//该文件的一组操作
... //还包含其它的很多
};
当执行 cat /proc/test/hello 时,调用的就是read_proc
当执行 echo abc > /proc/test/hello 时,调用的就是write_proc
create_proc_entry 创建一个proc文件
remove_proc_entry 删除一个proc文件
proc_mkdir 创建一个目录
proc_symlink 创建一个符号链接
create_proc_read_entry 创建一个只读的proc文件
proc_create_data 创建seqfile文件,proc存在问题,seqfile是用来解决proc函数一次只能读一页(4K)数据的问题;seqfile文件系统是自动检测分配内存的,不够时会自动给添加一页
4、为什么在写内核模块函数的时候加上 static?
答:内核模块函数默认是 static 的,但是内核默认是 extern,加上 static 就是 静态的;
又因为最后内核模块的函数最后都会被写到内核中,为了以后方便,也是一个习惯,就都加上
5、参考代码 <path>/02proc/*
6、在内核环境中,一定要注意出错处理,出错要将之前占用的全部资源释放
######################################
# 错误码的出处:
# include/asm-generic/errno.h
# include/asm-generic/errno-base.h
######################################
7、proc文件系统读函数
//先打开一个文件 fd = open("/proc/test_dir/test_att", xx(权限))
//用户态读 read(fd, buf, len)
//内核分配一页内存(4K)(page)
//len ---> count 读取长度
//*eof = 1;代表文件读取结束
//读取的时候,将读到的东西放到page内存中,结束时内核会自动将page内的东西放到buf(用户态传进来的)中
//读取大小受page大小限制,最大读4K;seqfile文件系统解决这个问题
int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data)
8、proc文件系统写函数
//ret = write(fd, buf, len)
//struct file *file ---> 就是用户态的 FILE *,fopen 打开的文件流;封装后在用户态无法看到这个结构体
//__user 代表是用户态分配的缓存;[4G - 1, 3G]内核缓存,[3G - 1,0]用户态缓存;两种缓存的使用方式是不一样
//buf ---> buffer
//len ---> count
//data ---> 初始化时的100,随便传的, 写内核的人自己定义的
int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data)
9、proc文件系统中从用户态拷贝
#include <asm/uaccess.h> //包含在这个头文件
//用户态 buffer ---> 内核buf
//user ---> kernel
//使用 memcpy()从内核把东西拷贝到用户态,不是一定出错,是可能出错,内核不容许隐患
因为拷贝内核的东西时会有权限问题,造成拷贝的数据不完全
//内核提供的宏定义
// min(count, 1024) //1024 是定义的 buf 的大小
// max(count, 1024)
//copy_from_user 是内核实现的函数
copy_from_user(buf, buffer, count)
############### seqfile 文件系统 ##############
1、对 proc 文件的操作只有简单的读写;对 seqfile 文件有一个操作集 ops,是一个结构体:
struct file_operations ops = {
.owner = THIS_MODULE,
.open = test_seq_open, //open,用户态,自己实现
.release = seq_release, //close ,用户态,内核实现
.llseek = seq_lseek, //lseek,用户态,内核实现
.read = seq_read, //read,用户态,内核实现
.write = test_seq_write, //write,用户态,自己实现
};
================================================
= 此结构体包含在头文件 <path>/include/linux/fs.h
= 这组操作于用户态的 I/O 操作对应
================================================
==========================================================================
= test_seq_open 自己实现的原因:因为类型不匹配,需要把 seq_open 函数封装一下
= test_seq_write 自己实现原因:因为需要我们自己决定要以什么样的方式写
=================================================================
2、seqfile 文件系统打开函数
int test_seq_open(struct inode *no, struct file *fp)
{
return seq_open(fp, &seq_ops);
}
//open--->vfs-inode file->sys_open-->test_seq_open
调用用户态的open函数,经过VFS(虚拟文件系统),进入系统调用的函数,再到test_seq_open
struct inode *nu 是在执行时内核创建的,
//seq_open 函数的 seq_ops 结构体是让 seq_read 用的
3、seq_read 函数操作:
struct seq_operations seq_ops = {
.start = seq_start,
.stop = seq_stop,
.next = seq_next,
.show = seq_show,
};
//seq_read 函数的执行过程
//read-->vfs-->sys_read-->seq_read-->start-show-next-show-next-show-......-stop
4.seq_read 的过程函数
void *seq_start(struct seq_file *m, loff_t *pos)
{
//返回第*pos个结点的指针
}
void seq_stop(struct seq_file *m, void *v)
{
//seq_start的反操作
}
//如果该函数返回一个NULL,则seq_read结束
void *seq_next(struct seq_file *m, void *v, loff_t *pos)
{
//++*pos
//返回第*pos个结点的指针
}
//v是seq_start和seq_next的返回值
int seq_show(struct seq_file *m, void *v)
{
struct item_st *tmp = v;
//ret += sprintf(page + ret, .....);
//sprintf(m->buf, "No:%d Len:%d Content:%s", tmp->no, tmp->len, tmp->content);
//在seq_read结束之后,内核会用copy_to_user(buffer, m->buf, xxxxxx)
return seq_printf(m, "No:%d Len:%d Content:%s", tmp->no, tmp->len, tmp->content);
}
5、简述 seqfile 过程:
创建seq_file
创建的时候绑定了一组操作ops(open,close,read,write,...)
这组操作用于:用户态--->VFS---->sys_open系列函数--->test_seq_open-->seq_open-->...
write里也要实现链表(自己选择的数据存储方式),把数据存住(临时)
read:start - show - next - show - next - show - stop
每一个 seq_file 都对应自己的结构体,必须在 seq_open 之前把函数保存进去,然后在read的时候才能找到这些函数
next返回个NULL,sig_read就结束了
############## proc 文件系统 ##################
1、 mount -t proc none /proc
ps ---> /proc/(每个结构体(每个进程)在这创建一个目录。以pid名字命名,进程的状态,关系等属性都是内核写在相应的目录下)
内核:找的是proc文件系统,我们只是通过上面的命令挂载到/proc下,找的不是proc目录,但是用户态的ps命令只会在proc目录下找,所以习惯放在proc目录
task_struct(每个进程都对应这么一个结构体) ---> task_struct的list(链表) --->
创建一个新的进程内核会自动分配一个这样的结构体(task_struct),再分配一个pid,然后把父进程的页表拷贝过来,所以父子进程共享前半段,当子进程进行不同的操作时会重新写页表
这些创建都是在磁盘上创建,proc文件系统上的文件在硬盘是不存在的,是存在于内存的;所以/proc里的文件只有内核代码能够创建,我们需要写模块来执行这些操作
不能这么创建,在/proc 下进行下列操作是错误的
mkdir /proc/test X(错)
touch /proc/test/hello X(错)
2、功能:
1>.调试:
a.printk
b.创建/proc/test/hello 打印到这个文件中。代替printk
2>.给内核传数据:
echo abc > /proc/test/hello
hello文件不能容纳数据,只是一个标识,是内核接口;abc的内容是传到内核的。
3、proc文件系统的头文件,包含各种函数的实现
<linux>/include/linux/proc_fs.h
struct proc_dir_entry{ //proc目录每个文件都对应这么一个结构体
void *data;
//这个值是写驱动的人提前写好的,内核不会操作这个值;在调用函数时会把这个值传给读写函数,无用就是NULL
//这是一个指针
read_proc_t *read_proc; //proc下文件的读函数指针
write_proc_t *write_proc; //proc下文件的写函数指针
loff_t size;//偏移
const struct inode_operations *proc_iops;//该文件的一组操作
... //还包含其它的很多
};
当执行 cat /proc/test/hello 时,调用的就是read_proc
当执行 echo abc > /proc/test/hello 时,调用的就是write_proc
create_proc_entry 创建一个proc文件
remove_proc_entry 删除一个proc文件
proc_mkdir 创建一个目录
proc_symlink 创建一个符号链接
create_proc_read_entry 创建一个只读的proc文件
proc_create_data 创建seqfile文件,proc存在问题,seqfile是用来解决proc函数一次只能读一页(4K)数据的问题;seqfile文件系统是自动检测分配内存的,不够时会自动给添加一页
4、为什么在写内核模块函数的时候加上 static?
答:内核模块函数默认是 static 的,但是内核默认是 extern,加上 static 就是 静态的;
又因为最后内核模块的函数最后都会被写到内核中,为了以后方便,也是一个习惯,就都加上
5、参考代码 <path>/02proc/*
6、在内核环境中,一定要注意出错处理,出错要将之前占用的全部资源释放
######################################
# 错误码的出处:
# include/asm-generic/errno.h
# include/asm-generic/errno-base.h
######################################
7、proc文件系统读函数
//先打开一个文件 fd = open("/proc/test_dir/test_att", xx(权限))
//用户态读 read(fd, buf, len)
//内核分配一页内存(4K)(page)
//len ---> count 读取长度
//*eof = 1;代表文件读取结束
//读取的时候,将读到的东西放到page内存中,结束时内核会自动将page内的东西放到buf(用户态传进来的)中
//读取大小受page大小限制,最大读4K;seqfile文件系统解决这个问题
int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data)
8、proc文件系统写函数
//ret = write(fd, buf, len)
//struct file *file ---> 就是用户态的 FILE *,fopen 打开的文件流;封装后在用户态无法看到这个结构体
//__user 代表是用户态分配的缓存;[4G - 1, 3G]内核缓存,[3G - 1,0]用户态缓存;两种缓存的使用方式是不一样
//buf ---> buffer
//len ---> count
//data ---> 初始化时的100,随便传的, 写内核的人自己定义的
int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data)
9、proc文件系统中从用户态拷贝
#include <asm/uaccess.h> //包含在这个头文件
//用户态 buffer ---> 内核buf
//user ---> kernel
//使用 memcpy()从内核把东西拷贝到用户态,不是一定出错,是可能出错,内核不容许隐患
因为拷贝内核的东西时会有权限问题,造成拷贝的数据不完全
//内核提供的宏定义
// min(count, 1024) //1024 是定义的 buf 的大小
// max(count, 1024)
//copy_from_user 是内核实现的函数
copy_from_user(buf, buffer, count)
############### seqfile 文件系统 ##############
1、对 proc 文件的操作只有简单的读写;对 seqfile 文件有一个操作集 ops,是一个结构体:
struct file_operations ops = {
.owner = THIS_MODULE,
.open = test_seq_open, //open,用户态,自己实现
.release = seq_release, //close ,用户态,内核实现
.llseek = seq_lseek, //lseek,用户态,内核实现
.read = seq_read, //read,用户态,内核实现
.write = test_seq_write, //write,用户态,自己实现
};
================================================
= 此结构体包含在头文件 <path>/include/linux/fs.h
= 这组操作于用户态的 I/O 操作对应
================================================
==========================================================================
= test_seq_open 自己实现的原因:因为类型不匹配,需要把 seq_open 函数封装一下
= test_seq_write 自己实现原因:因为需要我们自己决定要以什么样的方式写
=================================================================
2、seqfile 文件系统打开函数
int test_seq_open(struct inode *no, struct file *fp)
{
return seq_open(fp, &seq_ops);
}
//open--->vfs-inode file->sys_open-->test_seq_open
调用用户态的open函数,经过VFS(虚拟文件系统),进入系统调用的函数,再到test_seq_open
struct inode *nu 是在执行时内核创建的,
//seq_open 函数的 seq_ops 结构体是让 seq_read 用的
3、seq_read 函数操作:
struct seq_operations seq_ops = {
.start = seq_start,
.stop = seq_stop,
.next = seq_next,
.show = seq_show,
};
//seq_read 函数的执行过程
//read-->vfs-->sys_read-->seq_read-->start-show-next-show-next-show-......-stop
4.seq_read 的过程函数
void *seq_start(struct seq_file *m, loff_t *pos)
{
//返回第*pos个结点的指针
}
void seq_stop(struct seq_file *m, void *v)
{
//seq_start的反操作
}
//如果该函数返回一个NULL,则seq_read结束
void *seq_next(struct seq_file *m, void *v, loff_t *pos)
{
//++*pos
//返回第*pos个结点的指针
}
//v是seq_start和seq_next的返回值
int seq_show(struct seq_file *m, void *v)
{
struct item_st *tmp = v;
//ret += sprintf(page + ret, .....);
//sprintf(m->buf, "No:%d Len:%d Content:%s", tmp->no, tmp->len, tmp->content);
//在seq_read结束之后,内核会用copy_to_user(buffer, m->buf, xxxxxx)
return seq_printf(m, "No:%d Len:%d Content:%s", tmp->no, tmp->len, tmp->content);
}
5、简述 seqfile 过程:
创建seq_file
创建的时候绑定了一组操作ops(open,close,read,write,...)
这组操作用于:用户态--->VFS---->sys_open系列函数--->test_seq_open-->seq_open-->...
write里也要实现链表(自己选择的数据存储方式),把数据存住(临时)
read:start - show - next - show - next - show - stop
每一个 seq_file 都对应自己的结构体,必须在 seq_open 之前把函数保存进去,然后在read的时候才能找到这些函数
next返回个NULL,sig_read就结束了
相关文章推荐
- 在linux 内核中做开关变量的三种方法—— 利用proc 、sys文件系统,字符设备等与内核进行交互
- 调试文件系统代码的方法
- proc文件系统用于内核调试
- PROC文件系统介绍 &&以PROC在线调试LCM && EXPORT_SYMBOL的用法
- 内核proc文件系统与seq接口----内核proc文件系统编程接口
- /proc文件系统用于内核调试
- 内核proc文件系统与seq接口(5)---通用proc接口与seq_file接口实验
- 用户空间与内核空间的接口:proc文件系统
- 基于/proc伪文件系统的读取系统常见内核状态信息
- 用户空间和内核空间通讯之【proc文件系统】
- 使用 /sys 文件系统访问 Linux 内核:比/proc 更为理想的访问内核数据的途径
- [Android L]SEAndroid开放设备文件结点权限(读或写)方法(涵盖常用操作:sys/xxx、proc/xxx、SystemProperties)热门干货
- Nfs、tftp 联合运行调试内核及文件系统
- 嵌入式 内核中针对proc文件系统的编程函数总结
- 【移植Linux 3.4.2内核之四】修改内核代码支持YAFFS文件系统
- 使用qemu模拟调试内核和debian根文件系统
- 内核proc文件系统与seq接口(2)---内核proc文件系统编程接口
- [译]5.10. Tuning via /procs Filesystem 通过/proc文件系统来调整内核模块
- [Android L]SEAndroid开放设备文件结点权限(读或写)方法(涵盖常用操作:sys/xxx、proc/xxx、SystemProperties)
- 驱动程序调试方法之printk——自制proc文件(一)