680 lines · cpp
1//===-- StringExtractorGDBRemote.cpp --------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Utility/StringExtractorGDBRemote.h"10 11#include <cctype>12#include <cstring>13#include <optional>14 15StringExtractorGDBRemote::ResponseType16StringExtractorGDBRemote::GetResponseType() const {17 if (m_packet.empty())18 return eUnsupported;19 20 switch (m_packet[0]) {21 case 'E':22 if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) {23 if (m_packet.size() == 3)24 return eError;25 llvm::StringRef packet_ref(m_packet);26 if (packet_ref[3] == ';') {27 auto err_string = packet_ref.substr(4);28 for (auto e : err_string)29 if (!isxdigit(e))30 return eResponse;31 return eError;32 }33 }34 break;35 36 case 'O':37 if (m_packet.size() == 2 && m_packet[1] == 'K')38 return eOK;39 break;40 41 case '+':42 if (m_packet.size() == 1)43 return eAck;44 break;45 46 case '-':47 if (m_packet.size() == 1)48 return eNack;49 break;50 }51 return eResponse;52}53 54StringExtractorGDBRemote::ServerPacketType55StringExtractorGDBRemote::GetServerPacketType() const {56#define PACKET_MATCHES(s) \57 ((packet_size == (sizeof(s) - 1)) && (strcmp((packet_cstr), (s)) == 0))58#define PACKET_STARTS_WITH(s) \59 ((packet_size >= (sizeof(s) - 1)) && \60 ::strncmp(packet_cstr, s, (sizeof(s) - 1)) == 0)61 62 // Empty is not a supported packet...63 if (m_packet.empty())64 return eServerPacketType_invalid;65 66 const size_t packet_size = m_packet.size();67 const char *packet_cstr = m_packet.c_str();68 switch (m_packet[0]) {69 70 case '%':71 return eServerPacketType_notify;72 73 case '\x03':74 if (packet_size == 1)75 return eServerPacketType_interrupt;76 break;77 78 case '-':79 if (packet_size == 1)80 return eServerPacketType_nack;81 break;82 83 case '+':84 if (packet_size == 1)85 return eServerPacketType_ack;86 break;87 88 case 'A':89 return eServerPacketType_A;90 91 case 'Q':92 93 switch (packet_cstr[1]) {94 case 'E':95 if (PACKET_STARTS_WITH("QEnvironment:"))96 return eServerPacketType_QEnvironment;97 if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:"))98 return eServerPacketType_QEnvironmentHexEncoded;99 if (PACKET_STARTS_WITH("QEnableErrorStrings"))100 return eServerPacketType_QEnableErrorStrings;101 break;102 103 case 'P':104 if (PACKET_STARTS_WITH("QPassSignals:"))105 return eServerPacketType_QPassSignals;106 break;107 108 case 'S':109 if (PACKET_MATCHES("QStartNoAckMode"))110 return eServerPacketType_QStartNoAckMode;111 if (PACKET_STARTS_WITH("QSaveRegisterState"))112 return eServerPacketType_QSaveRegisterState;113 if (PACKET_STARTS_WITH("QSetDisableASLR:"))114 return eServerPacketType_QSetDisableASLR;115 if (PACKET_STARTS_WITH("QSetDetachOnError:"))116 return eServerPacketType_QSetDetachOnError;117 if (PACKET_STARTS_WITH("QSetSTDIN:"))118 return eServerPacketType_QSetSTDIN;119 if (PACKET_STARTS_WITH("QSetSTDOUT:"))120 return eServerPacketType_QSetSTDOUT;121 if (PACKET_STARTS_WITH("QSetSTDERR:"))122 return eServerPacketType_QSetSTDERR;123 if (PACKET_STARTS_WITH("QSetWorkingDir:"))124 return eServerPacketType_QSetWorkingDir;125 if (PACKET_STARTS_WITH("QSetLogging:"))126 return eServerPacketType_QSetLogging;127 if (PACKET_STARTS_WITH("QSetIgnoredExceptions"))128 return eServerPacketType_QSetIgnoredExceptions;129 if (PACKET_STARTS_WITH("QSetMaxPacketSize:"))130 return eServerPacketType_QSetMaxPacketSize;131 if (PACKET_STARTS_WITH("QSetMaxPayloadSize:"))132 return eServerPacketType_QSetMaxPayloadSize;133 if (PACKET_STARTS_WITH("QSetEnableAsyncProfiling;"))134 return eServerPacketType_QSetEnableAsyncProfiling;135 if (PACKET_STARTS_WITH("QSyncThreadState:"))136 return eServerPacketType_QSyncThreadState;137 break;138 139 case 'L':140 if (PACKET_STARTS_WITH("QLaunchArch:"))141 return eServerPacketType_QLaunchArch;142 if (PACKET_MATCHES("QListThreadsInStopReply"))143 return eServerPacketType_QListThreadsInStopReply;144 break;145 146 case 'M':147 if (PACKET_STARTS_WITH("QMemTags"))148 return eServerPacketType_QMemTags;149 break;150 151 case 'N':152 if (PACKET_STARTS_WITH("QNonStop:"))153 return eServerPacketType_QNonStop;154 break;155 156 case 'R':157 if (PACKET_STARTS_WITH("QRestoreRegisterState:"))158 return eServerPacketType_QRestoreRegisterState;159 break;160 161 case 'T':162 if (PACKET_MATCHES("QThreadSuffixSupported"))163 return eServerPacketType_QThreadSuffixSupported;164 break;165 }166 break;167 168 case 'q':169 switch (packet_cstr[1]) {170 case 's':171 if (PACKET_MATCHES("qsProcessInfo"))172 return eServerPacketType_qsProcessInfo;173 if (PACKET_MATCHES("qsThreadInfo"))174 return eServerPacketType_qsThreadInfo;175 break;176 177 case 'f':178 if (PACKET_STARTS_WITH("qfProcessInfo"))179 return eServerPacketType_qfProcessInfo;180 if (PACKET_STARTS_WITH("qfThreadInfo"))181 return eServerPacketType_qfThreadInfo;182 break;183 184 case 'C':185 if (packet_size == 2)186 return eServerPacketType_qC;187 break;188 189 case 'E':190 if (PACKET_STARTS_WITH("qEcho:"))191 return eServerPacketType_qEcho;192 break;193 194 case 'F':195 if (PACKET_STARTS_WITH("qFileLoadAddress:"))196 return eServerPacketType_qFileLoadAddress;197 break;198 199 case 'G':200 if (PACKET_STARTS_WITH("qGroupName:"))201 return eServerPacketType_qGroupName;202 if (PACKET_MATCHES("qGetWorkingDir"))203 return eServerPacketType_qGetWorkingDir;204 if (PACKET_MATCHES("qGetPid"))205 return eServerPacketType_qGetPid;206 if (PACKET_STARTS_WITH("qGetProfileData;"))207 return eServerPacketType_qGetProfileData;208 if (PACKET_MATCHES("qGDBServerVersion"))209 return eServerPacketType_qGDBServerVersion;210 break;211 212 case 'H':213 if (PACKET_MATCHES("qHostInfo"))214 return eServerPacketType_qHostInfo;215 break;216 217 case 'K':218 if (PACKET_STARTS_WITH("qKillSpawnedProcess"))219 return eServerPacketType_qKillSpawnedProcess;220 break;221 222 case 'L':223 if (PACKET_STARTS_WITH("qLaunchGDBServer"))224 return eServerPacketType_qLaunchGDBServer;225 if (PACKET_MATCHES("qLaunchSuccess"))226 return eServerPacketType_qLaunchSuccess;227 break;228 229 case 'M':230 if (PACKET_STARTS_WITH("qMemoryRegionInfo:"))231 return eServerPacketType_qMemoryRegionInfo;232 if (PACKET_MATCHES("qMemoryRegionInfo"))233 return eServerPacketType_qMemoryRegionInfoSupported;234 if (PACKET_STARTS_WITH("qModuleInfo:"))235 return eServerPacketType_qModuleInfo;236 if (PACKET_STARTS_WITH("qMemTags:"))237 return eServerPacketType_qMemTags;238 break;239 240 case 'P':241 if (PACKET_STARTS_WITH("qProcessInfoPID:"))242 return eServerPacketType_qProcessInfoPID;243 if (PACKET_STARTS_WITH("qPlatform_shell:"))244 return eServerPacketType_qPlatform_shell;245 if (PACKET_STARTS_WITH("qPlatform_mkdir:"))246 return eServerPacketType_qPlatform_mkdir;247 if (PACKET_STARTS_WITH("qPlatform_chmod:"))248 return eServerPacketType_qPlatform_chmod;249 if (PACKET_MATCHES("qProcessInfo"))250 return eServerPacketType_qProcessInfo;251 if (PACKET_STARTS_WITH("qPathComplete:"))252 return eServerPacketType_qPathComplete;253 break;254 255 case 'Q':256 if (PACKET_MATCHES("qQueryGDBServer"))257 return eServerPacketType_qQueryGDBServer;258 break;259 260 case 'R':261 if (PACKET_STARTS_WITH("qRcmd,"))262 return eServerPacketType_qRcmd;263 if (PACKET_STARTS_WITH("qRegisterInfo"))264 return eServerPacketType_qRegisterInfo;265 break;266 267 case 'S':268 if (PACKET_STARTS_WITH("qSaveCore"))269 return eServerPacketType_qLLDBSaveCore;270 if (PACKET_STARTS_WITH("qSpeedTest:"))271 return eServerPacketType_qSpeedTest;272 if (PACKET_MATCHES("qShlibInfoAddr"))273 return eServerPacketType_qShlibInfoAddr;274 if (PACKET_MATCHES("qStepPacketSupported"))275 return eServerPacketType_qStepPacketSupported;276 if (PACKET_STARTS_WITH("qSupported"))277 return eServerPacketType_qSupported;278 if (PACKET_MATCHES("qSyncThreadStateSupported"))279 return eServerPacketType_qSyncThreadStateSupported;280 if (PACKET_MATCHES("qStructuredDataPlugins"))281 return eServerPacketType_qStructuredDataPlugins;282 break;283 284 case 'T':285 if (PACKET_STARTS_WITH("qThreadExtraInfo,"))286 return eServerPacketType_qThreadExtraInfo;287 if (PACKET_STARTS_WITH("qThreadStopInfo"))288 return eServerPacketType_qThreadStopInfo;289 break;290 291 case 'U':292 if (PACKET_STARTS_WITH("qUserName:"))293 return eServerPacketType_qUserName;294 break;295 296 case 'V':297 if (PACKET_MATCHES("qVAttachOrWaitSupported"))298 return eServerPacketType_qVAttachOrWaitSupported;299 break;300 301 case 'W':302 if (PACKET_STARTS_WITH("qWatchpointSupportInfo:"))303 return eServerPacketType_qWatchpointSupportInfo;304 if (PACKET_MATCHES("qWatchpointSupportInfo"))305 return eServerPacketType_qWatchpointSupportInfoSupported;306 break;307 308 case 'X':309 if (PACKET_STARTS_WITH("qXfer:"))310 return eServerPacketType_qXfer;311 break;312 }313 break;314 315 case 'j':316 if (PACKET_STARTS_WITH("jModulesInfo:"))317 return eServerPacketType_jModulesInfo;318 if (PACKET_MATCHES("jSignalsInfo"))319 return eServerPacketType_jSignalsInfo;320 if (PACKET_MATCHES("jThreadsInfo"))321 return eServerPacketType_jThreadsInfo;322 323 if (PACKET_MATCHES("jLLDBTraceSupported"))324 return eServerPacketType_jLLDBTraceSupported;325 if (PACKET_STARTS_WITH("jLLDBTraceStop:"))326 return eServerPacketType_jLLDBTraceStop;327 if (PACKET_STARTS_WITH("jLLDBTraceStart:"))328 return eServerPacketType_jLLDBTraceStart;329 if (PACKET_STARTS_WITH("jLLDBTraceGetState:"))330 return eServerPacketType_jLLDBTraceGetState;331 if (PACKET_STARTS_WITH("jLLDBTraceGetBinaryData:"))332 return eServerPacketType_jLLDBTraceGetBinaryData;333 break;334 335 case 'v':336 if (PACKET_STARTS_WITH("vFile:")) {337 if (PACKET_STARTS_WITH("vFile:open:"))338 return eServerPacketType_vFile_open;339 else if (PACKET_STARTS_WITH("vFile:close:"))340 return eServerPacketType_vFile_close;341 else if (PACKET_STARTS_WITH("vFile:pread"))342 return eServerPacketType_vFile_pread;343 else if (PACKET_STARTS_WITH("vFile:pwrite"))344 return eServerPacketType_vFile_pwrite;345 else if (PACKET_STARTS_WITH("vFile:size"))346 return eServerPacketType_vFile_size;347 else if (PACKET_STARTS_WITH("vFile:exists"))348 return eServerPacketType_vFile_exists;349 else if (PACKET_STARTS_WITH("vFile:fstat"))350 return eServerPacketType_vFile_fstat;351 else if (PACKET_STARTS_WITH("vFile:stat"))352 return eServerPacketType_vFile_stat;353 else if (PACKET_STARTS_WITH("vFile:mode"))354 return eServerPacketType_vFile_mode;355 else if (PACKET_STARTS_WITH("vFile:MD5"))356 return eServerPacketType_vFile_md5;357 else if (PACKET_STARTS_WITH("vFile:symlink"))358 return eServerPacketType_vFile_symlink;359 else if (PACKET_STARTS_WITH("vFile:unlink"))360 return eServerPacketType_vFile_unlink;361 362 } else {363 if (PACKET_STARTS_WITH("vAttach;"))364 return eServerPacketType_vAttach;365 if (PACKET_STARTS_WITH("vAttachWait;"))366 return eServerPacketType_vAttachWait;367 if (PACKET_STARTS_WITH("vAttachOrWait;"))368 return eServerPacketType_vAttachOrWait;369 if (PACKET_STARTS_WITH("vAttachName;"))370 return eServerPacketType_vAttachName;371 if (PACKET_STARTS_WITH("vCont;"))372 return eServerPacketType_vCont;373 if (PACKET_MATCHES("vCont?"))374 return eServerPacketType_vCont_actions;375 if (PACKET_STARTS_WITH("vKill;"))376 return eServerPacketType_vKill;377 if (PACKET_STARTS_WITH("vRun;"))378 return eServerPacketType_vRun;379 if (PACKET_MATCHES("vStopped"))380 return eServerPacketType_vStopped;381 if (PACKET_MATCHES("vCtrlC"))382 return eServerPacketType_vCtrlC;383 if (PACKET_MATCHES("vStdio"))384 return eServerPacketType_vStdio;385 break;386 387 }388 break;389 case '_':390 switch (packet_cstr[1]) {391 case 'M':392 return eServerPacketType__M;393 394 case 'm':395 return eServerPacketType__m;396 }397 break;398 399 case '?':400 if (packet_size == 1)401 return eServerPacketType_stop_reason;402 break;403 404 case 'c':405 return eServerPacketType_c;406 407 case 'C':408 return eServerPacketType_C;409 410 case 'D':411 return eServerPacketType_D;412 413 case 'g':414 return eServerPacketType_g;415 416 case 'G':417 return eServerPacketType_G;418 419 case 'H':420 return eServerPacketType_H;421 422 case 'I':423 return eServerPacketType_I;424 425 case 'k':426 if (packet_size == 1)427 return eServerPacketType_k;428 break;429 430 case 'm':431 return eServerPacketType_m;432 433 case 'M':434 return eServerPacketType_M;435 436 case 'p':437 return eServerPacketType_p;438 439 case 'P':440 return eServerPacketType_P;441 442 case 's':443 if (packet_size == 1)444 return eServerPacketType_s;445 break;446 447 case 'S':448 return eServerPacketType_S;449 450 case 'x':451 return eServerPacketType_x;452 453 case 'X':454 return eServerPacketType_X;455 456 case 'T':457 return eServerPacketType_T;458 459 case 'z':460 if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4')461 return eServerPacketType_z;462 break;463 464 case 'Z':465 if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4')466 return eServerPacketType_Z;467 break;468 }469 return eServerPacketType_unimplemented;470}471 472bool StringExtractorGDBRemote::IsOKResponse() const {473 return GetResponseType() == eOK;474}475 476bool StringExtractorGDBRemote::IsUnsupportedResponse() const {477 return GetResponseType() == eUnsupported;478}479 480bool StringExtractorGDBRemote::IsNormalResponse() const {481 return GetResponseType() == eResponse;482}483 484bool StringExtractorGDBRemote::IsErrorResponse() const {485 return GetResponseType() == eError && isxdigit(m_packet[1]) &&486 isxdigit(m_packet[2]);487}488 489uint8_t StringExtractorGDBRemote::GetError() {490 if (GetResponseType() == eError) {491 SetFilePos(1);492 return GetHexU8(255);493 }494 return 0;495}496 497lldb_private::Status StringExtractorGDBRemote::GetStatus() {498 lldb_private::Status error;499 if (GetResponseType() == eError) {500 SetFilePos(1);501 uint8_t errc = GetHexU8(255);502 error = lldb_private::Status::FromErrorStringWithFormat("Error %u", errc);503 std::string error_messg;504 if (GetChar() == ';') {505 GetHexByteString(error_messg);506 error = lldb_private::Status(error_messg);507 }508 }509 return error;510}511 512size_t StringExtractorGDBRemote::GetEscapedBinaryData(std::string &str) {513 // Just get the data bytes in the string as514 // GDBRemoteCommunication::CheckForPacket() already removes any 0x7d escaped515 // characters. If any 0x7d characters are left in the packet, then they are516 // supposed to be there...517 str.clear();518 const size_t bytes_left = GetBytesLeft();519 if (bytes_left > 0) {520 str.assign(m_packet, m_index, bytes_left);521 m_index += bytes_left;522 }523 return str.size();524}525 526static bool527OKErrorNotSupportedResponseValidator(void *,528 const StringExtractorGDBRemote &response) {529 switch (response.GetResponseType()) {530 case StringExtractorGDBRemote::eOK:531 case StringExtractorGDBRemote::eError:532 case StringExtractorGDBRemote::eUnsupported:533 return true;534 535 case StringExtractorGDBRemote::eAck:536 case StringExtractorGDBRemote::eNack:537 case StringExtractorGDBRemote::eResponse:538 break;539 }540 return false;541}542 543static bool JSONResponseValidator(void *,544 const StringExtractorGDBRemote &response) {545 switch (response.GetResponseType()) {546 case StringExtractorGDBRemote::eUnsupported:547 case StringExtractorGDBRemote::eError:548 return true; // Accept unsupported or EXX as valid responses549 550 case StringExtractorGDBRemote::eOK:551 case StringExtractorGDBRemote::eAck:552 case StringExtractorGDBRemote::eNack:553 break;554 555 case StringExtractorGDBRemote::eResponse:556 // JSON that is returned in from JSON query packets is currently always557 // either a dictionary which starts with a '{', or an array which starts558 // with a '['. This is a quick validator to just make sure the response559 // could be valid JSON without having to validate all of the560 // JSON content.561 switch (response.GetStringRef()[0]) {562 case '{':563 return true;564 case '[':565 return true;566 default:567 break;568 }569 break;570 }571 return false;572}573 574static bool575ASCIIHexBytesResponseValidator(void *,576 const StringExtractorGDBRemote &response) {577 switch (response.GetResponseType()) {578 case StringExtractorGDBRemote::eUnsupported:579 case StringExtractorGDBRemote::eError:580 return true; // Accept unsupported or EXX as valid responses581 582 case StringExtractorGDBRemote::eOK:583 case StringExtractorGDBRemote::eAck:584 case StringExtractorGDBRemote::eNack:585 break;586 587 case StringExtractorGDBRemote::eResponse: {588 uint32_t valid_count = 0;589 for (const char ch : response.GetStringRef()) {590 if (!isxdigit(ch)) {591 return false;592 }593 if (++valid_count >= 16)594 break; // Don't validate all the characters in case the packet is very595 // large596 }597 return true;598 } break;599 }600 return false;601}602 603void StringExtractorGDBRemote::CopyResponseValidator(604 const StringExtractorGDBRemote &rhs) {605 m_validator = rhs.m_validator;606 m_validator_baton = rhs.m_validator_baton;607}608 609void StringExtractorGDBRemote::SetResponseValidator(610 ResponseValidatorCallback callback, void *baton) {611 m_validator = callback;612 m_validator_baton = baton;613}614 615void StringExtractorGDBRemote::SetResponseValidatorToOKErrorNotSupported() {616 m_validator = OKErrorNotSupportedResponseValidator;617 m_validator_baton = nullptr;618}619 620void StringExtractorGDBRemote::SetResponseValidatorToASCIIHexBytes() {621 m_validator = ASCIIHexBytesResponseValidator;622 m_validator_baton = nullptr;623}624 625void StringExtractorGDBRemote::SetResponseValidatorToJSON() {626 m_validator = JSONResponseValidator;627 m_validator_baton = nullptr;628}629 630bool StringExtractorGDBRemote::ValidateResponse() const {631 // If we have a validator callback, try to validate the callback632 if (m_validator)633 return m_validator(m_validator_baton, *this);634 else635 return true; // No validator, so response is valid636}637 638std::optional<std::pair<lldb::pid_t, lldb::tid_t>>639StringExtractorGDBRemote::GetPidTid(lldb::pid_t default_pid) {640 llvm::StringRef view = llvm::StringRef(m_packet).substr(m_index);641 size_t initial_length = view.size();642 lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;643 lldb::tid_t tid;644 645 if (view.consume_front("p")) {646 // process identifier647 if (view.consume_front("-1")) {648 // -1 is a special case649 pid = AllProcesses;650 } else if (view.consumeInteger(16, pid) || pid == 0) {651 // not a valid hex integer OR unsupported pid 0652 m_index = UINT64_MAX;653 return std::nullopt;654 }655 656 // "." must follow if we expect TID too; otherwise, we assume -1657 if (!view.consume_front(".")) {658 // update m_index659 m_index += initial_length - view.size();660 661 return {{pid, AllThreads}};662 }663 }664 665 // thread identifier666 if (view.consume_front("-1")) {667 // -1 is a special case668 tid = AllThreads;669 } else if (view.consumeInteger(16, tid) || tid == 0 || pid == AllProcesses) {670 // not a valid hex integer OR tid 0 OR pid -1 + a specific tid671 m_index = UINT64_MAX;672 return std::nullopt;673 }674 675 // update m_index676 m_index += initial_length - view.size();677 678 return {{pid != LLDB_INVALID_PROCESS_ID ? pid : default_pid, tid}};679}680