| //===-- 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/Utility/Listener.h" | |
| #include "lldb/Utility/Predicate.h" | |
| #include "lldb/Utility/StreamBuffer.h" | |
| #include "lldb/lldb-private.h" | |
| class CommunicationKDP : public lldb_private::Communication { | |
| public: | |
| const static uint32_t kMaxPacketSize = 1200; | |
| const static uint32_t kMaxDataSize = 1024; | |
| typedef lldb_private::StreamBuffer<4096> 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); | |
| ~CommunicationKDP() override; | |
| 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::string m_bytes; | |
| std::recursive_mutex m_bytes_mutex; | |
| 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 |