xref: /xnu-11215.81.4/tools/lldbmacros/mbufs.py (revision d4514f0bc1d3f944c22d92e68b646ac3fb40d452)
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 *
7
8from mbufdefines import *
9import xnudefines
10import kmemory
11
12def MbufZoneByName(name):
13    for i in range(1, int(kern.GetGlobalVariable('num_zones'))):
14        z = addressof(kern.globals.zone_array[i])
15        zs = addressof(kern.globals.zone_security_array[i])
16        if ZoneName(z, zs) == name:
17            return (z, zs)
18    return None
19
20# Macro: mbuf_stat
21@lldb_command('mbuf_stat')
22def MBufStat(cmd_args=None):
23    """ Print extended mbuf allocator statistics.
24    """
25    hdr_format = "{0: <16s} {1: >8s} {2: >8s} {3: ^16s} {4: >8s} {5: >12s} {6: >8s} {7: >8s} {8: >8s} {9: >8s}"
26    print(hdr_format.format('class', 'total', 'cached', 'uncached', 'inuse', 'failed', 'waiter', 'notified', 'purge', 'max'))
27    print(hdr_format.format('name', 'objs', 'objs', 'objs/slabs', 'objs', 'alloc count', 'count', 'count', 'count', 'objs'))
28    print(hdr_format.format('-'*16, '-'*8, '-'*8, '-'*16, '-'*8, '-'*12, '-'*8, '-'*8, '-'*8, '-'*8))
29    entry_format = "{0: <16s} {1: >8d} {2: >8d} {3:>7d} / {4:<6d} {5: >8d} {6: >12d} {7: >8d} {8: >8d} {9: >8d} {10: >8d}"
30    num_items = sizeof(kern.globals.mbuf_table) // sizeof(kern.globals.mbuf_table[0])
31    ncpus = int(kern.globals.ncpu)
32    mb_uses_mcache = int(kern.globals.mb_uses_mcache)
33    for i in range(num_items):
34        mbuf = kern.globals.mbuf_table[i]
35        mcs = Cast(mbuf.mtbl_stats, 'mb_class_stat_t *')
36        if mb_uses_mcache == 0:
37            cname = str(mcs.mbcl_cname)
38            if cname == "mbuf":
39                zone = MbufZoneByName("mbuf")
40            elif cname == "cl":
41                zone = MbufZoneByName("data.mbuf.cluster.2k")
42            elif cname == "bigcl":
43                zone = MbufZoneByName("data.mbuf.cluster.4k")
44            elif cname == "16kcl":
45                zone = MbufZoneByName("data.mbuf.cluster.16k")
46            elif cname == "mbuf_cl":
47                zone = MbufZoneByName("mbuf.composite.2k")
48            elif cname == "mbuf_bigcl":
49                zone = MbufZoneByName("mbuf.composite.4k")
50            elif cname == "mbuf_16kcl":
51                zone = MbufZoneByName("mbuf.composite.16k")
52            zone_stats = GetZone(zone[0], zone[1], [], [])
53            print(entry_format.format(cname,
54                                      int(zone_stats['size'] / mcs.mbcl_size),
55                                      zone_stats['cache_element_count'],
56                                      zone_stats['free_element_count'],
57                                      0,
58                                      int(zone_stats['used_size'] / mcs.mbcl_size),
59                                      zone_stats['alloc_fail_count'],
60                                      0, 0, 0,
61                                      mbuf.mtbl_maxlimit))
62
63        else:
64            mc = mbuf.mtbl_cache
65            total = 0
66            total += int(mc.mc_full.bl_total) * int(mc.mc_cpu[0].cc_bktsize)
67            ccp_arr = mc.mc_cpu
68            for i in range(ncpus):
69                ccp = ccp_arr[i]
70                if int(ccp.cc_objs) > 0:
71                    total += int(ccp.cc_objs)
72                if int(ccp.cc_pobjs) > 0:
73                    total += int(ccp.cc_pobjs)
74            print(entry_format.format(mcs.mbcl_cname, mcs.mbcl_total,  total,
75                                      mcs.mbcl_infree, mcs.mbcl_slab_cnt,
76                                      (mcs.mbcl_total - total - mcs.mbcl_infree),
77                                      mcs.mbcl_fail_cnt, mbuf.mtbl_cache.mc_waiter_cnt,
78                                      mcs.mbcl_notified, mcs.mbcl_purge_cnt,
79                                      mbuf.mtbl_maxlimit))
80# EndMacro: mbuf_stat
81
82def DumpMbufData(mp, count):
83    if kern.globals.mb_uses_mcache == 1:
84        mdata = mp.m_hdr.mh_data
85        mlen = mp.m_hdr.mh_len
86        flags = mp.m_hdr.mh_flags
87        if flags & M_EXT:
88            mdata = mp.M_dat.MH.MH_dat.MH_ext.ext_buf
89    else:
90        mdata = mp.M_hdr_common.M_hdr.mh_data
91        mlen = mp.M_hdr_common.M_hdr.mh_len
92        flags = mp.M_hdr_common.M_hdr.mh_flags
93        if flags & M_EXT:
94            mdata = mp.M_hdr_common.M_ext.ext_buf
95    if (count > mlen):
96        count = mlen
97    cmd = "memory read -force -size 1 -count {0:d} 0x{1:x}".format(count, mdata)
98    print(lldb_run_command(cmd))
99
100def DecodeMbufData(in_mp, decode_as="ether"):
101    import scapy.all
102    err = lldb.SBError()
103    scan = in_mp
104    while (scan):
105        full_buf = b''
106        mp = scan
107        while (mp):
108            if kern.globals.mb_uses_mcache == 1:
109                mdata = mp.m_hdr.mh_data
110                mlen = unsigned(mp.m_hdr.mh_len)
111                flags = mp.m_hdr.mh_flags
112                if flags & M_EXT:
113                    mdata = mp.M_dat.MH.MH_dat.MH_ext.ext_buf
114                mnext = mp.m_hdr.mh_next
115            else:
116                mdata = mp.M_hdr_common.M_hdr.mh_data
117                mlen = unsigned(mp.M_hdr_common.M_hdr.mh_len)
118                flags = mp.M_hdr_common.M_hdr.mh_flags
119                if flags & M_EXT:
120                    mdata = mp.M_hdr_common.M_ext.ext_buf
121                mnext = mp.M_hdr_common.M_hdr.mh_next
122
123            addr = mdata.GetSBValue().GetValueAsAddress()
124            buf = LazyTarget.GetProcess().ReadMemory(addr, mlen, err)
125            full_buf += buf
126            if mnext == 0:
127                try:
128                    if decode_as == "ether":
129                        pkt = scapy.layers.l2.Ether(full_buf)
130                    elif decode_as == "ip":
131                        pkt = scapy.layers.inet.IP(full_buf)
132                    elif decode_as == "ip6":
133                        pkt = scapy.layers.inet6.IPv6(full_buf)
134                    elif decode_as == "tcp":
135                        pkt = scapy.layers.inet.TCP(full_buf)
136                    elif decode_as == "udp":
137                        pkt = scapy.layers.inet.UDP(full_buf)
138                    else:
139                        print("invalid decoder" + decode_as)
140                        return
141                    pkt.show()
142                    break
143                except KeyboardInterrupt:
144                    raise KeyboardInterrupt
145                except:
146                    break
147            mp = mnext
148        if kern.globals.mb_uses_mcache == 1:
149            scan = scan.m_hdr.mh_nextpkt
150        else:
151            scan = scan.M_hdr_common.M_hdr.mh_nextpkt
152
153
154# Macro: mbuf_decode
155@lldb_command('mbuf_decode', '')
156def MbufDecode(cmd_args=None, cmd_options={}):
157    """Decode an mbuf using scapy.
158        Usage: mbuf_decode <mbuf address>
159    """
160    if cmd_args is None or len(cmd_args) < 1:
161        print("usage: mbuf_decode <address> [decode_as]")
162        return
163    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
164    if len(cmd_args) > 1:
165        decode_as = cmd_args[1]
166        DecodeMbufData(mp, decode_as)
167    else:
168        DecodeMbufData(mp)
169# EndMacro: mbuf_decode
170
171# Macro: mbuf_dumpdata
172@lldb_command('mbuf_dumpdata', 'C:')
173def MbufDumpData(cmd_args=None, cmd_options={}):
174    """Dump the mbuf data
175        Usage: mbuf_dumpdata  <mbuf address> [-C <count>]
176    """
177    if cmd_args is None or len(cmd_args) < 1:
178        print(MbufDumpData.__doc__)
179        return
180    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
181    if kern.globals.mb_uses_mcache == 1:
182        mdata = mp.m_hdr.mh_data
183        mhlen = mp.m_hdr.mh_len
184    else:
185        mdata = mp.M_hdr_common.M_hdr.mh_data
186        mhlen = mp.M_hdr_common.M_hdr.mh_len
187    mlen = 0
188    if "-C" in cmd_options:
189        mlen = ArgumentStringToInt(cmd_options["-C"])
190        if (mlen > mhlen):
191            mlen = mhlen
192    else:
193        mlen = mhlen
194    DumpMbufData(mp, mlen)
195# EndMacro: mbuf_dumpdata
196
197def ShowMbuf(prefix, mp, count, total, dump_data_len):
198    out_string = ""
199    mca = ""
200    if kern.globals.mb_uses_mcache == 1:
201        mhlen = mp.m_hdr.mh_len
202        mhtype = mp.m_hdr.mh_type
203        mhflags = mp.m_hdr.mh_flags
204        mhdata = mp.m_hdr.mh_data
205        if mhflags & M_EXT:
206            extbuf = mp.M_dat.MH.MH_dat.MH_ext.ext_buf
207        if kern.globals.mclaudit != 0:
208            mca += GetMbufBuf2Mca(mp) + ", "
209    else:
210        mhlen = mp.M_hdr_common.M_hdr.mh_len
211        mhtype = mp.M_hdr_common.M_hdr.mh_type
212        mhflags = mp.M_hdr_common.M_hdr.mh_flags
213        mhdata = mp.M_hdr_common.M_hdr.mh_data
214        if mhflags & M_EXT:
215            extbuf = mp.M_hdr_common.M_ext.ext_buf
216    mbuf_walk_format = "{0:s}{1:d} 0x{2:x} [len {3:d}, type {4:d}, data 0x{5:x}, "
217    out_string += mbuf_walk_format.format(prefix, count[0], mp, mhlen, mhtype, mhdata)
218    out_string += "flags " + GetMbufFlagsAsString(mhflags) + ", "
219    if (mhflags & M_PKTHDR):
220        out_string += GetMbufPktCrumbs(mp) + ", "
221    if (mhflags & M_EXT):
222        m_ext_format = "ext_buf 0x{0:x}, "
223        out_string += m_ext_format.format(extbuf)
224    if (mca != ""):
225        out_string += mca + ", "
226    total[0] = total[0] + mhlen
227    out_string += "total " + str(total[0]) + "]"
228    print(out_string)
229    if (dump_data_len > 0):
230        DumpMbufData(mp, dump_data_len)
231
232def WalkMufNext(prefix, mp, count, total, dump_data_len):
233    remaining_len = dump_data_len
234    while (mp):
235        if kern.globals.mb_uses_mcache == 1:
236            mhlen = mp.m_hdr.mh_len
237            mhnext = mp.m_hdr.mh_next
238        else:
239            mhlen = mp.M_hdr_common.M_hdr.mh_len
240            mhnext = mp.M_hdr_common.M_hdr.mh_next
241        count[0] += 1
242        ShowMbuf(prefix, mp, count, total, remaining_len)
243        if (remaining_len > mhlen):
244            remaining_len -= mhlen
245        else:
246            remaining_len = 0
247        mp = mhnext
248
249# Macro: mbuf_walkpkt
250@lldb_command('mbuf_walkpkt', 'C:')
251def MbufWalkPacket(cmd_args=None, cmd_options={}):
252    """ Walk the mbuf packet chain (m_nextpkt)
253        Usage: mbuf_walkpkt  <mbuf address> [-C <count>]
254    """
255    if not cmd_args:
256        raise ArgumentError("Missing argument 0 in user function.")
257    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
258
259    dump_data_len = 0
260    if "-C" in cmd_options:
261        dump_data_len = ArgumentStringToInt(cmd_options["-C"])
262
263    count_packet = 0
264    count_mbuf = 0
265    total_len = 0
266
267    while (mp):
268        count_packet += 1
269        prefix = "{0:d}.".format(count_packet)
270        count = [0]
271        total = [0]
272        WalkMufNext(prefix, mp, count, total, dump_data_len)
273        count_mbuf += count[0]
274        total_len += total[0]
275        if kern.globals.mb_uses_mcache == 1:
276            mp = mp.m_hdr.mh_nextpkt
277        else:
278            mp = mp.M_hdr_common.M_hdr.mh_nextpkt
279    out_string = "Total packets: {0:d} mbufs: {1:d} length: {2:d} ".format(count_packet, count_mbuf, total_len)
280    print(out_string)
281# EndMacro: mbuf_walkpkt
282
283# Macro: mbuf_walk
284@lldb_command('mbuf_walk', 'C:')
285def MbufWalk(cmd_args=None, cmd_options={}):
286    """ Walk the mbuf chain (m_next)
287        Usage: mbuf_walk  <mbuf address> [-C <count>]
288    """
289    if not cmd_args:
290        raise ArgumentError("Missing argument 0 in user function.")
291    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
292
293    dump_data_len = 0
294    if "-C" in cmd_options:
295        dump_data_len = ArgumentStringToInt(cmd_options["-C"])
296
297    count = [0]
298    total = [0]
299    prefix = ""
300    WalkMufNext(prefix, mp, count, total, dump_data_len)
301# EndMacro: mbuf_walk
302
303# Macro: mbuf_buf2slab
304@lldb_command('mbuf_buf2slab')
305def MbufBuf2Slab(cmd_args=None):
306    """ Given an mbuf object, find its corresponding slab address
307    """
308    if not cmd_args:
309        raise ArgumentError("Missing argument 0 in user function.")
310
311    if int(kern.globals.mb_uses_mcache) == 0:
312        print("mcache is disabled, use kasan whatis")
313        return
314
315    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
316    slab = GetMbufSlab(m)
317    if (kern.ptrsize == 8):
318        mbuf_slab_format = "0x{0:<16x}"
319        print(mbuf_slab_format.format(slab))
320    else:
321        mbuf_slab_format = "0x{0:<8x}"
322        print(mbuf_slab_format.format(slab))
323# EndMacro: mbuf_buf2slab
324
325# Macro: mbuf_buf2mca
326@lldb_command('mbuf_buf2mca')
327def MbufBuf2Mca(cmd_args=None):
328    """ Find the mcache audit structure of the corresponding mbuf
329    """
330    if int(kern.globals.mb_uses_mcache) == 0:
331        print("mcache is disabled, use kasan whatis")
332        return
333
334    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
335    print(GetMbufBuf2Mca(m))
336    return
337# EndMacro: mbuf_buf2mca
338
339# Macro: mbuf_slabs
340@lldb_command('mbuf_slabs')
341def MbufSlabs(cmd_args=None):
342    """ Print all slabs in the group
343    """
344
345    if int(kern.globals.mb_uses_mcache) == 0:
346        print("mcache is disabled, use kasan whatis or zprint")
347        return
348
349    out_string = ""
350    if not cmd_args:
351        raise ArgumentError("Invalid arguments passed.")
352
353    slg = kern.GetValueFromAddress(cmd_args[0], 'mcl_slabg_t *')
354    x = 0
355
356    if (kern.ptrsize == 8):
357        slabs_string_format = "{0:>4d}: 0x{1:16x} 0x{2:16x} 0x{3:016x} 0x{4:016x} {5:10d} {6:3d} {7:3d} {8:3d} {9:5d} {10:>6s} "
358        out_string += "slot  slab               next               obj                mca                tstamp     C   R   N   size   flags\n"
359        out_string += "----- ------------------ ------------------ ------------------ ------------------ ---------- --- --- --- ------ -----\n"
360    else:
361        slabs_string_format = "{0:>4d}: 0x{1:8x} 0x{2:8x} 0x{3:08x} 0x{4:08x} {5:10d} {6:3d} {7:3d} {8:3d} {9:5d} {10:>6s} "
362        out_string += "slot  slab       next       obj        mca        tstamp     C   R   N   size   flags\n"
363        out_string += "----- ---------- ---------- ---------- ---------- ---------- --- --- --- ------ -----\n"
364
365    mbutl = cast(kern.globals.mbutl, 'unsigned char *')
366    nslabspmb = int((1 << MBSHIFT) >> unsigned(kern.globals.page_shift))
367    while x < nslabspmb:
368        sl = addressof(slg.slg_slab[x])
369        mca = 0
370        obj = sl.sl_base
371        ts = 0
372
373        if (kern.globals.mclaudit != 0 and obj != 0):
374            mca = GetMbufMcaPtr(obj, sl.sl_class)
375            trn = (mca.mca_next_trn + unsigned(kern.globals.mca_trn_max) - 1) % unsigned(kern.globals.mca_trn_max)
376            ts = mca.mca_trns[trn].mca_tstamp
377
378        out_string += slabs_string_format.format((x + 1), sl, sl.sl_next, obj, mca, int(ts), int(sl.sl_class), int(sl.sl_refcnt), int(sl.sl_chunks), int(sl.sl_len), hex(sl.sl_flags))
379
380        if (sl.sl_flags != 0):
381            out_string += "<"
382            if sl.sl_flags & SLF_MAPPED:
383                out_string += "mapped"
384            if sl.sl_flags & SLF_PARTIAL:
385                out_string += ",partial"
386            if sl.sl_flags & SLF_DETACHED:
387                out_string += ",detached"
388            out_string += ">"
389        out_string += "\n"
390
391        if sl.sl_chunks > 1:
392            z = 1
393            c = sl.sl_len // sl.sl_chunks
394
395            while z < sl.sl_chunks:
396                obj = sl.sl_base + (c * z)
397                mca = 0
398                ts = 0
399
400                if (kern.globals.mclaudit != 0 ):
401                    mca = GetMbufMcaPtr(obj, sl.sl_class)
402                    trn = (mca.mca_next_trn + unsigned(kern.globals.mca_trn_max) - 1) % unsigned(kern.globals.mca_trn_max)
403                    ts = mca.mca_trns[trn].mca_tstamp
404
405                if (kern.ptrsize == 8):
406                    chunk_string_format = "                                            0x{0:16x} 0x{1:16x} {2:10d}\n"
407                else:
408                    chunk_string_format = "                            0x{0:8x} {1:4s} {2:10d}\n"
409
410                out_string += chunk_string_format.format(int(obj), int(mca), int(ts))
411
412                z += 1
413        x += 1
414    print(out_string)
415# EndMacro: mbuf_slabs
416
417# Macro: mbuf_slabstbl
418@lldb_command('mbuf_slabstbl')
419def MbufSlabsTbl(cmd_args=None):
420    """ Print slabs table
421    """
422    out_string = ""
423    x = 0
424
425    if int(kern.globals.mb_uses_mcache) == 0:
426        print("mcache is disabled, use kasan whatis or zprint")
427        return
428
429    if (kern.ptrsize == 8):
430        out_string += "slot slabg              slabs range\n"
431        out_string += "---- ------------------ -------------------------------------------\n"
432    else:
433        out_string += "slot slabg      slabs range\n"
434        out_string += "---- ---------- ---------------------------\n"
435
436    slabstbl = kern.globals.slabstbl
437    slabs_table_blank_string_format = "{0:>3d}: - \n"
438    nslabspmb = int(((1 << MBSHIFT) >> unsigned(kern.globals.page_shift)))
439    while (x < unsigned(kern.globals.maxslabgrp)):
440        slg = slabstbl[x]
441        if (slg == 0):
442            out_string += slabs_table_blank_string_format.format(x+1)
443        else:
444            if (kern.ptrsize == 8):
445                slabs_table_string_format = "{0:>3d}: 0x{1:16x}  [ 0x{2:16x} - 0x{3:16x} ]\n"
446                out_string += slabs_table_string_format.format(x+1, slg, addressof(slg.slg_slab[0]), addressof(slg.slg_slab[nslabspmb-1]))
447            else:
448                slabs_table_string_format = "{0:>3d}: 0x{1:8x}  [ 0x{2:8x} - 0x{3:8x} ]\n"
449                out_string += slabs_table_string_format.format(x+1, slg, addressof(slg.slg_slab[0]), addressof(slg.slg_slab[nslabspmb-1]))
450
451        x += 1
452    print(out_string)
453# EndMacro: mbuf_slabstbl
454
455def MbufDecode(mbuf, decode_pkt):
456    # Ignore free'd mbufs.
457    if kern.globals.mb_uses_mcache == 1:
458        mhlen = mbuf.m_hdr.mh_len
459        mhtype = mbuf.m_hdr.mh_type
460        mhflags = mbuf.m_hdr.mh_flags
461    else:
462        mhlen = mbuf.M_hdr_common.M_hdr.mh_len
463        mhtype = mbuf.M_hdr_common.M_hdr.mh_type
464        mhflags = mbuf.M_hdr_common.M_hdr.mh_flags
465    if mhtype == 0:
466        return
467    flags = int(mhflags)
468    length = int(mhlen)
469    if length < 20 or length > 8 * 1024:
470        # Likely not a packet.
471        return
472    out_string = "mbuf found @ 0x{0:x}, length {1:d}, {2:s}, {3:s}".format(mbuf, length, GetMbufFlags(mbuf), GetMbufPktCrumbs(mbuf))
473    print(out_string)
474    if flags & M_PKTHDR:
475        if kern.globals.mb_uses_mcache == 1:
476            rcvif = mbuf.M_dat.MH.MH_pkthdr.rcvif
477        else:
478            rcvif = mbuf.M_hdr_common.M_pkthdr.rcvif
479        if rcvif != 0:
480            try:
481                print("receive interface " + rcvif.if_xname)
482            except ValueError:
483                pass
484    if decode_pkt:
485        DecodeMbufData(mbuf)
486
487
488# Macro: mbuf_walk_slabs
489@lldb_command('mbuf_walk_slabs')
490def MbufWalkSlabs(cmd_args=None):
491    """
492    Walks the mbuf slabs table backwards and tries to detect and decode mbufs.
493    Use 'mbuf_walk_slabs decode' to decode the mbuf using scapy.
494    """
495    decode_pkt = False
496    if len(cmd_args) > 0 and cmd_args[0] == 'decode':
497        decode_pkt = True
498
499    if int(kern.globals.mb_uses_mcache) == 0:
500        for mbuf in kmemory.Zone("mbuf").iter_allocated(gettype("mbuf")):
501            MbufDecode(value(mbuf.AddressOf()), decode_pkt)
502        return
503
504    slabstbl = kern.globals.slabstbl
505    nslabspmb = int(((1 << MBSHIFT) >> unsigned(kern.globals.page_shift)))
506    mbutl = cast(kern.globals.mbutl, 'unsigned char *')
507    x = unsigned(kern.globals.maxslabgrp)
508    while x >= 0:
509        slg = slabstbl[x]
510        if (slg == 0):
511            x -= 1
512            continue
513        j = 0
514        while j < nslabspmb:
515            sl = addressof(slg.slg_slab[j])
516            obj = sl.sl_base
517            # Ignore slabs with a single chunk
518            # since that's unlikely to contain an mbuf
519            # (more likely a cluster).
520            if sl.sl_chunks > 1:
521                z = 0
522                c = sl.sl_len // sl.sl_chunks
523
524                while z < sl.sl_chunks:
525                    obj = kern.GetValueFromAddress(sl.sl_base + c * z)
526                    mbuf = cast(obj, 'struct mbuf *')
527                    MbufDecode(mbuf, decode_pkt)
528                    z += 1
529            j += 1
530        x -= 1
531
532# EndMacro: mbuf_walk_slabs
533
534def GetMbufMcaPtr(m, cl):
535    pgshift = int(kern.globals.page_shift)
536    ix = int((m - Cast(kern.globals.mbutl, 'char *')) >> pgshift)
537    page_addr = (Cast(kern.globals.mbutl, 'char *') + (ix << pgshift))
538
539
540    if (int(cl) == 0):
541        midx = int((m - page_addr) >> 8)
542        mca = kern.globals.mclaudit[ix].cl_audit[midx]
543    elif (int(cl) == 1):
544        midx = int((m - page_addr) >> 11)
545        mca = kern.globals.mclaudit[ix].cl_audit[midx]
546    elif (int(cl) == 2):
547        midx = int((m - page_addr) >> 12)
548        mca = kern.globals.mclaudit[ix].cl_audit[midx]
549    else:
550        mca = kern.globals.mclaudit[ix].cl_audit[0]
551    return Cast(mca, 'mcache_audit_t *')
552
553def GetMbufSlab(m):
554    pgshift = int(kern.globals.page_shift)
555    gix = int((Cast(m, 'char *') - Cast(kern.globals.mbutl, 'char *')) >> MBSHIFT)
556    slabstbl = kern.globals.slabstbl
557    ix = int((Cast(m, 'char *') - Cast(slabstbl[gix].slg_slab[0].sl_base, 'char *')) >> pgshift)
558    return addressof(slabstbl[gix].slg_slab[ix])
559
560def GetMbufBuf2Mca(m):
561    sl = GetMbufSlab(m)
562    mca = GetMbufMcaPtr(m, sl.sl_class)
563    return str(mca)
564
565def GetMbufWalkAllSlabs(show_a, show_f, show_tr):
566    out_string = ""
567
568    kern.globals.slabstbl[0]
569
570    x = 0
571    total = 0
572    total_a = 0
573    total_f = 0
574
575    if (show_a and not(show_f)):
576        out_string += "Searching only for active... \n"
577    if (not(show_a) and show_f):
578        out_string += "Searching only for inactive... \n"
579    if (show_a and show_f):
580        out_string += "Displaying all... \n"
581
582    if (kern.ptrsize == 8):
583        show_mca_string_format = "{0:>4s} {1:>4s} {2:>16s} {3:>16s} {4:>16} {5:>12s} {6:12s}"
584        out_string += show_mca_string_format.format("slot", "idx", "slab address", "mca address", "obj address", "type", "allocation state\n")
585    else:
586        show_mca_string_format = "{0:4s} {1:4s} {2:8s} {3:8s} {4:8} {5:12s} {6:12s}"
587        out_string += show_mca_string_format.format("slot", "idx", "slab address", "mca address", "obj address", "type", "allocation state\n")
588
589    nslabspmb = unsigned((1 << MBSHIFT) >> unsigned(kern.globals.page_shift))
590    while (x < unsigned(kern.globals.slabgrp)):
591        slg = kern.globals.slabstbl[x]
592        y = 0
593        while (y < nslabspmb):
594            sl = addressof(slg.slg_slab[y])
595            base = sl.sl_base
596            if (base == 0):
597                break
598
599            mca = GetMbufMcaPtr(base, sl.sl_class)
600            first = 1
601
602            while ((Cast(mca, 'int') != 0) and (unsigned(mca.mca_addr) != 0)):
603                printmca = 0
604                if (mca.mca_uflags & (MB_INUSE | MB_COMP_INUSE)):
605                    total_a = total_a + 1
606                    printmca = show_a
607                    if (show_tr > 2) and (mca.mca_uflags & MB_SCVALID) == 0:
608                        printmca = 0
609                else:
610                    total_f = total_f + 1
611                    printmca = show_f
612
613                if (printmca != 0):
614                    if (first == 1):
615                        if (kern.ptrsize == 8):
616                            mca_string_format = "{0:4d} {1:4d} 0x{2:16x} "
617                            out_string += mca_string_format.format(x, y, sl)
618                        else:
619                            mca_string_format = "{0:4d} {1:4d} 0x{02:8x} "
620                            out_string += mca_string_format.format(x, y, sl)
621                    else:
622                        if (kern.ptrsize == 8):
623                            out_string += "                             "
624                        else:
625                            out_string += "                     "
626
627                    if (kern.ptrsize == 8):
628                        mca_string_format = "0x{0:16x} 0x{1:16x}"
629                        out_string += mca_string_format.format(mca, mca.mca_addr)
630                    else:
631                        mca_string_format = "0x{0:8x} 0x{1:8x}"
632                        out_string += mca_string_format.format(mca, mca.mca_addr)
633
634                    out_string += GetMbufMcaCtype(mca, 0)
635
636                    if (mca.mca_uflags & (MB_INUSE | MB_COMP_INUSE)):
637                        out_string += "active        "
638                    else:
639                        out_string += "       freed "
640                    if (show_tr > 1) and (mca.mca_uflags & MB_SCVALID):
641                        m = Cast(mca.mca_addr, 'struct mbuf *')
642                        mbuf_string = GetMbufFlags(m)
643                        mbuf_string += " " + GetMbufPktCrumbs(m)
644                        if (mbuf_string != ""):
645                            if (kern.ptrsize == 8):
646                                out_string += "\n                              " + mbuf_string
647                            else:
648                                out_string += "\n                      " + mbuf_string
649                    if (first == 1):
650                        first = 0
651
652                    out_string += "\n"
653                    total = total + 1
654
655                    if (show_tr != 0):
656                        if (mca.mca_next_trn == 0):
657                            trn = 1
658                        else:
659                            trn = 0
660                        out_string += "Transaction " + str(int(trn)) + " at " + str(int(mca.mca_trns[int(trn)].mca_tstamp)) + " by thread: 0x" + str(hex(mca.mca_trns[int(trn)].mca_thread)) + ":\n"
661                        cnt = 0
662                        while (cnt < mca.mca_trns[int(trn)].mca_depth):
663                            kgm_pc = mca.mca_trns[int(trn)].mca_stack[int(cnt)]
664                            out_string += str(int(cnt) + 1) + " "
665                            out_string += GetPc(kgm_pc)
666                            cnt += 1
667
668                    print(out_string)
669                    out_string = ""
670                mca = mca.mca_next
671
672            y += 1
673
674        x += 1
675
676    if (total and show_a and show_f):
677        out_string += "total objects = " + str(int(total)) + "\n"
678        out_string += "active/unfreed objects = " + str(int(total_a)) + "\n"
679        out_string += "freed/in_cache objects = " + str(int(total_f)) + "\n"
680
681    return out_string
682
683def GetMbufFlagsAsString(mbuf_flags):
684    flags = (unsigned)(mbuf_flags & 0xff)
685    out_string = ""
686    i = 0
687    num = 1
688    while num <= flags:
689        if flags & num:
690            out_string += mbuf_flags_strings[i] + ","
691        i += 1
692        num = num << 1
693    return out_string.rstrip(",")
694
695def GetMbufFlags(m):
696    out_string = ""
697    if (m != 0):
698        if kern.globals.mb_uses_mcache == 1:
699            mhflags = m.m_hdr.mh_flags
700        else:
701            mhflags = m.M_hdr_common.M_hdr.mh_flags
702        out_string += "m_flags: " + hex(mhflags)
703        if (mhflags != 0):
704             out_string += " " + GetMbufFlagsAsString(mhflags)
705    return out_string
706
707MBUF_TYPES = [None] * 32
708MBUF_TYPES[0] = "MT_FREE"
709MBUF_TYPES[1] = "MT_DATA"
710MBUF_TYPES[2] = "MT_HEADER"
711MBUF_TYPES[3] = "MT_SOCKET"
712MBUF_TYPES[4] = "MT_PCB"
713MBUF_TYPES[5] = "MT_RTABLE"
714MBUF_TYPES[6] = "MT_HTABLE"
715MBUF_TYPES[7] = "MT_ATABLE"
716MBUF_TYPES[8] = "MT_SONAME"
717# 9 not used
718MBUF_TYPES[10] = "MT_SOOPTS"
719MBUF_TYPES[11] = "MT_FTABLE"
720MBUF_TYPES[12] = "MT_RIGHTS"
721MBUF_TYPES[13] = "MT_IFADDR"
722MBUF_TYPES[14] = "MT_CONTROL"
723MBUF_TYPES[15] = "MT_OOBDATA"
724MBUF_TYPES[16] = "MT_TAG"
725
726def GetMbufType(m):
727    out_string = ""
728    if (m != 0):
729        if kern.globals.mb_uses_mcache == 1:
730            mhtype = m.m_hdr.mh_type
731        else:
732            mhtype = m.M_hdr_common.M_hdr.mh_type
733        out_string += "type: " + MBUF_TYPES[mhtype]
734    return out_string
735
736# Macro: mbuf_show_m_flags
737@lldb_command('mbuf_show_m_flags')
738def MbufShowFlags(cmd_args=None):
739    """ Return a formatted string description of the mbuf flags
740    """
741    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
742    print(GetMbufFlags(m))
743
744def GetMbufPktCrumbsAsString(mbuf_crumbs):
745    flags = (unsigned)(mbuf_crumbs & 0xffff)
746    out_string = ""
747    i = 0
748    num = 1
749    while num <= flags:
750        if flags & num:
751            out_string += mbuf_pkt_crumb_strings[i] + ","
752        i += 1
753        num = num << 1
754    return out_string.rstrip(",")
755
756def GetMbufPktCrumbs(m):
757    out_string = ""
758    if (m != 0):
759        if kern.globals.mb_uses_mcache == 1:
760            mhflags = m.m_hdr.mh_flags
761        else:
762            mhflags = m.M_hdr_common.M_hdr.mh_flags
763        if (mhflags & M_PKTHDR) != 0:
764            if kern.globals.mb_uses_mcache == 1:
765                pktcrumbs = m.M_dat.MH.MH_pkthdr.pkt_crumbs
766            else:
767                pktcrumbs = m.M_hdr_common.M_pkthdr.pkt_crumbs
768            out_string += "pkt_crumbs: 0x{0:x}".format(pktcrumbs)
769            if (pktcrumbs != 0):
770                out_string += " " + GetMbufPktCrumbsAsString(pktcrumbs)
771    return out_string
772
773# Macro: mbuf_showpktcrumbs
774@lldb_command('mbuf_showpktcrumbs')
775def MbufShowPktCrumbs(cmd_args=None):
776    """ Print the packet crumbs of an mbuf object mca
777    """
778    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
779    print(GetMbufPktCrumbs(m))
780
781def GetMbufMcaCtype(mca, vopt):
782    cp = mca.mca_cache
783    mca_class = unsigned(cp.mc_private)
784    csize = unsigned(kern.globals.mbuf_table[mca_class].mtbl_stats.mbcl_size)
785    done = 0
786    out_string = "    "
787    if (csize == MSIZE):
788        if (vopt):
789            out_string += "M (mbuf) "
790        else:
791            out_string += "M     "
792        return out_string
793    if (csize == MCLBYTES):
794        if (vopt):
795            out_string += "CL (2K cluster) "
796        else:
797            out_string += "CL     "
798        return out_string
799    if (csize == MBIGCLBYTES):
800        if (vopt):
801            out_string += "BCL (4K cluster) "
802        else:
803            out_string += "BCL     "
804        return out_string
805    if (csize == M16KCLBYTES):
806        if (vopt):
807            out_string += "JCL (16K cluster) "
808        else:
809            out_string += "JCL     "
810        return out_string
811
812    if (csize == (MSIZE + MCLBYTES)):
813        if (mca.mca_uflags & MB_SCVALID):
814            if (mca.mca_uptr):
815                out_string += "M+CL  "
816                if vopt:
817                    out_string += "(paired mbuf, 2K cluster) "
818            else:
819                out_string += "M-CL  "
820                if vopt:
821                    out_string += "(unpaired mbuf, 2K cluster) "
822        else:
823            if (mca.mca_uptr):
824                out_string += "CL+M  "
825                if vopt:
826                    out_string += "(paired 2K cluster, mbuf) "
827            else:
828                out_string += "CL-M  "
829                if vopt:
830                    out_string += "(unpaired 2K cluster, mbuf) "
831        return out_string
832
833    if (csize == (MSIZE + MBIGCLBYTES)):
834        if (mca.mca_uflags & MB_SCVALID):
835            if (mca.mca_uptr):
836                out_string += "M+BCL  "
837                if vopt:
838                    out_string += "(paired mbuf, 4K cluster) "
839            else:
840                out_string += "M-BCL  "
841                if vopt:
842                    out_string += "(unpaired mbuf, 4K cluster) "
843        else:
844            if (mca.mca_uptr):
845                out_string += "BCL+M  "
846                if vopt:
847                    out_string += "(paired 4K cluster, mbuf) "
848            else:
849                out_string += "BCL-m  "
850                if vopt:
851                    out_string += "(unpaired 4K cluster, mbuf) "
852        return out_string
853
854    if (csize == (MSIZE + M16KCLBYTES)):
855        if (mca.mca_uflags & MB_SCVALID):
856            if (mca.mca_uptr):
857                out_string += "M+BCL  "
858                if vopt:
859                    out_string += "(paired mbuf, 4K cluster) "
860            else:
861                out_string += "M-BCL  "
862                if vopt:
863                    out_string += "(unpaired mbuf, 4K cluster) "
864        else:
865            if (mca.mca_uptr):
866                out_string += "BCL+M  "
867                if vopt:
868                    out_string += "(paired 4K cluster, mbuf) "
869            else:
870                out_string += "BCL-m  "
871                if vopt:
872                    out_string += "(unpaired 4K cluster, mbuf) "
873        return out_string
874
875    out_string += "unknown: " + cp.mc_name
876    return out_string
877
878
879def GetPointerAsString(kgm_pc):
880    if (kern.ptrsize == 8):
881        pointer_format_string = "0x{0:<16x} "
882    else:
883        pointer_format_string = "0x{0:<8x} "
884    return pointer_format_string.format(kgm_pc)
885
886def GetPc(kgm_pc):
887    out_string = GetSourceInformationForAddress(unsigned(kgm_pc)) + "\n"
888    return out_string
889
890
891def GetMbufWalkZone(show_a, show_f, show_tr):
892    out_string = ""
893    total = 0
894    total_a = 0
895    total_f = 0
896    if (show_a and not(show_f)):
897        out_string += "Searching only for active... \n"
898    if (not(show_a) and show_f):
899        out_string += "Searching only for inactive... \n"
900    if (show_a and show_f):
901        out_string += "Displaying all... \n"
902    f = "{0:>18s} {1:s}\n"
903    out_string += f.format("address", "type flags and crumbs")
904    print(out_string)
905    if show_a:
906        for mbuf_sbv in kmemory.Zone("mbuf").iter_allocated(gettype("mbuf")):
907            mbuf = value(mbuf_sbv.AddressOf())
908            total_a += 1
909            total += 1
910            mbuf_string = GetMbufFlags(mbuf)
911            mbuf_string += " " + GetMbufType(mbuf)
912            mbuf_string += " " + GetMbufPktCrumbs(mbuf)
913            if mbuf_string != "":
914                out_string = f.format(hex(mbuf), mbuf_string)
915            print(out_string)
916            if show_tr:
917                print(lldb_run_command('kasan whatis {addr}'.format(addr=hex(mbuf))))
918    if show_f:
919        for mbuf_sbv in kmemory.Zone("mbuf").iter_free(gettype("mbuf")):
920            mbuf = value(mbuf_sbv.AddressOf())
921            total_f += 1
922            total += 1
923            mbuf_string = GetMbufFlags(mbuf)
924            mbuf_string += " " + GetMbufType(mbuf)
925            mbuf_string += " " + GetMbufPktCrumbs(mbuf)
926            if mbuf_string != "":
927                out_string = f.format(hex(mbuf), mbuf_string)
928            print(out_string)
929            if show_tr:
930                print(lldb_run_command('kasan whatis {addr}'.format(addr=hex(mbuf))))
931
932    if total and show_a and show_f:
933        out_string += "total objects = " + str(int(total)) + "\n"
934        out_string += "active/unfreed objects = " + str(int(total_a)) + "\n"
935        out_string += "freed/in_cache objects = " + str(int(total_f)) + "\n"
936        print(out_string)
937
938
939# Macro: mbuf_showactive
940@lldb_command('mbuf_showactive')
941def MbufShowActive(cmd_args=None):
942    """ Print all active/in-use mbuf objects
943        Pass 1 to show the most recent transaction stack trace
944        Pass 2 to also display the mbuf flags and packet crumbs
945        Pass 3 to limit display to mbuf and skip clusters
946    """
947    if int(kern.globals.mb_uses_mcache) == 0:
948        if cmd_args:
949            GetMbufWalkZone(1, 0, ArgumentStringToInt(cmd_args[0]))
950        else:
951            GetMbufWalkZone(1, 0, 0)
952    else:
953        if cmd_args:
954            print(GetMbufWalkAllSlabs(1, 0, ArgumentStringToInt(cmd_args[0])))
955        else:
956            print(GetMbufWalkAllSlabs(1, 0, 0))
957# EndMacro: mbuf_showactive
958
959
960# Macro: mbuf_showinactive
961@lldb_command('mbuf_showinactive')
962def MbufShowInactive(cmd_args=None):
963    """ Print all freed/in-cache mbuf objects
964    """
965    if int(kern.globals.mb_uses_mcache) == 0:
966        GetMbufWalkZone(0, 1, 0)
967    else:
968        print(GetMbufWalkAllSlabs(0, 1, 0))
969# EndMacro: mbuf_showinactive
970
971# Macro: mbuf_show_type_summary
972@lldb_command('mbuf_show_type_summary')
973def MbufShowTypeSummary(cmd_args=None):
974    """
975    Print types of all allocated mbufs.
976    Only supported on Apple Silicon.
977    """
978    types = [0] * 32
979    for mbuf_sbv in kmemory.Zone("mbuf").iter_allocated(gettype("mbuf")):
980        mbuf = value(mbuf_sbv.AddressOf())
981        mhtype = mbuf.M_hdr_common.M_hdr.mh_type
982        types[mhtype] += 1
983    for mbuf_sbv in kmemory.Zone("mbuf").iter_free(gettype("mbuf")):
984        mbuf = value(mbuf_sbv.AddressOf())
985        mhtype = mbuf.M_hdr_common.M_hdr.mh_type
986        types[mhtype] += 1
987
988    print("mbuf types allocated and in the caches:")
989    for t in range(len(MBUF_TYPES)):
990        if types[t] != 0:
991            print(MBUF_TYPES[t], types[t])
992
993# EndMacro: mbuf_show_type_summary
994
995
996# Macro: mbuf_showmca
997@lldb_command('mbuf_showmca')
998def MbufShowMca(cmd_args=None):
999    """ Print the contents of an mbuf mcache audit structure
1000    """
1001    if int(kern.globals.mb_uses_mcache) == 0:
1002        print("mcache is disabled, use kasan whatis or zstack_findelem")
1003        return
1004    out_string = ""
1005    pgshift = unsigned(kern.globals.page_shift)
1006    if cmd_args:
1007        mca = kern.GetValueFromAddress(cmd_args[0], 'mcache_audit_t *')
1008        cp = mca.mca_cache
1009        out_string += "object type:\t"
1010        out_string += GetMbufMcaCtype(mca, 1)
1011        out_string += "\nControlling mcache :\t" + hex(mca.mca_cache) + " (" + str(cp.mc_name) + ")\n"
1012        if (mca.mca_uflags & MB_INUSE):
1013            out_string += " inuse"
1014        if (mca.mca_uflags & MB_COMP_INUSE):
1015            out_string += " comp_inuse"
1016        if (mca.mca_uflags & MB_SCVALID):
1017            out_string += " scvalid"
1018        out_string += "\n"
1019        if (mca.mca_uflags & MB_SCVALID):
1020            mbutl = Cast(kern.globals.mbutl, 'unsigned char *')
1021            ix = (mca.mca_addr - mbutl) >> pgshift
1022            clbase = mbutl + (ix << pgshift)
1023            mclidx = (mca.mca_addr - clbase) >> 8
1024            out_string += "mbuf obj :\t\t" + hex(mca.mca_addr) + "\n"
1025            out_string += "mbuf index :\t\t" + str(mclidx + 1) + " (out of 16) in cluster base " + hex(clbase) + "\n"
1026            if (int(mca.mca_uptr) != 0):
1027                peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *')
1028                out_string += "paired cluster obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n"
1029            out_string += "saved contents :\t" + hex(mca.mca_contents) + " (" + str(int(mca.mca_contents_size)) + " bytes)\n"
1030        else:
1031            out_string += "cluster obj :\t\t" + hex(mca.mca_addr) + "\n"
1032            if (mca.mca_uptr != 0):
1033                peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *')
1034                out_string += "paired mbuf obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n"
1035
1036        for idx in range(unsigned(kern.globals.mca_trn_max), 0, -1):
1037                trn = (mca.mca_next_trn + idx - 1) % unsigned(kern.globals.mca_trn_max)
1038                out_string += "transaction {:d} (tstamp {:d}, thread 0x{:x}):\n".format(trn, mca.mca_trns[trn].mca_tstamp, mca.mca_trns[trn].mca_thread)
1039                cnt = 0
1040                while (cnt < mca.mca_trns[trn].mca_depth):
1041                    kgm_pc = mca.mca_trns[trn].mca_stack[cnt]
1042                    out_string += "  " + str(cnt + 1) + ".  "
1043                    out_string += GetPc(kgm_pc)
1044                    cnt += 1
1045
1046        msc = cast(mca.mca_contents, 'mcl_saved_contents_t *')
1047        msa = addressof(msc.sc_scratch)
1048        if (mca.mca_uflags & MB_SCVALID):
1049            if (msa.msa_depth > 0):
1050                out_string += "Recent scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_tstamp, msa.msa_thread)
1051                cnt = 0
1052                while (cnt < msa.msa_depth):
1053                    kgm_pc = msa.msa_stack[cnt]
1054                    out_string += "  " + str(cnt + 1) + ".  "
1055                    out_string += GetPc(kgm_pc)
1056                    cnt += 1
1057
1058            if (msa.msa_pdepth > 0):
1059                out_string += "previous scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_ptstamp, msa.msa_pthread)
1060        if (msa):
1061            cnt = 0
1062            while (cnt < msa.msa_pdepth):
1063                kgm_pc = msa.msa_pstack[cnt]
1064                out_string += "  " + str(cnt + 1) + ".  "
1065                out_string += GetPc(kgm_pc)
1066                cnt += 1
1067    else:
1068        out_string += "Missing argument 0 in user function."
1069
1070    print(out_string)
1071# EndMacro: mbuf_showmca
1072
1073
1074# Macro: mbuf_showall
1075@lldb_command('mbuf_showall')
1076def MbufShowAll(cmd_args=None):
1077    """ Print all mbuf objects
1078    """
1079    if int(kern.globals.mb_uses_mcache) == 0:
1080        GetMbufWalkZone(1, 1, 1)
1081    else:
1082        print(GetMbufWalkAllSlabs(1, 1, 1))
1083# EndMacro: mbuf_showall
1084
1085# Macro: mbuf_countchain
1086@lldb_command('mbuf_countchain')
1087def MbufCountChain(cmd_args=None):
1088    """ Count the length of an mbuf chain
1089    """
1090    if not cmd_args:
1091        raise ArgumentError("Missing argument 0 in user function.")
1092
1093    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
1094
1095    pkt = 0
1096    nxt = 0
1097
1098    while (mp):
1099        pkt = pkt + 1
1100        if kern.globals.mb_uses_mcache == 1:
1101            mn = mp.m_hdr.mh_next
1102        else:
1103            mn = mp.M_hdr_common.M_hdr.mh_next
1104        while (mn):
1105            nxt = nxt + 1
1106            if kern.globals.mb_uses_mcache == 1:
1107                mn = mn.m_hdr.mh_next
1108            else:
1109                mn = mn.M_hdr_common.M_hdr.mh_next
1110            print1("mp 0x{:x} mn 0x{:x}".format(mp, mn))
1111
1112        if kern.globals.mb_uses_mcache == 1:
1113            mp = mp.m_hdr.mh_nextpkt
1114        else:
1115            mp = mp.M_hdr_common.M_hdr.mh_nextpkt
1116
1117        if (((pkt + nxt) % 50) == 0):
1118            print(" ..." + str(pkt_nxt))
1119
1120    print("Total: " + str(pkt + nxt) + " (via m_next: " + str(nxt) + ")")
1121# EndMacro: mbuf_countchain
1122
1123# Macro: mbuf_topleak
1124@lldb_command('mbuf_topleak')
1125def MbufTopLeak(cmd_args=None):
1126    """ Print the top suspected mbuf leakers
1127    """
1128    if int(kern.globals.mb_uses_mcache) == 0:
1129        print("mcache is disabled, use zleak")
1130        return
1131    topcnt = 0
1132    if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5):
1133        maxcnt = cmd_args[0]
1134    else:
1135        maxcnt = 5
1136    while (topcnt < maxcnt):
1137        print(GetMbufTraceLeak(kern.globals.mleak_top_trace[topcnt]))
1138        topcnt += 1
1139
1140# EndMacro: mbuf_topleak
1141
1142def GetMbufTraceLeak(trace):
1143    out_string = ""
1144    if (trace != 0 and trace.allocs != 0):
1145        out_string += hex(trace) + ":" + str(trace.allocs) + " outstanding allocs\n"
1146        out_string += "Backtrace saved " + str(trace.depth) + " deep\n"
1147        if (trace.depth != 0):
1148            cnt = 0
1149            while (cnt < trace.depth):
1150                out_string += str(cnt + 1) + ": "
1151                out_string += GetPc(trace.addr[cnt])
1152                out_string += "\n"
1153                cnt += 1
1154    return out_string
1155
1156@lldb_command('mbuf_largefailures')
1157def MbufLargeFailures(cmd_args=None):
1158    """ Print the largest allocation failures
1159    """
1160    if int(kern.globals.mb_uses_mcache) == 0:
1161        print("mcache is disabled, this macro is not available. use zleak to detect leaks")
1162        return
1163    topcnt = 0
1164    if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5):
1165        maxcnt = cmd_args[0]
1166    else:
1167        maxcnt = 5
1168    while (topcnt < maxcnt):
1169        trace = kern.globals.mtracelarge_table[topcnt]
1170        if (trace.size == 0):
1171            topcnt += 1
1172            continue
1173        print(str(trace.size))
1174        if (trace.depth != 0):
1175            cnt = 0
1176            while (cnt < trace.depth):
1177                print(str(cnt + 1) + ": " + GetPc(trace.addr[cnt]))
1178                cnt += 1
1179        topcnt += 1
1180
1181
1182# Macro: mbuf_traceleak
1183@lldb_command('mbuf_traceleak')
1184def MbufTraceLeak(cmd_args=None):
1185    """ Print the leak information for a given leak address
1186        Given an mbuf leak trace (mtrace) structure address, print out the
1187        stored information with that trace
1188        syntax: (lldb) mbuf_traceleak <addr>
1189    """
1190    if not cmd_args:
1191        raise ArgumentError("Missing argument 0 in user function.")
1192    if int(kern.globals.mb_uses_mcache) == 0:
1193        print("mcache is disabled, use kasan whatis")
1194        return
1195
1196    trace = kern.GetValueFromAddress(cmd_args[0], 'mtrace *')
1197    print(GetMbufTraceLeak(trace))
1198# EndMacro: mbuf_traceleak
1199
1200
1201# Macro: mcache_walkobj
1202@lldb_command('mcache_walkobj')
1203def McacheWalkObject(cmd_args=None):
1204    """ Given a mcache object address, walk its obj_next pointer
1205    """
1206    if not cmd_args:
1207        raise ArgumentError("Missing argument 0 in user function.")
1208    if int(kern.globals.mb_uses_mcache) == 0:
1209        print("mcache is disabled, use kasan whatis")
1210        return
1211
1212    out_string = ""
1213    p = kern.GetValueFromAddress(cmd_args[0], 'mcache_obj_t *')
1214    cnt = 1
1215    total = 0
1216    while (p):
1217        mcache_object_format = "{0:>4d}: 0x{1:>16x}"
1218        out_string += mcache_object_format.format(cnt, p) + "\n"
1219        p = p.obj_next
1220        cnt += 1
1221    print(out_string)
1222# EndMacro: mcache_walkobj
1223
1224# Macro: mcache_stat
1225@lldb_command('mcache_stat')
1226def McacheStat(cmd_args=None):
1227    """ Print all mcaches in the system.
1228    """
1229    if int(kern.globals.mb_uses_mcache) == 0:
1230        print("mcache is disabled, use kasan whatis")
1231        return
1232
1233    head = kern.globals.mcache_head
1234    out_string = ""
1235    mc = cast(head.lh_first, 'mcache *')
1236    if (kern.ptrsize == 8):
1237        mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>20s} {3:>5s} {4:>5s} {5:>20s} {6:>30s} {7:>18s}"
1238    else:
1239        mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>12s} {3:>5s} {4:>5s} {5:>12s} {6:>30s} {7:>18s}"
1240
1241    if (kern.ptrsize == 8):
1242        mcache_stat_data_format_string = "{0:<24s} {1:>12s} {2:>20s} {3:>5s} {4:>5s} {5:>22s} {6:>12d} {7:>8d} {8:>8d} {9:>18d}"
1243    else:
1244        mcache_stat_data_format_string = "{0:<24s} {1:>12s} {2:>12s} {3:>5s} {4:>5s} {5:>14s} {6:>12d} {7:>8d} {8:>8d} {9:>18d}"
1245
1246    out_string += mcache_stat_format_string.format("cache name", "cache state", "cache addr", "buf size", "buf align", "backing zone", "wait     nowait     failed", "bufs incache")
1247    out_string += "\n"
1248
1249    ncpu = int(kern.globals.ncpu)
1250    while mc != 0:
1251        bktsize = mc.mc_cpu[0].cc_bktsize
1252        cache_state = ""
1253        if (mc.mc_flags & MCF_NOCPUCACHE):
1254            cache_state = "disabled"
1255        else:
1256            if (bktsize == 0):
1257                cache_state = " offline"
1258            else:
1259                cache_state = " online"
1260        if (mc.mc_slab_zone != 0):
1261            backing_zone = mc.mc_slab_zone
1262        else:
1263            if (kern.ptrsize == 8):
1264                backing_zone = "            custom"
1265            else:
1266                backing_zone = "    custom"
1267
1268        total = 0
1269        total += mc.mc_full.bl_total * bktsize
1270        n = 0
1271        while(n < ncpu):
1272            ccp = mc.mc_cpu[n]
1273            if (ccp.cc_objs > 0):
1274                total += ccp.cc_objs
1275            if (ccp.cc_pobjs > 0):
1276                total += ccp.cc_pobjs
1277            n += 1
1278
1279        out_string += mcache_stat_data_format_string.format(mc.mc_name, cache_state, hex(mc), str(int(mc.mc_bufsize)), str(int(mc.mc_align)), hex(mc.mc_slab_zone), int(mc.mc_wretry_cnt), int(mc.mc_nwretry_cnt), int(mc.mc_nwfail_cnt), total)
1280        out_string += "\n"
1281        mc = cast(mc.mc_list.le_next, 'mcache *')
1282    print(out_string)
1283# EndMacro: mcache_stat
1284
1285# Macro: mcache_showcache
1286@lldb_command('mcache_showcache')
1287def McacheShowCache(cmd_args=None):
1288    """Display the number of objects in cache.
1289    """
1290    if int(kern.globals.mb_uses_mcache) == 0:
1291        print("mcache is disabled, use kasan whatis")
1292        return
1293    out_string = ""
1294    cp = kern.GetValueFromAddress(cmd_args[0], 'mcache_t *')
1295    bktsize = cp.mc_cpu[0].cc_bktsize
1296    cnt = 0
1297    total = 0
1298    mcache_cache_format = "{0:<4d} {1:>8d} {2:>8d} {3:>8d}"
1299    out_string += "Showing cache " + str(cp.mc_name) + " :\n\n"
1300    out_string += " CPU  cc_objs cc_pobjs    total\n"
1301    out_string += "----  ------- -------- --------\n"
1302    ncpu = int(kern.globals.ncpu)
1303    while (cnt < ncpu):
1304        ccp = cp.mc_cpu[cnt]
1305        objs = ccp.cc_objs
1306        if (objs <= 0):
1307            objs = 0
1308        pobjs = ccp.cc_pobjs
1309        if (pobjs <= 0):
1310            pobjs = 0
1311        tot_cpu = objs + pobjs
1312        total += tot_cpu
1313        out_string += mcache_cache_format.format(cnt, objs, pobjs, tot_cpu)
1314        out_string += "\n"
1315        cnt += 1
1316
1317    out_string += "                       ========\n"
1318    out_string += "                           " + str(total) + "\n\n"
1319    total += cp.mc_full.bl_total * bktsize
1320
1321    out_string += "Total # of full buckets (" + str(int(bktsize)) + " objs/bkt):\t" + str(int(cp.mc_full.bl_total)) + "\n"
1322    out_string += "Total # of objects cached:\t\t" + str(total) + "\n"
1323    print(out_string)
1324# EndMacro: mcache_showcache
1325
1326# Macro: mbuf_wdlog
1327@lldb_command('mbuf_wdlog')
1328def McacheShowWatchdogLog(cmd_args=None):
1329    """Display the watchdog log
1330    """
1331    lldb_run_command('settings set max-string-summary-length 4096')
1332    print('%s' % lldb_run_command('p/s mbwdog_logging').replace("\\n","\n"))
1333# EndMacro: mbuf_wdlog
1334