1 2""" Please make sure you read the README COMPLETELY BEFORE reading anything below. 3 It is very critical that you read coding guidelines in Section E in README file. 4""" 5 6from xnu import * 7from utils import * 8from string import * 9from net import * 10 11import xnudefines 12 13def IterateProcChannels(proc): 14 """ Iterate through all channels in the given process 15 16 params: 17 proc - the proc object 18 returns: nothing, this is meant to be used as a generator function 19 kc - yields each kern_channel in the process 20 """ 21 22 proc_filedesc = addressof(proc.p_fd) 23 proc_ofiles = proc_filedesc.fd_ofiles 24 25 for fd in xrange(0, unsigned(proc_filedesc.fd_afterlast)): 26 if unsigned(proc_ofiles[fd]) != 0: 27 proc_fd_fglob = proc_ofiles[fd].fp_glob 28 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 10): 29 proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *') 30 yield Cast(proc_fd_fglob_fg_data, 'kern_channel *') 31 32def IterateKernChannelRings(kc, kind): 33 """ Iterate through all rings on a given channel 34 """ 35 36 NR_RX = 0 37 NR_TX = 1 38 NR_A = 2 39 NR_F = 3 40 41 if kind == NR_RX: 42 rings = kc.ch_na.na_rx_rings 43 elif kind == NR_TX : 44 rings = kc.ch_na.na_tx_rings 45 elif kind == NR_A : 46 rings = kc.ch_na.na_alloc_rings 47 else : 48 rings = kc.ch_na.na_free_rings 49 50 # note that ch_last is actually one greater than the last 51 # as per the comment in ch_connect 52 for i in xrange(kc.ch_first[kind], kc.ch_last[kind]): 53 yield addressof(rings[i]) 54 55# Note this is broken if you have type summaries enabled 56# because we are summarizing the pointer to the structure 57# and not the structure itself. Unfortunately, that's 58# the pattern used elsewhere. 59# Trying to actually use the type summary will blow up 60# because it has a linked list pointer to itself 61# 62@lldb_type_summary(['kern_channel_t', 'kern_channel *']) 63@header('{:<20s} {:<36s}'.format('kern_channel', 'uuid')) 64def GetKernChannelSummary(kc): 65 """ Summarizes a kern_channel and related information 66 67 returns: str - summary of kern_channel 68 """ 69 70 format_string = '{o: <#020x} {u: <36s}' 71 return format_string.format( 72 o=kc, 73 u=GetUUIDSummary(kc.ch_info.cinfo_ch_id)) 74 75@lldb_type_summary(['__kern_channel_ring *']) 76@header('{:<20s} {:<65s} {:>10s} | {:<5s} {:<5s} | {:<5s} {:<5s} | {:<5s} {:<5s}'.format( 77 'kernchannelring', 'name', 'flags', 'kh', 'kt', 'rh', 'rt', 'h', 't')) 78def GetKernChannelRingSummary(kring): 79 """ Summarizes a __kern_channel_ring and related information 80 81 returns: str - summary of kern_channel_ring 82 """ 83 84 format_string = '{o: <#020x} "{name: <63s}" {flags: >#010x} | {kh: <5d} {kt: <5d} | {rh: <5d} {rt: <5d} | {h: <5d} {t: <5d}' 85 return format_string.format( 86 o=kring, 87 name=kring.ckr_name, 88 flags=kring.ckr_flags, 89 kh=kring.ckr_khead, 90 kt=kring.ckr_ktail, 91 rh=kring.ckr_rhead, 92 rt=kring.ckr_rtail, 93 h=kring.ckr_ring.ring_head, 94 t=kring.ckr_ring.ring_tail) 95 96@lldb_command('showprocchannels') 97def ShowProcChannels(cmd_args=None): 98 """ Show the skywalk channels for a given process. 99 100 usage: showprocchannels <proc_t> 101 """ 102 103 if not cmd_args: 104 raise ArgumentError('missing struct proc * argument') 105 106 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t') 107 108 print GetKernChannelSummary.header 109 for kc in IterateProcChannels(proc): 110 print GetKernChannelSummary(kc) 111 112@lldb_command('showchannelrings') 113def ShowChannelRings(cmd_args=None): 114 """ Show the skywalk rings for a given channel. 115 116 usage: showchannelrings <struct kern_channel *> 117 """ 118 119 if not cmd_args: 120 raise ArgumentError('missing struct kern_channel * argument') 121 122 kc = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *') 123 124 print "RX rings:" 125 print GetKernChannelRingSummary.header 126 for ring in IterateKernChannelRings(kc, 0) : 127 print GetKernChannelRingSummary(ring) 128 129 print "TX rings:" 130 print GetKernChannelRingSummary.header 131 for ring in IterateKernChannelRings(kc, 1) : 132 print GetKernChannelRingSummary(ring) 133 134 print "ALLOC rings:" 135 print GetKernChannelRingSummary.header 136 for ring in IterateKernChannelRings(kc, 2) : 137 print GetKernChannelRingSummary(ring) 138 139 print "FREE rings:" 140 print GetKernChannelRingSummary.header 141 for ring in IterateKernChannelRings(kc, 3) : 142 print GetKernChannelRingSummary(ring) 143 144def SkmemCacheModeAsString(mode) : 145 out_string = "" 146 SKM_MODE_NOCACHE = 0x1 147 SKM_MODE_AUDIT = 0x2 148 149 if (mode & SKM_MODE_NOCACHE) : 150 out_string += "n" 151 else : 152 out_string += "-" 153 if (mode & SKM_MODE_AUDIT) : 154 out_string += "a" 155 else : 156 out_string += "-" 157 158 return out_string 159 160@lldb_command('showskmemcache') 161def ShowSkmemCache(cmd_args=None) : 162 """ Show the global list of skmem caches 163 """ 164 165 format_string = "{:<4s} {:<18s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<4s} {:<s}" 166 print format_string.format("", "ADDR", "BUFI", "BUFM", "RESC", "SLCR", "SLDE", "SLAL", "SLFR", "DECO", "MODE", "NAME") 167 168 i = 1 169 skmhead = kern.globals.skmem_cache_head 170 171 for skm in IterateTAILQ_HEAD(skmhead, "skm_link") : 172 format_string = "{:>4d}: 0x{:<08x} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4d} {:<4s} \"{:<s}\"" 173 print format_string.format(i, skm, skm.skm_sl_bufinuse, skm.skm_sl_bufmax, skm.skm_sl_rescale, skm.skm_sl_create, skm.skm_sl_destroy, skm.skm_sl_alloc, skm.skm_sl_free, skm.skm_depot_contention, SkmemCacheModeAsString(skm.skm_mode), str(skm.skm_name)) 174 i += 1 175 176@lldb_command('showskmemslab') 177def ShowBufCtl(cmd_args=None) : 178 """ Show slabs and bufctls of a skmem cache 179 """ 180 181 if (cmd_args == None or len(cmd_args) == 0) : 182 print "Missing argument 0 (skmem_cache address)." 183 return 184 185 skm = kern.GetValueFromAddress(cmd_args[0], 'skmem_cache *') 186 187 for slab in IterateTAILQ_HEAD(skm.skm_sl_partial_list, "sl_link") : 188 format_string = "{:<18s} {:<4s} {:18s} {:18s}" 189 print format_string.format("slab", "ref", "base", "basem") 190 format_string = "0x{:<08x} {:<4d} 0x{:<08x} 0x{:08x}" 191 print format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem) 192 print "\t========================= free =========================" 193 format_string = "\t{:<18s} {:18s} {:18s}" 194 print format_string.format("bufctl", "buf_addr", "buf_addrm") 195 for bc in IterateListEntry(slab.sl_head, 'struct skmem_bufctl *', 196 'bc_link', list_prefix='s') : 197 format_string = "\t0x{:<08x} 0x{:<08x} 0x{:<08x}" 198 print format_string.format(bc, bc.bc_addr, bc.bc_addrm) 199 200 for slab in IterateTAILQ_HEAD(skm.skm_sl_empty_list, "sl_link") : 201 format_string = "{:<18s} {:<4s} {:18s} {:18s}" 202 print format_string.format("slab", "ref", "base", "basem") 203 format_string = "0x{:<08x} {:<4d} 0x{:<08x} 0x{:08x}" 204 print format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem) 205 print "\t========================= free =========================" 206 format_string = "\t{:<18s} {:18s} {:18s}" 207 print format_string.format("bufctl", "buf_addr", "buf_addrm") 208 for bc in IterateListEntry(slab.sl_head, 'struct skmem_bufctl *', 209 'bc_link', list_prefix='s') : 210 format_string = "\t0x{:<08x} 0x{:<08x} 0x{:<08x}" 211 print format_string.format(bc, bc.bc_addr, bc.bc_addrm) 212 213 print " " 214 for i in range(0, skm.skm_hash_mask + 1) : 215 format_string = "{:<18s} {:<4s}" 216 print format_string.format("bucket", "idx") 217 format_string = "0x{:<08x} {:<4d}" 218 print format_string.format(addressof(skm.skm_hash_table[i]), i) 219 print "\t====================== allocated =======================" 220 format_string = "\t{:<18s} {:18s} {:18s}" 221 print format_string.format("bufctl", "buf_addr", "buf_addrm") 222 for bc in IterateListEntry(skm.skm_hash_table[i].bcb_head, 223 'struct skmem_bufctl *', 'bc_link', list_prefix='s') : 224 format_string = "\t0x{:<08x} 0x{:<08x} 0x{:<08x}" 225 print format_string.format(bc, bc.bc_addr, bc.bc_addrm) 226 227def SkmemArenaTypeAsString(type) : 228 out_string = "" 229 SKMEM_ARENA_TYPE_NEXUS = 0 230 SKMEM_ARENA_TYPE_NECP = 1 231 SKMEM_ARENA_TYPE_SYSTEM = 2 232 233 if (type == SKMEM_ARENA_TYPE_NEXUS) : 234 out_string += "NEXUS" 235 elif (type == SKMEM_ARENA_TYPE_NECP) : 236 out_string += "NECP" 237 elif (type == SKMEM_ARENA_TYPE_SYSTEM) : 238 out_string += "SYSTEM" 239 else : 240 out_string += "?" 241 242 return out_string 243 244@lldb_command('showskmemarena') 245def ShowSkmemArena(cmd_args=None) : 246 """ Show the global list of skmem arenas 247 """ 248 249 i = 1 250 arhead = kern.globals.skmem_arena_head 251 252 for ar in IterateTAILQ_HEAD(arhead, "ar_link") : 253 format_string = "{:>4d}: 0x{:<08x} {:<6s} {:>5d} KB \"{:<s}\"" 254 print format_string.format(i, ar, SkmemArenaTypeAsString(ar.ar_type), ar.ar_mapsize >> 10, str(ar.ar_name)) 255 i += 1 256 257@lldb_command('showskmemregions') 258def ShowSkmemRegions(cmd_args=None) : 259 """ Show the global list of skmem regions 260 """ 261 262 i = 1 263 skrhead = kern.globals.skmem_region_head 264 265 for skr in IterateTAILQ_HEAD(skrhead, "skr_link") : 266 format_string = "{:>4d}: 0x{:<08x} \"{:<s}\"" 267 print format_string.format(i, skr, str(skr.skr_name)) 268 i += 1 269 270@lldb_command('showskmemregion') 271def ShowSkmemRegion(cmd_args=None) : 272 """ Show segments of a skmem region 273 """ 274 275 if (cmd_args == None or len(cmd_args) == 0) : 276 print "Missing argument 0 (skmem_region address)." 277 return 278 279 skr = kern.GetValueFromAddress(cmd_args[0], 'skmem_region *') 280 281 print "\t========================= free =========================" 282 for sg in IterateTAILQ_HEAD(skr.skr_seg_free, "sg_link") : 283 format_string = "{:<18s} {:<4s} {:18s} {:18s}" 284 print format_string.format("segment", "idx", "start", "end") 285 format_string = "0x{:<08x} {:<4d} 0x{:<08x} 0x{:08x}" 286 print format_string.format(sg, sg.sg_index, sg.sg_start, sg.sg_end) 287 format_string = "\t{:<18s} {:18s} {:18s}" 288 print format_string.format("bufctl", "buf_addr", "buf_addrm") 289 290 print " " 291 for i in range(0, skr.skr_hash_mask + 1) : 292 format_string = "{:<18s} {:<4s}" 293 print format_string.format("bucket", "idx") 294 format_string = "0x{:<08x} {:<4d}" 295 print format_string.format(addressof(skr.skr_hash_table[i]), i) 296 print "\t====================== allocated =======================" 297 format_string = "\t{:<18s} {:4s} {:18s} {:18s}" 298 print format_string.format("segment", "idx", "start", "end") 299 for sg in IterateTAILQ_HEAD(skr.skr_hash_table[i].sgb_head, "sg_link") : 300 format_string = "\t0x{:<08x} {:<4d} 0x{:<08x} 0x{:<08x}" 301 print format_string.format(sg, sg.sg_index, sg.sg_start, sg.sg_end) 302 303@lldb_command('showchannelupphash') 304def ShowChannelUppHash(cmd_args=None) : 305 """ Show channel user packet pool hash chain 306 """ 307 308 if (cmd_args == None or len(cmd_args) == 0) : 309 print "Missing argument 0 (skmem_cache address)." 310 return 311 312 ch = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *') 313 KERN_CHANNEL_UPP_HTBL_SIZE = 256 314 315 for i in range(KERN_CHANNEL_UPP_HTBL_SIZE) : 316 bkt = addressof(ch.ch_upp_hash_table[i]) 317 format_string = "{:>4d} 0x{:<08x}" 318 print format_string.format(i, bkt) 319 for kqum in IterateListEntry(bkt.upp_head, 'struct __kern_quantum *', 320 'qum_upp_link', list_prefix='s') : 321 format_string = "0x{:<08x}" 322 print format_string.format(kqum) 323 324@lldb_type_summary(['struct ns *']) 325@header('{:<20s} {:<5s} {:<48s} {:<4s}'.format('ns', 'proto', 'addr', 'nreservations')) 326def GetStructNsSummary(ns): 327 """ Summarizes a struct ns from the netns 328 329 returns: str - summary of struct ns 330 """ 331 332 if (ns.ns_proto == IPPROTO_TCP): 333 proto = "tcp" 334 elif (ns.ns_proto == IPPROTO_UDP): 335 proto = "udp" 336 else: 337 proto = str(ns.ns_proto) 338 339 if (ns.ns_addr_len == sizeof('struct in_addr')): 340 addr = GetInAddrAsString(addressof(ns.ns_inaddr)) 341 elif (ns.ns_addr_len == sizeof('struct in6_addr')): 342 addr = GetIn6AddrAsString(ns.ns_in6addr.__u6_addr.__u6_addr8) 343 else: 344 addr = str(ns_addr) + " bad len {:u}".format(ns.ns_addr_len) 345 346 format_string = '{o:#020x} {p:<5s} {a:<48s} {n:<4d}' 347 348 """ show ports and refs, one per line 349 """ 350 ports_string = "ports & refs\n" 351 for f in IterateRBTreeEntry(ns.ns_reservations, 'struct ns_reservation *', 'nsr_link'): 352 ports_string += "\t%u" % f.nsr_port 353 ports_string += "\tlisten %d\tskywalk %d\tbsd %d\tpf %d\n" % (f.nsr_refs[0], f.nsr_refs[1], f.nsr_refs[2], f.nsr_refs[3]) 354 """ show just the ports, not refs 355 offs = 0 356 ports_string = "\nports:\t" 357 for f in IterateRBTreeEntry(ns.ns_reservations, 'struct ns_reservation *', 'nsr_link'): 358 if (len(ports_string)-offs > 70): 359 ports_string += "\n\t" 360 offs = len(ports_string) 361 ports_string += " %u" % f.nsr_port 362 """ 363 364 return format_string.format( 365 o=ns, 366 p=proto, 367 a=addr, 368 n=ns.ns_n_reservations) + ports_string 369 370@lldb_command('shownetns') 371def ShowNetNS(cmd_args=None): 372 """ Show the netns table 373 """ 374 print"\nnetns_namespaces:" 375 print GetStructNsSummary.header 376 377 namespaces = kern.globals.netns_namespaces 378 for ns in IterateRBTreeEntry(namespaces, 'struct ns *', 'ns_link'): 379 print GetStructNsSummary(ns) 380 381 print "\nwild: (these should be duplicated above)" 382 print GetStructNsSummary.header 383 for i in range(0,4): 384 print GetStructNsSummary(kern.globals.netns_global_wild[i]) 385 386 print "\nnon wild:" 387 print GetStructNsSummary.header 388 for i in range(0,4): 389 print GetStructNsSummary(kern.globals.netns_global_non_wild[i]) 390 391 392NETNS_LISTENER = 0x00 393NETNS_SKYWALK = 0x01 394NETNS_BSD = 0x02 395NETNS_PF = 0x03 396NETNS_OWNER_MASK = 0x7 397 398netns_flag_strings = { 399 NETNS_LISTENER : "LISTENER", 400 NETNS_SKYWALK : "SKYWALK", 401 NETNS_BSD : "BSD", 402 NETNS_PF : "PF", 403} 404 405@lldb_type_summary(['struct ns_token *']) 406@header('{:<20s} {:<5s} {:<48s} {:<12s} {:<8s} {:<38s} {:<12s}'.format('nt', 'proto', 'addr', 'port', 'owner', 'ifp', 'flags')) 407def GetNsTokenSummary(nt): 408 """ Summarizes a struct ns from the netns 409 410 returns: str - summary of struct ns 411 """ 412 413 if (nt.nt_proto == IPPROTO_TCP): 414 proto = "tcp" 415 elif (nt.nt_proto == IPPROTO_UDP): 416 proto = "udp" 417 else: 418 proto = str(nt.nt_proto) 419 420 if (nt.nt_addr_len == sizeof('struct in_addr')): 421 addr = GetInAddrAsString(addressof(nt.nt_inaddr)) 422 elif (nt.nt_addr_len == sizeof('struct in6_addr')): 423 addr = GetIn6AddrAsString(nt.nt_in6addr.__u6_addr.__u6_addr8) 424 else: 425 addr = str(nt_addr) + " bad len {:u}".format(nt.nt_addr_len) 426 427 format_string = '{o:#020x} {p:<5s} {a:<48s} {pt:<12s} {wn:<8s} {ifp:38s} {f:#012x}' 428 429 ports = "%u" % nt.nt_port 430 431 ifp = "(struct ifnet *)" + hex(nt.nt_ifp) 432 433 owner = netns_flag_strings[nt.nt_flags & NETNS_OWNER_MASK] 434 435 return format_string.format( 436 o=nt, 437 p=proto, 438 a=addr, 439 pt=ports, 440 wn=owner, 441 ifp=ifp, 442 f=nt.nt_flags) 443 444@lldb_command("showallnetnstokens") 445def ShowAllNetNSTokens(cmd_args=None): 446 """ show all netns tokens 447 """ 448 449 tokenhead = kern.globals.netns_all_tokens 450 print GetNsTokenSummary.header 451 for nt in IterateListEntry(tokenhead, 'struct ns_token *', 'nt_all_link', list_prefix='s'): 452 print GetNsTokenSummary(nt) 453 454@lldb_command("shownetnstokens") 455def ShowNetNSTokens(cmd_args=None): 456 """ show netns tokens attached to an ifp 457 with no args, shows unbound tokens 458 """ 459 460 if (cmd_args == None or len(cmd_args) == 0): 461 print "No ifp argument provided, showing unbound tokens" 462 tokenhead = kern.globals.netns_unbound_tokens 463 elif len(cmd_args) > 0: 464 ifp = kern.GetValueFromAddress(cmd_args[0], 'ifnet *') 465 print "Showing tokens for ifp %r" % ifp 466 tokenhead = ifp.if_netns_tokens 467 else: 468 print "Missing ifp argument 0 in shownetnstokens" 469 print cmd_args 470 return 471 472 print GetNsTokenSummary.header 473 for nt in IterateListEntry(tokenhead, 'struct ns_token *', 'nt_ifp_link', list_prefix='s'): 474 print GetNsTokenSummary(nt) 475 476def IterateSTAILQ_HEAD(headval, element_name): 477 iter_val = headval.stqh_first 478 while unsigned(iter_val) != 0 : 479 yield iter_val 480 iter_val = iter_val.__getattr__(element_name).stqe_next 481 #end of yield loop 482 483@lldb_command("shownexuschannels") 484def ShowNexusChannels(cmd_args=None): 485 """ show nexus channels 486 """ 487 if (cmd_args == None or len(cmd_args) == 0): 488 print "Missing argument 0 (kern_nexus address)." 489 return 490 491 nx = kern.GetValueFromAddress(cmd_args[0], 'kern_nexus *') 492 i = 1 493 494 format_string = "{:>4s} {:<18s} {:>4s} {:<7s} {:<7s} {:<18s} {:<18s} {:<18s} {:>8s} {:6s} {:<18s} {:>4s} {:s}" 495 print format_string.format("", "addr", "refs", "txrings", "rxrings", "arena", "ioskmap", "mapaddr", "mapsize", "maprdr", "na", "fd", "process") 496 497 for ch in IterateSTAILQ_HEAD(nx.nx_ch_head, "ch_link"): 498 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})" 499 print format_string.format(i, ch, ch.ch_refcnt, ch.ch_first[0], ch.ch_last[0], ch.ch_first[1], ch.ch_last[1], ch.ch_mmap.ami_arena, ch.ch_mmap.ami_mapref, ch.ch_mmap.ami_mapaddr, ch.ch_mmap.ami_mapsize, ch.ch_mmap.ami_redirect, ch.ch_na, ch.ch_fd, ch.ch_name, ch.ch_pid) 500 i += 1 501 502 for ch in IterateSTAILQ_HEAD(nx.nx_ch_nonxref_head, "ch_link"): 503 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})" 504 print format_string.format(i, ch, ch.ch_refcnt, ch.ch_first[0], ch.ch_last[0], ch.ch_first[1], ch.ch_last[1], ch.ch_mmap.ami_arena, ch.ch_mmap.ami_mapref, ch.ch_mmap.ami_mapaddr, ch.ch_mmap.ami_mapsize, ch.ch_mmap.ami_redirect, ch.ch_na, ch.ch_fd, ch.ch_name, ch.ch_pid) 505 i += 1 506 507def IterateProcNECP(proc): 508 """ Iterate through all NECP descriptors in the given process 509 510 params: 511 proc - the proc object 512 returns: nothing, this is meant to be used as a generator function 513 necp - yields each necp_fd_data in the process 514 """ 515 516 proc_filedesc = addressof(proc.p_fd) 517 proc_ofiles = proc_filedesc.fd_ofiles 518 519 for fd in xrange(0, unsigned(proc_filedesc.fd_afterlast)): 520 if unsigned(proc_ofiles[fd]) != 0: 521 proc_fd_fglob = proc_ofiles[fd].fp_glob 522 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 9): 523 proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *') 524 yield Cast(proc_fd_fglob_fg_data, 'necp_fd_data *') 525 526def GetNECPClientBitFields(necp): 527 """ Return the bit fields in necp_client as string 528 529 returns: str - string representation of necp_client bit fields 530 """ 531 532 bitfields_string = '' 533 if necp.result_read != 0: 534 bitfields_string += 'r' 535 else: 536 bitfields_string += '-' 537 if necp.allow_multiple_flows != 0: 538 bitfields_string += 'm' 539 else: 540 bitfields_string += '-' 541 if necp.background != 0: 542 bitfields_string += 'b' 543 else: 544 bitfields_string += '-' 545 if necp.background_update != 0: 546 bitfields_string += 'B' 547 else: 548 bitfields_string += '-' 549 if necp.platform_binary != 0: 550 bitfields_string += 'p' 551 else: 552 bitfields_string += '-' 553 554 return bitfields_string 555 556def GetNECPFlowBitFields(flow_registration): 557 """ Return the bit fields in necp_client_flow_registration as string 558 559 returns: str - string representation of necp_client_flow_registration bit fields 560 """ 561 562 bitfields_string = '' 563 if flow_registration.flow_result_read != 0: 564 bitfields_string += 'r' 565 else: 566 bitfields_string += '-' 567 if flow_registration.defunct != 0: 568 bitfields_string += 'd' 569 else: 570 bitfields_string += '-' 571 572 return bitfields_string 573 574@lldb_type_summary(['necp_fd_data *']) 575@header('{:<20s} {:<8s}'.format('necp_fd_data', "flags")) 576def GetNECPSummary(necp): 577 """ Summarizes a necp_fd_data and related information 578 579 returns: str - summary of necp_fd_data 580 """ 581 582 format_string = '{o: <#020x} {u:<#08x}' 583 584 stats_arenas_string = "\n\n\t%-18s %-39s %-4s %-10s\n" % ("stats_arenas", "mmap", "refs", "flags") 585 for sa in IterateListEntry(necp.stats_arena_list, 'struct necp_arena_info *', 'nai_chain'): 586 stats_arenas_string += "\t0x%016x " % sa 587 stats_arenas_string += "[0x%016x-0x%016x) " % (sa.nai_mmap.ami_mapaddr,(sa.nai_mmap.ami_mapaddr+sa.nai_mmap.ami_mapsize)) 588 stats_arenas_string += "%4u " % sa.nai_use_count 589 stats_arenas_string += "0x%08x " % sa.nai_flags 590 stats_arenas_string += "\n" 591 592 clients_string = "" 593 for c in IterateRBTreeEntry(necp.clients, 'struct necp_client *', 'link'): 594 clients_string += "\n\t%-18s %-36s %-4s %-5s\n" % ("necp_clients", "client_id", "refs", "flags") 595 clients_string += "\t0x%016x " % c 596 clients_string += "%36s " % GetUUIDSummary(c.client_id) 597 clients_string += "%4u " % c.reference_count 598 clients_string += "%5s " % GetNECPClientBitFields(c) 599 count = 0; 600 for f in IterateRBTreeEntry(c.flow_registrations, 'struct necp_client_flow_registration *', 'client_link'): 601 if count == 0: 602 clients_string += "\n\t\t%-18s %-36s %-2s %-18s %-18s %-18s\n" % ("flow_registration", "registraton_id", "flags", "stats_arena", "kstats_obj", "ustats_obj") 603 clients_string += "\t\t0x%016x " % f 604 clients_string += "%36s " % GetUUIDSummary(f.registration_id) 605 clients_string += "%2s " % GetNECPFlowBitFields(f) 606 clients_string += "0x%016x " % f.stats_arena 607 clients_string += "0x%016x " % f.kstats_kaddr 608 clients_string += "0x%016x " % f.ustats_uaddr 609 clients_string += "\n" 610 611 return format_string.format( 612 o=necp, 613 u=necp.flags) + stats_arenas_string + clients_string 614 615@lldb_command('showprocnecp') 616def ShowProcNECP(cmd_args=None): 617 """ Show NECP descriptors for a given process. 618 619 usage: showprocnecp <proc_t> 620 """ 621 622 if not cmd_args: 623 raise ArgumentError('missing struct proc * argument') 624 625 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t') 626 627 print GetNECPSummary.header 628 for kc in IterateProcNECP(proc): 629 print GetNECPSummary(kc) 630 631def NexusTypePtr(nx): 632 if nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_FLOW_SWITCH"): 633 return "(struct nx_flowswitch *){:18s}".format(hex(nx.nx_arg)) 634 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_NET_IF"): 635 return " (struct nx_netif *){:18s}".format(hex(nx.nx_arg)) 636 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_USER_PIPE"): 637 return " (struct nx_upipe *){:18s}".format(hex(nx.nx_arg)) 638 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_KERNEL_PIPE"): 639 return " (struct kern_nexus *){:18s}".format(hex(nx)) 640 else: 641 return "unknown" 642 643def GetStructNexusSummary(nx): 644 nexus_summary_string = "" 645 nexus_summary_string += "{0:s} ".format(NexusTypePtr(nx)) 646 nexus_summary_string += "{0:30s} ".format(str(Cast(addressof(nx.nx_prov.nxprov_params.nxp_name), 'char *'))) 647 nexus_summary_string += "rings: tx {:2d} rx {:2d} slots: {:4d} rx {:4d} bufsize {:5d} metasize {:5d} mhints {:2d} ".format( 648 nx.nx_prov.nxprov_params.nxp_tx_rings, 649 nx.nx_prov.nxprov_params.nxp_rx_rings, 650 nx.nx_prov.nxprov_params.nxp_rx_slots, 651 nx.nx_prov.nxprov_params.nxp_tx_slots, 652 nx.nx_prov.nxprov_params.nxp_buf_size, 653 nx.nx_prov.nxprov_params.nxp_meta_size, 654 nx.nx_prov.nxprov_params.nxp_mhints) 655 656 return nexus_summary_string 657 658@lldb_command('shownexuses') 659def ShowNexuses(cmd_args=None): 660 """ Show Nexus. 661 662 usage: shownexues 663 """ 664 nexus_summaries = [] 665 nexuses = kern.globals.nx_head 666 for nx in IterateRBTreeEntry(nexuses, 'struct kern_nexus*', 'nx_link'): 667 nexus_summaries.append(GetStructNexusSummary(nx)) 668 nexus_summaries.sort() 669 for nx_str in nexus_summaries: 670 print "{0:s}".format(nx_str) 671 672def GetSockAddr4(in_addr): 673 return inet_ntoa(struct.pack("I", unsigned(in_addr.s_addr))) 674 675def GetSockAddr6(in6_addr): 676 addr = in6_addr.__u6_addr.__u6_addr8 677 addr_raw_string = ":".join(["{0:02x}{0:02x}".format(unsigned(addr[i]), 678 unsigned(addr[i+1])) for i in range(0, 16, 2)]) 679 return inet_ntop(AF_INET6, inet_pton(AF_INET6, addr_raw_string)) 680 681def FlowKeyStr(fk): 682 if fk.fk_ipver == 0x4: 683 src_str = GetSockAddr4(fk.fk_src._v4) 684 dst_str = GetSockAddr4(fk.fk_dst._v4) 685 elif fk.fk_ipver == 0x60: 686 src_str = GetSockAddr6(fk.fk_src._v6) 687 dst_str = GetSockAddr6(fk.fk_dst._v6) 688 else: 689 return "unkown ipver" 690 691 return "src={},dst={},proto={},sport={},dport={}".format(src_str, dst_str, 692 unsigned(fk.fk_proto), ntohs(fk.fk_sport), ntohs(fk.fk_dport)) 693 694def FlowEntryStr(fe): 695 return "(struct flow_entry*){} {} ".format(hex(fe), FlowKeyStr(fe.fe_key)) 696 697def GetFlowEntryPid(fe): 698 return fe.fe_pid 699 700def GetFlowswitchFlowEntries(fsw): 701 fm = kern.GetValueFromAddress(unsigned(fsw.fsw_flow_mgr), 'struct flow_mgr *') 702 cht = kern.GetValueFromAddress(unsigned(fm.fm_flow_table), 'struct cuckoo_hashtable *') 703 704 flows = [] 705 def GetCuckooNodeAsFLowEntry(node, hashValue): 706 fe = containerof(node, 'struct flow_entry', 'fe_cnode') 707 flows.append(fe) 708 709 CuckooHashtableForeach(cht, GetCuckooNodeAsFLowEntry) 710 return flows 711 712def IsNexusAFlowswitch(nx): 713 return nx.nx_prov.nxprov_params.nxp_type == GetEnumValue('nexus_type_t::NEXUS_TYPE_FLOW_SWITCH') 714 715def GetNexusAsFlowswitch(nx): 716 return kern.GetValueFromAddress(unsigned(nx.nx_arg), 'struct nx_flowswitch *') 717 718def FlowswitchStr(fsw): 719 return "{}:\n(struct nx_flowswitch *){}".format(str(fsw.fsw_ifp.if_xname), hex(fsw)) 720 721@lldb_command('showflowswitches') 722def ShowFlowswitches(cmd_args=None): 723 """ Show flow switches 724 725 usage: showflowswitches [ifname] 726 """ 727 ifname = "" 728 if len(cmd_args) == 1: 729 ifname = cmd_args[0] 730 731 nexuses = kern.globals.nx_head 732 for nx in IterateRBTreeEntry(nexuses, 'struct kern_nexus*', 'nx_link'): 733 if not IsNexusAFlowswitch(nx): 734 continue 735 fsw = GetNexusAsFlowswitch(nx) 736 if ifname not in str(fsw.fsw_ifp.if_xname): 737 continue 738 print "{}".format(FlowswitchStr(fsw)) 739 flows = GetFlowswitchFlowEntries(fsw) 740 flows.sort(key=GetFlowEntryPid) 741 for fe in flows: 742 print " {}".format(FlowEntryStr(fe)) 743 744def CuckooHashtableForeachSlot(cht, slotHandler): 745 for i in range(0, cht._n_buckets): 746 b = cht._buckets[i] 747 if unsigned(b._inuse) == 0: 748 continue 749 for j in range(0, kern.globals._CHT_BUCKET_SLOTS): 750 s = b._slots[j] 751 if unsigned(s._node) != 0: 752 slotHandler(s) 753 754def CuckooHashtableForeach(cht, handler): 755 def CuckooHashtableSlotHandler(s): 756 if unsigned(s._node) == 0: 757 return 758 node = s._node 759 while unsigned(node) != 0: 760 handler(node, s._hash) 761 node = node.next 762 CuckooHashtableForeachSlot(cht, CuckooHashtableSlotHandler) 763 764@lldb_command('showcuckoohashtable') 765def ShowCuckooHashtable(cmd_args=None): 766 """ Show Cuckoo Hashtable. 767 768 usage: showcuckoohashtable <struct cuckoo_hashtable *> 769 """ 770 if not cmd_args: 771 raise ArgumentError('missing struct cuckoo_hashtable * argument') 772 773 cht = kern.GetValueFromAddress(cmd_args[0], 'struct cuckoo_hashtable *') 774 775 print "(struct cuckoo_hashtable *){:18s} capacity {:d} entries {:d}".format(hex(cht), cht._capacity, cht._n_entries) 776 def CuckooHashtablePrintNode(node, hashValue): 777 print " node {} hash 0x{:08x}".format(hex(node), int(hashValue)) 778 779 CuckooHashtableForeach(cht, CuckooHashtablePrintNode) 780 781@lldb_command('showprotons') 782def ShowProtoNS(cmd_args=None): 783 """ Show the protons table 784 """ 785 786 protons_tokens = kern.globals.protons_tokens 787 for pt in IterateRBTreeEntry(protons_tokens, 'struct protons_token *', 'pt_link'): 788 print "(struct protons_token *){} protocol {:3} pid {:5} epid {:5} ref {:2} flags {}".format( 789 hex(pt), int(pt.pt_protocol), int(pt.pt_pid), int(pt.pt_epid), 790 int(pt.pt_refcnt.ref_count), hex(pt.pt_flags)) 791