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