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._sbval19k84obscure747.GetValueAsUnsigned() 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