brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.7 KiB · 40b5d03 Raw
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