xref: /xnu-8796.141.3/tools/lldbmacros/mbufs.py (revision 1b191cb58250d0705d8a51287127505aa4bc0789)
1
2""" Please make sure you read the README COMPLETELY BEFORE reading anything below.
3    It is very critical that you read coding guidelines in Section E in README file.
4"""
5from __future__ import absolute_import, division, print_function
6
7from builtins import hex
8from builtins import range
9
10from xnu import *
11from utils import *
12
13from mbufdefines import *
14import xnudefines
15
16# Macro: mbuf_stat
17@lldb_command('mbuf_stat')
18def MBufStat(cmd_args=None):
19    """ Print extended mbuf allocator statistics.
20    """
21    hdr_format = "{0: <16s} {1: >8s} {2: >8s} {3: ^16s} {4: >8s} {5: >12s} {6: >8s} {7: >8s} {8: >8s} {9: >8s}"
22    print(hdr_format.format('class', 'total', 'cached', 'uncached', 'inuse', 'failed', 'waiter', 'notified', 'purge', 'max'))
23    print(hdr_format.format('name', 'objs', 'objs', 'objs/slabs', 'objs', 'alloc count', 'count', 'count', 'count', 'objs'))
24    print(hdr_format.format('-'*16, '-'*8, '-'*8, '-'*16, '-'*8, '-'*12, '-'*8, '-'*8, '-'*8, '-'*8))
25    entry_format = "{0: <16s} {1: >8d} {2: >8d} {3:>7d} / {4:<6d} {5: >8d} {6: >12d} {7: >8d} {8: >8d} {9: >8d} {10: >8d}"
26    num_items = sizeof(kern.globals.mbuf_table) // sizeof(kern.globals.mbuf_table[0])
27    ncpus = int(kern.globals.ncpu)
28    for i in range(num_items):
29        mbuf = kern.globals.mbuf_table[i]
30        mcs = Cast(mbuf.mtbl_stats, 'mb_class_stat_t *')
31        mc = mbuf.mtbl_cache
32        total = 0
33        total += int(mc.mc_full.bl_total) * int(mc.mc_cpu[0].cc_bktsize)
34        ccp_arr = mc.mc_cpu
35        for i in range(ncpus):
36            ccp = ccp_arr[i]
37            if int(ccp.cc_objs) > 0:
38                total += int(ccp.cc_objs)
39            if int(ccp.cc_pobjs) > 0:
40                total += int(ccp.cc_pobjs)
41        print(entry_format.format(mcs.mbcl_cname, mcs.mbcl_total,  total,
42                                  mcs.mbcl_infree, mcs.mbcl_slab_cnt,
43                                  (mcs.mbcl_total - total - mcs.mbcl_infree),
44                                  mcs.mbcl_fail_cnt, mbuf.mtbl_cache.mc_waiter_cnt,
45                                  mcs.mbcl_notified, mcs.mbcl_purge_cnt,
46                                  mbuf.mtbl_maxlimit))
47# EndMacro: mbuf_stat
48
49def DumpMbufData(mp, count):
50    mdata = mp.m_hdr.mh_data
51    mlen = mp.m_hdr.mh_len
52    flags = mp.m_hdr.mh_flags
53    if flags & M_EXT:
54        mdata = mp.M_dat.MH.MH_dat.MH_ext.ext_buf
55    if (count > mlen):
56        count = mlen
57    cmd = "memory read -force -size 1 -count {0:d} 0x{1:x}".format(count, mdata)
58    print(lldb_run_command(cmd))
59
60def DecodeMbufData(mp):
61    import scapy.all
62    err = lldb.SBError()
63    full_buf = b''
64    while mp:
65        mdata = mp.m_hdr.mh_data
66        mlen = mp.m_hdr.mh_len
67        flags = mp.m_hdr.mh_flags
68        if flags & M_EXT:
69            mdata = mp.M_dat.MH.MH_dat.MH_ext.ext_buf
70        addr = mdata.GetSBValue().GetValueAsAddress()
71        buf = LazyTarget.GetProcess().ReadMemory(addr, unsigned(mlen), err)
72        full_buf += buf
73        if flags & M_PKTHDR:
74            mp = mp.m_hdr.mh_nextpkt
75        else:
76            mp = mp.m_hdr.mh_next
77    try:
78        pkt = scapy.layers.l2.Ether(full_buf)
79        pkt.show()
80    except:
81        pass
82
83# Macro: mbuf_decode
84@lldb_command('mbuf_decode', '')
85def MbufDecode(cmd_args=None, cmd_options={}):
86    """Decode an mbuf using scapy.
87        Usage: mbuf_decode <mbuf address>
88    """
89    if cmd_args == None or len(cmd_args) < 1:
90        print("usage: mbuf_decode <address>")
91        return
92    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
93    DecodeMbufData(mp)
94# EndMacro: mbuf_decode
95
96# Macro: mbuf_dumpdata
97@lldb_command('mbuf_dumpdata', 'C:')
98def MbufDumpData(cmd_args=None, cmd_options={}):
99    """Dump the mbuf data
100        Usage: mbuf_dumpdata  <mbuf address> [-C <count>]
101    """
102    if cmd_args == None or len(cmd_args) < 1:
103        print(MbufDumpData.__doc__)
104        return
105    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
106    mdata = mp.m_hdr.mh_data
107    mlen = 0
108    if "-C" in cmd_options:
109        mlen = ArgumentStringToInt(cmd_options["-C"])
110        if (mlen > mp.m_hdr.mh_len):
111            mlen = mp.m_hdr.mh_len
112    else:
113        mlen = mp.m_hdr.mh_len
114    DumpMbufData(mp, mlen)
115# EndMacro: mbuf_dumpdata
116
117def ShowMbuf(prefix, mp, count, total, dump_data_len):
118    out_string = ""
119    mbuf_walk_format = "{0:s}{1:d} 0x{2:x} [len {3:d}, type {4:d}, "
120    out_string += mbuf_walk_format.format(prefix, count[0], mp, mp.m_hdr.mh_len, mp.m_hdr.mh_type)
121    out_string += "flags " + GetMbufFlagsAsString(mp.m_hdr.mh_flags) + ", "
122    if (mp.m_hdr.mh_flags & M_PKTHDR):
123        out_string += GetMbufPktCrumbs(mp) + ", "
124    if (kern.globals.mclaudit != 0):
125        out_string += GetMbufBuf2Mca(mp) + ", "
126    total[0] = total[0] + mp.m_hdr.mh_len
127    out_string += "total " + str(total[0]) + "]"
128    print(out_string)
129    if (dump_data_len > 0):
130        DumpMbufData(mp, dump_data_len)
131
132def WalkMufNext(prefix, mp, count, total, dump_data_len):
133    remaining_len = dump_data_len
134    while (mp):
135        count[0] += 1
136        ShowMbuf(prefix, mp, count, total, remaining_len)
137        if (remaining_len > mp.m_hdr.mh_len):
138            remaining_len -= mp.m_hdr.mh_len
139        else:
140            remaining_len = 0
141        mp = mp.m_hdr.mh_next
142
143# Macro: mbuf_walkpkt
144@lldb_command('mbuf_walkpkt', 'C:')
145def MbufWalkPacket(cmd_args=None, cmd_options={}):
146    """ Walk the mbuf packet chain (m_nextpkt)
147        Usage: mbuf_walkpkt  <mbuf address> [-C <count>]
148    """
149    if not cmd_args:
150        raise ArgumentError("Missing argument 0 in user function.")
151    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
152
153    dump_data_len = 0
154    if "-C" in cmd_options:
155        dump_data_len = ArgumentStringToInt(cmd_options["-C"])
156
157    count_packet = 0
158    count_mbuf = 0
159    total_len = 0
160
161    while (mp):
162        count_packet += 1
163        prefix = "{0:d}.".format(count_packet)
164        count = [0]
165        total = [0]
166        WalkMufNext(prefix, mp, count, total, dump_data_len)
167        count_mbuf += count[0]
168        total_len += total[0]
169        mp = mp.m_hdr.mh_nextpkt
170    out_string = "Total packets: {0:d} mbufs: {1:d} length: {2:d} ".format(count_packet, count_mbuf, total_len)
171    print(out_string)
172# EndMacro: mbuf_walkpkt
173
174# Macro: mbuf_walk
175@lldb_command('mbuf_walk', 'C:')
176def MbufWalk(cmd_args=None, cmd_options={}):
177    """ Walk the mbuf chain (m_next)
178        Usage: mbuf_walk  <mbuf address> [-C <count>]
179    """
180    if not cmd_args:
181        raise ArgumentError("Missing argument 0 in user function.")
182    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
183
184    dump_data_len = 0
185    if "-C" in cmd_options:
186        dump_data_len = ArgumentStringToInt(cmd_options["-C"])
187
188    count = [0]
189    total = [0]
190    prefix = ""
191    WalkMufNext(prefix, mp, count, total, dump_data_len)
192# EndMacro: mbuf_walk
193
194# Macro: mbuf_buf2slab
195@lldb_command('mbuf_buf2slab')
196def MbufBuf2Slab(cmd_args=None):
197    """ Given an mbuf object, find its corresponding slab address
198    """
199    if not cmd_args:
200        raise ArgumentError("Missing argument 0 in user function.")
201
202    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
203    slab = GetMbufSlab(m)
204    if (kern.ptrsize == 8):
205        mbuf_slab_format = "0x{0:<16x}"
206        print(mbuf_slab_format.format(slab))
207    else:
208        mbuf_slab_format = "0x{0:<8x}"
209        print(mbuf_slab_format.format(slab))
210# EndMacro: mbuf_buf2slab
211
212# Macro: mbuf_buf2mca
213@lldb_command('mbuf_buf2mca')
214def MbufBuf2Mca(cmd_args=None):
215    """ Find the mcache audit structure of the corresponding mbuf
216    """
217    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
218    print(GetMbufBuf2Mca(m))
219    return
220# EndMacro: mbuf_buf2mca
221
222# Macro: mbuf_slabs
223@lldb_command('mbuf_slabs')
224def MbufSlabs(cmd_args=None):
225    """ Print all slabs in the group
226    """
227
228    out_string = ""
229    if not cmd_args:
230        raise ArgumentError("Invalid arguments passed.")
231
232    slg = kern.GetValueFromAddress(cmd_args[0], 'mcl_slabg_t *')
233    x = 0
234
235    if (kern.ptrsize == 8):
236        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} "
237        out_string += "slot  slab               next               obj                mca                tstamp     C   R   N   size   flags\n"
238        out_string += "----- ------------------ ------------------ ------------------ ------------------ ---------- --- --- --- ------ -----\n"
239    else:
240        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} "
241        out_string += "slot  slab       next       obj        mca        tstamp     C   R   N   size   flags\n"
242        out_string += "----- ---------- ---------- ---------- ---------- ---------- --- --- --- ------ -----\n"
243
244    mbutl = cast(kern.globals.mbutl, 'unsigned char *')
245    nslabspmb = int((1 << MBSHIFT) >> unsigned(kern.globals.page_shift))
246    while x < nslabspmb:
247        sl = addressof(slg.slg_slab[x])
248        mca = 0
249        obj = sl.sl_base
250        ts = 0
251
252        if (kern.globals.mclaudit != 0 and obj != 0):
253            mca = GetMbufMcaPtr(obj, sl.sl_class)
254            trn = (mca.mca_next_trn + unsigned(kern.globals.mca_trn_max) - 1) % unsigned(kern.globals.mca_trn_max)
255            ts = mca.mca_trns[trn].mca_tstamp
256
257        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))
258
259        if (sl.sl_flags != 0):
260            out_string += "<"
261            if sl.sl_flags & SLF_MAPPED:
262                out_string += "mapped"
263            if sl.sl_flags & SLF_PARTIAL:
264                out_string += ",partial"
265            if sl.sl_flags & SLF_DETACHED:
266                out_string += ",detached"
267            out_string += ">"
268        out_string += "\n"
269
270        if sl.sl_chunks > 1:
271            z = 1
272            c = sl.sl_len // sl.sl_chunks
273
274            while z < sl.sl_chunks:
275                obj = sl.sl_base + (c * z)
276                mca = 0
277                ts = 0
278
279                if (kern.globals.mclaudit != 0 ):
280                    mca = GetMbufMcaPtr(obj, sl.sl_class)
281                    trn = (mca.mca_next_trn + unsigned(kern.globals.mca_trn_max) - 1) % unsigned(kern.globals.mca_trn_max)
282                    ts = mca.mca_trns[trn].mca_tstamp
283
284                if (kern.ptrsize == 8):
285                    chunk_string_format = "                                            0x{0:16x} 0x{1:16x} {2:10d}\n"
286                else:
287                    chunk_string_format = "                            0x{0:8x} {1:4s} {2:10d}\n"
288
289                out_string += chunk_string_format.format(int(obj), int(mca), int(ts))
290
291                z += 1
292        x += 1
293    print(out_string)
294# EndMacro: mbuf_slabs
295
296# Macro: mbuf_slabstbl
297@lldb_command('mbuf_slabstbl')
298def MbufSlabsTbl(cmd_args=None):
299    """ Print slabs table
300    """
301    out_string = ""
302    x = 0
303
304    if (kern.ptrsize == 8):
305        out_string += "slot slabg              slabs range\n"
306        out_string += "---- ------------------ -------------------------------------------\n"
307    else:
308        out_string += "slot slabg      slabs range\n"
309        out_string += "---- ---------- ---------------------------\n"
310
311    slabstbl = kern.globals.slabstbl
312    slabs_table_blank_string_format = "{0:>3d}: - \n"
313    nslabspmb = int(((1 << MBSHIFT) >> unsigned(kern.globals.page_shift)))
314    while (x < unsigned(kern.globals.maxslabgrp)):
315        slg = slabstbl[x]
316        if (slg == 0):
317            out_string += slabs_table_blank_string_format.format(x+1)
318        else:
319            if (kern.ptrsize == 8):
320                slabs_table_string_format = "{0:>3d}: 0x{1:16x}  [ 0x{2:16x} - 0x{3:16x} ]\n"
321                out_string += slabs_table_string_format.format(x+1, slg, addressof(slg.slg_slab[0]), addressof(slg.slg_slab[nslabspmb-1]))
322            else:
323                slabs_table_string_format = "{0:>3d}: 0x{1:8x}  [ 0x{2:8x} - 0x{3:8x} ]\n"
324                out_string += slabs_table_string_format.format(x+1, slg, addressof(slg.slg_slab[0]), addressof(slg.slg_slab[nslabspmb-1]))
325
326        x += 1
327    print(out_string)
328# EndMacro: mbuf_slabstbl
329
330def MbufDecode(mbuf, decode_pkt):
331    # Ignore free'd mbufs.
332    if mbuf.m_hdr.mh_type == 0:
333        return
334    flags = int(mbuf.m_hdr.mh_flags)
335    length = int(mbuf.m_hdr.mh_len)
336    if length < 20 or length > 8 * 1024:
337        # Likely not a packet.
338        return
339    out_string = "mbuf found @ 0x{0:x}, length {1:d}, {2:s}, {3:s}".format(mbuf, length, GetMbufFlags(mbuf), GetMbufPktCrumbs(mbuf))
340    print(out_string)
341    if flags & M_EXT:
342        ext_buf = mbuf.M_dat.MH.MH_dat.MH_ext.ext_buf
343        ext_size = int(mbuf.M_dat.MH.MH_dat.MH_ext.ext_size)
344    if flags & M_PKTHDR:
345        rcvif = mbuf.M_dat.MH.MH_pkthdr.rcvif
346        if rcvif != 0:
347            try:
348                print("receive interface " + rcvif.if_xname)
349            except ValueError:
350                pass
351    if decode_pkt:
352        DecodeMbufData(mbuf)
353
354
355# Macro: mbuf_walk_slabs
356@lldb_command('mbuf_walk_slabs')
357def MbufWalkSlabs(cmd_args=None):
358    """
359    Walks the mbuf slabs table backwards and tries to detect and decode mbufs.
360    Use 'mbuf_walk_slabs decode' to decode the mbuf using scapy.
361    """
362    decode_pkt = False
363    if len(cmd_args) > 0 and cmd_args[0] == 'decode':
364        decode_pkt = True
365    slabstbl = kern.globals.slabstbl
366    nslabspmb = int(((1 << MBSHIFT) >> unsigned(kern.globals.page_shift)))
367    mbutl = cast(kern.globals.mbutl, 'unsigned char *')
368    x = unsigned(kern.globals.maxslabgrp)
369    while x >= 0:
370        slg = slabstbl[x]
371        if (slg == 0):
372            x -= 1
373            continue
374        j = 0
375        while j < nslabspmb:
376            sl = addressof(slg.slg_slab[j])
377            obj = sl.sl_base
378            # Ignore slabs with a single chunk
379            # since that's unlikely to contain an mbuf
380            # (more likely a cluster).
381            if sl.sl_chunks > 1:
382                z = 0
383                c = sl.sl_len // sl.sl_chunks
384
385                while z < sl.sl_chunks:
386                    obj = kern.GetValueFromAddress(sl.sl_base + c * z)
387                    mbuf = cast(obj, 'struct mbuf *')
388                    MbufDecode(mbuf, decode_pkt)
389                    z += 1
390            j += 1
391        x -= 1
392
393# EndMacro: mbuf_walk_slabs
394
395def GetMbufMcaPtr(m, cl):
396    pgshift = int(kern.globals.page_shift)
397    ix = int((m - Cast(kern.globals.mbutl, 'char *')) >> pgshift)
398    page_addr = (Cast(kern.globals.mbutl, 'char *') + (ix << pgshift))
399
400
401    if (int(cl) == 0):
402        midx = int((m - page_addr) >> 8)
403        mca = kern.globals.mclaudit[ix].cl_audit[midx]
404    elif (int(cl) == 1):
405        midx = int((m - page_addr) >> 11)
406        mca = kern.globals.mclaudit[ix].cl_audit[midx]
407    elif (int(cl) == 2):
408        midx = int((m - page_addr) >> 12)
409        mca = kern.globals.mclaudit[ix].cl_audit[midx]
410    else:
411        mca = kern.globals.mclaudit[ix].cl_audit[0]
412    return Cast(mca, 'mcache_audit_t *')
413
414def GetMbufSlab(m):
415    pgshift = int(kern.globals.page_shift)
416    gix = int((Cast(m, 'char *') - Cast(kern.globals.mbutl, 'char *')) >> MBSHIFT)
417    slabstbl = kern.globals.slabstbl
418    ix = int((Cast(m, 'char *') - Cast(slabstbl[gix].slg_slab[0].sl_base, 'char *')) >> pgshift)
419    return addressof(slabstbl[gix].slg_slab[ix])
420
421def GetMbufBuf2Mca(m):
422    sl = GetMbufSlab(m)
423    mca = GetMbufMcaPtr(m, sl.sl_class)
424    return str(mca)
425
426def GetMbufWalkAllSlabs(show_a, show_f, show_tr):
427    out_string = ""
428
429    kern.globals.slabstbl[0]
430
431    x = 0
432    total = 0
433    total_a = 0
434    total_f = 0
435
436    if (show_a and not(show_f)):
437        out_string += "Searching only for active... \n"
438    if (not(show_a) and show_f):
439        out_string += "Searching only for inactive... \n"
440    if (show_a and show_f):
441        out_string += "Displaying all... \n"
442
443    if (kern.ptrsize == 8):
444        show_mca_string_format = "{0:>4s} {1:>4s} {2:>16s} {3:>16s} {4:>16} {5:>12s} {6:12s}"
445        out_string += show_mca_string_format.format("slot", "idx", "slab address", "mca address", "obj address", "type", "allocation state\n")
446    else:
447        show_mca_string_format = "{0:4s} {1:4s} {2:8s} {3:8s} {4:8} {5:12s} {6:12s}"
448        out_string += show_mca_string_format.format("slot", "idx", "slab address", "mca address", "obj address", "type", "allocation state\n")
449
450    nslabspmb = unsigned((1 << MBSHIFT) >> unsigned(kern.globals.page_shift))
451    while (x < unsigned(kern.globals.slabgrp)):
452        slg = kern.globals.slabstbl[x]
453        y = 0
454        while (y < nslabspmb):
455            sl = addressof(slg.slg_slab[y])
456            base = sl.sl_base
457            if (base == 0):
458                break
459
460            mca = GetMbufMcaPtr(base, sl.sl_class)
461            first = 1
462
463            while ((Cast(mca, 'int') != 0) and (unsigned(mca.mca_addr) != 0)):
464                printmca = 0
465                if (mca.mca_uflags & (MB_INUSE | MB_COMP_INUSE)):
466                    total_a = total_a + 1
467                    printmca = show_a
468                    if (show_tr > 2) and (mca.mca_uflags & MB_SCVALID) == 0:
469                        printmca = 0
470                else:
471                    total_f = total_f + 1
472                    printmca = show_f
473
474                if (printmca != 0):
475                    if (first == 1):
476                        if (kern.ptrsize == 8):
477                            mca_string_format = "{0:4d} {1:4d} 0x{2:16x} "
478                            out_string += mca_string_format.format(x, y, sl)
479                        else:
480                            mca_string_format = "{0:4d} {1:4d} 0x{02:8x} "
481                            out_string += mca_string_format.format(x, y, sl)
482                    else:
483                        if (kern.ptrsize == 8):
484                            out_string += "                             "
485                        else:
486                            out_string += "                     "
487
488                    if (kern.ptrsize == 8):
489                        mca_string_format = "0x{0:16x} 0x{1:16x}"
490                        out_string += mca_string_format.format(mca, mca.mca_addr)
491                    else:
492                        mca_string_format = "0x{0:8x} 0x{1:8x}"
493                        out_string += mca_string_format.format(mca, mca.mca_addr)
494
495                    out_string += GetMbufMcaCtype(mca, 0)
496
497                    if (mca.mca_uflags & (MB_INUSE | MB_COMP_INUSE)):
498                        out_string += "active        "
499                    else:
500                        out_string += "       freed "
501                    if (show_tr > 1) and (mca.mca_uflags & MB_SCVALID):
502                        m = Cast(mca.mca_addr, 'struct mbuf *')
503                        mbuf_string = GetMbufFlags(m)
504                        mbuf_string += " " + GetMbufPktCrumbs(m)
505                        if (mbuf_string != ""):
506                            if (kern.ptrsize == 8):
507                                out_string += "\n                              " + mbuf_string
508                            else:
509                                out_string += "\n                      " + mbuf_string
510                    if (first == 1):
511                        first = 0
512
513                    out_string += "\n"
514                    total = total + 1
515
516                    if (show_tr != 0):
517                        if (mca.mca_next_trn == 0):
518                            trn = 1
519                        else:
520                            trn = 0
521                        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"
522                        cnt = 0
523                        while (cnt < mca.mca_trns[int(trn)].mca_depth):
524                            kgm_pc = mca.mca_trns[int(trn)].mca_stack[int(cnt)]
525                            out_string += str(int(cnt) + 1) + " "
526                            out_string += GetPc(kgm_pc)
527                            cnt += 1
528
529                    print(out_string)
530                    out_string = ""
531                mca = mca.mca_next
532
533            y += 1
534
535        x += 1
536
537    if (total and show_a and show_f):
538        out_string += "total objects = " + str(int(total)) + "\n"
539        out_string += "active/unfreed objects = " + str(int(total_a)) + "\n"
540        out_string += "freed/in_cache objects = " + str(int(total_f)) + "\n"
541
542    return out_string
543
544def GetMbufFlagsAsString(mbuf_flags):
545    flags = (unsigned)(mbuf_flags & 0xff)
546    out_string = ""
547    i = 0
548    num = 1
549    while num <= flags:
550        if flags & num:
551            out_string += mbuf_flags_strings[i] + ","
552        i += 1
553        num = num << 1
554    return out_string.rstrip(",")
555
556def GetMbufFlags(m):
557    out_string = ""
558    if (m != 0):
559        out_string += "m_flags: " + hex(m.m_hdr.mh_flags)
560        if (m.m_hdr.mh_flags != 0):
561             out_string += " " + GetMbufFlagsAsString(m.m_hdr.mh_flags)
562    return out_string
563
564# Macro: mbuf_show_m_flags
565@lldb_command('mbuf_show_m_flags')
566def MbufShowFlags(cmd_args=None):
567    """ Return a formatted string description of the mbuf flags
568    """
569    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
570    print(GetMbufFlags(m))
571
572def GetMbufPktCrumbsAsString(mbuf_crumbs):
573    flags = (unsigned)(mbuf_crumbs & 0xffff)
574    out_string = ""
575    i = 0
576    num = 1
577    while num <= flags:
578        if flags & num:
579            out_string += mbuf_pkt_crumb_strings[i] + ","
580        i += 1
581        num = num << 1
582    return out_string.rstrip(",")
583
584def GetMbufPktCrumbs(m):
585    out_string = ""
586    if (m != 0):
587        if (m.m_hdr.mh_flags & M_PKTHDR) != 0:
588            flags = m.M_dat.MH.MH_pkthdr.pkt_crumbs
589            out_string += "pkt_crumbs: 0x{0:x}".format(flags)
590            if (flags != 0):
591                out_string += " " + GetMbufPktCrumbsAsString(flags)
592    return out_string
593
594# Macro: mbuf_showpktcrumbs
595@lldb_command('mbuf_showpktcrumbs')
596def MbufShowPktCrumbs(cmd_args=None):
597    """ Print the packet crumbs of an mbuf object mca
598    """
599    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
600    print(GetMbufPktCrumbs(m))
601
602def GetMbufMcaCtype(mca, vopt):
603    cp = mca.mca_cache
604    mca_class = unsigned(cp.mc_private)
605    csize = unsigned(kern.globals.mbuf_table[mca_class].mtbl_stats.mbcl_size)
606    done = 0
607    out_string = "    "
608    if (csize == MSIZE):
609        if (vopt):
610            out_string += "M (mbuf) "
611        else:
612            out_string += "M     "
613        return out_string
614    if (csize == MCLBYTES):
615        if (vopt):
616            out_string += "CL (2K cluster) "
617        else:
618            out_string += "CL     "
619        return out_string
620    if (csize == MBIGCLBYTES):
621        if (vopt):
622            out_string += "BCL (4K cluster) "
623        else:
624            out_string += "BCL     "
625        return out_string
626    if (csize == M16KCLBYTES):
627        if (vopt):
628            out_string += "JCL (16K cluster) "
629        else:
630            out_string += "JCL     "
631        return out_string
632
633    if (csize == (MSIZE + MCLBYTES)):
634        if (mca.mca_uflags & MB_SCVALID):
635            if (mca.mca_uptr):
636                out_string += "M+CL  "
637                if vopt:
638                    out_string += "(paired mbuf, 2K cluster) "
639            else:
640                out_string += "M-CL  "
641                if vopt:
642                    out_string += "(unpaired mbuf, 2K cluster) "
643        else:
644            if (mca.mca_uptr):
645                out_string += "CL+M  "
646                if vopt:
647                    out_string += "(paired 2K cluster, mbuf) "
648            else:
649                out_string += "CL-M  "
650                if vopt:
651                    out_string += "(unpaired 2K cluster, mbuf) "
652        return out_string
653
654    if (csize == (MSIZE + MBIGCLBYTES)):
655        if (mca.mca_uflags & MB_SCVALID):
656            if (mca.mca_uptr):
657                out_string += "M+BCL  "
658                if vopt:
659                    out_string += "(paired mbuf, 4K cluster) "
660            else:
661                out_string += "M-BCL  "
662                if vopt:
663                    out_string += "(unpaired mbuf, 4K cluster) "
664        else:
665            if (mca.mca_uptr):
666                out_string += "BCL+M  "
667                if vopt:
668                    out_string += "(paired 4K cluster, mbuf) "
669            else:
670                out_string += "BCL-m  "
671                if vopt:
672                    out_string += "(unpaired 4K cluster, mbuf) "
673        return out_string
674
675    if (csize == (MSIZE + M16KCLBYTES)):
676        if (mca.mca_uflags & MB_SCVALID):
677            if (mca.mca_uptr):
678                out_string += "M+BCL  "
679                if vopt:
680                    out_string += "(paired mbuf, 4K cluster) "
681            else:
682                out_string += "M-BCL  "
683                if vopt:
684                    out_string += "(unpaired mbuf, 4K cluster) "
685        else:
686            if (mca.mca_uptr):
687                out_string += "BCL+M  "
688                if vopt:
689                    out_string += "(paired 4K cluster, mbuf) "
690            else:
691                out_string += "BCL-m  "
692                if vopt:
693                    out_string += "(unpaired 4K cluster, mbuf) "
694        return out_string
695
696    out_string += "unknown: " + cp.mc_name
697    return out_string
698
699
700def GetPointerAsString(kgm_pc):
701    if (kern.ptrsize == 8):
702        pointer_format_string = "0x{0:<16x} "
703    else:
704        pointer_format_string = "0x{0:<8x} "
705    return pointer_format_string.format(kgm_pc)
706
707def GetPc(kgm_pc):
708    out_string = GetSourceInformationForAddress(unsigned(kgm_pc)) + "\n"
709    return out_string
710
711
712# Macro: mbuf_showactive
713@lldb_command('mbuf_showactive')
714def MbufShowActive(cmd_args=None):
715    """ Print all active/in-use mbuf objects
716        Pass 1 to show the most recent transaction stack trace
717        Pass 2 to also display the mbuf flags and packet crumbs
718        Pass 3 to limit display to mbuf and skip cluaters
719    """
720    if cmd_args:
721        print(GetMbufWalkAllSlabs(1, 0, ArgumentStringToInt(cmd_args[0])))
722    else:
723        print(GetMbufWalkAllSlabs(1, 0, 0))
724# EndMacro: mbuf_showactive
725
726
727# Macro: mbuf_showinactive
728@lldb_command('mbuf_showinactive')
729def MbufShowInactive(cmd_args=None):
730    """ Print all freed/in-cache mbuf objects
731    """
732    print(GetMbufWalkAllSlabs(0, 1, 0))
733# EndMacro: mbuf_showinactive
734
735
736# Macro: mbuf_showmca
737@lldb_command('mbuf_showmca')
738def MbufShowMca(cmd_args=None):
739    """ Print the contents of an mbuf mcache audit structure
740    """
741    out_string = ""
742    pgshift = unsigned(kern.globals.page_shift)
743    if cmd_args:
744        mca = kern.GetValueFromAddress(cmd_args[0], 'mcache_audit_t *')
745        cp = mca.mca_cache
746        out_string += "object type:\t"
747        out_string += GetMbufMcaCtype(mca, 1)
748        out_string += "\nControlling mcache :\t" + hex(mca.mca_cache) + " (" + str(cp.mc_name) + ")\n"
749        if (mca.mca_uflags & MB_INUSE):
750            out_string += " inuse"
751        if (mca.mca_uflags & MB_COMP_INUSE):
752            out_string += " comp_inuse"
753        if (mca.mca_uflags & MB_SCVALID):
754            out_string += " scvalid"
755        out_string += "\n"
756        if (mca.mca_uflags & MB_SCVALID):
757            mbutl = Cast(kern.globals.mbutl, 'unsigned char *')
758            ix = (mca.mca_addr - mbutl) >> pgshift
759            clbase = mbutl + (ix << pgshift)
760            mclidx = (mca.mca_addr - clbase) >> 8
761            out_string += "mbuf obj :\t\t" + hex(mca.mca_addr) + "\n"
762            out_string += "mbuf index :\t\t" + str(mclidx + 1) + " (out of 16) in cluster base " + hex(clbase) + "\n"
763            if (int(mca.mca_uptr) != 0):
764                peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *')
765                out_string += "paired cluster obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n"
766            out_string += "saved contents :\t" + hex(mca.mca_contents) + " (" + str(int(mca.mca_contents_size)) + " bytes)\n"
767        else:
768            out_string += "cluster obj :\t\t" + hex(mca.mca_addr) + "\n"
769            if (mca.mca_uptr != 0):
770                peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *')
771                out_string += "paired mbuf obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n"
772
773        for idx in range(unsigned(kern.globals.mca_trn_max), 0, -1):
774                trn = (mca.mca_next_trn + idx - 1) % unsigned(kern.globals.mca_trn_max)
775                out_string += "transaction {:d} (tstamp {:d}, thread 0x{:x}):\n".format(trn, mca.mca_trns[trn].mca_tstamp, mca.mca_trns[trn].mca_thread)
776                cnt = 0
777                while (cnt < mca.mca_trns[trn].mca_depth):
778                    kgm_pc = mca.mca_trns[trn].mca_stack[cnt]
779                    out_string += "  " + str(cnt + 1) + ".  "
780                    out_string += GetPc(kgm_pc)
781                    cnt += 1
782
783        msc = cast(mca.mca_contents, 'mcl_saved_contents_t *')
784        msa = addressof(msc.sc_scratch)
785        if (mca.mca_uflags & MB_SCVALID):
786            if (msa.msa_depth > 0):
787                out_string += "Recent scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_tstamp, msa.msa_thread)
788                cnt = 0
789                while (cnt < msa.msa_depth):
790                    kgm_pc = msa.msa_stack[cnt]
791                    out_string += "  " + str(cnt + 1) + ".  "
792                    out_string += GetPc(kgm_pc)
793                    cnt += 1
794
795            if (msa.msa_pdepth > 0):
796                out_string += "previous scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_ptstamp, msa.msa_pthread)
797        if (msa):
798            cnt = 0
799            while (cnt < msa.msa_pdepth):
800                kgm_pc = msa.msa_pstack[cnt]
801                out_string += "  " + str(cnt + 1) + ".  "
802                out_string += GetPc(kgm_pc)
803                cnt += 1
804    else:
805        out_string += "Missing argument 0 in user function."
806
807    print(out_string)
808# EndMacro: mbuf_showmca
809
810
811# Macro: mbuf_showall
812@lldb_command('mbuf_showall')
813def MbufShowAll(cmd_args=None):
814    """ Print all mbuf objects
815    """
816    print(GetMbufWalkAllSlabs(1, 1, 1))
817# EndMacro: mbuf_showall
818
819# Macro: mbuf_countchain
820@lldb_command('mbuf_countchain')
821def MbufCountChain(cmd_args=None):
822    """ Count the length of an mbuf chain
823    """
824    if not cmd_args:
825        raise ArgumentError("Missing argument 0 in user function.")
826
827    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
828
829    pkt = 0
830    nxt = 0
831
832    while (mp):
833        pkt = pkt + 1
834        mn = mp.m_hdr.mh_next
835        while (mn):
836            nxt = nxt + 1
837            mn = mn.m_hdr.mh_next
838
839        mp = mp.m_hdr.mh_nextpkt
840
841        if (((pkt + nxt) % 50) == 0):
842            print(" ..." + str(pkt_nxt))
843
844    print("Total: " + str(pkt + nxt) + " (via m_next: " + str(nxt) + ")")
845# EndMacro: mbuf_countchain
846
847# Macro: mbuf_topleak
848@lldb_command('mbuf_topleak')
849def MbufTopLeak(cmd_args=None):
850    """ Print the top suspected mbuf leakers
851    """
852    topcnt = 0
853    if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5):
854        maxcnt = cmd_args[0]
855    else:
856        maxcnt = 5
857    while (topcnt < maxcnt):
858        print(GetMbufTraceLeak(kern.globals.mleak_top_trace[topcnt]))
859        topcnt += 1
860
861# EndMacro: mbuf_topleak
862
863def GetMbufTraceLeak(trace):
864    out_string = ""
865    if (trace != 0 and trace.allocs != 0):
866        out_string += hex(trace) + ":" + str(trace.allocs) + " outstanding allocs\n"
867        out_string += "Backtrace saved " + str(trace.depth) + " deep\n"
868        if (trace.depth != 0):
869            cnt = 0
870            while (cnt < trace.depth):
871                out_string += str(cnt + 1) + ": "
872                out_string += GetPc(trace.addr[cnt])
873                out_string += "\n"
874                cnt += 1
875    return out_string
876
877@lldb_command('mbuf_largefailures')
878def MbufLargeFailures(cmd_args=None):
879    """ Print the largest allocation failures
880    """
881    topcnt = 0
882    if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5):
883        maxcnt = cmd_args[0]
884    else:
885        maxcnt = 5
886    while (topcnt < maxcnt):
887        trace = kern.globals.mtracelarge_table[topcnt]
888        if (trace.size == 0):
889            topcnt += 1
890            continue
891        print(str(trace.size))
892        if (trace.depth != 0):
893            cnt = 0
894            while (cnt < trace.depth):
895                print(str(cnt + 1) + ": " + GetPc(trace.addr[cnt]))
896                cnt += 1
897        topcnt += 1
898
899
900# Macro: mbuf_traceleak
901@lldb_command('mbuf_traceleak')
902def MbufTraceLeak(cmd_args=None):
903    """ Print the leak information for a given leak address
904        Given an mbuf leak trace (mtrace) structure address, print out the
905        stored information with that trace
906        syntax: (lldb) mbuf_traceleak <addr>
907    """
908    if not cmd_args:
909        raise ArgumentError("Missing argument 0 in user function.")
910
911    trace = kern.GetValueFromAddress(cmd_args[0], 'mtrace *')
912    print(GetMbufTraceLeak(trace))
913# EndMacro: mbuf_traceleak
914
915
916# Macro: mcache_walkobj
917@lldb_command('mcache_walkobj')
918def McacheWalkObject(cmd_args=None):
919    """ Given a mcache object address, walk its obj_next pointer
920    """
921    if not cmd_args:
922        raise ArgumentError("Missing argument 0 in user function.")
923
924    out_string = ""
925    p = kern.GetValueFromAddress(cmd_args[0], 'mcache_obj_t *')
926    cnt = 1
927    total = 0
928    while (p):
929        mcache_object_format = "{0:>4d}: 0x{1:>16x}"
930        out_string += mcache_object_format.format(cnt, p) + "\n"
931        p = p.obj_next
932        cnt += 1
933    print(out_string)
934# EndMacro: mcache_walkobj
935
936# Macro: mcache_stat
937@lldb_command('mcache_stat')
938def McacheStat(cmd_args=None):
939    """ Print all mcaches in the system.
940    """
941    head = kern.globals.mcache_head
942    out_string = ""
943    mc = cast(head.lh_first, 'mcache *')
944    if (kern.ptrsize == 8):
945        mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>20s} {3:>5s} {4:>5s} {5:>20s} {6:>30s} {7:>18s}"
946    else:
947        mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>12s} {3:>5s} {4:>5s} {5:>12s} {6:>30s} {7:>18s}"
948
949    if (kern.ptrsize == 8):
950        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}"
951    else:
952        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}"
953
954    out_string += mcache_stat_format_string.format("cache name", "cache state", "cache addr", "buf size", "buf align", "backing zone", "wait     nowait     failed", "bufs incache")
955    out_string += "\n"
956
957    ncpu = int(kern.globals.ncpu)
958    while mc != 0:
959        bktsize = mc.mc_cpu[0].cc_bktsize
960        cache_state = ""
961        if (mc.mc_flags & MCF_NOCPUCACHE):
962            cache_state = "disabled"
963        else:
964            if (bktsize == 0):
965                cache_state = " offline"
966            else:
967                cache_state = " online"
968        if (mc.mc_slab_zone != 0):
969            backing_zone = mc.mc_slab_zone
970        else:
971            if (kern.ptrsize == 8):
972                backing_zone = "            custom"
973            else:
974                backing_zone = "    custom"
975
976        total = 0
977        total += mc.mc_full.bl_total * bktsize
978        n = 0
979        while(n < ncpu):
980            ccp = mc.mc_cpu[n]
981            if (ccp.cc_objs > 0):
982                total += ccp.cc_objs
983            if (ccp.cc_pobjs > 0):
984                total += ccp.cc_pobjs
985            n += 1
986
987        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)
988        out_string += "\n"
989        mc = cast(mc.mc_list.le_next, 'mcache *')
990    print(out_string)
991# EndMacro: mcache_stat
992
993# Macro: mcache_showcache
994@lldb_command('mcache_showcache')
995def McacheShowCache(cmd_args=None):
996    """Display the number of objects in cache.
997    """
998    out_string = ""
999    cp = kern.GetValueFromAddress(cmd_args[0], 'mcache_t *')
1000    bktsize = cp.mc_cpu[0].cc_bktsize
1001    cnt = 0
1002    total = 0
1003    mcache_cache_format = "{0:<4d} {1:>8d} {2:>8d} {3:>8d}"
1004    out_string += "Showing cache " + str(cp.mc_name) + " :\n\n"
1005    out_string += " CPU  cc_objs cc_pobjs    total\n"
1006    out_string += "----  ------- -------- --------\n"
1007    ncpu = int(kern.globals.ncpu)
1008    while (cnt < ncpu):
1009        ccp = cp.mc_cpu[cnt]
1010        objs = ccp.cc_objs
1011        if (objs <= 0):
1012            objs = 0
1013        pobjs = ccp.cc_pobjs
1014        if (pobjs <= 0):
1015            pobjs = 0
1016        tot_cpu = objs + pobjs
1017        total += tot_cpu
1018        out_string += mcache_cache_format.format(cnt, objs, pobjs, tot_cpu)
1019        out_string += "\n"
1020        cnt += 1
1021
1022    out_string += "                       ========\n"
1023    out_string += "                           " + str(total) + "\n\n"
1024    total += cp.mc_full.bl_total * bktsize
1025
1026    out_string += "Total # of full buckets (" + str(int(bktsize)) + " objs/bkt):\t" + str(int(cp.mc_full.bl_total)) + "\n"
1027    out_string += "Total # of objects cached:\t\t" + str(total) + "\n"
1028    print(out_string)
1029# EndMacro: mcache_showcache
1030
1031# Macro: mbuf_wdlog
1032@lldb_command('mbuf_wdlog')
1033def McacheShowWatchdogLog(cmd_args=None):
1034    """Display the watchdog log
1035    """
1036    lldb_run_command('settings set max-string-summary-length 4096')
1037    print('%s' % lldb_run_command('p/s mbwdog_logging').replace("\\n","\n"))
1038# EndMacro: mbuf_wdlog
1039