1// Copyright 2020 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef V8_DEBUG_WASM_GDB_SERVER_GDB_SERVER_H_ 6#define V8_DEBUG_WASM_GDB_SERVER_GDB_SERVER_H_ 7 8#include <map> 9#include <memory> 10#include "src/debug/wasm/gdb-server/gdb-server-thread.h" 11#include "src/debug/wasm/gdb-server/wasm-module-debug.h" 12 13namespace v8 { 14namespace internal { 15namespace wasm { 16namespace gdb_server { 17 18class TaskRunner; 19 20// class GdbServer acts as a manager for the GDB-remote stub. It is instantiated 21// as soon as the first Wasm module is loaded in the Wasm engine and spawns a 22// separate thread to accept connections and exchange messages with a debugger. 23// It will contain the logic to serve debugger queries and access the state of 24// the Wasm engine. 25class GdbServer { 26 public: 27 GdbServer(const GdbServer&) = delete; 28 GdbServer& operator=(const GdbServer&) = delete; 29 30 // Factory method: creates and returns a GdbServer. Spawns a "GDB-remote" 31 // thread that will be used to communicate with the debugger. 32 // May return null on failure. 33 // This should be called once, the first time a Wasm module is loaded in the 34 // Wasm engine. 35 static std::unique_ptr<GdbServer> Create(); 36 37 // Stops the "GDB-remote" thread and waits for it to complete. This should be 38 // called once, when the Wasm engine shuts down. 39 ~GdbServer(); 40 41 // Queries the set of the Wasm modules currently loaded. Each module is 42 // identified by a unique integer module id. 43 struct WasmModuleInfo { 44 uint32_t module_id; 45 std::string module_name; 46 }; 47 std::vector<WasmModuleInfo> GetLoadedModules( 48 bool clear_module_list_changed_flag = false); 49 50 bool HasModuleListChanged() const { return has_module_list_changed_; } 51 52 // Queries the value of the {index} global value in the Wasm module identified 53 // by {frame_index}. 54 // 55 bool GetWasmGlobal(uint32_t frame_index, uint32_t index, uint8_t* buffer, 56 uint32_t buffer_size, uint32_t* size); 57 58 // Queries the value of the {index} local value in the {frame_index}th stack 59 // frame in the Wasm module identified by {frame_index}. 60 // 61 bool GetWasmLocal(uint32_t frame_index, uint32_t index, uint8_t* buffer, 62 uint32_t buffer_size, uint32_t* size); 63 64 // Queries the value of the {index} value in the operand stack. 65 // 66 bool GetWasmStackValue(uint32_t frame_index, uint32_t index, uint8_t* buffer, 67 uint32_t buffer_size, uint32_t* size); 68 69 // Reads {size} bytes, starting from {offset}, from the Memory instance 70 // associated to the Wasm module identified by {module_id}. 71 // Returns the number of bytes copied to {buffer}, or 0 is case of error. 72 // Note: only one Memory for Module is currently supported. 73 // 74 uint32_t GetWasmMemory(uint32_t module_id, uint32_t offset, uint8_t* buffer, 75 uint32_t size); 76 77 // Reads {size} bytes, starting from {offset}, from the first Data segment 78 // in the Wasm module identified by {module_id}. 79 // Returns the number of bytes copied to {buffer}, or 0 is case of error. 80 // Note: only one Memory for Module is currently supported. 81 // 82 uint32_t GetWasmData(uint32_t module_id, uint32_t offset, uint8_t* buffer, 83 uint32_t size); 84 85 // Reads {size} bytes, starting from the low dword of {address}, from the Code 86 // space of th Wasm module identified by high dword of {address}. 87 // Returns the number of bytes copied to {buffer}, or 0 is case of error. 88 uint32_t GetWasmModuleBytes(wasm_addr_t address, uint8_t* buffer, 89 uint32_t size); 90 91 // Inserts a breakpoint at the offset {offset} of the Wasm module identified 92 // by {wasm_module_id}. 93 // Returns true if the breakpoint was successfully added. 94 bool AddBreakpoint(uint32_t wasm_module_id, uint32_t offset); 95 96 // Removes a breakpoint at the offset {offset} of the Wasm module identified 97 // by {wasm_module_id}. 98 // Returns true if the breakpoint was successfully removed. 99 bool RemoveBreakpoint(uint32_t wasm_module_id, uint32_t offset); 100 101 // Returns the current call stack as a vector of program counters. 102 std::vector<wasm_addr_t> GetWasmCallStack() const; 103 104 // Manage the set of Isolates for this GdbServer. 105 void AddIsolate(Isolate* isolate); 106 void RemoveIsolate(Isolate* isolate); 107 108 // Requests that the thread suspend execution at the next Wasm instruction. 109 void Suspend(); 110 111 // Handle stepping in wasm functions via the wasm interpreter. 112 void PrepareStep(); 113 114 // Called when the target debuggee can resume execution (for example after 115 // having been suspended on a breakpoint). Terminates the task runner leaving 116 // all pending tasks in the queue. 117 void QuitMessageLoopOnPause(); 118 119 private: 120 GdbServer(); 121 122 // When the target debuggee is suspended for a breakpoint or exception, blocks 123 // the main (isolate) thread and enters in a message loop. Here it waits on a 124 // queue of Task objects that are posted by the GDB-stub thread and that 125 // represent queries received from the debugger via the GDB-remote protocol. 126 void RunMessageLoopOnPause(); 127 128 // Post a task to run a callback in the isolate thread. 129 template <typename Callback> 130 auto RunSyncTask(Callback&& callback) const; 131 132 void AddWasmModule(uint32_t module_id, Local<debug::WasmScript> wasm_script); 133 134 // Given a Wasm module id, retrieves the corresponding debugging WasmScript 135 // object. 136 bool GetModuleDebugHandler(uint32_t module_id, 137 WasmModuleDebug** wasm_module_debug); 138 139 // Returns the debugging target. 140 Target& GetTarget() const; 141 142 // Class DebugDelegate implements the debug::DebugDelegate interface to 143 // receive notifications when debug events happen in a given isolate, like a 144 // script being loaded, a breakpoint being hit, an exception being thrown. 145 class DebugDelegate : public debug::DebugDelegate { 146 public: 147 DebugDelegate(Isolate* isolate, GdbServer* gdb_server); 148 ~DebugDelegate(); 149 150 // debug::DebugDelegate 151 void ScriptCompiled(Local<debug::Script> script, bool is_live_edited, 152 bool has_compile_error) override; 153 void BreakProgramRequested( 154 Local<v8::Context> paused_context, 155 const std::vector<debug::BreakpointId>& inspector_break_points_hit, 156 v8::debug::BreakReasons break_reasons) override; 157 void ExceptionThrown(Local<v8::Context> paused_context, 158 Local<Value> exception, Local<Value> promise, 159 bool is_uncaught, 160 debug::ExceptionType exception_type) override; 161 bool IsFunctionBlackboxed(Local<debug::Script> script, 162 const debug::Location& start, 163 const debug::Location& end) override; 164 165 private: 166 // Calculates module_id as: 167 // +--------------------+------------------- + 168 // | DebugDelegate::id_ | Script::Id() | 169 // +--------------------+------------------- + 170 // <----- 16 bit -----> <----- 16 bit -----> 171 uint32_t GetModuleId(uint32_t script_id) const { 172 DCHECK_LT(script_id, 0x10000); 173 DCHECK_LT(id_, 0x10000); 174 return id_ << 16 | script_id; 175 } 176 177 Isolate* isolate_; 178 uint32_t id_; 179 GdbServer* gdb_server_; 180 181 static std::atomic<uint32_t> id_s; 182 }; 183 184 // The GDB-stub thread where all the communication with the debugger happens. 185 std::unique_ptr<GdbServerThread> thread_; 186 187 // Used to transform the queries that arrive in the GDB-stub thread into 188 // tasks executed in the main (isolate) thread. 189 std::unique_ptr<TaskRunner> task_runner_; 190 191 std::atomic<bool> has_module_list_changed_; 192 193 ////////////////////////////////////////////////////////////////////////////// 194 // Always accessed in the isolate thread. 195 196 // Set of breakpoints currently defines in Wasm code. 197 typedef std::map<uint64_t, int> BreakpointsMap; 198 BreakpointsMap breakpoints_; 199 200 typedef std::map<uint32_t, WasmModuleDebug> ScriptsMap; 201 ScriptsMap scripts_; 202 203 typedef std::map<Isolate*, std::unique_ptr<DebugDelegate>> 204 IsolateDebugDelegateMap; 205 IsolateDebugDelegateMap isolate_delegates_; 206 207 // End of fields always accessed in the isolate thread. 208 ////////////////////////////////////////////////////////////////////////////// 209}; 210 211} // namespace gdb_server 212} // namespace wasm 213} // namespace internal 214} // namespace v8 215 216#endif // V8_DEBUG_WASM_GDB_SERVER_GDB_SERVER_H_ 217