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