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