diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:51:52 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:51:52 +0000 | 
| commit | 5f29bb8a675e8f96452b632e7129113f7dec850e (patch) | |
| tree | 3d3f2a0d3ad10872a4dcaba8ec8d1d20c87ab147 /source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | |
| parent | 88c643b6fec27eec436c8d138fee6346e92337d6 (diff) | |
Notes
Diffstat (limited to 'source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp')
| -rw-r--r-- | source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp | 210 | 
1 files changed, 134 insertions, 76 deletions
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index cdb63e72f6bd..196607665bba 100644 --- a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1,9 +1,8 @@  //===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===//  // -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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  //  //===----------------------------------------------------------------------===// @@ -21,6 +20,7 @@  #include "lldb/Host/ConnectionFileDescriptor.h"  #include "lldb/Host/Debug.h"  #include "lldb/Host/File.h" +#include "lldb/Host/FileAction.h"  #include "lldb/Host/FileSystem.h"  #include "lldb/Host/Host.h"  #include "lldb/Host/HostInfo.h" @@ -28,7 +28,6 @@  #include "lldb/Host/common/NativeProcessProtocol.h"  #include "lldb/Host/common/NativeRegisterContext.h"  #include "lldb/Host/common/NativeThreadProtocol.h" -#include "lldb/Target/FileAction.h"  #include "lldb/Target/MemoryRegionInfo.h"  #include "lldb/Utility/Args.h"  #include "lldb/Utility/DataBuffer.h" @@ -52,9 +51,7 @@ using namespace lldb_private;  using namespace lldb_private::process_gdb_remote;  using namespace llvm; -//----------------------------------------------------------------------  // GDBRemote Errors -//----------------------------------------------------------------------  namespace {  enum GDBRemoteServerError { @@ -66,9 +63,7 @@ enum GDBRemoteServerError {  };  } -//----------------------------------------------------------------------  // GDBRemoteCommunicationServerLLGS constructor -//----------------------------------------------------------------------  GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(      MainLoop &mainloop, const NativeProcessProtocol::Factory &process_factory)      : GDBRemoteCommunicationServerCommon("gdb-remote.server", @@ -149,8 +144,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {        StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo,        &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo);    RegisterMemberFunctionHandler( -      StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, -      &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); +      StringExtractorGDBRemote::eServerPacketType_qXfer, +      &GDBRemoteCommunicationServerLLGS::Handle_qXfer);    RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s,                                  &GDBRemoteCommunicationServerLLGS::Handle_s);    RegisterMemberFunctionHandler( @@ -192,6 +187,9 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {        StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead,        &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead); +  RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, +                                &GDBRemoteCommunicationServerLLGS::Handle_g); +    RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k,                          [this](StringExtractorGDBRemote packet, Status &error,                                 bool &interrupt, bool &quit) { @@ -623,7 +621,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(      } else {        // The thread name contains special chars, send as hex bytes.        response.PutCString("hexname:"); -      response.PutCStringAsRawHex8(thread_name.c_str()); +      response.PutStringAsRawHex8(thread_name);      }      response.PutChar(';');    } @@ -663,7 +661,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(          response.PutCString("jstopinfo:");          StreamString unescaped_response;          threads_info_sp->Write(unescaped_response); -        response.PutCStringAsRawHex8(unescaped_response.GetData()); +        response.PutStringAsRawHex8(unescaped_response.GetData());          response.PutChar(';');        } else          LLDB_LOG(log, "failed to prepare a jstopinfo field for pid {0}", @@ -764,7 +762,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread(    if (!description.empty()) {      // Description may contains special chars, send as hex bytes.      response.PutCString("description:"); -    response.PutCStringAsRawHex8(description.c_str()); +    response.PutStringAsRawHex8(description);      response.PutChar(';');    } else if ((tid_stop_info.reason == eStopReasonException) &&               tid_stop_info.details.exception.type) { @@ -1341,7 +1339,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir(    FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()};    if (working_dir) {      StreamString response; -    response.PutCStringAsRawHex8(working_dir.GetCString()); +    response.PutStringAsRawHex8(working_dir.GetCString());      return SendPacketNoLock(response.GetString());    } @@ -1897,6 +1895,61 @@ GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo(  }  GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_g(StringExtractorGDBRemote &packet) { +  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); + +  // Move past packet name. +  packet.SetFilePos(strlen("g")); + +  // Get the thread to use. +  NativeThreadProtocol *thread = GetThreadFromSuffix(packet); +  if (!thread) { +    LLDB_LOG(log, "failed, no thread available"); +    return SendErrorResponse(0x15); +  } + +  // Get the thread's register context. +  NativeRegisterContext ®_ctx = thread->GetRegisterContext(); + +  std::vector<uint8_t> regs_buffer; +  for (uint32_t reg_num = 0; reg_num < reg_ctx.GetUserRegisterCount(); +       ++reg_num) { +    const RegisterInfo *reg_info = reg_ctx.GetRegisterInfoAtIndex(reg_num); + +    if (reg_info == nullptr) { +      LLDB_LOG(log, "failed to get register info for register index {0}", +               reg_num); +      return SendErrorResponse(0x15); +    } + +    if (reg_info->value_regs != nullptr) +      continue; // skip registers that are contained in other registers + +    RegisterValue reg_value; +    Status error = reg_ctx.ReadRegister(reg_info, reg_value); +    if (error.Fail()) { +      LLDB_LOG(log, "failed to read register at index {0}", reg_num); +      return SendErrorResponse(0x15); +    } + +    if (reg_info->byte_offset + reg_info->byte_size >= regs_buffer.size()) +      // Resize the buffer to guarantee it can store the register offsetted +      // data. +      regs_buffer.resize(reg_info->byte_offset + reg_info->byte_size); + +    // Copy the register offsetted data to the buffer. +    memcpy(regs_buffer.data() + reg_info->byte_offset, reg_value.GetBytes(), +           reg_info->byte_size); +  } + +  // Write the response. +  StreamGDBRemote response; +  response.PutBytesAsRawHex8(regs_buffer.data(), regs_buffer.size()); + +  return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult  GDBRemoteCommunicationServerLLGS::Handle_p(StringExtractorGDBRemote &packet) {    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -2426,7 +2479,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(      // Return the error message.      response.PutCString("error:"); -    response.PutCStringAsRawHex8(error.AsCString()); +    response.PutStringAsRawHex8(error.AsCString());      response.PutChar(';');    } else {      // Range start and size. @@ -2454,7 +2507,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(      ConstString name = region_info.GetName();      if (name) {        response.PutCString("name:"); -      response.PutCStringAsRawHex8(name.AsCString()); +      response.PutStringAsRawHex8(name.AsCString());        response.PutChar(';');      }    } @@ -2694,94 +2747,99 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {    return PacketResult::Success;  } -GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read( -    StringExtractorGDBRemote &packet) { -// *BSD impls should be able to do this too. -#if defined(__linux__) || defined(__NetBSD__) -  Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - -  // Parse out the offset. -  packet.SetFilePos(strlen("qXfer:auxv:read::")); -  if (packet.GetBytesLeft() < 1) -    return SendIllFormedResponse(packet, -                                 "qXfer:auxv:read:: packet missing offset"); - -  const uint64_t auxv_offset = -      packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); -  if (auxv_offset == std::numeric_limits<uint64_t>::max()) -    return SendIllFormedResponse(packet, -                                 "qXfer:auxv:read:: packet missing offset"); - -  // Parse out comma. -  if (packet.GetBytesLeft() < 1 || packet.GetChar() != ',') -    return SendIllFormedResponse( -        packet, "qXfer:auxv:read:: packet missing comma after offset"); - -  // Parse out the length. -  const uint64_t auxv_length = -      packet.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); -  if (auxv_length == std::numeric_limits<uint64_t>::max()) -    return SendIllFormedResponse(packet, -                                 "qXfer:auxv:read:: packet missing length"); - -  // Grab the auxv data if we need it. -  if (!m_active_auxv_buffer_up) { +llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> +GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, +                                                 llvm::StringRef annex) { +  if (object == "auxv") {      // Make sure we have a valid process.      if (!m_debugged_process_up ||          (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { -      if (log) -        log->Printf( -            "GDBRemoteCommunicationServerLLGS::%s failed, no process available", -            __FUNCTION__); -      return SendErrorResponse(0x10); +      return llvm::createStringError(llvm::inconvertibleErrorCode(), +                                     "No process available");      }      // Grab the auxv data.      auto buffer_or_error = m_debugged_process_up->GetAuxvData(); -    if (!buffer_or_error) { -      std::error_code ec = buffer_or_error.getError(); -      LLDB_LOG(log, "no auxv data retrieved: {0}", ec.message()); -      return SendErrorResponse(ec.value()); -    } -    m_active_auxv_buffer_up = std::move(*buffer_or_error); +    if (!buffer_or_error) +      return llvm::errorCodeToError(buffer_or_error.getError()); +    return std::move(*buffer_or_error);    } +  return llvm::make_error<PacketUnimplementedError>( +      "Xfer object not supported"); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qXfer( +    StringExtractorGDBRemote &packet) { +  SmallVector<StringRef, 5> fields; +  // The packet format is "qXfer:<object>:<action>:<annex>:offset,length" +  StringRef(packet.GetStringRef()).split(fields, ':', 4); +  if (fields.size() != 5) +    return SendIllFormedResponse(packet, "malformed qXfer packet"); +  StringRef &xfer_object = fields[1]; +  StringRef &xfer_action = fields[2]; +  StringRef &xfer_annex = fields[3]; +  StringExtractor offset_data(fields[4]); +  if (xfer_action != "read") +    return SendUnimplementedResponse("qXfer action not supported"); +  // Parse offset. +  const uint64_t xfer_offset = +      offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); +  if (xfer_offset == std::numeric_limits<uint64_t>::max()) +    return SendIllFormedResponse(packet, "qXfer packet missing offset"); +  // Parse out comma. +  if (offset_data.GetChar() != ',') +    return SendIllFormedResponse(packet, +                                 "qXfer packet missing comma after offset"); +  // Parse out the length. +  const uint64_t xfer_length = +      offset_data.GetHexMaxU64(false, std::numeric_limits<uint64_t>::max()); +  if (xfer_length == std::numeric_limits<uint64_t>::max()) +    return SendIllFormedResponse(packet, "qXfer packet missing length"); + +  // Get a previously constructed buffer if it exists or create it now. +  std::string buffer_key = (xfer_object + xfer_action + xfer_annex).str(); +  auto buffer_it = m_xfer_buffer_map.find(buffer_key); +  if (buffer_it == m_xfer_buffer_map.end()) { +    auto buffer_up = ReadXferObject(xfer_object, xfer_annex); +    if (!buffer_up) +      return SendErrorResponse(buffer_up.takeError()); +    buffer_it = m_xfer_buffer_map +                    .insert(std::make_pair(buffer_key, std::move(*buffer_up))) +                    .first; +  } + +  // Send back the response    StreamGDBRemote response;    bool done_with_buffer = false; - -  llvm::StringRef buffer = m_active_auxv_buffer_up->getBuffer(); -  if (auxv_offset >= buffer.size()) { +  llvm::StringRef buffer = buffer_it->second->getBuffer(); +  if (xfer_offset >= buffer.size()) {      // We have nothing left to send.  Mark the buffer as complete.      response.PutChar('l');      done_with_buffer = true;    } else {      // Figure out how many bytes are available starting at the given offset. -    buffer = buffer.drop_front(auxv_offset); - +    buffer = buffer.drop_front(xfer_offset);      // Mark the response type according to whether we're reading the remainder -    // of the auxv data. -    if (auxv_length >= buffer.size()) { +    // of the data. +    if (xfer_length >= buffer.size()) {        // There will be nothing left to read after this        response.PutChar('l');        done_with_buffer = true;      } else {        // There will still be bytes to read after this request.        response.PutChar('m'); -      buffer = buffer.take_front(auxv_length); +      buffer = buffer.take_front(xfer_length);      } -      // Now write the data in encoded binary form.      response.PutEscapedBytes(buffer.data(), buffer.size());    }    if (done_with_buffer) -    m_active_auxv_buffer_up.reset(); +    m_xfer_buffer_map.erase(buffer_it);    return SendPacketNoLock(response.GetString()); -#else -  return SendUnimplementedResponse("not implemented on this platform"); -#endif  }  GDBRemoteCommunication::PacketResult @@ -3206,8 +3264,8 @@ uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID() {  void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() {    Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); -  LLDB_LOG(log, "clearing auxv buffer: {0}", m_active_auxv_buffer_up.get()); -  m_active_auxv_buffer_up.reset(); +  LLDB_LOG(log, "clearing {0} xfer buffers", m_xfer_buffer_map.size()); +  m_xfer_buffer_map.clear();  }  FileSpec  | 
