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"""
5
6from xnu import *
7from utils import *
8
9from mbufdefines import *
10import xnudefines
11
12# Macro: mbuf_stat
13@lldb_command('mbuf_stat')
14def MBufStat(cmd_args=None):
15    """ Print extended mbuf allocator statistics.
16    """
17    hdr_format = "{0: <16s} {1: >8s} {2: >8s} {3: ^16s} {4: >8s} {5: >12s} {6: >8s} {7: >8s} {8: >8s}"
18    print hdr_format.format('class', 'total', 'cached', 'uncached', 'inuse', 'failed', 'waiter', 'notified', 'purge')
19    print hdr_format.format('name', 'objs', 'objs', 'objs/slabs', 'objs', 'alloc count', 'count', 'count', 'count')
20    print hdr_format.format('-'*16, '-'*8, '-'*8, '-'*16, '-'*8, '-'*12, '-'*8, '-'*8, '-'*8)
21    entry_format = "{0: <16s} {1: >8d} {2: >8d} {3:>7d} / {4:<6d} {5: >8d} {6: >12d} {7: >8d} {8: >8d} {9: >8d}"
22    num_items = sizeof(kern.globals.mbuf_table) / sizeof(kern.globals.mbuf_table[0])
23    ncpus = int(kern.globals.ncpu)
24    for i in range(num_items):
25        mbuf = kern.globals.mbuf_table[i]
26        mcs = Cast(mbuf.mtbl_stats, 'mb_class_stat_t *')
27        mc = mbuf.mtbl_cache
28        total = 0
29        total += int(mc.mc_full.bl_total) * int(mc.mc_cpu[0].cc_bktsize)
30        ccp_arr = mc.mc_cpu
31        for i in range(ncpus):
32            ccp = ccp_arr[i]
33            if int(ccp.cc_objs) > 0:
34                total += int(ccp.cc_objs)
35            if int(ccp.cc_pobjs) > 0:
36                total += int(ccp.cc_pobjs)
37        print entry_format.format(mcs.mbcl_cname, mcs.mbcl_total,  total,
38                                  mcs.mbcl_infree, mcs.mbcl_slab_cnt,
39                                  (mcs.mbcl_total - total - mcs.mbcl_infree),
40                                  mcs.mbcl_fail_cnt, mbuf.mtbl_cache.mc_waiter_cnt,
41                                  mcs.mbcl_notified, mcs.mbcl_purge_cnt
42                                  )
43# EndMacro: mbuf_stat
44
45# Macro: mbuf_walk_mleak_traces
46@lldb_command('mbuf_walk_mleak_traces')
47def MbufWalkMleakTraces(cmd_args=None):
48    """ Print mleak_traces
49    """
50    i = 0
51    while (i<256):
52        trace = kern.globals.mleak_traces[i]
53        out_string = ""
54        if (trace.allocs != 0):
55            print "Index: " + str(i)
56            out_string += ":" + str(trace.allocs) + " outstanding allocs\n"
57            out_string += str(trace.hitcount) + " hitcount\n"
58            out_string += str(trace.collisions) + " collisions\n"
59            out_string += "Backtrace saved " + str(trace.depth) + " deep\n"
60            if (trace.depth != 0):
61                cnt = 0
62                while (cnt < trace.depth):
63                    out_string += str(cnt + 1) + ": "
64                    out_string += GetPc(trace.addr[cnt])
65                    out_string += "\n"
66                    cnt += 1
67            print out_string
68        i +=1
69# EndMacro: mbuf_walk_mleak_traces
70
71# Macro: mbuf_walkpkt
72@lldb_command('mbuf_walkpkt')
73def MbufWalkPacket(cmd_args=None):
74    """ Walk the mbuf packet chain (m_nextpkt)
75    """
76    if not cmd_args:
77        raise ArgumentError("Missing argument 0 in user function.")
78
79    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
80    cnt = 1
81    tot = 0
82    while (mp):
83        out_string = ""
84        mbuf_walk_packet_format = "{0:4d} 0x{1:x} [len {2:4d}, type {3:2d}, "
85        out_string += mbuf_walk_packet_format.format(cnt, mp, mp.m_hdr.mh_len, mp.m_hdr.mh_type)
86        if (kern.globals.mclaudit != 0):
87            out_string += GetMbufBuf2Mca(mp) + ", "
88        tot = tot + mp.m_hdr.mh_len
89        out_string += "total " + str(tot) + "]"
90        print out_string
91        mp = mp.m_hdr.mh_nextpkt
92        cnt += 1
93# EndMacro: mbuf_walkpkt
94
95# Macro: mbuf_walk
96@lldb_command('mbuf_walk')
97def MbufWalk(cmd_args=None):
98    """ Walk the mbuf chain (m_next)
99    """
100    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
101    cnt = 1
102    tot = 0
103    while (mp):
104        out_string = ""
105        mbuf_walk_format = "{0:4d} 0x{1:x} [len {2:4d}, type {3:2d}, "
106        out_string += mbuf_walk_format.format(cnt, mp, mp.m_hdr.mh_len, mp.m_hdr.mh_type)
107        if (kern.globals.mclaudit != 0):
108            out_string += GetMbufBuf2Mca(mp) + ", "
109        tot = tot + mp.m_hdr.mh_len
110        out_string += "total " + str(tot) + "]"
111        print out_string
112        mp = mp.m_hdr.mh_next
113        cnt += 1
114# EndMacro: mbuf_walk
115
116# Macro: mbuf_buf2slab
117@lldb_command('mbuf_buf2slab')
118def MbufBuf2Slab(cmd_args=None):
119    """ Given an mbuf object, find its corresponding slab address
120    """
121    if not cmd_args:
122        raise ArgumentError("Missing argument 0 in user function.")
123
124    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
125    gix = (m - Cast(kern.globals.mbutl, 'char *')) >> MBSHIFT
126    slabstbl = kern.globals.slabstbl
127    ix = (m - Cast(slabstbl[int(gix)].slg_slab[0].sl_base, 'char *')) >> 12
128    slab = addressof(slabstbl[int(gix)].slg_slab[int(ix)])
129    if (kern.ptrsize == 8):
130        mbuf_slab_format = "0x{0:<16x}"
131        print mbuf_slab_format.format(slab)
132    else:
133        mbuf_slab_format = "0x{0:<8x}"
134        print mbuf_slab_format.format(slab)
135# EndMacro: mbuf_buf2slab
136
137# Macro: mbuf_buf2mca
138@lldb_command('mbuf_buf2mca')
139def MbufBuf2Mca(cmd_args=None):
140    """ Find the mcache audit structure of the corresponding mbuf
141    """
142    m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
143    print GetMbufBuf2Mca(m)
144    return
145# EndMacro: mbuf_buf2mca
146
147# Macro: mbuf_slabs
148@lldb_command('mbuf_slabs')
149def MbufSlabs(cmd_args=None):
150    """ Print all slabs in the group
151    """
152
153    out_string = ""
154    if not cmd_args:
155        raise ArgumentError("Invalid arguments passed.")
156
157    slg = kern.GetValueFromAddress(cmd_args[0], 'mcl_slabg_t *')
158    x = 0
159
160    if (kern.ptrsize == 8):
161        slabs_string_format = "{0:>4d}: 0x{1:16x} 0x{2:16x} 0x{3:16x} {4:4s} {5:20d} {6:3d} {7:3d} {8:3d} {9:3d} {10:>6s} "
162        out_string += "slot slab               next               obj                mca                tstamp     C  R  N   size flags\n"
163        out_string += "---- ------------------ ------------------ ------------------ ------------------ ---------- -- -- -- ------ -----\n"
164    else:
165        slabs_string_format = "{0:>4d}: 0x{1:8x} 0x{2:8x} 0x{3:8x} {4:4s} {5:20d} {6:3d} {7:3d} {8:3d} {9:3d} {10:>6s} "
166        out_string += "slot slab       next       obj        mca        tstamp     C  R  N   size flags\n"
167        out_string += "---- ---------- ---------- ---------- ---------- ---------- -- -- -- ------ -----\n"
168
169    mbutl = cast(kern.globals.mbutl, 'union mbigcluster *')
170    while x < NSLABSPMB:
171        sl = addressof(slg.slg_slab[x])
172        mca = 0
173        obj = sl.sl_base
174        ts = 0
175
176        if (kern.globals.mclaudit != 0):
177            ix = (obj - Cast(kern.globals.mbutl, 'char *')) >> 12
178            clbase = mbutl + (sizeof(dereference(mbutl)) * ix)
179            mclidx = (obj - clbase) >> 8
180            mca = kern.globals.mclaudit[int(ix)].cl_audit[int(mclidx)]
181            trn = (mca.mca_next_trn + kern.globals.mca_trn_max - 1) % kern.globals.mca_trn_max
182            ts = mca.mca_trns[trn].mca_tstamp
183
184        out_string += slabs_string_format.format((x + 1), sl, sl.sl_next, obj, hex(mca), int(ts), int(sl.sl_class), int(sl.sl_refcnt), int(sl.sl_chunks), int(sl.sl_len), hex(sl.sl_flags))
185
186        if (sl.sl_flags != 0):
187            out_string += "<"
188            if sl.sl_flags & SLF_MAPPED:
189                out_string += "mapped"
190            if sl.sl_flags & SLF_PARTIAL:
191                out_string += ",partial"
192            if sl.sl_flags & SLF_DETACHED:
193                out_string += ",detached"
194            out_string += ">"
195        out_string += "\n"
196
197        if sl.sl_chunks > 1:
198            z = 1
199            c = sl.sl_len/sl.sl_chunks
200
201            while z < sl.sl_chunks:
202                obj = sl.sl_base + (c * z)
203                mca = 0
204                ts = 0
205
206                if (kern.globals.mclaudit != 0):
207                    ix = (obj - Cast(kern.globals.mbutl, 'char *')) >> 12
208                    clbase = mbutl + (sizeof(dereference(mbutl)) * ix)
209                    mclidx = (obj - clbase) >> 8
210                    mca = kern.globals.mclaudit[int(ix)].cl_audit[int(mclidx)]
211                    trn = (mca.mca_next_trn + kern.globals.mca_trn_max - 1) % kern.globals.mca_trn_max
212                    ts = mca.mca_trns[trn].mca_tstamp
213
214                if (kern.ptrsize == 8):
215                    out_string += "                                            " + hex(obj) + " " + hex(mca) + "                    " + str(unsigned(ts)) + "\n"
216                else:
217                    out_string += "                            " + hex(obj) + " " + hex(mca) + "           " + str(unsigned(ts)) + "\n"
218
219                z += 1
220        x += 1
221    print out_string
222# EndMacro: mbuf_slabs
223
224# Macro: mbuf_slabstbl
225@lldb_command('mbuf_slabstbl')
226def MbufSlabsTbl(cmd_args=None):
227    """ Print slabs table
228    """
229    out_string = ""
230    x = 0
231
232    if (kern.ptrsize == 8):
233        out_string += "slot slabg              slabs range\n"
234        out_string += "---- ------------------ -------------------------------------------\n"
235    else:
236        out_string += "slot slabg      slabs range\n"
237        out_string += "---- ---------- ---------------------------\n"
238
239    slabstbl = kern.globals.slabstbl
240    slabs_table_blank_string_format = "{0:>3d}: - \n"
241    while (x < unsigned(kern.globals.maxslabgrp)):
242        slg = slabstbl[x]
243        if (slg == 0):
244            out_string += slabs_table_blank_string_format.format(x+1)
245        else:
246            if (kern.ptrsize == 8):
247                slabs_table_string_format = "{0:>3d}: 0x{1:16x}  [ 0x{2:16x} - 0x{3:16x} ]\n"
248                out_string += slabs_table_string_format.format(x+1, slg, addressof(slg.slg_slab[0]), addressof(slg.slg_slab[NSLABSPMB-1]))
249            else:
250                slabs_table_string_format = "{0:>3d}: 0x{1:8x}  [ 0x{2:8x} - 0x{3:8x} ]\n"
251                out_string += slabs_table_string_format.format(x+1, slg, addressof(slg.slg_slab[0]), addressof(slg.slg_slab[NSLABSPMB-1]))
252
253        x += 1
254    print out_string
255# EndMacro: mbuf_slabstbl
256
257
258def GetMbufBuf2Mca(m):
259    ix = (m - Cast(kern.globals.mbutl, 'char *')) >> 12
260    #mbutl = Cast(kern.globals.mbutl, 'union mbigcluster *')
261    mbutl = cast(kern.globals.mbutl, 'union mbigcluster *')
262    clbase = mbutl + (sizeof(dereference(mbutl)) * ix)
263    mclidx = (m - clbase) >> 8
264    mca = kern.globals.mclaudit[int(ix)].cl_audit[int(mclidx)]
265    return str(mca)
266
267def GetMbufWalkAllSlabs(show_a, show_f, show_tr):
268    out_string = ""
269
270    kern.globals.slabstbl[0]
271
272    x = 0
273    total = 0
274    total_a = 0
275    total_f = 0
276
277    if (show_a and not(show_f)):
278        out_string += "Searching only for active... \n"
279    if (not(show_a) and show_f):
280        out_string += "Searching only for inactive... \n"
281    if (show_a and show_f):
282        out_string += "Displaying all... \n"
283
284    if (kern.ptrsize == 8):
285        show_mca_string_format = "{0:>4s} {1:>4s} {2:>16s} {3:>16s} {4:>16} {5:>12s} {6:12s}"
286        out_string += show_mca_string_format.format("slot", "idx", "slab address", "mca address", "obj address", "type", "allocation state\n")
287    else:
288        show_mca_string_format = "{0:4s} {1:4s} {2:8s} {3:8s} {4:8} {5:12s} {6:12s}"
289        out_string += show_mca_string_format.format("slot", "idx", "slab address", "mca address", "obj address", "type", "allocation state\n")
290
291    while (x < unsigned(kern.globals.slabgrp)):
292        slg = kern.globals.slabstbl[x]
293        y = 0
294        stop = 0
295        while ((y < NSLABSPMB) and (stop == 0)):
296            sl = addressof(slg.slg_slab[y])
297            base = sl.sl_base
298            mbutl = cast(kern.globals.mbutl, 'union mbigcluster *')
299            ix = (base - mbutl) >> 12
300            clbase = mbutl + (sizeof(dereference(mbutl)) * ix)
301            mclidx = (base - clbase) >> 8
302            mca = kern.globals.mclaudit[int(ix)].cl_audit[int(mclidx)]
303            first = 1
304
305            while ((Cast(mca, 'int') != 0) and (unsigned(mca.mca_addr) != 0)):
306                printmca = 0
307                if (mca.mca_uflags & (MB_INUSE | MB_COMP_INUSE)):
308                    total_a = total_a + 1
309                    printmca = show_a
310                else:
311                    total_f = total_f + 1
312                    printmca = show_f
313
314                if (printmca != 0):
315                    if (first == 1):
316                        if (kern.ptrsize == 8):
317                            mca_string_format = "{0:4d} {1:4d} 0x{2:16x} "
318                            out_string += mca_string_format.format(x, y, sl)
319                        else:
320                            mca_string_format = "{0:4d} {1:4d} 0x{02:8x} "
321                            out_string += mca_string_format.format(x, y, sl)
322                    else:
323                        if (kern.ptrsize == 8):
324                            out_string += "                             "
325                        else:
326                            out_string += "                     "
327
328                    if (kern.ptrsize == 8):
329                        mca_string_format = "0x{0:16x} 0x{1:16x}"
330                        out_string += mca_string_format.format(mca, mca.mca_addr)
331                    else:
332                        mca_string_format = "0x{0:8x} 0x{1:8x}"
333                        out_string += mca_string_format.format(mca, mca.mca_addr)
334
335                    out_string += GetMbufMcaCtype(mca, 0)
336
337                    if (mca.mca_uflags & (MB_INUSE | MB_COMP_INUSE)):
338                        out_string += "active        "
339                    else:
340                        out_string += "       freed "
341                    if (first == 1):
342                        first = 0
343                    out_string += "\n"
344                    total = total + 1
345
346                    if (show_tr != 0):
347                        idx = int(show_tr)
348                        trn = (mca.mca_next_trn + idx - 1) % unsigned(kern.globals.mca_trn_max)
349                        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"
350                        cnt = 0
351                        while (cnt < mca.mca_trns[int(trn)].mca_depth):
352                            kgm_pc = mca.mca_trns[int(trn)].mca_stack[int(cnt)]
353                            out_string += str(int(cnt) + 1) + " "
354                            out_string += GetPc(kgm_pc)
355                            cnt += 1
356
357                    print out_string
358                    out_string = ""
359                mca = mca.mca_next
360
361            y += 1
362            if (slg.slg_slab[int(y)].sl_base == 0):
363                stop = 1
364        x += 1
365
366    if (total and show_a and show_f):
367        out_string += "total objects = " + str(int(total)) + "\n"
368        out_string += "active/unfreed objects = " + str(int(total_a)) + "\n"
369        out_string += "freed/in_cache objects = " + str(int(total_f)) + "\n"
370
371    return out_string
372
373def GetMbufMcaCtype(mca, vopt):
374    cp = mca.mca_cache
375    mca_class = unsigned(cp.mc_private)
376    csize = unsigned(kern.globals.mbuf_table[mca_class].mtbl_stats.mbcl_size)
377    done = 0
378    out_string = "    "
379    if (csize == MSIZE):
380        if (vopt):
381            out_string += "M (mbuf) "
382        else:
383            out_string += "M     "
384        return out_string
385    if (csize == MCLBYTES):
386        if (vopt):
387            out_string += "CL (2K cluster) "
388        else:
389            out_string += "CL     "
390        return out_string
391    if (csize == NBPG):
392        if (vopt):
393            out_string += "BCL (4K cluster) "
394        else:
395            out_string += "BCL     "
396        return out_string
397    if (csize == M16KCLBYTES):
398        if (vopt):
399            out_string += "JCL (16K cluster) "
400        else:
401            out_string += "JCL     "
402        return out_string
403
404    if (csize == (MSIZE + MCLBYTES)):
405        if (mca.mca_uflags & MB_SCVALID):
406            if (mca.mca_uptr):
407                out_string += "M+CL  "
408                if vopt:
409                    out_string += "(paired mbuf, 2K cluster) "
410            else:
411                out_string += "M-CL  "
412                if vopt:
413                    out_string += "(unpaired mbuf, 2K cluster) "
414        else:
415            if (mca.mca_uptr):
416                out_string += "CL+M  "
417                if vopt:
418                    out_string += "(paired 2K cluster, mbuf) "
419            else:
420                out_string += "CL-M  "
421                if vopt:
422                    out_string += "(unpaired 2K cluster, mbuf) "
423        return out_string
424
425    if (csize == (MSIZE + NBPG)):
426        if (mca.mca_uflags & MB_SCVALID):
427            if (mca.mca_uptr):
428                out_string += "M+BCL  "
429                if vopt:
430                    out_string += "(paired mbuf, 4K cluster) "
431            else:
432                out_string += "M-BCL  "
433                if vopt:
434                    out_string += "(unpaired mbuf, 4K cluster) "
435        else:
436            if (mca.mca_uptr):
437                out_string += "BCL+M  "
438                if vopt:
439                    out_string += "(paired 4K cluster, mbuf) "
440            else:
441                out_string += "BCL-m  "
442                if vopt:
443                    out_string += "(unpaired 4K cluster, mbuf) "
444        return out_string
445
446    if (csize == (MSIZE + M16KCLBYTES)):
447        if (mca.mca_uflags & MB_SCVALID):
448            if (mca.mca_uptr):
449                out_string += "M+BCL  "
450                if vopt:
451                    out_string += "(paired mbuf, 4K cluster) "
452            else:
453                out_string += "M-BCL  "
454                if vopt:
455                    out_string += "(unpaired mbuf, 4K cluster) "
456        else:
457            if (mca.mca_uptr):
458                out_string += "BCL+M  "
459                if vopt:
460                    out_string += "(paired 4K cluster, mbuf) "
461            else:
462                out_string += "BCL-m  "
463                if vopt:
464                    out_string += "(unpaired 4K cluster, mbuf) "
465        return out_string
466
467    out_string += "unknown: " + cp.mc_name
468    return out_string
469
470kgm_pkmod = 0
471kgm_pkmodst = 0
472kgm_pkmoden = 0
473
474def GetPointerAsString(kgm_pc):
475    if (kern.ptrsize == 8):
476        pointer_format_string = "0x{0:<16x} "
477    else:
478        pointer_format_string = "0x{0:<8x} "
479    return pointer_format_string.format(kgm_pc)
480
481def GetKmodAddrIntAsString(kgm_pc):
482    global kgm_pkmod
483    global kgm_pkmodst
484    global kgm_pkmoden
485
486    out_string = ""
487    mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16)
488
489    out_string += GetPointerAsString(kgm_pc)
490    if ((unsigned(kgm_pc) >= unsigned(kgm_pkmodst)) and (unsigned(kgm_pc) < unsigned(kgm_pkmoden))):
491            kgm_off = kgm_pc - kgm_pkmodst
492            out_string += "<" + str(Cast(kgm_pkmod, 'kmod_info_t *').name) + " + 0x" + str(kgm_off) + ">"
493    else:
494        kgm_kmodp = kern.globals.kmod
495        if ((kern.arch == 'x86_64') and (long(kgm_pc) >= long(mh_execute_addr))):
496            kgm_kmodp = 0
497
498        while kgm_kmodp:
499            kgm_off = unsigned((kgm_pc - kgm_kmodp.address) & 0x00000000ffffffff)
500            if ((long(kgm_kmodp.address) <= long(kgm_pc)) and (kgm_off) < unsigned(kgm_kmodp.size)):
501                kgm_pkmod = kgm_kmodp
502                kgm_pkmodst = unsigned(kgm_kmodp.address)
503                kgm_pkmoden = unsigned(kgm_pkmodst + kgm_kmodp.size)
504                kgm_kmodp = 0
505            else:
506                kgm_kmodp = kgm_kmodp.next
507    return out_string
508
509def GetPc(kgm_pc):
510    out_string = ""
511    mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16)
512    if (unsigned(kgm_pc) < unsigned(mh_execute_addr) or unsigned(kgm_pc) >= unsigned(kern.globals.vm_kernel_top)):
513        out_string += GetKmodAddrIntAsString(kgm_pc)
514    else:
515        out_string += GetSourceInformationForAddress(int(kgm_pc))
516    return out_string + "\n"
517
518
519# Macro: mbuf_showactive
520@lldb_command('mbuf_showactive')
521def MbufShowActive(cmd_args=None):
522    """ Print all active/in-use mbuf objects
523    """
524    if cmd_args:
525        print GetMbufWalkAllSlabs(1, 0, cmd_args[0])
526    else:
527        print GetMbufWalkAllSlabs(1, 0, 0)
528# EndMacro: mbuf_showactive
529
530
531# Macro: mbuf_showinactive
532@lldb_command('mbuf_showinactive')
533def MbufShowInactive(cmd_args=None):
534    """ Print all freed/in-cache mbuf objects
535    """
536    print GetMbufWalkAllSlabs(0, 1, 0)
537# EndMacro: mbuf_showinactive
538
539
540# Macro: mbuf_showmca
541@lldb_command('mbuf_showmca')
542def MbufShowMca(cmd_args=None):
543    """ Print the contents of an mbuf mcache audit structure
544    """
545    out_string = ""
546    if cmd_args:
547        mca = kern.GetValueFromAddress(cmd_args[0], 'mcache_audit_t *')
548        cp = mca.mca_cache
549        out_string += "object type:\t"
550        out_string += GetMbufMcaCtype(mca, 1)
551        out_string += "\nControlling mcache :\t" + hex(mca.mca_cache) + " (" + str(cp.mc_name) + ")\n"
552        if (mca.mca_uflags & MB_SCVALID):
553            mbutl = cast(kern.globals.mbutl, 'union mbigcluster *')
554            ix = (mca.mca_addr - mbutl) >> 12
555            clbase = mbutl + (sizeof(dereference(mbutl)) * ix)
556            mclidx = (mca.mca_addr - clbase) >> 8
557            out_string += "mbuf obj :\t\t" + hex(mca.mca_addr) + "\n"
558            out_string += "mbuf index :\t\t" + str(mclidx + 1) + " (out of 16) in cluster base " + hex(clbase) + "\n"
559            if (int(mca.mca_uptr) != 0):
560                peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *')
561                out_string += "paired cluster obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n"
562            out_string += "saved contents :\t" + hex(mca.mca_contents) + " (" + str(int(mca.mca_contents_size)) + " bytes)\n"
563        else:
564            out_string += "cluster obj :\t\t" + hex(mca.mca_addr) + "\n"
565            if (mca.mca_uptr != 0):
566                peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *')
567                out_string += "paired mbuf obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n"
568
569        for idx in range(kern.globals.mca_trn_max, 0, -1):
570                trn = (mca.mca_next_trn + idx - 1) % unsigned(kern.globals.mca_trn_max)
571                out_string += "transaction {:d} (tstamp {:d}, thread 0x{:x}):\n".format(trn, mca.mca_trns[trn].mca_tstamp, mca.mca_trns[trn].mca_thread)
572                cnt = 0
573                while (cnt < mca.mca_trns[trn].mca_depth):
574                    kgm_pc = mca.mca_trns[trn].mca_stack[cnt]
575                    out_string += "  " + str(cnt + 1) + ".  "
576                    out_string += GetPc(kgm_pc)
577                    cnt += 1
578
579        msc = cast(mca.mca_contents, 'mcl_saved_contents_t *')
580        msa = addressof(msc.sc_scratch)
581        if (mca.mca_uflags & MB_SCVALID):
582            if (msa.msa_depth > 0):
583                out_string += "Recent scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_tstamp, msa.msa_thread)
584                cnt = 0
585                while (cnt < msa.msa_depth):
586                    kgm_pc = msa.msa_stack[cnt]
587                    out_string += "  " + str(cnt + 1) + ".  "
588                    out_string += GetPc(kgm_pc)
589                    cnt += 1
590
591            if (msa.msa_pdepth > 0):
592                out_string += "previous scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_ptstamp, msa.msa_pthread)
593        if (msa):
594            cnt = 0
595            while (cnt < msa.msa_pdepth):
596                kgm_pc = msa.msa_pstack[cnt]
597                out_string += "  " + str(cnt + 1) + ".  "
598                out_string += GetPc(kgm_pc)
599                cnt += 1
600    else:
601        out_string += "Missing argument 0 in user function."
602
603    print out_string
604# EndMacro: mbuf_showmca
605
606
607# Macro: mbuf_showall
608@lldb_command('mbuf_showall')
609def MbufShowAll(cmd_args=None):
610    """ Print all mbuf objects
611    """
612    print GetMbufWalkAllSlabs(1, 1, 0)
613# EndMacro: mbuf_showall
614
615# Macro: mbuf_countchain
616@lldb_command('mbuf_countchain')
617def MbufCountChain(cmd_args=None):
618    """ Count the length of an mbuf chain
619    """
620    if not cmd_args:
621        raise ArgumentError("Missing argument 0 in user function.")
622
623    mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *')
624
625    pkt = 0
626    nxt = 0
627
628    while (mp):
629        pkt = pkt + 1
630        mn = mp.m_hdr.mh_next
631        while (mn):
632            nxt = nxt + 1
633            mn = mn.m_hdr.mh_next
634
635        mp = mp.m_hdr.mh_nextpkt
636
637        if (((pkt + nxt) % 50) == 0):
638            print " ..." + str(pkt_nxt)
639
640    print "Total: " + str(pkt + nxt) + " (via m_next: " + str(nxt) + ")"
641# EndMacro: mbuf_countchain
642
643
644
645# Macro: mbuf_topleak
646@lldb_command('mbuf_topleak')
647def MbufTopLeak(cmd_args=None):
648    """ Print the top suspected mbuf leakers
649    """
650    topcnt = 0
651    if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5):
652        maxcnt = cmd_args[0]
653    else:
654        maxcnt = 5
655    while (topcnt < maxcnt):
656        print GetMbufTraceLeak(kern.globals.mleak_top_trace[topcnt])
657        topcnt += 1
658
659# EndMacro: mbuf_topleak
660
661def GetMbufTraceLeak(trace):
662    out_string = ""
663    if (trace.allocs != 0):
664        out_string += hex(trace) + ":" + str(trace.allocs) + " outstanding allocs\n"
665        out_string += "Backtrace saved " + str(trace.depth) + " deep\n"
666        if (trace.depth != 0):
667            cnt = 0
668            while (cnt < trace.depth):
669                out_string += str(cnt + 1) + ": "
670                out_string += GetPc(trace.addr[cnt])
671                out_string += "\n"
672                cnt += 1
673    return out_string
674
675
676# Macro: mbuf_traceleak
677@lldb_command('mbuf_traceleak')
678def MbufTraceLeak(cmd_args=None):
679    """ Print the leak information for a given leak address
680        Given an mbuf leak trace (mtrace) structure address, print out the
681        stored information with that trace
682        syntax: (lldb) mbuf_traceleak <addr>
683    """
684    if not cmd_args:
685        raise ArgumentError("Missing argument 0 in user function.")
686
687    trace = kern.GetValueFromAddress(cmd_args[0], 'mtrace *')
688    print GetMbufTraceLeak(trace)
689# EndMacro: mbuf_traceleak
690
691
692# Macro: mcache_walkobj
693@lldb_command('mcache_walkobj')
694def McacheWalkObject(cmd_args=None):
695    """ Given a mcache object address, walk its obj_next pointer
696    """
697    if not cmd_args:
698        raise ArgumentError("Missing argument 0 in user function.")
699
700    out_string = ""
701    p = kern.GetValueFromAddress(cmd_args[0], 'mcache_obj_t *')
702    cnt = 1
703    total = 0
704    while (p):
705        mcache_object_format = "{0:>4d}: 0x{1:>16x}"
706        out_string += mcache_object_format.format(cnt, p) + "\n"
707        p = p.obj_next
708        cnt += 1
709    print out_string
710# EndMacro: mcache_walkobj
711
712# Macro: mcache_stat
713@lldb_command('mcache_stat')
714def McacheStat(cmd_args=None):
715    """ Print all mcaches in the system.
716    """
717    head = kern.globals.mcache_head
718    out_string = ""
719    mc = cast(head.lh_first, 'mcache *')
720    if (kern.ptrsize == 8):
721        mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>20s} {3:>5s} {4:>5s} {5:>20s} {6:>30s} {7:>18s}"
722    else:
723        mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>12s} {3:>5s} {4:>5s} {5:>12s} {6:>30s} {7:>18s}"
724
725    if (kern.ptrsize == 8):
726        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}"
727    else:
728        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}"
729
730    out_string += mcache_stat_format_string.format("cache name", "cache state", "cache addr", "buf size", "buf align", "backing zone", "wait     nowait     failed", "bufs incache")
731    out_string += "\n"
732
733    ncpu = int(kern.globals.ncpu)
734    while mc != 0:
735        bktsize = mc.mc_cpu[0].cc_bktsize
736        cache_state = ""
737        if (mc.mc_flags & MCF_NOCPUCACHE):
738            cache_state = "disabled"
739        else:
740            if (bktsize == 0):
741                cache_state = " offline"
742            else:
743                cache_state = " online"
744        if (mc.mc_slab_zone != 0):
745            backing_zone = mc.mc_slab_zone
746        else:
747            if (kern.ptrsize == 8):
748                backing_zone = "            custom"
749            else:
750                backing_zone = "    custom"
751
752        total = 0
753        total += mc.mc_full.bl_total * bktsize
754        n = 0
755        while(n < ncpu):
756            ccp = mc.mc_cpu[n]
757            if (ccp.cc_objs > 0):
758                total += ccp.cc_objs
759            if (ccp.cc_pobjs > 0):
760                total += ccp.cc_pobjs
761            n += 1
762            ccp += 1
763
764        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)
765        out_string += "\n"
766        mc = cast(mc.mc_list.le_next, 'mcache *')
767    print out_string
768# EndMacro: mcache_stat
769
770# Macro: mcache_showcache
771@lldb_command('mcache_showcache')
772def McacheShowCache(cmd_args=None):
773    """Display the number of objects in cache.
774    """
775    out_string = ""
776    cp = kern.GetValueFromAddress(cmd_args[0], 'mcache_t *')
777    bktsize = cp.mc_cpu[0].cc_bktsize
778    cnt = 0
779    total = 0
780    mcache_cache_format = "{0:<4d} {1:>8d} {2:>8d} {3:>8d}"
781    out_string += "Showing cache " + str(cp.mc_name) + " :\n\n"
782    out_string += " CPU  cc_objs cc_pobjs    total\n"
783    out_string += "----  ------- -------- --------\n"
784    ncpu = int(kern.globals.ncpu)
785    while (cnt < ncpu):
786        ccp = cp.mc_cpu[cnt]
787        objs = ccp.cc_objs
788        if (objs <= 0):
789            objs = 0
790        pobjs = ccp.cc_pobjs
791        if (pobjs <= 0):
792            pobjs = 0
793        tot_cpu = objs + pobjs
794        total += tot_cpu
795        out_string += mcache_cache_format.format(cnt, objs, pobjs, tot_cpu)
796        out_string += "\n"
797        cnt += 1
798
799    out_string += "                       ========\n"
800    out_string += "                           " + str(total) + "\n\n"
801    total += cp.mc_full.bl_total * bktsize
802
803    out_string += "Total # of full buckets (" + str(int(bktsize)) + " objs/bkt):\t" + str(int(cp.mc_full.bl_total)) + "\n"
804    out_string += "Total # of objects cached:\t\t" + str(total) + "\n"
805    print out_string
806# EndMacro: mcache_showcache
807