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