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