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