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