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_TARGET_H_
6#define V8_DEBUG_WASM_GDB_SERVER_TARGET_H_
7
8#include <atomic>
9#include <map>
10#include "src/base/macros.h"
11#include "src/debug/wasm/gdb-server/gdb-remote-util.h"
12
13namespace v8 {
14namespace internal {
15namespace wasm {
16namespace gdb_server {
17
18class GdbServer;
19class Packet;
20class Session;
21
22// Class Target represents a debugging target. It contains the logic to decode
23// incoming GDB-remote packets, execute them forwarding the debugger commands
24// and queries to the Wasm engine, and send back GDB-remote packets.
25class Target {
26 public:
27  // Contruct a Target object.
28  explicit Target(GdbServer* gdb_server);
29  Target(const Target&) = delete;
30  Target& operator=(const Target&) = delete;
31
32  // This function spin on a debugging session, until it closes.
33  void Run(Session* ses);
34
35  void Terminate();
36  bool IsTerminated() const { return status_ == Status::Terminated; }
37
38  // Notifies that the debuggee thread suspended at a breakpoint.
39  void OnProgramBreak(Isolate* isolate,
40                      const std::vector<wasm_addr_t>& call_frames);
41  // Notifies that the debuggee thread suspended because of an unhandled
42  // exception.
43  void OnException(Isolate* isolate,
44                   const std::vector<wasm_addr_t>& call_frames);
45
46  // Returns the state at the moment of the thread suspension.
47  const std::vector<wasm_addr_t> GetCallStack() const;
48  wasm_addr_t GetCurrentPc() const;
49  Isolate* GetCurrentIsolate() const { return current_isolate_; }
50
51 private:
52  void OnSuspended(Isolate* isolate, int signal,
53                   const std::vector<wasm_addr_t>& call_frames);
54
55  // Initializes a map used to make fast lookups when handling query packets
56  // that have a constant response.
57  void InitQueryPropertyMap();
58
59  // Blocks waiting for one of these two events to occur:
60  // - A network packet arrives from the debugger, or the debugger connection is
61  //   closed;
62  // - The debuggee suspends execution because of a trap or breakpoint.
63  void WaitForDebugEvent();
64  void ProcessDebugEvent();
65
66  // Processes GDB-remote packets that arrive from the debugger.
67  // This method should be called when the debuggee has suspended its execution.
68  void ProcessCommands();
69
70  // Requests that the thread suspends execution at the next Wasm instruction.
71  void Suspend();
72
73  enum class ErrorCode { None = 0, BadFormat = 1, BadArgs = 2, Failed = 3 };
74
75  enum class ProcessPacketResult {
76    Paused,    // The command was processed, debuggee still paused.
77    Continue,  // The debuggee should resume execution.
78    Detach,    // Request to detach from the debugger.
79    Kill       // Request to terminate the debuggee process.
80  };
81  // This function always succeedes, since all errors are reported as an error
82  // string "Exx" where xx is a two digit number.
83  // The return value indicates if the target can resume execution or it is
84  // still paused.
85  ProcessPacketResult ProcessPacket(Packet* pkt_in, Packet* pkt_out);
86
87  // Processes a general query packet
88  ErrorCode ProcessQueryPacket(const Packet* pkt_in, Packet* pkt_out);
89
90  // Formats a 'Stop-reply' packet, which is sent in response of a 'c'
91  // (continue), 's' (step) and '?' (query halt reason) commands.
92  void SetStopReply(Packet* pkt_out) const;
93
94  enum class Status { Running, WaitingForSuspension, Suspended, Terminated };
95
96  void SetStatus(Status status, int8_t signal = 0,
97                 std::vector<wasm_addr_t> call_frames_ = {},
98                 Isolate* isolate = nullptr);
99
100  GdbServer* gdb_server_;
101
102  std::atomic<Status> status_;
103
104  // Signal being processed.
105  std::atomic<int8_t> cur_signal_;
106
107  // Session object not owned by the Target.
108  Session* session_;
109
110  // Map used to make fast lookups when handling query packets.
111  typedef std::map<std::string, std::string> QueryPropertyMap;
112  QueryPropertyMap query_properties_;
113
114  bool debugger_initial_suspension_;
115
116  // Used to block waiting for suspension
117  v8::base::Semaphore semaphore_;
118
119  mutable v8::base::Mutex mutex_;
120  //////////////////////////////////////////////////////////////////////////////
121  // Protected by {mutex_}:
122
123  // Current isolate. This is not null only when the target is in a Suspended
124  // state and it is the isolate associated to the current call stack and used
125  // for all debugging activities.
126  Isolate* current_isolate_;
127
128  // Call stack when the execution is suspended.
129  std::vector<wasm_addr_t> call_frames_;
130
131  // End of fields protected by {mutex_}.
132  //////////////////////////////////////////////////////////////////////////////
133};
134
135}  // namespace gdb_server
136}  // namespace wasm
137}  // namespace internal
138}  // namespace v8
139
140#endif  // V8_DEBUG_WASM_GDB_SERVER_TARGET_H_
141