1//===-- DAP.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_DAP_DAP_H
10#define LLDB_TOOLS_LLDB_DAP_DAP_H
11
12#include "DAPForward.h"
13#include "ExceptionBreakpoint.h"
14#include "FunctionBreakpoint.h"
15#include "InstructionBreakpoint.h"
16#include "OutputRedirector.h"
17#include "ProgressEvent.h"
18#include "Protocol/ProtocolBase.h"
19#include "Protocol/ProtocolRequests.h"
20#include "Protocol/ProtocolTypes.h"
21#include "SourceBreakpoint.h"
22#include "Transport.h"
23#include "Variables.h"
24#include "lldb/API/SBBroadcaster.h"
25#include "lldb/API/SBCommandInterpreter.h"
26#include "lldb/API/SBDebugger.h"
27#include "lldb/API/SBError.h"
28#include "lldb/API/SBFile.h"
29#include "lldb/API/SBFormat.h"
30#include "lldb/API/SBFrame.h"
31#include "lldb/API/SBMutex.h"
32#include "lldb/API/SBTarget.h"
33#include "lldb/API/SBThread.h"
34#include "lldb/lldb-types.h"
35#include "llvm/ADT/DenseMap.h"
36#include "llvm/ADT/DenseSet.h"
37#include "llvm/ADT/FunctionExtras.h"
38#include "llvm/ADT/SmallSet.h"
39#include "llvm/ADT/StringMap.h"
40#include "llvm/ADT/StringRef.h"
41#include "llvm/ADT/StringSet.h"
42#include "llvm/Support/Error.h"
43#include "llvm/Support/JSON.h"
44#include "llvm/Support/Threading.h"
45#include <condition_variable>
46#include <cstdint>
47#include <deque>
48#include <memory>
49#include <mutex>
50#include <optional>
51#include <thread>
52#include <vector>
53
54#define NO_TYPENAME "<no-type>"
55
56namespace lldb_dap {
57
58typedef std::map<std::pair<uint32_t, uint32_t>, SourceBreakpoint>
59 SourceBreakpointMap;
60typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap;
61typedef llvm::DenseMap<lldb::addr_t, InstructionBreakpoint>
62 InstructionBreakpointMap;
63
64using AdapterFeature = protocol::AdapterFeature;
65using ClientFeature = protocol::ClientFeature;
66
67enum class OutputType { Console, Important, Stdout, Stderr, Telemetry };
68
69/// Buffer size for handling output events.
70constexpr uint64_t OutputBufferSize = (1u << 12);
71
72enum DAPBroadcasterBits {
73 eBroadcastBitStopEventThread = 1u << 0,
74 eBroadcastBitStopProgressThread = 1u << 1
75};
76
77enum class ReplMode { Variable = 0, Command, Auto };
78
79struct DAP {
80 /// Path to the lldb-dap binary itself.
81 static llvm::StringRef debug_adapter_path;
82
83 Log *log;
84 Transport &transport;
85 lldb::SBFile in;
86 OutputRedirector out;
87 OutputRedirector err;
88
89 /// Configuration specified by the launch or attach commands.
90 protocol::Configuration configuration;
91
92 /// The debugger instance for this DAP session.
93 lldb::SBDebugger debugger;
94
95 /// The target instance for this DAP session.
96 lldb::SBTarget target;
97
98 Variables variables;
99 lldb::SBBroadcaster broadcaster;
100 FunctionBreakpointMap function_breakpoints;
101 InstructionBreakpointMap instruction_breakpoints;
102 std::optional<std::vector<ExceptionBreakpoint>> exception_breakpoints;
103 llvm::once_flag init_exception_breakpoints_flag;
104
105 /// Map step in target id to list of function targets that user can choose.
106 llvm::DenseMap<lldb::addr_t, std::string> step_in_targets;
107
108 /// A copy of the last LaunchRequest so we can reuse its arguments if we get a
109 /// RestartRequest. Restarting an AttachRequest is not supported.
110 std::optional<protocol::LaunchRequestArguments> last_launch_request;
111
112 /// The focused thread for this DAP session.
113 lldb::tid_t focus_tid = LLDB_INVALID_THREAD_ID;
114
115 bool disconnecting = false;
116 llvm::once_flag terminated_event_flag;
117 bool stop_at_entry = false;
118 bool is_attach = false;
119
120 /// The process event thread normally responds to process exited events by
121 /// shutting down the entire adapter. When we're restarting, we keep the id of
122 /// the old process here so we can detect this case and keep running.
123 lldb::pid_t restarting_process_id = LLDB_INVALID_PROCESS_ID;
124
125 /// Whether we have received the ConfigurationDone request, indicating that
126 /// the client has finished initialization of the debug adapter.
127 bool configuration_done;
128
129 bool waiting_for_run_in_terminal = false;
130 ProgressEventReporter progress_event_reporter;
131
132 /// Keep track of the last stop thread index IDs as threads won't go away
133 /// unless we send a "thread" event to indicate the thread exited.
134 llvm::DenseSet<lldb::tid_t> thread_ids;
135
136 uint32_t reverse_request_seq = 0;
137 std::mutex call_mutex;
138 llvm::SmallDenseMap<int64_t, std::unique_ptr<ResponseHandler>>
139 inflight_reverse_requests;
140 ReplMode repl_mode;
141 lldb::SBFormat frame_format;
142 lldb::SBFormat thread_format;
143
144 /// This is used to allow request_evaluate to handle empty expressions
145 /// (ie the user pressed 'return' and expects the previous expression to
146 /// repeat). If the previous expression was a command, this string will be
147 /// empty; if the previous expression was a variable expression, this string
148 /// will contain that expression.
149 std::string last_nonempty_var_expression;
150
151 /// The set of features supported by the connected client.
152 llvm::DenseSet<ClientFeature> clientFeatures;
153
154 /// The initial thread list upon attaching.
155 std::vector<protocol::Thread> initial_thread_list;
156
157 /// Keep track of all the modules our client knows about: either through the
158 /// modules request or the module events.
159 /// @{
160 std::mutex modules_mutex;
161 llvm::StringSet<> modules;
162 /// @}
163
164 /// Number of lines of assembly code to show when no debug info is available.
165 static constexpr uint32_t k_number_of_assembly_lines_for_nodebug = 32;
166
167 /// Creates a new DAP sessions.
168 ///
169 /// \param[in] log
170 /// Log stream, if configured.
171 /// \param[in] default_repl_mode
172 /// Default repl mode behavior, as configured by the binary.
173 /// \param[in] pre_init_commands
174 /// LLDB commands to execute as soon as the debugger instance is
175 /// allocated.
176 /// \param[in] transport
177 /// Transport for this debug session.
178 DAP(Log *log, const ReplMode default_repl_mode,
179 std::vector<std::string> pre_init_commands, Transport &transport);
180
181 ~DAP();
182
183 /// DAP is not copyable.
184 /// @{
185 DAP(const DAP &rhs) = delete;
186 void operator=(const DAP &rhs) = delete;
187 /// @}
188
189 ExceptionBreakpoint *GetExceptionBreakpoint(llvm::StringRef filter);
190 ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id);
191
192 /// Redirect stdout and stderr fo the IDE's console output.
193 ///
194 /// Errors in this operation will be printed to the log file and the IDE's
195 /// console output as well.
196 llvm::Error ConfigureIO(std::FILE *overrideOut = nullptr,
197 std::FILE *overrideErr = nullptr);
198
199 /// Stop event handler threads.
200 void StopEventHandlers();
201
202 /// Configures the debug adapter for launching/attaching.
203 void SetConfiguration(const protocol::Configuration &confing, bool is_attach);
204
205 /// Configure source maps based on the current `DAPConfiguration`.
206 void ConfigureSourceMaps();
207
208 /// Serialize the JSON value into a string and send the JSON packet to the
209 /// "out" stream.
210 void SendJSON(const llvm::json::Value &json);
211 /// Send the given message to the client
212 void Send(const protocol::Message &message);
213
214 void SendOutput(OutputType o, const llvm::StringRef output);
215
216 void SendProgressEvent(uint64_t progress_id, const char *message,
217 uint64_t completed, uint64_t total);
218
219 void __attribute__((format(printf, 3, 4)))
220 SendFormattedOutput(OutputType o, const char *format, ...);
221
222 static int64_t GetNextSourceReference();
223
224 ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread);
225
226 lldb::SBThread GetLLDBThread(lldb::tid_t id);
227 lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments);
228
229 lldb::SBFrame GetLLDBFrame(uint64_t frame_id);
230 /// TODO: remove this function when we finish migrating to the
231 /// new protocol types.
232 lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
233
234 void PopulateExceptionBreakpoints();
235
236 /// Attempt to determine if an expression is a variable expression or
237 /// lldb command using a heuristic based on the first term of the
238 /// expression.
239 ///
240 /// \param[in] frame
241 /// The frame, used as context to detect local variable names
242 /// \param[inout] expression
243 /// The expression string. Might be modified by this function to
244 /// remove the leading escape character.
245 /// \param[in] partial_expression
246 /// Whether the provided `expression` is only a prefix of the
247 /// final expression. If `true`, this function might return
248 /// `ReplMode::Auto` to indicate that the expression could be
249 /// either an expression or a statement, depending on the rest of
250 /// the expression.
251 /// \return the expression mode
252 ReplMode DetectReplMode(lldb::SBFrame frame, std::string &expression,
253 bool partial_expression);
254
255 /// \return
256 /// \b false if a fatal error was found while executing these commands,
257 /// according to the rules of \a LLDBUtils::RunLLDBCommands.
258 bool RunLLDBCommands(llvm::StringRef prefix,
259 llvm::ArrayRef<std::string> commands);
260
261 llvm::Error RunAttachCommands(llvm::ArrayRef<std::string> attach_commands);
262 llvm::Error RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands);
263 llvm::Error RunPreInitCommands();
264 llvm::Error RunInitCommands();
265 llvm::Error RunPreRunCommands();
266 void RunPostRunCommands();
267 void RunStopCommands();
268 void RunExitCommands();
269 void RunTerminateCommands();
270
271 /// Create a new SBTarget object from the given request arguments.
272 ///
273 /// \param[out] error
274 /// An SBError object that will contain an error description if
275 /// function failed to create the target.
276 ///
277 /// \return
278 /// An SBTarget object.
279 lldb::SBTarget CreateTarget(lldb::SBError &error);
280
281 /// Set given target object as a current target for lldb-dap and start
282 /// listeing for its breakpoint events.
283 void SetTarget(const lldb::SBTarget target);
284
285 bool HandleObject(const protocol::Message &M);
286
287 /// Disconnect the DAP session.
288 llvm::Error Disconnect();
289
290 /// Disconnect the DAP session and optionally terminate the debuggee.
291 llvm::Error Disconnect(bool terminateDebuggee);
292
293 /// Send a "terminated" event to indicate the process is done being debugged.
294 void SendTerminatedEvent();
295
296 llvm::Error Loop();
297
298 /// Send a Debug Adapter Protocol reverse request to the IDE.
299 ///
300 /// \param[in] command
301 /// The reverse request command.
302 ///
303 /// \param[in] arguments
304 /// The reverse request arguments.
305 template <typename Handler>
306 void SendReverseRequest(llvm::StringRef command,
307 llvm::json::Value arguments) {
308 int64_t id;
309 {
310 std::lock_guard<std::mutex> locker(call_mutex);
311 id = ++reverse_request_seq;
312 inflight_reverse_requests[id] = std::make_unique<Handler>(command, id);
313 }
314
315 SendJSON(json: llvm::json::Object{
316 {.K: "type", .V: "request"},
317 {.K: "seq", .V: id},
318 {.K: "command", .V: command},
319 {.K: "arguments", .V: std::move(arguments)},
320 });
321 }
322
323 /// The set of capablities supported by this adapter.
324 protocol::Capabilities GetCapabilities();
325
326 /// Debuggee will continue from stopped state.
327 void WillContinue() { variables.Clear(); }
328
329 /// Poll the process to wait for it to reach the eStateStopped state.
330 ///
331 /// Wait for the process hit a stopped state. When running a launch with
332 /// "launchCommands", or attach with "attachCommands", the calls might take
333 /// some time to stop at the entry point since the command is asynchronous. We
334 /// need to sync up with the process and make sure it is stopped before we
335 /// proceed to do anything else as we will soon be asked to set breakpoints
336 /// and other things that require the process to be stopped. We must use
337 /// polling because "attachCommands" or "launchCommands" may or may not send
338 /// process state change events depending on if the user modifies the async
339 /// setting in the debugger. Since both "attachCommands" and "launchCommands"
340 /// could end up using any combination of LLDB commands, we must ensure we can
341 /// also catch when the process stops, so we must poll the process to make
342 /// sure we handle all cases.
343 ///
344 /// \param[in] seconds
345 /// The number of seconds to poll the process to wait until it is stopped.
346 ///
347 /// \return Error if waiting for the process fails, no error if succeeds.
348 lldb::SBError WaitForProcessToStop(std::chrono::seconds seconds);
349
350 void SetFrameFormat(llvm::StringRef format);
351
352 void SetThreadFormat(llvm::StringRef format);
353
354 InstructionBreakpoint *GetInstructionBreakpoint(const lldb::break_id_t bp_id);
355
356 InstructionBreakpoint *GetInstructionBPFromStopReason(lldb::SBThread &thread);
357
358 /// Checks if the request is cancelled.
359 bool IsCancelled(const protocol::Request &);
360
361 /// Clears the cancel request from the set of tracked cancel requests.
362 void ClearCancelRequest(const protocol::CancelArguments &);
363
364 lldb::SBMutex GetAPIMutex() const { return target.GetAPIMutex(); }
365
366 void StartEventThread();
367 void StartProgressEventThread();
368
369 /// Sets the given protocol `breakpoints` in the given `source`, while
370 /// removing any existing breakpoints in the given source if they are not in
371 /// `breakpoint`.
372 ///
373 /// \param[in] source
374 /// The relevant source of the breakpoints.
375 ///
376 /// \param[in] breakpoints
377 /// The breakpoints to set.
378 ///
379 /// \return a vector of the breakpoints that were set.
380 std::vector<protocol::Breakpoint> SetSourceBreakpoints(
381 const protocol::Source &source,
382 const std::optional<std::vector<protocol::SourceBreakpoint>>
383 &breakpoints);
384
385private:
386 std::vector<protocol::Breakpoint> SetSourceBreakpoints(
387 const protocol::Source &source,
388 const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints,
389 SourceBreakpointMap &existing_breakpoints);
390
391 /// Registration of request handler.
392 /// @{
393 void RegisterRequests();
394 template <typename Handler> void RegisterRequest() {
395 request_handlers[Handler::GetCommand()] = std::make_unique<Handler>(*this);
396 }
397 llvm::StringMap<std::unique_ptr<BaseRequestHandler>> request_handlers;
398 /// @}
399
400 /// Event threads.
401 /// @{
402 void EventThread();
403 void ProgressEventThread();
404
405 std::thread event_thread;
406 std::thread progress_event_thread;
407 /// @}
408
409 /// Queue for all incoming messages.
410 std::deque<protocol::Message> m_queue;
411 std::mutex m_queue_mutex;
412 std::condition_variable m_queue_cv;
413
414 std::mutex m_cancelled_requests_mutex;
415 llvm::SmallSet<int64_t, 4> m_cancelled_requests;
416
417 std::mutex m_active_request_mutex;
418 const protocol::Request *m_active_request;
419
420 llvm::StringMap<SourceBreakpointMap> m_source_breakpoints;
421 llvm::DenseMap<int64_t, SourceBreakpointMap> m_source_assembly_breakpoints;
422};
423
424} // namespace lldb_dap
425
426#endif
427

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lldb/tools/lldb-dap/DAP.h