With respect to character devices: Sometime way back in the 2.6ish kernel, the fops field of struct char_device_struct ceased to be used for anything, and on those kernels (like 2.6.18), dev always reports the OPERATIONS field as "(none)": crash-4.0-8.10> dev CHRDEV NAME OPERATIONS 1 mem (none) 2 pty (none) 3 ttyp (none) 4 /dev/vc/0 (none) 4 tty (none) 4 ttyS (none) 5 /dev/tty (none) 5 /dev/console (none) 5 /dev/ptmx (none) 7 vcs (none) 10 misc (none) 13 input (none) 21 sg (none) 29 fb (none) ... Then recently (by 2.6.28, anyway), someone noticed that the fops field was unused and removed it from struct char_device_struct altogether, so now we get: crash-4.0-8.10> dev dev: invalid structure member offset: char_device_struct_fops FILE: dev.c LINE: 221 FUNCTION: dump_chrdevs() [/home/bobm/bin/crash-4.0-8.10] error trace: 452e75 => 4cf528 => 4cf957 => 50d8d3 CHRDEV NAME OPERATIONS 50d8d3: OFFSET_verify+168 4cf957: dump_chrdevs+1043 4cf528: cmd_dev+198 452e75: exec_command+306 dev: invalid structure member offset: char_device_struct_fops FILE: dev.c LINE: 221 FUNCTION: dump_chrdevs() crash-4.0-8.10> The attached patch changes the behavior in both cases to something like this: crash-4.0-8.10fix> dev CHRDEV NAME OPERATIONS 1 mem ffffffff8043ee00 <memory_fops> 2 pty (none) 3 ttyp (none) 4 /dev/vc/0 (none) 4 tty (none) 4 ttyS (none) 5 /dev/tty (none) 5 /dev/console (none) 5 /dev/ptmx (none) 7 vcs ffffffff8043ff40 <vcs_fops> 10 misc ffffffff8043fe40 <misc_fops> 13 input ffffffff805413c0 <input_fops> 21 sg (none) 29 fb ffffffff80531c60 <fb_fops> Which is definitely an improvement. But wondering about those remaining (none) entries, I found that if I pursue info through the cdev_map with a series of crash commands like this: crash-4.0-8.10fix> p (*cdev_map.probes[2]).data $7 = (void *) 0xffff81013a66c408 crash-4.0-8.10fix> p (*(struct cdev *)0xffff81013a66c408).ops $8 = (const struct file_operations *) 0xffffffff8043f860 crash-4.0-8.10fix> sym 0xffffffff8043f860 ffffffff8043f860 (r) tty_fops crash-4.0-8.10fix> p (*cdev_map.probes[21]).data $9 = (void *) 0xffff81013acf8d80 crash-4.0-8.10fix> p (*(struct cdev *)0xffff81013acf8d80).ops $10 = (const struct file_operations *) 0xffffffff8820ee00 crash-4.0-8.10fix> sym 0xffffffff8820ee00 ffffffff8820ee00 (d) sg_fops I can come up with believable file_ops values for (most? all?) of the others. And this leads me to wonder if crash shouldn't be collecting this info in a similar manner to fill in the other OPERATIONS fields. But now I'm quite a bit past what I know about how the character device stuff works. Thanks, Bob Montgomery Working at HP
--- defs.h.orig 2009-06-02 14:13:50.000000000 -0600 +++ defs.h 2009-06-02 14:49:27.000000000 -0600 @@ -1385,6 +1385,8 @@ struct offset_table { long char_device_struct_name; long char_device_struct_fops; long char_device_struct_major; + long char_device_struct_cdev; + long cdev_ops; long gendisk_major; long gendisk_disk_name; long gendisk_fops; @@ -1548,6 +1550,7 @@ struct size_table { /* stash of long gendisk; long address_space; long char_device_struct; + long cdev; long inet_sock; long in6_addr; long socket; --- dev.c.orig 2009-06-02 14:05:59.000000000 -0600 +++ dev.c 2009-06-02 15:26:47.000000000 -0600 @@ -138,8 +138,8 @@ dump_chrdevs(ulong flags) ulong ops; } chrdevs[MAX_DEV], *cp; ulong *cdp; - char *char_device_struct_buf; - ulong next, savenext, name, fops; + char *char_device_struct_buf, *cdev_buf; + ulong next, savenext, name, fops, cdev; int major; int name_typecode; size_t name_size; @@ -217,8 +217,24 @@ char_device_struct: break; } - fops = ULONG(char_device_struct_buf + - OFFSET(char_device_struct_fops)); + fops = NULL; + if (VALID_MEMBER(char_device_struct_cdev) && + VALID_STRUCT(cdev)) { + cdev = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_cdev)); + cdev_buf = GETBUF(SIZE(cdev)); + if (cdev) { + readmem(cdev, KVADDR, cdev_buf, + SIZE(cdev), + "cdev", FAULT_ON_ERROR); + fops = ULONG(cdev_buf + + OFFSET(cdev_ops)); + } + } else { + fops = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_fops)); + } + major = INT(char_device_struct_buf + OFFSET(char_device_struct_major)); @@ -267,8 +283,24 @@ char_device_struct: break; } - fops = ULONG(char_device_struct_buf + - OFFSET(char_device_struct_fops)); + fops = NULL; + if (VALID_MEMBER(char_device_struct_cdev) && + VALID_STRUCT(cdev)) { + cdev = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_cdev)); + cdev_buf = GETBUF(SIZE(cdev)); + if (cdev) { + readmem(cdev, KVADDR, cdev_buf, + SIZE(cdev), + "cdev", FAULT_ON_ERROR); + fops = ULONG(cdev_buf + + OFFSET(cdev_ops)); + } + } else { + fops = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_fops)); + } + major = INT(char_device_struct_buf + OFFSET(char_device_struct_major)); --- kernel.c.orig 2009-06-02 14:13:38.000000000 -0600 +++ kernel.c 2009-06-02 14:49:27.000000000 -0600 @@ -463,8 +463,15 @@ kernel_init() "char_device_struct", "fops"); MEMBER_OFFSET_INIT(char_device_struct_major, "char_device_struct", "major"); + MEMBER_OFFSET_INIT(char_device_struct_cdev, + "char_device_struct", "cdev"); } + STRUCT_SIZE_INIT(cdev, "cdev"); + if (VALID_STRUCT(cdev)) + MEMBER_OFFSET_INIT(cdev_ops, + "cdev", "ops"); + MEMBER_OFFSET_INIT(module_kallsyms_start, "module", "kallsyms_start"); --- symbols.c.orig 2009-06-02 14:13:44.000000000 -0600 +++ symbols.c 2009-06-02 14:49:27.000000000 -0600 @@ -7024,6 +7024,11 @@ dump_offset_table(char *spec, ulong make OFFSET(char_device_struct_fops)); fprintf(fp, " char_device_struct_major: %ld\n", OFFSET(char_device_struct_major)); + fprintf(fp, " char_device_struct_cdev: %ld\n", + OFFSET(char_device_struct_cdev)); + + fprintf(fp, " cdev_ops: %ld\n", + OFFSET(cdev_ops)); fprintf(fp, " blk_major_name_next: %ld\n", OFFSET(blk_major_name_next));
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility