diff options
Diffstat (limited to 'source/Plugins/Process/MacOSX-Kernel')
18 files changed, 4657 insertions, 0 deletions
| diff --git a/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt new file mode 100644 index 0000000000000..681b7405e2b8e --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginProcessMacOSXKernel +  CommunicationKDP.cpp +  ProcessKDP.cpp +  ProcessKDPLog.cpp +  RegisterContextKDP_arm.cpp +  RegisterContextKDP_arm64.cpp +  RegisterContextKDP_i386.cpp +  RegisterContextKDP_x86_64.cpp +  ThreadKDP.cpp +  ) diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp new file mode 100644 index 0000000000000..5c1c3284a35c2 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -0,0 +1,1445 @@ +//===-- CommunicationKDP.cpp ------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "CommunicationKDP.h" + +// C Includes +#include <errno.h> +#include <limits.h> +#include <string.h> + +// C++ Includes + +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/State.h" +#include "lldb/Core/UUID.h" +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/TimeValue.h" +#include "lldb/Target/Process.h" + +// Project includes +#include "ProcessKDPLog.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// CommunicationKDP constructor +//---------------------------------------------------------------------- +CommunicationKDP::CommunicationKDP (const char *comm_name) : +    Communication(comm_name), +    m_addr_byte_size (4), +    m_byte_order (eByteOrderLittle), +    m_packet_timeout (5), +    m_sequence_mutex (Mutex::eMutexTypeRecursive), +    m_is_running (false), +    m_session_key (0u), +    m_request_sequence_id (0u), +    m_exception_sequence_id (0u), +    m_kdp_version_version (0u), +    m_kdp_version_feature (0u), +    m_kdp_hostinfo_cpu_mask (0u), +    m_kdp_hostinfo_cpu_type (0u), +    m_kdp_hostinfo_cpu_subtype (0u) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +CommunicationKDP::~CommunicationKDP() +{ +    if (IsConnected()) +    { +        Disconnect(); +    } +} + +bool +CommunicationKDP::SendRequestPacket (const PacketStreamType &request_packet) +{ +    Mutex::Locker locker(m_sequence_mutex); +    return SendRequestPacketNoLock (request_packet); +} + +#if 0 +typedef struct { +	uint8_t     request;	// Either: CommandType | ePacketTypeRequest, or CommandType | ePacketTypeReply +	uint8_t     sequence; +	uint16_t    length;		// Length of entire packet including this header +	uint32_t	key;		// Session key +} kdp_hdr_t; +#endif + +void +CommunicationKDP::MakeRequestPacketHeader (CommandType request_type, +                                           PacketStreamType &request_packet, +                                           uint16_t request_length) +{ +    request_packet.Clear(); +    request_packet.PutHex8 (request_type | ePacketTypeRequest); // Set the request type +    request_packet.PutHex8 (m_request_sequence_id++);           // Sequence number +    request_packet.PutHex16 (request_length);                   // Length of the packet including this header +    request_packet.PutHex32 (m_session_key);                    // Session key +} + +bool +CommunicationKDP::SendRequestAndGetReply (const CommandType command, +                                          const PacketStreamType &request_packet, +                                          DataExtractor &reply_packet) +{ +    if (IsRunning()) +    { +        Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS)); +        if (log) +        { +            PacketStreamType log_strm; +            DumpPacket (log_strm, request_packet.GetData(), request_packet.GetSize()); +            log->Printf("error: kdp running, not sending packet: %.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); +        } +        return false; +    } + +    Mutex::Locker locker(m_sequence_mutex); +#ifdef LLDB_CONFIGURATION_DEBUG +    // NOTE: this only works for packets that are in native endian byte order +    assert (request_packet.GetSize() == *((uint16_t *)(request_packet.GetData() + 2))); +#endif +    lldb::offset_t offset = 1; +    const uint32_t num_retries = 3; +    for (uint32_t i=0; i<num_retries; ++i) +    { +        if (SendRequestPacketNoLock(request_packet)) +        { +            const uint8_t request_sequence_id = (uint8_t)request_packet.GetData()[1]; +            while (1) +            { +                if (WaitForPacketWithTimeoutMicroSecondsNoLock (reply_packet, GetPacketTimeoutInMicroSeconds ())) +                { +                    offset = 0; +                    const uint8_t reply_command = reply_packet.GetU8 (&offset); +                    const uint8_t reply_sequence_id = reply_packet.GetU8 (&offset); +                    if (request_sequence_id == reply_sequence_id) +                    { +                        // The sequent ID was correct, now verify we got the response we were looking for +                        if ((reply_command & eCommandTypeMask) == command) +                        { +                            // Success +                            if (command == KDP_RESUMECPUS) +                                m_is_running.SetValue(true, eBroadcastAlways); +                            return true; +                        } +                        else +                        { +                            // Failed to get the correct response, bail +                            reply_packet.Clear(); +                            return false; +                        } +                    } +                    else if (reply_sequence_id > request_sequence_id) +                    { +                        // Sequence ID was greater than the sequence ID of the packet we sent, something +                        // is really wrong... +                        reply_packet.Clear(); +                        return false; +                    } +                    else +                    { +                        // The reply sequence ID was less than our current packet's sequence ID +                        // so we should keep trying to get a response because this was a response +                        // for a previous packet that we must have retried. +                    } +                } +                else +                { +                    // Break and retry sending the packet as we didn't get a response due to timeout +                    break; +                } +            } +        } +    } +    reply_packet.Clear(); +    return false; +} + +bool +CommunicationKDP::SendRequestPacketNoLock (const PacketStreamType &request_packet) +{ +    if (IsConnected()) +    { +        const char *packet_data = request_packet.GetData(); +        const size_t packet_size = request_packet.GetSize(); + +        Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS)); +        if (log) +        { +            PacketStreamType log_strm;             +            DumpPacket (log_strm, packet_data, packet_size); +            log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); +        } +        ConnectionStatus status = eConnectionStatusSuccess; + +        size_t bytes_written = Write (packet_data,  +                                      packet_size,  +                                      status,  +                                      NULL); + +        if (bytes_written == packet_size) +            return true; +         +        if (log) +            log->Printf ("error: failed to send packet entire packet %" PRIu64 " of %" PRIu64 " bytes sent", (uint64_t)bytes_written, (uint64_t)packet_size); +    } +    return false; +} + +bool +CommunicationKDP::GetSequenceMutex (Mutex::Locker& locker) +{ +    return locker.TryLock (m_sequence_mutex); +} + + +bool +CommunicationKDP::WaitForNotRunningPrivate (const TimeValue *timeout_ptr) +{ +    return m_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL); +} + +size_t +CommunicationKDP::WaitForPacketWithTimeoutMicroSeconds (DataExtractor &packet, uint32_t timeout_usec) +{ +    Mutex::Locker locker(m_sequence_mutex); +    return WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec); +} + +size_t +CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock (DataExtractor &packet, uint32_t timeout_usec) +{ +    uint8_t buffer[8192]; +    Error error; + +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS | KDP_LOG_VERBOSE)); + +    // Check for a packet from our cache first without trying any reading... +    if (CheckForPacket (NULL, 0, packet)) +        return packet.GetByteSize(); + +    bool timed_out = false; +    while (IsConnected() && !timed_out) +    { +        lldb::ConnectionStatus status = eConnectionStatusNoConnection; +        size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error); +         +        if (log) +            log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64, +                         __PRETTY_FUNCTION__, +                         timeout_usec,  +                         Communication::ConnectionStatusAsCString (status), +                         error.AsCString(),  +                         (uint64_t)bytes_read); + +        if (bytes_read > 0) +        { +            if (CheckForPacket (buffer, bytes_read, packet)) +                return packet.GetByteSize(); +        } +        else +        { +            switch (status) +            { +            case eConnectionStatusInterrupted: +            case eConnectionStatusTimedOut: +                timed_out = true; +                break; +            case eConnectionStatusSuccess: +                //printf ("status = success but error = %s\n", error.AsCString("<invalid>")); +                break; +                 +            case eConnectionStatusEndOfFile: +            case eConnectionStatusNoConnection: +            case eConnectionStatusLostConnection: +            case eConnectionStatusError: +                Disconnect(); +                break; +            } +        } +    } +    packet.Clear ();     +    return 0; +} + +bool +CommunicationKDP::CheckForPacket (const uint8_t *src, size_t src_len, DataExtractor &packet) +{ +    // Put the packet data into the buffer in a thread safe fashion +    Mutex::Locker locker(m_bytes_mutex); +     +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PACKETS)); + +    if (src && src_len > 0) +    { +        if (log && log->GetVerbose()) +        { +            PacketStreamType log_strm; +            DataExtractor::DumpHexBytes (&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS); +            log->Printf ("CommunicationKDP::%s adding %u bytes: %s", +                         __FUNCTION__,  +                         (uint32_t)src_len,  +                         log_strm.GetData()); +        } +        m_bytes.append ((const char *)src, src_len); +    } + +    // Make sure we at least have enough bytes for a packet header +    const size_t bytes_available = m_bytes.size(); +    if (bytes_available >= 8) +    { +        packet.SetData (&m_bytes[0], bytes_available, m_byte_order); +        lldb::offset_t offset = 0; +        uint8_t reply_command = packet.GetU8(&offset); +        switch (reply_command) +        { +        case ePacketTypeRequest | KDP_EXCEPTION: +        case ePacketTypeRequest | KDP_TERMINATION: +            // We got an exception request, so be sure to send an ACK +            { +                PacketStreamType request_ack_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +                // Set the reply but and make the ACK packet +                request_ack_packet.PutHex8 (reply_command | ePacketTypeReply); +                request_ack_packet.PutHex8 (packet.GetU8(&offset)); +                request_ack_packet.PutHex16 (packet.GetU16(&offset)); +                request_ack_packet.PutHex32 (packet.GetU32(&offset)); +                m_is_running.SetValue(false, eBroadcastAlways); +                // Ack to the exception or termination +                SendRequestPacketNoLock (request_ack_packet); +            } +            // Fall through to case below to get packet contents +        case ePacketTypeReply | KDP_CONNECT: +        case ePacketTypeReply | KDP_DISCONNECT: +        case ePacketTypeReply | KDP_HOSTINFO: +        case ePacketTypeReply | KDP_VERSION: +        case ePacketTypeReply | KDP_MAXBYTES: +        case ePacketTypeReply | KDP_READMEM: +        case ePacketTypeReply | KDP_WRITEMEM: +        case ePacketTypeReply | KDP_READREGS: +        case ePacketTypeReply | KDP_WRITEREGS: +        case ePacketTypeReply | KDP_LOAD: +        case ePacketTypeReply | KDP_IMAGEPATH: +        case ePacketTypeReply | KDP_SUSPEND: +        case ePacketTypeReply | KDP_RESUMECPUS: +        case ePacketTypeReply | KDP_BREAKPOINT_SET: +        case ePacketTypeReply | KDP_BREAKPOINT_REMOVE: +        case ePacketTypeReply | KDP_REGIONS: +        case ePacketTypeReply | KDP_REATTACH: +        case ePacketTypeReply | KDP_HOSTREBOOT: +        case ePacketTypeReply | KDP_READMEM64: +        case ePacketTypeReply | KDP_WRITEMEM64: +        case ePacketTypeReply | KDP_BREAKPOINT_SET64: +        case ePacketTypeReply | KDP_BREAKPOINT_REMOVE64: +        case ePacketTypeReply | KDP_KERNELVERSION: +        case ePacketTypeReply | KDP_READPHYSMEM64: +        case ePacketTypeReply | KDP_WRITEPHYSMEM64: +        case ePacketTypeReply | KDP_READIOPORT: +        case ePacketTypeReply | KDP_WRITEIOPORT: +        case ePacketTypeReply | KDP_READMSR64: +        case ePacketTypeReply | KDP_WRITEMSR64: +        case ePacketTypeReply | KDP_DUMPINFO: +            { +                offset = 2; +                const uint16_t length = packet.GetU16 (&offset); +                if (length <= bytes_available) +                { +                    // We have an entire packet ready, we need to copy the data +                    // bytes into a buffer that will be owned by the packet and +                    // erase the bytes from our communcation buffer "m_bytes" +                    packet.SetData (DataBufferSP (new DataBufferHeap (&m_bytes[0], length))); +                    m_bytes.erase (0, length); +                     +                    if (log) +                    { +                        PacketStreamType log_strm; +                        DumpPacket (log_strm, packet); +                         +                        log->Printf("%.*s", (uint32_t)log_strm.GetSize(), log_strm.GetData()); +                    } +                    return true; +                } +            } +            break; + +        default: +            // Unrecognized reply command byte, erase this byte and try to get back on track +            if (log) +                log->Printf ("CommunicationKDP::%s: tossing junk byte: 0x%2.2x",  +                             __FUNCTION__,  +                             (uint8_t)m_bytes[0]); +            m_bytes.erase(0, 1); +            break; +        } +    } +    packet.Clear(); +    return false; +} + + +bool +CommunicationKDP::SendRequestConnect (uint16_t reply_port,  +                                      uint16_t exc_port,  +                                      const char *greeting) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    if (greeting == NULL) +        greeting = ""; + +    const CommandType command = KDP_CONNECT; +    // Length is 82 uint16_t and the length of the greeting C string with the terminating NULL +    const uint32_t command_length = 8 + 2 + 2 + ::strlen(greeting) + 1; +    MakeRequestPacketHeader (command, request_packet, command_length); +    // Always send connect ports as little endian +    request_packet.SetByteOrder (eByteOrderLittle); +    request_packet.PutHex16 (htons(reply_port)); +    request_packet.PutHex16 (htons(exc_port)); +    request_packet.SetByteOrder (m_byte_order); +    request_packet.PutCString (greeting); +    DataExtractor reply_packet; +    return SendRequestAndGetReply (command, request_packet, reply_packet); +} + +void +CommunicationKDP::ClearKDPSettings () +{ +    m_request_sequence_id = 0; +    m_kdp_version_version = 0; +    m_kdp_version_feature = 0; +    m_kdp_hostinfo_cpu_mask = 0; +    m_kdp_hostinfo_cpu_type = 0; +    m_kdp_hostinfo_cpu_subtype = 0; +} + +bool +CommunicationKDP::SendRequestReattach (uint16_t reply_port) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_REATTACH; +    // Length is 8 bytes for the header plus 2 bytes for the reply UDP port +    const uint32_t command_length = 8 + 2; +    MakeRequestPacketHeader (command, request_packet, command_length); +    // Always send connect ports as little endian +    request_packet.SetByteOrder (eByteOrderLittle); +    request_packet.PutHex16(htons(reply_port)); +    request_packet.SetByteOrder (m_byte_order); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        // Reset the sequence ID to zero for reattach +        ClearKDPSettings (); +        lldb::offset_t offset = 4; +        m_session_key = reply_packet.GetU32 (&offset); +        return true; +    } +    return false; +} + +uint32_t +CommunicationKDP::GetVersion () +{ +    if (!VersionIsValid()) +        SendRequestVersion(); +    return m_kdp_version_version; +} + +uint32_t +CommunicationKDP::GetFeatureFlags () +{ +    if (!VersionIsValid()) +        SendRequestVersion(); +    return m_kdp_version_feature; +} + +bool +CommunicationKDP::SendRequestVersion () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_VERSION; +    const uint32_t command_length = 8; +    MakeRequestPacketHeader (command, request_packet, command_length); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        m_kdp_version_version = reply_packet.GetU32 (&offset); +        m_kdp_version_feature = reply_packet.GetU32 (&offset); +        return true; +    } +    return false; +} + +#if 0 // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... +const char * +CommunicationKDP::GetImagePath () +{ +    if (m_image_path.empty()) +        SendRequestImagePath(); +    return m_image_path.c_str(); +} + +bool +CommunicationKDP::SendRequestImagePath () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_IMAGEPATH; +    const uint32_t command_length = 8; +    MakeRequestPacketHeader (command, request_packet, command_length); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        const char *path = reply_packet.PeekCStr(8); +        if (path && path[0]) +            m_kernel_version.assign (path); +        return true; +    } +    return false; +} +#endif + +uint32_t +CommunicationKDP::GetCPUMask () +{ +    if (!HostInfoIsValid()) +        SendRequestHostInfo(); +    return m_kdp_hostinfo_cpu_mask; +} + +uint32_t +CommunicationKDP::GetCPUType () +{ +    if (!HostInfoIsValid()) +        SendRequestHostInfo(); +    return m_kdp_hostinfo_cpu_type; +} + +uint32_t +CommunicationKDP::GetCPUSubtype () +{ +    if (!HostInfoIsValid()) +        SendRequestHostInfo(); +    return m_kdp_hostinfo_cpu_subtype; +} + +lldb_private::UUID +CommunicationKDP::GetUUID () +{ +    UUID uuid; +    if (GetKernelVersion() == NULL) +        return uuid; + +    if (m_kernel_version.find("UUID=") == std::string::npos) +        return uuid; + +    size_t p = m_kernel_version.find("UUID=") + strlen ("UUID="); +    std::string uuid_str = m_kernel_version.substr(p, 36); +    if (uuid_str.size() < 32) +        return uuid; + +    if (uuid.SetFromCString (uuid_str.c_str()) == 0) +    { +        UUID invalid_uuid; +        return invalid_uuid; +    } + +    return uuid; +} + +bool +CommunicationKDP::RemoteIsEFI () +{ +    if (GetKernelVersion() == NULL) +        return false; +    if (strncmp (m_kernel_version.c_str(), "EFI", 3) == 0) +        return true; +    else +        return false; +} + +bool +CommunicationKDP::RemoteIsDarwinKernel () +{ +    if (GetKernelVersion() == NULL) +        return false; +    if (m_kernel_version.find("Darwin Kernel") != std::string::npos) +        return true; +    else +        return false; +} + +lldb::addr_t +CommunicationKDP::GetLoadAddress () +{ +    if (GetKernelVersion() == NULL) +        return LLDB_INVALID_ADDRESS; + +    if (m_kernel_version.find("stext=") == std::string::npos) +        return LLDB_INVALID_ADDRESS; +    size_t p = m_kernel_version.find("stext=") + strlen ("stext="); +    if (m_kernel_version[p] != '0' || m_kernel_version[p + 1] != 'x') +        return LLDB_INVALID_ADDRESS; + +    addr_t kernel_load_address; +    errno = 0; +    kernel_load_address = ::strtoul (m_kernel_version.c_str() + p, NULL, 16); +    if (errno != 0 || kernel_load_address == 0) +        return LLDB_INVALID_ADDRESS; + +    return kernel_load_address; +} + +bool +CommunicationKDP::SendRequestHostInfo () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_HOSTINFO; +    const uint32_t command_length = 8; +    MakeRequestPacketHeader (command, request_packet, command_length); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        m_kdp_hostinfo_cpu_mask     = reply_packet.GetU32 (&offset); +        m_kdp_hostinfo_cpu_type     = reply_packet.GetU32 (&offset); +        m_kdp_hostinfo_cpu_subtype  = reply_packet.GetU32 (&offset); +         +        ArchSpec kernel_arch; +        kernel_arch.SetArchitecture (eArchTypeMachO,  +                                     m_kdp_hostinfo_cpu_type,  +                                     m_kdp_hostinfo_cpu_subtype); +     +        m_addr_byte_size = kernel_arch.GetAddressByteSize(); +        m_byte_order = kernel_arch.GetByteOrder(); +        return true; +    } +    return false; +} + +const char * +CommunicationKDP::GetKernelVersion () +{ +    if (m_kernel_version.empty()) +        SendRequestKernelVersion (); +    return m_kernel_version.c_str(); +} + +bool +CommunicationKDP::SendRequestKernelVersion () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_KERNELVERSION; +    const uint32_t command_length = 8; +    MakeRequestPacketHeader (command, request_packet, command_length); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        const char *kernel_version_cstr = reply_packet.PeekCStr(8); +        if (kernel_version_cstr && kernel_version_cstr[0]) +            m_kernel_version.assign (kernel_version_cstr); +        return true; +    } +    return false; +} + +bool +CommunicationKDP::SendRequestDisconnect () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_DISCONNECT; +    const uint32_t command_length = 8; +    MakeRequestPacketHeader (command, request_packet, command_length); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        // Are we supposed to get a reply for disconnect? +    } +    ClearKDPSettings (); +    return true; +} + +uint32_t +CommunicationKDP::SendRequestReadMemory (lldb::addr_t addr,  +                                         void *dst,  +                                         uint32_t dst_len, +                                         Error &error) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    bool use_64 = (GetVersion() >= 11); +    uint32_t command_addr_byte_size = use_64 ? 8 : 4; +    const CommandType command = use_64 ? KDP_READMEM64 : KDP_READMEM; +    // Size is header + address size + uint32_t length +    const uint32_t command_length = 8 + command_addr_byte_size + 4; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutMaxHex64 (addr, command_addr_byte_size); +    request_packet.PutHex32 (dst_len); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        uint32_t kdp_error = reply_packet.GetU32 (&offset); +        uint32_t src_len = reply_packet.GetByteSize() - 12; +         +        if (src_len > 0) +        { +            const void *src = reply_packet.GetData(&offset, src_len); +            if (src) +            { +                ::memcpy (dst, src, src_len); +                error.Clear(); +                return src_len; +            } +        } +        if (kdp_error) +            error.SetErrorStringWithFormat ("kdp read memory failed (error %u)", kdp_error); +        else +            error.SetErrorString ("kdp read memory failed"); +    } +    else +    { +        error.SetErrorString ("failed to send packet"); +    } +    return 0; +} + + +uint32_t +CommunicationKDP::SendRequestWriteMemory (lldb::addr_t addr,  +                                          const void *src,  +                                          uint32_t src_len, +                                          Error &error) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    bool use_64 = (GetVersion() >= 11); +    uint32_t command_addr_byte_size = use_64 ? 8 : 4; +    const CommandType command = use_64 ? KDP_WRITEMEM64 : KDP_WRITEMEM; +    // Size is header + address size + uint32_t length +    const uint32_t command_length = 8 + command_addr_byte_size + 4 + src_len; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutMaxHex64 (addr, command_addr_byte_size); +    request_packet.PutHex32 (src_len); +    request_packet.PutRawBytes(src, src_len); + +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        uint32_t kdp_error = reply_packet.GetU32 (&offset); +        if (kdp_error) +            error.SetErrorStringWithFormat ("kdp write memory failed (error %u)", kdp_error); +        else +        { +            error.Clear(); +            return src_len; +        } +    } +    else +    { +        error.SetErrorString ("failed to send packet"); +    } +    return 0; +} + +bool +CommunicationKDP::SendRawRequest (uint8_t command_byte, +                                  const void *src,  // Raw packet payload bytes +                                  uint32_t src_len, // Raw packet payload length +                                  DataExtractor &reply_packet, +                                  Error &error) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    // Size is header + address size + uint32_t length +    const uint32_t command_length = 8 + src_len; +    const CommandType command = (CommandType)command_byte; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutRawBytes(src, src_len); +     +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        uint32_t kdp_error = reply_packet.GetU32 (&offset); +        if (kdp_error  && (command_byte != KDP_DUMPINFO)) +            error.SetErrorStringWithFormat ("request packet 0x%8.8x failed (error %u)", command_byte, kdp_error); +        else +        { +            error.Clear(); +            return true; +        } +    } +    else +    { +        error.SetErrorString ("failed to send packet"); +    } +    return false; +} + + +const char * +CommunicationKDP::GetCommandAsCString (uint8_t command) +{ +    switch (command) +    { +    case KDP_CONNECT:               return "KDP_CONNECT"; +    case KDP_DISCONNECT:            return "KDP_DISCONNECT"; +    case KDP_HOSTINFO:              return "KDP_HOSTINFO"; +    case KDP_VERSION:               return "KDP_VERSION"; +    case KDP_MAXBYTES:              return "KDP_MAXBYTES"; +    case KDP_READMEM:               return "KDP_READMEM"; +    case KDP_WRITEMEM:              return "KDP_WRITEMEM"; +    case KDP_READREGS:              return "KDP_READREGS"; +    case KDP_WRITEREGS:             return "KDP_WRITEREGS"; +    case KDP_LOAD:                  return "KDP_LOAD"; +    case KDP_IMAGEPATH:             return "KDP_IMAGEPATH"; +    case KDP_SUSPEND:               return "KDP_SUSPEND"; +    case KDP_RESUMECPUS:            return "KDP_RESUMECPUS"; +    case KDP_EXCEPTION:             return "KDP_EXCEPTION"; +    case KDP_TERMINATION:           return "KDP_TERMINATION"; +    case KDP_BREAKPOINT_SET:        return "KDP_BREAKPOINT_SET"; +    case KDP_BREAKPOINT_REMOVE:     return "KDP_BREAKPOINT_REMOVE"; +    case KDP_REGIONS:               return "KDP_REGIONS"; +    case KDP_REATTACH:              return "KDP_REATTACH"; +    case KDP_HOSTREBOOT:            return "KDP_HOSTREBOOT"; +    case KDP_READMEM64:             return "KDP_READMEM64"; +    case KDP_WRITEMEM64:            return "KDP_WRITEMEM64"; +    case KDP_BREAKPOINT_SET64:      return "KDP_BREAKPOINT64_SET"; +    case KDP_BREAKPOINT_REMOVE64:   return "KDP_BREAKPOINT64_REMOVE"; +    case KDP_KERNELVERSION:         return "KDP_KERNELVERSION"; +    case KDP_READPHYSMEM64:         return "KDP_READPHYSMEM64"; +    case KDP_WRITEPHYSMEM64:        return "KDP_WRITEPHYSMEM64"; +    case KDP_READIOPORT:            return "KDP_READIOPORT"; +    case KDP_WRITEIOPORT:           return "KDP_WRITEIOPORT"; +    case KDP_READMSR64:             return "KDP_READMSR64"; +    case KDP_WRITEMSR64:            return "KDP_WRITEMSR64"; +    case KDP_DUMPINFO:              return "KDP_DUMPINFO"; +    } +    return NULL; +} + +void +CommunicationKDP::DumpPacket (Stream &s, const void *data, uint32_t data_len) +{ +    DataExtractor extractor (data, data_len, m_byte_order, m_addr_byte_size); +    DumpPacket (s, extractor); +} + +void +CommunicationKDP::DumpPacket (Stream &s, const DataExtractor& packet) +{ +    const char *error_desc = NULL; +    if (packet.GetByteSize() < 8) +    { +        error_desc = "error: invalid packet (too short): "; +    } +    else +    { +        lldb::offset_t offset = 0; +        const uint8_t first_packet_byte = packet.GetU8 (&offset); +        const uint8_t sequence_id = packet.GetU8 (&offset); +        const uint16_t length = packet.GetU16 (&offset); +        const uint32_t key = packet.GetU32 (&offset); +        const CommandType command = ExtractCommand (first_packet_byte); +        const char *command_name = GetCommandAsCString (command); +        if (command_name) +        { +            const bool is_reply = ExtractIsReply(first_packet_byte); +            s.Printf ("(running=%i) %s %24s: 0x%2.2x 0x%2.2x 0x%4.4x 0x%8.8x ", +                      IsRunning(), +                      is_reply ? "<--" : "-->", +                      command_name, +                      first_packet_byte, +                      sequence_id, +                      length, +                      key); +             +            if (is_reply) +            { +                // Dump request reply packets +                switch (command) +                { +                    // Commands that return a single 32 bit error +                    case KDP_CONNECT: +                    case KDP_WRITEMEM: +                    case KDP_WRITEMEM64: +                    case KDP_BREAKPOINT_SET: +                    case KDP_BREAKPOINT_REMOVE: +                    case KDP_BREAKPOINT_SET64: +                    case KDP_BREAKPOINT_REMOVE64: +                    case KDP_WRITEREGS: +                    case KDP_LOAD: +                    case KDP_WRITEIOPORT: +                    case KDP_WRITEMSR64: +                        { +                            const uint32_t error = packet.GetU32 (&offset); +                            s.Printf(" (error=0x%8.8x)", error); +                        } +                        break; +                     +                    case KDP_DISCONNECT: +                    case KDP_REATTACH: +                    case KDP_HOSTREBOOT: +                    case KDP_SUSPEND: +                    case KDP_RESUMECPUS: +                    case KDP_EXCEPTION: +                    case KDP_TERMINATION: +                        // No return value for the reply, just the header to ack +                        s.PutCString(" ()"); +                        break; + +                    case KDP_HOSTINFO: +                        { +                            const uint32_t cpu_mask = packet.GetU32 (&offset); +                            const uint32_t cpu_type = packet.GetU32 (&offset); +                            const uint32_t cpu_subtype = packet.GetU32 (&offset); +                            s.Printf(" (cpu_mask=0x%8.8x, cpu_type=0x%8.8x, cpu_subtype=0x%8.8x)", cpu_mask, cpu_type, cpu_subtype); +                        } +                        break; +                         +                    case KDP_VERSION: +                        { +                            const uint32_t version = packet.GetU32 (&offset); +                            const uint32_t feature = packet.GetU32 (&offset); +                            s.Printf(" (version=0x%8.8x, feature=0x%8.8x)", version, feature); +                        } +                        break; +                         +                    case KDP_REGIONS: +                        { +                            const uint32_t region_count = packet.GetU32 (&offset); +                            s.Printf(" (count = %u", region_count);  +                            for (uint32_t i=0; i<region_count; ++i) +                            { +                                const addr_t region_addr = packet.GetPointer (&offset); +                                const uint32_t region_size = packet.GetU32 (&offset); +                                const uint32_t region_prot = packet.GetU32 (&offset); +                                s.Printf("\n\tregion[%" PRIu64 "] = { range = [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 "), size = 0x%8.8x, prot = %s }", region_addr, region_addr, region_addr + region_size, region_size, GetPermissionsAsCString (region_prot)); +                            } +                        } +                        break; + +                    case KDP_READMEM: +                    case KDP_READMEM64: +                    case KDP_READPHYSMEM64: +                        { +                            const uint32_t error = packet.GetU32 (&offset); +                            const uint32_t count = packet.GetByteSize() - offset; +                            s.Printf(" (error = 0x%8.8x:\n", error);  +                            if (count > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatBytesWithASCII,     // Format to use +                                             1,                         // Size of each item in bytes +                                             count,                     // Number of items +                                             16,                        // Number per line +                                             m_last_read_memory_addr,   // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                        } +                        break; + +                    case KDP_READREGS: +                        { +                            const uint32_t error = packet.GetU32 (&offset); +                            const uint32_t count = packet.GetByteSize() - offset; +                            s.Printf(" (error = 0x%8.8x regs:\n", error);  +                            if (count > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             m_addr_byte_size,          // Size of each item in bytes +                                             count / m_addr_byte_size,  // Number of items +                                             16 / m_addr_byte_size,     // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                        } +                        break; + +                    case KDP_KERNELVERSION: +                        { +                            const char *kernel_version = packet.PeekCStr(8); +                            s.Printf(" (version = \"%s\")", kernel_version); +                        } +                        break; +                         +                    case KDP_MAXBYTES: +                        { +                            const uint32_t max_bytes = packet.GetU32 (&offset); +                            s.Printf(" (max_bytes = 0x%8.8x (%u))", max_bytes, max_bytes); +                        } +                        break; +                    case KDP_IMAGEPATH: +                        { +                            const char *path = packet.GetCStr(&offset); +                            s.Printf(" (path = \"%s\")", path); +                        } +                        break; + +                    case KDP_READIOPORT: +                    case KDP_READMSR64: +                        { +                            const uint32_t error = packet.GetU32 (&offset); +                            const uint32_t count = packet.GetByteSize() - offset; +                            s.Printf(" (error = 0x%8.8x io:\n", error);  +                            if (count > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             1,                         // Size of each item in bytes +                                             count,                     // Number of items +                                             16,                        // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                        } +                        break; +                    case KDP_DUMPINFO: +                        { +                            const uint32_t count = packet.GetByteSize() - offset; +                            s.Printf(" (count = %u, bytes = \n", count); +                            if (count > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             1,                         // Size of each item in bytes +                                             count,                     // Number of items +                                             16,                        // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                             +                        } +                        break; +                         +                    default: +                        s.Printf(" (add support for dumping this packet reply!!!");  +                        break; +                     +                }  +            } +            else +            { +                // Dump request packets +                switch (command) +                { +                    case KDP_CONNECT:                +                        { +                            const uint16_t reply_port = ntohs(packet.GetU16 (&offset)); +                            const uint16_t exc_port = ntohs(packet.GetU16 (&offset)); +                            s.Printf(" (reply_port = %u, exc_port = %u, greeting = \"%s\")", reply_port, exc_port, packet.GetCStr(&offset)); +                        } +                        break; +                                  +                    case KDP_DISCONNECT: +                    case KDP_HOSTREBOOT: +                    case KDP_HOSTINFO: +                    case KDP_VERSION: +                    case KDP_REGIONS: +                    case KDP_KERNELVERSION: +                    case KDP_MAXBYTES: +                    case KDP_IMAGEPATH: +                    case KDP_SUSPEND: +                        // No args, just the header in the request... +                        s.PutCString(" ()"); +                        break; + +                    case KDP_RESUMECPUS: +                        { +                            const uint32_t cpu_mask = packet.GetU32 (&offset); +                            s.Printf(" (cpu_mask = 0x%8.8x)", cpu_mask); +                        } +                        break; + +                    case KDP_READMEM: +                        { +                            const uint32_t addr = packet.GetU32 (&offset); +                            const uint32_t size = packet.GetU32 (&offset); +                            s.Printf(" (addr = 0x%8.8x, size = %u)", addr, size); +                            m_last_read_memory_addr = addr; +                        } +                        break; + +                    case KDP_WRITEMEM: +                        { +                            const uint32_t addr = packet.GetU32 (&offset); +                            const uint32_t size = packet.GetU32 (&offset); +                            s.Printf(" (addr = 0x%8.8x, size = %u, bytes = \n", addr, size); +                            if (size > 0) +                                DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr); +                        } +                        break; + +                    case KDP_READMEM64: +                        { +                            const uint64_t addr = packet.GetU64 (&offset); +                            const uint32_t size = packet.GetU32 (&offset); +                            s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u)", addr, size); +                            m_last_read_memory_addr = addr; +                        } +                        break; + +                    case KDP_READPHYSMEM64: +                        { +                            const uint64_t addr = packet.GetU64 (&offset); +                            const uint32_t size = packet.GetU32 (&offset); +                            const uint32_t lcpu = packet.GetU16 (&offset); +                            s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u)", addr, size, lcpu); +                            m_last_read_memory_addr = addr; +                        } +                        break; + +                    case KDP_WRITEMEM64: +                        { +                            const uint64_t addr = packet.GetU64 (&offset); +                            const uint32_t size = packet.GetU32 (&offset); +                            s.Printf(" (addr = 0x%16.16" PRIx64 ", size = %u, bytes = \n", addr, size); +                            if (size > 0) +                                DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr); +                        } +                        break; + +                    case KDP_WRITEPHYSMEM64: +                        { +                            const uint64_t addr = packet.GetU64 (&offset); +                            const uint32_t size = packet.GetU32 (&offset); +                            const uint32_t lcpu = packet.GetU16 (&offset); +                            s.Printf(" (addr = 0x%16.16llx, size = %u, lcpu = %u, bytes = \n", addr, size, lcpu); +                            if (size > 0) +                                DataExtractor::DumpHexBytes(&s, packet.GetData(&offset, size), size, 32, addr); +                        } +                        break; + +                    case KDP_READREGS: +                        { +                            const uint32_t cpu = packet.GetU32 (&offset); +                            const uint32_t flavor = packet.GetU32 (&offset); +                            s.Printf(" (cpu = %u, flavor = %u)", cpu, flavor); +                        } +                        break; + +                    case KDP_WRITEREGS: +                        { +                            const uint32_t cpu = packet.GetU32 (&offset); +                            const uint32_t flavor = packet.GetU32 (&offset); +                            const uint32_t nbytes = packet.GetByteSize() - offset; +                            s.Printf(" (cpu = %u, flavor = %u, regs = \n", cpu, flavor); +                            if (nbytes > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             m_addr_byte_size,          // Size of each item in bytes +                                             nbytes / m_addr_byte_size, // Number of items +                                             16 / m_addr_byte_size,     // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                        } +                        break; + + +                    case KDP_BREAKPOINT_SET: +                    case KDP_BREAKPOINT_REMOVE: +                        { +                            const uint32_t addr = packet.GetU32 (&offset); +                            s.Printf(" (addr = 0x%8.8x)", addr); +                        } +                        break; + +                    case KDP_BREAKPOINT_SET64: +                    case KDP_BREAKPOINT_REMOVE64: +                        { +                            const uint64_t addr = packet.GetU64 (&offset); +                            s.Printf(" (addr = 0x%16.16" PRIx64 ")", addr); +                        } +                        break; + + +                    case KDP_LOAD: +                        { +                            const char *path = packet.GetCStr(&offset); +                            s.Printf(" (path = \"%s\")", path); +                        } +                        break; + +                    case KDP_EXCEPTION: +                        { +                            const uint32_t count = packet.GetU32 (&offset); +                             +                            for (uint32_t i=0; i<count; ++i) +                            { +                                const uint32_t cpu = packet.GetU32 (&offset); +                                const uint32_t exc = packet.GetU32 (&offset); +                                const uint32_t code = packet.GetU32 (&offset); +                                const uint32_t subcode = packet.GetU32 (&offset); +                                const char *exc_cstr = NULL; +                                switch (exc) +                                { +                                    case 1:  exc_cstr = "EXC_BAD_ACCESS"; break; +                                    case 2:  exc_cstr = "EXC_BAD_INSTRUCTION"; break; +                                    case 3:  exc_cstr = "EXC_ARITHMETIC"; break; +                                    case 4:  exc_cstr = "EXC_EMULATION"; break; +                                    case 5:  exc_cstr = "EXC_SOFTWARE"; break; +                                    case 6:  exc_cstr = "EXC_BREAKPOINT"; break; +                                    case 7:  exc_cstr = "EXC_SYSCALL"; break; +                                    case 8:  exc_cstr = "EXC_MACH_SYSCALL"; break; +                                    case 9:  exc_cstr = "EXC_RPC_ALERT"; break; +                                    case 10: exc_cstr = "EXC_CRASH"; break; +                                    default: +                                        break; +                                } + +                                s.Printf ("{ cpu = 0x%8.8x, exc = %s (%u), code = %u (0x%8.8x), subcode = %u (0x%8.8x)} ",  +                                          cpu, exc_cstr, exc, code, code, subcode, subcode); +                            } +                        } +                        break; + +                    case KDP_TERMINATION: +                        { +                            const uint32_t term_code = packet.GetU32 (&offset); +                            const uint32_t exit_code = packet.GetU32 (&offset); +                            s.Printf(" (term_code = 0x%8.8x (%u), exit_code = 0x%8.8x (%u))", term_code, term_code, exit_code, exit_code); +                        } +                        break; + +                    case KDP_REATTACH: +                        { +                            const uint16_t reply_port = ntohs(packet.GetU16 (&offset)); +                            s.Printf(" (reply_port = %u)", reply_port); +                        } +                        break; + +                    case KDP_READMSR64: +                        { +                            const uint32_t address = packet.GetU32 (&offset); +                            const uint16_t lcpu = packet.GetU16 (&offset); +                            s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x)", address, lcpu); +                        } +                        break; + +                    case KDP_WRITEMSR64: +                        { +                            const uint32_t address = packet.GetU32 (&offset); +                            const uint16_t lcpu = packet.GetU16 (&offset); +                            const uint32_t nbytes = packet.GetByteSize() - offset; +                            s.Printf(" (address=0x%8.8x, lcpu=0x%4.4x, nbytes=0x%8.8x)", lcpu, address, nbytes); +                            if (nbytes > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             1,                         // Size of each item in bytes +                                             nbytes,                    // Number of items +                                             16,                        // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                        } +                        break; + +                    case KDP_READIOPORT: +                        { +                            const uint16_t lcpu = packet.GetU16 (&offset); +                            const uint16_t address = packet.GetU16 (&offset); +                            const uint16_t nbytes = packet.GetU16 (&offset); +                            s.Printf(" (lcpu=0x%4.4x, address=0x%4.4x, nbytes=%u)", lcpu, address, nbytes); +                        } +                        break; + +                    case KDP_WRITEIOPORT: +                         { +                            const uint16_t lcpu = packet.GetU16 (&offset); +                            const uint16_t address = packet.GetU16 (&offset); +                            const uint16_t nbytes = packet.GetU16 (&offset); +                            s.Printf(" (lcpu = %u, addr = 0x%4.4x, nbytes = %u, bytes = \n", lcpu, address, nbytes); +                            if (nbytes > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             1,                         // Size of each item in bytes +                                             nbytes,                    // Number of items +                                             16,                        // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                        } +                        break; +                         +                    case KDP_DUMPINFO: +                        { +                            const uint32_t count = packet.GetByteSize() - offset; +                            s.Printf(" (count = %u, bytes = \n", count); +                            if (count > 0) +                                packet.Dump (&s,                        // Stream to dump to +                                             offset,                    // Offset within "packet" +                                             eFormatHex,                // Format to use +                                             1,                         // Size of each item in bytes +                                             count,                     // Number of items +                                             16,                        // Number per line +                                             LLDB_INVALID_ADDRESS,      // Don't show addresses before each line +                                             0, 0);                     // No bitfields +                             +                        } +                        break; +                         +               } +            } +        } +        else +        { +            error_desc = "error: invalid packet command: "; +        } +    } + +    if (error_desc) +    { +        s.PutCString (error_desc); + +        packet.Dump (&s,                    // Stream to dump to +                     0,                     // Offset into "packet" +                     eFormatBytes,          // Dump as hex bytes +                     1,                     // Size of each item is 1 for single bytes +                     packet.GetByteSize(),  // Number of bytes +                     UINT32_MAX,            // Num bytes per line +                     LLDB_INVALID_ADDRESS,  // Base address +                     0, 0);                 // Bitfield info set to not do anything bitfield related +    } +} + +uint32_t +CommunicationKDP::SendRequestReadRegisters (uint32_t cpu, +                                            uint32_t flavor, +                                            void *dst, +                                            uint32_t dst_len, +                                            Error &error) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_READREGS; +    // Size is header + 4 byte cpu and 4 byte flavor +    const uint32_t command_length = 8 + 4 + 4; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutHex32 (cpu); +    request_packet.PutHex32 (flavor); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        uint32_t kdp_error = reply_packet.GetU32 (&offset); +        uint32_t src_len = reply_packet.GetByteSize() - 12; +         +        if (src_len > 0) +        { +            const uint32_t bytes_to_copy = std::min<uint32_t>(src_len, dst_len); +            const void *src = reply_packet.GetData(&offset, bytes_to_copy); +            if (src) +            { +                ::memcpy (dst, src, bytes_to_copy); +                error.Clear(); +                // Return the number of bytes we could have returned regardless if +                // we copied them or not, just so we know when things don't match up +                return src_len; +            } +        } +        if (kdp_error) +            error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error); +        else +            error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u", cpu, flavor); +    } +    else +    { +        error.SetErrorString ("failed to send packet"); +    } +    return 0; +} + +uint32_t +CommunicationKDP::SendRequestWriteRegisters (uint32_t cpu, +                                             uint32_t flavor, +                                             const void *src, +                                             uint32_t src_len, +                                             Error &error) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_WRITEREGS; +    // Size is header + 4 byte cpu and 4 byte flavor +    const uint32_t command_length = 8 + 4 + 4 + src_len; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutHex32 (cpu); +    request_packet.PutHex32 (flavor); +    request_packet.Write(src, src_len); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        uint32_t kdp_error = reply_packet.GetU32 (&offset); +        if (kdp_error == 0) +            return src_len; +        error.SetErrorStringWithFormat("failed to read kdp registers for cpu %u flavor %u (error %u)", cpu, flavor, kdp_error); +    } +    else +    { +        error.SetErrorString ("failed to send packet"); +    } +    return 0; +} + + +bool +CommunicationKDP::SendRequestResume () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_RESUMECPUS; +    const uint32_t command_length = 12; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutHex32(GetCPUMask()); + +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +        return true; +    return false; +} + +bool +CommunicationKDP::SendRequestBreakpoint (bool set, addr_t addr) +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    bool use_64 = (GetVersion() >= 11); +    uint32_t command_addr_byte_size = use_64 ? 8 : 4; +    const CommandType command = set ? (use_64 ? KDP_BREAKPOINT_SET64    : KDP_BREAKPOINT_SET   ): +                                      (use_64 ? KDP_BREAKPOINT_REMOVE64 : KDP_BREAKPOINT_REMOVE); + +    const uint32_t command_length = 8 + command_addr_byte_size; +    MakeRequestPacketHeader (command, request_packet, command_length); +    request_packet.PutMaxHex64 (addr, command_addr_byte_size); +     +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +    { +        lldb::offset_t offset = 8; +        uint32_t kdp_error = reply_packet.GetU32 (&offset);         +        if (kdp_error == 0) +            return true; +    } +    return false; +} + +bool +CommunicationKDP::SendRequestSuspend () +{ +    PacketStreamType request_packet (Stream::eBinary, m_addr_byte_size, m_byte_order); +    const CommandType command = KDP_SUSPEND; +    const uint32_t command_length = 8; +    MakeRequestPacketHeader (command, request_packet, command_length); +    DataExtractor reply_packet; +    if (SendRequestAndGetReply (command, request_packet, reply_packet)) +        return true; +    return false; +} + diff --git a/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h new file mode 100644 index 0000000000000..98a146d5a06da --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h @@ -0,0 +1,347 @@ +//===-- CommunicationKDP.h --------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommunicationKDP_h_ +#define liblldb_CommunicationKDP_h_ + +// C Includes +// C++ Includes +#include <list> +#include <string> + +// Other libraries and framework includes +// Project includes +#include "lldb/lldb-private.h" +#include "lldb/Core/Communication.h" +#include "lldb/Core/Listener.h" +#include "lldb/Core/StreamBuffer.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Host/Predicate.h" +#include "lldb/Host/TimeValue.h" + +class CommunicationKDP : public lldb_private::Communication +{ +public: +    enum +    { +        eBroadcastBitRunPacketSent = kLoUserBroadcastBit +    }; +     +    const static uint32_t kMaxPacketSize = 1200; +    const static uint32_t kMaxDataSize = 1024; +    typedef lldb_private::StreamBuffer<1024> PacketStreamType; +    typedef enum  +    { +        KDP_CONNECT = 0u,                +        KDP_DISCONNECT, +        KDP_HOSTINFO, +        KDP_VERSION, +        KDP_MAXBYTES, +        KDP_READMEM, +        KDP_WRITEMEM, +        KDP_READREGS, +        KDP_WRITEREGS, +        KDP_LOAD, +        KDP_IMAGEPATH, +        KDP_SUSPEND, +        KDP_RESUMECPUS, +        KDP_EXCEPTION, +        KDP_TERMINATION, +        KDP_BREAKPOINT_SET, +        KDP_BREAKPOINT_REMOVE, +        KDP_REGIONS, +        KDP_REATTACH, +        KDP_HOSTREBOOT, +        KDP_READMEM64, +        KDP_WRITEMEM64, +        KDP_BREAKPOINT_SET64, +        KDP_BREAKPOINT_REMOVE64, +        KDP_KERNELVERSION, +        KDP_READPHYSMEM64, +        KDP_WRITEPHYSMEM64, +        KDP_READIOPORT, +        KDP_WRITEIOPORT, +        KDP_READMSR64, +        KDP_WRITEMSR64, +        KDP_DUMPINFO +    } CommandType; + +    enum  +    { +        KDP_FEATURE_BP = (1u << 0) +    }; + +    typedef enum +    { +        KDP_PROTERR_SUCCESS = 0, +        KDP_PROTERR_ALREADY_CONNECTED, +        KDP_PROTERR_BAD_NBYTES, +        KDP_PROTERR_BADFLAVOR +    } KDPError; +     +    typedef enum +    { +        ePacketTypeRequest  = 0x00u, +        ePacketTypeReply    = 0x80u, +        ePacketTypeMask     = 0x80u, +        eCommandTypeMask    = 0x7fu +    } PacketType; +    //------------------------------------------------------------------ +    // Constructors and Destructors +    //------------------------------------------------------------------ +    CommunicationKDP (const char *comm_name); + +    virtual +    ~CommunicationKDP(); + +    bool +    SendRequestPacket (const PacketStreamType &request_packet); + +    // Wait for a packet within 'nsec' seconds +    size_t +    WaitForPacketWithTimeoutMicroSeconds (lldb_private::DataExtractor &response, +                                          uint32_t usec); + +    bool +    GetSequenceMutex(lldb_private::Mutex::Locker& locker); + +    bool +    CheckForPacket (const uint8_t *src,  +                    size_t src_len,  +                    lldb_private::DataExtractor &packet); +    bool +    IsRunning() const +    { +        return m_is_running.GetValue(); +    } + +    //------------------------------------------------------------------ +    // Set the global packet timeout. +    // +    // For clients, this is the timeout that gets used when sending +    // packets and waiting for responses. For servers, this might not +    // get used, and if it doesn't this should be moved to the +    // CommunicationKDPClient. +    //------------------------------------------------------------------ +    uint32_t  +    SetPacketTimeout (uint32_t packet_timeout) +    { +        const uint32_t old_packet_timeout = m_packet_timeout; +        m_packet_timeout = packet_timeout; +        return old_packet_timeout; +    } + +    uint32_t +    GetPacketTimeoutInMicroSeconds () const +    { +        return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec; +    } +     +    //------------------------------------------------------------------ +    // Public Request Packets +    //------------------------------------------------------------------ +    bool +    SendRequestConnect (uint16_t reply_port,  +                        uint16_t exc_port,  +                        const char *greeting); + +    bool +    SendRequestReattach (uint16_t reply_port); + +    bool +    SendRequestDisconnect (); +     +    uint32_t +    SendRequestReadMemory (lldb::addr_t addr,  +                           void *dst,  +                           uint32_t dst_size, +                           lldb_private::Error &error); + +    uint32_t +    SendRequestWriteMemory (lldb::addr_t addr,  +                            const void *src,  +                            uint32_t src_len, +                            lldb_private::Error &error); + +    bool +    SendRawRequest (uint8_t command_byte, +                    const void *src, +                    uint32_t src_len, +                    lldb_private::DataExtractor &reply, +                    lldb_private::Error &error); + +    uint32_t +    SendRequestReadRegisters (uint32_t cpu, +                              uint32_t flavor, +                              void *dst,  +                              uint32_t dst_size, +                              lldb_private::Error &error); + +    uint32_t +    SendRequestWriteRegisters (uint32_t cpu, +                               uint32_t flavor, +                               const void *src, +                               uint32_t src_size, +                               lldb_private::Error &error); + +    const char * +    GetKernelVersion (); +     +    // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... +    // const char * +    // GetImagePath (); + +    uint32_t +    GetVersion (); + +    uint32_t +    GetFeatureFlags (); + +    bool +    LocalBreakpointsAreSupported () +    { +        return (GetFeatureFlags() & KDP_FEATURE_BP) != 0; +    } + +    uint32_t +    GetCPUMask (); +     +    uint32_t +    GetCPUType (); +     +    uint32_t +    GetCPUSubtype (); + +    lldb_private::UUID  +    GetUUID (); + +    bool +    RemoteIsEFI (); + +    bool +    RemoteIsDarwinKernel (); + +    lldb::addr_t +    GetLoadAddress (); + +    bool +    SendRequestResume (); + +    bool +    SendRequestSuspend (); + +    bool +    SendRequestBreakpoint (bool set, lldb::addr_t addr); + +protected: + +    bool +    SendRequestPacketNoLock (const PacketStreamType &request_packet); + +    size_t +    WaitForPacketWithTimeoutMicroSecondsNoLock (lldb_private::DataExtractor &response,  +                                                uint32_t timeout_usec); + +    bool +    WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr); + +    void +    MakeRequestPacketHeader (CommandType request_type,  +                             PacketStreamType &request_packet, +                             uint16_t request_length); + +    //------------------------------------------------------------------ +    // Protected Request Packets (use public accessors which will cache +    // results. +    //------------------------------------------------------------------ +    bool +    SendRequestVersion (); +     +    bool +    SendRequestHostInfo (); + +    bool +    SendRequestKernelVersion (); +     +    // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... +    //bool +    //SendRequestImagePath (); + +    void +    DumpPacket (lldb_private::Stream &s,  +                const void *data,  +                uint32_t data_len); + +    void +    DumpPacket (lldb_private::Stream &s,  +                const lldb_private::DataExtractor& extractor); + +    bool +    VersionIsValid() const +    { +        return m_kdp_version_version != 0; +    } + +    bool +    HostInfoIsValid() const +    { +        return m_kdp_hostinfo_cpu_type != 0; +    } + +    bool +    ExtractIsReply (uint8_t first_packet_byte) const +    { +        // TODO: handle big endian... +        return (first_packet_byte & ePacketTypeMask) != 0; +    } + +    CommandType +    ExtractCommand (uint8_t first_packet_byte) const +    { +        // TODO: handle big endian... +        return (CommandType)(first_packet_byte & eCommandTypeMask); +    } +     +    static const char * +    GetCommandAsCString (uint8_t command); + +    void +    ClearKDPSettings (); +     +    bool +    SendRequestAndGetReply (const CommandType command, +                            const PacketStreamType &request_packet,  +                            lldb_private::DataExtractor &reply_packet); +    //------------------------------------------------------------------ +    // Classes that inherit from CommunicationKDP can see and modify these +    //------------------------------------------------------------------ +    uint32_t m_addr_byte_size; +    lldb::ByteOrder m_byte_order; +    uint32_t m_packet_timeout; +    lldb_private::Mutex m_sequence_mutex;    // Restrict access to sending/receiving packets to a single thread at a time +    lldb_private::Predicate<bool> m_is_running; +    uint32_t m_session_key; +    uint8_t m_request_sequence_id; +    uint8_t m_exception_sequence_id; +    uint32_t m_kdp_version_version; +    uint32_t m_kdp_version_feature; +    uint32_t m_kdp_hostinfo_cpu_mask; +    uint32_t m_kdp_hostinfo_cpu_type; +    uint32_t m_kdp_hostinfo_cpu_subtype; +    std::string m_kernel_version; +    //std::string m_image_path; // Disable KDP_IMAGEPATH for now, it seems to hang the KDP connection... +    lldb::addr_t m_last_read_memory_addr; // Last memory read address for logging +private: +    //------------------------------------------------------------------ +    // For CommunicationKDP only +    //------------------------------------------------------------------ +    DISALLOW_COPY_AND_ASSIGN (CommunicationKDP); +}; + +#endif  // liblldb_CommunicationKDP_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/Makefile b/source/Plugins/Process/MacOSX-Kernel/Makefile new file mode 100644 index 0000000000000..e42f390ffe0d6 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Process/MacOSX-Darwin/Makefile -------*- Makefile -*-===## +#  +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +#  +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginProcessDarwin +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp new file mode 100644 index 0000000000000..628f76d104fe3 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -0,0 +1,1211 @@ +//===-- ProcessKDP.cpp ------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include <errno.h> +#include <stdlib.h> + +// C++ Includes +#include <mutex> + +// Other libraries and framework includes +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/State.h" +#include "lldb/Core/UUID.h" +#include "lldb/Host/ConnectionFileDescriptor.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/Symbols.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Host/common/TCPSocket.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandObjectMultiword.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionGroupString.h" +#include "lldb/Interpreter/OptionGroupUInt64.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/StringExtractor.h" + +#define USEC_PER_SEC 1000000 + +// Project includes +#include "ProcessKDP.h" +#include "ProcessKDPLog.h" +#include "ThreadKDP.h" +#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" +#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + +    static PropertyDefinition +    g_properties[] = +    { +        { "packet-timeout" , OptionValue::eTypeUInt64 , true , 5, NULL, NULL, "Specify the default packet timeout in seconds." }, +        {  NULL            , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL  } +    }; +     +    enum +    { +        ePropertyPacketTimeout +    }; + +    class PluginProperties : public Properties +    { +    public: +         +        static ConstString +        GetSettingName () +        { +            return ProcessKDP::GetPluginNameStatic(); +        } + +        PluginProperties() : +            Properties () +        { +            m_collection_sp.reset (new OptionValueProperties(GetSettingName())); +            m_collection_sp->Initialize(g_properties); +        } +         +        virtual +        ~PluginProperties() +        { +        } +         +        uint64_t +        GetPacketTimeout() +        { +            const uint32_t idx = ePropertyPacketTimeout; +            return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value); +        } +    }; + +    typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; + +    static const ProcessKDPPropertiesSP & +    GetGlobalPluginProperties() +    { +        static ProcessKDPPropertiesSP g_settings_sp; +        if (!g_settings_sp) +            g_settings_sp.reset (new PluginProperties ()); +        return g_settings_sp; +    } +     +} // anonymous namespace end + +static const lldb::tid_t g_kernel_tid = 1; + +ConstString +ProcessKDP::GetPluginNameStatic() +{ +    static ConstString g_name("kdp-remote"); +    return g_name; +} + +const char * +ProcessKDP::GetPluginDescriptionStatic() +{ +    return "KDP Remote protocol based debugging plug-in for darwin kernel debugging."; +} + +void +ProcessKDP::Terminate() +{ +    PluginManager::UnregisterPlugin (ProcessKDP::CreateInstance); +} + + +lldb::ProcessSP +ProcessKDP::CreateInstance (TargetSP target_sp, +                            Listener &listener, +                            const FileSpec *crash_file_path) +{ +    lldb::ProcessSP process_sp; +    if (crash_file_path == NULL) +        process_sp.reset(new ProcessKDP (target_sp, listener)); +    return process_sp; +} + +bool +ProcessKDP::CanDebug(TargetSP target_sp, bool plugin_specified_by_name) +{ +    if (plugin_specified_by_name) +        return true; + +    // For now we are just making sure the file exists for a given module +    Module *exe_module = target_sp->GetExecutableModulePointer(); +    if (exe_module) +    { +        const llvm::Triple &triple_ref = target_sp->GetArchitecture().GetTriple(); +        switch (triple_ref.getOS()) +        { +            case llvm::Triple::Darwin:  // Should use "macosx" for desktop and "ios" for iOS, but accept darwin just in case +            case llvm::Triple::MacOSX:  // For desktop targets +            case llvm::Triple::IOS:     // For arm targets +            case llvm::Triple::TvOS: +            case llvm::Triple::WatchOS: +                if (triple_ref.getVendor() == llvm::Triple::Apple) +                { +                    ObjectFile *exe_objfile = exe_module->GetObjectFile(); +                    if (exe_objfile->GetType() == ObjectFile::eTypeExecutable &&  +                        exe_objfile->GetStrata() == ObjectFile::eStrataKernel) +                        return true; +                } +                break; + +            default: +                break; +        } +    } +    return false; +} + +//---------------------------------------------------------------------- +// ProcessKDP constructor +//---------------------------------------------------------------------- +ProcessKDP::ProcessKDP(TargetSP target_sp, Listener &listener) : +    Process (target_sp, listener), +    m_comm("lldb.process.kdp-remote.communication"), +    m_async_broadcaster (NULL, "lldb.process.kdp-remote.async-broadcaster"), +    m_dyld_plugin_name (), +    m_kernel_load_addr (LLDB_INVALID_ADDRESS), +    m_command_sp(), +    m_kernel_thread_wp() +{ +    m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit,   "async thread should exit"); +    m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue,           "async thread continue"); +    const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout(); +    if (timeout_seconds > 0) +        m_comm.SetPacketTimeout(timeout_seconds); +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ProcessKDP::~ProcessKDP() +{ +    Clear(); +    // We need to call finalize on the process before destroying ourselves +    // to make sure all of the broadcaster cleanup goes as planned. If we +    // destruct this class, then Process::~Process() might have problems +    // trying to fully destroy the broadcaster. +    Finalize(); +} + +//---------------------------------------------------------------------- +// PluginInterface +//---------------------------------------------------------------------- +lldb_private::ConstString +ProcessKDP::GetPluginName() +{ +    return GetPluginNameStatic(); +} + +uint32_t +ProcessKDP::GetPluginVersion() +{ +    return 1; +} + +Error +ProcessKDP::WillLaunch (Module* module) +{ +    Error error; +    error.SetErrorString ("launching not supported in kdp-remote plug-in"); +    return error; +} + +Error +ProcessKDP::WillAttachToProcessWithID (lldb::pid_t pid) +{ +    Error error; +    error.SetErrorString ("attaching to a by process ID not supported in kdp-remote plug-in"); +    return error; +} + +Error +ProcessKDP::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) +{ +    Error error; +    error.SetErrorString ("attaching to a by process name not supported in kdp-remote plug-in"); +    return error; +} + +bool +ProcessKDP::GetHostArchitecture(ArchSpec &arch) +{ +    uint32_t cpu = m_comm.GetCPUType(); +    if (cpu) +    { +        uint32_t sub = m_comm.GetCPUSubtype(); +        arch.SetArchitecture(eArchTypeMachO, cpu, sub); +        // Leave architecture vendor as unspecified unknown +        arch.GetTriple().setVendor(llvm::Triple::UnknownVendor); +        arch.GetTriple().setVendorName(llvm::StringRef()); +        return true; +    } +    arch.Clear(); +    return false; +} + +Error +ProcessKDP::DoConnectRemote (Stream *strm, const char *remote_url) +{ +    Error error; + +    // Don't let any JIT happen when doing KDP as we can't allocate +    // memory and we don't want to be mucking with threads that might +    // already be handling exceptions +    SetCanJIT(false); + +    if (remote_url == NULL || remote_url[0] == '\0') +    { +        error.SetErrorStringWithFormat ("invalid connection URL '%s'", remote_url); +        return error; +    } + +    std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); +    if (conn_ap.get()) +    { +        // Only try once for now. +        // TODO: check if we should be retrying? +        const uint32_t max_retry_count = 1; +        for (uint32_t retry_count = 0; retry_count < max_retry_count; ++retry_count) +        { +            if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess) +                break; +            usleep (100000); +        } +    } + +    if (conn_ap->IsConnected()) +    { +        const TCPSocket& socket = static_cast<const TCPSocket&>(*conn_ap->GetReadObject()); +        const uint16_t reply_port = socket.GetLocalPortNumber(); + +        if (reply_port != 0) +        { +            m_comm.SetConnection(conn_ap.release()); + +            if (m_comm.SendRequestReattach(reply_port)) +            { +                if (m_comm.SendRequestConnect(reply_port, reply_port, "Greetings from LLDB...")) +                { +                    m_comm.GetVersion(); + +                    Target &target = GetTarget(); +                    ArchSpec kernel_arch; +                    // The host architecture +                    GetHostArchitecture(kernel_arch); +                    ArchSpec target_arch = target.GetArchitecture(); +                    // Merge in any unspecified stuff into the target architecture in +                    // case the target arch isn't set at all or incompletely. +                    target_arch.MergeFrom(kernel_arch); +                    target.SetArchitecture(target_arch); + +                    /* Get the kernel's UUID and load address via KDP_KERNELVERSION packet.  */ +                    /* An EFI kdp session has neither UUID nor load address. */ + +                    UUID kernel_uuid = m_comm.GetUUID (); +                    addr_t kernel_load_addr = m_comm.GetLoadAddress (); + +                    if (m_comm.RemoteIsEFI ()) +                    { +                        // Select an invalid plugin name for the dynamic loader so one doesn't get used +                        // since EFI does its own manual loading via python scripting +                        static ConstString g_none_dynamic_loader("none"); +                        m_dyld_plugin_name = g_none_dynamic_loader; + +                        if (kernel_uuid.IsValid()) { +                            // If EFI passed in a UUID= try to lookup UUID +                            // The slide will not be provided. But the UUID +                            // lookup will be used to launch EFI debug scripts +                            // from the dSYM, that can load all of the symbols. +                            ModuleSpec module_spec; +                            module_spec.GetUUID() = kernel_uuid; +                            module_spec.GetArchitecture() = target.GetArchitecture(); + +                            // Lookup UUID locally, before attempting dsymForUUID like action +                            module_spec.GetSymbolFileSpec() = Symbols::LocateExecutableSymbolFile(module_spec); +                            if (module_spec.GetSymbolFileSpec()) +                            { +                                ModuleSpec executable_module_spec = Symbols::LocateExecutableObjectFile (module_spec); +                                if (executable_module_spec.GetFileSpec().Exists()) +                                { +                                    module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); +                                } +                            } +                            if (!module_spec.GetSymbolFileSpec() || !module_spec.GetSymbolFileSpec()) +                                 Symbols::DownloadObjectAndSymbolFile (module_spec, true); + +                            if (module_spec.GetFileSpec().Exists()) +                            { +                                ModuleSP module_sp(new Module (module_spec)); +                                if (module_sp.get() && module_sp->GetObjectFile()) +                                { +                                    // Get the current target executable +                                    ModuleSP exe_module_sp (target.GetExecutableModule ()); + +                                    // Make sure you don't already have the right module loaded and they will be uniqued +                                    if (exe_module_sp.get() != module_sp.get()) +                                        target.SetExecutableModule (module_sp, false); +                                } +                            } +                        } +                    } +                    else if (m_comm.RemoteIsDarwinKernel ()) +                    { +                        m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); +                        if (kernel_load_addr != LLDB_INVALID_ADDRESS) +                        { +                            m_kernel_load_addr = kernel_load_addr; +                        } +                    } + +                    // Set the thread ID +                    UpdateThreadListIfNeeded (); +                    SetID (1); +                    GetThreadList (); +                    SetPrivateState (eStateStopped); +                    StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream()); +                    if (async_strm_sp) +                    { +                        const char *cstr; +                        if ((cstr = m_comm.GetKernelVersion ()) != NULL) +                        { +                            async_strm_sp->Printf ("Version: %s\n", cstr); +                            async_strm_sp->Flush(); +                        } +//                      if ((cstr = m_comm.GetImagePath ()) != NULL) +//                      { +//                          async_strm_sp->Printf ("Image Path: %s\n", cstr); +//                          async_strm_sp->Flush(); +//                      }             +                    } +                } +                else +                { +                    error.SetErrorString("KDP_REATTACH failed"); +                } +            } +            else +            { +                error.SetErrorString("KDP_REATTACH failed"); +            } +        } +        else +        { +            error.SetErrorString("invalid reply port from UDP connection"); +        } +    } +    else +    { +        if (error.Success()) +            error.SetErrorStringWithFormat ("failed to connect to '%s'", remote_url); +    } +    if (error.Fail()) +        m_comm.Disconnect(); + +    return error; +} + +//---------------------------------------------------------------------- +// Process Control +//---------------------------------------------------------------------- +Error +ProcessKDP::DoLaunch (Module *exe_module,  +                      ProcessLaunchInfo &launch_info) +{ +    Error error; +    error.SetErrorString ("launching not supported in kdp-remote plug-in"); +    return error; +} + +Error +ProcessKDP::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) +{ +    Error error; +    error.SetErrorString ("attach to process by ID is not suppported in kdp remote debugging"); +    return error; +} + +Error +ProcessKDP::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) +{ +    Error error; +    error.SetErrorString ("attach to process by name is not suppported in kdp remote debugging"); +    return error; +} + + +void +ProcessKDP::DidAttach (ArchSpec &process_arch) +{ +    Process::DidAttach(process_arch); +     +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); +    if (log) +        log->Printf ("ProcessKDP::DidAttach()"); +    if (GetID() != LLDB_INVALID_PROCESS_ID) +    { +        GetHostArchitecture(process_arch); +    } +} + +addr_t +ProcessKDP::GetImageInfoAddress() +{ +    return m_kernel_load_addr; +} + +lldb_private::DynamicLoader * +ProcessKDP::GetDynamicLoader () +{ +    if (m_dyld_ap.get() == NULL) +        m_dyld_ap.reset (DynamicLoader::FindPlugin(this, m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString())); +    return m_dyld_ap.get(); +} + +Error +ProcessKDP::WillResume () +{ +    return Error(); +} + +Error +ProcessKDP::DoResume () +{ +    Error error; +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); +    // Only start the async thread if we try to do any process control +    if (!m_async_thread.IsJoinable()) +        StartAsyncThread(); + +    bool resume = false; +     +    // With KDP there is only one thread we can tell what to do +    ThreadSP kernel_thread_sp (m_thread_list.FindThreadByProtocolID(g_kernel_tid)); +                             +    if (kernel_thread_sp) +    { +        const StateType thread_resume_state = kernel_thread_sp->GetTemporaryResumeState(); +         +        if (log) +            log->Printf ("ProcessKDP::DoResume() thread_resume_state = %s", StateAsCString(thread_resume_state)); +        switch (thread_resume_state) +        { +            case eStateSuspended: +                // Nothing to do here when a thread will stay suspended +                // we just leave the CPU mask bit set to zero for the thread +                if (log) +                    log->Printf ("ProcessKDP::DoResume() = suspended???"); +                break; +                 +            case eStateStepping: +                { +                    lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext()); + +                    if (reg_ctx_sp) +                    { +                        if (log) +                            log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true);"); +                        reg_ctx_sp->HardwareSingleStep (true); +                        resume = true; +                    } +                    else +                    { +                        error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID()); +                    } +                } +                break; +     +            case eStateRunning: +                { +                    lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext()); +                     +                    if (reg_ctx_sp) +                    { +                        if (log) +                            log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (false);"); +                        reg_ctx_sp->HardwareSingleStep (false); +                        resume = true; +                    } +                    else +                    { +                        error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID()); +                    } +                } +                break; + +            default: +                // The only valid thread resume states are listed above +                assert (!"invalid thread resume state"); +                break; +        } +    } + +    if (resume) +    { +        if (log) +            log->Printf ("ProcessKDP::DoResume () sending resume"); +         +        if (m_comm.SendRequestResume ()) +        { +            m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue); +            SetPrivateState(eStateRunning); +        } +        else +            error.SetErrorString ("KDP resume failed"); +    } +    else +    { +        error.SetErrorString ("kernel thread is suspended");         +    } +     +    return error; +} + +lldb::ThreadSP +ProcessKDP::GetKernelThread() +{ +    // KDP only tells us about one thread/core. Any other threads will usually +    // be the ones that are read from memory by the OS plug-ins. +     +    ThreadSP thread_sp (m_kernel_thread_wp.lock()); +    if (!thread_sp) +    { +        thread_sp.reset(new ThreadKDP (*this, g_kernel_tid)); +        m_kernel_thread_wp = thread_sp; +    } +    return thread_sp; +} + + + + +bool +ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) +{ +    // locker will keep a mutex locked until it goes out of scope +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_THREAD)); +    if (log && log->GetMask().Test(KDP_LOG_VERBOSE)) +        log->Printf ("ProcessKDP::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); +     +    // Even though there is a CPU mask, it doesn't mean we can see each CPU +    // individually, there is really only one. Lets call this thread 1. +    ThreadSP thread_sp (old_thread_list.FindThreadByProtocolID(g_kernel_tid, false)); +    if (!thread_sp) +        thread_sp = GetKernelThread (); +    new_thread_list.AddThread(thread_sp); + +    return new_thread_list.GetSize(false) > 0; +} + +void +ProcessKDP::RefreshStateAfterStop () +{ +    // Let all threads recover from stopping and do any clean up based +    // on the previous thread state (if any). +    m_thread_list.RefreshStateAfterStop(); +} + +Error +ProcessKDP::DoHalt (bool &caused_stop) +{ +    Error error; +     +    if (m_comm.IsRunning()) +    { +        if (m_destroy_in_process) +        { +            // If we are attemping to destroy, we need to not return an error to +            // Halt or DoDestroy won't get called. +            // We are also currently running, so send a process stopped event +            SetPrivateState (eStateStopped); +        } +        else +        { +            error.SetErrorString ("KDP cannot interrupt a running kernel"); +        } +    } +    return error; +} + +Error +ProcessKDP::DoDetach(bool keep_stopped) +{ +    Error error; +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); +    if (log) +        log->Printf ("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped); +     +    if (m_comm.IsRunning()) +    { +        // We are running and we can't interrupt a running kernel, so we need +        // to just close the connection to the kernel and hope for the best +    } +    else +    { +        // If we are going to keep the target stopped, then don't send the disconnect message. +        if (!keep_stopped && m_comm.IsConnected()) +        { +            const bool success = m_comm.SendRequestDisconnect(); +            if (log) +            { +                if (success) +                    log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully"); +                else +                    log->PutCString ("ProcessKDP::DoDetach() connection channel shutdown failed"); +            } +            m_comm.Disconnect (); +        } +    } +    StopAsyncThread ();     +    m_comm.Clear(); +     +    SetPrivateState (eStateDetached); +    ResumePrivateStateThread(); +     +    //KillDebugserverProcess (); +    return error; +} + +Error +ProcessKDP::DoDestroy () +{ +    // For KDP there really is no difference between destroy and detach +    bool keep_stopped = false; +    return DoDetach(keep_stopped); +} + +//------------------------------------------------------------------ +// Process Queries +//------------------------------------------------------------------ + +bool +ProcessKDP::IsAlive () +{ +    return m_comm.IsConnected() && Process::IsAlive(); +} + +//------------------------------------------------------------------ +// Process Memory +//------------------------------------------------------------------ +size_t +ProcessKDP::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) +{ +    uint8_t *data_buffer = (uint8_t *) buf; +    if (m_comm.IsConnected()) +    { +        const size_t max_read_size = 512; +        size_t total_bytes_read = 0; + +        // Read the requested amount of memory in 512 byte chunks +        while (total_bytes_read < size) +        { +            size_t bytes_to_read_this_request = size - total_bytes_read; +            if (bytes_to_read_this_request > max_read_size) +            { +                bytes_to_read_this_request = max_read_size; +            } +            size_t bytes_read = m_comm.SendRequestReadMemory (addr + total_bytes_read,  +                                                              data_buffer + total_bytes_read,  +                                                              bytes_to_read_this_request, error); +            total_bytes_read += bytes_read; +            if (error.Fail() || bytes_read == 0) +            { +                return total_bytes_read; +            } +        } + +        return total_bytes_read; +    } +    error.SetErrorString ("not connected"); +    return 0; +} + +size_t +ProcessKDP::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) +{ +    if (m_comm.IsConnected()) +        return m_comm.SendRequestWriteMemory (addr, buf, size, error); +    error.SetErrorString ("not connected"); +    return 0; +} + +lldb::addr_t +ProcessKDP::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) +{ +    error.SetErrorString ("memory allocation not suppported in kdp remote debugging"); +    return LLDB_INVALID_ADDRESS; +} + +Error +ProcessKDP::DoDeallocateMemory (lldb::addr_t addr) +{ +    Error error; +    error.SetErrorString ("memory deallocation not suppported in kdp remote debugging"); +    return error; +} + +Error +ProcessKDP::EnableBreakpointSite (BreakpointSite *bp_site) +{ +    if (m_comm.LocalBreakpointsAreSupported ()) +    { +        Error error; +        if (!bp_site->IsEnabled()) +        { +            if (m_comm.SendRequestBreakpoint(true, bp_site->GetLoadAddress())) +            { +                bp_site->SetEnabled(true); +                bp_site->SetType (BreakpointSite::eExternal); +            } +            else +            { +                error.SetErrorString ("KDP set breakpoint failed"); +            } +        } +        return error; +    } +    return EnableSoftwareBreakpoint (bp_site); +} + +Error +ProcessKDP::DisableBreakpointSite (BreakpointSite *bp_site) +{ +    if (m_comm.LocalBreakpointsAreSupported ()) +    { +        Error error; +        if (bp_site->IsEnabled()) +        { +            BreakpointSite::Type bp_type = bp_site->GetType(); +            if (bp_type == BreakpointSite::eExternal) +            { +                if (m_destroy_in_process && m_comm.IsRunning()) +                { +                    // We are trying to destroy our connection and we are running +                    bp_site->SetEnabled(false); +                } +                else +                { +                    if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress())) +                        bp_site->SetEnabled(false); +                    else +                        error.SetErrorString ("KDP remove breakpoint failed"); +                } +            } +            else +            { +                error = DisableSoftwareBreakpoint (bp_site); +            } +        } +        return error; +    } +    return DisableSoftwareBreakpoint (bp_site); +} + +Error +ProcessKDP::EnableWatchpoint (Watchpoint *wp, bool notify) +{ +    Error error; +    error.SetErrorString ("watchpoints are not suppported in kdp remote debugging"); +    return error; +} + +Error +ProcessKDP::DisableWatchpoint (Watchpoint *wp, bool notify) +{ +    Error error; +    error.SetErrorString ("watchpoints are not suppported in kdp remote debugging"); +    return error; +} + +void +ProcessKDP::Clear() +{ +    m_thread_list.Clear(); +} + +Error +ProcessKDP::DoSignal (int signo) +{ +    Error error; +    error.SetErrorString ("sending signals is not suppported in kdp remote debugging"); +    return error; +} + +void +ProcessKDP::Initialize() +{ +    static std::once_flag g_once_flag; + +    std::call_once(g_once_flag, []() +    { +        PluginManager::RegisterPlugin (GetPluginNameStatic(), +                                       GetPluginDescriptionStatic(), +                                       CreateInstance, +                                       DebuggerInitialize); + +        Log::Callbacks log_callbacks = { +            ProcessKDPLog::DisableLog, +            ProcessKDPLog::EnableLog, +            ProcessKDPLog::ListLogCategories +        }; + +        Log::RegisterLogChannel (ProcessKDP::GetPluginNameStatic(), log_callbacks); +    }); +} + +void +ProcessKDP::DebuggerInitialize (lldb_private::Debugger &debugger) +{ +    if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName())) +    { +        const bool is_global_setting = true; +        PluginManager::CreateSettingForProcessPlugin (debugger, +                                                      GetGlobalPluginProperties()->GetValueProperties(), +                                                      ConstString ("Properties for the kdp-remote process plug-in."), +                                                      is_global_setting); +    } +} + +bool +ProcessKDP::StartAsyncThread () +{ +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); +     +    if (log) +        log->Printf ("ProcessKDP::StartAsyncThread ()"); + +    if (m_async_thread.IsJoinable()) +        return true; + +    m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.kdp-remote.async>", ProcessKDP::AsyncThread, this, NULL); +    return m_async_thread.IsJoinable(); +} + +void +ProcessKDP::StopAsyncThread () +{ +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); +     +    if (log) +        log->Printf ("ProcessKDP::StopAsyncThread ()"); +     +    m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); +     +    // Stop the stdio thread +    if (m_async_thread.IsJoinable()) +        m_async_thread.Join(nullptr); +} + + +void * +ProcessKDP::AsyncThread (void *arg) +{ +    ProcessKDP *process = (ProcessKDP*) arg; +     +    const lldb::pid_t pid = process->GetID(); + +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); +    if (log) +        log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread starting...", arg, pid); +     +    Listener listener ("ProcessKDP::AsyncThread"); +    EventSP event_sp; +    const uint32_t desired_event_mask = eBroadcastBitAsyncContinue | +                                        eBroadcastBitAsyncThreadShouldExit; +     +     +    if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask) +    { +        bool done = false; +        while (!done) +        { +            if (log) +                log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", +                             pid); +            if (listener.WaitForEvent (NULL, event_sp)) +            { +                uint32_t event_type = event_sp->GetType(); +                if (log) +                    log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") Got an event of type: %d...", +                                 pid, +                                 event_type); +                 +                // When we are running, poll for 1 second to try and get an exception +                // to indicate the process has stopped. If we don't get one, check to +                // make sure no one asked us to exit +                bool is_running = false; +                DataExtractor exc_reply_packet; +                do +                { +                    switch (event_type) +                    { +                    case eBroadcastBitAsyncContinue: +                        { +                            is_running = true; +                            if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds (exc_reply_packet, 1 * USEC_PER_SEC)) +                            { +                                ThreadSP thread_sp (process->GetKernelThread()); +                                if (thread_sp) +                                { +                                    lldb::RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); +                                    if (reg_ctx_sp) +                                        reg_ctx_sp->InvalidateAllRegisters(); +                                    static_cast<ThreadKDP *>(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet); +                                } + +                                // TODO: parse the stop reply packet +                                is_running = false;                                 +                                process->SetPrivateState(eStateStopped); +                            } +                            else +                            { +                                // Check to see if we are supposed to exit. There is no way to +                                // interrupt a running kernel, so all we can do is wait for an +                                // exception or detach... +                                if (listener.GetNextEvent(event_sp)) +                                { +                                    // We got an event, go through the loop again +                                    event_type = event_sp->GetType(); +                                } +                            } +                        } +                        break; +                             +                    case eBroadcastBitAsyncThreadShouldExit: +                        if (log) +                            log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", +                                         pid); +                        done = true; +                        is_running = false; +                        break; +                             +                    default: +                        if (log) +                            log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got unknown event 0x%8.8x", +                                         pid, +                                         event_type); +                        done = true; +                        is_running = false; +                        break; +                    } +                } while (is_running); +            } +            else +            { +                if (log) +                    log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", +                                 pid); +                done = true; +            } +        } +    } +     +    if (log) +        log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread exiting...", +                     arg, +                     pid); + +    process->m_async_thread.Reset(); +    return NULL; +} + + +class CommandObjectProcessKDPPacketSend : public CommandObjectParsed +{ +private: +     +    OptionGroupOptions m_option_group; +    OptionGroupUInt64 m_command_byte; +    OptionGroupString m_packet_data; +     +    virtual Options * +    GetOptions () +    { +        return &m_option_group; +    } +     + +public: +    CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) : +        CommandObjectParsed (interpreter, +                             "process plugin packet send", +                             "Send a custom packet through the KDP protocol by specifying the command byte and the packet payload data. A packet will be sent with a correct header and payload, and the raw result bytes will be displayed as a string value. ", +                             NULL), +        m_option_group (interpreter), +        m_command_byte(LLDB_OPT_SET_1, true , "command", 'c', 0, eArgTypeNone, "Specify the command byte to use when sending the KDP request packet.", 0), +        m_packet_data (LLDB_OPT_SET_1, false, "payload", 'p', 0, eArgTypeNone, "Specify packet payload bytes as a hex ASCII string with no spaces or hex prefixes.", NULL) +    { +        m_option_group.Append (&m_command_byte, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +        m_option_group.Append (&m_packet_data , LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); +        m_option_group.Finalize(); +    } +     +    ~CommandObjectProcessKDPPacketSend () +    { +    } +     +    bool +    DoExecute (Args& command, CommandReturnObject &result) +    { +        const size_t argc = command.GetArgumentCount(); +        if (argc == 0) +        { +            if (!m_command_byte.GetOptionValue().OptionWasSet()) +            { +                result.AppendError ("the --command option must be set to a valid command byte"); +                result.SetStatus (eReturnStatusFailed); +            } +            else +            { +                const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0); +                if (command_byte > 0 && command_byte <= UINT8_MAX) +                { +                    ProcessKDP *process = (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr(); +                    if (process) +                    { +                        const StateType state = process->GetState(); +                         +                        if (StateIsStoppedState (state, true)) +                        { +                            std::vector<uint8_t> payload_bytes; +                            const char *ascii_hex_bytes_cstr = m_packet_data.GetOptionValue().GetCurrentValue(); +                            if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) +                            { +                                StringExtractor extractor(ascii_hex_bytes_cstr); +                                const size_t ascii_hex_bytes_cstr_len = extractor.GetStringRef().size(); +                                if (ascii_hex_bytes_cstr_len & 1) +                                { +                                    result.AppendErrorWithFormat ("payload data must contain an even number of ASCII hex characters: '%s'", ascii_hex_bytes_cstr); +                                    result.SetStatus (eReturnStatusFailed); +                                    return false; +                                } +                                payload_bytes.resize(ascii_hex_bytes_cstr_len/2); +                                if (extractor.GetHexBytes(&payload_bytes[0], payload_bytes.size(), '\xdd') != payload_bytes.size()) +                                { +                                    result.AppendErrorWithFormat ("payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr); +                                    result.SetStatus (eReturnStatusFailed); +                                    return false; +                                } +                            } +                            Error error; +                            DataExtractor reply; +                            process->GetCommunication().SendRawRequest (command_byte, +                                                                        payload_bytes.empty() ? NULL : payload_bytes.data(), +                                                                        payload_bytes.size(), +                                                                        reply, +                                                                        error); +                             +                            if (error.Success()) +                            { +                                // Copy the binary bytes into a hex ASCII string for the result +                                StreamString packet; +                                packet.PutBytesAsRawHex8(reply.GetDataStart(), +                                                         reply.GetByteSize(), +                                                         endian::InlHostByteOrder(), +                                                         endian::InlHostByteOrder()); +                                result.AppendMessage(packet.GetString().c_str()); +                                result.SetStatus (eReturnStatusSuccessFinishResult); +                                return true; +                            } +                            else +                            { +                                const char *error_cstr = error.AsCString(); +                                if (error_cstr && error_cstr[0]) +                                    result.AppendError (error_cstr); +                                else +                                    result.AppendErrorWithFormat ("unknown error 0x%8.8x", error.GetError()); +                                result.SetStatus (eReturnStatusFailed); +                                return false; +                            } +                        } +                        else +                        { +                            result.AppendErrorWithFormat ("process must be stopped in order to send KDP packets, state is %s", StateAsCString (state)); +                            result.SetStatus (eReturnStatusFailed); +                        } +                    } +                    else +                    { +                        result.AppendError ("invalid process"); +                        result.SetStatus (eReturnStatusFailed); +                    } +                } +                else +                { +                    result.AppendErrorWithFormat ("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte); +                    result.SetStatus (eReturnStatusFailed); +                } +            } +        } +        else +        { +            result.AppendErrorWithFormat ("'%s' takes no arguments, only options.", m_cmd_name.c_str()); +            result.SetStatus (eReturnStatusFailed); +        } +        return false; +    } +}; + +class CommandObjectProcessKDPPacket : public CommandObjectMultiword +{ +private: + +public: +    CommandObjectProcessKDPPacket(CommandInterpreter &interpreter) : +    CommandObjectMultiword (interpreter, +                            "process plugin packet", +                            "Commands that deal with KDP remote packets.", +                            NULL) +    { +        LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessKDPPacketSend (interpreter))); +    } +     +    ~CommandObjectProcessKDPPacket () +    { +    } +}; + +class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword +{ +public: +    CommandObjectMultiwordProcessKDP (CommandInterpreter &interpreter) : +    CommandObjectMultiword (interpreter, +                            "process plugin", +                            "A set of commands for operating on a ProcessKDP process.", +                            "process plugin <subcommand> [<subcommand-options>]") +    { +        LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessKDPPacket    (interpreter))); +    } +     +    ~CommandObjectMultiwordProcessKDP () +    { +    } +}; + +CommandObject * +ProcessKDP::GetPluginCommandObject() +{ +    if (!m_command_sp) +        m_command_sp.reset (new CommandObjectMultiwordProcessKDP (GetTarget().GetDebugger().GetCommandInterpreter())); +    return m_command_sp.get(); +} + diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h new file mode 100644 index 0000000000000..fe9a4e2844bf3 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h @@ -0,0 +1,274 @@ +//===-- ProcessKDP.h --------------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ProcessKDP_h_ +#define liblldb_ProcessKDP_h_ + +// C Includes + +// C++ Includes +#include <list> +#include <vector> + +// Other libraries and framework includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Broadcaster.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/StringList.h" +#include "lldb/Core/ThreadSafeValue.h" +#include "lldb/Host/HostThread.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +#include "CommunicationKDP.h" + +class ThreadKDP; + +class ProcessKDP : public lldb_private::Process +{ +public: +    //------------------------------------------------------------------ +    // Constructors and Destructors +    //------------------------------------------------------------------ +    static lldb::ProcessSP +    CreateInstance (lldb::TargetSP target_sp, +                    lldb_private::Listener &listener, +                    const lldb_private::FileSpec *crash_file_path); +     +    static void +    Initialize(); +     +    static void +    DebuggerInitialize (lldb_private::Debugger &debugger); + +    static void +    Terminate(); +     +    static lldb_private::ConstString +    GetPluginNameStatic(); +     +    static const char * +    GetPluginDescriptionStatic(); +     +    //------------------------------------------------------------------ +    // Constructors and Destructors +    //------------------------------------------------------------------ +    ProcessKDP(lldb::TargetSP target_sp, lldb_private::Listener &listener); +     +    virtual +    ~ProcessKDP(); +     +    //------------------------------------------------------------------ +    // Check if a given Process +    //------------------------------------------------------------------ +    virtual bool +    CanDebug (lldb::TargetSP target_sp, +              bool plugin_specified_by_name); +     +    virtual lldb_private::CommandObject * +    GetPluginCommandObject(); +     +    //------------------------------------------------------------------ +    // Creating a new process, or attaching to an existing one +    //------------------------------------------------------------------ +    virtual lldb_private::Error +    WillLaunch (lldb_private::Module* module); +     +    virtual lldb_private::Error +    DoLaunch (lldb_private::Module *exe_module,  +              lldb_private::ProcessLaunchInfo &launch_info); +     +    virtual lldb_private::Error +    WillAttachToProcessWithID (lldb::pid_t pid); +     +    virtual lldb_private::Error +    WillAttachToProcessWithName (const char *process_name, bool wait_for_launch); +     +    virtual lldb_private::Error +    DoConnectRemote (lldb_private::Stream *strm, const char *remote_url); +     +    virtual lldb_private::Error +    DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info); +     +    virtual lldb_private::Error +    DoAttachToProcessWithName (const char *process_name, const lldb_private::ProcessAttachInfo &attach_info); +     +    virtual void +    DidAttach (lldb_private::ArchSpec &process_arch); +     +    lldb::addr_t +    GetImageInfoAddress(); + +    lldb_private::DynamicLoader * +    GetDynamicLoader (); + +    //------------------------------------------------------------------ +    // PluginInterface protocol +    //------------------------------------------------------------------ +    virtual lldb_private::ConstString +    GetPluginName(); +     +    virtual uint32_t +    GetPluginVersion(); +     +    //------------------------------------------------------------------ +    // Process Control +    //------------------------------------------------------------------ +    virtual lldb_private::Error +    WillResume (); +     +    virtual lldb_private::Error +    DoResume (); +     +    virtual lldb_private::Error +    DoHalt (bool &caused_stop); +     +    virtual lldb_private::Error +    DoDetach (bool keep_stopped); +     +    virtual lldb_private::Error +    DoSignal (int signal); +     +    virtual lldb_private::Error +    DoDestroy (); +     +    virtual void +    RefreshStateAfterStop(); +     +    //------------------------------------------------------------------ +    // Process Queries +    //------------------------------------------------------------------ +    virtual bool +    IsAlive (); +     +    //------------------------------------------------------------------ +    // Process Memory +    //------------------------------------------------------------------ +    virtual size_t +    DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); +     +    virtual size_t +    DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error); +     +    virtual lldb::addr_t +    DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error); +     +    virtual lldb_private::Error +    DoDeallocateMemory (lldb::addr_t ptr); + +    //---------------------------------------------------------------------- +    // Process Breakpoints +    //---------------------------------------------------------------------- +    virtual lldb_private::Error +    EnableBreakpointSite (lldb_private::BreakpointSite *bp_site); +     +    virtual lldb_private::Error +    DisableBreakpointSite (lldb_private::BreakpointSite *bp_site); +     +    //---------------------------------------------------------------------- +    // Process Watchpoints +    //---------------------------------------------------------------------- +    virtual lldb_private::Error +    EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true); +     +    virtual lldb_private::Error +    DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true); +     +    CommunicationKDP & +    GetCommunication() +    { +        return m_comm; +    } + +protected: +    friend class ThreadKDP; +    friend class CommunicationKDP; +     +    //---------------------------------------------------------------------- +    // Accessors +    //---------------------------------------------------------------------- +    bool +    IsRunning ( lldb::StateType state ) +    { +        return    state == lldb::eStateRunning || IsStepping(state); +    } +     +    bool +    IsStepping ( lldb::StateType state) +    { +        return    state == lldb::eStateStepping; +    } + +    bool +    CanResume ( lldb::StateType state) +    { +        return state == lldb::eStateStopped; +    } +     +    bool +    HasExited (lldb::StateType state) +    { +        return state == lldb::eStateExited; +    } + +    bool +    GetHostArchitecture (lldb_private::ArchSpec &arch); + +    bool +    ProcessIDIsValid ( ) const; +     +    void +    Clear ( ); +     +    virtual bool +    UpdateThreadList (lldb_private::ThreadList &old_thread_list,  +                      lldb_private::ThreadList &new_thread_list); +     +    enum +    { +        eBroadcastBitAsyncContinue                  = (1 << 0), +        eBroadcastBitAsyncThreadShouldExit          = (1 << 1) +    }; +     +    lldb::ThreadSP +    GetKernelThread (); + +    //------------------------------------------------------------------ +    /// Broadcaster event bits definitions. +    //------------------------------------------------------------------ +    CommunicationKDP m_comm; +    lldb_private::Broadcaster m_async_broadcaster; +    lldb_private::HostThread m_async_thread; +    lldb_private::ConstString m_dyld_plugin_name; +    lldb::addr_t m_kernel_load_addr; +    lldb::CommandObjectSP m_command_sp; +    lldb::ThreadWP m_kernel_thread_wp; + + +    bool +    StartAsyncThread (); +     +    void +    StopAsyncThread (); +     +    static void * +    AsyncThread (void *arg); +     +private: +    //------------------------------------------------------------------ +    // For ProcessKDP only +    //------------------------------------------------------------------ +     +    DISALLOW_COPY_AND_ASSIGN (ProcessKDP); +     +}; + +#endif  // liblldb_ProcessKDP_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp new file mode 100644 index 0000000000000..79cb62aa0066e --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.cpp @@ -0,0 +1,186 @@ +//===-- ProcessKDPLog.cpp ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ProcessKDPLog.h" + +#include "lldb/Interpreter/Args.h" +#include "lldb/Core/StreamFile.h" + +#include "ProcessKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +// We want to avoid global constructors where code needs to be run so here we +// control access to our static g_log_sp by hiding it in a singleton function +// that will construct the static g_log_sp the first time this function is  +// called. +static bool g_log_enabled = false; +static Log * g_log = NULL; +static Log * +GetLog () +{ +    if (!g_log_enabled) +        return NULL; +    return g_log; +} + +Log * +ProcessKDPLog::GetLogIfAllCategoriesSet (uint32_t mask) +{ +    Log *log(GetLog ()); +    if (log && mask) +    { +        uint32_t log_mask = log->GetMask().Get(); +        if ((log_mask & mask) != mask) +            return NULL; +    } +    return log; +} + +void +ProcessKDPLog::DisableLog (const char **categories, Stream *feedback_strm) +{ +    Log *log (GetLog ()); +    if (log) +    { +        uint32_t flag_bits = 0; +         +        if (categories[0] != NULL) +        { +            flag_bits = log->GetMask().Get(); +            for (size_t i = 0; categories[i] != NULL; ++i) +            { +                const char *arg = categories[i]; +                 + +                if      (::strcasecmp (arg, "all")        == 0 ) flag_bits &= ~KDP_LOG_ALL; +                else if (::strcasecmp (arg, "async")      == 0 ) flag_bits &= ~KDP_LOG_ASYNC; +                else if (::strncasecmp (arg, "break", 5)  == 0 ) flag_bits &= ~KDP_LOG_BREAKPOINTS; +                else if (::strncasecmp (arg, "comm", 4)   == 0 ) flag_bits &= ~KDP_LOG_COMM; +                else if (::strcasecmp (arg, "default")    == 0 ) flag_bits &= ~KDP_LOG_DEFAULT; +                else if (::strcasecmp (arg, "packets")    == 0 ) flag_bits &= ~KDP_LOG_PACKETS; +                else if (::strcasecmp (arg, "memory")     == 0 ) flag_bits &= ~KDP_LOG_MEMORY; +                else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~KDP_LOG_MEMORY_DATA_SHORT; +                else if (::strcasecmp (arg, "data-long")  == 0 ) flag_bits &= ~KDP_LOG_MEMORY_DATA_LONG; +                else if (::strcasecmp (arg, "process")    == 0 ) flag_bits &= ~KDP_LOG_PROCESS; +                else if (::strcasecmp (arg, "step")       == 0 ) flag_bits &= ~KDP_LOG_STEP; +                else if (::strcasecmp (arg, "thread")     == 0 ) flag_bits &= ~KDP_LOG_THREAD; +                else if (::strcasecmp (arg, "verbose")    == 0 ) flag_bits &= ~KDP_LOG_VERBOSE; +                else if (::strncasecmp (arg, "watch", 5)  == 0 ) flag_bits &= ~KDP_LOG_WATCHPOINTS; +                else +                { +                    feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); +                    ListLogCategories (feedback_strm); +                } +                 +            } +        } +         +        log->GetMask().Reset (flag_bits); +        if (flag_bits == 0) +            g_log_enabled = false; +    } +     +    return; +} + +Log * +ProcessKDPLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm) +{ +    // Try see if there already is a log - that way we can reuse its settings. +    // We could reuse the log in toto, but we don't know that the stream is the same. +    uint32_t flag_bits = 0; +    if (g_log) +        flag_bits = g_log->GetMask().Get(); + +    // Now make a new log with this stream if one was provided +    if (log_stream_sp) +    { +        if (g_log) +            g_log->SetStream(log_stream_sp); +        else +            g_log = new Log(log_stream_sp); +    } + +    if (g_log) +    { +        bool got_unknown_category = false; +        for (size_t i=0; categories[i] != NULL; ++i) +        { +            const char *arg = categories[i]; + +            if      (::strcasecmp (arg, "all")        == 0 ) flag_bits |= KDP_LOG_ALL; +            else if (::strcasecmp (arg, "async")      == 0 ) flag_bits |= KDP_LOG_ASYNC; +            else if (::strncasecmp (arg, "break", 5)  == 0 ) flag_bits |= KDP_LOG_BREAKPOINTS; +            else if (::strncasecmp (arg, "comm", 4)   == 0 ) flag_bits |= KDP_LOG_COMM; +            else if (::strcasecmp (arg, "default")    == 0 ) flag_bits |= KDP_LOG_DEFAULT; +            else if (::strcasecmp (arg, "packets")    == 0 ) flag_bits |= KDP_LOG_PACKETS; +            else if (::strcasecmp (arg, "memory")     == 0 ) flag_bits |= KDP_LOG_MEMORY; +            else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= KDP_LOG_MEMORY_DATA_SHORT; +            else if (::strcasecmp (arg, "data-long")  == 0 ) flag_bits |= KDP_LOG_MEMORY_DATA_LONG; +            else if (::strcasecmp (arg, "process")    == 0 ) flag_bits |= KDP_LOG_PROCESS; +            else if (::strcasecmp (arg, "step")       == 0 ) flag_bits |= KDP_LOG_STEP; +            else if (::strcasecmp (arg, "thread")     == 0 ) flag_bits |= KDP_LOG_THREAD; +            else if (::strcasecmp (arg, "verbose")    == 0 ) flag_bits |= KDP_LOG_VERBOSE; +            else if (::strncasecmp (arg, "watch", 5)  == 0 ) flag_bits |= KDP_LOG_WATCHPOINTS; +            else +            { +                feedback_strm->Printf("error: unrecognized log category '%s'\n", arg); +                if (got_unknown_category == false) +                { +                    got_unknown_category = true; +                    ListLogCategories (feedback_strm); +                } +            } +        } +        if (flag_bits == 0) +            flag_bits = KDP_LOG_DEFAULT; +        g_log->GetMask().Reset(flag_bits); +        g_log->GetOptions().Reset(log_options); +    } +    g_log_enabled = true; +    return g_log; +} + +void +ProcessKDPLog::ListLogCategories (Stream *strm) +{ +    strm->Printf ("Logging categories for '%s':\n" +                  "  all - turn on all available logging categories\n" +                  "  async - log asynchronous activity\n" +                  "  break - log breakpoints\n" +                  "  communication - log communication activity\n" +                  "  default - enable the default set of logging categories for liblldb\n" +                  "  packets - log gdb remote packets\n" +                  "  memory - log memory reads and writes\n" +                  "  data-short - log memory bytes for memory reads and writes for short transactions only\n" +                  "  data-long - log memory bytes for memory reads and writes for all transactions\n" +                  "  process - log process events and activities\n" +                  "  thread - log thread events and activities\n" +                  "  step - log step related activities\n" +                  "  verbose - enable verbose logging\n" +                  "  watch - log watchpoint related activities\n", +                  ProcessKDP::GetPluginNameStatic().GetCString()); +} + + +void +ProcessKDPLog::LogIf (uint32_t mask, const char *format, ...) +{ +    Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (mask)); +    if (log) +    { +        va_list args; +        va_start (args, format); +        log->VAPrintf (format, args); +        va_end (args); +    } +} diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h new file mode 100644 index 0000000000000..0cb32d9b2dcfa --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDPLog.h @@ -0,0 +1,54 @@ +//===-- ProcessKDPLog.h -----------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ProcessKDPLog_h_ +#define liblldb_ProcessKDPLog_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes + +// Project includes +#include "lldb/Core/Log.h" + +#define KDP_LOG_VERBOSE                  (1u << 0) +#define KDP_LOG_PROCESS                  (1u << 1) +#define KDP_LOG_THREAD                   (1u << 2) +#define KDP_LOG_PACKETS                  (1u << 3) +#define KDP_LOG_MEMORY                   (1u << 4)    // Log memory reads/writes calls +#define KDP_LOG_MEMORY_DATA_SHORT        (1u << 5)    // Log short memory reads/writes bytes +#define KDP_LOG_MEMORY_DATA_LONG         (1u << 6)    // Log all memory reads/writes bytes +#define KDP_LOG_BREAKPOINTS              (1u << 7) +#define KDP_LOG_WATCHPOINTS              (1u << 8) +#define KDP_LOG_STEP                     (1u << 9) +#define KDP_LOG_COMM                     (1u << 10) +#define KDP_LOG_ASYNC                    (1u << 11) +#define KDP_LOG_ALL                      (UINT32_MAX) +#define KDP_LOG_DEFAULT                  KDP_LOG_PACKETS + +class ProcessKDPLog +{ +public: +    static lldb_private::Log * +    GetLogIfAllCategoriesSet(uint32_t mask = 0); + +    static void +    DisableLog (const char **categories, lldb_private::Stream *feedback_strm); + +    static lldb_private::Log * +    EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, lldb_private::Stream *feedback_strm); + +    static void +    ListLogCategories (lldb_private::Stream *strm); + +    static void +    LogIf (uint32_t mask, const char *format, ...); +}; + +#endif  // liblldb_ProcessKDPLog_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp new file mode 100644 index 0000000000000..449ac646ab3c5 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp @@ -0,0 +1,161 @@ +//===-- RegisterContextKDP_arm.cpp ------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextKDP_arm.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_arm::RegisterContextKDP_arm (ThreadKDP &thread, uint32_t concrete_frame_idx) : +    RegisterContextDarwin_arm (thread, concrete_frame_idx), +    m_kdp_thread (thread) +{ +} + +RegisterContextKDP_arm::~RegisterContextKDP_arm() +{ +} + +int +RegisterContextKDP_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + + diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h new file mode 100644 index 0000000000000..1e547289d9ceb --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h @@ -0,0 +1,61 @@ +//===-- RegisterContextKDP_arm.h --------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_arm_h_ +#define liblldb_RegisterContextKDP_arm_h_ + +// C Includes + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" + +class ThreadKDP; + +class RegisterContextKDP_arm : public RegisterContextDarwin_arm +{ +public: + +    RegisterContextKDP_arm (ThreadKDP &thread,  +                            uint32_t concrete_frame_idx); + +    virtual +    ~RegisterContextKDP_arm(); + +protected: + +    virtual int +    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); +     +    int +    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); +     +    int +    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); +     +    int +    DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg); +     +    int +    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); +     +    int +    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); +     +    int +    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); +     +    int +    DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg); +     +    ThreadKDP &m_kdp_thread; +}; + +#endif  // liblldb_RegisterContextKDP_arm_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp new file mode 100644 index 0000000000000..ed62f1982d3c7 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp @@ -0,0 +1,161 @@ +//===-- RegisterContextKDP_arm64.cpp ------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextKDP_arm64.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_arm64::RegisterContextKDP_arm64 (ThreadKDP &thread, uint32_t concrete_frame_idx) : +    RegisterContextDarwin_arm64 (thread, concrete_frame_idx), +    m_kdp_thread (thread) +{ +} + +RegisterContextKDP_arm64::~RegisterContextKDP_arm64() +{ +} + +int +RegisterContextKDP_arm64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_arm64::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, DBGRegSet, &dbg, sizeof(dbg), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + + diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h new file mode 100644 index 0000000000000..8780b7be4a9ac --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h @@ -0,0 +1,61 @@ +//===-- RegisterContextKDP_arm64.h --------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_arm64_h_ +#define liblldb_RegisterContextKDP_arm64_h_ + +// C Includes + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" + +class ThreadKDP; + +class RegisterContextKDP_arm64 : public RegisterContextDarwin_arm64 +{ +public: + +    RegisterContextKDP_arm64 (ThreadKDP &thread,  +                            uint32_t concrete_frame_idx); + +    virtual +    ~RegisterContextKDP_arm64(); + +protected: + +    virtual int +    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); +     +    int +    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); +     +    int +    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); +     +    int +    DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg); +     +    int +    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); +     +    int +    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); +     +    int +    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); +     +    int +    DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg); +     +    ThreadKDP &m_kdp_thread; +}; + +#endif  // liblldb_RegisterContextKDP_arm64_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp new file mode 100644 index 0000000000000..882b0c2e931d8 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp @@ -0,0 +1,129 @@ +//===-- RegisterContextKDP_i386.cpp -----------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "RegisterContextKDP_i386.h" +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_i386::RegisterContextKDP_i386 (ThreadKDP &thread, uint32_t concrete_frame_idx) : +    RegisterContextDarwin_i386 (thread, concrete_frame_idx), +    m_kdp_thread (thread) +{ +} + +RegisterContextKDP_i386::~RegisterContextKDP_i386() +{ +} + +int +RegisterContextKDP_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + + diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h new file mode 100644 index 0000000000000..4b6bc5b262f7f --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h @@ -0,0 +1,53 @@ +//===-- RegisterContextKDP_i386.h -------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_i386_h_ +#define liblldb_RegisterContextKDP_i386_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" + +class ThreadKDP; + +class RegisterContextKDP_i386 : public RegisterContextDarwin_i386 +{ +public: +    RegisterContextKDP_i386 (ThreadKDP &thread,  +                             uint32_t concrete_frame_idx); +     +    virtual +    ~RegisterContextKDP_i386(); +     +protected: +     +    virtual int +    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); +     +    int +    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); +     +    int +    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); +     +    int +    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); +     +    int +    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); +     +    int +    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); +     +    ThreadKDP &m_kdp_thread; +}; + +#endif  // liblldb_RegisterContextKDP_i386_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp new file mode 100644 index 0000000000000..f4247a5da272a --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp @@ -0,0 +1,127 @@ +//===-- RegisterContextKDP_x86_64.cpp ---------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "RegisterContextKDP_x86_64.h" +#include "ProcessKDP.h" +#include "ThreadKDP.h" + +using namespace lldb; +using namespace lldb_private; + + +RegisterContextKDP_x86_64::RegisterContextKDP_x86_64 (ThreadKDP &thread, uint32_t concrete_frame_idx) : +    RegisterContextDarwin_x86_64 (thread, concrete_frame_idx), +    m_kdp_thread (thread) +{ +} + +RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64() +{ +} + +int +RegisterContextKDP_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestReadRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, GPRRegSet, &gpr, sizeof(gpr), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, FPURegSet, &fpu, sizeof(fpu), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} + +int +RegisterContextKDP_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) +{ +    ProcessSP process_sp (CalculateProcess()); +    if (process_sp) +    { +        Error error; +        if (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().SendRequestWriteRegisters (tid, EXCRegSet, &exc, sizeof(exc), error)) +        { +            if (error.Success()) +                return 0; +        } +    } +    return -1; +} diff --git a/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h new file mode 100644 index 0000000000000..a426349198ff6 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h @@ -0,0 +1,54 @@ +//===-- RegisterContextKDP_x86_64.h -----------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextKDP_x86_64_h_ +#define liblldb_RegisterContextKDP_x86_64_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" + +class ThreadKDP; + +class RegisterContextKDP_x86_64 : public RegisterContextDarwin_x86_64 +{ +public: +     +    RegisterContextKDP_x86_64 (ThreadKDP &thread,  +                               uint32_t concrete_frame_idx); +     +    virtual +    ~RegisterContextKDP_x86_64(); +     +protected: +     +    virtual int +    DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr); +     +    int +    DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu); +     +    int +    DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc); +     +    int +    DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr); +     +    int +    DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu); +     +    int +    DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc); +     +    ThreadKDP &m_kdp_thread; +}; + +#endif  // liblldb_RegisterContextKDP_x86_64_h_ diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp new file mode 100644 index 0000000000000..3b8bed101a8a2 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.cpp @@ -0,0 +1,211 @@ +//===-- ThreadKDP.cpp -------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + + +#include "ThreadKDP.h" + +#include "lldb/Utility/SafeMachO.h" + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/State.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Unwind.h" +#include "lldb/Breakpoint/Watchpoint.h" + +#include "ProcessKDP.h" +#include "ProcessKDPLog.h" +#include "RegisterContextKDP_arm.h" +#include "RegisterContextKDP_arm64.h" +#include "RegisterContextKDP_i386.h" +#include "RegisterContextKDP_x86_64.h" +#include "Plugins/Process/Utility/StopInfoMachException.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Thread Registers +//---------------------------------------------------------------------- + +ThreadKDP::ThreadKDP (Process &process, lldb::tid_t tid) : +    Thread(process, tid), +    m_thread_name (), +    m_dispatch_queue_name (), +    m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS) +{ +    ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::ThreadKDP (tid = 0x%4.4x)", this, GetID()); +} + +ThreadKDP::~ThreadKDP () +{ +    ProcessKDPLog::LogIf(KDP_LOG_THREAD, "%p: ThreadKDP::~ThreadKDP (tid = 0x%4.4x)", this, GetID()); +    DestroyThread(); +} + +const char * +ThreadKDP::GetName () +{ +    if (m_thread_name.empty()) +        return NULL; +    return m_thread_name.c_str(); +} + +const char * +ThreadKDP::GetQueueName () +{ +    return NULL; +} + +void +ThreadKDP::RefreshStateAfterStop() +{ +    // Invalidate all registers in our register context. We don't set "force" to +    // true because the stop reply packet might have had some register values +    // that were expedited and these will already be copied into the register +    // context by the time this function gets called. The KDPRegisterContext +    // class has been made smart enough to detect when it needs to invalidate +    // which registers are valid by putting hooks in the register read and  +    // register supply functions where they check the process stop ID and do +    // the right thing. +    const bool force = false; +    lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext()); +    if (reg_ctx_sp) +        reg_ctx_sp->InvalidateIfNeeded (force); +} + +bool +ThreadKDP::ThreadIDIsValid (lldb::tid_t thread) +{ +    return thread != 0; +} + +void +ThreadKDP::Dump(Log *log, uint32_t index) +{ +} + + +bool +ThreadKDP::ShouldStop (bool &step_more) +{ +    return true; +} +lldb::RegisterContextSP +ThreadKDP::GetRegisterContext () +{ +    if (m_reg_context_sp.get() == NULL) +        m_reg_context_sp = CreateRegisterContextForFrame (NULL); +    return m_reg_context_sp; +} + +lldb::RegisterContextSP +ThreadKDP::CreateRegisterContextForFrame (StackFrame *frame) +{ +    lldb::RegisterContextSP reg_ctx_sp; +    uint32_t concrete_frame_idx = 0; +     +    if (frame) +        concrete_frame_idx = frame->GetConcreteFrameIndex (); + +    if (concrete_frame_idx == 0) +    { +        ProcessSP process_sp (CalculateProcess()); +        if (process_sp) +        { +            switch (static_cast<ProcessKDP *>(process_sp.get())->GetCommunication().GetCPUType()) +            { +                case llvm::MachO::CPU_TYPE_ARM: +                    reg_ctx_sp.reset (new RegisterContextKDP_arm (*this, concrete_frame_idx)); +                    break; +                case llvm::MachO::CPU_TYPE_ARM64: +                    reg_ctx_sp.reset (new RegisterContextKDP_arm64 (*this, concrete_frame_idx)); +                    break; +                case llvm::MachO::CPU_TYPE_I386: +                    reg_ctx_sp.reset (new RegisterContextKDP_i386 (*this, concrete_frame_idx)); +                    break; +                case llvm::MachO::CPU_TYPE_X86_64: +                    reg_ctx_sp.reset (new RegisterContextKDP_x86_64 (*this, concrete_frame_idx)); +                    break; +                default: +                    assert (!"Add CPU type support in KDP"); +                    break; +            } +        } +    } +    else +    { +        Unwind *unwinder = GetUnwinder (); +        if (unwinder) +            reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame); +    } +    return reg_ctx_sp; +} + +bool +ThreadKDP::CalculateStopInfo () +{ +    ProcessSP process_sp (GetProcess()); +    if (process_sp) +    { +        if (m_cached_stop_info_sp) +        { +            SetStopInfo (m_cached_stop_info_sp); +        } +        else +        { +            SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, SIGSTOP)); +        } +        return true; +    } +    return false; +} + +void +ThreadKDP::SetStopInfoFrom_KDP_EXCEPTION (const DataExtractor &exc_reply_packet) +{ +    lldb::offset_t offset = 0; +    uint8_t reply_command = exc_reply_packet.GetU8(&offset); +    if (reply_command == CommunicationKDP::KDP_EXCEPTION) +    { +        offset = 8; +        const uint32_t count = exc_reply_packet.GetU32 (&offset); +        if (count >= 1) +        { +            //const uint32_t cpu = exc_reply_packet.GetU32 (&offset); +            offset += 4; // Skip the useless CPU field +            const uint32_t exc_type = exc_reply_packet.GetU32 (&offset); +            const uint32_t exc_code = exc_reply_packet.GetU32 (&offset); +            const uint32_t exc_subcode = exc_reply_packet.GetU32 (&offset); +            // We have to make a copy of the stop info because the thread list +            // will iterate through the threads and clear all stop infos.. +             +            // Let the StopInfoMachException::CreateStopReasonWithMachException() +            // function update the PC if needed as we might hit a software breakpoint +            // and need to decrement the PC (i386 and x86_64 need this) and KDP +            // doesn't do this for us. +            const bool pc_already_adjusted = false; +            const bool adjust_pc_if_needed = true; + +            m_cached_stop_info_sp = StopInfoMachException::CreateStopReasonWithMachException (*this, +                                                                                              exc_type, +                                                                                              2, +                                                                                              exc_code, +                                                                                              exc_subcode, +                                                                                              0, +                                                                                              pc_already_adjusted, +                                                                                              adjust_pc_if_needed);             +        } +    } +} + diff --git a/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h new file mode 100644 index 0000000000000..7dc373f035505 --- /dev/null +++ b/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h @@ -0,0 +1,98 @@ +//===-- ThreadKDP.h ---------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ThreadKDP_h_ +#define liblldb_ThreadKDP_h_ + +#include <string> + +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +class ProcessKDP; + +class ThreadKDP : public lldb_private::Thread +{ +public: +    ThreadKDP (lldb_private::Process &process, +               lldb::tid_t tid); + +    virtual +    ~ThreadKDP (); + +    virtual void +    RefreshStateAfterStop(); + +    virtual const char * +    GetName (); + +    virtual const char * +    GetQueueName (); + +    virtual lldb::RegisterContextSP +    GetRegisterContext (); + +    virtual lldb::RegisterContextSP +    CreateRegisterContextForFrame (lldb_private::StackFrame *frame); + +    void +    Dump (lldb_private::Log *log, uint32_t index); + +    static bool +    ThreadIDIsValid (lldb::tid_t thread); + +    bool +    ShouldStop (bool &step_more); + +    const char * +    GetBasicInfoAsString (); + +    void +    SetName (const char *name) +    { +        if (name && name[0]) +            m_thread_name.assign (name); +        else +            m_thread_name.clear(); +    } + +    lldb::addr_t +    GetThreadDispatchQAddr () +    { +        return m_thread_dispatch_qaddr; +    } + +    void +    SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr) +    { +        m_thread_dispatch_qaddr = thread_dispatch_qaddr; +    } +     +    void +    SetStopInfoFrom_KDP_EXCEPTION (const lldb_private::DataExtractor &exc_reply_packet); + +protected: +     +    friend class ProcessKDP; + +    //------------------------------------------------------------------ +    // Member variables. +    //------------------------------------------------------------------ +    std::string m_thread_name; +    std::string m_dispatch_queue_name; +    lldb::addr_t m_thread_dispatch_qaddr; +    lldb::StopInfoSP m_cached_stop_info_sp; +    //------------------------------------------------------------------ +    // Protected member functions. +    //------------------------------------------------------------------ +    virtual bool +    CalculateStopInfo (); +}; + +#endif  // liblldb_ThreadKDP_h_ | 
