reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
//===-- TestClient.h --------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_SERVER_TESTS_TESTCLIENT_H
#define LLDB_SERVER_TESTS_TESTCLIENT_H

#include "MessageObjects.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
#include "lldb/Host/ProcessLaunchInfo.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Connection.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/FormatVariadic.h"
#include <memory>
#include <string>

#if LLDB_SERVER_IS_DEBUGSERVER
#define LLGS_TEST(x) DISABLED_ ## x
#define DS_TEST(x) x
#else
#define LLGS_TEST(x) x
#define DS_TEST(x) DISABLED_ ## x
#endif

namespace llgs_tests {
class TestClient
    : public lldb_private::process_gdb_remote::GDBRemoteCommunicationClient {
public:
  static bool IsDebugServer() { return LLDB_SERVER_IS_DEBUGSERVER; }
  static bool IsLldbServer() { return !IsDebugServer(); }

  /// Launches the server, connects it to the client and returns the client. If
  /// Log is non-empty, the server will write it's log to this file.
  static llvm::Expected<std::unique_ptr<TestClient>> launch(llvm::StringRef Log);

  /// Launches the server, while specifying the inferior on its command line.
  /// When the client connects, it already has a process ready.
  static llvm::Expected<std::unique_ptr<TestClient>>
  launch(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> InferiorArgs);

  /// Allows user to pass additional arguments to the server. Be careful when
  /// using this for generic tests, as the two stubs have different
  /// command-line interfaces.
  static llvm::Expected<std::unique_ptr<TestClient>>
  launchCustom(llvm::StringRef Log, llvm::ArrayRef<llvm::StringRef> ServerArgs, llvm::ArrayRef<llvm::StringRef> InferiorArgs);


  ~TestClient() override;
  llvm::Error SetInferior(llvm::ArrayRef<std::string> inferior_args);
  llvm::Error ListThreadsInStopReply();
  llvm::Error SetBreakpoint(unsigned long address);
  llvm::Error ContinueAll();
  llvm::Error ContinueThread(unsigned long thread_id);
  const ProcessInfo &GetProcessInfo();
  llvm::Expected<JThreadsInfo> GetJThreadsInfo();
  const StopReply &GetLatestStopReply();
  template <typename T> llvm::Expected<const T &> GetLatestStopReplyAs() {
    assert(m_stop_reply);
    if (const auto *Reply = llvm::dyn_cast<T>(m_stop_reply.get()))
      return *Reply;
    return llvm::make_error<llvm::StringError>(
        llvm::formatv("Unexpected Stop Reply {0}", m_stop_reply->getKind()),
        llvm::inconvertibleErrorCode());
  }
  llvm::Error SendMessage(llvm::StringRef message);
  llvm::Error SendMessage(llvm::StringRef message,
                          std::string &response_string);
  llvm::Error SendMessage(llvm::StringRef message, std::string &response_string,
                          PacketResult expected_result);

  template <typename P, typename... CreateArgs>
  llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message,
                                                      CreateArgs &&... Args);
  unsigned int GetPcRegisterId();

private:
  TestClient(std::unique_ptr<lldb_private::Connection> Conn);

  llvm::Error initializeConnection();
  llvm::Error qProcessInfo();
  llvm::Error qRegisterInfos();
  llvm::Error queryProcess();
  llvm::Error Continue(llvm::StringRef message);
  std::string FormatFailedResult(
      const std::string &message,
      lldb_private::process_gdb_remote::GDBRemoteCommunication::PacketResult
          result);

  llvm::Optional<ProcessInfo> m_process_info;
  std::unique_ptr<StopReply> m_stop_reply;
  std::vector<lldb_private::RegisterInfo> m_register_infos;
  unsigned int m_pc_register = LLDB_INVALID_REGNUM;
};

template <typename P, typename... CreateArgs>
llvm::Expected<typename P::result_type>
TestClient::SendMessage(llvm::StringRef Message, CreateArgs &&... Args) {
  std::string ResponseText;
  if (llvm::Error E = SendMessage(Message, ResponseText))
    return std::move(E);
  return P::create(ResponseText, std::forward<CreateArgs>(Args)...);
}

} // namespace llgs_tests

#endif // LLDB_SERVER_TESTS_TESTCLIENT_H