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