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.
9 from core
.lazytarget
import *
14 from collections
import defaultdict
16 def GetProcName(proc
):
17 """ returns a string name of the process. Longer variant is preffered if provided.
19 proc: value object representing a proc in the kernel.
21 str: a string name of the process linked to the task.
23 name
= str(proc
.p_name
)
27 return str(proc
.p_comm
)
29 def GetProcNameForTask(task
):
30 """ returns a string name of the process. If proc is not valid the proc
31 name is looked up in the associated importance structure (if
32 available). If no name can be found, "unknown" is returned.
34 task: value object represeting a task in the kernel.
36 str : A string name of the process linked to the task
39 if unsigned(task
.bsd_info
):
40 p
= Cast(task
.bsd_info
, 'proc *')
43 if (hasattr(task
, 'task_imp_base') and
44 hasattr(task
.task_imp_base
, 'iit_procname') and
45 unsigned(task
.task_imp_base
) != 0):
46 return str(task
.task_imp_base
.iit_procname
)
50 def GetProcPIDForTask(task
):
51 """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned.
53 task: value object representing a task in the kernel
55 int : pid of the process or -1 if not found
57 if task
and unsigned(task
.bsd_info
):
58 p
= Cast(task
.bsd_info
, 'proc *')
59 return unsigned(p
.p_pid
)
62 return unsigned(task
.audit_token
.val
[5])
66 def GetProcInfo(proc
):
67 """ returns a string name, pid, parent and task for a proc_t. Decodes cred, flag and p_stat fields.
69 proc : value object representing a proc in the kernel
71 str : A string describing various information for process.
74 out_string
+= ("Process {p: <#020x}\n\tname {0: <32s}\n\tpid:{p.p_pid: <6d} " +
75 "task:{p.task: <#020x} p_stat:{p.p_stat: <6d} parent pid: {p.p_ppid: <6d}\n"
76 ).format(GetProcName(proc
), p
=proc
)
80 out_string
+= "Cred: euid {:d} ruid {:d} svuid {:d}\n".format(ucred
.cr_posix
.cr_uid
,
81 ucred
.cr_posix
.cr_ruid
,
82 ucred
.cr_posix
.cr_svuid
)
84 flags
= int(proc
.p_flag
)
85 out_string
+= "Flags: {0: <#020x}\n".format(flags
)
90 out_string
+= "\t" + xnudefines
.proc_flag_explain_strings
[i
] + "\n"
91 elif num
== 0x4: #special case for 32bit flag
92 out_string
+= "\t" + xnudefines
.proc_flag_explain_strings
[0] + "\n"
95 out_string
+= "State: "
96 state_val
= proc
.p_stat
97 if state_val
< 1 or state_val
> len(xnudefines
.proc_state_strings
) :
98 out_string
+= "(Unknown)"
100 out_string
+= xnudefines
.proc_state_strings
[int(state_val
)]
104 def GetProcNameForPid(pid
):
105 """ Finds the name of the process corresponding to a given pid
107 pid : int, pid you want to find the procname for
109 str : Name of the process corresponding to the pid, "Unknown" if not found
112 if int(p
.p_pid
) == int(pid
):
113 return GetProcName(p
)
116 def GetProcForPid(search_pid
):
117 """ Finds the value object representing a proc in the kernel based on its pid
119 search_pid : int, pid whose proc structure you want to find
121 value : The value object representing the proc, if a proc corresponding
122 to the given pid is found. Returns None otherwise
125 return kern
.globals.initproc
127 headp
= kern
.globals.allproc
128 for proc
in IterateListEntry(headp
, 'struct proc *', 'p_list'):
129 if proc
.p_pid
== search_pid
:
133 @lldb_command('allproc')
134 def AllProc(cmd_args
=None):
135 """ Walk through the allproc structure and print procinfo for each process structure.
137 cmd_args - [] : array of strings passed from lldb command prompt
139 for proc
in kern
.procs
:
140 print GetProcInfo(proc
)
143 @lldb_command('zombproc')
144 def ZombProc(cmd_args
=None):
145 """ Routine to print out all procs in the zombie list
147 cmd_args - [] : array of strings passed from lldb command prompt
149 if len(kern
.zombprocs
) != 0:
150 print "\nZombie Processes:"
151 for proc
in kern
.zombprocs
:
152 print GetProcInfo(proc
) + "\n\n"
154 @lldb_command('zombtasks')
155 def ZombTasks(cmd_args
=None):
156 """ Routine to print out all tasks in the zombie list
160 if len(kern
.zombprocs
) != 0:
161 header
= "\nZombie Tasks:\n"
162 header
+= GetTaskSummary
.header
+ " " + GetProcSummary
.header
163 for proc
in kern
.zombprocs
:
165 t
= Cast(proc
.task
, 'task *')
166 out_str
+= GetTaskSummary(t
) +" "+ GetProcSummary(proc
) + "\n"
171 @lldb_command('zombstacks')
172 def ZombStacks(cmd_args
=None):
173 """ Routine to print out all stacks of tasks that are exiting
176 for proc
in kern
.zombprocs
:
179 print "\nZombie Stacks:"
181 t
= Cast(proc
.task
, 'task *')
185 def GetASTSummary(ast
):
186 """ Summarizes an AST field
201 T - AST_TELEMETRY_USER
202 T - AST_TELEMETRY_KERNEL
203 T - AST_TELEMETRY_WINDOWED
213 thread_state_chars
= {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A',
214 0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400: 'r', 0x800: 'a',
215 0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S',
216 0x20000: 'D', 0x40000: 'I', 0x80000: 'E', 0x100000: 'R', 0x200000: 'N'}
219 while mask
<= 0x200000:
220 state_str
+= thread_state_chars
[int(state
& mask
)]
226 @lldb_type_summary(['kcdata_descriptor *', 'kcdata_descriptor_t'])
227 @header("{0: <20s} {1: <20s} {2: <20s} {3: <10s} {4: <5s}".format("kcdata_descriptor", "begin_addr", "cur_pos", "size", "flags"))
228 def GetKCDataSummary(kcdata
):
229 """ Summarizes kcdata_descriptor structure
230 params: kcdata: value - value object representing kcdata_descriptor
231 returns: str - summary of the kcdata object
233 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: <10d} {4: <#05x}"
234 return format_string
.format(kcdata
, kcdata
.kcd_addr_begin
, kcdata
.kcd_addr_end
, kcdata
.kcd_length
, kcdata
.kcd_flags
)
237 @lldb_type_summary(['task', 'task_t'])
238 @header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags"))
239 def GetTaskSummary(task
, showcorpse
=False):
240 """ Summarizes the important fields in task structure.
241 params: task: value - value object representing a task in kernel
242 returns: str - summary of the task
245 format_string
= '{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: <5s}'
246 thread_count
= int(task
.thread_count
)
248 if hasattr(task
, "suppression_generation") and (int(task
.suppression_generation
) & 0x1) == 0x1:
250 if hasattr(task
, "effective_policy") and int(task
.effective_policy
.tep_sup_active
) == 1:
252 if hasattr(task
, "suspend_count") and int(task
.suspend_count
) > 0:
254 if hasattr(task
, 'task_imp_base') and unsigned(task
.task_imp_base
):
255 tib
= task
.task_imp_base
256 if int(tib
.iit_receiver
) == 1:
258 if int(tib
.iit_donor
) == 1:
260 if int(tib
.iit_assertcnt
) > 0:
263 # check if corpse flag is set
264 if unsigned(task
.t_flags
) & 0x20:
266 if unsigned(task
.t_flags
) & 0x40:
269 out_string
+= format_string
.format(task
, task
.map, task
.itk_space
, thread_count
, task_flags
)
270 if showcorpse
is True and unsigned(task
.corpse_info
) != 0:
271 out_string
+= " " + GetKCDataSummary(task
.corpse_info
)
274 def GetThreadName(thread
):
275 """ Get the name of a thread, if possible. Returns the empty string
278 if int(thread
.uthread
) != 0:
279 uthread
= Cast(thread
.uthread
, 'uthread *')
280 if int(uthread
.pth_name
) != 0 :
281 th_name_strval
= Cast(uthread
.pth_name
, 'char *')
282 if len(str(th_name_strval
)) > 0 :
283 return str(th_name_strval
)
287 @lldb_type_summary(['thread *', 'thread_t'])
288 @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', 'waitq', 'wait_event', 'wmesg', 'thread_name'))
289 def GetThreadSummary(thread
):
290 """ Summarize the thread structure. It decodes the wait state and waitevents from the data in the struct.
291 params: thread: value - value objecte representing a thread in kernel
292 returns: str - summary of a thread
300 A - Terminated and on termination queue
311 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}"
312 thread_ptr_str
= str("{0: <#020x}".format(thread
))
313 if int(thread
.static_param
) :
314 thread_ptr_str
+="[WQ]"
315 thread_id
= hex(thread
.thread_id
)
316 processor
= hex(thread
.last_processor
)
317 base_priority
= str(int(thread
.base_pri
))
318 sched_priority
= str(int(thread
.sched_pri
))
320 mode
= str(thread
.sched_mode
)
321 if "TIMESHARE" in mode
:
322 sched_mode
+="timeshare"
323 elif "FIXED" in mode
:
325 elif "REALTIME" in mode
:
326 sched_mode
+="realtime"
328 if (unsigned(thread
.bound_processor
) != 0):
332 if (unsigned(thread
.sched_flags
) & 0x0004):
336 thread_name
= GetThreadName(thread
)
337 if int(thread
.uthread
) != 0:
338 uthread
= Cast(thread
.uthread
, 'uthread *')
340 #check for io_policy flags
341 if int(uthread
.uu_flag
) & 0x400:
342 io_policy_str
+='RAGE '
344 #now flags for task_policy
348 if int(thread
.effective_policy
.thep_darwinbg
) != 0:
350 if int(thread
.effective_policy
.thep_io_tier
) != 0:
352 if int(thread
.effective_policy
.thep_io_passive
) != 0:
354 if int(thread
.effective_policy
.thep_terminated
) != 0:
357 state
= int(thread
.state
)
358 thread_state_chars
= {0x0:'', 0x1:'W', 0x2:'S', 0x4:'R', 0x8:'U', 0x10:'H', 0x20:'A', 0x40:'P', 0x80:'I'}
362 state_str
+= thread_state_chars
[int(state
& mask
)]
365 if int(thread
.inspection
):
368 ast
= int(thread
.ast
) |
int(thread
.reason
)
369 ast_str
= GetASTSummary(ast
)
371 #wait queue information
375 if ( state
& 0x1 ) != 0:
376 #we need to look at the waitqueue as well
377 wait_queue_str
= str("{0: <#020x}".format(int(hex(thread
.waitq
), 16)))
378 wait_event_str
= str("{0: <#020x}".format(int(hex(thread
.wait_event
), 16)))
379 wait_event_str_sym
= kern
.Symbolicate(int(hex(thread
.wait_event
), 16))
380 if len(wait_event_str_sym
) > 0:
381 wait_event_str
= wait_event_str
.strip() + " <" + wait_event_str_sym
+ ">"
382 if int(thread
.uthread
) != 0 :
383 uthread
= Cast(thread
.uthread
, 'uthread *')
384 if int(uthread
.uu_wmesg
) != 0:
385 wait_message
= str(Cast(uthread
.uu_wmesg
, 'char *'))
387 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
)
391 def GetTaskRoleString(role
):
393 0 : "TASK_UNSPECIFIED",
394 1 : "TASK_FOREGROUND_APPLICATION",
395 2 : "TASK_BACKGROUND_APPLICATION",
396 3 : "TASK_CONTROL_APPLICATION",
397 4 : "TASK_GRAPHICS_SERVER",
398 5 : "TASK_THROTTLE_APPLICATION",
399 6 : "TASK_NONUI_APPLICATION",
400 7 : "TASK_DEFAULT_APPLICATION",
402 return role_strs
[int(role
)]
404 def GetCoalitionFlagString(coal
):
406 if (coal
.privileged
):
407 flags
.append('privileged')
408 if (coal
.termrequested
):
409 flags
.append('termrequested')
410 if (coal
.terminated
):
411 flags
.append('terminated')
413 flags
.append('reaped')
415 flags
.append('notified')
417 flags
.append('efficient')
418 return "|".join(flags
)
420 def GetCoalitionTasks(queue
, coal_type
, thread_details
=False):
422 0x0 : "SFI_CLASS_UNSPECIFIED",
423 0x1 : "SFI_CLASS_DARWIN_BG",
424 0x2 : "SFI_CLASS_APP_NAP",
425 0x3 : "SFI_CLASS_MANAGED_FOCAL",
426 0x4 : "SFI_CLASS_MANAGED_NONFOCAL",
427 0x5 : "SFI_CLASS_DEFAULT_FOCAL",
428 0x6 : "SFI_CLASS_DEFAULT_NONFOCAL",
429 0x7 : "SFI_CLASS_KERNEL",
430 0x8 : "SFI_CLASS_OPTED_OUT",
431 0x9 : "SFI_CLASS_UTILITY",
432 0xA : "SFI_CLASS_LEGACY_FOCAL",
433 0xB : "SFI_CLASS_LEGACY_NONFOCAL",
434 0xC : "SFI_CLASS_USER_INITIATED_FOCAL",
435 0xD : "SFI_CLASS_USER_INITIATED_NONFOCAL",
436 0xE : "SFI_CLASS_USER_INTERACTIVE_FOCAL",
437 0xF : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL",
438 0x10 : "SFI_CLASS_MAINTENANCE",
441 field_name
= 'task_coalition'
442 for task
in IterateLinkageChain(queue
, 'task *', field_name
, coal_type
* sizeof('queue_chain_t')):
443 task_str
= "({0: <d},{1: #x}, {2: <s}, {3: <s})".format(GetProcPIDForTask(task
),task
,GetProcNameForTask(task
),GetTaskRoleString(task
.effective_policy
.tep_role
))
445 for thread
in IterateQueue(task
.threads
, "thread_t", "task_threads"):
446 task_str
+= "\n\t\t\t|-> thread:" + hex(thread
) + ", " + sfi_strs
[int(thread
.sfi_class
)]
447 tasks
.append(task_str
)
450 def GetCoalitionTypeString(type):
451 """ Convert a coalition type field into a string
452 Currently supported types (from <mach/coalition.h>):
453 COALITION_TYPE_RESOURCE
454 COALITION_TYPE_JETSAM
456 if type == 0: # COALITION_TYPE_RESOURCE
462 def GetResourceCoalitionSummary(coal
, verbose
=False):
463 """ Summarize a resource coalition
465 out_string
= "Resource Coalition:\n\t Ledger:\n"
466 thread_details
= False
467 if config
['verbosity'] > vSCRIPT
:
468 thread_details
= True
469 ledgerp
= coal
.r
.ledger
470 if verbose
and unsigned(ledgerp
) != 0:
472 while i
!= ledgerp
.l_template
.lt_cnt
:
474 out_string
+= GetLedgerEntrySummary(kern
.globals.task_ledger_template
, ledgerp
.l_entries
[i
], i
)
476 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
)
477 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
)
478 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
)
479 out_string
+= "\n\t cpu_ptime {0: <d}".format(coal
.r
.cpu_ptime
)
481 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_DEFAULT] {0: <d}".format(coal
.r
.cpu_time_eqos
[0])
482 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_MAINTENANCE] {0: <d}".format(coal
.r
.cpu_time_eqos
[1])
483 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_BACKGROUND] {0: <d}".format(coal
.r
.cpu_time_eqos
[2])
484 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_UTILITY] {0: <d}".format(coal
.r
.cpu_time_eqos
[3])
485 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_LEGACY] {0: <d}".format(coal
.r
.cpu_time_eqos
[4])
486 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_USER_INITIATED] {0: <d}".format(coal
.r
.cpu_time_eqos
[5])
487 out_string
+= "\n\t cpu_time_effective[THREAD_QOS_USER_INTERACTIVE] {0: <d}".format(coal
.r
.cpu_time_eqos
[6])
488 out_string
+= "\n\t Tasks:\n\t\t"
489 tasks
= GetCoalitionTasks(addressof(coal
.r
.tasks
), 0, thread_details
)
490 out_string
+= "\n\t\t".join(tasks
)
493 def GetJetsamCoalitionSummary(coal
, verbose
=False):
494 out_string
= "Jetsam Coalition:"
495 thread_details
= False
496 if config
['verbosity'] > vSCRIPT
:
497 thread_details
= True
498 if unsigned(coal
.j
.leader
) == 0:
499 out_string
+= "\n\t NO Leader!"
501 out_string
+= "\n\t Leader:\n\t\t"
502 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
))
503 out_string
+= "\n\t Extensions:\n\t\t"
504 tasks
= GetCoalitionTasks(addressof(coal
.j
.extensions
), 1, thread_details
)
505 out_string
+= "\n\t\t".join(tasks
)
506 out_string
+= "\n\t XPC Services:\n\t\t"
507 tasks
= GetCoalitionTasks(addressof(coal
.j
.services
), 1, thread_details
)
508 out_string
+= "\n\t\t".join(tasks
)
509 out_string
+= "\n\t Other Tasks:\n\t\t"
510 tasks
= GetCoalitionTasks(addressof(coal
.j
.other
), 1, thread_details
)
511 out_string
+= "\n\t\t".join(tasks
)
512 out_string
+= "\n\t Thread Group: {0: <#020x}\n".format(coal
.j
.thread_group
)
515 @lldb_type_summary(['coalition_t', 'coalition *'])
516 @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"))
517 def GetCoalitionSummary(coal
):
518 if unsigned(coal
) == 0:
519 return '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'.format(0, "", -1, -1, -1, -1, -1, "")
521 format_string
= '{0: <#020x} {1: <15s} {2: <10d} {3: <10d} {4: <10d} {5: <12d} {6: <12d} {7: <s}'
522 type_string
= GetCoalitionTypeString(coal
.type)
523 flag_string
= GetCoalitionFlagString(coal
)
524 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
)
527 def GetCoalitionInfo(coal
, verbose
=False):
528 """ returns a string describing a coalition, including details about the particular coalition type.
530 coal : value object representing a coalition in the kernel
532 str : A string describing the coalition.
534 if unsigned(coal
) == 0:
535 return "<null coalition>"
536 typestr
= GetCoalitionTypeString(coal
.type)
537 flagstr
= GetCoalitionFlagString(coal
)
539 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
)
540 if coal
.type == 0: # COALITION_TYPE_RESOURCE
541 out_string
+= GetResourceCoalitionSummary(coal
, verbose
)
542 elif coal
.type == 1: # COALITION_TYPE_JETSAM
543 out_string
+= GetJetsamCoalitionSummary(coal
, verbose
)
545 out_string
+= "Unknown Type"
549 # Macro: showcoalitioninfo
551 @lldb_command('showcoalitioninfo')
552 def ShowCoalitionInfo(cmd_args
=None, cmd_options
={}):
553 """ Display more detailed information about a coalition
554 Usage: showcoalitioninfo <address of coalition>
557 if config
['verbosity'] > vHUMAN
:
560 raise ArgumentError("No arguments passed")
561 coal
= kern
.GetValueFromAddress(cmd_args
[0], 'coalition *')
563 print "unknown arguments:", str(cmd_args
)
565 print GetCoalitionInfo(coal
, verbose
)
567 # EndMacro: showcoalitioninfo
569 # Macro: showallcoalitions
571 @lldb_command('showallcoalitions')
572 def ShowAllCoalitions(cmd_args
=None):
573 """ Print a summary listing of all the coalitions
576 print GetCoalitionSummary
.header
577 for c
in kern
.coalitions
:
578 print GetCoalitionSummary(c
)
580 # EndMacro: showallcoalitions
582 # Macro: showallthreadgroups
584 @lldb_type_summary(['struct thread_group *', 'thread_group *'])
585 @header("{0: <20s} {1: <5s} {2: <16s} {3: <5s} {4: <8s} {5: <20s}".format("thread_group", "id", "name", "refc", "flags", "recommendation"))
586 def GetThreadGroupSummary(tg
):
587 if unsigned(tg
) == 0:
588 return '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'.format(0, -1, "", -1, "", -1)
590 format_string
= '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'
592 if (tg
.tg_flags
& 0x1):
594 if (tg
.tg_flags
& 0x2):
596 out_string
+= format_string
.format(tg
, tg
.tg_id
, tg
.tg_name
, tg
.tg_refcount
.ref_count
, tg_flags
, tg
.tg_recommendation
)
599 @lldb_command('showallthreadgroups')
600 def ShowAllThreadGroups(cmd_args
=None):
601 """ Print a summary listing of all thread groups
604 print GetThreadGroupSummary
.header
605 for tg
in kern
.thread_groups
:
606 print GetThreadGroupSummary(tg
)
608 # EndMacro: showallthreadgroups
610 # Macro: showtaskcoalitions
612 @lldb_command('showtaskcoalitions', 'F:')
613 def ShowTaskCoalitions(cmd_args
=None, cmd_options
={}):
617 if "-F" in cmd_options
:
618 task_list
= FindTasksByName(cmd_options
["-F"])
620 t
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
623 raise ArgumentError("No arguments passed")
625 if len(task_list
) > 0:
626 print GetCoalitionSummary
.header
627 for task
in task_list
:
628 print GetCoalitionSummary(task
.coalition
[0])
629 print GetCoalitionSummary(task
.coalition
[1])
631 # EndMacro: showtaskcoalitions
633 @lldb_type_summary(['proc', 'proc *'])
634 @header("{0: >6s} {1: <18s} {2: >11s} {3: ^10s} {4: <32s}".format("pid", "process", "io_policy", "wq_state", "command"))
635 def GetProcSummary(proc
):
636 """ Summarize the process data.
638 proc : value - value representaitng a proc * in kernel
640 str - string summary of the process.
643 format_string
= "{0: >6d} {1: <#018x} {2: >11s} {3: >2d} {4: >2d} {5: >2d} {6: <32s}"
644 pval
= proc
.GetSBValue()
645 #code.interact(local=locals())
646 if str(pval
.GetType()) != str(gettype('proc *')) :
647 return "Unknown type " + str(pval
.GetType()) + " " + str(hex(proc
))
649 out_string
+= "Process " + hex(proc
) + " is not valid."
651 pid
= int(proc
.p_pid
)
652 proc_addr
= int(hex(proc
), 16)
654 if int(proc
.p_lflag
) & 0x400000 :
655 proc_rage_str
= "RAGE"
657 task
= Cast(proc
.task
, 'task *')
661 if int(task
.effective_policy
.tep_darwinbg
) != 0:
663 if int(task
.effective_policy
.tep_lowpri_cpu
) != 0:
666 if int(task
.effective_policy
.tep_io_tier
) != 0:
668 if int(task
.effective_policy
.tep_io_passive
) != 0:
670 if int(task
.effective_policy
.tep_terminated
) != 0:
673 if int(task
.effective_policy
.tep_latency_qos
) != 0:
675 if int(task
.effective_policy
.tep_sup_active
) != 0:
680 work_queue
= Cast(proc
.p_wqptr
, 'workqueue *')
681 if proc
.p_wqptr
!= 0 :
682 wq_num_threads
= int(work_queue
.wq_nthreads
)
683 wq_idle_threads
= int(work_queue
.wq_thidlecount
)
684 wq_req_threads
= int(work_queue
.wq_reqcount
)
693 process_name
= GetProcName(proc
)
694 if process_name
== 'xpcproxy':
695 for thread
in IterateQueue(task
.threads
, 'thread *', 'task_threads'):
696 thread_name
= GetThreadName(thread
)
698 process_name
+= ' (' + thread_name
+ ')'
700 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
)
703 @lldb_type_summary(['tty_dev_t', 'tty_dev_t *'])
704 @header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","master", "slave", "open", "free", "name", "revoke"))
705 def GetTTYDevSummary(tty_dev
):
706 """ Summarizes the important fields in tty_dev_t structure.
707 params: tty_dev: value - value object representing a tty_dev_t in kernel
708 returns: str - summary of the tty_dev
711 format_string
= "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}"
712 open_fn
= kern
.Symbolicate(int(hex(tty_dev
.open), 16))
713 free_fn
= kern
.Symbolicate(int(hex(tty_dev
.free
), 16))
714 name_fn
= kern
.Symbolicate(int(hex(tty_dev
.name
), 16))
715 revoke_fn
= kern
.Symbolicate(int(hex(tty_dev
.revoke
), 16))
716 out_string
+= format_string
.format(tty_dev
, tty_dev
.master
, tty_dev
.slave
, open_fn
, free_fn
, name_fn
, revoke_fn
)
721 @lldb_command('showtask', 'F:')
722 def ShowTask(cmd_args
=None, cmd_options
={}):
723 """ Routine to print a summary listing of given task
724 Usage: showtask <address of task>
725 or : showtask -F <name of task>
728 if "-F" in cmd_options
:
729 task_list
= FindTasksByName(cmd_options
['-F'])
732 raise ArgumentError("Invalid arguments passed.")
734 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
736 raise ("Unknown arguments: %r" % cmd_args
)
737 task_list
.append(tval
)
739 for tval
in task_list
:
740 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
741 pval
= Cast(tval
.bsd_info
, 'proc *')
742 print GetTaskSummary(tval
) +" "+ GetProcSummary(pval
)
748 @lldb_command('showpid')
749 def ShowPid(cmd_args
=None):
750 """ Routine to print a summary listing of task corresponding to given pid
751 Usage: showpid <pid value>
754 raise ArgumentError("No arguments passed")
755 pidval
= ArgumentStringToInt(cmd_args
[0])
757 pval
= Cast(t
.bsd_info
, 'proc *')
758 if pval
and pval
.p_pid
== pidval
:
759 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
760 print GetTaskSummary(t
) + " " + GetProcSummary(pval
)
767 @lldb_command('showproc')
768 def ShowProc(cmd_args
=None):
769 """ Routine to print a summary listing of task corresponding to given proc
770 Usage: showproc <address of proc>
773 raise ArgumentError("No arguments passed")
774 pval
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
776 print "unknown arguments:", str(cmd_args
)
778 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
779 tval
= Cast(pval
.task
, 'task *')
780 print GetTaskSummary(tval
) +" "+ GetProcSummary(pval
)
784 # Macro: showprocinfo
786 @lldb_command('showprocinfo')
787 def ShowProcInfo(cmd_args
=None):
788 """ Routine to display name, pid, parent & task for the given proc address
789 It also shows the Cred, Flags and state of the process
790 Usage: showprocinfo <address of proc>
793 raise ArgumentError("No arguments passed")
794 pval
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
796 print "unknown arguments:", str(cmd_args
)
798 print GetProcInfo(pval
)
800 # EndMacro: showprocinfo
802 #Macro: showprocfiles
804 @lldb_command('showprocfiles')
805 def ShowProcFiles(cmd_args
=None):
806 """ Given a proc_t pointer, display the list of open file descriptors for the referenced process.
807 Usage: showprocfiles <proc_t>
810 print ShowProcFiles
.__doc
__
812 proc
= kern
.GetValueFromAddress(cmd_args
[0], 'proc_t')
813 proc_filedesc
= proc
.p_fd
814 proc_lastfile
= unsigned(proc_filedesc
.fd_lastfile
)
815 proc_ofiles
= proc_filedesc
.fd_ofiles
816 if unsigned(proc_ofiles
) == 0:
817 print 'No open files for proc {0: <s}'.format(cmd_args
[0])
819 print "{0: <5s} {1: <18s} {2: <10s} {3: <8s} {4: <18s} {5: <64s}".format('FD', 'FILEGLOB', 'FG_FLAGS', 'FG_TYPE', 'FG_DATA','INFO')
820 print "{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format("")
823 while count
<= proc_lastfile
:
824 if unsigned(proc_ofiles
[count
]) != 0:
826 proc_fd_flags
= proc_ofiles
[count
].fp_flags
827 proc_fd_fglob
= proc_ofiles
[count
].fp_glob
828 out_str
+= "{0: <5d} ".format(count
)
829 out_str
+= "{0: <#18x} ".format(unsigned(proc_fd_fglob
))
830 out_str
+= "0x{0:0>8x} ".format(unsigned(proc_fd_flags
))
831 proc_fd_ftype
= unsigned(proc_fd_fglob
.fg_ops
.fo_type
)
832 if proc_fd_ftype
in xnudefines
.filetype_strings
:
833 out_str
+= "{0: <8s} ".format(xnudefines
.filetype_strings
[proc_fd_ftype
])
835 out_str
+= "?: {0: <5d} ".format(proc_fd_ftype
)
836 out_str
+= "{0: <#18x} ".format(unsigned(proc_fd_fglob
.fg_data
))
837 if proc_fd_ftype
== 1:
838 fd_name
= Cast(proc_fd_fglob
.fg_data
, 'struct vnode *').v_name
839 out_str
+= "{0: <64s}".format(fd_name
)
844 #EndMacro: showprocfiles
848 @lldb_command('showtty')
849 def ShowTTY(cmd_args
=None):
850 """ Display information about a struct tty
851 Usage: showtty <tty struct>
854 print ShowTTY
.__doc
__
857 tty
= kern
.GetValueFromAddress(cmd_args
[0], 'struct tty *')
858 print "TTY structure at: {0: <s}".format(cmd_args
[0])
859 print "Last input to raw queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty
.t_rawq
.c_cs
), tty
.t_rawq
.c_cs
)
860 print "Last input to canonical queue: {0: <#18x} \"{1: <s}\"".format(unsigned(tty
.t_canq
.c_cs
), tty
.t_canq
.c_cs
)
861 print "Last output data: {0: <#18x} \"{1: <s}\"".format(unsigned(tty
.t_outq
.c_cs
), tty
.t_outq
.c_cs
)
863 ['', 'TS_SO_OLOWAT (Wake up when output <= low water)'],
864 ['- (synchronous I/O mode)', 'TS_ASYNC (async I/O mode)'],
865 ['', 'TS_BUSY (Draining output)'],
866 ['- (Carrier is NOT present)', 'TS_CARR_ON (Carrier is present)'],
867 ['', 'TS_FLUSH (Outq has been flushed during DMA)'],
868 ['- (Open has NOT completed)', 'TS_ISOPEN (Open has completed)'],
869 ['', 'TS_TBLOCK (Further input blocked)'],
870 ['', 'TS_TIMEOUT (Wait for output char processing)'],
871 ['', 'TS_TTSTOP (Output paused)'],
872 ['', 'TS_WOPEN (Open in progress)'],
873 ['', 'TS_XCLUDE (Tty requires exclusivity)'],
874 ['', 'TS_BKSL (State for lowercase \\ work)'],
875 ['', 'TS_CNTTB (Counting tab width, ignore FLUSHO)'],
876 ['', 'TS_ERASE (Within a \\.../ for PRTRUB)'],
877 ['', 'TS_LNCH (Next character is literal)'],
878 ['', 'TS_TYPEN (Retyping suspended input (PENDIN))'],
879 ['', 'TS_CAN_BYPASS_L_RINT (Device in "raw" mode)'],
880 ['- (Connection NOT open)', 'TS_CONNECTED (Connection open)'],
881 ['', 'TS_SNOOP (Device is being snooped on)'],
882 ['', 'TS_SO_OCOMPLETE (Wake up when output completes)'],
883 ['', 'TS_ZOMBIE (Connection lost)'],
884 ['', 'TS_CAR_OFLOW (For MDMBUF - handle in driver)'],
885 ['', 'TS_CTS_OFLOW (For CCTS_OFLOW - handle in driver)'],
886 ['', 'TS_DSR_OFLOW (For CDSR_OFLOW - handle in driver)']
890 tty_state
= unsigned(tty
.t_state
)
893 if tty_state
& mask
!= 0:
894 if len(tty_state_info
[index
][1]) > 0:
895 print '\t' + tty_state_info
[index
][1]
897 if len(tty_state_info
[index
][0]) > 0:
898 print '\t' + tty_state_info
[index
][0]
901 print "Flags: 0x{0:0>8x}".format(unsigned(tty
.t_flags
))
902 print "Foreground Process Group: 0x{0:0>16x}".format(unsigned(tty
.t_pgrp
))
903 print "Enclosing session: 0x{0:0>16x}".format(unsigned(tty
.t_session
))
905 print "\tInput Flags: 0x{0:0>8x}".format(unsigned(tty
.t_termios
.c_iflag
))
906 print "\tOutput Flags: 0x{0:0>8x}".format(unsigned(tty
.t_termios
.c_oflag
))
907 print "\tControl Flags: 0x{0:0>8x}".format(unsigned(tty
.t_termios
.c_cflag
))
908 print "\tLocal Flags: 0x{0:0>8x}".format(unsigned(tty
.t_termios
.c_lflag
))
909 print "\tInput Speed: {0: <8d}".format(tty
.t_termios
.c_ispeed
)
910 print "\tOutput Speed: {0: <8d}".format(tty
.t_termios
.c_ospeed
)
911 print "High Watermark: {0: <d} bytes".format(tty
.t_hiwat
)
912 print "Low Watermark : {0: <d} bytes".format(tty
.t_lowat
)
916 #Macro showallttydevs
918 @lldb_command('showallttydevs')
919 def ShowAllTTYDevs(cmd_args
=[], cmd_options
={}):
920 """ Show a list of ttydevs registered in the system.
924 tty_dev_head
= kern
.globals.tty_dev_head
925 tty_dev
= tty_dev_head
926 print GetTTYDevSummary
.header
927 while unsigned(tty_dev
) != 0:
928 print GetTTYDevSummary(tty_dev
)
929 tty_dev
= tty_dev
.next
932 #EndMacro: showallttydevs
934 #Macro: dumpthread_terminate_queue
936 @lldb_command('dumpthread_terminate_queue')
937 def DumpThreadTerminateQueue(cmd_args
=None):
938 """ Displays the contents of the specified call_entry queue.
939 Usage: dumpthread_terminate_queue
943 print GetThreadSummary
.header
944 for th
in IterateMPSCQueue(addressof(kern
.globals.thread_terminate_queue
.mpd_queue
), 'struct thread', 'mpsc_links'):
945 print GetThreadSummary(th
)
947 print "{0: <d} entries!".format(count
)
949 #EndMacro: dumpthread_terminate_queue
951 #Macro: dumpcrashed_thread_queue
953 @lldb_command('dumpcrashed_thread_queue')
954 def DumpCrashedThreadsQueue(cmd_args
=None):
955 """ Displays the contents of the specified call_entry queue.
956 Usage: dumpcrashed_thread_queue
960 print GetThreadSummary
.header
961 for th
in IterateQueue(addressof(kern
.globals.crashed_threads_queue
), 'struct thread *', 'q_link'):
962 print GetThreadSummary(th
)
964 print "{0: <d} entries!".format(count
)
966 #EndMacro: dumpcrashed_thread_queue
968 #Macro: dumpcallqueue
970 @lldb_command('dumpcallqueue')
971 def DumpCallQueue(cmd_args
=None):
972 """ Displays the contents of the specified call_entry queue.
973 Usage: dumpcallqueue <queue_head_t *>
976 raise ArgumentError("Invalid arguments")
978 print "{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC')
979 callhead
= kern
.GetValueFromAddress(cmd_args
[0], 'queue_head_t *')
981 for callentry
in IterateQueue(callhead
, 'struct call_entry *', 'q_link'):
982 print "{0: <#18x} {1: <#18x} {2: <#18x} {3: <64d} {4: <#18x}".format(
983 unsigned(callentry
), unsigned(callentry
.param0
), unsigned(callentry
.param1
),
984 unsigned(callentry
.deadline
), unsigned(callentry
.func
))
986 print "{0: <d} entries!".format(count
)
988 #EndMacro: dumpcallqueue
990 @lldb_command('showalltasklogicalwrites')
991 def ShowAllTaskIOStats(cmd_args
=None):
992 """ Commad to print I/O stats for all tasks
994 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")
996 pval
= Cast(t
.bsd_info
, 'proc *')
997 print "{0: <#18x} {1: >20d} {2: >20d} {3: >20d} {4: >20d} {5: <20s} {6: <20s} {7: <20s} {8: <20s} {9: <20s}".format(t
,
998 t
.task_writes_counters_internal
.task_immediate_writes
,
999 t
.task_writes_counters_internal
.task_deferred_writes
,
1000 t
.task_writes_counters_internal
.task_invalidated_writes
,
1001 t
.task_writes_counters_internal
.task_metadata_writes
,
1002 t
.task_writes_counters_external
.task_immediate_writes
,
1003 t
.task_writes_counters_external
.task_deferred_writes
,
1004 t
.task_writes_counters_external
.task_invalidated_writes
,
1005 t
.task_writes_counters_external
.task_metadata_writes
,
1009 @lldb_command('showalltasks','C', fancy
=True)
1010 def ShowAllTasks(cmd_args
=None, cmd_options
={}, O
=None):
1011 """ Routine to print a summary listing of all the tasks
1012 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1013 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1014 io_policy -> RAGE - rapid aging of vnodes requested
1015 NORM - normal I/O explicitly requested (this is the default)
1016 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1017 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1018 Usage: (lldb) showalltasks -C : describe the corpse structure
1023 if '-C' in cmd_options
:
1025 extra_hdr
+= " " + GetKCDataSummary
.header
1027 with O
.table(GetTaskSummary
.header
+ extra_hdr
+ " " + GetProcSummary
.header
):
1028 for t
in kern
.tasks
:
1029 pval
= Cast(t
.bsd_info
, 'proc *')
1030 print GetTaskSummary(t
, showcorpse
) + " " + GetProcSummary(pval
)
1034 @lldb_command('taskforpmap')
1035 def TaskForPmap(cmd_args
=None):
1036 """ Find the task whose pmap corresponds to <pmap>.
1037 Syntax: (lldb) taskforpmap <pmap>
1038 Multiple -v's can be specified for increased verbosity
1040 if cmd_args
== None or len(cmd_args
) < 1:
1041 raise ArgumentError("Too few arguments to taskforpmap.")
1042 pmap
= kern
.GetValueFromAddress(cmd_args
[0], 'pmap_t')
1043 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1044 for tasklist
in [kern
.tasks
, kern
.terminated_tasks
]:
1046 if kern
.GetValueFromAddress(unsigned(t
.map.pmap
), 'pmap_t') == pmap
:
1047 pval
= Cast(t
.bsd_info
, 'proc *')
1048 out_str
= GetTaskSummary(t
) + " " + GetProcSummary(pval
)
1051 @lldb_command('showterminatedtasks')
1052 def ShowTerminatedTasks(cmd_args
=None):
1053 """ Routine to print a summary listing of all the terminated tasks
1054 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1055 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1056 io_policy -> RAGE - rapid aging of vnodes requested
1057 NORM - normal I/O explicitly requested (this is the default)
1058 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1059 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1060 syntax: (lldb)showallterminatedtasks
1063 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1064 for t
in kern
.terminated_tasks
:
1066 # If the task has been terminated it's likely that the process is
1067 # gone too. If there is no proc it may still be possible to find
1068 # the original proc name.
1069 pval
= Cast(t
.bsd_info
, 'proc *')
1071 psummary
= GetProcSummary(pval
)
1073 name
= GetProcNameForTask(t
);
1074 pslen
= GetProcSummary
.header
.find("command");
1075 psummary
= "{0: <{indent}} {1: <s}".format("", name
, indent
= pslen
- 1)
1077 print GetTaskSummary(t
) + " " + psummary
1081 # Macro: showtaskstacks
1083 def ShowTaskStacks(task
):
1084 """ Print a task with summary and stack information for each of its threads
1087 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1088 pval
= Cast(task
.bsd_info
, 'proc *')
1089 print GetTaskSummary(task
) + " " + GetProcSummary(pval
)
1090 for th
in IterateQueue(task
.threads
, 'thread *', 'task_threads'):
1091 print " " + GetThreadSummary
.header
1092 print " " + GetThreadSummary(th
)
1093 print GetThreadBackTrace(th
, prefix
=" ") + "\n"
1095 def FindTasksByName(searchstr
, ignore_case
=True):
1096 """ Search the list of tasks by name.
1098 searchstr: str - a regex like string to search for task
1099 ignore_case: bool - If False then exact matching will be enforced
1101 [] - array of task object. Empty if not found any
1105 re_options
= re
.IGNORECASE
1106 search_regex
= re
.compile(searchstr
, re_options
)
1108 for t
in kern
.tasks
:
1109 pval
= Cast(t
.bsd_info
, "proc *")
1110 process_name
= "{:s}".format(GetProcName(pval
))
1111 if search_regex
.search(process_name
):
1115 @lldb_command('showtaskstacks', 'F:')
1116 def ShowTaskStacksCmdHelper(cmd_args
=None, cmd_options
={}):
1117 """ Routine to print out the stack for each thread in a task
1118 Usage: showtaskstacks <0xaddress of task>
1119 or: showtaskstacks -F launchd
1122 if "-F" in cmd_options
:
1123 find_task_str
= cmd_options
["-F"]
1124 task_list
= FindTasksByName(find_task_str
)
1125 for tval
in task_list
:
1126 ShowTaskStacks(tval
)
1130 raise ArgumentError("No arguments passed")
1132 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
1134 raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args
)))
1136 ShowTaskStacks(tval
)
1139 # EndMacro: showtaskstacks
1141 def CheckTaskProcRefs(task
, proc
):
1142 for thread
in IterateQueue(task
.threads
, 'thread *', 'task_threads'):
1143 if int(thread
.uthread
) == 0:
1145 uthread
= Cast(thread
.uthread
, 'uthread *')
1146 refcount
= int(uthread
.uu_proc_refcount
)
1147 uu_ref_index
= int(uthread
.uu_pindex
)
1150 for ref
in range(0, uu_ref_index
):
1151 if unsigned(uthread
.uu_proc_ps
[ref
]) == unsigned(proc
):
1152 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1153 pval
= Cast(task
.bsd_info
, 'proc *')
1154 print GetTaskSummary(task
) + " " + GetProcSummary(pval
)
1155 print "\t" + GetThreadSummary
.header
1156 print "\t" + GetThreadSummary(thread
) + "\n"
1158 for frame
in range (0, 10):
1159 trace_addr
= unsigned(uthread
.uu_proc_pcs
[ref
][frame
])
1160 symbol_arr
= kern
.SymbolicateFromAddress(unsigned(trace_addr
))
1162 symbol_str
= str(symbol_arr
[0].addr
)
1165 print '{0: <#x} {1: <s}'.format(trace_addr
, symbol_str
)
1168 @lldb_command('showprocrefs')
1169 def ShowProcRefs(cmd_args
= None):
1170 """ Display information on threads/BTs that could be holding a reference on the specified proc
1171 NOTE: We can't say affirmatively if any of these references are still held since
1172 there's no way to pair references with drop-refs in the current infrastructure.
1173 Usage: showprocrefs <proc>
1175 if cmd_args
== None or len(cmd_args
) < 1:
1176 raise ArgumentError("No arguments passed")
1178 proc
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
1180 for t
in kern
.tasks
:
1181 CheckTaskProcRefs(t
, proc
)
1182 for t
in kern
.terminated_tasks
:
1183 CheckTaskProcRefs(t
, proc
)
1187 @lldb_command('showallthreads')
1188 def ShowAllThreads(cmd_args
= None):
1189 """ Display info about all threads in the system
1192 # Terminated threads get prefixed with a 'T'
1193 def ShowTaskTerminatedThreads(task
):
1194 tlist
= tmap
.get(unsigned(task
), [])
1196 print "T\t" + GetThreadSummary(thval
)
1198 # Task -> [thread, ..] map of terminated threads
1199 tmap
= defaultdict(list)
1200 for thr
in kern
.terminated_threads
:
1201 tmap
[unsigned(thr
.task
)].append(thr
)
1203 for t
in kern
.tasks
:
1204 ShowTaskThreads([str(int(t
))])
1205 ShowTaskTerminatedThreads(t
)
1208 for t
in kern
.terminated_tasks
:
1209 print "Terminated: \n"
1210 ShowTaskThreads([str(int(t
))])
1211 ShowTaskTerminatedThreads(t
)
1216 @lldb_command('showterminatedthreads')
1217 def ShowTerminatedThreads(cmd_args
=None):
1218 """ Display info about all terminated threads in the system
1222 print GetThreadSummary
.header
1223 for t
in kern
.terminated_threads
:
1224 print GetThreadSummary(t
)
1228 @lldb_command('showtaskthreads', "F:")
1229 def ShowTaskThreads(cmd_args
= None, cmd_options
={}):
1230 """ Display thread information for a given task
1231 Usage: showtaskthreads <0xaddress of task>
1232 or: showtaskthreads -F <name>
1235 if "-F" in cmd_options
:
1236 task_list
= FindTasksByName(cmd_options
["-F"])
1238 t
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
1241 raise ArgumentError("No arguments passed")
1243 for task
in task_list
:
1244 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1245 pval
= Cast(task
.bsd_info
, 'proc *')
1246 print GetTaskSummary(task
) + " " + GetProcSummary(pval
)
1247 print "\t" + GetThreadSummary
.header
1248 for thval
in IterateQueue(task
.threads
, 'thread *', 'task_threads'):
1249 print "\t" + GetThreadSummary(thval
)
1252 @lldb_command('showact')
1253 def ShowAct(cmd_args
=None):
1254 """ Routine to print out the state of a specific thread.
1255 usage: showact <activation>
1258 raise ArgumentError("No arguments passed")
1259 threadval
= kern
.GetValueFromAddress(cmd_args
[0], 'thread *')
1260 print GetThreadSummary
.header
1261 print GetThreadSummary(threadval
)
1263 @lldb_command('showactstack')
1264 def ShowActStack(cmd_args
=None):
1265 """ Routine to print out the stack of a specific thread.
1266 usage: showactstack <activation>
1269 raise ArgumentError("No arguments passed")
1270 threadval
= kern
.GetValueFromAddress(cmd_args
[0], 'thread *')
1271 print GetThreadSummary
.header
1272 print GetThreadSummary(threadval
)
1273 print GetThreadBackTrace(threadval
, prefix
="\t")
1276 @lldb_command('switchtoact')
1277 def SwitchToAct(cmd_args
=None):
1278 """ Switch to different context specified by activation
1279 This command allows gdb to examine the execution context and call
1280 stack for the specified activation. For example, to view the backtrace
1281 for an activation issue "switchtoact <address>", followed by "bt".
1282 Before resuming execution, issue a "resetctx" command, to
1283 return to the original execution context.
1285 if cmd_args
is None or len(cmd_args
) < 1:
1286 raise ArgumentError("No arguments passed")
1287 thval
= kern
.GetValueFromAddress(cmd_args
[0], 'thread *')
1288 lldbthread
= GetLLDBThreadForKernelThread(thval
)
1289 print GetThreadSummary
.header
1290 print GetThreadSummary(thval
)
1291 LazyTarget
.GetProcess().selected_thread
= lldbthread
1292 if not LazyTarget
.GetProcess().SetSelectedThread(lldbthread
):
1293 print "Failed to switch thread."
1296 @lldb_command('switchtoregs')
1297 def SwitchToRegs(cmd_args
=None):
1298 """ Routine to switch to a register state.
1299 Usage: (lldb) switchtoregs <struct arm_saved_state[64] *>
1300 This command creates a fake thread in lldb with the saved register state.
1301 Note: This command ONLY works for ARM based kernel setup.
1304 if cmd_args
== None or len(cmd_args
) < 1:
1305 raise ArgumentError("No arguments passed")
1307 lldb_process
= LazyTarget
.GetProcess()
1309 saved_state
= ArgumentStringToInt(cmd_args
[0])
1310 # any change to this logic requires change in operating_system.py as well
1311 fake_thread_id
= 0xdead0000 |
(saved_state
& ~
0xffff0000)
1312 fake_thread_id
= fake_thread_id
& 0xdeadffff
1313 lldb_process
.CreateOSPluginThread(0xdeadbeef, saved_state
)
1314 lldbthread
= lldb_process
.GetThreadByID(int(fake_thread_id
))
1316 if not lldbthread
.IsValid():
1317 print "Failed to create thread"
1320 lldb_process
.selected_thread
= lldbthread
1321 if not lldb_process
.SetSelectedThread(lldbthread
):
1322 print "Failed to switch thread"
1323 print "Switched to Fake thread created from register state at 0x%x" % saved_state
1327 # Macro: showallstacks
1328 @lldb_command('showallstacks')
1329 def ShowAllStacks(cmd_args
=None):
1330 """Routine to print out the stack for each thread in the system.
1332 for t
in kern
.tasks
:
1338 # EndMacro: showallstacks
1340 # Macro: showcurrentstacks
1341 @lldb_command('showcurrentstacks')
1342 def ShowCurrentStacks(cmd_args
=None):
1343 """ Routine to print out the thread running on each cpu (incl. its stack)
1345 processor_list
= kern
.GetGlobalVariable('processor_list')
1346 current_processor
= processor_list
1347 while unsigned(current_processor
) > 0:
1348 print "\n" + GetProcessorSummary(current_processor
)
1349 active_thread
= current_processor
.active_thread
1350 if unsigned(active_thread
) != 0 :
1351 task_val
= active_thread
.task
1352 proc_val
= Cast(task_val
.bsd_info
, 'proc *')
1353 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1354 print GetTaskSummary(task_val
) + " " + GetProcSummary(proc_val
)
1355 print "\t" + GetThreadSummary
.header
1356 print "\t" + GetThreadSummary(active_thread
)
1357 print "\tBacktrace:"
1358 print GetThreadBackTrace(active_thread
, prefix
="\t")
1359 current_processor
= current_processor
.processor_list
1361 # EndMacro: showcurrentstacks
1363 @lldb_command('showcurrentthreads')
1364 def ShowCurrentThreads(cmd_args
=None):
1365 """ Display info about threads running on each cpu """
1366 processor_list
= kern
.GetGlobalVariable('processor_list')
1367 current_processor
= processor_list
1368 while unsigned(current_processor
) > 0:
1369 print GetProcessorSummary(current_processor
)
1370 active_thread
= current_processor
.active_thread
1371 if unsigned(active_thread
) != 0 :
1372 task_val
= active_thread
.task
1373 proc_val
= Cast(task_val
.bsd_info
, 'proc *')
1374 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1375 print GetTaskSummary(task_val
) + " " + GetProcSummary(proc_val
)
1376 print "\t" + GetThreadSummary
.header
1377 print "\t" + GetThreadSummary(active_thread
)
1378 current_processor
= current_processor
.processor_list
1381 def GetFullBackTrace(frame_addr
, verbosity
= vHUMAN
, prefix
= ""):
1382 """ Get backtrace across interrupt context.
1383 params: frame_addr - int - address in memory which is a frame pointer (ie. rbp, r7)
1384 prefix - str - prefix for each line of output.
1389 frame_ptr
= frame_addr
1390 previous_frame_ptr
= 0
1391 # <rdar://problem/12677290> lldb unable to find symbol for _mh_execute_header
1392 mh_execute_addr
= int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16)
1393 while frame_ptr
and frame_ptr
!= previous_frame_ptr
and bt_count
< 128:
1394 if (not kern
.arch
.startswith('arm') and frame_ptr
< mh_execute_addr
) or (kern
.arch
.startswith('arm') and frame_ptr
> mh_execute_addr
):
1396 pc_val
= kern
.GetValueFromAddress(frame_ptr
+ kern
.ptrsize
,'uintptr_t *')
1397 pc_val
= kern
.StripKernelPAC(unsigned(dereference(pc_val
)))
1398 out_string
+= prefix
+ GetSourceInformationForAddress(pc_val
) + "\n"
1400 previous_frame_ptr
= frame_ptr
1401 frame_val
= kern
.GetValueFromAddress((frame_ptr
), 'uintptr_t *')
1402 if unsigned(frame_val
) == 0:
1404 frame_ptr
= unsigned(dereference(frame_val
))
1408 @lldb_command('fullbt')
1409 def FullBackTrace(cmd_args
=[]):
1410 """ Show full backtrace across the interrupt boundary.
1411 Syntax: fullbt <frame ptr>
1412 Example: fullbt `$rbp`
1414 if len(cmd_args
) < 1:
1415 print FullBackTrace
.__doc
__
1417 print GetFullBackTrace(ArgumentStringToInt(cmd_args
[0]), prefix
="\t")
1419 @lldb_command('fullbtall')
1420 def FullBackTraceAll(cmd_args
=[]):
1421 """ Show full backtrace across the interrupt boundary for threads running on all processors.
1425 for processor
in IterateLinkedList(kern
.globals.processor_list
, 'processor_list') :
1426 print "\n" + GetProcessorSummary(processor
)
1427 active_thread
= processor
.active_thread
1428 if unsigned(active_thread
) != 0 :
1429 task_val
= active_thread
.task
1430 proc_val
= Cast(task_val
.bsd_info
, 'proc *')
1431 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1432 print GetTaskSummary(task_val
) + " " + GetProcSummary(proc_val
)
1433 print "\t" + GetThreadSummary
.header
1434 print "\t" + GetThreadSummary(active_thread
)
1435 print "\tBacktrace:"
1437 ThreadVal
= GetLLDBThreadForKernelThread(active_thread
)
1439 FramePtr
= ThreadVal
.frames
[0].GetFP()
1441 print GetFullBackTrace(unsigned(FramePtr
), prefix
="\t")
1444 @lldb_command('symbolicate')
1445 def SymbolicateAddress(cmd_args
=[]):
1446 """ Symbolicate an address for symbol information from loaded symbols
1447 Example: "symbolicate 0xaddr" is equivalent to "output/a 0xaddr"
1449 if len(cmd_args
) < 1:
1450 print "Invalid address.\nSyntax: symbolicate <address>"
1452 print GetSourceInformationForAddress(ArgumentStringToInt(cmd_args
[0]))
1455 @lldb_command('showinitchild')
1456 def ShowInitChild(cmd_args
=None):
1457 """ Routine to print out all processes in the system
1458 which are children of init process
1460 headp
= kern
.globals.initproc
.p_children
1461 for pp
in IterateListEntry(headp
, 'struct proc *', 'p_sibling'):
1462 print GetProcInfo(pp
)
1465 @lldb_command('showproctree')
1466 def ShowProcTree(cmd_args
=None):
1467 """ Routine to print the processes in the system in a hierarchical tree form. This routine does not print zombie processes.
1468 If no argument is given, showproctree will print all the processes in the system.
1469 If pid is specified, showproctree prints all the descendants of the indicated process
1473 search_pid
= ArgumentStringToInt(cmd_args
[0])
1476 print "pid specified must be a positive number"
1477 print ShowProcTree
.__doc
__
1480 hdr_format
= "{0: <6s} {1: <14s} {2: <9s}\n"
1481 out_string
= hdr_format
.format("PID", "PROCESS", "POINTER")
1482 out_string
+= hdr_format
.format('='*3, '='*7, '='*7)
1483 proc
= GetProcForPid(search_pid
)
1484 out_string
+= "{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(proc
.p_ppid
, GetProcName(proc
.p_pptr
), unsigned(proc
.p_pptr
))
1485 out_string
+= "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(proc
.p_pid
, GetProcName(proc
), unsigned(proc
))
1487 ShowProcTreeRecurse(proc
, "| ")
1491 def ShowProcTreeRecurse(proc
, prefix
=""):
1492 """ Prints descendants of a given proc in hierarchial tree form
1494 proc : core.value representing a struct proc * in the kernel
1496 str : String containing info about a given proc and its descendants in tree form
1498 if proc
.p_childrencnt
> 0:
1499 head_ptr
= proc
.p_children
.lh_first
1501 for p
in IterateListEntry(proc
.p_children
, 'struct proc *', 'p_sibling'):
1502 print prefix
+ "|--{0: <6d} {1: <32s} [ {2: #019x} ]\n".format(p
.p_pid
, GetProcName(p
), unsigned(p
))
1503 ShowProcTreeRecurse(p
, prefix
+ "| ")
1505 @lldb_command('showthreadfortid')
1506 def ShowThreadForTid(cmd_args
=None):
1507 """ The thread structure contains a unique thread_id value for each thread.
1508 This command is used to retrieve the address of the thread structure(thread_t)
1509 corresponding to a given thread_id.
1512 print "Please provide thread_t whose tid you'd like to look up"
1513 print ShowThreadForTid
.__doc
__
1515 search_tid
= ArgumentStringToInt(cmd_args
[0])
1516 for taskp
in kern
.tasks
:
1517 for actp
in IterateQueue(taskp
.threads
, 'struct thread *', 'task_threads'):
1518 if search_tid
== int(actp
.thread_id
):
1519 print "Found {0: #019x}".format(actp
)
1520 print GetThreadSummary
.header
1521 print GetThreadSummary(actp
)
1523 print "Not a valid thread_id"
1525 def GetProcessorSummary(processor
):
1526 """ Internal function to print summary of processor
1527 params: processor - value representing struct processor *
1528 return: str - representing the details of given processor
1531 processor_state_str
= "INVALID"
1532 processor_state
= int(processor
.state
)
1534 processor_states
= {
1538 # 3 (formerly INACTIVE)
1544 if processor_state
in processor_states
:
1545 processor_state_str
= "{0: <11s} ".format(processor_states
[processor_state
])
1547 processor_recommended_str
= ""
1548 if int(processor
.is_recommended
) == 0:
1549 processor_recommended_str
= " (not recommended)"
1552 preemption_disable
= 0
1553 preemption_disable_str
= ""
1555 if kern
.arch
== 'x86_64':
1556 cpu_data
= kern
.globals.cpu_data_ptr
[processor
.cpu_id
]
1557 if (cpu_data
!= 0) :
1558 ast
= cpu_data
.cpu_pending_ast
1559 preemption_disable
= cpu_data
.cpu_preemption_level
1560 # On arm64, it's kern.globals.CpuDataEntries[processor.cpu_id].cpu_data_vaddr
1561 # but LLDB can't find CpuDataEntries...
1563 ast_str
= GetASTSummary(ast
)
1565 if (preemption_disable
!= 0) :
1566 preemption_disable_str
= "Preemption Disabled"
1568 out_str
= "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {:<s}{:<s} {:<s}\n".format(
1569 processor
, int(processor
.cpu_id
), ast_str
, processor_state_str
, processor_recommended_str
,
1570 preemption_disable_str
)
1573 def GetLedgerEntry(ledger_template
, ledger
, i
):
1574 """ Internal function to get internals of a ledger entry (*not* a ledger itself)
1575 params: ledger_template - value representing struct ledger_template_t for the task or thread
1576 ledger - value representing struct ledger_entry *
1577 return: entry - entry dictionary
1579 ledger_limit_infinity
= (uint64_t(0x1).value
<< 63) - 1
1580 lf_refill_scheduled
= 0x0400
1581 lf_tracking_max
= 0x4000
1583 now
= unsigned(kern
.globals.sched_tick
) / 20
1588 entry
["key"] = str(ledger_template
.lt_entries
[i
].et_key
)
1589 entry
["credit"] = unsigned(ledger
.le_credit
)
1590 entry
["debit"] = unsigned(ledger
.le_debit
)
1591 entry
["balance"] = entry
["credit"] - entry
["debit"]
1592 if (ledger
.le_flags
& lf_tracking_max
):
1593 entry
["interval_max"] = unsigned(ledger
._le
._le
_max
.le_interval_max
)
1594 entry
["lifetime_max"] = unsigned(ledger
._le
._le
_max
.le_lifetime_max
)
1596 if (unsigned(ledger
.le_limit
) != ledger_limit_infinity
):
1597 entry
["limit"] = unsigned(ledger
.le_limit
)
1599 if (ledger
.le_flags
& lf_refill_scheduled
):
1600 entry
["refill_period"] = unsigned (ledger
._le
.le_refill
.le_refill_period
)
1602 if (unsigned(ledger
.le_warn_percent
) < 65535):
1603 entry
["warn_percent"] = unsigned (ledger
.le_warn_percent
* 100 / 65536)
1604 entry
["flags"] = int(ledger
.le_flags
)
1608 def FormatLedgerEntrySummary(entry
, i
, show_footprint_interval_max
=False):
1609 """ internal function to format a ledger entry into a string
1610 params: entry - A python dictionary containing the ledger entry
1611 return: str - formatted output information of ledger entries
1614 out_str
+= "{: >32s} {:<2d}:".format(entry
["key"], i
)
1615 out_str
+= "{: >15d} ".format(entry
["balance"])
1617 if (show_footprint_interval_max
):
1618 if entry
.has_key("interval_max"):
1619 out_str
+= "{:12d} ".format(entry
["interval_max"])
1623 if entry
.has_key("lifetime_max"):
1624 out_str
+= "{:14d} ".format(entry
["lifetime_max"])
1628 out_str
+= "{:12d} {:12d} ".format(entry
["credit"], entry
["debit"])
1629 if entry
.has_key("limit"):
1630 out_str
+= "{:12d} ".format(unsigned(entry
["limit"]))
1634 if entry
.has_key("refill_period"):
1635 out_str
+= "{:15d} ".format(entry
["refill_period"])
1636 out_str
+= "{:9d} ".format((entry
["limit"] * 100) / entry
["refill_period"])
1641 if entry
.has_key("warn_percent"):
1642 out_str
+= "{:9d} ".format(entry
["warn_percent"])
1646 if entry
.has_key("limit"):
1647 if entry
["balance"] > entry
["limit"]:
1654 out_str
+= "{:#8x}\n".format(entry
["flags"])
1657 def GetLedgerEntrySummary(ledger_template
, ledger
, i
, show_footprint_interval_max
=False):
1658 """ internal function to get internals of a ledger entry (*not* a ledger itself)
1659 params: ledger_template - value representing struct ledger_template_t for the task or thread
1660 ledger - value representing struct ledger_entry *
1661 return: str - formatted output information of ledger entries
1663 entry
= GetLedgerEntry(ledger_template
, ledger
, i
)
1664 return FormatLedgerEntrySummary(entry
, i
)
1667 def GetThreadLedgers(thread_val
):
1668 """ Internal function to get a summary of ledger entries for the given thread
1669 params: thread_val - value representing struct thread *
1670 return: thread - python dictionary containing threads's ledger entries. This can
1671 be printed directly with FormatThreadLedgerSummmary or outputted as json.
1674 thread
["address"] = unsigned(thread_val
)
1675 ledgerp
= thread_val
.t_threadledger
1676 thread
["entries"] = []
1679 while i
!= ledgerp
.l_template
.lt_cnt
:
1680 thread
["entries"].append(GetLedgerEntry(kern
.globals.thread_ledger_template
,
1681 ledgerp
.l_entries
[i
], i
))
1685 def FormatThreadLedgerSummary(thread
):
1686 """ Internal function to print a thread's ledger entries
1687 params: thread - python dictionary containing thread's ledger entries
1688 return: str - formatted output information for ledger entries of the input thread
1690 out_str
= " [{:#08x}]\n".format(thread
["address"])
1691 entries
= thread
["entries"]
1692 for i
, entry
in enumerate(entries
):
1693 out_str
+= FormatLedgerEntrySummary(entry
, i
)
1696 def GetTaskLedgers(task_val
):
1697 """ Internal function to get summary of ledger entries from the task and its threads
1698 params: task_val - value representing struct task *
1699 return: task - python dictionary containing tasks's ledger entries. This can
1700 be printed directly with FormatTaskLedgerSummary or outputted as json.
1702 task_ledgerp
= task_val
.ledger
1706 task
["address"] = unsigned(task_val
)
1708 pval
= Cast(task_val
.bsd_info
, 'proc *')
1710 task
["name"] = GetProcName(pval
)
1711 task
["pid"] = int(pval
.p_pid
)
1713 task
["entries"] = []
1714 while i
!= task_ledgerp
.l_template
.lt_cnt
:
1715 task
["entries"].append(GetLedgerEntry(kern
.globals.task_ledger_template
, task_ledgerp
.l_entries
[i
], i
))
1719 task
["threads"] = []
1720 for thval
in IterateQueue(task_val
.threads
, 'thread *', 'task_threads'):
1721 task
["threads"].append(GetThreadLedgers(thval
))
1725 @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(
1726 "task [thread]", "entry", "#", "balance", "lifetime_max", "credit",
1727 "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags"))
1728 def FormatTaskLedgerSummary(task
, show_footprint_interval_max
=False):
1729 """ Internal function to get summary of ledger entries from the task and its threads
1730 params: task_val - value representing struct task *
1731 return: str - formatted output information for ledger entries of the input task
1734 out_str
+= "{: #08x} ".format(task
["address"])
1735 if task
.has_key("name"):
1736 out_str
+= "{: <5s}:\n".format(task
["name"])
1738 out_str
+= "Invalid process\n"
1740 for i
, entry
in enumerate(task
["entries"]):
1741 out_str
+= FormatLedgerEntrySummary(entry
, i
, show_footprint_interval_max
)
1743 for thread
in task
["threads"]:
1744 out_str
+= FormatThreadLedgerSummary(thread
)
1748 # Macro: showtaskledgers
1750 @lldb_command('showtaskledgers', 'JF:I')
1751 def ShowTaskLedgers(cmd_args
=None, cmd_options
={}):
1752 """ Routine to print a summary of ledger entries for the task and all of its threads
1753 or : showtaskledgers [ -I ] [-J] [ -F ] <task>
1755 -I: show footprint interval max (DEV/DEBUG only)
1756 -F: specify task via name instead of address
1761 if "-F" in cmd_options
:
1762 task_list
= FindTasksByName(cmd_options
["-F"])
1763 for tval
in task_list
:
1764 print FormatTaskLedgerSummary
.header
1765 ledgers
= GetTaskLedgers(tval
)
1766 print FormatTaskLedgerSummary(ledgers
)
1768 if "-J" in cmd_options
:
1772 raise ArgumentError("No arguments passed.")
1773 show_footprint_interval_max
= False
1774 if "-I" in cmd_options
:
1775 show_footprint_interval_max
= True
1776 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
1778 raise ArgumentError("unknown arguments: %r" %cmd
_args
)
1779 ledgers
= GetTaskLedgers(tval
)
1781 print json
.dumps(ledgers
)
1783 if (show_footprint_interval_max
):
1784 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(
1785 "task [thread]", "entry", "#", "balance", "intrvl_max", "lifetime_max", "credit",
1786 "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags")
1788 print FormatTaskLedgerSummary
.header
1789 print FormatTaskLedgerSummary(ledgers
, show_footprint_interval_max
)
1791 # EndMacro: showtaskledgers
1793 # Macro: showalltaskledgers
1795 @lldb_command('showalltaskledgers', "J")
1796 def ShowAllTaskLedgers(cmd_args
=None, cmd_options
={}):
1797 """ Routine to print a summary of ledger entries for all tasks and respective threads
1798 Usage: showalltaskledgers [-J]
1802 if "-J" in cmd_options
:
1805 for t
in kern
.tasks
:
1806 task_val
= unsigned(t
)
1808 ShowTaskLedgers([task_val
], cmd_options
=cmd_options
)
1810 tasks
.append(GetTaskLedgers(t
))
1812 print json
.dumps(tasks
)
1814 # EndMacro: showalltaskledgers
1816 # Macro: showprocuuidpolicytable
1818 @lldb_type_summary(['proc_uuid_policy_entry'])
1819 @header("{0: <36s} {1: <10s}".format("uuid", "flags"))
1820 def GetProcUUIDPolicyEntrySummary(entry
):
1821 """ Summarizes the important fields in proc_uuid_policy_entry structure.
1822 params: entry: value - value object representing an entry
1823 returns: str - summary of the entry
1827 data
.append(int(entry
.uuid
[i
]))
1828 flags
= unsigned(entry
.flags
)
1829 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
)
1832 @lldb_command('showprocuuidpolicytable')
1833 def ShowProcUUIDPolicyTable(cmd_args
=None):
1834 """ Routine to print the proc UUID policy table
1835 Usage: showprocuuidpolicytable
1837 hashslots
= unsigned(kern
.globals.proc_uuid_policy_hash_mask
)
1838 print "{0: <8s} ".format("slot") + GetProcUUIDPolicyEntrySummary
.header
1839 for i
in range(0, hashslots
+1):
1840 headp
= addressof(kern
.globals.proc_uuid_policy_hashtbl
[i
])
1842 for entry
in IterateListEntry(headp
, 'struct proc_uuid_policy_entry *', 'entries'):
1843 print "{0: >2d}.{1: <5d} ".format(i
, entrynum
) + GetProcUUIDPolicyEntrySummary(entry
)
1847 # EndMacro: showprocuuidpolicytable
1849 @lldb_command('showalltaskpolicy')
1850 def ShowAllTaskPolicy(cmd_args
=None):
1852 Routine to print a summary listing of all the tasks
1853 wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items"
1854 if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung
1855 io_policy -> RAGE - rapid aging of vnodes requested
1856 NORM - normal I/O explicitly requested (this is the default)
1857 PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions)
1858 THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes)
1861 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
1862 for t
in kern
.tasks
:
1863 pval
= Cast(t
.bsd_info
, 'proc *')
1864 print GetTaskSummary(t
) +" "+ GetProcSummary(pval
)
1865 requested_strings
= [
1866 ["int_darwinbg", "DBG-int"],
1867 ["ext_darwinbg", "DBG-ext"],
1868 ["int_iotier", "iotier-int"],
1869 ["ext_iotier", "iotier-ext"],
1870 ["int_iopassive", "passive-int"],
1871 ["ext_iopassive", "passive-ext"],
1872 ["bg_iotier", "bg-iotier"],
1873 ["terminated", "terminated"],
1874 ["th_pidbind_bg", "bg-pidbind"],
1875 ["t_apptype", "apptype"],
1876 ["t_boosted", "boosted"],
1878 ["t_tal_enabled", "tal-enabled"],
1879 ["t_base_latency_qos", "latency-base"],
1880 ["t_over_latency_qos", "latency-override"],
1881 ["t_base_through_qos", "throughput-base"],
1882 ["t_over_through_qos", "throughput-override"]
1886 for value
in requested_strings
:
1887 if t
.requested_policy
.__getattr
__(value
[0]) :
1888 requested
+=value
[1] + ": " + str(t
.requested_policy
.__getattr
__(value
[0])) + " "
1892 suppression_strings
= [
1893 ["t_sup_active", "active"],
1894 ["t_sup_lowpri_cpu", "lowpri-cpu"],
1895 ["t_sup_timer", "timer-throttling"],
1896 ["t_sup_disk", "disk-throttling"],
1897 ["t_sup_cpu_limit", "cpu-limits"],
1898 ["t_sup_suspend", "suspend"],
1899 ["t_sup_bg_sockets", "bg-sockets"]
1903 for value
in suppression_strings
:
1904 if t
.requested_policy
.__getattr
__(value
[0]) :
1905 suppression
+=value
[1] + ": " + str(t
.requested_policy
.__getattr
__(value
[0])) + " "
1909 effective_strings
= [
1910 ["darwinbg", "background"],
1911 ["lowpri_cpu", "lowpri-cpu"],
1912 ["io_tier", "iotier"],
1913 ["io_passive", "passive"],
1914 ["all_sockets_bg", "bg-allsockets"],
1915 ["new_sockets_bg", "bg-newsockets"],
1916 ["bg_iotier", "bg-iotier"],
1917 ["terminated", "terminated"],
1918 ["t_gpu_deny", "gpu-deny"],
1919 ["t_tal_engaged", "tal-engaged"],
1920 ["t_suspended", "suspended"],
1921 ["t_watchers_bg", "bg-watchers"],
1922 ["t_latency_qos", "latency-qos"],
1923 ["t_through_qos", "throughput-qos"],
1924 ["t_sup_active", "suppression-active"],
1929 for value
in effective_strings
:
1930 if t
.effective_policy
.__getattr
__(value
[0]) :
1931 effective
+=value
[1] + ": " + str(t
.effective_policy
.__getattr
__(value
[0])) + " "
1935 print "requested: " + requested
1936 print "suppression: " + suppression
1937 print "effective: " + effective
1940 @lldb_type_summary(['wait_queue', 'wait_queue_t'])
1941 @header("{: <20s} {: <20s} {: <15s} {:<5s} {:<5s} {: <20s}".format("waitq", "interlock", "policy", "members", "threads", "eventmask"))
1942 def GetWaitQSummary(waitq
):
1943 """ Summarizes the important fields in task structure.
1944 params: task: value - value object representing a task in kernel
1945 returns: str - summary of the task
1948 format_string
= '{: <#020x} {: <#020x} {: <15s} {: <5d} {: <5d} {: <#020x}'
1952 if (waitq
.wq_fifo
== 1) :
1957 if (waitq
.wq_prepost
== 1) :
1960 if (waitq
.wq_type
== 0x3) :
1962 elif (waitq
.wq_type
== 0x2) :
1967 out_string
+= format_string
.format(waitq
, unsigned(waitq
.wq_interlock
.lock_data
), policy
, 0, 0, unsigned(waitq
.wq_eventmask
))
1969 out_string
+= "\n" + GetThreadSummary
.header
1971 for thread
in IterateQueue(waitq
.wq_queue
, "thread_t", "links"):
1972 out_string
+= "\n" + GetThreadSummary(thread
)
1977 @lldb_command('showallsuspendedtasks', '')
1978 def ShowSuspendedTasks(cmd_args
=[], options
={}):
1979 """ Show a list of suspended tasks with their process name summary.
1981 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
1982 for t
in kern
.tasks
:
1983 if t
.suspend_count
> 0:
1984 print GetTaskSummary(t
) + ' ' + GetProcSummary(Cast(t
.bsd_info
, 'proc *'))
1988 @lldb_command('showallpte')
1989 def ShowAllPte(cmd_args
=None):
1990 """ Prints out the physical address of the pte for all tasks
1992 head_taskp
= addressof(kern
.globals.tasks
)
1993 taskp
= Cast(head_taskp
.next
, 'task *')
1994 while taskp
!= head_taskp
:
1995 procp
= Cast(taskp
.bsd_info
, 'proc *')
1996 out_str
= "task = {:#x} pte = {:#x}\t".format(taskp
, taskp
.map.pmap
.ttep
)
1998 out_str
+= "{:s}\n".format(GetProcName(procp
))
2002 taskp
= Cast(taskp
.tasks
.next
, 'struct task *')
2004 # EndMacro: showallpte
2006 # Macro: showallrefcounts
2007 @lldb_command('showallrefcounts')
2008 @header("{0: <20s} {1: ^10s}".format("task", "ref_count"))
2009 def ShowAllRefCounts(cmd_args
=None):
2010 """ Prints the ref_count of all tasks
2013 head_taskp
= addressof(kern
.globals.tasks
)
2014 taskp
= Cast(head_taskp
.next
, 'task *')
2015 print ShowAllRefCounts
.header
2016 while taskp
!= head_taskp
:
2017 out_str
+= "{: <#20x}".format(taskp
)
2018 out_str
+= "{: ^10d}\n".format(taskp
.ref_count
)
2019 taskp
= Cast(taskp
.tasks
.next
, 'task *')
2021 # EndMacro: showallrefcounts
2023 # Macro: showallrunnablethreads
2024 @lldb_command('showallrunnablethreads')
2025 def ShowAllRunnableThreads(cmd_args
=None):
2026 """ Prints the sched usage information for all threads of each task
2029 for taskp
in kern
.tasks
:
2030 for actp
in IterateQueue(taskp
.threads
, 'thread *', 'task_threads'):
2031 if int(actp
.state
& 0x4):
2032 ShowActStack([unsigned(actp
)])
2034 # EndMacro: showallrunnablethreads
2036 # Macro: showallschedusage
2037 @lldb_command('showallschedusage')
2038 @header("{0:<20s} {1:^10s} {2:^10s} {3:^15s}".format("Thread", "Priority", "State", "sched_usage"))
2039 def ShowAllSchedUsage(cmd_args
=None):
2040 """ Prints the sched usage information for all threads of each task
2043 for taskp
in kern
.tasks
:
2044 ShowTask([unsigned(taskp
)])
2045 print ShowAllSchedUsage
.header
2046 for actp
in IterateQueue(taskp
.threads
, 'thread *', 'task_threads'):
2047 out_str
= "{: <#20x}".format(actp
)
2048 out_str
+= "{: ^10s}".format(str(int(actp
.sched_pri
)))
2049 state
= int(actp
.state
)
2050 thread_state_chars
= {0:'', 1:'W', 2:'S', 4:'R', 8:'U', 16:'H', 32:'A', 64:'P', 128:'I'}
2052 state_str
+= thread_state_chars
[int(state
& 0x1)]
2053 state_str
+= thread_state_chars
[int(state
& 0x2)]
2054 state_str
+= thread_state_chars
[int(state
& 0x4)]
2055 state_str
+= thread_state_chars
[int(state
& 0x8)]
2056 state_str
+= thread_state_chars
[int(state
& 0x10)]
2057 state_str
+= thread_state_chars
[int(state
& 0x20)]
2058 state_str
+= thread_state_chars
[int(state
& 0x40)]
2059 state_str
+= thread_state_chars
[int(state
& 0x80)]
2060 out_str
+= "{: ^10s}".format(state_str
)
2061 out_str
+= "{: >15d}".format(actp
.sched_usage
)
2062 print out_str
+ "\n"
2065 # EndMacro: showallschedusage
2067 #Macro: showprocfilessummary
2068 @lldb_command('showprocfilessummary')
2069 @header("{0: <20s} {1: <20s} {2: >10s}".format("Process", "Name", "Number of Open Files"))
2070 def ShowProcFilesSummary(cmd_args
=None):
2071 """ Display the summary of open file descriptors for all processes in task list
2072 Usage: showprocfilessummary
2074 print ShowProcFilesSummary
.header
2075 for proc
in kern
.procs
:
2076 proc_filedesc
= proc
.p_fd
2077 proc_ofiles
= proc_filedesc
.fd_ofiles
2078 proc_lastfile
= unsigned(proc_filedesc
.fd_lastfile
)
2081 if proc_filedesc
.fd_nfiles
!= 0:
2082 while count
<= proc_lastfile
:
2083 if unsigned(proc_ofiles
[count
]) != 0:
2084 proc_file_count
+= 1
2086 print "{0: <#020x} {1: <32s} {2: >10d}".format(proc
, GetProcName(proc
), proc_file_count
)
2088 #EndMacro: showprocfilessummary
2090 @lldb_command('workinguserstacks')
2091 def WorkingUserStacks(cmd_args
=None):
2092 """ Print out the user stack for each thread in a task, followed by the user libraries.
2093 Syntax: (lldb) workinguserstacks <task_t>
2096 print "Insufficient arguments" + ShowTaskUserStacks
.__doc
__
2098 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
2099 print GetTaskSummary
.header
+ " " + GetProcSummary
.header
2100 pval
= Cast(task
.bsd_info
, 'proc *')
2101 print GetTaskSummary(task
) + " " + GetProcSummary(pval
) + "\n \n"
2102 for thval
in IterateQueue(task
.threads
, 'thread *', 'task_threads'):
2103 print "For thread 0x{0:x}".format(thval
)
2105 ShowThreadUserStack([hex(thval
)])
2106 except Exception as exc_err
:
2107 print "Failed to show user stack for thread 0x{0:x}".format(thval
)
2111 print "Enable debugging ('(lldb) xnudebug debug') to see detailed trace."
2112 WorkingUserLibraries([hex(task
)])
2115 @static_var("exec_load_path", 0)
2116 @lldb_command("workingkuserlibraries")
2117 def WorkingUserLibraries(cmd_args
=None):
2118 """ Show binary images known by dyld in target task
2119 For a given user task, inspect the dyld shared library state and print information about all Mach-O images.
2120 Syntax: (lldb)workinguserlibraries <task_t>
2123 print "Insufficient arguments"
2124 print ShowTaskUserLibraries
.__doc
__
2127 print "{0: <18s} {1: <12s} {2: <36s} {3: <50s}".format('address','type','uuid','path')
2128 out_format
= "0x{0:0>16x} {1: <12s} {2: <36s} {3: <50s}"
2129 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task_t')
2130 is_task_64
= int(task
.t_flags
) & 0x1
2131 dyld_all_image_infos_address
= unsigned(task
.all_image_info_addr
)
2133 if dyld_all_image_infos_address
== 0:
2134 print "No dyld shared library information available for task"
2136 vers_info_data
= GetUserDataAsString(task
, dyld_all_image_infos_address
, 112)
2137 version
= _ExtractDataFromString(vers_info_data
, cur_data_offset
, "uint32_t")
2138 cur_data_offset
+= 4
2140 print "Unknown dyld all_image_infos version number %d" % version
2141 image_info_count
= _ExtractDataFromString(vers_info_data
, cur_data_offset
, "uint32_t")
2142 WorkingUserLibraries
.exec_load_path
= 0
2144 image_info_size
= 24
2145 image_info_array_address
= _ExtractDataFromString(vers_info_data
, 8, "uint64_t")
2146 dyld_load_address
= _ExtractDataFromString(vers_info_data
, 8*4, "uint64_t")
2147 dyld_all_image_infos_address_from_struct
= _ExtractDataFromString(vers_info_data
, 8*13, "uint64_t")
2149 image_info_size
= 12
2150 image_info_array_address
= _ExtractDataFromString(vers_info_data
, 4*2, "uint32_t")
2151 dyld_load_address
= _ExtractDataFromString(vers_info_data
, 4*5, "uint32_t")
2152 dyld_all_image_infos_address_from_struct
= _ExtractDataFromString(vers_info_data
, 4*14, "uint32_t")
2153 # Account for ASLR slide before dyld can fix the structure
2154 dyld_load_address
= dyld_load_address
+ (dyld_all_image_infos_address
- dyld_all_image_infos_address_from_struct
)
2157 while i
< image_info_count
:
2158 image_info_address
= image_info_array_address
+ i
* image_info_size
2159 img_data
= GetUserDataAsString(task
, image_info_address
, image_info_size
)
2161 image_info_addr
= _ExtractDataFromString(img_data
, 0, "uint64_t")
2162 image_info_path
= _ExtractDataFromString(img_data
, 8, "uint64_t")
2164 image_info_addr
= _ExtractDataFromString(img_data
, 0, "uint32_t")
2165 image_info_path
= _ExtractDataFromString(img_data
, 4, "uint32_t")
2166 PrintImageInfo(task
, image_info_addr
, image_info_path
)
2169 # load_path might get set when the main executable is processed.
2170 if WorkingUserLibraries
.exec_load_path
!= 0:
2171 PrintImageInfo(task
, dyld_load_address
, WorkingUserLibraries
.exec_load_path
)
2174 # Macro: showstackaftertask
2175 @lldb_command('showstackaftertask','F:')
2176 def Showstackaftertask(cmd_args
=None,cmd_options
={}):
2177 """ Routine to print the thread stacks for all tasks succeeding a given task
2178 Usage: showstackaftertask <0xaddress of task>
2179 or: showstackaftertask -F <taskname>
2181 if "-F" in cmd_options
:
2182 # Find the task pointer corresponding to its task name
2183 find_task_str
= cmd_options
["-F"]
2184 task_list
= FindTasksByName(find_task_str
)
2186 # Iterate through the list of tasks and print all task stacks thereafter
2187 for tval
in task_list
:
2188 ListTaskStacks(tval
)
2192 raise ArgumentError("Insufficient arguments")
2193 tval
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
2195 raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args
)))
2197 ListTaskStacks(tval
)
2201 # EndMacro: showstackaftertask
2203 def ListTaskStacks(task
):
2204 """ Search for a given task and print the list of all task stacks thereafter.
2206 # Initialize local variable task_flag to mark when a given task is found.
2209 for t
in kern
.tasks
:
2210 if (task_flag
== 1):
2216 # Macro: showstackafterthread
2217 @lldb_command('showstackafterthread')
2218 def Showstackafterthread(cmd_args
= None):
2219 """ Routine to print the stacks of all threads succeeding a given thread.
2220 Usage: Showstackafterthread <0xaddress of thread>
2222 # local variable thread_flag is used to mark when a given thread is found.
2225 threadval
= kern
.GetValueFromAddress(cmd_args
[0], 'thread *')
2227 raise ArgumentError("No arguments passed")
2228 # Iterate through list of all tasks to look up a given thread
2229 for t
in kern
.tasks
:
2231 pval
= Cast(t
.bsd_info
, 'proc *')
2232 print GetTaskSummary
.header
+ " "+ GetProcSummary
.header
2233 print GetTaskSummary(t
) + " "+ GetProcSummary(pval
)
2235 # Look up for a given thread from the the list of threads of a given task
2236 for thval
in IterateQueue(t
.threads
, 'thread *', 'task_threads'):
2237 if (thread_flag
==1):
2239 print " " + GetThreadSummary
.header
2240 print " " + GetThreadSummary(thval
)
2241 print GetThreadBackTrace(thval
, prefix
="\t")+"\n"
2244 if(thval
==threadval
):
2245 pval
= Cast(t
.bsd_info
, 'proc *')
2246 process_name
= "{:s}".format(GetProcName(pval
))
2248 print " *** Continuing to dump the thread stacks from the process *** :" + " " + process_name