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