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