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""" 5 6from xnu import * 7import sys, shlex 8from utils import * 9from core.lazytarget import * 10import xnudefines 11 12def GetProcNameForTask(task): 13 """ returns a string name of the process. if proc is not valid "unknown" is returned 14 params: 15 task: value object represeting a task in the kernel. 16 returns: 17 str : A string name of the process linked to the task 18 """ 19 if not task or not unsigned(task.bsd_info): 20 return "unknown" 21 p = Cast(task.bsd_info, 'proc *') 22 return str(p.p_comm) 23 24def GetProcPIDForTask(task): 25 """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned. 26 params: 27 task: value object representing a task in the kernel 28 returns: 29 int : pid of the process or -1 if not found 30 """ 31 if task and unsigned(task.bsd_info): 32 p = Cast(task.bsd_info, 'proc *') 33 return unsigned(p.p_pid) 34 35 if task : 36 return unsigned(task.audit_token.val[5]) 37 38 return -1 39 40def GetProcInfo(proc): 41 """ returns a string name, pid, parent and task for a proc_t. Decodes cred, flag and p_stat fields. 42 params: 43 proc : value object representing a proc in the kernel 44 returns: 45 str : A string describing various information for process. 46 """ 47 out_string = "" 48 out_string += ("Process {p: <#020x}\n\tname {p.p_comm: <20s}\n\tpid:{p.p_pid: <6d} " + 49 "task:{p.task: <#020x} p_stat:{p.p_stat: <6d} parent pid: {p.p_ppid: <6d}\n" 50 ).format(p=proc) 51 #print the Creds 52 ucred = proc.p_ucred 53 if ucred: 54 out_string += "Cred: euid {:d} ruid {:d} svuid {:d}\n".format(ucred.cr_posix.cr_uid, 55 ucred.cr_posix.cr_ruid, 56 ucred.cr_posix.cr_svuid ) 57 #print the flags 58 flags = int(proc.p_flag) 59 out_string += "Flags: {0: <#020x}\n".format(flags) 60 i = 1 61 num = 1 62 while num <= flags: 63 if flags & num: 64 out_string += "\t" + xnudefines.proc_flag_explain_strings[i] + "\n" 65 elif num == 0x4: #special case for 32bit flag 66 out_string += "\t" + xnudefines.proc_flag_explain_strings[0] + "\n" 67 i += 1 68 num = num << 1 69 out_string += "State: " 70 state_val = proc.p_stat 71 if state_val < 1 or state_val > len(xnudefines.proc_state_strings) : 72 out_string += "(Unknown)" 73 else: 74 out_string += xnudefines.proc_state_strings[int(state_val)] 75 76 return out_string 77 78def GetProcNameForPid(pid): 79 """ Finds the name of the process corresponding to a given pid 80 params: 81 pid : int, pid you want to find the procname for 82 returns 83 str : Name of the process corresponding to the pid, "Unknown" if not found 84 """ 85 for p in kern.procs: 86 if int(p.p_pid) == int(pid): 87 return str(p.p_comm) 88 return "Unknown" 89 90def GetProcForPid(search_pid): 91 """ Finds the value object representing a proc in the kernel based on its pid 92 params: 93 search_pid : int, pid whose proc structure you want to find 94 returns: 95 value : The value object representing the proc, if a proc corresponding 96 to the given pid is found. Returns None otherwise 97 """ 98 if search_pid == 0: 99 return kern.globals.initproc 100 else: 101 headp = kern.globals.allproc 102 for proc in IterateListEntry(headp, 'struct proc *', 'p_list'): 103 if proc.p_pid == search_pid: 104 return proc 105 return None 106 107@lldb_command('allproc') 108def AllProc(cmd_args=None): 109 """ Walk through the allproc structure and print procinfo for each process structure. 110 params: 111 cmd_args - [] : array of strings passed from lldb command prompt 112 """ 113 for proc in kern.procs : 114 print GetProcInfo(proc) 115 116 117@lldb_command('zombproc') 118def ZombProc(cmd_args=None): 119 """ Routine to print out all procs in the zombie list 120 params: 121 cmd_args - [] : array of strings passed from lldb command prompt 122 """ 123 if len(kern.zombprocs) != 0: 124 print "\nZombie Processes:" 125 for proc in kern.zombprocs: 126 print GetProcInfo(proc) + "\n\n" 127 128@lldb_command('zombtasks') 129def ZombTasks(cmd_args=None): 130 """ Routine to print out all tasks in the zombie list 131 params: None 132 """ 133 out_str = "" 134 if len(kern.zombprocs) != 0: 135 header = "\nZombie Tasks:\n" 136 header += GetTaskSummary.header + " " + GetProcSummary.header 137 for proc in kern.zombprocs: 138 if proc.p_stat != 5: 139 t = Cast(proc.task, 'task *') 140 out_str += GetTaskSummary(t) +" "+ GetProcSummary(proc) + "\n" 141 if out_str != "": 142 print header 143 print out_str 144 145@lldb_command('zombstacks') 146def ZombStacks(cmd_args=None): 147 """ Routine to print out all stacks of tasks that are exiting 148 """ 149 header_flag = 0 150 for proc in kern.zombprocs: 151 if proc.p_stat != 5: 152 if header_flag == 0: 153 print "\nZombie Stacks:" 154 header_flag = 1 155 t = Cast(proc.task, 'task *') 156 ShowTaskStacks(t) 157#End of Zombstacks 158 159def GetASTSummary(ast): 160 """ Summarizes an AST field 161 Flags: 162 P - AST_PREEMPT 163 Q - AST_QUANTUM 164 U - AST_URGENT 165 H - AST_HANDOFF 166 Y - AST_YIELD 167 A - AST_APC 168 L - AST_LEDGER 169 B - AST_BSD 170 K - AST_KPERF 171 M - AST_MACF 172 C - AST_CHUD 173 C - AST_CHUD_URGENT 174 G - AST_GUARD 175 T - AST_TELEMETRY_USER 176 T - AST_TELEMETRY_KERNEL 177 T - AST_TELEMETRY_WINDOWED 178 S - AST_SFI 179 """ 180 out_string = "" 181 state = int(ast) 182 thread_state_chars = {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A', 183 0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400:'C', 0x800:'C', 184 0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S'} 185 state_str = '' 186 mask = 0x1 187 while mask <= 0x10000 : 188 state_str += thread_state_chars[int(state & mask)] 189 mask = mask << 1 190 191 return state_str 192 193 194@lldb_type_summary(['task', 'task_t']) 195@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags")) 196def GetTaskSummary(task): 197 """ Summarizes the important fields in task structure. 198 params: task: value - value object representing a task in kernel 199 returns: str - summary of the task 200 """ 201 out_string = "" 202 format_string = '{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: <5s}' 203 thread_count = int(task.thread_count) 204 task_flags = '' 205 if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1: 206 task_flags += 'P' 207 if hasattr(task, "suspend_count") and int(task.suspend_count) > 0: 208 task_flags += 'S' 209 if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base): 210 tib = task.task_imp_base 211 if int(tib.iit_receiver) == 1: 212 task_flags += 'R' 213 if int(tib.iit_donor) == 1: 214 task_flags += 'D' 215 if int(tib.iit_assertcnt) > 0: 216 task_flags += 'B' 217 out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags) 218 return out_string 219 220@lldb_type_summary(['thread *', 'thread_t']) 221@header("{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}".format('thread', 'thread_id', 'processor', 'base', 'pri', 'sched_mode', 'io_policy', 'state', 'ast', 'wait_queue', 'wait_event', 'wmesg', 'thread_name')) 222def GetThreadSummary(thread): 223 """ Summarize the thread structure. It decodes the wait state and waitevents from the data in the struct. 224 params: thread: value - value objecte representing a thread in kernel 225 returns: str - summary of a thread 226 227 State flags: 228 W - WAIT 229 S - SUSP 230 R - RUN 231 U - Uninterruptible 232 H - Terminated 233 A - Terminated and on termination queue 234 I - Idle thread 235 236 policy flags: 237 B - darwinbg 238 L - lowpri cpu 239 T - IO throttle 240 P - IO passive 241 D - Terminated 242 """ 243 out_string = "" 244 format_string = "{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}" 245 thread_ptr_str = str("{0: <#020x}".format(thread)) 246 if int(thread.static_param) : 247 thread_ptr_str+="[WQ]" 248 thread_id = hex(thread.thread_id) 249 thread_name = '' 250 processor = hex(thread.last_processor) 251 base_priority = str(int(thread.priority)) 252 sched_priority = str(int(thread.sched_pri)) 253 sched_mode = '' 254 mode = str(thread.sched_mode) 255 if "TIMESHARE" in mode: 256 sched_mode+="timeshare" 257 elif "FIXED" in mode: 258 sched_mode+="fixed" 259 elif "REALTIME" in mode: 260 sched_mode+="realtime" 261 262 if (unsigned(thread.bound_processor) != 0): 263 sched_mode+=" bound" 264 265 # TH_SFLAG_THROTTLED 266 if (unsigned(thread.sched_flags) & 0x0004): 267 sched_mode+=" BG" 268 269 io_policy_str = "" 270 if int(thread.uthread) != 0: 271 uthread = Cast(thread.uthread, 'uthread *') 272 #check for thread name 273 if int(uthread.pth_name) != 0 : 274 th_name_strval = Cast(uthread.pth_name, 'char *') 275 if len(str(th_name_strval)) > 0 : 276 thread_name = str(th_name_strval) 277 278 #check for io_policy flags 279 if int(uthread.uu_flag) & 0x400: 280 io_policy_str+='RAGE ' 281 282 #now flags for task_policy 283 284 io_policy_str = "" 285 286 if int(thread.effective_policy.darwinbg) != 0: 287 io_policy_str += "B" 288 if int(thread.effective_policy.lowpri_cpu) != 0: 289 io_policy_str += "L" 290 291 if int(thread.effective_policy.io_tier) != 0: 292 io_policy_str += "T" 293 if int(thread.effective_policy.io_passive) != 0: 294 io_policy_str += "P" 295 if int(thread.effective_policy.terminated) != 0: 296 io_policy_str += "D" 297 298 state = int(thread.state) 299 thread_state_chars = {0x0:'', 0x1:'W', 0x2:'S', 0x4:'R', 0x8:'U', 0x10:'H', 0x20:'A', 0x40:'P', 0x80:'I'} 300 state_str = '' 301 mask = 0x1 302 while mask <= 0x80 : 303 state_str += thread_state_chars[int(state & mask)] 304 mask = mask << 1 305 306 ast = int(thread.ast) | int(thread.reason) 307 ast_str = GetASTSummary(ast) 308 309 #wait queue information 310 wait_queue_str = '' 311 wait_event_str = '' 312 wait_message = '' 313 if ( state & 0x1 ) != 0: 314 #we need to look at the waitqueue as well 315 wait_queue_str = str("{0: <#020x}".format(int(hex(thread.wait_queue), 16))) 316 wait_event_str = str("{0: <#020x}".format(int(hex(thread.wait_event), 16))) 317 wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16)) 318 if len(wait_event_str_sym) > 0: 319 wait_event_str = wait_event_str.strip() + " <" + wait_event_str_sym + ">" 320 if int(thread.uthread) != 0 : 321 uthread = Cast(thread.uthread, 'uthread *') 322 if int(uthread.uu_wmesg) != 0: 323 wait_message = str(Cast(uthread.uu_wmesg, 'char *')) 324 325 out_string += format_string.format(thread_ptr_str, thread_id, processor, base_priority, sched_priority, sched_mode, io_policy_str, state_str, ast_str, wait_queue_str, wait_event_str, wait_message, thread_name) 326 return out_string 327 328 329@lldb_type_summary(['coalition_t', 'coalition']) 330@header("type coalition summary (header tbw)") 331def GetCoalitionSummary(coal): 332 out_string = "" 333 format_string = '{0: <#020x} {1: <d} {2: <d} {3: <d}' 334 flags_string = '' 335 if (coal.terminated): 336 flags_string += ' terminated' 337 if (coal.reaped): 338 flags_string += ' reaped' 339 out_string += format_string.format(coal, coal.id, coal.ref_count, coal.active_count, ) 340 return out_string 341 342@lldb_type_summary(['proc', 'proc *']) 343@header("{0: >6s} {1: ^20s} {2: >14s} {3: ^10s} {4: <20s}".format("pid", "process", "io_policy", "wq_state", "command")) 344def GetProcSummary(proc): 345 """ Summarize the process data. 346 params: 347 proc : value - value representaitng a proc * in kernel 348 returns: 349 str - string summary of the process. 350 """ 351 out_string = "" 352 format_string= "{0: >6d} {1: >#020x} {2: >14s} {3: >2d} {4: >2d} {5: >2d} {6: <20s}" 353 pval = proc.GetSBValue() 354 #code.interact(local=locals()) 355 if str(pval.GetType()) != str(gettype('proc *')) : 356 return "Unknown type " + str(pval.GetType()) + " " + str(hex(proc)) 357 if not proc: 358 out_string += "Process " + hex(proc) + " is not valid." 359 return out_string 360 pid = int(proc.p_pid) 361 proc_addr = int(hex(proc), 16) 362 proc_rage_str = "" 363 if int(proc.p_lflag) & 0x400000 : 364 proc_rage_str = "RAGE" 365 366 task = Cast(proc.task, 'task *') 367 368 io_policy_str = "" 369 370 if int(task.effective_policy.darwinbg) != 0: 371 io_policy_str += "B" 372 if int(task.effective_policy.lowpri_cpu) != 0: 373 io_policy_str += "L" 374 375 if int(task.effective_policy.io_tier) != 0: 376 io_policy_str += "T" 377 if int(task.effective_policy.io_passive) != 0: 378 io_policy_str += "P" 379 if int(task.effective_policy.terminated) != 0: 380 io_policy_str += "D" 381 382 if int(task.effective_policy.t_suspended) != 0: 383 io_policy_str += "S" 384 if int(task.effective_policy.t_latency_qos) != 0: 385 io_policy_str += "Q" 386 if int(task.effective_policy.t_sup_active) != 0: 387 io_policy_str += "A" 388 389 390 try: 391 work_queue = Cast(proc.p_wqptr, 'workqueue *') 392 if proc.p_wqptr != 0 : 393 wq_num_threads = int(work_queue.wq_nthreads) 394 wq_idle_threads = int(work_queue.wq_thidlecount) 395 wq_req_threads = int(work_queue.wq_reqcount) 396 else: 397 wq_num_threads = 0 398 wq_idle_threads = 0 399 wq_req_threads = 0 400 except: 401 wq_num_threads = -1 402 wq_idle_threads = -1 403 wq_req_threads = -1 404 process_name = str(proc.p_comm) 405 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) 406 return out_string 407 408@lldb_type_summary(['tty_dev_t', 'tty_dev_t *']) 409@header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","master", "slave", "open", "free", "name", "revoke")) 410def GetTTYDevSummary(tty_dev): 411 """ Summarizes the important fields in tty_dev_t structure. 412 params: tty_dev: value - value object representing a tty_dev_t in kernel 413 returns: str - summary of the tty_dev 414 """ 415 out_string = "" 416 format_string = "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}" 417 open_fn = kern.Symbolicate(int(hex(tty_dev.open), 16)) 418 free_fn = kern.Symbolicate(int(hex(tty_dev.free), 16)) 419 name_fn = kern.Symbolicate(int(hex(tty_dev.name), 16)) 420 revoke_fn = kern.Symbolicate(int(hex(tty_dev.revoke), 16)) 421 out_string += format_string.format(tty_dev, tty_dev.master, tty_dev.slave, open_fn, free_fn, name_fn, revoke_fn) 422 return out_string 423 424@lldb_type_summary(['kqueue *']) 425@header("{: <20s} {: <20s} {: <6s} {: <20s} {: <10s}".format('kqueue', 'process', '#events', 'wqs', 'state')) 426def GetKQueueSummary(kq): 427 """ summarizes kqueue information 428 returns: str - summary of kqueue 429 """ 430 out_string = "" 431 format_string = "{o: <#020x} {o.kq_p: <#020x} {o.kq_count: <6d} {o.kq_wqs: <#020x} {st_str: <10s}" 432 state = int(kq.kq_state) 433 state_str = '' 434 mask = 0x1 435 while mask <= 0x80 : 436 if int(state & mask): 437 state_str += ' ' + xnudefines.kq_state_strings[int(state & mask)] 438 mask = mask << 1 439 out_string += format_string.format(o=kq, st_str=state_str) 440 return out_string 441 442@lldb_type_summary(['knote *']) 443@header("{0: <20s}".format('knote')) 444def GetKnoteSummary(kn): 445 """ Summarizes a knote and related information 446 returns: str - summary of knote 447 """ 448 out_string = "" 449 format_string = "{o: <#020x}" 450 out_string += format_string.format(o=kn) 451 return out_string 452 453# Macro: showtask 454 455@lldb_command('showtask', 'F:') 456def ShowTask(cmd_args=None, cmd_options={}): 457 """ Routine to print a summary listing of given task 458 Usage: showtask <address of task> 459 or : showtask -F <name of task> 460 """ 461 task_list = [] 462 if "-F" in cmd_options: 463 task_list = FindTasksByName(cmd_options['-F']) 464 else: 465 if not cmd_args: 466 raise ArgumentError("Invalid arguments passed.") 467 468 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 469 if not tval: 470 raise ("Unknown arguments: %r" % cmd_args) 471 task_list.append(tval) 472 473 for tval in task_list: 474 print GetTaskSummary.header + " " + GetProcSummary.header 475 pval = Cast(tval.bsd_info, 'proc *') 476 print GetTaskSummary(tval) +" "+ GetProcSummary(pval) 477 478# EndMacro: showtask 479 480# Macro: showpid 481 482@lldb_command('showpid') 483def ShowPid(cmd_args=None): 484 """ Routine to print a summary listing of task corresponding to given pid 485 Usage: showpid <pid value> 486 """ 487 if not cmd_args: 488 print "No arguments passed" 489 print ShowPid.__doc__ 490 return False 491 pidval = ArgumentStringToInt(cmd_args[0]) 492 for t in kern.tasks: 493 pval = Cast(t.bsd_info, 'proc *') 494 if pval and pval.p_pid == pidval: 495 print GetTaskSummary.header + " " + GetProcSummary.header 496 print GetTaskSummary(t) + " " + GetProcSummary(pval) 497 break 498 499# EndMacro: showpid 500 501# Macro: showproc 502 503@lldb_command('showproc') 504def ShowProc(cmd_args=None): 505 """ Routine to print a summary listing of task corresponding to given proc 506 Usage: showproc <address of proc> 507 """ 508 if not cmd_args: 509 print "No arguments passed" 510 print ShowProc.__doc__ 511 return False 512 pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') 513 if not pval: 514 print "unknown arguments:", str(cmd_args) 515 return False 516 print GetTaskSummary.header + " " + GetProcSummary.header 517 tval = Cast(pval.task, 'task *') 518 print GetTaskSummary(tval) +" "+ GetProcSummary(pval) 519 520# EndMacro: showproc 521 522# Macro: showprocinfo 523 524@lldb_command('showprocinfo') 525def ShowProcInfo(cmd_args=None): 526 """ Routine to display name, pid, parent & task for the given proc address 527 It also shows the Cred, Flags and state of the process 528 Usage: showprocinfo <address of proc> 529 """ 530 if not cmd_args: 531 print "No arguments passed" 532 print ShowProcInfo.__doc__ 533 return False 534 pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') 535 if not pval: 536 print "unknown arguments:", str(cmd_args) 537 return False 538 print GetProcInfo(pval) 539 540# EndMacro: showprocinfo 541 542#Macro: showprocfiles 543 544@lldb_command('showprocfiles') 545def ShowProcFiles(cmd_args=None): 546 """ Given a proc_t pointer, display the list of open file descriptors for the referenced process. 547 Usage: showprocfiles <proc_t> 548 """ 549 if not cmd_args: 550 print ShowProcFiles.__doc__ 551 return 552 proc = kern.GetValueFromAddress(cmd_args[0], 'proc_t') 553 proc_filedesc = proc.p_fd 554 proc_lastfile = unsigned(proc_filedesc.fd_lastfile) 555 proc_ofiles = proc_filedesc.fd_ofiles 556 if unsigned(proc_ofiles) == 0: 557 print 'No open files for proc {0: <s}'.format(cmd_args[0]) 558 return 559 print "{0: <5s} {1: <18s} {2: <10s} {3: <8s} {4: <18s} {5: <64s}".format('FD', 'FILEGLOB', 'FG_FLAGS', 'FG_TYPE', 'FG_DATA','INFO') 560 print "{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format("") 561 count = 0 562 563 # Filetype map 564 filetype_dict = { 565 1: 'VNODE', 566 2: 'SOCKET', 567 3: 'PSXSHM', 568 4: 'PSXSEM', 569 5: 'KQUEUE', 570 6: 'PIPE', 571 7: 'FSEVENTS' 572 } 573 574 while count <= proc_lastfile: 575 if unsigned(proc_ofiles[count]) != 0: 576 out_str = '' 577 proc_fd_flags = proc_ofiles[count].f_flags 578 proc_fd_fglob = proc_ofiles[count].f_fglob 579 out_str += "{0: <5d} ".format(count) 580 out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob)) 581 out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags)) 582 proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type) 583 if proc_fd_ftype in filetype_dict: 584 out_str += "{0: <8s} ".format(filetype_dict[proc_fd_ftype]) 585 else: 586 out_str += "?: {0: <5d} ".format(proc_fd_ftype) 587 out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob.fg_data)) 588 if proc_fd_ftype == 1: 589 fd_name = Cast(proc_fd_fglob.fg_data, 'struct vnode *').v_name 590 out_str += "{0: <64s}".format(fd_name) 591 out_str += "\n" 592 print out_str 593 count += 1 594 595#EndMacro: showprocfiles 596 597#Macro: showkqueue 598@lldb_command('showkqueue' ,'') 599def ShowKQueue(cmd_args=[], cmd_options={}): 600 """ Given a struct kqueue pointer, display the summary of the kqueue 601 Usage: (lldb) showkqueue <struct kqueue *> 602 """ 603 if not cmd_args: 604 raise ArgumentError('Invalid arguments') 605 606 kq = kern.GetValueFromAddress(cmd_args[0], 'struct kqueue *') 607 print GetKQueueSummary.header 608 print GetKQueueSummary(kq) 609 610#EndMacro: showkqueue 611 612#Macro: showtty 613 614@lldb_command('showtty') 615def ShowTTY(cmd_args=None): 616 """ Display information about a struct tty 617 Usage: showtty <tty struct> 618 """ 619 if not cmd_args: 620 print ShowTTY.__doc__ 621 return 622 623 tty = kern.GetValueFromAddress(cmd_args[0], 'struct tty *') 624 print "TTY structure at: {0: <s}".format(cmd_args[0]) 625 print "Last input to raw queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_rawq.c_cs), tty.t_rawq.c_cs) 626 print "Last input to canonical queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_canq.c_cs), tty.t_canq.c_cs) 627 print "Last output data: {0: <#18x} \"{1: <s}\"".format(unsigned(tty.t_outq.c_cs), tty.t_outq.c_cs) 628 tty_state_info = [ 629 ['', 'TS_SO_OLOWAT (Wake up when output <= low water)'], 630 ['- (synchronous I/O mode)', 'TS_ASYNC (async I/O mode)'], 631 ['', 'TS_BUSY (Draining output)'], 632 ['- (Carrier is NOT present)', 'TS_CARR_ON (Carrier is present)'], 633 ['', 'TS_FLUSH (Outq has been flushed during DMA)'], 634 ['- (Open has NOT completed)', 'TS_ISOPEN (Open has completed)'], 635 ['', 'TS_TBLOCK (Further input blocked)'], 636 ['', 'TS_TIMEOUT (Wait for output char processing)'], 637 ['', 'TS_TTSTOP (Output paused)'], 638 ['', 'TS_WOPEN (Open in progress)'], 639 ['', 'TS_XCLUDE (Tty requires exclusivity)'], 640 ['', 'TS_BKSL (State for lowercase \\ work)'], 641 ['', 'TS_CNTTB (Counting tab width, ignore FLUSHO)'], 642 ['', 'TS_ERASE (Within a \\.../ for PRTRUB)'], 643 ['', 'TS_LNCH (Next character is literal)'], 644 ['', 'TS_TYPEN (Retyping suspended input (PENDIN))'], 645 ['', 'TS_CAN_BYPASS_L_RINT (Device in "raw" mode)'], 646 ['- (Connection NOT open)', 'TS_CONNECTED (Connection open)'], 647 ['', 'TS_SNOOP (Device is being snooped on)'], 648 ['', 'TS_SO_OCOMPLETE (Wake up when output completes)'], 649 ['', 'TS_ZOMBIE (Connection lost)'], 650 ['', 'TS_CAR_OFLOW (For MDMBUF - handle in driver)'], 651 ['', 'TS_CTS_OFLOW (For CCTS_OFLOW - handle in driver)'], 652 ['', 'TS_DSR_OFLOW (For CDSR_OFLOW - handle in driver)'] 653 ] 654 index = 0 655 mask = 0x1 656 tty_state = unsigned(tty.t_state) 657 print "State:" 658 while index < 24: 659 if tty_state & mask != 0: 660 if len(tty_state_info[index][1]) > 0: 661 print '\t' + tty_state_info[index][1] 662 else: 663 if len(tty_state_info[index][0]) > 0: 664 print '\t' + tty_state_info[index][0] 665 index += 1 666 mask = mask << 1 667 print "Flags: 0x{0:0>8x}".format(unsigned(tty.t_flags)) 668 print "Foreground Process Group: 0x{0:0>16x}".format(unsigned(tty.t_pgrp)) 669 print "Enclosing session: 0x{0:0>16x}".format(unsigned(tty.t_session)) 670 print "Termios:" 671 print "\tInput Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_iflag)) 672 print "\tOutput Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_oflag)) 673 print "\tControl Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_cflag)) 674 print "\tLocal Flags: 0x{0:0>8x}".format(unsigned(tty.t_termios.c_lflag)) 675 print "\tInput Speed: {0: <8d}".format(tty.t_termios.c_ispeed) 676 print "\tOutput Speed: {0: <8d}".format(tty.t_termios.c_ospeed) 677 print "High Watermark: {0: <d} bytes".format(tty.t_hiwat) 678 print "Low Watermark : {0: <d} bytes".format(tty.t_lowat) 679 680#EndMacro: showtty 681 682#Macro showallttydevs 683 684@lldb_command('showallttydevs') 685def ShowAllTTYDevs(cmd_args=[], cmd_options={}): 686 """ Show a list of ttydevs registered in the system. 687 Usage: 688 (lldb)showallttydevs 689 """ 690 tty_dev_head = kern.globals.tty_dev_head 691 tty_dev = tty_dev_head 692 print GetTTYDevSummary.header 693 while unsigned(tty_dev) != 0: 694 print GetTTYDevSummary(tty_dev) 695 tty_dev = tty_dev.next 696 return "" 697 698#EndMacro: showallttydevs 699 700#Macro: dumpcallqueue 701 702@lldb_command('dumpcallqueue') 703def DumpCallQueue(cmd_args=None): 704 """ Displays the contents of the specified call_entry queue. 705 Usage: dumpcallqueue <queue_head_t *> 706 """ 707 if not cmd_args: 708 print DumpCallQueue.__doc__ 709 return 710 print "{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC') 711 callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *') 712 count = 0 713 for callentry in IterateQueue(callhead, 'struct call_entry *', 'q_link'): 714 print "{0: <#18x} {1: <#18x} {2: <#18x} {3: <64d} {4: <#18x}".format( 715 unsigned(callentry), unsigned(callentry.param0), unsigned(callentry.param1), 716 unsigned(callentry.deadline), unsigned(callentry.func)) 717 count += 1 718 print "{0: <d} entries!".format(count) 719 720#EndMacro: dumpcallqueue 721 722@lldb_command('showallcoalitions') 723def ShowAllCoalitions(cmd_args=None): 724 """ Routine to print a summary listing of all the coalitions 725 """ 726 global kern 727 print GetCoalitionSummary.header 728 for c in kern.coalitions: 729 print GetCoalitionSummary(c) 730 731@lldb_command('showalltasks') 732def ShowAllTasks(cmd_args=None): 733 """ Routine to print a summary listing of all the tasks 734 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" 735 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung 736 io_policy -> RAGE - rapid aging of vnodes requested 737 NORM - normal I/O explicitly requested (this is the default) 738 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) 739 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) 740 """ 741 global kern 742 print GetTaskSummary.header + " " + GetProcSummary.header 743 for t in kern.tasks: 744 pval = Cast(t.bsd_info, 'proc *') 745 print GetTaskSummary(t) +" "+ GetProcSummary(pval) 746 ZombTasks() 747 748@lldb_command('showterminatedtasks') 749def ShowTerminatedTasks(cmd_args=None): 750 """ Routine to print a summary listing of all the terminated tasks 751 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" 752 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung 753 io_policy -> RAGE - rapid aging of vnodes requested 754 NORM - normal I/O explicitly requested (this is the default) 755 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) 756 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) 757 syntax: (lldb)showallterminatedtasks 758 """ 759 global kern 760 print GetTaskSummary.header + " " + GetProcSummary.header 761 for t in kern.terminated_tasks: 762 pval = Cast(t.bsd_info, 'proc *') 763 print GetTaskSummary(t) +" "+ GetProcSummary(pval) 764 return True 765 766# Macro: showtaskstacks 767 768def ShowTaskStacks(task): 769 """ Print a task with summary and stack information for each of its threads 770 """ 771 global kern 772 print GetTaskSummary.header + " " + GetProcSummary.header 773 pval = Cast(task.bsd_info, 'proc *') 774 print GetTaskSummary(task) + " " + GetProcSummary(pval) 775 for th in IterateQueue(task.threads, 'thread *', 'task_threads'): 776 print " " + GetThreadSummary.header 777 print " " + GetThreadSummary(th) 778 print GetThreadBackTrace(th, prefix=" ") + "\n" 779 780def FindTasksByName(searchstr, ignore_case=True): 781 """ Search the list of tasks by name. 782 params: 783 searchstr: str - a regex like string to search for task 784 ignore_case: bool - If False then exact matching will be enforced 785 returns: 786 [] - array of task object. Empty if not found any 787 """ 788 re_options = 0 789 if ignore_case: 790 re_options = re.IGNORECASE 791 search_regex = re.compile(searchstr, re_options) 792 retval = [] 793 for t in kern.tasks: 794 pval = Cast(t.bsd_info, "proc *") 795 process_name = "{:s}".format(pval.p_comm) 796 if search_regex.search(process_name): 797 retval.append(t) 798 return retval 799 800@lldb_command('showtaskstacks', 'F:') 801def ShowTaskStacksCmdHelper(cmd_args=None, cmd_options={}): 802 """ Routine to print out the stack for each thread in a task 803 Usage: showtaskstacks <0xaddress of task> 804 or: showtaskstacks -F launchd 805 """ 806 807 if "-F" in cmd_options: 808 find_task_str = cmd_options["-F"] 809 task_list = FindTasksByName(find_task_str) 810 for tval in task_list: 811 ShowTaskStacks(tval) 812 return 813 814 if not cmd_args: 815 raise ArgumentError("No arguments passed") 816 817 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 818 if not tval: 819 raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args))) 820 else: 821 ShowTaskStacks(tval) 822 return 823 824# EndMacro: showtaskstacks 825 826@lldb_command('showallthreads') 827def ShowAllThreads(cmd_args = None): 828 """ Display info about all threads in the system 829 """ 830 for t in kern.tasks: 831 ShowTaskThreads([str(int(t))]) 832 print " \n" 833 834 for t in kern.terminated_tasks: 835 print "Terminated: \n" 836 ShowTaskThreads([str(int(t))]) 837 print " \n" 838 839 return 840 841@lldb_command('showtaskthreads', "F:") 842def ShowTaskThreads(cmd_args = None, cmd_options={}): 843 """ Display thread information for a given task 844 Usage: showtaskthreads <0xaddress of task> 845 or: showtaskthreads -F <name> 846 """ 847 task_list = [] 848 if "-F" in cmd_options: 849 task_list = FindTasksByName(cmd_options["-F"]) 850 elif cmd_args: 851 t = kern.GetValueFromAddress(cmd_args[0], 'task *') 852 task_list.append(t) 853 else: 854 raise ArgumentError("No arguments passed") 855 856 for task in task_list: 857 print GetTaskSummary.header + " " + GetProcSummary.header 858 pval = Cast(task.bsd_info, 'proc *') 859 print GetTaskSummary(task) + " " + GetProcSummary(pval) 860 print "\t" + GetThreadSummary.header 861 for thval in IterateQueue(task.threads, 'thread *', 'task_threads'): 862 print "\t" + GetThreadSummary(thval) 863 return 864 865@lldb_command('showact') 866def ShowAct(cmd_args=None): 867 """ Routine to print out the state of a specific thread. 868 usage: showact <activation> 869 """ 870 if cmd_args == None or len(cmd_args) < 1: 871 print "No arguments passed" 872 print ShowAct.__doc__ 873 return False 874 threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 875 print GetThreadSummary.header 876 print GetThreadSummary(threadval) 877 878@lldb_command('showactstack') 879def ShowActStack(cmd_args=None): 880 """ Routine to print out the stack of a specific thread. 881 usage: showactstack <activation> 882 """ 883 if cmd_args == None or len(cmd_args) < 1: 884 print "No arguments passed" 885 print ShowAct.__doc__.strip() 886 return False 887 threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 888 print GetThreadSummary.header 889 print GetThreadSummary(threadval) 890 print GetThreadBackTrace(threadval, prefix="\t") 891 return 892 893@lldb_command('switchtoact') 894def SwitchToAct(cmd_args=None): 895 """ Switch to different context specified by activation 896 This command allows gdb to examine the execution context and call 897 stack for the specified activation. For example, to view the backtrace 898 for an activation issue "switchtoact <address>", followed by "bt". 899 Before resuming execution, issue a "resetctx" command, to 900 return to the original execution context. 901 """ 902 if cmd_args == None or len(cmd_args) < 1: 903 print "No arguments passed" 904 print SwitchToAct.__doc__.strip() 905 return False 906 thval = kern.GetValueFromAddress(cmd_args[0], 'thread *') 907 lldbthread = GetLLDBThreadForKernelThread(thval) 908 print GetThreadSummary.header 909 print GetThreadSummary(thval) 910 LazyTarget.GetProcess().selected_thread = lldbthread 911 if not LazyTarget.GetProcess().SetSelectedThread(lldbthread): 912 print "Failed to switch thread." 913 return 914# Macro: showallstacks 915@lldb_command('showallstacks') 916def ShowAllStacks(cmd_args=None): 917 """Routine to print out the stack for each thread in the system. 918 """ 919 for t in kern.tasks: 920 ShowTaskStacks(t) 921 print " \n" 922 ZombStacks() 923 return 924 925# EndMacro: showallstacks 926 927# Macro: showcurrentstacks 928@lldb_command('showcurrentstacks') 929def ShowCurrentStacks(cmd_args=None): 930 """ Routine to print out the thread running on each cpu (incl. its stack) 931 """ 932 processor_list = kern.GetGlobalVariable('processor_list') 933 current_processor = processor_list 934 while unsigned(current_processor) > 0: 935 print "\n" + GetProcessorSummary(current_processor) 936 active_thread = current_processor.active_thread 937 if unsigned(active_thread) != 0 : 938 task_val = active_thread.task 939 proc_val = Cast(task_val.bsd_info, 'proc *') 940 print GetTaskSummary.header + " " + GetProcSummary.header 941 print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val) 942 print "\t" + GetThreadSummary.header 943 print "\t" + GetThreadSummary(active_thread) 944 print "\tBacktrace:" 945 print GetThreadBackTrace(active_thread, prefix="\t") 946 current_processor = current_processor.processor_list 947 return 948# EndMacro: showcurrentstacks 949 950@lldb_command('showcurrentthreads') 951def ShowCurrentThreads(cmd_args=None): 952 """ Display info about threads running on each cpu """ 953 processor_list = kern.GetGlobalVariable('processor_list') 954 current_processor = processor_list 955 while unsigned(current_processor) > 0: 956 print GetProcessorSummary(current_processor) 957 active_thread = current_processor.active_thread 958 if unsigned(active_thread) != 0 : 959 task_val = active_thread.task 960 proc_val = Cast(task_val.bsd_info, 'proc *') 961 print GetTaskSummary.header + " " + GetProcSummary.header 962 print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val) 963 print "\t" + GetThreadSummary.header 964 print "\t" + GetThreadSummary(active_thread) 965 current_processor = current_processor.processor_list 966 return 967 968def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""): 969 """ Get backtrace across interrupt context. 970 params: frame_addr - int - address in memory which is a frame pointer (ie. rbp, r7) 971 prefix - str - prefix for each line of output. 972 973 """ 974 out_string = "" 975 bt_count = 0 976 frame_ptr = frame_addr 977 previous_frame_ptr = 0 978 # <rdar://problem/12677290> lldb unable to find symbol for _mh_execute_header 979 mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16) 980 while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128: 981 if (kern.arch != 'arm' and frame_ptr < mh_execute_addr) or (kern.arch == 'arm' and frame_ptr > mh_execute_addr): 982 break 983 pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *') 984 pc_val = unsigned(dereference(pc_val)) 985 out_string += prefix + GetSourceInformationForAddress(pc_val) + "\n" 986 bt_count +=1 987 previous_frame_ptr = frame_ptr 988 frame_val = kern.GetValueFromAddress((frame_ptr), 'uintptr_t *') 989 if unsigned(frame_val) == 0: 990 break 991 frame_ptr = unsigned(dereference(frame_val)) 992 993 return out_string 994 995@lldb_command('fullbt') 996def FullBackTrace(cmd_args=[]): 997 """ Show full backtrace across the interrupt boundary. 998 Syntax: fullbt <frame ptr> 999 Example: fullbt `$rbp` 1000 """ 1001 if len(cmd_args) < 1: 1002 print FullBackTrace.__doc__ 1003 return False 1004 print GetFullBackTrace(ArgumentStringToInt(cmd_args[0]), prefix="\t") 1005 1006@lldb_command('fullbtall') 1007def FullBackTraceAll(cmd_args=[]): 1008 """ Show full backtrace across the interrupt boundary for threads running on all processors. 1009 Syntax: fullbtall 1010 Example: fullbtall 1011 """ 1012 for processor in IterateLinkedList(kern.globals.processor_list, 'processor_list') : 1013 print "\n" + GetProcessorSummary(processor) 1014 active_thread = processor.active_thread 1015 if unsigned(active_thread) != 0 : 1016 task_val = active_thread.task 1017 proc_val = Cast(task_val.bsd_info, 'proc *') 1018 print GetTaskSummary.header + " " + GetProcSummary.header 1019 print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val) 1020 print "\t" + GetThreadSummary.header 1021 print "\t" + GetThreadSummary(active_thread) 1022 print "\tBacktrace:" 1023 1024 ThreadVal = GetLLDBThreadForKernelThread(active_thread) 1025 1026 FramePtr = ThreadVal.frames[0].GetFP() 1027 1028 print GetFullBackTrace(unsigned(FramePtr), prefix="\t") 1029 1030 1031@lldb_command('symbolicate') 1032def SymbolicateAddress(cmd_args=[]): 1033 """ Symbolicate an address for symbol information from loaded symbols 1034 Example: "symbolicate 0xaddr" is equivalent to "output/a 0xaddr" 1035 """ 1036 if len(cmd_args) < 1: 1037 print "Invalid address.\nSyntax: symbolicate <address>" 1038 return False 1039 print GetSourceInformationForAddress(ArgumentStringToInt(cmd_args[0])) 1040 return True 1041 1042@lldb_command('showinitchild') 1043def ShowInitChild(cmd_args=None): 1044 """ Routine to print out all processes in the system 1045 which are children of init process 1046 """ 1047 headp = kern.globals.initproc.p_children 1048 for pp in IterateListEntry(headp, 'struct proc *', 'p_sibling'): 1049 print GetProcInfo(pp) 1050 return 1051 1052@lldb_command('showproctree') 1053def ShowProcTree(cmd_args=None): 1054 """ Routine to print the processes in the system in a hierarchical tree form. This routine does not print zombie processes. 1055 If no argument is given, showproctree will print all the processes in the system. 1056 If pid is specified, showproctree prints all the descendants of the indicated process 1057 """ 1058 search_pid = 0 1059 if cmd_args: 1060 search_pid = ArgumentStringToInt(cmd_args[0]) 1061 1062 if search_pid < 0: 1063 print "pid specified must be a positive number" 1064 print ShowProcTree.__doc__ 1065 return 1066 1067 hdr_format = "{0: <6s} {1: <14s} {2: <9s}\n" 1068 out_string = hdr_format.format("PID", "PROCESS", "POINTER") 1069 out_string += hdr_format.format('='*3, '='*7, '='*7) 1070 proc = GetProcForPid(search_pid) 1071 out_string += "{0: <6d} {1: <14s} [ {2: #019x} ]\n".format(proc.p_ppid, proc.p_pptr.p_comm, unsigned(proc.p_pptr)) 1072 out_string += "|--{0: <6d} {1: <16s} [ {2: #019x} ]\n".format(proc.p_pid, proc.p_comm, unsigned(proc)) 1073 print out_string 1074 ShowProcTreeRecurse(proc, "| ") 1075 1076 return 1077 1078def ShowProcTreeRecurse(proc, prefix=""): 1079 """ Prints descendants of a given proc in hierarchial tree form 1080 params: 1081 proc : core.value representing a struct proc * in the kernel 1082 returns: 1083 str : String containing info about a given proc and its descendants in tree form 1084 """ 1085 if proc.p_childrencnt > 0: 1086 head_ptr = proc.p_children.lh_first 1087 1088 for p in IterateListEntry(proc.p_children, 'struct proc *', 'p_sibling'): 1089 print prefix + "|--{0: <6d} {1: <16s} [ {2: #019x} ]\n".format(p.p_pid, p.p_comm, unsigned(p)) 1090 ShowProcTreeRecurse(p, prefix + "| ") 1091 1092@lldb_command('showthreadfortid') 1093def ShowThreadForTid(cmd_args=None): 1094 """ The thread structure contains a unique thread_id value for each thread. 1095 This command is used to retrieve the address of the thread structure(thread_t) 1096 corresponding to a given thread_id. 1097 """ 1098 if not cmd_args: 1099 print "Please provide thread_t whose tid you'd like to look up" 1100 print ShowThreadForTid.__doc__ 1101 return 1102 search_tid = ArgumentStringToInt(cmd_args[0]) 1103 for taskp in kern.tasks: 1104 for actp in IterateQueue(taskp.threads, 'struct thread *', 'task_threads'): 1105 if search_tid == int(actp.thread_id): 1106 print "Found {0: #019x}".format(actp) 1107 print GetThreadSummary.header 1108 print GetThreadSummary(actp) 1109 return 1110 print "Not a valid thread_id" 1111 1112# Macro: showallprocessors 1113 1114def GetProcessorSummary(processor): 1115 """ Internal function to print summary of processor 1116 params: processor - value representing struct processor * 1117 return: str - representing the details of given processor 1118 """ 1119 1120 processor_state_str = "INVALID" 1121 processor_state = int(processor.state) 1122 1123 processor_states = { 1124 0: 'OFF_LINE', 1125 1: 'SHUTDOWN', 1126 2: 'START', 1127 # 3 (formerly INACTIVE) 1128 4: 'IDLE', 1129 5: 'DISPATCHING', 1130 6: 'RUNNING' 1131 } 1132 1133 if processor_state in processor_states: 1134 processor_state_str = "{0: <11s} ".format(processor_states[processor_state]) 1135 1136 out_str = "Processor {: <#018x} cpu_id {:>#4x} State {:<s}\n".format(processor, int(processor.cpu_id), processor_state_str) 1137 return out_str 1138 1139def GetGroupSetSummary(runq, task_map): 1140 """ Internal function to print summary of group run queue 1141 params: runq - value representing struct run_queue * 1142 return: str - representing the details of given run_queue 1143 """ 1144 out_str = " runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency) 1145 1146 runq_queue_i = 0 1147 runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0]) 1148 1149 for runq_queue_i in range(runq_queue_count) : 1150 runq_queue_head = addressof(runq.queues[runq_queue_i]) 1151 runq_queue_p = runq_queue_head.next 1152 1153 if unsigned(runq_queue_p) != unsigned(runq_queue_head): 1154 runq_queue_this_count = 0 1155 1156 for entry in IterateQueue(runq_queue_head, "sched_entry_t", "links"): 1157 runq_queue_this_count += 1 1158 1159 out_str += " Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count) 1160 for entry in IterateQueue(runq_queue_head, "sched_entry_t", "links"): 1161 group = entry.group 1162 task = task_map.get(unsigned(group), "Unknown task!") 1163 out_str += "\tEntry [{: <#012x}] Priority {: <3d} Group {: <#012x} Task {: <#012x}\n".format(unsigned(entry), entry.sched_pri, unsigned(entry.group), unsigned(task)) 1164 1165 return out_str 1166 1167@lldb_command('showrunq') 1168def ShowRunq(cmd_args=None): 1169 """ Routine to print information of a runq 1170 Usage: showrunq <runq> 1171 """ 1172 out_str = '' 1173 runq = kern.GetValueFromAddress(cmd_args[0], 'struct run_queue *') 1174 out_str += GetRunQSummary(runq) 1175 print out_str 1176 1177def GetRunQSummary(runq): 1178 """ Internal function to print summary of run_queue 1179 params: runq - value representing struct run_queue * 1180 return: str - representing the details of given run_queue 1181 """ 1182 out_str = " runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency) 1183 1184 runq_queue_i = 0 1185 runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0]) 1186 1187 for runq_queue_i in range(runq_queue_count) : 1188 runq_queue_head = addressof(runq.queues[runq_queue_i]) 1189 runq_queue_p = runq_queue_head.next 1190 1191 if unsigned(runq_queue_p) != unsigned(runq_queue_head): 1192 runq_queue_this_count = 0 1193 1194 for thread in IterateQueue(runq_queue_head, "thread_t", "links"): 1195 runq_queue_this_count += 1 1196 1197 out_str += " Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count) 1198 out_str += "\t" + GetThreadSummary.header + "\n" 1199 for thread in IterateQueue(runq_queue_head, "thread_t", "links"): 1200 out_str += "\t" + GetThreadSummary(thread) + "\n" 1201 if config['verbosity'] > vHUMAN : 1202 out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n" 1203 return out_str 1204 1205 1206def GetGrrrSummary(grrr_runq): 1207 """ Internal function to print summary of grrr_run_queue 1208 params: grrr_runq - value representing struct grrr_run_queue * 1209 return: str - representing the details of given grrr_run_queue 1210 """ 1211 out_str = " GRRR Info: Count {: <10d} Weight {: <10d} Current Group {: <#012x}\n".format(grrr_runq.count, 1212 grrr_runq.weight, grrr_runq.current_group) 1213 grrr_group_i = 0 1214 grrr_group_count = sizeof(grrr_runq.groups)/sizeof(grrr_runq.groups[0]) 1215 for grrr_group_i in range(grrr_group_count) : 1216 grrr_group = addressof(grrr_runq.groups[grrr_group_i]) 1217 if grrr_group.count > 0: 1218 out_str += " Group {: <3d} [{: <#012x}] ".format(grrr_group.index, grrr_group) 1219 out_str += "Count {:d} Weight {:d}\n".format(grrr_group.count, grrr_group.weight) 1220 grrr_group_client_head = addressof(grrr_group.clients) 1221 out_str += GetThreadSummary.header 1222 for thread in IterateQueue(grrr_group_client_head, "thread_t", "links"): 1223 out_str += "\t" + GetThreadSummary(thread) + "\n" 1224 if config['verbosity'] > vHUMAN : 1225 out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n" 1226 return out_str 1227 1228@lldb_command('showallprocessors') 1229def ShowAllProcessors(cmd_args=None): 1230 """ Routine to print information of all psets and processors 1231 Usage: showallprocessors 1232 """ 1233 pset = addressof(kern.globals.pset0) 1234 show_grrr = 0 1235 show_priority_runq = 0 1236 show_priority_pset_runq = 0 1237 show_group_pset_runq = 0 1238 show_fairshare_grrr = 0 1239 show_fairshare_list = 0 1240 sched_enum_val = kern.globals._sched_enum 1241 1242 if sched_enum_val == 1: 1243 show_priority_runq = 1 1244 show_fairshare_list = 1 1245 elif sched_enum_val == 2: 1246 show_priority_pset_runq = 1 1247 show_fairshare_list = 1 1248 elif sched_enum_val == 4: 1249 show_grrr = 1 1250 show_fairshare_grrr = 1 1251 elif sched_enum_val == 5: 1252 show_priority_runq = 1 1253 show_group_pset_runq = 1 1254 show_fairshare_list = 1 1255 elif sched_enum_val == 6: 1256 show_priority_pset_runq = 1 1257 show_priority_runq = 1 1258 show_fairshare_list = 1 1259 1260 out_str = '' 1261 1262 out_str += "Scheduler: {:s} ({:s}, {:d})\n".format(kern.globals.sched_string, 1263 kern.Symbolicate(unsigned(kern.globals.sched_current_dispatch)), 1264 sched_enum_val) 1265 1266 out_str += "Runnable threads: {:d} Timeshare threads: {:d} Background threads {:d}\n".format( 1267 kern.globals.sched_run_count, kern.globals.sched_share_count, kern.globals.sched_background_count) 1268 1269 if show_group_pset_runq: 1270 # Create a group->task mapping 1271 task_map = {} 1272 for task in kern.tasks: 1273 task_map[unsigned(task.sched_group)] = task 1274 for task in kern.terminated_tasks: 1275 task_map[unsigned(task.sched_group)] = task 1276 1277 while unsigned(pset) != 0: 1278 out_str += "Processor Set {: <#012x} Count {:d} (cpu_id {:<#x}-{:<#x})\n".format(pset, 1279 pset.cpu_set_count, pset.cpu_set_low, pset.cpu_set_hi) 1280 1281 if show_priority_pset_runq: 1282 runq = pset.pset_runq 1283 out_str += GetRunQSummary(runq) 1284 1285 if show_group_pset_runq: 1286 out_str += "Main Runq:\n" 1287 runq = pset.pset_runq 1288 out_str += GetGroupSetSummary(runq, task_map) 1289 out_str += "All Groups:\n" 1290 # TODO: Possibly output task header for each group 1291 for group in IterateQueue(kern.globals.sched_groups, "sched_group_t", "sched_groups"): 1292 if (group.runq.count != 0) : 1293 task = task_map.get(unsigned(group), "Unknown task!") 1294 out_str += "Group {: <#012x} Task {: <#012x}\n".format(unsigned(group), unsigned(task)) 1295 out_str += GetRunQSummary(group.runq) 1296 1297 out_str += " Active Processors:\n" 1298 for processor in IterateQueue(pset.active_queue, "processor_t", "processor_queue"): 1299 out_str += " " 1300 out_str += GetProcessorSummary(processor) 1301 if show_priority_runq: 1302 runq = processor.runq 1303 out_str += GetRunQSummary(runq) 1304 if show_grrr: 1305 grrr_runq = processor.grrr_runq 1306 out_str += GetGrrrSummary(grrr_runq) 1307 1308 out_str += " Idle Processors:\n" 1309 for processor in IterateQueue(pset.idle_queue, "processor_t", "processor_queue"): 1310 out_str += " " + GetProcessorSummary(processor) 1311 if show_priority_runq: 1312 out_str += GetRunQSummary(processor.runq) 1313 1314 out_str += " Idle Secondary Processors:\n" 1315 for processor in IterateQueue(pset.idle_secondary_queue, "processor_t", "processor_queue"): 1316 out_str += " " + GetProcessorSummary(processor) 1317 if show_priority_runq: 1318 out_str += GetRunQSummary(processor.runq) 1319 1320 pset = pset.pset_list 1321 1322 out_str += "\nRealtime Queue Count {:d}\n".format(kern.globals.rt_runq.count) 1323 for rt_runq_thread in IterateQueue(kern.globals.rt_runq.queue, "thread_t", "links"): 1324 out_str += ShowTask([unsigned(rt_runq_thread.task)]) 1325 out_str += ShowAct([unsigned(rt_runq_thread)]) 1326 1327 out_str += "\n" 1328 if show_fairshare_list: 1329 out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_runq.count) 1330 for fs_runq_thread in IterateQueue(kern.globals.fs_runq.queue, "thread_t", "links"): 1331 out_str += ShowTask([unsigned(fs_runq_thread.task)]) 1332 out_str += ShowAct([unsigned(rt_runq_thread)]) 1333 if show_fairshare_grrr: 1334 out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_grrr_runq.count) 1335 fs_grrr = addressof(kern.globals.fs_grrr_runq) 1336 out_str += GetGrrrSummary(fs_grrr) 1337 1338 print out_str 1339# EndMacro: showallprocessors 1340 1341def GetLedgerEntrySummary(ledger_template, ledger, i): 1342 """ Internal function to get internals of a ledger entry (*not* a ledger itself) 1343 params: ledger_template - value representing struct ledger_template_t for the task or thread 1344 ledger - value representing struct ledger_entry * 1345 return: str - formatted output information of ledger entries 1346 """ 1347 ledger_limit_infinity = (uint64_t(0x1).value << 63) - 1 1348 lf_refill_scheduled = 0x0400 1349 lf_tracking_max = 0x4000 1350 1351 out_str = '' 1352 now = unsigned(kern.globals.sched_tick) / 20 1353 lim_pct = 0 1354 1355 out_str += "{: >32s} {:<2d}:".format(ledger_template.lt_entries[i].et_key, i) 1356 out_str += "{: >15d} ".format(unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) 1357 if (ledger.le_flags & lf_tracking_max): 1358 out_str += "{:9d} {:5d} ".format(ledger._le.le_peaks[0].le_max, now - unsigned(ledger._le.le_peaks[0].le_time)) 1359 out_str += "{:9d} {:4d} ".format(ledger._le.le_peaks[1].le_max, now - unsigned(ledger._le.le_peaks[1].le_time)) 1360 else: 1361 out_str += " - - - - " 1362 1363 out_str += "{:12d} {:12d} ".format(unsigned(ledger.le_credit), unsigned(ledger.le_debit)) 1364 if (unsigned(ledger.le_limit) != ledger_limit_infinity): 1365 out_str += "{:12d} ".format(unsigned(ledger.le_limit)) 1366 else: 1367 out_str += " - " 1368 1369 if (ledger.le_flags & lf_refill_scheduled): 1370 out_str += "{:15d} ".format(ledger._le.le_refill.le_refill_period) 1371 else: 1372 out_str += " - " 1373 1374 if (ledger.le_flags & lf_refill_scheduled): 1375 out_str += "{:9d} ".format((unsigned(ledger.le_limit) * 100) / ledger._le.le_refill.le_refill_period) 1376 else: 1377 out_str += " - " 1378 1379 if (unsigned(ledger.le_warn_level) != ledger_limit_infinity): 1380 out_str += "{:9d} ".format((unsigned(ledger.le_warn_level) * 100) / unsigned(ledger.le_limit)) 1381 else: 1382 out_str += " - " 1383 1384 if ((unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) > unsigned(ledger.le_limit)): 1385 out_str += " X " 1386 else: 1387 out_str += " " 1388 1389 out_str += "{:#8x}\n".format(ledger.le_flags) 1390 return out_str 1391 1392def GetThreadLedgerSummary(thread_val): 1393 """ Internal function to get a summary of ledger entries for the given thread 1394 params: thread - value representing struct thread * 1395 return: str - formatted output information for ledger entries of the input thread 1396 """ 1397 out_str = " [{:#08x}]\n".format(thread_val) 1398 ledgerp = thread_val.t_threadledger 1399 if ledgerp: 1400 i = 0 1401 while i != ledgerp.l_template.lt_cnt: 1402 out_str += GetLedgerEntrySummary(kern.globals.thread_ledger_template, 1403 ledgerp.l_entries[i], i) 1404 i = i + 1 1405 return out_str 1406 1407@header("{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >9s} {5: >6s} {6: >8s} {7: <10s} {8: <9s} \ 1408 {9: <12s} {10: <7s} {11: <15s} {12: <8s} {13: <9s} {14: <6s} {15: >6s}".format( 1409 "task [thread]", "entry", "#", "balance", "peakA", "(age)", "peakB", "(age)", "credit", 1410 "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags")) 1411def GetTaskLedgers(task_val): 1412 """ Internal function to get summary of ledger entries from the task and its threads 1413 params: task_val - value representing struct task * 1414 return: str - formatted output information for ledger entries of the input task 1415 """ 1416 out_str = '' 1417 task_ledgerp = task_val.ledger 1418 i = 0 1419 out_str += "{: #08x} ".format(task_val) 1420 pval = Cast(task_val.bsd_info, 'proc *') 1421 if pval: 1422 out_str += "{: <5s}:\n".format(pval.p_comm) 1423 else: 1424 out_str += "Invalid process:\n" 1425 while i != task_ledgerp.l_template.lt_cnt: 1426 out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i) 1427 i = i + 1 1428 1429 # Now walk threads 1430 for thval in IterateQueue(task_val.threads, 'thread *', 'task_threads'): 1431 out_str += GetThreadLedgerSummary(thval) 1432 1433 return out_str 1434 1435# Macro: showtaskledgers 1436 1437@lldb_command('showtaskledgers', 'F:') 1438def ShowTaskLedgers(cmd_args=None, cmd_options={}): 1439 """ Routine to print a summary of ledger entries for the task and all of its threads 1440 Usage: showtaskledgers <address of task> 1441 or : showtaskledgers -F <name of task> 1442 """ 1443 if "-F" in cmd_options: 1444 task_list = FindTasksByName(cmd_options["-F"]) 1445 for tval in task_list: 1446 print GetTaskLedgers.header 1447 print GetTaskLedgers(tval) 1448 return 1449 1450 if not cmd_args: 1451 raise ArgumentError("No arguments passed.") 1452 tval = kern.GetValueFromAddress(cmd_args[0], 'task *') 1453 if not tval: 1454 raise ArgumentError("unknown arguments: %r" %cmd_args) 1455 print GetTaskLedgers.header 1456 print GetTaskLedgers(tval) 1457 1458# EndMacro: showtaskledgers 1459 1460# Macro: showalltaskledgers 1461 1462@lldb_command('showalltaskledgers') 1463def ShowAllTaskLedgers(cmd_args=None): 1464 """ Routine to print a summary of ledger entries for all tasks and respective threads 1465 Usage: showalltaskledgers 1466 """ 1467 for t in kern.tasks: 1468 task_val = unsigned(t) 1469 ShowTaskLedgers([task_val]) 1470 1471# EndMacro: showalltaskledgers 1472 1473# Macro: showprocuuidpolicytable 1474 1475@lldb_type_summary(['proc_uuid_policy_entry']) 1476@header("{0: <36s} {1: <10s}".format("uuid", "flags")) 1477def GetProcUUIDPolicyEntrySummary(entry): 1478 """ Summarizes the important fields in proc_uuid_policy_entry structure. 1479 params: entry: value - value object representing an entry 1480 returns: str - summary of the entry 1481 """ 1482 data = [] 1483 for i in range(16): 1484 data.append(int(entry.uuid[i])) 1485 flags = unsigned(entry.flags) 1486 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) 1487 return out_string 1488 1489@lldb_command('showprocuuidpolicytable') 1490def ShowProcUUIDPolicyTable(cmd_args=None): 1491 """ Routine to print the proc UUID policy table 1492 Usage: showprocuuidpolicytable 1493 """ 1494 hashslots = unsigned(kern.globals.proc_uuid_policy_hash_mask) 1495 print "{0: <8s} ".format("slot") + GetProcUUIDPolicyEntrySummary.header 1496 for i in range(0, hashslots+1): 1497 headp = addressof(kern.globals.proc_uuid_policy_hashtbl[i]) 1498 entrynum = 0 1499 for entry in IterateListEntry(headp, 'struct proc_uuid_policy_entry *', 'entries'): 1500 print "{0: >2d}.{1: <5d} ".format(i, entrynum) + GetProcUUIDPolicyEntrySummary(entry) 1501 entrynum += 1 1502 1503 1504# EndMacro: showprocuuidpolicytable 1505 1506@lldb_command('showalltaskpolicy') 1507def ShowAllTaskPolicy(cmd_args=None): 1508 """ 1509 Routine to print a summary listing of all the tasks 1510 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" 1511 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung 1512 io_policy -> RAGE - rapid aging of vnodes requested 1513 NORM - normal I/O explicitly requested (this is the default) 1514 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) 1515 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) 1516 """ 1517 global kern 1518 print GetTaskSummary.header + " " + GetProcSummary.header 1519 for t in kern.tasks: 1520 pval = Cast(t.bsd_info, 'proc *') 1521 print GetTaskSummary(t) +" "+ GetProcSummary(pval) 1522 requested_strings = [ 1523 ["int_darwinbg", "DBG-int"], 1524 ["ext_darwinbg", "DBG-ext"], 1525 ["int_iotier", "iotier-int"], 1526 ["ext_iotier", "iotier-ext"], 1527 ["int_iopassive", "passive-int"], 1528 ["ext_iopassive", "passive-ext"], 1529 ["bg_iotier", "bg-iotier"], 1530 ["terminated", "terminated"], 1531 ["th_pidbind_bg", "bg-pidbind"], 1532 ["th_workq_bg", "bg-workq"], 1533 ["t_apptype", "apptype"], 1534 ["t_boosted", "boosted"], 1535 ["t_int_gpu_deny", "gpudeny-int"], 1536 ["t_ext_gpu_deny", "gpudeny-ext"], 1537 ["t_role", "role"], 1538 ["t_tal_enabled", "tal-enabled"], 1539 ["t_base_latency_qos", "latency-base"], 1540 ["t_over_latency_qos", "latency-override"], 1541 ["t_base_through_qos", "throughput-base"], 1542 ["t_over_through_qos", "throughput-override"] 1543 ] 1544 1545 requested="" 1546 for value in requested_strings: 1547 if t.requested_policy.__getattr__(value[0]) : 1548 requested+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " " 1549 else: 1550 requested+="" 1551 1552 suppression_strings = [ 1553 ["t_sup_active", "active"], 1554 ["t_sup_lowpri_cpu", "lowpri-cpu"], 1555 ["t_sup_timer", "timer-throttling"], 1556 ["t_sup_disk", "disk-throttling"], 1557 ["t_sup_cpu_limit", "cpu-limits"], 1558 ["t_sup_suspend", "suspend"], 1559 ["t_sup_bg_sockets", "bg-sockets"] 1560 ] 1561 1562 suppression="" 1563 for value in suppression_strings: 1564 if t.requested_policy.__getattr__(value[0]) : 1565 suppression+=value[1] + ": " + str(t.requested_policy.__getattr__(value[0])) + " " 1566 else: 1567 suppression+="" 1568 1569 effective_strings = [ 1570 ["darwinbg", "background"], 1571 ["lowpri_cpu", "lowpri-cpu"], 1572 ["io_tier", "iotier"], 1573 ["io_passive", "passive"], 1574 ["all_sockets_bg", "bg-allsockets"], 1575 ["new_sockets_bg", "bg-newsockets"], 1576 ["bg_iotier", "bg-iotier"], 1577 ["terminated", "terminated"], 1578 ["t_gpu_deny", "gpu-deny"], 1579 ["t_tal_engaged", "tal-engaged"], 1580 ["t_suspended", "suspended"], 1581 ["t_watchers_bg", "bg-watchers"], 1582 ["t_latency_qos", "latency-qos"], 1583 ["t_through_qos", "throughput-qos"], 1584 ["t_sup_active", "suppression-active"], 1585 ["t_role", "role"] 1586 ] 1587 1588 effective="" 1589 for value in effective_strings: 1590 if t.effective_policy.__getattr__(value[0]) : 1591 effective+=value[1] + ": " + str(t.effective_policy.__getattr__(value[0])) + " " 1592 else: 1593 effective+="" 1594 1595 1596 pended_strings = [ 1597 ["t_updating_policy", "updating"], 1598 ["update_sockets", "update_sockets"], 1599 ["t_update_timers", "update_timers"], 1600 ["t_update_watchers", "update_watchers"] 1601 ] 1602 1603 pended="" 1604 for value in pended_strings: 1605 if t.pended_policy.__getattr__(value[0]) : 1606 pended+=value[1] + ": " + str(t.pended_policy.__getattr__(value[0])) + " " 1607 else: 1608 pended+="" 1609 1610 print "requested: " + requested 1611 print "suppression: " + suppression 1612 print "effective: " + effective 1613 print "pended: " + pended 1614 1615 1616@lldb_type_summary(['wait_queue', 'wait_queue_t']) 1617@header("{: <20s} {: <20s} {: <15s} {:<5s} {:<5s} {: <20s}".format("waitq", "interlock", "policy", "members", "threads", "eventmask")) 1618def GetWaitQSummary(waitq): 1619 """ Summarizes the important fields in task structure. 1620 params: task: value - value object representing a task in kernel 1621 returns: str - summary of the task 1622 """ 1623 out_string = "" 1624 format_string = '{: <#020x} {: <#020x} {: <15s} {: <5d} {: <5d} {: <#020x}' 1625 1626 wqtype = "" 1627 1628 if (waitq.wq_fifo == 1) : 1629 wqtype += "FIFO" 1630 else : 1631 wqtype += "PRIO" 1632 1633 if (waitq.wq_prepost == 1) : 1634 wqtype += "Prepost" 1635 1636 if (waitq.wq_type == 0x3) : 1637 wqtype += "Set" 1638 elif (waitq.wq_type == 0x2) : 1639 wqtype += "Queue" 1640 else : 1641 wqtype += "INVALID" 1642 1643 out_string += format_string.format(waitq, unsigned(waitq.wq_interlock.lock_data), policy, 0, 0, unsigned(waitq.wq_eventmask)) 1644 1645 out_string += "\n" + GetThreadSummary.header 1646 1647 for thread in IterateQueue(waitq.wq_queue, "thread_t", "links"): 1648 out_string += "\n" + GetThreadSummary(thread) 1649 1650 return out_string 1651 1652 1653@lldb_command('showallsuspendedtasks', '') 1654def ShowSuspendedTasks(cmd_args=[], options={}): 1655 """ Show a list of suspended tasks with their process name summary. 1656 """ 1657 print GetTaskSummary.header + ' ' + GetProcSummary.header 1658 for t in kern.tasks: 1659 if t.suspend_count > 0: 1660 print GetTaskSummary(t) + ' ' + GetProcSummary(Cast(t.bsd_info, 'proc *')) 1661 return True 1662 1663 1664