使用NDB调试Linux字符设备
使用NDB调试Linux字符设备
cdev_init
在Linux中字符设备通过cdev结构体来表示,为了观察Linux上面的字符设备的创建过程,就需要在cdev_init处设置断点。
给cdev_init设置断点后,接着g跑起来,给GDK8插入鼠标,然后等待断点命中。
断点命中后,先查看 cdev结构体信息。
owner:该设备驱动程序所属的内核模块。
ops:file_operations结构体指针,file_operations结构体用于文件操作。
dev:设备号。
dv
@ x0 cdev = ffffffc0f0ab7458
@ x1 fops = ffffff80094fc138
dt lk!cdev 0xffffffc0f0ab7458
Local var @ x0 Type cdev*+0x000 kobj : kobject+0x060 owner : (null)+0x068 ops : (null)+0x070 list : list_head+0x080 dev : 0+0x084 count : 0
通过上面的信息可以看到,因为刚到`cdev_init`,所以很多信息都还是空的,不过不要紧,接下来信息会写入结构体内。
在cdev_init内可以看到,这个函数的主要作用就是给cdev结构体分配空间,并给cdev内的list、kobj、ops进行赋值。
INIT_LIST_HEAD:初始化list_head结构体。
kobject_init:初始化kobject结构体。
fops:是从`evdev_connect`传递过来的。
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{memset(cdev, 0, sizeof *cdev);INIT_LIST_HEAD(&cdev->list);kobject_init(&cdev->kobj, &ktype_cdev_default);cdev->ops = fops;
}
cdev_init完成后,会回到evdev_connect内,并通过cdev_device_add开始添加设备。
cdev_device_add
继续g起来,cdev_device_add断点命中后,查看一下局部变量。
其中dev的device结构体的指针,在evdev_connect内通过device_initialize函数赋值给evdev结构体中的device结构体。
lk!cdev_device_add:
ffffff8008265028 a9bd7bfd stp x29, x30, [sp, #-0x30]!
dv
@ x0 cdev = ffffffc0eddddc58
@ x1 dev = ffffffc0edddd8a8
@ x20 rc = 41
在cdev_device_add内首先会检查设备号,如果设备号不为0,就会开始设置cdev。
int cdev_device_add(struct cdev *cdev, struct device *dev)
{int rc = 0;if (dev->devt) {cdev_set_parent(cdev, &dev->kobj);rc = cdev_add(cdev, dev->devt, 1);if (rc)return rc;}rc = device_add(dev);if (rc)cdev_del(cdev);return rc;
}
cdev_set_parent主要目的是设置kobject的parent成员,避免在cdev结构体被释放之前,父项发生释放。
void cdev_set_parent(struct cdev *p, struct kobject *kobj)
{WARN_ON(!kobj->state_initialized);p->kobj.parent = kobj;
}
cdev_set_parent完成任务后,就会进入cdev_add内。
kobj_map用来把字符设备编号和cdev结构体一起保存到cdev_map列表里。后面要打开一个字符设备文件时,kobj_lookup会根据设备编号就可以找到 cdev 结构变量,取出其中的ops字段,然后开始操作文件。
kobject_get是用来增加引用计数的。
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{int error;p->dev = dev;p->count = count;error = kobj_map(cdev_map, dev, count, NULL,exact_match, exact_lock, p);if (error)return error;kobject_get(p->kobj.parent);return 0;
}
查看cdev_map结构体信息。
可以看到probes应该是一个数组,设备号应该就是存储在这个数组里面。
dt lk!cdev_map
0xffffffc0`00212800+0x000 probes : [255] 0xffffffc0`0a264600+0x7f8 lock : 0xffffff80`09e61608
通过dd查看0xffffffc00a264600,可以看到一个很特殊的信息082648a0 ffffff80。
dd 0xffffffc00a264600
ffffffc0`0a264600 00000000 00000000 00000001 00000000
ffffffc0`0a264610 ffffffff ffffffff 00000000 00000000
ffffffc0`0a264620 082648a0 ffffff80 00000000 00000000
ffffffc0`0a264630 00000000 00000000 00000000 00000000
ffffffc0`0a264640 00000000 00000000 00000000 00000000
ffffffc0`0a264650 00000000 00000000 00000000 00000000
ffffffc0`0a264660 00000000 00000000 00000000 00000000
ffffffc0`0a264670 00000000 00000000 00000000 00000000
ln看一下符号信息,可以知道这是base_probe的地址。
ln ffffff80082648a0
(ffffff80`082648a0) lk!base_probe
Exact matches:lk!base_probe (dev_t, int*, void*)
先不管上面的,进入kobj_map里面看一下。
int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,struct module *module, kobj_probe_t *probe,int (*lock)(dev_t, void *), void *data)
{unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;unsigned index = MAJOR(dev);unsigned i;struct probe *p;if (n > 255)n = 255;p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL);if (p == NULL)return -ENOMEM;for (i = 0; i < n; i++, p++) {p->owner = module;p->get = probe;p->lock = lock;p->dev = dev;p->range = range;p->data = data;}mutex_lock(domain->lock);for (i = 0, p -= n; i < n; i++, p++, index++) {struct probe **s = &domain->probes[index % 255];while (*s && (*s)->range < range)s = &(*s)->next;p->next = *s;*s = p;}mutex_unlock(domain->lock);return 0;
}
看到struct probe *p;可以知道,这些设备信息是通过链表的形式链接起来的,并且从上面可以知道每个probe结构体里面都有base_probe函数,用来获取更多的设备信息。
/dev/
通过比较下面有无鼠标插入时的/dev/列表,可以发现有鼠标插入时的/dev/列表多了hidraw0、hidraw1、hidraw2这三个文件,而这三个文件就是hidraw驱动提供与USB或蓝牙进行交互的虚拟文件。
未插入鼠标时,/dev/的设备列表。
LED_HT1628 loop3 ram1 tty15 tty46 usbmon5
ashmem loop4 ram10 tty16 tty47 vcs
binder loop5 ram11 tty17 tty48 vcs1
block loop6 ram12 tty18 tty49 vcs2
btrfs-control loop7 ram13 tty19 tty5 vcs3
bus mali ram14 tty2 tty50 vcs4
cec0 mapper ram15 tty20 tty51 vcs5
char mem ram2 tty21 tty52 vcs6
console memory_bandwidth ram3 tty22 tty53 vcs7
cpu_dma_latency mmcblk1 ram4 tty23 tty54 vcsa
disk mmcblk1boot0 ram5 tty24 tty55 vcsa1
dri mmcblk1boot1 ram6 tty25 tty56 vcsa2
fb0 mmcblk1p1 ram7 tty26 tty57 vcsa3
fd mmcblk1p2 ram8 tty27 tty58 vcsa4
full mmcblk1p3 ram9 tty28 tty59 vcsa5
fuse mmcblk1p4 random tty29 tty6 vcsa6
gpiochip0 mmcblk1p5 rfkill tty3 tty60 vcsa7
gpiochip1 mmcblk1p6 rga tty30 tty61 vcsu
gpiochip2 mmcblk1p7 shm tty31 tty62 vcsu1
gpiochip3 mmcblk1p8 snd tty32 tty63 vcsu2
hdmi_hdcp1x mmcblk1rpmb stderr tty33 tty7 vcsu3
hwbinder mpp_service stdin tty34 tty8 vcsu4
hwrng mqueue stdout tty35 tty9 vcsu5
i2c-4 ndbbox sw_sync tty36 ttyFIQ0 vcsu6
iep net tee0 tty37 ttyS0 vcsu7
initctl network_latency teepriv0 tty38 uhid vendor_storage
input network_throughput tty tty39 uinput vndbinder
ion null tty0 tty4 urandom watchdog
kmsg opteearmtz00 tty1 tty40 usb-ffs watchdog0
log pmsg0 tty10 tty41 usbmon0 zero
loop-control ppp tty11 tty42 usbmon1 zram0
loop0 ptmx tty12 tty43 usbmon2
loop1 pts tty13 tty44 usbmon3
loop2 ram0 tty14 tty45 usbmon4
插入鼠标时,/dev/的设备列表。
LED_HT1628 loop1 ram0 tty15 tty47 vcs
ashmem loop2 ram1 tty16 tty48 vcs1
binder loop3 ram10 tty17 tty49 vcs2
block loop4 ram11 tty18 tty5 vcs3
btrfs-control loop5 ram12 tty19 tty50 vcs4
bus loop6 ram13 tty2 tty51 vcs5
cec0 loop7 ram14 tty20 tty52 vcs6
char mali ram15 tty21 tty53 vcs7
console mapper ram2 tty22 tty54 vcsa
cpu_dma_latency mem ram3 tty23 tty55 vcsa1
disk memory_bandwidth ram4 tty24 tty56 vcsa2
dri mmcblk1 ram5 tty25 tty57 vcsa3
fb0 mmcblk1boot0 ram6 tty26 tty58 vcsa4
fd mmcblk1boot1 ram7 tty27 tty59 vcsa5
full mmcblk1p1 ram8 tty28 tty6 vcsa6
fuse mmcblk1p2 ram9 tty29 tty60 vcsa7
gpiochip0 mmcblk1p3 random tty3 tty61 vcsu
gpiochip1 mmcblk1p4 rfkill tty30 tty62 vcsu1
gpiochip2 mmcblk1p5 rga tty31 tty63 vcsu2
gpiochip3 mmcblk1p6 shm tty32 tty7 vcsu3
hdmi_hdcp1x mmcblk1p7 snd tty33 tty8 vcsu4
hidraw0 mmcblk1p8 stderr tty34 tty9 vcsu5
hidraw1 mmcblk1rpmb stdin tty35 ttyFIQ0 vcsu6
hidraw2 mpp_service stdout tty36 ttyS0 vcsu7
hwbinder mqueue sw_sync tty37 uhid vendor_storage
hwrng ndbbox tee0 tty38 uinput vndbinder
i2c-4 net teepriv0 tty39 urandom watchdog
iep network_latency tty tty4 usb watchdog0
initctl network_throughput tty0 tty40 usb-ffs zero
input null tty1 tty41 usbmon0 zram0
ion opteearmtz00 tty10 tty42 usbmon1
kmsg pmsg0 tty11 tty43 usbmon2
log ppp tty12 tty44 usbmon3
loop-control ptmx tty13 tty45 usbmon4
loop0 pts tty14 tty46 usbmon5
使用NDB调试Linux字符设备相关推荐
- linux字符设备驱动在哪里设置,从点一个灯开始学写Linux字符设备驱动!
原标题:从点一个灯开始学写Linux字符设备驱动! [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一 ...
- Linux 字符设备驱动的编写
Linux 字符设备驱动的编写 作者:解琛 时间:2020 年 8 月 17 日 Linux 字符设备驱动的编写 一.Linux 设备分类 二.open() 三.数据结构 3.1 struct fil ...
- 一张图掌握 Linux 字符设备驱动架构!【建议收藏】
目录 一. Linux 中字符设备驱动简介 二. 字符设备驱动快速入门(超简单demo) 1. demo 2. 代码编译 3. 加载驱动模块 4. 创建设备节点文件 5. APP设备文件操作 6. 卸 ...
- ()shi linux字符设备,Linux字符设备驱动基础(三)
Linux字符设备驱动基础(三) 6 创建设备节点 6.1 手动创建设备节点 查看申请的设备名及主设备号: cat /proc/devices # cat /proc/devices Characte ...
- linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说
一.软件操作硬件设备模型 在进行嵌入式开发的过程中,在常做的事情就是驱动配置硬件设 备,然后根据功能需求使用硬件设备,实现功能的逻辑.如下图为其 相互之间的关系. 如上图所示: 驱动程序:主要作为操作 ...
- linux字符设备文件的打开操作,Linux字符设备驱动模型之字符设备初始化
因为Linux字符设备驱动主要依赖于struct cdev结构,原型为: 所以我们需要对所使用到的结构成员进行配置,驱动开发所使用到的结构成员分别为:[unsigned int count;].[de ...
- linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点
嵌入式Linux字符设备驱动开发流程--以LED为例 前言 留空 头文件 #include 查看系统设备类 ls /sys/class 设备类结构体 文件(路径):include/linux/devi ...
- linux字符设备驱动的 ioctl 幻数
在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能.首先,我们先来看看3.0内核下../include/linux/fs.h中fil ...
- Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析
前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...
最新文章
- Leetcode232.栈实现队列
- Qos和区分服务(DiffServ)
- java封装,继承和多态
- zabbix 监控项自动发现过滤_Zabbix监控之配置Linux自动发现与自动注册报警
- 【Android 应用开发】 Fragment 详解
- jdk安装后提示错误
- 使用ssh连接WSL
- socket通信数据类型
- 【转】.net框架读书笔记---CLR内存管理\垃圾收集(七)
- freemarker -自定义指令
- gsea结果分析图怎么看_微信公众平台数据分析怎么看
- mysql主从复制 读写分离
- 路由器-路由器以及×××-Client之间的×××
- 验证码生成php代码,一个php验证码生成类代码
- Moq -.NET的Mocking库
- Unique Email Addresses
- 让MySQL不区分大小写
- 用户空间缺页异常pte_handle_fault()分析--(下)--写时复制
- wireshark显示过滤器和捕获过滤器
- HtmlUnit实现人人网登陆