使用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字符设备相关推荐

  1. linux字符设备驱动在哪里设置,从点一个灯开始学写Linux字符设备驱动!

    原标题:从点一个灯开始学写Linux字符设备驱动! [导读] 前一篇文章,介绍了如何将一个hello word模块编译进内核或者编译为动态加载内核模块,本篇来介绍一下如何利用Linux驱动模型来完成一 ...

  2. Linux 字符设备驱动的编写

    Linux 字符设备驱动的编写 作者:解琛 时间:2020 年 8 月 17 日 Linux 字符设备驱动的编写 一.Linux 设备分类 二.open() 三.数据结构 3.1 struct fil ...

  3. 一张图掌握 Linux 字符设备驱动架构!【建议收藏】

    目录 一. Linux 中字符设备驱动简介 二. 字符设备驱动快速入门(超简单demo) 1. demo 2. 代码编译 3. 加载驱动模块 4. 创建设备节点文件 5. APP设备文件操作 6. 卸 ...

  4. ()shi linux字符设备,Linux字符设备驱动基础(三)

    Linux字符设备驱动基础(三) 6 创建设备节点 6.1 手动创建设备节点 查看申请的设备名及主设备号: cat /proc/devices # cat /proc/devices Characte ...

  5. linux设备模型 字符设备,Linux 字符设备驱动模型之框架解说

    一.软件操作硬件设备模型 在进行嵌入式开发的过程中,在常做的事情就是驱动配置硬件设 备,然后根据功能需求使用硬件设备,实现功能的逻辑.如下图为其 相互之间的关系. 如上图所示: 驱动程序:主要作为操作 ...

  6. linux字符设备文件的打开操作,Linux字符设备驱动模型之字符设备初始化

    因为Linux字符设备驱动主要依赖于struct cdev结构,原型为: 所以我们需要对所使用到的结构成员进行配置,驱动开发所使用到的结构成员分别为:[unsigned int count;].[de ...

  7. linux生成驱动编译的头文件,嵌入式Linux字符设备驱动——5生成字符设备节点

    嵌入式Linux字符设备驱动开发流程--以LED为例 前言 留空 头文件 #include 查看系统设备类 ls /sys/class 设备类结构体 文件(路径):include/linux/devi ...

  8. linux字符设备驱动的 ioctl 幻数

    在Linux字符设备驱动入门(一)中,我们实现了字符设备的简单读写字符功能,接下来我们要在这个基础上加入ioctl功能.首先,我们先来看看3.0内核下../include/linux/fs.h中fil ...

  9. Linux 字符设备驱动结构(四)—— file_operations 结构体知识解析

    前面在 Linux 字符设备驱动开发基础 (三)-- 字符设备驱动结构(中) ,我们已经介绍了两种重要的数据结构 struct inode{...}与 struct file{...} ,下面来介绍另 ...

最新文章

  1. Leetcode232.栈实现队列
  2. Qos和区分服务(DiffServ)
  3. java封装,继承和多态
  4. zabbix 监控项自动发现过滤_Zabbix监控之配置Linux自动发现与自动注册报警
  5. 【Android 应用开发】 Fragment 详解
  6. jdk安装后提示错误
  7. 使用ssh连接WSL
  8. socket通信数据类型
  9. 【转】.net框架读书笔记---CLR内存管理\垃圾收集(七)
  10. freemarker -自定义指令
  11. gsea结果分析图怎么看_微信公众平台数据分析怎么看
  12. mysql主从复制 读写分离
  13. 路由器-路由器以及×××-Client之间的×××
  14. 验证码生成php代码,一个php验证码生成类代码
  15. Moq -.NET的Mocking库
  16. Unique Email Addresses
  17. 让MySQL不区分大小写
  18. 用户空间缺页异常pte_handle_fault()分析--(下)--写时复制
  19. wireshark显示过滤器和捕获过滤器
  20. HtmlUnit实现人人网登陆

热门文章

  1. Ada的另一个身份--计算机语言
  2. [原]红帽 Red Hat Linux相关产品iso镜像下载
  3. 西单,王府井购物小记
  4. 2018最佳网页设计:就是要你灵感爆棚!!!
  5. 美国雷曼兄弟公司简介
  6. 为什么单精度浮点数的精度是7位
  7. learnOpenGL-深度测试
  8. PHP程序员及网站设计师职业要求
  9. 泰课unity系列黑暗之光学习笔记1
  10. Linux进程管理学习心得