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}".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            symbol = frame.GetSymbol()
328            file_addr = addr.GetFileAddress()
329            start_addr = symbol.GetStartAddress().GetFileAddress()
330            symbol_name = symbol.GetName()
331            symbol_offset = file_addr - start_addr
332            out_string += prefix
333            if not is_continuation:
334                out_string += "{fp:#018x} ".format(fp = frame_p)
335            out_string += "{addr:#018x} {mod}`{symbol} + {offset} \n".format(addr=load_addr, mod=mod_name, symbol=symbol_name, offset=symbol_offset)
336        else:
337            # Debug info is available for 'function'.
338            func_name = frame.GetFunctionName()
339            file_name = frame.GetLineEntry().GetFileSpec().GetFilename()
340            line_num = frame.GetLineEntry().GetLine()
341            func_name = '%s [inlined]' % func_name if frame.IsInlined() else func_name
342            if is_continuation and frame.IsInlined():
343                debuglog("Skipping frame for thread {:#018x} since its inlined".format(thread_obj))
344                continue
345            out_string += prefix
346            if not is_continuation:
347                out_string += "{fp:#018x} ".format(fp=frame_p)
348            out_string += "{addr:#018x} {func}{args} \n".format(addr=load_addr,
349                                    func=func_name,
350                                    file=file_name, line=line_num,
351                                    args="(" + (str(frame.arguments).replace("\n", ", ") if len(frame.arguments) > 0 else "void") + ")")
352        iteration += 1
353        if frame_p:
354            last_frame_p = frame_p
355
356    if not is_continuation and last_frame_p:
357        out_string += prefix + "stackbottom = {:#018x}".format(last_frame_p)
358    out_string = out_string.replace("variable not available","")
359    return out_string
360
361def GetSourceInformationForAddress(addr):
362    """ convert and address to function +offset information.
363        params: addr - int address in the binary to be symbolicated
364        returns: string of format "0xaddress: function + offset"
365    """
366    symbols = kern.SymbolicateFromAddress(addr)
367    format_string = "{0:#018x} <{1:s} + {2:#0x}>"
368    offset = 0
369    function_name = ""
370    if len(symbols) > 0:
371        s = symbols[0]
372        function_name = str(s.name)
373        offset = addr - s.GetStartAddress().GetLoadAddress(LazyTarget.GetTarget())
374    if function_name == "":
375        function_name = "???"
376    return format_string.format(addr, function_name, offset)
377
378def GetFrameLocalVariable(variable_name, frame_no=0):
379    """ Find a local variable by name
380        params:
381          variable_name: str - name of variable to search for
382        returns:
383          core.value - if the variable is found.
384          None   - if not found or not Valid
385    """
386    retval = None
387    sbval = None
388    lldb_SBThread = LazyTarget.GetProcess().GetSelectedThread()
389    frame = lldb_SBThread.GetSelectedFrame()
390    if frame_no :
391      frame = lldb_SBThread.GetFrameAtIndex(frame_no)
392    if frame :
393      sbval = frame.FindVariable(variable_name)
394    if sbval and sbval.IsValid():
395      retval = core.cvalue.value(sbval)
396    return retval
397
398# Begin Macros for kernel debugging
399
400@lldb_command('kgmhelp')
401def KernelDebugCommandsHelp(cmd_args=None):
402    """ Show a list of registered commands for kenel debugging.
403    """
404    global lldb_command_documentation
405    print "List of commands provided by " + MODULE_NAME + " for kernel debugging."
406    cmds = lldb_command_documentation.keys()
407    cmds.sort()
408    for cmd in cmds:
409        if type(lldb_command_documentation[cmd][-1]) == type(""):
410            print " {0: <20s} - {1}".format(cmd , lldb_command_documentation[cmd][1].split("\n")[0].strip())
411        else:
412            print " {0: <20s} - {1}".format(cmd , "No help string found.")
413    print """
414    Each of the functions listed here accept the following common options.
415        -h  Show the help string for the command.
416        -o <path/to/filename>   The output of this command execution will be saved to file. Parser information or errors will
417                                not be sent to file though. eg /tmp/output.txt
418        -s <filter_string>      The "filter_string" param is parsed to python regex expression and each line of output
419                                will be printed/saved only if it matches the expression.
420        -v [-v...]  Each additional -v will increase the verbosity of the command.
421        -p <plugin_name>        Send the output of the command to plugin. Please see README for usage of plugins.
422
423    Additionally, each command implementation may have more options. "(lldb) help <command> " will show these options.
424    """
425    return None
426
427
428@lldb_command('showraw')
429def ShowRawCommand(cmd_args=None):
430    """ A command to disable the kernel summaries and show data as seen by the system.
431        This is useful when trying to read every field of a struct as compared to brief summary
432    """
433    command = " ".join(cmd_args)
434    lldb.debugger.HandleCommand('type category disable kernel' )
435    lldb.debugger.HandleCommand( command )
436    lldb.debugger.HandleCommand('type category enable kernel' )
437
438
439@lldb_command('xnudebug')
440def XnuDebugCommand(cmd_args=None):
441    """  command interface for operating on the xnu macros. Allowed commands are as follows
442        reload:
443            Reload a submodule from the xnu/tools/lldb directory. Do not include the ".py" suffix in modulename.
444            usage: xnudebug reload <modulename> (eg. memory, process, stats etc)
445        test:
446            Start running registered test with <name> from various modules.
447            usage: xnudebug test <name> (eg. test_memstats)
448        testall:
449            Go through all registered tests and run them
450        debug:
451            Toggle state of debug configuration flag.
452    """
453    global config
454    command_args = cmd_args
455    if len(command_args) == 0:
456        raise ArgumentError("No command specified.")
457    supported_subcommands = ['debug', 'reload', 'test', 'testall']
458    subcommand = GetLongestMatchOption(command_args[0], supported_subcommands, True)
459
460    if len(subcommand) == 0:
461        raise ArgumentError("Subcommand (%s) is not a valid command. " % str(command_args[0]))
462
463    subcommand = subcommand[0].lower()
464    if subcommand == 'debug':
465        if command_args[-1].lower().find('dis') >=0 and config['debug']:
466            config['debug'] = False
467            print "Disabled debug logging."
468        elif command_args[-1].lower().find('dis') < 0 and not config['debug']:
469            config['debug'] = True
470            EnableLLDBAPILogging()  # provided by utils.py
471            print "Enabled debug logging. \nPlease run 'xnudebug debug disable' to disable it again. "
472
473    if subcommand == 'reload':
474        module_name = command_args[-1]
475        if module_name in sys.modules:
476            reload(sys.modules[module_name])
477            print module_name + " is reloaded from " + sys.modules[module_name].__file__
478        else:
479            print "Unable to locate module named ", module_name
480    if subcommand == 'testall':
481        for test_name in lldb_command_tests.keys():
482            print "[BEGIN]", test_name
483            res = lldb_command_tests[test_name][2](kern, config, lldb, True)
484            if res:
485                print "[PASSED] {:s}".format(test_name)
486            else:
487                print "[FAILED] {:s}".format(test_name)
488    if subcommand == 'test':
489        test_name = command_args[-1]
490        if test_name in lldb_command_tests:
491            test = lldb_command_tests[test_name]
492            print "Running test {:s}".format(test[0])
493            if test[2](kern, config, lldb, True) :
494                print "[PASSED] {:s}".format(test[0])
495            else:
496                print "[FAILED] {:s}".format(test[0])
497            return ""
498        else:
499            print "No such test registered with name: {:s}".format(test_name)
500            print "XNUDEBUG Available tests are:"
501            for i in lldb_command_tests.keys():
502                print i
503        return None
504
505    return False
506
507@lldb_command('showversion')
508def ShowVersion(cmd_args=None):
509    """ Read the kernel version string from a fixed address in low
510        memory. Useful if you don't know which kernel is on the other end,
511        and need to find the appropriate symbols. Beware that if you've
512        loaded a symbol file, but aren't connected to a remote target,
513        the version string from the symbol file will be displayed instead.
514        This macro expects to be connected to the remote kernel to function
515        correctly.
516
517    """
518    print kern.version
519
520
521@lldb_command('paniclog')
522def ShowPanicLog(cmd_args=None):
523    """ Display the paniclog information
524    """
525    panic_buf = kern.globals.debug_buf
526    panic_buf_start = addressof(panic_buf)
527    panic_buf_end = unsigned(kern.globals.debug_buf_ptr)
528    num_bytes = panic_buf_end - panic_buf_start
529    if num_bytes == 0 :
530        return
531    panic_data = panic_buf.GetSBValue().GetData()
532    err = lldb.SBError()
533    line = ''
534    for i in range(0, num_bytes):
535        c = panic_data.GetUnsignedInt8(err, i)
536        if chr(c) == '\n':
537            if line =='':
538                line = " "
539            print line
540            line = ''
541        else:
542            line += chr(c)
543
544    if len(line) > 0:
545        print line
546
547    return
548
549@lldb_command('showbootargs')
550def ShowBootArgs(cmd_args=None):
551    """ Display boot arguments passed to the target kernel
552    """
553    bootargs = Cast(kern.GetGlobalVariable('PE_state').bootArgs, 'boot_args *')
554    bootargs_cmd = bootargs.CommandLine
555    print str(bootargs_cmd)
556
557@static_var("last_process_uniq_id", 1)
558def GetDebuggerStopIDValue():
559    """ Create a unique session identifier.
560        returns:
561            int - a unique number identified by processid and stopid.
562    """
563    stop_id = 0
564    process_obj = LazyTarget.GetProcess()
565    if hasattr(process_obj, "GetStopID"):
566        stop_id = process_obj.GetStopID()
567    proc_uniq_id = 0
568    if hasattr(process_obj, 'GetUniqueID'):
569        proc_uniq_id = process_obj.GetUniqueID()
570        #FIXME <rdar://problem/13034329> forces us to do this twice
571        proc_uniq_id = process_obj.GetUniqueID()
572    else:
573        GetDebuggerStopIDValue.last_process_uniq_id +=1
574        proc_uniq_id = GetDebuggerStopIDValue.last_process_uniq_id + 1
575
576    stop_id_str = "{:d}:{:d}".format(proc_uniq_id, stop_id)
577    return hash(stop_id_str)
578
579# The initialization code to add your commands
580_xnu_framework_init = False
581def __lldb_init_module(debugger, internal_dict):
582    global kern, lldb_command_documentation, config, _xnu_framework_init
583    if _xnu_framework_init:
584        return
585    _xnu_framework_init = True
586    caching._GetDebuggerSessionID = GetDebuggerStopIDValue
587    debugger.HandleCommand('type summary add --regex --summary-string "${var%s}" -C yes -p -v "char \[[0-9]*\]"')
588    debugger.HandleCommand('type format add --format hex -C yes uintptr_t')
589    kern = KernelTarget(debugger)
590    print "xnu debug macros loaded successfully. Run showlldbtypesummaries to enable type summaries."
591
592__lldb_init_module(lldb.debugger, None)
593
594@lldb_command("showlldbtypesummaries")
595def ShowLLDBTypeSummaries(cmd_args=[]):
596    """ Enable/Disable kernel type summaries. Default is disabled.
597        Usage: showlldbtypesummaries [enable|disable]
598        default is enable
599    """
600    global config
601    action = "enable"
602    trailer_msg = ''
603    if len(cmd_args) > 0 and cmd_args[0].lower().find('disable') >=0:
604        action = "disable"
605        config['showTypeSummary'] = False
606        trailer_msg = "Please run 'showlldbtypesummaries enable' to enable the summary feature."
607    else:
608        config['showTypeSummary'] = True
609        SetupLLDBTypeSummaries(True)
610        trailer_msg = "Please run 'showlldbtypesummaries disable' to disable the summary feature."
611    lldb_run_command("type category "+ action +" kernel")
612    print "Successfully "+action+"d the kernel type summaries. %s" % trailer_msg
613
614from memory import *
615from process import *
616from ipc import *
617from pmap import *
618from ioreg import *
619from mbufs import *
620from net import *
621from kdp import *
622from userspace import *
623from pci import *
624from misc import *
625from apic import *
626from scheduler import *
627