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 <condition_variable> 15 #include <cstdio> 16 #include <iosfwd> 17 #include <map> 18 #include <set> 19 #include <thread> 20 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/DenseSet.h" 23 #include "llvm/ADT/StringMap.h" 24 #include "llvm/ADT/StringRef.h" 25 #include "llvm/Support/JSON.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 #include "lldb/API/SBAttachInfo.h" 29 #include "lldb/API/SBBreakpoint.h" 30 #include "lldb/API/SBBreakpointLocation.h" 31 #include "lldb/API/SBCommandInterpreter.h" 32 #include "lldb/API/SBCommandReturnObject.h" 33 #include "lldb/API/SBCommunication.h" 34 #include "lldb/API/SBDebugger.h" 35 #include "lldb/API/SBEvent.h" 36 #include "lldb/API/SBHostOS.h" 37 #include "lldb/API/SBInstruction.h" 38 #include "lldb/API/SBInstructionList.h" 39 #include "lldb/API/SBLanguageRuntime.h" 40 #include "lldb/API/SBLaunchInfo.h" 41 #include "lldb/API/SBLineEntry.h" 42 #include "lldb/API/SBListener.h" 43 #include "lldb/API/SBProcess.h" 44 #include "lldb/API/SBStream.h" 45 #include "lldb/API/SBStringList.h" 46 #include "lldb/API/SBTarget.h" 47 #include "lldb/API/SBThread.h" 48 49 #include "ExceptionBreakpoint.h" 50 #include "FunctionBreakpoint.h" 51 #include "IOStream.h" 52 #include "ProgressEvent.h" 53 #include "RunInTerminal.h" 54 #include "SourceBreakpoint.h" 55 #include "SourceReference.h" 56 57 #define VARREF_LOCALS (int64_t)1 58 #define VARREF_GLOBALS (int64_t)2 59 #define VARREF_REGS (int64_t)3 60 #define VARREF_FIRST_VAR_IDX (int64_t)4 61 #define VARREF_IS_SCOPE(v) (VARREF_LOCALS <= 1 && v < VARREF_FIRST_VAR_IDX) 62 #define VARIDX_TO_VARREF(i) ((i) + VARREF_FIRST_VAR_IDX) 63 #define VARREF_TO_VARIDX(v) ((v)-VARREF_FIRST_VAR_IDX) 64 #define NO_TYPENAME "<no-type>" 65 66 namespace lldb_vscode { 67 68 typedef llvm::DenseMap<uint32_t, SourceBreakpoint> SourceBreakpointMap; 69 typedef llvm::StringMap<FunctionBreakpoint> FunctionBreakpointMap; 70 enum class OutputType { Console, Stdout, Stderr, Telemetry }; 71 72 enum VSCodeBroadcasterBits { 73 eBroadcastBitStopEventThread = 1u << 0, 74 eBroadcastBitStopProgressThread = 1u << 1 75 }; 76 77 typedef void (*RequestCallback)(const llvm::json::Object &command); 78 79 enum class PacketStatus { 80 Success = 0, 81 EndOfFile, 82 JSONMalformed, 83 JSONNotObject 84 }; 85 86 struct VSCode { 87 std::string debug_adaptor_path; 88 InputStream input; 89 OutputStream output; 90 lldb::SBDebugger debugger; 91 lldb::SBTarget target; 92 lldb::SBValueList variables; 93 lldb::SBBroadcaster broadcaster; 94 int64_t num_regs; 95 int64_t num_locals; 96 int64_t num_globals; 97 std::thread event_thread; 98 std::thread progress_event_thread; 99 std::unique_ptr<std::ofstream> log; 100 llvm::DenseMap<lldb::addr_t, int64_t> addr_to_source_ref; 101 llvm::DenseMap<int64_t, SourceReference> source_map; 102 llvm::StringMap<SourceBreakpointMap> source_breakpoints; 103 FunctionBreakpointMap function_breakpoints; 104 std::vector<ExceptionBreakpoint> exception_breakpoints; 105 std::vector<std::string> init_commands; 106 std::vector<std::string> pre_run_commands; 107 std::vector<std::string> exit_commands; 108 std::vector<std::string> stop_commands; 109 std::vector<std::string> terminate_commands; 110 lldb::tid_t focus_tid; 111 bool sent_terminated_event; 112 bool stop_at_entry; 113 bool is_attach; 114 uint32_t reverse_request_seq; 115 std::map<std::string, RequestCallback> request_handlers; 116 bool waiting_for_run_in_terminal; 117 ProgressEventReporter progress_event_reporter; 118 // Keep track of the last stop thread index IDs as threads won't go away 119 // unless we send a "thread" event to indicate the thread exited. 120 llvm::DenseSet<lldb::tid_t> thread_ids; 121 VSCode(); 122 ~VSCode(); 123 VSCode(const VSCode &rhs) = delete; 124 void operator=(const VSCode &rhs) = delete; 125 int64_t GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const; 126 ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter); 127 ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id); 128 129 // Serialize the JSON value into a string and send the JSON packet to 130 // the "out" stream. 131 void SendJSON(const llvm::json::Value &json); 132 133 std::string ReadJSON(); 134 135 void SendOutput(OutputType o, const llvm::StringRef output); 136 137 void SendProgressEvent(uint64_t progress_id, const char *message, 138 uint64_t completed, uint64_t total); 139 140 void __attribute__((format(printf, 3, 4))) 141 SendFormattedOutput(OutputType o, const char *format, ...); 142 143 static int64_t GetNextSourceReference(); 144 145 ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread); 146 147 lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); 148 149 lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); 150 151 llvm::json::Value CreateTopLevelScopes(); 152 153 void RunLLDBCommands(llvm::StringRef prefix, 154 const std::vector<std::string> &commands); 155 156 void RunInitCommands(); 157 void RunPreRunCommands(); 158 void RunStopCommands(); 159 void RunExitCommands(); 160 void RunTerminateCommands(); 161 162 /// Create a new SBTarget object from the given request arguments. 163 /// \param[in] arguments 164 /// Launch configuration arguments. 165 /// 166 /// \param[out] error 167 /// An SBError object that will contain an error description if 168 /// function failed to create the target. 169 /// 170 /// \return 171 /// An SBTarget object. 172 lldb::SBTarget CreateTargetFromArguments(const llvm::json::Object &arguments, 173 lldb::SBError &error); 174 175 /// Set given target object as a current target for lldb-vscode and start 176 /// listeing for its breakpoint events. 177 void SetTarget(const lldb::SBTarget target); 178 179 const std::map<std::string, RequestCallback> &GetRequestHandlers(); 180 181 PacketStatus GetNextObject(llvm::json::Object &object); 182 bool HandleObject(const llvm::json::Object &object); 183 184 /// Send a Debug Adapter Protocol reverse request to the IDE 185 /// 186 /// \param[in] request 187 /// The payload of the request to send. 188 /// 189 /// \param[out] response 190 /// The response of the IDE. It might be undefined if there was an error. 191 /// 192 /// \return 193 /// A \a PacketStatus object indicating the sucess or failure of the 194 /// request. 195 PacketStatus SendReverseRequest(llvm::json::Object request, 196 llvm::json::Object &response); 197 198 /// Registers a callback handler for a Debug Adapter Protocol request 199 /// 200 /// \param[in] request 201 /// The name of the request following the Debug Adapter Protocol 202 /// specification. 203 /// 204 /// \param[in] callback 205 /// The callback to execute when the given request is triggered by the 206 /// IDE. 207 void RegisterRequestCallback(std::string request, RequestCallback callback); 208 209 private: 210 // Send the JSON in "json_str" to the "out" stream. Correctly send the 211 // "Content-Length:" field followed by the length, followed by the raw 212 // JSON bytes. 213 void SendJSON(const std::string &json_str); 214 }; 215 216 extern VSCode g_vsc; 217 218 } // namespace lldb_vscode 219 220 #endif 221