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