1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright (C) 2019 Intel Corporation. 3# 4 5import gdb 6 7 8class SpdkTailqList(object): 9 10 def __init__(self, list_pointer, list_member, tailq_name_list): 11 self.list_pointer = list_pointer 12 self.tailq_name_list = tailq_name_list 13 self.list_member = list_member 14 self.list = gdb.parse_and_eval(self.list_pointer) 15 16 def __iter__(self): 17 curr = self.list['tqh_first'] 18 while curr: 19 yield self.list_member(curr) 20 for tailq_name in self.tailq_name_list: 21 curr = curr[tailq_name] 22 curr = curr['tqe_next'] 23 24 25class SpdkNormalTailqList(SpdkTailqList): 26 27 def __init__(self, list_pointer, list_member): 28 super(SpdkNormalTailqList, self).__init__(list_pointer, list_member, 29 ['tailq']) 30 31 32class SpdkRbTree(object): 33 34 def __init__(self, tree_pointer, tree_member, tree_name_list): 35 self.tree_pointer = tree_pointer 36 self.tree_name_list = tree_name_list 37 self.tree_member = tree_member 38 self.tree = gdb.parse_and_eval(self.tree_pointer) 39 40 def get_left_node(self, node): 41 return node['node']['rbe_left'] 42 43 def get_right_node(self, node): 44 return node['node']['rbe_right'] 45 46 def traverse_rb_tree(self, node): 47 if node: 48 self.rb_list.append(node) 49 self.traverse_rb_tree(self.get_left_node(node)) 50 self.traverse_rb_tree(self.get_right_node(node)) 51 52 def __iter__(self): 53 self.rb_list = [] 54 tree_top = self.tree['rbh_root'] 55 if tree_top: 56 self.traverse_rb_tree(tree_top) 57 for rb_node in self.rb_list: 58 yield self.tree_member(rb_node) 59 else: 60 yield 61 62 63class SpdkArr(object): 64 65 def __init__(self, arr_pointer, num_elements, element_type): 66 self.arr_pointer = arr_pointer 67 self.num_elements = num_elements 68 self.element_type = element_type 69 70 def __iter__(self): 71 for i in range(0, self.num_elements): 72 curr = (self.arr_pointer + i).dereference() 73 if (curr == 0x0): 74 continue 75 yield self.element_type(curr) 76 77 78class SpdkPrintCommand(gdb.Command): 79 80 def __init__(self, name, element_list): 81 self.element_list = element_list 82 gdb.Command.__init__(self, name, 83 gdb.COMMAND_DATA, 84 gdb.COMPLETE_SYMBOL, 85 True) 86 87 def print_element_list(self, element_list): 88 first = True 89 for element in element_list: 90 if first: 91 first = False 92 else: 93 print("---------------") 94 print("\n" + str(element) + "\n") 95 96 def invoke(self, arg, from_tty): 97 self.print_element_list(self.element_list) 98 99 100class SpdkObject(object): 101 102 def __init__(self, gdb_obj): 103 self.obj = gdb_obj 104 105 def get_name(self): 106 return self.obj['name'] 107 108 def __str__(self): 109 s = "SPDK object of type %s at %s" % (self.type_name, str(self.obj)) 110 s += '\n((%s*) %s)' % (self.type_name, str(self.obj)) 111 s += '\nname %s' % self.get_name() 112 return s 113 114 115class IoDevice(SpdkObject): 116 117 type_name = 'struct io_device' 118 119 120class IoDevices(SpdkRbTree): 121 122 def __init__(self): 123 super(IoDevices, self).__init__('g_io_devices', IoDevice, ['rbh_root']) 124 125 126class spdk_print_io_devices(SpdkPrintCommand): 127 128 def __init__(self): 129 io_devices = IoDevices() 130 name = 'spdk_print_io_devices' 131 super(spdk_print_io_devices, self).__init__(name, io_devices) 132 133 134class Bdev(SpdkObject): 135 136 type_name = 'struct spdk_bdev' 137 138 139class BdevMgrBdevs(SpdkTailqList): 140 141 def __init__(self): 142 tailq_name_list = ['internal', 'link'] 143 super(BdevMgrBdevs, self).__init__('g_bdev_mgr->bdevs', Bdev, tailq_name_list) 144 145 146class spdk_print_bdevs(SpdkPrintCommand): 147 name = 'spdk_print_bdevs' 148 149 def __init__(self): 150 bdevs = BdevMgrBdevs() 151 super(spdk_print_bdevs, self).__init__(self.name, bdevs) 152 153 154class spdk_find_bdev(spdk_print_bdevs): 155 156 name = 'spdk_find_bdev' 157 158 def invoke(self, arg, from_tty): 159 print(arg) 160 bdev_query = [bdev for bdev in self.element_list 161 if str(bdev.get_name()).find(arg) != -1] 162 if bdev_query == []: 163 print("Cannot find bdev with name %s" % arg) 164 return 165 166 self.print_element_list(bdev_query) 167 168 169class NvmfSubsystem(SpdkObject): 170 171 type_name = 'struct spdk_nvmf_subsystem' 172 173 def __init__(self, ptr): 174 self.ptr = ptr 175 gdb_obj = self.ptr.cast(gdb.lookup_type(self.type_name).pointer()) 176 super(NvmfSubsystem, self).__init__(gdb_obj) 177 178 def get_name(self): 179 return self.obj['subnqn'] 180 181 def get_id(self): 182 return int(self.obj['id']) 183 184 def get_ns_list(self): 185 max_nsid = int(self.obj['max_nsid']) 186 ns_list = [] 187 for i in range(0, max_nsid): 188 nsptr = (self.obj['ns'] + i).dereference() 189 if nsptr == 0x0: 190 continue 191 ns = nsptr.cast(gdb.lookup_type('struct spdk_nvmf_ns').pointer()) 192 ns_list.append(ns) 193 return ns_list 194 195 def __str__(self): 196 s = super(NvmfSubsystem, self).__str__() 197 s += '\nnqn %s' % self.get_name() 198 s += '\nID %d' % self.get_id() 199 for ns in self.get_ns_list(): 200 s += '\t%s' % str(ns) 201 return s 202 203 204class SpdkNvmfTgtSubsystems(SpdkArr): 205 206 def get_num_subsystems(self): 207 try: # version >= 18.11 208 return int(self.spdk_nvmf_tgt['max_subsystems']) 209 except RuntimeError: # version < 18.11 210 return int(self.spdk_nvmf_tgt['opts']['max_subsystems']) 211 212 def __init__(self): 213 self.spdk_nvmf_tgt = gdb.parse_and_eval("g_spdk_nvmf_tgt") 214 subsystems = gdb.parse_and_eval("g_spdk_nvmf_tgt->subsystems") 215 super(SpdkNvmfTgtSubsystems, self).__init__(subsystems, 216 self.get_num_subsystems(), 217 NvmfSubsystem) 218 219 220class spdk_print_nvmf_subsystems(SpdkPrintCommand): 221 222 def __init__(self): 223 name = 'spdk_print_nvmf_subsystems' 224 nvmf_tgt_subsystems = SpdkNvmfTgtSubsystems() 225 super(spdk_print_nvmf_subsystems, self).__init__(name, nvmf_tgt_subsystems) 226 227 228class IoChannel(SpdkObject): 229 230 type_name = 'struct spdk_io_channel' 231 232 def get_ref(self): 233 234 return int(self.obj['ref']) 235 236 def get_device(self): 237 return self.obj['dev'] 238 239 def get_device_name(self): 240 return self.obj['dev']['name'] 241 242 def get_name(self): 243 return "" 244 245 def __str__(self): 246 s = super(IoChannel, self).__str__() + '\n' 247 s += 'ref %d\n' % self.get_ref() 248 s += 'device %s (%s)\n' % (self.get_device(), self.get_device_name()) 249 return s 250 251 252class IoChannels(SpdkRbTree): 253 254 def __init__(self, tree_obj): 255 self.tree_name_list = ['rbh_root'] 256 self.tree_member = IoChannel 257 self.tree = tree_obj 258 259 260class SpdkThread(SpdkObject): 261 262 type_name = 'struct spdk_thread' 263 264 def __init__(self, gdb_obj): 265 super(SpdkThread, self).__init__(gdb_obj) 266 self.io_channels = IoChannels(self.obj['io_channels']) 267 268 def __str__(self): 269 s = super(SpdkThread, self).__str__() + '\n' 270 s += "IO Channels:\n" 271 for io_channel in self.get_io_channels(): 272 channel_lines = str(io_channel).split('\n') 273 s += '\n'.join('\t%s' % line for line in channel_lines if line is not '') 274 s += '\n' 275 s += '\t---------------\n' 276 s += '\n' 277 return s 278 279 def get_io_channels(self): 280 return self.io_channels 281 282 283class SpdkThreads(SpdkNormalTailqList): 284 285 def __init__(self): 286 super(SpdkThreads, self).__init__('g_threads', SpdkThread) 287 288 289class spdk_print_threads(SpdkPrintCommand): 290 291 def __init__(self): 292 name = "spdk_print_threads" 293 threads = SpdkThreads() 294 super(spdk_print_threads, self).__init__(name, threads) 295 296 297class spdk_load_macros(gdb.Command): 298 299 def __init__(self): 300 gdb.Command.__init__(self, 'spdk_load_macros', 301 gdb.COMMAND_DATA, 302 gdb.COMPLETE_SYMBOL, 303 True) 304 self.loaded = False 305 306 def invoke(self, arg, from_tty): 307 if arg == '--reload': 308 print('Reloading spdk information') 309 reload = True 310 else: 311 reload = False 312 313 if self.loaded and not reload: 314 return 315 316 spdk_print_threads() 317 spdk_print_bdevs() 318 spdk_print_io_devices() 319 spdk_print_nvmf_subsystems() 320 spdk_find_bdev() 321 322 323spdk_load_macros() 324