]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/xnu.py
xnu-6153.141.1.tar.gz
[apple/xnu.git] / tools / lldbmacros / xnu.py
CommitLineData
5ba3f43e 1import sys, subprocess, os, re, time, getopt, shlex, xnudefines
39236c6e
A
2import lldb
3from functools import wraps
4from ctypes import c_ulonglong as uint64_t
5from ctypes import c_void_p as voidptr_t
6import code
7import core
8from core import caching
9from core.standard import *
10from core.configuration import *
11from core.kernelcore import *
12from utils import *
13from core.lazytarget import *
14
5ba3f43e 15MODULE_NAME=__name__
39236c6e
A
16
17""" Kernel Debugging macros for lldb.
18 Please make sure you read the README COMPLETELY BEFORE reading anything below.
5ba3f43e 19 It is very critical that you read coding guidelines in Section E in README file.
39236c6e
A
20"""
21
5ba3f43e
A
22COMMON_HELP_STRING = """
23 -h Show the help string for the command.
cb323159
A
24 -c [always|auto|never|0|1]
25 Control the colorized output of certain commands
5ba3f43e
A
26 -o <path/to/filename> The output of this command execution will be saved to file. Parser information or errors will
27 not be sent to file though. eg /tmp/output.txt
28 -s <filter_string> The "filter_string" param is parsed to python regex expression and each line of output
29 will be printed/saved only if it matches the expression.
30 -v [-v...] Each additional -v will increase the verbosity of the command.
31 -p <plugin_name> Send the output of the command to plugin. Please see README for usage of plugins.
32"""
39236c6e 33# End Utility functions
5ba3f43e 34# Debugging specific utility functions
39236c6e
A
35
36#decorators. Not to be called directly.
37
38def static_var(var_name, initial_value):
39 def _set_var(obj):
40 setattr(obj, var_name, initial_value)
41 return obj
42 return _set_var
43
44def header(initial_value):
45 def _set_header(obj):
46 setattr(obj, 'header', initial_value)
47 return obj
48 return _set_header
49
cb323159 50# holds type declarations done by xnu.
39236c6e 51#DONOTTOUCHME: Exclusive use of lldb_type_summary only.
cb323159 52lldb_summary_definitions = {}
39236c6e 53def lldb_type_summary(types_list):
cb323159 54 """ A function decorator to register a summary for a type in lldb.
39236c6e
A
55 params: types_list - [] an array of types that you wish to register a summary callback function. (ex. ['task *', 'task_t'])
56 returns: Nothing. This is a decorator.
57 """
58 def _get_summary(obj):
59 def _internal_summary_function(lldbval, internal_dict):
60 out_string= ""
61 if internal_dict != None and len(obj.header) > 0 :
62 out_string += "\n" + obj.header +"\n"
63 out_string += obj( core.value(lldbval) )
64 return out_string
cb323159 65
39236c6e
A
66 myglobals = globals()
67 summary_function_name = "LLDBSummary" + obj.__name__
68 myglobals[summary_function_name] = _internal_summary_function
69 summary_function = myglobals[summary_function_name]
70 summary_function.__doc__ = obj.__doc__
cb323159 71
39236c6e
A
72 global lldb_summary_definitions
73 for single_type in types_list:
74 if config['showTypeSummary']:
75 if single_type in lldb_summary_definitions.keys():
76 lldb.debugger.HandleCommand("type summary delete --category kernel \""+ single_type + "\"")
77 lldb.debugger.HandleCommand("type summary add \""+ single_type +"\" --category kernel --python-function " + MODULE_NAME + "." + summary_function_name)
78 lldb_summary_definitions[single_type] = obj
cb323159 79
39236c6e
A
80 return obj
81 return _get_summary
82
cb323159 83#global cache of documentation for lldb commands exported by this module
39236c6e
A
84#DONOTTOUCHME: Exclusive use of lldb_command only.
85lldb_command_documentation = {}
86
cb323159 87def lldb_command(cmd_name, option_string = '', fancy=False):
39236c6e
A
88 """ A function decorator to define a command with namd 'cmd_name' in the lldb scope to call python function.
89 params: cmd_name - str : name of command to be set in lldb prompt.
cb323159 90 option_string - str: getopt like option string. Only CAPITAL LETTER options allowed.
39236c6e 91 see README on Customizing command options.
cb323159 92 fancy - bool : whether the command will receive an 'O' object to do fancy output (tables, indent, color)
39236c6e
A
93 """
94 if option_string != option_string.upper():
95 raise RuntimeError("Cannot setup command with lowercase option args. %s" % option_string)
96
97 def _cmd(obj):
98 def _internal_command_function(debugger, command, result, internal_dict):
99 global config, lldb_run_command_state
813fb2f6 100 stream = CommandOutput(cmd_name, result)
39236c6e
A
101 # need to avoid printing on stdout if called from lldb_run_command.
102 if 'active' in lldb_run_command_state and lldb_run_command_state['active']:
103 debuglog('Running %s from lldb_run_command' % command)
104 else:
105 result.SetImmediateOutputFile(sys.__stdout__)
106
107 command_args = shlex.split(command)
108 lldb.debugger.HandleCommand('type category disable kernel' )
109 def_verbose_level = config['verbosity']
cb323159 110
39236c6e
A
111 try:
112 stream.setOptions(command_args, option_string)
113 if stream.verbose_level != 0:
cb323159 114 config['verbosity'] += stream.verbose_level
39236c6e 115 with RedirectStdStreams(stdout=stream) :
cb323159 116 args = { 'cmd_args': stream.target_cmd_args }
39236c6e 117 if option_string:
cb323159
A
118 args['cmd_options'] = stream.target_cmd_options
119 if fancy:
120 args['O'] = stream
121 obj(**args)
39236c6e
A
122 except KeyboardInterrupt:
123 print "Execution interrupted by user"
124 except ArgumentError as arg_error:
125 if str(arg_error) != "HELP":
126 print "Argument Error: " + str(arg_error)
127 print "{0:s}:\n {1:s}".format(cmd_name, obj.__doc__.strip())
128 return False
129 except Exception as exc:
130 if not config['debug']:
131 print """
132************ LLDB found an exception ************
133There has been an uncaught exception. A possible cause could be that remote connection has been disconnected.
134However, it is recommended that you report the exception to lldb/kernel debugging team about it.
135************ Please run 'xnudebug debug enable' to start collecting logs. ************
136 """
137 raise
138
139 if config['showTypeSummary']:
140 lldb.debugger.HandleCommand('type category enable kernel' )
cb323159 141
39236c6e
A
142 if stream.pluginRequired :
143 plugin = LoadXNUPlugin(stream.pluginName)
144 if plugin == None :
145 print "Could not load plugins."+stream.pluginName
146 return
147 plugin.plugin_init(kern, config, lldb, kern.IsDebuggerConnected())
148 return_data = plugin.plugin_execute(cmd_name, result.GetOutput())
149 ProcessXNUPluginResult(return_data)
150 plugin.plugin_cleanup()
cb323159 151
39236c6e
A
152 #restore the verbose level after command is complete
153 config['verbosity'] = def_verbose_level
cb323159 154
39236c6e
A
155 return
156
157 myglobals = globals()
158 command_function_name = obj.__name__+"Command"
159 myglobals[command_function_name] = _internal_command_function
160 command_function = myglobals[command_function_name]
161 if not obj.__doc__ :
162 print "ERROR: Cannot register command({:s}) without documentation".format(cmd_name)
163 return obj
5ba3f43e 164 obj.__doc__ += "\n" + COMMON_HELP_STRING
39236c6e
A
165 command_function.__doc__ = obj.__doc__
166 global lldb_command_documentation
167 if cmd_name in lldb_command_documentation:
168 lldb.debugger.HandleCommand("command script delete "+cmd_name)
169 lldb_command_documentation[cmd_name] = (obj.__name__, obj.__doc__.lstrip(), option_string)
170 lldb.debugger.HandleCommand("command script add -f " + MODULE_NAME + "." + command_function_name + " " + cmd_name)
cb323159
A
171
172 if fancy:
173 def wrapped_fun(cmd_args=None, cmd_options={}, O=None):
174 if O is None:
175 stream = CommandOutput(cmd_name, fhandle=sys.stdout)
176 with RedirectStdStreams(stdout=stream):
177 return obj(cmd_args, cmd_options, stream)
178 else:
179 return obj(cmd_args, cmd_options, O)
180 return wrapped_fun
39236c6e
A
181 return obj
182 return _cmd
183
184def lldb_alias(alias_name, cmd_line):
cb323159 185 """ define an alias in the lldb command line.
39236c6e
A
186 A programatic way of registering an alias. This basically does
187 (lldb)command alias alias_name "cmd_line"
cb323159 188 ex.
39236c6e
A
189 lldb_alias('readphys16', 'readphys 16')
190 """
191 alias_name = alias_name.strip()
192 cmd_line = cmd_line.strip()
193 lldb.debugger.HandleCommand("command alias " + alias_name + " "+ cmd_line)
194
195def SetupLLDBTypeSummaries(reset=False):
196 global lldb_summary_definitions, MODULE_NAME
197 if reset == True:
198 lldb.debugger.HandleCommand("type category delete kernel ")
199 for single_type in lldb_summary_definitions.keys():
200 summary_function = lldb_summary_definitions[single_type]
201 lldb_cmd = "type summary add \""+ single_type +"\" --category kernel --python-function " + MODULE_NAME + ".LLDBSummary" + summary_function.__name__
202 debuglog(lldb_cmd)
203 lldb.debugger.HandleCommand(lldb_cmd)
204 if config['showTypeSummary']:
205 lldb.debugger.HandleCommand("type category enable kernel")
206 else:
207 lldb.debugger.HandleCommand("type category disable kernel")
208
209 return
210
211def LoadXNUPlugin(name):
cb323159 212 """ Try to load a plugin from the plugins directory.
39236c6e
A
213 """
214 retval = None
215 name=name.strip()
216 try:
217 module_obj = __import__('plugins.'+name, globals(), locals(), [], -1)
218 module_obj = module_obj.__dict__[name]
219 defs = dir(module_obj)
220 if 'plugin_init' in defs and 'plugin_execute' in defs and 'plugin_cleanup' in defs:
221 retval = module_obj
222 else:
223 print "Plugin is not correctly implemented. Please read documentation on implementing plugins"
224 except:
225 print "plugin not found :"+name
cb323159 226
39236c6e
A
227 return retval
228
229def ProcessXNUPluginResult(result_data):
230 """ Look at the returned data from plugin and see if anymore actions are required or not
231 params: result_data - list of format (status, out_string, more_commands)
232 """
233 ret_status = result_data[0]
234 ret_string = result_data[1]
235 ret_commands = result_data[2]
cb323159 236
39236c6e
A
237 if ret_status == False:
238 print "Plugin failed: " + ret_string
239 return
240 print ret_string
241 if len(ret_commands) >= 0:
242 for cmd in ret_commands:
243 print "Running command on behalf of plugin:" + cmd
244 lldb.debugger.HandleCommand(cmd)
245 return
246
247# holds tests registered with xnu.
248#DONOTTOUCHME: Exclusive use of xnudebug_test only
249lldb_command_tests = {}
250def xnudebug_test(test_name):
cb323159 251 """ A function decoratore to register a test with the framework. Each test is supposed to be of format
39236c6e 252 def Test<name>(kernel_target, config, lldb_obj, isConnected )
cb323159 253
39236c6e
A
254 NOTE: The testname should start with "Test" else exception will be raised.
255 """
256 def _test(obj):
257 global lldb_command_tests
258 if obj.__name__.find("Test") != 0 :
cb323159 259 print "Test name ", obj.__name__ , " should start with Test"
39236c6e
A
260 raise ValueError
261 lldb_command_tests[test_name] = (test_name, obj.__name__, obj, obj.__doc__)
262 return obj
263 return _test
264
265
266# End Debugging specific utility functions
cb323159 267# Kernel Debugging specific classes and accessor methods
39236c6e
A
268
269# global access object for target kernel
270
271def GetObjectAtIndexFromArray(array_base, index):
272 """ Subscript indexing for arrays that are represented in C as pointers.
273 for ex. int *arr = malloc(20*sizeof(int));
cb323159 274 now to get 3rd int from 'arr' you'd do
39236c6e
A
275 arr[2] in C
276 GetObjectAtIndexFromArray(arr_val,2)
277 params:
278 array_base : core.value - representing a pointer type (ex. base of type 'ipc_entry *')
279 index : int - 0 based index into the array
280 returns:
281 core.value : core.value of the same type as array_base_val but pointing to index'th element
282 """
283 array_base_val = array_base.GetSBValue()
284 base_address = array_base_val.GetValueAsUnsigned()
285 size = array_base_val.GetType().GetPointeeType().GetByteSize()
286 obj_address = base_address + (index * size)
287 obj = kern.GetValueFromAddress(obj_address, array_base_val.GetType().GetName())
288 return Cast(obj, array_base_val.GetType())
289
290
291kern = None
292
293def GetLLDBThreadForKernelThread(thread_obj):
294 """ Get a reference to lldb.SBThread representation for kernel thread.
295 params:
cb323159
A
296 thread_obj : core.cvalue - thread object of type thread_t
297 returns
39236c6e
A
298 lldb.SBThread - lldb thread object for getting backtrace/registers etc.
299 """
300 tid = unsigned(thread_obj.thread_id)
301 lldb_process = LazyTarget.GetProcess()
302 sbthread = lldb_process.GetThreadByID(tid)
303 if not sbthread.IsValid():
304 # in case lldb doesnt know about this thread, create one
305 if hasattr(lldb_process, "CreateOSPluginThread"):
306 debuglog("creating os plugin thread on the fly for {0:d} 0x{1:x}".format(tid, thread_obj))
307 lldb_process.CreateOSPluginThread(tid, unsigned(thread_obj))
308 else:
309 raise RuntimeError("LLDB process does not support CreateOSPluginThread.")
310 sbthread = lldb_process.GetThreadByID(tid)
311
312 if not sbthread.IsValid():
fe8ab488
A
313 raise RuntimeError("Unable to find lldb thread for tid={0:d} thread = {1:#018x} (#16049947: have you put 'settings set target.load-script-from-symbol-file true' in your .lldbinit?)".format(tid, thread_obj))
314
39236c6e
A
315 return sbthread
316
39037602
A
317def GetKextSymbolInfo(load_addr):
318 """ Get a string descriptiong load_addr <kextname> + offset
319 params:
320 load_addr - int address value of pc in backtrace.
321 returns: str - kext name + offset string. If no cached data available, warning message is returned.
322 """
323 symbol_name = "None"
324 symbol_offset = load_addr
325 kmod_val = kern.globals.kmod
5ba3f43e 326 if not kern.arch.startswith('arm64'):
39037602
A
327 for kval in IterateLinkedList(kmod_val, 'next'):
328 if load_addr >= unsigned(kval.address) and \
329 load_addr <= (unsigned(kval.address) + unsigned(kval.size)):
330 symbol_name = kval.name
331 symbol_offset = load_addr - unsigned(kval.address)
332 break
333 return "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset)
334
335 # only for arm64 we do lookup for split kexts.
336 cached_kext_info = caching.GetDynamicCacheData("kern.kexts.loadinformation", [])
337 if not cached_kext_info and str(GetConnectionProtocol()) == "core":
338 cached_kext_info = GetKextLoadInformation()
339
340 if not cached_kext_info:
341 return "{:#018x} ~ kext info not available. please run 'showallkexts' once ~ \n".format(load_addr)
342
343 for kval in cached_kext_info:
344 text_seg = kval[5]
345 if load_addr >= text_seg.vmaddr and \
346 load_addr <= (text_seg.vmaddr + text_seg.vmsize):
347 symbol_name = kval[2]
348 symbol_offset = load_addr - text_seg.vmaddr
349 break
350 return "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset)
351
39236c6e
A
352def GetThreadBackTrace(thread_obj, verbosity = vHUMAN, prefix = ""):
353 """ Get a string to display back trace for a thread.
354 params:
355 thread_obj - core.cvalue : a thread object of type thread_t.
356 verbosity - int : either of vHUMAN, vSCRIPT or vDETAIL to describe the verbosity of output
357 prefix - str : a string prefix added before the line for each frame.
358 isContinuation - bool : is thread a continuation?
359 returns:
360 str - a multi line string showing each frame in backtrace.
361 """
362 is_continuation = not bool(unsigned(thread_obj.kernel_stack))
363 thread_val = GetLLDBThreadForKernelThread(thread_obj)
364 out_string = ""
365 kernel_stack = unsigned(thread_obj.kernel_stack)
366 reserved_stack = unsigned(thread_obj.reserved_stack)
367 if not is_continuation:
368 if kernel_stack and reserved_stack:
369 out_string += prefix + "reserved_stack = {:#018x}\n".format(reserved_stack)
370 out_string += prefix + "kernel_stack = {:#018x}\n".format(kernel_stack)
371 else:
372 out_string += prefix + "continuation ="
373 iteration = 0
374 last_frame_p = 0
375 for frame in thread_val.frames:
376 addr = frame.GetPCAddress()
377 load_addr = addr.GetLoadAddress(LazyTarget.GetTarget())
378 function = frame.GetFunction()
379 frame_p = frame.GetFP()
380 mod_name = frame.GetModule().GetFileSpec().GetFilename()
381
382 if iteration == 0 and not is_continuation:
383 out_string += prefix +"stacktop = {:#018x}\n".format(frame_p)
fe8ab488 384
39236c6e
A
385 if not function:
386 # No debug info for 'function'.
cb323159 387 out_string += prefix
39236c6e 388 if not is_continuation:
cb323159
A
389 out_string += "{fp:#018x} ".format(fp = frame_p)
390
fe8ab488
A
391 symbol = frame.GetSymbol()
392 if not symbol:
39037602 393 out_string += GetKextSymbolInfo(load_addr)
fe8ab488
A
394 else:
395 file_addr = addr.GetFileAddress()
396 start_addr = symbol.GetStartAddress().GetFileAddress()
397 symbol_name = symbol.GetName()
398 symbol_offset = file_addr - start_addr
cb323159 399 out_string += "{addr:#018x} {mod}`{symbol} + {offset:#x} \n".format(addr=load_addr,
fe8ab488 400 mod=mod_name, symbol=symbol_name, offset=symbol_offset)
39236c6e
A
401 else:
402 # Debug info is available for 'function'.
403 func_name = frame.GetFunctionName()
404 file_name = frame.GetLineEntry().GetFileSpec().GetFilename()
405 line_num = frame.GetLineEntry().GetLine()
406 func_name = '%s [inlined]' % func_name if frame.IsInlined() else func_name
407 if is_continuation and frame.IsInlined():
408 debuglog("Skipping frame for thread {:#018x} since its inlined".format(thread_obj))
cb323159
A
409 continue
410 out_string += prefix
39236c6e
A
411 if not is_continuation:
412 out_string += "{fp:#018x} ".format(fp=frame_p)
413 out_string += "{addr:#018x} {func}{args} \n".format(addr=load_addr,
414 func=func_name,
415 file=file_name, line=line_num,
416 args="(" + (str(frame.arguments).replace("\n", ", ") if len(frame.arguments) > 0 else "void") + ")")
cb323159 417 iteration += 1
39236c6e
A
418 if frame_p:
419 last_frame_p = frame_p
420
421 if not is_continuation and last_frame_p:
422 out_string += prefix + "stackbottom = {:#018x}".format(last_frame_p)
423 out_string = out_string.replace("variable not available","")
424 return out_string
425
426def GetSourceInformationForAddress(addr):
cb323159 427 """ convert and address to function +offset information.
39236c6e 428 params: addr - int address in the binary to be symbolicated
cb323159 429 returns: string of format "0xaddress: function + offset"
39236c6e
A
430 """
431 symbols = kern.SymbolicateFromAddress(addr)
432 format_string = "{0:#018x} <{1:s} + {2:#0x}>"
433 offset = 0
434 function_name = ""
435 if len(symbols) > 0:
436 s = symbols[0]
437 function_name = str(s.name)
438 offset = addr - s.GetStartAddress().GetLoadAddress(LazyTarget.GetTarget())
439 if function_name == "":
440 function_name = "???"
441 return format_string.format(addr, function_name, offset)
442
443def GetFrameLocalVariable(variable_name, frame_no=0):
444 """ Find a local variable by name
445 params:
446 variable_name: str - name of variable to search for
cb323159 447 returns:
39236c6e
A
448 core.value - if the variable is found.
449 None - if not found or not Valid
450 """
451 retval = None
452 sbval = None
453 lldb_SBThread = LazyTarget.GetProcess().GetSelectedThread()
454 frame = lldb_SBThread.GetSelectedFrame()
455 if frame_no :
456 frame = lldb_SBThread.GetFrameAtIndex(frame_no)
457 if frame :
458 sbval = frame.FindVariable(variable_name)
459 if sbval and sbval.IsValid():
460 retval = core.cvalue.value(sbval)
461 return retval
462
463# Begin Macros for kernel debugging
464
465@lldb_command('kgmhelp')
466def KernelDebugCommandsHelp(cmd_args=None):
467 """ Show a list of registered commands for kenel debugging.
468 """
469 global lldb_command_documentation
470 print "List of commands provided by " + MODULE_NAME + " for kernel debugging."
471 cmds = lldb_command_documentation.keys()
472 cmds.sort()
473 for cmd in cmds:
474 if type(lldb_command_documentation[cmd][-1]) == type(""):
475 print " {0: <20s} - {1}".format(cmd , lldb_command_documentation[cmd][1].split("\n")[0].strip())
476 else:
477 print " {0: <20s} - {1}".format(cmd , "No help string found.")
5ba3f43e
A
478 print 'Each of the functions listed here accept the following common options. '
479 print COMMON_HELP_STRING
480 print 'Additionally, each command implementation may have more options. "(lldb) help <command> " will show these options.'
39236c6e
A
481 return None
482
483
cb323159 484@lldb_command('showraw')
39236c6e 485def ShowRawCommand(cmd_args=None):
cb323159 486 """ A command to disable the kernel summaries and show data as seen by the system.
39236c6e
A
487 This is useful when trying to read every field of a struct as compared to brief summary
488 """
489 command = " ".join(cmd_args)
490 lldb.debugger.HandleCommand('type category disable kernel' )
491 lldb.debugger.HandleCommand( command )
492 lldb.debugger.HandleCommand('type category enable kernel' )
cb323159 493
39236c6e
A
494
495@lldb_command('xnudebug')
496def XnuDebugCommand(cmd_args=None):
497 """ command interface for operating on the xnu macros. Allowed commands are as follows
498 reload:
499 Reload a submodule from the xnu/tools/lldb directory. Do not include the ".py" suffix in modulename.
500 usage: xnudebug reload <modulename> (eg. memory, process, stats etc)
39037602
A
501 flushcache:
502 remove any cached data held in static or dynamic data cache.
503 usage: xnudebug flushcache
39236c6e
A
504 test:
505 Start running registered test with <name> from various modules.
506 usage: xnudebug test <name> (eg. test_memstats)
507 testall:
508 Go through all registered tests and run them
509 debug:
510 Toggle state of debug configuration flag.
511 """
512 global config
513 command_args = cmd_args
514 if len(command_args) == 0:
515 raise ArgumentError("No command specified.")
39037602 516 supported_subcommands = ['debug', 'reload', 'test', 'testall', 'flushcache']
39236c6e
A
517 subcommand = GetLongestMatchOption(command_args[0], supported_subcommands, True)
518
519 if len(subcommand) == 0:
520 raise ArgumentError("Subcommand (%s) is not a valid command. " % str(command_args[0]))
39037602 521
39236c6e
A
522 subcommand = subcommand[0].lower()
523 if subcommand == 'debug':
524 if command_args[-1].lower().find('dis') >=0 and config['debug']:
525 config['debug'] = False
526 print "Disabled debug logging."
527 elif command_args[-1].lower().find('dis') < 0 and not config['debug']:
528 config['debug'] = True
529 EnableLLDBAPILogging() # provided by utils.py
530 print "Enabled debug logging. \nPlease run 'xnudebug debug disable' to disable it again. "
39037602
A
531 if subcommand == 'flushcache':
532 print "Current size of cache: {}".format(caching.GetSizeOfCache())
533 caching.ClearAllCache()
534
39236c6e
A
535 if subcommand == 'reload':
536 module_name = command_args[-1]
537 if module_name in sys.modules:
538 reload(sys.modules[module_name])
539 print module_name + " is reloaded from " + sys.modules[module_name].__file__
540 else:
541 print "Unable to locate module named ", module_name
542 if subcommand == 'testall':
543 for test_name in lldb_command_tests.keys():
544 print "[BEGIN]", test_name
545 res = lldb_command_tests[test_name][2](kern, config, lldb, True)
546 if res:
547 print "[PASSED] {:s}".format(test_name)
548 else:
549 print "[FAILED] {:s}".format(test_name)
550 if subcommand == 'test':
551 test_name = command_args[-1]
552 if test_name in lldb_command_tests:
553 test = lldb_command_tests[test_name]
554 print "Running test {:s}".format(test[0])
cb323159 555 if test[2](kern, config, lldb, True) :
39236c6e
A
556 print "[PASSED] {:s}".format(test[0])
557 else:
558 print "[FAILED] {:s}".format(test[0])
cb323159 559 return ""
39236c6e
A
560 else:
561 print "No such test registered with name: {:s}".format(test_name)
562 print "XNUDEBUG Available tests are:"
563 for i in lldb_command_tests.keys():
564 print i
565 return None
cb323159 566
39236c6e
A
567 return False
568
569@lldb_command('showversion')
570def ShowVersion(cmd_args=None):
571 """ Read the kernel version string from a fixed address in low
572 memory. Useful if you don't know which kernel is on the other end,
573 and need to find the appropriate symbols. Beware that if you've
574 loaded a symbol file, but aren't connected to a remote target,
575 the version string from the symbol file will be displayed instead.
576 This macro expects to be connected to the remote kernel to function
577 correctly.
578
579 """
580 print kern.version
581
cb323159
A
582def ProcessPanicStackshot(panic_stackshot_addr, panic_stackshot_len):
583 """ Process the panic stackshot from the panic header, saving it to a file if it is valid
584 params: panic_stackshot_addr : start address of the panic stackshot binary data
585 panic_stackshot_len : length of the stackshot binary data
586 returns: nothing
39236c6e 587 """
cb323159
A
588 if not panic_stackshot_addr:
589 print "No panic stackshot available (invalid addr)"
590 return
3e170ce0 591
cb323159
A
592 if not panic_stackshot_len:
593 print "No panic stackshot available (zero length)"
594 return;
3e170ce0 595
cb323159
A
596 ts = int(time.time())
597 ss_binfile = "/tmp/panic_%d.bin" % ts
598 ss_ipsfile = "/tmp/stacks_%d.ips" % ts
5ba3f43e 599
cb323159
A
600 if not SaveDataToFile(panic_stackshot_addr, panic_stackshot_len, ss_binfile, None):
601 print "Failed to save stackshot binary data to file"
602 return
603
604 self_path = str(__file__)
605 base_dir_name = self_path[:self_path.rfind("/")]
606 print "python %s/kcdata.py %s -s %s" % (base_dir_name, ss_binfile, ss_ipsfile)
607 (c,so,se) = RunShellCommand("python %s/kcdata.py %s -s %s" % (base_dir_name, ss_binfile, ss_ipsfile))
608 if c == 0:
609 print "Saved ips stackshot file as %s" % ss_ipsfile
610 return
5ba3f43e 611 else:
cb323159 612 print "Failed to run command: exit code: %d, SO: %s SE: %s" % (c, so, se)
cc8bc92a 613 return
5ba3f43e 614
cb323159
A
615def ParseEmbeddedPanicLog(panic_header, cmd_options={}):
616 panic_buf = Cast(panic_header, 'char *')
617 panic_log_magic = unsigned(panic_header.eph_magic)
618 panic_log_begin_offset = unsigned(panic_header.eph_panic_log_offset)
619 panic_log_len = unsigned(panic_header.eph_panic_log_len)
620 other_log_begin_offset = unsigned(panic_header.eph_other_log_offset)
621 other_log_len = unsigned(panic_header.eph_other_log_len)
622 expected_panic_magic = xnudefines.EMBEDDED_PANIC_MAGIC
623 panic_stackshot_addr = unsigned(panic_header) + unsigned(panic_header.eph_stackshot_offset)
624 panic_stackshot_len = unsigned(panic_header.eph_stackshot_len)
625 panic_header_flags = unsigned(panic_header.eph_panic_flags)
626
627 warn_str = ""
628 out_str = ""
629
cc8bc92a 630 if panic_log_magic != 0 and panic_log_magic != expected_panic_magic:
cb323159 631 warn_str += "BAD MAGIC! Found 0x%x expected 0x%x" % (panic_log_magic,
cc8bc92a 632 expected_panic_magic)
5ba3f43e 633
cb323159
A
634 if warn_str:
635 print "\n %s" % warn_str
636 if panic_log_begin_offset == 0:
637 return
638
639 if "-S" in cmd_options:
640 if panic_header_flags & xnudefines.EMBEDDED_PANIC_STACKSHOT_SUCCEEDED_FLAG:
641 ProcessPanicStackshot(panic_stackshot_addr, panic_stackshot_len)
642 else:
643 print "No panic stackshot available"
cc8bc92a
A
644
645 panic_log_curindex = 0
646 while panic_log_curindex < panic_log_len:
647 p_char = str(panic_buf[(panic_log_begin_offset + panic_log_curindex)])
648 out_str += p_char
649 panic_log_curindex += 1
5ba3f43e 650
cc8bc92a
A
651 if other_log_begin_offset != 0:
652 other_log_curindex = 0
653 while other_log_curindex < other_log_len:
654 p_char = str(panic_buf[(other_log_begin_offset + other_log_curindex)])
5ba3f43e 655 out_str += p_char
cc8bc92a 656 other_log_curindex += 1
5ba3f43e
A
657
658 print out_str
cb323159
A
659 return
660
661def ParseMacOSPanicLog(panic_header, cmd_options={}):
662 panic_buf = Cast(panic_header, 'char *')
663 panic_log_magic = unsigned(panic_header.mph_magic)
664 panic_log_begin_offset = unsigned(panic_header.mph_panic_log_offset)
665 panic_log_len = unsigned(panic_header.mph_panic_log_len)
666 other_log_begin_offset = unsigned(panic_header.mph_other_log_offset)
667 other_log_len = unsigned(panic_header.mph_other_log_len)
668 cur_debug_buf_ptr_offset = (unsigned(kern.globals.debug_buf_ptr) - unsigned(panic_header))
669 if other_log_begin_offset != 0 and (other_log_len == 0 or other_log_len < (cur_debug_buf_ptr_offset - other_log_begin_offset)):
670 other_log_len = cur_debug_buf_ptr_offset - other_log_begin_offset
671 expected_panic_magic = xnudefines.MACOS_PANIC_MAGIC
672 panic_stackshot_addr = unsigned(panic_header) + unsigned(panic_header.mph_stackshot_offset)
673 panic_stackshot_len = unsigned(panic_header.mph_stackshot_len)
674 panic_header_flags = unsigned(panic_header.mph_panic_flags)
675
676 warn_str = ""
677 out_str = ""
678
679 if panic_log_magic != 0 and panic_log_magic != expected_panic_magic:
680 warn_str += "BAD MAGIC! Found 0x%x expected 0x%x" % (panic_log_magic,
681 expected_panic_magic)
3e170ce0 682
fe8ab488 683 if warn_str:
5ba3f43e 684 print "\n %s" % warn_str
cb323159
A
685 if panic_log_begin_offset == 0:
686 return
687
688 if "-S" in cmd_options:
689 if panic_header_flags & xnudefines.MACOS_PANIC_STACKSHOT_SUCCEEDED_FLAG:
690 ProcessPanicStackshot(panic_stackshot_addr, panic_stackshot_len)
691 else:
692 print "No panic stackshot available"
693
694 panic_log_curindex = 0
695 while panic_log_curindex < panic_log_len:
696 p_char = str(panic_buf[(panic_log_begin_offset + panic_log_curindex)])
697 out_str += p_char
698 panic_log_curindex += 1
699
700 if other_log_begin_offset != 0:
701 other_log_curindex = 0
702 while other_log_curindex < other_log_len:
703 p_char = str(panic_buf[(other_log_begin_offset + other_log_curindex)])
704 out_str += p_char
705 other_log_curindex += 1
706
707 print out_str
708 return
709
710def ParseAURRPanicLog(panic_header, cmd_options={}):
711 reset_cause = {
712 0x0: "OTHER",
713 0x1: "CATERR",
714 0x2: "SWD_TIMEOUT",
715 0x3: "GLOBAL RESET",
716 0x4: "STRAIGHT TO S5",
717 }
718
719 expected_panic_magic = xnudefines.AURR_PANIC_MAGIC
720
721 panic_buf = Cast(panic_header, 'char *')
722
723 try:
724 # This line will blow up if there's not type info for this struct (older kernel)
725 # We fall back to manual parsing below
726 aurr_panic_header = Cast(panic_header, 'struct efi_aurr_panic_header *')
727 panic_log_magic = unsigned(aurr_panic_header.efi_aurr_magic)
728 panic_log_version = unsigned(aurr_panic_header.efi_aurr_version)
729 panic_log_reset_cause = unsigned(aurr_panic_header.efi_aurr_reset_cause)
730 panic_log_reset_log_offset = unsigned(aurr_panic_header.efi_aurr_reset_log_offset)
731 panic_log_reset_log_len = unsigned(aurr_panic_header.efi_aurr_reset_log_len)
732 except Exception as e:
733 print "*** Warning: kernel symbol file has no type information for 'struct efi_aurr_panic_header'..."
734 print "*** Warning: trying to manually parse..."
735 aurr_panic_header = Cast(panic_header, "uint32_t *")
736 panic_log_magic = unsigned(aurr_panic_header[0])
737 # panic_log_crc = unsigned(aurr_panic_header[1])
738 panic_log_version = unsigned(aurr_panic_header[2])
739 panic_log_reset_cause = unsigned(aurr_panic_header[3])
740 panic_log_reset_log_offset = unsigned(aurr_panic_header[4])
741 panic_log_reset_log_len = unsigned(aurr_panic_header[5])
742
743 if panic_log_magic != 0 and panic_log_magic != expected_panic_magic:
744 print "BAD MAGIC! Found 0x%x expected 0x%x" % (panic_log_magic,
745 expected_panic_magic)
746 return
747
748 print "AURR Panic Version: %d" % (panic_log_version)
749
750 # When it comes time to extend this in the future, please follow the
751 # construct used below in ShowPanicLog()
752 if panic_log_version in (xnudefines.AURR_PANIC_VERSION, xnudefines.AURR_CRASHLOG_PANIC_VERSION):
753 # AURR Report Version 1 (AURR/MacEFI) or 2 (Crashlog)
754 # see macefifirmware/Vendor/Apple/EfiPkg/AppleDebugSupport/Library/Debugger.h
755 print "Reset Cause: 0x%x (%s)" % (panic_log_reset_cause, reset_cause.get(panic_log_reset_cause, "UNKNOWN"))
756
757 # Adjust panic log string length (cap to maximum supported values)
758 if panic_log_version == xnudefines.AURR_PANIC_VERSION:
759 max_string_len = panic_log_reset_log_len and min(panic_log_reset_log_len, xnudefines.AURR_PANIC_STRING_LEN) or 0
760 elif panic_log_version == xnudefines.AURR_CRASHLOG_PANIC_VERSION:
761 max_string_len = xnudefines.CRASHLOG_PANIC_STRING_LEN
762
763 panic_str_offset = 0
764 out_str = ""
765
766 while panic_str_offset < max_string_len:
767 p_char = str(panic_buf[panic_log_reset_log_offset + panic_str_offset])
768 out_str += p_char
769 panic_str_offset += 1
770
771 print out_str
3e170ce0 772
cb323159
A
773 # Save Crashlog Binary Data (if available)
774 if "-S" in cmd_options and panic_log_version == xnudefines.AURR_CRASHLOG_PANIC_VERSION:
775 crashlog_binary_offset = panic_log_reset_log_offset + xnudefines.CRASHLOG_PANIC_STRING_LEN
776 crashlog_binary_size = (panic_log_reset_log_len > xnudefines.CRASHLOG_PANIC_STRING_LEN) and (panic_log_reset_log_len - xnudefines.CRASHLOG_PANIC_STRING_LEN) or 0
777
778 if 0 == crashlog_binary_size:
779 print "No crashlog data found..."
780 return
781
782 # Save to file
783 ts = int(time.time())
784 ss_binfile = "/tmp/crashlog_%d.bin" % ts
785
786 if not SaveDataToFile(panic_buf + crashlog_binary_offset, crashlog_binary_size, ss_binfile, None):
787 print "Failed to save crashlog binary data to file"
788 return
789 else:
790 return ParseUnknownPanicLog(panic_header, cmd_options)
791
792 return
793
794def ParseUnknownPanicLog(panic_header, cmd_options={}):
795 magic_ptr = Cast(panic_header, 'uint32_t *')
796 panic_log_magic = dereference(magic_ptr)
797 print "Unrecognized panic header format. Magic: 0x%x..." % unsigned(panic_log_magic)
798 print "Panic region starts at 0x%08x" % int(panic_header)
799 print "Hint: To dump this panic header in order to try manually parsing it, use this command:"
800 print " (lldb) memory read -fx -s4 -c64 0x%08x" % int(panic_header)
801 print " ^ that will dump the first 256 bytes of the panic region"
802 ## TBD: Hexdump some bits here to allow folks to poke at the region manually?
39236c6e
A
803 return
804
cb323159
A
805
806@lldb_command('paniclog', 'SM')
807def ShowPanicLog(cmd_args=None, cmd_options={}):
808 """ Display the paniclog information
809 usage: (lldb) paniclog
810 options:
811 -v : increase verbosity
812 -S : parse stackshot data (if panic stackshot available)
813 -M : parse macOS panic area (print panic string (if available), and/or capture crashlog info)
814 """
815
816 if "-M" in cmd_options:
817 if not hasattr(kern.globals, "mac_panic_header"):
818 print "macOS panic data requested but unavailable on this device"
819 return
820 panic_header = kern.globals.mac_panic_header
821 # DEBUG HACK FOR TESTING
822 #panic_header = kern.GetValueFromAddress(0xfffffff054098000, "uint32_t *")
823 else:
824 panic_header = kern.globals.panic_info
825
826 if hasattr(panic_header, "eph_magic"):
827 panic_log_magic = unsigned(panic_header.eph_magic)
828 elif hasattr(panic_header, "mph_magic"):
829 panic_log_magic = unsigned(panic_header.mph_magic)
830 else:
831 print "*** Warning: unsure of panic header format, trying anyway"
832 magic_ptr = Cast(panic_header, 'uint32_t *')
833 panic_log_magic = int(dereference(magic_ptr))
834
835 if panic_log_magic == 0:
836 # No panic here..
837 return
838
839 panic_parsers = {
840 int(xnudefines.AURR_PANIC_MAGIC) : ParseAURRPanicLog,
841 int(xnudefines.MACOS_PANIC_MAGIC) : ParseMacOSPanicLog,
842 int(xnudefines.EMBEDDED_PANIC_MAGIC) : ParseEmbeddedPanicLog,
843 }
844
845 # Find the right parser (fall back to unknown parser above)
846 parser = panic_parsers.get(panic_log_magic, ParseUnknownPanicLog)
847
848 # execute it
849 return parser(panic_header, cmd_options)
850
39236c6e
A
851@lldb_command('showbootargs')
852def ShowBootArgs(cmd_args=None):
853 """ Display boot arguments passed to the target kernel
854 """
855 bootargs = Cast(kern.GetGlobalVariable('PE_state').bootArgs, 'boot_args *')
856 bootargs_cmd = bootargs.CommandLine
857 print str(bootargs_cmd)
858
859@static_var("last_process_uniq_id", 1)
860def GetDebuggerStopIDValue():
cb323159 861 """ Create a unique session identifier.
39236c6e
A
862 returns:
863 int - a unique number identified by processid and stopid.
864 """
865 stop_id = 0
866 process_obj = LazyTarget.GetProcess()
867 if hasattr(process_obj, "GetStopID"):
868 stop_id = process_obj.GetStopID()
869 proc_uniq_id = 0
870 if hasattr(process_obj, 'GetUniqueID'):
871 proc_uniq_id = process_obj.GetUniqueID()
872 #FIXME <rdar://problem/13034329> forces us to do this twice
873 proc_uniq_id = process_obj.GetUniqueID()
874 else:
875 GetDebuggerStopIDValue.last_process_uniq_id +=1
876 proc_uniq_id = GetDebuggerStopIDValue.last_process_uniq_id + 1
877
cb323159 878 stop_id_str = "{:d}:{:d}".format(proc_uniq_id, stop_id)
39236c6e
A
879 return hash(stop_id_str)
880
881# The initialization code to add your commands
882_xnu_framework_init = False
883def __lldb_init_module(debugger, internal_dict):
884 global kern, lldb_command_documentation, config, _xnu_framework_init
885 if _xnu_framework_init:
886 return
887 _xnu_framework_init = True
888 caching._GetDebuggerSessionID = GetDebuggerStopIDValue
889 debugger.HandleCommand('type summary add --regex --summary-string "${var%s}" -C yes -p -v "char \[[0-9]*\]"')
890 debugger.HandleCommand('type format add --format hex -C yes uintptr_t')
891 kern = KernelTarget(debugger)
cb323159
A
892 if not hasattr(lldb.SBValue, 'GetValueAsAddress'):
893 warn_str = "WARNING: lldb version is too old. Some commands may break. Please update to latest lldb."
894 if os.isatty(sys.__stdout__.fileno()):
895 warn_str = VT.DarkRed + warn_str + VT.Default
896 print warn_str
39236c6e
A
897 print "xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries."
898
899__lldb_init_module(lldb.debugger, None)
900
901@lldb_command("showlldbtypesummaries")
902def ShowLLDBTypeSummaries(cmd_args=[]):
903 """ Enable/Disable kernel type summaries. Default is disabled.
904 Usage: showlldbtypesummaries [enable|disable]
905 default is enable
906 """
907 global config
908 action = "enable"
909 trailer_msg = ''
910 if len(cmd_args) > 0 and cmd_args[0].lower().find('disable') >=0:
911 action = "disable"
912 config['showTypeSummary'] = False
913 trailer_msg = "Please run 'showlldbtypesummaries enable' to enable the summary feature."
914 else:
915 config['showTypeSummary'] = True
916 SetupLLDBTypeSummaries(True)
917 trailer_msg = "Please run 'showlldbtypesummaries disable' to disable the summary feature."
918 lldb_run_command("type category "+ action +" kernel")
919 print "Successfully "+action+"d the kernel type summaries. %s" % trailer_msg
920
fe8ab488
A
921@lldb_command('walkqueue_head', 'S')
922def WalkQueueHead(cmd_args=[], cmd_options={}):
cb323159 923 """ walk a queue_head_t and list all members in it. Note this is for queue_head_t. refer to osfmk/kern/queue.h
fe8ab488
A
924 Option: -S - suppress summary output.
925 Usage: (lldb) walkqueue_head <queue_entry *> <struct type> <fieldname>
926 ex: (lldb) walkqueue_head 0x7fffff80 "thread *" "task_threads"
cb323159 927
fe8ab488
A
928 """
929 global lldb_summary_definitions
930 if not cmd_args:
931 raise ArgumentError("invalid arguments")
932 if len(cmd_args) != 3:
933 raise ArgumentError("insufficient arguments")
934 queue_head = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *')
935 el_type = cmd_args[1]
936 field_name = cmd_args[2]
937 showsummary = False
938 if el_type in lldb_summary_definitions:
939 showsummary = True
940 if '-S' in cmd_options:
941 showsummary = False
942
943 for i in IterateQueue(queue_head, el_type, field_name):
944 if showsummary:
945 print lldb_summary_definitions[el_type](i)
946 else:
947 print "{0: <#020x}".format(i)
cb323159 948
fe8ab488
A
949
950
4ba76501 951@lldb_command('walklist_entry', 'SE')
fe8ab488
A
952def WalkList(cmd_args=[], cmd_options={}):
953 """ iterate over a list as defined with LIST_ENTRY in bsd/sys/queue.h
954 params:
955 object addr - value : address of object
956 element_type - str : Type of the next element
957 field_name - str : Name of the field in next element's structure
958
4ba76501
A
959 Options: -S - suppress summary output.
960 -E - Iterate using SLIST_ENTRYs
961
fe8ab488
A
962 Usage: (lldb) walklist_entry <obj with list_entry *> <struct type> <fieldname>
963 ex: (lldb) walklist_entry 0x7fffff80 "struct proc *" "p_sibling"
cb323159 964
fe8ab488
A
965 """
966 global lldb_summary_definitions
967 if not cmd_args:
968 raise ArgumentError("invalid arguments")
969 if len(cmd_args) != 3:
970 raise ArgumentError("insufficient arguments")
971 el_type = cmd_args[1]
972 queue_head = kern.GetValueFromAddress(cmd_args[0], el_type)
973 field_name = cmd_args[2]
fe8ab488
A
974 showsummary = False
975 if el_type in lldb_summary_definitions:
976 showsummary = True
977 if '-S' in cmd_options:
978 showsummary = False
4ba76501
A
979 if '-E' in cmd_options:
980 prefix = 's'
981 else:
982 prefix = ''
fe8ab488
A
983 elt = queue_head
984 while unsigned(elt) != 0:
985 i = elt
4ba76501 986 elt = elt.__getattr__(field_name).__getattr__(prefix + 'le_next')
fe8ab488
A
987 if showsummary:
988 print lldb_summary_definitions[el_type](i)
989 else:
990 print "{0: <#020x}".format(i)
991
94ff46dc 992def trace_parse_Copt(Copt):
0a7de745
A
993 """Parses the -C option argument and returns a list of CPUs
994 """
995 cpusOpt = Copt
996 cpuList = cpusOpt.split(",")
997 chosen_cpus = []
998 for cpu_num_string in cpuList:
999 try:
1000 if '-' in cpu_num_string:
1001 parts = cpu_num_string.split('-')
1002 if len(parts) != 2 or not (parts[0].isdigit() and parts[1].isdigit()):
1003 raise ArgumentError("Invalid cpu specification: %s" % cpu_num_string)
1004 firstRange = int(parts[0])
1005 lastRange = int(parts[1])
1006 if firstRange >= kern.globals.real_ncpus or lastRange >= kern.globals.real_ncpus:
1007 raise ValueError()
1008 if lastRange < firstRange:
1009 raise ArgumentError("Invalid CPU range specified: `%s'" % cpu_num_string)
1010 for cpu_num in range(firstRange, lastRange + 1):
1011 if cpu_num not in chosen_cpus:
1012 chosen_cpus.append(cpu_num)
1013 else:
1014 chosen_cpu = int(cpu_num_string)
1015 if chosen_cpu < 0 or chosen_cpu >= kern.globals.real_ncpus:
1016 raise ValueError()
1017 if chosen_cpu not in chosen_cpus:
1018 chosen_cpus.append(chosen_cpu)
1019 except ValueError:
1020 raise ArgumentError("Invalid CPU number specified. Valid range is 0..%d" % (kern.globals.real_ncpus - 1))
1021
1022 return chosen_cpus
1023
1024
94ff46dc
A
1025IDX_CPU = 0
1026IDX_RINGPOS = 1
1027IDX_RINGENTRY = 2
1028def Trace_cmd(cmd_args=[], cmd_options={}, headerString=lambda:"", entryString=lambda x:"", ring=[], entries_per_cpu=0, max_backtraces=0):
1029 """Generic trace dumper helper function
0a7de745 1030 """
0a7de745
A
1031
1032 if '-S' in cmd_options:
1033 field_arg = cmd_options['-S']
1034 try:
94ff46dc 1035 getattr(ring[0][0], field_arg)
0a7de745
A
1036 sort_key_field_name = field_arg
1037 except AttributeError:
1038 raise ArgumentError("Invalid sort key field name `%s'" % field_arg)
1039 else:
1040 sort_key_field_name = 'start_time_abs'
1041
1042 if '-C' in cmd_options:
94ff46dc 1043 chosen_cpus = trace_parse_Copt(cmd_options['-C'])
0a7de745
A
1044 else:
1045 chosen_cpus = [x for x in range(kern.globals.real_ncpus)]
1046
1047 try:
1048 limit_output_count = int(cmd_options['-N'])
1049 except ValueError:
1050 raise ArgumentError("Invalid output count `%s'" % cmd_options['-N']);
1051 except KeyError:
1052 limit_output_count = None
1053
1054 reverse_sort = '-R' in cmd_options
1055 backtraces = '-B' in cmd_options
1056
1057 # entries will be a list of 3-tuples, each holding the CPU on which the iotrace entry was collected,
1058 # the original ring index, and the iotrace entry.
1059 entries = []
1060 for x in chosen_cpus:
94ff46dc 1061 ring_slice = [(x, y, ring[x][y]) for y in range(entries_per_cpu)]
0a7de745
A
1062 entries.extend(ring_slice)
1063
1064 total_entries = len(entries)
1065
1066 entries.sort(key=lambda x: getattr(x[IDX_RINGENTRY], sort_key_field_name), reverse=reverse_sort)
1067
1068 if limit_output_count is not None and limit_output_count > total_entries:
1069 print ("NOTE: Output count `%d' is too large; showing all %d entries" % (limit_output_count, total_entries));
1070 limit_output_count = total_entries
1071
1072 if len(chosen_cpus) < kern.globals.real_ncpus:
1073 print "NOTE: Limiting to entries from cpu%s %s" % ("s" if len(chosen_cpus) > 1 else "", str(chosen_cpus))
1074
1075 if limit_output_count is not None and limit_output_count < total_entries:
1076 entries_to_display = limit_output_count
1077 print "NOTE: Limiting to the %s" % ("first entry" if entries_to_display == 1 else ("first %d entries" % entries_to_display))
1078 else:
1079 entries_to_display = total_entries
1080
94ff46dc 1081 print headerString()
0a7de745
A
1082
1083 for x in xrange(entries_to_display):
94ff46dc
A
1084 print entryString(entries[x])
1085
0a7de745 1086 if backtraces:
94ff46dc 1087 for btidx in range(max_backtraces):
0a7de745
A
1088 nextbt = entries[x][IDX_RINGENTRY].backtrace[btidx]
1089 if nextbt == 0:
1090 break
1091 print "\t" + GetSourceInformationForAddress(nextbt)
94ff46dc
A
1092
1093
1094@lldb_command('iotrace', 'C:N:S:RB')
1095def IOTrace_cmd(cmd_args=[], cmd_options={}):
1096 """ Prints the iotrace ring buffers for all CPUs by default.
1097 Arguments:
1098 -B : Print backtraces for each ring entry
1099 -C <cpuSpec#>[,...,<cpuSpec#N>] : Limit trace entries to those generated by the specified CPUs (each cpuSpec can be a
1100 single CPU number or a range separated by a dash (e.g. "0-3"))
1101 -N <count> : Limit output to the first <count> entries (across all chosen CPUs)
1102 -R : Display results in reverse-sorted order (oldest first; default is newest-first)
1103 -S <sort_key_field_name> : Sort output by specified iotrace_entry_t field name (instead of by timestamp)
1104 """
1105 MAX_IOTRACE_BACKTRACES = 16
1106
1107 if kern.arch != "x86_64":
1108 print "Sorry, iotrace is an x86-only command."
1109 return
1110
1111 hdrString = lambda : "%-19s %-8s %-10s %-20s SZ %-18s %-17s DATA" % (
1112 "START TIME",
1113 "DURATION",
1114 "CPU#[RIDX]",
1115 " TYPE",
1116 " VIRT ADDR",
1117 " PHYS ADDR")
1118
1119 entryString = lambda x : "%-20u(%6u) %6s[%02d] %-20s %-2d 0x%016x 0x%016x 0x%x" % (
1120 x[IDX_RINGENTRY].start_time_abs,
1121 x[IDX_RINGENTRY].duration,
1122 "CPU%d" % x[IDX_CPU],
1123 x[IDX_RINGPOS],
1124 str(x[IDX_RINGENTRY].iotype).split("=")[1].strip(),
1125 x[IDX_RINGENTRY].size,
1126 x[IDX_RINGENTRY].vaddr,
1127 x[IDX_RINGENTRY].paddr,
1128 x[IDX_RINGENTRY].val)
1129
1130 Trace_cmd(cmd_args, cmd_options, hdrString, entryString, kern.globals.iotrace_ring, kern.globals.iotrace_entries_per_cpu, MAX_IOTRACE_BACKTRACES)
1131
1132
1133@lldb_command('ttrace', 'C:N:S:RB')
1134def TrapTrace_cmd(cmd_args=[], cmd_options={}):
1135 """ Prints the iotrace ring buffers for all CPUs by default.
1136 Arguments:
1137 -B : Print backtraces for each ring entry
1138 -C <cpuSpec#>[,...,<cpuSpec#N>] : Limit trace entries to those generated by the specified CPUs (each cpuSpec can be a
1139 single CPU number or a range separated by a dash (e.g. "0-3"))
1140 -N <count> : Limit output to the first <count> entries (across all chosen CPUs)
1141 -R : Display results in reverse-sorted order (oldest first; default is newest-first)
1142 -S <sort_key_field_name> : Sort output by specified traptrace_entry_t field name (instead of by timestamp)
1143 """
1144 MAX_TRAPTRACE_BACKTRACES = 8
1145
1146 if kern.arch != "x86_64":
1147 print "Sorry, ttrace is an x86-only command."
1148 return
1149
1150 hdrString = lambda : "%-30s CPU#[RIDX] VECT INTERRUPTED_THREAD PREMLV INTRLV INTERRUPTED_PC" % (
1151 "START TIME (DURATION [ns])")
1152 entryString = lambda x : "%-20u(%6s) %8s[%02d] 0x%02x 0x%016x %6d %6d %s" % (
1153 x[IDX_RINGENTRY].start_time_abs,
1154 str(x[IDX_RINGENTRY].duration) if hex(x[IDX_RINGENTRY].duration) != "0xffffffffffffffff" else 'inprog',
1155 "CPU%d" % x[IDX_CPU],
1156 x[IDX_RINGPOS],
1157 int(x[IDX_RINGENTRY].vector),
1158 x[IDX_RINGENTRY].curthread,
1159 x[IDX_RINGENTRY].curpl,
1160 x[IDX_RINGENTRY].curil,
1161 GetSourceInformationForAddress(x[IDX_RINGENTRY].interrupted_pc))
1162
1163 Trace_cmd(cmd_args, cmd_options, hdrString, entryString, kern.globals.traptrace_ring,
1164 kern.globals.traptrace_entries_per_cpu, MAX_TRAPTRACE_BACKTRACES)
0a7de745
A
1165
1166
4ba76501
A
1167@lldb_command('showsysctls', 'P:')
1168def ShowSysctls(cmd_args=[], cmd_options={}):
1169 """ Walks the list of sysctl data structures, printing out each during traversal.
1170 Arguments:
1171 -P <string> : Limit output to sysctls starting with the specified prefix.
1172 """
1173 if '-P' in cmd_options:
1174 _ShowSysctl_prefix = cmd_options['-P']
1175 allowed_prefixes = _ShowSysctl_prefix.split('.')
1176 if allowed_prefixes:
1177 for x in xrange(1, len(allowed_prefixes)):
1178 allowed_prefixes[x] = allowed_prefixes[x - 1] + "." + allowed_prefixes[x]
1179 else:
1180 _ShowSysctl_prefix = ''
1181 allowed_prefixes = []
1182 def IterateSysctls(oid, parent_str, i):
1183 headp = oid
1184 parentstr = "<none>" if parent_str is None else parent_str
1185 for pp in IterateListEntry(headp, 'struct sysctl_oid *', 'oid_link', 's'):
1186 type = pp.oid_kind & 0xf
1187 next_parent = str(pp.oid_name)
1188 if parent_str is not None:
1189 next_parent = parent_str + "." + next_parent
1190 st = (" " * i) + str(pp.GetSBValue().Dereference()).replace("\n", "\n" + (" " * i))
1191 if type == 1 and pp.oid_arg1 != 0:
1192 # Check allowed_prefixes to see if we can recurse from root to the allowed prefix.
1193 # To recurse further, we need to check only the the next parent starts with the user-specified
1194 # prefix
1195 if next_parent not in allowed_prefixes and next_parent.startswith(_ShowSysctl_prefix) is False:
1196 continue
1197 print 'parent = "%s"' % parentstr, st[st.find("{"):]
1198 IterateSysctls(Cast(pp.oid_arg1, "struct sysctl_oid_list *"), next_parent, i + 2)
1199 elif _ShowSysctl_prefix == '' or next_parent.startswith(_ShowSysctl_prefix):
1200 print ('parent = "%s"' % parentstr), st[st.find("{"):]
1201 IterateSysctls(kern.globals.sysctl__children, None, 0)
1202
fe8ab488
A
1203
1204
39236c6e
A
1205from memory import *
1206from process import *
cb323159 1207from ipc import *
39236c6e
A
1208from pmap import *
1209from ioreg import *
1210from mbufs import *
1211from net import *
d9a64523 1212from skywalk import *
39236c6e
A
1213from kdp import *
1214from userspace import *
1215from pci import *
1216from misc import *
1217from apic import *
1218from scheduler import *
fe8ab488
A
1219from atm import *
1220from structanalyze import *
1221from ipcimportancedetail import *
1222from bank import *
d9a64523 1223from turnstile import *
5ba3f43e 1224from kasan import *
3e170ce0
A
1225from kauth import *
1226from waitq import *
1227from usertaskgdbserver import *
39037602
A
1228from ktrace import *
1229from pgtrace import *
1230from xnutriage import *
5ba3f43e 1231from kevent import *
d9a64523 1232from workqueue import *
cb323159 1233from ulock import *
5ba3f43e 1234from ntstat import *
a39ff7e2 1235from zonetriage import *
cb323159 1236from sysreg import *