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