1 //===-- LLDBUtils.cpp -------------------------------------------*- 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 #include "LLDBUtils.h" 10 #include "DAP.h" 11 #include "JSONUtils.h" 12 #include "lldb/API/SBStringList.h" 13 14 #include <mutex> 15 16 namespace lldb_dap { 17 18 bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, 19 const llvm::ArrayRef<std::string> &commands, 20 llvm::raw_ostream &strm, bool parse_command_directives) { 21 if (commands.empty()) 22 return true; 23 24 bool did_print_prefix = false; 25 26 lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter(); 27 for (llvm::StringRef command : commands) { 28 lldb::SBCommandReturnObject result; 29 bool quiet_on_success = false; 30 bool check_error = false; 31 32 while (parse_command_directives) { 33 if (command.starts_with("?")) { 34 command = command.drop_front(); 35 quiet_on_success = true; 36 } else if (command.starts_with("!")) { 37 command = command.drop_front(); 38 check_error = true; 39 } else { 40 break; 41 } 42 } 43 44 { 45 // Prevent simultaneous calls to HandleCommand, e.g. EventThreadFunction 46 // may asynchronously call RunExitCommands when we are already calling 47 // RunTerminateCommands. 48 static std::mutex handle_command_mutex; 49 std::lock_guard<std::mutex> locker(handle_command_mutex); 50 interp.HandleCommand(command.str().c_str(), result, 51 /*add_to_history=*/true); 52 } 53 54 const bool got_error = !result.Succeeded(); 55 // The if statement below is assuming we always print out `!` prefixed 56 // lines. The only time we don't print is when we have `quiet_on_success == 57 // true` and we don't have an error. 58 if (quiet_on_success ? got_error : true) { 59 if (!did_print_prefix && !prefix.empty()) { 60 strm << prefix << "\n"; 61 did_print_prefix = true; 62 } 63 strm << "(lldb) " << command << "\n"; 64 auto output_len = result.GetOutputSize(); 65 if (output_len) { 66 const char *output = result.GetOutput(); 67 strm << output; 68 } 69 auto error_len = result.GetErrorSize(); 70 if (error_len) { 71 const char *error = result.GetError(); 72 strm << error; 73 } 74 } 75 if (check_error && got_error) 76 return false; // Stop running commands. 77 } 78 return true; 79 } 80 81 std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, 82 const llvm::ArrayRef<std::string> &commands, 83 bool &required_command_failed, 84 bool parse_command_directives) { 85 required_command_failed = false; 86 std::string s; 87 llvm::raw_string_ostream strm(s); 88 required_command_failed = !RunLLDBCommands(debugger, prefix, commands, strm, 89 parse_command_directives); 90 return s; 91 } 92 93 std::string 94 RunLLDBCommandsVerbatim(lldb::SBDebugger &debugger, llvm::StringRef prefix, 95 const llvm::ArrayRef<std::string> &commands) { 96 bool required_command_failed = false; 97 return RunLLDBCommands(debugger, prefix, commands, required_command_failed, 98 /*parse_command_directives=*/false); 99 } 100 101 bool ThreadHasStopReason(lldb::SBThread &thread) { 102 switch (thread.GetStopReason()) { 103 case lldb::eStopReasonTrace: 104 case lldb::eStopReasonPlanComplete: 105 case lldb::eStopReasonBreakpoint: 106 case lldb::eStopReasonWatchpoint: 107 case lldb::eStopReasonInstrumentation: 108 case lldb::eStopReasonSignal: 109 case lldb::eStopReasonException: 110 case lldb::eStopReasonExec: 111 case lldb::eStopReasonProcessorTrace: 112 case lldb::eStopReasonFork: 113 case lldb::eStopReasonVFork: 114 case lldb::eStopReasonVForkDone: 115 case lldb::eStopReasonInterrupt: 116 return true; 117 case lldb::eStopReasonThreadExiting: 118 case lldb::eStopReasonInvalid: 119 case lldb::eStopReasonNone: 120 break; 121 } 122 return false; 123 } 124 125 static uint32_t constexpr THREAD_INDEX_SHIFT = 19; 126 127 uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id) { 128 return dap_frame_id >> THREAD_INDEX_SHIFT; 129 } 130 131 uint32_t GetLLDBFrameID(uint64_t dap_frame_id) { 132 return dap_frame_id & ((1u << THREAD_INDEX_SHIFT) - 1); 133 } 134 135 int64_t MakeDAPFrameID(lldb::SBFrame &frame) { 136 return ((int64_t)frame.GetThread().GetIndexID() << THREAD_INDEX_SHIFT) | 137 frame.GetFrameID(); 138 } 139 140 lldb::SBEnvironment 141 GetEnvironmentFromArguments(const llvm::json::Object &arguments) { 142 lldb::SBEnvironment envs{}; 143 constexpr llvm::StringRef env_key = "env"; 144 const llvm::json::Value *raw_json_env = arguments.get(env_key); 145 146 if (!raw_json_env) 147 return envs; 148 149 if (raw_json_env->kind() == llvm::json::Value::Object) { 150 auto env_map = GetStringMap(arguments, env_key); 151 for (const auto &[key, value] : env_map) 152 envs.Set(key.c_str(), value.c_str(), true); 153 154 } else if (raw_json_env->kind() == llvm::json::Value::Array) { 155 const auto envs_strings = GetStrings(&arguments, env_key); 156 lldb::SBStringList entries{}; 157 for (const auto &env : envs_strings) 158 entries.AppendString(env.c_str()); 159 160 envs.SetEntries(entries, true); 161 } 162 return envs; 163 } 164 165 } // namespace lldb_dap 166