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