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) == 0: 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) == 0: 178 raise ArgumentError() 179 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 cmd_args is None or len(cmd_args) == 0: 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 cmd_args is None or len(cmd_args) == 0: 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 cmd_args is None or len(cmd_args) == 0: 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 cmd_args is None or len(cmd_args) == 0: 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 if cmd_args is None or len(cmd_args) == 0: 742 raise ArgumentError() 743 744 m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *') 745 print(GetMbufFlags(m)) 746 747def GetMbufPktCrumbsAsString(mbuf_crumbs): 748 flags = (unsigned)(mbuf_crumbs & 0xffff) 749 out_string = "" 750 i = 0 751 num = 1 752 while num <= flags: 753 if flags & num: 754 out_string += mbuf_pkt_crumb_strings[i] + "," 755 i += 1 756 num = num << 1 757 return out_string.rstrip(",") 758 759def GetMbufPktCrumbs(m): 760 out_string = "" 761 if (m != 0): 762 if kern.globals.mb_uses_mcache == 1: 763 mhflags = m.m_hdr.mh_flags 764 else: 765 mhflags = m.M_hdr_common.M_hdr.mh_flags 766 if (mhflags & M_PKTHDR) != 0: 767 if kern.globals.mb_uses_mcache == 1: 768 pktcrumbs = m.M_dat.MH.MH_pkthdr.pkt_crumbs 769 else: 770 pktcrumbs = m.M_hdr_common.M_pkthdr.pkt_crumbs 771 out_string += "pkt_crumbs: 0x{0:x}".format(pktcrumbs) 772 if (pktcrumbs != 0): 773 out_string += " " + GetMbufPktCrumbsAsString(pktcrumbs) 774 return out_string 775 776# Macro: mbuf_showpktcrumbs 777@lldb_command('mbuf_showpktcrumbs') 778def MbufShowPktCrumbs(cmd_args=None): 779 """ Print the packet crumbs of an mbuf object mca 780 """ 781 if cmd_args is None or len(cmd_args) == 0: 782 raise ArgumentError() 783 784 m = kern.GetValueFromAddress(cmd_args[0], 'mbuf *') 785 print(GetMbufPktCrumbs(m)) 786 787def GetMbufMcaCtype(mca, vopt): 788 cp = mca.mca_cache 789 mca_class = unsigned(cp.mc_private) 790 csize = unsigned(kern.globals.mbuf_table[mca_class].mtbl_stats.mbcl_size) 791 done = 0 792 out_string = " " 793 if (csize == MSIZE): 794 if (vopt): 795 out_string += "M (mbuf) " 796 else: 797 out_string += "M " 798 return out_string 799 if (csize == MCLBYTES): 800 if (vopt): 801 out_string += "CL (2K cluster) " 802 else: 803 out_string += "CL " 804 return out_string 805 if (csize == MBIGCLBYTES): 806 if (vopt): 807 out_string += "BCL (4K cluster) " 808 else: 809 out_string += "BCL " 810 return out_string 811 if (csize == M16KCLBYTES): 812 if (vopt): 813 out_string += "JCL (16K cluster) " 814 else: 815 out_string += "JCL " 816 return out_string 817 818 if (csize == (MSIZE + MCLBYTES)): 819 if (mca.mca_uflags & MB_SCVALID): 820 if (mca.mca_uptr): 821 out_string += "M+CL " 822 if vopt: 823 out_string += "(paired mbuf, 2K cluster) " 824 else: 825 out_string += "M-CL " 826 if vopt: 827 out_string += "(unpaired mbuf, 2K cluster) " 828 else: 829 if (mca.mca_uptr): 830 out_string += "CL+M " 831 if vopt: 832 out_string += "(paired 2K cluster, mbuf) " 833 else: 834 out_string += "CL-M " 835 if vopt: 836 out_string += "(unpaired 2K cluster, mbuf) " 837 return out_string 838 839 if (csize == (MSIZE + MBIGCLBYTES)): 840 if (mca.mca_uflags & MB_SCVALID): 841 if (mca.mca_uptr): 842 out_string += "M+BCL " 843 if vopt: 844 out_string += "(paired mbuf, 4K cluster) " 845 else: 846 out_string += "M-BCL " 847 if vopt: 848 out_string += "(unpaired mbuf, 4K cluster) " 849 else: 850 if (mca.mca_uptr): 851 out_string += "BCL+M " 852 if vopt: 853 out_string += "(paired 4K cluster, mbuf) " 854 else: 855 out_string += "BCL-m " 856 if vopt: 857 out_string += "(unpaired 4K cluster, mbuf) " 858 return out_string 859 860 if (csize == (MSIZE + M16KCLBYTES)): 861 if (mca.mca_uflags & MB_SCVALID): 862 if (mca.mca_uptr): 863 out_string += "M+BCL " 864 if vopt: 865 out_string += "(paired mbuf, 4K cluster) " 866 else: 867 out_string += "M-BCL " 868 if vopt: 869 out_string += "(unpaired mbuf, 4K cluster) " 870 else: 871 if (mca.mca_uptr): 872 out_string += "BCL+M " 873 if vopt: 874 out_string += "(paired 4K cluster, mbuf) " 875 else: 876 out_string += "BCL-m " 877 if vopt: 878 out_string += "(unpaired 4K cluster, mbuf) " 879 return out_string 880 881 out_string += "unknown: " + cp.mc_name 882 return out_string 883 884 885def GetPointerAsString(kgm_pc): 886 if (kern.ptrsize == 8): 887 pointer_format_string = "0x{0:<16x} " 888 else: 889 pointer_format_string = "0x{0:<8x} " 890 return pointer_format_string.format(kgm_pc) 891 892def GetPc(kgm_pc): 893 out_string = GetSourceInformationForAddress(unsigned(kgm_pc)) + "\n" 894 return out_string 895 896 897def GetMbufWalkZone(show_a, show_f, show_tr): 898 out_string = "" 899 total = 0 900 total_a = 0 901 total_f = 0 902 if (show_a and not(show_f)): 903 out_string += "Searching only for active... \n" 904 if (not(show_a) and show_f): 905 out_string += "Searching only for inactive... \n" 906 if (show_a and show_f): 907 out_string += "Displaying all... \n" 908 f = "{0:>18s} {1:s}\n" 909 out_string += f.format("address", "type flags and crumbs") 910 print(out_string) 911 if show_a: 912 for mbuf_sbv in kmemory.Zone("mbuf").iter_allocated(gettype("mbuf")): 913 mbuf = value(mbuf_sbv.AddressOf()) 914 total_a += 1 915 total += 1 916 mbuf_string = GetMbufFlags(mbuf) 917 mbuf_string += " " + GetMbufType(mbuf) 918 mbuf_string += " " + GetMbufPktCrumbs(mbuf) 919 if mbuf_string != "": 920 out_string = f.format(hex(mbuf), mbuf_string) 921 print(out_string) 922 if show_tr: 923 print(lldb_run_command('kasan whatis {addr}'.format(addr=hex(mbuf)))) 924 if show_f: 925 for mbuf_sbv in kmemory.Zone("mbuf").iter_free(gettype("mbuf")): 926 mbuf = value(mbuf_sbv.AddressOf()) 927 total_f += 1 928 total += 1 929 mbuf_string = GetMbufFlags(mbuf) 930 mbuf_string += " " + GetMbufType(mbuf) 931 mbuf_string += " " + GetMbufPktCrumbs(mbuf) 932 if mbuf_string != "": 933 out_string = f.format(hex(mbuf), mbuf_string) 934 print(out_string) 935 if show_tr: 936 print(lldb_run_command('kasan whatis {addr}'.format(addr=hex(mbuf)))) 937 938 if total and show_a and show_f: 939 out_string += "total objects = " + str(int(total)) + "\n" 940 out_string += "active/unfreed objects = " + str(int(total_a)) + "\n" 941 out_string += "freed/in_cache objects = " + str(int(total_f)) + "\n" 942 print(out_string) 943 944 945# Macro: mbuf_showactive 946@lldb_command('mbuf_showactive') 947def MbufShowActive(cmd_args=None): 948 """ Print all active/in-use mbuf objects 949 Pass 1 to show the most recent transaction stack trace 950 Pass 2 to also display the mbuf flags and packet crumbs 951 Pass 3 to limit display to mbuf and skip clusters 952 """ 953 if int(kern.globals.mb_uses_mcache) == 0: 954 if cmd_args: 955 GetMbufWalkZone(1, 0, ArgumentStringToInt(cmd_args[0])) 956 else: 957 GetMbufWalkZone(1, 0, 0) 958 else: 959 if cmd_args: 960 print(GetMbufWalkAllSlabs(1, 0, ArgumentStringToInt(cmd_args[0]))) 961 else: 962 print(GetMbufWalkAllSlabs(1, 0, 0)) 963# EndMacro: mbuf_showactive 964 965 966# Macro: mbuf_showinactive 967@lldb_command('mbuf_showinactive') 968def MbufShowInactive(cmd_args=None): 969 """ Print all freed/in-cache mbuf objects 970 """ 971 if int(kern.globals.mb_uses_mcache) == 0: 972 GetMbufWalkZone(0, 1, 0) 973 else: 974 print(GetMbufWalkAllSlabs(0, 1, 0)) 975# EndMacro: mbuf_showinactive 976 977# Macro: mbuf_show_type_summary 978@lldb_command('mbuf_show_type_summary') 979def MbufShowTypeSummary(cmd_args=None): 980 """ 981 Print types of all allocated mbufs. 982 Only supported on Apple Silicon. 983 """ 984 types = [0] * 32 985 for mbuf_sbv in kmemory.Zone("mbuf").iter_allocated(gettype("mbuf")): 986 mbuf = value(mbuf_sbv.AddressOf()) 987 mhtype = mbuf.M_hdr_common.M_hdr.mh_type 988 types[mhtype] += 1 989 for mbuf_sbv in kmemory.Zone("mbuf").iter_free(gettype("mbuf")): 990 mbuf = value(mbuf_sbv.AddressOf()) 991 mhtype = mbuf.M_hdr_common.M_hdr.mh_type 992 types[mhtype] += 1 993 994 print("mbuf types allocated and in the caches:") 995 for t in range(len(MBUF_TYPES)): 996 if types[t] != 0: 997 print(MBUF_TYPES[t], types[t]) 998 999# EndMacro: mbuf_show_type_summary 1000 1001 1002# Macro: mbuf_showmca 1003@lldb_command('mbuf_showmca') 1004def MbufShowMca(cmd_args=None): 1005 """ Print the contents of an mbuf mcache audit structure 1006 """ 1007 if int(kern.globals.mb_uses_mcache) == 0: 1008 print("mcache is disabled, use kasan whatis or zstack_findelem") 1009 return 1010 out_string = "" 1011 pgshift = unsigned(kern.globals.page_shift) 1012 if cmd_args: 1013 mca = kern.GetValueFromAddress(cmd_args[0], 'mcache_audit_t *') 1014 cp = mca.mca_cache 1015 out_string += "object type:\t" 1016 out_string += GetMbufMcaCtype(mca, 1) 1017 out_string += "\nControlling mcache :\t" + hex(mca.mca_cache) + " (" + str(cp.mc_name) + ")\n" 1018 if (mca.mca_uflags & MB_INUSE): 1019 out_string += " inuse" 1020 if (mca.mca_uflags & MB_COMP_INUSE): 1021 out_string += " comp_inuse" 1022 if (mca.mca_uflags & MB_SCVALID): 1023 out_string += " scvalid" 1024 out_string += "\n" 1025 if (mca.mca_uflags & MB_SCVALID): 1026 mbutl = Cast(kern.globals.mbutl, 'unsigned char *') 1027 ix = (mca.mca_addr - mbutl) >> pgshift 1028 clbase = mbutl + (ix << pgshift) 1029 mclidx = (mca.mca_addr - clbase) >> 8 1030 out_string += "mbuf obj :\t\t" + hex(mca.mca_addr) + "\n" 1031 out_string += "mbuf index :\t\t" + str(mclidx + 1) + " (out of 16) in cluster base " + hex(clbase) + "\n" 1032 if (int(mca.mca_uptr) != 0): 1033 peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *') 1034 out_string += "paired cluster obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n" 1035 out_string += "saved contents :\t" + hex(mca.mca_contents) + " (" + str(int(mca.mca_contents_size)) + " bytes)\n" 1036 else: 1037 out_string += "cluster obj :\t\t" + hex(mca.mca_addr) + "\n" 1038 if (mca.mca_uptr != 0): 1039 peer_mca = cast(mca.mca_uptr, 'mcache_audit_t *') 1040 out_string += "paired mbuf obj :\t" + hex(peer_mca.mca_addr) + " (mca " + hex(peer_mca) + ")\n" 1041 1042 for idx in range(unsigned(kern.globals.mca_trn_max), 0, -1): 1043 trn = (mca.mca_next_trn + idx - 1) % unsigned(kern.globals.mca_trn_max) 1044 out_string += "transaction {:d} (tstamp {:d}, thread 0x{:x}):\n".format(trn, mca.mca_trns[trn].mca_tstamp, mca.mca_trns[trn].mca_thread) 1045 cnt = 0 1046 while (cnt < mca.mca_trns[trn].mca_depth): 1047 kgm_pc = mca.mca_trns[trn].mca_stack[cnt] 1048 out_string += " " + str(cnt + 1) + ". " 1049 out_string += GetPc(kgm_pc) 1050 cnt += 1 1051 1052 msc = cast(mca.mca_contents, 'mcl_saved_contents_t *') 1053 msa = addressof(msc.sc_scratch) 1054 if (mca.mca_uflags & MB_SCVALID): 1055 if (msa.msa_depth > 0): 1056 out_string += "Recent scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_tstamp, msa.msa_thread) 1057 cnt = 0 1058 while (cnt < msa.msa_depth): 1059 kgm_pc = msa.msa_stack[cnt] 1060 out_string += " " + str(cnt + 1) + ". " 1061 out_string += GetPc(kgm_pc) 1062 cnt += 1 1063 1064 if (msa.msa_pdepth > 0): 1065 out_string += "previous scratch transaction (tstamp {:d}, thread 0x{:x}):\n".format(msa.msa_ptstamp, msa.msa_pthread) 1066 if (msa): 1067 cnt = 0 1068 while (cnt < msa.msa_pdepth): 1069 kgm_pc = msa.msa_pstack[cnt] 1070 out_string += " " + str(cnt + 1) + ". " 1071 out_string += GetPc(kgm_pc) 1072 cnt += 1 1073 else: 1074 out_string += "Missing argument 0 in user function." 1075 1076 print(out_string) 1077# EndMacro: mbuf_showmca 1078 1079 1080# Macro: mbuf_showall 1081@lldb_command('mbuf_showall') 1082def MbufShowAll(cmd_args=None): 1083 """ Print all mbuf objects 1084 """ 1085 if int(kern.globals.mb_uses_mcache) == 0: 1086 GetMbufWalkZone(1, 1, 1) 1087 else: 1088 print(GetMbufWalkAllSlabs(1, 1, 1)) 1089# EndMacro: mbuf_showall 1090 1091# Macro: mbuf_countchain 1092@lldb_command('mbuf_countchain') 1093def MbufCountChain(cmd_args=None): 1094 """ Count the length of an mbuf chain 1095 """ 1096 if cmd_args is None or len(cmd_args) == 0: 1097 raise ArgumentError("Missing argument 0 in user function.") 1098 1099 mp = kern.GetValueFromAddress(cmd_args[0], 'mbuf *') 1100 1101 pkt = 0 1102 nxt = 0 1103 1104 while (mp): 1105 pkt = pkt + 1 1106 if kern.globals.mb_uses_mcache == 1: 1107 mn = mp.m_hdr.mh_next 1108 else: 1109 mn = mp.M_hdr_common.M_hdr.mh_next 1110 while (mn): 1111 nxt = nxt + 1 1112 if kern.globals.mb_uses_mcache == 1: 1113 mn = mn.m_hdr.mh_next 1114 else: 1115 mn = mn.M_hdr_common.M_hdr.mh_next 1116 print("mp 0x{:x} mn 0x{:x}".format(mp, mn)) 1117 1118 if kern.globals.mb_uses_mcache == 1: 1119 mp = mp.m_hdr.mh_nextpkt 1120 else: 1121 mp = mp.M_hdr_common.M_hdr.mh_nextpkt 1122 1123 if (((pkt + nxt) % 50) == 0): 1124 print(" ..." + str(pkt_nxt)) 1125 1126 print("Total: " + str(pkt + nxt) + " (via m_next: " + str(nxt) + ")") 1127# EndMacro: mbuf_countchain 1128 1129# Macro: mbuf_topleak 1130@lldb_command('mbuf_topleak') 1131def MbufTopLeak(cmd_args=None): 1132 """ Print the top suspected mbuf leakers 1133 """ 1134 if int(kern.globals.mb_uses_mcache) == 0: 1135 print("mcache is disabled, use zleak") 1136 return 1137 topcnt = 0 1138 if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5): 1139 maxcnt = cmd_args[0] 1140 else: 1141 maxcnt = 5 1142 while (topcnt < maxcnt): 1143 print(GetMbufTraceLeak(kern.globals.mleak_top_trace[topcnt])) 1144 topcnt += 1 1145 1146# EndMacro: mbuf_topleak 1147 1148def GetMbufTraceLeak(trace): 1149 out_string = "" 1150 if (trace != 0 and trace.allocs != 0): 1151 out_string += hex(trace) + ":" + str(trace.allocs) + " outstanding allocs\n" 1152 out_string += "Backtrace saved " + str(trace.depth) + " deep\n" 1153 if (trace.depth != 0): 1154 cnt = 0 1155 while (cnt < trace.depth): 1156 out_string += str(cnt + 1) + ": " 1157 out_string += GetPc(trace.addr[cnt]) 1158 out_string += "\n" 1159 cnt += 1 1160 return out_string 1161 1162@lldb_command('mbuf_largefailures') 1163def MbufLargeFailures(cmd_args=None): 1164 """ Print the largest allocation failures 1165 """ 1166 if int(kern.globals.mb_uses_mcache) == 0: 1167 print("mcache is disabled, this macro is not available. use zleak to detect leaks") 1168 return 1169 topcnt = 0 1170 if (int(len(cmd_args)) > 0 and int(cmd_args[0]) < 5): 1171 maxcnt = cmd_args[0] 1172 else: 1173 maxcnt = 5 1174 while (topcnt < maxcnt): 1175 trace = kern.globals.mtracelarge_table[topcnt] 1176 if (trace.size == 0): 1177 topcnt += 1 1178 continue 1179 print(str(trace.size)) 1180 if (trace.depth != 0): 1181 cnt = 0 1182 while (cnt < trace.depth): 1183 print(str(cnt + 1) + ": " + GetPc(trace.addr[cnt])) 1184 cnt += 1 1185 topcnt += 1 1186 1187 1188# Macro: mbuf_traceleak 1189@lldb_command('mbuf_traceleak') 1190def MbufTraceLeak(cmd_args=None): 1191 """ Print the leak information for a given leak address 1192 Given an mbuf leak trace (mtrace) structure address, print out the 1193 stored information with that trace 1194 syntax: (lldb) mbuf_traceleak <addr> 1195 """ 1196 if cmd_args is None or len(cmd_args) == 0: 1197 raise ArgumentError("Missing argument 0 in user function.") 1198 1199 if int(kern.globals.mb_uses_mcache) == 0: 1200 print("mcache is disabled, use kasan whatis") 1201 return 1202 1203 trace = kern.GetValueFromAddress(cmd_args[0], 'mtrace *') 1204 print(GetMbufTraceLeak(trace)) 1205# EndMacro: mbuf_traceleak 1206 1207 1208# Macro: mcache_walkobj 1209@lldb_command('mcache_walkobj') 1210def McacheWalkObject(cmd_args=None): 1211 """ Given a mcache object address, walk its obj_next pointer 1212 """ 1213 if cmd_args is None or len(cmd_args) == 0: 1214 raise ArgumentError("Missing argument 0 in user function.") 1215 1216 if int(kern.globals.mb_uses_mcache) == 0: 1217 print("mcache is disabled, use kasan whatis") 1218 return 1219 1220 out_string = "" 1221 p = kern.GetValueFromAddress(cmd_args[0], 'mcache_obj_t *') 1222 cnt = 1 1223 total = 0 1224 while (p): 1225 mcache_object_format = "{0:>4d}: 0x{1:>16x}" 1226 out_string += mcache_object_format.format(cnt, p) + "\n" 1227 p = p.obj_next 1228 cnt += 1 1229 print(out_string) 1230# EndMacro: mcache_walkobj 1231 1232# Macro: mcache_stat 1233@lldb_command('mcache_stat') 1234def McacheStat(cmd_args=None): 1235 """ Print all mcaches in the system. 1236 """ 1237 if int(kern.globals.mb_uses_mcache) == 0: 1238 print("mcache is disabled, use kasan whatis") 1239 return 1240 1241 head = kern.globals.mcache_head 1242 out_string = "" 1243 mc = cast(head.lh_first, 'mcache *') 1244 if (kern.ptrsize == 8): 1245 mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>20s} {3:>5s} {4:>5s} {5:>20s} {6:>30s} {7:>18s}" 1246 else: 1247 mcache_stat_format_string = "{0:<24s} {1:>8s} {2:>12s} {3:>5s} {4:>5s} {5:>12s} {6:>30s} {7:>18s}" 1248 1249 if (kern.ptrsize == 8): 1250 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}" 1251 else: 1252 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}" 1253 1254 out_string += mcache_stat_format_string.format("cache name", "cache state", "cache addr", "buf size", "buf align", "backing zone", "wait nowait failed", "bufs incache") 1255 out_string += "\n" 1256 1257 ncpu = int(kern.globals.ncpu) 1258 while mc != 0: 1259 bktsize = mc.mc_cpu[0].cc_bktsize 1260 cache_state = "" 1261 if (mc.mc_flags & MCF_NOCPUCACHE): 1262 cache_state = "disabled" 1263 else: 1264 if (bktsize == 0): 1265 cache_state = " offline" 1266 else: 1267 cache_state = " online" 1268 if (mc.mc_slab_zone != 0): 1269 backing_zone = mc.mc_slab_zone 1270 else: 1271 if (kern.ptrsize == 8): 1272 backing_zone = " custom" 1273 else: 1274 backing_zone = " custom" 1275 1276 total = 0 1277 total += mc.mc_full.bl_total * bktsize 1278 n = 0 1279 while(n < ncpu): 1280 ccp = mc.mc_cpu[n] 1281 if (ccp.cc_objs > 0): 1282 total += ccp.cc_objs 1283 if (ccp.cc_pobjs > 0): 1284 total += ccp.cc_pobjs 1285 n += 1 1286 1287 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) 1288 out_string += "\n" 1289 mc = cast(mc.mc_list.le_next, 'mcache *') 1290 print(out_string) 1291# EndMacro: mcache_stat 1292 1293# Macro: mcache_showcache 1294@lldb_command('mcache_showcache') 1295def McacheShowCache(cmd_args=None): 1296 """Display the number of objects in cache. 1297 """ 1298 if int(kern.globals.mb_uses_mcache) == 0: 1299 print("mcache is disabled, use kasan whatis") 1300 return 1301 out_string = "" 1302 cp = kern.GetValueFromAddress(cmd_args[0], 'mcache_t *') 1303 bktsize = cp.mc_cpu[0].cc_bktsize 1304 cnt = 0 1305 total = 0 1306 mcache_cache_format = "{0:<4d} {1:>8d} {2:>8d} {3:>8d}" 1307 out_string += "Showing cache " + str(cp.mc_name) + " :\n\n" 1308 out_string += " CPU cc_objs cc_pobjs total\n" 1309 out_string += "---- ------- -------- --------\n" 1310 ncpu = int(kern.globals.ncpu) 1311 while (cnt < ncpu): 1312 ccp = cp.mc_cpu[cnt] 1313 objs = ccp.cc_objs 1314 if (objs <= 0): 1315 objs = 0 1316 pobjs = ccp.cc_pobjs 1317 if (pobjs <= 0): 1318 pobjs = 0 1319 tot_cpu = objs + pobjs 1320 total += tot_cpu 1321 out_string += mcache_cache_format.format(cnt, objs, pobjs, tot_cpu) 1322 out_string += "\n" 1323 cnt += 1 1324 1325 out_string += " ========\n" 1326 out_string += " " + str(total) + "\n\n" 1327 total += cp.mc_full.bl_total * bktsize 1328 1329 out_string += "Total # of full buckets (" + str(int(bktsize)) + " objs/bkt):\t" + str(int(cp.mc_full.bl_total)) + "\n" 1330 out_string += "Total # of objects cached:\t\t" + str(total) + "\n" 1331 print(out_string) 1332# EndMacro: mcache_showcache 1333 1334# Macro: mbuf_wdlog 1335@lldb_command('mbuf_wdlog') 1336def McacheShowWatchdogLog(cmd_args=None): 1337 """Display the watchdog log 1338 """ 1339 lldb_run_command('settings set max-string-summary-length 4096') 1340 print('%s' % lldb_run_command('p/s mbwdog_logging').replace("\\n","\n")) 1341# EndMacro: mbuf_wdlog 1342