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