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