diff options
author | Leonard Crestez <leonard.crestez@nxp.com> | 2019-07-16 19:30:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-16 22:23:24 -0400 |
commit | 778c1f5ccbd95722cf84d2233c6acbf4d01a3ec7 (patch) | |
tree | 7a9c17a17417f89dcb0fd9a993312b874a2ddea0 /scripts/gdb/linux/device.py | |
parent | 8207d4a88e1ef4ab54f05f2f18edd444a5099099 (diff) |
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>
Diffstat (limited to 'scripts/gdb/linux/device.py')
-rw-r--r-- | scripts/gdb/linux/device.py | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/scripts/gdb/linux/device.py b/scripts/gdb/linux/device.py new file mode 100644 index 000000000000..16376c5cfec6 --- /dev/null +++ b/scripts/gdb/linux/device.py | |||
@@ -0,0 +1,182 @@ | |||
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() | ||