11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/gdb-server-thread.h"
61cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/gdb-server.h"
71cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/session.h"
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_cinamespace v8 {
101cb0ef41Sopenharmony_cinamespace internal {
111cb0ef41Sopenharmony_cinamespace wasm {
121cb0ef41Sopenharmony_cinamespace gdb_server {
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciGdbServerThread::GdbServerThread(GdbServer* gdb_server)
151cb0ef41Sopenharmony_ci    : Thread(v8::base::Thread::Options("GdbServerThread")),
161cb0ef41Sopenharmony_ci      gdb_server_(gdb_server),
171cb0ef41Sopenharmony_ci      start_semaphore_(0) {}
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_cibool GdbServerThread::StartAndInitialize() {
201cb0ef41Sopenharmony_ci  // Executed in the Isolate thread.
211cb0ef41Sopenharmony_ci  if (!Start()) {
221cb0ef41Sopenharmony_ci    return false;
231cb0ef41Sopenharmony_ci  }
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci  // We need to make sure that {Stop} is never called before the thread has
261cb0ef41Sopenharmony_ci  // completely initialized {transport_} and {target_}. Otherwise there could be
271cb0ef41Sopenharmony_ci  // a race condition where in the main thread {Stop} might get called before
281cb0ef41Sopenharmony_ci  // the transport is created, and then in the GDBServer thread we may have time
291cb0ef41Sopenharmony_ci  // to setup the transport and block on accept() before the main thread blocks
301cb0ef41Sopenharmony_ci  // on joining the thread.
311cb0ef41Sopenharmony_ci  // The small performance hit caused by this Wait should be negligeable because
321cb0ef41Sopenharmony_ci  // this operation happensat most once per process and only when the
331cb0ef41Sopenharmony_ci  // --wasm-gdb-remote flag is set.
341cb0ef41Sopenharmony_ci  start_semaphore_.Wait();
351cb0ef41Sopenharmony_ci  return !!target_;
361cb0ef41Sopenharmony_ci}
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_civoid GdbServerThread::CleanupThread() {
391cb0ef41Sopenharmony_ci  // Executed in the GdbServer thread.
401cb0ef41Sopenharmony_ci  v8::base::MutexGuard guard(&mutex_);
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  target_ = nullptr;
431cb0ef41Sopenharmony_ci  transport_ = nullptr;
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci#if _WIN32
461cb0ef41Sopenharmony_ci  ::WSACleanup();
471cb0ef41Sopenharmony_ci#endif
481cb0ef41Sopenharmony_ci}
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_civoid GdbServerThread::Run() {
511cb0ef41Sopenharmony_ci  // Executed in the GdbServer thread.
521cb0ef41Sopenharmony_ci#ifdef _WIN32
531cb0ef41Sopenharmony_ci  // Initialize Winsock
541cb0ef41Sopenharmony_ci  WSADATA wsaData;
551cb0ef41Sopenharmony_ci  int iResult = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
561cb0ef41Sopenharmony_ci  if (iResult != 0) {
571cb0ef41Sopenharmony_ci    TRACE_GDB_REMOTE("GdbServerThread::Run: WSAStartup failed\n");
581cb0ef41Sopenharmony_ci    return;
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci#endif
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  // If the default port is not available, try any port.
631cb0ef41Sopenharmony_ci  SocketBinding socket_binding = SocketBinding::Bind(FLAG_wasm_gdb_remote_port);
641cb0ef41Sopenharmony_ci  if (!socket_binding.IsValid()) {
651cb0ef41Sopenharmony_ci    socket_binding = SocketBinding::Bind(0);
661cb0ef41Sopenharmony_ci  }
671cb0ef41Sopenharmony_ci  if (!socket_binding.IsValid()) {
681cb0ef41Sopenharmony_ci    TRACE_GDB_REMOTE("GdbServerThread::Run: Failed to bind any TCP port\n");
691cb0ef41Sopenharmony_ci    return;
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci  TRACE_GDB_REMOTE("gdb-remote(%d) : Connect GDB with 'target remote :%d\n",
721cb0ef41Sopenharmony_ci                   __LINE__, socket_binding.GetBoundPort());
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  transport_ = socket_binding.CreateTransport();
751cb0ef41Sopenharmony_ci  target_ = std::make_unique<Target>(gdb_server_);
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  // Here we have completed the initialization, and the thread that called
781cb0ef41Sopenharmony_ci  // {StartAndInitialize} may resume execution.
791cb0ef41Sopenharmony_ci  start_semaphore_.Signal();
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  while (!target_->IsTerminated()) {
821cb0ef41Sopenharmony_ci    // Wait for incoming connections.
831cb0ef41Sopenharmony_ci    if (!transport_->AcceptConnection()) {
841cb0ef41Sopenharmony_ci      continue;
851cb0ef41Sopenharmony_ci    }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci    // Create a new session for this connection
881cb0ef41Sopenharmony_ci    Session session(transport_.get());
891cb0ef41Sopenharmony_ci    TRACE_GDB_REMOTE("GdbServerThread: Connected\n");
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci    // Run this session for as long as it lasts
921cb0ef41Sopenharmony_ci    target_->Run(&session);
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci  CleanupThread();
951cb0ef41Sopenharmony_ci}
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_civoid GdbServerThread::Stop() {
981cb0ef41Sopenharmony_ci  // Executed in the Isolate thread.
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  // Synchronized, becauses {Stop} might be called while {Run} is still
1011cb0ef41Sopenharmony_ci  // initializing {transport_} and {target_}. If this happens and the thread is
1021cb0ef41Sopenharmony_ci  // blocked waiting for an incoming connection or GdbServer for incoming
1031cb0ef41Sopenharmony_ci  // packets, it will unblocked when {transport_} is closed.
1041cb0ef41Sopenharmony_ci  v8::base::MutexGuard guard(&mutex_);
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  if (target_) {
1071cb0ef41Sopenharmony_ci    target_->Terminate();
1081cb0ef41Sopenharmony_ci  }
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  if (transport_) {
1111cb0ef41Sopenharmony_ci    transport_->Close();
1121cb0ef41Sopenharmony_ci  }
1131cb0ef41Sopenharmony_ci}
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci}  // namespace gdb_server
1161cb0ef41Sopenharmony_ci}  // namespace wasm
1171cb0ef41Sopenharmony_ci}  // namespace internal
1181cb0ef41Sopenharmony_ci}  // namespace v8
119