Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scripts/gdb: add helpers to find and list devices

Add helper commands and functions for finding pointers to struct device
by enumerating linux device bus/class infrastructure. This can be used
to fetch subsystem and driver-specific structs:

(gdb) p *$container_of($lx_device_find_by_class_name("net", "eth0"), "struct net_device", "dev")
(gdb) p *$container_of($lx_device_find_by_bus_name("i2c", "0-004b"), "struct i2c_client", "dev")
(gdb) p *(struct imx_port*)$lx_device_find_by_class_name("tty", "ttymxc1")->parent->driver_data

Several generic "lx-device-list" functions are included to enumerate
devices by bus and class:

(gdb) lx-device-list-bus usb
(gdb) lx-device-list-class
(gdb) lx-device-list-tree &platform_bus

Similar information is available in /sys but pointer values are
deliberately hidden.

Link: http://lkml.kernel.org/r/c948628041311cbf1b9b4cff3dda7d2073cb3eaa.1561492937.git.leonard.crestez@nxp.com
Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Reviewed-by: Stephen Boyd <sboyd@kernel.org>
Cc: Kieran Bingham <kbingham@kernel.org>
Cc: Jan Kiszka <jan.kiszka@siemens.com>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Leonard Crestez and committed by
Linus Torvalds
778c1f5c 8207d4a8

+183
+182
scripts/gdb/linux/device.py
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Copyright (c) NXP 2019 4 + 5 + import gdb 6 + 7 + from linux.utils import CachedType 8 + from linux.utils import container_of 9 + from linux.lists import list_for_each_entry 10 + 11 + 12 + device_private_type = CachedType('struct device_private') 13 + device_type = CachedType('struct device') 14 + 15 + subsys_private_type = CachedType('struct subsys_private') 16 + kobject_type = CachedType('struct kobject') 17 + kset_type = CachedType('struct kset') 18 + 19 + bus_type = CachedType('struct bus_type') 20 + class_type = CachedType('struct class') 21 + 22 + 23 + def dev_name(dev): 24 + dev_init_name = dev['init_name'] 25 + if dev_init_name: 26 + return dev_init_name.string() 27 + return dev['kobj']['name'].string() 28 + 29 + 30 + def kset_for_each_object(kset): 31 + return list_for_each_entry(kset['list'], 32 + kobject_type.get_type().pointer(), "entry") 33 + 34 + 35 + def for_each_bus(): 36 + for kobj in kset_for_each_object(gdb.parse_and_eval('bus_kset')): 37 + subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj') 38 + subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys') 39 + yield subsys_priv['bus'] 40 + 41 + 42 + def for_each_class(): 43 + for kobj in kset_for_each_object(gdb.parse_and_eval('class_kset')): 44 + subsys = container_of(kobj, kset_type.get_type().pointer(), 'kobj') 45 + subsys_priv = container_of(subsys, subsys_private_type.get_type().pointer(), 'subsys') 46 + yield subsys_priv['class'] 47 + 48 + 49 + def get_bus_by_name(name): 50 + for item in for_each_bus(): 51 + if item['name'].string() == name: 52 + return item 53 + raise gdb.GdbError("Can't find bus type {!r}".format(name)) 54 + 55 + 56 + def get_class_by_name(name): 57 + for item in for_each_class(): 58 + if item['name'].string() == name: 59 + return item 60 + raise gdb.GdbError("Can't find device class {!r}".format(name)) 61 + 62 + 63 + klist_type = CachedType('struct klist') 64 + klist_node_type = CachedType('struct klist_node') 65 + 66 + 67 + def klist_for_each(klist): 68 + return list_for_each_entry(klist['k_list'], 69 + klist_node_type.get_type().pointer(), 'n_node') 70 + 71 + 72 + def bus_for_each_device(bus): 73 + for kn in klist_for_each(bus['p']['klist_devices']): 74 + dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_bus') 75 + yield dp['device'] 76 + 77 + 78 + def class_for_each_device(cls): 79 + for kn in klist_for_each(cls['p']['klist_devices']): 80 + dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_class') 81 + yield dp['device'] 82 + 83 + 84 + def device_for_each_child(dev): 85 + for kn in klist_for_each(dev['p']['klist_children']): 86 + dp = container_of(kn, device_private_type.get_type().pointer(), 'knode_parent') 87 + yield dp['device'] 88 + 89 + 90 + def _show_device(dev, level=0, recursive=False): 91 + gdb.write('{}dev {}:\t{}\n'.format('\t' * level, dev_name(dev), dev)) 92 + if recursive: 93 + for child in device_for_each_child(dev): 94 + _show_device(child, level + 1, recursive) 95 + 96 + 97 + class LxDeviceListBus(gdb.Command): 98 + '''Print devices on a bus (or all buses if not specified)''' 99 + 100 + def __init__(self): 101 + super(LxDeviceListBus, self).__init__('lx-device-list-bus', gdb.COMMAND_DATA) 102 + 103 + def invoke(self, arg, from_tty): 104 + if not arg: 105 + for bus in for_each_bus(): 106 + gdb.write('bus {}:\t{}\n'.format(bus['name'].string(), bus)) 107 + for dev in bus_for_each_device(bus): 108 + _show_device(dev, level=1) 109 + else: 110 + bus = get_bus_by_name(arg) 111 + if not bus: 112 + raise gdb.GdbError("Can't find bus {!r}".format(arg)) 113 + for dev in bus_for_each_device(bus): 114 + _show_device(dev) 115 + 116 + 117 + class LxDeviceListClass(gdb.Command): 118 + '''Print devices in a class (or all classes if not specified)''' 119 + 120 + def __init__(self): 121 + super(LxDeviceListClass, self).__init__('lx-device-list-class', gdb.COMMAND_DATA) 122 + 123 + def invoke(self, arg, from_tty): 124 + if not arg: 125 + for cls in for_each_class(): 126 + gdb.write("class {}:\t{}\n".format(cls['name'].string(), cls)) 127 + for dev in class_for_each_device(cls): 128 + _show_device(dev, level=1) 129 + else: 130 + cls = get_class_by_name(arg) 131 + for dev in class_for_each_device(cls): 132 + _show_device(dev) 133 + 134 + 135 + class LxDeviceListTree(gdb.Command): 136 + '''Print a device and its children recursively''' 137 + 138 + def __init__(self): 139 + super(LxDeviceListTree, self).__init__('lx-device-list-tree', gdb.COMMAND_DATA) 140 + 141 + def invoke(self, arg, from_tty): 142 + if not arg: 143 + raise gdb.GdbError('Please provide pointer to struct device') 144 + dev = gdb.parse_and_eval(arg) 145 + if dev.type != device_type.get_type().pointer(): 146 + raise gdb.GdbError('Please provide pointer to struct device') 147 + _show_device(dev, level=0, recursive=True) 148 + 149 + 150 + class LxDeviceFindByBusName(gdb.Function): 151 + '''Find struct device by bus and name (both strings)''' 152 + 153 + def __init__(self): 154 + super(LxDeviceFindByBusName, self).__init__('lx_device_find_by_bus_name') 155 + 156 + def invoke(self, bus, name): 157 + name = name.string() 158 + bus = get_bus_by_name(bus.string()) 159 + for dev in bus_for_each_device(bus): 160 + if dev_name(dev) == name: 161 + return dev 162 + 163 + 164 + class LxDeviceFindByClassName(gdb.Function): 165 + '''Find struct device by class and name (both strings)''' 166 + 167 + def __init__(self): 168 + super(LxDeviceFindByClassName, self).__init__('lx_device_find_by_class_name') 169 + 170 + def invoke(self, cls, name): 171 + name = name.string() 172 + cls = get_class_by_name(cls.string()) 173 + for dev in class_for_each_device(cls): 174 + if dev_name(dev) == name: 175 + return dev 176 + 177 + 178 + LxDeviceListBus() 179 + LxDeviceListClass() 180 + LxDeviceListTree() 181 + LxDeviceFindByBusName() 182 + LxDeviceFindByClassName()
+1
scripts/gdb/vmlinux-gdb.py
··· 36 36 import linux.timerlist 37 37 import linux.clk 38 38 import linux.genpd 39 + import linux.device