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 is 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, 'bc_link', list_prefix='s') : 200 format_string = "\t0x{:<08x} 0x{:<08x} 0x{:<08x}" 201 print(format_string.format(bc, bc.bc_addr, bc.bc_addrm)) 202 203 for slab in IterateTAILQ_HEAD(skm.skm_sl_empty_list, "sl_link") : 204 format_string = "{:<18s} {:<4s} {:18s} {:18s}" 205 print(format_string.format("slab", "ref", "base", "basem")) 206 format_string = "0x{:<08x} {:<4d} 0x{:<08x} 0x{:08x}" 207 print(format_string.format(slab, slab.sl_refcnt, slab.sl_base, slab.sl_basem)) 208 print("\t========================= free =========================") 209 format_string = "\t{:<18s} {:18s} {:18s}" 210 print(format_string.format("bufctl", "buf_addr", "buf_addrm")) 211 for bc in IterateListEntry(slab.sl_head, 'bc_link', list_prefix='s') : 212 format_string = "\t0x{:<08x} 0x{:<08x} 0x{:<08x}" 213 print(format_string.format(bc, bc.bc_addr, bc.bc_addrm)) 214 215 print(" ") 216 for i in range(0, skm.skm_hash_mask + 1) : 217 format_string = "{:<18s} {:<4s}" 218 print(format_string.format("bucket", "idx")) 219 format_string = "0x{:<08x} {:<4d}" 220 print(format_string.format(addressof(skm.skm_hash_table[i]), i)) 221 print("\t====================== allocated =======================") 222 format_string = "\t{:<18s} {:18s} {:18s}" 223 print(format_string.format("bufctl", "buf_addr", "buf_addrm")) 224 for bc in IterateListEntry(skm.skm_hash_table[i].bcb_head, 'bc_link', 225 list_prefix='s') : 226 format_string = "\t0x{:<08x} 0x{:<08x} 0x{:<08x}" 227 print(format_string.format(bc, bc.bc_addr, bc.bc_addrm)) 228 229def SkmemArenaTypeAsString(type) : 230 out_string = "" 231 SKMEM_ARENA_TYPE_NEXUS = 0 232 SKMEM_ARENA_TYPE_NECP = 1 233 SKMEM_ARENA_TYPE_SYSTEM = 2 234 235 if (type == SKMEM_ARENA_TYPE_NEXUS) : 236 out_string += "NEXUS" 237 elif (type == SKMEM_ARENA_TYPE_NECP) : 238 out_string += "NECP" 239 elif (type == SKMEM_ARENA_TYPE_SYSTEM) : 240 out_string += "SYSTEM" 241 else : 242 out_string += "?" 243 244 return out_string 245 246@lldb_command('showskmemarena') 247def ShowSkmemArena(cmd_args=None) : 248 """ Show the global list of skmem arenas 249 """ 250 251 i = 1 252 arhead = kern.globals.skmem_arena_head 253 254 for ar in IterateTAILQ_HEAD(arhead, "ar_link") : 255 format_string = "{:>4d}: 0x{:<08x} {:<6s} {:>5d} KB \"{:<s}\"" 256 print(format_string.format(i, ar, SkmemArenaTypeAsString(ar.ar_type), ar.ar_mapsize >> 10, str(ar.ar_name))) 257 i += 1 258 259@lldb_command('showskmemregions') 260def ShowSkmemRegions(cmd_args=None) : 261 """ Show the global list of skmem regions 262 """ 263 264 i = 1 265 skrhead = kern.globals.skmem_region_head 266 267 for skr in IterateTAILQ_HEAD(skrhead, "skr_link") : 268 format_string = "{:>4d}: 0x{:<08x} \"{:<s}\"" 269 print(format_string.format(i, skr, str(skr.skr_name))) 270 i += 1 271 272@lldb_command('showskmemregion') 273def ShowSkmemRegion(cmd_args=None) : 274 """ Show segments of a skmem region 275 """ 276 277 if cmd_args is None or len(cmd_args) == 0 : 278 print("Missing argument 0 (skmem_region address).") 279 return 280 281 skr = kern.GetValueFromAddress(cmd_args[0], 'skmem_region *') 282 283 print("\t========================= free =========================") 284 for sg in IterateTAILQ_HEAD(skr.skr_seg_free, "sg_link") : 285 format_string = "{:<18s} {:<4s} {:18s} {:18s}" 286 print(format_string.format("segment", "idx", "start", "end")) 287 format_string = "0x{:<08x} {:<4d} 0x{:<08x} 0x{:08x}" 288 print(format_string.format(sg, sg.sg_index, sg.sg_start, sg.sg_end)) 289 format_string = "\t{:<18s} {:18s} {:18s}" 290 print(format_string.format("bufctl", "buf_addr", "buf_addrm")) 291 292 print(" ") 293 for i in range(0, skr.skr_hash_mask + 1) : 294 format_string = "{:<18s} {:<4s}" 295 print(format_string.format("bucket", "idx")) 296 format_string = "0x{:<08x} {:<4d}" 297 print(format_string.format(addressof(skr.skr_hash_table[i]), i)) 298 print("\t====================== allocated =======================") 299 format_string = "\t{:<18s} {:4s} {:18s} {:18s}" 300 print(format_string.format("segment", "idx", "start", "end")) 301 for sg in IterateTAILQ_HEAD(skr.skr_hash_table[i].sgb_head, "sg_link") : 302 format_string = "\t0x{:<08x} {:<4d} 0x{:<08x} 0x{:<08x}" 303 print(format_string.format(sg, sg.sg_index, sg.sg_start, sg.sg_end)) 304 305@lldb_command('showchannelupphash') 306def ShowChannelUppHash(cmd_args=None) : 307 """ Show channel user packet pool hash chain 308 """ 309 310 if cmd_args is None or len(cmd_args) == 0 : 311 print("Missing argument 0 (skmem_cache address).") 312 return 313 314 ch = kern.GetValueFromAddress(cmd_args[0], 'kern_channel *') 315 KERN_CHANNEL_UPP_HTBL_SIZE = 256 316 317 for i in range(KERN_CHANNEL_UPP_HTBL_SIZE) : 318 bkt = addressof(ch.ch_upp_hash_table[i]) 319 format_string = "{:>4d} 0x{:<08x}" 320 print(format_string.format(i, bkt)) 321 for kqum in IterateListEntry(bkt.upp_head, 'qum_upp_link', list_prefix='s') : 322 format_string = "0x{:<08x}" 323 print(format_string.format(kqum)) 324 325@lldb_type_summary(['struct ns *']) 326@header('{:<20s} {:<5s} {:<48s} {:<4s}'.format('ns', 'proto', 'addr', 'nreservations')) 327def GetStructNsSummary(ns): 328 """ Summarizes a struct ns from the netns 329 330 returns: str - summary of struct ns 331 """ 332 333 if (ns.ns_proto == IPPROTO_TCP): 334 proto = "tcp" 335 elif (ns.ns_proto == IPPROTO_UDP): 336 proto = "udp" 337 else: 338 proto = str(ns.ns_proto) 339 340 if (ns.ns_addr_len == sizeof('struct in_addr')): 341 addr = GetInAddrAsString(addressof(ns.ns_inaddr)) 342 elif (ns.ns_addr_len == sizeof('struct in6_addr')): 343 addr = GetIn6AddrAsString(ns.ns_in6addr.__u6_addr.__u6_addr8) 344 else: 345 addr = str(ns_addr) + " bad len {:u}".format(ns.ns_addr_len) 346 347 format_string = '{o:#020x} {p:<5s} {a:<48s} {n:<4d}' 348 349 """ show ports and refs, one per line 350 """ 351 ports_string = "ports & refs\n" 352 for f in IterateRBTreeEntry(ns.ns_reservations, 'nsr_link'): 353 ports_string += "\t%u" % f.nsr_port 354 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]) 355 """ show just the ports, not refs 356 offs = 0 357 ports_string = "\nports:\t" 358 for f in IterateRBTreeEntry(ns.ns_reservations, 'nsr_link'): 359 if (len(ports_string)-offs > 70): 360 ports_string += "\n\t" 361 offs = len(ports_string) 362 ports_string += " %u" % f.nsr_port 363 """ 364 365 return format_string.format( 366 o=ns, 367 p=proto, 368 a=addr, 369 n=ns.ns_n_reservations) + ports_string 370 371@lldb_command('shownetns') 372def ShowNetNS(cmd_args=None): 373 """ Show the netns table 374 """ 375 print("\nnetns_namespaces:") 376 print(GetStructNsSummary.header) 377 378 namespaces = kern.globals.netns_namespaces 379 for ns in IterateRBTreeEntry(namespaces, 'ns_link'): 380 print(GetStructNsSummary(ns)) 381 382 print("\nwild: (these should be duplicated above)") 383 print(GetStructNsSummary.header) 384 for i in range(0,4): 385 print(GetStructNsSummary(kern.globals.netns_global_wild[i])) 386 387 print("\nnon wild:") 388 print(GetStructNsSummary.header) 389 for i in range(0,4): 390 print(GetStructNsSummary(kern.globals.netns_global_non_wild[i])) 391 392 393NETNS_LISTENER = 0x00 394NETNS_SKYWALK = 0x01 395NETNS_BSD = 0x02 396NETNS_PF = 0x03 397NETNS_OWNER_MASK = 0x7 398 399netns_flag_strings = { 400 NETNS_LISTENER : "LISTENER", 401 NETNS_SKYWALK : "SKYWALK", 402 NETNS_BSD : "BSD", 403 NETNS_PF : "PF", 404} 405 406@lldb_type_summary(['struct ns_token *']) 407@header('{:<20s} {:<5s} {:<48s} {:<12s} {:<8s} {:<38s} {:<12s}'.format('nt', 'proto', 'addr', 'port', 'owner', 'ifp', 'flags')) 408def GetNsTokenSummary(nt): 409 """ Summarizes a struct ns from the netns 410 411 returns: str - summary of struct ns 412 """ 413 414 if (nt.nt_proto == IPPROTO_TCP): 415 proto = "tcp" 416 elif (nt.nt_proto == IPPROTO_UDP): 417 proto = "udp" 418 else: 419 proto = str(nt.nt_proto) 420 421 if (nt.nt_addr_len == sizeof('struct in_addr')): 422 addr = GetInAddrAsString(addressof(nt.nt_inaddr)) 423 elif (nt.nt_addr_len == sizeof('struct in6_addr')): 424 addr = GetIn6AddrAsString(nt.nt_in6addr.__u6_addr.__u6_addr8) 425 else: 426 addr = str(nt_addr) + " bad len {:u}".format(nt.nt_addr_len) 427 428 format_string = '{o:#020x} {p:<5s} {a:<48s} {pt:<12s} {wn:<8s} {ifp:38s} {f:#012x}' 429 430 ports = "%u" % nt.nt_port 431 432 ifp = "(struct ifnet *)" + hex(nt.nt_ifp) 433 434 owner = netns_flag_strings[nt.nt_flags & NETNS_OWNER_MASK] 435 436 return format_string.format( 437 o=nt, 438 p=proto, 439 a=addr, 440 pt=ports, 441 wn=owner, 442 ifp=ifp, 443 f=nt.nt_flags) 444 445@lldb_command("showallnetnstokens") 446def ShowAllNetNSTokens(cmd_args=None): 447 """ show all netns tokens 448 """ 449 450 tokenhead = kern.globals.netns_all_tokens 451 print(GetNsTokenSummary.header) 452 for nt in IterateListEntry(tokenhead, 'nt_all_link', list_prefix='s'): 453 print(GetNsTokenSummary(nt)) 454 455@lldb_command("shownetnstokens") 456def ShowNetNSTokens(cmd_args=None): 457 """ show netns tokens attached to an ifp 458 with no args, shows unbound tokens 459 """ 460 461 if cmd_args is None or len(cmd_args) == 0: 462 print("No ifp argument provided, showing unbound tokens") 463 tokenhead = kern.globals.netns_unbound_tokens 464 elif len(cmd_args) > 0: 465 ifp = kern.GetValueFromAddress(cmd_args[0], 'ifnet *') 466 print("Showing tokens for ifp %r" % ifp) 467 tokenhead = ifp.if_netns_tokens 468 else: 469 print("Missing ifp argument 0 in shownetnstokens") 470 print(cmd_args) 471 return 472 473 print(GetNsTokenSummary.header) 474 for nt in IterateListEntry(tokenhead, 'nt_ifp_link', list_prefix='s'): 475 print(GetNsTokenSummary(nt)) 476 477def IterateSTAILQ_HEAD(headval, element_name): 478 iter_val = headval.stqh_first 479 while unsigned(iter_val) != 0 : 480 yield iter_val 481 iter_val = iter_val.__getattr__(element_name).stqe_next 482 #end of yield loop 483 484@lldb_command("shownexuschannels") 485def ShowNexusChannels(cmd_args=None): 486 """ show nexus channels 487 """ 488 if cmd_args is None or len(cmd_args) == 0: 489 print("Missing argument 0 (kern_nexus address).") 490 return 491 492 nx = kern.GetValueFromAddress(cmd_args[0], 'kern_nexus *') 493 i = 1 494 495 format_string = "{:>4s} {:<18s} {:>4s} {:<7s} {:<7s} {:<18s} {:<18s} {:<18s} {:>8s} {:6s} {:<18s} {:>4s} {:s}" 496 print(format_string.format("", "addr", "refs", "txrings", "rxrings", "arena", "ioskmap", "mapaddr", "mapsize", "maprdr", "na", "fd", "process")) 497 498 for ch in IterateSTAILQ_HEAD(nx.nx_ch_head, "ch_link"): 499 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})" 500 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)) 501 i += 1 502 503 for ch in IterateSTAILQ_HEAD(nx.nx_ch_nonxref_head, "ch_link"): 504 format_string = "{:>4d}: 0x{:<08x} {:>4d} [{:2d},{:2d}] [{:2d},{:2d}] 0x{:<08x} 0x{:<08x} 0x{:<16x} {:>8d} {:>6d} 0x{:<08x} {:>4d} {:s}({:d})" 505 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)) 506 i += 1 507 508def IterateProcNECP(proc): 509 """ Iterate through all NECP descriptors in the given process 510 511 params: 512 proc - the proc object 513 returns: nothing, this is meant to be used as a generator function 514 necp - yields each necp_fd_data in the process 515 """ 516 517 proc_filedesc = addressof(proc.p_fd) 518 proc_ofiles = proc_filedesc.fd_ofiles 519 520 for fd in range(0, unsigned(proc_filedesc.fd_afterlast)): 521 if unsigned(proc_ofiles[fd]) != 0: 522 proc_fd_fglob = proc_ofiles[fd].fp_glob 523 if (unsigned(proc_fd_fglob.fg_ops.fo_type) == 9): 524 proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *') 525 yield Cast(proc_fd_fglob_fg_data, 'necp_fd_data *') 526 527def GetNECPClientBitFields(necp): 528 """ Return the bit fields in necp_client as string 529 530 returns: str - string representation of necp_client bit fields 531 """ 532 533 bitfields_string = '' 534 if necp.result_read != 0: 535 bitfields_string += 'r' 536 else: 537 bitfields_string += '-' 538 if necp.allow_multiple_flows != 0: 539 bitfields_string += 'm' 540 else: 541 bitfields_string += '-' 542 if necp.background != 0: 543 bitfields_string += 'b' 544 else: 545 bitfields_string += '-' 546 if necp.background_update != 0: 547 bitfields_string += 'B' 548 else: 549 bitfields_string += '-' 550 if necp.platform_binary != 0: 551 bitfields_string += 'p' 552 else: 553 bitfields_string += '-' 554 555 return bitfields_string 556 557def GetNECPFlowBitFields(flow_registration): 558 """ Return the bit fields in necp_client_flow_registration as string 559 560 returns: str - string representation of necp_client_flow_registration bit fields 561 """ 562 563 bitfields_string = '' 564 if flow_registration.flow_result_read != 0: 565 bitfields_string += 'r' 566 else: 567 bitfields_string += '-' 568 if flow_registration.defunct != 0: 569 bitfields_string += 'd' 570 else: 571 bitfields_string += '-' 572 573 return bitfields_string 574 575@lldb_type_summary(['necp_fd_data *']) 576@header('{:<20s} {:<8s}'.format('necp_fd_data', "flags")) 577def GetNECPSummary(necp): 578 """ Summarizes a necp_fd_data and related information 579 580 returns: str - summary of necp_fd_data 581 """ 582 583 format_string = '{o: <#020x} {u:<#08x}' 584 585 stats_arenas_string = "\n\n\t%-18s %-39s %-4s %-10s\n" % ("stats_arenas", "mmap", "refs", "flags") 586 for sa in IterateListEntry(necp.stats_arena_list, 'nai_chain'): 587 stats_arenas_string += "\t0x%016x " % sa 588 stats_arenas_string += "[0x%016x-0x%016x) " % (sa.nai_mmap.ami_mapaddr,(sa.nai_mmap.ami_mapaddr+sa.nai_mmap.ami_mapsize)) 589 stats_arenas_string += "%4u " % sa.nai_use_count 590 stats_arenas_string += "0x%08x " % sa.nai_flags 591 stats_arenas_string += "\n" 592 593 clients_string = "" 594 for c in IterateRBTreeEntry(necp.clients, 'link'): 595 clients_string += "\n\t%-18s %-36s %-4s %-5s\n" % ("necp_clients", "client_id", "refs", "flags") 596 clients_string += "\t0x%016x " % c 597 clients_string += "%36s " % GetUUIDSummary(c.client_id) 598 clients_string += "%4u " % c.reference_count 599 clients_string += "%5s " % GetNECPClientBitFields(c) 600 count = 0; 601 for f in IterateRBTreeEntry(c.flow_registrations, 'client_link'): 602 if count == 0: 603 clients_string += "\n\t\t%-18s %-36s %-2s %-18s %-18s %-18s\n" % ("flow_registration", "registraton_id", "flags", "stats_arena", "kstats_obj", "ustats_obj") 604 clients_string += "\t\t0x%016x " % f 605 clients_string += "%36s " % GetUUIDSummary(f.registration_id) 606 clients_string += "%2s " % GetNECPFlowBitFields(f) 607 clients_string += "0x%016x " % f.stats_arena 608 clients_string += "0x%016x " % f.kstats_kaddr 609 clients_string += "0x%016x " % f.ustats_uaddr 610 clients_string += "\n" 611 612 return format_string.format( 613 o=necp, 614 u=necp.flags) + stats_arenas_string + clients_string 615 616@lldb_command('showprocnecp') 617def ShowProcNECP(cmd_args=None): 618 """ Show NECP descriptors for a given process. 619 620 usage: showprocnecp <proc_t> 621 """ 622 623 if not cmd_args: 624 raise ArgumentError('missing struct proc * argument') 625 626 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t') 627 628 print(GetNECPSummary.header) 629 for kc in IterateProcNECP(proc): 630 print(GetNECPSummary(kc)) 631 632def NexusTypePtr(nx): 633 if nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_FLOW_SWITCH"): 634 return "(struct nx_flowswitch *){:18s}".format(hex(nx.nx_arg)) 635 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_NET_IF"): 636 return " (struct nx_netif *){:18s}".format(hex(nx.nx_arg)) 637 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_USER_PIPE"): 638 return " (struct nx_upipe *){:18s}".format(hex(nx.nx_arg)) 639 elif nx.nx_prov.nxprov_params.nxp_type == GetEnumValue("nexus_type_t::NEXUS_TYPE_KERNEL_PIPE"): 640 return " (struct kern_nexus *){:18s}".format(hex(nx)) 641 else: 642 return "unknown" 643 644def GetStructNexusSummary(nx): 645 nexus_summary_string = "" 646 nexus_summary_string += "{0:s} ".format(NexusTypePtr(nx)) 647 nexus_summary_string += "{0:30s} ".format(str(Cast(addressof(nx.nx_prov.nxprov_params.nxp_name), 'char *'))) 648 nexus_summary_string += "rings: tx {:2d} rx {:2d} slots: {:4d} rx {:4d} bufsize {:5d} metasize {:5d} mhints {:2d} ".format( 649 nx.nx_prov.nxprov_params.nxp_tx_rings, 650 nx.nx_prov.nxprov_params.nxp_rx_rings, 651 nx.nx_prov.nxprov_params.nxp_rx_slots, 652 nx.nx_prov.nxprov_params.nxp_tx_slots, 653 nx.nx_prov.nxprov_params.nxp_buf_size, 654 nx.nx_prov.nxprov_params.nxp_meta_size, 655 nx.nx_prov.nxprov_params.nxp_mhints) 656 657 return nexus_summary_string 658 659@lldb_command('shownexuses') 660def ShowNexuses(cmd_args=None): 661 """ Show Nexus. 662 663 usage: shownexues 664 """ 665 nexus_summaries = [] 666 nexuses = kern.globals.nx_head 667 for nx in IterateRBTreeEntry(nexuses, 'nx_link'): 668 nexus_summaries.append(GetStructNexusSummary(nx)) 669 nexus_summaries.sort() 670 for nx_str in nexus_summaries: 671 print("{0:s}".format(nx_str)) 672 673def GetSockAddr4(in_addr): 674 return inet_ntoa(struct.pack("I", unsigned(in_addr.s_addr))) 675 676def GetSockAddr6(in6_addr): 677 addr = in6_addr.__u6_addr.__u6_addr8 678 addr_raw_string = ":".join(["{0:02x}{0:02x}".format(unsigned(addr[i]), 679 unsigned(addr[i+1])) for i in range(0, 16, 2)]) 680 return inet_ntop(AF_INET6, inet_pton(AF_INET6, addr_raw_string)) 681 682def FlowKeyStr(fk): 683 if fk.fk_ipver == 0x4: 684 src_str = GetSockAddr4(fk.fk_src._v4) 685 dst_str = GetSockAddr4(fk.fk_dst._v4) 686 elif fk.fk_ipver == 0x60: 687 src_str = GetSockAddr6(fk.fk_src._v6) 688 dst_str = GetSockAddr6(fk.fk_dst._v6) 689 else: 690 return "unkown ipver" 691 692 return "src={},dst={},proto={},sport={},dport={}".format(src_str, dst_str, 693 unsigned(fk.fk_proto), ntohs(fk.fk_sport), ntohs(fk.fk_dport)) 694 695def FlowEntryStr(fe): 696 return "(struct flow_entry*){} {} ".format(hex(fe), FlowKeyStr(fe.fe_key)) 697 698def GetFlowEntryPid(fe): 699 return fe.fe_pid 700 701def GetFlowswitchFlowEntries(fsw): 702 fm = kern.GetValueFromAddress(unsigned(fsw.fsw_flow_mgr), 'struct flow_mgr *') 703 cht = kern.GetValueFromAddress(unsigned(fm.fm_flow_table), 'struct cuckoo_hashtable *') 704 705 flows = [] 706 def GetCuckooNodeAsFLowEntry(node, hashValue): 707 fe = containerof(node, 'struct flow_entry', 'fe_cnode') 708 flows.append(fe) 709 710 CuckooHashtableForeach(cht, GetCuckooNodeAsFLowEntry) 711 return flows 712 713def IsNexusAFlowswitch(nx): 714 return nx.nx_prov.nxprov_params.nxp_type == GetEnumValue('nexus_type_t::NEXUS_TYPE_FLOW_SWITCH') 715 716def GetNexusAsFlowswitch(nx): 717 return kern.GetValueFromAddress(unsigned(nx.nx_arg), 'struct nx_flowswitch *') 718 719def FlowswitchStr(fsw): 720 return "{}:\n(struct nx_flowswitch *){}".format(str(fsw.fsw_ifp.if_xname), hex(fsw)) 721 722@lldb_command('showflowswitches') 723def ShowFlowswitches(cmd_args=None): 724 """ Show flow switches 725 726 usage: showflowswitches [ifname] 727 """ 728 ifname = "" 729 if len(cmd_args) == 1: 730 ifname = cmd_args[0] 731 732 nexuses = kern.globals.nx_head 733 for nx in IterateRBTreeEntry(nexuses, 'nx_link'): 734 if not IsNexusAFlowswitch(nx): 735 continue 736 fsw = GetNexusAsFlowswitch(nx) 737 if ifname not in str(fsw.fsw_ifp.if_xname): 738 continue 739 print("{}".format(FlowswitchStr(fsw))) 740 flows = GetFlowswitchFlowEntries(fsw) 741 flows.sort(key=GetFlowEntryPid) 742 for fe in flows: 743 print(" {}".format(FlowEntryStr(fe))) 744 745def CuckooHashtableForeachSlot(cht, slotHandler): 746 for i in range(0, cht._n_buckets): 747 b = cht._buckets[i] 748 if unsigned(b._inuse) == 0: 749 continue 750 for j in range(0, kern.globals._CHT_BUCKET_SLOTS): 751 s = b._slots[j] 752 if unsigned(s._node) != 0: 753 slotHandler(s) 754 755def CuckooHashtableForeach(cht, handler): 756 def CuckooHashtableSlotHandler(s): 757 if unsigned(s._node) == 0: 758 return 759 node = s._node 760 while unsigned(node) != 0: 761 handler(node, s._hash) 762 node = node.next 763 CuckooHashtableForeachSlot(cht, CuckooHashtableSlotHandler) 764 765@lldb_command('showcuckoohashtable') 766def ShowCuckooHashtable(cmd_args=None): 767 """ Show Cuckoo Hashtable. 768 769 usage: showcuckoohashtable <struct cuckoo_hashtable *> 770 """ 771 if not cmd_args: 772 raise ArgumentError('missing struct cuckoo_hashtable * argument') 773 774 cht = kern.GetValueFromAddress(cmd_args[0], 'struct cuckoo_hashtable *') 775 776 print("(struct cuckoo_hashtable *){:18s} capacity {:d} entries {:d}".format(hex(cht), cht._capacity, cht._n_entries)) 777 def CuckooHashtablePrintNode(node, hashValue): 778 print(" node {} hash 0x{:08x}".format(hex(node), int(hashValue))) 779 780 CuckooHashtableForeach(cht, CuckooHashtablePrintNode) 781 782@lldb_command('showprotons') 783def ShowProtoNS(cmd_args=None): 784 """ Show the protons table 785 """ 786 787 protons_tokens = kern.globals.protons_tokens 788 for pt in IterateRBTreeEntry(protons_tokens, 'pt_link'): 789 print("(struct protons_token *){} protocol {:3} pid {:5} epid {:5} ref {:2} flags {}".format( 790 hex(pt), int(pt.pt_protocol), int(pt.pt_pid), int(pt.pt_epid), 791 int(pt.pt_refcnt.ref_count), hex(pt.pt_flags))) 792