Commit | Line | Data |
---|---|---|
778c1f5c LC |
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') | |
801a2b1b | 39 | yield subsys_priv |
778c1f5c LC |
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') | |
801a2b1b | 46 | yield subsys_priv |
778c1f5c LC |
47 | |
48 | ||
49 | def get_bus_by_name(name): | |
50 | for item in for_each_bus(): | |
801a2b1b | 51 | if item['bus']['name'].string() == name: |
778c1f5c LC |
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(): | |
801a2b1b | 58 | if item['class']['name'].string() == name: |
778c1f5c LC |
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): | |
801a2b1b | 73 | for kn in klist_for_each(bus['klist_devices']): |
778c1f5c LC |
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): | |
801a2b1b | 79 | for kn in klist_for_each(cls['klist_devices']): |
778c1f5c LC |
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(): | |
801a2b1b | 106 | gdb.write('bus {}:\t{}\n'.format(bus['bus']['name'].string(), bus)) |
778c1f5c LC |
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(): | |
801a2b1b | 126 | gdb.write("class {}:\t{}\n".format(cls['class']['name'].string(), cls)) |
778c1f5c LC |
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() |