1import sys, subprocess, os, re, time, getopt, shlex
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
15MODULE_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
27def 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
33def 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.
41lldb_summary_definitions = {}
42def 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.
74lldb_command_documentation = {}
75
76def 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 ************
119There has been an uncaught exception. A possible cause could be that remote connection has been disconnected.
120However, 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
159def 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
170def 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
186def 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
204def 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
224lldb_command_tests = {}
225def 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
246def 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
266kern = None
267
268def 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
292def GetThreadBackTrace(thread_obj, verbosity = vHUMAN, prefix = ""):
293    """ Get a string to display back trace for a thread.
294        params:
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?
299        returns:
300            str - a multi line string showing each frame in backtrace.
301    """
302    is_continuation = not bool(unsigned(thread_obj.kernel_stack))
303    thread_val = GetLLDBThreadForKernelThread(thread_obj)
304    out_string = ""
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)
311    else:
312        out_string += prefix + "continuation ="
313    iteration = 0
314    last_frame_p = 0
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()
321
322        if iteration == 0 and not is_continuation:
323            out_string += prefix +"stacktop = {:#018x}\n".format(frame_p)
324
325        if not function:
326            # No debug info for 'function'.
327            out_string += prefix
328            if not is_continuation:
329                out_string += "{fp:#018x} ".format(fp = frame_p)
330
331            symbol = frame.GetSymbol()
332            if not symbol:
333                symbol_name = "None"
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)
341                        break
342                out_string += "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset)
343            else:
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)
350        else:
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))
358                continue
359            out_string += prefix
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,
363                                    func=func_name,
364                                    file=file_name, line=line_num,
365                                    args="(" + (str(frame.arguments).replace("\n", ", ") if len(frame.arguments) > 0 else "void") + ")")
366        iteration += 1
367        if frame_p:
368            last_frame_p = frame_p
369
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","")
373    return out_string
374
375def 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"
379    """
380    symbols = kern.SymbolicateFromAddress(addr)
381    format_string = "{0:#018x} <{1:s} + {2:#0x}>"
382    offset = 0
383    function_name = ""
384    if len(symbols) > 0:
385        s = symbols[0]
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)
391
392def GetFrameLocalVariable(variable_name, frame_no=0):
393    """ Find a local variable by name
394        params:
395          variable_name: str - name of variable to search for
396        returns:
397          core.value - if the variable is found.
398          None   - if not found or not Valid
399    """
400    retval = None
401    sbval = None
402    lldb_SBThread = LazyTarget.GetProcess().GetSelectedThread()
403    frame = lldb_SBThread.GetSelectedFrame()
404    if frame_no :
405      frame = lldb_SBThread.GetFrameAtIndex(frame_no)
406    if frame :
407      sbval = frame.FindVariable(variable_name)
408    if sbval and sbval.IsValid():
409      retval = core.cvalue.value(sbval)
410    return retval
411
412# Begin Macros for kernel debugging
413
414@lldb_command('kgmhelp')
415def KernelDebugCommandsHelp(cmd_args=None):
416    """ Show a list of registered commands for kenel debugging.
417    """
418    global lldb_command_documentation
419    print "List of commands provided by " + MODULE_NAME + " for kernel debugging."
420    cmds = lldb_command_documentation.keys()
421    cmds.sort()
422    for cmd in cmds:
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())
425        else:
426            print " {0: <20s} - {1}".format(cmd , "No help string found.")
427    print """
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.
436
437    Additionally, each command implementation may have more options. "(lldb) help <command> " will show these options.
438    """
439    return None
440
441
442@lldb_command('showraw')
443def 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
446    """
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' )
451
452
453@lldb_command('xnudebug')
454def XnuDebugCommand(cmd_args=None):
455    """  command interface for operating on the xnu macros. Allowed commands are as follows
456        reload:
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)
459        test:
460            Start running registered test with <name> from various modules.
461            usage: xnudebug test <name> (eg. test_memstats)
462        testall:
463            Go through all registered tests and run them
464        debug:
465            Toggle state of debug configuration flag.
466    """
467    global config
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)
473
474    if len(subcommand) == 0:
475        raise ArgumentError("Subcommand (%s) is not a valid command. " % str(command_args[0]))
476
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. "
486
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__
492        else:
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)
498            if res:
499                print "[PASSED] {:s}".format(test_name)
500            else:
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])
509            else:
510                print "[FAILED] {:s}".format(test[0])
511            return ""
512        else:
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():
516                print i
517        return None
518
519    return False
520
521@lldb_command('showversion')
522def 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
529        correctly.
530
531    """
532    print kern.version
533
534
535@lldb_command('paniclog')
536def ShowPanicLog(cmd_args=None):
537    """ Display the paniclog information
538        usage: (lldb) paniclog
539        options:
540            -v : increase verbosity
541    """
542    panic_buf = kern.globals.debug_buf_addr
543    panic_buf_start = unsigned(panic_buf)
544    panic_buf_end = unsigned(kern.globals.debug_buf_ptr)
545    num_bytes = panic_buf_end - panic_buf_start
546    if num_bytes == 0 :
547        return
548    warn_str = ""
549    if num_bytes > 4096 and config['verbosity'] == vHUMAN:
550        num_bytes = 4096
551        warn_str = "LLDBMacro Warning: The paniclog is too large. Trimming to 4096 bytes."
552        warn_str += " If you wish to see entire log please use '-v' argument."
553    out_str = ""
554    for i in range(num_bytes):
555        p_char = str(panic_buf[i])
556        out_str += p_char
557        if p_char == '\n':
558            print out_str
559            out_str = ""
560    if warn_str:
561        print warn_str
562    return
563
564@lldb_command('showbootargs')
565def ShowBootArgs(cmd_args=None):
566    """ Display boot arguments passed to the target kernel
567    """
568    bootargs = Cast(kern.GetGlobalVariable('PE_state').bootArgs, 'boot_args *')
569    bootargs_cmd = bootargs.CommandLine
570    print str(bootargs_cmd)
571
572@static_var("last_process_uniq_id", 1)
573def GetDebuggerStopIDValue():
574    """ Create a unique session identifier.
575        returns:
576            int - a unique number identified by processid and stopid.
577    """
578    stop_id = 0
579    process_obj = LazyTarget.GetProcess()
580    if hasattr(process_obj, "GetStopID"):
581        stop_id = process_obj.GetStopID()
582    proc_uniq_id = 0
583    if hasattr(process_obj, 'GetUniqueID'):
584        proc_uniq_id = process_obj.GetUniqueID()
585        #FIXME <rdar://problem/13034329> forces us to do this twice
586        proc_uniq_id = process_obj.GetUniqueID()
587    else:
588        GetDebuggerStopIDValue.last_process_uniq_id +=1
589        proc_uniq_id = GetDebuggerStopIDValue.last_process_uniq_id + 1
590
591    stop_id_str = "{:d}:{:d}".format(proc_uniq_id, stop_id)
592    return hash(stop_id_str)
593
594# The initialization code to add your commands
595_xnu_framework_init = False
596def __lldb_init_module(debugger, internal_dict):
597    global kern, lldb_command_documentation, config, _xnu_framework_init
598    if _xnu_framework_init:
599        return
600    _xnu_framework_init = True
601    caching._GetDebuggerSessionID = GetDebuggerStopIDValue
602    debugger.HandleCommand('type summary add --regex --summary-string "${var%s}" -C yes -p -v "char \[[0-9]*\]"')
603    debugger.HandleCommand('type format add --format hex -C yes uintptr_t')
604    kern = KernelTarget(debugger)
605    print "xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries."
606
607__lldb_init_module(lldb.debugger, None)
608
609@lldb_command("showlldbtypesummaries")
610def ShowLLDBTypeSummaries(cmd_args=[]):
611    """ Enable/Disable kernel type summaries. Default is disabled.
612        Usage: showlldbtypesummaries [enable|disable]
613        default is enable
614    """
615    global config
616    action = "enable"
617    trailer_msg = ''
618    if len(cmd_args) > 0 and cmd_args[0].lower().find('disable') >=0:
619        action = "disable"
620        config['showTypeSummary'] = False
621        trailer_msg = "Please run 'showlldbtypesummaries enable' to enable the summary feature."
622    else:
623        config['showTypeSummary'] = True
624        SetupLLDBTypeSummaries(True)
625        trailer_msg = "Please run 'showlldbtypesummaries disable' to disable the summary feature."
626    lldb_run_command("type category "+ action +" kernel")
627    print "Successfully "+action+"d the kernel type summaries. %s" % trailer_msg
628
629@lldb_command('walkqueue_head', 'S')
630def WalkQueueHead(cmd_args=[], cmd_options={}):
631    """ walk a queue_head_t and list all members in it. Note this is for queue_head_t. refer to osfmk/kern/queue.h
632        Option: -S - suppress summary output.
633        Usage: (lldb) walkqueue_head  <queue_entry *> <struct type> <fieldname>
634        ex:    (lldb) walkqueue_head  0x7fffff80 "thread *" "task_threads"
635
636    """
637    global lldb_summary_definitions
638    if not cmd_args:
639        raise ArgumentError("invalid arguments")
640    if len(cmd_args) != 3:
641        raise ArgumentError("insufficient arguments")
642    queue_head = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *')
643    el_type = cmd_args[1]
644    field_name = cmd_args[2]
645    showsummary = False
646    if el_type in lldb_summary_definitions:
647        showsummary = True
648    if '-S' in cmd_options:
649        showsummary = False
650
651    for i in IterateQueue(queue_head, el_type, field_name):
652        if showsummary:
653            print lldb_summary_definitions[el_type](i)
654        else:
655            print "{0: <#020x}".format(i)
656
657
658
659@lldb_command('walklist_entry', 'S')
660def WalkList(cmd_args=[], cmd_options={}):
661    """ iterate over a list as defined with LIST_ENTRY in bsd/sys/queue.h
662        params:
663            object addr  - value : address of object
664            element_type - str   : Type of the next element
665            field_name   - str   : Name of the field in next element's structure
666
667        Option: -S - suppress summary output.
668        Usage: (lldb) walklist_entry  <obj with list_entry *> <struct type> <fieldname>
669        ex:    (lldb) walklist_entry  0x7fffff80 "struct proc *" "p_sibling"
670
671    """
672    global lldb_summary_definitions
673    if not cmd_args:
674        raise ArgumentError("invalid arguments")
675    if len(cmd_args) != 3:
676        raise ArgumentError("insufficient arguments")
677    el_type = cmd_args[1]
678    queue_head = kern.GetValueFromAddress(cmd_args[0], el_type)
679    field_name = cmd_args[2]
680
681    showsummary = False
682    if el_type in lldb_summary_definitions:
683        showsummary = True
684    if '-S' in cmd_options:
685        showsummary = False
686    elt = queue_head
687    while unsigned(elt) != 0:
688        i = elt
689        elt = elt.__getattr__(field_name).le_next
690        if showsummary:
691            print lldb_summary_definitions[el_type](i)
692        else:
693            print "{0: <#020x}".format(i)
694
695
696
697from memory import *
698from process import *
699from ipc import *
700from pmap import *
701from ioreg import *
702from mbufs import *
703from net import *
704from kdp import *
705from userspace import *
706from pci import *
707from misc import *
708from apic import *
709from scheduler import *
710from atm import *
711from structanalyze import *
712from ipcimportancedetail import *
713from bank import *
714
715