X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..813fb2f63a553c957e917ede5f119b021d6ce391:/tools/lldbmacros/xnu.py diff --git a/tools/lldbmacros/xnu.py b/tools/lldbmacros/xnu.py index a3c5b1b5a..b8bcc6bed 100644 --- a/tools/lldbmacros/xnu.py +++ b/tools/lldbmacros/xnu.py @@ -85,7 +85,7 @@ def lldb_command(cmd_name, option_string = ''): def _cmd(obj): def _internal_command_function(debugger, command, result, internal_dict): global config, lldb_run_command_state - stream = CommandOutput(result) + stream = CommandOutput(cmd_name, result) # need to avoid printing on stdout if called from lldb_run_command. if 'active' in lldb_run_command_state and lldb_run_command_state['active']: debuglog('Running %s from lldb_run_command' % command) @@ -289,6 +289,41 @@ def GetLLDBThreadForKernelThread(thread_obj): return sbthread +def GetKextSymbolInfo(load_addr): + """ Get a string descriptiong load_addr + offset + params: + load_addr - int address value of pc in backtrace. + returns: str - kext name + offset string. If no cached data available, warning message is returned. + """ + symbol_name = "None" + symbol_offset = load_addr + kmod_val = kern.globals.kmod + if kern.arch not in ('arm64',): + for kval in IterateLinkedList(kmod_val, 'next'): + if load_addr >= unsigned(kval.address) and \ + load_addr <= (unsigned(kval.address) + unsigned(kval.size)): + symbol_name = kval.name + symbol_offset = load_addr - unsigned(kval.address) + break + return "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset) + + # only for arm64 we do lookup for split kexts. + cached_kext_info = caching.GetDynamicCacheData("kern.kexts.loadinformation", []) + if not cached_kext_info and str(GetConnectionProtocol()) == "core": + cached_kext_info = GetKextLoadInformation() + + if not cached_kext_info: + return "{:#018x} ~ kext info not available. please run 'showallkexts' once ~ \n".format(load_addr) + + for kval in cached_kext_info: + text_seg = kval[5] + if load_addr >= text_seg.vmaddr and \ + load_addr <= (text_seg.vmaddr + text_seg.vmsize): + symbol_name = kval[2] + symbol_offset = load_addr - text_seg.vmaddr + break + return "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset) + def GetThreadBackTrace(thread_obj, verbosity = vHUMAN, prefix = ""): """ Get a string to display back trace for a thread. params: @@ -330,16 +365,7 @@ def GetThreadBackTrace(thread_obj, verbosity = vHUMAN, prefix = ""): symbol = frame.GetSymbol() if not symbol: - symbol_name = "None" - symbol_offset = load_addr - kmod_val = kern.globals.kmod - for kval in IterateLinkedList(kmod_val, 'next'): - if load_addr >= unsigned(kval.address) and \ - load_addr <= (unsigned(kval.address) + unsigned(kval.size)): - symbol_name = kval.name - symbol_offset = load_addr - unsigned(kval.address) - break - out_string += "{:#018x} {:s} + {:#x} \n".format(load_addr, symbol_name, symbol_offset) + out_string += GetKextSymbolInfo(load_addr) else: file_addr = addr.GetFileAddress() start_addr = symbol.GetStartAddress().GetFileAddress() @@ -456,6 +482,9 @@ def XnuDebugCommand(cmd_args=None): reload: Reload a submodule from the xnu/tools/lldb directory. Do not include the ".py" suffix in modulename. usage: xnudebug reload (eg. memory, process, stats etc) + flushcache: + remove any cached data held in static or dynamic data cache. + usage: xnudebug flushcache test: Start running registered test with from various modules. usage: xnudebug test (eg. test_memstats) @@ -468,12 +497,12 @@ def XnuDebugCommand(cmd_args=None): command_args = cmd_args if len(command_args) == 0: raise ArgumentError("No command specified.") - supported_subcommands = ['debug', 'reload', 'test', 'testall'] + supported_subcommands = ['debug', 'reload', 'test', 'testall', 'flushcache'] subcommand = GetLongestMatchOption(command_args[0], supported_subcommands, True) if len(subcommand) == 0: raise ArgumentError("Subcommand (%s) is not a valid command. " % str(command_args[0])) - + subcommand = subcommand[0].lower() if subcommand == 'debug': if command_args[-1].lower().find('dis') >=0 and config['debug']: @@ -483,7 +512,10 @@ def XnuDebugCommand(cmd_args=None): config['debug'] = True EnableLLDBAPILogging() # provided by utils.py print "Enabled debug logging. \nPlease run 'xnudebug debug disable' to disable it again. " - + if subcommand == 'flushcache': + print "Current size of cache: {}".format(caching.GetSizeOfCache()) + caching.ClearAllCache() + if subcommand == 'reload': module_name = command_args[-1] if module_name in sys.modules: @@ -532,33 +564,74 @@ def ShowVersion(cmd_args=None): print kern.version -@lldb_command('paniclog') -def ShowPanicLog(cmd_args=None): +@lldb_command('paniclog', 'S') +def ShowPanicLog(cmd_args=None, cmd_options={}): """ Display the paniclog information usage: (lldb) paniclog options: -v : increase verbosity + -S : parse stackshot data (if panic stackshot available) """ + binary_data_bytes_to_skip = 0 + if hasattr(kern.globals, "kc_panic_data"): + binary_data_bytes_to_skip = unsigned(kern.globals.kc_panic_data.kcd_addr_end) - unsigned(kern.globals.kc_panic_data.kcd_addr_begin) + if binary_data_bytes_to_skip > 0: + binary_data_bytes_to_skip += sizeof("struct kcdata_item") + else: + binary_data_bytes_to_skip = 0 + + if "-S" in cmd_options: + if hasattr(kern.globals, "kc_panic_data"): + kc_data = unsigned(addressof(kern.globals.kc_panic_data)) + ts = int(time.time()) + ss_binfile = "/tmp/panic_%d.bin" % ts + ss_ipsfile = "/tmp/stacks_%d.ips" % ts + print "savekcdata 0x%x -O %s" % (kc_data, ss_binfile) + SaveKCDataToFile(["0x%x" % kc_data], {"-O":ss_binfile}) + self_path = str(__file__) + base_dir_name = self_path[:self_path.rfind("/")] + print "python %s/kcdata.py %s -s %s" % (base_dir_name, ss_binfile, ss_ipsfile) + (c,so,se) = RunShellCommand("python %s/kcdata.py %s -s %s" % (base_dir_name, ss_binfile, ss_ipsfile)) + if c == 0: + print "Saved ips stackshot file as %s" % ss_ipsfile + else: + print "Failed to run command: exit code: %d, SO: %s SE: %s" % (c, so, se) + else: + print "kc_panic_data is unavailable for this kernel config." + panic_buf = kern.globals.debug_buf_addr panic_buf_start = unsigned(panic_buf) panic_buf_end = unsigned(kern.globals.debug_buf_ptr) num_bytes = panic_buf_end - panic_buf_start if num_bytes == 0 : return - warn_str = "" - if num_bytes > 4096 and config['verbosity'] == vHUMAN: - num_bytes = 4096 - warn_str = "LLDBMacro Warning: The paniclog is too large. Trimming to 4096 bytes." - warn_str += " If you wish to see entire log please use '-v' argument." out_str = "" - for i in range(num_bytes): - p_char = str(panic_buf[i]) + warn_str = "" + num_print_bytes = 0 + in_binary_data_region = False + pos = 0 + while pos < num_bytes: + p_char = str(panic_buf[pos]) out_str += p_char if p_char == '\n': - print out_str + if not in_binary_data_region: + num_print_bytes += 1 + print out_str[:-1] + if (out_str.find("Data: BEGIN>>") >= 0): + in_binary_data_region = True + pos += binary_data_bytes_to_skip - 1 + if (out_str.find("<= 0): + in_binary_data_region = False out_str = "" + if num_print_bytes > 4096 and config['verbosity'] == vHUMAN: + warn_str = "LLDBMacro Warning: The paniclog is too large. Trimming to 4096 bytes." + warn_str += " If you wish to see entire log please use '-v' argument." + break + pos += 1 + if warn_str: print warn_str + return @lldb_command('showbootargs') @@ -711,4 +784,9 @@ from atm import * from structanalyze import * from ipcimportancedetail import * from bank import * - +from kauth import * +from waitq import * +from usertaskgdbserver import * +from ktrace import * +from pgtrace import * +from xnutriage import *