You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
249 lines
7.6 KiB
249 lines
7.6 KiB
//===-- 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<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);
|
|
|
|
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
|