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