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