1 import sys
, subprocess
, os
, re
, time
, getopt
, shlex
3 from functools
import wraps
4 from ctypes
import c_ulonglong
as uint64_t
5 from ctypes
import c_void_p
as voidptr_t
8 from core
import caching
9 from core
.standard
import *
10 from core
.configuration
import *
11 from core
.kernelcore
import *
13 from core
.lazytarget
import *
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.
22 # End Utility functions
23 # Debugging specific utility functions
25 #decorators. Not to be called directly.
27 def static_var(var_name
, initial_value
):
29 setattr(obj
, var_name
, initial_value
)
33 def header(initial_value
):
35 setattr(obj
, 'header', initial_value
)
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.
47 def _get_summary(obj
):
48 def _internal_summary_function(lldbval
, internal_dict
):
50 if internal_dict
!= None and len(obj
.header
) > 0 :
51 out_string
+= "\n" + obj
.header
+"\n"
52 out_string
+= obj( core
.value(lldbval
) )
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
__
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
72 #global cache of documentation for lldb commands exported by this module
73 #DONOTTOUCHME: Exclusive use of lldb_command only.
74 lldb_command_documentation
= {}
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.
82 if option_string
!= option_string
.upper():
83 raise RuntimeError("Cannot setup command with lowercase option args. %s" % option_string
)
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
)
93 result
.SetImmediateOutputFile(sys
.__stdout
__)
95 command_args
= shlex
.split(command
)
96 lldb
.debugger
.HandleCommand('type category disable kernel' )
97 def_verbose_level
= config
['verbosity']
100 stream
.setOptions(command_args
, option_string
)
101 if stream
.verbose_level
!= 0:
102 config
['verbosity'] += stream
.verbose_level
103 with RedirectStdStreams(stdout
=stream
) :
105 obj(cmd_args
=stream
.target_cmd_args
, cmd_options
=stream
.target_cmd_options
)
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())
115 except Exception as exc
:
116 if not config
['debug']:
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. ************
125 if config
['showTypeSummary']:
126 lldb
.debugger
.HandleCommand('type category enable kernel' )
128 if stream
.pluginRequired
:
129 plugin
= LoadXNUPlugin(stream
.pluginName
)
131 print "Could not load plugins."+stream
.pluginName
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()
138 #restore the verbose level after command is complete
139 config
['verbosity'] = def_verbose_level
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
]
148 print "ERROR: Cannot register command({:s}) without documentation".format(cmd_name
)
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
)
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"
164 lldb_alias('readphys16', 'readphys 16')
166 alias_name
= alias_name
.strip()
167 cmd_line
= cmd_line
.strip()
168 lldb
.debugger
.HandleCommand("command alias " + alias_name
+ " "+ cmd_line
)
170 def SetupLLDBTypeSummaries(reset
=False):
171 global lldb_summary_definitions
, MODULE_NAME
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
__
178 lldb
.debugger
.HandleCommand(lldb_cmd
)
179 if config
['showTypeSummary']:
180 lldb
.debugger
.HandleCommand("type category enable kernel")
182 lldb
.debugger
.HandleCommand("type category disable kernel")
186 def LoadXNUPlugin(name
):
187 """ Try to load a plugin from the plugins directory.
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
:
198 print "Plugin is not correctly implemented. Please read documentation on implementing plugins"
200 print "plugin not found :"+name
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)
208 ret_status
= result_data
[0]
209 ret_string
= result_data
[1]
210 ret_commands
= result_data
[2]
212 if ret_status
== False:
213 print "Plugin failed: " + 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
)
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 )
229 NOTE: The testname should start with "Test" else exception will be raised.
232 global lldb_command_tests
233 if obj
.__name
__.find("Test") != 0 :
234 print "Test name ", obj
.__name
__ , " should start with Test"
236 lldb_command_tests
[test_name
] = (test_name
, obj
.__name
__, obj
, obj
.__doc
__)
241 # End Debugging specific utility functions
242 # Kernel Debugging specific classes and accessor methods
244 # global access object for target kernel
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
251 GetObjectAtIndexFromArray(arr_val,2)
253 array_base : core.value - representing a pointer type (ex. base of type 'ipc_entry *')
254 index : int - 0 based index into the array
256 core.value : core.value of the same type as array_base_val but pointing to index'th element
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())
268 def GetLLDBThreadForKernelThread(thread_obj
):
269 """ Get a reference to lldb.SBThread representation for kernel thread.
271 thread_obj : core.cvalue - thread object of type thread_t
273 lldb.SBThread - lldb thread object for getting backtrace/registers etc.
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
))
284 raise RuntimeError("LLDB process does not support CreateOSPluginThread.")
285 sbthread
= lldb_process
.GetThreadByID(tid
)
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
))
292 def GetThreadBackTrace(thread_obj
, verbosity
= vHUMAN
, prefix
= ""):
293 """ Get a string to display back trace for a thread.
295 thread_obj - core.cvalue : a thread object of type thread_t.
296 verbosity - int : either of vHUMAN, vSCRIPT or vDETAIL to describe the verbosity of output
297 prefix - str : a string prefix added before the line for each frame.
298 isContinuation - bool : is thread a continuation?
300 str - a multi line string showing each frame in backtrace.
302 is_continuation
= not bool(unsigned(thread_obj
.kernel_stack
))
303 thread_val
= GetLLDBThreadForKernelThread(thread_obj
)
305 kernel_stack
= unsigned(thread_obj
.kernel_stack
)
306 reserved_stack
= unsigned(thread_obj
.reserved_stack
)
307 if not is_continuation
:
308 if kernel_stack
and reserved_stack
:
309 out_string
+= prefix
+ "reserved_stack = {:#018x}\n".format(reserved_stack
)
310 out_string
+= prefix
+ "kernel_stack = {:#018x}\n".format(kernel_stack
)
312 out_string
+= prefix
+ "continuation ="
315 for frame
in thread_val
.frames
:
316 addr
= frame
.GetPCAddress()
317 load_addr
= addr
.GetLoadAddress(LazyTarget
.GetTarget())
318 function
= frame
.GetFunction()
319 frame_p
= frame
.GetFP()
320 mod_name
= frame
.GetModule().GetFileSpec().GetFilename()
322 if iteration
== 0 and not is_continuation
:
323 out_string
+= prefix
+"stacktop = {:#018x}\n".format(frame_p
)
326 # No debug info for 'function'.
328 if not is_continuation
:
329 out_string
+= "{fp:#018x} ".format(fp
= frame_p
)
331 symbol
= frame
.GetSymbol()
334 symbol_offset
= load_addr
335 kmod_val
= kern
.globals.kmod
336 for kval
in IterateLinkedList(kmod_val
, 'next'):
337 if load_addr
>= unsigned(kval
.address
) and \
338 load_addr
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
339 symbol_name
= kval
.name
340 symbol_offset
= load_addr
- unsigned(kval
.address
)
342 out_string
+= "{:#018x} {:s} + {:#x} \n".format(load_addr
, symbol_name
, symbol_offset
)
344 file_addr
= addr
.GetFileAddress()
345 start_addr
= symbol
.GetStartAddress().GetFileAddress()
346 symbol_name
= symbol
.GetName()
347 symbol_offset
= file_addr
- start_addr
348 out_string
+= "{addr:#018x} {mod}`{symbol} + {offset:#x} \n".format(addr
=load_addr
,
349 mod
=mod_name
, symbol
=symbol_name
, offset
=symbol_offset
)
351 # Debug info is available for 'function'.
352 func_name
= frame
.GetFunctionName()
353 file_name
= frame
.GetLineEntry().GetFileSpec().GetFilename()
354 line_num
= frame
.GetLineEntry().GetLine()
355 func_name
= '%s [inlined]' % func_name
if frame
.IsInlined() else func_name
356 if is_continuation
and frame
.IsInlined():
357 debuglog("Skipping frame for thread {:#018x} since its inlined".format(thread_obj
))
360 if not is_continuation
:
361 out_string
+= "{fp:#018x} ".format(fp
=frame_p
)
362 out_string
+= "{addr:#018x} {func}{args} \n".format(addr
=load_addr
,
364 file=file_name
, line
=line_num
,
365 args
="(" + (str(frame
.arguments
).replace("\n", ", ") if len(frame
.arguments
) > 0 else "void") + ")")
368 last_frame_p
= frame_p
370 if not is_continuation
and last_frame_p
:
371 out_string
+= prefix
+ "stackbottom = {:#018x}".format(last_frame_p
)
372 out_string
= out_string
.replace("variable not available","")
375 def GetSourceInformationForAddress(addr
):
376 """ convert and address to function +offset information.
377 params: addr - int address in the binary to be symbolicated
378 returns: string of format "0xaddress: function + offset"
380 symbols
= kern
.SymbolicateFromAddress(addr
)
381 format_string
= "{0:#018x} <{1:s} + {2:#0x}>"
386 function_name
= str(s
.name
)
387 offset
= addr
- s
.GetStartAddress().GetLoadAddress(LazyTarget
.GetTarget())
388 if function_name
== "":
389 function_name
= "???"
390 return format_string
.format(addr
, function_name
, offset
)
392 def GetFrameLocalVariable(variable_name
, frame_no
=0):
393 """ Find a local variable by name
395 variable_name: str - name of variable to search for
397 core.value - if the variable is found.
398 None - if not found or not Valid
402 lldb_SBThread
= LazyTarget
.GetProcess().GetSelectedThread()
403 frame
= lldb_SBThread
.GetSelectedFrame()
405 frame
= lldb_SBThread
.GetFrameAtIndex(frame_no
)
407 sbval
= frame
.FindVariable(variable_name
)
408 if sbval
and sbval
.IsValid():
409 retval
= core
.cvalue
.value(sbval
)
412 # Begin Macros for kernel debugging
414 @lldb_command('kgmhelp')
415 def KernelDebugCommandsHelp(cmd_args
=None):
416 """ Show a list of registered commands for kenel debugging.
418 global lldb_command_documentation
419 print "List of commands provided by " + MODULE_NAME
+ " for kernel debugging."
420 cmds
= lldb_command_documentation
.keys()
423 if type(lldb_command_documentation
[cmd
][-1]) == type(""):
424 print " {0: <20s} - {1}".format(cmd
, lldb_command_documentation
[cmd
][1].split("\n")[0].strip())
426 print " {0: <20s} - {1}".format(cmd
, "No help string found.")
428 Each of the functions listed here accept the following common options.
429 -h Show the help string for the command.
430 -o <path/to/filename> The output of this command execution will be saved to file. Parser information or errors will
431 not be sent to file though. eg /tmp/output.txt
432 -s <filter_string> The "filter_string" param is parsed to python regex expression and each line of output
433 will be printed/saved only if it matches the expression.
434 -v [-v...] Each additional -v will increase the verbosity of the command.
435 -p <plugin_name> Send the output of the command to plugin. Please see README for usage of plugins.
437 Additionally, each command implementation may have more options. "(lldb) help <command> " will show these options.
442 @lldb_command('showraw')
443 def ShowRawCommand(cmd_args
=None):
444 """ A command to disable the kernel summaries and show data as seen by the system.
445 This is useful when trying to read every field of a struct as compared to brief summary
447 command
= " ".join(cmd_args
)
448 lldb
.debugger
.HandleCommand('type category disable kernel' )
449 lldb
.debugger
.HandleCommand( command
)
450 lldb
.debugger
.HandleCommand('type category enable kernel' )
453 @lldb_command('xnudebug')
454 def XnuDebugCommand(cmd_args
=None):
455 """ command interface for operating on the xnu macros. Allowed commands are as follows
457 Reload a submodule from the xnu/tools/lldb directory. Do not include the ".py" suffix in modulename.
458 usage: xnudebug reload <modulename> (eg. memory, process, stats etc)
460 Start running registered test with <name> from various modules.
461 usage: xnudebug test <name> (eg. test_memstats)
463 Go through all registered tests and run them
465 Toggle state of debug configuration flag.
468 command_args
= cmd_args
469 if len(command_args
) == 0:
470 raise ArgumentError("No command specified.")
471 supported_subcommands
= ['debug', 'reload', 'test', 'testall']
472 subcommand
= GetLongestMatchOption(command_args
[0], supported_subcommands
, True)
474 if len(subcommand
) == 0:
475 raise ArgumentError("Subcommand (%s) is not a valid command. " % str(command_args
[0]))
477 subcommand
= subcommand
[0].lower()
478 if subcommand
== 'debug':
479 if command_args
[-1].lower().find('dis') >=0 and config
['debug']:
480 config
['debug'] = False
481 print "Disabled debug logging."
482 elif command_args
[-1].lower().find('dis') < 0 and not config
['debug']:
483 config
['debug'] = True
484 EnableLLDBAPILogging() # provided by utils.py
485 print "Enabled debug logging. \nPlease run 'xnudebug debug disable' to disable it again. "
487 if subcommand
== 'reload':
488 module_name
= command_args
[-1]
489 if module_name
in sys
.modules
:
490 reload(sys
.modules
[module_name
])
491 print module_name
+ " is reloaded from " + sys
.modules
[module_name
].__file
__
493 print "Unable to locate module named ", module_name
494 if subcommand
== 'testall':
495 for test_name
in lldb_command_tests
.keys():
496 print "[BEGIN]", test_name
497 res
= lldb_command_tests
[test_name
][2](kern
, config
, lldb
, True)
499 print "[PASSED] {:s}".format(test_name
)
501 print "[FAILED] {:s}".format(test_name
)
502 if subcommand
== 'test':
503 test_name
= command_args
[-1]
504 if test_name
in lldb_command_tests
:
505 test
= lldb_command_tests
[test_name
]
506 print "Running test {:s}".format(test
[0])
507 if test
[2](kern
, config
, lldb
, True) :
508 print "[PASSED] {:s}".format(test
[0])
510 print "[FAILED] {:s}".format(test
[0])
513 print "No such test registered with name: {:s}".format(test_name
)
514 print "XNUDEBUG Available tests are:"
515 for i
in lldb_command_tests
.keys():
521 @lldb_command('showversion')
522 def ShowVersion(cmd_args
=None):
523 """ Read the kernel version string from a fixed address in low
524 memory. Useful if you don't know which kernel is on the other end,
525 and need to find the appropriate symbols. Beware that if you've
526 loaded a symbol file, but aren't connected to a remote target,
527 the version string from the symbol file will be displayed instead.
528 This macro expects to be connected to the remote kernel to function
535 @lldb_command('paniclog', 'S')
536 def ShowPanicLog(cmd_args
=None, cmd_options
={}):
537 """ Display the paniclog information
538 usage: (lldb) paniclog
540 -v : increase verbosity
541 -S : parse stackshot data (if panic stackshot available)
543 binary_data_bytes_to_skip
= 0
544 if hasattr(kern
.globals, "kc_panic_data"):
545 binary_data_bytes_to_skip
= unsigned(kern
.globals.kc_panic_data
.kcd_addr_end
) - unsigned(kern
.globals.kc_panic_data
.kcd_addr_begin
)
546 if binary_data_bytes_to_skip
> 0:
547 binary_data_bytes_to_skip
+= sizeof("struct kcdata_item")
549 binary_data_bytes_to_skip
= 0
551 if "-S" in cmd_options
:
552 if hasattr(kern
.globals, "kc_panic_data"):
553 kc_data
= unsigned(addressof(kern
.globals.kc_panic_data
))
554 ts
= int(time
.time())
555 ss_binfile
= "/tmp/panic_%d.bin" % ts
556 ss_ipsfile
= "/tmp/stacks_%d.ips" % ts
557 print "savekcdata 0x%x -O %s" % (kc_data
, ss_binfile
)
558 SaveKCDataToFile(["0x%x" % kc_data
], {"-O":ss_binfile}
)
559 self_path
= str(__file__
)
560 base_dir_name
= self_path
[:self_path
.rfind("/")]
561 print "python %s/kcdata.py %s -s %s" % (base_dir_name
, ss_binfile
, ss_ipsfile
)
562 (c
,so
,se
) = RunShellCommand("python %s/kcdata.py %s -s %s" % (base_dir_name
, ss_binfile
, ss_ipsfile
))
564 print "Saved ips stackshot file as %s" % ss_ipsfile
566 print "Failed to run command: exit code: %d, SO: %s SE: %s" % (c
, so
, se
)
568 print "kc_panic_data is unavailable for this kernel config."
570 panic_buf
= kern
.globals.debug_buf_addr
571 panic_buf_start
= unsigned(panic_buf
)
572 panic_buf_end
= unsigned(kern
.globals.debug_buf_ptr
)
573 num_bytes
= panic_buf_end
- panic_buf_start
579 in_binary_data_region
= False
581 while pos
< num_bytes
:
582 p_char
= str(panic_buf
[pos
])
585 if not in_binary_data_region
:
588 if (out_str
.find("Data: BEGIN>>") >= 0):
589 in_binary_data_region
= True
590 pos
+= binary_data_bytes_to_skip
- 1
591 if (out_str
.find("<<END") >= 0):
592 in_binary_data_region
= False
594 if num_print_bytes
> 4096 and config
['verbosity'] == vHUMAN
:
595 warn_str
= "LLDBMacro Warning: The paniclog is too large. Trimming to 4096 bytes."
596 warn_str
+= " If you wish to see entire log please use '-v' argument."
605 @lldb_command('showbootargs')
606 def ShowBootArgs(cmd_args
=None):
607 """ Display boot arguments passed to the target kernel
609 bootargs
= Cast(kern
.GetGlobalVariable('PE_state').bootArgs
, 'boot_args *')
610 bootargs_cmd
= bootargs
.CommandLine
611 print str(bootargs_cmd
)
613 @static_var("last_process_uniq_id", 1)
614 def GetDebuggerStopIDValue():
615 """ Create a unique session identifier.
617 int - a unique number identified by processid and stopid.
620 process_obj
= LazyTarget
.GetProcess()
621 if hasattr(process_obj
, "GetStopID"):
622 stop_id
= process_obj
.GetStopID()
624 if hasattr(process_obj
, 'GetUniqueID'):
625 proc_uniq_id
= process_obj
.GetUniqueID()
626 #FIXME <rdar://problem/13034329> forces us to do this twice
627 proc_uniq_id
= process_obj
.GetUniqueID()
629 GetDebuggerStopIDValue
.last_process_uniq_id
+=1
630 proc_uniq_id
= GetDebuggerStopIDValue
.last_process_uniq_id
+ 1
632 stop_id_str
= "{:d}:{:d}".format(proc_uniq_id
, stop_id
)
633 return hash(stop_id_str
)
635 # The initialization code to add your commands
636 _xnu_framework_init
= False
637 def __lldb_init_module(debugger
, internal_dict
):
638 global kern
, lldb_command_documentation
, config
, _xnu_framework_init
639 if _xnu_framework_init
:
641 _xnu_framework_init
= True
642 caching
._GetDebuggerSessionID
= GetDebuggerStopIDValue
643 debugger
.HandleCommand('type summary add --regex --summary-string "${var%s}" -C yes -p -v "char \[[0-9]*\]"')
644 debugger
.HandleCommand('type format add --format hex -C yes uintptr_t')
645 kern
= KernelTarget(debugger
)
646 print "xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries."
648 __lldb_init_module(lldb
.debugger
, None)
650 @lldb_command("showlldbtypesummaries")
651 def ShowLLDBTypeSummaries(cmd_args
=[]):
652 """ Enable/Disable kernel type summaries. Default is disabled.
653 Usage: showlldbtypesummaries [enable|disable]
659 if len(cmd_args
) > 0 and cmd_args
[0].lower().find('disable') >=0:
661 config
['showTypeSummary'] = False
662 trailer_msg
= "Please run 'showlldbtypesummaries enable' to enable the summary feature."
664 config
['showTypeSummary'] = True
665 SetupLLDBTypeSummaries(True)
666 trailer_msg
= "Please run 'showlldbtypesummaries disable' to disable the summary feature."
667 lldb_run_command("type category "+ action
+" kernel")
668 print "Successfully "+action
+"d the kernel type summaries. %s" % trailer_msg
670 @lldb_command('walkqueue_head', 'S')
671 def WalkQueueHead(cmd_args
=[], cmd_options
={}):
672 """ walk a queue_head_t and list all members in it. Note this is for queue_head_t. refer to osfmk/kern/queue.h
673 Option: -S - suppress summary output.
674 Usage: (lldb) walkqueue_head <queue_entry *> <struct type> <fieldname>
675 ex: (lldb) walkqueue_head 0x7fffff80 "thread *" "task_threads"
678 global lldb_summary_definitions
680 raise ArgumentError("invalid arguments")
681 if len(cmd_args
) != 3:
682 raise ArgumentError("insufficient arguments")
683 queue_head
= kern
.GetValueFromAddress(cmd_args
[0], 'struct queue_entry *')
684 el_type
= cmd_args
[1]
685 field_name
= cmd_args
[2]
687 if el_type
in lldb_summary_definitions
:
689 if '-S' in cmd_options
:
692 for i
in IterateQueue(queue_head
, el_type
, field_name
):
694 print lldb_summary_definitions
[el_type
](i
)
696 print "{0: <#020x}".format(i
)
700 @lldb_command('walklist_entry', 'S')
701 def WalkList(cmd_args
=[], cmd_options
={}):
702 """ iterate over a list as defined with LIST_ENTRY in bsd/sys/queue.h
704 object addr - value : address of object
705 element_type - str : Type of the next element
706 field_name - str : Name of the field in next element's structure
708 Option: -S - suppress summary output.
709 Usage: (lldb) walklist_entry <obj with list_entry *> <struct type> <fieldname>
710 ex: (lldb) walklist_entry 0x7fffff80 "struct proc *" "p_sibling"
713 global lldb_summary_definitions
715 raise ArgumentError("invalid arguments")
716 if len(cmd_args
) != 3:
717 raise ArgumentError("insufficient arguments")
718 el_type
= cmd_args
[1]
719 queue_head
= kern
.GetValueFromAddress(cmd_args
[0], el_type
)
720 field_name
= cmd_args
[2]
723 if el_type
in lldb_summary_definitions
:
725 if '-S' in cmd_options
:
728 while unsigned(elt
) != 0:
730 elt
= elt
.__getattr
__(field_name
).le_next
732 print lldb_summary_definitions
[el_type
](i
)
734 print "{0: <#020x}".format(i
)
739 from process
import *
746 from userspace
import *
750 from scheduler
import *
752 from structanalyze
import *
753 from ipcimportancedetail
import *
757 from usertaskgdbserver
import *