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