xref: /xnu-12377.41.6/tools/lldbmacros/skywalk.py (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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