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