//---------------------------------------------------------------------------- // // GdbSrvRspClient.h // // This class implements the RSP communication protocol used to communicate with the // GdbServer stub. This class can be instantiated by using a TCPIP communication class // or serial protocol class for connecting, sending and receiving data over the // link layer (TCP/IP or RS-232). // // Copyright (c) Microsoft. All rights reserved. //---------------------------------------------------------------------------- #pragma once #include "stdafx.h" #include #include #include #include #include #include "TextHelpers.h" #include "HandleHelpers.h" #include "TcpConnectorStream.h" namespace GdbSrvControllerLib { using namespace std; // Convert a number to an ASCII hex digit. #define NumberToAciiHex(number) ((number < 10) ? ('0' + number) : ('a' + number - 10)) // Convert to hex number from ASCII hex #define AciiHexAFToNumber(number) ((number >= 'a' && number <= 'f') ? (number - 'a' + 10) : 0) #define AciiHexToNumber(number) ((number >= '0' && number <= '9') ? (number - '0') : AciiHexAFToNumber(number)) // This is a random number that indicates the maximum attempts for sending packets. // The RSP protocol states that we should continue resending the packet if the // '+' ACK packet does not arrive, but if we do this then we could lock the // entire dbgeng.dll thread, so we will have this random number as the floor limit // for resending packets. Also, the user could cancel the resending sequence // by interrupting the session (CTRL-BREAK). const int MAX_PACKETS_ATTEMPTS = 3; // This constant indicates all cores operation const unsigned C_ALLCORES = 0xffffffff; // Check if we reach the maximum allowed retry attempts #define IS_MAX_ATTEMPTS(retry) (retry > MAX_PACKETS_ATTEMPTS) #define IS_RETRY_ALLOWED(retry) (retry < MAX_PACKETS_ATTEMPTS) // This is the list of supported query feature packets typedef enum { PACKET_VCONT = 0, PACKET_QSTART_NO_ACKMODE, PACKET_SIZE, PACKET_READ_TRACE32_SPECIAL_MEM, PACKET_WRITE_TRACE32_SPECIAL_MEM, MAX_FEATURES } RSP_FEATURES; // Short Packet type response typedef enum { RSP_OK, RSP_ERROR, RSP_STOP_REPLY, RSP_IGNORE_REPLY } RSP_Response_Packet; // Identifies an unexpected packet response for the type of the command #define IS_BAD_REPLY(ch) ((ch == RSP_STOP_REPLY) || (ch == RSP_IGNORE_REPLY)) // This structure describes the query feature packet local cache. // This cache is used by the client to enable/disable features // supported by the DbgServer implementation. typedef struct { bool isEnabled; int featureDefaultValue; string name; } PacketConfig; // This structured is used to configure the RSP client to work with the specific link layer typedef struct { // Maximum connection attempts unsigned int connectAttempts; // Send timeout (milliseconds) unsigned int sendTimeout; // Receive timeout (milliseconds) unsigned int recvTimeout; // Pointer to the function to do a call back for displaying // send and receive comm. data. pSetDisplayCommData pDisplayCommDataFunc; // Pointer to the Text processing object. // It's used for displaying comm. data. IGdbSrvTextHandler * pTextHandler; } RSP_CONFIG_COMM_SESSION; // This class implement the client RSP protocol used to communicate // with the GdbServer template class GdbSrvRspClient final { public: // Construct the RSP client object for the passed in LinkLayer type // The connection string format depends on the linklayer type. GdbSrvRspClient(_In_ const vector &coreConnectionParameters); ~GdbSrvRspClient(); // Set the configuration options used by the link layer session bool ConfigRspSession(_In_ const RSP_CONFIG_COMM_SESSION * pConfigData, _In_ unsigned core); // Connect to the remote GdbServer bool ConnectRsp(); // Connect to specific core bool ConnectRspToCore(_In_ const wstring &connectionStr, _In_ unsigned core); // Attach to a core by creating a new channel and connect to it. bool AttachRspToCore(_In_ const wstring &connectionStr, _In_ unsigned core); // Sends RSP client packet to the GdbServer bool SendRspPacket(_In_ const string & command, _In_ unsigned activeCore); // Receives a RSP packet from the GdbServer bool ReceiveRspPacket(_Out_ string & response, _In_ unsigned activeCore, _In_ bool isWaitForever) { bool IsPollingChannelMode = false; return ReceiveRspPacketEx(response, activeCore, isWaitForever, IsPollingChannelMode, true); } bool ReceiveRspPacketEx(_Out_ string & response, _In_ unsigned activeCore, _In_ bool isWaitForever, _Inout_ bool & IsPollingChannelMode, _In_ bool fReset); // Send an interrupt message (CTRL-C) bool SendRspInterrupt() { return SendRspInterruptEx(true, 0); } // Get the RSP connection status bool GetRspSessionStatus(_Out_ HRESULT & error, _In_ unsigned core); // Retrieves the last error from the link layer int GetRspLastError(); // Shutdown the RSP protocol bool ShutDownRsp(); // Close specific core RSP channel bool CloseRspCore(_In_ const wstring &closeStr, _In_ unsigned core); // Display RSP linklayer errors void HandleRspErrors(_In_ GdbSrvTextType textType); // Updates the RSP query packet storage. bool UpdateRspPacketFeatures(_In_ const string & features); // Get a copy of the current stored features. void GetRspPacketFeatures(_Out_ PacketConfig * pConfig, _In_ RSP_FEATURES index); // Get the number of connected link layers (it's used for multi-core GdbServer connections) size_t GetNumberOfStreamConnections(); // Send the interrup to specific processor cores. bool SendRspInterruptToProcessorCores(_In_ bool fResetAllCores, _In_ unsigned activeCore) { return SendRspInterruptEx(fResetAllCores, activeCore); } // Discard any pending response void DiscardResponse(_In_ unsigned activeCore); // Check if the GDB Server feature is enabled bool IsFeatureEnabled(_In_ unsigned feature); private: ValidHandleWrapper m_interruptEvent; unique_ptr m_pConnector; static PacketConfig s_RspProtocolFeatures[MAX_FEATURES]; static RSP_CONFIG_COMM_SESSION s_LinkLayerConfigOptions; CRITICAL_SECTION m_gdbSrvRspLock; int WaitForRspPacketStart(_In_ int maxPacketLength, _In_ TcpIpStream * pStream, _In_ bool isRspWaitNeeded, _Inout_ bool & IsPollingChannelMode, _In_ bool fResetBuffer); string CreateSendRspPacket(_In_ const string & command); void SetProtocolFeatureValue(_In_ size_t index, _In_ int value); void SetProtocolFeatureFlag(_In_ size_t index, _In_ bool value); bool GetNoAckModeRequired(_In_ const string & command); bool SendRspInterruptEx(_In_ bool fResetAllCores, _In_ unsigned activeCore); }; }