101263c6cSJonas Devlieghere //===-- LLDBUtils.cpp -------------------------------------------*- C++ -*-===// 201263c6cSJonas Devlieghere // 301263c6cSJonas Devlieghere // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 401263c6cSJonas Devlieghere // See https://llvm.org/LICENSE.txt for license information. 501263c6cSJonas Devlieghere // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 601263c6cSJonas Devlieghere // 701263c6cSJonas Devlieghere //===----------------------------------------------------------------------===// 801263c6cSJonas Devlieghere 901263c6cSJonas Devlieghere #include "LLDBUtils.h" 1001263c6cSJonas Devlieghere #include "DAP.h" 1109c258efSAdrian Vogelsgesang #include "JSONUtils.h" 1209c258efSAdrian Vogelsgesang #include "lldb/API/SBStringList.h" 1301263c6cSJonas Devlieghere 14e427e934SJordan Rupprecht #include <mutex> 15e427e934SJordan Rupprecht 1601263c6cSJonas Devlieghere namespace lldb_dap { 1701263c6cSJonas Devlieghere 18*e5ba1172SJohn Harrison bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, 1901263c6cSJonas Devlieghere const llvm::ArrayRef<std::string> &commands, 20aa207674SWalter Erquinigo llvm::raw_ostream &strm, bool parse_command_directives) { 2101263c6cSJonas Devlieghere if (commands.empty()) 22aa207674SWalter Erquinigo return true; 23aa207674SWalter Erquinigo 24aa207674SWalter Erquinigo bool did_print_prefix = false; 25aa207674SWalter Erquinigo 26*e5ba1172SJohn Harrison lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter(); 27aa207674SWalter Erquinigo for (llvm::StringRef command : commands) { 2801263c6cSJonas Devlieghere lldb::SBCommandReturnObject result; 29aa207674SWalter Erquinigo bool quiet_on_success = false; 30aa207674SWalter Erquinigo bool check_error = false; 31aa207674SWalter Erquinigo 32aa207674SWalter Erquinigo while (parse_command_directives) { 33aa207674SWalter Erquinigo if (command.starts_with("?")) { 34aa207674SWalter Erquinigo command = command.drop_front(); 35aa207674SWalter Erquinigo quiet_on_success = true; 36aa207674SWalter Erquinigo } else if (command.starts_with("!")) { 37aa207674SWalter Erquinigo command = command.drop_front(); 38aa207674SWalter Erquinigo check_error = true; 39aa207674SWalter Erquinigo } else { 40aa207674SWalter Erquinigo break; 41aa207674SWalter Erquinigo } 42aa207674SWalter Erquinigo } 43aa207674SWalter Erquinigo 44e427e934SJordan Rupprecht { 45e427e934SJordan Rupprecht // Prevent simultaneous calls to HandleCommand, e.g. EventThreadFunction 46e427e934SJordan Rupprecht // may asynchronously call RunExitCommands when we are already calling 47e427e934SJordan Rupprecht // RunTerminateCommands. 48e427e934SJordan Rupprecht static std::mutex handle_command_mutex; 49e427e934SJordan Rupprecht std::lock_guard<std::mutex> locker(handle_command_mutex); 502011cbcdScmtice interp.HandleCommand(command.str().c_str(), result, 512011cbcdScmtice /*add_to_history=*/true); 52e427e934SJordan Rupprecht } 53e427e934SJordan Rupprecht 54aa207674SWalter Erquinigo const bool got_error = !result.Succeeded(); 55aa207674SWalter Erquinigo // The if statement below is assuming we always print out `!` prefixed 56aa207674SWalter Erquinigo // lines. The only time we don't print is when we have `quiet_on_success == 57aa207674SWalter Erquinigo // true` and we don't have an error. 58aa207674SWalter Erquinigo if (quiet_on_success ? got_error : true) { 59aa207674SWalter Erquinigo if (!did_print_prefix && !prefix.empty()) { 60aa207674SWalter Erquinigo strm << prefix << "\n"; 61aa207674SWalter Erquinigo did_print_prefix = true; 62aa207674SWalter Erquinigo } 6301263c6cSJonas Devlieghere strm << "(lldb) " << command << "\n"; 6401263c6cSJonas Devlieghere auto output_len = result.GetOutputSize(); 6501263c6cSJonas Devlieghere if (output_len) { 6601263c6cSJonas Devlieghere const char *output = result.GetOutput(); 6701263c6cSJonas Devlieghere strm << output; 6801263c6cSJonas Devlieghere } 6901263c6cSJonas Devlieghere auto error_len = result.GetErrorSize(); 7001263c6cSJonas Devlieghere if (error_len) { 7101263c6cSJonas Devlieghere const char *error = result.GetError(); 7201263c6cSJonas Devlieghere strm << error; 7301263c6cSJonas Devlieghere } 7401263c6cSJonas Devlieghere } 75aa207674SWalter Erquinigo if (check_error && got_error) 76aa207674SWalter Erquinigo return false; // Stop running commands. 77aa207674SWalter Erquinigo } 78aa207674SWalter Erquinigo return true; 7901263c6cSJonas Devlieghere } 8001263c6cSJonas Devlieghere 81*e5ba1172SJohn Harrison std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, 82aa207674SWalter Erquinigo const llvm::ArrayRef<std::string> &commands, 83aa207674SWalter Erquinigo bool &required_command_failed, 84aa207674SWalter Erquinigo bool parse_command_directives) { 85aa207674SWalter Erquinigo required_command_failed = false; 8601263c6cSJonas Devlieghere std::string s; 8701263c6cSJonas Devlieghere llvm::raw_string_ostream strm(s); 88*e5ba1172SJohn Harrison required_command_failed = !RunLLDBCommands(debugger, prefix, commands, strm, 89*e5ba1172SJohn Harrison parse_command_directives); 9001263c6cSJonas Devlieghere return s; 9101263c6cSJonas Devlieghere } 9201263c6cSJonas Devlieghere 93aa207674SWalter Erquinigo std::string 94*e5ba1172SJohn Harrison RunLLDBCommandsVerbatim(lldb::SBDebugger &debugger, llvm::StringRef prefix, 95aa207674SWalter Erquinigo const llvm::ArrayRef<std::string> &commands) { 96aa207674SWalter Erquinigo bool required_command_failed = false; 97*e5ba1172SJohn Harrison return RunLLDBCommands(debugger, prefix, commands, required_command_failed, 98aa207674SWalter Erquinigo /*parse_command_directives=*/false); 99aa207674SWalter Erquinigo } 100aa207674SWalter Erquinigo 10101263c6cSJonas Devlieghere bool ThreadHasStopReason(lldb::SBThread &thread) { 10201263c6cSJonas Devlieghere switch (thread.GetStopReason()) { 10301263c6cSJonas Devlieghere case lldb::eStopReasonTrace: 10401263c6cSJonas Devlieghere case lldb::eStopReasonPlanComplete: 10501263c6cSJonas Devlieghere case lldb::eStopReasonBreakpoint: 10601263c6cSJonas Devlieghere case lldb::eStopReasonWatchpoint: 10701263c6cSJonas Devlieghere case lldb::eStopReasonInstrumentation: 10801263c6cSJonas Devlieghere case lldb::eStopReasonSignal: 10901263c6cSJonas Devlieghere case lldb::eStopReasonException: 11001263c6cSJonas Devlieghere case lldb::eStopReasonExec: 11101263c6cSJonas Devlieghere case lldb::eStopReasonProcessorTrace: 11201263c6cSJonas Devlieghere case lldb::eStopReasonFork: 11301263c6cSJonas Devlieghere case lldb::eStopReasonVFork: 11401263c6cSJonas Devlieghere case lldb::eStopReasonVForkDone: 115f838fa82Sjeffreytan81 case lldb::eStopReasonInterrupt: 11601263c6cSJonas Devlieghere return true; 11701263c6cSJonas Devlieghere case lldb::eStopReasonThreadExiting: 11801263c6cSJonas Devlieghere case lldb::eStopReasonInvalid: 11901263c6cSJonas Devlieghere case lldb::eStopReasonNone: 12001263c6cSJonas Devlieghere break; 12101263c6cSJonas Devlieghere } 12201263c6cSJonas Devlieghere return false; 12301263c6cSJonas Devlieghere } 12401263c6cSJonas Devlieghere 12501263c6cSJonas Devlieghere static uint32_t constexpr THREAD_INDEX_SHIFT = 19; 12601263c6cSJonas Devlieghere 12701263c6cSJonas Devlieghere uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id) { 12801263c6cSJonas Devlieghere return dap_frame_id >> THREAD_INDEX_SHIFT; 12901263c6cSJonas Devlieghere } 13001263c6cSJonas Devlieghere 13101263c6cSJonas Devlieghere uint32_t GetLLDBFrameID(uint64_t dap_frame_id) { 13201263c6cSJonas Devlieghere return dap_frame_id & ((1u << THREAD_INDEX_SHIFT) - 1); 13301263c6cSJonas Devlieghere } 13401263c6cSJonas Devlieghere 13501263c6cSJonas Devlieghere int64_t MakeDAPFrameID(lldb::SBFrame &frame) { 13601263c6cSJonas Devlieghere return ((int64_t)frame.GetThread().GetIndexID() << THREAD_INDEX_SHIFT) | 13701263c6cSJonas Devlieghere frame.GetFrameID(); 13801263c6cSJonas Devlieghere } 13901263c6cSJonas Devlieghere 140d4c17891SDa-Viper lldb::SBEnvironment 141d4c17891SDa-Viper GetEnvironmentFromArguments(const llvm::json::Object &arguments) { 142d4c17891SDa-Viper lldb::SBEnvironment envs{}; 143d4c17891SDa-Viper constexpr llvm::StringRef env_key = "env"; 144d4c17891SDa-Viper const llvm::json::Value *raw_json_env = arguments.get(env_key); 145d4c17891SDa-Viper 146d4c17891SDa-Viper if (!raw_json_env) 147d4c17891SDa-Viper return envs; 148d4c17891SDa-Viper 149d4c17891SDa-Viper if (raw_json_env->kind() == llvm::json::Value::Object) { 150d4c17891SDa-Viper auto env_map = GetStringMap(arguments, env_key); 151d4c17891SDa-Viper for (const auto &[key, value] : env_map) 152d4c17891SDa-Viper envs.Set(key.c_str(), value.c_str(), true); 153d4c17891SDa-Viper 154d4c17891SDa-Viper } else if (raw_json_env->kind() == llvm::json::Value::Array) { 155d4c17891SDa-Viper const auto envs_strings = GetStrings(&arguments, env_key); 156d4c17891SDa-Viper lldb::SBStringList entries{}; 157d4c17891SDa-Viper for (const auto &env : envs_strings) 158d4c17891SDa-Viper entries.AppendString(env.c_str()); 159d4c17891SDa-Viper 160d4c17891SDa-Viper envs.SetEntries(entries, true); 161d4c17891SDa-Viper } 162d4c17891SDa-Viper return envs; 163d4c17891SDa-Viper } 164d4c17891SDa-Viper 16501263c6cSJonas Devlieghere } // namespace lldb_dap 166