//---------------------------------------------------------------------------- // // GdbSrvControllerLib.h // // A class that runs a GdbServer client that services the DbgEng-Exdi debugger // requests. // // Copyright (c) Microsoft. All rights reserved. //---------------------------------------------------------------------------- #pragma once #include #include #include #include #include "BufferWrapper.h" #include "HandleHelpers.h" #include "GdbSrvRspClient.h" namespace GdbSrvControllerLib { // Maximum number of supported GdbServer CPU registers by supported architecture. const int MAX_REG_X86_NUMBER = 40; const int MAX_REG_AMD64_NUMBER = 55; const int MAX_REG_ARM32_NUMBER = 50; const int MAX_REG_ARM64_NUMBER = 68; typedef enum { UNKNOWN_ARCH, X86_ARCH, AMD64_ARCH, ARM32_ARCH, ARM64_ARCH } TargetArchitecture; // This type indicates the signal types returned by the DbgServer typedef enum { TARGET_UNKNOWN = 0, // The target process has been terminated. TARGET_BREAK_SIGUP = 1, // The debugger sends a CTRL_break TARGET_BREAK_SIGINT = 2, // The target is broken because the debugger requests a break. TARGET_BREAK_SIGTRAP = 5, // The process exited TARGET_PROCESS_EXIT = 6, // END marker TARGET_MARKER } TARGET_HALTED; // This structure indicates the register description for each architecture // This will be used for processing the DbgServer register reply commands // The order matches with the order how it is sent by the GdbServer stub. struct RegistersStruct { // Register Name description std::string name; // The register index (ascii hex decimal number) std::string nameOrder; // Register size in bytes size_t registerSize; }; typedef std::map gdbRegisterMapOrder; typedef ULONGLONG AddressType; // This structure indicates the fields of the stop reply reason response. typedef struct { TARGET_HALTED stopReason; ULONG processorNumber; AddressType currentAddress; // Stop reply packet response status struct { WORD isSAAPacket: 1; // Set if the stop reply packet is S AA format WORD isTAAPacket: 1; // Set if the stop reply packet is T AA format WORD isWAAPacket: 1; // Set if the stop reply packet is W AA format WORD isThreadFound: 1; // Set if the stop reply packet contains the 'thread' number (core processor number) WORD isPcRegFound: 1; // Set if the PC register was found in the response WORD isPowerDown: 1; // Set if the stop reply packet is 'S00' (Power down or target running). WORD isCoreRunning: 1; // Set if the stop reply packet is 'OK' (the Core is running or it's not unknown state) WORD fUnUsed: 9; } status; } StopReplyPacketStruct; // // This is used to set the type of memory packet that will be be sent to the Gdb Server. // In general, these flags are mutually exclusive, but it's up to the implementation to use them. // typedef struct { WORD isPhysical: 1; // Set if the query is to access physical memory WORD isSupervisor: 1; // Set if the query is to access supervisor/system mode memory WORD isSpecialRegs: 1; // Set if the query is to access memory pointed by Special registers WORD isData:1; // Set if the query is to access user mode memory. WORD isHypervisor:1; // Set if the query is to access hypervisor memory. WORD fUnUsed: 11; } memoryAccessType; // // This class implements the High level functionality supported by the GdbServer stub. // Basically, it translates the DbgEng-Exdi requested functionality to GdbServer commands. // class GdbSrvController { public: virtual ~GdbSrvController(); // Connect to the GdbServer. bool ConnectGdbSrv(); // Check if the GdbServer is still connected. bool CheckGdbSrvAlive(_Out_ HRESULT & error); // Configure the GdbServer communication session. bool ConfigureGdbSrvCommSession(_In_ bool fDisplayCommData, _In_ int core); // Execute a basic GdbServer command. virtual std::string ExecuteCommand(_In_ LPCSTR pCommand); // Execute a basic GdbServer command with extended command attributes. virtual std::string ExecuteCommandEx(_In_ LPCSTR pCommand, _In_ bool isExecCmd, _In_ size_t stringSize); // Execute a basic GdbServer command with extended command attributes on a particular processor core. virtual std::string ExecuteCommandOnProcessor(_In_ LPCSTR pCommand, _In_ bool isExecCmd, _In_ size_t stringSize, _In_ unsigned processor); // Handle the responses for the asynchronous commnads (the stop reason reply responses). bool HandleAsynchronousCommandResponse(_In_ const std::string & cmdResponse, _Out_ StopReplyPacketStruct * pRspPacket); // Interrupt the target by posting the interrupt character sequence. bool InterruptTarget(); // Determines if the target is halted due to a debug(signal) break. bool IsTargetHalted(); // Retrieves the last used processor number. unsigned GetLastKnownActiveCpu(); // Set the last Active Cpu void SetLastKnownActiveCpu(_In_ unsigned cpu); // Obtains the location offset of the Windows OS specific stored KPCR array. AddressType GetKpcrOffset(_In_ unsigned processorNumber); // Get the number of processors supported by the target. unsigned GetProcessorCount(); // Get the general GdbServer-RSP protocol response type. RSP_Response_Packet GetRspResponse(_In_ const std::string & reply); // Obtains the stored target architecture. TargetArchitecture GetTargetArchitecture(); // Request the current value for all target CPU registers. std::map QueryAllRegisters(_In_ unsigned processorNumber); // Request a sub-set of all target CPU registers. std::map QueryRegisters(_In_ unsigned processorNumber, _In_reads_(numberOfElements) const char * registerNames[], _In_ const size_t numberOfElements); // Utility function to get a 64 bit register value. static ULONGLONG ParseRegisterValue(_In_ const std::string &stringValue); // Utility function to get a 32 bit register value. static DWORD ParseRegisterValue32(_In_ const std::string &stringValue); // Utility function to get a variable size regiter value (the register can be a vector). static void ParseRegisterVariableSize(_In_ const std::string ®isterValue, _Out_writes_bytes_(registerAreaLength) BYTE pRegisterArea[], _In_ int registerAreaLength); // Read the target virtual memory. SimpleCharBuffer ReadMemory(_In_ AddressType address, _In_ size_t size, _In_ const memoryAccessType memType); // Request the GDbServer supported features. bool ReqGdbServerSupportedFeatures(); // Request the Windows OS Thread information block. bool RequestTIB(); // Reports the reason of the break. TARGET_HALTED ReportReasonTargetHalted(_Out_ StopReplyPacketStruct * pStopReply); // Request restart the target. bool RestartGdbSrvTarget(); // Store the KPCR offset for later usage. void SetKpcrOffset(_In_ unsigned processorNumber, _In_ AddressType kpcrOffset); // Set the value of the specific register set. void SetRegisters(_In_ unsigned processorNumber, _In_ const std::map ®isterValues, _In_ bool isRegisterValuePtr); // Stores the target architecture. void SetTargetArchitecture(_In_ TargetArchitecture targetArch); // Stores the pointer of the text logging class. void SetTextHandler(_In_ IGdbSrvTextHandler * pHandler); // Set the thread/processor number bool SetThreadCommand(_In_ unsigned processorNumber, _In_ const char * pOperation); // Close the connection with the GdbServer. void ShutdownGdbSrv(); // Write a value to the target virtual memory at specific address. bool WriteMemory(_In_ AddressType address, _In_ size_t size, _In_ const void * pRawBuffer, _Out_ DWORD * pdwBytesWritten, _In_ const memoryAccessType memType); // Get the number of RSP GdbServer connections. unsigned GetNumberOfRspConnections(); // Execute the same command on multiple processors. Accept only the first response. std::string ExecuteCommandOnMultiProcessors(_In_ LPCSTR pCommand, _In_ bool isRspWaitNeeded, _In_ size_t stringSize); // Display a message on the command line log windows void DisplayLogEntry(_In_reads_bytes_(readSize) const char * pBuffer, _In_ size_t readSize); // Execute a GdbSrv function. bool ExecuteExdiFunction(_In_ unsigned core, _In_ LPCWSTR pFunctionToExecute); // Execute a GdbSrv monitor command. SimpleCharBuffer ExecuteExdiGdbSrvMonitor(_In_ unsigned dwProcessorNumber, _In_ LPCWSTR pFunctionToExecute); // Create and fill the Neon register array void CreateNeonRegisterNameArray(_In_ const std::string & registerName, _Out_writes_bytes_(numberOfRegArrayElem) std::unique_ptr pRegNameArray[], _In_ size_t numberOfRegArrayElem); // Get the first thread/core index obtained from the Gdb Server qfThreadInfo packet response int GetFirstThreadIndex(); // GetPacketType based on the current memory type void GetMemoryPacketType(_In_ DWORD64 cpsrRegValue, _Out_ memoryAccessType * pMemType); // Check if the current architecture is 64 bits bool Is64BitArchitecture(); // Read the MSR registers HRESULT ReadMsrRegister(_In_ DWORD dwProcessorNumber, _In_ DWORD dwRegisterIndex, _Out_ ULONG64 * pValue); // Write to the MSR register HRESULT WriteMsrRegister(_In_ DWORD dwProcessorNumber, _In_ DWORD dwRegisterIndex, _In_ ULONG64 value); protected: bool IsReplyOK(_In_ const std::string & reply); bool IsReplyError(_In_ const std::string & reply); bool IsStopReply(_In_ const std::string & reply); GdbSrvController(_In_ const std::vector &coreConnectionParameters); private: class GdbSrvControllerImpl; std::unique_ptr m_pGdbSrvControllerImpl; }; }