xref: /spdk/scripts/gdb_macros.py (revision 9943e42af621807bda745cd608c2fe869c29a24e)
1#   SPDX-License-Identifier: BSD-3-Clause
2#   Copyright (C) 2019 Intel Corporation.
3#   Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4#
5
6import gdb
7import gdb.printing
8
9
10class SpdkTailqList(object):
11
12    def __init__(self, list_pointer, list_member, tailq_name_list):
13        self.list_pointer = list_pointer
14        self.tailq_name_list = tailq_name_list
15        self.list_member = list_member
16        self.list = gdb.parse_and_eval(self.list_pointer)
17
18    def __iter__(self):
19        curr = self.list['tqh_first']
20        while curr:
21            yield self.list_member(curr)
22            for tailq_name in self.tailq_name_list:
23                curr = curr[tailq_name]
24            curr = curr['tqe_next']
25
26
27class SpdkNormalTailqList(SpdkTailqList):
28
29    def __init__(self, list_pointer, list_member):
30        super(SpdkNormalTailqList, self).__init__(list_pointer, list_member,
31                                                  ['tailq'])
32
33
34class SpdkRbTree(object):
35
36    def __init__(self, tree_pointer, tree_member, tree_name_list):
37        self.tree_pointer = tree_pointer
38        self.tree_name_list = tree_name_list
39        self.tree_member = tree_member
40        self.tree = gdb.parse_and_eval(self.tree_pointer)
41
42    def get_left_node(self, node):
43        return node['node']['rbe_left']
44
45    def get_right_node(self, node):
46        return node['node']['rbe_right']
47
48    def traverse_rb_tree(self, node):
49        if node:
50            self.rb_list.append(node)
51            self.traverse_rb_tree(self.get_left_node(node))
52            self.traverse_rb_tree(self.get_right_node(node))
53
54    def __iter__(self):
55        self.rb_list = []
56        tree_top = self.tree['rbh_root']
57        if tree_top:
58            self.traverse_rb_tree(tree_top)
59            for rb_node in self.rb_list:
60                yield self.tree_member(rb_node)
61        else:
62            yield
63
64
65class SpdkArr(object):
66
67    def __init__(self, arr_pointer, num_elements, element_type):
68        self.arr_pointer = arr_pointer
69        self.num_elements = num_elements
70        self.element_type = element_type
71
72    def __iter__(self):
73        for i in range(0, self.num_elements):
74            curr = (self.arr_pointer + i).dereference()
75            if (curr == 0x0):
76                continue
77            yield self.element_type(curr)
78
79
80class SpdkPrintCommand(gdb.Command):
81
82    def __init__(self, name, element_list):
83        self.element_list = element_list
84        gdb.Command.__init__(self, name,
85                             gdb.COMMAND_DATA,
86                             gdb.COMPLETE_SYMBOL,
87                             True)
88
89    def print_element_list(self, element_list):
90        first = True
91        for element in element_list:
92            if first:
93                first = False
94            else:
95                print("---------------")
96            print("\n" + str(element) + "\n")
97
98    def invoke(self, arg, from_tty):
99        self.print_element_list(self.element_list)
100
101
102class SpdkObject(object):
103
104    def __init__(self, gdb_obj):
105        self.obj = gdb_obj
106
107    def get_name(self):
108        return self.obj['name']
109
110    def __str__(self):
111        s = "SPDK object of type %s at %s" % (self.type_name, str(self.obj))
112        s += '\n((%s*) %s)' % (self.type_name, str(self.obj))
113        s += '\nname %s' % self.get_name()
114        return s
115
116
117class IoDevice(SpdkObject):
118
119    type_name = 'struct io_device'
120
121
122class IoDevices(SpdkRbTree):
123
124    def __init__(self):
125        super(IoDevices, self).__init__('g_io_devices', IoDevice, ['rbh_root'])
126
127
128class spdk_print_io_devices(SpdkPrintCommand):
129
130    def __init__(self):
131        try:
132            io_devices = IoDevices()
133        except RuntimeError as e:
134            print("Cannot load IO devices: " + str(e))
135            return
136        name = 'spdk_print_io_devices'
137        super(spdk_print_io_devices, self).__init__(name, io_devices)
138
139
140class Bdev(SpdkObject):
141
142    type_name = 'struct spdk_bdev'
143
144
145class BdevMgrBdevs(SpdkTailqList):
146
147    def __init__(self):
148        tailq_name_list = ['internal', 'link']
149        super(BdevMgrBdevs, self).__init__('g_bdev_mgr->bdevs', Bdev, tailq_name_list)
150
151
152class spdk_print_bdevs(SpdkPrintCommand):
153    name = 'spdk_print_bdevs'
154
155    def __init__(self):
156        try:
157            bdevs = BdevMgrBdevs()
158        except RuntimeError as e:
159            print("Cannot load bdevs: " + str(e))
160            return
161        super(spdk_print_bdevs, self).__init__(self.name, bdevs)
162
163
164class spdk_find_bdev(spdk_print_bdevs):
165
166    name = 'spdk_find_bdev'
167
168    def invoke(self, arg, from_tty):
169        print(arg)
170        bdev_query = [bdev for bdev in self.element_list
171                      if str(bdev.get_name()).find(arg) != -1]
172        if bdev_query == []:
173            print("Cannot find bdev with name %s" % arg)
174            return
175
176        self.print_element_list(bdev_query)
177
178
179class NvmfSubsystem(SpdkObject):
180
181    type_name = 'struct spdk_nvmf_subsystem'
182
183    def __init__(self, ptr):
184        self.ptr = ptr
185        gdb_obj = self.ptr.cast(gdb.lookup_type(self.type_name).pointer())
186        super(NvmfSubsystem, self).__init__(gdb_obj)
187
188    def get_name(self):
189        return self.obj['subnqn']
190
191    def get_id(self):
192        return int(self.obj['id'])
193
194    def get_ns_list(self):
195        max_nsid = int(self.obj['max_nsid'])
196        ns_list = []
197        for i in range(0, max_nsid):
198            nsptr = (self.obj['ns'] + i).dereference()
199            if nsptr == 0x0:
200                continue
201            ns = nsptr.cast(gdb.lookup_type('struct spdk_nvmf_ns').pointer())
202            ns_list.append(ns)
203        return ns_list
204
205    def __str__(self):
206        s = super(NvmfSubsystem, self).__str__()
207        s += '\nnqn %s' % self.get_name()
208        s += '\nID %d' % self.get_id()
209        for ns in self.get_ns_list():
210            s += '\t%s' % str(ns)
211        return s
212
213
214class SpdkNvmfTgtSubsystems(SpdkArr):
215
216    def get_num_subsystems(self):
217        try:  # version >= 18.11
218            return int(self.spdk_nvmf_tgt['max_subsystems'])
219        except RuntimeError:  # version < 18.11
220            return int(self.spdk_nvmf_tgt['opts']['max_subsystems'])
221
222    def __init__(self):
223        try:
224            self.spdk_nvmf_tgt = gdb.parse_and_eval("g_spdk_nvmf_tgt")
225        except RuntimeError as e:
226            print("Cannot load nvmf target subsystems: " + str(e))
227            return
228        subsystems = gdb.parse_and_eval("g_spdk_nvmf_tgt->subsystems")
229        super(SpdkNvmfTgtSubsystems, self).__init__(subsystems,
230                                                    self.get_num_subsystems(),
231                                                    NvmfSubsystem)
232
233
234class spdk_print_nvmf_subsystems(SpdkPrintCommand):
235
236    def __init__(self):
237        name = 'spdk_print_nvmf_subsystems'
238        nvmf_tgt_subsystems = SpdkNvmfTgtSubsystems()
239        super(spdk_print_nvmf_subsystems, self).__init__(name, nvmf_tgt_subsystems)
240
241
242class IoChannel(SpdkObject):
243
244    type_name = 'struct spdk_io_channel'
245
246    def get_ref(self):
247
248        return int(self.obj['ref'])
249
250    def get_device(self):
251        return self.obj['dev']
252
253    def get_device_name(self):
254        return self.obj['dev']['name']
255
256    def get_name(self):
257        return ""
258
259    def __str__(self):
260        s = super(IoChannel, self).__str__() + '\n'
261        s += 'ref %d\n' % self.get_ref()
262        s += 'device %s (%s)\n' % (self.get_device(), self.get_device_name())
263        return s
264
265
266class IoChannels(SpdkRbTree):
267
268    def __init__(self, tree_obj):
269        self.tree_name_list = ['rbh_root']
270        self.tree_member = IoChannel
271        self.tree = tree_obj
272
273
274class SpdkThread(SpdkObject):
275
276    type_name = 'struct spdk_thread'
277
278    def __init__(self, gdb_obj):
279        super(SpdkThread, self).__init__(gdb_obj)
280        self.io_channels = IoChannels(self.obj['io_channels'])
281
282    def __str__(self):
283        s = super(SpdkThread, self).__str__() + '\n'
284        s += "IO Channels:\n"
285        for io_channel in self.get_io_channels():
286            channel_lines = str(io_channel).split('\n')
287            s += '\n'.join('\t%s' % line for line in channel_lines if line != '')
288            s += '\n'
289            s += '\t---------------\n'
290            s += '\n'
291        return s
292
293    def get_io_channels(self):
294        return self.io_channels
295
296
297class SpdkThreads(SpdkNormalTailqList):
298
299    def __init__(self):
300        super(SpdkThreads, self).__init__('g_threads', SpdkThread)
301
302
303class spdk_print_threads(SpdkPrintCommand):
304
305    def __init__(self):
306        name = "spdk_print_threads"
307        threads = SpdkThreads()
308        super(spdk_print_threads, self).__init__(name, threads)
309
310
311class SpdkSpinlockStackPrinter(object):
312
313    def __init__(self, val):
314        self.val = val
315
316    def to_array(self):
317        ret = []
318        count = self.val['depth']
319        for i in range(count):
320            line = ''
321            addr = self.val['addrs'][i]
322            line += ' ' + str(addr)
323            # Source and line (sal) only exists for objects with debug info
324            sal = gdb.find_pc_line(int(addr))
325            try:
326                line += ' ' + str(sal.symtab.filename)
327                line += ':' + str(sal.line)
328            except AttributeError as e:
329                pass
330            ret.append(line)
331        return ret
332
333    def to_string(self):
334        return 'struct sspin_stack:\n' + '\n'.join(self.to_array())
335
336    def display_hint(self):
337        return 'struct sspin_stack'
338
339
340class SpdkSpinlockPrinter(object):
341
342    def __init__(self, val):
343        self.val = val
344
345    def to_string(self):
346        thread = self.val['thread']
347        internal = self.val['internal']
348        s = 'struct spdk_spinlock:'
349        s += '\n  Locked by spdk_thread: '
350        if thread == 0:
351            s += 'not locked'
352        else:
353            s += str(thread)
354        if internal != 0:
355            stacks = [
356                ['Initialized', 'init_stack'],
357                ['Last locked', 'lock_stack'],
358                ['Last unlocked', 'unlock_stack']]
359            for stack in stacks:
360                s += '\n  ' + stack[0] + ' at:\n    '
361                frames = SpdkSpinlockStackPrinter(internal[stack[1]])
362                s += '\n    '.join(frames.to_array())
363        return s
364
365    def display_hint(self):
366        return 'struct spdk_spinlock'
367
368
369class spdk_load_macros(gdb.Command):
370
371    def __init__(self):
372        gdb.Command.__init__(self, 'spdk_load_macros',
373                             gdb.COMMAND_DATA,
374                             gdb.COMPLETE_SYMBOL,
375                             True)
376        self.loaded = False
377
378    def load_pretty_printers(self):
379        pp = gdb.printing.RegexpCollectionPrettyPrinter("spdk_library")
380        pp.add_printer('sspin_stack', '^sspin_stack$',
381                       SpdkSpinlockStackPrinter)
382        pp.add_printer('spdk_spinlock', '^spdk_spinlock$', SpdkSpinlockPrinter)
383        gdb.printing.register_pretty_printer(gdb.current_objfile(), pp)
384
385    def invoke(self, arg, from_tty):
386        if arg == '--reload':
387            print('Reloading spdk information')
388            reload = True
389        else:
390            reload = False
391            # These can only load once
392            self.load_pretty_printers()
393
394        if self.loaded and not reload:
395            return
396
397        spdk_print_threads()
398        spdk_print_bdevs()
399        spdk_print_io_devices()
400        spdk_print_nvmf_subsystems()
401        spdk_find_bdev()
402
403
404spdk_load_macros()
405