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