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 "IOStream.h" 16 #include "InstructionBreakpoint.h" 17 #include "OutputRedirector.h" 18 #include "ProgressEvent.h" 19 #include "SourceBreakpoint.h" 20 #include "lldb/API/SBBroadcaster.h" 21 #include "lldb/API/SBCommandInterpreter.h" 22 #include "lldb/API/SBDebugger.h" 23 #include "lldb/API/SBError.h" 24 #include "lldb/API/SBFile.h" 25 #include "lldb/API/SBFormat.h" 26 #include "lldb/API/SBFrame.h" 27 #include "lldb/API/SBTarget.h" 28 #include "lldb/API/SBThread.h" 29 #include "lldb/API/SBValue.h" 30 #include "lldb/API/SBValueList.h" 31 #include "lldb/lldb-types.h" 32 #include "llvm/ADT/DenseMap.h" 33 #include "llvm/ADT/DenseSet.h" 34 #include "llvm/ADT/StringMap.h" 35 #include "llvm/ADT/StringRef.h" 36 #include "llvm/Support/Error.h" 37 #include "llvm/Support/JSON.h" 38 #include "llvm/Support/Threading.h" 39 #include <map> 40 #include <mutex> 41 #include <optional> 42 #include <thread> 43 #include <vector> 44 45 #define VARREF_LOCALS (int64_t)1 46 #define VARREF_GLOBALS (int64_t)2 47 #define VARREF_REGS (int64_t)3 48 #define VARREF_FIRST_VAR_IDX (int64_t)4 49 #define NO_TYPENAME "<no-type>" 50 51 namespace lldb_dap { 52 53 typedef llvm::DenseMap<uint32_t, SourceBreakpoint> SourceBreakpointMap; 54 typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap; 55 typedef llvm::DenseMap<lldb::addr_t, InstructionBreakpoint> 56 InstructionBreakpointMap; 57 58 enum class OutputType { Console, Stdout, Stderr, Telemetry }; 59 60 /// Buffer size for handling output events. 61 constexpr uint64_t OutputBufferSize = (1u << 12); 62 63 enum DAPBroadcasterBits { 64 eBroadcastBitStopEventThread = 1u << 0, 65 eBroadcastBitStopProgressThread = 1u << 1 66 }; 67 68 typedef void (*RequestCallback)(DAP &dap, const llvm::json::Object &command); 69 typedef void (*ResponseCallback)(llvm::Expected<llvm::json::Value> value); 70 71 enum class PacketStatus { 72 Success = 0, 73 EndOfFile, 74 JSONMalformed, 75 JSONNotObject 76 }; 77 78 enum class ReplMode { Variable = 0, Command, Auto }; 79 80 struct Variables { 81 /// Variable_reference start index of permanent expandable variable. 82 static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); 83 84 lldb::SBValueList locals; 85 lldb::SBValueList globals; 86 lldb::SBValueList registers; 87 88 int64_t next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; 89 int64_t next_permanent_var_ref{PermanentVariableStartIndex}; 90 91 /// Variables that are alive in this stop state. 92 /// Will be cleared when debuggee resumes. 93 llvm::DenseMap<int64_t, lldb::SBValue> referenced_variables; 94 /// Variables that persist across entire debug session. 95 /// These are the variables evaluated from debug console REPL. 96 llvm::DenseMap<int64_t, lldb::SBValue> referenced_permanent_variables; 97 98 /// Check if \p var_ref points to a variable that should persist for the 99 /// entire duration of the debug session, e.g. repl expandable variables 100 static bool IsPermanentVariableReference(int64_t var_ref); 101 102 /// \return a new variableReference. 103 /// Specify is_permanent as true for variable that should persist entire 104 /// debug session. 105 int64_t GetNewVariableReference(bool is_permanent); 106 107 /// \return the expandable variable corresponding with variableReference 108 /// value of \p value. 109 /// If \p var_ref is invalid an empty SBValue is returned. 110 lldb::SBValue GetVariable(int64_t var_ref) const; 111 112 /// Insert a new \p variable. 113 /// \return variableReference assigned to this expandable variable. 114 int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); 115 116 /// Clear all scope variables and non-permanent expandable variables. 117 void Clear(); 118 }; 119 120 struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { 121 DAP &dap; 122 explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; 123 bool DoExecute(lldb::SBDebugger debugger, char **command, 124 lldb::SBCommandReturnObject &result) override; 125 }; 126 127 struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { 128 DAP &dap; 129 explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; 130 bool DoExecute(lldb::SBDebugger debugger, char **command, 131 lldb::SBCommandReturnObject &result) override; 132 }; 133 134 struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { 135 DAP &dap; 136 explicit SendEventRequestHandler(DAP &d) : dap(d) {}; 137 bool DoExecute(lldb::SBDebugger debugger, char **command, 138 lldb::SBCommandReturnObject &result) override; 139 }; 140 141 struct DAP { 142 llvm::StringRef debug_adaptor_path; 143 std::ofstream *log; 144 InputStream input; 145 OutputStream output; 146 lldb::SBFile in; 147 OutputRedirector out; 148 OutputRedirector err; 149 lldb::SBDebugger debugger; 150 lldb::SBTarget target; 151 Variables variables; 152 lldb::SBBroadcaster broadcaster; 153 std::thread event_thread; 154 std::thread progress_event_thread; 155 llvm::StringMap<SourceBreakpointMap> source_breakpoints; 156 FunctionBreakpointMap function_breakpoints; 157 InstructionBreakpointMap instruction_breakpoints; 158 std::optional<std::vector<ExceptionBreakpoint>> exception_breakpoints; 159 llvm::once_flag init_exception_breakpoints_flag; 160 std::vector<std::string> pre_init_commands; 161 std::vector<std::string> init_commands; 162 std::vector<std::string> pre_run_commands; 163 std::vector<std::string> post_run_commands; 164 std::vector<std::string> exit_commands; 165 std::vector<std::string> stop_commands; 166 std::vector<std::string> terminate_commands; 167 // Map step in target id to list of function targets that user can choose. 168 llvm::DenseMap<lldb::addr_t, std::string> step_in_targets; 169 // A copy of the last LaunchRequest or AttachRequest so we can reuse its 170 // arguments if we get a RestartRequest. 171 std::optional<llvm::json::Object> last_launch_or_attach_request; 172 lldb::tid_t focus_tid; 173 bool disconnecting = false; 174 llvm::once_flag terminated_event_flag; 175 bool stop_at_entry; 176 bool is_attach; 177 bool enable_auto_variable_summaries; 178 bool enable_synthetic_child_debugging; 179 bool display_extended_backtrace; 180 // The process event thread normally responds to process exited events by 181 // shutting down the entire adapter. When we're restarting, we keep the id of 182 // the old process here so we can detect this case and keep running. 183 lldb::pid_t restarting_process_id; 184 bool configuration_done_sent; 185 std::map<std::string, RequestCallback, std::less<>> request_handlers; 186 bool waiting_for_run_in_terminal; 187 ProgressEventReporter progress_event_reporter; 188 // Keep track of the last stop thread index IDs as threads won't go away 189 // unless we send a "thread" event to indicate the thread exited. 190 llvm::DenseSet<lldb::tid_t> thread_ids; 191 uint32_t reverse_request_seq; 192 std::mutex call_mutex; 193 std::map<int /* request_seq */, ResponseCallback /* reply handler */> 194 inflight_reverse_requests; 195 ReplMode repl_mode; 196 std::string command_escape_prefix = "`"; 197 lldb::SBFormat frame_format; 198 lldb::SBFormat thread_format; 199 // This is used to allow request_evaluate to handle empty expressions 200 // (ie the user pressed 'return' and expects the previous expression to 201 // repeat). If the previous expression was a command, this string will be 202 // empty; if the previous expression was a variable expression, this string 203 // will contain that expression. 204 std::string last_nonempty_var_expression; 205 206 DAP(llvm::StringRef path, std::ofstream *log, ReplMode repl_mode, 207 StreamDescriptor input, StreamDescriptor output); 208 ~DAP(); 209 DAP(const DAP &rhs) = delete; 210 void operator=(const DAP &rhs) = delete; 211 ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter); 212 ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id); 213 214 /// Redirect stdout and stderr fo the IDE's console output. 215 /// 216 /// Errors in this operation will be printed to the log file and the IDE's 217 /// console output as well. 218 llvm::Error ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr); 219 220 /// Stop the redirected IO threads and associated pipes. 221 void StopIO(); 222 223 // Serialize the JSON value into a string and send the JSON packet to 224 // the "out" stream. 225 void SendJSON(const llvm::json::Value &json); 226 227 std::string ReadJSON(); 228 229 void SendOutput(OutputType o, const llvm::StringRef output); 230 231 void SendProgressEvent(uint64_t progress_id, const char *message, 232 uint64_t completed, uint64_t total); 233 234 void __attribute__((format(printf, 3, 4))) 235 SendFormattedOutput(OutputType o, const char *format, ...); 236 237 static int64_t GetNextSourceReference(); 238 239 ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread); 240 241 lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); 242 243 lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); 244 245 llvm::json::Value CreateTopLevelScopes(); 246 247 void PopulateExceptionBreakpoints(); 248 249 /// Attempt to determine if an expression is a variable expression or 250 /// lldb command using a heuristic based on the first term of the 251 /// expression. 252 /// 253 /// \param[in] frame 254 /// The frame, used as context to detect local variable names 255 /// \param[inout] expression 256 /// The expression string. Might be modified by this function to 257 /// remove the leading escape character. 258 /// \param[in] partial_expression 259 /// Whether the provided `expression` is only a prefix of the 260 /// final expression. If `true`, this function might return 261 /// `ReplMode::Auto` to indicate that the expression could be 262 /// either an expression or a statement, depending on the rest of 263 /// the expression. 264 /// \return the expression mode 265 ReplMode DetectReplMode(lldb::SBFrame frame, std::string &expression, 266 bool partial_expression); 267 268 /// \return 269 /// \b false if a fatal error was found while executing these commands, 270 /// according to the rules of \a LLDBUtils::RunLLDBCommands. 271 bool RunLLDBCommands(llvm::StringRef prefix, 272 llvm::ArrayRef<std::string> commands); 273 274 llvm::Error RunAttachCommands(llvm::ArrayRef<std::string> attach_commands); 275 llvm::Error RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands); 276 llvm::Error RunPreInitCommands(); 277 llvm::Error RunInitCommands(); 278 llvm::Error RunPreRunCommands(); 279 void RunPostRunCommands(); 280 void RunStopCommands(); 281 void RunExitCommands(); 282 void RunTerminateCommands(); 283 284 /// Create a new SBTarget object from the given request arguments. 285 /// \param[in] arguments 286 /// Launch configuration arguments. 287 /// 288 /// \param[out] error 289 /// An SBError object that will contain an error description if 290 /// function failed to create the target. 291 /// 292 /// \return 293 /// An SBTarget object. 294 lldb::SBTarget CreateTargetFromArguments(const llvm::json::Object &arguments, 295 lldb::SBError &error); 296 297 /// Set given target object as a current target for lldb-dap and start 298 /// listeing for its breakpoint events. 299 void SetTarget(const lldb::SBTarget target); 300 301 const std::map<std::string, RequestCallback> &GetRequestHandlers(); 302 303 PacketStatus GetNextObject(llvm::json::Object &object); 304 bool HandleObject(const llvm::json::Object &object); 305 306 llvm::Error Loop(); 307 308 /// Send a Debug Adapter Protocol reverse request to the IDE. 309 /// 310 /// \param[in] command 311 /// The reverse request command. 312 /// 313 /// \param[in] arguments 314 /// The reverse request arguements. 315 /// 316 /// \param[in] callback 317 /// A callback to execute when the response arrives. 318 void SendReverseRequest(llvm::StringRef command, llvm::json::Value arguments, 319 ResponseCallback callback); 320 321 /// Registers a callback handler for a Debug Adapter Protocol request 322 /// 323 /// \param[in] request 324 /// The name of the request following the Debug Adapter Protocol 325 /// specification. 326 /// 327 /// \param[in] callback 328 /// The callback to execute when the given request is triggered by the 329 /// IDE. 330 void RegisterRequestCallback(std::string request, RequestCallback callback); 331 332 /// Debuggee will continue from stopped state. 333 void WillContinue() { variables.Clear(); } 334 335 /// Poll the process to wait for it to reach the eStateStopped state. 336 /// 337 /// Wait for the process hit a stopped state. When running a launch with 338 /// "launchCommands", or attach with "attachCommands", the calls might take 339 /// some time to stop at the entry point since the command is asynchronous. We 340 /// need to sync up with the process and make sure it is stopped before we 341 /// proceed to do anything else as we will soon be asked to set breakpoints 342 /// and other things that require the process to be stopped. We must use 343 /// polling because "attachCommands" or "launchCommands" may or may not send 344 /// process state change events depending on if the user modifies the async 345 /// setting in the debugger. Since both "attachCommands" and "launchCommands" 346 /// could end up using any combination of LLDB commands, we must ensure we can 347 /// also catch when the process stops, so we must poll the process to make 348 /// sure we handle all cases. 349 /// 350 /// \param[in] seconds 351 /// The number of seconds to poll the process to wait until it is stopped. 352 /// 353 /// \return Error if waiting for the process fails, no error if succeeds. 354 lldb::SBError WaitForProcessToStop(uint32_t seconds); 355 356 void SetFrameFormat(llvm::StringRef format); 357 358 void SetThreadFormat(llvm::StringRef format); 359 360 InstructionBreakpoint *GetInstructionBreakpoint(const lldb::break_id_t bp_id); 361 362 InstructionBreakpoint *GetInstructionBPFromStopReason(lldb::SBThread &thread); 363 364 private: 365 // Send the JSON in "json_str" to the "out" stream. Correctly send the 366 // "Content-Length:" field followed by the length, followed by the raw 367 // JSON bytes. 368 void SendJSON(const std::string &json_str); 369 }; 370 371 } // namespace lldb_dap 372 373 #endif 374