]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/xnu.py
xnu-3789.21.4.tar.gz
[apple/xnu.git] / tools / lldbmacros / xnu.py
index a3c5b1b5a10486f70c53c448b6c663a2dd2a6f61..f93fd476d4b255cf6139bd00a051e6906d91079b 100644 (file)
@@ -289,6 +289,41 @@ def GetLLDBThreadForKernelThread(thread_obj):
 
     return sbthread
 
 
     return sbthread
 
+def GetKextSymbolInfo(load_addr):
+    """ Get a string descriptiong load_addr <kextname> + 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:
 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 = 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()
             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 <modulename> (eg. memory, process, stats etc)
         reload:
             Reload a submodule from the xnu/tools/lldb directory. Do not include the ".py" suffix in modulename.
             usage: xnudebug reload <modulename> (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 <name> from various modules.
             usage: xnudebug test <name> (eg. test_memstats)
         test:
             Start running registered test with <name> from various modules.
             usage: xnudebug test <name> (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.")
     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 = 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']:
     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. "
             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:
     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
 
 
     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
     """ 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
     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 = ""
     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':
         out_str += p_char
         if p_char == '\n':
-            print out_str
+            if not in_binary_data_region:
+                num_print_bytes += 1
+                print out_str
+            if (out_str.find("Data: BEGIN>>") >= 0):
+                in_binary_data_region = True
+                pos += binary_data_bytes_to_skip - 1
+            if (out_str.find("<<END") >= 0):
+                in_binary_data_region = False
             out_str = ""
             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
     if warn_str:
         print warn_str
+
     return
 
 @lldb_command('showbootargs')
     return
 
 @lldb_command('showbootargs')
@@ -711,4 +784,9 @@ from atm import *
 from structanalyze import *
 from ipcimportancedetail import *
 from bank 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 *