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