1 2""" Please make sure you read the README file COMPLETELY BEFORE reading anything below. 3 It is very critical that you read coding guidelines in Section E in README file. 4""" 5from typing import Union, Optional 6from xnu import * 7import sys, shlex 8from utils import * 9from core.lazytarget import * 10import time 11import xnudefines 12import kmemory 13import memory 14import json 15 16from collections import defaultdict, namedtuple 17 18NO_PROC_NAME = "unknown" 19P_LHASTASK = 0x00000002 20TF_HASPROC = 0x00800000 21 22THREAD_STATE_CHARS = { 23 0x0: '', 24 0x1: 'W', 25 0x2: 'S', 26 0x4: 'R', 27 0x8: 'U', 28 0x10: 'H', 29 0x20: 'A', 30 0x40: 'P', 31 0x80: 'I', 32 0x100: 'K' 33} 34LAST_THREAD_STATE = 0x100 35 36def GetProcPID(proc): 37 """ returns the PID of a process. 38 params: 39 proc: value object representing a proc in the kernel. 40 returns: 41 int: the pid of the process. 42 """ 43 return unsigned(proc.p_pid) if proc is not None else -1 44 45def GetProcPlatform(proc): 46 """ returns the platform identifier of a process. 47 params: 48 proc: value object representing a proc in the kernel. 49 returns: 50 int: the platform identifier of the process. 51 """ 52 if not proc: 53 return None 54 return int(proc.p_proc_ro.p_platform_data.p_platform) 55 56def GetProcName(proc): 57 """ returns a string name of the process. Longer variant is preffered if provided. 58 params: 59 proc: value object representing a proc in the kernel. 60 returns: 61 str: a string name of the process linked to the task. 62 """ 63 if proc is None: 64 return NO_PROC_NAME 65 name = str(proc.p_name) 66 return name if name != '' else str(proc.p_comm) 67 68def GetProcNameForTask(task): 69 """ returns a string name of the process. If proc is not valid the proc 70 name is looked up in the associated importance structure (if 71 available). If no name can be found, "unknown" is returned. 72 params: 73 task: value object represeting a task in the kernel. 74 returns: 75 str : A string name of the process linked to the task 76 """ 77 if task: 78 p = GetProcFromTask(task) 79 if p is not None: 80 return GetProcName(p) 81 82 if (hasattr(task, 'task_imp_base') and 83 hasattr(task.task_imp_base, 'iit_procname') and 84 unsigned(task.task_imp_base) != 0): 85 return str(task.task_imp_base.iit_procname) 86 87 return NO_PROC_NAME 88 89def GetProcPIDForTask(task): 90 """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned. 91 params: 92 task: value object representing a task in the kernel 93 returns: 94 int : pid of the process or -1 if not found 95 """ 96 if not task: 97 return -1 98 99 p = GetProcFromTask(task) 100 if p is not None: 101 return GetProcPID(p) 102 103 proc_ro = Cast(task.bsd_info_ro, 'proc_ro *') 104 pid = unsigned(proc_ro.task_tokens.audit_token.val[5]) 105 return pid 106 107def GetProcStartAbsTimeForTask(task): 108 if task: 109 p = GetProcFromTask(task) 110 if p is not None: 111 return p.p_stats.ps_start 112 return None 113 114def GetProcInfo(proc): 115 """ returns a string name, pid, parent and task for a proc_t. Decodes cred, flag and p_stat fields. 116 params: 117 proc : value object representing a proc in the kernel 118 returns: 119 str : A string describing various information for process. 120 """ 121 out_string = "" 122 out_string += ("Process {p: <#020x}\n\tname {0: <32s}\n\tpid:{1: <6d} " + 123 "task:{task: <#020x} p_stat:{p.p_stat: <6d} parent pid: {p.p_ppid: <6d}\n" 124 ).format(GetProcName(proc), GetProcPID(proc), task=GetTaskFromProc(proc), p=proc) 125 #print the Creds 126 ucred = proc.p_proc_ro.p_ucred.__smr_ptr 127 if ucred: 128 out_string += "Cred: euid {:d} ruid {:d} svuid {:d}\n".format(ucred.cr_posix.cr_uid, 129 ucred.cr_posix.cr_ruid, 130 ucred.cr_posix.cr_svuid ) 131 #print the flags 132 flags = int(proc.p_flag) 133 out_string += "Flags: {0: <#020x}\n".format(flags) 134 num = 1 135 while num <= flags: 136 if flags & num: 137 explain_str = xnudefines.proc_flag_explain_strings.get(num, 'unknown') 138 out_string += "\t0x{:08x} - ".format(num) + explain_str + "\n" 139 elif num == 0x4: #special case for 32bit flag 140 out_string += "\t!0x00000004 - process is 32 bit\n" 141 num = num << 1 142 out_string += "State: " 143 state_val = proc.p_stat 144 if state_val < 1 or state_val > len(xnudefines.proc_state_strings) : 145 out_string += "(Unknown)" 146 else: 147 out_string += xnudefines.proc_state_strings[int(state_val)] 148 149 return out_string 150 151def GetProcNameForPid(pid): 152 """ Finds the name of the process corresponding to a given pid 153 params: 154 pid : int, pid you want to find the procname for 155 returns 156 str : Name of the process corresponding to the pid, "Unknown" if not found 157 """ 158 for p in kern.procs: 159 if int(GetProcPID(p)) == int(pid): 160 return GetProcName(p) 161 return NO_PROC_NAME 162 163def GetProcForPid(search_pid): 164 """ Finds the value object representing a proc in the kernel based on its pid 165 params: 166 search_pid : int, pid whose proc structure you want to find 167 returns: 168 value : The value object representing the proc, if a proc corresponding 169 to the given pid is found. Returns None otherwise 170 """ 171 if search_pid == 0: 172 return kern.globals.initproc 173 else: 174 headp = kern.globals.allproc 175 for proc in IterateListEntry(headp, 'p_list'): 176 if GetProcPID(proc) == search_pid: 177 return proc 178 return None 179 180@lldb_command('allproc') 181def AllProc(cmd_args=None): 182 """ Walk through the allproc structure and print procinfo for each process structure. 183 params: 184 cmd_args - [] : array of strings passed from lldb command prompt 185 """ 186 for proc in kern.procs : 187 print(GetProcInfo(proc)) 188 189 190@lldb_command('zombproc') 191def ZombProc(cmd_args=None): 192 """ Routine to print out all procs in the zombie list 193 params: 194 cmd_args - [] : array of strings passed from lldb command prompt 195 """ 196 if any(kern.zombprocs): 197 print("\nZombie Processes:") 198 for proc in kern.zombprocs: 199 print(GetProcInfo(proc) + "\n\n") 200 201@lldb_command('zombtasks') 202def ZombTasks(cmd_args=None): 203 """ Routine to print out all tasks in the zombie list 204 params: None 205 """ 206 out_str = "" 207 if any(kern.zombprocs): 208 header = "\nZombie Tasks:\n" 209 header += GetTaskSummary.header + " " + GetProcSummary.header 210 for proc in kern.zombprocs: 211 if proc.p_stat != 5: 212 t = GetTaskFromProc(proc) 213 out_str += GetTaskSummary(t) +" "+ GetProcSummary(proc) + "\n" 214 if out_str != "": 215 print(header) 216 print(out_str) 217 218# Macro: zombstacks 219def ShowZombStacks(O=None, regex=None): 220 header_flag = 0 221 for proc in kern.zombprocs: 222 if proc.p_stat != 5: 223 if header_flag == 0: 224 print("\nZombie Stacks:") 225 header_flag = 1 226 t = GetTaskFromProc(proc) 227 if t is not None: 228 ShowTaskStacks(t, O=O, regex=regex) 229 230@lldb_command('zombstacks', fancy=True) 231def ZombStacksCommand(cmd_args=None, cmd_options={}, O=None): 232 """ Routine to print out all stacks of tasks that are exiting 233 """ 234 ShowZombStacks(O=O) 235# EndMacro: zombstacks 236 237 238""" AST Flags: 239 P - AST_PREEMPT 240 Q - AST_QUANTUM 241 U - AST_URGENT 242 H - AST_HANDOFF 243 Y - AST_YIELD 244 A - AST_APC 245 L - AST_LEDGER 246 B - AST_BSD 247 K - AST_KPERF 248 M - AST_MACF 249 r - AST_RESET_PCS 250 a - AST_ARCADE 251 G - AST_GUARD 252 T - AST_TELEMETRY_USER 253 T - AST_TELEMETRY_KERNEL 254 T - AST_TELEMETRY_WINDOWED 255 S - AST_SFI 256 D - AST_DTRACE 257 I - AST_TELEMETRY_IO 258 E - AST_KEVENT 259 R - AST_REBALANCE 260 p - AST_PROC_RESOURCE 261 d - AST_DEBUG_ASSERT 262 T - AST_TELEMETRY_MACF 263""" 264_AST_CHARS = { 265 0x1: 'P', 0x2: 'Q', 0x4: 'U', 0x8: 'H', 0x10: 'Y', 0x20: 'A', 266 0x40: 'L', 0x80: 'B', 0x100: 'K', 0x200: 'M', 0x400: 'r', 0x800: 'a', 267 0x1000: 'G', 0x2000: 'T', 0x4000: 'T', 0x8000: 'T', 0x10000: 'S', 268 0x20000: 'D', 0x40000: 'I', 0x80000: 'E', 0x100000: 'R', 269 0x400000: 'p', 0x800000: 'd', 0x1000000: 'T' 270} 271 272 273def GetASTSummary(ast): 274 """ Summarizes an AST field """ 275 276 state = int(ast) 277 state_str = '' 278 279 for ast, char in _AST_CHARS.items(): 280 state_str += char if state & ast else '' 281 282 return state_str 283 284 285@lldb_type_summary(['kcdata_descriptor *', 'kcdata_descriptor_t']) 286@header("{0: <20s} {1: <20s} {2: <20s} {3: <10s} {4: <5s}".format("kcdata_descriptor", "begin_addr", "cur_pos", "size", "flags")) 287def GetKCDataSummary(kcdata): 288 """ Summarizes kcdata_descriptor structure 289 params: kcdata: value - value object representing kcdata_descriptor 290 returns: str - summary of the kcdata object 291 """ 292 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <10d} {4: <#05x}" 293 return format_string.format(kcdata, kcdata.kcd_addr_begin, kcdata.kcd_addr_end, kcdata.kcd_length, kcdata.kcd_flags) 294 295INVALID_TASK_SUMMARY = "Process is not valid." 296 297@lldb_type_summary(['task', 'task_t']) 298@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags")) 299def GetTaskSummary(task: Optional[value], showcorpse=False) -> str: 300 """ Summarizes the important fields in task structure. 301 params: task: value - value object representing a task in kernel 302 returns: str - summary of the task 303 """ 304 if task is None: 305 return INVALID_TASK_SUMMARY 306 307 out_string = "" 308 format_string = '{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: <5s}' 309 thread_count = int(task.thread_count) 310 task_flags = '' 311 if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1: 312 task_flags += 'P' 313 if hasattr(task, "effective_policy") and int(task.effective_policy.tep_sup_active) == 1: 314 task_flags += 'N' 315 if hasattr(task, "suspend_count") and int(task.suspend_count) > 0: 316 task_flags += 'S' 317 if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base): 318 tib = task.task_imp_base 319 if int(tib.iit_receiver) == 1: 320 task_flags += 'R' 321 if int(tib.iit_donor) == 1: 322 task_flags += 'D' 323 if int(tib.iit_assertcnt) > 0: 324 task_flags += 'B' 325 326 proc_ro = Cast(task.bsd_info_ro, 'proc_ro *') 327 328 # check if corpse flag is set 329 if unsigned(proc_ro.t_flags_ro) & 0x20: 330 task_flags += 'C' 331 if unsigned(task.t_flags) & 0x40: 332 task_flags += 'P' 333 334 out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags) 335 if showcorpse is True and unsigned(task.corpse_info) != 0: 336 out_string += " " + GetKCDataSummary(task.corpse_info) 337 return out_string 338 339@header("{0: <28s}".format("task_role")) 340def GetTaskRoleSummary(task): 341 """ Summarizes task_role structure 342 params: task: value - value object representing task 343 returns: str - summary of the task role string 344 """ 345 format_string = "{0: <28s}" 346 task_role = task.effective_policy.tep_role 347 return format_string.format(GetTaskRoleString(task_role)) 348 349def GetMachThread(uthread): 350 """ Converts the passed in value interpreted as a uthread_t into a thread_t 351 """ 352 addr = unsigned(uthread) - sizeof('struct thread') 353 thread = kern.GetValueFromAddress(addr, 'struct thread *') 354 return thread 355 356def GetBSDThread(thread: Union[lldb.SBValue, value]) -> value: 357 """ Converts the passed in value interpreted as a thread_t into a uthread_t 358 """ 359 addr = unsigned(thread) + sizeof('struct thread') 360 return kern.CreateValueFromAddress(addr, 'struct uthread') 361 362def GetProcFromTask(task) -> Optional[value]: 363 """ Converts the passed in value interpreted as a task_t into a proc_t 364 """ 365 if unsigned(task) and unsigned(task.t_flags) & TF_HASPROC: 366 addr = unsigned(task) - kern.globals.proc_struct_size 367 return value(task.GetSBValue().xCreateValueFromAddress( 368 'proc', addr, gettype('struct proc') 369 ).AddressOf()) 370 return None 371 372def GetTaskFromProc(proc) -> Optional[value]: 373 """ Converts the passed in value interpreted as a proc_t into a task_t 374 """ 375 if unsigned(proc) and unsigned(proc.p_lflag) & P_LHASTASK: 376 addr = unsigned(proc) + kern.globals.proc_struct_size 377 return value(proc.GetSBValue().xCreateValueFromAddress( 378 'task', addr, gettype('struct task') 379 ).AddressOf()) 380 return None 381 382def GetThreadNameFromBSDThread(uthread): 383 """ Get the name of a thread from a BSD thread, if possible. 384 Returns the empty string otherwise. 385 """ 386 if int(uthread.pth_name) != 0 : 387 th_name_strval = Cast(uthread.pth_name, 'char *') 388 if len(str(th_name_strval)) > 0 : 389 return str(th_name_strval) 390 391 return '' 392 393def GetThreadName(thread): 394 """ Get the name of a thread, if possible. Returns the empty string 395 otherwise. 396 """ 397 uthread = GetBSDThread(thread) 398 return GetThreadNameFromBSDThread(uthread) 399 400ThreadSummary = namedtuple('ThreadSummary', [ 401 'thread', 'tid', 'task', 'processor', 'base', 'pri', 'sched_mode', 'io_policy', 402 'state', 'ast', 'waitq', 'wait_evt', 'wait_evt_sym', 'wait_msg', 403 'name']) 404ThreadSummaryNames = ThreadSummary(*ThreadSummary._fields) 405ThreadSummaryFormat = ( 406 '{ts.thread: <20s} {ts.tid: <10s} {ts.task: <20s} {ts.processor: <20s} {ts.base: <6s} ' 407 '{ts.pri: <6s} {ts.sched_mode: <10s} {ts.io_policy: <15s} ' 408 '{ts.state: <8s} {ts.ast: <12s} {ts.waitq: <18s} {ts.wait_evt: <18s} ' 409 '{ts.wait_evt_sym: <30s} {ts.wait_msg: <20s} {ts.name: <20s}') 410 411@lldb_type_summary(['thread *', 'thread_t']) 412@header(ThreadSummaryFormat.format(ts=ThreadSummaryNames)) 413def GetThreadSummary(thread, O=None): 414 """ Summarize the thread structure. 415 416 params: thread: value - value object representing a thread in kernel 417 returns: str - summary of a thread 418 419 State flags: 420 W - Wait asserted 421 S - Suspended 422 R - Runnable 423 U - Uninterruptible 424 H - Terminated 425 A - Terminated (on queue) 426 I - Idle thread 427 C - Crashed thread 428 K - Waking 429 430 policy flags: 431 B - darwinbg 432 T - IO throttle 433 P - IO passive 434 D - Terminated 435 """ 436 437 # Check that this is a valid thread (if possible). 438 if hasattr(thread, "thread_magic") and thread.thread_magic != 0x1234ABCDDCBA4321: 439 # Do not raise exception so iterators like showscheduler don't abort. 440 return f"{thread:<#018x} <invalid thread>" 441 442 thread_ptr_str = '{:<#018x}'.format(thread) 443 thread_task_ptr_str = '{:<#018x}'.format(thread.t_tro.tro_task) 444 445 if int(thread.static_param): 446 thread_ptr_str += ' W' 447 thread_id = hex(thread.thread_id) 448 processor = hex(thread.last_processor) 449 base_priority = str(int(thread.base_pri)) 450 sched_priority = str(int(thread.sched_pri)) 451 sched_mode = '' 452 mode = str(thread.sched_mode) 453 if 'TIMESHARE' in mode: 454 sched_mode += 'TMSHR' 455 elif 'FIXED' in mode: 456 sched_mode += 'FIXED' 457 elif 'REALTIME' in mode: 458 sched_mode += 'RT' 459 460 if (unsigned(thread.bound_processor) != 0): 461 sched_mode += ' BIND' 462 463 TH_SFLAG_THROTTLED = 0x4 464 if (unsigned(thread.sched_flags) & TH_SFLAG_THROTTLED): 465 sched_mode += ' BG' 466 467 uthread = GetBSDThread(thread) 468 thread_name = GetThreadNameFromBSDThread(uthread) 469 470 io_policy_str = "" 471 if int(uthread.uu_flag) & 0x400: 472 io_policy_str += 'RAGE ' 473 if int(thread.effective_policy.thep_darwinbg) != 0: 474 io_policy_str += 'B' 475 if int(thread.effective_policy.thep_io_tier) != 0: 476 io_policy_str += 'T' 477 if int(thread.effective_policy.thep_io_passive) != 0: 478 io_policy_str += 'P' 479 if int(thread.effective_policy.thep_terminated) != 0: 480 io_policy_str += 'D' 481 482 state = int(thread.state) 483 state_str = '' 484 mask = 0x1 485 while mask <= LAST_THREAD_STATE: 486 state_str += THREAD_STATE_CHARS[int(state & mask)] 487 mask <<= 1 488 489 if int(thread.inspection): 490 state_str += 'C' 491 492 ast = int(thread.ast) | int(thread.reason) 493 ast_str = GetASTSummary(ast) 494 495 wait_queue_str = '' 496 wait_event_str = '' 497 wait_event_str_sym = '' 498 wait_message = '' 499 if (state & 0x1) != 0: 500 wait_queue_str = '{:<#018x}'.format(unsigned(thread.waitq.wq_q)) 501 wait_event_str = '{:<#018x}'.format(unsigned(thread.wait_event)) 502 wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16)) 503 if int(uthread.uu_wmesg) != 0: 504 wait_message = str(Cast(uthread.uu_wmesg, 'char *')) 505 506 ts = ThreadSummary( 507 thread=thread_ptr_str, tid=thread_id, 508 task=thread_task_ptr_str, processor=processor, 509 base=base_priority, pri=sched_priority, sched_mode=sched_mode, 510 io_policy=io_policy_str, state=state_str, ast=ast_str, 511 waitq=wait_queue_str, wait_evt=wait_event_str, 512 wait_evt_sym=wait_event_str_sym, wait_msg=wait_message, 513 name=thread_name) 514 if O is not None: 515 return O.format(ThreadSummaryFormat, ts=ts) 516 else: 517 return ThreadSummaryFormat.format(ts=ts) 518 519 520def GetTaskRoleString(role): 521 role_strs = { 522 -1 : "TASK_RENICED", 523 0 : "TASK_UNSPECIFIED", 524 1 : "TASK_FOREGROUND_APPLICATION", 525 2 : "TASK_BACKGROUND_APPLICATION", 526 3 : "TASK_CONTROL_APPLICATION", 527 4 : "TASK_GRAPHICS_SERVER", 528 5 : "TASK_THROTTLE_APPLICATION", 529 6 : "TASK_NONUI_APPLICATION", 530 7 : "TASK_DEFAULT_APPLICATION", 531 8 : "TASK_DARWINBG_APPLICATION" 532 } 533 return role_strs[int(role)] 534 535def GetCoalitionFlagString(coal): 536 flags = [] 537 if (coal.privileged): 538 flags.append('privileged') 539 if (coal.termrequested): 540 flags.append('termrequested') 541 if (coal.terminated): 542 flags.append('terminated') 543 if (coal.reaped): 544 flags.append('reaped') 545 if (coal.notified): 546 flags.append('notified') 547 if (coal.efficient): 548 flags.append('efficient') 549 return "|".join(flags) 550 551def GetCoalitionTasks(queue, coal_type, thread_details=False): 552 sfi_strs = { 553 0x0 : "SFI_CLASS_UNSPECIFIED", 554 0x1 : "SFI_CLASS_DARWIN_BG", 555 0x2 : "SFI_CLASS_APP_NAP", 556 0x3 : "SFI_CLASS_MANAGED_FOCAL", 557 0x4 : "SFI_CLASS_MANAGED_NONFOCAL", 558 0x5 : "SFI_CLASS_DEFAULT_FOCAL", 559 0x6 : "SFI_CLASS_DEFAULT_NONFOCAL", 560 0x7 : "SFI_CLASS_KERNEL", 561 0x8 : "SFI_CLASS_OPTED_OUT", 562 0x9 : "SFI_CLASS_UTILITY", 563 0xA : "SFI_CLASS_LEGACY_FOCAL", 564 0xB : "SFI_CLASS_LEGACY_NONFOCAL", 565 0xC : "SFI_CLASS_USER_INITIATED_FOCAL", 566 0xD : "SFI_CLASS_USER_INITIATED_NONFOCAL", 567 0xE : "SFI_CLASS_USER_INTERACTIVE_FOCAL", 568 0xF : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL", 569 0x10 : "SFI_CLASS_MAINTENANCE", 570 } 571 tasks = [] 572 field_path = '.task_coalition[{}]'.format(coal_type) 573 for task in IterateLinkageChain(queue, 'task *', field_path): 574 task_str = "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(task),task,GetProcNameForTask(task),GetTaskRoleString(task.effective_policy.tep_role)) 575 if thread_details: 576 for thread in IterateQueue(task.threads, "thread_t", "task_threads"): 577 task_str += "\n\t\t\t|-> thread:" + hex(thread) + ", " + sfi_strs[int(thread.sfi_class)] 578 tasks.append(task_str) 579 return tasks 580 581def GetCoalitionTypeString(type): 582 """ Convert a coalition type field into a string 583 Currently supported types (from <mach/coalition.h>): 584 COALITION_TYPE_RESOURCE 585 COALITION_TYPE_JETSAM 586 """ 587 if type == 0: # COALITION_TYPE_RESOURCE 588 return 'RESOURCE' 589 if type == 1: 590 return 'JETSAM' 591 return '<unknown>' 592 593def GetResourceCoalitionSummary(coal, verbose=False): 594 """ Summarize a resource coalition 595 """ 596 out_string = "Resource Coalition:\n\t Ledger:\n" 597 thread_details = False 598 if config['verbosity'] > vSCRIPT: 599 thread_details = True 600 ledgerp = coal.r.ledger 601 if verbose and unsigned(ledgerp) != 0: 602 i = 0 603 while i != ledgerp.l_template.lt_cnt: 604 out_string += "\t\t" 605 out_string += GetLedgerEntrySummary(kern.globals.task_ledger_template, ledgerp, i) 606 i = i + 1 607 out_string += "\t bytesread {0: <d}\n\t byteswritten {1: <d}\n\t gpu_time {2: <d}".format(coal.r.bytesread, coal.r.byteswritten, coal.r.gpu_time) 608 out_string += "\n\t total_tasks {0: <d}\n\t dead_tasks {1: <d}\n\t active_tasks {2: <d}".format(coal.r.task_count, coal.r.dead_task_count, coal.r.task_count - coal.r.dead_task_count) 609 out_string += "\n\t last_became_nonempty_time {0: <d}\n\t time_nonempty {1: <d}".format(coal.r.last_became_nonempty_time, coal.r.time_nonempty) 610 if verbose: 611 out_string += "\n\t cpu_time_effective[THREAD_QOS_DEFAULT] {0: <d}".format(coal.r.cpu_time_eqos[0]) 612 out_string += "\n\t cpu_time_effective[THREAD_QOS_MAINTENANCE] {0: <d}".format(coal.r.cpu_time_eqos[1]) 613 out_string += "\n\t cpu_time_effective[THREAD_QOS_BACKGROUND] {0: <d}".format(coal.r.cpu_time_eqos[2]) 614 out_string += "\n\t cpu_time_effective[THREAD_QOS_UTILITY] {0: <d}".format(coal.r.cpu_time_eqos[3]) 615 out_string += "\n\t cpu_time_effective[THREAD_QOS_LEGACY] {0: <d}".format(coal.r.cpu_time_eqos[4]) 616 out_string += "\n\t cpu_time_effective[THREAD_QOS_USER_INITIATED] {0: <d}".format(coal.r.cpu_time_eqos[5]) 617 out_string += "\n\t cpu_time_effective[THREAD_QOS_USER_INTERACTIVE] {0: <d}".format(coal.r.cpu_time_eqos[6]) 618 out_string += "\n\t Tasks:\n\t\t" 619 tasks = GetCoalitionTasks(addressof(coal.r.tasks), 0, thread_details) 620 out_string += "\n\t\t".join(tasks) 621 return out_string 622 623def GetJetsamCoalitionSummary(coal, verbose=False): 624 out_string = "Jetsam Coalition:" 625 thread_details = False 626 if config['verbosity'] > vSCRIPT: 627 thread_details = True 628 if unsigned(coal.j.leader) == 0: 629 out_string += "\n\t NO Leader!" 630 else: 631 out_string += "\n\t Leader:\n\t\t" 632 out_string += "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(coal.j.leader),coal.j.leader,GetProcNameForTask(coal.j.leader),GetTaskRoleString(coal.j.leader.effective_policy.tep_role)) 633 out_string += "\n\t Extensions:\n\t\t" 634 tasks = GetCoalitionTasks(addressof(coal.j.extensions), 1, thread_details) 635 out_string += "\n\t\t".join(tasks) 636 out_string += "\n\t XPC Services:\n\t\t" 637 tasks = GetCoalitionTasks(addressof(coal.j.services), 1, thread_details) 638 out_string += "\n\t\t".join(tasks) 639 out_string += "\n\t Other Tasks:\n\t\t" 640 tasks = GetCoalitionTasks(addressof(coal.j.other), 1, thread_details) 641 out_string += "\n\t\t".join(tasks) 642 out_string += "\n\t Thread Group: {0: <#020x}\n".format(coal.j.thread_group) 643 return out_string 644 645@lldb_type_summary(['coalition_t', 'coalition *']) 646@header("{0: <20s} {1: <15s} {2: <10s} {3: <10s} {4: <10s} {5: <12s} {6: <12s} {7: <20s}".format("coalition", "type", "id", "ref count", "act count", "focal cnt", "nonfocal cnt","flags")) 647def GetCoalitionSummary(coal): 648 if unsigned(coal) == 0: 649 return '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'.format(0, "", -1, -1, -1, -1, -1, "") 650 out_string = "" 651 format_string = '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}' 652 type_string = GetCoalitionTypeString(coal.type) 653 flag_string = GetCoalitionFlagString(coal) 654 out_string += format_string.format(coal, type_string, coal.id, coal.ref_count, coal.active_count, coal.focal_task_count, coal.nonfocal_task_count, flag_string) 655 return out_string 656 657def GetCoalitionInfo(coal, verbose=False): 658 """ returns a string describing a coalition, including details about the particular coalition type. 659 params: 660 coal : value object representing a coalition in the kernel 661 returns: 662 str : A string describing the coalition. 663 """ 664 if unsigned(coal) == 0: 665 return "<null coalition>" 666 typestr = GetCoalitionTypeString(coal.type) 667 flagstr = GetCoalitionFlagString(coal) 668 out_string = "" 669 out_string += "Coalition {c: <#020x}\n\tID {c.id: <d}\n\tType {c.type: <d} ({t: <s})\n\tRefCount {c.ref_count: <d}\n\tActiveCount {c.active_count: <d}\n\tFocal Tasks: {c.focal_task_count: <d}\n\tNon-Focal Tasks: {c.nonfocal_task_count: <d}\n\tFlags {f: <s}\n\t".format(c=coal,t=typestr,f=flagstr) 670 if coal.type == 0: # COALITION_TYPE_RESOURCE 671 out_string += GetResourceCoalitionSummary(coal, verbose) 672 elif coal.type == 1: # COALITION_TYPE_JETSAM 673 out_string += GetJetsamCoalitionSummary(coal, verbose) 674 else: 675 out_string += "Unknown Type" 676 677 return out_string 678 679# Macro: showcoalitioninfo 680 681@lldb_command('showcoalitioninfo') 682def ShowCoalitionInfo(cmd_args=None, cmd_options={}): 683 """ Display more detailed information about a coalition 684 Usage: showcoalitioninfo <address of coalition> 685 """ 686 verbose = False 687 if config['verbosity'] > vHUMAN: 688 verbose = True 689 if not cmd_args: 690 raise ArgumentError("No arguments passed") 691 coal = kern.GetValueFromAddress(cmd_args[0], 'coalition *') 692 if not coal: 693 print("unknown arguments:", str(cmd_args)) 694 return False 695 print(GetCoalitionInfo(coal, verbose)) 696 697# EndMacro: showcoalitioninfo 698 699# Macro: showallcoalitions 700 701@lldb_command('showallcoalitions') 702def ShowAllCoalitions(cmd_args=None): 703 """ Print a summary listing of all the coalitions 704 """ 705 global kern 706 print(GetCoalitionSummary.header) 707 for c in kern.coalitions: 708 print(GetCoalitionSummary(c)) 709 710# EndMacro: showallcoalitions 711 712# Macro: showcurrentforegroundapps 713 714@lldb_command('showcurrentforegroundapps') 715def ShowCurrentForegroundStatus(cmd_args=None): 716 """ Print current listing of foreground applications 717 """ 718 global kern 719 print(GetTaskSummary.header + " " + GetProcSummary.header + " " + GetTaskRoleSummary.header) 720 for t in kern.tasks: 721 task_role = t.effective_policy.tep_role 722 # Only print tasks where tep_role is 'TASK_FOREGROUND_APPLICATION = 1' 723 if (task_role == 1): 724 pval = GetProcFromTask(t) 725 print(GetTaskSummary(t), GetProcSummary(pval), GetTaskRoleSummary(t)) 726 727# EndMacro: showcurrentforegroundapps 728 729# Macro: showallthreadgroups 730 731@lldb_type_summary(['struct thread_group *', 'thread_group *']) 732@header("{0: <20s} {1: <5s} {2: <16s} {3: <5s} {4: <8s} {5: <20s}".format("thread_group", "id", "name", "refc", "flags", "recommendation")) 733def GetThreadGroupSummary(tg): 734 if unsigned(tg) == 0: 735 return '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'.format(0, -1, "", -1, "", -1) 736 out_string = "" 737 format_string = '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}' 738 tg_flags = '' 739 if (tg.tg_flags & 0x1): 740 tg_flags += 'E' 741 if (tg.tg_flags & 0x2): 742 tg_flags += 'A' 743 if (tg.tg_flags & 0x4): 744 tg_flags += 'C' 745 if (tg.tg_flags & 0x100): 746 tg_flags += 'U' 747 out_string += format_string.format(tg, tg.tg_id, tg.tg_name, tg.tg_refcount.ref_count, tg_flags, tg.tg_recommendation) 748 return out_string 749 750@lldb_command('showallthreadgroups') 751def ShowAllThreadGroups(cmd_args=None): 752 """ Print a summary listing of all thread groups 753 """ 754 global kern 755 print(GetThreadGroupSummary.header) 756 for tg in kern.thread_groups: 757 print(GetThreadGroupSummary(tg)) 758 759# EndMacro: showallthreadgroups 760 761# Macro: showtaskcoalitions 762 763@lldb_command('showtaskcoalitions', 'F:') 764def ShowTaskCoalitions(cmd_args=None, cmd_options={}): 765 """ 766 """ 767 task_list = [] 768 if "-F" in cmd_options: 769 task_list = FindTasksByName(cmd_options["-F"]) 770 elif cmd_args: 771 t = kern.GetValueFromAddress(cmd_args[0], 'task *') 772 task_list.append(t) 773 else: 774 raise ArgumentError("No arguments passed") 775 776 if len(task_list) > 0: 777 print(GetCoalitionSummary.header) 778 for task in task_list: 779 print(GetCoalitionSummary(task.coalition[0])) 780 print(GetCoalitionSummary(task.coalition[1])) 781 782# EndMacro: showtaskcoalitions 783 784INVALID_PROC_SUMMARY = "Process is not valid." 785 786@lldb_type_summary(['proc', 'proc *']) 787@header("{0: >6s} {1: <18s} {2: >11s} {3: ^10s} {4: <32s}".format("pid", "process", "io_policy", "wq_state", "command")) 788def GetProcSummary(proc: Optional[value]) -> str: 789 """ Summarize the process data. 790 params: 791 proc : value - value representaitng a proc * in kernel 792 returns: 793 str - string summary of the process. 794 """ 795 if proc is None: 796 return INVALID_PROC_SUMMARY 797 798 out_string = "" 799 format_string= "{0: >6d} {1: <#018x} {2: >11s} {3: >2d} {4: >2d} {5: >2d} {6: <32s}" 800 pval = proc.GetSBValue() 801 #code.interact(local=locals()) 802 if str(pval.GetType()) != str(gettype('proc *')) : 803 return "Unknown type " + str(pval.GetType()) + " " + str(hex(proc)) 804 pid = int(GetProcPID(proc)) 805 proc_addr = int(hex(proc), 16) 806 proc_rage_str = "" 807 if int(proc.p_lflag) & 0x400000 : 808 proc_rage_str = "RAGE" 809 810 task = GetTaskFromProc(proc) 811 if task is None: 812 return "Process is not associated with a Task" 813 814 io_policy_str = "" 815 816 if int(task.effective_policy.tep_darwinbg) != 0: 817 io_policy_str += "B" 818 if int(task.effective_policy.tep_lowpri_cpu) != 0: 819 io_policy_str += "L" 820 821 if int(task.effective_policy.tep_io_tier) != 0: 822 io_policy_str += "T" 823 if int(task.effective_policy.tep_io_passive) != 0: 824 io_policy_str += "P" 825 if int(task.effective_policy.tep_terminated) != 0: 826 io_policy_str += "D" 827 828 if int(task.effective_policy.tep_latency_qos) != 0: 829 io_policy_str += "Q" 830 if int(task.effective_policy.tep_sup_active) != 0: 831 io_policy_str += "A" 832 833 if int(proc.p_refcount) & GetEnumValue("proc_ref_bits_t::P_REF_SHADOW") : 834 io_policy_str += "S" 835 836 837 try: 838 work_queue = proc.p_wqptr 839 if proc.p_wqptr != 0 : 840 wq_num_threads = int(work_queue.wq_nthreads) 841 wq_idle_threads = int(work_queue.wq_thidlecount) 842 wq_req_threads = int(work_queue.wq_reqcount) 843 else: 844 wq_num_threads = 0 845 wq_idle_threads = 0 846 wq_req_threads = 0 847 except: 848 wq_num_threads = -1 849 wq_idle_threads = -1 850 wq_req_threads = -1 851 process_name = GetProcName(proc) 852 if process_name == 'xpcproxy': 853 for thread in IterateQueue(task.threads, 'thread *', 'task_threads'): 854 thread_name = GetThreadName(thread) 855 if thread_name: 856 process_name += ' (' + thread_name + ')' 857 break 858 out_string += format_string.format(pid, proc_addr, " ".join([proc_rage_str, io_policy_str]), wq_num_threads, wq_idle_threads, wq_req_threads, process_name) 859 return out_string 860 861@lldb_type_summary(['tty_dev_t', 'tty_dev_t *']) 862@header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","primary", "replica", "open", "free", "name", "revoke")) 863def GetTTYDevSummary(tty_dev): 864 """ Summarizes the important fields in tty_dev_t structure. 865 params: tty_dev: value - value object representing a tty_dev_t in kernel 866 returns: str - summary of the tty_dev 867 """ 868 out_string = "" 869 format_string = "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}" 870 open_fn = kern.Symbolicate(int(hex(tty_dev.open), 16)) 871 free_fn = kern.Symbolicate(int(hex(tty_dev.free), 16)) 872 name_fn = kern.Symbolicate(int(hex(tty_dev.name), 16)) 873 revoke_fn = kern.Symbolicate(int(hex(tty_dev.revoke), 16)) 874 out_string += format_string.format(tty_dev, tty_dev.primary, tty_dev.replica, open_fn, free_fn, name_fn, revoke_fn) 875 return out_string 876 877# Macro: showtask 878 879@lldb_command('showtask', 'F:') 880def ShowTask(cmd_args=None, cmd_options={}): 881 """ Routine to print a summary listing of given task 882 Usage: showtask <address of task> 883 or : showtask -F <name of task> 884 """ 885 task_list = [] 886 if "-F" in cmd_options: 887 task_list = FindTasksByName(cmd_options['-F']) 888 else: 889 if not cmd_args: 890 raise ArgumentError("Invalid arguments passed.") 891 892 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 893 if not tval: 894 raise ArgumentError("Unknown arguments: {:s}".format(cmd_args[0])) 895 task_list.append(tval) 896 897 for tval in task_list: 898 print(GetTaskSummary.header + " " + GetProcSummary.header) 899 pval = GetProcFromTask(tval) 900 print(GetTaskSummary(tval) +" "+ GetProcSummary(pval)) 901 902# EndMacro: showtask 903 904# Macro: showpid 905 906@lldb_command('showpid') 907def ShowPid(cmd_args=None): 908 """ Routine to print a summary listing of task corresponding to given pid 909 Usage: showpid <pid value> 910 """ 911 if not cmd_args: 912 raise ArgumentError("No arguments passed") 913 pidval = ArgumentStringToInt(cmd_args[0]) 914 for t in kern.tasks: 915 pval = GetProcFromTask(t) 916 if pval is not None and GetProcPID(pval) == pidval: 917 print(GetTaskSummary.header + " " + GetProcSummary.header) 918 print(GetTaskSummary(t) + " " + GetProcSummary(pval)) 919 break 920 921# EndMacro: showpid 922 923# Macro: showproc 924 925@lldb_command('showproc') 926def ShowProc(cmd_args=None): 927 """ Routine to print a summary listing of task corresponding to given proc 928 Usage: showproc <address of proc> 929 """ 930 if not cmd_args: 931 raise ArgumentError("No arguments passed") 932 pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') 933 if not pval: 934 print("unknown arguments:", str(cmd_args)) 935 return False 936 print(GetTaskSummary.header + " " + GetProcSummary.header) 937 tval = GetTaskFromProc(pval) 938 print(GetTaskSummary(tval) + " " + GetProcSummary(pval)) 939 940# EndMacro: showproc 941 942# Macro: showprocinfo 943 944@lldb_command('showprocinfo') 945def ShowProcInfo(cmd_args=None): 946 """ Routine to display name, pid, parent & task for the given proc address 947 It also shows the Cred, Flags and state of the process 948 Usage: showprocinfo <address of proc> 949 """ 950 if not cmd_args: 951 raise ArgumentError("No arguments passed") 952 pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') 953 if not pval: 954 print("unknown arguments:", str(cmd_args)) 955 return False 956 print(GetProcInfo(pval)) 957 958# EndMacro: showprocinfo 959 960#Macro: showprocfiles 961 962@lldb_command('showprocfiles') 963def ShowProcFiles(cmd_args=None): 964 """ Given a proc_t pointer, display the list of open file descriptors for the referenced process. 965 Usage: showprocfiles <proc_t> 966 """ 967 if not cmd_args: 968 print(ShowProcFiles.__doc__) 969 return 970 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t') 971 proc_filedesc = addressof(proc.p_fd) 972 proc_ofiles = proc_filedesc.fd_ofiles 973 if unsigned(proc_ofiles) == 0: 974 print('No open files for proc {0: <s}'.format(cmd_args[0])) 975 return 976 print("{0: <5s} {1: <18s} {2: <10s} {3: <8s} {4: <18s} {5: <64s}".format('FD', 'FILEGLOB', 'FG_FLAGS', 'FG_TYPE', 'FG_DATA','INFO')) 977 print("{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format("")) 978 979 for fd in range(0, unsigned(proc_filedesc.fd_afterlast)): 980 if unsigned(proc_ofiles[fd]) != 0: 981 out_str = '' 982 proc_fd_flags = proc_ofiles[fd].fp_flags 983 proc_fd_fglob = proc_ofiles[fd].fp_glob 984 proc_fd_fglob_fg_data = Cast(proc_fd_fglob.fg_data, 'void *') 985 out_str += "{0: <5d} ".format(fd) 986 out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob)) 987 out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags)) 988 proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type) 989 if proc_fd_ftype in xnudefines.filetype_strings: 990 out_str += "{0: <8s} ".format(xnudefines.filetype_strings[proc_fd_ftype]) 991 else: 992 out_str += "?: {0: <5d} ".format(proc_fd_ftype) 993 out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob_fg_data)) 994 if proc_fd_ftype == 1: 995 fd_name = Cast(proc_fd_fglob_fg_data, 'struct vnode *').v_name 996 out_str += "{0: <64s}".format(fd_name) 997 out_str += "\n" 998 print(out_str) 999 1000#EndMacro: showprocfiles 1001 1002#Macro: showtty 1003 1004@lldb_command('showtty') 1005def ShowTTY(cmd_args=None): 1006 """ Display information about a struct tty 1007 Usage: showtty <tty struct> 1008 """ 1009 if not cmd_args: 1010 print(ShowTTY.__doc__) 1011 return 1012 1013 tty = kern.GetValueFromAddress(cmd_args[0], 'struct tty *') 1014 print("TTY structure at: {0: <s}".format(cmd_args[0])) 1015 print("Last input to raw queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_rawq.c_cs), tty.t_rawq.c_cs)) 1016 print("Last input to canonical queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_canq.c_cs), tty.t_canq.c_cs)) 1017 print("Last output data: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_outq.c_cs), tty.t_outq.c_cs)) 1018 tty_state_info = [ 1019 ['', 'TS_SO_OLOWAT (Wake up when output <= low water)'], 1020 ['- (synchronous I/O mode)', 'TS_ASYNC (async I/O mode)'], 1021 ['', 'TS_BUSY (Draining output)'], 1022 ['- (Carrier is NOT present)', 'TS_CARR_ON (Carrier is present)'], 1023 ['', 'TS_FLUSH (Outq has been flushed during DMA)'], 1024 ['- (Open has NOT completed)', 'TS_ISOPEN (Open has completed)'], 1025 ['', 'TS_TBLOCK (Further input blocked)'], 1026 ['', 'TS_TIMEOUT (Wait for output char processing)'], 1027 ['', 'TS_TTSTOP (Output paused)'], 1028 ['', 'TS_WOPEN (Open in progress)'], 1029 ['', 'TS_XCLUDE (Tty requires exclusivity)'], 1030 ['', 'TS_BKSL (State for lowercase \\ work)'], 1031 ['', 'TS_CNTTB (Counting tab width, ignore FLUSHO)'], 1032 ['', 'TS_ERASE (Within a \\.../ for PRTRUB)'], 1033 ['', 'TS_LNCH (Next character is literal)'], 1034 ['', 'TS_TYPEN (Retyping suspended input (PENDIN))'], 1035 ['', 'TS_CAN_BYPASS_L_RINT (Device in "raw" mode)'], 1036 ['- (Connection NOT open)', 'TS_CONNECTED (Connection open)'], 1037 ['', 'TS_SNOOP (Device is being snooped on)'], 1038 ['', 'TS_SO_OCOMPLETE (Wake up when output completes)'], 1039 ['', 'TS_ZOMBIE (Connection lost)'], 1040 ['', 'TS_CAR_OFLOW (For MDMBUF - handle in driver)'], 1041 ['', 'TS_CTS_OFLOW (For CCTS_OFLOW - handle in driver)'], 1042 ['', 'TS_DSR_OFLOW (For CDSR_OFLOW - handle in driver)'] 1043 ] 1044 index = 0 1045 mask = 0x1 1046 tty_state = unsigned(tty.t_state) 1047 print("State:") 1048 while index < 24: 1049 if tty_state & mask != 0: 1050 if len(tty_state_info[index][1]) > 0: 1051 print('\t' + tty_state_info[index][1]) 1052 else: 1053 if len(tty_state_info[index][0]) > 0: 1054 print('\t' + tty_state_info[index][0]) 1055 index += 1 1056 mask = mask << 1 1057 print("Flags: 0x{0:0>8x}".format(unsigned(tty.t_flags))) 1058 print("Foreground Process Group: 0x{0:0>16x}".format(unsigned(tty.t_pgrp))) 1059 print("Enclosing session: 0x{0:0>16x}".format(unsigned(tty.t_session))) 1060 print("Termios:") 1061 print("\tInput Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_iflag))) 1062 print("\tOutput Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_oflag))) 1063 print("\tControl Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_cflag))) 1064 print("\tLocal Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_lflag))) 1065 print("\tInput Speed: {0: <8d}".format(tty.t_termios.c_ispeed)) 1066 print("\tOutput Speed: {0: <8d}".format(tty.t_termios.c_ospeed)) 1067 print("High Watermark: {0: <d} bytes".format(tty.t_hiwat)) 1068 print("Low Watermark : {0: <d} bytes".format(tty.t_lowat)) 1069 1070#EndMacro: showtty 1071 1072#Macro showallttydevs 1073 1074@lldb_command('showallttydevs') 1075def ShowAllTTYDevs(cmd_args=[], cmd_options={}): 1076 """ Show a list of ttydevs registered in the system. 1077 Usage: 1078 (lldb)showallttydevs 1079 """ 1080 tty_dev_head = kern.globals.tty_dev_head 1081 tty_dev = tty_dev_head 1082 print(GetTTYDevSummary.header) 1083 while unsigned(tty_dev) != 0: 1084 print(GetTTYDevSummary(tty_dev)) 1085 tty_dev = tty_dev.next 1086 return "" 1087 1088#EndMacro: showallttydevs 1089 1090#Macro: dumpthread_terminate_queue 1091 1092@lldb_command('dumpthread_terminate_queue', fancy=True) 1093def DumpThreadTerminateQueue(cmd_args=None, cmd_options={}, O=None): 1094 """ Displays the contents of the specified call_entry queue. 1095 Usage: dumpthread_terminate_queue 1096 """ 1097 1098 count = 0 1099 with O.table(GetThreadSummary.header): 1100 for th in IterateMPSCQueue(addressof(kern.globals.thread_terminate_queue.mpd_queue), 'struct thread', 'mpsc_links'): 1101 print(GetThreadSummary(th, O=O)) 1102 count += 1 1103 print("{0: <d} entries!".format(count)) 1104 1105#EndMacro: dumpthread_terminate_queue 1106 1107#Macro: dumpcrashed_thread_queue 1108 1109@lldb_command('dumpcrashed_thread_queue', fancy=True) 1110def DumpCrashedThreadsQueue(cmd_args=None, cmd_options={}, O=None): 1111 """ Displays the contents of the specified call_entry queue. 1112 Usage: dumpcrashed_thread_queue 1113 """ 1114 1115 count = 0 1116 with O.table(GetThreadSummary.header): 1117 for th in IterateQueue(addressof(kern.globals.crashed_threads_queue), 'struct thread *', 'q_link'): 1118 print(GetThreadSummary(th), O=O) 1119 count += 1 1120 print("{0: <d} entries!".format(count)) 1121 1122#EndMacro: dumpcrashed_thread_queue 1123 1124#Macro: dumpcallqueue 1125 1126@lldb_command('dumpcallqueue') 1127def DumpCallQueue(cmd_args=None): 1128 """ Displays the contents of the specified call_entry queue. 1129 Usage: dumpcallqueue <queue_head_t *> 1130 """ 1131 if not cmd_args: 1132 raise ArgumentError("Invalid arguments") 1133 1134 print("{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC')) 1135 callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *') 1136 count = 0 1137 for callentry in IterateQueue(callhead, 'struct call_entry *', 'q_link'): 1138 print("{0: <#18x} {1: <#18x} {2: <#18x} {3: <64d} {4: <#18x}".format( 1139 unsigned(callentry), unsigned(callentry.param0), unsigned(callentry.param1), 1140 unsigned(callentry.deadline), unsigned(callentry.func))) 1141 count += 1 1142 print("{0: <d} entries!".format(count)) 1143 1144#EndMacro: dumpcallqueue 1145 1146@lldb_command('showalltasklogicalwrites') 1147def ShowAllTaskIOStats(cmd_args=None): 1148 """ Commad to print I/O stats for all tasks 1149 """ 1150 print("{0: <20s} {1: <20s} {2: <20s} {3: <20s} {4: <20s} {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <32}".format("task", "Immediate Writes", "Deferred Writes", "Invalidated Writes", "Metadata Writes", "Immediate Writes to External", "Deferred Writes to External", "Invalidated Writes to External", "Metadata Writes to External", "name")) 1151 for t in kern.tasks: 1152 pval = GetProcFromTask(t) 1153 print("{0: <#18x} {1: >20d} {2: >20d} {3: >20d} {4: >20d} {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <20s}".format(t, 1154 t.task_writes_counters_internal.task_immediate_writes, 1155 t.task_writes_counters_internal.task_deferred_writes, 1156 t.task_writes_counters_internal.task_invalidated_writes, 1157 t.task_writes_counters_internal.task_metadata_writes, 1158 t.task_writes_counters_external.task_immediate_writes, 1159 t.task_writes_counters_external.task_deferred_writes, 1160 t.task_writes_counters_external.task_invalidated_writes, 1161 t.task_writes_counters_external.task_metadata_writes, 1162 GetProcName(pval))) 1163 1164 1165@lldb_command('showalltasks','C R', fancy=True) 1166def ShowAllTasks(cmd_args=None, cmd_options={}, O=None): 1167 """ Routine to print a summary listing of all the tasks 1168 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" 1169 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung 1170 io_policy -> RAGE - rapid aging of vnodes requested 1171 NORM - normal I/O explicitly requested (this is the default) 1172 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) 1173 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) 1174 Usage: (lldb) showalltasks -C : describe the corpse structure 1175 Usage: (lldb) showalltasks -R : describe the task role app status 1176 """ 1177 global kern 1178 extra_hdr = '' 1179 showcorpse = False 1180 showrole = False 1181 if '-C' in cmd_options: 1182 showcorpse = True 1183 extra_hdr += " " + GetKCDataSummary.header 1184 1185 if '-R' in cmd_options: 1186 showrole = True 1187 extra_hdr += " " + GetTaskRoleSummary.header 1188 1189 with O.table(GetTaskSummary.header + extra_hdr + " " + GetProcSummary.header): 1190 for t in kern.tasks: 1191 pval = GetProcFromTask(t) 1192 print(GetTaskSummary(t, showcorpse) + " " + (GetTaskRoleSummary(t) + " " if showrole else "") 1193 + GetProcSummary(pval)) 1194 1195 ZombTasks() 1196 1197def TaskForPmapHelper(pmap) -> Optional[value]: 1198 """ Given a pmap pointer, return the task pointer which contains that 1199 address space. 1200 1201 pmap: PMAP pointer whose task to find. 1202 """ 1203 for tasklist in [kern.tasks, kern.terminated_tasks]: 1204 for task in tasklist: 1205 if kern.GetValueFromAddress(unsigned(task.map.pmap), 'pmap_t') == pmap: 1206 return task 1207 1208 return None 1209 1210@lldb_command('taskforpmap') 1211def TaskForPmap(cmd_args=None): 1212 """ Find the task whose pmap corresponds to <pmap>. 1213 Syntax: (lldb) taskforpmap <pmap> 1214 Multiple -v's can be specified for increased verbosity 1215 """ 1216 if cmd_args is None or len(cmd_args) < 1: 1217 raise ArgumentError("Too few arguments to taskforpmap.") 1218 pmap = kern.GetValueFromAddress(cmd_args[0], 'pmap_t') 1219 task = TaskForPmapHelper(pmap) 1220 1221 if task is None: 1222 print("Couldn't find task for pmap {:#x}".format(pmap)) 1223 return 1224 1225 print(GetTaskSummary.header + " " + GetProcSummary.header) 1226 pval = GetProcFromTask(task) 1227 print(GetTaskSummary(task) + " " + GetProcSummary(pval)) 1228 1229@lldb_command('showterminatedtasks') 1230def ShowTerminatedTasks(cmd_args=None): 1231 """ Routine to print a summary listing of all the terminated tasks 1232 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" 1233 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung 1234 io_policy -> RAGE - rapid aging of vnodes requested 1235 NORM - normal I/O explicitly requested (this is the default) 1236 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) 1237 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) 1238 syntax: (lldb)showallterminatedtasks 1239 """ 1240 global kern 1241 print(GetTaskSummary.header + " " + GetProcSummary.header) 1242 for t in kern.terminated_tasks: 1243 1244 # If the task has been terminated it's likely that the process is 1245 # gone too. If there is no proc it may still be possible to find 1246 # the original proc name. 1247 pval = GetProcFromTask(t) 1248 if pval is not None: 1249 psummary = GetProcSummary(pval) 1250 else: 1251 name = GetProcNameForTask(t); 1252 pslen = GetProcSummary.header.find("command"); 1253 psummary = "{0: <{indent}} {1: <s}".format("", name, indent = pslen - 1) 1254 1255 print(GetTaskSummary(t) + " " + psummary) 1256 1257 return True 1258 1259# Macro: showtaskstacks 1260 1261def TokenExistsInStack(thread, regex): 1262 thread_val = GetLLDBThreadForKernelThread(thread) 1263 for frame in thread_val.frames: 1264 if frame.GetFunction(): 1265 func_name = frame.GetFunctionName() 1266 func_arguments = frame.arguments 1267 matching_argument = any( 1268 True if regex.search(str(arg.type)) or regex.search(str(arg.value)) else False 1269 for arg in func_arguments 1270 ) 1271 if regex.search(func_name) or matching_argument: 1272 return True 1273 return False 1274 1275def ShowTaskStacks(task, O=None, regex=None): 1276 """ Print a task with summary and stack information for each of its threads 1277 """ 1278 global kern 1279 first = True 1280 1281 for th in IterateQueue(task.threads, 'thread *', 'task_threads'): 1282 if regex is None or TokenExistsInStack(th, regex): 1283 if first: 1284 print(GetTaskSummary.header + " " + GetProcSummary.header) 1285 pval = GetProcFromTask(task) 1286 print(GetTaskSummary(task) + " " + GetProcSummary(pval)) 1287 first = False 1288 with O.table(GetThreadSummary.header, indent=True): 1289 print(GetThreadSummary(th, O=O)) 1290 print(GetThreadBackTrace(th, prefix=" ") + "\n") 1291 1292 1293def FindTasksByName(searchstr, ignore_case=True): 1294 """ Search the list of tasks by name. 1295 params: 1296 searchstr: str - a regex like string to search for task 1297 ignore_case: bool - If False then exact matching will be enforced 1298 returns: 1299 [] - array of task object. Empty if not found any 1300 """ 1301 re_options = 0 1302 if ignore_case: 1303 re_options = re.IGNORECASE 1304 search_regex = re.compile(searchstr, re_options) 1305 retval = [] 1306 for t in kern.tasks: 1307 pval = GetProcFromTask(t) 1308 process_name = "{:s}".format(GetProcName(pval)) 1309 if search_regex.search(process_name): 1310 retval.append(t) 1311 return retval 1312 1313@lldb_command('showtaskstacks', 'F:', fancy=True) 1314def ShowTaskStacksCmdHelper(cmd_args=None, cmd_options={}, O=None): 1315 """ Routine to print out the stack for each thread in a task 1316 Usage: showtaskstacks <0xaddress of task> 1317 or: showtaskstacks -F launchd 1318 """ 1319 1320 if "-F" in cmd_options: 1321 find_task_str = cmd_options["-F"] 1322 task_list = FindTasksByName(find_task_str) 1323 for tval in task_list: 1324 ShowTaskStacks(tval, O=O) 1325 return 1326 1327 if not cmd_args: 1328 raise ArgumentError("No arguments passed") 1329 1330 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 1331 if not tval: 1332 raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args))) 1333 else: 1334 ShowTaskStacks(tval, O=O) 1335 1336# EndMacro: showtaskstacks 1337 1338def CheckTaskProcRefs(task, proc, O=None): 1339 btlib = kmemory.BTLibrary.get_shared() 1340 1341 for thread in IterateQueue(task.threads, 'thread *', 'task_threads'): 1342 uthread = GetBSDThread(thread) 1343 refcount = int(uthread.uu_proc_refcount) 1344 uu_ref_info = uthread.uu_proc_ref_info 1345 if int(uu_ref_info) == 0: 1346 continue 1347 uu_ref_index = int(uu_ref_info.upri_pindex) 1348 if refcount == 0: 1349 continue 1350 for ref in range(0, uu_ref_index): 1351 if unsigned(uu_ref_info.upri_proc_ps[ref]) == unsigned(proc): 1352 print(GetTaskSummary.header + " " + GetProcSummary.header) 1353 pval = GetProcFromTask(task) 1354 print(GetTaskSummary(task) + " " + GetProcSummary(pval)) 1355 with O.table(GetThreadSummary.header, indent=True): 1356 print(GetThreadSummary(thread, O=O)) 1357 1358 bts = btlib.get_stack(unsigned(uu_ref_info.upri_proc_stacks[ref])) 1359 print(*bts.symbolicated_frames(), sep="\n") 1360 1361@lldb_command('showprocrefs', fancy=True) 1362def ShowProcRefs(cmd_args=None, cmd_options={}, O=None): 1363 """ Display information on threads/BTs that could be holding a reference on the specified proc 1364 NOTE: We can't say affirmatively if any of these references are still held since 1365 there's no way to pair references with drop-refs in the current infrastructure. 1366 Usage: showprocrefs <proc> 1367 """ 1368 if cmd_args is None or len(cmd_args) < 1: 1369 raise ArgumentError("No arguments passed") 1370 1371 proc = kern.GetValueFromAddress(cmd_args[0], 'proc *') 1372 1373 for t in kern.tasks: 1374 CheckTaskProcRefs(t, proc, O=O) 1375 for t in kern.terminated_tasks: 1376 CheckTaskProcRefs(t, proc, O=O) 1377 1378@lldb_command('showallthreads', fancy=True) 1379def ShowAllThreads(cmd_args=None, cmd_options={}, O=None): 1380 """ Display info about all threads in the system 1381 """ 1382 1383 # Terminated threads get prefixed with a 'T' 1384 def ShowTaskTerminatedThreads(task, O=O): 1385 tlist = tmap.get(unsigned(task), []) 1386 for thval in tlist: 1387 print("T\t" + GetThreadSummary(thval, O=O)) 1388 1389 # Task -> [thread, ..] map of terminated threads 1390 tmap = defaultdict(list) 1391 for thr in kern.terminated_threads: 1392 tmap[unsigned(thr.t_tro.tro_task)].append(thr) 1393 1394 for t in kern.tasks: 1395 ShowTaskThreads([str(int(t))], O=O) 1396 ShowTaskTerminatedThreads(t, O=O) 1397 print(" \n") 1398 1399 for t in kern.terminated_tasks: 1400 print("Terminated: \n") 1401 ShowTaskThreads([str(int(t))], O=O) 1402 ShowTaskTerminatedThreads(t, O=O) 1403 print(" \n") 1404 1405 return 1406 1407@lldb_command('showterminatedthreads', fancy=True) 1408def ShowTerminatedThreads(cmd_args=None, cmd_options={}, O=None): 1409 """ Display info about all terminated threads in the system 1410 """ 1411 1412 with O.table(GetThreadSummary.header, indent=True): 1413 for t in kern.terminated_threads: 1414 print(GetThreadSummary(t, O=O)) 1415 1416 1417@lldb_command('showtaskthreads', "F:", fancy=True) 1418def ShowTaskThreads(cmd_args = None, cmd_options={}, O=None): 1419 """ List the threads of a task. 1420 Usage: showtaskthreads <task-ptr> 1421 or: showtaskthreads -F <name> 1422 """ 1423 task_list = [] 1424 if "-F" in cmd_options: 1425 task_list = FindTasksByName(cmd_options["-F"]) 1426 elif cmd_args: 1427 t = kern.GetValueFromAddress(cmd_args[0], 'task *') 1428 task_list = [t] 1429 else: 1430 raise ArgumentError("No arguments passed") 1431 1432 for task in task_list: 1433 print(GetTaskSummary.header + " " + GetProcSummary.header) 1434 pval = GetProcFromTask(task) 1435 print(GetTaskSummary(task) + " " + GetProcSummary(pval)) 1436 with O.table(GetThreadSummary.header, indent=True): 1437 for thval in IterateQueue(task.threads, 'thread *', 'task_threads'): 1438 print(GetThreadSummary(thval, O=O)) 1439 return 1440 1441@lldb_command('showact', fancy=True) 1442def ShowAct(cmd_args=None, cmd_options={}, O=None): 1443 """ Routine to print out the state of a specific thread. 1444 usage: showact <activation> 1445 """ 1446 if not cmd_args: 1447 raise ArgumentError("No arguments passed") 1448 threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 1449 with O.table(GetThreadSummary.header): 1450 print(GetThreadSummary(threadval, O=O)) 1451 1452@lldb_command('showactstack', fancy=True) 1453def ShowActStack(cmd_args=None, cmd_options={}, O=None): 1454 """ Routine to print out the stack of a specific thread. 1455 usage: showactstack <activation> 1456 """ 1457 if not cmd_args: 1458 raise ArgumentError("No arguments passed") 1459 threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 1460 with O.table(GetThreadSummary.header): 1461 print(GetThreadSummary(threadval, O=O)) 1462 print(GetThreadBackTrace(threadval, prefix="\t")) 1463 return 1464 1465@lldb_command('switchtoact', fancy=True) 1466def SwitchToAct(cmd_args=None, cmd_options={}, O=None): 1467 """ Switch to different context specified by activation 1468 This command allows gdb to examine the execution context and call 1469 stack for the specified activation. For example, to view the backtrace 1470 for an activation issue "switchtoact <address>", followed by "bt". 1471 Before resuming execution, issue a "resetctx" command, to 1472 return to the original execution context. 1473 """ 1474 if cmd_args is None or len(cmd_args) < 1: 1475 raise ArgumentError("No arguments passed") 1476 thval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 1477 lldbthread = GetLLDBThreadForKernelThread(thval) 1478 with O.table(GetThreadSummary.header): 1479 print(GetThreadSummary(thval, O=O)) 1480 LazyTarget.GetProcess().selected_thread = lldbthread 1481 if not LazyTarget.GetProcess().SetSelectedThread(lldbthread): 1482 print("Failed to switch thread.") 1483 return 1484 1485@lldb_command('switchtoregs') 1486def SwitchToRegs(cmd_args=None): 1487 """ Routine to switch to a register state. 1488 Usage: (lldb) switchtoregs <struct arm_saved_state[64] *> 1489 This command creates a fake thread in lldb with the saved register state. 1490 Note: This command ONLY works for ARM based kernel setup. 1491 """ 1492 1493 if cmd_args is None or len(cmd_args) < 1: 1494 raise ArgumentError("No arguments passed") 1495 1496 lldb_process = LazyTarget.GetProcess() 1497 1498 saved_state = ArgumentStringToInt(cmd_args[0]) 1499 # any change to this logic requires change in operating_system.py as well 1500 fake_thread_id = 0xdead0000 | (saved_state & ~0xffff0000) 1501 fake_thread_id = fake_thread_id & 0xdeadffff 1502 lldb_process.CreateOSPluginThread(0xdeadbeef, saved_state) 1503 lldbthread = lldb_process.GetThreadByID(int(fake_thread_id)) 1504 1505 if not lldbthread.IsValid(): 1506 print("Failed to create thread") 1507 return 1508 1509 lldb_process.selected_thread = lldbthread 1510 if not lldb_process.SetSelectedThread(lldbthread): 1511 print("Failed to switch thread") 1512 print("Switched to Fake thread created from register state at {:#x}".format( 1513 saved_state)) 1514 1515# Macro: showcallchains 1516CallChainNode = namedtuple("CallChainNode", "callers threads") 1517 1518def GatherCallChainsDFS(cur_node: CallChainNode, call_chains, cur_path): 1519 if cur_node.threads: 1520 call_chain = " <- ".join(cur_path) 1521 call_chains[call_chain] = cur_node.threads 1522 1523 for next_func_name, next_node in cur_node.callers.items(): 1524 cur_path.append(next_func_name) 1525 GatherCallChainsDFS(next_node, call_chains, cur_path) 1526 cur_path.pop() 1527 1528 1529def GetCallChains(filter_regex) -> dict[str, list[str]]: 1530 ## Filter threads and build call graph 1531 root = CallChainNode({"root": CallChainNode({}, [])}, []) 1532 1533 zomb_tasks = [t for proc in kern.zombprocs if (t := GetTaskFromProc(proc)) is not None] 1534 for t in kern.tasks + zomb_tasks: 1535 for th in IterateQueue(t.threads, 'thread *', 'task_threads'): 1536 thread_val = GetLLDBThreadForKernelThread(th) 1537 cur_node = root 1538 prev_func_name = "root" 1539 matched = False 1540 1541 for frame in thread_val.frames: 1542 if frame.GetFunction(): 1543 func_name = frame.GetFunctionName() 1544 func_arguments = frame.arguments 1545 matching_argument = any( 1546 True if filter_regex.match(str(arg.type)) or filter_regex.match(str(arg.value)) else False 1547 for arg in func_arguments 1548 ) 1549 if filter_regex.match(func_name) or matching_argument: 1550 matched = True 1551 1552 callers = cur_node.callers[prev_func_name].callers 1553 callers[func_name] = callers.get(func_name, CallChainNode({}, [])) 1554 1555 cur_node = cur_node.callers[prev_func_name] 1556 prev_func_name = func_name 1557 1558 if matched: 1559 cur_node.callers[prev_func_name].threads.append(th) 1560 1561 ## gather call chains 1562 call_chains: dict[str, list[str]] = {} 1563 GatherCallChainsDFS(root.callers["root"], call_chains, []) 1564 1565 return call_chains 1566 1567CallChainThreadInfo = namedtuple('CallChainThreadInfo', ['hex', 'state', 'base', 'pri', 'since_off', 'wait_evt', 'wait_evt_sym', 'thread_name', 'task_name']) 1568 1569@lldb_command('showcallchains', fancy=True) 1570def ShowCallChains(cmd_args=None, cmd_options={}, O=None): 1571 """Routine to print out thread IDs, bucketized by function call chains 1572 1573 Usage: showcallchains <regex> 1574 The regex filters function names. Function names that don't match the regex are ignored. 1575 """ 1576 1577 if not cmd_args: 1578 raise ArgumentError("No arguments passed.") 1579 1580 show_call_chain(cmd_args[0],O) 1581 1582def show_call_chain(param, O=None): 1583 1584 try: 1585 regex = re.compile(param) 1586 except: 1587 raise ArgumentError("Invalid predicate regex passed: {}".format(param[0])) 1588 1589 call_chains = GetCallChains(regex) 1590 1591 summary_str = "{info.hex: <20s} {info.state: <8s} {info.base: <6s} {info.pri: <10s} {info.since_off: <20s} {info.wait_evt: <20s} {info.wait_evt_sym: <20s} {info.thread_name: <20.20s} {info.task_name: <20s}" 1592 header = summary_str.format(info=CallChainThreadInfo('thread', 'state', 'base', 'pri', 'since-off (us)', 'wait_evt', 'wait_evt_sym', 'thread_name', 'task_name')) 1593 1594 ## sort desc by time_since_off 1595 from scheduler import GetSchedMostRecentDispatch 1596 most_recent_dispatch = GetSchedMostRecentDispatch(False) 1597 def GetTimeSinceOff(th): 1598 last_off = th.last_run_time 1599 time_since_off_abs = unsigned(most_recent_dispatch - last_off) 1600 return time_since_off_abs 1601 1602 for call_chain, threads in call_chains.copy().items(): 1603 call_chains[call_chain] = sorted( 1604 zip(threads, (GetTimeSinceOff(th) for th in threads)), 1605 reverse=True, 1606 key=lambda a: a[1] 1607 ) 1608 1609 ## print results 1610 for call_chain, threads in sorted( 1611 list(call_chains.items()), 1612 key = lambda a: len(a[1]) 1613 ): 1614 print("{0}, {1} thread{2}".format(call_chain, len(threads), len(threads) > 1 and "s" or "")) 1615 1616 with O.table(header, indent=True): 1617 for th, time_since_off_abs in threads: 1618 thread_hex = '{:<#018x}'.format(th) 1619 base_priority = str(int(th.base_pri)) 1620 sched_priority = str(int(th.sched_pri)) 1621 1622 state = int(th.state) 1623 state_str = '' 1624 mask = 0x1 1625 while mask <= LAST_THREAD_STATE: 1626 state_str += THREAD_STATE_CHARS[int(state & mask)] 1627 mask <<= 1 1628 if int(th.inspection): 1629 state_str += 'C' 1630 1631 wait_event_str = '' 1632 wait_event_str_sym = '' 1633 if state & 0x1: # WAIT 1634 wait_event_str = '{:<#018x}'.format(unsigned(th.wait_event)) 1635 wait_event_str_sym = kern.Symbolicate(int(hex(th.wait_event), 16)) 1636 1637 time_since_off_us = "{:,}".format(kern.GetNanotimeFromAbstime(time_since_off_abs) / 1000.0) 1638 1639 uthread = GetBSDThread(th) 1640 thread_name = GetThreadNameFromBSDThread(uthread) 1641 1642 pval = GetProcFromTask(th.t_tro.tro_task) 1643 task_name = GetProcName(pval) 1644 1645 info = CallChainThreadInfo(hex=thread_hex, state=state_str, base=base_priority, pri=sched_priority, since_off=time_since_off_us, 1646 wait_evt=wait_event_str, wait_evt_sym=wait_event_str_sym, thread_name=thread_name, task_name=task_name) 1647 info_str = summary_str.format(info=info) 1648 1649 print(O.format(info_str)) 1650 print("") 1651 1652 print("Summary:") 1653 print("{} different call chains".format(len(call_chains))) 1654# Endmacro showcallchains 1655 1656 1657# Macro: showallstacks 1658@lldb_command('showallstacks', "R:", fancy=True) 1659def ShowAllStacks(cmd_args=None, cmd_options={}, O=None): 1660 """Routine to print out the stack for each thread in the system. 1661 Usage: showallstacks [-R REGEX] 1662 -R : Only show stacks with function names matching the provided regular expression 1663 """ 1664 if "-R" in cmd_options: 1665 regex = re.compile(cmd_options['-R']) 1666 else: 1667 regex = None 1668 for t in kern.tasks: 1669 ShowTaskStacks(t, O=O, regex=regex) 1670 if regex is None: 1671 print(" \n") 1672 1673 ShowZombStacks(O=O, regex=regex) 1674# EndMacro: showallstacks 1675 1676# Macro: showcurrentstacks 1677@lldb_command('showcurrentstacks', fancy=True) 1678def ShowCurrentStacks(cmd_args=None, cmd_options={}, O=None): 1679 """ Routine to print out the thread running on each cpu (incl. its stack) 1680 """ 1681 processor_list = kern.GetGlobalVariable('processor_list') 1682 current_processor = processor_list 1683 while unsigned(current_processor) > 0: 1684 print("\n" + GetProcessorSummary(current_processor)) 1685 active_thread = current_processor.active_thread 1686 if unsigned(active_thread) != 0: 1687 task_val = active_thread.t_tro.tro_task 1688 proc_val = GetProcFromTask(task_val) 1689 print(GetTaskSummary.header + " " + GetProcSummary.header) 1690 print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val)) 1691 with O.table(GetThreadSummary.header, indent=True): 1692 print(GetThreadSummary(active_thread, O=O)) 1693 print("\tBacktrace:") 1694 print(GetThreadBackTrace(active_thread, prefix="\t")) 1695 current_processor = current_processor.processor_list 1696 return 1697# EndMacro: showcurrentstacks 1698 1699@lldb_command('showcurrentthreads', fancy=True) 1700def ShowCurrentThreads(cmd_args=None, cmd_options={}, O=None): 1701 """ Display info about threads running on each cpu """ 1702 processor_list = kern.GetGlobalVariable('processor_list') 1703 current_processor = processor_list 1704 while unsigned(current_processor) > 0: 1705 print(GetProcessorSummary(current_processor)) 1706 active_thread = current_processor.active_thread 1707 if unsigned(active_thread) != 0 : 1708 task_val = active_thread.t_tro.tro_task 1709 proc_val = GetProcFromTask(task_val) 1710 print(GetTaskSummary.header + " " + GetProcSummary.header) 1711 print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val)) 1712 with O.table(GetThreadSummary.header, indent=True): 1713 print(GetThreadSummary(active_thread, O=O)) 1714 current_processor = current_processor.processor_list 1715 return 1716 1717def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""): 1718 """ Get backtrace across interrupt context. 1719 params: frame_addr - int - address in memory which is a frame pointer (ie. rbp, r7) 1720 prefix - str - prefix for each line of output. 1721 1722 """ 1723 out_string = "" 1724 bt_count = 0 1725 frame_ptr = frame_addr 1726 previous_frame_ptr = 0 1727 while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128: 1728 pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *') 1729 pc_val = kern.StripKernelPAC(unsigned(dereference(pc_val))) 1730 out_string += prefix + GetSourceInformationForAddress(pc_val) + "\n" 1731 bt_count +=1 1732 previous_frame_ptr = frame_ptr 1733 frame_val = kern.GetValueFromAddress((frame_ptr), 'uintptr_t *') 1734 if unsigned(frame_val) == 0: 1735 break 1736 frame_ptr = unsigned(dereference(frame_val)) 1737 1738 return out_string 1739 1740@lldb_command('fullbt') 1741def FullBackTrace(cmd_args=[]): 1742 """ Show full backtrace across the interrupt boundary. 1743 Syntax: fullbt <frame ptr> 1744 Example: fullbt `$rbp` 1745 """ 1746 if len(cmd_args) < 1: 1747 print(FullBackTrace.__doc__) 1748 return False 1749 print(GetFullBackTrace(ArgumentStringToInt(cmd_args[0]), prefix="\t")) 1750 1751@lldb_command('fullbtall', fancy=True) 1752def FullBackTraceAll(cmd_args=[], cmd_options={}, O=None): 1753 """ Show full backtrace across the interrupt boundary for threads running on all processors. 1754 Syntax: fullbtall 1755 Example: fullbtall 1756 """ 1757 for processor in IterateLinkedList(kern.globals.processor_list, 'processor_list') : 1758 print("\n" + GetProcessorSummary(processor)) 1759 active_thread = processor.active_thread 1760 if unsigned(active_thread) != 0 : 1761 task_val = active_thread.t_tro.tro_task 1762 proc_val = GetProcFromTask(task_val) 1763 print(GetTaskSummary.header + " " + GetProcSummary.header) 1764 print(GetTaskSummary(task_val) + " " + GetProcSummary(proc_val)) 1765 with O.table(GetThreadSummary.header, indent=True): 1766 print(GetThreadSummary(active_thread, O=O)) 1767 print("\tBacktrace:") 1768 1769 ThreadVal = GetLLDBThreadForKernelThread(active_thread) 1770 1771 FramePtr = ThreadVal.frames[0].GetFP() 1772 1773 print(GetFullBackTrace(unsigned(FramePtr), prefix="\t")) 1774 1775 1776@lldb_command('symbolicate') 1777def SymbolicateAddress(cmd_args=[]): 1778 """ Symbolicate an address for symbol information from loaded symbols 1779 Example: "symbolicate 0xaddr" is equivalent to "output/a 0xaddr" 1780 """ 1781 if len(cmd_args) < 1: 1782 print("Invalid address.\nSyntax: symbolicate <address>") 1783 return False 1784 print(GetSourceInformationForAddress(ArgumentStringToInt(cmd_args[0]))) 1785 return True 1786 1787@lldb_command('showinitchild') 1788def ShowInitChild(cmd_args=None): 1789 """ Routine to print out all processes in the system 1790 which are children of init process 1791 """ 1792 headp = kern.globals.initproc.p_children 1793 for pp in IterateListEntry(headp, 'p_sibling'): 1794 print(GetProcInfo(pp)) 1795 return 1796 1797@lldb_command('showproctree') 1798def ShowProcTree(cmd_args=None): 1799 """ Routine to print the processes in the system in a hierarchical tree form. This routine does not print zombie processes. 1800 If no argument is given, showproctree will print all the processes in the system. 1801 If pid is specified, showproctree prints all the descendants of the indicated process 1802 """ 1803 search_pid = 0 1804 if cmd_args: 1805 search_pid = ArgumentStringToInt(cmd_args[0]) 1806 1807 if search_pid < 0: 1808 print("pid specified must be a positive number") 1809 print(ShowProcTree.__doc__) 1810 return 1811 1812 hdr_format = "{0: <6s} {1: <14s} {2: <9s}\n" 1813 out_string = hdr_format.format("PID", "PROCESS", "POINTER") 1814 out_string += hdr_format.format('='*3, '='*7, '='*7) 1815 proc = GetProcForPid(search_pid) 1816 out_string += "{0: <6d} {1: <32s} [ {2: #019x} ]\n".format( 1817 proc.p_ppid, GetProcName(proc.p_pptr), unsigned(proc.p_pptr)) 1818 out_string += "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format( 1819 GetProcPID(proc), GetProcName(proc), unsigned(proc)) 1820 print(out_string) 1821 ShowProcTreeRecurse(proc, "| ") 1822 1823def ShowProcTreeRecurse(proc, prefix=""): 1824 """ Prints descendants of a given proc in hierarchial tree form 1825 params: 1826 proc : core.value representing a struct proc * in the kernel 1827 returns: 1828 str : String containing info about a given proc and its descendants in tree form 1829 """ 1830 if proc.p_childrencnt > 0: 1831 head_ptr = proc.p_children.lh_first 1832 1833 for p in IterateListEntry(proc.p_children, 'p_sibling'): 1834 print(prefix + "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format( 1835 GetProcPID(p), GetProcName(p), unsigned(p))) 1836 ShowProcTreeRecurse(p, prefix + "| ") 1837 1838@lldb_command('showthreadfortid', fancy=True) 1839def ShowThreadForTid(cmd_args=None, O=None): 1840 """ The thread structure contains a unique thread_id value for each thread. 1841 This command is used to retrieve the address of the thread structure(thread_t) 1842 corresponding to a given thread_id. 1843 """ 1844 if not cmd_args: 1845 print("Please provide thread_t whose tid you'd like to look up") 1846 print(ShowThreadForTid.__doc__) 1847 return 1848 search_tid = ArgumentStringToInt(cmd_args[0]) 1849 for taskp in kern.tasks: 1850 for actp in IterateQueue(taskp.threads, 'struct thread *', 'task_threads'): 1851 if search_tid == int(actp.thread_id): 1852 print("Found {0: #019x}".format(actp)) 1853 with O.table(GetThreadSummary.header): 1854 print(GetThreadSummary(actp, O=O)) 1855 return 1856 print("Not a valid thread_id") 1857 1858def GetProcessorSummary(processor): 1859 """ Internal function to print summary of processor 1860 params: processor - value representing struct processor * 1861 return: str - representing the details of given processor 1862 """ 1863 1864 processor_state_str = "INVALID" 1865 processor_state = int(processor.state) 1866 1867 processor_states = { 1868 0: 'OFF_LINE', 1869 1: 'SHUTDOWN', 1870 2: 'START', 1871 3: 'PENDING_OFFLINE', 1872 4: 'IDLE', 1873 5: 'DISPATCHING', 1874 6: 'RUNNING' 1875 } 1876 1877 if processor_state in processor_states: 1878 processor_state_str = "{0: <11s} ".format(processor_states[processor_state]) 1879 1880 processor_recommended_str = "" 1881 if int(processor.is_recommended) == 0: 1882 processor_recommended_str = " (not recommended)" 1883 1884 ast = 0 1885 preemption_disable = 0 1886 preemption_disable_str = "" 1887 1888 if kern.arch == 'x86_64': 1889 cpu_data = kern.globals.cpu_data_ptr[processor.cpu_id] 1890 if (cpu_data != 0) : 1891 ast = cpu_data.cpu_pending_ast 1892 preemption_disable = cpu_data.cpu_preemption_level 1893 # On arm64, it's kern.globals.CpuDataEntries[processor.cpu_id].cpu_data_vaddr 1894 # but LLDB can't find CpuDataEntries... 1895 1896 ast_str = GetASTSummary(ast) 1897 1898 if (preemption_disable != 0) : 1899 preemption_disable_str = "Preemption Disabled" 1900 1901 processor_reasons = { 1902 0: '(REASON_NONE)', 1903 1: '(REASON_SYSTEM)', 1904 2: '(REASON_USER)', 1905 3: '(REASON_CLPC_SYSTEM)', 1906 4: '(REASON_CLPC_USER)' 1907 } 1908 1909 processor_shutdown_reason_str = ""; 1910 processor_shutdown_reason = int(processor.last_shutdown_reason) 1911 1912 if processor_state in {0, 1, 3}: 1913 processor_shutdown_reason_str = processor_reasons[processor_shutdown_reason] 1914 1915 out_str = "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {:<s}{:<s}{:<s} {:<s}\n".format( 1916 processor, int(processor.cpu_id), ast_str, processor_state_str, processor_shutdown_reason_str, 1917 processor_recommended_str, preemption_disable_str) 1918 return out_str 1919 1920ledger_limit_infinity = (uint64_t(0x1).value << 63) - 1 1921 1922def GetLedgerEntryIndex(template, name): 1923 i = 0 1924 while i != template.lt_cnt: 1925 if str(template.lt_entries[i].et_key) == name: 1926 return i 1927 i = i + 1 1928 return -1 1929 1930def GetLedgerEntryWithTemplate(ledger_template, ledgerp, i): 1931 """ Internal function to get internals of a ledger entry (*not* a ledger itself) 1932 params: ledger_template - value representing struct ledger_template_t for the task or thread 1933 ledgerp - value representing ledger pointer 1934 i - index in ledger 1935 return: entry - entry dictionary 1936 """ 1937 lf_refill_scheduled = 0x0400 1938 lf_tracking_max = 0x4000 1939 1940 now = unsigned(kern.globals.sched_tick) // 20 1941 lim_pct = 0 1942 1943 entry = {} 1944 1945 et = ledger_template.lt_entries[i] 1946 entry["key"] = str(et.et_key) 1947 if et.et_size == sizeof("struct ledger_entry_small"): 1948 les = ledgerp.l_entries[et.et_offset] 1949 entry["credit"] = unsigned(les.les_credit) 1950 entry["debit"] = 0 1951 entry["flags"] = int(les.les_flags) 1952 entry["limit"] = ledger_limit_infinity 1953 elif et.et_size == sizeof("struct ledger_entry"): 1954 le = Cast(addressof(ledgerp.l_entries[et.et_offset]), "struct ledger_entry *") 1955 entry["credit"] = unsigned(le.le_credit) 1956 entry["debit"] = unsigned(le.le_debit) 1957 if (le.le_flags & lf_tracking_max): 1958 if hasattr(le._le._le_max, "le_interval_max"): 1959 entry["interval_max"] = unsigned(le._le._le_max.le_interval_max) 1960 entry["lifetime_max"] = unsigned(le._le._le_max.le_lifetime_max) 1961 1962 entry["limit"] = unsigned(le.le_limit) 1963 1964 if (le.le_flags & lf_refill_scheduled): 1965 entry["refill_period"] = unsigned (le._le.le_refill.le_refill_period) 1966 1967 if (unsigned(le.le_warn_percent) < 65535): 1968 entry["warn_percent"] = unsigned (le.le_warn_percent * 100 / 65536) 1969 entry["flags"] = int(le.le_flags) 1970 entry["diag_threshold_scaled"] = int(le.le_diag_threshold_scaled) 1971 else: 1972 return None 1973 1974 entry["balance"] = entry["credit"] - entry["debit"] 1975 return entry 1976 1977def GetLedgerEntryWithName(ledger_template, ledger, name): 1978 idx = GetLedgerEntryIndex(ledger_template, name) 1979 assert(idx != -1) 1980 return GetLedgerEntryWithTemplate(ledger_template, ledger, idx) 1981 1982def FormatLedgerEntrySummary(entry, i, show_footprint_interval_max=False): 1983 """ internal function to format a ledger entry into a string 1984 params: entry - A python dictionary containing the ledger entry 1985 return: str - formatted output information of ledger entries 1986 """ 1987 out_str = '' 1988 out_str += "{: >32s} {:<2d}:".format(entry["key"], i) 1989 out_str += "{: >15d} ".format(entry["balance"]) 1990 1991 if (show_footprint_interval_max): 1992 if "interval_max" in entry: 1993 out_str += "{:12d} ".format(entry["interval_max"]) 1994 else: 1995 out_str += " - " 1996 1997 if "lifetime_max" in entry: 1998 out_str += "{:14d} ".format(entry["lifetime_max"]) 1999 else: 2000 out_str += " - " 2001 2002 out_str += "{:12d} {:12d} ".format(entry["credit"], entry["debit"]) 2003 if entry.get('limit', unsigned(ledger_limit_infinity)) != unsigned(ledger_limit_infinity): 2004 out_str += "{:12d} ".format(unsigned(entry["limit"])) 2005 else: 2006 out_str += " - " 2007 2008 if "refill_period" in entry: 2009 out_str += "{:15d} ".format(entry["refill_period"]) 2010 if entry["refill_period"] != 0: 2011 out_str += "{:9d} ".format((entry["limit"] * 100) // entry["refill_period"]) 2012 else: 2013 out_str += "XXXXX - " 2014 else: 2015 out_str += " - " 2016 out_str += " - " 2017 2018 if "warn_percent" in entry: 2019 out_str += "{:9d} ".format(entry["warn_percent"]) 2020 else: 2021 out_str += " - " 2022 2023 if "limit" in entry: 2024 if entry["balance"] > entry["limit"]: 2025 out_str += " X " 2026 else: 2027 out_str += " " 2028 else: 2029 out_str += " " 2030 2031 out_str += "{:#8x}\n".format(entry["flags"]) 2032 return out_str 2033 2034def GetLedgerEntrySummary(ledger_template, ledger, i, show_footprint_interval_max=False): 2035 """ internal function to get internals of a ledger entry (*not* a ledger itself) 2036 params: ledger_template - value representing struct ledger_template_t for the task or thread 2037 ledger - value representing ledger pointer 2038 return: str - formatted output information of ledger entries 2039 """ 2040 entry = GetLedgerEntryWithTemplate(ledger_template, ledger, i) 2041 return FormatLedgerEntrySummary(entry, i) 2042 2043 2044def GetThreadLedgers(thread_val): 2045 """ Internal function to get a summary of ledger entries for the given thread 2046 params: thread_val - value representing struct thread * 2047 return: thread - python dictionary containing threads's ledger entries. This can 2048 be printed directly with FormatThreadLedgerSummmary or outputted as json. 2049 """ 2050 thread = {} 2051 thread["address"] = unsigned(thread_val) 2052 ledgerp = thread_val.t_threadledger 2053 thread["entries"] = [] 2054 if ledgerp: 2055 i = 0 2056 while i != ledgerp.l_template.lt_cnt: 2057 thread["entries"].append(GetLedgerEntryWithTemplate(kern.globals.thread_ledger_template, 2058 ledgerp, i)) 2059 i = i + 1 2060 return thread 2061 2062def FormatThreadLedgerSummary(thread): 2063 """ Internal function to print a thread's ledger entries 2064 params: thread - python dictionary containing thread's ledger entries 2065 return: str - formatted output information for ledger entries of the input thread 2066 """ 2067 out_str = " [{:#08x}]\n".format(thread["address"]) 2068 entries = thread["entries"] 2069 for i, entry in enumerate(entries): 2070 out_str += FormatLedgerEntrySummary(entry, i) 2071 return out_str 2072 2073def GetTaskLedgers(task_val): 2074 """ Internal function to get summary of ledger entries from the task and its threads 2075 params: task_val - value representing struct task * 2076 return: task - python dictionary containing tasks's ledger entries. This can 2077 be printed directly with FormatTaskLedgerSummary or outputted as json. 2078 """ 2079 task_ledgerp = task_val.ledger 2080 i = 0 2081 tasks = [] 2082 task = {} 2083 task["address"] = unsigned(task_val) 2084 2085 pval = GetProcFromTask(task_val) 2086 if pval is not None: 2087 task["name"] = GetProcName(pval) 2088 task["pid"] = int(GetProcPID(pval)) 2089 2090 task["entries"] = [] 2091 while i != task_ledgerp.l_template.lt_cnt: 2092 task["entries"].append(GetLedgerEntryWithTemplate(kern.globals.task_ledger_template, task_ledgerp, i)) 2093 i = i + 1 2094 2095 # Now walk threads 2096 task["threads"] = [] 2097 for thval in IterateQueue(task_val.threads, 'thread *', 'task_threads'): 2098 task["threads"].append(GetThreadLedgers(thval)) 2099 2100 return task 2101 2102@header("{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >14s} {5: >12s} {6: >12s} {7: >12s} {8: <15s} {9: <8s} {10: <9s} {11: <6s} {12: >6s}".format( 2103 "task [thread]", "entry", "#", "balance", "lifetime_max", "credit", 2104 "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags")) 2105def FormatTaskLedgerSummary(task, show_footprint_interval_max=False): 2106 """ Internal function to get summary of ledger entries from the task and its threads 2107 params: task_val - value representing struct task * 2108 return: str - formatted output information for ledger entries of the input task 2109 """ 2110 out_str = '' 2111 out_str += "{: #08x} ".format(task["address"]) 2112 if "name" in task: 2113 out_str += "{: <5s}:\n".format(task["name"]) 2114 else: 2115 out_str += "Invalid process\n" 2116 2117 for i, entry in enumerate(task["entries"]): 2118 out_str += FormatLedgerEntrySummary(entry, i, show_footprint_interval_max) 2119 2120 for thread in task["threads"]: 2121 out_str += FormatThreadLedgerSummary(thread) 2122 return out_str 2123 2124 2125# Macro: showtaskledgers 2126 2127@lldb_command('showtaskledgers', 'JF:I') 2128def ShowTaskLedgers(cmd_args=None, cmd_options={}): 2129 """ Routine to print a summary of ledger entries for the task and all of its threads 2130 or : showtaskledgers [ -I ] [-J] [ -F ] <task> 2131 options: 2132 -I: show footprint interval max (DEV/DEBUG only) 2133 -F: specify task via name instead of address 2134 -J: output json 2135 - 2136 """ 2137 print_json = False 2138 if "-F" in cmd_options: 2139 task_list = FindTasksByName(cmd_options["-F"]) 2140 for tval in task_list: 2141 print(FormatTaskLedgerSummary.header) 2142 ledgers = GetTaskLedgers(tval) 2143 print(FormatTaskLedgerSummary(ledgers)) 2144 return 2145 if "-J" in cmd_options: 2146 print_json = True 2147 2148 if not cmd_args: 2149 raise ArgumentError("No arguments passed.") 2150 show_footprint_interval_max = False 2151 if "-I" in cmd_options: 2152 show_footprint_interval_max = True 2153 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 2154 if not tval: 2155 raise ArgumentError("unknown arguments: %r" %cmd_args) 2156 ledgers = GetTaskLedgers(tval) 2157 if print_json: 2158 print(json.dumps(ledgers)) 2159 else: 2160 if (show_footprint_interval_max): 2161 print("{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >12s} {5: >14s} {6: >12s} {7: >12s} {8: >12s} {9: <15s} {10: <8s} {11: <9s} {12: <6s} {13: >6s}".format( 2162 "task [thread]", "entry", "#", "balance", "intrvl_max", "lifetime_max", "credit", 2163 "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags")) 2164 else: 2165 print(FormatTaskLedgerSummary.header) 2166 print(FormatTaskLedgerSummary(ledgers, show_footprint_interval_max)) 2167 2168# EndMacro: showtaskledgers 2169 2170# Macro: showalltaskledgers 2171 2172@lldb_command('showalltaskledgers', "J") 2173def ShowAllTaskLedgers(cmd_args=None, cmd_options={}): 2174 """ Routine to print a summary of ledger entries for all tasks and respective threads 2175 Usage: showalltaskledgers [-J] 2176 -J : Output json 2177 """ 2178 print_json = False 2179 if "-J" in cmd_options: 2180 print_json = True 2181 tasks = [] 2182 for t in kern.tasks: 2183 task_val = unsigned(t) 2184 if not print_json: 2185 ShowTaskLedgers([task_val], cmd_options=cmd_options) 2186 else: 2187 tasks.append(GetTaskLedgers(t)) 2188 if print_json: 2189 print(json.dumps(tasks)) 2190 2191# EndMacro: showalltaskledgers 2192 2193# Macro: showprocuuidpolicytable 2194 2195@lldb_type_summary(['proc_uuid_policy_entry']) 2196@header("{0: <36s} {1: <10s}".format("uuid", "flags")) 2197def GetProcUUIDPolicyEntrySummary(entry): 2198 """ Summarizes the important fields in proc_uuid_policy_entry structure. 2199 params: entry: value - value object representing an entry 2200 returns: str - summary of the entry 2201 """ 2202 data = [] 2203 for i in range(16): 2204 data.append(int(entry.uuid[i])) 2205 flags = unsigned(entry.flags) 2206 out_string = "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X} 0x{b:0>8x}".format(a=data, b=flags) 2207 return out_string 2208 2209@lldb_command('showprocuuidpolicytable') 2210def ShowProcUUIDPolicyTable(cmd_args=None): 2211 """ Routine to print the proc UUID policy table 2212 Usage: showprocuuidpolicytable 2213 """ 2214 hashslots = unsigned(kern.globals.proc_uuid_policy_hash_mask) 2215 print("{0: <8s} ".format("slot") + GetProcUUIDPolicyEntrySummary.header) 2216 for i in range(0, hashslots+1): 2217 headp = addressof(kern.globals.proc_uuid_policy_hashtbl[i]) 2218 entrynum = 0 2219 for entry in IterateListEntry(headp, 'entries'): 2220 print("{0: >2d}.{1: <5d} ".format(i, entrynum) + GetProcUUIDPolicyEntrySummary(entry)) 2221 entrynum += 1 2222 2223 2224# EndMacro: showprocuuidpolicytable 2225 2226@lldb_command('showalltaskpolicy') 2227def ShowAllTaskPolicy(cmd_args=None): 2228 """ 2229 Routine to print a summary listing of all the tasks 2230 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" 2231 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung 2232 io_policy -> RAGE - rapid aging of vnodes requested 2233 NORM - normal I/O explicitly requested (this is the default) 2234 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) 2235 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) 2236 """ 2237 global kern 2238 print(GetTaskSummary.header + " " + GetProcSummary.header) 2239 for t in kern.tasks: 2240 pval = GetProcFromTask(t) 2241 print(GetTaskSummary(t) +" "+ GetProcSummary(pval)) 2242 requested_strings = [ 2243 ["int_darwinbg", "DBG-int"], 2244 ["ext_darwinbg", "DBG-ext"], 2245 ["int_iotier", "iotier-int"], 2246 ["ext_iotier", "iotier-ext"], 2247 ["int_iopassive", "passive-int"], 2248 ["ext_iopassive", "passive-ext"], 2249 ["bg_iotier", "bg-iotier"], 2250 ["terminated", "terminated"], 2251 ["th_pidbind_bg", "bg-pidbind"], 2252 ["t_apptype", "apptype"], 2253 ["t_boosted", "boosted"], 2254 ["t_role", "role"], 2255 ["t_tal_enabled", "tal-enabled"], 2256 ["t_base_latency_qos", "latency-base"], 2257 ["t_over_latency_qos", "latency-override"], 2258 ["t_base_through_qos", "throughput-base"], 2259 ["t_over_through_qos", "throughput-override"] 2260 ] 2261 2262 requested="" 2263 for value in requested_strings: 2264 if t.requested_policy.__getattr__(value[0]) : 2265 requested+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " " 2266 else: 2267 requested+="" 2268 2269 suppression_strings = [ 2270 ["t_sup_active", "active"], 2271 ["t_sup_lowpri_cpu", "lowpri-cpu"], 2272 ["t_sup_timer", "timer-throttling"], 2273 ["t_sup_disk", "disk-throttling"], 2274 ["t_sup_cpu_limit", "cpu-limits"], 2275 ["t_sup_suspend", "suspend"], 2276 ["t_sup_bg_sockets", "bg-sockets"] 2277 ] 2278 2279 suppression="" 2280 for value in suppression_strings: 2281 if t.requested_policy.__getattr__(value[0]) : 2282 suppression+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " " 2283 else: 2284 suppression+="" 2285 2286 effective_strings = [ 2287 ["darwinbg", "background"], 2288 ["lowpri_cpu", "lowpri-cpu"], 2289 ["io_tier", "iotier"], 2290 ["io_passive", "passive"], 2291 ["all_sockets_bg", "bg-allsockets"], 2292 ["new_sockets_bg", "bg-newsockets"], 2293 ["bg_iotier", "bg-iotier"], 2294 ["terminated", "terminated"], 2295 ["t_gpu_deny", "gpu-deny"], 2296 ["t_tal_engaged", "tal-engaged"], 2297 ["t_suspended", "suspended"], 2298 ["t_watchers_bg", "bg-watchers"], 2299 ["t_latency_qos", "latency-qos"], 2300 ["t_through_qos", "throughput-qos"], 2301 ["t_sup_active", "suppression-active"], 2302 ["t_role", "role"] 2303 ] 2304 2305 effective="" 2306 for value in effective_strings: 2307 if t.effective_policy.__getattr__(value[0]) : 2308 effective+=value[1] + ": " + str(t.effective_policy.__getattr__(value[0])) + " " 2309 else: 2310 effective+="" 2311 2312 print("requested: " + requested) 2313 print("suppression: " + suppression) 2314 print("effective: " + effective) 2315 2316 2317@lldb_command('showallsuspendedtasks', '') 2318def ShowSuspendedTasks(cmd_args=[], options={}): 2319 """ Show a list of suspended tasks with their process name summary. 2320 """ 2321 print(GetTaskSummary.header + ' ' + GetProcSummary.header) 2322 for t in kern.tasks: 2323 if t.suspend_count > 0: 2324 print(GetTaskSummary(t) + ' ' + GetProcSummary(GetProcFromTask(t))) 2325 return True 2326 2327# Macro: showallpte 2328@lldb_command('showallpte') 2329def ShowAllPte(cmd_args=None): 2330 """ Prints out the physical address of the pte for all tasks 2331 """ 2332 head_taskp = addressof(kern.globals.tasks) 2333 taskp = Cast(head_taskp.next, 'task *') 2334 while taskp != head_taskp: 2335 out_str = "task = {:#x} pte = {:#x}\t".format(taskp, taskp.map.pmap.ttep) 2336 procp = GetProcFromTask(taskp) 2337 if procp is not None: 2338 out_str += "{:s}\n".format(GetProcName(procp)) 2339 else: 2340 out_str += "\n" 2341 print(out_str) 2342 taskp = Cast(taskp.tasks.next, 'struct task *') 2343 2344# EndMacro: showallpte 2345 2346# Macro: showallrefcounts 2347@lldb_command('showallrefcounts') 2348@header("{0: <20s} {1: ^10s}".format("task", "ref_count")) 2349def ShowAllRefCounts(cmd_args=None): 2350 """ Prints the ref_count of all tasks 2351 """ 2352 out_str = '' 2353 head_taskp = addressof(kern.globals.tasks) 2354 taskp = Cast(head_taskp.next, 'task *') 2355 print(ShowAllRefCounts.header) 2356 while taskp != head_taskp: 2357 out_str += "{: <#20x}".format(taskp) 2358 out_str += "{: ^10d}\n".format(taskp.ref_count.ref_count) 2359 taskp = Cast(taskp.tasks.next, 'task *') 2360 print(out_str) 2361# EndMacro: showallrefcounts 2362 2363# Macro: showallrunnablethreads 2364@lldb_command('showallrunnablethreads', fancy=True) 2365def ShowAllRunnableThreads(cmd_args=None, cmd_options={}, O=None): 2366 """ Prints the sched usage information for all threads of each task 2367 """ 2368 out_str = '' 2369 for taskp in kern.tasks: 2370 for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'): 2371 if int(actp.state & 0x4): 2372 ShowActStack([unsigned(actp)], O=O) 2373 2374# EndMacro: showallrunnablethreads 2375 2376# Macro: showallschedusage 2377@lldb_command('showallschedusage') 2378@header("{0:<20s} {1:^10s} {2:^10s} {3:^15s}".format("Thread", "Priority", "State", "sched_usage")) 2379def ShowAllSchedUsage(cmd_args=None): 2380 """ Prints the sched usage information for all threads of each task 2381 """ 2382 out_str = '' 2383 for taskp in kern.tasks: 2384 ShowTask([unsigned(taskp)]) 2385 print(ShowAllSchedUsage.header) 2386 for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'): 2387 out_str = "{: <#20x}".format(actp) 2388 out_str += "{: ^10s}".format(str(int(actp.sched_pri))) 2389 state = int(actp.state) 2390 state_str = '' 2391 mask = 0x1 2392 while mask <= LAST_THREAD_STATE: 2393 state_str += THREAD_STATE_CHARS[int(state & mask)] 2394 mask <<= 1 2395 out_str += "{: ^10s}".format(state_str) 2396 out_str += "{: >15d}".format(actp.sched_usage) 2397 print(out_str + "\n") 2398 print("\n\n") 2399 2400# EndMacro: showallschedusage 2401 2402#Macro: showprocfilessummary 2403@lldb_command('showprocfilessummary') 2404@header("{0: <20s} {1: <20s} {2: >10s}".format("Process", "Name", "Number of Open Files")) 2405def ShowProcFilesSummary(cmd_args=None): 2406 """ Display the summary of open file descriptors for all processes in task list 2407 Usage: showprocfilessummary 2408 """ 2409 print(ShowProcFilesSummary.header) 2410 for proc in kern.procs: 2411 proc_filedesc = addressof(proc.p_fd) 2412 proc_ofiles = proc_filedesc.fd_ofiles 2413 proc_file_count = 0 2414 for fd in range(0, proc_filedesc.fd_afterlast): 2415 if unsigned(proc_ofiles[fd]) != 0: 2416 proc_file_count += 1 2417 print("{0: <#020x} {1: <32s} {2: >10d}".format(proc, GetProcName(proc), proc_file_count)) 2418 2419#EndMacro: showprocfilessummary 2420 2421@lldb_command('workinguserstacks') 2422def WorkingUserStacks(cmd_args=None): 2423 """ Print out the user stack for each thread in a task, followed by the user libraries. 2424 Syntax: (lldb) workinguserstacks <task_t> 2425 """ 2426 if not cmd_args: 2427 print("Insufficient arguments" + ShowTaskUserStacks.__doc__) 2428 return False 2429 task = kern.GetValueFromAddress(cmd_args[0], 'task *') 2430 print(GetTaskSummary.header + " " + GetProcSummary.header) 2431 pval = GetProcFromTask(task) 2432 print(GetTaskSummary(task) + " " + GetProcSummary(pval) + "\n \n") 2433 for thval in IterateQueue(task.threads, 'thread *', 'task_threads'): 2434 print("For thread 0x{0:x}".format(thval)) 2435 try: 2436 ShowThreadUserStack([hex(thval)]) 2437 except Exception as exc_err: 2438 print("Failed to show user stack for thread 0x{0:x}".format(thval)) 2439 if config['debug']: 2440 raise exc_err 2441 else: 2442 print("Enable debugging ('(lldb) xnudebug debug') to see detailed trace.") 2443 WorkingUserLibraries([hex(task)]) 2444 2445@static_var("exec_load_path", 0) 2446@lldb_command("workingkuserlibraries") 2447def WorkingUserLibraries(cmd_args=None): 2448 """ Show binary images known by dyld in target task 2449 For a given user task, inspect the dyld shared library state and print information about all Mach-O images. 2450 Syntax: (lldb)workinguserlibraries <task_t> 2451 """ 2452 if not cmd_args: 2453 print("Insufficient arguments") 2454 print(ShowTaskUserLibraries.__doc__) 2455 return False 2456 2457 print("{0: <18s} {1: <12s} {2: <36s} {3: <50s}".format('address','type','uuid','path')) 2458 out_format = "0x{0:0>16x} {1: <12s} {2: <36s} {3: <50s}" 2459 task = kern.GetValueFromAddress(cmd_args[0], 'task_t') 2460 is_task_64 = int(task.t_flags) & 0x1 2461 dyld_all_image_infos_address = unsigned(task.all_image_info_addr) 2462 cur_data_offset = 0 2463 if dyld_all_image_infos_address == 0: 2464 print("No dyld shared library information available for task") 2465 return False 2466 vers_info_data = GetUserDataAsString(task, dyld_all_image_infos_address, 112) 2467 version = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t") 2468 cur_data_offset += 4 2469 if version > 12: 2470 print("Unknown dyld all_image_infos version number %d" % version) 2471 image_info_count = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t") 2472 WorkingUserLibraries.exec_load_path = 0 2473 if is_task_64: 2474 image_info_size = 24 2475 image_info_array_address = _ExtractDataFromString(vers_info_data, 8, "uint64_t") 2476 dyld_load_address = _ExtractDataFromString(vers_info_data, 8*4, "uint64_t") 2477 dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 8*13, "uint64_t") 2478 else: 2479 image_info_size = 12 2480 image_info_array_address = _ExtractDataFromString(vers_info_data, 4*2, "uint32_t") 2481 dyld_load_address = _ExtractDataFromString(vers_info_data, 4*5, "uint32_t") 2482 dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 4*14, "uint32_t") 2483 # Account for ASLR slide before dyld can fix the structure 2484 dyld_load_address = dyld_load_address + (dyld_all_image_infos_address - dyld_all_image_infos_address_from_struct) 2485 2486 i = 0 2487 while i < image_info_count: 2488 image_info_address = image_info_array_address + i * image_info_size 2489 img_data = GetUserDataAsString(task, image_info_address, image_info_size) 2490 if is_task_64: 2491 image_info_addr = _ExtractDataFromString(img_data, 0, "uint64_t") 2492 image_info_path = _ExtractDataFromString(img_data, 8, "uint64_t") 2493 else: 2494 image_info_addr = _ExtractDataFromString(img_data, 0, "uint32_t") 2495 image_info_path = _ExtractDataFromString(img_data, 4, "uint32_t") 2496 PrintImageInfo(task, image_info_addr, image_info_path) 2497 i += 1 2498 2499 # load_path might get set when the main executable is processed. 2500 if WorkingUserLibraries.exec_load_path != 0: 2501 PrintImageInfo(task, dyld_load_address, WorkingUserLibraries.exec_load_path) 2502 return 2503 2504# Macro: showstackaftertask 2505 2506@lldb_command('showstackaftertask', 'F:', fancy=True) 2507def Showstackaftertask(cmd_args=None, cmd_options={}, O=None): 2508 """ Routine to print the thread stacks for all tasks succeeding a given task 2509 Usage: showstackaftertask <0xaddress of task> 2510 or: showstackaftertask -F <taskname> 2511 """ 2512 if "-F" in cmd_options: 2513 # Find the task pointer corresponding to its task name 2514 find_task_str = cmd_options["-F"] 2515 task_list = FindTasksByName(find_task_str) 2516 2517 # Iterate through the list of tasks and print all task stacks thereafter 2518 for tval in task_list: 2519 ListTaskStacks(tval, O=O) 2520 return 2521 2522 if not cmd_args: 2523 raise ArgumentError("Insufficient arguments") 2524 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 2525 if not tval: 2526 raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args))) 2527 else: 2528 ListTaskStacks(tval, O=O) 2529 2530 ShowZombStacks(O=O) 2531 2532# EndMacro: showstackaftertask 2533 2534def ListTaskStacks(task, O=None): 2535 """ Search for a given task and print the list of all task stacks thereafter. 2536 """ 2537 # Initialize local variable task_flag to mark when a given task is found. 2538 task_flag=0 2539 2540 for t in kern.tasks: 2541 if (task_flag == 1): 2542 ShowTaskStacks(t, O=O) 2543 print("\n") 2544 if (t == task): 2545 task_flag = 1 2546 2547# Macro: showstackafterthread 2548@lldb_command('showstackafterthread', fancy=True) 2549def Showstackafterthread(cmd_args=None, cmd_options={}, O=None): 2550 """ Routine to print the stacks of all threads succeeding a given thread. 2551 Usage: Showstackafterthread <0xaddress of thread> 2552 """ 2553 # local variable thread_flag is used to mark when a given thread is found. 2554 thread_flag=0 2555 if cmd_args: 2556 threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 2557 else: 2558 raise ArgumentError("No arguments passed") 2559 # Iterate through list of all tasks to look up a given thread 2560 for t in kern.tasks: 2561 if(thread_flag==1): 2562 pval = GetProcFromTask(t) 2563 print(GetTaskSummary.header + " "+ GetProcSummary.header) 2564 print(GetTaskSummary(t) + " "+ GetProcSummary(pval)) 2565 print("\n") 2566 # Look up for a given thread from the the list of threads of a given task 2567 for thval in IterateQueue(t.threads, 'thread *', 'task_threads'): 2568 if thread_flag == 1: 2569 print("\n") 2570 with O.table(GetThreadSummary.header, indent=True): 2571 print(GetThreadSummary(active_thread, O=O)) 2572 print(GetThreadBackTrace(thval, prefix="\t")+"\n") 2573 print("\n") 2574 2575 if thval == threadval: 2576 pval = GetProcFromTask(t) 2577 process_name = "{:s}".format(GetProcName(pval)) 2578 print("\n\n") 2579 print(" *** Continuing to dump the thread stacks from the process *** :" + " " + process_name) 2580 print("\n\n") 2581 thread_flag = 1 2582 print('\n') 2583 return 2584 2585