]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/kdp.py
xnu-2422.1.72.tar.gz
[apple/xnu.git] / tools / lldbmacros / kdp.py
diff --git a/tools/lldbmacros/kdp.py b/tools/lldbmacros/kdp.py
new file mode 100644 (file)
index 0000000..7c31630
--- /dev/null
@@ -0,0 +1,285 @@
+from xnu import *
+from utils import *
+import sys
+
+def GetKDPPacketHeaderInt(request=0, is_reply=False, seq=0, length=0, key=0):
+    """ create a 64 bit number that could be saved as pkt_hdr_t
+        params:
+            request:int   - 7 bit kdp_req_t request type
+            is_reply:bool - False => request, True => reply 
+            seq: int      - 8  sequence number within session 
+            length: int   - 16 bit length of entire pkt including hdr 
+            key: int      - session key 
+        returns:
+            int - 64 bit number to be saved in memory
+    """
+    retval = request 
+    if is_reply:
+        retval = 1<<7 |retval
+    retval = (seq << 8) | retval
+    retval = (length << 16) | retval
+    #retval = (retval << 32) | key
+    retval = (key << 32) | retval
+    return retval
+
+
+def KDPDumpInfo(subcmd, file_name="", dest_ip="", router_ip="", port=0):
+    """ Setup the state for DUMP INFO commands for sending coredump etc
+    """
+    if "kdp" != GetConnectionProtocol():
+        print "Target is not connected over kdp. Nothing to do here."
+        return False
+    input_address = unsigned(addressof(kern.globals.manual_pkt.input))
+    len_address = unsigned(addressof(kern.globals.manual_pkt.len))
+    data_address = unsigned(addressof(kern.globals.manual_pkt.data))
+    if not WriteInt32ToMemoryAddress(0, input_address):
+        return False
+
+    kdp_pkt_size = GetType('kdp_dumpinfo_req_t').GetByteSize()
+    if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
+        return False
+
+    data_addr = int(addressof(kern.globals.manual_pkt))
+    pkt = kern.GetValueFromAddress(data_addr, 'kdp_dumpinfo_req_t *')
+    if len(file_name) > 49:
+        file_name = file_name[:49]
+    if len(dest_ip) > 15:
+        dest_ip = dest_ip[:15]
+    if len(router_ip) > 15:
+        router_ip = router_ip[:15]
+
+    header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_DUMPINFO'), length=kdp_pkt_size)
+    # 0x1f is same as KDP_DUMPINFO
+    if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and
+         WriteInt32ToMemoryAddress(subcmd, int(addressof(pkt.type))) and
+         WriteStringToMemoryAddress(file_name, int(addressof(pkt.name))) and
+         WriteStringToMemoryAddress(dest_ip, int(addressof(pkt.destip))) and
+         WriteStringToMemoryAddress(router_ip, int(addressof(pkt.routerip)))
+         ):
+         #We have saved important data successfully
+        if port > 0:
+            if not WriteInt32ToMemoryAddress(port, int(addressof(pkt.port))):
+                return False
+        if WriteInt32ToMemoryAddress(1, input_address):
+            return True
+    return False
+
+@lldb_command('sendcore')
+def KDPSendCore(cmd_args=None):
+    """  Configure kernel to send a coredump to the specified IP
+    Syntax: sendcore <IP address> [filename]
+    Configure the kernel to transmit a kernel coredump to a server (kdumpd) 
+    at the specified IP address. This is useful when the remote target has
+    not been previously configured to transmit coredumps, and you wish to
+    preserve kernel state for later examination. NOTE: You must issue a "continue"
+    command after using this macro to trigger the kernel coredump. The kernel
+    will resume waiting in the debugger after completion of the coredump. You
+    may disable coredumps by executing the "disablecore" macro. You can 
+    optionally specify the filename to be used for the generated core file.
+
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        print KDPSendCore.__doc__
+        return False
+    ip_address = cmd_args[0]
+    filename=""
+    if len(cmd_args) >=2:
+        filename = cmd_args[1].strip()
+    retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_CORE'), file_name=filename, dest_ip=ip_address)
+    if retval:
+        print "Remote system has been setup for coredump. Please detach/continue the system. "
+        return True
+    else:
+        print "Something went wrong. Failed to setup the coredump on the target."
+        return False
+
+    
+@lldb_command('sendsyslog')
+def KDPSendSyslog(cmd_args=None):
+    """ Configure kernel to send a system log to the specified IP
+        Syntax: sendsyslog <IP address> [filename]
+        Configure the kernel to transmit a kernel system log to a server (kdumpd) 
+        at the specified IP address. NOTE: You must issue a "continue"
+        command after using this macro to trigger the kernel system log. The kernel
+        will resume waiting in the debugger after completion. You can optionally
+        specify the name to be used for the generated system log.
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        print KDPSendSyslog.__doc__
+        return False
+    ip_address = cmd_args[0]
+    filename =""
+    if len(cmd_args) >=2:
+        filename = cmd_args[1].strip()
+    retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SYSTEMLOG'), file_name = filename, dest_ip = ip_address)
+    if retval:
+        print "Remote system has been setup to send system log. please detach/continue the system."
+        return True
+    else:
+        print "Something went wrong. Failed to setup the systemlog on the target."
+        return False
+
+@lldb_command('sendpaniclog')
+def KDPSendPaniclog(cmd_args=None):
+    """ Configure kernel to send a panic log to the specified IP
+        Syntax: sendpaniclog <IP address> [filename]
+        Configure the kernel to transmit a kernel paniclog to a server (kdumpd) 
+        at the specified IP address. NOTE: You must issue a "continue"
+        command after using this macro to trigger the kernel panic log. The kernel
+        will resume waiting in the debugger after completion. You can optionally
+        specify the name to be used for the generated panic log.
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        print KDPSendPaniclog.__doc__
+        return False
+    ip_address = cmd_args[0]
+    filename =""
+    if len(cmd_args) >=2:
+        filename = cmd_args[1].strip()
+    retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_PANICLOG'), file_name = filename, dest_ip = ip_address)
+    if retval:
+        print "Remote system has been setup to send panic log. please detach/continue the system."
+        return True
+    else:
+        print "Something went wrong. Failed to setup the paniclog on the target."
+        return False
+
+
+@lldb_command('disablecore')
+def KDPDisableCore(cmd_args=None):
+    """ Configure the kernel to disable coredump transmission
+        Reconfigures the kernel so that it no longer transmits kernel coredumps. This
+        complements the "sendcore" macro, but it may be used if the kernel has been
+        configured to transmit coredumps through boot-args as well.
+
+    """
+    retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_DISABLE'))
+    if retval :
+        print "Disabled coredump functionality on remote system."
+    else:
+        print "Failed to disable coredump functionality."
+    return retval
+
+@lldb_command('resume_on')
+def KDPResumeON(cmd_args=None):
+    """ The target system will resume when detaching  or exiting from lldb. 
+        This is the default behavior.
+    """
+    subcmd = GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SETINFO') | GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_RESUME') 
+    retval = KDPDumpInfo(subcmd)
+    if retval :
+        print "Target system will resume on detaching from lldb."
+    else:
+        print "Failed to enable resume functionality."
+    return retval
+
+@lldb_command('resume_off')
+def KDPResumeON(cmd_args=None):
+    """ The target system will not resume when detaching  or exiting from lldb. 
+    """
+    subcmd = GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SETINFO') | GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_NORESUME') 
+    retval = KDPDumpInfo(subcmd)
+    if retval :
+        print "Target system will not resume on detaching from lldb."
+    else:
+        print "Failed to disable resume functionality."
+    return retval
+
+
+
+@lldb_command('getdumpinfo')
+def KDPGetDumpInfo(cmd_args=None):
+    """ Retrieve the current remote dump settings.
+    """
+    if not KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_GETINFO')):
+        print "Failed to get dump settings."
+        return False
+    dumpinfo = Cast(addressof(kern.globals.manual_pkt.data), 'kdp_dumpinfo_reply_t *')
+    target_dump_type = int(dumpinfo.type)
+    if target_dump_type & GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_REBOOT'):
+        print "System will reboot after kernel info gets dumped."
+    else:
+        print "System will not reboot after kernel info gets dumped."
+    if target_dump_type & GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_RESUME'):
+        print "System will allow a re-attach after KDP disconnect."
+    else:
+        print "System will not allow a re-attach after KDP disconnect."
+    target_dump_type = target_dump_type & GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_MASK')
+    if target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_DISABLE'):
+        print "Kernel not setup for remote dumps."
+    else:
+        kern_dump_type = ''
+        if target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_CORE'):
+            kern_dump_type = "Core File"
+        elif target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_PANICLOG'):
+            kern_dump_type = "Panic Log"
+        elif target_dump_type == GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SYSTEMLOG'):
+            kern_dump_type = "System Log"
+        print "Kernel dump type:" + kern_dump_type
+        fname = "(autogenerated)"
+        if int(dumpinfo.name[0]) != 0:
+            fname = str(dumpinfo.name)
+        print "Filename: " + fname
+        print "Network Info: {:s} [{:d}] , Router: {:s}".format(dumpinfo.destip, dumpinfo.port, dumpinfo.routerip)
+    # end of get dump info
+
+
+@lldb_command('kdp-reenter')
+def KDPReenter(cmd_args=None):
+    """ Schedules reentry into the debugger 
+        after <seconds> seconds, and resumes the target.
+        usage: kdp-reenter <seconds>
+    """
+    if len(cmd_args) < 1:
+        print "Please provide valid time in seconds"
+        print KDPReenter.__doc__
+        return False
+
+    if "kdp" != GetConnectionProtocol():
+        print "Target is not connected over kdp. Nothing to do here."
+        return False
+
+    num_seconds = ArgumentStringToInt(cmd_args[0])
+    milliseconds_to_sleep = num_seconds * 1000
+    if WriteInt32ToMemoryAddress(milliseconds_to_sleep, addressof(kern.globals.kdp_reentry_deadline)):
+        lldb.debugger.HandleCommand('process continue')
+        return True
+    print "Failed to setup kdp-reentry."
+    return False
+
+@lldb_command('kdp-reboot')
+def KDPReboot(cmd_args=None):
+    """ Restart the remote target
+    """
+    if "kdp" != GetConnectionProtocol():
+        print "Target is not connected over kdp. Nothing to do here."
+        return False
+
+    print "Rebooting the remote machine."
+    lldb.debugger.HandleCommand('process plugin packet send --command 0x13')
+    lldb.debugger.HandleCommand('detach')
+    return True
+
+@lldb_command('setdumpinfo')
+def KDPSetDumpInfo(cmd_args=None):
+    """ Configure the current remote dump settings. 
+        Specify "" if you want to use the defaults (filename) or previously configured
+        settings (ip/router). Specify 0 for the port if you wish to 
+        use the previously configured/default setting for that.
+        Syntax: setdumpinfo <filename> <ip> <router> <port>
+    """
+    if not cmd_args:
+        print KDPSetDumpInfo.__doc__
+        return False
+    if len(cmd_args) < 4:
+        print "Not enough arguments."
+        print KDPSetDumpInfo.__doc__
+        return False
+    portnum = ArgumentStringToInt(cmd_args[3])
+    retval = KDPDumpInfo(GetEnumValue('kdp_dumpinfo_t::KDP_DUMPINFO_SETINFO'), cmd_args[0], cmd_args[1], cmd_args[2], portnum)
+    if retval:
+        print "Successfully saved the dumpinfo."
+    else:
+        print "Failed to save the dumpinfo."
+    return retval
+