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#ifndef V8_DEBUG_WASM_GDB_SERVER_GDB_SERVER_H_ 61cb0ef41Sopenharmony_ci#define V8_DEBUG_WASM_GDB_SERVER_GDB_SERVER_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include <map> 91cb0ef41Sopenharmony_ci#include <memory> 101cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/gdb-server-thread.h" 111cb0ef41Sopenharmony_ci#include "src/debug/wasm/gdb-server/wasm-module-debug.h" 121cb0ef41Sopenharmony_ci 131cb0ef41Sopenharmony_cinamespace v8 { 141cb0ef41Sopenharmony_cinamespace internal { 151cb0ef41Sopenharmony_cinamespace wasm { 161cb0ef41Sopenharmony_cinamespace gdb_server { 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ciclass TaskRunner; 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci// class GdbServer acts as a manager for the GDB-remote stub. It is instantiated 211cb0ef41Sopenharmony_ci// as soon as the first Wasm module is loaded in the Wasm engine and spawns a 221cb0ef41Sopenharmony_ci// separate thread to accept connections and exchange messages with a debugger. 231cb0ef41Sopenharmony_ci// It will contain the logic to serve debugger queries and access the state of 241cb0ef41Sopenharmony_ci// the Wasm engine. 251cb0ef41Sopenharmony_ciclass GdbServer { 261cb0ef41Sopenharmony_ci public: 271cb0ef41Sopenharmony_ci GdbServer(const GdbServer&) = delete; 281cb0ef41Sopenharmony_ci GdbServer& operator=(const GdbServer&) = delete; 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci // Factory method: creates and returns a GdbServer. Spawns a "GDB-remote" 311cb0ef41Sopenharmony_ci // thread that will be used to communicate with the debugger. 321cb0ef41Sopenharmony_ci // May return null on failure. 331cb0ef41Sopenharmony_ci // This should be called once, the first time a Wasm module is loaded in the 341cb0ef41Sopenharmony_ci // Wasm engine. 351cb0ef41Sopenharmony_ci static std::unique_ptr<GdbServer> Create(); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci // Stops the "GDB-remote" thread and waits for it to complete. This should be 381cb0ef41Sopenharmony_ci // called once, when the Wasm engine shuts down. 391cb0ef41Sopenharmony_ci ~GdbServer(); 401cb0ef41Sopenharmony_ci 411cb0ef41Sopenharmony_ci // Queries the set of the Wasm modules currently loaded. Each module is 421cb0ef41Sopenharmony_ci // identified by a unique integer module id. 431cb0ef41Sopenharmony_ci struct WasmModuleInfo { 441cb0ef41Sopenharmony_ci uint32_t module_id; 451cb0ef41Sopenharmony_ci std::string module_name; 461cb0ef41Sopenharmony_ci }; 471cb0ef41Sopenharmony_ci std::vector<WasmModuleInfo> GetLoadedModules( 481cb0ef41Sopenharmony_ci bool clear_module_list_changed_flag = false); 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci bool HasModuleListChanged() const { return has_module_list_changed_; } 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ci // Queries the value of the {index} global value in the Wasm module identified 531cb0ef41Sopenharmony_ci // by {frame_index}. 541cb0ef41Sopenharmony_ci // 551cb0ef41Sopenharmony_ci bool GetWasmGlobal(uint32_t frame_index, uint32_t index, uint8_t* buffer, 561cb0ef41Sopenharmony_ci uint32_t buffer_size, uint32_t* size); 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ci // Queries the value of the {index} local value in the {frame_index}th stack 591cb0ef41Sopenharmony_ci // frame in the Wasm module identified by {frame_index}. 601cb0ef41Sopenharmony_ci // 611cb0ef41Sopenharmony_ci bool GetWasmLocal(uint32_t frame_index, uint32_t index, uint8_t* buffer, 621cb0ef41Sopenharmony_ci uint32_t buffer_size, uint32_t* size); 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci // Queries the value of the {index} value in the operand stack. 651cb0ef41Sopenharmony_ci // 661cb0ef41Sopenharmony_ci bool GetWasmStackValue(uint32_t frame_index, uint32_t index, uint8_t* buffer, 671cb0ef41Sopenharmony_ci uint32_t buffer_size, uint32_t* size); 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci // Reads {size} bytes, starting from {offset}, from the Memory instance 701cb0ef41Sopenharmony_ci // associated to the Wasm module identified by {module_id}. 711cb0ef41Sopenharmony_ci // Returns the number of bytes copied to {buffer}, or 0 is case of error. 721cb0ef41Sopenharmony_ci // Note: only one Memory for Module is currently supported. 731cb0ef41Sopenharmony_ci // 741cb0ef41Sopenharmony_ci uint32_t GetWasmMemory(uint32_t module_id, uint32_t offset, uint8_t* buffer, 751cb0ef41Sopenharmony_ci uint32_t size); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci // Reads {size} bytes, starting from {offset}, from the first Data segment 781cb0ef41Sopenharmony_ci // in the Wasm module identified by {module_id}. 791cb0ef41Sopenharmony_ci // Returns the number of bytes copied to {buffer}, or 0 is case of error. 801cb0ef41Sopenharmony_ci // Note: only one Memory for Module is currently supported. 811cb0ef41Sopenharmony_ci // 821cb0ef41Sopenharmony_ci uint32_t GetWasmData(uint32_t module_id, uint32_t offset, uint8_t* buffer, 831cb0ef41Sopenharmony_ci uint32_t size); 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci // Reads {size} bytes, starting from the low dword of {address}, from the Code 861cb0ef41Sopenharmony_ci // space of th Wasm module identified by high dword of {address}. 871cb0ef41Sopenharmony_ci // Returns the number of bytes copied to {buffer}, or 0 is case of error. 881cb0ef41Sopenharmony_ci uint32_t GetWasmModuleBytes(wasm_addr_t address, uint8_t* buffer, 891cb0ef41Sopenharmony_ci uint32_t size); 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci // Inserts a breakpoint at the offset {offset} of the Wasm module identified 921cb0ef41Sopenharmony_ci // by {wasm_module_id}. 931cb0ef41Sopenharmony_ci // Returns true if the breakpoint was successfully added. 941cb0ef41Sopenharmony_ci bool AddBreakpoint(uint32_t wasm_module_id, uint32_t offset); 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ci // Removes a breakpoint at the offset {offset} of the Wasm module identified 971cb0ef41Sopenharmony_ci // by {wasm_module_id}. 981cb0ef41Sopenharmony_ci // Returns true if the breakpoint was successfully removed. 991cb0ef41Sopenharmony_ci bool RemoveBreakpoint(uint32_t wasm_module_id, uint32_t offset); 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci // Returns the current call stack as a vector of program counters. 1021cb0ef41Sopenharmony_ci std::vector<wasm_addr_t> GetWasmCallStack() const; 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_ci // Manage the set of Isolates for this GdbServer. 1051cb0ef41Sopenharmony_ci void AddIsolate(Isolate* isolate); 1061cb0ef41Sopenharmony_ci void RemoveIsolate(Isolate* isolate); 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci // Requests that the thread suspend execution at the next Wasm instruction. 1091cb0ef41Sopenharmony_ci void Suspend(); 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci // Handle stepping in wasm functions via the wasm interpreter. 1121cb0ef41Sopenharmony_ci void PrepareStep(); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci // Called when the target debuggee can resume execution (for example after 1151cb0ef41Sopenharmony_ci // having been suspended on a breakpoint). Terminates the task runner leaving 1161cb0ef41Sopenharmony_ci // all pending tasks in the queue. 1171cb0ef41Sopenharmony_ci void QuitMessageLoopOnPause(); 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci private: 1201cb0ef41Sopenharmony_ci GdbServer(); 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci // When the target debuggee is suspended for a breakpoint or exception, blocks 1231cb0ef41Sopenharmony_ci // the main (isolate) thread and enters in a message loop. Here it waits on a 1241cb0ef41Sopenharmony_ci // queue of Task objects that are posted by the GDB-stub thread and that 1251cb0ef41Sopenharmony_ci // represent queries received from the debugger via the GDB-remote protocol. 1261cb0ef41Sopenharmony_ci void RunMessageLoopOnPause(); 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_ci // Post a task to run a callback in the isolate thread. 1291cb0ef41Sopenharmony_ci template <typename Callback> 1301cb0ef41Sopenharmony_ci auto RunSyncTask(Callback&& callback) const; 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci void AddWasmModule(uint32_t module_id, Local<debug::WasmScript> wasm_script); 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci // Given a Wasm module id, retrieves the corresponding debugging WasmScript 1351cb0ef41Sopenharmony_ci // object. 1361cb0ef41Sopenharmony_ci bool GetModuleDebugHandler(uint32_t module_id, 1371cb0ef41Sopenharmony_ci WasmModuleDebug** wasm_module_debug); 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci // Returns the debugging target. 1401cb0ef41Sopenharmony_ci Target& GetTarget() const; 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci // Class DebugDelegate implements the debug::DebugDelegate interface to 1431cb0ef41Sopenharmony_ci // receive notifications when debug events happen in a given isolate, like a 1441cb0ef41Sopenharmony_ci // script being loaded, a breakpoint being hit, an exception being thrown. 1451cb0ef41Sopenharmony_ci class DebugDelegate : public debug::DebugDelegate { 1461cb0ef41Sopenharmony_ci public: 1471cb0ef41Sopenharmony_ci DebugDelegate(Isolate* isolate, GdbServer* gdb_server); 1481cb0ef41Sopenharmony_ci ~DebugDelegate(); 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci // debug::DebugDelegate 1511cb0ef41Sopenharmony_ci void ScriptCompiled(Local<debug::Script> script, bool is_live_edited, 1521cb0ef41Sopenharmony_ci bool has_compile_error) override; 1531cb0ef41Sopenharmony_ci void BreakProgramRequested( 1541cb0ef41Sopenharmony_ci Local<v8::Context> paused_context, 1551cb0ef41Sopenharmony_ci const std::vector<debug::BreakpointId>& inspector_break_points_hit, 1561cb0ef41Sopenharmony_ci v8::debug::BreakReasons break_reasons) override; 1571cb0ef41Sopenharmony_ci void ExceptionThrown(Local<v8::Context> paused_context, 1581cb0ef41Sopenharmony_ci Local<Value> exception, Local<Value> promise, 1591cb0ef41Sopenharmony_ci bool is_uncaught, 1601cb0ef41Sopenharmony_ci debug::ExceptionType exception_type) override; 1611cb0ef41Sopenharmony_ci bool IsFunctionBlackboxed(Local<debug::Script> script, 1621cb0ef41Sopenharmony_ci const debug::Location& start, 1631cb0ef41Sopenharmony_ci const debug::Location& end) override; 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci private: 1661cb0ef41Sopenharmony_ci // Calculates module_id as: 1671cb0ef41Sopenharmony_ci // +--------------------+------------------- + 1681cb0ef41Sopenharmony_ci // | DebugDelegate::id_ | Script::Id() | 1691cb0ef41Sopenharmony_ci // +--------------------+------------------- + 1701cb0ef41Sopenharmony_ci // <----- 16 bit -----> <----- 16 bit -----> 1711cb0ef41Sopenharmony_ci uint32_t GetModuleId(uint32_t script_id) const { 1721cb0ef41Sopenharmony_ci DCHECK_LT(script_id, 0x10000); 1731cb0ef41Sopenharmony_ci DCHECK_LT(id_, 0x10000); 1741cb0ef41Sopenharmony_ci return id_ << 16 | script_id; 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci Isolate* isolate_; 1781cb0ef41Sopenharmony_ci uint32_t id_; 1791cb0ef41Sopenharmony_ci GdbServer* gdb_server_; 1801cb0ef41Sopenharmony_ci 1811cb0ef41Sopenharmony_ci static std::atomic<uint32_t> id_s; 1821cb0ef41Sopenharmony_ci }; 1831cb0ef41Sopenharmony_ci 1841cb0ef41Sopenharmony_ci // The GDB-stub thread where all the communication with the debugger happens. 1851cb0ef41Sopenharmony_ci std::unique_ptr<GdbServerThread> thread_; 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci // Used to transform the queries that arrive in the GDB-stub thread into 1881cb0ef41Sopenharmony_ci // tasks executed in the main (isolate) thread. 1891cb0ef41Sopenharmony_ci std::unique_ptr<TaskRunner> task_runner_; 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci std::atomic<bool> has_module_list_changed_; 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci ////////////////////////////////////////////////////////////////////////////// 1941cb0ef41Sopenharmony_ci // Always accessed in the isolate thread. 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci // Set of breakpoints currently defines in Wasm code. 1971cb0ef41Sopenharmony_ci typedef std::map<uint64_t, int> BreakpointsMap; 1981cb0ef41Sopenharmony_ci BreakpointsMap breakpoints_; 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_ci typedef std::map<uint32_t, WasmModuleDebug> ScriptsMap; 2011cb0ef41Sopenharmony_ci ScriptsMap scripts_; 2021cb0ef41Sopenharmony_ci 2031cb0ef41Sopenharmony_ci typedef std::map<Isolate*, std::unique_ptr<DebugDelegate>> 2041cb0ef41Sopenharmony_ci IsolateDebugDelegateMap; 2051cb0ef41Sopenharmony_ci IsolateDebugDelegateMap isolate_delegates_; 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_ci // End of fields always accessed in the isolate thread. 2081cb0ef41Sopenharmony_ci ////////////////////////////////////////////////////////////////////////////// 2091cb0ef41Sopenharmony_ci}; 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci} // namespace gdb_server 2121cb0ef41Sopenharmony_ci} // namespace wasm 2131cb0ef41Sopenharmony_ci} // namespace internal 2141cb0ef41Sopenharmony_ci} // namespace v8 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ci#endif // V8_DEBUG_WASM_GDB_SERVER_GDB_SERVER_H_ 217