Coverage Report

Created: 2023-09-21 18:56

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/tools/lldb-vscode/VSCode.h
Line
Count
Source (jump to first uncovered line)
1
//===-- VSCode.h ------------------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLDB_TOOLS_LLDB_VSCODE_VSCODE_H
10
#define LLDB_TOOLS_LLDB_VSCODE_VSCODE_H
11
12
#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
13
14
#include <atomic>
15
#include <condition_variable>
16
#include <cstdio>
17
#include <future>
18
#include <iosfwd>
19
#include <map>
20
#include <optional>
21
#include <set>
22
#include <thread>
23
24
#include "llvm/ADT/DenseMap.h"
25
#include "llvm/ADT/DenseSet.h"
26
#include "llvm/ADT/StringMap.h"
27
#include "llvm/ADT/StringRef.h"
28
#include "llvm/Support/JSON.h"
29
#include "llvm/Support/raw_ostream.h"
30
31
#include "lldb/API/SBAttachInfo.h"
32
#include "lldb/API/SBBreakpoint.h"
33
#include "lldb/API/SBBreakpointLocation.h"
34
#include "lldb/API/SBCommandInterpreter.h"
35
#include "lldb/API/SBCommandReturnObject.h"
36
#include "lldb/API/SBCommunication.h"
37
#include "lldb/API/SBDebugger.h"
38
#include "lldb/API/SBEvent.h"
39
#include "lldb/API/SBHostOS.h"
40
#include "lldb/API/SBInstruction.h"
41
#include "lldb/API/SBInstructionList.h"
42
#include "lldb/API/SBLanguageRuntime.h"
43
#include "lldb/API/SBLaunchInfo.h"
44
#include "lldb/API/SBLineEntry.h"
45
#include "lldb/API/SBListener.h"
46
#include "lldb/API/SBProcess.h"
47
#include "lldb/API/SBStream.h"
48
#include "lldb/API/SBStringList.h"
49
#include "lldb/API/SBTarget.h"
50
#include "lldb/API/SBThread.h"
51
52
#include "ExceptionBreakpoint.h"
53
#include "FunctionBreakpoint.h"
54
#include "IOStream.h"
55
#include "ProgressEvent.h"
56
#include "RunInTerminal.h"
57
#include "SourceBreakpoint.h"
58
59
0
#define VARREF_LOCALS (int64_t)1
60
0
#define VARREF_GLOBALS (int64_t)2
61
0
#define VARREF_REGS (int64_t)3
62
#define VARREF_FIRST_VAR_IDX (int64_t)4
63
1
#define NO_TYPENAME "<no-type>"
64
65
namespace lldb_vscode {
66
67
typedef llvm::DenseMap<uint32_t, SourceBreakpoint> SourceBreakpointMap;
68
typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap;
69
enum class OutputType { Console, Stdout, Stderr, Telemetry };
70
71
enum VSCodeBroadcasterBits {
72
  eBroadcastBitStopEventThread = 1u << 0,
73
  eBroadcastBitStopProgressThread = 1u << 1
74
};
75
76
typedef void (*RequestCallback)(const llvm::json::Object &command);
77
typedef void (*ResponseCallback)(llvm::Expected<llvm::json::Value> value);
78
79
enum class PacketStatus {
80
  Success = 0,
81
  EndOfFile,
82
  JSONMalformed,
83
  JSONNotObject
84
};
85
86
enum class ReplMode { Variable = 0, Command, Auto };
87
88
/// The detected context of an expression based off the current repl mode.
89
enum class ExpressionContext {
90
  Variable = 0,
91
  Command,
92
};
93
94
struct Variables {
95
  /// Variable_reference start index of permanent expandable variable.
96
  static constexpr int64_t PermanentVariableStartIndex = (1ll << 32);
97
98
  lldb::SBValueList locals;
99
  lldb::SBValueList globals;
100
  lldb::SBValueList registers;
101
102
  int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX};
103
  int64_t next_permanent_var_ref{PermanentVariableStartIndex};
104
105
  /// Expandable variables that are alive in this stop state.
106
  /// Will be cleared when debuggee resumes.
107
  llvm::DenseMap<int64_t, lldb::SBValue> expandable_variables;
108
  /// Expandable variables that persist across entire debug session.
109
  /// These are the variables evaluated from debug console REPL.
110
  llvm::DenseMap<int64_t, lldb::SBValue> expandable_permanent_variables;
111
112
  /// Check if \p var_ref points to a variable that should persist for the
113
  /// entire duration of the debug session, e.g. repl expandable variables
114
  static bool IsPermanentVariableReference(int64_t var_ref);
115
116
  /// \return a new variableReference.
117
  /// Specify is_permanent as true for variable that should persist entire
118
  /// debug session.
119
  int64_t GetNewVariableReference(bool is_permanent);
120
121
  /// \return the expandable variable corresponding with variableReference
122
  /// value of \p value.
123
  /// If \p var_ref is invalid an empty SBValue is returned.
124
  lldb::SBValue GetVariable(int64_t var_ref) const;
125
126
  /// Insert a new \p variable.
127
  /// \return variableReference assigned to this expandable variable.
128
  int64_t InsertExpandableVariable(lldb::SBValue variable, bool is_permanent);
129
130
  /// Clear all scope variables and non-permanent expandable variables.
131
  void Clear();
132
};
133
134
struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface {
135
  bool DoExecute(lldb::SBDebugger debugger, char **command,
136
                 lldb::SBCommandReturnObject &result) override;
137
};
138
139
struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface {
140
  bool DoExecute(lldb::SBDebugger debugger, char **command,
141
                 lldb::SBCommandReturnObject &result) override;
142
};
143
144
struct VSCode {
145
  std::string debug_adaptor_path;
146
  InputStream input;
147
  OutputStream output;
148
  lldb::SBDebugger debugger;
149
  lldb::SBTarget target;
150
  Variables variables;
151
  lldb::SBBroadcaster broadcaster;
152
  std::thread event_thread;
153
  std::thread progress_event_thread;
154
  std::unique_ptr<std::ofstream> log;
155
  llvm::StringMap<SourceBreakpointMap> source_breakpoints;
156
  FunctionBreakpointMap function_breakpoints;
157
  std::vector<ExceptionBreakpoint> exception_breakpoints;
158
  std::vector<std::string> init_commands;
159
  std::vector<std::string> pre_run_commands;
160
  std::vector<std::string> exit_commands;
161
  std::vector<std::string> stop_commands;
162
  std::vector<std::string> terminate_commands;
163
  // A copy of the last LaunchRequest or AttachRequest so we can reuse its
164
  // arguments if we get a RestartRequest.
165
  std::optional<llvm::json::Object> last_launch_or_attach_request;
166
  lldb::tid_t focus_tid;
167
  std::atomic<bool> sent_terminated_event;
168
  bool stop_at_entry;
169
  bool is_attach;
170
  bool enable_auto_variable_summaries;
171
  bool enable_synthetic_child_debugging;
172
  // The process event thread normally responds to process exited events by
173
  // shutting down the entire adapter. When we're restarting, we keep the id of
174
  // the old process here so we can detect this case and keep running.
175
  lldb::pid_t restarting_process_id;
176
  bool configuration_done_sent;
177
  std::map<std::string, RequestCallback> request_handlers;
178
  bool waiting_for_run_in_terminal;
179
  ProgressEventReporter progress_event_reporter;
180
  // Keep track of the last stop thread index IDs as threads won't go away
181
  // unless we send a "thread" event to indicate the thread exited.
182
  llvm::DenseSet<lldb::tid_t> thread_ids;
183
  uint32_t reverse_request_seq;
184
  std::mutex call_mutex;
185
  std::map<int /* request_seq */, ResponseCallback /* reply handler */>
186
      inflight_reverse_requests;
187
  StartDebuggingRequestHandler start_debugging_request_handler;
188
  ReplModeRequestHandler repl_mode_request_handler;
189
  ReplMode repl_mode;
190
  bool auto_repl_mode_collision_warning;
191
192
  VSCode();
193
  ~VSCode();
194
  VSCode(const VSCode &rhs) = delete;
195
  void operator=(const VSCode &rhs) = delete;
196
  ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter);
197
  ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id);
198
199
  // Serialize the JSON value into a string and send the JSON packet to
200
  // the "out" stream.
201
  void SendJSON(const llvm::json::Value &json);
202
203
  std::string ReadJSON();
204
205
  void SendOutput(OutputType o, const llvm::StringRef output);
206
207
  void SendProgressEvent(uint64_t progress_id, const char *message,
208
                         uint64_t completed, uint64_t total);
209
210
  void __attribute__((format(printf, 3, 4)))
211
  SendFormattedOutput(OutputType o, const char *format, ...);
212
213
  static int64_t GetNextSourceReference();
214
215
  ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread);
216
217
  lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments);
218
219
  lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
220
221
  llvm::json::Value CreateTopLevelScopes();
222
223
  ExpressionContext DetectExpressionContext(lldb::SBFrame &frame,
224
                                            std::string &text);
225
226
  void RunLLDBCommands(llvm::StringRef prefix,
227
                       const std::vector<std::string> &commands);
228
229
  void RunInitCommands();
230
  void RunPreRunCommands();
231
  void RunStopCommands();
232
  void RunExitCommands();
233
  void RunTerminateCommands();
234
235
  /// Create a new SBTarget object from the given request arguments.
236
  /// \param[in] arguments
237
  ///     Launch configuration arguments.
238
  ///
239
  /// \param[out] error
240
  ///     An SBError object that will contain an error description if
241
  ///     function failed to create the target.
242
  ///
243
  /// \return
244
  ///     An SBTarget object.
245
  lldb::SBTarget CreateTargetFromArguments(const llvm::json::Object &arguments,
246
                                           lldb::SBError &error);
247
248
  /// Set given target object as a current target for lldb-vscode and start
249
  /// listeing for its breakpoint events.
250
  void SetTarget(const lldb::SBTarget target);
251
252
  const std::map<std::string, RequestCallback> &GetRequestHandlers();
253
254
  PacketStatus GetNextObject(llvm::json::Object &object);
255
  bool HandleObject(const llvm::json::Object &object);
256
257
  llvm::Error Loop();
258
259
  /// Send a Debug Adapter Protocol reverse request to the IDE.
260
  ///
261
  /// \param[in] command
262
  ///   The reverse request command.
263
  ///
264
  /// \param[in] arguments
265
  ///   The reverse request arguements.
266
  ///
267
  /// \param[in] callback
268
  ///   A callback to execute when the response arrives.
269
  void SendReverseRequest(llvm::StringRef command, llvm::json::Value arguments,
270
                          ResponseCallback callback);
271
272
  /// Registers a callback handler for a Debug Adapter Protocol request
273
  ///
274
  /// \param[in] request
275
  ///     The name of the request following the Debug Adapter Protocol
276
  ///     specification.
277
  ///
278
  /// \param[in] callback
279
  ///     The callback to execute when the given request is triggered by the
280
  ///     IDE.
281
  void RegisterRequestCallback(std::string request, RequestCallback callback);
282
283
  /// Debuggee will continue from stopped state.
284
1
  void WillContinue() { variables.Clear(); }
285
286
  /// Poll the process to wait for it to reach the eStateStopped state.
287
  ///
288
  /// Wait for the process hit a stopped state. When running a launch with
289
  /// "launchCommands", or attach with  "attachCommands", the calls might take
290
  /// some time to stop at the entry point since the command is asynchronous. We
291
  /// need to sync up with the process and make sure it is stopped before we
292
  /// proceed to do anything else as we will soon be asked to set breakpoints
293
  /// and other things that require the process to be stopped. We must use
294
  /// polling because "attachCommands" or "launchCommands" may or may not send
295
  /// process state change events depending on if the user modifies the async
296
  /// setting in the debugger. Since both "attachCommands" and "launchCommands"
297
  /// could end up using any combination of LLDB commands, we must ensure we can
298
  /// also catch when the process stops, so we must poll the process to make
299
  /// sure we handle all cases.
300
  ///
301
  /// \param[in] seconds
302
  ///   The number of seconds to poll the process to wait until it is stopped.
303
  ///
304
  /// \return Error if waiting for the process fails, no error if succeeds.
305
  lldb::SBError WaitForProcessToStop(uint32_t seconds);
306
307
private:
308
  // Send the JSON in "json_str" to the "out" stream. Correctly send the
309
  // "Content-Length:" field followed by the length, followed by the raw
310
  // JSON bytes.
311
  void SendJSON(const std::string &json_str);
312
};
313
314
extern VSCode g_vsc;
315
316
} // namespace lldb_vscode
317
318
#endif