| //===-- CommunicationKDP.h --------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLDB_SOURCE_PLUGINS_PROCESS_MACOSX_KERNEL_COMMUNICATIONKDP_H |
| #define LLDB_SOURCE_PLUGINS_PROCESS_MACOSX_KERNEL_COMMUNICATIONKDP_H |
| |
| #include <list> |
| #include <mutex> |
| #include <string> |
| |
| #include "lldb/Core/Communication.h" |
| #include "lldb/Core/StreamBuffer.h" |
| #include "lldb/Utility/Listener.h" |
| #include "lldb/Utility/Predicate.h" |
| #include "lldb/lldb-private.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; |
| enum CommandType { |
| 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 |
| }; |
| |
| enum { KDP_FEATURE_BP = (1u << 0) }; |
| |
| enum KDPError { |
| KDP_PROTERR_SUCCESS = 0, |
| KDP_PROTERR_ALREADY_CONNECTED, |
| KDP_PROTERR_BAD_NBYTES, |
| KDP_PROTERR_BADFLAVOR |
| }; |
| |
| enum PacketType { |
| ePacketTypeRequest = 0x00u, |
| ePacketTypeReply = 0x80u, |
| ePacketTypeMask = 0x80u, |
| eCommandTypeMask = 0x7fu |
| }; |
| // 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(std::unique_lock<std::recursive_mutex> &lock); |
| |
| 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. |
| std::chrono::seconds SetPacketTimeout(std::chrono::seconds packet_timeout) { |
| const auto old_packet_timeout = m_packet_timeout; |
| m_packet_timeout = packet_timeout; |
| return old_packet_timeout; |
| } |
| |
| std::chrono::seconds GetPacketTimeout() const { return m_packet_timeout; } |
| |
| // 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::Status &error); |
| |
| uint32_t SendRequestWriteMemory(lldb::addr_t addr, const void *src, |
| uint32_t src_len, |
| lldb_private::Status &error); |
| |
| bool SendRawRequest(uint8_t command_byte, const void *src, uint32_t src_len, |
| lldb_private::DataExtractor &reply, |
| lldb_private::Status &error); |
| |
| uint32_t SendRequestReadRegisters(uint32_t cpu, uint32_t flavor, void *dst, |
| uint32_t dst_size, |
| lldb_private::Status &error); |
| |
| uint32_t SendRequestWriteRegisters(uint32_t cpu, uint32_t flavor, |
| const void *src, uint32_t src_size, |
| lldb_private::Status &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 std::chrono::microseconds &timeout); |
| |
| 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; |
| std::chrono::seconds m_packet_timeout; |
| std::recursive_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 |
| CommunicationKDP(const CommunicationKDP &) = delete; |
| const CommunicationKDP &operator=(const CommunicationKDP &) = delete; |
| }; |
| |
| #endif // LLDB_SOURCE_PLUGINS_PROCESS_MACOSX_KERNEL_COMMUNICATIONKDP_H |