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