//---------------------------------------------------------------------------- // // cfgExdiGdbSrvHelper.cpp // // Helper for reading the Exdi-GdbServer configuration file. // // Copyright (c) Microsoft. All rights reserved. //---------------------------------------------------------------------------- #include "ExdiGdbSrvSample.h" #include #include #include #include #include #include #include #include #include #include "HandleHelpers.h" #include "GdbSrvControllerLib.h" #include "cfgExdiGdbSrvHelper.h" using namespace GdbSrvControllerLib; using namespace std; //============================================================================= // Private defines and typedefs //============================================================================= // Tag-attribute maximum length. const size_t C_MAX_ATTR_LENGTH = (256 + 1); // This type indicate the Exdi component configuration data. typedef struct { wstring agentNamePacket; // Agent name wstring uuid; // Class identifier. bool fDisplayCommPackets; // Flag if set then we display the communication packets characters. bool fDebuggerSessionByCore; // Flag if set then we do debug only by core processor, so step and continue // commands happen only on one core at the time. If not set then we // let all cores run when we do step/continue commands. bool fExceptionThrowEnabled; // Allow throwing exception by the Exdi COM server. // Used to disallow throwing exceptions when memory failures occur. } ConfigExdiData; // This type indicates the Target data. typedef struct { TargetArchitecture targetArchitecture; // The target architecture. DWORD targetFamily; // The target architecture. unsigned numberOfCores; // Number of cores of the target processor CPU. bool fEnabledIntelFpSseContext; // Flag if set then the Intel floating SSE context is processed. } ConfigExdiTargetData; // This type indicates the GdbServer specific data. typedef struct { bool fMultiCoreGdbServer; // Flag if set then we support multi-core connections with the DbgServer, so // there will be one GdbServer launched for each core CPU. size_t maxServerPacketLength; // Maximum GdbServer packet length. int maxConnectAttempts; // Connect session maximum attempts int sendTimeout; // Send RSP packet timeout int receiveTimeout; // Receive timeout vector coreConnectionParameters; // Connection string (hostname-ip:port) for each GdbServer core instance. } ConfigGdbServerData; // This type indicates the data structure that will be created after processing // the Exdi-GdbServer input xml config file. typedef struct { ConfigExdiData component; // Component data ConfigExdiTargetData target; // Target data ConfigGdbServerData gdbServer; // Server data } ConfigExdiGdbSrvData; typedef struct { WCHAR fMultiCoreGdbServer[C_MAX_ATTR_LENGTH]; // Flag if set then we support multi-core connections with the DbgServer, so // There will be one GdbServer launched for each core CPU. WCHAR maxServerPacketLength[C_MAX_ATTR_LENGTH]; // Maximum GdbServer packet length. WCHAR maxConnectAttempts[C_MAX_ATTR_LENGTH]; // Connect session maximum attempts WCHAR sendTimeout[C_MAX_ATTR_LENGTH]; // Send RSP packet timeout WCHAR receiveTimeout[C_MAX_ATTR_LENGTH]; // Receive timeout WCHAR coreConnectionParameter[C_MAX_ATTR_LENGTH]; // Connection string (hostname-ip:port) for each GdbServer core instance. } ConfigGdbServerDataEntry; typedef struct { WCHAR agentNamePacket[C_MAX_ATTR_LENGTH]; // Agent name WCHAR uuid[C_MAX_ATTR_LENGTH]; // Class identifier. WCHAR fDisplayCommPackets[C_MAX_ATTR_LENGTH]; // Flag if set then we display the communication packets characters. WCHAR fDebuggerSessionByCore[C_MAX_ATTR_LENGTH]; // Flag if set then we do debug only by core processor, so step and continue // commands happen only on one core at the time. If not set then we // let all cores run when we do step/continue commands. WCHAR fExceptionThrowEnabled[C_MAX_ATTR_LENGTH]; // Allow throwing exception by the Exdi COM server. // Used to disallow throwing exceptions when memory failures occur. } ConfigExdiDataEntry; typedef struct { WCHAR targetArchitecture[C_MAX_ATTR_LENGTH]; // The target architecture. WCHAR targetFamily[C_MAX_ATTR_LENGTH]; // The target family WCHAR numberOfCores[C_MAX_ATTR_LENGTH]; // Number of cores of the target processor CPU. WCHAR fEnabledIntelFpSseContext[C_MAX_ATTR_LENGTH]; // Flag if set then the Intel floating SSE context is processed. } ConfigExdiTargetDataEntry; // List-node element structure. typedef struct { LIST_ENTRY token; // Attribute pair localName="value" wstring localName; wstring value; } AttrList_NodeElem_Struct, *PAttrList_NodeElem_Struct; // List Tag-Attributes typedef struct { PCWSTR tagName; // Each list node will be allocated as a AttrList_NodeElem_Struct structure. LIST_ENTRY attrPair; } TAG_ATTR_LIST; // This type indicates the xmllite error code notification structure. typedef struct { HRESULT hr; PCWSTR pMessage; } XMLLITE_ERROR_STRUCT; // Attribute name handler types. typedef bool (* pXmlAttrValueHandler)(_In_ PCWSTR pAttrValue, _In_ size_t fieldOffset, _In_ size_t totalSizeOfStruct, _In_ size_t numberOfElements, _Out_ void * pInputData); // This structure indicates the mapping between the local name attribute value and its corresponding handler. typedef struct { PCWSTR pTagName; // Tag name PCWSTR pLocalName; // Attribute name pXmlAttrValueHandler pHandler; // Handler for processing the attribute value size_t outStructFieldOffset; // This is the field offset used for updating the out structure size_t structFieldNumberOfElements; // This is the filed number of elements } XML_ATTRNAME_HANDLER_STRUCT; // Function helper for reading the attributes value from the xml file. bool XmlGetStringValue(_In_z_ PCWSTR pAttrValue, _In_ size_t fieldOffset, _In_ size_t totalSizeOfStruct, _In_ size_t numberOfElements, _Out_writes_(totalSizeOfStruct) void * pOutData); //============================================================================= // Private data definitions //============================================================================= const WCHAR exdiGdbServerConfigData[] = L"ExdiGdbServerConfigData"; const WCHAR exdiGdbServerTargetData[] = L"ExdiGdbServerTargetData"; const WCHAR gdbServerConnectionParameters[] = L"GdbServerConnectionParameters"; const WCHAR gdbServerConnectionValue[] = L"Value"; const WCHAR gdbServerAgentNamePacket[] = L"agentNamePacket"; const WCHAR gdbServerUuid[] = L"uuid"; const WCHAR displayCommPackets[] = L"displayCommPackets"; const WCHAR debuggerSessionByCore[] = L"debuggerSessionByCore"; const WCHAR enableThrowExceptions[] = L"enableThrowExceptionOnMemoryErrors"; const WCHAR targetArchitectureName[] = L"targetArchitecture"; const WCHAR targetFamilyName[] = L"targetFamily"; const WCHAR numberOfCoresName[] = L"numberOfCores"; const WCHAR enableSseContextName[] = L"enableSseContext"; const WCHAR multiCoreGdbServer[] = L"MultiCoreGdbServerSessions"; const WCHAR maximumGdbServerPacketLength[] = L"MaximumGdbServerPacketLength"; const WCHAR hostNameAndPort[] = L"HostNameAndPort"; const WCHAR maximumConnectAttempts[] = L"MaximumConnectAttempts"; const WCHAR sendPacketTimeout[] = L"SendPacketTimeout"; const WCHAR receivePacketTimeout[] = L"ReceivePacketTimeout"; // General debugger information - handler map const XML_ATTRNAME_HANDLER_STRUCT attrExdiServerHandlerMap[] = { {exdiGdbServerConfigData, gdbServerAgentNamePacket, XmlGetStringValue, FIELD_OFFSET(ConfigExdiDataEntry, agentNamePacket), C_MAX_ATTR_LENGTH}, {exdiGdbServerConfigData, gdbServerUuid, XmlGetStringValue, FIELD_OFFSET(ConfigExdiDataEntry, uuid), C_MAX_ATTR_LENGTH}, {exdiGdbServerConfigData, displayCommPackets, XmlGetStringValue, FIELD_OFFSET(ConfigExdiDataEntry, fDisplayCommPackets), C_MAX_ATTR_LENGTH}, {exdiGdbServerConfigData, debuggerSessionByCore, XmlGetStringValue, FIELD_OFFSET(ConfigExdiDataEntry, fDebuggerSessionByCore), C_MAX_ATTR_LENGTH}, {exdiGdbServerConfigData, enableThrowExceptions, XmlGetStringValue, FIELD_OFFSET(ConfigExdiDataEntry, fExceptionThrowEnabled), C_MAX_ATTR_LENGTH}, }; // Attribute name - handler map for the GdbServer server tag info const XML_ATTRNAME_HANDLER_STRUCT attrNameServerTarget[] = { {exdiGdbServerTargetData, targetArchitectureName, XmlGetStringValue, FIELD_OFFSET(ConfigExdiTargetDataEntry, targetArchitecture), C_MAX_ATTR_LENGTH}, {exdiGdbServerTargetData, targetFamilyName, XmlGetStringValue, FIELD_OFFSET(ConfigExdiTargetDataEntry, targetFamily), C_MAX_ATTR_LENGTH}, {exdiGdbServerTargetData, numberOfCoresName, XmlGetStringValue, FIELD_OFFSET(ConfigExdiTargetDataEntry, numberOfCores), C_MAX_ATTR_LENGTH}, {exdiGdbServerTargetData, enableSseContextName, XmlGetStringValue, FIELD_OFFSET(ConfigExdiTargetDataEntry, fEnabledIntelFpSseContext), C_MAX_ATTR_LENGTH}, }; // General debugger information - handler map const XML_ATTRNAME_HANDLER_STRUCT attrExdiServerConnection[] = { {gdbServerConnectionParameters, multiCoreGdbServer, XmlGetStringValue, FIELD_OFFSET(ConfigGdbServerDataEntry, fMultiCoreGdbServer), C_MAX_ATTR_LENGTH}, {gdbServerConnectionParameters, maximumGdbServerPacketLength, XmlGetStringValue, FIELD_OFFSET(ConfigGdbServerDataEntry, maxServerPacketLength), C_MAX_ATTR_LENGTH}, {gdbServerConnectionParameters, maximumConnectAttempts, XmlGetStringValue, FIELD_OFFSET(ConfigGdbServerDataEntry, maxConnectAttempts), C_MAX_ATTR_LENGTH}, {gdbServerConnectionParameters, sendPacketTimeout, XmlGetStringValue, FIELD_OFFSET(ConfigGdbServerDataEntry, sendTimeout), C_MAX_ATTR_LENGTH}, {gdbServerConnectionParameters, receivePacketTimeout, XmlGetStringValue, FIELD_OFFSET(ConfigGdbServerDataEntry, receiveTimeout), C_MAX_ATTR_LENGTH}, {gdbServerConnectionValue, hostNameAndPort, XmlGetStringValue, FIELD_OFFSET(ConfigGdbServerDataEntry, coreConnectionParameter), C_MAX_ATTR_LENGTH}, }; // XmlLite error code - text map const XMLLITE_ERROR_STRUCT xmlLiteErrorMap[] = { { S_OK, L"S_OK" }, { S_FALSE, L"S_FALSE" }, { E_FAIL, L"E_FAIL" }, { E_INVALIDARG, L"E_INVALIDARG" }, { E_OUTOFMEMORY, L"E_OUTOFMEMORY" }, { MX_E_MX, L"0xC00CEE00 MX_E_MX ???" }, { MX_E_INPUTEND, L"0xC00CEE01 MX_E_INPUTEND unexpected end of input" }, { MX_E_ENCODING, L"0xC00CEE02 MX_E_ENCODING unrecognized encoding" }, { MX_E_ENCODINGSWITCH, L"0xC00CEE03 MX_E_ENCODINGSWITCH unable to switch the encoding" }, { MX_E_ENCODINGSIGNATURE, L"0xC00CEE04 MX_E_ENCODINGSIGNATURE unrecognized input signature" }, { WC_E_WC, L"0xC00CEE20 WC_E_WC ???" }, { WC_E_WHITESPACE, L"0xC00CEE21 WC_E_WHITESPACE whitespace expected" }, { WC_E_SEMICOLON, L"0xC00CEE22 WC_E_SEMICOLON semicolon expected" }, { WC_E_GREATERTHAN, L"0xC00CEE23 WC_E_GREATERTHAN '>' expected" }, { WC_E_QUOTE, L"0xC00CEE24 WC_E_QUOTE quote expected" }, { WC_E_EQUAL, L"0xC00CEE25 WC_E_EQUAL equal expected" }, { WC_E_LESSTHAN, L"0xC00CEE26 WC_E_LESSTHAN wfc: no '<' in attribute value" }, { WC_E_HEXDIGIT, L"0xC00CEE27 WC_E_HEXDIGIT hexadecimal digit expected" }, { WC_E_DIGIT, L"0xC00CEE28 WC_E_DIGIT decimal digit expected" }, { WC_E_LEFTBRACKET, L"0xC00CEE29 WC_E_LEFTBRACKET '[' expected" }, { WC_E_LEFTPAREN, L"0xC00CEE2A WC_E_LEFTPAREN '(' expected" }, { WC_E_XMLCHARACTER, L"0xC00CEE2B WC_E_XMLCHARACTER illegal xml character" }, { WC_E_NAMECHARACTER, L"0xC00CEE2C WC_E_NAMECHARACTER illegal name character" }, { WC_E_SYNTAX, L"0xC00CEE2D WC_E_SYNTAX incorrect document syntax" }, { WC_E_CDSECT, L"0xC00CEE2E WC_E_CDSECT incorrect CDATA section syntax" }, { WC_E_COMMENT, L"0xC00CEE2F WC_E_COMMENT incorrect comment syntax" }, { WC_E_CONDSECT, L"0xC00CEE30 WC_E_CONDSECT incorrect conditional section syntax" }, { WC_E_DECLATTLIST, L"0xC00CEE31 WC_E_DECLATTLIST incorrect ATTLIST declaration syntax" }, { WC_E_DECLDOCTYPE, L"0xC00CEE32 WC_E_DECLDOCTYPE incorrect DOCTYPE declaration syntax" }, { WC_E_DECLELEMENT, L"0xC00CEE33 WC_E_DECLELEMENT incorrect ELEMENT declaration syntax" }, { WC_E_DECLENTITY, L"0xC00CEE34 WC_E_DECLENTITY incorrect ENTITY declaration syntax" }, { WC_E_DECLNOTATION, L"0xC00CEE35 WC_E_DECLNOTATION incorrect NOTATION declaration syntax" }, { WC_E_NDATA, L"0xC00CEE36 WC_E_NDATA NDATA expected" }, { WC_E_PUBLIC, L"0xC00CEE37 WC_E_PUBLIC PUBLIC expected" }, { WC_E_SYSTEM, L"0xC00CEE38 WC_E_SYSTEM SYSTEM expected" }, { WC_E_NAME, L"0xC00CEE39 WC_E_NAME name expected" }, { WC_E_ROOTELEMENT, L"0xC00CEE3A WC_E_ROOTELEMENT one root element " }, { WC_E_ELEMENTMATCH, L"0xC00CEE3B WC_E_ELEMENTMATCH wfc: element type match" }, { WC_E_UNIQUEATTRIBUTE, L"0xC00CEE3C WC_E_UNIQUEATTRIBUTE wfc: unique attribute spec" }, { WC_E_TEXTXMLDECL, L"0xC00CEE3D WC_E_TEXTXMLDECL text/xmldecl not at the beginning of input" }, { WC_E_LEADINGXML, L"0xC00CEE3E WC_E_LEADINGXML leading 'xml' " }, { WC_E_TEXTDECL, L"0xC00CEE3F WC_E_TEXTDECL incorrect text declaration syntax" }, { WC_E_XMLDECL, L"0xC00CEE40 WC_E_XMLDECL incorrect xml declaration syntax" }, { WC_E_ENCNAME, L"0xC00CEE41 WC_E_ENCNAME incorrect encoding name syntax" }, { WC_E_PUBLICID, L"0xC00CEE42 WC_E_PUBLICID incorrect public identifier syntax" }, { WC_E_PESINTERNALSUBSET, L"0xC00CEE43 WC_E_PESINTERNALSUBSET wfc: pes in internal subset" }, { WC_E_PESBETWEENDECLS, L"0xC00CEE44 WC_E_PESBETWEENDECLS wfc: pes between declarations" }, { WC_E_NORECURSION, L"0xC00CEE45 WC_E_NORECURSION wfc: no recursion" }, { WC_E_ENTITYCONTENT, L"0xC00CEE46 WC_E_ENTITYCONTENT entity content not well formed" }, { WC_E_UNDECLAREDENTITY, L"0xC00CEE47 WC_E_UNDECLAREDENTITY wfc: undeclared entity " }, { WC_E_PARSEDENTITY, L"0xC00CEE48 WC_E_PARSEDENTITY wfc: parsed entity" }, { WC_E_NOEXTERNALENTITYREF, L"0xC00CEE49 WC_E_NOEXTERNALENTITYREF wfc: no external entity references" }, { WC_E_PI, L"0xC00CEE4A WC_E_PI incorrect processing instruction syntax" }, { WC_E_SYSTEMID, L"0xC00CEE4B WC_E_SYSTEMID incorrect system identifier syntax" }, { WC_E_QUESTIONMARK, L"0xC00CEE4C WC_E_QUESTIONMARK '?' expected" }, { WC_E_CDSECTEND, L"0xC00CEE4D WC_E_CDSECTEND no ']]>' in element content" }, { WC_E_MOREDATA, L"0xC00CEE4E WC_E_MOREDATA not all chunks of value have been read" }, { WC_E_DTDPROHIBITED, L"0xC00CEE4F WC_E_DTDPROHIBITED DTD was found but is prohibited" }, { WC_E_INVALIDXMLSPACE, L"0xC00CEE50 WC_E_INVALIDXMLSPACE Invalid xml:space value" }, { NC_E_NC, L"0xC00CEE60 NC_E_NC ???" }, { NC_E_QNAMECHARACTER, L"0xC00CEE61 NC_E_QNAMECHARACTER illegal qualified name character" }, { NC_E_QNAMECOLON, L"0xC00CEE62 NC_E_QNAMECOLON multiple colons in qualified name" }, { NC_E_NAMECOLON, L"0xC00CEE63 NC_E_NAMECOLON colon in name" }, { NC_E_DECLAREDPREFIX, L"0xC00CEE64 NC_E_DECLAREDPREFIX declared prefix" }, { NC_E_UNDECLAREDPREFIX, L"0xC00CEE65 NC_E_UNDECLAREDPREFIX undeclared prefix" }, { NC_E_EMPTYURI, L"0xC00CEE66 NC_E_EMPTYURI non default namespace with empty uri" }, { NC_E_XMLPREFIXRESERVED, L"0xC00CEE67 NC_E_XMLPREFIXRESERVED \"xml\" prefix is reserved and must have the http://www.w3.org/XML/1998/namespace URI" }, { NC_E_XMLNSPREFIXRESERVED, L"0xC00CEE68 NC_E_XMLNSPREFIXRESERVED \"xmlns\" prefix is reserved for use by XML" }, { NC_E_XMLURIRESERVED, L"0xC00CEE69 xml namespace URI (http://www.w3.org/XML/1998/namespace) must be assigned only to prefix \"xml\"" }, { NC_E_XMLNSURIRESERVED, L"0xC00CEE6A xmlns namespace URI (http://www.w3.org/2000/xmlns/) is reserved and must not be used" }, { SC_E_SC, L"0xC00CEE80 SC_E_SC ???" }, { SC_E_MAXELEMENTDEPTH, L"0xC00CEE81 SC_E_MAXELEMENTDEPTH max element depth was exceeded" }, { SC_E_MAXENTITYEXPANSION, L"0xC00CEE82 SC_E_MAXENTITYEXPANSION max number of expanded entities was exceeded" }, }; //============================================================================= // Private function declarations //============================================================================= // Find the error message PCWSTR GetXmlErrorMsg(HRESULT hr) { for (size_t i = 0; i < ARRAYSIZE(xmlLiteErrorMap); ++i) { if (xmlLiteErrorMap[i].hr == hr) { return xmlLiteErrorMap[i].pMessage; } } static wchar_t errorMsgBuf[128] = {}; StringCchPrintfW(errorMsgBuf, 127, L"0x%.8X !! Unknown Error !!", hr); return errorMsgBuf; } void ReportXmlError(_In_ PCWSTR pMessage) { assert(pMessage != nullptr); MessageBox(0, reinterpret_cast(pMessage), nullptr, MB_ICONERROR); } void ReportXmlExceptionCode(_In_ PCWSTR pMessage, _In_ DWORD exceptCode) { WCHAR message[C_MAX_ATTR_LENGTH] = L""; swprintf_s(message, ARRAYSIZE(message), L"%s (exception Code: 0x%x)\n", pMessage, exceptCode); ReportXmlError(message); } void ReportExceptionError(_In_ PCSTR pMessage) { assert(pMessage != nullptr); size_t messageLength = strlen(pMessage) + 1; unique_ptr pUnicodeMsg(new (nothrow) wchar_t[messageLength]); if (pUnicodeMsg != nullptr) { if (MultiByteToWideChar(CP_ACP, 0, pMessage, -1, pUnicodeMsg.get(), static_cast(messageLength)) != 0) { ReportXmlError(pUnicodeMsg.get()); } else { ReportXmlError(L"Failed converting the exception ASCII string to UNICODE\n"); } } else { ReportXmlError(L"Failed allocating memory for the exception message\n"); } } bool XmlGetStringValue(_In_z_ PCWSTR pAttrValue, _In_ size_t fieldOffset, _In_ size_t totalSizeOfStruct, _In_ size_t numberOfElements, _Out_writes_(totalSizeOfStruct) void * pOutData) { bool isGet = false; try { assert(pAttrValue != nullptr && pOutData != nullptr); BYTE * pStart = (static_cast(pOutData)) + fieldOffset; BYTE * pEnd = (static_cast(pOutData)) + totalSizeOfStruct; PWSTR pString = reinterpret_cast(pStart); size_t leftElements = (reinterpret_cast(pEnd) - pString); if (fieldOffset > totalSizeOfStruct || numberOfElements > leftElements) { throw exception("The structure field offset does not belong to the current passed in structure"); } wcscpy_s(pString, numberOfElements, pAttrValue); isGet = true; } catch (exception & ex) { ReportExceptionError(ex.what()); } return isGet; } inline bool IsExdiGdbServerConfigDataTag(_In_ PCWSTR pTagName) { assert(pTagName != nullptr); bool isDone = false; if (_wcsicmp(pTagName, exdiGdbServerConfigData) == 0) { isDone = true; } return isDone; } inline bool IsExdiGdbServerTargetDataTag(_In_ PCWSTR pTagName) { assert(pTagName != nullptr); bool isDone = false; if (_wcsicmp(pTagName, exdiGdbServerTargetData) == 0) { isDone = true; } return isDone; } inline bool IsGdbServerConnectionParametersTag(_In_ PCWSTR pTagName) { assert(pTagName != nullptr); bool isDone = false; if (_wcsicmp(pTagName, gdbServerConnectionParameters) == 0) { isDone = true; } return isDone; } inline bool IsGdbServerValueTag(_In_ PCWSTR pTagName) { assert(pTagName != nullptr); bool isDone = false; if (_wcsicmp(pTagName, gdbServerConnectionValue) == 0) { isDone = true; } return isDone; } TargetArchitecture GetTargetGdbServerArchitecture(_In_ PCWSTR pDataString) { assert(pDataString != nullptr); TargetArchitecture targetData = UNKNOWN_ARCH; if (_wcsicmp(pDataString, L"X86") == 0) { targetData = X86_ARCH; } else if (_wcsicmp(pDataString, L"X64") == 0) { assert(false); } else if (_wcsicmp(pDataString, L"ARM") == 0) { targetData = ARM32_ARCH; } else if (_wcsicmp(pDataString, L"ARM64") == 0) { targetData = ARM64_ARCH; } else { MessageBox(0, _T("The configuration file contains an unsupported target architecture."), _T("EXDI-GdbServer Sample"), MB_ICONERROR); } return targetData; } DWORD GetTargetGdbServerFamily(_In_ PCWSTR pDataString) { assert(pDataString != nullptr); DWORD targetData = PROCESSOR_FAMILY_UNK; if (_wcsicmp(pDataString, L"ProcessorFamilyX86") == 0) { targetData = PROCESSOR_FAMILY_X86; } else if (_wcsicmp(pDataString, L"ProcessorFamilyX64") == 0) { assert(false); } else if (_wcsicmp(pDataString, L"ProcessorFamilyARM") == 0) { targetData = PROCESSOR_FAMILY_ARM; } else if (_wcsicmp(pDataString, L"ProcessorFamilyARM64") == 0) { targetData = PROCESSOR_FAMILY_ARMV8ARCH64; } else { MessageBox(0, _T("The configuration file contains an unsupported family target type."), _T("EXDI-GdbServer Sample"), MB_ICONERROR); } return targetData; } class ConfigExdiGdbServerHelper::ConfigExdiGdbServerHelperImpl { public: ConfigExdiGdbServerHelperImpl(): m_XmlLiteReader(nullptr), m_IStream(nullptr) { ZeroMemory(&m_ExdiGdbServerData, sizeof(ConfigExdiGdbSrvData)); } ~ConfigExdiGdbServerHelperImpl() { } // This function will read the file/default memory and load the // table with the values. bool ReadConfigFile(_In_opt_ PCWSTR pXmlConfigFile) { assert(pXmlConfigFile != nullptr); bool isReadDone = false; __try { // Create the XML reader HRESULT hr = InitHelper(); if (SUCCEEDED(hr)) { // Create the stream (file/memory) hr = CreateStream(pXmlConfigFile); if (SUCCEEDED(hr)) { hr = ReadStream(); if (SUCCEEDED(hr)) { isReadDone = true; } TerminateHelper(); } } if (!isReadDone) { // Report the HRESULT error here ReportXmlError(GetXmlErrorMsg(hr)); } } __except (EXCEPTION_EXECUTE_HANDLER) { ReportXmlExceptionCode(L"A Windows Exception was catched in the function ConfigExdiGdbServerHelper::ReadConfigFile().\n", GetExceptionCode()); throw; } return isReadDone; } inline void GetExdiComponentAgentNamePacket(_Out_ wstring & packetName) { packetName = m_ExdiGdbServerData.component.agentNamePacket; } inline void GetExdiComponentUuid(_Out_ wstring & uuid) { uuid = m_ExdiGdbServerData.component.uuid; } inline bool GetDisplayCommPacketsCharacters() { return m_ExdiGdbServerData.component.fDisplayCommPackets; } inline bool GetDebuggerSessionByCore() { return m_ExdiGdbServerData.component.fDebuggerSessionByCore; } inline TargetArchitecture GetTargetArchitecture() { return m_ExdiGdbServerData.target.targetArchitecture; } inline DWORD GetTargetFamily() { return m_ExdiGdbServerData.target.targetFamily; } inline unsigned GetNumberOfCores() { return m_ExdiGdbServerData.target.numberOfCores; } inline bool GetIntelSseContext() { return m_ExdiGdbServerData.target.fEnabledIntelFpSseContext; } inline bool GetMultiCoreGdbServer() { return m_ExdiGdbServerData.gdbServer.fMultiCoreGdbServer; } inline size_t GetMaxServerPacketLength() { return m_ExdiGdbServerData.gdbServer.maxServerPacketLength; } inline int GetMaxConnectAttempts() { return m_ExdiGdbServerData.gdbServer.maxConnectAttempts; } inline int GetSendPacketTimeout() { return m_ExdiGdbServerData.gdbServer.sendTimeout; } inline int GetReceiveTimeout() { return m_ExdiGdbServerData.gdbServer.receiveTimeout; } inline void GetGdbServerConnectionParameters(_Out_ vector & coreConnections) { coreConnections = m_ExdiGdbServerData.gdbServer.coreConnectionParameters; } inline bool IsExceptionThrowEnabled() { return m_ExdiGdbServerData.component.fExceptionThrowEnabled; } private: CComPtr m_XmlLiteReader; CComPtr m_IStream; ConfigExdiGdbSrvData m_ExdiGdbServerData; // Xml helper related functionality inline bool IsMemoryXmlBuffer(_In_opt_ PCWSTR pXmlConfigFile) {return (pXmlConfigFile == nullptr);} // ConfigExdiGdbServerHelper function HRESULT InitHelper() { // Create IXmlReader object. HRESULT hr = CreateXmlReader(__uuidof(IXmlReader), reinterpret_cast(&m_XmlLiteReader), nullptr); if (SUCCEEDED(hr)) { // Set IXmlReader properties. // Prohibit the Document Type Definitions (DTDs) in the document. hr = m_XmlLiteReader->SetProperty(XmlReaderProperty_DtdProcessing, DtdProcessing_Prohibit); } if (!SUCCEEDED(hr)) { TerminateHelper(); } return hr; } // Terminate the helper HRESULT TerminateHelper() { m_XmlLiteReader.Release(); m_IStream.Release(); return S_OK; } LPCWSTR GetXmlBuffer() { // We won't implement it by using a memory xml buffer. return nullptr; } HRESULT CreateStream(_In_opt_ PCWSTR pXmlConfigFile) { HRESULT hr = S_OK; // Is there any passed file path? if (IsMemoryXmlBuffer(pXmlConfigFile)) { // Create a memory stream LPCWSTR pBuffer = GetXmlBuffer(); assert(pBuffer != nullptr); size_t bufferSize = 0; // Find buffer length. hr = StringCbLengthW(pBuffer,(STRSAFE_MAX_CCH * sizeof(WCHAR)), &bufferSize); if (SUCCEEDED(hr)) { // Create stream from buffer. m_IStream.Attach(SHCreateMemStream(reinterpret_cast(pBuffer), static_cast(bufferSize))); if (m_IStream == nullptr) { hr = E_FAIL; } } } else { // Create a file stream hr = SHCreateStreamOnFileW(pXmlConfigFile, STGM_READ, &m_IStream); } if (SUCCEEDED(hr)) { // Set the input source of the XML document to be parsed. hr = m_XmlLiteReader->SetInput(m_IStream); if (SUCCEEDED(hr)) { // Set maximum dept allowed levels of nesting in elements. hr = m_XmlLiteReader->SetProperty(XmlReaderProperty_MaxElementDepth, 50); } } if (!SUCCEEDED(hr)) { TerminateHelper(); } return hr; } // Validates the XML tag-Attribute value and get the value from the xml file HRESULT GetXmlTagAttributeValues(_In_ TAG_ATTR_LIST * const pTagAttrList, _In_ const XML_ATTRNAME_HANDLER_STRUCT * pMap, _In_ size_t mapSize, size_t maxSizeOfOutStructData, _Out_writes_bytes_(maxSizeOfOutStructData) void * pOutData) { assert(pOutData != nullptr && pMap != nullptr && pTagAttrList != nullptr); HRESULT hr = E_FAIL; try { for (size_t i = 0; i < mapSize; ++i, ++pMap) { if (_wcsicmp(pMap->pTagName, pTagAttrList->tagName) == 0) { // Walk through the list of attributes PLIST_ENTRY next = pTagAttrList->attrPair.Flink; if (next != nullptr) { while (next != &pTagAttrList->attrPair) { PAttrList_NodeElem_Struct pElem = CONTAINING_RECORD(next, AttrList_NodeElem_Struct, token); assert(pElem != nullptr); if (_wcsicmp(pMap->pLocalName, pElem->localName.c_str()) == 0) { bool isDone = pMap->pHandler(pElem->value.c_str(), pMap->outStructFieldOffset, maxSizeOfOutStructData, pMap->structFieldNumberOfElements, pOutData); if (isDone) { hr = S_OK; } break; } next = pElem->token.Flink; } } } } } catch (exception & ex) { ReportExceptionError(ex.what()); hr = E_FAIL; } catch(...) { ReportXmlError(L"Unrecognized exception happened in ConfigExdiGdbServerHelperImpl::GetXmlTagAttributeValues()\n"); hr = E_FAIL; } return hr; } // Clear the nodes from the list. void ClearTagAttributesList(_Inout_ TAG_ATTR_LIST * const pTagAttrList) { assert(pTagAttrList != nullptr); PLIST_ENTRY next = pTagAttrList->attrPair.Flink; if (next != nullptr) { while (next != &pTagAttrList->attrPair) { PAttrList_NodeElem_Struct pElem = CONTAINING_RECORD(next, AttrList_NodeElem_Struct, token); assert(pElem != nullptr); RemoveEntryList(next); next = pElem->token.Flink; delete pElem; } } } HRESULT HandleTagAttributeList(_In_ TAG_ATTR_LIST * const pTagAttrList) { assert(pTagAttrList != nullptr); HRESULT hr = E_FAIL; try { bool isSet = false; if (IsExdiGdbServerConfigDataTag(pTagAttrList->tagName)) { ConfigExdiDataEntry exdiData = {}; hr = GetXmlTagAttributeValues(pTagAttrList, attrExdiServerHandlerMap, ARRAYSIZE(attrExdiServerHandlerMap), sizeof(ConfigExdiDataEntry), static_cast(&exdiData)); if (SUCCEEDED(hr)) { m_ExdiGdbServerData.component.agentNamePacket = exdiData.agentNamePacket; m_ExdiGdbServerData.component.uuid = exdiData.uuid; m_ExdiGdbServerData.component.fDisplayCommPackets = (_wcsicmp(exdiData.fDisplayCommPackets, L"yes") == 0) ? true : false; m_ExdiGdbServerData.component.fDebuggerSessionByCore = (_wcsicmp(exdiData.fDebuggerSessionByCore, L"yes") == 0) ? true : false; m_ExdiGdbServerData.component.fExceptionThrowEnabled = (_wcsicmp(exdiData.fExceptionThrowEnabled, L"yes") == 0) ? true : false; isSet = true; } } else if (IsExdiGdbServerTargetDataTag(pTagAttrList->tagName)) { ConfigExdiTargetDataEntry targetData = {}; hr = GetXmlTagAttributeValues(pTagAttrList, attrNameServerTarget, ARRAYSIZE(attrNameServerTarget), sizeof(ConfigExdiTargetDataEntry), static_cast(&targetData)); if (SUCCEEDED(hr)) { m_ExdiGdbServerData.target.targetArchitecture = GetTargetGdbServerArchitecture(targetData.targetArchitecture); m_ExdiGdbServerData.target.targetFamily = GetTargetGdbServerFamily(targetData.targetFamily); m_ExdiGdbServerData.target.numberOfCores = _wtoi(targetData.numberOfCores); m_ExdiGdbServerData.target.fEnabledIntelFpSseContext = (_wcsicmp(targetData.fEnabledIntelFpSseContext, L"yes") == 0) ? true : false; isSet = true; } } else if (IsGdbServerConnectionParametersTag(pTagAttrList->tagName)) { ConfigGdbServerDataEntry gdbServer = {}; hr = GetXmlTagAttributeValues(pTagAttrList, attrExdiServerConnection, ARRAYSIZE(attrExdiServerConnection), sizeof(ConfigGdbServerDataEntry), static_cast(&gdbServer)); if (SUCCEEDED(hr)) { m_ExdiGdbServerData.gdbServer.fMultiCoreGdbServer = (_wcsicmp(gdbServer.fMultiCoreGdbServer, L"yes") == 0) ? true : false; m_ExdiGdbServerData.gdbServer.maxServerPacketLength = _wtoi(gdbServer.maxServerPacketLength); m_ExdiGdbServerData.gdbServer.maxConnectAttempts = _wtoi(gdbServer.maxConnectAttempts); m_ExdiGdbServerData.gdbServer.sendTimeout = _wtoi(gdbServer.sendTimeout); m_ExdiGdbServerData.gdbServer.receiveTimeout = _wtoi(gdbServer.receiveTimeout); isSet = true; } } else if (IsGdbServerValueTag(pTagAttrList->tagName)) { assert(m_ExdiGdbServerData.gdbServer.coreConnectionParameters.size() <= m_ExdiGdbServerData.target.numberOfCores); ConfigGdbServerDataEntry gdbServer = {}; hr = GetXmlTagAttributeValues(pTagAttrList, attrExdiServerConnection, ARRAYSIZE(attrExdiServerConnection), sizeof(ConfigGdbServerDataEntry), static_cast(&gdbServer)); if (SUCCEEDED(hr)) { m_ExdiGdbServerData.gdbServer.coreConnectionParameters.push_back(gdbServer.coreConnectionParameter); isSet = true; } } if (!isSet) { ReportXmlError(L"Failed setting a value in ConfigExdiGdbServerHelperImpl::HandleTagAttributeList()\n"); hr = E_FAIL; } } catch (exception & ex) { ReportExceptionError(ex.what()); } catch(...) { ReportXmlError(L"Unrecognized exception happened in ConfigExdiGdbServerHelperImpl::ProcessAttributeList()\n"); } return hr; } HRESULT ProcessAttributeList(_In_ TAG_ATTR_LIST * const pTagAttrList) { HRESULT hr = E_FAIL; __try { hr = HandleTagAttributeList(pTagAttrList); } __finally { ClearTagAttributesList(pTagAttrList); } return hr; } // Parses the attributes for the current tag HRESULT ParseAttributes(_Inout_ TAG_ATTR_LIST * pTagAttrList) { assert(pTagAttrList != nullptr); HRESULT hr = E_FAIL; try { hr = m_XmlLiteReader->MoveToFirstAttribute(); while (SUCCEEDED(hr)) { PCWSTR pAttribName = nullptr; PCWSTR pAttribValue = nullptr; HRESULT hr = m_XmlLiteReader->GetLocalName(&pAttribName, nullptr); if (SUCCEEDED(hr)) { hr = m_XmlLiteReader->GetValue(&pAttribValue, nullptr); if (SUCCEEDED(hr)) { // Add a new element to the list PAttrList_NodeElem_Struct pListNode = new (nothrow) AttrList_NodeElem_Struct; assert(pListNode != nullptr); pListNode->localName += pAttribName; pListNode->value += pAttribValue; // Insert the element in the list InsertTailList(&pTagAttrList->attrPair, &pListNode->token); } else { break; } } else { break; } if (SUCCEEDED(hr)) { hr = m_XmlLiteReader->MoveToNextAttribute(); if (hr == S_FALSE) { break; } } } } catch (exception & ex) { ReportExceptionError(ex.what()); throw; } catch(...) { ReportXmlError(L"Unrecognized exception happened in ConfigExdiGdbServerHelperImpl::ParseAttributes()\n"); throw; } return hr; } HRESULT ReadStream() { HRESULT hr = E_FAIL; bool isForcedEnd = false; while (!m_XmlLiteReader->IsEOF() && !isForcedEnd) { XmlNodeType nodeType; hr = m_XmlLiteReader->Read(&nodeType); if (FAILED(hr) || (hr == S_FALSE)) { break; } switch(nodeType) { case XmlNodeType_XmlDeclaration: case XmlNodeType_ProcessingInstruction: case XmlNodeType_Comment: case XmlNodeType_DocumentType: break; case XmlNodeType_Element: { PCWSTR pTagName = nullptr; hr = m_XmlLiteReader->GetLocalName(&pTagName, nullptr); if (SUCCEEDED(hr) && (pTagName != nullptr)) { TAG_ATTR_LIST tagAttrList = {}; InitializeListHead(&tagAttrList.attrPair); size_t copyLength = wcslen(pTagName) + 1; unique_ptr pTagNameCopy(new (nothrow) WCHAR[copyLength]); if (pTagNameCopy != nullptr) { ZeroMemory(pTagNameCopy.get(), sizeof(WCHAR) * (copyLength)); wcscpy_s(pTagNameCopy.get(), copyLength, pTagName); tagAttrList.tagName = pTagNameCopy.get(); // Parse the XML tag hr = ParseAttributes(&tagAttrList); if (SUCCEEDED(hr)) { hr = ProcessAttributeList(&tagAttrList); if (FAILED(hr)) { isForcedEnd = true; break; } } else { // Try removing any added element to the list ClearTagAttributesList(&tagAttrList); isForcedEnd = true; } } else { isForcedEnd = true; hr = E_OUTOFMEMORY; } } } break; } } return hr; } }; ConfigExdiGdbServerHelper & ConfigExdiGdbServerHelper::GetInstanceCfgExdiGdbServer(_In_opt_ PCWSTR pXmlConfigFile) { static ConfigExdiGdbServerHelper * pInstance = nullptr; if (pInstance == nullptr) { pInstance = new (nothrow) ConfigExdiGdbServerHelper(pXmlConfigFile); if (pInstance == nullptr) { throw _com_error(ERROR_NOT_ENOUGH_MEMORY); } } return *pInstance; } ConfigExdiGdbServerHelper::ConfigExdiGdbServerHelper(_In_opt_ PCWSTR pXmlConfigFile) { m_pConfigExdiGdbServerHelperImpl = unique_ptr(new (nothrow) ConfigExdiGdbServerHelperImpl()); assert(m_pConfigExdiGdbServerHelperImpl != nullptr); if (!m_pConfigExdiGdbServerHelperImpl->ReadConfigFile(pXmlConfigFile)) { m_pConfigExdiGdbServerHelperImpl = nullptr; throw _com_error(HRESULT_FROM_WIN32(GetLastError())); } } ConfigExdiGdbServerHelper::~ConfigExdiGdbServerHelper(){} TargetArchitecture ConfigExdiGdbServerHelper::GetTargetArchitecture() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetTargetArchitecture(); } DWORD ConfigExdiGdbServerHelper::GetTargetFamily() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetTargetFamily(); } bool ConfigExdiGdbServerHelper::GetDisplayCommPacketsCharacters() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetDisplayCommPacketsCharacters(); } bool ConfigExdiGdbServerHelper::GetDebuggerSessionByCore() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetDebuggerSessionByCore(); } bool ConfigExdiGdbServerHelper::GetIntelSseContext() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetIntelSseContext(); } void ConfigExdiGdbServerHelper::GetExdiComponentAgentNamePacket(_Out_ wstring & packetName) { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); m_pConfigExdiGdbServerHelperImpl->GetExdiComponentAgentNamePacket(packetName); } void ConfigExdiGdbServerHelper::GetExdiComponentUuid(_Out_ wstring & uuid) { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); m_pConfigExdiGdbServerHelperImpl->GetExdiComponentUuid(uuid); } unsigned ConfigExdiGdbServerHelper::GetNumberOfCores() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetNumberOfCores(); } bool ConfigExdiGdbServerHelper::GetMultiCoreGdbServer() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetMultiCoreGdbServer(); } size_t ConfigExdiGdbServerHelper::GetMaxServerPacketLength() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetMaxServerPacketLength(); } int ConfigExdiGdbServerHelper::GetMaxConnectAttempts() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetMaxConnectAttempts(); } int ConfigExdiGdbServerHelper::GetSendPacketTimeout() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetSendPacketTimeout(); } int ConfigExdiGdbServerHelper::GetReceiveTimeout() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->GetReceiveTimeout(); } void ConfigExdiGdbServerHelper::GetGdbServerConnectionParameters(_Out_ vector & coreConnections) { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); m_pConfigExdiGdbServerHelperImpl->GetGdbServerConnectionParameters(coreConnections); } bool ConfigExdiGdbServerHelper::IsExceptionThrowEnabled() { assert(m_pConfigExdiGdbServerHelperImpl != nullptr); return m_pConfigExdiGdbServerHelperImpl->IsExceptionThrowEnabled(); }