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