diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp b/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp new file mode 100644 index 00000000000..a011e9246d1 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -0,0 +1,604 @@ +//===-- StringExtractorGDBRemote.cpp ----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/StringExtractorGDBRemote.h" + +#include <ctype.h> +#include <string.h> + +StringExtractorGDBRemote::ResponseType +StringExtractorGDBRemote::GetResponseType() const { + if (m_packet.empty()) + return eUnsupported; + + switch (m_packet[0]) { + case 'E': + if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) { + if (m_packet.size() == 3) + return eError; + llvm::StringRef packet_ref(m_packet); + if (packet_ref[3] == ';') { + auto err_string = packet_ref.substr(4); + for (auto e : err_string) + if (!isxdigit(e)) + return eResponse; + return eError; + } + } + break; + + case 'O': + if (m_packet.size() == 2 && m_packet[1] == 'K') + return eOK; + break; + + case '+': + if (m_packet.size() == 1) + return eAck; + break; + + case '-': + if (m_packet.size() == 1) + return eNack; + break; + } + return eResponse; +} + +StringExtractorGDBRemote::ServerPacketType +StringExtractorGDBRemote::GetServerPacketType() const { +#define PACKET_MATCHES(s) \ + ((packet_size == (sizeof(s) - 1)) && (strcmp((packet_cstr), (s)) == 0)) +#define PACKET_STARTS_WITH(s) \ + ((packet_size >= (sizeof(s) - 1)) && \ + ::strncmp(packet_cstr, s, (sizeof(s) - 1)) == 0) + + // Empty is not a supported packet... + if (m_packet.empty()) + return eServerPacketType_invalid; + + const size_t packet_size = m_packet.size(); + const char *packet_cstr = m_packet.c_str(); + switch (m_packet[0]) { + + case '%': + return eServerPacketType_notify; + + case '\x03': + if (packet_size == 1) + return eServerPacketType_interrupt; + break; + + case '-': + if (packet_size == 1) + return eServerPacketType_nack; + break; + + case '+': + if (packet_size == 1) + return eServerPacketType_ack; + break; + + case 'A': + return eServerPacketType_A; + + case 'Q': + + switch (packet_cstr[1]) { + case 'E': + if (PACKET_STARTS_WITH("QEnvironment:")) + return eServerPacketType_QEnvironment; + if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:")) + return eServerPacketType_QEnvironmentHexEncoded; + if (PACKET_STARTS_WITH("QEnableErrorStrings")) + return eServerPacketType_QEnableErrorStrings; + break; + + case 'P': + if (PACKET_STARTS_WITH("QPassSignals:")) + return eServerPacketType_QPassSignals; + break; + + case 'S': + if (PACKET_MATCHES("QStartNoAckMode")) + return eServerPacketType_QStartNoAckMode; + if (PACKET_STARTS_WITH("QSaveRegisterState")) + return eServerPacketType_QSaveRegisterState; + if (PACKET_STARTS_WITH("QSetDisableASLR:")) + return eServerPacketType_QSetDisableASLR; + if (PACKET_STARTS_WITH("QSetDetachOnError:")) + return eServerPacketType_QSetDetachOnError; + if (PACKET_STARTS_WITH("QSetSTDIN:")) + return eServerPacketType_QSetSTDIN; + if (PACKET_STARTS_WITH("QSetSTDOUT:")) + return eServerPacketType_QSetSTDOUT; + if (PACKET_STARTS_WITH("QSetSTDERR:")) + return eServerPacketType_QSetSTDERR; + if (PACKET_STARTS_WITH("QSetWorkingDir:")) + return eServerPacketType_QSetWorkingDir; + if (PACKET_STARTS_WITH("QSetLogging:")) + return eServerPacketType_QSetLogging; + if (PACKET_STARTS_WITH("QSetMaxPacketSize:")) + return eServerPacketType_QSetMaxPacketSize; + if (PACKET_STARTS_WITH("QSetMaxPayloadSize:")) + return eServerPacketType_QSetMaxPayloadSize; + if (PACKET_STARTS_WITH("QSetEnableAsyncProfiling;")) + return eServerPacketType_QSetEnableAsyncProfiling; + if (PACKET_STARTS_WITH("QSyncThreadState:")) + return eServerPacketType_QSyncThreadState; + break; + + case 'L': + if (PACKET_STARTS_WITH("QLaunchArch:")) + return eServerPacketType_QLaunchArch; + if (PACKET_MATCHES("QListThreadsInStopReply")) + return eServerPacketType_QListThreadsInStopReply; + break; + + case 'R': + if (PACKET_STARTS_WITH("QRestoreRegisterState:")) + return eServerPacketType_QRestoreRegisterState; + break; + + case 'T': + if (PACKET_MATCHES("QThreadSuffixSupported")) + return eServerPacketType_QThreadSuffixSupported; + break; + } + break; + + case 'q': + switch (packet_cstr[1]) { + case 's': + if (PACKET_MATCHES("qsProcessInfo")) + return eServerPacketType_qsProcessInfo; + if (PACKET_MATCHES("qsThreadInfo")) + return eServerPacketType_qsThreadInfo; + break; + + case 'f': + if (PACKET_STARTS_WITH("qfProcessInfo")) + return eServerPacketType_qfProcessInfo; + if (PACKET_STARTS_WITH("qfThreadInfo")) + return eServerPacketType_qfThreadInfo; + break; + + case 'C': + if (packet_size == 2) + return eServerPacketType_qC; + break; + + case 'E': + if (PACKET_STARTS_WITH("qEcho:")) + return eServerPacketType_qEcho; + break; + + case 'F': + if (PACKET_STARTS_WITH("qFileLoadAddress:")) + return eServerPacketType_qFileLoadAddress; + break; + + case 'G': + if (PACKET_STARTS_WITH("qGroupName:")) + return eServerPacketType_qGroupName; + if (PACKET_MATCHES("qGetWorkingDir")) + return eServerPacketType_qGetWorkingDir; + if (PACKET_MATCHES("qGetPid")) + return eServerPacketType_qGetPid; + if (PACKET_STARTS_WITH("qGetProfileData;")) + return eServerPacketType_qGetProfileData; + if (PACKET_MATCHES("qGDBServerVersion")) + return eServerPacketType_qGDBServerVersion; + break; + + case 'H': + if (PACKET_MATCHES("qHostInfo")) + return eServerPacketType_qHostInfo; + break; + + case 'K': + if (PACKET_STARTS_WITH("qKillSpawnedProcess")) + return eServerPacketType_qKillSpawnedProcess; + break; + + case 'L': + if (PACKET_STARTS_WITH("qLaunchGDBServer")) + return eServerPacketType_qLaunchGDBServer; + if (PACKET_MATCHES("qLaunchSuccess")) + return eServerPacketType_qLaunchSuccess; + break; + + case 'M': + if (PACKET_STARTS_WITH("qMemoryRegionInfo:")) + return eServerPacketType_qMemoryRegionInfo; + if (PACKET_MATCHES("qMemoryRegionInfo")) + return eServerPacketType_qMemoryRegionInfoSupported; + if (PACKET_STARTS_WITH("qModuleInfo:")) + return eServerPacketType_qModuleInfo; + break; + + case 'P': + if (PACKET_STARTS_WITH("qProcessInfoPID:")) + return eServerPacketType_qProcessInfoPID; + if (PACKET_STARTS_WITH("qPlatform_shell:")) + return eServerPacketType_qPlatform_shell; + if (PACKET_STARTS_WITH("qPlatform_mkdir:")) + return eServerPacketType_qPlatform_mkdir; + if (PACKET_STARTS_WITH("qPlatform_chmod:")) + return eServerPacketType_qPlatform_chmod; + if (PACKET_MATCHES("qProcessInfo")) + return eServerPacketType_qProcessInfo; + break; + + case 'Q': + if (PACKET_MATCHES("qQueryGDBServer")) + return eServerPacketType_qQueryGDBServer; + break; + + case 'R': + if (PACKET_STARTS_WITH("qRcmd,")) + return eServerPacketType_qRcmd; + if (PACKET_STARTS_WITH("qRegisterInfo")) + return eServerPacketType_qRegisterInfo; + break; + + case 'S': + if (PACKET_STARTS_WITH("qSpeedTest:")) + return eServerPacketType_qSpeedTest; + if (PACKET_MATCHES("qShlibInfoAddr")) + return eServerPacketType_qShlibInfoAddr; + if (PACKET_MATCHES("qStepPacketSupported")) + return eServerPacketType_qStepPacketSupported; + if (PACKET_STARTS_WITH("qSupported")) + return eServerPacketType_qSupported; + if (PACKET_MATCHES("qSyncThreadStateSupported")) + return eServerPacketType_qSyncThreadStateSupported; + break; + + case 'T': + if (PACKET_STARTS_WITH("qThreadExtraInfo,")) + return eServerPacketType_qThreadExtraInfo; + if (PACKET_STARTS_WITH("qThreadStopInfo")) + return eServerPacketType_qThreadStopInfo; + break; + + case 'U': + if (PACKET_STARTS_WITH("qUserName:")) + return eServerPacketType_qUserName; + break; + + case 'V': + if (PACKET_MATCHES("qVAttachOrWaitSupported")) + return eServerPacketType_qVAttachOrWaitSupported; + break; + + case 'W': + if (PACKET_STARTS_WITH("qWatchpointSupportInfo:")) + return eServerPacketType_qWatchpointSupportInfo; + if (PACKET_MATCHES("qWatchpointSupportInfo")) + return eServerPacketType_qWatchpointSupportInfoSupported; + break; + + case 'X': + if (PACKET_STARTS_WITH("qXfer:")) + return eServerPacketType_qXfer; + break; + } + break; + + case 'j': + if (PACKET_STARTS_WITH("jModulesInfo:")) + return eServerPacketType_jModulesInfo; + if (PACKET_MATCHES("jSignalsInfo")) + return eServerPacketType_jSignalsInfo; + if (PACKET_MATCHES("jThreadsInfo")) + return eServerPacketType_jThreadsInfo; + if (PACKET_STARTS_WITH("jTraceBufferRead:")) + return eServerPacketType_jTraceBufferRead; + if (PACKET_STARTS_WITH("jTraceConfigRead:")) + return eServerPacketType_jTraceConfigRead; + if (PACKET_STARTS_WITH("jTraceMetaRead:")) + return eServerPacketType_jTraceMetaRead; + if (PACKET_STARTS_WITH("jTraceStart:")) + return eServerPacketType_jTraceStart; + if (PACKET_STARTS_WITH("jTraceStop:")) + return eServerPacketType_jTraceStop; + break; + + case 'v': + if (PACKET_STARTS_WITH("vFile:")) { + if (PACKET_STARTS_WITH("vFile:open:")) + return eServerPacketType_vFile_open; + else if (PACKET_STARTS_WITH("vFile:close:")) + return eServerPacketType_vFile_close; + else if (PACKET_STARTS_WITH("vFile:pread")) + return eServerPacketType_vFile_pread; + else if (PACKET_STARTS_WITH("vFile:pwrite")) + return eServerPacketType_vFile_pwrite; + else if (PACKET_STARTS_WITH("vFile:size")) + return eServerPacketType_vFile_size; + else if (PACKET_STARTS_WITH("vFile:exists")) + return eServerPacketType_vFile_exists; + else if (PACKET_STARTS_WITH("vFile:stat")) + return eServerPacketType_vFile_stat; + else if (PACKET_STARTS_WITH("vFile:mode")) + return eServerPacketType_vFile_mode; + else if (PACKET_STARTS_WITH("vFile:MD5")) + return eServerPacketType_vFile_md5; + else if (PACKET_STARTS_WITH("vFile:symlink")) + return eServerPacketType_vFile_symlink; + else if (PACKET_STARTS_WITH("vFile:unlink")) + return eServerPacketType_vFile_unlink; + + } else { + if (PACKET_STARTS_WITH("vAttach;")) + return eServerPacketType_vAttach; + if (PACKET_STARTS_WITH("vAttachWait;")) + return eServerPacketType_vAttachWait; + if (PACKET_STARTS_WITH("vAttachOrWait;")) + return eServerPacketType_vAttachOrWait; + if (PACKET_STARTS_WITH("vAttachName;")) + return eServerPacketType_vAttachName; + if (PACKET_STARTS_WITH("vCont;")) + return eServerPacketType_vCont; + if (PACKET_MATCHES("vCont?")) + return eServerPacketType_vCont_actions; + } + break; + case '_': + switch (packet_cstr[1]) { + case 'M': + return eServerPacketType__M; + + case 'm': + return eServerPacketType__m; + } + break; + + case '?': + if (packet_size == 1) + return eServerPacketType_stop_reason; + break; + + case 'c': + return eServerPacketType_c; + + case 'C': + return eServerPacketType_C; + + case 'D': + if (packet_size == 1) + return eServerPacketType_D; + break; + + case 'g': + return eServerPacketType_g; + + case 'G': + return eServerPacketType_G; + + case 'H': + return eServerPacketType_H; + + case 'I': + return eServerPacketType_I; + + case 'k': + if (packet_size == 1) + return eServerPacketType_k; + break; + + case 'm': + return eServerPacketType_m; + + case 'M': + return eServerPacketType_M; + + case 'p': + return eServerPacketType_p; + + case 'P': + return eServerPacketType_P; + + case 's': + if (packet_size == 1) + return eServerPacketType_s; + break; + + case 'S': + return eServerPacketType_S; + + case 'x': + return eServerPacketType_x; + + case 'X': + return eServerPacketType_X; + + case 'T': + return eServerPacketType_T; + + case 'z': + if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4') + return eServerPacketType_z; + break; + + case 'Z': + if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4') + return eServerPacketType_Z; + break; + } + return eServerPacketType_unimplemented; +} + +bool StringExtractorGDBRemote::IsOKResponse() const { + return GetResponseType() == eOK; +} + +bool StringExtractorGDBRemote::IsUnsupportedResponse() const { + return GetResponseType() == eUnsupported; +} + +bool StringExtractorGDBRemote::IsNormalResponse() const { + return GetResponseType() == eResponse; +} + +bool StringExtractorGDBRemote::IsErrorResponse() const { + return GetResponseType() == eError && isxdigit(m_packet[1]) && + isxdigit(m_packet[2]); +} + +uint8_t StringExtractorGDBRemote::GetError() { + if (GetResponseType() == eError) { + SetFilePos(1); + return GetHexU8(255); + } + return 0; +} + +lldb_private::Status StringExtractorGDBRemote::GetStatus() { + lldb_private::Status error; + if (GetResponseType() == eError) { + SetFilePos(1); + uint8_t errc = GetHexU8(255); + error.SetError(errc, lldb::eErrorTypeGeneric); + + error.SetErrorStringWithFormat("Error %u", errc); + std::string error_messg; + if (GetChar() == ';') { + GetHexByteString(error_messg); + error.SetErrorString(error_messg); + } + } + return error; +} + +size_t StringExtractorGDBRemote::GetEscapedBinaryData(std::string &str) { + // Just get the data bytes in the string as + // GDBRemoteCommunication::CheckForPacket() already removes any 0x7d escaped + // characters. If any 0x7d characters are left in the packet, then they are + // supposed to be there... + str.clear(); + const size_t bytes_left = GetBytesLeft(); + if (bytes_left > 0) { + str.assign(m_packet, m_index, bytes_left); + m_index += bytes_left; + } + return str.size(); +} + +static bool +OKErrorNotSupportedResponseValidator(void *, + const StringExtractorGDBRemote &response) { + switch (response.GetResponseType()) { + case StringExtractorGDBRemote::eOK: + case StringExtractorGDBRemote::eError: + case StringExtractorGDBRemote::eUnsupported: + return true; + + case StringExtractorGDBRemote::eAck: + case StringExtractorGDBRemote::eNack: + case StringExtractorGDBRemote::eResponse: + break; + } + return false; +} + +static bool JSONResponseValidator(void *, + const StringExtractorGDBRemote &response) { + switch (response.GetResponseType()) { + case StringExtractorGDBRemote::eUnsupported: + case StringExtractorGDBRemote::eError: + return true; // Accept unsupported or EXX as valid responses + + case StringExtractorGDBRemote::eOK: + case StringExtractorGDBRemote::eAck: + case StringExtractorGDBRemote::eNack: + break; + + case StringExtractorGDBRemote::eResponse: + // JSON that is returned in from JSON query packets is currently always + // either a dictionary which starts with a '{', or an array which starts + // with a '['. This is a quick validator to just make sure the response + // could be valid JSON without having to validate all of the + // JSON content. + switch (response.GetStringRef()[0]) { + case '{': + return true; + case '[': + return true; + default: + break; + } + break; + } + return false; +} + +static bool +ASCIIHexBytesResponseValidator(void *, + const StringExtractorGDBRemote &response) { + switch (response.GetResponseType()) { + case StringExtractorGDBRemote::eUnsupported: + case StringExtractorGDBRemote::eError: + return true; // Accept unsupported or EXX as valid responses + + case StringExtractorGDBRemote::eOK: + case StringExtractorGDBRemote::eAck: + case StringExtractorGDBRemote::eNack: + break; + + case StringExtractorGDBRemote::eResponse: { + uint32_t valid_count = 0; + for (const char ch : response.GetStringRef()) { + if (!isxdigit(ch)) { + return false; + } + if (++valid_count >= 16) + break; // Don't validate all the characters in case the packet is very + // large + } + return true; + } break; + } + return false; +} + +void StringExtractorGDBRemote::CopyResponseValidator( + const StringExtractorGDBRemote &rhs) { + m_validator = rhs.m_validator; + m_validator_baton = rhs.m_validator_baton; +} + +void StringExtractorGDBRemote::SetResponseValidator( + ResponseValidatorCallback callback, void *baton) { + m_validator = callback; + m_validator_baton = baton; +} + +void StringExtractorGDBRemote::SetResponseValidatorToOKErrorNotSupported() { + m_validator = OKErrorNotSupportedResponseValidator; + m_validator_baton = nullptr; +} + +void StringExtractorGDBRemote::SetResponseValidatorToASCIIHexBytes() { + m_validator = ASCIIHexBytesResponseValidator; + m_validator_baton = nullptr; +} + +void StringExtractorGDBRemote::SetResponseValidatorToJSON() { + m_validator = JSONResponseValidator; + m_validator_baton = nullptr; +} + +bool StringExtractorGDBRemote::ValidateResponse() const { + // If we have a validator callback, try to validate the callback + if (m_validator) + return m_validator(m_validator_baton, *this); + else + return true; // No validator, so response is valid +} |