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.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <inttypes.h>
81cb0ef41Sopenharmony_ci#include <functional>
91cb0ef41Sopenharmony_ci#include "src/api/api-inl.h"
101cb0ef41Sopenharmony_ci#include "src/api/api.h"
111cb0ef41Sopenharmony_ci#include "src/debug/debug.h"
121cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/gdb-server-thread.h"
131cb0ef41Sopenharmony_ci#include "src/utils/locked-queue-inl.h"
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cinamespace v8 {
161cb0ef41Sopenharmony_cinamespace internal {
171cb0ef41Sopenharmony_cinamespace wasm {
181cb0ef41Sopenharmony_cinamespace gdb_server {
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cistatic const uint32_t kMaxWasmCallStack = 20;
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci// A TaskRunner is an object that runs posted tasks (in the form of closure
231cb0ef41Sopenharmony_ci// objects). Tasks are queued and run, in order, in the thread where the
241cb0ef41Sopenharmony_ci// TaskRunner::RunMessageLoop() is called.
251cb0ef41Sopenharmony_ciclass TaskRunner {
261cb0ef41Sopenharmony_ci public:
271cb0ef41Sopenharmony_ci  // Class Task wraps a std::function with a semaphore to signal its completion.
281cb0ef41Sopenharmony_ci  // This logic would be neatly implemented with std::packaged_tasks but we
291cb0ef41Sopenharmony_ci  // cannot use <future> in V8.
301cb0ef41Sopenharmony_ci  class Task {
311cb0ef41Sopenharmony_ci   public:
321cb0ef41Sopenharmony_ci    Task(base::Semaphore* ready_semaphore, std::function<void()> func)
331cb0ef41Sopenharmony_ci        : ready_semaphore_(ready_semaphore), func_(func) {}
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci    void Run() {
361cb0ef41Sopenharmony_ci      func_();
371cb0ef41Sopenharmony_ci      ready_semaphore_->Signal();
381cb0ef41Sopenharmony_ci    }
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci    // A semaphore object passed by the thread that posts a task.
411cb0ef41Sopenharmony_ci    // The sender can Wait on this semaphore to block until the task has
421cb0ef41Sopenharmony_ci    // completed execution in the TaskRunner thread.
431cb0ef41Sopenharmony_ci    base::Semaphore* ready_semaphore_;
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci    // The function to run.
461cb0ef41Sopenharmony_ci    std::function<void()> func_;
471cb0ef41Sopenharmony_ci  };
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ci  TaskRunner()
501cb0ef41Sopenharmony_ci      : process_queue_semaphore_(0),
511cb0ef41Sopenharmony_ci        nested_loop_count_(0),
521cb0ef41Sopenharmony_ci        is_terminated_(false) {}
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  TaskRunner(const TaskRunner&) = delete;
551cb0ef41Sopenharmony_ci  TaskRunner& operator=(const TaskRunner&) = delete;
561cb0ef41Sopenharmony_ci
571cb0ef41Sopenharmony_ci  // Starts the task runner. All tasks posted are run, in order, in the thread
581cb0ef41Sopenharmony_ci  // that calls this function.
591cb0ef41Sopenharmony_ci  void Run() {
601cb0ef41Sopenharmony_ci    is_terminated_ = false;
611cb0ef41Sopenharmony_ci    int loop_number = ++nested_loop_count_;
621cb0ef41Sopenharmony_ci    while (nested_loop_count_ == loop_number && !is_terminated_) {
631cb0ef41Sopenharmony_ci      std::shared_ptr<Task> task = GetNext();
641cb0ef41Sopenharmony_ci      if (task) {
651cb0ef41Sopenharmony_ci        task->Run();
661cb0ef41Sopenharmony_ci      }
671cb0ef41Sopenharmony_ci    }
681cb0ef41Sopenharmony_ci  }
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  // Terminates the task runner. Tasks that are still pending in the queue are
711cb0ef41Sopenharmony_ci  // not discarded and will be executed when the task runner is restarted.
721cb0ef41Sopenharmony_ci  void Terminate() {
731cb0ef41Sopenharmony_ci    DCHECK_LT(0, nested_loop_count_);
741cb0ef41Sopenharmony_ci    --nested_loop_count_;
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci    is_terminated_ = true;
771cb0ef41Sopenharmony_ci    process_queue_semaphore_.Signal();
781cb0ef41Sopenharmony_ci  }
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  // Posts a task to the task runner, to be executed in the task runner thread.
811cb0ef41Sopenharmony_ci  template <typename Functor>
821cb0ef41Sopenharmony_ci  auto Append(base::Semaphore* ready_semaphore, Functor&& task) {
831cb0ef41Sopenharmony_ci    queue_.Enqueue(std::make_shared<Task>(ready_semaphore, task));
841cb0ef41Sopenharmony_ci    process_queue_semaphore_.Signal();
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci private:
881cb0ef41Sopenharmony_ci  std::shared_ptr<Task> GetNext() {
891cb0ef41Sopenharmony_ci    while (!is_terminated_) {
901cb0ef41Sopenharmony_ci      if (queue_.IsEmpty()) {
911cb0ef41Sopenharmony_ci        process_queue_semaphore_.Wait();
921cb0ef41Sopenharmony_ci      }
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci      std::shared_ptr<Task> task;
951cb0ef41Sopenharmony_ci      if (queue_.Dequeue(&task)) {
961cb0ef41Sopenharmony_ci        return task;
971cb0ef41Sopenharmony_ci      }
981cb0ef41Sopenharmony_ci    }
991cb0ef41Sopenharmony_ci    return nullptr;
1001cb0ef41Sopenharmony_ci  }
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  LockedQueue<std::shared_ptr<Task>> queue_;
1031cb0ef41Sopenharmony_ci  v8::base::Semaphore process_queue_semaphore_;
1041cb0ef41Sopenharmony_ci  int nested_loop_count_;
1051cb0ef41Sopenharmony_ci  std::atomic<bool> is_terminated_;
1061cb0ef41Sopenharmony_ci};
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ciGdbServer::GdbServer() : has_module_list_changed_(false) {
1091cb0ef41Sopenharmony_ci  task_runner_ = std::make_unique<TaskRunner>();
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_citemplate <typename Functor>
1131cb0ef41Sopenharmony_ciauto GdbServer::RunSyncTask(Functor&& callback) const {
1141cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
1151cb0ef41Sopenharmony_ci  v8::base::Semaphore ready_semaphore(0);
1161cb0ef41Sopenharmony_ci  task_runner_->Append(&ready_semaphore, callback);
1171cb0ef41Sopenharmony_ci  ready_semaphore.Wait();
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci// static
1211cb0ef41Sopenharmony_cistd::unique_ptr<GdbServer> GdbServer::Create() {
1221cb0ef41Sopenharmony_ci  DCHECK(FLAG_wasm_gdb_remote);
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  std::unique_ptr<GdbServer> gdb_server(new GdbServer());
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  // Spawns the GDB-stub thread where all the communication with the debugger
1271cb0ef41Sopenharmony_ci  // happens.
1281cb0ef41Sopenharmony_ci  gdb_server->thread_ = std::make_unique<GdbServerThread>(gdb_server.get());
1291cb0ef41Sopenharmony_ci  if (!gdb_server->thread_->StartAndInitialize()) {
1301cb0ef41Sopenharmony_ci    TRACE_GDB_REMOTE(
1311cb0ef41Sopenharmony_ci        "Cannot initialize thread, GDB-remote debugging will be disabled.\n");
1321cb0ef41Sopenharmony_ci    return nullptr;
1331cb0ef41Sopenharmony_ci  }
1341cb0ef41Sopenharmony_ci  return gdb_server;
1351cb0ef41Sopenharmony_ci}
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ciGdbServer::~GdbServer() {
1381cb0ef41Sopenharmony_ci  // All Isolates have been deregistered.
1391cb0ef41Sopenharmony_ci  DCHECK(isolate_delegates_.empty());
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci  if (thread_) {
1421cb0ef41Sopenharmony_ci    // Waits for the GDB-stub thread to terminate.
1431cb0ef41Sopenharmony_ci    thread_->Stop();
1441cb0ef41Sopenharmony_ci    thread_->Join();
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_civoid GdbServer::RunMessageLoopOnPause() { task_runner_->Run(); }
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_civoid GdbServer::QuitMessageLoopOnPause() { task_runner_->Terminate(); }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_cistd::vector<GdbServer::WasmModuleInfo> GdbServer::GetLoadedModules(
1531cb0ef41Sopenharmony_ci    bool clear_module_list_changed_flag) {
1541cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
1551cb0ef41Sopenharmony_ci  std::vector<GdbServer::WasmModuleInfo> modules;
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  RunSyncTask([this, &modules, clear_module_list_changed_flag]() {
1581cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
1591cb0ef41Sopenharmony_ci    for (const auto& pair : scripts_) {
1601cb0ef41Sopenharmony_ci      uint32_t module_id = pair.first;
1611cb0ef41Sopenharmony_ci      const WasmModuleDebug& module_debug = pair.second;
1621cb0ef41Sopenharmony_ci      modules.push_back({module_id, module_debug.GetModuleName()});
1631cb0ef41Sopenharmony_ci    }
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ci    if (clear_module_list_changed_flag) has_module_list_changed_ = false;
1661cb0ef41Sopenharmony_ci  });
1671cb0ef41Sopenharmony_ci  return modules;
1681cb0ef41Sopenharmony_ci}
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_cibool GdbServer::GetModuleDebugHandler(uint32_t module_id,
1711cb0ef41Sopenharmony_ci                                      WasmModuleDebug** wasm_module_debug) {
1721cb0ef41Sopenharmony_ci  // Always executed in the isolate thread.
1731cb0ef41Sopenharmony_ci  ScriptsMap::iterator scriptIterator = scripts_.find(module_id);
1741cb0ef41Sopenharmony_ci  if (scriptIterator != scripts_.end()) {
1751cb0ef41Sopenharmony_ci    *wasm_module_debug = &scriptIterator->second;
1761cb0ef41Sopenharmony_ci    return true;
1771cb0ef41Sopenharmony_ci  }
1781cb0ef41Sopenharmony_ci  wasm_module_debug = nullptr;
1791cb0ef41Sopenharmony_ci  return false;
1801cb0ef41Sopenharmony_ci}
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_cibool GdbServer::GetWasmGlobal(uint32_t frame_index, uint32_t index,
1831cb0ef41Sopenharmony_ci                              uint8_t* buffer, uint32_t buffer_size,
1841cb0ef41Sopenharmony_ci                              uint32_t* size) {
1851cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
1861cb0ef41Sopenharmony_ci  bool result = false;
1871cb0ef41Sopenharmony_ci  RunSyncTask([this, &result, frame_index, index, buffer, buffer_size, size]() {
1881cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
1891cb0ef41Sopenharmony_ci    result = WasmModuleDebug::GetWasmGlobal(GetTarget().GetCurrentIsolate(),
1901cb0ef41Sopenharmony_ci                                            frame_index, index, buffer,
1911cb0ef41Sopenharmony_ci                                            buffer_size, size);
1921cb0ef41Sopenharmony_ci  });
1931cb0ef41Sopenharmony_ci  return result;
1941cb0ef41Sopenharmony_ci}
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_cibool GdbServer::GetWasmLocal(uint32_t frame_index, uint32_t index,
1971cb0ef41Sopenharmony_ci                             uint8_t* buffer, uint32_t buffer_size,
1981cb0ef41Sopenharmony_ci                             uint32_t* size) {
1991cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2001cb0ef41Sopenharmony_ci  bool result = false;
2011cb0ef41Sopenharmony_ci  RunSyncTask([this, &result, frame_index, index, buffer, buffer_size, size]() {
2021cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2031cb0ef41Sopenharmony_ci    result = WasmModuleDebug::GetWasmLocal(GetTarget().GetCurrentIsolate(),
2041cb0ef41Sopenharmony_ci                                           frame_index, index, buffer,
2051cb0ef41Sopenharmony_ci                                           buffer_size, size);
2061cb0ef41Sopenharmony_ci  });
2071cb0ef41Sopenharmony_ci  return result;
2081cb0ef41Sopenharmony_ci}
2091cb0ef41Sopenharmony_ci
2101cb0ef41Sopenharmony_cibool GdbServer::GetWasmStackValue(uint32_t frame_index, uint32_t index,
2111cb0ef41Sopenharmony_ci                                  uint8_t* buffer, uint32_t buffer_size,
2121cb0ef41Sopenharmony_ci                                  uint32_t* size) {
2131cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2141cb0ef41Sopenharmony_ci  bool result = false;
2151cb0ef41Sopenharmony_ci  RunSyncTask([this, &result, frame_index, index, buffer, buffer_size, size]() {
2161cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2171cb0ef41Sopenharmony_ci    result = WasmModuleDebug::GetWasmStackValue(GetTarget().GetCurrentIsolate(),
2181cb0ef41Sopenharmony_ci                                                frame_index, index, buffer,
2191cb0ef41Sopenharmony_ci                                                buffer_size, size);
2201cb0ef41Sopenharmony_ci  });
2211cb0ef41Sopenharmony_ci  return result;
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_ciuint32_t GdbServer::GetWasmMemory(uint32_t module_id, uint32_t offset,
2251cb0ef41Sopenharmony_ci                                  uint8_t* buffer, uint32_t size) {
2261cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2271cb0ef41Sopenharmony_ci  uint32_t bytes_read = 0;
2281cb0ef41Sopenharmony_ci  RunSyncTask([this, &bytes_read, module_id, offset, buffer, size]() {
2291cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2301cb0ef41Sopenharmony_ci    WasmModuleDebug* module_debug = nullptr;
2311cb0ef41Sopenharmony_ci    if (GetModuleDebugHandler(module_id, &module_debug)) {
2321cb0ef41Sopenharmony_ci      bytes_read = module_debug->GetWasmMemory(GetTarget().GetCurrentIsolate(),
2331cb0ef41Sopenharmony_ci                                               offset, buffer, size);
2341cb0ef41Sopenharmony_ci    }
2351cb0ef41Sopenharmony_ci  });
2361cb0ef41Sopenharmony_ci  return bytes_read;
2371cb0ef41Sopenharmony_ci}
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ciuint32_t GdbServer::GetWasmData(uint32_t module_id, uint32_t offset,
2401cb0ef41Sopenharmony_ci                                uint8_t* buffer, uint32_t size) {
2411cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2421cb0ef41Sopenharmony_ci  uint32_t bytes_read = 0;
2431cb0ef41Sopenharmony_ci  RunSyncTask([this, &bytes_read, module_id, offset, buffer, size]() {
2441cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2451cb0ef41Sopenharmony_ci    WasmModuleDebug* module_debug = nullptr;
2461cb0ef41Sopenharmony_ci    if (GetModuleDebugHandler(module_id, &module_debug)) {
2471cb0ef41Sopenharmony_ci      bytes_read = module_debug->GetWasmData(GetTarget().GetCurrentIsolate(),
2481cb0ef41Sopenharmony_ci                                             offset, buffer, size);
2491cb0ef41Sopenharmony_ci    }
2501cb0ef41Sopenharmony_ci  });
2511cb0ef41Sopenharmony_ci  return bytes_read;
2521cb0ef41Sopenharmony_ci}
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ciuint32_t GdbServer::GetWasmModuleBytes(wasm_addr_t wasm_addr, uint8_t* buffer,
2551cb0ef41Sopenharmony_ci                                       uint32_t size) {
2561cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2571cb0ef41Sopenharmony_ci  uint32_t bytes_read = 0;
2581cb0ef41Sopenharmony_ci  RunSyncTask([this, &bytes_read, wasm_addr, buffer, size]() {
2591cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2601cb0ef41Sopenharmony_ci    WasmModuleDebug* module_debug;
2611cb0ef41Sopenharmony_ci    if (GetModuleDebugHandler(wasm_addr.ModuleId(), &module_debug)) {
2621cb0ef41Sopenharmony_ci      bytes_read = module_debug->GetWasmModuleBytes(wasm_addr, buffer, size);
2631cb0ef41Sopenharmony_ci    }
2641cb0ef41Sopenharmony_ci  });
2651cb0ef41Sopenharmony_ci  return bytes_read;
2661cb0ef41Sopenharmony_ci}
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_cibool GdbServer::AddBreakpoint(uint32_t wasm_module_id, uint32_t offset) {
2691cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2701cb0ef41Sopenharmony_ci  bool result = false;
2711cb0ef41Sopenharmony_ci  RunSyncTask([this, &result, wasm_module_id, offset]() {
2721cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2731cb0ef41Sopenharmony_ci    WasmModuleDebug* module_debug;
2741cb0ef41Sopenharmony_ci    if (GetModuleDebugHandler(wasm_module_id, &module_debug)) {
2751cb0ef41Sopenharmony_ci      int breakpoint_id = 0;
2761cb0ef41Sopenharmony_ci      if (module_debug->AddBreakpoint(offset, &breakpoint_id)) {
2771cb0ef41Sopenharmony_ci        breakpoints_[wasm_addr_t(wasm_module_id, offset)] = breakpoint_id;
2781cb0ef41Sopenharmony_ci        result = true;
2791cb0ef41Sopenharmony_ci      }
2801cb0ef41Sopenharmony_ci    }
2811cb0ef41Sopenharmony_ci  });
2821cb0ef41Sopenharmony_ci  return result;
2831cb0ef41Sopenharmony_ci}
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_cibool GdbServer::RemoveBreakpoint(uint32_t wasm_module_id, uint32_t offset) {
2861cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
2871cb0ef41Sopenharmony_ci  bool result = false;
2881cb0ef41Sopenharmony_ci  RunSyncTask([this, &result, wasm_module_id, offset]() {
2891cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
2901cb0ef41Sopenharmony_ci    BreakpointsMap::iterator it =
2911cb0ef41Sopenharmony_ci        breakpoints_.find(wasm_addr_t(wasm_module_id, offset));
2921cb0ef41Sopenharmony_ci    if (it != breakpoints_.end()) {
2931cb0ef41Sopenharmony_ci      int breakpoint_id = it->second;
2941cb0ef41Sopenharmony_ci      breakpoints_.erase(it);
2951cb0ef41Sopenharmony_ci
2961cb0ef41Sopenharmony_ci      WasmModuleDebug* module_debug;
2971cb0ef41Sopenharmony_ci      if (GetModuleDebugHandler(wasm_module_id, &module_debug)) {
2981cb0ef41Sopenharmony_ci        module_debug->RemoveBreakpoint(offset, breakpoint_id);
2991cb0ef41Sopenharmony_ci        result = true;
3001cb0ef41Sopenharmony_ci      }
3011cb0ef41Sopenharmony_ci    }
3021cb0ef41Sopenharmony_ci  });
3031cb0ef41Sopenharmony_ci  return result;
3041cb0ef41Sopenharmony_ci}
3051cb0ef41Sopenharmony_ci
3061cb0ef41Sopenharmony_cistd::vector<wasm_addr_t> GdbServer::GetWasmCallStack() const {
3071cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
3081cb0ef41Sopenharmony_ci  std::vector<wasm_addr_t> result;
3091cb0ef41Sopenharmony_ci  RunSyncTask([this, &result]() {
3101cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
3111cb0ef41Sopenharmony_ci    result = GetTarget().GetCallStack();
3121cb0ef41Sopenharmony_ci  });
3131cb0ef41Sopenharmony_ci  return result;
3141cb0ef41Sopenharmony_ci}
3151cb0ef41Sopenharmony_ci
3161cb0ef41Sopenharmony_civoid GdbServer::AddIsolate(Isolate* isolate) {
3171cb0ef41Sopenharmony_ci  // Executed in the isolate thread.
3181cb0ef41Sopenharmony_ci  if (isolate_delegates_.find(isolate) == isolate_delegates_.end()) {
3191cb0ef41Sopenharmony_ci    isolate_delegates_[isolate] =
3201cb0ef41Sopenharmony_ci        std::make_unique<DebugDelegate>(isolate, this);
3211cb0ef41Sopenharmony_ci  }
3221cb0ef41Sopenharmony_ci}
3231cb0ef41Sopenharmony_ci
3241cb0ef41Sopenharmony_civoid GdbServer::RemoveIsolate(Isolate* isolate) {
3251cb0ef41Sopenharmony_ci  // Executed in the isolate thread.
3261cb0ef41Sopenharmony_ci  auto it = isolate_delegates_.find(isolate);
3271cb0ef41Sopenharmony_ci  if (it != isolate_delegates_.end()) {
3281cb0ef41Sopenharmony_ci    for (auto it = scripts_.begin(); it != scripts_.end();) {
3291cb0ef41Sopenharmony_ci      if (it->second.GetIsolate() == isolate) {
3301cb0ef41Sopenharmony_ci        it = scripts_.erase(it);
3311cb0ef41Sopenharmony_ci        has_module_list_changed_ = true;
3321cb0ef41Sopenharmony_ci      } else {
3331cb0ef41Sopenharmony_ci        ++it;
3341cb0ef41Sopenharmony_ci      }
3351cb0ef41Sopenharmony_ci    }
3361cb0ef41Sopenharmony_ci    isolate_delegates_.erase(it);
3371cb0ef41Sopenharmony_ci  }
3381cb0ef41Sopenharmony_ci}
3391cb0ef41Sopenharmony_ci
3401cb0ef41Sopenharmony_civoid GdbServer::Suspend() {
3411cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
3421cb0ef41Sopenharmony_ci  auto it = isolate_delegates_.begin();
3431cb0ef41Sopenharmony_ci  if (it != isolate_delegates_.end()) {
3441cb0ef41Sopenharmony_ci    Isolate* isolate = it->first;
3451cb0ef41Sopenharmony_ci    v8::Isolate* v8Isolate = (v8::Isolate*)isolate;
3461cb0ef41Sopenharmony_ci    v8Isolate->RequestInterrupt(
3471cb0ef41Sopenharmony_ci        // Executed in the isolate thread.
3481cb0ef41Sopenharmony_ci        [](v8::Isolate* isolate, void*) {
3491cb0ef41Sopenharmony_ci          if (v8::debug::AllFramesOnStackAreBlackboxed(isolate)) {
3501cb0ef41Sopenharmony_ci            v8::debug::SetBreakOnNextFunctionCall(isolate);
3511cb0ef41Sopenharmony_ci          } else {
3521cb0ef41Sopenharmony_ci            v8::debug::BreakRightNow(isolate);
3531cb0ef41Sopenharmony_ci          }
3541cb0ef41Sopenharmony_ci        },
3551cb0ef41Sopenharmony_ci        this);
3561cb0ef41Sopenharmony_ci  }
3571cb0ef41Sopenharmony_ci}
3581cb0ef41Sopenharmony_ci
3591cb0ef41Sopenharmony_civoid GdbServer::PrepareStep() {
3601cb0ef41Sopenharmony_ci  // Executed in the GDBServerThread.
3611cb0ef41Sopenharmony_ci  wasm_addr_t pc = GetTarget().GetCurrentPc();
3621cb0ef41Sopenharmony_ci  RunSyncTask([this, pc]() {
3631cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
3641cb0ef41Sopenharmony_ci    WasmModuleDebug* module_debug;
3651cb0ef41Sopenharmony_ci    if (GetModuleDebugHandler(pc.ModuleId(), &module_debug)) {
3661cb0ef41Sopenharmony_ci      module_debug->PrepareStep();
3671cb0ef41Sopenharmony_ci    }
3681cb0ef41Sopenharmony_ci  });
3691cb0ef41Sopenharmony_ci}
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_civoid GdbServer::AddWasmModule(uint32_t module_id,
3721cb0ef41Sopenharmony_ci                              Local<debug::WasmScript> wasm_script) {
3731cb0ef41Sopenharmony_ci  // Executed in the isolate thread.
3741cb0ef41Sopenharmony_ci  DCHECK_EQ(Script::TYPE_WASM, Utils::OpenHandle(*wasm_script)->type());
3751cb0ef41Sopenharmony_ci  v8::Isolate* isolate = wasm_script->GetIsolate();
3761cb0ef41Sopenharmony_ci  scripts_.insert(
3771cb0ef41Sopenharmony_ci      std::make_pair(module_id, WasmModuleDebug(isolate, wasm_script)));
3781cb0ef41Sopenharmony_ci  has_module_list_changed_ = true;
3791cb0ef41Sopenharmony_ci
3801cb0ef41Sopenharmony_ci  if (FLAG_wasm_pause_waiting_for_debugger && scripts_.size() == 1) {
3811cb0ef41Sopenharmony_ci    TRACE_GDB_REMOTE("Paused, waiting for a debugger to attach...\n");
3821cb0ef41Sopenharmony_ci    Suspend();
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci}
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ciTarget& GdbServer::GetTarget() const { return thread_->GetTarget(); }
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci// static
3891cb0ef41Sopenharmony_cistd::atomic<uint32_t> GdbServer::DebugDelegate::id_s;
3901cb0ef41Sopenharmony_ci
3911cb0ef41Sopenharmony_ciGdbServer::DebugDelegate::DebugDelegate(Isolate* isolate, GdbServer* gdb_server)
3921cb0ef41Sopenharmony_ci    : isolate_(isolate), id_(id_s++), gdb_server_(gdb_server) {
3931cb0ef41Sopenharmony_ci  isolate_->SetCaptureStackTraceForUncaughtExceptions(
3941cb0ef41Sopenharmony_ci      true, kMaxWasmCallStack, v8::StackTrace::kOverview);
3951cb0ef41Sopenharmony_ci
3961cb0ef41Sopenharmony_ci  // Register the delegate
3971cb0ef41Sopenharmony_ci  isolate_->debug()->SetDebugDelegate(this);
3981cb0ef41Sopenharmony_ci  v8::debug::TierDownAllModulesPerIsolate((v8::Isolate*)isolate_);
3991cb0ef41Sopenharmony_ci  v8::debug::ChangeBreakOnException((v8::Isolate*)isolate_,
4001cb0ef41Sopenharmony_ci                                    v8::debug::BreakOnUncaughtException);
4011cb0ef41Sopenharmony_ci}
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ciGdbServer::DebugDelegate::~DebugDelegate() {
4041cb0ef41Sopenharmony_ci  // Deregister the delegate
4051cb0ef41Sopenharmony_ci  isolate_->debug()->SetDebugDelegate(nullptr);
4061cb0ef41Sopenharmony_ci}
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_civoid GdbServer::DebugDelegate::ScriptCompiled(Local<debug::Script> script,
4091cb0ef41Sopenharmony_ci                                              bool is_live_edited,
4101cb0ef41Sopenharmony_ci                                              bool has_compile_error) {
4111cb0ef41Sopenharmony_ci  // Executed in the isolate thread.
4121cb0ef41Sopenharmony_ci  if (script->IsWasm()) {
4131cb0ef41Sopenharmony_ci    DCHECK_EQ(reinterpret_cast<v8::Isolate*>(isolate_), script->GetIsolate());
4141cb0ef41Sopenharmony_ci    gdb_server_->AddWasmModule(GetModuleId(script->Id()),
4151cb0ef41Sopenharmony_ci                               script.As<debug::WasmScript>());
4161cb0ef41Sopenharmony_ci  }
4171cb0ef41Sopenharmony_ci}
4181cb0ef41Sopenharmony_ci
4191cb0ef41Sopenharmony_civoid GdbServer::DebugDelegate::BreakProgramRequested(
4201cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
4211cb0ef41Sopenharmony_ci    Local<v8::Context> paused_context,
4221cb0ef41Sopenharmony_ci    const std::vector<debug::BreakpointId>& inspector_break_points_hit,
4231cb0ef41Sopenharmony_ci    v8::debug::BreakReasons break_reasons) {
4241cb0ef41Sopenharmony_ci  gdb_server_->GetTarget().OnProgramBreak(
4251cb0ef41Sopenharmony_ci      isolate_, WasmModuleDebug::GetCallStack(id_, isolate_));
4261cb0ef41Sopenharmony_ci  gdb_server_->RunMessageLoopOnPause();
4271cb0ef41Sopenharmony_ci}
4281cb0ef41Sopenharmony_ci
4291cb0ef41Sopenharmony_civoid GdbServer::DebugDelegate::ExceptionThrown(
4301cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
4311cb0ef41Sopenharmony_ci    Local<v8::Context> paused_context, Local<Value> exception,
4321cb0ef41Sopenharmony_ci    Local<Value> promise, bool is_uncaught,
4331cb0ef41Sopenharmony_ci    debug::ExceptionType exception_type) {
4341cb0ef41Sopenharmony_ci  if (exception_type == v8::debug::kException && is_uncaught) {
4351cb0ef41Sopenharmony_ci    gdb_server_->GetTarget().OnException(
4361cb0ef41Sopenharmony_ci        isolate_, WasmModuleDebug::GetCallStack(id_, isolate_));
4371cb0ef41Sopenharmony_ci    gdb_server_->RunMessageLoopOnPause();
4381cb0ef41Sopenharmony_ci  }
4391cb0ef41Sopenharmony_ci}
4401cb0ef41Sopenharmony_ci
4411cb0ef41Sopenharmony_cibool GdbServer::DebugDelegate::IsFunctionBlackboxed(
4421cb0ef41Sopenharmony_ci    // Executed in the isolate thread.
4431cb0ef41Sopenharmony_ci    Local<debug::Script> script, const debug::Location& start,
4441cb0ef41Sopenharmony_ci    const debug::Location& end) {
4451cb0ef41Sopenharmony_ci  return false;
4461cb0ef41Sopenharmony_ci}
4471cb0ef41Sopenharmony_ci
4481cb0ef41Sopenharmony_ci}  // namespace gdb_server
4491cb0ef41Sopenharmony_ci}  // namespace wasm
4501cb0ef41Sopenharmony_ci}  // namespace internal
4511cb0ef41Sopenharmony_ci}  // namespace v8
452