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