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