1dda28197Spatrick //===-- Debugger.cpp ------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Core/Debugger.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
12*f6aab3d8Srobert #include "lldb/Core/DebuggerEvents.h"
13061da546Spatrick #include "lldb/Core/FormatEntity.h"
14061da546Spatrick #include "lldb/Core/Mangled.h"
15061da546Spatrick #include "lldb/Core/ModuleList.h"
16*f6aab3d8Srobert #include "lldb/Core/ModuleSpec.h"
17061da546Spatrick #include "lldb/Core/PluginManager.h"
18061da546Spatrick #include "lldb/Core/StreamAsynchronousIO.h"
19061da546Spatrick #include "lldb/Core/StreamFile.h"
20061da546Spatrick #include "lldb/DataFormatters/DataVisualization.h"
21061da546Spatrick #include "lldb/Expression/REPL.h"
22061da546Spatrick #include "lldb/Host/File.h"
23061da546Spatrick #include "lldb/Host/FileSystem.h"
24061da546Spatrick #include "lldb/Host/HostInfo.h"
25061da546Spatrick #include "lldb/Host/Terminal.h"
26061da546Spatrick #include "lldb/Host/ThreadLauncher.h"
27061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
28be691f3bSpatrick #include "lldb/Interpreter/CommandReturnObject.h"
29061da546Spatrick #include "lldb/Interpreter/OptionValue.h"
30*f6aab3d8Srobert #include "lldb/Interpreter/OptionValueLanguage.h"
31061da546Spatrick #include "lldb/Interpreter/OptionValueProperties.h"
32061da546Spatrick #include "lldb/Interpreter/OptionValueSInt64.h"
33061da546Spatrick #include "lldb/Interpreter/OptionValueString.h"
34061da546Spatrick #include "lldb/Interpreter/Property.h"
35061da546Spatrick #include "lldb/Interpreter/ScriptInterpreter.h"
36061da546Spatrick #include "lldb/Symbol/Function.h"
37061da546Spatrick #include "lldb/Symbol/Symbol.h"
38061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
39061da546Spatrick #include "lldb/Target/Language.h"
40061da546Spatrick #include "lldb/Target/Process.h"
41061da546Spatrick #include "lldb/Target/StructuredDataPlugin.h"
42061da546Spatrick #include "lldb/Target/Target.h"
43061da546Spatrick #include "lldb/Target/TargetList.h"
44061da546Spatrick #include "lldb/Target/Thread.h"
45061da546Spatrick #include "lldb/Target/ThreadList.h"
46061da546Spatrick #include "lldb/Utility/AnsiTerminal.h"
47*f6aab3d8Srobert #include "lldb/Utility/Diagnostics.h"
48061da546Spatrick #include "lldb/Utility/Event.h"
49*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
50061da546Spatrick #include "lldb/Utility/Listener.h"
51061da546Spatrick #include "lldb/Utility/Log.h"
52061da546Spatrick #include "lldb/Utility/State.h"
53061da546Spatrick #include "lldb/Utility/Stream.h"
54061da546Spatrick #include "lldb/Utility/StreamString.h"
55*f6aab3d8Srobert #include "lldb/lldb-enumerations.h"
56061da546Spatrick
57061da546Spatrick #if defined(_WIN32)
58061da546Spatrick #include "lldb/Host/windows/PosixApi.h"
59061da546Spatrick #include "lldb/Host/windows/windows.h"
60061da546Spatrick #endif
61061da546Spatrick
62061da546Spatrick #include "llvm/ADT/STLExtras.h"
63061da546Spatrick #include "llvm/ADT/StringRef.h"
64061da546Spatrick #include "llvm/ADT/iterator.h"
65061da546Spatrick #include "llvm/Support/DynamicLibrary.h"
66061da546Spatrick #include "llvm/Support/FileSystem.h"
67061da546Spatrick #include "llvm/Support/Process.h"
68*f6aab3d8Srobert #include "llvm/Support/ThreadPool.h"
69061da546Spatrick #include "llvm/Support/Threading.h"
70061da546Spatrick #include "llvm/Support/raw_ostream.h"
71061da546Spatrick
72be691f3bSpatrick #include <cstdio>
73be691f3bSpatrick #include <cstdlib>
74be691f3bSpatrick #include <cstring>
75061da546Spatrick #include <list>
76061da546Spatrick #include <memory>
77061da546Spatrick #include <mutex>
78*f6aab3d8Srobert #include <optional>
79061da546Spatrick #include <set>
80061da546Spatrick #include <string>
81061da546Spatrick #include <system_error>
82061da546Spatrick
83*f6aab3d8Srobert // Includes for pipe()
84*f6aab3d8Srobert #if defined(_WIN32)
85*f6aab3d8Srobert #include <fcntl.h>
86*f6aab3d8Srobert #include <io.h>
87*f6aab3d8Srobert #else
88*f6aab3d8Srobert #include <unistd.h>
89*f6aab3d8Srobert #endif
90*f6aab3d8Srobert
91061da546Spatrick namespace lldb_private {
92061da546Spatrick class Address;
93061da546Spatrick }
94061da546Spatrick
95061da546Spatrick using namespace lldb;
96061da546Spatrick using namespace lldb_private;
97061da546Spatrick
98061da546Spatrick static lldb::user_id_t g_unique_id = 1;
99061da546Spatrick static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
100061da546Spatrick
101061da546Spatrick #pragma mark Static Functions
102061da546Spatrick
103061da546Spatrick typedef std::vector<DebuggerSP> DebuggerList;
104061da546Spatrick static std::recursive_mutex *g_debugger_list_mutex_ptr =
105061da546Spatrick nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
106061da546Spatrick static DebuggerList *g_debugger_list_ptr =
107061da546Spatrick nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
108*f6aab3d8Srobert static llvm::ThreadPool *g_thread_pool = nullptr;
109061da546Spatrick
110061da546Spatrick static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {
111061da546Spatrick {
112061da546Spatrick Debugger::eStopDisassemblyTypeNever,
113061da546Spatrick "never",
114061da546Spatrick "Never show disassembly when displaying a stop context.",
115061da546Spatrick },
116061da546Spatrick {
117061da546Spatrick Debugger::eStopDisassemblyTypeNoDebugInfo,
118061da546Spatrick "no-debuginfo",
119061da546Spatrick "Show disassembly when there is no debug information.",
120061da546Spatrick },
121061da546Spatrick {
122061da546Spatrick Debugger::eStopDisassemblyTypeNoSource,
123061da546Spatrick "no-source",
124061da546Spatrick "Show disassembly when there is no source information, or the source "
125061da546Spatrick "file "
126061da546Spatrick "is missing when displaying a stop context.",
127061da546Spatrick },
128061da546Spatrick {
129061da546Spatrick Debugger::eStopDisassemblyTypeAlways,
130061da546Spatrick "always",
131061da546Spatrick "Always show disassembly when displaying a stop context.",
132061da546Spatrick },
133061da546Spatrick };
134061da546Spatrick
135061da546Spatrick static constexpr OptionEnumValueElement g_language_enumerators[] = {
136061da546Spatrick {
137061da546Spatrick eScriptLanguageNone,
138061da546Spatrick "none",
139061da546Spatrick "Disable scripting languages.",
140061da546Spatrick },
141061da546Spatrick {
142061da546Spatrick eScriptLanguagePython,
143061da546Spatrick "python",
144061da546Spatrick "Select python as the default scripting language.",
145061da546Spatrick },
146061da546Spatrick {
147061da546Spatrick eScriptLanguageDefault,
148061da546Spatrick "default",
149061da546Spatrick "Select the lldb default as the default scripting language.",
150061da546Spatrick },
151061da546Spatrick };
152061da546Spatrick
153*f6aab3d8Srobert static constexpr OptionEnumValueElement g_dwim_print_verbosities[] = {
154*f6aab3d8Srobert {eDWIMPrintVerbosityNone, "none",
155*f6aab3d8Srobert "Use no verbosity when running dwim-print."},
156*f6aab3d8Srobert {eDWIMPrintVerbosityExpression, "expression",
157*f6aab3d8Srobert "Use partial verbosity when running dwim-print - display a message when "
158*f6aab3d8Srobert "`expression` evaluation is used."},
159*f6aab3d8Srobert {eDWIMPrintVerbosityFull, "full",
160*f6aab3d8Srobert "Use full verbosity when running dwim-print."},
161*f6aab3d8Srobert };
162*f6aab3d8Srobert
163061da546Spatrick static constexpr OptionEnumValueElement s_stop_show_column_values[] = {
164061da546Spatrick {
165061da546Spatrick eStopShowColumnAnsiOrCaret,
166061da546Spatrick "ansi-or-caret",
167061da546Spatrick "Highlight the stop column with ANSI terminal codes when color/ANSI "
168061da546Spatrick "mode is enabled; otherwise, fall back to using a text-only caret (^) "
169061da546Spatrick "as if \"caret-only\" mode was selected.",
170061da546Spatrick },
171061da546Spatrick {
172061da546Spatrick eStopShowColumnAnsi,
173061da546Spatrick "ansi",
174061da546Spatrick "Highlight the stop column with ANSI terminal codes when running LLDB "
175061da546Spatrick "with color/ANSI enabled.",
176061da546Spatrick },
177061da546Spatrick {
178061da546Spatrick eStopShowColumnCaret,
179061da546Spatrick "caret",
180061da546Spatrick "Highlight the stop column with a caret character (^) underneath the "
181061da546Spatrick "stop column. This method introduces a new line in source listings "
182061da546Spatrick "that display thread stop locations.",
183061da546Spatrick },
184061da546Spatrick {
185061da546Spatrick eStopShowColumnNone,
186061da546Spatrick "none",
187061da546Spatrick "Do not highlight the stop column.",
188061da546Spatrick },
189061da546Spatrick };
190061da546Spatrick
191061da546Spatrick #define LLDB_PROPERTIES_debugger
192061da546Spatrick #include "CoreProperties.inc"
193061da546Spatrick
194061da546Spatrick enum {
195061da546Spatrick #define LLDB_PROPERTIES_debugger
196061da546Spatrick #include "CorePropertiesEnum.inc"
197061da546Spatrick };
198061da546Spatrick
199061da546Spatrick LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;
200061da546Spatrick
SetPropertyValue(const ExecutionContext * exe_ctx,VarSetOperationType op,llvm::StringRef property_path,llvm::StringRef value)201061da546Spatrick Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
202061da546Spatrick VarSetOperationType op,
203061da546Spatrick llvm::StringRef property_path,
204061da546Spatrick llvm::StringRef value) {
205061da546Spatrick bool is_load_script =
206061da546Spatrick (property_path == "target.load-script-from-symbol-file");
207061da546Spatrick // These properties might change how we visualize data.
208061da546Spatrick bool invalidate_data_vis = (property_path == "escape-non-printables");
209061da546Spatrick invalidate_data_vis |=
210061da546Spatrick (property_path == "target.max-zero-padding-in-float-format");
211061da546Spatrick if (invalidate_data_vis) {
212061da546Spatrick DataVisualization::ForceUpdate();
213061da546Spatrick }
214061da546Spatrick
215061da546Spatrick TargetSP target_sp;
216*f6aab3d8Srobert LoadScriptFromSymFile load_script_old_value = eLoadScriptFromSymFileFalse;
217061da546Spatrick if (is_load_script && exe_ctx->GetTargetSP()) {
218061da546Spatrick target_sp = exe_ctx->GetTargetSP();
219061da546Spatrick load_script_old_value =
220061da546Spatrick target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
221061da546Spatrick }
222061da546Spatrick Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));
223061da546Spatrick if (error.Success()) {
224061da546Spatrick // FIXME it would be nice to have "on-change" callbacks for properties
225061da546Spatrick if (property_path == g_debugger_properties[ePropertyPrompt].name) {
226061da546Spatrick llvm::StringRef new_prompt = GetPrompt();
227061da546Spatrick std::string str = lldb_private::ansi::FormatAnsiTerminalCodes(
228061da546Spatrick new_prompt, GetUseColor());
229061da546Spatrick if (str.length())
230061da546Spatrick new_prompt = str;
231061da546Spatrick GetCommandInterpreter().UpdatePrompt(new_prompt);
232061da546Spatrick auto bytes = std::make_unique<EventDataBytes>(new_prompt);
233061da546Spatrick auto prompt_change_event_sp = std::make_shared<Event>(
234061da546Spatrick CommandInterpreter::eBroadcastBitResetPrompt, bytes.release());
235061da546Spatrick GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp);
236061da546Spatrick } else if (property_path == g_debugger_properties[ePropertyUseColor].name) {
237061da546Spatrick // use-color changed. Ping the prompt so it can reset the ansi terminal
238061da546Spatrick // codes.
239061da546Spatrick SetPrompt(GetPrompt());
240dda28197Spatrick } else if (property_path == g_debugger_properties[ePropertyUseSourceCache].name) {
241dda28197Spatrick // use-source-cache changed. Wipe out the cache contents if it was disabled.
242dda28197Spatrick if (!GetUseSourceCache()) {
243dda28197Spatrick m_source_file_cache.Clear();
244dda28197Spatrick }
245061da546Spatrick } else if (is_load_script && target_sp &&
246061da546Spatrick load_script_old_value == eLoadScriptFromSymFileWarn) {
247061da546Spatrick if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==
248061da546Spatrick eLoadScriptFromSymFileTrue) {
249061da546Spatrick std::list<Status> errors;
250061da546Spatrick StreamString feedback_stream;
251061da546Spatrick if (!target_sp->LoadScriptingResources(errors, &feedback_stream)) {
252061da546Spatrick Stream &s = GetErrorStream();
253061da546Spatrick for (auto error : errors) {
254061da546Spatrick s.Printf("%s\n", error.AsCString());
255061da546Spatrick }
256061da546Spatrick if (feedback_stream.GetSize())
257061da546Spatrick s.PutCString(feedback_stream.GetString());
258061da546Spatrick }
259061da546Spatrick }
260061da546Spatrick }
261061da546Spatrick }
262061da546Spatrick return error;
263061da546Spatrick }
264061da546Spatrick
GetAutoConfirm() const265061da546Spatrick bool Debugger::GetAutoConfirm() const {
266061da546Spatrick const uint32_t idx = ePropertyAutoConfirm;
267061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
268061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
269061da546Spatrick }
270061da546Spatrick
GetDisassemblyFormat() const271061da546Spatrick const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const {
272061da546Spatrick const uint32_t idx = ePropertyDisassemblyFormat;
273061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
274061da546Spatrick }
275061da546Spatrick
GetFrameFormat() const276061da546Spatrick const FormatEntity::Entry *Debugger::GetFrameFormat() const {
277061da546Spatrick const uint32_t idx = ePropertyFrameFormat;
278061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
279061da546Spatrick }
280061da546Spatrick
GetFrameFormatUnique() const281061da546Spatrick const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const {
282061da546Spatrick const uint32_t idx = ePropertyFrameFormatUnique;
283061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
284061da546Spatrick }
285061da546Spatrick
GetStopDisassemblyMaxSize() const286be691f3bSpatrick uint32_t Debugger::GetStopDisassemblyMaxSize() const {
287be691f3bSpatrick const uint32_t idx = ePropertyStopDisassemblyMaxSize;
288be691f3bSpatrick return m_collection_sp->GetPropertyAtIndexAsUInt64(
289be691f3bSpatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
290be691f3bSpatrick }
291be691f3bSpatrick
GetNotifyVoid() const292061da546Spatrick bool Debugger::GetNotifyVoid() const {
293061da546Spatrick const uint32_t idx = ePropertyNotiftVoid;
294061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
295061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
296061da546Spatrick }
297061da546Spatrick
GetPrompt() const298061da546Spatrick llvm::StringRef Debugger::GetPrompt() const {
299061da546Spatrick const uint32_t idx = ePropertyPrompt;
300061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsString(
301061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_cstr_value);
302061da546Spatrick }
303061da546Spatrick
SetPrompt(llvm::StringRef p)304061da546Spatrick void Debugger::SetPrompt(llvm::StringRef p) {
305061da546Spatrick const uint32_t idx = ePropertyPrompt;
306061da546Spatrick m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p);
307061da546Spatrick llvm::StringRef new_prompt = GetPrompt();
308061da546Spatrick std::string str =
309061da546Spatrick lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor());
310061da546Spatrick if (str.length())
311061da546Spatrick new_prompt = str;
312061da546Spatrick GetCommandInterpreter().UpdatePrompt(new_prompt);
313061da546Spatrick }
314061da546Spatrick
GetThreadFormat() const315061da546Spatrick const FormatEntity::Entry *Debugger::GetThreadFormat() const {
316061da546Spatrick const uint32_t idx = ePropertyThreadFormat;
317061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
318061da546Spatrick }
319061da546Spatrick
GetThreadStopFormat() const320061da546Spatrick const FormatEntity::Entry *Debugger::GetThreadStopFormat() const {
321061da546Spatrick const uint32_t idx = ePropertyThreadStopFormat;
322061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
323061da546Spatrick }
324061da546Spatrick
GetScriptLanguage() const325061da546Spatrick lldb::ScriptLanguage Debugger::GetScriptLanguage() const {
326061da546Spatrick const uint32_t idx = ePropertyScriptLanguage;
327061da546Spatrick return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration(
328061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
329061da546Spatrick }
330061da546Spatrick
SetScriptLanguage(lldb::ScriptLanguage script_lang)331061da546Spatrick bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) {
332061da546Spatrick const uint32_t idx = ePropertyScriptLanguage;
333061da546Spatrick return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx,
334061da546Spatrick script_lang);
335061da546Spatrick }
336061da546Spatrick
GetREPLLanguage() const337*f6aab3d8Srobert lldb::LanguageType Debugger::GetREPLLanguage() const {
338*f6aab3d8Srobert const uint32_t idx = ePropertyREPLLanguage;
339*f6aab3d8Srobert OptionValueLanguage *value =
340*f6aab3d8Srobert m_collection_sp->GetPropertyAtIndexAsOptionValueLanguage(nullptr, idx);
341*f6aab3d8Srobert if (value)
342*f6aab3d8Srobert return value->GetCurrentValue();
343*f6aab3d8Srobert return LanguageType();
344*f6aab3d8Srobert }
345*f6aab3d8Srobert
SetREPLLanguage(lldb::LanguageType repl_lang)346*f6aab3d8Srobert bool Debugger::SetREPLLanguage(lldb::LanguageType repl_lang) {
347*f6aab3d8Srobert const uint32_t idx = ePropertyREPLLanguage;
348*f6aab3d8Srobert return m_collection_sp->SetPropertyAtIndexAsLanguage(nullptr, idx, repl_lang);
349*f6aab3d8Srobert }
350*f6aab3d8Srobert
GetTerminalWidth() const351061da546Spatrick uint32_t Debugger::GetTerminalWidth() const {
352061da546Spatrick const uint32_t idx = ePropertyTerminalWidth;
353061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsSInt64(
354061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
355061da546Spatrick }
356061da546Spatrick
SetTerminalWidth(uint32_t term_width)357061da546Spatrick bool Debugger::SetTerminalWidth(uint32_t term_width) {
358dda28197Spatrick if (auto handler_sp = m_io_handler_stack.Top())
359dda28197Spatrick handler_sp->TerminalSizeChanged();
360dda28197Spatrick
361061da546Spatrick const uint32_t idx = ePropertyTerminalWidth;
362061da546Spatrick return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width);
363061da546Spatrick }
364061da546Spatrick
GetUseExternalEditor() const365061da546Spatrick bool Debugger::GetUseExternalEditor() const {
366061da546Spatrick const uint32_t idx = ePropertyUseExternalEditor;
367061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
368061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
369061da546Spatrick }
370061da546Spatrick
SetUseExternalEditor(bool b)371061da546Spatrick bool Debugger::SetUseExternalEditor(bool b) {
372061da546Spatrick const uint32_t idx = ePropertyUseExternalEditor;
373061da546Spatrick return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
374061da546Spatrick }
375061da546Spatrick
GetUseColor() const376061da546Spatrick bool Debugger::GetUseColor() const {
377061da546Spatrick const uint32_t idx = ePropertyUseColor;
378061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
379061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
380061da546Spatrick }
381061da546Spatrick
SetUseColor(bool b)382061da546Spatrick bool Debugger::SetUseColor(bool b) {
383061da546Spatrick const uint32_t idx = ePropertyUseColor;
384061da546Spatrick bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
385061da546Spatrick SetPrompt(GetPrompt());
386061da546Spatrick return ret;
387061da546Spatrick }
388061da546Spatrick
GetShowProgress() const389*f6aab3d8Srobert bool Debugger::GetShowProgress() const {
390*f6aab3d8Srobert const uint32_t idx = ePropertyShowProgress;
391*f6aab3d8Srobert return m_collection_sp->GetPropertyAtIndexAsBoolean(
392*f6aab3d8Srobert nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
393*f6aab3d8Srobert }
394*f6aab3d8Srobert
SetShowProgress(bool show_progress)395*f6aab3d8Srobert bool Debugger::SetShowProgress(bool show_progress) {
396*f6aab3d8Srobert const uint32_t idx = ePropertyShowProgress;
397*f6aab3d8Srobert return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx,
398*f6aab3d8Srobert show_progress);
399*f6aab3d8Srobert }
400*f6aab3d8Srobert
GetShowProgressAnsiPrefix() const401*f6aab3d8Srobert llvm::StringRef Debugger::GetShowProgressAnsiPrefix() const {
402*f6aab3d8Srobert const uint32_t idx = ePropertyShowProgressAnsiPrefix;
403*f6aab3d8Srobert return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
404*f6aab3d8Srobert }
405*f6aab3d8Srobert
GetShowProgressAnsiSuffix() const406*f6aab3d8Srobert llvm::StringRef Debugger::GetShowProgressAnsiSuffix() const {
407*f6aab3d8Srobert const uint32_t idx = ePropertyShowProgressAnsiSuffix;
408*f6aab3d8Srobert return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
409*f6aab3d8Srobert }
410*f6aab3d8Srobert
GetUseAutosuggestion() const411be691f3bSpatrick bool Debugger::GetUseAutosuggestion() const {
412be691f3bSpatrick const uint32_t idx = ePropertyShowAutosuggestion;
413be691f3bSpatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
414be691f3bSpatrick nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
415be691f3bSpatrick }
416be691f3bSpatrick
GetAutosuggestionAnsiPrefix() const417*f6aab3d8Srobert llvm::StringRef Debugger::GetAutosuggestionAnsiPrefix() const {
418*f6aab3d8Srobert const uint32_t idx = ePropertyShowAutosuggestionAnsiPrefix;
419*f6aab3d8Srobert return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
420*f6aab3d8Srobert }
421*f6aab3d8Srobert
GetAutosuggestionAnsiSuffix() const422*f6aab3d8Srobert llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
423*f6aab3d8Srobert const uint32_t idx = ePropertyShowAutosuggestionAnsiSuffix;
424*f6aab3d8Srobert return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
425*f6aab3d8Srobert }
426*f6aab3d8Srobert
GetUseSourceCache() const427dda28197Spatrick bool Debugger::GetUseSourceCache() const {
428dda28197Spatrick const uint32_t idx = ePropertyUseSourceCache;
429dda28197Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
430dda28197Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
431dda28197Spatrick }
432dda28197Spatrick
SetUseSourceCache(bool b)433dda28197Spatrick bool Debugger::SetUseSourceCache(bool b) {
434dda28197Spatrick const uint32_t idx = ePropertyUseSourceCache;
435dda28197Spatrick bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
436dda28197Spatrick if (!ret) {
437dda28197Spatrick m_source_file_cache.Clear();
438dda28197Spatrick }
439dda28197Spatrick return ret;
440dda28197Spatrick }
GetHighlightSource() const441061da546Spatrick bool Debugger::GetHighlightSource() const {
442061da546Spatrick const uint32_t idx = ePropertyHighlightSource;
443061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(
444061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
445061da546Spatrick }
446061da546Spatrick
GetStopShowColumn() const447061da546Spatrick StopShowColumn Debugger::GetStopShowColumn() const {
448061da546Spatrick const uint32_t idx = ePropertyStopShowColumn;
449061da546Spatrick return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration(
450061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
451061da546Spatrick }
452061da546Spatrick
GetStopShowColumnAnsiPrefix() const453061da546Spatrick llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const {
454061da546Spatrick const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;
455061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
456061da546Spatrick }
457061da546Spatrick
GetStopShowColumnAnsiSuffix() const458061da546Spatrick llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const {
459061da546Spatrick const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;
460061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
461061da546Spatrick }
462061da546Spatrick
GetStopShowLineMarkerAnsiPrefix() const463dda28197Spatrick llvm::StringRef Debugger::GetStopShowLineMarkerAnsiPrefix() const {
464dda28197Spatrick const uint32_t idx = ePropertyStopShowLineMarkerAnsiPrefix;
465dda28197Spatrick return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
466dda28197Spatrick }
467dda28197Spatrick
GetStopShowLineMarkerAnsiSuffix() const468dda28197Spatrick llvm::StringRef Debugger::GetStopShowLineMarkerAnsiSuffix() const {
469dda28197Spatrick const uint32_t idx = ePropertyStopShowLineMarkerAnsiSuffix;
470dda28197Spatrick return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
471dda28197Spatrick }
472dda28197Spatrick
GetStopSourceLineCount(bool before) const473061da546Spatrick uint32_t Debugger::GetStopSourceLineCount(bool before) const {
474061da546Spatrick const uint32_t idx =
475061da546Spatrick before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
476061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsSInt64(
477061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
478061da546Spatrick }
479061da546Spatrick
GetStopDisassemblyDisplay() const480061da546Spatrick Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const {
481061da546Spatrick const uint32_t idx = ePropertyStopDisassemblyDisplay;
482061da546Spatrick return (Debugger::StopDisassemblyType)
483061da546Spatrick m_collection_sp->GetPropertyAtIndexAsEnumeration(
484061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
485061da546Spatrick }
486061da546Spatrick
GetDisassemblyLineCount() const487061da546Spatrick uint32_t Debugger::GetDisassemblyLineCount() const {
488061da546Spatrick const uint32_t idx = ePropertyStopDisassemblyCount;
489061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsSInt64(
490061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
491061da546Spatrick }
492061da546Spatrick
GetAutoOneLineSummaries() const493061da546Spatrick bool Debugger::GetAutoOneLineSummaries() const {
494061da546Spatrick const uint32_t idx = ePropertyAutoOneLineSummaries;
495061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
496061da546Spatrick }
497061da546Spatrick
GetEscapeNonPrintables() const498061da546Spatrick bool Debugger::GetEscapeNonPrintables() const {
499061da546Spatrick const uint32_t idx = ePropertyEscapeNonPrintables;
500061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
501061da546Spatrick }
502061da546Spatrick
GetAutoIndent() const503061da546Spatrick bool Debugger::GetAutoIndent() const {
504061da546Spatrick const uint32_t idx = ePropertyAutoIndent;
505061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
506061da546Spatrick }
507061da546Spatrick
SetAutoIndent(bool b)508061da546Spatrick bool Debugger::SetAutoIndent(bool b) {
509061da546Spatrick const uint32_t idx = ePropertyAutoIndent;
510061da546Spatrick return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
511061da546Spatrick }
512061da546Spatrick
GetPrintDecls() const513061da546Spatrick bool Debugger::GetPrintDecls() const {
514061da546Spatrick const uint32_t idx = ePropertyPrintDecls;
515061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
516061da546Spatrick }
517061da546Spatrick
SetPrintDecls(bool b)518061da546Spatrick bool Debugger::SetPrintDecls(bool b) {
519061da546Spatrick const uint32_t idx = ePropertyPrintDecls;
520061da546Spatrick return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
521061da546Spatrick }
522061da546Spatrick
GetTabSize() const523061da546Spatrick uint32_t Debugger::GetTabSize() const {
524061da546Spatrick const uint32_t idx = ePropertyTabSize;
525061da546Spatrick return m_collection_sp->GetPropertyAtIndexAsUInt64(
526061da546Spatrick nullptr, idx, g_debugger_properties[idx].default_uint_value);
527061da546Spatrick }
528061da546Spatrick
SetTabSize(uint32_t tab_size)529061da546Spatrick bool Debugger::SetTabSize(uint32_t tab_size) {
530061da546Spatrick const uint32_t idx = ePropertyTabSize;
531061da546Spatrick return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size);
532061da546Spatrick }
533061da546Spatrick
GetDWIMPrintVerbosity() const534*f6aab3d8Srobert lldb::DWIMPrintVerbosity Debugger::GetDWIMPrintVerbosity() const {
535*f6aab3d8Srobert const uint32_t idx = ePropertyDWIMPrintVerbosity;
536*f6aab3d8Srobert return (lldb::DWIMPrintVerbosity)
537*f6aab3d8Srobert m_collection_sp->GetPropertyAtIndexAsEnumeration(
538*f6aab3d8Srobert nullptr, idx, g_debugger_properties[idx].default_uint_value);
539*f6aab3d8Srobert }
540*f6aab3d8Srobert
541061da546Spatrick #pragma mark Debugger
542061da546Spatrick
543061da546Spatrick // const DebuggerPropertiesSP &
544061da546Spatrick // Debugger::GetSettings() const
545061da546Spatrick //{
546061da546Spatrick // return m_properties_sp;
547061da546Spatrick //}
548061da546Spatrick //
549061da546Spatrick
Initialize(LoadPluginCallbackType load_plugin_callback)550061da546Spatrick void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) {
551061da546Spatrick assert(g_debugger_list_ptr == nullptr &&
552061da546Spatrick "Debugger::Initialize called more than once!");
553061da546Spatrick g_debugger_list_mutex_ptr = new std::recursive_mutex();
554061da546Spatrick g_debugger_list_ptr = new DebuggerList();
555*f6aab3d8Srobert g_thread_pool = new llvm::ThreadPool(llvm::optimal_concurrency());
556061da546Spatrick g_load_plugin_callback = load_plugin_callback;
557061da546Spatrick }
558061da546Spatrick
Terminate()559061da546Spatrick void Debugger::Terminate() {
560061da546Spatrick assert(g_debugger_list_ptr &&
561061da546Spatrick "Debugger::Terminate called without a matching Debugger::Initialize!");
562061da546Spatrick
563*f6aab3d8Srobert if (g_thread_pool) {
564*f6aab3d8Srobert // The destructor will wait for all the threads to complete.
565*f6aab3d8Srobert delete g_thread_pool;
566*f6aab3d8Srobert }
567*f6aab3d8Srobert
568061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
569*f6aab3d8Srobert // Clear our global list of debugger objects
570061da546Spatrick {
571061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
572061da546Spatrick for (const auto &debugger : *g_debugger_list_ptr)
573061da546Spatrick debugger->Clear();
574061da546Spatrick g_debugger_list_ptr->clear();
575061da546Spatrick }
576061da546Spatrick }
577061da546Spatrick }
578061da546Spatrick
SettingsInitialize()579061da546Spatrick void Debugger::SettingsInitialize() { Target::SettingsInitialize(); }
580061da546Spatrick
SettingsTerminate()581061da546Spatrick void Debugger::SettingsTerminate() { Target::SettingsTerminate(); }
582061da546Spatrick
LoadPlugin(const FileSpec & spec,Status & error)583061da546Spatrick bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) {
584061da546Spatrick if (g_load_plugin_callback) {
585061da546Spatrick llvm::sys::DynamicLibrary dynlib =
586061da546Spatrick g_load_plugin_callback(shared_from_this(), spec, error);
587061da546Spatrick if (dynlib.isValid()) {
588061da546Spatrick m_loaded_plugins.push_back(dynlib);
589061da546Spatrick return true;
590061da546Spatrick }
591061da546Spatrick } else {
592061da546Spatrick // The g_load_plugin_callback is registered in SBDebugger::Initialize() and
593061da546Spatrick // if the public API layer isn't available (code is linking against all of
594061da546Spatrick // the internal LLDB static libraries), then we can't load plugins
595061da546Spatrick error.SetErrorString("Public API layer is not available");
596061da546Spatrick }
597061da546Spatrick return false;
598061da546Spatrick }
599061da546Spatrick
600061da546Spatrick static FileSystem::EnumerateDirectoryResult
LoadPluginCallback(void * baton,llvm::sys::fs::file_type ft,llvm::StringRef path)601061da546Spatrick LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,
602061da546Spatrick llvm::StringRef path) {
603061da546Spatrick Status error;
604061da546Spatrick
605061da546Spatrick static ConstString g_dylibext(".dylib");
606061da546Spatrick static ConstString g_solibext(".so");
607061da546Spatrick
608061da546Spatrick if (!baton)
609061da546Spatrick return FileSystem::eEnumerateDirectoryResultQuit;
610061da546Spatrick
611061da546Spatrick Debugger *debugger = (Debugger *)baton;
612061da546Spatrick
613061da546Spatrick namespace fs = llvm::sys::fs;
614061da546Spatrick // If we have a regular file, a symbolic link or unknown file type, try and
615061da546Spatrick // process the file. We must handle unknown as sometimes the directory
616061da546Spatrick // enumeration might be enumerating a file system that doesn't have correct
617061da546Spatrick // file type information.
618061da546Spatrick if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||
619061da546Spatrick ft == fs::file_type::type_unknown) {
620061da546Spatrick FileSpec plugin_file_spec(path);
621061da546Spatrick FileSystem::Instance().Resolve(plugin_file_spec);
622061da546Spatrick
623061da546Spatrick if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&
624061da546Spatrick plugin_file_spec.GetFileNameExtension() != g_solibext) {
625061da546Spatrick return FileSystem::eEnumerateDirectoryResultNext;
626061da546Spatrick }
627061da546Spatrick
628061da546Spatrick Status plugin_load_error;
629061da546Spatrick debugger->LoadPlugin(plugin_file_spec, plugin_load_error);
630061da546Spatrick
631061da546Spatrick return FileSystem::eEnumerateDirectoryResultNext;
632061da546Spatrick } else if (ft == fs::file_type::directory_file ||
633061da546Spatrick ft == fs::file_type::symlink_file ||
634061da546Spatrick ft == fs::file_type::type_unknown) {
635061da546Spatrick // Try and recurse into anything that a directory or symbolic link. We must
636061da546Spatrick // also do this for unknown as sometimes the directory enumeration might be
637061da546Spatrick // enumerating a file system that doesn't have correct file type
638061da546Spatrick // information.
639061da546Spatrick return FileSystem::eEnumerateDirectoryResultEnter;
640061da546Spatrick }
641061da546Spatrick
642061da546Spatrick return FileSystem::eEnumerateDirectoryResultNext;
643061da546Spatrick }
644061da546Spatrick
InstanceInitialize()645061da546Spatrick void Debugger::InstanceInitialize() {
646061da546Spatrick const bool find_directories = true;
647061da546Spatrick const bool find_files = true;
648061da546Spatrick const bool find_other = true;
649061da546Spatrick char dir_path[PATH_MAX];
650061da546Spatrick if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) {
651061da546Spatrick if (FileSystem::Instance().Exists(dir_spec) &&
652061da546Spatrick dir_spec.GetPath(dir_path, sizeof(dir_path))) {
653061da546Spatrick FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
654061da546Spatrick find_files, find_other,
655061da546Spatrick LoadPluginCallback, this);
656061da546Spatrick }
657061da546Spatrick }
658061da546Spatrick
659061da546Spatrick if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) {
660061da546Spatrick if (FileSystem::Instance().Exists(dir_spec) &&
661061da546Spatrick dir_spec.GetPath(dir_path, sizeof(dir_path))) {
662061da546Spatrick FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
663061da546Spatrick find_files, find_other,
664061da546Spatrick LoadPluginCallback, this);
665061da546Spatrick }
666061da546Spatrick }
667061da546Spatrick
668061da546Spatrick PluginManager::DebuggerInitialize(*this);
669061da546Spatrick }
670061da546Spatrick
CreateInstance(lldb::LogOutputCallback log_callback,void * baton)671061da546Spatrick DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback,
672061da546Spatrick void *baton) {
673061da546Spatrick DebuggerSP debugger_sp(new Debugger(log_callback, baton));
674061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
675061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
676061da546Spatrick g_debugger_list_ptr->push_back(debugger_sp);
677061da546Spatrick }
678061da546Spatrick debugger_sp->InstanceInitialize();
679061da546Spatrick return debugger_sp;
680061da546Spatrick }
681061da546Spatrick
Destroy(DebuggerSP & debugger_sp)682061da546Spatrick void Debugger::Destroy(DebuggerSP &debugger_sp) {
683061da546Spatrick if (!debugger_sp)
684061da546Spatrick return;
685061da546Spatrick
686be691f3bSpatrick CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter();
687be691f3bSpatrick
688be691f3bSpatrick if (cmd_interpreter.GetSaveSessionOnQuit()) {
689be691f3bSpatrick CommandReturnObject result(debugger_sp->GetUseColor());
690be691f3bSpatrick cmd_interpreter.SaveTranscript(result);
691be691f3bSpatrick if (result.Succeeded())
692*f6aab3d8Srobert (*debugger_sp->GetAsyncOutputStream()) << result.GetOutputData() << '\n';
693be691f3bSpatrick else
694*f6aab3d8Srobert (*debugger_sp->GetAsyncErrorStream()) << result.GetErrorData() << '\n';
695be691f3bSpatrick }
696be691f3bSpatrick
697061da546Spatrick debugger_sp->Clear();
698061da546Spatrick
699061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
700061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
701061da546Spatrick DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
702061da546Spatrick for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
703061da546Spatrick if ((*pos).get() == debugger_sp.get()) {
704061da546Spatrick g_debugger_list_ptr->erase(pos);
705061da546Spatrick return;
706061da546Spatrick }
707061da546Spatrick }
708061da546Spatrick }
709061da546Spatrick }
710061da546Spatrick
FindDebuggerWithInstanceName(ConstString instance_name)711061da546Spatrick DebuggerSP Debugger::FindDebuggerWithInstanceName(ConstString instance_name) {
712061da546Spatrick DebuggerSP debugger_sp;
713061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
714061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
715061da546Spatrick DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
716061da546Spatrick for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
717061da546Spatrick if ((*pos)->m_instance_name == instance_name) {
718061da546Spatrick debugger_sp = *pos;
719061da546Spatrick break;
720061da546Spatrick }
721061da546Spatrick }
722061da546Spatrick }
723061da546Spatrick return debugger_sp;
724061da546Spatrick }
725061da546Spatrick
FindTargetWithProcessID(lldb::pid_t pid)726061da546Spatrick TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) {
727061da546Spatrick TargetSP target_sp;
728061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
729061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
730061da546Spatrick DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
731061da546Spatrick for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
732061da546Spatrick target_sp = (*pos)->GetTargetList().FindTargetWithProcessID(pid);
733061da546Spatrick if (target_sp)
734061da546Spatrick break;
735061da546Spatrick }
736061da546Spatrick }
737061da546Spatrick return target_sp;
738061da546Spatrick }
739061da546Spatrick
FindTargetWithProcess(Process * process)740061da546Spatrick TargetSP Debugger::FindTargetWithProcess(Process *process) {
741061da546Spatrick TargetSP target_sp;
742061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
743061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
744061da546Spatrick DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
745061da546Spatrick for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
746061da546Spatrick target_sp = (*pos)->GetTargetList().FindTargetWithProcess(process);
747061da546Spatrick if (target_sp)
748061da546Spatrick break;
749061da546Spatrick }
750061da546Spatrick }
751061da546Spatrick return target_sp;
752061da546Spatrick }
753061da546Spatrick
GetStaticBroadcasterClass()754be691f3bSpatrick ConstString Debugger::GetStaticBroadcasterClass() {
755be691f3bSpatrick static ConstString class_name("lldb.debugger");
756be691f3bSpatrick return class_name;
757be691f3bSpatrick }
758be691f3bSpatrick
Debugger(lldb::LogOutputCallback log_callback,void * baton)759061da546Spatrick Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
760061da546Spatrick : UserID(g_unique_id++),
761061da546Spatrick Properties(std::make_shared<OptionValueProperties>()),
762061da546Spatrick m_input_file_sp(std::make_shared<NativeFile>(stdin, false)),
763061da546Spatrick m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)),
764061da546Spatrick m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)),
765061da546Spatrick m_input_recorder(nullptr),
766061da546Spatrick m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),
767061da546Spatrick m_terminal_state(), m_target_list(*this), m_platform_list(),
768061da546Spatrick m_listener_sp(Listener::MakeListener("lldb.Debugger")),
769061da546Spatrick m_source_manager_up(), m_source_file_cache(),
770061da546Spatrick m_command_interpreter_up(
771061da546Spatrick std::make_unique<CommandInterpreter>(*this, false)),
772dda28197Spatrick m_io_handler_stack(), m_instance_name(), m_loaded_plugins(),
773061da546Spatrick m_event_handler_thread(), m_io_handler_thread(),
774061da546Spatrick m_sync_broadcaster(nullptr, "lldb.debugger.sync"),
775be691f3bSpatrick m_broadcaster(m_broadcaster_manager_sp,
776be691f3bSpatrick GetStaticBroadcasterClass().AsCString()),
777061da546Spatrick m_forward_listener_sp(), m_clear_once() {
778be691f3bSpatrick m_instance_name.SetString(llvm::formatv("debugger_{0}", GetID()).str());
779061da546Spatrick if (log_callback)
780*f6aab3d8Srobert m_callback_handler_sp =
781*f6aab3d8Srobert std::make_shared<CallbackLogHandler>(log_callback, baton);
782061da546Spatrick m_command_interpreter_up->Initialize();
783061da546Spatrick // Always add our default platform to the platform list
784061da546Spatrick PlatformSP default_platform_sp(Platform::GetHostPlatform());
785061da546Spatrick assert(default_platform_sp);
786061da546Spatrick m_platform_list.Append(default_platform_sp, true);
787061da546Spatrick
788be691f3bSpatrick // Create the dummy target.
789be691f3bSpatrick {
790be691f3bSpatrick ArchSpec arch(Target::GetDefaultArchitecture());
791be691f3bSpatrick if (!arch.IsValid())
792be691f3bSpatrick arch = HostInfo::GetArchitecture();
793be691f3bSpatrick assert(arch.IsValid() && "No valid default or host archspec");
794be691f3bSpatrick const bool is_dummy_target = true;
795be691f3bSpatrick m_dummy_target_sp.reset(
796be691f3bSpatrick new Target(*this, arch, default_platform_sp, is_dummy_target));
797be691f3bSpatrick }
798061da546Spatrick assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?");
799061da546Spatrick
800061da546Spatrick m_collection_sp->Initialize(g_debugger_properties);
801061da546Spatrick m_collection_sp->AppendProperty(
802061da546Spatrick ConstString("target"),
803061da546Spatrick ConstString("Settings specify to debugging targets."), true,
804*f6aab3d8Srobert Target::GetGlobalProperties().GetValueProperties());
805061da546Spatrick m_collection_sp->AppendProperty(
806061da546Spatrick ConstString("platform"), ConstString("Platform settings."), true,
807*f6aab3d8Srobert Platform::GetGlobalPlatformProperties().GetValueProperties());
808061da546Spatrick m_collection_sp->AppendProperty(
809061da546Spatrick ConstString("symbols"), ConstString("Symbol lookup and cache settings."),
810061da546Spatrick true, ModuleList::GetGlobalModuleListProperties().GetValueProperties());
811061da546Spatrick if (m_command_interpreter_up) {
812061da546Spatrick m_collection_sp->AppendProperty(
813061da546Spatrick ConstString("interpreter"),
814061da546Spatrick ConstString("Settings specify to the debugger's command interpreter."),
815061da546Spatrick true, m_command_interpreter_up->GetValueProperties());
816061da546Spatrick }
817061da546Spatrick OptionValueSInt64 *term_width =
818061da546Spatrick m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64(
819061da546Spatrick nullptr, ePropertyTerminalWidth);
820061da546Spatrick term_width->SetMinimumValue(10);
821061da546Spatrick term_width->SetMaximumValue(1024);
822061da546Spatrick
823061da546Spatrick // Turn off use-color if this is a dumb terminal.
824061da546Spatrick const char *term = getenv("TERM");
825061da546Spatrick if (term && !strcmp(term, "dumb"))
826061da546Spatrick SetUseColor(false);
827061da546Spatrick // Turn off use-color if we don't write to a terminal with color support.
828061da546Spatrick if (!GetOutputFile().GetIsTerminalWithColors())
829061da546Spatrick SetUseColor(false);
830061da546Spatrick
831061da546Spatrick #if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
832061da546Spatrick // Enabling use of ANSI color codes because LLDB is using them to highlight
833061da546Spatrick // text.
834061da546Spatrick llvm::sys::Process::UseANSIEscapeCodes(true);
835061da546Spatrick #endif
836061da546Spatrick }
837061da546Spatrick
~Debugger()838061da546Spatrick Debugger::~Debugger() { Clear(); }
839061da546Spatrick
Clear()840061da546Spatrick void Debugger::Clear() {
841061da546Spatrick // Make sure we call this function only once. With the C++ global destructor
842061da546Spatrick // chain having a list of debuggers and with code that can be running on
843061da546Spatrick // other threads, we need to ensure this doesn't happen multiple times.
844061da546Spatrick //
845061da546Spatrick // The following functions call Debugger::Clear():
846061da546Spatrick // Debugger::~Debugger();
847061da546Spatrick // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);
848061da546Spatrick // static void Debugger::Terminate();
849061da546Spatrick llvm::call_once(m_clear_once, [this]() {
850061da546Spatrick ClearIOHandlers();
851061da546Spatrick StopIOHandlerThread();
852061da546Spatrick StopEventHandlerThread();
853061da546Spatrick m_listener_sp->Clear();
854be691f3bSpatrick for (TargetSP target_sp : m_target_list.Targets()) {
855061da546Spatrick if (target_sp) {
856be691f3bSpatrick if (ProcessSP process_sp = target_sp->GetProcessSP())
857061da546Spatrick process_sp->Finalize();
858061da546Spatrick target_sp->Destroy();
859061da546Spatrick }
860061da546Spatrick }
861061da546Spatrick m_broadcaster_manager_sp->Clear();
862061da546Spatrick
863061da546Spatrick // Close the input file _before_ we close the input read communications
864061da546Spatrick // class as it does NOT own the input file, our m_input_file does.
865061da546Spatrick m_terminal_state.Clear();
866061da546Spatrick GetInputFile().Close();
867061da546Spatrick
868061da546Spatrick m_command_interpreter_up->Clear();
869061da546Spatrick });
870061da546Spatrick }
871061da546Spatrick
GetCloseInputOnEOF() const872061da546Spatrick bool Debugger::GetCloseInputOnEOF() const {
873061da546Spatrick // return m_input_comm.GetCloseOnEOF();
874061da546Spatrick return false;
875061da546Spatrick }
876061da546Spatrick
SetCloseInputOnEOF(bool b)877061da546Spatrick void Debugger::SetCloseInputOnEOF(bool b) {
878061da546Spatrick // m_input_comm.SetCloseOnEOF(b);
879061da546Spatrick }
880061da546Spatrick
GetAsyncExecution()881061da546Spatrick bool Debugger::GetAsyncExecution() {
882061da546Spatrick return !m_command_interpreter_up->GetSynchronous();
883061da546Spatrick }
884061da546Spatrick
SetAsyncExecution(bool async_execution)885061da546Spatrick void Debugger::SetAsyncExecution(bool async_execution) {
886061da546Spatrick m_command_interpreter_up->SetSynchronous(!async_execution);
887061da546Spatrick }
888061da546Spatrick
GetInputRecorder()889061da546Spatrick repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; }
890061da546Spatrick
OpenPipe(int fds[2],std::size_t size)891*f6aab3d8Srobert static inline int OpenPipe(int fds[2], std::size_t size) {
892*f6aab3d8Srobert #ifdef _WIN32
893*f6aab3d8Srobert return _pipe(fds, size, O_BINARY);
894*f6aab3d8Srobert #else
895*f6aab3d8Srobert (void)size;
896*f6aab3d8Srobert return pipe(fds);
897*f6aab3d8Srobert #endif
898*f6aab3d8Srobert }
899*f6aab3d8Srobert
SetInputString(const char * data)900*f6aab3d8Srobert Status Debugger::SetInputString(const char *data) {
901*f6aab3d8Srobert Status result;
902*f6aab3d8Srobert enum PIPES { READ, WRITE }; // Indexes for the read and write fds
903*f6aab3d8Srobert int fds[2] = {-1, -1};
904*f6aab3d8Srobert
905*f6aab3d8Srobert if (data == nullptr) {
906*f6aab3d8Srobert result.SetErrorString("String data is null");
907*f6aab3d8Srobert return result;
908*f6aab3d8Srobert }
909*f6aab3d8Srobert
910*f6aab3d8Srobert size_t size = strlen(data);
911*f6aab3d8Srobert if (size == 0) {
912*f6aab3d8Srobert result.SetErrorString("String data is empty");
913*f6aab3d8Srobert return result;
914*f6aab3d8Srobert }
915*f6aab3d8Srobert
916*f6aab3d8Srobert if (OpenPipe(fds, size) != 0) {
917*f6aab3d8Srobert result.SetErrorString(
918*f6aab3d8Srobert "can't create pipe file descriptors for LLDB commands");
919*f6aab3d8Srobert return result;
920*f6aab3d8Srobert }
921*f6aab3d8Srobert
922*f6aab3d8Srobert int r = write(fds[WRITE], data, size);
923*f6aab3d8Srobert (void)r;
924*f6aab3d8Srobert // Close the write end of the pipe, so that the command interpreter will exit
925*f6aab3d8Srobert // when it consumes all the data.
926*f6aab3d8Srobert llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
927*f6aab3d8Srobert
928*f6aab3d8Srobert // Open the read file descriptor as a FILE * that we can return as an input
929*f6aab3d8Srobert // handle.
930*f6aab3d8Srobert FILE *commands_file = fdopen(fds[READ], "rb");
931*f6aab3d8Srobert if (commands_file == nullptr) {
932*f6aab3d8Srobert result.SetErrorStringWithFormat("fdopen(%i, \"rb\") failed (errno = %i) "
933*f6aab3d8Srobert "when trying to open LLDB commands pipe",
934*f6aab3d8Srobert fds[READ], errno);
935*f6aab3d8Srobert llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
936*f6aab3d8Srobert return result;
937*f6aab3d8Srobert }
938*f6aab3d8Srobert
939*f6aab3d8Srobert SetInputFile((FileSP)std::make_shared<NativeFile>(commands_file, true));
940*f6aab3d8Srobert return result;
941*f6aab3d8Srobert }
942*f6aab3d8Srobert
SetInputFile(FileSP file_sp)943*f6aab3d8Srobert void Debugger::SetInputFile(FileSP file_sp) {
944061da546Spatrick assert(file_sp && file_sp->IsValid());
945be691f3bSpatrick m_input_file_sp = std::move(file_sp);
946061da546Spatrick // Save away the terminal state if that is relevant, so that we can restore
947061da546Spatrick // it in RestoreInputState.
948061da546Spatrick SaveInputTerminalState();
949061da546Spatrick }
950061da546Spatrick
SetOutputFile(FileSP file_sp)951061da546Spatrick void Debugger::SetOutputFile(FileSP file_sp) {
952061da546Spatrick assert(file_sp && file_sp->IsValid());
953061da546Spatrick m_output_stream_sp = std::make_shared<StreamFile>(file_sp);
954061da546Spatrick }
955061da546Spatrick
SetErrorFile(FileSP file_sp)956061da546Spatrick void Debugger::SetErrorFile(FileSP file_sp) {
957061da546Spatrick assert(file_sp && file_sp->IsValid());
958061da546Spatrick m_error_stream_sp = std::make_shared<StreamFile>(file_sp);
959061da546Spatrick }
960061da546Spatrick
SaveInputTerminalState()961061da546Spatrick void Debugger::SaveInputTerminalState() {
962061da546Spatrick int fd = GetInputFile().GetDescriptor();
963061da546Spatrick if (fd != File::kInvalidDescriptor)
964061da546Spatrick m_terminal_state.Save(fd, true);
965061da546Spatrick }
966061da546Spatrick
RestoreInputTerminalState()967061da546Spatrick void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); }
968061da546Spatrick
GetSelectedExecutionContext()969061da546Spatrick ExecutionContext Debugger::GetSelectedExecutionContext() {
970be691f3bSpatrick bool adopt_selected = true;
971be691f3bSpatrick ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected);
972be691f3bSpatrick return ExecutionContext(exe_ctx_ref);
973061da546Spatrick }
974061da546Spatrick
DispatchInputInterrupt()975061da546Spatrick void Debugger::DispatchInputInterrupt() {
976dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
977dda28197Spatrick IOHandlerSP reader_sp(m_io_handler_stack.Top());
978061da546Spatrick if (reader_sp)
979061da546Spatrick reader_sp->Interrupt();
980061da546Spatrick }
981061da546Spatrick
DispatchInputEndOfFile()982061da546Spatrick void Debugger::DispatchInputEndOfFile() {
983dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
984dda28197Spatrick IOHandlerSP reader_sp(m_io_handler_stack.Top());
985061da546Spatrick if (reader_sp)
986061da546Spatrick reader_sp->GotEOF();
987061da546Spatrick }
988061da546Spatrick
ClearIOHandlers()989061da546Spatrick void Debugger::ClearIOHandlers() {
990061da546Spatrick // The bottom input reader should be the main debugger input reader. We do
991061da546Spatrick // not want to close that one here.
992dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
993dda28197Spatrick while (m_io_handler_stack.GetSize() > 1) {
994dda28197Spatrick IOHandlerSP reader_sp(m_io_handler_stack.Top());
995061da546Spatrick if (reader_sp)
996061da546Spatrick PopIOHandler(reader_sp);
997061da546Spatrick }
998061da546Spatrick }
999061da546Spatrick
RunIOHandlers()1000dda28197Spatrick void Debugger::RunIOHandlers() {
1001dda28197Spatrick IOHandlerSP reader_sp = m_io_handler_stack.Top();
1002061da546Spatrick while (true) {
1003061da546Spatrick if (!reader_sp)
1004061da546Spatrick break;
1005061da546Spatrick
1006061da546Spatrick reader_sp->Run();
1007dda28197Spatrick {
1008dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(
1009dda28197Spatrick m_io_handler_synchronous_mutex);
1010061da546Spatrick
1011061da546Spatrick // Remove all input readers that are done from the top of the stack
1012061da546Spatrick while (true) {
1013dda28197Spatrick IOHandlerSP top_reader_sp = m_io_handler_stack.Top();
1014061da546Spatrick if (top_reader_sp && top_reader_sp->GetIsDone())
1015061da546Spatrick PopIOHandler(top_reader_sp);
1016061da546Spatrick else
1017061da546Spatrick break;
1018061da546Spatrick }
1019dda28197Spatrick reader_sp = m_io_handler_stack.Top();
1020dda28197Spatrick }
1021061da546Spatrick }
1022061da546Spatrick ClearIOHandlers();
1023061da546Spatrick }
1024061da546Spatrick
RunIOHandlerSync(const IOHandlerSP & reader_sp)1025dda28197Spatrick void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) {
1026dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_synchronous_mutex);
1027061da546Spatrick
1028061da546Spatrick PushIOHandler(reader_sp);
1029061da546Spatrick IOHandlerSP top_reader_sp = reader_sp;
1030dda28197Spatrick
1031061da546Spatrick while (top_reader_sp) {
1032dda28197Spatrick if (!top_reader_sp)
1033dda28197Spatrick break;
1034dda28197Spatrick
1035061da546Spatrick top_reader_sp->Run();
1036061da546Spatrick
1037dda28197Spatrick // Don't unwind past the starting point.
1038061da546Spatrick if (top_reader_sp.get() == reader_sp.get()) {
1039061da546Spatrick if (PopIOHandler(reader_sp))
1040061da546Spatrick break;
1041061da546Spatrick }
1042061da546Spatrick
1043dda28197Spatrick // If we pushed new IO handlers, pop them if they're done or restart the
1044dda28197Spatrick // loop to run them if they're not.
1045061da546Spatrick while (true) {
1046dda28197Spatrick top_reader_sp = m_io_handler_stack.Top();
1047dda28197Spatrick if (top_reader_sp && top_reader_sp->GetIsDone()) {
1048061da546Spatrick PopIOHandler(top_reader_sp);
1049dda28197Spatrick // Don't unwind past the starting point.
1050dda28197Spatrick if (top_reader_sp.get() == reader_sp.get())
1051dda28197Spatrick return;
1052dda28197Spatrick } else {
1053061da546Spatrick break;
1054061da546Spatrick }
1055061da546Spatrick }
1056061da546Spatrick }
1057dda28197Spatrick }
1058dda28197Spatrick
IsTopIOHandler(const lldb::IOHandlerSP & reader_sp)1059dda28197Spatrick bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) {
1060dda28197Spatrick return m_io_handler_stack.IsTop(reader_sp);
1061dda28197Spatrick }
1062dda28197Spatrick
CheckTopIOHandlerTypes(IOHandler::Type top_type,IOHandler::Type second_top_type)1063dda28197Spatrick bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,
1064dda28197Spatrick IOHandler::Type second_top_type) {
1065dda28197Spatrick return m_io_handler_stack.CheckTopIOHandlerTypes(top_type, second_top_type);
1066dda28197Spatrick }
1067dda28197Spatrick
PrintAsync(const char * s,size_t len,bool is_stdout)1068dda28197Spatrick void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {
1069*f6aab3d8Srobert bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout);
1070*f6aab3d8Srobert if (!printed) {
1071*f6aab3d8Srobert lldb::StreamFileSP stream =
1072*f6aab3d8Srobert is_stdout ? m_output_stream_sp : m_error_stream_sp;
1073*f6aab3d8Srobert stream->Write(s, len);
1074*f6aab3d8Srobert }
1075dda28197Spatrick }
1076dda28197Spatrick
GetTopIOHandlerControlSequence(char ch)1077dda28197Spatrick ConstString Debugger::GetTopIOHandlerControlSequence(char ch) {
1078dda28197Spatrick return m_io_handler_stack.GetTopIOHandlerControlSequence(ch);
1079dda28197Spatrick }
1080dda28197Spatrick
GetIOHandlerCommandPrefix()1081dda28197Spatrick const char *Debugger::GetIOHandlerCommandPrefix() {
1082dda28197Spatrick return m_io_handler_stack.GetTopIOHandlerCommandPrefix();
1083dda28197Spatrick }
1084dda28197Spatrick
GetIOHandlerHelpPrologue()1085dda28197Spatrick const char *Debugger::GetIOHandlerHelpPrologue() {
1086dda28197Spatrick return m_io_handler_stack.GetTopIOHandlerHelpPrologue();
1087dda28197Spatrick }
1088dda28197Spatrick
RemoveIOHandler(const IOHandlerSP & reader_sp)1089dda28197Spatrick bool Debugger::RemoveIOHandler(const IOHandlerSP &reader_sp) {
1090dda28197Spatrick return PopIOHandler(reader_sp);
1091dda28197Spatrick }
1092dda28197Spatrick
RunIOHandlerAsync(const IOHandlerSP & reader_sp,bool cancel_top_handler)1093dda28197Spatrick void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp,
1094dda28197Spatrick bool cancel_top_handler) {
1095dda28197Spatrick PushIOHandler(reader_sp, cancel_top_handler);
1096dda28197Spatrick }
1097061da546Spatrick
AdoptTopIOHandlerFilesIfInvalid(FileSP & in,StreamFileSP & out,StreamFileSP & err)1098061da546Spatrick void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
1099061da546Spatrick StreamFileSP &err) {
1100061da546Spatrick // Before an IOHandler runs, it must have in/out/err streams. This function
1101061da546Spatrick // is called when one ore more of the streams are nullptr. We use the top
1102061da546Spatrick // input reader's in/out/err streams, or fall back to the debugger file
1103061da546Spatrick // handles, or we fall back onto stdin/stdout/stderr as a last resort.
1104061da546Spatrick
1105dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
1106dda28197Spatrick IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
1107061da546Spatrick // If no STDIN has been set, then set it appropriately
1108061da546Spatrick if (!in || !in->IsValid()) {
1109061da546Spatrick if (top_reader_sp)
1110061da546Spatrick in = top_reader_sp->GetInputFileSP();
1111061da546Spatrick else
1112061da546Spatrick in = GetInputFileSP();
1113061da546Spatrick // If there is nothing, use stdin
1114061da546Spatrick if (!in)
1115061da546Spatrick in = std::make_shared<NativeFile>(stdin, false);
1116061da546Spatrick }
1117061da546Spatrick // If no STDOUT has been set, then set it appropriately
1118061da546Spatrick if (!out || !out->GetFile().IsValid()) {
1119061da546Spatrick if (top_reader_sp)
1120061da546Spatrick out = top_reader_sp->GetOutputStreamFileSP();
1121061da546Spatrick else
1122061da546Spatrick out = GetOutputStreamSP();
1123061da546Spatrick // If there is nothing, use stdout
1124061da546Spatrick if (!out)
1125061da546Spatrick out = std::make_shared<StreamFile>(stdout, false);
1126061da546Spatrick }
1127061da546Spatrick // If no STDERR has been set, then set it appropriately
1128061da546Spatrick if (!err || !err->GetFile().IsValid()) {
1129061da546Spatrick if (top_reader_sp)
1130061da546Spatrick err = top_reader_sp->GetErrorStreamFileSP();
1131061da546Spatrick else
1132061da546Spatrick err = GetErrorStreamSP();
1133061da546Spatrick // If there is nothing, use stderr
1134061da546Spatrick if (!err)
1135061da546Spatrick err = std::make_shared<StreamFile>(stderr, false);
1136061da546Spatrick }
1137061da546Spatrick }
1138061da546Spatrick
PushIOHandler(const IOHandlerSP & reader_sp,bool cancel_top_handler)1139061da546Spatrick void Debugger::PushIOHandler(const IOHandlerSP &reader_sp,
1140061da546Spatrick bool cancel_top_handler) {
1141061da546Spatrick if (!reader_sp)
1142061da546Spatrick return;
1143061da546Spatrick
1144dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
1145061da546Spatrick
1146061da546Spatrick // Get the current top input reader...
1147dda28197Spatrick IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
1148061da546Spatrick
1149061da546Spatrick // Don't push the same IO handler twice...
1150061da546Spatrick if (reader_sp == top_reader_sp)
1151061da546Spatrick return;
1152061da546Spatrick
1153061da546Spatrick // Push our new input reader
1154dda28197Spatrick m_io_handler_stack.Push(reader_sp);
1155061da546Spatrick reader_sp->Activate();
1156061da546Spatrick
1157061da546Spatrick // Interrupt the top input reader to it will exit its Run() function and let
1158061da546Spatrick // this new input reader take over
1159061da546Spatrick if (top_reader_sp) {
1160061da546Spatrick top_reader_sp->Deactivate();
1161061da546Spatrick if (cancel_top_handler)
1162061da546Spatrick top_reader_sp->Cancel();
1163061da546Spatrick }
1164061da546Spatrick }
1165061da546Spatrick
PopIOHandler(const IOHandlerSP & pop_reader_sp)1166061da546Spatrick bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) {
1167061da546Spatrick if (!pop_reader_sp)
1168061da546Spatrick return false;
1169061da546Spatrick
1170dda28197Spatrick std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
1171061da546Spatrick
1172061da546Spatrick // The reader on the stop of the stack is done, so let the next read on the
1173061da546Spatrick // stack refresh its prompt and if there is one...
1174dda28197Spatrick if (m_io_handler_stack.IsEmpty())
1175061da546Spatrick return false;
1176061da546Spatrick
1177dda28197Spatrick IOHandlerSP reader_sp(m_io_handler_stack.Top());
1178061da546Spatrick
1179061da546Spatrick if (pop_reader_sp != reader_sp)
1180061da546Spatrick return false;
1181061da546Spatrick
1182061da546Spatrick reader_sp->Deactivate();
1183061da546Spatrick reader_sp->Cancel();
1184dda28197Spatrick m_io_handler_stack.Pop();
1185061da546Spatrick
1186dda28197Spatrick reader_sp = m_io_handler_stack.Top();
1187061da546Spatrick if (reader_sp)
1188061da546Spatrick reader_sp->Activate();
1189061da546Spatrick
1190061da546Spatrick return true;
1191061da546Spatrick }
1192061da546Spatrick
GetAsyncOutputStream()1193061da546Spatrick StreamSP Debugger::GetAsyncOutputStream() {
1194*f6aab3d8Srobert return std::make_shared<StreamAsynchronousIO>(*this, true, GetUseColor());
1195061da546Spatrick }
1196061da546Spatrick
GetAsyncErrorStream()1197061da546Spatrick StreamSP Debugger::GetAsyncErrorStream() {
1198*f6aab3d8Srobert return std::make_shared<StreamAsynchronousIO>(*this, false, GetUseColor());
1199061da546Spatrick }
1200061da546Spatrick
GetNumDebuggers()1201061da546Spatrick size_t Debugger::GetNumDebuggers() {
1202061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1203061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1204061da546Spatrick return g_debugger_list_ptr->size();
1205061da546Spatrick }
1206061da546Spatrick return 0;
1207061da546Spatrick }
1208061da546Spatrick
GetDebuggerAtIndex(size_t index)1209061da546Spatrick lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) {
1210061da546Spatrick DebuggerSP debugger_sp;
1211061da546Spatrick
1212061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1213061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1214061da546Spatrick if (index < g_debugger_list_ptr->size())
1215061da546Spatrick debugger_sp = g_debugger_list_ptr->at(index);
1216061da546Spatrick }
1217061da546Spatrick
1218061da546Spatrick return debugger_sp;
1219061da546Spatrick }
1220061da546Spatrick
FindDebuggerWithID(lldb::user_id_t id)1221061da546Spatrick DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) {
1222061da546Spatrick DebuggerSP debugger_sp;
1223061da546Spatrick
1224061da546Spatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1225061da546Spatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1226061da546Spatrick DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
1227061da546Spatrick for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
1228061da546Spatrick if ((*pos)->GetID() == id) {
1229061da546Spatrick debugger_sp = *pos;
1230061da546Spatrick break;
1231061da546Spatrick }
1232061da546Spatrick }
1233061da546Spatrick }
1234061da546Spatrick return debugger_sp;
1235061da546Spatrick }
1236061da546Spatrick
FormatDisassemblerAddress(const FormatEntity::Entry * format,const SymbolContext * sc,const SymbolContext * prev_sc,const ExecutionContext * exe_ctx,const Address * addr,Stream & s)1237061da546Spatrick bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format,
1238061da546Spatrick const SymbolContext *sc,
1239061da546Spatrick const SymbolContext *prev_sc,
1240061da546Spatrick const ExecutionContext *exe_ctx,
1241061da546Spatrick const Address *addr, Stream &s) {
1242061da546Spatrick FormatEntity::Entry format_entry;
1243061da546Spatrick
1244061da546Spatrick if (format == nullptr) {
1245061da546Spatrick if (exe_ctx != nullptr && exe_ctx->HasTargetScope())
1246061da546Spatrick format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
1247061da546Spatrick if (format == nullptr) {
1248061da546Spatrick FormatEntity::Parse("${addr}: ", format_entry);
1249061da546Spatrick format = &format_entry;
1250061da546Spatrick }
1251061da546Spatrick }
1252061da546Spatrick bool function_changed = false;
1253061da546Spatrick bool initial_function = false;
1254061da546Spatrick if (prev_sc && (prev_sc->function || prev_sc->symbol)) {
1255061da546Spatrick if (sc && (sc->function || sc->symbol)) {
1256061da546Spatrick if (prev_sc->symbol && sc->symbol) {
1257061da546Spatrick if (!sc->symbol->Compare(prev_sc->symbol->GetName(),
1258061da546Spatrick prev_sc->symbol->GetType())) {
1259061da546Spatrick function_changed = true;
1260061da546Spatrick }
1261061da546Spatrick } else if (prev_sc->function && sc->function) {
1262061da546Spatrick if (prev_sc->function->GetMangled() != sc->function->GetMangled()) {
1263061da546Spatrick function_changed = true;
1264061da546Spatrick }
1265061da546Spatrick }
1266061da546Spatrick }
1267061da546Spatrick }
1268061da546Spatrick // The first context on a list of instructions will have a prev_sc that has
1269061da546Spatrick // no Function or Symbol -- if SymbolContext had an IsValid() method, it
1270061da546Spatrick // would return false. But we do get a prev_sc pointer.
1271061da546Spatrick if ((sc && (sc->function || sc->symbol)) && prev_sc &&
1272061da546Spatrick (prev_sc->function == nullptr && prev_sc->symbol == nullptr)) {
1273061da546Spatrick initial_function = true;
1274061da546Spatrick }
1275061da546Spatrick return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr,
1276061da546Spatrick function_changed, initial_function);
1277061da546Spatrick }
1278061da546Spatrick
SetLoggingCallback(lldb::LogOutputCallback log_callback,void * baton)1279061da546Spatrick void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
1280061da546Spatrick void *baton) {
1281061da546Spatrick // For simplicity's sake, I am not going to deal with how to close down any
1282061da546Spatrick // open logging streams, I just redirect everything from here on out to the
1283061da546Spatrick // callback.
1284*f6aab3d8Srobert m_callback_handler_sp =
1285*f6aab3d8Srobert std::make_shared<CallbackLogHandler>(log_callback, baton);
1286be691f3bSpatrick }
1287be691f3bSpatrick
PrivateReportProgress(Debugger & debugger,uint64_t progress_id,const std::string & message,uint64_t completed,uint64_t total,bool is_debugger_specific)1288be691f3bSpatrick static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
1289be691f3bSpatrick const std::string &message,
1290be691f3bSpatrick uint64_t completed, uint64_t total,
1291be691f3bSpatrick bool is_debugger_specific) {
1292be691f3bSpatrick // Only deliver progress events if we have any progress listeners.
1293be691f3bSpatrick const uint32_t event_type = Debugger::eBroadcastBitProgress;
1294be691f3bSpatrick if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type))
1295be691f3bSpatrick return;
1296*f6aab3d8Srobert EventSP event_sp(new Event(
1297*f6aab3d8Srobert event_type, new ProgressEventData(progress_id, message, completed, total,
1298*f6aab3d8Srobert is_debugger_specific)));
1299be691f3bSpatrick debugger.GetBroadcaster().BroadcastEvent(event_sp);
1300be691f3bSpatrick }
1301be691f3bSpatrick
ReportProgress(uint64_t progress_id,const std::string & message,uint64_t completed,uint64_t total,std::optional<lldb::user_id_t> debugger_id)1302be691f3bSpatrick void Debugger::ReportProgress(uint64_t progress_id, const std::string &message,
1303be691f3bSpatrick uint64_t completed, uint64_t total,
1304*f6aab3d8Srobert std::optional<lldb::user_id_t> debugger_id) {
1305be691f3bSpatrick // Check if this progress is for a specific debugger.
1306*f6aab3d8Srobert if (debugger_id) {
1307be691f3bSpatrick // It is debugger specific, grab it and deliver the event if the debugger
1308be691f3bSpatrick // still exists.
1309be691f3bSpatrick DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);
1310be691f3bSpatrick if (debugger_sp)
1311be691f3bSpatrick PrivateReportProgress(*debugger_sp, progress_id, message, completed,
1312be691f3bSpatrick total, /*is_debugger_specific*/ true);
1313be691f3bSpatrick return;
1314be691f3bSpatrick }
1315be691f3bSpatrick // The progress event is not debugger specific, iterate over all debuggers
1316be691f3bSpatrick // and deliver a progress event to each one.
1317be691f3bSpatrick if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1318be691f3bSpatrick std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1319be691f3bSpatrick DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
1320be691f3bSpatrick for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos)
1321be691f3bSpatrick PrivateReportProgress(*(*pos), progress_id, message, completed, total,
1322be691f3bSpatrick /*is_debugger_specific*/ false);
1323be691f3bSpatrick }
1324be691f3bSpatrick }
1325be691f3bSpatrick
PrivateReportDiagnostic(Debugger & debugger,DiagnosticEventData::Type type,std::string message,bool debugger_specific)1326*f6aab3d8Srobert static void PrivateReportDiagnostic(Debugger &debugger,
1327*f6aab3d8Srobert DiagnosticEventData::Type type,
1328*f6aab3d8Srobert std::string message,
1329*f6aab3d8Srobert bool debugger_specific) {
1330*f6aab3d8Srobert uint32_t event_type = 0;
1331*f6aab3d8Srobert switch (type) {
1332*f6aab3d8Srobert case DiagnosticEventData::Type::Info:
1333*f6aab3d8Srobert assert(false && "DiagnosticEventData::Type::Info should not be broadcast");
1334*f6aab3d8Srobert return;
1335*f6aab3d8Srobert case DiagnosticEventData::Type::Warning:
1336*f6aab3d8Srobert event_type = Debugger::eBroadcastBitWarning;
1337*f6aab3d8Srobert break;
1338*f6aab3d8Srobert case DiagnosticEventData::Type::Error:
1339*f6aab3d8Srobert event_type = Debugger::eBroadcastBitError;
1340*f6aab3d8Srobert break;
1341*f6aab3d8Srobert }
1342*f6aab3d8Srobert
1343*f6aab3d8Srobert Broadcaster &broadcaster = debugger.GetBroadcaster();
1344*f6aab3d8Srobert if (!broadcaster.EventTypeHasListeners(event_type)) {
1345*f6aab3d8Srobert // Diagnostics are too important to drop. If nobody is listening, print the
1346*f6aab3d8Srobert // diagnostic directly to the debugger's error stream.
1347*f6aab3d8Srobert DiagnosticEventData event_data(type, std::move(message), debugger_specific);
1348*f6aab3d8Srobert StreamSP stream = debugger.GetAsyncErrorStream();
1349*f6aab3d8Srobert event_data.Dump(stream.get());
1350*f6aab3d8Srobert return;
1351*f6aab3d8Srobert }
1352*f6aab3d8Srobert EventSP event_sp = std::make_shared<Event>(
1353*f6aab3d8Srobert event_type,
1354*f6aab3d8Srobert new DiagnosticEventData(type, std::move(message), debugger_specific));
1355*f6aab3d8Srobert broadcaster.BroadcastEvent(event_sp);
1356*f6aab3d8Srobert }
1357*f6aab3d8Srobert
ReportDiagnosticImpl(DiagnosticEventData::Type type,std::string message,std::optional<lldb::user_id_t> debugger_id,std::once_flag * once)1358*f6aab3d8Srobert void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type,
1359*f6aab3d8Srobert std::string message,
1360*f6aab3d8Srobert std::optional<lldb::user_id_t> debugger_id,
1361*f6aab3d8Srobert std::once_flag *once) {
1362*f6aab3d8Srobert auto ReportDiagnosticLambda = [&]() {
1363*f6aab3d8Srobert // The diagnostic subsystem is optional but we still want to broadcast
1364*f6aab3d8Srobert // events when it's disabled.
1365*f6aab3d8Srobert if (Diagnostics::Enabled())
1366*f6aab3d8Srobert Diagnostics::Instance().Report(message);
1367*f6aab3d8Srobert
1368*f6aab3d8Srobert // We don't broadcast info events.
1369*f6aab3d8Srobert if (type == DiagnosticEventData::Type::Info)
1370*f6aab3d8Srobert return;
1371*f6aab3d8Srobert
1372*f6aab3d8Srobert // Check if this diagnostic is for a specific debugger.
1373*f6aab3d8Srobert if (debugger_id) {
1374*f6aab3d8Srobert // It is debugger specific, grab it and deliver the event if the debugger
1375*f6aab3d8Srobert // still exists.
1376*f6aab3d8Srobert DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);
1377*f6aab3d8Srobert if (debugger_sp)
1378*f6aab3d8Srobert PrivateReportDiagnostic(*debugger_sp, type, std::move(message), true);
1379*f6aab3d8Srobert return;
1380*f6aab3d8Srobert }
1381*f6aab3d8Srobert // The diagnostic event is not debugger specific, iterate over all debuggers
1382*f6aab3d8Srobert // and deliver a diagnostic event to each one.
1383*f6aab3d8Srobert if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1384*f6aab3d8Srobert std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1385*f6aab3d8Srobert for (const auto &debugger : *g_debugger_list_ptr)
1386*f6aab3d8Srobert PrivateReportDiagnostic(*debugger, type, message, false);
1387*f6aab3d8Srobert }
1388*f6aab3d8Srobert };
1389*f6aab3d8Srobert
1390*f6aab3d8Srobert if (once)
1391*f6aab3d8Srobert std::call_once(*once, ReportDiagnosticLambda);
1392*f6aab3d8Srobert else
1393*f6aab3d8Srobert ReportDiagnosticLambda();
1394*f6aab3d8Srobert }
1395*f6aab3d8Srobert
ReportWarning(std::string message,std::optional<lldb::user_id_t> debugger_id,std::once_flag * once)1396*f6aab3d8Srobert void Debugger::ReportWarning(std::string message,
1397*f6aab3d8Srobert std::optional<lldb::user_id_t> debugger_id,
1398*f6aab3d8Srobert std::once_flag *once) {
1399*f6aab3d8Srobert ReportDiagnosticImpl(DiagnosticEventData::Type::Warning, std::move(message),
1400*f6aab3d8Srobert debugger_id, once);
1401*f6aab3d8Srobert }
1402*f6aab3d8Srobert
ReportError(std::string message,std::optional<lldb::user_id_t> debugger_id,std::once_flag * once)1403*f6aab3d8Srobert void Debugger::ReportError(std::string message,
1404*f6aab3d8Srobert std::optional<lldb::user_id_t> debugger_id,
1405*f6aab3d8Srobert std::once_flag *once) {
1406*f6aab3d8Srobert ReportDiagnosticImpl(DiagnosticEventData::Type::Error, std::move(message),
1407*f6aab3d8Srobert debugger_id, once);
1408*f6aab3d8Srobert }
1409*f6aab3d8Srobert
ReportInfo(std::string message,std::optional<lldb::user_id_t> debugger_id,std::once_flag * once)1410*f6aab3d8Srobert void Debugger::ReportInfo(std::string message,
1411*f6aab3d8Srobert std::optional<lldb::user_id_t> debugger_id,
1412*f6aab3d8Srobert std::once_flag *once) {
1413*f6aab3d8Srobert ReportDiagnosticImpl(DiagnosticEventData::Type::Info, std::move(message),
1414*f6aab3d8Srobert debugger_id, once);
1415*f6aab3d8Srobert }
1416*f6aab3d8Srobert
ReportSymbolChange(const ModuleSpec & module_spec)1417*f6aab3d8Srobert void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) {
1418*f6aab3d8Srobert if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1419*f6aab3d8Srobert std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1420*f6aab3d8Srobert for (DebuggerSP debugger_sp : *g_debugger_list_ptr) {
1421*f6aab3d8Srobert EventSP event_sp = std::make_shared<Event>(
1422*f6aab3d8Srobert Debugger::eBroadcastSymbolChange,
1423*f6aab3d8Srobert new SymbolChangeEventData(debugger_sp, module_spec));
1424*f6aab3d8Srobert debugger_sp->GetBroadcaster().BroadcastEvent(event_sp);
1425*f6aab3d8Srobert }
1426*f6aab3d8Srobert }
1427*f6aab3d8Srobert }
1428*f6aab3d8Srobert
1429*f6aab3d8Srobert static std::shared_ptr<LogHandler>
CreateLogHandler(LogHandlerKind log_handler_kind,int fd,bool should_close,size_t buffer_size)1430*f6aab3d8Srobert CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,
1431*f6aab3d8Srobert size_t buffer_size) {
1432*f6aab3d8Srobert switch (log_handler_kind) {
1433*f6aab3d8Srobert case eLogHandlerStream:
1434*f6aab3d8Srobert return std::make_shared<StreamLogHandler>(fd, should_close, buffer_size);
1435*f6aab3d8Srobert case eLogHandlerCircular:
1436*f6aab3d8Srobert return std::make_shared<RotatingLogHandler>(buffer_size);
1437*f6aab3d8Srobert case eLogHandlerSystem:
1438*f6aab3d8Srobert return std::make_shared<SystemLogHandler>();
1439*f6aab3d8Srobert case eLogHandlerCallback:
1440*f6aab3d8Srobert return {};
1441*f6aab3d8Srobert }
1442*f6aab3d8Srobert return {};
1443*f6aab3d8Srobert }
1444*f6aab3d8Srobert
EnableLog(llvm::StringRef channel,llvm::ArrayRef<const char * > categories,llvm::StringRef log_file,uint32_t log_options,size_t buffer_size,LogHandlerKind log_handler_kind,llvm::raw_ostream & error_stream)1445061da546Spatrick bool Debugger::EnableLog(llvm::StringRef channel,
1446061da546Spatrick llvm::ArrayRef<const char *> categories,
1447061da546Spatrick llvm::StringRef log_file, uint32_t log_options,
1448*f6aab3d8Srobert size_t buffer_size, LogHandlerKind log_handler_kind,
1449061da546Spatrick llvm::raw_ostream &error_stream) {
1450061da546Spatrick
1451*f6aab3d8Srobert std::shared_ptr<LogHandler> log_handler_sp;
1452*f6aab3d8Srobert if (m_callback_handler_sp) {
1453*f6aab3d8Srobert log_handler_sp = m_callback_handler_sp;
1454061da546Spatrick // For now when using the callback mode you always get thread & timestamp.
1455061da546Spatrick log_options |=
1456061da546Spatrick LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
1457061da546Spatrick } else if (log_file.empty()) {
1458*f6aab3d8Srobert log_handler_sp =
1459*f6aab3d8Srobert CreateLogHandler(log_handler_kind, GetOutputFile().GetDescriptor(),
1460*f6aab3d8Srobert /*should_close=*/false, buffer_size);
1461061da546Spatrick } else {
1462*f6aab3d8Srobert auto pos = m_stream_handlers.find(log_file);
1463*f6aab3d8Srobert if (pos != m_stream_handlers.end())
1464*f6aab3d8Srobert log_handler_sp = pos->second.lock();
1465*f6aab3d8Srobert if (!log_handler_sp) {
1466dda28197Spatrick File::OpenOptions flags =
1467*f6aab3d8Srobert File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
1468061da546Spatrick if (log_options & LLDB_LOG_OPTION_APPEND)
1469dda28197Spatrick flags |= File::eOpenOptionAppend;
1470dda28197Spatrick else
1471dda28197Spatrick flags |= File::eOpenOptionTruncate;
1472be691f3bSpatrick llvm::Expected<FileUP> file = FileSystem::Instance().Open(
1473dda28197Spatrick FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false);
1474dda28197Spatrick if (!file) {
1475be691f3bSpatrick error_stream << "Unable to open log file '" << log_file
1476be691f3bSpatrick << "': " << llvm::toString(file.takeError()) << "\n";
1477061da546Spatrick return false;
1478061da546Spatrick }
1479dda28197Spatrick
1480*f6aab3d8Srobert log_handler_sp =
1481*f6aab3d8Srobert CreateLogHandler(log_handler_kind, (*file)->GetDescriptor(),
1482*f6aab3d8Srobert /*should_close=*/true, buffer_size);
1483*f6aab3d8Srobert m_stream_handlers[log_file] = log_handler_sp;
1484061da546Spatrick }
1485061da546Spatrick }
1486*f6aab3d8Srobert assert(log_handler_sp);
1487061da546Spatrick
1488061da546Spatrick if (log_options == 0)
1489*f6aab3d8Srobert log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
1490061da546Spatrick
1491*f6aab3d8Srobert return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories,
1492061da546Spatrick error_stream);
1493061da546Spatrick }
1494061da546Spatrick
1495061da546Spatrick ScriptInterpreter *
GetScriptInterpreter(bool can_create,std::optional<lldb::ScriptLanguage> language)1496061da546Spatrick Debugger::GetScriptInterpreter(bool can_create,
1497*f6aab3d8Srobert std::optional<lldb::ScriptLanguage> language) {
1498061da546Spatrick std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex);
1499061da546Spatrick lldb::ScriptLanguage script_language =
1500061da546Spatrick language ? *language : GetScriptLanguage();
1501061da546Spatrick
1502061da546Spatrick if (!m_script_interpreters[script_language]) {
1503061da546Spatrick if (!can_create)
1504061da546Spatrick return nullptr;
1505061da546Spatrick m_script_interpreters[script_language] =
1506061da546Spatrick PluginManager::GetScriptInterpreterForLanguage(script_language, *this);
1507061da546Spatrick }
1508061da546Spatrick
1509061da546Spatrick return m_script_interpreters[script_language].get();
1510061da546Spatrick }
1511061da546Spatrick
GetSourceManager()1512061da546Spatrick SourceManager &Debugger::GetSourceManager() {
1513061da546Spatrick if (!m_source_manager_up)
1514061da546Spatrick m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());
1515061da546Spatrick return *m_source_manager_up;
1516061da546Spatrick }
1517061da546Spatrick
1518061da546Spatrick // This function handles events that were broadcast by the process.
HandleBreakpointEvent(const EventSP & event_sp)1519061da546Spatrick void Debugger::HandleBreakpointEvent(const EventSP &event_sp) {
1520061da546Spatrick using namespace lldb;
1521061da546Spatrick const uint32_t event_type =
1522061da546Spatrick Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(
1523061da546Spatrick event_sp);
1524061da546Spatrick
1525061da546Spatrick // if (event_type & eBreakpointEventTypeAdded
1526061da546Spatrick // || event_type & eBreakpointEventTypeRemoved
1527061da546Spatrick // || event_type & eBreakpointEventTypeEnabled
1528061da546Spatrick // || event_type & eBreakpointEventTypeDisabled
1529061da546Spatrick // || event_type & eBreakpointEventTypeCommandChanged
1530061da546Spatrick // || event_type & eBreakpointEventTypeConditionChanged
1531061da546Spatrick // || event_type & eBreakpointEventTypeIgnoreChanged
1532061da546Spatrick // || event_type & eBreakpointEventTypeLocationsResolved)
1533061da546Spatrick // {
1534061da546Spatrick // // Don't do anything about these events, since the breakpoint
1535061da546Spatrick // commands already echo these actions.
1536061da546Spatrick // }
1537061da546Spatrick //
1538061da546Spatrick if (event_type & eBreakpointEventTypeLocationsAdded) {
1539061da546Spatrick uint32_t num_new_locations =
1540061da546Spatrick Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(
1541061da546Spatrick event_sp);
1542061da546Spatrick if (num_new_locations > 0) {
1543061da546Spatrick BreakpointSP breakpoint =
1544061da546Spatrick Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
1545061da546Spatrick StreamSP output_sp(GetAsyncOutputStream());
1546061da546Spatrick if (output_sp) {
1547061da546Spatrick output_sp->Printf("%d location%s added to breakpoint %d\n",
1548061da546Spatrick num_new_locations, num_new_locations == 1 ? "" : "s",
1549061da546Spatrick breakpoint->GetID());
1550061da546Spatrick output_sp->Flush();
1551061da546Spatrick }
1552061da546Spatrick }
1553061da546Spatrick }
1554061da546Spatrick // else if (event_type & eBreakpointEventTypeLocationsRemoved)
1555061da546Spatrick // {
1556061da546Spatrick // // These locations just get disabled, not sure it is worth spamming
1557061da546Spatrick // folks about this on the command line.
1558061da546Spatrick // }
1559061da546Spatrick // else if (event_type & eBreakpointEventTypeLocationsResolved)
1560061da546Spatrick // {
1561061da546Spatrick // // This might be an interesting thing to note, but I'm going to
1562061da546Spatrick // leave it quiet for now, it just looked noisy.
1563061da546Spatrick // }
1564061da546Spatrick }
1565061da546Spatrick
FlushProcessOutput(Process & process,bool flush_stdout,bool flush_stderr)1566061da546Spatrick void Debugger::FlushProcessOutput(Process &process, bool flush_stdout,
1567061da546Spatrick bool flush_stderr) {
1568061da546Spatrick const auto &flush = [&](Stream &stream,
1569061da546Spatrick size_t (Process::*get)(char *, size_t, Status &)) {
1570061da546Spatrick Status error;
1571061da546Spatrick size_t len;
1572061da546Spatrick char buffer[1024];
1573061da546Spatrick while ((len = (process.*get)(buffer, sizeof(buffer), error)) > 0)
1574061da546Spatrick stream.Write(buffer, len);
1575061da546Spatrick stream.Flush();
1576061da546Spatrick };
1577061da546Spatrick
1578061da546Spatrick std::lock_guard<std::mutex> guard(m_output_flush_mutex);
1579061da546Spatrick if (flush_stdout)
1580061da546Spatrick flush(*GetAsyncOutputStream(), &Process::GetSTDOUT);
1581061da546Spatrick if (flush_stderr)
1582061da546Spatrick flush(*GetAsyncErrorStream(), &Process::GetSTDERR);
1583061da546Spatrick }
1584061da546Spatrick
1585061da546Spatrick // This function handles events that were broadcast by the process.
HandleProcessEvent(const EventSP & event_sp)1586061da546Spatrick void Debugger::HandleProcessEvent(const EventSP &event_sp) {
1587061da546Spatrick using namespace lldb;
1588061da546Spatrick const uint32_t event_type = event_sp->GetType();
1589061da546Spatrick ProcessSP process_sp =
1590061da546Spatrick (event_type == Process::eBroadcastBitStructuredData)
1591061da546Spatrick ? EventDataStructuredData::GetProcessFromEvent(event_sp.get())
1592061da546Spatrick : Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
1593061da546Spatrick
1594061da546Spatrick StreamSP output_stream_sp = GetAsyncOutputStream();
1595061da546Spatrick StreamSP error_stream_sp = GetAsyncErrorStream();
1596061da546Spatrick const bool gui_enabled = IsForwardingEvents();
1597061da546Spatrick
1598061da546Spatrick if (!gui_enabled) {
1599061da546Spatrick bool pop_process_io_handler = false;
1600061da546Spatrick assert(process_sp);
1601061da546Spatrick
1602061da546Spatrick bool state_is_stopped = false;
1603061da546Spatrick const bool got_state_changed =
1604061da546Spatrick (event_type & Process::eBroadcastBitStateChanged) != 0;
1605061da546Spatrick const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
1606061da546Spatrick const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
1607061da546Spatrick const bool got_structured_data =
1608061da546Spatrick (event_type & Process::eBroadcastBitStructuredData) != 0;
1609061da546Spatrick
1610061da546Spatrick if (got_state_changed) {
1611061da546Spatrick StateType event_state =
1612061da546Spatrick Process::ProcessEventData::GetStateFromEvent(event_sp.get());
1613061da546Spatrick state_is_stopped = StateIsStoppedState(event_state, false);
1614061da546Spatrick }
1615061da546Spatrick
1616061da546Spatrick // Display running state changes first before any STDIO
1617061da546Spatrick if (got_state_changed && !state_is_stopped) {
1618061da546Spatrick Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),
1619061da546Spatrick pop_process_io_handler);
1620061da546Spatrick }
1621061da546Spatrick
1622061da546Spatrick // Now display STDOUT and STDERR
1623061da546Spatrick FlushProcessOutput(*process_sp, got_stdout || got_state_changed,
1624061da546Spatrick got_stderr || got_state_changed);
1625061da546Spatrick
1626061da546Spatrick // Give structured data events an opportunity to display.
1627061da546Spatrick if (got_structured_data) {
1628061da546Spatrick StructuredDataPluginSP plugin_sp =
1629061da546Spatrick EventDataStructuredData::GetPluginFromEvent(event_sp.get());
1630061da546Spatrick if (plugin_sp) {
1631061da546Spatrick auto structured_data_sp =
1632061da546Spatrick EventDataStructuredData::GetObjectFromEvent(event_sp.get());
1633061da546Spatrick if (output_stream_sp) {
1634061da546Spatrick StreamString content_stream;
1635061da546Spatrick Status error =
1636061da546Spatrick plugin_sp->GetDescription(structured_data_sp, content_stream);
1637061da546Spatrick if (error.Success()) {
1638061da546Spatrick if (!content_stream.GetString().empty()) {
1639061da546Spatrick // Add newline.
1640061da546Spatrick content_stream.PutChar('\n');
1641061da546Spatrick content_stream.Flush();
1642061da546Spatrick
1643061da546Spatrick // Print it.
1644061da546Spatrick output_stream_sp->PutCString(content_stream.GetString());
1645061da546Spatrick }
1646061da546Spatrick } else {
1647*f6aab3d8Srobert error_stream_sp->Format("Failed to print structured "
1648*f6aab3d8Srobert "data with plugin {0}: {1}",
1649*f6aab3d8Srobert plugin_sp->GetPluginName(), error);
1650061da546Spatrick }
1651061da546Spatrick }
1652061da546Spatrick }
1653061da546Spatrick }
1654061da546Spatrick
1655061da546Spatrick // Now display any stopped state changes after any STDIO
1656061da546Spatrick if (got_state_changed && state_is_stopped) {
1657061da546Spatrick Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),
1658061da546Spatrick pop_process_io_handler);
1659061da546Spatrick }
1660061da546Spatrick
1661061da546Spatrick output_stream_sp->Flush();
1662061da546Spatrick error_stream_sp->Flush();
1663061da546Spatrick
1664061da546Spatrick if (pop_process_io_handler)
1665061da546Spatrick process_sp->PopProcessIOHandler();
1666061da546Spatrick }
1667061da546Spatrick }
1668061da546Spatrick
HandleThreadEvent(const EventSP & event_sp)1669061da546Spatrick void Debugger::HandleThreadEvent(const EventSP &event_sp) {
1670061da546Spatrick // At present the only thread event we handle is the Frame Changed event, and
1671061da546Spatrick // all we do for that is just reprint the thread status for that thread.
1672061da546Spatrick using namespace lldb;
1673061da546Spatrick const uint32_t event_type = event_sp->GetType();
1674061da546Spatrick const bool stop_format = true;
1675061da546Spatrick if (event_type == Thread::eBroadcastBitStackChanged ||
1676061da546Spatrick event_type == Thread::eBroadcastBitThreadSelected) {
1677061da546Spatrick ThreadSP thread_sp(
1678061da546Spatrick Thread::ThreadEventData::GetThreadFromEvent(event_sp.get()));
1679061da546Spatrick if (thread_sp) {
1680061da546Spatrick thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format);
1681061da546Spatrick }
1682061da546Spatrick }
1683061da546Spatrick }
1684061da546Spatrick
IsForwardingEvents()1685061da546Spatrick bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; }
1686061da546Spatrick
EnableForwardEvents(const ListenerSP & listener_sp)1687061da546Spatrick void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) {
1688061da546Spatrick m_forward_listener_sp = listener_sp;
1689061da546Spatrick }
1690061da546Spatrick
CancelForwardEvents(const ListenerSP & listener_sp)1691061da546Spatrick void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) {
1692061da546Spatrick m_forward_listener_sp.reset();
1693061da546Spatrick }
1694061da546Spatrick
DefaultEventHandler()1695*f6aab3d8Srobert lldb::thread_result_t Debugger::DefaultEventHandler() {
1696061da546Spatrick ListenerSP listener_sp(GetListener());
1697061da546Spatrick ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
1698061da546Spatrick ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());
1699061da546Spatrick ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());
1700061da546Spatrick BroadcastEventSpec target_event_spec(broadcaster_class_target,
1701061da546Spatrick Target::eBroadcastBitBreakpointChanged);
1702061da546Spatrick
1703061da546Spatrick BroadcastEventSpec process_event_spec(
1704061da546Spatrick broadcaster_class_process,
1705061da546Spatrick Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT |
1706061da546Spatrick Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData);
1707061da546Spatrick
1708061da546Spatrick BroadcastEventSpec thread_event_spec(broadcaster_class_thread,
1709061da546Spatrick Thread::eBroadcastBitStackChanged |
1710061da546Spatrick Thread::eBroadcastBitThreadSelected);
1711061da546Spatrick
1712061da546Spatrick listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
1713061da546Spatrick target_event_spec);
1714061da546Spatrick listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
1715061da546Spatrick process_event_spec);
1716061da546Spatrick listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
1717061da546Spatrick thread_event_spec);
1718061da546Spatrick listener_sp->StartListeningForEvents(
1719061da546Spatrick m_command_interpreter_up.get(),
1720061da546Spatrick CommandInterpreter::eBroadcastBitQuitCommandReceived |
1721061da546Spatrick CommandInterpreter::eBroadcastBitAsynchronousOutputData |
1722061da546Spatrick CommandInterpreter::eBroadcastBitAsynchronousErrorData);
1723061da546Spatrick
1724*f6aab3d8Srobert listener_sp->StartListeningForEvents(
1725*f6aab3d8Srobert &m_broadcaster, eBroadcastBitProgress | eBroadcastBitWarning |
1726*f6aab3d8Srobert eBroadcastBitError | eBroadcastSymbolChange);
1727*f6aab3d8Srobert
1728061da546Spatrick // Let the thread that spawned us know that we have started up and that we
1729061da546Spatrick // are now listening to all required events so no events get missed
1730061da546Spatrick m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
1731061da546Spatrick
1732061da546Spatrick bool done = false;
1733061da546Spatrick while (!done) {
1734061da546Spatrick EventSP event_sp;
1735*f6aab3d8Srobert if (listener_sp->GetEvent(event_sp, std::nullopt)) {
1736061da546Spatrick if (event_sp) {
1737061da546Spatrick Broadcaster *broadcaster = event_sp->GetBroadcaster();
1738061da546Spatrick if (broadcaster) {
1739061da546Spatrick uint32_t event_type = event_sp->GetType();
1740061da546Spatrick ConstString broadcaster_class(broadcaster->GetBroadcasterClass());
1741061da546Spatrick if (broadcaster_class == broadcaster_class_process) {
1742061da546Spatrick HandleProcessEvent(event_sp);
1743061da546Spatrick } else if (broadcaster_class == broadcaster_class_target) {
1744061da546Spatrick if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
1745061da546Spatrick event_sp.get())) {
1746061da546Spatrick HandleBreakpointEvent(event_sp);
1747061da546Spatrick }
1748061da546Spatrick } else if (broadcaster_class == broadcaster_class_thread) {
1749061da546Spatrick HandleThreadEvent(event_sp);
1750061da546Spatrick } else if (broadcaster == m_command_interpreter_up.get()) {
1751061da546Spatrick if (event_type &
1752061da546Spatrick CommandInterpreter::eBroadcastBitQuitCommandReceived) {
1753061da546Spatrick done = true;
1754061da546Spatrick } else if (event_type &
1755061da546Spatrick CommandInterpreter::eBroadcastBitAsynchronousErrorData) {
1756061da546Spatrick const char *data = static_cast<const char *>(
1757061da546Spatrick EventDataBytes::GetBytesFromEvent(event_sp.get()));
1758061da546Spatrick if (data && data[0]) {
1759061da546Spatrick StreamSP error_sp(GetAsyncErrorStream());
1760061da546Spatrick if (error_sp) {
1761061da546Spatrick error_sp->PutCString(data);
1762061da546Spatrick error_sp->Flush();
1763061da546Spatrick }
1764061da546Spatrick }
1765061da546Spatrick } else if (event_type & CommandInterpreter::
1766061da546Spatrick eBroadcastBitAsynchronousOutputData) {
1767061da546Spatrick const char *data = static_cast<const char *>(
1768061da546Spatrick EventDataBytes::GetBytesFromEvent(event_sp.get()));
1769061da546Spatrick if (data && data[0]) {
1770061da546Spatrick StreamSP output_sp(GetAsyncOutputStream());
1771061da546Spatrick if (output_sp) {
1772061da546Spatrick output_sp->PutCString(data);
1773061da546Spatrick output_sp->Flush();
1774061da546Spatrick }
1775061da546Spatrick }
1776061da546Spatrick }
1777*f6aab3d8Srobert } else if (broadcaster == &m_broadcaster) {
1778*f6aab3d8Srobert if (event_type & Debugger::eBroadcastBitProgress)
1779*f6aab3d8Srobert HandleProgressEvent(event_sp);
1780*f6aab3d8Srobert else if (event_type & Debugger::eBroadcastBitWarning)
1781*f6aab3d8Srobert HandleDiagnosticEvent(event_sp);
1782*f6aab3d8Srobert else if (event_type & Debugger::eBroadcastBitError)
1783*f6aab3d8Srobert HandleDiagnosticEvent(event_sp);
1784061da546Spatrick }
1785061da546Spatrick }
1786061da546Spatrick
1787061da546Spatrick if (m_forward_listener_sp)
1788061da546Spatrick m_forward_listener_sp->AddEvent(event_sp);
1789061da546Spatrick }
1790061da546Spatrick }
1791061da546Spatrick }
1792061da546Spatrick return {};
1793061da546Spatrick }
1794061da546Spatrick
StartEventHandlerThread()1795061da546Spatrick bool Debugger::StartEventHandlerThread() {
1796061da546Spatrick if (!m_event_handler_thread.IsJoinable()) {
1797061da546Spatrick // We must synchronize with the DefaultEventHandler() thread to ensure it
1798061da546Spatrick // is up and running and listening to events before we return from this
1799061da546Spatrick // function. We do this by listening to events for the
1800061da546Spatrick // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
1801061da546Spatrick ConstString full_name("lldb.debugger.event-handler");
1802061da546Spatrick ListenerSP listener_sp(Listener::MakeListener(full_name.AsCString()));
1803061da546Spatrick listener_sp->StartListeningForEvents(&m_sync_broadcaster,
1804061da546Spatrick eBroadcastBitEventThreadIsListening);
1805061da546Spatrick
1806dda28197Spatrick llvm::StringRef thread_name =
1807061da546Spatrick full_name.GetLength() < llvm::get_max_thread_name_length()
1808dda28197Spatrick ? full_name.GetStringRef()
1809061da546Spatrick : "dbg.evt-handler";
1810061da546Spatrick
1811061da546Spatrick // Use larger 8MB stack for this thread
1812061da546Spatrick llvm::Expected<HostThread> event_handler_thread =
1813*f6aab3d8Srobert ThreadLauncher::LaunchThread(
1814*f6aab3d8Srobert thread_name, [this] { return DefaultEventHandler(); },
1815061da546Spatrick g_debugger_event_thread_stack_bytes);
1816061da546Spatrick
1817061da546Spatrick if (event_handler_thread) {
1818061da546Spatrick m_event_handler_thread = *event_handler_thread;
1819061da546Spatrick } else {
1820*f6aab3d8Srobert LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}",
1821061da546Spatrick llvm::toString(event_handler_thread.takeError()));
1822061da546Spatrick }
1823061da546Spatrick
1824061da546Spatrick // Make sure DefaultEventHandler() is running and listening to events
1825061da546Spatrick // before we return from this function. We are only listening for events of
1826061da546Spatrick // type eBroadcastBitEventThreadIsListening so we don't need to check the
1827061da546Spatrick // event, we just need to wait an infinite amount of time for it (nullptr
1828061da546Spatrick // timeout as the first parameter)
1829061da546Spatrick lldb::EventSP event_sp;
1830*f6aab3d8Srobert listener_sp->GetEvent(event_sp, std::nullopt);
1831061da546Spatrick }
1832061da546Spatrick return m_event_handler_thread.IsJoinable();
1833061da546Spatrick }
1834061da546Spatrick
StopEventHandlerThread()1835061da546Spatrick void Debugger::StopEventHandlerThread() {
1836061da546Spatrick if (m_event_handler_thread.IsJoinable()) {
1837061da546Spatrick GetCommandInterpreter().BroadcastEvent(
1838061da546Spatrick CommandInterpreter::eBroadcastBitQuitCommandReceived);
1839061da546Spatrick m_event_handler_thread.Join(nullptr);
1840061da546Spatrick }
1841061da546Spatrick }
1842061da546Spatrick
IOHandlerThread()1843*f6aab3d8Srobert lldb::thread_result_t Debugger::IOHandlerThread() {
1844*f6aab3d8Srobert RunIOHandlers();
1845*f6aab3d8Srobert StopEventHandlerThread();
1846061da546Spatrick return {};
1847061da546Spatrick }
1848061da546Spatrick
HandleProgressEvent(const lldb::EventSP & event_sp)1849*f6aab3d8Srobert void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
1850*f6aab3d8Srobert auto *data = ProgressEventData::GetEventDataFromEvent(event_sp.get());
1851*f6aab3d8Srobert if (!data)
1852*f6aab3d8Srobert return;
1853*f6aab3d8Srobert
1854*f6aab3d8Srobert // Do some bookkeeping for the current event, regardless of whether we're
1855*f6aab3d8Srobert // going to show the progress.
1856*f6aab3d8Srobert const uint64_t id = data->GetID();
1857*f6aab3d8Srobert if (m_current_event_id) {
1858*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Events);
1859*f6aab3d8Srobert if (log && log->GetVerbose()) {
1860*f6aab3d8Srobert StreamString log_stream;
1861*f6aab3d8Srobert log_stream.AsRawOstream()
1862*f6aab3d8Srobert << static_cast<void *>(this) << " Debugger(" << GetID()
1863*f6aab3d8Srobert << ")::HandleProgressEvent( m_current_event_id = "
1864*f6aab3d8Srobert << *m_current_event_id << ", data = { ";
1865*f6aab3d8Srobert data->Dump(&log_stream);
1866*f6aab3d8Srobert log_stream << " } )";
1867*f6aab3d8Srobert log->PutString(log_stream.GetString());
1868*f6aab3d8Srobert }
1869*f6aab3d8Srobert if (id != *m_current_event_id)
1870*f6aab3d8Srobert return;
1871*f6aab3d8Srobert if (data->GetCompleted() == data->GetTotal())
1872*f6aab3d8Srobert m_current_event_id.reset();
1873*f6aab3d8Srobert } else {
1874*f6aab3d8Srobert m_current_event_id = id;
1875*f6aab3d8Srobert }
1876*f6aab3d8Srobert
1877*f6aab3d8Srobert // Decide whether we actually are going to show the progress. This decision
1878*f6aab3d8Srobert // can change between iterations so check it inside the loop.
1879*f6aab3d8Srobert if (!GetShowProgress())
1880*f6aab3d8Srobert return;
1881*f6aab3d8Srobert
1882*f6aab3d8Srobert // Determine whether the current output file is an interactive terminal with
1883*f6aab3d8Srobert // color support. We assume that if we support ANSI escape codes we support
1884*f6aab3d8Srobert // vt100 escape codes.
1885*f6aab3d8Srobert File &file = GetOutputFile();
1886*f6aab3d8Srobert if (!file.GetIsInteractive() || !file.GetIsTerminalWithColors())
1887*f6aab3d8Srobert return;
1888*f6aab3d8Srobert
1889*f6aab3d8Srobert StreamSP output = GetAsyncOutputStream();
1890*f6aab3d8Srobert
1891*f6aab3d8Srobert // Print over previous line, if any.
1892*f6aab3d8Srobert output->Printf("\r");
1893*f6aab3d8Srobert
1894*f6aab3d8Srobert if (data->GetCompleted() == data->GetTotal()) {
1895*f6aab3d8Srobert // Clear the current line.
1896*f6aab3d8Srobert output->Printf("\x1B[2K");
1897*f6aab3d8Srobert output->Flush();
1898*f6aab3d8Srobert return;
1899*f6aab3d8Srobert }
1900*f6aab3d8Srobert
1901*f6aab3d8Srobert // Trim the progress message if it exceeds the window's width and print it.
1902*f6aab3d8Srobert std::string message = data->GetMessage();
1903*f6aab3d8Srobert if (data->IsFinite())
1904*f6aab3d8Srobert message = llvm::formatv("[{0}/{1}] {2}", data->GetCompleted(),
1905*f6aab3d8Srobert data->GetTotal(), message)
1906*f6aab3d8Srobert .str();
1907*f6aab3d8Srobert
1908*f6aab3d8Srobert // Trim the progress message if it exceeds the window's width and print it.
1909*f6aab3d8Srobert const uint32_t term_width = GetTerminalWidth();
1910*f6aab3d8Srobert const uint32_t ellipsis = 3;
1911*f6aab3d8Srobert if (message.size() + ellipsis >= term_width)
1912*f6aab3d8Srobert message = message.substr(0, term_width - ellipsis);
1913*f6aab3d8Srobert
1914*f6aab3d8Srobert const bool use_color = GetUseColor();
1915*f6aab3d8Srobert llvm::StringRef ansi_prefix = GetShowProgressAnsiPrefix();
1916*f6aab3d8Srobert if (!ansi_prefix.empty())
1917*f6aab3d8Srobert output->Printf(
1918*f6aab3d8Srobert "%s", ansi::FormatAnsiTerminalCodes(ansi_prefix, use_color).c_str());
1919*f6aab3d8Srobert
1920*f6aab3d8Srobert output->Printf("%s...", message.c_str());
1921*f6aab3d8Srobert
1922*f6aab3d8Srobert llvm::StringRef ansi_suffix = GetShowProgressAnsiSuffix();
1923*f6aab3d8Srobert if (!ansi_suffix.empty())
1924*f6aab3d8Srobert output->Printf(
1925*f6aab3d8Srobert "%s", ansi::FormatAnsiTerminalCodes(ansi_suffix, use_color).c_str());
1926*f6aab3d8Srobert
1927*f6aab3d8Srobert // Clear until the end of the line.
1928*f6aab3d8Srobert output->Printf("\x1B[K\r");
1929*f6aab3d8Srobert
1930*f6aab3d8Srobert // Flush the output.
1931*f6aab3d8Srobert output->Flush();
1932*f6aab3d8Srobert }
1933*f6aab3d8Srobert
HandleDiagnosticEvent(const lldb::EventSP & event_sp)1934*f6aab3d8Srobert void Debugger::HandleDiagnosticEvent(const lldb::EventSP &event_sp) {
1935*f6aab3d8Srobert auto *data = DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
1936*f6aab3d8Srobert if (!data)
1937*f6aab3d8Srobert return;
1938*f6aab3d8Srobert
1939*f6aab3d8Srobert StreamSP stream = GetAsyncErrorStream();
1940*f6aab3d8Srobert data->Dump(stream.get());
1941*f6aab3d8Srobert }
1942*f6aab3d8Srobert
HasIOHandlerThread()1943061da546Spatrick bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); }
1944061da546Spatrick
StartIOHandlerThread()1945061da546Spatrick bool Debugger::StartIOHandlerThread() {
1946061da546Spatrick if (!m_io_handler_thread.IsJoinable()) {
1947061da546Spatrick llvm::Expected<HostThread> io_handler_thread = ThreadLauncher::LaunchThread(
1948*f6aab3d8Srobert "lldb.debugger.io-handler", [this] { return IOHandlerThread(); },
1949061da546Spatrick 8 * 1024 * 1024); // Use larger 8MB stack for this thread
1950061da546Spatrick if (io_handler_thread) {
1951061da546Spatrick m_io_handler_thread = *io_handler_thread;
1952061da546Spatrick } else {
1953*f6aab3d8Srobert LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}",
1954061da546Spatrick llvm::toString(io_handler_thread.takeError()));
1955061da546Spatrick }
1956061da546Spatrick }
1957061da546Spatrick return m_io_handler_thread.IsJoinable();
1958061da546Spatrick }
1959061da546Spatrick
StopIOHandlerThread()1960061da546Spatrick void Debugger::StopIOHandlerThread() {
1961061da546Spatrick if (m_io_handler_thread.IsJoinable()) {
1962061da546Spatrick GetInputFile().Close();
1963061da546Spatrick m_io_handler_thread.Join(nullptr);
1964061da546Spatrick }
1965061da546Spatrick }
1966061da546Spatrick
JoinIOHandlerThread()1967061da546Spatrick void Debugger::JoinIOHandlerThread() {
1968061da546Spatrick if (HasIOHandlerThread()) {
1969061da546Spatrick thread_result_t result;
1970061da546Spatrick m_io_handler_thread.Join(&result);
1971061da546Spatrick m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
1972061da546Spatrick }
1973061da546Spatrick }
1974061da546Spatrick
GetSelectedOrDummyTarget(bool prefer_dummy)1975be691f3bSpatrick Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) {
1976061da546Spatrick if (!prefer_dummy) {
1977be691f3bSpatrick if (TargetSP target = m_target_list.GetSelectedTarget())
1978be691f3bSpatrick return *target;
1979061da546Spatrick }
1980061da546Spatrick return GetDummyTarget();
1981061da546Spatrick }
1982061da546Spatrick
RunREPL(LanguageType language,const char * repl_options)1983061da546Spatrick Status Debugger::RunREPL(LanguageType language, const char *repl_options) {
1984061da546Spatrick Status err;
1985061da546Spatrick FileSpec repl_executable;
1986061da546Spatrick
1987*f6aab3d8Srobert if (language == eLanguageTypeUnknown)
1988*f6aab3d8Srobert language = GetREPLLanguage();
1989*f6aab3d8Srobert
1990061da546Spatrick if (language == eLanguageTypeUnknown) {
1991061da546Spatrick LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
1992061da546Spatrick
1993061da546Spatrick if (auto single_lang = repl_languages.GetSingularLanguage()) {
1994061da546Spatrick language = *single_lang;
1995061da546Spatrick } else if (repl_languages.Empty()) {
1996*f6aab3d8Srobert err.SetErrorString(
1997061da546Spatrick "LLDB isn't configured with REPL support for any languages.");
1998061da546Spatrick return err;
1999061da546Spatrick } else {
2000*f6aab3d8Srobert err.SetErrorString(
2001061da546Spatrick "Multiple possible REPL languages. Please specify a language.");
2002061da546Spatrick return err;
2003061da546Spatrick }
2004061da546Spatrick }
2005061da546Spatrick
2006061da546Spatrick Target *const target =
2007061da546Spatrick nullptr; // passing in an empty target means the REPL must create one
2008061da546Spatrick
2009061da546Spatrick REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options));
2010061da546Spatrick
2011061da546Spatrick if (!err.Success()) {
2012061da546Spatrick return err;
2013061da546Spatrick }
2014061da546Spatrick
2015061da546Spatrick if (!repl_sp) {
2016061da546Spatrick err.SetErrorStringWithFormat("couldn't find a REPL for %s",
2017061da546Spatrick Language::GetNameForLanguageType(language));
2018061da546Spatrick return err;
2019061da546Spatrick }
2020061da546Spatrick
2021061da546Spatrick repl_sp->SetCompilerOptions(repl_options);
2022061da546Spatrick repl_sp->RunLoop();
2023061da546Spatrick
2024061da546Spatrick return err;
2025061da546Spatrick }
2026*f6aab3d8Srobert
GetThreadPool()2027*f6aab3d8Srobert llvm::ThreadPool &Debugger::GetThreadPool() {
2028*f6aab3d8Srobert assert(g_thread_pool &&
2029*f6aab3d8Srobert "Debugger::GetThreadPool called before Debugger::Initialize");
2030*f6aab3d8Srobert return *g_thread_pool;
2031*f6aab3d8Srobert }
2032