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 | |
56 | namespace lldb_dap { |
57 | |
58 | typedef std::map<std::pair<uint32_t, uint32_t>, SourceBreakpoint> |
59 | SourceBreakpointMap; |
60 | typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap; |
61 | typedef llvm::DenseMap<lldb::addr_t, InstructionBreakpoint> |
62 | InstructionBreakpointMap; |
63 | |
64 | using AdapterFeature = protocol::AdapterFeature; |
65 | using ClientFeature = protocol::ClientFeature; |
66 | |
67 | enum class OutputType { Console, Important, Stdout, Stderr, Telemetry }; |
68 | |
69 | /// Buffer size for handling output events. |
70 | constexpr uint64_t OutputBufferSize = (1u << 12); |
71 | |
72 | enum DAPBroadcasterBits { |
73 | eBroadcastBitStopEventThread = 1u << 0, |
74 | eBroadcastBitStopProgressThread = 1u << 1 |
75 | }; |
76 | |
77 | enum class ReplMode { Variable = 0, Command, Auto }; |
78 | |
79 | struct 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 | |
385 | private: |
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 | |