- 浏览: 137918 次
最新评论
【Linux 驱动】第四章 调试技术
1)cd linux-source-3.0.0
2)lsusb /*查看所有连接到系统的USB设备*/
3)拔掉USB设备,然后再运行一遍lsusb命令,这样就可以确定以上哪条信息是针对你的新硬件的了。
Bus 002 Device 004: ID 1e3d:2093 /*我的硬件识别信息*/
其中ID 1e3d:2093这个信息对我们很有用处,我们需要用它来查找内核中与硬件匹配的信息。1e3d代表的是厂商ID,就是哪家厂商。2093是硬件ID。
下面开始用1e3d搜索内核源码树:
4)grep -i -R-l 0403 drivers
drivers/usb/serial/ftdi_sio.mod.o
drivers/usb/serial/ftdi_sio.ko
drivers/usb/serial/ftdi_sio.mod.c
drivers/watchdog/pcwd_pci.ko
drivers/watchdog/pcwd_pci.mod.c
drivers/watchdog/pcwd_pci.mod.o
drivers/bluetooth/btusb.ko
drivers/bluetooth/btusb.mod.c
drivers/bluetooth/btusb.mod.o
drivers/media/rc/keymaps/rc-hauppauge.c
drivers/media/rc/keymaps/rc-dib0700-rc5.c
drivers/media/dvb/dvb-usb/dvb-usb-vp702x.mod.c
drivers/media/dvb/dvb-usb/nova-t-usb2.c
drivers/media/dvb/dvb-usb/dvb-usb-vp702x.ko
drivers/media/dvb/dvb-usb/dvb-usb-vp702x.mod.o
该命令执行完后,会在屏幕上显示若干条以.data .c .h等为结尾的文件,比如drivers/usb/serial/ftdi_sio.ko不用看最后一部分,前三个目录名就可以确定这是个USB串口设备。同样的判断方法,我们就可以确定我们需要的内核文件了。以防万一,我们进入这个文件中,USB驱动告诉内核它们支持哪些谁被,以便内核可以把驱动绑定到设备上。一般在一个结构体变量中列出制造商ID和设备ID。如果我们设备的制造商ID和设备ID在里面的话,说明这个驱动支持我们的硬件设备。
cd linux-3.0.0 /*进入内核文件中*/
find –type f –name Makefile | xargs grep XXXXX/*会显示一个以CONFIG_为前缀的字段*/
找到这个字段后,返回内核Makefile文件中,使用内核配置工具menuconfig,搜索这个字段。最后在该程序菜单中相应位置启动这个驱动。
- struct proc_dir_entry*create_proc_read_entry(constchar*name,mode_t mode,
- struct proc_dir_entry*base,
- read_proc_t*read_proc,void*data);
- /*创建proc文件接口
- **name:要创建的文件名称
- **mode:该文件的保护码,0表示系统默认值
- **base:指定文件所在目录,base如果为NULL,表示在proc根目录下创建该文件
- **read_proc:该文件的read_proc函数,读取该文件时调用
- **data:传递给read_proc的参数
- */
- int(*read_proc)(char*page,char**start,off_t offset,intcount,int*eof,void*data);
- /*
- **page:指针指向用来写入数据的缓冲区
- **start:返回实际的数据写到内存页得哪个位置
- **offset,count:和read方法一样
- **eof:指向一个整形数,当没有数据可返回时,驱动程序必须设置这个参数
- **data:提供给驱动程序的专用数据指针,可用于内部记录
- */
- 返回值:必须返回存放到内存页缓冲区的字节数,*eof和*start也属于返回值
- void remove_proc_entry(constchar*name,struct proc_dir_entry*base)//如果删除已卸载模块,内核会崩溃
- /*移除proc文件
- **name:文件名
- **base:目录,和创建前面一样
- */
Seq_file的实现基于proc文件。使用Seq_file,用户必须抽象出一个链接对象,然后可以依次遍历这个链接对象。这个链接对象可以是链表,数组,哈希表等等。
编程接口
Seq_file必须实现四个操作函数:start(), next(), show(), stop()。
structseq_operations{
void*(*start)(structseq_file*m,loff_t*pos);
void(*stop)(structseq_file*m,void*v);
void*(*next)(structseq_file*m,void*v,loff_t*pos);
int (*show)(structseq_file*m,void*v);
};
start():
stop():
next():
show():
对遍历对象进行操作的函数。主要是调用seq_printf(), seq_puts()之类的函数,打印出这个对象节点的信息。
下图描述了seq_file函数对一个链表的遍历。
2、重要的数据结构
除了struct seq_operations以外,另一个最重要的数据结构是structseq_file:
structseq_file{
char *buf;
size_t size;
size_t from;
size_t count;
loff_t index;
u64 version;
struct mutex lock;
const struct seq_operations *op;
void *private;
};
该结构会在seq_open函数调用中分配,然后作为参数传递给每个seq_file的操作函数。Privat变量可以用来在各个操作函数之间传递参数。
3、Seq_file使用示例:
#include/* for use of init_net*/
#include/* We're doing kernel work */
#include/* Specifically, a module */
#include/* Necessary because we use proc fs */
#include/* forseq_file*/
#definePROC_NAME"my_seq_proc"
MODULE_LICENSE("GPL");
staticvoid*my_seq_start(structseq_file*s,loff_t*pos)
{
staticunsignedlongcounter=0;
printk(KERN_INFO"Invoke start\n");
/* beginning a new sequence ? */
if(*pos==0)
{
/* yes => return a non null value to begin the sequence */
printk(KERN_INFO"pos == 0\n");
return&counter;
}
else
{
/* no => it's the end of the sequence, return end to stop reading */
*pos=0;
printk(KERN_INFO"pos != 0\n");
returnNULL;
}
}
staticvoid*my_seq_next(structseq_file*s,void*v,loff_t*pos)
{
unsignedlong*tmp_v=(unsignedlong*)v;
printk(KERN_INFO"Invoke next\n");
(*tmp_v)++;
(*pos)++;
returnNULL;
}
staticvoidmy_seq_stop(structseq_file*s,void*v)
{
printk(KERN_INFO"Invoke stop\n");
/* nothing to do, we use a static value in start() */
}
staticintmy_seq_show(structseq_file*s,void*v)
{
printk(KERN_INFO"Invoke show\n");
loff_t*spos=(loff_t*)v;
seq_printf(s,"%Ld\n",*spos);
return0;
}
staticstructseq_operations my_seq_ops={
.start=my_seq_start,
.next=my_seq_next,
.stop=my_seq_stop,
.show=my_seq_show
};
staticintmy_open(structinode*inode,structfile*file)
{
returnseq_open(file,&my_seq_ops);
};
staticstructfile_operations my_file_ops={
.owner=THIS_MODULE,
.open=my_open,
.read=seq_read,
.llseek=seq_lseek,
.release=seq_release
};
intinit_module(void)
{
structproc_dir_entry*entry;
entry=create_proc_entry(PROC_NAME,0,init_net.proc_net);
if(entry){
entry->proc_fops=&my_file_ops;
}
printk(KERN_INFO"Initialze my_seq_proc success!\n");
return0;
}
/**
* This function is called when the module is unloaded.
*
*/
voidcleanup_module(void)
{
remove_proc_entry(PROC_NAME,init_net.proc_net);
printk(KERN_INFO"Remove my_seq_proc success!\n");
}
该程序在/proc/net下注册一个my_seq_proc文件。
1. 引用空指针
Unable to handle kernel NULL pointer dereference at virtual address 00000000
printing eip:
d083a064
Oops: 0002 [#1]
SMP
CPU: 0
EIP: 0060:[<d083a064>] Not tainted
EFLAGS: 00010246 (2.6.6)
EIP is at faulty_write+0x4/0x10 [faulty]
eax: 00000000 ebx: 00000000 ecx: 00000000 edx: 00000000
esi: cf8b2460 edi: cf8b2480 ebp: 00000005 esp: c31c5f74
ds: 007b es: 007b ss: 0068
Process bash (pid: 2086, threadinfo=c31c4000 task=cfa0a6c0)
Stack: c0150558 cf8b2460 080e9408 00000005 cf8b2480 00000000 cf8b2460 cf8b2460
fffffff7 080e9408 c31c4000 c0150682 cf8b2460 080e9408 00000005 cf8b2480
00000000 00000001 00000005 c0103f8f 00000001 080e9408 00000005 00000005
Call Trace:
[<c0150558>] vfs_write+0xb8/0x130
[<c0150682>] sys_write+0x42/0x70
[<c0103f8f>] syscall_call+0x7/0xb
Code: 89 15 00 00 00 00 c3 90 8d 74 26 00 83 ec 0c b8 00 a6 83 d0
这个错误消息比较明显的,指到了空指针,位置在faulty_write 后 四个字节。
2. 堆栈被破坏
EIP: 0010:[<00000000>]
Unable to handle kernel paging request at virtual address ffffffff
printing eip:
ffffffff
Oops: 0000 [#5]
SMP
CPU: 0
EIP: 0060:[<ffffffff>] Not tainted
EFLAGS: 00010296 (2.6.6)
EIP is at 0xffffffff
eax: 0000000c ebx: ffffffff ecx: 00000000 edx: bfffda7c
esi: cf434f00 edi: ffffffff ebp: 00002000 esp: c27fff78
ds: 007b es: 007b ss: 0068
Process head (pid: 2331, threadinfo=c27fe000 task=c3226150)
Stack: ffffffff bfffda70 00002000 cf434f20 00000001 00000286 cf434f00 fffffff7
bfffda70 c27fe000 c0150612 cf434f00 bfffda70 00002000 cf434f20 00000000
00000003 00002000 c0103f8f 00000003 bfffda70 00002000 00002000 bfffda70
Call Trace:
[<c0150612>] sys_read+0x42/0x70
[<c0103f8f>] syscall_call+0x7/0xb
Code:Bad EIP value.
这个错误信息比较隐晦的。 说的是,找不到一个虚拟地址。 EIP一看就是个乱七八糟的值。
call trace不完整,只指示到了 sys_read。
造成错误的源代码是:
ssize_t faulty_read(struct file *filp, char __user *buf,size_t count, loff_t *pos)
{
int ret;
char stack_buf[4];
/* Let's try a buffer overflow */
memset(stack_buf, 0xff, 20);
if (count > 4)
count = 4; /* copy 4 bytes to the user */
ret = copy_to_user(buf, stack_buf, count);
if (!ret)
return count;
return ret;
}
相关推荐
第4章 调试技术 第5章 字符设备驱动程序的扩展操作 第6章 时间流 第7章 获取内存 第8章 硬件管理 第9章 中断处理 第10章 合理使用数据类型 第11章 kerneld和高级模块化 第12章 加载快设备驱动程序 第13章 MMAP和DMA ...
第4章 基本概念 第5章 字符设备驱动程序 第6章 串行设备驱动程序 第7章 输入设备驱动程序 第8章 I2C协议 第9章 PCMCIA和CF 第10章 PCI 第11章 USB 第12章 视频驱动程序 ...
Linux设备驱动详解【第二版】,作者宋宝华,此版PDF是经过本人整理的文字版PDF,带目录、高清无水印版。...第4篇 Linux设备驱动调试、移植 第22章 Linux设备驱动的调试 564 第23章 Linux设备驱动的移植 602
第4章 基本概念 第5章 字符设备驱动程序 第6章 串行设备驱动程序 第7章 输入设备驱动程序 第8章 I2C协议 第9章 PCMCIA和CF 第10章 PCI 第11章 USB 第12章 视频驱动程序 第13章 音频驱动程序 第14章 块...
第4章 调试技术 第5章 字符设备驱动程序的扩展操作 第6章 时间流 第7章 获取内存 第8章 硬件管理 第9章 中断处理 第10章 合理使用数据类型 第11章 kerneld和高级模块化 第十二章 加载快设备驱动程序 第十三章 MMAP...
第一天 1.Linux驱动简介 2.字符设备驱动程序设计 3.驱动调试技术 4. 并发与竞态 第二天 1.Ioctl型驱动 2.内核等待队列 3. 阻塞型驱动程序设计 4.Poll设备操作 第三天 1.Mmap设备操作 2. 硬件访问 3. 混杂...
第18章 Linux内核调试技术 第4篇 嵌入式Linux设备驱动开发篇 第19章 字符设备驱动程序 第20章 Linux异常处理体系结构 第21章 扩展串口驱动程序移植 第22章 网卡驱动程序移植 第23章 IDE...
第四章 调试技术.doc 第五章 字符设备驱动程序的扩展操作.doc 第六章 时间流.doc 第七章 获取内存.doc 第八章 硬件管理.doc ... ... ... 第十六章 核心源码的物理布局.doc 第十七章 最新进展.doc
第4章 调试嵌入式系统程序 4.1 嵌入式系统调试方法 4.1.1 实时在线仿真 4.1.2 模拟调试 4.1.3 软件调试 4.1.4 BDM/JTAG调试 4.2 ARM仿真器 4.2.1 techorICE ARM仿真器 4.2.2 ARM仿真器工作原理 4.2.3 ARM...
第4章 基本概念61 4.1 设备和驱动程序介绍61 4.2 中断处理63 4.2.1 中断上下文63 4.2.2 分配irq号64 4.2.3 设备实例:导航杆65 4.2.4 softirq和tasklet68 4.3 linux设备模型71 4.3.1 udev71 4.3.2...
第四章 调试技术 内核中的调试支持 通过打印调试 通过查询调试 通过监视调试 调试系统故障 调试器和相关工具 第五章 并发和竞态 scull的缺陷 并发及其管理 信号量和互斥体 completion 自旋锁 锁陷阱 ...
第4章 Windows、Linux环境下相关工具、命令的使用 第2篇 ARM9嵌入式系统基础实例篇 第5章 GPIO接口 第6章 存储器控制 第7章 内存管理单元MMU 第8章 NAND Flash控制器 第9章 中断体系结构 第10章 系统时钟和定时器 ...
-第4章、Linux内核模块 -第5章、Linux文件系统与设备文件系统 -第6章、字符设备驱动 -第7章、Linux设备驱动中的并发控制 -第8章、Linux设备驱动中的阻塞与非阻塞IO -第9章、Linux设备驱动中的异步通知与异步IO -第10...
在我看linux设备驱动程序第4章调试技术的时候,一开始就遇到了问题,怎么在内核中开启调试选项,这本书帮我解决了。所以共享给同样遇到这样问题的朋友。也谢谢书的作者。
第四章:创建嵌入式系统开发环境;第五章:Bootloader;第六章:linux系统在ARM平台的移植;第七章:linux设备驱动程序开发;第八章:网络设备驱动程序开发;第九章:USB驱动程序开发;第十章:图形用户接口;第十一...
第 1 章 第一章 设备驱动简介 第 2 章 建立和运行模块 第 3 章 字符驱动 第 4 章 调试技术 第 5 章 并发和竞争情况 第 6 章 高级字符驱动操作 第 7 章 时间, 延时, 和延后工作
第4章 Windows、Linux环境下相关工具、命令的使用 第2篇 ARM9嵌入式系统基础实例篇 第5章 GPIO接口 第6章 存储器控制 第7章 内存管理单元MMU 第8章 NANDFlash控制器 第9章 中断体系结构 ...