Path: blob/main/contrib/llvm-project/lldb/source/Core/Debugger.cpp
39587 views
//===-- Debugger.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Core/Debugger.h"910#include "lldb/Breakpoint/Breakpoint.h"11#include "lldb/Core/DebuggerEvents.h"12#include "lldb/Core/FormatEntity.h"13#include "lldb/Core/Mangled.h"14#include "lldb/Core/ModuleList.h"15#include "lldb/Core/ModuleSpec.h"16#include "lldb/Core/PluginManager.h"17#include "lldb/Core/Progress.h"18#include "lldb/Core/StreamAsynchronousIO.h"19#include "lldb/DataFormatters/DataVisualization.h"20#include "lldb/Expression/REPL.h"21#include "lldb/Host/File.h"22#include "lldb/Host/FileSystem.h"23#include "lldb/Host/HostInfo.h"24#include "lldb/Host/StreamFile.h"25#include "lldb/Host/Terminal.h"26#include "lldb/Host/ThreadLauncher.h"27#include "lldb/Interpreter/CommandInterpreter.h"28#include "lldb/Interpreter/CommandReturnObject.h"29#include "lldb/Interpreter/OptionValue.h"30#include "lldb/Interpreter/OptionValueLanguage.h"31#include "lldb/Interpreter/OptionValueProperties.h"32#include "lldb/Interpreter/OptionValueSInt64.h"33#include "lldb/Interpreter/OptionValueString.h"34#include "lldb/Interpreter/Property.h"35#include "lldb/Interpreter/ScriptInterpreter.h"36#include "lldb/Symbol/Function.h"37#include "lldb/Symbol/Symbol.h"38#include "lldb/Symbol/SymbolContext.h"39#include "lldb/Target/Language.h"40#include "lldb/Target/Process.h"41#include "lldb/Target/StructuredDataPlugin.h"42#include "lldb/Target/Target.h"43#include "lldb/Target/TargetList.h"44#include "lldb/Target/Thread.h"45#include "lldb/Target/ThreadList.h"46#include "lldb/Utility/AnsiTerminal.h"47#include "lldb/Utility/Event.h"48#include "lldb/Utility/LLDBLog.h"49#include "lldb/Utility/Listener.h"50#include "lldb/Utility/Log.h"51#include "lldb/Utility/State.h"52#include "lldb/Utility/Stream.h"53#include "lldb/Utility/StreamString.h"54#include "lldb/lldb-enumerations.h"5556#if defined(_WIN32)57#include "lldb/Host/windows/PosixApi.h"58#include "lldb/Host/windows/windows.h"59#endif6061#include "llvm/ADT/STLExtras.h"62#include "llvm/ADT/StringRef.h"63#include "llvm/ADT/iterator.h"64#include "llvm/Support/DynamicLibrary.h"65#include "llvm/Support/FileSystem.h"66#include "llvm/Support/Process.h"67#include "llvm/Support/ThreadPool.h"68#include "llvm/Support/Threading.h"69#include "llvm/Support/raw_ostream.h"7071#include <cstdio>72#include <cstdlib>73#include <cstring>74#include <list>75#include <memory>76#include <mutex>77#include <optional>78#include <set>79#include <string>80#include <system_error>8182// Includes for pipe()83#if defined(_WIN32)84#include <fcntl.h>85#include <io.h>86#else87#include <unistd.h>88#endif8990namespace lldb_private {91class Address;92}9394using namespace lldb;95using namespace lldb_private;9697static lldb::user_id_t g_unique_id = 1;98static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;99100#pragma mark Static Functions101102static std::recursive_mutex *g_debugger_list_mutex_ptr =103nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain104static Debugger::DebuggerList *g_debugger_list_ptr =105nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain106static llvm::DefaultThreadPool *g_thread_pool = nullptr;107108static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {109{110Debugger::eStopDisassemblyTypeNever,111"never",112"Never show disassembly when displaying a stop context.",113},114{115Debugger::eStopDisassemblyTypeNoDebugInfo,116"no-debuginfo",117"Show disassembly when there is no debug information.",118},119{120Debugger::eStopDisassemblyTypeNoSource,121"no-source",122"Show disassembly when there is no source information, or the source "123"file "124"is missing when displaying a stop context.",125},126{127Debugger::eStopDisassemblyTypeAlways,128"always",129"Always show disassembly when displaying a stop context.",130},131};132133static constexpr OptionEnumValueElement g_language_enumerators[] = {134{135eScriptLanguageNone,136"none",137"Disable scripting languages.",138},139{140eScriptLanguagePython,141"python",142"Select python as the default scripting language.",143},144{145eScriptLanguageDefault,146"default",147"Select the lldb default as the default scripting language.",148},149};150151static constexpr OptionEnumValueElement g_dwim_print_verbosities[] = {152{eDWIMPrintVerbosityNone, "none",153"Use no verbosity when running dwim-print."},154{eDWIMPrintVerbosityExpression, "expression",155"Use partial verbosity when running dwim-print - display a message when "156"`expression` evaluation is used."},157{eDWIMPrintVerbosityFull, "full",158"Use full verbosity when running dwim-print."},159};160161static constexpr OptionEnumValueElement s_stop_show_column_values[] = {162{163eStopShowColumnAnsiOrCaret,164"ansi-or-caret",165"Highlight the stop column with ANSI terminal codes when color/ANSI "166"mode is enabled; otherwise, fall back to using a text-only caret (^) "167"as if \"caret-only\" mode was selected.",168},169{170eStopShowColumnAnsi,171"ansi",172"Highlight the stop column with ANSI terminal codes when running LLDB "173"with color/ANSI enabled.",174},175{176eStopShowColumnCaret,177"caret",178"Highlight the stop column with a caret character (^) underneath the "179"stop column. This method introduces a new line in source listings "180"that display thread stop locations.",181},182{183eStopShowColumnNone,184"none",185"Do not highlight the stop column.",186},187};188189#define LLDB_PROPERTIES_debugger190#include "CoreProperties.inc"191192enum {193#define LLDB_PROPERTIES_debugger194#include "CorePropertiesEnum.inc"195};196197LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;198199Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,200VarSetOperationType op,201llvm::StringRef property_path,202llvm::StringRef value) {203bool is_load_script =204(property_path == "target.load-script-from-symbol-file");205// These properties might change how we visualize data.206bool invalidate_data_vis = (property_path == "escape-non-printables");207invalidate_data_vis |=208(property_path == "target.max-zero-padding-in-float-format");209if (invalidate_data_vis) {210DataVisualization::ForceUpdate();211}212213TargetSP target_sp;214LoadScriptFromSymFile load_script_old_value = eLoadScriptFromSymFileFalse;215if (is_load_script && exe_ctx && exe_ctx->GetTargetSP()) {216target_sp = exe_ctx->GetTargetSP();217load_script_old_value =218target_sp->TargetProperties::GetLoadScriptFromSymbolFile();219}220Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));221if (error.Success()) {222// FIXME it would be nice to have "on-change" callbacks for properties223if (property_path == g_debugger_properties[ePropertyPrompt].name) {224llvm::StringRef new_prompt = GetPrompt();225std::string str = lldb_private::ansi::FormatAnsiTerminalCodes(226new_prompt, GetUseColor());227if (str.length())228new_prompt = str;229GetCommandInterpreter().UpdatePrompt(new_prompt);230auto bytes = std::make_unique<EventDataBytes>(new_prompt);231auto prompt_change_event_sp = std::make_shared<Event>(232CommandInterpreter::eBroadcastBitResetPrompt, bytes.release());233GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp);234} else if (property_path == g_debugger_properties[ePropertyUseColor].name) {235// use-color changed. Ping the prompt so it can reset the ansi terminal236// codes.237SetPrompt(GetPrompt());238} else if (property_path ==239g_debugger_properties[ePropertyPromptAnsiPrefix].name ||240property_path ==241g_debugger_properties[ePropertyPromptAnsiSuffix].name) {242// Prompt colors changed. Ping the prompt so it can reset the ansi243// terminal codes.244SetPrompt(GetPrompt());245} else if (property_path ==246g_debugger_properties[ePropertyUseSourceCache].name) {247// use-source-cache changed. Wipe out the cache contents if it was248// disabled.249if (!GetUseSourceCache()) {250m_source_file_cache.Clear();251}252} else if (is_load_script && target_sp &&253load_script_old_value == eLoadScriptFromSymFileWarn) {254if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==255eLoadScriptFromSymFileTrue) {256std::list<Status> errors;257StreamString feedback_stream;258if (!target_sp->LoadScriptingResources(errors, feedback_stream)) {259Stream &s = GetErrorStream();260for (auto error : errors) {261s.Printf("%s\n", error.AsCString());262}263if (feedback_stream.GetSize())264s.PutCString(feedback_stream.GetString());265}266}267}268}269return error;270}271272bool Debugger::GetAutoConfirm() const {273constexpr uint32_t idx = ePropertyAutoConfirm;274return GetPropertyAtIndexAs<bool>(275idx, g_debugger_properties[idx].default_uint_value != 0);276}277278const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const {279constexpr uint32_t idx = ePropertyDisassemblyFormat;280return GetPropertyAtIndexAs<const FormatEntity::Entry *>(idx);281}282283const FormatEntity::Entry *Debugger::GetFrameFormat() const {284constexpr uint32_t idx = ePropertyFrameFormat;285return GetPropertyAtIndexAs<const FormatEntity::Entry *>(idx);286}287288const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const {289constexpr uint32_t idx = ePropertyFrameFormatUnique;290return GetPropertyAtIndexAs<const FormatEntity::Entry *>(idx);291}292293uint64_t Debugger::GetStopDisassemblyMaxSize() const {294constexpr uint32_t idx = ePropertyStopDisassemblyMaxSize;295return GetPropertyAtIndexAs<uint64_t>(296idx, g_debugger_properties[idx].default_uint_value);297}298299bool Debugger::GetNotifyVoid() const {300constexpr uint32_t idx = ePropertyNotiftVoid;301return GetPropertyAtIndexAs<uint64_t>(302idx, g_debugger_properties[idx].default_uint_value != 0);303}304305llvm::StringRef Debugger::GetPrompt() const {306constexpr uint32_t idx = ePropertyPrompt;307return GetPropertyAtIndexAs<llvm::StringRef>(308idx, g_debugger_properties[idx].default_cstr_value);309}310311llvm::StringRef Debugger::GetPromptAnsiPrefix() const {312const uint32_t idx = ePropertyPromptAnsiPrefix;313return GetPropertyAtIndexAs<llvm::StringRef>(314idx, g_debugger_properties[idx].default_cstr_value);315}316317llvm::StringRef Debugger::GetPromptAnsiSuffix() const {318const uint32_t idx = ePropertyPromptAnsiSuffix;319return GetPropertyAtIndexAs<llvm::StringRef>(320idx, g_debugger_properties[idx].default_cstr_value);321}322323void Debugger::SetPrompt(llvm::StringRef p) {324constexpr uint32_t idx = ePropertyPrompt;325SetPropertyAtIndex(idx, p);326llvm::StringRef new_prompt = GetPrompt();327std::string str =328lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor());329if (str.length())330new_prompt = str;331GetCommandInterpreter().UpdatePrompt(new_prompt);332}333334const FormatEntity::Entry *Debugger::GetThreadFormat() const {335constexpr uint32_t idx = ePropertyThreadFormat;336return GetPropertyAtIndexAs<const FormatEntity::Entry *>(idx);337}338339const FormatEntity::Entry *Debugger::GetThreadStopFormat() const {340constexpr uint32_t idx = ePropertyThreadStopFormat;341return GetPropertyAtIndexAs<const FormatEntity::Entry *>(idx);342}343344lldb::ScriptLanguage Debugger::GetScriptLanguage() const {345const uint32_t idx = ePropertyScriptLanguage;346return GetPropertyAtIndexAs<lldb::ScriptLanguage>(347idx, static_cast<lldb::ScriptLanguage>(348g_debugger_properties[idx].default_uint_value));349}350351bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) {352const uint32_t idx = ePropertyScriptLanguage;353return SetPropertyAtIndex(idx, script_lang);354}355356lldb::LanguageType Debugger::GetREPLLanguage() const {357const uint32_t idx = ePropertyREPLLanguage;358return GetPropertyAtIndexAs<LanguageType>(idx, {});359}360361bool Debugger::SetREPLLanguage(lldb::LanguageType repl_lang) {362const uint32_t idx = ePropertyREPLLanguage;363return SetPropertyAtIndex(idx, repl_lang);364}365366uint64_t Debugger::GetTerminalWidth() const {367const uint32_t idx = ePropertyTerminalWidth;368return GetPropertyAtIndexAs<uint64_t>(369idx, g_debugger_properties[idx].default_uint_value);370}371372bool Debugger::SetTerminalWidth(uint64_t term_width) {373if (auto handler_sp = m_io_handler_stack.Top())374handler_sp->TerminalSizeChanged();375376const uint32_t idx = ePropertyTerminalWidth;377return SetPropertyAtIndex(idx, term_width);378}379380bool Debugger::GetUseExternalEditor() const {381const uint32_t idx = ePropertyUseExternalEditor;382return GetPropertyAtIndexAs<bool>(383idx, g_debugger_properties[idx].default_uint_value != 0);384}385386bool Debugger::SetUseExternalEditor(bool b) {387const uint32_t idx = ePropertyUseExternalEditor;388return SetPropertyAtIndex(idx, b);389}390391llvm::StringRef Debugger::GetExternalEditor() const {392const uint32_t idx = ePropertyExternalEditor;393return GetPropertyAtIndexAs<llvm::StringRef>(394idx, g_debugger_properties[idx].default_cstr_value);395}396397bool Debugger::SetExternalEditor(llvm::StringRef editor) {398const uint32_t idx = ePropertyExternalEditor;399return SetPropertyAtIndex(idx, editor);400}401402bool Debugger::GetUseColor() const {403const uint32_t idx = ePropertyUseColor;404return GetPropertyAtIndexAs<bool>(405idx, g_debugger_properties[idx].default_uint_value != 0);406}407408bool Debugger::SetUseColor(bool b) {409const uint32_t idx = ePropertyUseColor;410bool ret = SetPropertyAtIndex(idx, b);411SetPrompt(GetPrompt());412return ret;413}414415bool Debugger::GetShowProgress() const {416const uint32_t idx = ePropertyShowProgress;417return GetPropertyAtIndexAs<bool>(418idx, g_debugger_properties[idx].default_uint_value != 0);419}420421bool Debugger::SetShowProgress(bool show_progress) {422const uint32_t idx = ePropertyShowProgress;423return SetPropertyAtIndex(idx, show_progress);424}425426llvm::StringRef Debugger::GetShowProgressAnsiPrefix() const {427const uint32_t idx = ePropertyShowProgressAnsiPrefix;428return GetPropertyAtIndexAs<llvm::StringRef>(429idx, g_debugger_properties[idx].default_cstr_value);430}431432llvm::StringRef Debugger::GetShowProgressAnsiSuffix() const {433const uint32_t idx = ePropertyShowProgressAnsiSuffix;434return GetPropertyAtIndexAs<llvm::StringRef>(435idx, g_debugger_properties[idx].default_cstr_value);436}437438bool Debugger::GetUseAutosuggestion() const {439const uint32_t idx = ePropertyShowAutosuggestion;440return GetPropertyAtIndexAs<bool>(441idx, g_debugger_properties[idx].default_uint_value != 0);442}443444llvm::StringRef Debugger::GetAutosuggestionAnsiPrefix() const {445const uint32_t idx = ePropertyShowAutosuggestionAnsiPrefix;446return GetPropertyAtIndexAs<llvm::StringRef>(447idx, g_debugger_properties[idx].default_cstr_value);448}449450llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {451const uint32_t idx = ePropertyShowAutosuggestionAnsiSuffix;452return GetPropertyAtIndexAs<llvm::StringRef>(453idx, g_debugger_properties[idx].default_cstr_value);454}455456llvm::StringRef Debugger::GetRegexMatchAnsiPrefix() const {457const uint32_t idx = ePropertyShowRegexMatchAnsiPrefix;458return GetPropertyAtIndexAs<llvm::StringRef>(459idx, g_debugger_properties[idx].default_cstr_value);460}461462llvm::StringRef Debugger::GetRegexMatchAnsiSuffix() const {463const uint32_t idx = ePropertyShowRegexMatchAnsiSuffix;464return GetPropertyAtIndexAs<llvm::StringRef>(465idx, g_debugger_properties[idx].default_cstr_value);466}467468bool Debugger::GetShowDontUsePoHint() const {469const uint32_t idx = ePropertyShowDontUsePoHint;470return GetPropertyAtIndexAs<bool>(471idx, g_debugger_properties[idx].default_uint_value != 0);472}473474bool Debugger::GetUseSourceCache() const {475const uint32_t idx = ePropertyUseSourceCache;476return GetPropertyAtIndexAs<bool>(477idx, g_debugger_properties[idx].default_uint_value != 0);478}479480bool Debugger::SetUseSourceCache(bool b) {481const uint32_t idx = ePropertyUseSourceCache;482bool ret = SetPropertyAtIndex(idx, b);483if (!ret) {484m_source_file_cache.Clear();485}486return ret;487}488bool Debugger::GetHighlightSource() const {489const uint32_t idx = ePropertyHighlightSource;490return GetPropertyAtIndexAs<bool>(491idx, g_debugger_properties[idx].default_uint_value != 0);492}493494StopShowColumn Debugger::GetStopShowColumn() const {495const uint32_t idx = ePropertyStopShowColumn;496return GetPropertyAtIndexAs<lldb::StopShowColumn>(497idx, static_cast<lldb::StopShowColumn>(498g_debugger_properties[idx].default_uint_value));499}500501llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const {502const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;503return GetPropertyAtIndexAs<llvm::StringRef>(504idx, g_debugger_properties[idx].default_cstr_value);505}506507llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const {508const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;509return GetPropertyAtIndexAs<llvm::StringRef>(510idx, g_debugger_properties[idx].default_cstr_value);511}512513llvm::StringRef Debugger::GetStopShowLineMarkerAnsiPrefix() const {514const uint32_t idx = ePropertyStopShowLineMarkerAnsiPrefix;515return GetPropertyAtIndexAs<llvm::StringRef>(516idx, g_debugger_properties[idx].default_cstr_value);517}518519llvm::StringRef Debugger::GetStopShowLineMarkerAnsiSuffix() const {520const uint32_t idx = ePropertyStopShowLineMarkerAnsiSuffix;521return GetPropertyAtIndexAs<llvm::StringRef>(522idx, g_debugger_properties[idx].default_cstr_value);523}524525uint64_t Debugger::GetStopSourceLineCount(bool before) const {526const uint32_t idx =527before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;528return GetPropertyAtIndexAs<uint64_t>(529idx, g_debugger_properties[idx].default_uint_value);530}531532Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const {533const uint32_t idx = ePropertyStopDisassemblyDisplay;534return GetPropertyAtIndexAs<Debugger::StopDisassemblyType>(535idx, static_cast<Debugger::StopDisassemblyType>(536g_debugger_properties[idx].default_uint_value));537}538539uint64_t Debugger::GetDisassemblyLineCount() const {540const uint32_t idx = ePropertyStopDisassemblyCount;541return GetPropertyAtIndexAs<uint64_t>(542idx, g_debugger_properties[idx].default_uint_value);543}544545bool Debugger::GetAutoOneLineSummaries() const {546const uint32_t idx = ePropertyAutoOneLineSummaries;547return GetPropertyAtIndexAs<bool>(548idx, g_debugger_properties[idx].default_uint_value != 0);549}550551bool Debugger::GetEscapeNonPrintables() const {552const uint32_t idx = ePropertyEscapeNonPrintables;553return GetPropertyAtIndexAs<bool>(554idx, g_debugger_properties[idx].default_uint_value != 0);555}556557bool Debugger::GetAutoIndent() const {558const uint32_t idx = ePropertyAutoIndent;559return GetPropertyAtIndexAs<bool>(560idx, g_debugger_properties[idx].default_uint_value != 0);561}562563bool Debugger::SetAutoIndent(bool b) {564const uint32_t idx = ePropertyAutoIndent;565return SetPropertyAtIndex(idx, b);566}567568bool Debugger::GetPrintDecls() const {569const uint32_t idx = ePropertyPrintDecls;570return GetPropertyAtIndexAs<bool>(571idx, g_debugger_properties[idx].default_uint_value != 0);572}573574bool Debugger::SetPrintDecls(bool b) {575const uint32_t idx = ePropertyPrintDecls;576return SetPropertyAtIndex(idx, b);577}578579uint64_t Debugger::GetTabSize() const {580const uint32_t idx = ePropertyTabSize;581return GetPropertyAtIndexAs<uint64_t>(582idx, g_debugger_properties[idx].default_uint_value);583}584585bool Debugger::SetTabSize(uint64_t tab_size) {586const uint32_t idx = ePropertyTabSize;587return SetPropertyAtIndex(idx, tab_size);588}589590lldb::DWIMPrintVerbosity Debugger::GetDWIMPrintVerbosity() const {591const uint32_t idx = ePropertyDWIMPrintVerbosity;592return GetPropertyAtIndexAs<lldb::DWIMPrintVerbosity>(593idx, static_cast<lldb::DWIMPrintVerbosity>(594g_debugger_properties[idx].default_uint_value));595}596597#pragma mark Debugger598599// const DebuggerPropertiesSP &600// Debugger::GetSettings() const601//{602// return m_properties_sp;603//}604//605606void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) {607assert(g_debugger_list_ptr == nullptr &&608"Debugger::Initialize called more than once!");609g_debugger_list_mutex_ptr = new std::recursive_mutex();610g_debugger_list_ptr = new DebuggerList();611g_thread_pool = new llvm::DefaultThreadPool(llvm::optimal_concurrency());612g_load_plugin_callback = load_plugin_callback;613}614615void Debugger::Terminate() {616assert(g_debugger_list_ptr &&617"Debugger::Terminate called without a matching Debugger::Initialize!");618619if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {620std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);621for (const auto &debugger : *g_debugger_list_ptr)622debugger->HandleDestroyCallback();623}624625if (g_thread_pool) {626// The destructor will wait for all the threads to complete.627delete g_thread_pool;628}629630if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {631// Clear our global list of debugger objects632{633std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);634for (const auto &debugger : *g_debugger_list_ptr)635debugger->Clear();636g_debugger_list_ptr->clear();637}638}639}640641void Debugger::SettingsInitialize() { Target::SettingsInitialize(); }642643void Debugger::SettingsTerminate() { Target::SettingsTerminate(); }644645bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) {646if (g_load_plugin_callback) {647llvm::sys::DynamicLibrary dynlib =648g_load_plugin_callback(shared_from_this(), spec, error);649if (dynlib.isValid()) {650m_loaded_plugins.push_back(dynlib);651return true;652}653} else {654// The g_load_plugin_callback is registered in SBDebugger::Initialize() and655// if the public API layer isn't available (code is linking against all of656// the internal LLDB static libraries), then we can't load plugins657error.SetErrorString("Public API layer is not available");658}659return false;660}661662static FileSystem::EnumerateDirectoryResult663LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,664llvm::StringRef path) {665Status error;666667static constexpr llvm::StringLiteral g_dylibext(".dylib");668static constexpr llvm::StringLiteral g_solibext(".so");669670if (!baton)671return FileSystem::eEnumerateDirectoryResultQuit;672673Debugger *debugger = (Debugger *)baton;674675namespace fs = llvm::sys::fs;676// If we have a regular file, a symbolic link or unknown file type, try and677// process the file. We must handle unknown as sometimes the directory678// enumeration might be enumerating a file system that doesn't have correct679// file type information.680if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||681ft == fs::file_type::type_unknown) {682FileSpec plugin_file_spec(path);683FileSystem::Instance().Resolve(plugin_file_spec);684685if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&686plugin_file_spec.GetFileNameExtension() != g_solibext) {687return FileSystem::eEnumerateDirectoryResultNext;688}689690Status plugin_load_error;691debugger->LoadPlugin(plugin_file_spec, plugin_load_error);692693return FileSystem::eEnumerateDirectoryResultNext;694} else if (ft == fs::file_type::directory_file ||695ft == fs::file_type::symlink_file ||696ft == fs::file_type::type_unknown) {697// Try and recurse into anything that a directory or symbolic link. We must698// also do this for unknown as sometimes the directory enumeration might be699// enumerating a file system that doesn't have correct file type700// information.701return FileSystem::eEnumerateDirectoryResultEnter;702}703704return FileSystem::eEnumerateDirectoryResultNext;705}706707void Debugger::InstanceInitialize() {708const bool find_directories = true;709const bool find_files = true;710const bool find_other = true;711char dir_path[PATH_MAX];712if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) {713if (FileSystem::Instance().Exists(dir_spec) &&714dir_spec.GetPath(dir_path, sizeof(dir_path))) {715FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,716find_files, find_other,717LoadPluginCallback, this);718}719}720721if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) {722if (FileSystem::Instance().Exists(dir_spec) &&723dir_spec.GetPath(dir_path, sizeof(dir_path))) {724FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,725find_files, find_other,726LoadPluginCallback, this);727}728}729730PluginManager::DebuggerInitialize(*this);731}732733DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback,734void *baton) {735DebuggerSP debugger_sp(new Debugger(log_callback, baton));736if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {737std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);738g_debugger_list_ptr->push_back(debugger_sp);739}740debugger_sp->InstanceInitialize();741return debugger_sp;742}743744void Debugger::HandleDestroyCallback() {745const lldb::user_id_t user_id = GetID();746// Invoke and remove all the callbacks in an FIFO order. Callbacks which are747// added during this loop will be appended, invoked and then removed last.748// Callbacks which are removed during this loop will not be invoked.749while (true) {750DestroyCallbackInfo callback_info;751{752std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);753if (m_destroy_callbacks.empty())754break;755// Pop the first item in the list756callback_info = m_destroy_callbacks.front();757m_destroy_callbacks.erase(m_destroy_callbacks.begin());758}759// Call the destroy callback with user id and baton760callback_info.callback(user_id, callback_info.baton);761}762}763764void Debugger::Destroy(DebuggerSP &debugger_sp) {765if (!debugger_sp)766return;767768debugger_sp->HandleDestroyCallback();769CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter();770771if (cmd_interpreter.GetSaveSessionOnQuit()) {772CommandReturnObject result(debugger_sp->GetUseColor());773cmd_interpreter.SaveTranscript(result);774if (result.Succeeded())775(*debugger_sp->GetAsyncOutputStream()) << result.GetOutputData() << '\n';776else777(*debugger_sp->GetAsyncErrorStream()) << result.GetErrorData() << '\n';778}779780debugger_sp->Clear();781782if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {783std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);784DebuggerList::iterator pos, end = g_debugger_list_ptr->end();785for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {786if ((*pos).get() == debugger_sp.get()) {787g_debugger_list_ptr->erase(pos);788return;789}790}791}792}793794DebuggerSP795Debugger::FindDebuggerWithInstanceName(llvm::StringRef instance_name) {796if (!g_debugger_list_ptr || !g_debugger_list_mutex_ptr)797return DebuggerSP();798799std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);800for (const DebuggerSP &debugger_sp : *g_debugger_list_ptr) {801if (!debugger_sp)802continue;803804if (llvm::StringRef(debugger_sp->GetInstanceName()) == instance_name)805return debugger_sp;806}807return DebuggerSP();808}809810TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) {811TargetSP target_sp;812if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {813std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);814DebuggerList::iterator pos, end = g_debugger_list_ptr->end();815for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {816target_sp = (*pos)->GetTargetList().FindTargetWithProcessID(pid);817if (target_sp)818break;819}820}821return target_sp;822}823824TargetSP Debugger::FindTargetWithProcess(Process *process) {825TargetSP target_sp;826if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {827std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);828DebuggerList::iterator pos, end = g_debugger_list_ptr->end();829for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {830target_sp = (*pos)->GetTargetList().FindTargetWithProcess(process);831if (target_sp)832break;833}834}835return target_sp;836}837838llvm::StringRef Debugger::GetStaticBroadcasterClass() {839static constexpr llvm::StringLiteral class_name("lldb.debugger");840return class_name;841}842843Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)844: UserID(g_unique_id++),845Properties(std::make_shared<OptionValueProperties>()),846m_input_file_sp(std::make_shared<NativeFile>(stdin, false)),847m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)),848m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)),849m_input_recorder(nullptr),850m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),851m_terminal_state(), m_target_list(*this), m_platform_list(),852m_listener_sp(Listener::MakeListener("lldb.Debugger")),853m_source_manager_up(), m_source_file_cache(),854m_command_interpreter_up(855std::make_unique<CommandInterpreter>(*this, false)),856m_io_handler_stack(),857m_instance_name(llvm::formatv("debugger_{0}", GetID()).str()),858m_loaded_plugins(), m_event_handler_thread(), m_io_handler_thread(),859m_sync_broadcaster(nullptr, "lldb.debugger.sync"),860m_broadcaster(m_broadcaster_manager_sp,861GetStaticBroadcasterClass().str()),862m_forward_listener_sp(), m_clear_once() {863// Initialize the debugger properties as early as possible as other parts of864// LLDB will start querying them during construction.865m_collection_sp->Initialize(g_debugger_properties);866m_collection_sp->AppendProperty(867"target", "Settings specify to debugging targets.", true,868Target::GetGlobalProperties().GetValueProperties());869m_collection_sp->AppendProperty(870"platform", "Platform settings.", true,871Platform::GetGlobalPlatformProperties().GetValueProperties());872m_collection_sp->AppendProperty(873"symbols", "Symbol lookup and cache settings.", true,874ModuleList::GetGlobalModuleListProperties().GetValueProperties());875m_collection_sp->AppendProperty(876LanguageProperties::GetSettingName(), "Language settings.", true,877Language::GetGlobalLanguageProperties().GetValueProperties());878if (m_command_interpreter_up) {879m_collection_sp->AppendProperty(880"interpreter",881"Settings specify to the debugger's command interpreter.", true,882m_command_interpreter_up->GetValueProperties());883}884if (log_callback)885m_callback_handler_sp =886std::make_shared<CallbackLogHandler>(log_callback, baton);887m_command_interpreter_up->Initialize();888// Always add our default platform to the platform list889PlatformSP default_platform_sp(Platform::GetHostPlatform());890assert(default_platform_sp);891m_platform_list.Append(default_platform_sp, true);892893// Create the dummy target.894{895ArchSpec arch(Target::GetDefaultArchitecture());896if (!arch.IsValid())897arch = HostInfo::GetArchitecture();898assert(arch.IsValid() && "No valid default or host archspec");899const bool is_dummy_target = true;900m_dummy_target_sp.reset(901new Target(*this, arch, default_platform_sp, is_dummy_target));902}903assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?");904905OptionValueUInt64 *term_width =906m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64(907ePropertyTerminalWidth);908term_width->SetMinimumValue(10);909term_width->SetMaximumValue(1024);910911// Turn off use-color if this is a dumb terminal.912const char *term = getenv("TERM");913if (term && !strcmp(term, "dumb"))914SetUseColor(false);915// Turn off use-color if we don't write to a terminal with color support.916if (!GetOutputFile().GetIsTerminalWithColors())917SetUseColor(false);918919if (Diagnostics::Enabled()) {920m_diagnostics_callback_id = Diagnostics::Instance().AddCallback(921[this](const FileSpec &dir) -> llvm::Error {922for (auto &entry : m_stream_handlers) {923llvm::StringRef log_path = entry.first();924llvm::StringRef file_name = llvm::sys::path::filename(log_path);925FileSpec destination = dir.CopyByAppendingPathComponent(file_name);926std::error_code ec =927llvm::sys::fs::copy_file(log_path, destination.GetPath());928if (ec)929return llvm::errorCodeToError(ec);930}931return llvm::Error::success();932});933}934935#if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)936// Enabling use of ANSI color codes because LLDB is using them to highlight937// text.938llvm::sys::Process::UseANSIEscapeCodes(true);939#endif940}941942Debugger::~Debugger() { Clear(); }943944void Debugger::Clear() {945// Make sure we call this function only once. With the C++ global destructor946// chain having a list of debuggers and with code that can be running on947// other threads, we need to ensure this doesn't happen multiple times.948//949// The following functions call Debugger::Clear():950// Debugger::~Debugger();951// static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);952// static void Debugger::Terminate();953llvm::call_once(m_clear_once, [this]() {954ClearIOHandlers();955StopIOHandlerThread();956StopEventHandlerThread();957m_listener_sp->Clear();958for (TargetSP target_sp : m_target_list.Targets()) {959if (target_sp) {960if (ProcessSP process_sp = target_sp->GetProcessSP())961process_sp->Finalize(false /* not destructing */);962target_sp->Destroy();963}964}965m_broadcaster_manager_sp->Clear();966967// Close the input file _before_ we close the input read communications968// class as it does NOT own the input file, our m_input_file does.969m_terminal_state.Clear();970GetInputFile().Close();971972m_command_interpreter_up->Clear();973974if (Diagnostics::Enabled())975Diagnostics::Instance().RemoveCallback(m_diagnostics_callback_id);976});977}978979bool Debugger::GetAsyncExecution() {980return !m_command_interpreter_up->GetSynchronous();981}982983void Debugger::SetAsyncExecution(bool async_execution) {984m_command_interpreter_up->SetSynchronous(!async_execution);985}986987repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; }988989static inline int OpenPipe(int fds[2], std::size_t size) {990#ifdef _WIN32991return _pipe(fds, size, O_BINARY);992#else993(void)size;994return pipe(fds);995#endif996}997998Status Debugger::SetInputString(const char *data) {999Status result;1000enum PIPES { READ, WRITE }; // Indexes for the read and write fds1001int fds[2] = {-1, -1};10021003if (data == nullptr) {1004result.SetErrorString("String data is null");1005return result;1006}10071008size_t size = strlen(data);1009if (size == 0) {1010result.SetErrorString("String data is empty");1011return result;1012}10131014if (OpenPipe(fds, size) != 0) {1015result.SetErrorString(1016"can't create pipe file descriptors for LLDB commands");1017return result;1018}10191020int r = write(fds[WRITE], data, size);1021(void)r;1022// Close the write end of the pipe, so that the command interpreter will exit1023// when it consumes all the data.1024llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);10251026// Open the read file descriptor as a FILE * that we can return as an input1027// handle.1028FILE *commands_file = fdopen(fds[READ], "rb");1029if (commands_file == nullptr) {1030result.SetErrorStringWithFormat("fdopen(%i, \"rb\") failed (errno = %i) "1031"when trying to open LLDB commands pipe",1032fds[READ], errno);1033llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);1034return result;1035}10361037SetInputFile((FileSP)std::make_shared<NativeFile>(commands_file, true));1038return result;1039}10401041void Debugger::SetInputFile(FileSP file_sp) {1042assert(file_sp && file_sp->IsValid());1043m_input_file_sp = std::move(file_sp);1044// Save away the terminal state if that is relevant, so that we can restore1045// it in RestoreInputState.1046SaveInputTerminalState();1047}10481049void Debugger::SetOutputFile(FileSP file_sp) {1050assert(file_sp && file_sp->IsValid());1051m_output_stream_sp = std::make_shared<StreamFile>(file_sp);1052}10531054void Debugger::SetErrorFile(FileSP file_sp) {1055assert(file_sp && file_sp->IsValid());1056m_error_stream_sp = std::make_shared<StreamFile>(file_sp);1057}10581059void Debugger::SaveInputTerminalState() {1060int fd = GetInputFile().GetDescriptor();1061if (fd != File::kInvalidDescriptor)1062m_terminal_state.Save(fd, true);1063}10641065void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); }10661067ExecutionContext Debugger::GetSelectedExecutionContext() {1068bool adopt_selected = true;1069ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected);1070return ExecutionContext(exe_ctx_ref);1071}10721073void Debugger::DispatchInputInterrupt() {1074std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());1075IOHandlerSP reader_sp(m_io_handler_stack.Top());1076if (reader_sp)1077reader_sp->Interrupt();1078}10791080void Debugger::DispatchInputEndOfFile() {1081std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());1082IOHandlerSP reader_sp(m_io_handler_stack.Top());1083if (reader_sp)1084reader_sp->GotEOF();1085}10861087void Debugger::ClearIOHandlers() {1088// The bottom input reader should be the main debugger input reader. We do1089// not want to close that one here.1090std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());1091while (m_io_handler_stack.GetSize() > 1) {1092IOHandlerSP reader_sp(m_io_handler_stack.Top());1093if (reader_sp)1094PopIOHandler(reader_sp);1095}1096}10971098void Debugger::RunIOHandlers() {1099IOHandlerSP reader_sp = m_io_handler_stack.Top();1100while (true) {1101if (!reader_sp)1102break;11031104reader_sp->Run();1105{1106std::lock_guard<std::recursive_mutex> guard(1107m_io_handler_synchronous_mutex);11081109// Remove all input readers that are done from the top of the stack1110while (true) {1111IOHandlerSP top_reader_sp = m_io_handler_stack.Top();1112if (top_reader_sp && top_reader_sp->GetIsDone())1113PopIOHandler(top_reader_sp);1114else1115break;1116}1117reader_sp = m_io_handler_stack.Top();1118}1119}1120ClearIOHandlers();1121}11221123void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) {1124std::lock_guard<std::recursive_mutex> guard(m_io_handler_synchronous_mutex);11251126PushIOHandler(reader_sp);1127IOHandlerSP top_reader_sp = reader_sp;11281129while (top_reader_sp) {1130top_reader_sp->Run();11311132// Don't unwind past the starting point.1133if (top_reader_sp.get() == reader_sp.get()) {1134if (PopIOHandler(reader_sp))1135break;1136}11371138// If we pushed new IO handlers, pop them if they're done or restart the1139// loop to run them if they're not.1140while (true) {1141top_reader_sp = m_io_handler_stack.Top();1142if (top_reader_sp && top_reader_sp->GetIsDone()) {1143PopIOHandler(top_reader_sp);1144// Don't unwind past the starting point.1145if (top_reader_sp.get() == reader_sp.get())1146return;1147} else {1148break;1149}1150}1151}1152}11531154bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) {1155return m_io_handler_stack.IsTop(reader_sp);1156}11571158bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,1159IOHandler::Type second_top_type) {1160return m_io_handler_stack.CheckTopIOHandlerTypes(top_type, second_top_type);1161}11621163void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {1164bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout);1165if (!printed) {1166lldb::StreamFileSP stream =1167is_stdout ? m_output_stream_sp : m_error_stream_sp;1168stream->Write(s, len);1169}1170}11711172llvm::StringRef Debugger::GetTopIOHandlerControlSequence(char ch) {1173return m_io_handler_stack.GetTopIOHandlerControlSequence(ch);1174}11751176const char *Debugger::GetIOHandlerCommandPrefix() {1177return m_io_handler_stack.GetTopIOHandlerCommandPrefix();1178}11791180const char *Debugger::GetIOHandlerHelpPrologue() {1181return m_io_handler_stack.GetTopIOHandlerHelpPrologue();1182}11831184bool Debugger::RemoveIOHandler(const IOHandlerSP &reader_sp) {1185return PopIOHandler(reader_sp);1186}11871188void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp,1189bool cancel_top_handler) {1190PushIOHandler(reader_sp, cancel_top_handler);1191}11921193void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,1194StreamFileSP &err) {1195// Before an IOHandler runs, it must have in/out/err streams. This function1196// is called when one ore more of the streams are nullptr. We use the top1197// input reader's in/out/err streams, or fall back to the debugger file1198// handles, or we fall back onto stdin/stdout/stderr as a last resort.11991200std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());1201IOHandlerSP top_reader_sp(m_io_handler_stack.Top());1202// If no STDIN has been set, then set it appropriately1203if (!in || !in->IsValid()) {1204if (top_reader_sp)1205in = top_reader_sp->GetInputFileSP();1206else1207in = GetInputFileSP();1208// If there is nothing, use stdin1209if (!in)1210in = std::make_shared<NativeFile>(stdin, false);1211}1212// If no STDOUT has been set, then set it appropriately1213if (!out || !out->GetFile().IsValid()) {1214if (top_reader_sp)1215out = top_reader_sp->GetOutputStreamFileSP();1216else1217out = GetOutputStreamSP();1218// If there is nothing, use stdout1219if (!out)1220out = std::make_shared<StreamFile>(stdout, false);1221}1222// If no STDERR has been set, then set it appropriately1223if (!err || !err->GetFile().IsValid()) {1224if (top_reader_sp)1225err = top_reader_sp->GetErrorStreamFileSP();1226else1227err = GetErrorStreamSP();1228// If there is nothing, use stderr1229if (!err)1230err = std::make_shared<StreamFile>(stderr, false);1231}1232}12331234void Debugger::PushIOHandler(const IOHandlerSP &reader_sp,1235bool cancel_top_handler) {1236if (!reader_sp)1237return;12381239std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());12401241// Get the current top input reader...1242IOHandlerSP top_reader_sp(m_io_handler_stack.Top());12431244// Don't push the same IO handler twice...1245if (reader_sp == top_reader_sp)1246return;12471248// Push our new input reader1249m_io_handler_stack.Push(reader_sp);1250reader_sp->Activate();12511252// Interrupt the top input reader to it will exit its Run() function and let1253// this new input reader take over1254if (top_reader_sp) {1255top_reader_sp->Deactivate();1256if (cancel_top_handler)1257top_reader_sp->Cancel();1258}1259}12601261bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) {1262if (!pop_reader_sp)1263return false;12641265std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());12661267// The reader on the stop of the stack is done, so let the next read on the1268// stack refresh its prompt and if there is one...1269if (m_io_handler_stack.IsEmpty())1270return false;12711272IOHandlerSP reader_sp(m_io_handler_stack.Top());12731274if (pop_reader_sp != reader_sp)1275return false;12761277reader_sp->Deactivate();1278reader_sp->Cancel();1279m_io_handler_stack.Pop();12801281reader_sp = m_io_handler_stack.Top();1282if (reader_sp)1283reader_sp->Activate();12841285return true;1286}12871288StreamSP Debugger::GetAsyncOutputStream() {1289return std::make_shared<StreamAsynchronousIO>(*this, true, GetUseColor());1290}12911292StreamSP Debugger::GetAsyncErrorStream() {1293return std::make_shared<StreamAsynchronousIO>(*this, false, GetUseColor());1294}12951296void Debugger::RequestInterrupt() {1297std::lock_guard<std::mutex> guard(m_interrupt_mutex);1298m_interrupt_requested++;1299}13001301void Debugger::CancelInterruptRequest() {1302std::lock_guard<std::mutex> guard(m_interrupt_mutex);1303if (m_interrupt_requested > 0)1304m_interrupt_requested--;1305}13061307bool Debugger::InterruptRequested() {1308// This is the one we should call internally. This will return true either1309// if there's a debugger interrupt and we aren't on the IOHandler thread,1310// or if we are on the IOHandler thread and there's a CommandInterpreter1311// interrupt.1312if (!IsIOHandlerThreadCurrentThread()) {1313std::lock_guard<std::mutex> guard(m_interrupt_mutex);1314return m_interrupt_requested != 0;1315}1316return GetCommandInterpreter().WasInterrupted();1317}13181319Debugger::InterruptionReport::InterruptionReport(1320std::string function_name, const llvm::formatv_object_base &payload)1321: m_function_name(std::move(function_name)),1322m_interrupt_time(std::chrono::system_clock::now()),1323m_thread_id(llvm::get_threadid()) {1324llvm::raw_string_ostream desc(m_description);1325desc << payload << "\n";1326}13271328void Debugger::ReportInterruption(const InterruptionReport &report) {1329// For now, just log the description:1330Log *log = GetLog(LLDBLog::Host);1331LLDB_LOG(log, "Interruption: {0}", report.m_description);1332}13331334Debugger::DebuggerList Debugger::DebuggersRequestingInterruption() {1335DebuggerList result;1336if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1337std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1338for (auto debugger_sp : *g_debugger_list_ptr) {1339if (debugger_sp->InterruptRequested())1340result.push_back(debugger_sp);1341}1342}1343return result;1344}13451346size_t Debugger::GetNumDebuggers() {1347if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1348std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1349return g_debugger_list_ptr->size();1350}1351return 0;1352}13531354lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) {1355DebuggerSP debugger_sp;13561357if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1358std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1359if (index < g_debugger_list_ptr->size())1360debugger_sp = g_debugger_list_ptr->at(index);1361}13621363return debugger_sp;1364}13651366DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) {1367DebuggerSP debugger_sp;13681369if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1370std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1371DebuggerList::iterator pos, end = g_debugger_list_ptr->end();1372for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {1373if ((*pos)->GetID() == id) {1374debugger_sp = *pos;1375break;1376}1377}1378}1379return debugger_sp;1380}13811382bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format,1383const SymbolContext *sc,1384const SymbolContext *prev_sc,1385const ExecutionContext *exe_ctx,1386const Address *addr, Stream &s) {1387FormatEntity::Entry format_entry;13881389if (format == nullptr) {1390if (exe_ctx != nullptr && exe_ctx->HasTargetScope())1391format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();1392if (format == nullptr) {1393FormatEntity::Parse("${addr}: ", format_entry);1394format = &format_entry;1395}1396}1397bool function_changed = false;1398bool initial_function = false;1399if (prev_sc && (prev_sc->function || prev_sc->symbol)) {1400if (sc && (sc->function || sc->symbol)) {1401if (prev_sc->symbol && sc->symbol) {1402if (!sc->symbol->Compare(prev_sc->symbol->GetName(),1403prev_sc->symbol->GetType())) {1404function_changed = true;1405}1406} else if (prev_sc->function && sc->function) {1407if (prev_sc->function->GetMangled() != sc->function->GetMangled()) {1408function_changed = true;1409}1410}1411}1412}1413// The first context on a list of instructions will have a prev_sc that has1414// no Function or Symbol -- if SymbolContext had an IsValid() method, it1415// would return false. But we do get a prev_sc pointer.1416if ((sc && (sc->function || sc->symbol)) && prev_sc &&1417(prev_sc->function == nullptr && prev_sc->symbol == nullptr)) {1418initial_function = true;1419}1420return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr,1421function_changed, initial_function);1422}14231424void Debugger::AssertCallback(llvm::StringRef message,1425llvm::StringRef backtrace,1426llvm::StringRef prompt) {1427Debugger::ReportError(1428llvm::formatv("{0}\n{1}{2}", message, backtrace, prompt).str());1429}14301431void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,1432void *baton) {1433// For simplicity's sake, I am not going to deal with how to close down any1434// open logging streams, I just redirect everything from here on out to the1435// callback.1436m_callback_handler_sp =1437std::make_shared<CallbackLogHandler>(log_callback, baton);1438}14391440void Debugger::SetDestroyCallback(1441lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) {1442std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);1443m_destroy_callbacks.clear();1444const lldb::callback_token_t token = m_destroy_callback_next_token++;1445m_destroy_callbacks.emplace_back(token, destroy_callback, baton);1446}14471448lldb::callback_token_t Debugger::AddDestroyCallback(1449lldb_private::DebuggerDestroyCallback destroy_callback, void *baton) {1450std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);1451const lldb::callback_token_t token = m_destroy_callback_next_token++;1452m_destroy_callbacks.emplace_back(token, destroy_callback, baton);1453return token;1454}14551456bool Debugger::RemoveDestroyCallback(lldb::callback_token_t token) {1457std::lock_guard<std::mutex> guard(m_destroy_callback_mutex);1458for (auto it = m_destroy_callbacks.begin(); it != m_destroy_callbacks.end();1459++it) {1460if (it->token == token) {1461m_destroy_callbacks.erase(it);1462return true;1463}1464}1465return false;1466}14671468static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,1469std::string title, std::string details,1470uint64_t completed, uint64_t total,1471bool is_debugger_specific,1472uint32_t progress_broadcast_bit) {1473// Only deliver progress events if we have any progress listeners.1474if (!debugger.GetBroadcaster().EventTypeHasListeners(progress_broadcast_bit))1475return;14761477EventSP event_sp(new Event(1478progress_broadcast_bit,1479new ProgressEventData(progress_id, std::move(title), std::move(details),1480completed, total, is_debugger_specific)));1481debugger.GetBroadcaster().BroadcastEvent(event_sp);1482}14831484void Debugger::ReportProgress(uint64_t progress_id, std::string title,1485std::string details, uint64_t completed,1486uint64_t total,1487std::optional<lldb::user_id_t> debugger_id,1488uint32_t progress_category_bit) {1489// Check if this progress is for a specific debugger.1490if (debugger_id) {1491// It is debugger specific, grab it and deliver the event if the debugger1492// still exists.1493DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);1494if (debugger_sp)1495PrivateReportProgress(*debugger_sp, progress_id, std::move(title),1496std::move(details), completed, total,1497/*is_debugger_specific*/ true,1498progress_category_bit);1499return;1500}1501// The progress event is not debugger specific, iterate over all debuggers1502// and deliver a progress event to each one.1503if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1504std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1505DebuggerList::iterator pos, end = g_debugger_list_ptr->end();1506for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos)1507PrivateReportProgress(*(*pos), progress_id, title, details, completed,1508total, /*is_debugger_specific*/ false,1509progress_category_bit);1510}1511}15121513static void PrivateReportDiagnostic(Debugger &debugger, Severity severity,1514std::string message,1515bool debugger_specific) {1516uint32_t event_type = 0;1517switch (severity) {1518case eSeverityInfo:1519assert(false && "eSeverityInfo should not be broadcast");1520return;1521case eSeverityWarning:1522event_type = lldb::eBroadcastBitWarning;1523break;1524case eSeverityError:1525event_type = lldb::eBroadcastBitError;1526break;1527}15281529Broadcaster &broadcaster = debugger.GetBroadcaster();1530if (!broadcaster.EventTypeHasListeners(event_type)) {1531// Diagnostics are too important to drop. If nobody is listening, print the1532// diagnostic directly to the debugger's error stream.1533DiagnosticEventData event_data(severity, std::move(message),1534debugger_specific);1535StreamSP stream = debugger.GetAsyncErrorStream();1536event_data.Dump(stream.get());1537return;1538}1539EventSP event_sp = std::make_shared<Event>(1540event_type,1541new DiagnosticEventData(severity, std::move(message), debugger_specific));1542broadcaster.BroadcastEvent(event_sp);1543}15441545void Debugger::ReportDiagnosticImpl(Severity severity, std::string message,1546std::optional<lldb::user_id_t> debugger_id,1547std::once_flag *once) {1548auto ReportDiagnosticLambda = [&]() {1549// Always log diagnostics to the system log.1550Host::SystemLog(severity, message);15511552// The diagnostic subsystem is optional but we still want to broadcast1553// events when it's disabled.1554if (Diagnostics::Enabled())1555Diagnostics::Instance().Report(message);15561557// We don't broadcast info events.1558if (severity == lldb::eSeverityInfo)1559return;15601561// Check if this diagnostic is for a specific debugger.1562if (debugger_id) {1563// It is debugger specific, grab it and deliver the event if the debugger1564// still exists.1565DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);1566if (debugger_sp)1567PrivateReportDiagnostic(*debugger_sp, severity, std::move(message),1568true);1569return;1570}1571// The diagnostic event is not debugger specific, iterate over all debuggers1572// and deliver a diagnostic event to each one.1573if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1574std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1575for (const auto &debugger : *g_debugger_list_ptr)1576PrivateReportDiagnostic(*debugger, severity, message, false);1577}1578};15791580if (once)1581std::call_once(*once, ReportDiagnosticLambda);1582else1583ReportDiagnosticLambda();1584}15851586void Debugger::ReportWarning(std::string message,1587std::optional<lldb::user_id_t> debugger_id,1588std::once_flag *once) {1589ReportDiagnosticImpl(eSeverityWarning, std::move(message), debugger_id, once);1590}15911592void Debugger::ReportError(std::string message,1593std::optional<lldb::user_id_t> debugger_id,1594std::once_flag *once) {1595ReportDiagnosticImpl(eSeverityError, std::move(message), debugger_id, once);1596}15971598void Debugger::ReportInfo(std::string message,1599std::optional<lldb::user_id_t> debugger_id,1600std::once_flag *once) {1601ReportDiagnosticImpl(eSeverityInfo, std::move(message), debugger_id, once);1602}16031604void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) {1605if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {1606std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);1607for (DebuggerSP debugger_sp : *g_debugger_list_ptr) {1608EventSP event_sp = std::make_shared<Event>(1609lldb::eBroadcastSymbolChange,1610new SymbolChangeEventData(debugger_sp, module_spec));1611debugger_sp->GetBroadcaster().BroadcastEvent(event_sp);1612}1613}1614}16151616static std::shared_ptr<LogHandler>1617CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,1618size_t buffer_size) {1619switch (log_handler_kind) {1620case eLogHandlerStream:1621return std::make_shared<StreamLogHandler>(fd, should_close, buffer_size);1622case eLogHandlerCircular:1623return std::make_shared<RotatingLogHandler>(buffer_size);1624case eLogHandlerSystem:1625return std::make_shared<SystemLogHandler>();1626case eLogHandlerCallback:1627return {};1628}1629return {};1630}16311632bool Debugger::EnableLog(llvm::StringRef channel,1633llvm::ArrayRef<const char *> categories,1634llvm::StringRef log_file, uint32_t log_options,1635size_t buffer_size, LogHandlerKind log_handler_kind,1636llvm::raw_ostream &error_stream) {16371638std::shared_ptr<LogHandler> log_handler_sp;1639if (m_callback_handler_sp) {1640log_handler_sp = m_callback_handler_sp;1641// For now when using the callback mode you always get thread & timestamp.1642log_options |=1643LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;1644} else if (log_file.empty()) {1645log_handler_sp =1646CreateLogHandler(log_handler_kind, GetOutputFile().GetDescriptor(),1647/*should_close=*/false, buffer_size);1648} else {1649auto pos = m_stream_handlers.find(log_file);1650if (pos != m_stream_handlers.end())1651log_handler_sp = pos->second.lock();1652if (!log_handler_sp) {1653File::OpenOptions flags =1654File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;1655if (log_options & LLDB_LOG_OPTION_APPEND)1656flags |= File::eOpenOptionAppend;1657else1658flags |= File::eOpenOptionTruncate;1659llvm::Expected<FileUP> file = FileSystem::Instance().Open(1660FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false);1661if (!file) {1662error_stream << "Unable to open log file '" << log_file1663<< "': " << llvm::toString(file.takeError()) << "\n";1664return false;1665}16661667log_handler_sp =1668CreateLogHandler(log_handler_kind, (*file)->GetDescriptor(),1669/*should_close=*/true, buffer_size);1670m_stream_handlers[log_file] = log_handler_sp;1671}1672}1673assert(log_handler_sp);16741675if (log_options == 0)1676log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME;16771678return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories,1679error_stream);1680}16811682ScriptInterpreter *1683Debugger::GetScriptInterpreter(bool can_create,1684std::optional<lldb::ScriptLanguage> language) {1685std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex);1686lldb::ScriptLanguage script_language =1687language ? *language : GetScriptLanguage();16881689if (!m_script_interpreters[script_language]) {1690if (!can_create)1691return nullptr;1692m_script_interpreters[script_language] =1693PluginManager::GetScriptInterpreterForLanguage(script_language, *this);1694}16951696return m_script_interpreters[script_language].get();1697}16981699SourceManager &Debugger::GetSourceManager() {1700if (!m_source_manager_up)1701m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());1702return *m_source_manager_up;1703}17041705// This function handles events that were broadcast by the process.1706void Debugger::HandleBreakpointEvent(const EventSP &event_sp) {1707using namespace lldb;1708const uint32_t event_type =1709Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(1710event_sp);17111712// if (event_type & eBreakpointEventTypeAdded1713// || event_type & eBreakpointEventTypeRemoved1714// || event_type & eBreakpointEventTypeEnabled1715// || event_type & eBreakpointEventTypeDisabled1716// || event_type & eBreakpointEventTypeCommandChanged1717// || event_type & eBreakpointEventTypeConditionChanged1718// || event_type & eBreakpointEventTypeIgnoreChanged1719// || event_type & eBreakpointEventTypeLocationsResolved)1720// {1721// // Don't do anything about these events, since the breakpoint1722// commands already echo these actions.1723// }1724//1725if (event_type & eBreakpointEventTypeLocationsAdded) {1726uint32_t num_new_locations =1727Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(1728event_sp);1729if (num_new_locations > 0) {1730BreakpointSP breakpoint =1731Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);1732StreamSP output_sp(GetAsyncOutputStream());1733if (output_sp) {1734output_sp->Printf("%d location%s added to breakpoint %d\n",1735num_new_locations, num_new_locations == 1 ? "" : "s",1736breakpoint->GetID());1737output_sp->Flush();1738}1739}1740}1741// else if (event_type & eBreakpointEventTypeLocationsRemoved)1742// {1743// // These locations just get disabled, not sure it is worth spamming1744// folks about this on the command line.1745// }1746// else if (event_type & eBreakpointEventTypeLocationsResolved)1747// {1748// // This might be an interesting thing to note, but I'm going to1749// leave it quiet for now, it just looked noisy.1750// }1751}17521753void Debugger::FlushProcessOutput(Process &process, bool flush_stdout,1754bool flush_stderr) {1755const auto &flush = [&](Stream &stream,1756size_t (Process::*get)(char *, size_t, Status &)) {1757Status error;1758size_t len;1759char buffer[1024];1760while ((len = (process.*get)(buffer, sizeof(buffer), error)) > 0)1761stream.Write(buffer, len);1762stream.Flush();1763};17641765std::lock_guard<std::mutex> guard(m_output_flush_mutex);1766if (flush_stdout)1767flush(*GetAsyncOutputStream(), &Process::GetSTDOUT);1768if (flush_stderr)1769flush(*GetAsyncErrorStream(), &Process::GetSTDERR);1770}17711772// This function handles events that were broadcast by the process.1773void Debugger::HandleProcessEvent(const EventSP &event_sp) {1774using namespace lldb;1775const uint32_t event_type = event_sp->GetType();1776ProcessSP process_sp =1777(event_type == Process::eBroadcastBitStructuredData)1778? EventDataStructuredData::GetProcessFromEvent(event_sp.get())1779: Process::ProcessEventData::GetProcessFromEvent(event_sp.get());17801781StreamSP output_stream_sp = GetAsyncOutputStream();1782StreamSP error_stream_sp = GetAsyncErrorStream();1783const bool gui_enabled = IsForwardingEvents();17841785if (!gui_enabled) {1786bool pop_process_io_handler = false;1787assert(process_sp);17881789bool state_is_stopped = false;1790const bool got_state_changed =1791(event_type & Process::eBroadcastBitStateChanged) != 0;1792const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;1793const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;1794const bool got_structured_data =1795(event_type & Process::eBroadcastBitStructuredData) != 0;17961797if (got_state_changed) {1798StateType event_state =1799Process::ProcessEventData::GetStateFromEvent(event_sp.get());1800state_is_stopped = StateIsStoppedState(event_state, false);1801}18021803// Display running state changes first before any STDIO1804if (got_state_changed && !state_is_stopped) {1805// This is a public stop which we are going to announce to the user, so1806// we should force the most relevant frame selection here.1807Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),1808SelectMostRelevantFrame,1809pop_process_io_handler);1810}18111812// Now display STDOUT and STDERR1813FlushProcessOutput(*process_sp, got_stdout || got_state_changed,1814got_stderr || got_state_changed);18151816// Give structured data events an opportunity to display.1817if (got_structured_data) {1818StructuredDataPluginSP plugin_sp =1819EventDataStructuredData::GetPluginFromEvent(event_sp.get());1820if (plugin_sp) {1821auto structured_data_sp =1822EventDataStructuredData::GetObjectFromEvent(event_sp.get());1823if (output_stream_sp) {1824StreamString content_stream;1825Status error =1826plugin_sp->GetDescription(structured_data_sp, content_stream);1827if (error.Success()) {1828if (!content_stream.GetString().empty()) {1829// Add newline.1830content_stream.PutChar('\n');1831content_stream.Flush();18321833// Print it.1834output_stream_sp->PutCString(content_stream.GetString());1835}1836} else {1837error_stream_sp->Format("Failed to print structured "1838"data with plugin {0}: {1}",1839plugin_sp->GetPluginName(), error);1840}1841}1842}1843}18441845// Now display any stopped state changes after any STDIO1846if (got_state_changed && state_is_stopped) {1847Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),1848SelectMostRelevantFrame,1849pop_process_io_handler);1850}18511852output_stream_sp->Flush();1853error_stream_sp->Flush();18541855if (pop_process_io_handler)1856process_sp->PopProcessIOHandler();1857}1858}18591860void Debugger::HandleThreadEvent(const EventSP &event_sp) {1861// At present the only thread event we handle is the Frame Changed event, and1862// all we do for that is just reprint the thread status for that thread.1863using namespace lldb;1864const uint32_t event_type = event_sp->GetType();1865const bool stop_format = true;1866if (event_type == Thread::eBroadcastBitStackChanged ||1867event_type == Thread::eBroadcastBitThreadSelected) {1868ThreadSP thread_sp(1869Thread::ThreadEventData::GetThreadFromEvent(event_sp.get()));1870if (thread_sp) {1871thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format);1872}1873}1874}18751876bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; }18771878void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) {1879m_forward_listener_sp = listener_sp;1880}18811882void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) {1883m_forward_listener_sp.reset();1884}18851886lldb::thread_result_t Debugger::DefaultEventHandler() {1887ListenerSP listener_sp(GetListener());1888ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());1889ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());1890ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());1891BroadcastEventSpec target_event_spec(broadcaster_class_target,1892Target::eBroadcastBitBreakpointChanged);18931894BroadcastEventSpec process_event_spec(1895broadcaster_class_process,1896Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT |1897Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData);18981899BroadcastEventSpec thread_event_spec(broadcaster_class_thread,1900Thread::eBroadcastBitStackChanged |1901Thread::eBroadcastBitThreadSelected);19021903listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,1904target_event_spec);1905listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,1906process_event_spec);1907listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,1908thread_event_spec);1909listener_sp->StartListeningForEvents(1910m_command_interpreter_up.get(),1911CommandInterpreter::eBroadcastBitQuitCommandReceived |1912CommandInterpreter::eBroadcastBitAsynchronousOutputData |1913CommandInterpreter::eBroadcastBitAsynchronousErrorData);19141915listener_sp->StartListeningForEvents(1916&m_broadcaster, lldb::eBroadcastBitProgress | lldb::eBroadcastBitWarning |1917lldb::eBroadcastBitError |1918lldb::eBroadcastSymbolChange);19191920// Let the thread that spawned us know that we have started up and that we1921// are now listening to all required events so no events get missed1922m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);19231924bool done = false;1925while (!done) {1926EventSP event_sp;1927if (listener_sp->GetEvent(event_sp, std::nullopt)) {1928if (event_sp) {1929Broadcaster *broadcaster = event_sp->GetBroadcaster();1930if (broadcaster) {1931uint32_t event_type = event_sp->GetType();1932ConstString broadcaster_class(broadcaster->GetBroadcasterClass());1933if (broadcaster_class == broadcaster_class_process) {1934HandleProcessEvent(event_sp);1935} else if (broadcaster_class == broadcaster_class_target) {1936if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(1937event_sp.get())) {1938HandleBreakpointEvent(event_sp);1939}1940} else if (broadcaster_class == broadcaster_class_thread) {1941HandleThreadEvent(event_sp);1942} else if (broadcaster == m_command_interpreter_up.get()) {1943if (event_type &1944CommandInterpreter::eBroadcastBitQuitCommandReceived) {1945done = true;1946} else if (event_type &1947CommandInterpreter::eBroadcastBitAsynchronousErrorData) {1948const char *data = static_cast<const char *>(1949EventDataBytes::GetBytesFromEvent(event_sp.get()));1950if (data && data[0]) {1951StreamSP error_sp(GetAsyncErrorStream());1952if (error_sp) {1953error_sp->PutCString(data);1954error_sp->Flush();1955}1956}1957} else if (event_type & CommandInterpreter::1958eBroadcastBitAsynchronousOutputData) {1959const char *data = static_cast<const char *>(1960EventDataBytes::GetBytesFromEvent(event_sp.get()));1961if (data && data[0]) {1962StreamSP output_sp(GetAsyncOutputStream());1963if (output_sp) {1964output_sp->PutCString(data);1965output_sp->Flush();1966}1967}1968}1969} else if (broadcaster == &m_broadcaster) {1970if (event_type & lldb::eBroadcastBitProgress)1971HandleProgressEvent(event_sp);1972else if (event_type & lldb::eBroadcastBitWarning)1973HandleDiagnosticEvent(event_sp);1974else if (event_type & lldb::eBroadcastBitError)1975HandleDiagnosticEvent(event_sp);1976}1977}19781979if (m_forward_listener_sp)1980m_forward_listener_sp->AddEvent(event_sp);1981}1982}1983}1984return {};1985}19861987bool Debugger::StartEventHandlerThread() {1988if (!m_event_handler_thread.IsJoinable()) {1989// We must synchronize with the DefaultEventHandler() thread to ensure it1990// is up and running and listening to events before we return from this1991// function. We do this by listening to events for the1992// eBroadcastBitEventThreadIsListening from the m_sync_broadcaster1993ConstString full_name("lldb.debugger.event-handler");1994ListenerSP listener_sp(Listener::MakeListener(full_name.AsCString()));1995listener_sp->StartListeningForEvents(&m_sync_broadcaster,1996eBroadcastBitEventThreadIsListening);19971998llvm::StringRef thread_name =1999full_name.GetLength() < llvm::get_max_thread_name_length()2000? full_name.GetStringRef()2001: "dbg.evt-handler";20022003// Use larger 8MB stack for this thread2004llvm::Expected<HostThread> event_handler_thread =2005ThreadLauncher::LaunchThread(2006thread_name, [this] { return DefaultEventHandler(); },2007g_debugger_event_thread_stack_bytes);20082009if (event_handler_thread) {2010m_event_handler_thread = *event_handler_thread;2011} else {2012LLDB_LOG_ERROR(GetLog(LLDBLog::Host), event_handler_thread.takeError(),2013"failed to launch host thread: {0}");2014}20152016// Make sure DefaultEventHandler() is running and listening to events2017// before we return from this function. We are only listening for events of2018// type eBroadcastBitEventThreadIsListening so we don't need to check the2019// event, we just need to wait an infinite amount of time for it (nullptr2020// timeout as the first parameter)2021lldb::EventSP event_sp;2022listener_sp->GetEvent(event_sp, std::nullopt);2023}2024return m_event_handler_thread.IsJoinable();2025}20262027void Debugger::StopEventHandlerThread() {2028if (m_event_handler_thread.IsJoinable()) {2029GetCommandInterpreter().BroadcastEvent(2030CommandInterpreter::eBroadcastBitQuitCommandReceived);2031m_event_handler_thread.Join(nullptr);2032}2033}20342035lldb::thread_result_t Debugger::IOHandlerThread() {2036RunIOHandlers();2037StopEventHandlerThread();2038return {};2039}20402041void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {2042auto *data = ProgressEventData::GetEventDataFromEvent(event_sp.get());2043if (!data)2044return;20452046// Do some bookkeeping for the current event, regardless of whether we're2047// going to show the progress.2048const uint64_t id = data->GetID();2049if (m_current_event_id) {2050Log *log = GetLog(LLDBLog::Events);2051if (log && log->GetVerbose()) {2052StreamString log_stream;2053log_stream.AsRawOstream()2054<< static_cast<void *>(this) << " Debugger(" << GetID()2055<< ")::HandleProgressEvent( m_current_event_id = "2056<< *m_current_event_id << ", data = { ";2057data->Dump(&log_stream);2058log_stream << " } )";2059log->PutString(log_stream.GetString());2060}2061if (id != *m_current_event_id)2062return;2063if (data->GetCompleted() == data->GetTotal())2064m_current_event_id.reset();2065} else {2066m_current_event_id = id;2067}20682069// Decide whether we actually are going to show the progress. This decision2070// can change between iterations so check it inside the loop.2071if (!GetShowProgress())2072return;20732074// Determine whether the current output file is an interactive terminal with2075// color support. We assume that if we support ANSI escape codes we support2076// vt100 escape codes.2077File &file = GetOutputFile();2078if (!file.GetIsInteractive() || !file.GetIsTerminalWithColors())2079return;20802081StreamSP output = GetAsyncOutputStream();20822083// Print over previous line, if any.2084output->Printf("\r");20852086if (data->GetCompleted() == data->GetTotal()) {2087// Clear the current line.2088output->Printf("\x1B[2K");2089output->Flush();2090return;2091}20922093// Trim the progress message if it exceeds the window's width and print it.2094std::string message = data->GetMessage();2095if (data->IsFinite())2096message = llvm::formatv("[{0}/{1}] {2}", data->GetCompleted(),2097data->GetTotal(), message)2098.str();20992100// Trim the progress message if it exceeds the window's width and print it.2101const uint32_t term_width = GetTerminalWidth();2102const uint32_t ellipsis = 3;2103if (message.size() + ellipsis >= term_width)2104message = message.substr(0, term_width - ellipsis);21052106const bool use_color = GetUseColor();2107llvm::StringRef ansi_prefix = GetShowProgressAnsiPrefix();2108if (!ansi_prefix.empty())2109output->Printf(2110"%s", ansi::FormatAnsiTerminalCodes(ansi_prefix, use_color).c_str());21112112output->Printf("%s...", message.c_str());21132114llvm::StringRef ansi_suffix = GetShowProgressAnsiSuffix();2115if (!ansi_suffix.empty())2116output->Printf(2117"%s", ansi::FormatAnsiTerminalCodes(ansi_suffix, use_color).c_str());21182119// Clear until the end of the line.2120output->Printf("\x1B[K\r");21212122// Flush the output.2123output->Flush();2124}21252126void Debugger::HandleDiagnosticEvent(const lldb::EventSP &event_sp) {2127auto *data = DiagnosticEventData::GetEventDataFromEvent(event_sp.get());2128if (!data)2129return;21302131StreamSP stream = GetAsyncErrorStream();2132data->Dump(stream.get());2133}21342135bool Debugger::HasIOHandlerThread() const {2136return m_io_handler_thread.IsJoinable();2137}21382139HostThread Debugger::SetIOHandlerThread(HostThread &new_thread) {2140HostThread old_host = m_io_handler_thread;2141m_io_handler_thread = new_thread;2142return old_host;2143}21442145bool Debugger::StartIOHandlerThread() {2146if (!m_io_handler_thread.IsJoinable()) {2147llvm::Expected<HostThread> io_handler_thread = ThreadLauncher::LaunchThread(2148"lldb.debugger.io-handler", [this] { return IOHandlerThread(); },21498 * 1024 * 1024); // Use larger 8MB stack for this thread2150if (io_handler_thread) {2151m_io_handler_thread = *io_handler_thread;2152} else {2153LLDB_LOG_ERROR(GetLog(LLDBLog::Host), io_handler_thread.takeError(),2154"failed to launch host thread: {0}");2155}2156}2157return m_io_handler_thread.IsJoinable();2158}21592160void Debugger::StopIOHandlerThread() {2161if (m_io_handler_thread.IsJoinable()) {2162GetInputFile().Close();2163m_io_handler_thread.Join(nullptr);2164}2165}21662167void Debugger::JoinIOHandlerThread() {2168if (HasIOHandlerThread()) {2169thread_result_t result;2170m_io_handler_thread.Join(&result);2171m_io_handler_thread = LLDB_INVALID_HOST_THREAD;2172}2173}21742175bool Debugger::IsIOHandlerThreadCurrentThread() const {2176if (!HasIOHandlerThread())2177return false;2178return m_io_handler_thread.EqualsThread(Host::GetCurrentThread());2179}21802181Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) {2182if (!prefer_dummy) {2183if (TargetSP target = m_target_list.GetSelectedTarget())2184return *target;2185}2186return GetDummyTarget();2187}21882189Status Debugger::RunREPL(LanguageType language, const char *repl_options) {2190Status err;2191FileSpec repl_executable;21922193if (language == eLanguageTypeUnknown)2194language = GetREPLLanguage();21952196if (language == eLanguageTypeUnknown) {2197LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();21982199if (auto single_lang = repl_languages.GetSingularLanguage()) {2200language = *single_lang;2201} else if (repl_languages.Empty()) {2202err.SetErrorString(2203"LLDB isn't configured with REPL support for any languages.");2204return err;2205} else {2206err.SetErrorString(2207"Multiple possible REPL languages. Please specify a language.");2208return err;2209}2210}22112212Target *const target =2213nullptr; // passing in an empty target means the REPL must create one22142215REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options));22162217if (!err.Success()) {2218return err;2219}22202221if (!repl_sp) {2222err.SetErrorStringWithFormat("couldn't find a REPL for %s",2223Language::GetNameForLanguageType(language));2224return err;2225}22262227repl_sp->SetCompilerOptions(repl_options);2228repl_sp->RunLoop();22292230return err;2231}22322233llvm::ThreadPoolInterface &Debugger::GetThreadPool() {2234assert(g_thread_pool &&2235"Debugger::GetThreadPool called before Debugger::Initialize");2236return *g_thread_pool;2237}223822392240