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