使用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(stru