]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/xnu.py
xnu-4570.1.46.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.
24 -o <path/to/filename> The output of this command execution will be saved to file. Parser information or errors will
25 not be sent to file though. eg /tmp/output.txt
26 -s <filter_string> The "filter_string" param is parsed to python regex expression and each line of output
27 will be printed/saved only if it matches the expression.
28 -v [-v...] Each additional -v will increase the verbosity of the command.
29 -p <plugin_name> Send the output of the command to plugin. Please see README for usage of plugins.
30"""
39236c6e 31# End Utility functions
5ba3f43e 32# Debugging specific utility functions
39236c6e
A
33
34#decorators. Not to be called directly.
35
36def static_var(var_name, initial_value):
37 def _set_var(obj):
38 setattr(obj, var_name, initial_value)
39 return obj
40 return _set_var
41
42def header(initial_value):
43 def _set_header(obj):
44 setattr(obj, 'header', initial_value)
45 return obj
46 return _set_header
47
48# holds type declarations done by xnu.
49#DONOTTOUCHME: Exclusive use of lldb_type_summary only.
50lldb_summary_definitions = {}
51def lldb_type_summary(types_list):
52 """ A function decorator to register a summary for a type in lldb.
53 params: types_list - [] an array of types that you wish to register a summary callback function. (ex. ['task *', 'task_t'])
54 returns: Nothing. This is a decorator.
55 """
56 def _get_summary(obj):
57 def _internal_summary_function(lldbval, internal_dict):
58 out_string= ""
59 if internal_dict != None and len(obj.header) > 0 :
60 out_string += "\n" + obj.header +"\n"
61 out_string += obj( core.value(lldbval) )
62 return out_string
63
64 myglobals = globals()
65 summary_function_name = "LLDBSummary" + obj.__name__
66 myglobals[summary_function_name] = _internal_summary_function
67 summary_function = myglobals[summary_function_name]
68 summary_function.__doc__ = obj.__doc__
69
70 global lldb_summary_definitions
71 for single_type in types_list:
72 if config['showTypeSummary']:
73 if single_type in lldb_summary_definitions.keys():
74 lldb.debugger.HandleCommand("type summary delete --category kernel \""+ single_type + "\"")
75 lldb.debugger.HandleCommand("type summary add \""+ single_type +"\" --category kernel --python-function " + MODULE_NAME + "." + summary_function_name)
76 lldb_summary_definitions[single_type] = obj
77
78 return obj
79 return _get_summary
80
81#global cache of documentation for lldb commands exported by this module
82#DONOTTOUCHME: Exclusive use of lldb_command only.
83lldb_command_documentation = {}
84
85def lldb_command(cmd_name, option_string = ''):
86 """ A function decorator to define a command with namd 'cmd_name' in the lldb scope to call python function.
87 params: cmd_name - str : name of command to be set in lldb prompt.
88 option_string - str: getopt like option string. Only CAPITAL LETTER options allowed.
89 see README on Customizing command options.
90 """
91 if option_string != option_string.upper():
92 raise RuntimeError("Cannot setup command with lowercase option args. %s" % option_string)
93
94 def _cmd(obj):
95 def _internal_command_function(debugger, command, result, internal_dict):
96 global config, lldb_run_command_state
813fb2f6 97 stream = CommandOutput(cmd_name, result)
39236c6e
A
98 # need to avoid printing on stdout if called from lldb_run_command.
99 if 'active' in lldb_run_command_state and lldb_run_command_state['active']:
100 debuglog('Running %s from lldb_run_command' % command)
101 else:
102 result.SetImmediateOutputFile(sys.__stdout__)
103
104 command_args = shlex.split(command)
105 lldb.debugger.HandleCommand('type category disable kernel' )
106 def_verbose_level = config['verbosity']
107
108 try:
109 stream.setOptions(command_args, option_string)
110 if stream.verbose_level != 0:
fe8ab488 111 config['verbosity'] += stream.verbose_level
39236c6e
A
112 with RedirectStdStreams(stdout=stream) :
113 if option_string:
114 obj(cmd_args=stream.target_cmd_args, cmd_options=stream.target_cmd_options)
115 else:
116 obj(cmd_args=stream.target_cmd_args)
117 except KeyboardInterrupt:
118 print "Execution interrupted by user"
119 except ArgumentError as arg_error:
120 if str(arg_error) != "HELP":
121 print "Argument Error: " + str(arg_error)
122 print "{0:s}:\n {1:s}".format(cmd_name, obj.__doc__.strip())
123 return False
124 except Exception as exc:
125 if not config['debug']:
126 print """
127************ LLDB found an exception ************
128There has been an uncaught exception. A possible cause could be that remote connection has been disconnected.
129However, it is recommended that you report the exception to lldb/kernel debugging team about it.
130************ Please run 'xnudebug debug enable' to start collecting logs. ************
131 """
132 raise
133
134 if config['showTypeSummary']:
135 lldb.debugger.HandleCommand('type category enable kernel' )
136
137 if stream.pluginRequired :
138 plugin = LoadXNUPlugin(stream.pluginName)
139 if plugin == None :
140 print "Could not load plugins."+stream.pluginName
141 return
142 plugin.plugin_init(kern, config, lldb, kern.IsDebuggerConnected())
143 return_data = plugin.plugin_execute(cmd_name, result.GetOutput())
144 ProcessXNUPluginResult(return_data)
145 plugin.plugin_cleanup()
146
147 #restore the verbose level after command is complete
148 config['verbosity'] = def_verbose_level
149
150 return
151
152 myglobals = globals()
153 command_function_name = obj.__name__+"Command"
154 myglobals[command_function_name] = _internal_command_function
155 command_function = myglobals[command_function_name]
156 if not obj.__doc__ :
157 print "ERROR: Cannot register command({:s}) without documentation".format(cmd_name)
158 return obj
5ba3f43e 159 obj.__doc__ += "\n" + COMMON_HELP_STRING
39236c6e
A
160 command_function.__doc__ = obj.__doc__
161 global lldb_command_documentation
162 if cmd_name in lldb_command_documentation:
163 lldb.debugger.HandleCommand("command script delete "+cmd_name)
164 lldb_command_documentation[cmd_name] = (obj.__name__, obj.__doc__.lstrip(), option_string)
165 lldb.debugger.HandleCommand("command script add -f " + MODULE_NAME + "." + command_function_name + " " + cmd_name)
166 return obj
167 return _cmd
168
169def lldb_alias(alias_name, cmd_line):
170 """ define an alias in the lldb command line.
171 A programatic way of registering an alias. This basically does
172 (lldb)command alias alias_name "cmd_line"
173 ex.
174 lldb_alias('readphys16', 'readphys 16')
175 """
176 alias_name = alias_name.strip()
177 cmd_line = cmd_line.strip()
178 lldb.debugger.HandleCommand("command alias " + alias_name + " "+ cmd_line)
179
180def SetupLLDBTypeSummaries(reset=False):
181 global lldb_summary_definitions, MODULE_NAME
182 if reset == True:
183 lldb.debugger.HandleCommand("type category delete kernel ")
184 for single_type in lldb_summary_definitions.keys():
185 summary_function = lldb_summary_definitions[single_type]
186 lldb_cmd = "type summary add \""+ single_type +"\" --category kernel --python-function " + MODULE_NAME + ".LLDBSummary" + summary_function.__name__
187 debuglog(lldb_cmd)
188 lldb.debugger.HandleCommand(lldb_cmd)
189 if config['showTypeSummary']:
190 lldb.debugger.HandleCommand("type category enable kernel")
191 else:
192 lldb.debugger.HandleCommand("type category disable kernel")
193
194 return
195
196def LoadXNUPlugin(name):
197 """ Try to load a plugin from the plugins directory.
198 """
199 retval = None
200 name=name.strip()
201 try:
202 module_obj = __import__('plugins.'+name, globals(), locals(), [], -1)
203 module_obj = module_obj.__dict__[name]
204 defs = dir(module_obj)
205 if 'plugin_init' in defs and 'plugin_execute' in defs and 'plugin_cleanup' in defs:
206 retval = module_obj
207 else:
208 print "Plugin is not correctly implemented. Please read documentation on implementing plugins"
209 except:
210 print "plugin not found :"+name
211
212 return retval
213
214def ProcessXNUPluginResult(result_data):
215 """ Look at the returned data from plugin and see if anymore actions are required or not
216 params: result_data - list of format (status, out_string, more_commands)
217 """
218 ret_status = result_data[0]
219 ret_string = result_data[1]
220 ret_commands = result_data[2]
221
222 if ret_status == False:
223 print "Plugin failed: " + ret_string
224 return
225 print ret_string
226 if len(ret_commands) >= 0:
227 for cmd in ret_commands:
228 print "Running command on behalf of plugin:" + cmd
229 lldb.debugger.HandleCommand(cmd)
230 return
231
232# holds tests registered with xnu.
233#DONOTTOUCHME: Exclusive use of xnudebug_test only
234lldb_command_tests = {}
235def xnudebug_test(test_name):
236 """ A function decoratore to register a test with the framework. Each test is supposed to be of format
237 def Test<name>(kernel_target, config, lldb_obj, isConnected )
238
239 NOTE: The testname should start with "Test" else exception will be raised.
240 """
241 def _test(obj):
242 global lldb_command_tests
243 if obj.__name__.find("Test") != 0 :
244 print "Test name ", obj.__name__ , " should start with Test"
245 raise ValueError
246 lldb_command_tests[test_name] = (test_name, obj.__name__, obj, obj.__doc__)
247 return obj
248 return _test
249
250
251# End Debugging specific utility functions
252# Kernel Debugging specific classes and accessor methods
253
254# global access object for target kernel
255
256def GetObjectAtIndexFromArray(array_base, index):
257 """ Subscript indexing for arrays that are represented in C as pointers.
258 for ex. int *arr = malloc(20*sizeof(int));
259 now to get 3rd int from 'arr' you'd do
260 arr[2] in C
261 GetObjectAtIndexFromArray(arr_val,2)
262 params:
263 array_base : core.value - representing a pointer type (ex. base of type 'ipc_entry *')
264 index : int - 0 based index into the array
265 returns:
266 core.value : core.value of the same type as array_base_val but pointing to index'th element
267 """
268 array_base_val = array_base.GetSBValue()
269 base_address = array_base_val.GetValueAsUnsigned()
270 size = array_base_val.GetType().GetPointeeType().GetByteSize()
271 obj_address = base_address + (index * size)
272 obj = kern.GetValueFromAddress(obj_address, array_base_val.GetType().GetName())
273 return Cast(obj, array_base_val.GetType())
274
275
276kern = None
277
278def GetLLDBThreadForKernelThread(thread_obj):
279 """ Get a reference to lldb.SBThread representation for kernel thread.
280 params:
281 thread_obj : core.cvalue - thread object of type thread_t
282 returns
283 lldb.SBThread - lldb thread object for getting backtrace/registers etc.
284 """
285 tid = unsigned(thread_obj.thread_id)
286 lldb_process = LazyTarget.GetProcess()
287 sbthread = lldb_process.GetThreadByID(tid)
288 if not sbthread.IsValid():
289 # in case lldb doesnt know about this thread, create one
290 if hasattr(lldb_process, "CreateOSPluginThread"):
291 debuglog("creating os plugin thread on the fly for {0:d} 0x{1:x}".format(tid, thread_obj))
292 lldb_process.CreateOSPluginThread(tid, unsigned(thread_obj))
293 else:
294 raise RuntimeError("LLDB process does not support CreateOSPluginThread.")
295 sbthread = lldb_process.GetThreadByID(tid)
296
297 if not sbthread.IsValid():
fe8ab488
A
298 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))
299
39236c6e
A
300 return sbthread
301
39037602
A
302def GetKextSymbolInfo(load_addr):
303 """ Get a string descriptiong load_addr <kextname> + offset
304 params:
305 load_addr - int address value of pc in backtrace.
306 returns: str - kext name + offset string. If no cached data available, warning message is returned.
307 """
308 symbol_name = "None"
309 symbol_offset = load_addr
310 kmod_val = kern.globals.kmod
5ba3f43e 311 if not kern.arch.startswith('arm64'):
39037602
A
312 for kval in IterateLinkedList(kmod_val, 'next'):
313 if load_addr >= unsigned(kval.address) and \
314 load_addr <= (unsigned(kval.address) + unsigned(kval.size)):
315 symbol_name = kval.name
316 symbol_offset = load_addr - unsigned(kval.address)
317 break
318 return "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset)
319
320 # only for arm64 we do lookup for split kexts.
321 cached_kext_info = caching.GetDynamicCacheData("kern.kexts.loadinformation", [])
322 if not cached_kext_info and str(GetConnectionProtocol()) == "core":
323 cached_kext_info = GetKextLoadInformation()
324
325 if not cached_kext_info:
326 return "{:#018x} ~ kext info not available. please run 'showallkexts' once ~ \n".format(load_addr)
327
328 for kval in cached_kext_info:
329 text_seg = kval[5]
330 if load_addr >= text_seg.vmaddr and \
331 load_addr <= (text_seg.vmaddr + text_seg.vmsize):
332 symbol_name = kval[2]
333 symbol_offset = load_addr - text_seg.vmaddr
334 break
335 return "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset)
336
39236c6e
A
337def GetThreadBackTrace(thread_obj, verbosity = vHUMAN, prefix = ""):
338 """ Get a string to display back trace for a thread.
339 params:
340 thread_obj - core.cvalue : a thread object of type thread_t.
341 verbosity - int : either of vHUMAN, vSCRIPT or vDETAIL to describe the verbosity of output
342 prefix - str : a string prefix added before the line for each frame.
343 isContinuation - bool : is thread a continuation?
344 returns:
345 str - a multi line string showing each frame in backtrace.
346 """
347 is_continuation = not bool(unsigned(thread_obj.kernel_stack))
348 thread_val = GetLLDBThreadForKernelThread(thread_obj)
349 out_string = ""
350 kernel_stack = unsigned(thread_obj.kernel_stack)
351 reserved_stack = unsigned(thread_obj.reserved_stack)
352 if not is_continuation:
353 if kernel_stack and reserved_stack:
354 out_string += prefix + "reserved_stack = {:#018x}\n".format(reserved_stack)
355 out_string += prefix + "kernel_stack = {:#018x}\n".format(kernel_stack)
356 else:
357 out_string += prefix + "continuation ="
358 iteration = 0
359 last_frame_p = 0
360 for frame in thread_val.frames:
361 addr = frame.GetPCAddress()
362 load_addr = addr.GetLoadAddress(LazyTarget.GetTarget())
363 function = frame.GetFunction()
364 frame_p = frame.GetFP()
365 mod_name = frame.GetModule().GetFileSpec().GetFilename()
366
367 if iteration == 0 and not is_continuation:
368 out_string += prefix +"stacktop = {:#018x}\n".format(frame_p)
fe8ab488 369
39236c6e
A
370 if not function:
371 # No debug info for 'function'.
39236c6e
A
372 out_string += prefix
373 if not is_continuation:
374 out_string += "{fp:#018x} ".format(fp = frame_p)
fe8ab488
A
375
376 symbol = frame.GetSymbol()
377 if not symbol:
39037602 378 out_string += GetKextSymbolInfo(load_addr)
fe8ab488
A
379 else:
380 file_addr = addr.GetFileAddress()
381 start_addr = symbol.GetStartAddress().GetFileAddress()
382 symbol_name = symbol.GetName()
383 symbol_offset = file_addr - start_addr
384 out_string += "{addr:#018x} {mod}`{symbol} + {offset:#x} \n".format(addr=load_addr,
385 mod=mod_name, symbol=symbol_name, offset=symbol_offset)
39236c6e
A
386 else:
387 # Debug info is available for 'function'.
388 func_name = frame.GetFunctionName()
389 file_name = frame.GetLineEntry().GetFileSpec().GetFilename()
390 line_num = frame.GetLineEntry().GetLine()
391 func_name = '%s [inlined]' % func_name if frame.IsInlined() else func_name
392 if is_continuation and frame.IsInlined():
393 debuglog("Skipping frame for thread {:#018x} since its inlined".format(thread_obj))
394 continue
395 out_string += prefix
396 if not is_continuation:
397 out_string += "{fp:#018x} ".format(fp=frame_p)
398 out_string += "{addr:#018x} {func}{args} \n".format(addr=load_addr,
399 func=func_name,
400 file=file_name, line=line_num,
401 args="(" + (str(frame.arguments).replace("\n", ", ") if len(frame.arguments) > 0 else "void") + ")")
402 iteration += 1
403 if frame_p:
404 last_frame_p = frame_p
405
406 if not is_continuation and last_frame_p:
407 out_string += prefix + "stackbottom = {:#018x}".format(last_frame_p)
408 out_string = out_string.replace("variable not available","")
409 return out_string
410
411def GetSourceInformationForAddress(addr):
412 """ convert and address to function +offset information.
413 params: addr - int address in the binary to be symbolicated
414 returns: string of format "0xaddress: function + offset"
415 """
416 symbols = kern.SymbolicateFromAddress(addr)
417 format_string = "{0:#018x} <{1:s} + {2:#0x}>"
418 offset = 0
419 function_name = ""
420 if len(symbols) > 0:
421 s = symbols[0]
422 function_name = str(s.name)
423 offset = addr - s.GetStartAddress().GetLoadAddress(LazyTarget.GetTarget())
424 if function_name == "":
425 function_name = "???"
426 return format_string.format(addr, function_name, offset)
427
428def GetFrameLocalVariable(variable_name, frame_no=0):
429 """ Find a local variable by name
430 params:
431 variable_name: str - name of variable to search for
432 returns:
433 core.value - if the variable is found.
434 None - if not found or not Valid
435 """
436 retval = None
437 sbval = None
438 lldb_SBThread = LazyTarget.GetProcess().GetSelectedThread()
439 frame = lldb_SBThread.GetSelectedFrame()
440 if frame_no :
441 frame = lldb_SBThread.GetFrameAtIndex(frame_no)
442 if frame :
443 sbval = frame.FindVariable(variable_name)
444 if sbval and sbval.IsValid():
445 retval = core.cvalue.value(sbval)
446 return retval
447
448# Begin Macros for kernel debugging
449
450@lldb_command('kgmhelp')
451def KernelDebugCommandsHelp(cmd_args=None):
452 """ Show a list of registered commands for kenel debugging.
453 """
454 global lldb_command_documentation
455 print "List of commands provided by " + MODULE_NAME + " for kernel debugging."
456 cmds = lldb_command_documentation.keys()
457 cmds.sort()
458 for cmd in cmds:
459 if type(lldb_command_documentation[cmd][-1]) == type(""):
460 print " {0: <20s} - {1}".format(cmd , lldb_command_documentation[cmd][1].split("\n")[0].strip())
461 else:
462 print " {0: <20s} - {1}".format(cmd , "No help string found.")
5ba3f43e
A
463 print 'Each of the functions listed here accept the following common options. '
464 print COMMON_HELP_STRING
465 print 'Additionally, each command implementation may have more options. "(lldb) help <command> " will show these options.'
39236c6e
A
466 return None
467
468
469@lldb_command('showraw')
470def ShowRawCommand(cmd_args=None):
471 """ A command to disable the kernel summaries and show data as seen by the system.
472 This is useful when trying to read every field of a struct as compared to brief summary
473 """
474 command = " ".join(cmd_args)
475 lldb.debugger.HandleCommand('type category disable kernel' )
476 lldb.debugger.HandleCommand( command )
477 lldb.debugger.HandleCommand('type category enable kernel' )
478
479
480@lldb_command('xnudebug')
481def XnuDebugCommand(cmd_args=None):
482 """ command interface for operating on the xnu macros. Allowed commands are as follows
483 reload:
484 Reload a submodule from the xnu/tools/lldb directory. Do not include the ".py" suffix in modulename.
485 usage: xnudebug reload <modulename> (eg. memory, process, stats etc)
39037602
A
486 flushcache:
487 remove any cached data held in static or dynamic data cache.
488 usage: xnudebug flushcache
39236c6e
A
489 test:
490 Start running registered test with <name> from various modules.
491 usage: xnudebug test <name> (eg. test_memstats)
492 testall:
493 Go through all registered tests and run them
494 debug:
495 Toggle state of debug configuration flag.
496 """
497 global config
498 command_args = cmd_args
499 if len(command_args) == 0:
500 raise ArgumentError("No command specified.")
39037602 501 supported_subcommands = ['debug', 'reload', 'test', 'testall', 'flushcache']
39236c6e
A
502 subcommand = GetLongestMatchOption(command_args[0], supported_subcommands, True)
503
504 if len(subcommand) == 0:
505 raise ArgumentError("Subcommand (%s) is not a valid command. " % str(command_args[0]))
39037602 506
39236c6e
A
507 subcommand = subcommand[0].lower()
508 if subcommand == 'debug':
509 if command_args[-1].lower().find('dis') >=0 and config['debug']:
510 config['debug'] = False
511 print "Disabled debug logging."
512 elif command_args[-1].lower().find('dis') < 0 and not config['debug']:
513 config['debug'] = True
514 EnableLLDBAPILogging() # provided by utils.py
515 print "Enabled debug logging. \nPlease run 'xnudebug debug disable' to disable it again. "
39037602
A
516 if subcommand == 'flushcache':
517 print "Current size of cache: {}".format(caching.GetSizeOfCache())
518 caching.ClearAllCache()
519
39236c6e
A
520 if subcommand == 'reload':
521 module_name = command_args[-1]
522 if module_name in sys.modules:
523 reload(sys.modules[module_name])
524 print module_name + " is reloaded from " + sys.modules[module_name].__file__
525 else:
526 print "Unable to locate module named ", module_name
527 if subcommand == 'testall':
528 for test_name in lldb_command_tests.keys():
529 print "[BEGIN]", test_name
530 res = lldb_command_tests[test_name][2](kern, config, lldb, True)
531 if res:
532 print "[PASSED] {:s}".format(test_name)
533 else:
534 print "[FAILED] {:s}".format(test_name)
535 if subcommand == 'test':
536 test_name = command_args[-1]
537 if test_name in lldb_command_tests:
538 test = lldb_command_tests[test_name]
539 print "Running test {:s}".format(test[0])
540 if test[2](kern, config, lldb, True) :
541 print "[PASSED] {:s}".format(test[0])
542 else:
543 print "[FAILED] {:s}".format(test[0])
544 return ""
545 else:
546 print "No such test registered with name: {:s}".format(test_name)
547 print "XNUDEBUG Available tests are:"
548 for i in lldb_command_tests.keys():
549 print i
550 return None
551
552 return False
553
554@lldb_command('showversion')
555def ShowVersion(cmd_args=None):
556 """ Read the kernel version string from a fixed address in low
557 memory. Useful if you don't know which kernel is on the other end,
558 and need to find the appropriate symbols. Beware that if you've
559 loaded a symbol file, but aren't connected to a remote target,
560 the version string from the symbol file will be displayed instead.
561 This macro expects to be connected to the remote kernel to function
562 correctly.
563
564 """
565 print kern.version
566
567
3e170ce0
A
568@lldb_command('paniclog', 'S')
569def ShowPanicLog(cmd_args=None, cmd_options={}):
39236c6e 570 """ Display the paniclog information
fe8ab488
A
571 usage: (lldb) paniclog
572 options:
573 -v : increase verbosity
3e170ce0 574 -S : parse stackshot data (if panic stackshot available)
39236c6e 575 """
3e170ce0
A
576
577 if "-S" in cmd_options:
578 if hasattr(kern.globals, "kc_panic_data"):
5ba3f43e
A
579 stackshot_saved = False
580 if kern.arch == 'x86_64':
581 if kern.globals.panic_stackshot_len != 0:
582 stackshot_saved = True
583 else:
584 print "No panic stackshot available"
3e170ce0 585 else:
5ba3f43e
A
586 if unsigned(kern.globals.panic_info.eph_panic_flags) & xnudefines.EMBEDDED_PANIC_STACKSHOT_SUCCEEDED_FLAG:
587 stackshot_saved = True
588 else:
589 print "No panic stackshot available"
590 if stackshot_saved:
591 kc_data = unsigned(addressof(kern.globals.kc_panic_data))
592 ts = int(time.time())
593 ss_binfile = "/tmp/panic_%d.bin" % ts
594 ss_ipsfile = "/tmp/stacks_%d.ips" % ts
595 print "savekcdata 0x%x -O %s" % (kc_data, ss_binfile)
596 SaveKCDataToFile(["0x%x" % kc_data], {"-O":ss_binfile})
597 self_path = str(__file__)
598 base_dir_name = self_path[:self_path.rfind("/")]
599 print "python %s/kcdata.py %s -s %s" % (base_dir_name, ss_binfile, ss_ipsfile)
600 (c,so,se) = RunShellCommand("python %s/kcdata.py %s -s %s" % (base_dir_name, ss_binfile, ss_ipsfile))
601 if c == 0:
602 print "Saved ips stackshot file as %s" % ss_ipsfile
603 else:
604 print "Failed to run command: exit code: %d, SO: %s SE: %s" % (c, so, se)
3e170ce0
A
605 else:
606 print "kc_panic_data is unavailable for this kernel config."
607
fe8ab488 608 out_str = ""
3e170ce0 609 warn_str = ""
5ba3f43e
A
610
611 if kern.arch == 'x86_64':
612 panic_buf = kern.globals.debug_buf_base
613 panic_buf_start = unsigned(panic_buf)
614 panic_buf_end = unsigned(kern.globals.debug_buf_ptr)
615 num_bytes = panic_buf_end - panic_buf_start
616 if num_bytes == 0:
617 return
618 num_print_bytes = 0
619 pos = 0
620 while pos < num_bytes:
621 p_char = str(panic_buf[pos])
622 out_str += p_char
623 pos += 1
624 else:
625 panic_buf = Cast(kern.globals.panic_info, 'char *')
626 panic_log_magic = unsigned(kern.globals.panic_info.eph_magic)
627 panic_log_begin_offset = unsigned(kern.globals.panic_info.eph_panic_log_offset)
628 panic_log_len = unsigned(kern.globals.panic_info.eph_panic_log_len)
629 other_log_begin_offset = unsigned(kern.globals.panic_info.eph_other_log_offset)
630 other_log_len = unsigned(kern.globals.panic_info.eph_other_log_len)
631
632 if panic_log_begin_offset == 0:
633 return
634
635 if panic_log_magic != 0 and panic_log_magic != xnudefines.EMBEDDED_PANIC_MAGIC:
636 warn_str += "BAD MAGIC! Found 0x%x expected 0x%x".format(panic_log_magic,
637 xnudefines.EMBEDDED_PANIC_MAGIC)
638
639 if panic_log_begin_offset == 0:
640 if warn_str:
641 print "\n %s" % warn_str
642 return
643
644 panic_log_curindex = 0
645 while panic_log_curindex < panic_log_len:
646 p_char = str(panic_buf[(panic_log_begin_offset + panic_log_curindex)])
647 out_str += p_char
648 panic_log_curindex += 1
649
650 if other_log_begin_offset != 0:
651 other_log_curindex = 0
652 while other_log_curindex < other_log_len:
653 p_char = str(panic_buf[(other_log_begin_offset + other_log_curindex)])
654 out_str += p_char
655 other_log_curindex += 1
656
657 print out_str
3e170ce0 658
fe8ab488 659 if warn_str:
5ba3f43e 660 print "\n %s" % warn_str
3e170ce0 661
39236c6e
A
662 return
663
664@lldb_command('showbootargs')
665def ShowBootArgs(cmd_args=None):
666 """ Display boot arguments passed to the target kernel
667 """
668 bootargs = Cast(kern.GetGlobalVariable('PE_state').bootArgs, 'boot_args *')
669 bootargs_cmd = bootargs.CommandLine
670 print str(bootargs_cmd)
671
672@static_var("last_process_uniq_id", 1)
673def GetDebuggerStopIDValue():
674 """ Create a unique session identifier.
675 returns:
676 int - a unique number identified by processid and stopid.
677 """
678 stop_id = 0
679 process_obj = LazyTarget.GetProcess()
680 if hasattr(process_obj, "GetStopID"):
681 stop_id = process_obj.GetStopID()
682 proc_uniq_id = 0
683 if hasattr(process_obj, 'GetUniqueID'):
684 proc_uniq_id = process_obj.GetUniqueID()
685 #FIXME <rdar://problem/13034329> forces us to do this twice
686 proc_uniq_id = process_obj.GetUniqueID()
687 else:
688 GetDebuggerStopIDValue.last_process_uniq_id +=1
689 proc_uniq_id = GetDebuggerStopIDValue.last_process_uniq_id + 1
690
691 stop_id_str = "{:d}:{:d}".format(proc_uniq_id, stop_id)
692 return hash(stop_id_str)
693
694# The initialization code to add your commands
695_xnu_framework_init = False
696def __lldb_init_module(debugger, internal_dict):
697 global kern, lldb_command_documentation, config, _xnu_framework_init
698 if _xnu_framework_init:
699 return
700 _xnu_framework_init = True
701 caching._GetDebuggerSessionID = GetDebuggerStopIDValue
702 debugger.HandleCommand('type summary add --regex --summary-string "${var%s}" -C yes -p -v "char \[[0-9]*\]"')
703 debugger.HandleCommand('type format add --format hex -C yes uintptr_t')
704 kern = KernelTarget(debugger)
705 print "xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries."
706
707__lldb_init_module(lldb.debugger, None)
708
709@lldb_command("showlldbtypesummaries")
710def ShowLLDBTypeSummaries(cmd_args=[]):
711 """ Enable/Disable kernel type summaries. Default is disabled.
712 Usage: showlldbtypesummaries [enable|disable]
713 default is enable
714 """
715 global config
716 action = "enable"
717 trailer_msg = ''
718 if len(cmd_args) > 0 and cmd_args[0].lower().find('disable') >=0:
719 action = "disable"
720 config['showTypeSummary'] = False
721 trailer_msg = "Please run 'showlldbtypesummaries enable' to enable the summary feature."
722 else:
723 config['showTypeSummary'] = True
724 SetupLLDBTypeSummaries(True)
725 trailer_msg = "Please run 'showlldbtypesummaries disable' to disable the summary feature."
726 lldb_run_command("type category "+ action +" kernel")
727 print "Successfully "+action+"d the kernel type summaries. %s" % trailer_msg
728
fe8ab488
A
729@lldb_command('walkqueue_head', 'S')
730def WalkQueueHead(cmd_args=[], cmd_options={}):
731 """ walk a queue_head_t and list all members in it. Note this is for queue_head_t. refer to osfmk/kern/queue.h
732 Option: -S - suppress summary output.
733 Usage: (lldb) walkqueue_head <queue_entry *> <struct type> <fieldname>
734 ex: (lldb) walkqueue_head 0x7fffff80 "thread *" "task_threads"
735
736 """
737 global lldb_summary_definitions
738 if not cmd_args:
739 raise ArgumentError("invalid arguments")
740 if len(cmd_args) != 3:
741 raise ArgumentError("insufficient arguments")
742 queue_head = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *')
743 el_type = cmd_args[1]
744 field_name = cmd_args[2]
745 showsummary = False
746 if el_type in lldb_summary_definitions:
747 showsummary = True
748 if '-S' in cmd_options:
749 showsummary = False
750
751 for i in IterateQueue(queue_head, el_type, field_name):
752 if showsummary:
753 print lldb_summary_definitions[el_type](i)
754 else:
755 print "{0: <#020x}".format(i)
756
757
758
759@lldb_command('walklist_entry', 'S')
760def WalkList(cmd_args=[], cmd_options={}):
761 """ iterate over a list as defined with LIST_ENTRY in bsd/sys/queue.h
762 params:
763 object addr - value : address of object
764 element_type - str : Type of the next element
765 field_name - str : Name of the field in next element's structure
766
767 Option: -S - suppress summary output.
768 Usage: (lldb) walklist_entry <obj with list_entry *> <struct type> <fieldname>
769 ex: (lldb) walklist_entry 0x7fffff80 "struct proc *" "p_sibling"
770
771 """
772 global lldb_summary_definitions
773 if not cmd_args:
774 raise ArgumentError("invalid arguments")
775 if len(cmd_args) != 3:
776 raise ArgumentError("insufficient arguments")
777 el_type = cmd_args[1]
778 queue_head = kern.GetValueFromAddress(cmd_args[0], el_type)
779 field_name = cmd_args[2]
780
781 showsummary = False
782 if el_type in lldb_summary_definitions:
783 showsummary = True
784 if '-S' in cmd_options:
785 showsummary = False
786 elt = queue_head
787 while unsigned(elt) != 0:
788 i = elt
789 elt = elt.__getattr__(field_name).le_next
790 if showsummary:
791 print lldb_summary_definitions[el_type](i)
792 else:
793 print "{0: <#020x}".format(i)
794
795
796
39236c6e
A
797from memory import *
798from process import *
799from ipc import *
800from pmap import *
801from ioreg import *
802from mbufs import *
803from net import *
804from kdp import *
805from userspace import *
806from pci import *
807from misc import *
808from apic import *
809from scheduler import *
fe8ab488
A
810from atm import *
811from structanalyze import *
812from ipcimportancedetail import *
813from bank import *
5ba3f43e 814from kasan import *
3e170ce0
A
815from kauth import *
816from waitq import *
817from usertaskgdbserver import *
39037602
A
818from ktrace import *
819from pgtrace import *
820from xnutriage import *
5ba3f43e
A
821from kevent import *
822from ntstat import *
823