When gdb_macros.py is used with unit tests some of the globals it expects are not present. This commit handles the relevant exceptions so a missing symbol does not prevent the use of macros that are initialized later. Signed-off-by: Mike Gerdts <mgerdts@nvidia.com> Change-Id: Ic81f0dfa705839c9a03fb76e934684716b710390 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15999 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
337 lines
9.1 KiB
Python
337 lines
9.1 KiB
Python
# SPDX-License-Identifier: BSD-3-Clause
|
|
# Copyright (C) 2019 Intel Corporation.
|
|
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
#
|
|
|
|
import gdb
|
|
|
|
|
|
class SpdkTailqList(object):
|
|
|
|
def __init__(self, list_pointer, list_member, tailq_name_list):
|
|
self.list_pointer = list_pointer
|
|
self.tailq_name_list = tailq_name_list
|
|
self.list_member = list_member
|
|
self.list = gdb.parse_and_eval(self.list_pointer)
|
|
|
|
def __iter__(self):
|
|
curr = self.list['tqh_first']
|
|
while curr:
|
|
yield self.list_member(curr)
|
|
for tailq_name in self.tailq_name_list:
|
|
curr = curr[tailq_name]
|
|
curr = curr['tqe_next']
|
|
|
|
|
|
class SpdkNormalTailqList(SpdkTailqList):
|
|
|
|
def __init__(self, list_pointer, list_member):
|
|
super(SpdkNormalTailqList, self).__init__(list_pointer, list_member,
|
|
['tailq'])
|
|
|
|
|
|
class SpdkRbTree(object):
|
|
|
|
def __init__(self, tree_pointer, tree_member, tree_name_list):
|
|
self.tree_pointer = tree_pointer
|
|
self.tree_name_list = tree_name_list
|
|
self.tree_member = tree_member
|
|
self.tree = gdb.parse_and_eval(self.tree_pointer)
|
|
|
|
def get_left_node(self, node):
|
|
return node['node']['rbe_left']
|
|
|
|
def get_right_node(self, node):
|
|
return node['node']['rbe_right']
|
|
|
|
def traverse_rb_tree(self, node):
|
|
if node:
|
|
self.rb_list.append(node)
|
|
self.traverse_rb_tree(self.get_left_node(node))
|
|
self.traverse_rb_tree(self.get_right_node(node))
|
|
|
|
def __iter__(self):
|
|
self.rb_list = []
|
|
tree_top = self.tree['rbh_root']
|
|
if tree_top:
|
|
self.traverse_rb_tree(tree_top)
|
|
for rb_node in self.rb_list:
|
|
yield self.tree_member(rb_node)
|
|
else:
|
|
yield
|
|
|
|
|
|
class SpdkArr(object):
|
|
|
|
def __init__(self, arr_pointer, num_elements, element_type):
|
|
self.arr_pointer = arr_pointer
|
|
self.num_elements = num_elements
|
|
self.element_type = element_type
|
|
|
|
def __iter__(self):
|
|
for i in range(0, self.num_elements):
|
|
curr = (self.arr_pointer + i).dereference()
|
|
if (curr == 0x0):
|
|
continue
|
|
yield self.element_type(curr)
|
|
|
|
|
|
class SpdkPrintCommand(gdb.Command):
|
|
|
|
def __init__(self, name, element_list):
|
|
self.element_list = element_list
|
|
gdb.Command.__init__(self, name,
|
|
gdb.COMMAND_DATA,
|
|
gdb.COMPLETE_SYMBOL,
|
|
True)
|
|
|
|
def print_element_list(self, element_list):
|
|
first = True
|
|
for element in element_list:
|
|
if first:
|
|
first = False
|
|
else:
|
|
print("---------------")
|
|
print("\n" + str(element) + "\n")
|
|
|
|
def invoke(self, arg, from_tty):
|
|
self.print_element_list(self.element_list)
|
|
|
|
|
|
class SpdkObject(object):
|
|
|
|
def __init__(self, gdb_obj):
|
|
self.obj = gdb_obj
|
|
|
|
def get_name(self):
|
|
return self.obj['name']
|
|
|
|
def __str__(self):
|
|
s = "SPDK object of type %s at %s" % (self.type_name, str(self.obj))
|
|
s += '\n((%s*) %s)' % (self.type_name, str(self.obj))
|
|
s += '\nname %s' % self.get_name()
|
|
return s
|
|
|
|
|
|
class IoDevice(SpdkObject):
|
|
|
|
type_name = 'struct io_device'
|
|
|
|
|
|
class IoDevices(SpdkRbTree):
|
|
|
|
def __init__(self):
|
|
super(IoDevices, self).__init__('g_io_devices', IoDevice, ['rbh_root'])
|
|
|
|
|
|
class spdk_print_io_devices(SpdkPrintCommand):
|
|
|
|
def __init__(self):
|
|
try:
|
|
io_devices = IoDevices()
|
|
except RuntimeError as e:
|
|
print("Cannot load IO devices: " + str(e))
|
|
return
|
|
name = 'spdk_print_io_devices'
|
|
super(spdk_print_io_devices, self).__init__(name, io_devices)
|
|
|
|
|
|
class Bdev(SpdkObject):
|
|
|
|
type_name = 'struct spdk_bdev'
|
|
|
|
|
|
class BdevMgrBdevs(SpdkTailqList):
|
|
|
|
def __init__(self):
|
|
tailq_name_list = ['internal', 'link']
|
|
super(BdevMgrBdevs, self).__init__('g_bdev_mgr->bdevs', Bdev, tailq_name_list)
|
|
|
|
|
|
class spdk_print_bdevs(SpdkPrintCommand):
|
|
name = 'spdk_print_bdevs'
|
|
|
|
def __init__(self):
|
|
try:
|
|
bdevs = BdevMgrBdevs()
|
|
except RuntimeError as e:
|
|
print("Cannot load bdevs: " + str(e))
|
|
return
|
|
super(spdk_print_bdevs, self).__init__(self.name, bdevs)
|
|
|
|
|
|
class spdk_find_bdev(spdk_print_bdevs):
|
|
|
|
name = 'spdk_find_bdev'
|
|
|
|
def invoke(self, arg, from_tty):
|
|
print(arg)
|
|
bdev_query = [bdev for bdev in self.element_list
|
|
if str(bdev.get_name()).find(arg) != -1]
|
|
if bdev_query == []:
|
|
print("Cannot find bdev with name %s" % arg)
|
|
return
|
|
|
|
self.print_element_list(bdev_query)
|
|
|
|
|
|
class NvmfSubsystem(SpdkObject):
|
|
|
|
type_name = 'struct spdk_nvmf_subsystem'
|
|
|
|
def __init__(self, ptr):
|
|
self.ptr = ptr
|
|
gdb_obj = self.ptr.cast(gdb.lookup_type(self.type_name).pointer())
|
|
super(NvmfSubsystem, self).__init__(gdb_obj)
|
|
|
|
def get_name(self):
|
|
return self.obj['subnqn']
|
|
|
|
def get_id(self):
|
|
return int(self.obj['id'])
|
|
|
|
def get_ns_list(self):
|
|
max_nsid = int(self.obj['max_nsid'])
|
|
ns_list = []
|
|
for i in range(0, max_nsid):
|
|
nsptr = (self.obj['ns'] + i).dereference()
|
|
if nsptr == 0x0:
|
|
continue
|
|
ns = nsptr.cast(gdb.lookup_type('struct spdk_nvmf_ns').pointer())
|
|
ns_list.append(ns)
|
|
return ns_list
|
|
|
|
def __str__(self):
|
|
s = super(NvmfSubsystem, self).__str__()
|
|
s += '\nnqn %s' % self.get_name()
|
|
s += '\nID %d' % self.get_id()
|
|
for ns in self.get_ns_list():
|
|
s += '\t%s' % str(ns)
|
|
return s
|
|
|
|
|
|
class SpdkNvmfTgtSubsystems(SpdkArr):
|
|
|
|
def get_num_subsystems(self):
|
|
try: # version >= 18.11
|
|
return int(self.spdk_nvmf_tgt['max_subsystems'])
|
|
except RuntimeError: # version < 18.11
|
|
return int(self.spdk_nvmf_tgt['opts']['max_subsystems'])
|
|
|
|
def __init__(self):
|
|
try:
|
|
self.spdk_nvmf_tgt = gdb.parse_and_eval("g_spdk_nvmf_tgt")
|
|
except RuntimeError as e:
|
|
print("Cannot load nvmf target subsystems: " + str(e))
|
|
return
|
|
subsystems = gdb.parse_and_eval("g_spdk_nvmf_tgt->subsystems")
|
|
super(SpdkNvmfTgtSubsystems, self).__init__(subsystems,
|
|
self.get_num_subsystems(),
|
|
NvmfSubsystem)
|
|
|
|
|
|
class spdk_print_nvmf_subsystems(SpdkPrintCommand):
|
|
|
|
def __init__(self):
|
|
name = 'spdk_print_nvmf_subsystems'
|
|
nvmf_tgt_subsystems = SpdkNvmfTgtSubsystems()
|
|
super(spdk_print_nvmf_subsystems, self).__init__(name, nvmf_tgt_subsystems)
|
|
|
|
|
|
class IoChannel(SpdkObject):
|
|
|
|
type_name = 'struct spdk_io_channel'
|
|
|
|
def get_ref(self):
|
|
|
|
return int(self.obj['ref'])
|
|
|
|
def get_device(self):
|
|
return self.obj['dev']
|
|
|
|
def get_device_name(self):
|
|
return self.obj['dev']['name']
|
|
|
|
def get_name(self):
|
|
return ""
|
|
|
|
def __str__(self):
|
|
s = super(IoChannel, self).__str__() + '\n'
|
|
s += 'ref %d\n' % self.get_ref()
|
|
s += 'device %s (%s)\n' % (self.get_device(), self.get_device_name())
|
|
return s
|
|
|
|
|
|
class IoChannels(SpdkRbTree):
|
|
|
|
def __init__(self, tree_obj):
|
|
self.tree_name_list = ['rbh_root']
|
|
self.tree_member = IoChannel
|
|
self.tree = tree_obj
|
|
|
|
|
|
class SpdkThread(SpdkObject):
|
|
|
|
type_name = 'struct spdk_thread'
|
|
|
|
def __init__(self, gdb_obj):
|
|
super(SpdkThread, self).__init__(gdb_obj)
|
|
self.io_channels = IoChannels(self.obj['io_channels'])
|
|
|
|
def __str__(self):
|
|
s = super(SpdkThread, self).__str__() + '\n'
|
|
s += "IO Channels:\n"
|
|
for io_channel in self.get_io_channels():
|
|
channel_lines = str(io_channel).split('\n')
|
|
s += '\n'.join('\t%s' % line for line in channel_lines if line is not '')
|
|
s += '\n'
|
|
s += '\t---------------\n'
|
|
s += '\n'
|
|
return s
|
|
|
|
def get_io_channels(self):
|
|
return self.io_channels
|
|
|
|
|
|
class SpdkThreads(SpdkNormalTailqList):
|
|
|
|
def __init__(self):
|
|
super(SpdkThreads, self).__init__('g_threads', SpdkThread)
|
|
|
|
|
|
class spdk_print_threads(SpdkPrintCommand):
|
|
|
|
def __init__(self):
|
|
name = "spdk_print_threads"
|
|
threads = SpdkThreads()
|
|
super(spdk_print_threads, self).__init__(name, threads)
|
|
|
|
|
|
class spdk_load_macros(gdb.Command):
|
|
|
|
def __init__(self):
|
|
gdb.Command.__init__(self, 'spdk_load_macros',
|
|
gdb.COMMAND_DATA,
|
|
gdb.COMPLETE_SYMBOL,
|
|
True)
|
|
self.loaded = False
|
|
|
|
def invoke(self, arg, from_tty):
|
|
if arg == '--reload':
|
|
print('Reloading spdk information')
|
|
reload = True
|
|
else:
|
|
reload = False
|
|
|
|
if self.loaded and not reload:
|
|
return
|
|
|
|
spdk_print_threads()
|
|
spdk_print_bdevs()
|
|
spdk_print_io_devices()
|
|
spdk_print_nvmf_subsystems()
|
|
spdk_find_bdev()
|
|
|
|
|
|
spdk_load_macros()
|