180814287SRaphael Isemann //===-- Debugger.cpp ------------------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner
94a33d318SGreg Clayton #include "lldb/Core/Debugger.h"
104a33d318SGreg Clayton
11672d2c12SJonas Devlieghere #include "lldb/Breakpoint/Breakpoint.h"
125e65e79bSJonas Devlieghere #include "lldb/Core/DebuggerEvents.h"
13554f68d3SGreg Clayton #include "lldb/Core/FormatEntity.h"
14672d2c12SJonas Devlieghere #include "lldb/Core/Mangled.h"
15672d2c12SJonas Devlieghere #include "lldb/Core/ModuleList.h"
16e8cd0c98SGreg Clayton #include "lldb/Core/PluginManager.h"
175b52f0c7SJim Ingham #include "lldb/Core/StreamAsynchronousIO.h"
1844d93782SGreg Clayton #include "lldb/Core/StreamFile.h"
195548cb50SEnrico Granata #include "lldb/DataFormatters/DataVisualization.h"
203e7e915dSSean Callanan #include "lldb/Expression/REPL.h"
21672d2c12SJonas Devlieghere #include "lldb/Host/File.h"
2235e4c84cSJonas Devlieghere #include "lldb/Host/FileSystem.h"
2342ff0ad8SZachary Turner #include "lldb/Host/HostInfo.h"
24a3406614SGreg Clayton #include "lldb/Host/Terminal.h"
2539de3110SZachary Turner #include "lldb/Host/ThreadLauncher.h"
266611103cSGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h"
27d6b64612SMed Ismail Bennani #include "lldb/Interpreter/CommandReturnObject.h"
28672d2c12SJonas Devlieghere #include "lldb/Interpreter/OptionValue.h"
2946a28a95SJonas Devlieghere #include "lldb/Interpreter/OptionValueLanguage.h"
30633a29cfSZachary Turner #include "lldb/Interpreter/OptionValueProperties.h"
3167cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueSInt64.h"
3267cc0636SGreg Clayton #include "lldb/Interpreter/OptionValueString.h"
33672d2c12SJonas Devlieghere #include "lldb/Interpreter/Property.h"
34672d2c12SJonas Devlieghere #include "lldb/Interpreter/ScriptInterpreter.h"
351f746071SGreg Clayton #include "lldb/Symbol/Function.h"
361f746071SGreg Clayton #include "lldb/Symbol/Symbol.h"
37672d2c12SJonas Devlieghere #include "lldb/Symbol/SymbolContext.h"
383e7e915dSSean Callanan #include "lldb/Target/Language.h"
3930fdc8d8SChris Lattner #include "lldb/Target/Process.h"
4075930019STodd Fiala #include "lldb/Target/StructuredDataPlugin.h"
4184a53dfbSEnrico Granata #include "lldb/Target/Target.h"
42b9c1b51eSKate Stone #include "lldb/Target/TargetList.h"
4330fdc8d8SChris Lattner #include "lldb/Target/Thread.h"
44672d2c12SJonas Devlieghere #include "lldb/Target/ThreadList.h"
455a31471eSGreg Clayton #include "lldb/Utility/AnsiTerminal.h"
46181b823bSPavel Labath #include "lldb/Utility/Event.h"
47c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
48181b823bSPavel Labath #include "lldb/Utility/Listener.h"
49672d2c12SJonas Devlieghere #include "lldb/Utility/Log.h"
509e046f02SJonas Devlieghere #include "lldb/Utility/Reproducer.h"
51f23b829aSLevon Ter-Grigoryan #include "lldb/Utility/ReproducerProvider.h"
52d821c997SPavel Labath #include "lldb/Utility/State.h"
53672d2c12SJonas Devlieghere #include "lldb/Utility/Stream.h"
54bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
552f3df613SZachary Turner
56b1cb0b79SNico Weber #if defined(_WIN32)
57672d2c12SJonas Devlieghere #include "lldb/Host/windows/PosixApi.h"
588aa23614SDavid Bolvansky #include "lldb/Host/windows/windows.h"
592f3df613SZachary Turner #endif
602f3df613SZachary Turner
61672d2c12SJonas Devlieghere #include "llvm/ADT/None.h"
62672d2c12SJonas Devlieghere #include "llvm/ADT/STLExtras.h"
632f3df613SZachary Turner #include "llvm/ADT/StringRef.h"
64672d2c12SJonas Devlieghere #include "llvm/ADT/iterator.h"
652f3df613SZachary Turner #include "llvm/Support/DynamicLibrary.h"
662f3df613SZachary Turner #include "llvm/Support/FileSystem.h"
678aa23614SDavid Bolvansky #include "llvm/Support/Process.h"
6820048f31SLuboš Luňák #include "llvm/Support/ThreadPool.h"
692f3df613SZachary Turner #include "llvm/Support/Threading.h"
70672d2c12SJonas Devlieghere #include "llvm/Support/raw_ostream.h"
712f3df613SZachary Turner
7276e47d48SRaphael Isemann #include <cstdio>
7376e47d48SRaphael Isemann #include <cstdlib>
7476e47d48SRaphael Isemann #include <cstring>
75672d2c12SJonas Devlieghere #include <list>
76672d2c12SJonas Devlieghere #include <memory>
772f3df613SZachary Turner #include <mutex>
78672d2c12SJonas Devlieghere #include <set>
79672d2c12SJonas Devlieghere #include <string>
80672d2c12SJonas Devlieghere #include <system_error>
812f3df613SZachary Turner
82f23b829aSLevon Ter-Grigoryan // Includes for pipe()
83f23b829aSLevon Ter-Grigoryan #if defined(_WIN32)
84f23b829aSLevon Ter-Grigoryan #include <fcntl.h>
85f23b829aSLevon Ter-Grigoryan #include <io.h>
86f23b829aSLevon Ter-Grigoryan #else
87f23b829aSLevon Ter-Grigoryan #include <unistd.h>
88f23b829aSLevon Ter-Grigoryan #endif
89f23b829aSLevon Ter-Grigoryan
902f3df613SZachary Turner namespace lldb_private {
912f3df613SZachary Turner class Address;
922f3df613SZachary Turner }
9330fdc8d8SChris Lattner
9430fdc8d8SChris Lattner using namespace lldb;
9530fdc8d8SChris Lattner using namespace lldb_private;
9630fdc8d8SChris Lattner
97ebc1bb27SCaroline Tice static lldb::user_id_t g_unique_id = 1;
987c2896a2SZachary Turner static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024;
99ebc1bb27SCaroline Tice
1001b654882SGreg Clayton #pragma mark Static Functions
1011b654882SGreg Clayton
1021b654882SGreg Clayton typedef std::vector<DebuggerSP> DebuggerList;
103b9c1b51eSKate Stone static std::recursive_mutex *g_debugger_list_mutex_ptr =
104b9c1b51eSKate Stone nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
105b9c1b51eSKate Stone static DebuggerList *g_debugger_list_ptr =
106b9c1b51eSKate Stone nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain
107e372b98dSGreg Clayton
1088fe53c49STatyana Krasnukha static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = {
109e063ecccSJonas Devlieghere {
110e063ecccSJonas Devlieghere Debugger::eStopDisassemblyTypeNever,
111e063ecccSJonas Devlieghere "never",
112e063ecccSJonas Devlieghere "Never show disassembly when displaying a stop context.",
113e063ecccSJonas Devlieghere },
114e063ecccSJonas Devlieghere {
115e063ecccSJonas Devlieghere Debugger::eStopDisassemblyTypeNoDebugInfo,
116e063ecccSJonas Devlieghere "no-debuginfo",
117e063ecccSJonas Devlieghere "Show disassembly when there is no debug information.",
118e063ecccSJonas Devlieghere },
119e063ecccSJonas Devlieghere {
120e063ecccSJonas Devlieghere Debugger::eStopDisassemblyTypeNoSource,
121e063ecccSJonas Devlieghere "no-source",
122e063ecccSJonas Devlieghere "Show disassembly when there is no source information, or the source "
123e063ecccSJonas Devlieghere "file "
124e063ecccSJonas Devlieghere "is missing when displaying a stop context.",
125e063ecccSJonas Devlieghere },
126e063ecccSJonas Devlieghere {
127e063ecccSJonas Devlieghere Debugger::eStopDisassemblyTypeAlways,
128e063ecccSJonas Devlieghere "always",
129e063ecccSJonas Devlieghere "Always show disassembly when displaying a stop context.",
130e063ecccSJonas Devlieghere },
131e063ecccSJonas Devlieghere };
132e372b98dSGreg Clayton
1338fe53c49STatyana Krasnukha static constexpr OptionEnumValueElement g_language_enumerators[] = {
134e063ecccSJonas Devlieghere {
135e063ecccSJonas Devlieghere eScriptLanguageNone,
136e063ecccSJonas Devlieghere "none",
137e063ecccSJonas Devlieghere "Disable scripting languages.",
138e063ecccSJonas Devlieghere },
139e063ecccSJonas Devlieghere {
140e063ecccSJonas Devlieghere eScriptLanguagePython,
141e063ecccSJonas Devlieghere "python",
142e063ecccSJonas Devlieghere "Select python as the default scripting language.",
143e063ecccSJonas Devlieghere },
144e063ecccSJonas Devlieghere {
145e063ecccSJonas Devlieghere eScriptLanguageDefault,
146e063ecccSJonas Devlieghere "default",
147e063ecccSJonas Devlieghere "Select the lldb default as the default scripting language.",
148e063ecccSJonas Devlieghere },
149e063ecccSJonas Devlieghere };
150e372b98dSGreg Clayton
1518fe53c49STatyana Krasnukha static constexpr OptionEnumValueElement s_stop_show_column_values[] = {
152e063ecccSJonas Devlieghere {
153e063ecccSJonas Devlieghere eStopShowColumnAnsiOrCaret,
154e063ecccSJonas Devlieghere "ansi-or-caret",
155e063ecccSJonas Devlieghere "Highlight the stop column with ANSI terminal codes when color/ANSI "
156e063ecccSJonas Devlieghere "mode is enabled; otherwise, fall back to using a text-only caret (^) "
157e063ecccSJonas Devlieghere "as if \"caret-only\" mode was selected.",
158e063ecccSJonas Devlieghere },
159e063ecccSJonas Devlieghere {
160e063ecccSJonas Devlieghere eStopShowColumnAnsi,
161e063ecccSJonas Devlieghere "ansi",
162e063ecccSJonas Devlieghere "Highlight the stop column with ANSI terminal codes when running LLDB "
163e063ecccSJonas Devlieghere "with color/ANSI enabled.",
164e063ecccSJonas Devlieghere },
165e063ecccSJonas Devlieghere {
166e063ecccSJonas Devlieghere eStopShowColumnCaret,
167e063ecccSJonas Devlieghere "caret",
168e063ecccSJonas Devlieghere "Highlight the stop column with a caret character (^) underneath the "
169e063ecccSJonas Devlieghere "stop column. This method introduces a new line in source listings "
170e063ecccSJonas Devlieghere "that display thread stop locations.",
171e063ecccSJonas Devlieghere },
172e063ecccSJonas Devlieghere {
173e063ecccSJonas Devlieghere eStopShowColumnNone,
174e063ecccSJonas Devlieghere "none",
175e063ecccSJonas Devlieghere "Do not highlight the stop column.",
176e063ecccSJonas Devlieghere },
177e063ecccSJonas Devlieghere };
1789666ba75STodd Fiala
179971f9ca6SJonas Devlieghere #define LLDB_PROPERTIES_debugger
1806a253d37SJordan Rupprecht #include "CoreProperties.inc"
18167cc0636SGreg Clayton
182b9c1b51eSKate Stone enum {
183971f9ca6SJonas Devlieghere #define LLDB_PROPERTIES_debugger
1846a253d37SJordan Rupprecht #include "CorePropertiesEnum.inc"
18567cc0636SGreg Clayton };
18667cc0636SGreg Clayton
187df370550SEugene Zelenko LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr;
1884c05410fSGreg Clayton
SetPropertyValue(const ExecutionContext * exe_ctx,VarSetOperationType op,llvm::StringRef property_path,llvm::StringRef value)18997206d57SZachary Turner Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx,
1904c05410fSGreg Clayton VarSetOperationType op,
19197206d57SZachary Turner llvm::StringRef property_path,
19297206d57SZachary Turner llvm::StringRef value) {
193e063ecccSJonas Devlieghere bool is_load_script =
194e063ecccSJonas Devlieghere (property_path == "target.load-script-from-symbol-file");
195e5814d78SRaphael Isemann // These properties might change how we visualize data.
196e5814d78SRaphael Isemann bool invalidate_data_vis = (property_path == "escape-non-printables");
197e5814d78SRaphael Isemann invalidate_data_vis |=
198e5814d78SRaphael Isemann (property_path == "target.max-zero-padding-in-float-format");
199e5814d78SRaphael Isemann if (invalidate_data_vis) {
200e5814d78SRaphael Isemann DataVisualization::ForceUpdate();
201e5814d78SRaphael Isemann }
202e5814d78SRaphael Isemann
20384a53dfbSEnrico Granata TargetSP target_sp;
204397ddd5fSEnrico Granata LoadScriptFromSymFile load_script_old_value;
205b9c1b51eSKate Stone if (is_load_script && exe_ctx->GetTargetSP()) {
20684a53dfbSEnrico Granata target_sp = exe_ctx->GetTargetSP();
207b9c1b51eSKate Stone load_script_old_value =
208b9c1b51eSKate Stone target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
20984a53dfbSEnrico Granata }
21097206d57SZachary Turner Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value));
211b9c1b51eSKate Stone if (error.Success()) {
21284a53dfbSEnrico Granata // FIXME it would be nice to have "on-change" callbacks for properties
213a8ea5955SJonas Devlieghere if (property_path == g_debugger_properties[ePropertyPrompt].name) {
214514d8cd8SZachary Turner llvm::StringRef new_prompt = GetPrompt();
2154b3c0fd5SJonas Devlieghere std::string str = lldb_private::ansi::FormatAnsiTerminalCodes(
216b9c1b51eSKate Stone new_prompt, GetUseColor());
217c3ce7f27SMichael Sartain if (str.length())
218771ef6d4SMalcolm Parsons new_prompt = str;
21944d93782SGreg Clayton GetCommandInterpreter().UpdatePrompt(new_prompt);
220a8f3ae7cSJonas Devlieghere auto bytes = std::make_unique<EventDataBytes>(new_prompt);
2212f3df613SZachary Turner auto prompt_change_event_sp = std::make_shared<Event>(
2222f3df613SZachary Turner CommandInterpreter::eBroadcastBitResetPrompt, bytes.release());
2234c05410fSGreg Clayton GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp);
224a8ea5955SJonas Devlieghere } else if (property_path == g_debugger_properties[ePropertyUseColor].name) {
225b9c1b51eSKate Stone // use-color changed. Ping the prompt so it can reset the ansi terminal
226b9c1b51eSKate Stone // codes.
227c3ce7f27SMichael Sartain SetPrompt(GetPrompt());
228acae69d0SEmre Kultursay } else if (property_path == g_debugger_properties[ePropertyUseSourceCache].name) {
229acae69d0SEmre Kultursay // use-source-cache changed. Wipe out the cache contents if it was disabled.
230acae69d0SEmre Kultursay if (!GetUseSourceCache()) {
231acae69d0SEmre Kultursay m_source_file_cache.Clear();
232acae69d0SEmre Kultursay }
233b9c1b51eSKate Stone } else if (is_load_script && target_sp &&
234b9c1b51eSKate Stone load_script_old_value == eLoadScriptFromSymFileWarn) {
235b9c1b51eSKate Stone if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() ==
236b9c1b51eSKate Stone eLoadScriptFromSymFileTrue) {
23797206d57SZachary Turner std::list<Status> errors;
2389730339bSEnrico Granata StreamString feedback_stream;
239b9c1b51eSKate Stone if (!target_sp->LoadScriptingResources(errors, &feedback_stream)) {
2407ca15ba7SLawrence D'Anna Stream &s = GetErrorStream();
241b9c1b51eSKate Stone for (auto error : errors) {
2427ca15ba7SLawrence D'Anna s.Printf("%s\n", error.AsCString());
24384a53dfbSEnrico Granata }
2449730339bSEnrico Granata if (feedback_stream.GetSize())
2457ca15ba7SLawrence D'Anna s.PutCString(feedback_stream.GetString());
24684a53dfbSEnrico Granata }
24784a53dfbSEnrico Granata }
248ebdc1ac0SEnrico Granata }
2494c05410fSGreg Clayton }
2504c05410fSGreg Clayton return error;
2514c05410fSGreg Clayton }
2524c05410fSGreg Clayton
GetAutoConfirm() const253b9c1b51eSKate Stone bool Debugger::GetAutoConfirm() const {
25467cc0636SGreg Clayton const uint32_t idx = ePropertyAutoConfirm;
255b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsBoolean(
256a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
25767cc0636SGreg Clayton }
25867cc0636SGreg Clayton
GetDisassemblyFormat() const259b9c1b51eSKate Stone const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const {
260aff1b357SJason Molenda const uint32_t idx = ePropertyDisassemblyFormat;
261df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
262aff1b357SJason Molenda }
263aff1b357SJason Molenda
GetFrameFormat() const264b9c1b51eSKate Stone const FormatEntity::Entry *Debugger::GetFrameFormat() const {
26567cc0636SGreg Clayton const uint32_t idx = ePropertyFrameFormat;
266df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
26767cc0636SGreg Clayton }
26867cc0636SGreg Clayton
GetFrameFormatUnique() const2697f1c1211SPavel Labath const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const {
2707f1c1211SPavel Labath const uint32_t idx = ePropertyFrameFormatUnique;
2717f1c1211SPavel Labath return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
2727f1c1211SPavel Labath }
2737f1c1211SPavel Labath
GetStopDisassemblyMaxSize() const274b889ef42SMed Ismail Bennani uint32_t Debugger::GetStopDisassemblyMaxSize() const {
275b889ef42SMed Ismail Bennani const uint32_t idx = ePropertyStopDisassemblyMaxSize;
276b889ef42SMed Ismail Bennani return m_collection_sp->GetPropertyAtIndexAsUInt64(
277b889ef42SMed Ismail Bennani nullptr, idx, g_debugger_properties[idx].default_uint_value);
278b889ef42SMed Ismail Bennani }
279b889ef42SMed Ismail Bennani
GetNotifyVoid() const280b9c1b51eSKate Stone bool Debugger::GetNotifyVoid() const {
28167cc0636SGreg Clayton const uint32_t idx = ePropertyNotiftVoid;
282b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsBoolean(
283a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
28467cc0636SGreg Clayton }
28567cc0636SGreg Clayton
GetPrompt() const286514d8cd8SZachary Turner llvm::StringRef Debugger::GetPrompt() const {
28767cc0636SGreg Clayton const uint32_t idx = ePropertyPrompt;
288b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsString(
289a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_cstr_value);
29067cc0636SGreg Clayton }
29167cc0636SGreg Clayton
SetPrompt(llvm::StringRef p)292514d8cd8SZachary Turner void Debugger::SetPrompt(llvm::StringRef p) {
29367cc0636SGreg Clayton const uint32_t idx = ePropertyPrompt;
294df370550SEugene Zelenko m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p);
295514d8cd8SZachary Turner llvm::StringRef new_prompt = GetPrompt();
296b9c1b51eSKate Stone std::string str =
2974b3c0fd5SJonas Devlieghere lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor());
298c3ce7f27SMichael Sartain if (str.length())
299771ef6d4SMalcolm Parsons new_prompt = str;
30044d93782SGreg Clayton GetCommandInterpreter().UpdatePrompt(new_prompt);
30167cc0636SGreg Clayton }
30267cc0636SGreg Clayton
GetReproducerPath() const3039e046f02SJonas Devlieghere llvm::StringRef Debugger::GetReproducerPath() const {
3049e046f02SJonas Devlieghere auto &r = repro::Reproducer::Instance();
305*1b4b12a3SNico Weber return r.GetReproducerPath().GetCString();
3069e046f02SJonas Devlieghere }
3079e046f02SJonas Devlieghere
GetThreadFormat() const308b9c1b51eSKate Stone const FormatEntity::Entry *Debugger::GetThreadFormat() const {
30967cc0636SGreg Clayton const uint32_t idx = ePropertyThreadFormat;
310df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
31167cc0636SGreg Clayton }
31267cc0636SGreg Clayton
GetThreadStopFormat() const3136a9767c7SJim Ingham const FormatEntity::Entry *Debugger::GetThreadStopFormat() const {
3146a9767c7SJim Ingham const uint32_t idx = ePropertyThreadStopFormat;
3156a9767c7SJim Ingham return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
3166a9767c7SJim Ingham }
3176a9767c7SJim Ingham
GetScriptLanguage() const318b9c1b51eSKate Stone lldb::ScriptLanguage Debugger::GetScriptLanguage() const {
31967cc0636SGreg Clayton const uint32_t idx = ePropertyScriptLanguage;
320b9c1b51eSKate Stone return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration(
321a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
32267cc0636SGreg Clayton }
32367cc0636SGreg Clayton
SetScriptLanguage(lldb::ScriptLanguage script_lang)324b9c1b51eSKate Stone bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) {
32567cc0636SGreg Clayton const uint32_t idx = ePropertyScriptLanguage;
326b9c1b51eSKate Stone return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx,
327b9c1b51eSKate Stone script_lang);
32867cc0636SGreg Clayton }
32967cc0636SGreg Clayton
GetREPLLanguage() const33046a28a95SJonas Devlieghere lldb::LanguageType Debugger::GetREPLLanguage() const {
33146a28a95SJonas Devlieghere const uint32_t idx = ePropertyREPLLanguage;
33246a28a95SJonas Devlieghere OptionValueLanguage *value =
33346a28a95SJonas Devlieghere m_collection_sp->GetPropertyAtIndexAsOptionValueLanguage(nullptr, idx);
33446a28a95SJonas Devlieghere if (value)
33546a28a95SJonas Devlieghere return value->GetCurrentValue();
33646a28a95SJonas Devlieghere return LanguageType();
33746a28a95SJonas Devlieghere }
33846a28a95SJonas Devlieghere
SetREPLLanguage(lldb::LanguageType repl_lang)33946a28a95SJonas Devlieghere bool Debugger::SetREPLLanguage(lldb::LanguageType repl_lang) {
34046a28a95SJonas Devlieghere const uint32_t idx = ePropertyREPLLanguage;
34146a28a95SJonas Devlieghere return m_collection_sp->SetPropertyAtIndexAsLanguage(nullptr, idx, repl_lang);
34246a28a95SJonas Devlieghere }
34346a28a95SJonas Devlieghere
GetTerminalWidth() const344b9c1b51eSKate Stone uint32_t Debugger::GetTerminalWidth() const {
34567cc0636SGreg Clayton const uint32_t idx = ePropertyTerminalWidth;
346b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsSInt64(
347a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
34867cc0636SGreg Clayton }
34967cc0636SGreg Clayton
SetTerminalWidth(uint32_t term_width)350b9c1b51eSKate Stone bool Debugger::SetTerminalWidth(uint32_t term_width) {
351d9166ad2SFred Riss if (auto handler_sp = m_io_handler_stack.Top())
352d9166ad2SFred Riss handler_sp->TerminalSizeChanged();
353d9166ad2SFred Riss
35467cc0636SGreg Clayton const uint32_t idx = ePropertyTerminalWidth;
355df370550SEugene Zelenko return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width);
35667cc0636SGreg Clayton }
35767cc0636SGreg Clayton
GetUseExternalEditor() const358b9c1b51eSKate Stone bool Debugger::GetUseExternalEditor() const {
35967cc0636SGreg Clayton const uint32_t idx = ePropertyUseExternalEditor;
360b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsBoolean(
361a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
36267cc0636SGreg Clayton }
36367cc0636SGreg Clayton
SetUseExternalEditor(bool b)364b9c1b51eSKate Stone bool Debugger::SetUseExternalEditor(bool b) {
36567cc0636SGreg Clayton const uint32_t idx = ePropertyUseExternalEditor;
366df370550SEugene Zelenko return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
36767cc0636SGreg Clayton }
36867cc0636SGreg Clayton
GetUseColor() const369b9c1b51eSKate Stone bool Debugger::GetUseColor() const {
370c3ce7f27SMichael Sartain const uint32_t idx = ePropertyUseColor;
371b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsBoolean(
372a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
373c3ce7f27SMichael Sartain }
374c3ce7f27SMichael Sartain
SetUseColor(bool b)375b9c1b51eSKate Stone bool Debugger::SetUseColor(bool b) {
376c3ce7f27SMichael Sartain const uint32_t idx = ePropertyUseColor;
377df370550SEugene Zelenko bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
378c3ce7f27SMichael Sartain SetPrompt(GetPrompt());
379c3ce7f27SMichael Sartain return ret;
380c3ce7f27SMichael Sartain }
381c3ce7f27SMichael Sartain
GetShowProgress() const3825a27b998SJonas Devlieghere bool Debugger::GetShowProgress() const {
3835a27b998SJonas Devlieghere const uint32_t idx = ePropertyShowProgress;
3845a27b998SJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsBoolean(
3855a27b998SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
3865a27b998SJonas Devlieghere }
3875a27b998SJonas Devlieghere
SetShowProgress(bool show_progress)388cbcb3bceSJonas Devlieghere bool Debugger::SetShowProgress(bool show_progress) {
389cbcb3bceSJonas Devlieghere const uint32_t idx = ePropertyShowProgress;
390cbcb3bceSJonas Devlieghere return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx,
391cbcb3bceSJonas Devlieghere show_progress);
392cbcb3bceSJonas Devlieghere }
393cbcb3bceSJonas Devlieghere
GetShowProgressAnsiPrefix() const394097d46f4SJonas Devlieghere llvm::StringRef Debugger::GetShowProgressAnsiPrefix() const {
395097d46f4SJonas Devlieghere const uint32_t idx = ePropertyShowProgressAnsiPrefix;
396097d46f4SJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
397097d46f4SJonas Devlieghere }
398097d46f4SJonas Devlieghere
GetShowProgressAnsiSuffix() const399097d46f4SJonas Devlieghere llvm::StringRef Debugger::GetShowProgressAnsiSuffix() const {
400097d46f4SJonas Devlieghere const uint32_t idx = ePropertyShowProgressAnsiSuffix;
401097d46f4SJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
402097d46f4SJonas Devlieghere }
403097d46f4SJonas Devlieghere
GetUseAutosuggestion() const404de9e8502SShu Anzai bool Debugger::GetUseAutosuggestion() const {
405de9e8502SShu Anzai const uint32_t idx = ePropertyShowAutosuggestion;
406de9e8502SShu Anzai return m_collection_sp->GetPropertyAtIndexAsBoolean(
407de9e8502SShu Anzai nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
408de9e8502SShu Anzai }
409de9e8502SShu Anzai
GetAutosuggestionAnsiPrefix() const410080635efSJonas Devlieghere llvm::StringRef Debugger::GetAutosuggestionAnsiPrefix() const {
411080635efSJonas Devlieghere const uint32_t idx = ePropertyShowAutosuggestionAnsiPrefix;
412080635efSJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
413080635efSJonas Devlieghere }
414080635efSJonas Devlieghere
GetAutosuggestionAnsiSuffix() const415080635efSJonas Devlieghere llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
416080635efSJonas Devlieghere const uint32_t idx = ePropertyShowAutosuggestionAnsiSuffix;
417080635efSJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
418080635efSJonas Devlieghere }
419080635efSJonas Devlieghere
GetUseSourceCache() const420acae69d0SEmre Kultursay bool Debugger::GetUseSourceCache() const {
421acae69d0SEmre Kultursay const uint32_t idx = ePropertyUseSourceCache;
422acae69d0SEmre Kultursay return m_collection_sp->GetPropertyAtIndexAsBoolean(
423acae69d0SEmre Kultursay nullptr, idx, g_debugger_properties[idx].default_uint_value != 0);
424acae69d0SEmre Kultursay }
425acae69d0SEmre Kultursay
SetUseSourceCache(bool b)426acae69d0SEmre Kultursay bool Debugger::SetUseSourceCache(bool b) {
427acae69d0SEmre Kultursay const uint32_t idx = ePropertyUseSourceCache;
428acae69d0SEmre Kultursay bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
429acae69d0SEmre Kultursay if (!ret) {
430acae69d0SEmre Kultursay m_source_file_cache.Clear();
431acae69d0SEmre Kultursay }
432acae69d0SEmre Kultursay return ret;
433acae69d0SEmre Kultursay }
GetHighlightSource() const434566afa0aSRaphael Isemann bool Debugger::GetHighlightSource() const {
435566afa0aSRaphael Isemann const uint32_t idx = ePropertyHighlightSource;
436566afa0aSRaphael Isemann return m_collection_sp->GetPropertyAtIndexAsBoolean(
437a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
438566afa0aSRaphael Isemann }
439566afa0aSRaphael Isemann
GetStopShowColumn() const4409666ba75STodd Fiala StopShowColumn Debugger::GetStopShowColumn() const {
4419666ba75STodd Fiala const uint32_t idx = ePropertyStopShowColumn;
4429666ba75STodd Fiala return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration(
443a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
4449666ba75STodd Fiala }
4459666ba75STodd Fiala
GetStopShowColumnAnsiPrefix() const44620786326SRaphael Isemann llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const {
4479666ba75STodd Fiala const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;
44820786326SRaphael Isemann return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
4499666ba75STodd Fiala }
4509666ba75STodd Fiala
GetStopShowColumnAnsiSuffix() const45120786326SRaphael Isemann llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const {
4529666ba75STodd Fiala const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;
45320786326SRaphael Isemann return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
4549666ba75STodd Fiala }
4559666ba75STodd Fiala
GetStopShowLineMarkerAnsiPrefix() const456841be985SJonas Devlieghere llvm::StringRef Debugger::GetStopShowLineMarkerAnsiPrefix() const {
457841be985SJonas Devlieghere const uint32_t idx = ePropertyStopShowLineMarkerAnsiPrefix;
458841be985SJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
459841be985SJonas Devlieghere }
460841be985SJonas Devlieghere
GetStopShowLineMarkerAnsiSuffix() const461841be985SJonas Devlieghere llvm::StringRef Debugger::GetStopShowLineMarkerAnsiSuffix() const {
462841be985SJonas Devlieghere const uint32_t idx = ePropertyStopShowLineMarkerAnsiSuffix;
463841be985SJonas Devlieghere return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "");
464841be985SJonas Devlieghere }
465841be985SJonas Devlieghere
GetStopSourceLineCount(bool before) const466b9c1b51eSKate Stone uint32_t Debugger::GetStopSourceLineCount(bool before) const {
467b9c1b51eSKate Stone const uint32_t idx =
468b9c1b51eSKate Stone before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
469b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsSInt64(
470a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
47167cc0636SGreg Clayton }
47267cc0636SGreg Clayton
GetStopDisassemblyDisplay() const473b9c1b51eSKate Stone Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const {
47467cc0636SGreg Clayton const uint32_t idx = ePropertyStopDisassemblyDisplay;
475b9c1b51eSKate Stone return (Debugger::StopDisassemblyType)
476b9c1b51eSKate Stone m_collection_sp->GetPropertyAtIndexAsEnumeration(
477a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
47867cc0636SGreg Clayton }
47967cc0636SGreg Clayton
GetDisassemblyLineCount() const480b9c1b51eSKate Stone uint32_t Debugger::GetDisassemblyLineCount() const {
48167cc0636SGreg Clayton const uint32_t idx = ePropertyStopDisassemblyCount;
482b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsSInt64(
483a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
48467cc0636SGreg Clayton }
485e372b98dSGreg Clayton
GetAutoOneLineSummaries() const486b9c1b51eSKate Stone bool Debugger::GetAutoOneLineSummaries() const {
48790a8db30SEnrico Granata const uint32_t idx = ePropertyAutoOneLineSummaries;
488df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
489ebdc1ac0SEnrico Granata }
490553fad5cSEnrico Granata
GetEscapeNonPrintables() const491b9c1b51eSKate Stone bool Debugger::GetEscapeNonPrintables() const {
492ebdc1ac0SEnrico Granata const uint32_t idx = ePropertyEscapeNonPrintables;
493df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
494553fad5cSEnrico Granata }
495553fad5cSEnrico Granata
GetAutoIndent() const496b9c1b51eSKate Stone bool Debugger::GetAutoIndent() const {
4976681041dSSean Callanan const uint32_t idx = ePropertyAutoIndent;
498df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
4996681041dSSean Callanan }
5006681041dSSean Callanan
SetAutoIndent(bool b)501b9c1b51eSKate Stone bool Debugger::SetAutoIndent(bool b) {
5026681041dSSean Callanan const uint32_t idx = ePropertyAutoIndent;
503df370550SEugene Zelenko return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
5046681041dSSean Callanan }
5056681041dSSean Callanan
GetPrintDecls() const506b9c1b51eSKate Stone bool Debugger::GetPrintDecls() const {
5076681041dSSean Callanan const uint32_t idx = ePropertyPrintDecls;
508df370550SEugene Zelenko return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true);
5096681041dSSean Callanan }
5106681041dSSean Callanan
SetPrintDecls(bool b)511b9c1b51eSKate Stone bool Debugger::SetPrintDecls(bool b) {
5126681041dSSean Callanan const uint32_t idx = ePropertyPrintDecls;
513df370550SEugene Zelenko return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
5146681041dSSean Callanan }
5156681041dSSean Callanan
GetTabSize() const516b9c1b51eSKate Stone uint32_t Debugger::GetTabSize() const {
5176681041dSSean Callanan const uint32_t idx = ePropertyTabSize;
518b9c1b51eSKate Stone return m_collection_sp->GetPropertyAtIndexAsUInt64(
519a8ea5955SJonas Devlieghere nullptr, idx, g_debugger_properties[idx].default_uint_value);
5206681041dSSean Callanan }
5216681041dSSean Callanan
SetTabSize(uint32_t tab_size)522b9c1b51eSKate Stone bool Debugger::SetTabSize(uint32_t tab_size) {
5236681041dSSean Callanan const uint32_t idx = ePropertyTabSize;
524df370550SEugene Zelenko return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size);
5256681041dSSean Callanan }
5266681041dSSean Callanan
5271b654882SGreg Clayton #pragma mark Debugger
5281b654882SGreg Clayton
52967cc0636SGreg Clayton // const DebuggerPropertiesSP &
53067cc0636SGreg Clayton // Debugger::GetSettings() const
53167cc0636SGreg Clayton //{
53267cc0636SGreg Clayton // return m_properties_sp;
53367cc0636SGreg Clayton //}
53467cc0636SGreg Clayton //
53599d0faf2SGreg Clayton
Initialize(LoadPluginCallbackType load_plugin_callback)536b9c1b51eSKate Stone void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) {
537b9c1b51eSKate Stone assert(g_debugger_list_ptr == nullptr &&
538b9c1b51eSKate Stone "Debugger::Initialize called more than once!");
5396c42e063SGreg Clayton g_debugger_list_mutex_ptr = new std::recursive_mutex();
5406c42e063SGreg Clayton g_debugger_list_ptr = new DebuggerList();
5415fb8f797SGreg Clayton g_load_plugin_callback = load_plugin_callback;
54299d0faf2SGreg Clayton }
54330fdc8d8SChris Lattner
Terminate()544b9c1b51eSKate Stone void Debugger::Terminate() {
545b9c1b51eSKate Stone assert(g_debugger_list_ptr &&
546b9c1b51eSKate Stone "Debugger::Terminate called without a matching Debugger::Initialize!");
547e6e2bb38SZachary Turner
548b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
54995af9d88SQuinn Pham // Clear our global list of debugger objects
5506c42e063SGreg Clayton {
5516c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
5526c42e063SGreg Clayton for (const auto &debugger : *g_debugger_list_ptr)
553f3cd1819SOleksiy Vyalov debugger->Clear();
5546c42e063SGreg Clayton g_debugger_list_ptr->clear();
5556c42e063SGreg Clayton }
5566c42e063SGreg Clayton }
55730fdc8d8SChris Lattner }
55830fdc8d8SChris Lattner
SettingsInitialize()559b9c1b51eSKate Stone void Debugger::SettingsInitialize() { Target::SettingsInitialize(); }
56020bd37f7SCaroline Tice
SettingsTerminate()561b9c1b51eSKate Stone void Debugger::SettingsTerminate() { Target::SettingsTerminate(); }
56220bd37f7SCaroline Tice
LoadPlugin(const FileSpec & spec,Status & error)56397206d57SZachary Turner bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) {
564b9c1b51eSKate Stone if (g_load_plugin_callback) {
565b9c1b51eSKate Stone llvm::sys::DynamicLibrary dynlib =
566b9c1b51eSKate Stone g_load_plugin_callback(shared_from_this(), spec, error);
567b9c1b51eSKate Stone if (dynlib.isValid()) {
56858a559c0SZachary Turner m_loaded_plugins.push_back(dynlib);
56921dfcd9dSEnrico Granata return true;
57021dfcd9dSEnrico Granata }
571b9c1b51eSKate Stone } else {
57205097246SAdrian Prantl // The g_load_plugin_callback is registered in SBDebugger::Initialize() and
57305097246SAdrian Prantl // if the public API layer isn't available (code is linking against all of
57405097246SAdrian Prantl // the internal LLDB static libraries), then we can't load plugins
5755fb8f797SGreg Clayton error.SetErrorString("Public API layer is not available");
5765fb8f797SGreg Clayton }
57721dfcd9dSEnrico Granata return false;
57821dfcd9dSEnrico Granata }
57921dfcd9dSEnrico Granata
58035e4c84cSJonas Devlieghere static FileSystem::EnumerateDirectoryResult
LoadPluginCallback(void * baton,llvm::sys::fs::file_type ft,llvm::StringRef path)5817d86ee5aSZachary Turner LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft,
58235e4c84cSJonas Devlieghere llvm::StringRef path) {
58397206d57SZachary Turner Status error;
58421dfcd9dSEnrico Granata
585ad8d48f9SJonas Devlieghere static ConstString g_dylibext(".dylib");
586ad8d48f9SJonas Devlieghere static ConstString g_solibext(".so");
58721dfcd9dSEnrico Granata
58821dfcd9dSEnrico Granata if (!baton)
58935e4c84cSJonas Devlieghere return FileSystem::eEnumerateDirectoryResultQuit;
59021dfcd9dSEnrico Granata
59121dfcd9dSEnrico Granata Debugger *debugger = (Debugger *)baton;
59221dfcd9dSEnrico Granata
5937d86ee5aSZachary Turner namespace fs = llvm::sys::fs;
59405097246SAdrian Prantl // If we have a regular file, a symbolic link or unknown file type, try and
59505097246SAdrian Prantl // process the file. We must handle unknown as sometimes the directory
59621dfcd9dSEnrico Granata // enumeration might be enumerating a file system that doesn't have correct
59721dfcd9dSEnrico Granata // file type information.
5987d86ee5aSZachary Turner if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file ||
5997d86ee5aSZachary Turner ft == fs::file_type::type_unknown) {
6008f3be7a3SJonas Devlieghere FileSpec plugin_file_spec(path);
6018f3be7a3SJonas Devlieghere FileSystem::Instance().Resolve(plugin_file_spec);
60221dfcd9dSEnrico Granata
6033cf443ddSMichael Sartain if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&
604b9c1b51eSKate Stone plugin_file_spec.GetFileNameExtension() != g_solibext) {
60535e4c84cSJonas Devlieghere return FileSystem::eEnumerateDirectoryResultNext;
6063cf443ddSMichael Sartain }
60721dfcd9dSEnrico Granata
60897206d57SZachary Turner Status plugin_load_error;
609e743c782SEnrico Granata debugger->LoadPlugin(plugin_file_spec, plugin_load_error);
61021dfcd9dSEnrico Granata
61135e4c84cSJonas Devlieghere return FileSystem::eEnumerateDirectoryResultNext;
6127d86ee5aSZachary Turner } else if (ft == fs::file_type::directory_file ||
6137d86ee5aSZachary Turner ft == fs::file_type::symlink_file ||
6147d86ee5aSZachary Turner ft == fs::file_type::type_unknown) {
61505097246SAdrian Prantl // Try and recurse into anything that a directory or symbolic link. We must
61605097246SAdrian Prantl // also do this for unknown as sometimes the directory enumeration might be
61705097246SAdrian Prantl // enumerating a file system that doesn't have correct file type
61821dfcd9dSEnrico Granata // information.
61935e4c84cSJonas Devlieghere return FileSystem::eEnumerateDirectoryResultEnter;
62021dfcd9dSEnrico Granata }
62121dfcd9dSEnrico Granata
62235e4c84cSJonas Devlieghere return FileSystem::eEnumerateDirectoryResultNext;
62321dfcd9dSEnrico Granata }
62421dfcd9dSEnrico Granata
InstanceInitialize()625b9c1b51eSKate Stone void Debugger::InstanceInitialize() {
62621dfcd9dSEnrico Granata const bool find_directories = true;
62721dfcd9dSEnrico Granata const bool find_files = true;
62821dfcd9dSEnrico Granata const bool find_other = true;
62921dfcd9dSEnrico Granata char dir_path[PATH_MAX];
63060f028ffSPavel Labath if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) {
631dbd7fabaSJonas Devlieghere if (FileSystem::Instance().Exists(dir_spec) &&
632dbd7fabaSJonas Devlieghere dir_spec.GetPath(dir_path, sizeof(dir_path))) {
63335e4c84cSJonas Devlieghere FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
63435e4c84cSJonas Devlieghere find_files, find_other,
63535e4c84cSJonas Devlieghere LoadPluginCallback, this);
63621dfcd9dSEnrico Granata }
63721dfcd9dSEnrico Granata }
63821dfcd9dSEnrico Granata
63960f028ffSPavel Labath if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) {
640dbd7fabaSJonas Devlieghere if (FileSystem::Instance().Exists(dir_spec) &&
641dbd7fabaSJonas Devlieghere dir_spec.GetPath(dir_path, sizeof(dir_path))) {
64235e4c84cSJonas Devlieghere FileSystem::Instance().EnumerateDirectory(dir_path, find_directories,
64335e4c84cSJonas Devlieghere find_files, find_other,
64435e4c84cSJonas Devlieghere LoadPluginCallback, this);
64521dfcd9dSEnrico Granata }
64621dfcd9dSEnrico Granata }
647e8cd0c98SGreg Clayton
648e8cd0c98SGreg Clayton PluginManager::DebuggerInitialize(*this);
64921dfcd9dSEnrico Granata }
65021dfcd9dSEnrico Granata
CreateInstance(lldb::LogOutputCallback log_callback,void * baton)651b9c1b51eSKate Stone DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback,
652b9c1b51eSKate Stone void *baton) {
653228063cdSJim Ingham DebuggerSP debugger_sp(new Debugger(log_callback, baton));
654b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
6556c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
6566c42e063SGreg Clayton g_debugger_list_ptr->push_back(debugger_sp);
6576611103cSGreg Clayton }
65821dfcd9dSEnrico Granata debugger_sp->InstanceInitialize();
6596611103cSGreg Clayton return debugger_sp;
6606611103cSGreg Clayton }
6616611103cSGreg Clayton
Destroy(DebuggerSP & debugger_sp)662b9c1b51eSKate Stone void Debugger::Destroy(DebuggerSP &debugger_sp) {
663df370550SEugene Zelenko if (!debugger_sp)
664e02657b1SCaroline Tice return;
665e02657b1SCaroline Tice
666d6b64612SMed Ismail Bennani CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter();
667d6b64612SMed Ismail Bennani
668d6b64612SMed Ismail Bennani if (cmd_interpreter.GetSaveSessionOnQuit()) {
669d6b64612SMed Ismail Bennani CommandReturnObject result(debugger_sp->GetUseColor());
670d6b64612SMed Ismail Bennani cmd_interpreter.SaveTranscript(result);
671d6b64612SMed Ismail Bennani if (result.Succeeded())
6723d08c778SJonas Devlieghere (*debugger_sp->GetAsyncOutputStream()) << result.GetOutputData() << '\n';
673d6b64612SMed Ismail Bennani else
6743d08c778SJonas Devlieghere (*debugger_sp->GetAsyncErrorStream()) << result.GetErrorData() << '\n';
675d6b64612SMed Ismail Bennani }
676d6b64612SMed Ismail Bennani
6778314c525SJim Ingham debugger_sp->Clear();
6788314c525SJim Ingham
679b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
6806c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
6816c42e063SGreg Clayton DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
682b9c1b51eSKate Stone for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
683b9c1b51eSKate Stone if ((*pos).get() == debugger_sp.get()) {
6846c42e063SGreg Clayton g_debugger_list_ptr->erase(pos);
685e02657b1SCaroline Tice return;
686e02657b1SCaroline Tice }
687e02657b1SCaroline Tice }
688e02657b1SCaroline Tice }
689c15f55e2SGreg Clayton }
690e02657b1SCaroline Tice
FindDebuggerWithInstanceName(ConstString instance_name)691e063ecccSJonas Devlieghere DebuggerSP Debugger::FindDebuggerWithInstanceName(ConstString instance_name) {
6924d122c40SGreg Clayton DebuggerSP debugger_sp;
693b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
6946c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
6956c42e063SGreg Clayton DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
696b9c1b51eSKate Stone for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
697b9c1b51eSKate Stone if ((*pos)->m_instance_name == instance_name) {
6986920b52bSGreg Clayton debugger_sp = *pos;
6996920b52bSGreg Clayton break;
7006920b52bSGreg Clayton }
7016920b52bSGreg Clayton }
7026920b52bSGreg Clayton }
7033df9a8dfSCaroline Tice return debugger_sp;
7043df9a8dfSCaroline Tice }
7056611103cSGreg Clayton
FindTargetWithProcessID(lldb::pid_t pid)706b9c1b51eSKate Stone TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) {
7074d122c40SGreg Clayton TargetSP target_sp;
708b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
7096c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
7106c42e063SGreg Clayton DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
711b9c1b51eSKate Stone for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
7126611103cSGreg Clayton target_sp = (*pos)->GetTargetList().FindTargetWithProcessID(pid);
7136611103cSGreg Clayton if (target_sp)
7146611103cSGreg Clayton break;
7156611103cSGreg Clayton }
716c15f55e2SGreg Clayton }
7176611103cSGreg Clayton return target_sp;
7186611103cSGreg Clayton }
7196611103cSGreg Clayton
FindTargetWithProcess(Process * process)720b9c1b51eSKate Stone TargetSP Debugger::FindTargetWithProcess(Process *process) {
721e4e45924SGreg Clayton TargetSP target_sp;
722b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
7236c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
7246c42e063SGreg Clayton DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
725b9c1b51eSKate Stone for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
726e4e45924SGreg Clayton target_sp = (*pos)->GetTargetList().FindTargetWithProcess(process);
727e4e45924SGreg Clayton if (target_sp)
728e4e45924SGreg Clayton break;
729e4e45924SGreg Clayton }
730c15f55e2SGreg Clayton }
731e4e45924SGreg Clayton return target_sp;
732e4e45924SGreg Clayton }
733e4e45924SGreg Clayton
GetStaticBroadcasterClass()734e122877fSGreg Clayton ConstString Debugger::GetStaticBroadcasterClass() {
735e122877fSGreg Clayton static ConstString class_name("lldb.debugger");
736e122877fSGreg Clayton return class_name;
737e122877fSGreg Clayton }
738e122877fSGreg Clayton
Debugger(lldb::LogOutputCallback log_callback,void * baton)739b9c1b51eSKate Stone Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton)
740b9c1b51eSKate Stone : UserID(g_unique_id++),
7412f3df613SZachary Turner Properties(std::make_shared<OptionValueProperties>()),
742f913fd6eSLawrence D'Anna m_input_file_sp(std::make_shared<NativeFile>(stdin, false)),
7437ca15ba7SLawrence D'Anna m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)),
7447ca15ba7SLawrence D'Anna m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)),
745d77c2e09SJonas Devlieghere m_input_recorder(nullptr),
746583bbb1dSJim Ingham m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()),
747b9c1b51eSKate Stone m_terminal_state(), m_target_list(*this), m_platform_list(),
748583bbb1dSJim Ingham m_listener_sp(Listener::MakeListener("lldb.Debugger")),
749d5b44036SJonas Devlieghere m_source_manager_up(), m_source_file_cache(),
750f20dd1d5SJonas Devlieghere m_command_interpreter_up(
751a8f3ae7cSJonas Devlieghere std::make_unique<CommandInterpreter>(*this, false)),
7527ce2de2cSJonas Devlieghere m_io_handler_stack(), m_instance_name(), m_loaded_plugins(),
753bbf70c04SJonas Devlieghere m_event_handler_thread(), m_io_handler_thread(),
7544329fe42SGreg Clayton m_sync_broadcaster(nullptr, "lldb.debugger.sync"),
755e122877fSGreg Clayton m_broadcaster(m_broadcaster_manager_sp,
756e122877fSGreg Clayton GetStaticBroadcasterClass().AsCString()),
757b9c1b51eSKate Stone m_forward_listener_sp(), m_clear_once() {
758db203e02SRaphael Isemann m_instance_name.SetString(llvm::formatv("debugger_{0}", GetID()).str());
759228063cdSJim Ingham if (log_callback)
760de747565SJonas Devlieghere m_callback_handler_sp =
761de747565SJonas Devlieghere std::make_shared<CallbackLogHandler>(log_callback, baton);
762d5b44036SJonas Devlieghere m_command_interpreter_up->Initialize();
763ded470d3SGreg Clayton // Always add our default platform to the platform list
764615eb7e6SGreg Clayton PlatformSP default_platform_sp(Platform::GetHostPlatform());
765df370550SEugene Zelenko assert(default_platform_sp);
766ded470d3SGreg Clayton m_platform_list.Append(default_platform_sp, true);
76767cc0636SGreg Clayton
76816e5a347SVedant Kumar // Create the dummy target.
76916e5a347SVedant Kumar {
77016e5a347SVedant Kumar ArchSpec arch(Target::GetDefaultArchitecture());
77116e5a347SVedant Kumar if (!arch.IsValid())
77216e5a347SVedant Kumar arch = HostInfo::GetArchitecture();
77316e5a347SVedant Kumar assert(arch.IsValid() && "No valid default or host archspec");
77416e5a347SVedant Kumar const bool is_dummy_target = true;
77516e5a347SVedant Kumar m_dummy_target_sp.reset(
77616e5a347SVedant Kumar new Target(*this, arch, default_platform_sp, is_dummy_target));
77716e5a347SVedant Kumar }
778d43d912bSRaphael Isemann assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?");
779d43d912bSRaphael Isemann
780a8ea5955SJonas Devlieghere m_collection_sp->Initialize(g_debugger_properties);
781b9c1b51eSKate Stone m_collection_sp->AppendProperty(
782b9c1b51eSKate Stone ConstString("target"),
783b9c1b51eSKate Stone ConstString("Settings specify to debugging targets."), true,
7843d7161e3SPavel Labath Target::GetGlobalProperties().GetValueProperties());
785b9c1b51eSKate Stone m_collection_sp->AppendProperty(
786b9c1b51eSKate Stone ConstString("platform"), ConstString("Platform settings."), true,
7873d7161e3SPavel Labath Platform::GetGlobalPlatformProperties().GetValueProperties());
788235354beSAdrian Prantl m_collection_sp->AppendProperty(
7893cd29bcfSAdrian Prantl ConstString("symbols"), ConstString("Symbol lookup and cache settings."),
7903cd29bcfSAdrian Prantl true, ModuleList::GetGlobalModuleListProperties().GetValueProperties());
791d5b44036SJonas Devlieghere if (m_command_interpreter_up) {
792b9c1b51eSKate Stone m_collection_sp->AppendProperty(
793b9c1b51eSKate Stone ConstString("interpreter"),
794754a9369SGreg Clayton ConstString("Settings specify to the debugger's command interpreter."),
795d5b44036SJonas Devlieghere true, m_command_interpreter_up->GetValueProperties());
796754a9369SGreg Clayton }
797b9c1b51eSKate Stone OptionValueSInt64 *term_width =
798b9c1b51eSKate Stone m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64(
799b9c1b51eSKate Stone nullptr, ePropertyTerminalWidth);
80067cc0636SGreg Clayton term_width->SetMinimumValue(10);
80167cc0636SGreg Clayton term_width->SetMaximumValue(1024);
802c3ce7f27SMichael Sartain
803c3ce7f27SMichael Sartain // Turn off use-color if this is a dumb terminal.
804c3ce7f27SMichael Sartain const char *term = getenv("TERM");
805c3ce7f27SMichael Sartain if (term && !strcmp(term, "dumb"))
806c3ce7f27SMichael Sartain SetUseColor(false);
807eca9ce14SRaphael Isemann // Turn off use-color if we don't write to a terminal with color support.
8087ca15ba7SLawrence D'Anna if (!GetOutputFile().GetIsTerminalWithColors())
809eca9ce14SRaphael Isemann SetUseColor(false);
8108aa23614SDavid Bolvansky
8118aa23614SDavid Bolvansky #if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
8128aa23614SDavid Bolvansky // Enabling use of ANSI color codes because LLDB is using them to highlight
8138aa23614SDavid Bolvansky // text.
8148aa23614SDavid Bolvansky llvm::sys::Process::UseANSIEscapeCodes(true);
8158aa23614SDavid Bolvansky #endif
81630fdc8d8SChris Lattner }
81730fdc8d8SChris Lattner
~Debugger()818b9c1b51eSKate Stone Debugger::~Debugger() { Clear(); }
8198314c525SJim Ingham
Clear()820b9c1b51eSKate Stone void Debugger::Clear() {
82105097246SAdrian Prantl // Make sure we call this function only once. With the C++ global destructor
82205097246SAdrian Prantl // chain having a list of debuggers and with code that can be running on
82305097246SAdrian Prantl // other threads, we need to ensure this doesn't happen multiple times.
8244329fe42SGreg Clayton //
8254329fe42SGreg Clayton // The following functions call Debugger::Clear():
8264329fe42SGreg Clayton // Debugger::~Debugger();
8274329fe42SGreg Clayton // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp);
8284329fe42SGreg Clayton // static void Debugger::Terminate();
829c5f28e2aSKamil Rytarowski llvm::call_once(m_clear_once, [this]() {
83044d93782SGreg Clayton ClearIOHandlers();
83144d93782SGreg Clayton StopIOHandlerThread();
83244d93782SGreg Clayton StopEventHandlerThread();
833583bbb1dSJim Ingham m_listener_sp->Clear();
834de448c0aSJonas Devlieghere for (TargetSP target_sp : m_target_list.Targets()) {
835b9c1b51eSKate Stone if (target_sp) {
836de448c0aSJonas Devlieghere if (ProcessSP process_sp = target_sp->GetProcessSP())
8371fd07059SJim Ingham process_sp->Finalize();
838ccbc08e6SGreg Clayton target_sp->Destroy();
8396611103cSGreg Clayton }
84030fdc8d8SChris Lattner }
841583bbb1dSJim Ingham m_broadcaster_manager_sp->Clear();
84230fdc8d8SChris Lattner
843b9c1b51eSKate Stone // Close the input file _before_ we close the input read communications
84405097246SAdrian Prantl // class as it does NOT own the input file, our m_input_file does.
845c5917d9aSJim Ingham m_terminal_state.Clear();
8467ca15ba7SLawrence D'Anna GetInputFile().Close();
8470c4129f2SGreg Clayton
848d5b44036SJonas Devlieghere m_command_interpreter_up->Clear();
8494329fe42SGreg Clayton });
8508314c525SJim Ingham }
85130fdc8d8SChris Lattner
GetCloseInputOnEOF() const852b9c1b51eSKate Stone bool Debugger::GetCloseInputOnEOF() const {
85344d93782SGreg Clayton // return m_input_comm.GetCloseOnEOF();
85444d93782SGreg Clayton return false;
855fc3f027dSGreg Clayton }
856fc3f027dSGreg Clayton
SetCloseInputOnEOF(bool b)857b9c1b51eSKate Stone void Debugger::SetCloseInputOnEOF(bool b) {
85844d93782SGreg Clayton // m_input_comm.SetCloseOnEOF(b);
859fc3f027dSGreg Clayton }
860fc3f027dSGreg Clayton
GetAsyncExecution()861b9c1b51eSKate Stone bool Debugger::GetAsyncExecution() {
862d5b44036SJonas Devlieghere return !m_command_interpreter_up->GetSynchronous();
86330fdc8d8SChris Lattner }
86430fdc8d8SChris Lattner
SetAsyncExecution(bool async_execution)865b9c1b51eSKate Stone void Debugger::SetAsyncExecution(bool async_execution) {
866d5b44036SJonas Devlieghere m_command_interpreter_up->SetSynchronous(!async_execution);
86730fdc8d8SChris Lattner }
86830fdc8d8SChris Lattner
GetInputRecorder()869d77c2e09SJonas Devlieghere repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; }
870d77c2e09SJonas Devlieghere
OpenPipe(int fds[2],std::size_t size)871f23b829aSLevon Ter-Grigoryan static inline int OpenPipe(int fds[2], std::size_t size) {
872f23b829aSLevon Ter-Grigoryan #ifdef _WIN32
873f23b829aSLevon Ter-Grigoryan return _pipe(fds, size, O_BINARY);
874f23b829aSLevon Ter-Grigoryan #else
875f23b829aSLevon Ter-Grigoryan (void)size;
876f23b829aSLevon Ter-Grigoryan return pipe(fds);
877f23b829aSLevon Ter-Grigoryan #endif
878f23b829aSLevon Ter-Grigoryan }
879f23b829aSLevon Ter-Grigoryan
SetInputString(const char * data)880f23b829aSLevon Ter-Grigoryan Status Debugger::SetInputString(const char *data) {
881f23b829aSLevon Ter-Grigoryan Status result;
882f23b829aSLevon Ter-Grigoryan enum PIPES { READ, WRITE }; // Indexes for the read and write fds
883f23b829aSLevon Ter-Grigoryan int fds[2] = {-1, -1};
884f23b829aSLevon Ter-Grigoryan
885f23b829aSLevon Ter-Grigoryan if (data == nullptr) {
886f23b829aSLevon Ter-Grigoryan result.SetErrorString("String data is null");
887f23b829aSLevon Ter-Grigoryan return result;
888f23b829aSLevon Ter-Grigoryan }
889f23b829aSLevon Ter-Grigoryan
890f23b829aSLevon Ter-Grigoryan size_t size = strlen(data);
891f23b829aSLevon Ter-Grigoryan if (size == 0) {
892f23b829aSLevon Ter-Grigoryan result.SetErrorString("String data is empty");
893f23b829aSLevon Ter-Grigoryan return result;
894f23b829aSLevon Ter-Grigoryan }
895f23b829aSLevon Ter-Grigoryan
896f23b829aSLevon Ter-Grigoryan if (OpenPipe(fds, size) != 0) {
897f23b829aSLevon Ter-Grigoryan result.SetErrorString(
898f23b829aSLevon Ter-Grigoryan "can't create pipe file descriptors for LLDB commands");
899f23b829aSLevon Ter-Grigoryan return result;
900f23b829aSLevon Ter-Grigoryan }
901f23b829aSLevon Ter-Grigoryan
9026e388242SMartin Storsjö int r = write(fds[WRITE], data, size);
9036e388242SMartin Storsjö (void)r;
904f23b829aSLevon Ter-Grigoryan // Close the write end of the pipe, so that the command interpreter will exit
905f23b829aSLevon Ter-Grigoryan // when it consumes all the data.
906f23b829aSLevon Ter-Grigoryan llvm::sys::Process::SafelyCloseFileDescriptor(fds[WRITE]);
907f23b829aSLevon Ter-Grigoryan
908f23b829aSLevon Ter-Grigoryan // Open the read file descriptor as a FILE * that we can return as an input
909f23b829aSLevon Ter-Grigoryan // handle.
910f23b829aSLevon Ter-Grigoryan FILE *commands_file = fdopen(fds[READ], "rb");
911f23b829aSLevon Ter-Grigoryan if (commands_file == nullptr) {
912f23b829aSLevon Ter-Grigoryan result.SetErrorStringWithFormat("fdopen(%i, \"rb\") failed (errno = %i) "
913f23b829aSLevon Ter-Grigoryan "when trying to open LLDB commands pipe",
914f23b829aSLevon Ter-Grigoryan fds[READ], errno);
915f23b829aSLevon Ter-Grigoryan llvm::sys::Process::SafelyCloseFileDescriptor(fds[READ]);
916f23b829aSLevon Ter-Grigoryan return result;
917f23b829aSLevon Ter-Grigoryan }
918f23b829aSLevon Ter-Grigoryan
919f23b829aSLevon Ter-Grigoryan return SetInputFile(
920f23b829aSLevon Ter-Grigoryan (FileSP)std::make_shared<NativeFile>(commands_file, true));
921f23b829aSLevon Ter-Grigoryan }
922f23b829aSLevon Ter-Grigoryan
SetInputFile(FileSP file_sp)923f23b829aSLevon Ter-Grigoryan Status Debugger::SetInputFile(FileSP file_sp) {
924f23b829aSLevon Ter-Grigoryan Status error;
925f23b829aSLevon Ter-Grigoryan repro::DataRecorder *recorder = nullptr;
926f23b829aSLevon Ter-Grigoryan if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator())
927f23b829aSLevon Ter-Grigoryan recorder = g->GetOrCreate<repro::CommandProvider>().GetNewRecorder();
928f23b829aSLevon Ter-Grigoryan
929f23b829aSLevon Ter-Grigoryan static std::unique_ptr<repro::MultiLoader<repro::CommandProvider>> loader =
930f23b829aSLevon Ter-Grigoryan repro::MultiLoader<repro::CommandProvider>::Create(
931f23b829aSLevon Ter-Grigoryan repro::Reproducer::Instance().GetLoader());
932f23b829aSLevon Ter-Grigoryan if (loader) {
933f23b829aSLevon Ter-Grigoryan llvm::Optional<std::string> nextfile = loader->GetNextFile();
934f23b829aSLevon Ter-Grigoryan FILE *fh = nextfile ? FileSystem::Instance().Fopen(nextfile->c_str(), "r")
935f23b829aSLevon Ter-Grigoryan : nullptr;
936f23b829aSLevon Ter-Grigoryan // FIXME Jonas Devlieghere: shouldn't this error be propagated out to the
937f23b829aSLevon Ter-Grigoryan // reproducer somehow if fh is NULL?
938f23b829aSLevon Ter-Grigoryan if (fh) {
939f23b829aSLevon Ter-Grigoryan file_sp = std::make_shared<NativeFile>(fh, true);
940f23b829aSLevon Ter-Grigoryan }
941f23b829aSLevon Ter-Grigoryan }
942f23b829aSLevon Ter-Grigoryan
943f23b829aSLevon Ter-Grigoryan if (!file_sp || !file_sp->IsValid()) {
944f23b829aSLevon Ter-Grigoryan error.SetErrorString("invalid file");
945f23b829aSLevon Ter-Grigoryan return error;
946f23b829aSLevon Ter-Grigoryan }
947f23b829aSLevon Ter-Grigoryan
948f23b829aSLevon Ter-Grigoryan SetInputFile(file_sp, recorder);
949f23b829aSLevon Ter-Grigoryan return error;
950f23b829aSLevon Ter-Grigoryan }
951f23b829aSLevon Ter-Grigoryan
SetInputFile(FileSP file_sp,repro::DataRecorder * recorder)95296898eb6SLawrence D'Anna void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) {
95396898eb6SLawrence D'Anna assert(file_sp && file_sp->IsValid());
954d77c2e09SJonas Devlieghere m_input_recorder = recorder;
955c4701c9cSJonas Devlieghere m_input_file_sp = std::move(file_sp);
95605097246SAdrian Prantl // Save away the terminal state if that is relevant, so that we can restore
95705097246SAdrian Prantl // it in RestoreInputState.
958c5917d9aSJim Ingham SaveInputTerminalState();
95930fdc8d8SChris Lattner }
96030fdc8d8SChris Lattner
SetOutputFile(FileSP file_sp)96196898eb6SLawrence D'Anna void Debugger::SetOutputFile(FileSP file_sp) {
96296898eb6SLawrence D'Anna assert(file_sp && file_sp->IsValid());
9637ca15ba7SLawrence D'Anna m_output_stream_sp = std::make_shared<StreamFile>(file_sp);
96430fdc8d8SChris Lattner }
96530fdc8d8SChris Lattner
SetErrorFile(FileSP file_sp)96696898eb6SLawrence D'Anna void Debugger::SetErrorFile(FileSP file_sp) {
96796898eb6SLawrence D'Anna assert(file_sp && file_sp->IsValid());
9687ca15ba7SLawrence D'Anna m_error_stream_sp = std::make_shared<StreamFile>(file_sp);
96930fdc8d8SChris Lattner }
97030fdc8d8SChris Lattner
SaveInputTerminalState()971b9c1b51eSKate Stone void Debugger::SaveInputTerminalState() {
9727ca15ba7SLawrence D'Anna int fd = GetInputFile().GetDescriptor();
9737ca15ba7SLawrence D'Anna if (fd != File::kInvalidDescriptor)
9747ca15ba7SLawrence D'Anna m_terminal_state.Save(fd, true);
97544d93782SGreg Clayton }
976c5917d9aSJim Ingham
RestoreInputTerminalState()977b9c1b51eSKate Stone void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); }
978c5917d9aSJim Ingham
GetSelectedExecutionContext()979b9c1b51eSKate Stone ExecutionContext Debugger::GetSelectedExecutionContext() {
980a39bcbcaSTatyana Krasnukha bool adopt_selected = true;
981a39bcbcaSTatyana Krasnukha ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected);
982a39bcbcaSTatyana Krasnukha return ExecutionContext(exe_ctx_ref);
98330fdc8d8SChris Lattner }
98430fdc8d8SChris Lattner
DispatchInputInterrupt()985b9c1b51eSKate Stone void Debugger::DispatchInputInterrupt() {
9867ce2de2cSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
9877ce2de2cSJonas Devlieghere IOHandlerSP reader_sp(m_io_handler_stack.Top());
988efed6131SCaroline Tice if (reader_sp)
98944d93782SGreg Clayton reader_sp->Interrupt();
990efed6131SCaroline Tice }
991efed6131SCaroline Tice
DispatchInputEndOfFile()992b9c1b51eSKate Stone void Debugger::DispatchInputEndOfFile() {
9937ce2de2cSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
9947ce2de2cSJonas Devlieghere IOHandlerSP reader_sp(m_io_handler_stack.Top());
995efed6131SCaroline Tice if (reader_sp)
99644d93782SGreg Clayton reader_sp->GotEOF();
997efed6131SCaroline Tice }
998efed6131SCaroline Tice
ClearIOHandlers()999b9c1b51eSKate Stone void Debugger::ClearIOHandlers() {
1000b9c1b51eSKate Stone // The bottom input reader should be the main debugger input reader. We do
1001b9c1b51eSKate Stone // not want to close that one here.
10027ce2de2cSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
10037ce2de2cSJonas Devlieghere while (m_io_handler_stack.GetSize() > 1) {
10047ce2de2cSJonas Devlieghere IOHandlerSP reader_sp(m_io_handler_stack.Top());
10053d6086f6SCaroline Tice if (reader_sp)
10064446487dSPavel Labath PopIOHandler(reader_sp);
10073d6086f6SCaroline Tice }
10083d6086f6SCaroline Tice }
10093d6086f6SCaroline Tice
RunIOHandlers()10102671df9bSJonas Devlieghere void Debugger::RunIOHandlers() {
101104de24e6SJonas Devlieghere IOHandlerSP reader_sp = m_io_handler_stack.Top();
1012b9c1b51eSKate Stone while (true) {
101330fdc8d8SChris Lattner if (!reader_sp)
101430fdc8d8SChris Lattner break;
101530fdc8d8SChris Lattner
101644d93782SGreg Clayton reader_sp->Run();
101704de24e6SJonas Devlieghere {
101804de24e6SJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(
101904de24e6SJonas Devlieghere m_io_handler_synchronous_mutex);
102044d93782SGreg Clayton
102144d93782SGreg Clayton // Remove all input readers that are done from the top of the stack
1022b9c1b51eSKate Stone while (true) {
10237ce2de2cSJonas Devlieghere IOHandlerSP top_reader_sp = m_io_handler_stack.Top();
102444d93782SGreg Clayton if (top_reader_sp && top_reader_sp->GetIsDone())
10254446487dSPavel Labath PopIOHandler(top_reader_sp);
102630fdc8d8SChris Lattner else
102730fdc8d8SChris Lattner break;
102830fdc8d8SChris Lattner }
102904de24e6SJonas Devlieghere reader_sp = m_io_handler_stack.Top();
103004de24e6SJonas Devlieghere }
103130fdc8d8SChris Lattner }
103244d93782SGreg Clayton ClearIOHandlers();
103344d93782SGreg Clayton }
103430fdc8d8SChris Lattner
RunIOHandlerSync(const IOHandlerSP & reader_sp)103504de24e6SJonas Devlieghere void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) {
103604de24e6SJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_synchronous_mutex);
103704de24e6SJonas Devlieghere
103804de24e6SJonas Devlieghere PushIOHandler(reader_sp);
103904de24e6SJonas Devlieghere IOHandlerSP top_reader_sp = reader_sp;
104004de24e6SJonas Devlieghere
104104de24e6SJonas Devlieghere while (top_reader_sp) {
104204de24e6SJonas Devlieghere if (!top_reader_sp)
104304de24e6SJonas Devlieghere break;
104404de24e6SJonas Devlieghere
104504de24e6SJonas Devlieghere top_reader_sp->Run();
104604de24e6SJonas Devlieghere
104704de24e6SJonas Devlieghere // Don't unwind past the starting point.
104804de24e6SJonas Devlieghere if (top_reader_sp.get() == reader_sp.get()) {
104904de24e6SJonas Devlieghere if (PopIOHandler(reader_sp))
105004de24e6SJonas Devlieghere break;
105104de24e6SJonas Devlieghere }
105204de24e6SJonas Devlieghere
105304de24e6SJonas Devlieghere // If we pushed new IO handlers, pop them if they're done or restart the
105404de24e6SJonas Devlieghere // loop to run them if they're not.
105504de24e6SJonas Devlieghere while (true) {
105604de24e6SJonas Devlieghere top_reader_sp = m_io_handler_stack.Top();
105704de24e6SJonas Devlieghere if (top_reader_sp && top_reader_sp->GetIsDone()) {
105804de24e6SJonas Devlieghere PopIOHandler(top_reader_sp);
105904de24e6SJonas Devlieghere // Don't unwind past the starting point.
106004de24e6SJonas Devlieghere if (top_reader_sp.get() == reader_sp.get())
106104de24e6SJonas Devlieghere return;
106204de24e6SJonas Devlieghere } else {
106304de24e6SJonas Devlieghere break;
106404de24e6SJonas Devlieghere }
106504de24e6SJonas Devlieghere }
106604de24e6SJonas Devlieghere }
106704de24e6SJonas Devlieghere }
106804de24e6SJonas Devlieghere
IsTopIOHandler(const lldb::IOHandlerSP & reader_sp)1069b9c1b51eSKate Stone bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) {
10707ce2de2cSJonas Devlieghere return m_io_handler_stack.IsTop(reader_sp);
107144d93782SGreg Clayton }
107230fdc8d8SChris Lattner
CheckTopIOHandlerTypes(IOHandler::Type top_type,IOHandler::Type second_top_type)1073b9c1b51eSKate Stone bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type,
1074b9c1b51eSKate Stone IOHandler::Type second_top_type) {
10757ce2de2cSJonas Devlieghere return m_io_handler_stack.CheckTopIOHandlerTypes(top_type, second_top_type);
10766681041dSSean Callanan }
10776681041dSSean Callanan
PrintAsync(const char * s,size_t len,bool is_stdout)1078b9c1b51eSKate Stone void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) {
10792436c570SJonas Devlieghere bool printed = m_io_handler_stack.PrintAsync(s, len, is_stdout);
10802436c570SJonas Devlieghere if (!printed) {
10812436c570SJonas Devlieghere lldb::StreamFileSP stream =
10822436c570SJonas Devlieghere is_stdout ? m_output_stream_sp : m_error_stream_sp;
10832436c570SJonas Devlieghere stream->Write(s, len);
10842436c570SJonas Devlieghere }
10854446487dSPavel Labath }
108644d93782SGreg Clayton
GetTopIOHandlerControlSequence(char ch)1087b9c1b51eSKate Stone ConstString Debugger::GetTopIOHandlerControlSequence(char ch) {
10887ce2de2cSJonas Devlieghere return m_io_handler_stack.GetTopIOHandlerControlSequence(ch);
108930fdc8d8SChris Lattner }
109030fdc8d8SChris Lattner
GetIOHandlerCommandPrefix()1091b9c1b51eSKate Stone const char *Debugger::GetIOHandlerCommandPrefix() {
10927ce2de2cSJonas Devlieghere return m_io_handler_stack.GetTopIOHandlerCommandPrefix();
1093a487aa4cSKate Stone }
1094a487aa4cSKate Stone
GetIOHandlerHelpPrologue()1095b9c1b51eSKate Stone const char *Debugger::GetIOHandlerHelpPrologue() {
10967ce2de2cSJonas Devlieghere return m_io_handler_stack.GetTopIOHandlerHelpPrologue();
1097a487aa4cSKate Stone }
1098a487aa4cSKate Stone
RemoveIOHandler(const IOHandlerSP & reader_sp)10997ce2de2cSJonas Devlieghere bool Debugger::RemoveIOHandler(const IOHandlerSP &reader_sp) {
11007ce2de2cSJonas Devlieghere return PopIOHandler(reader_sp);
11017ce2de2cSJonas Devlieghere }
11027ce2de2cSJonas Devlieghere
RunIOHandlerAsync(const IOHandlerSP & reader_sp,bool cancel_top_handler)11037ce2de2cSJonas Devlieghere void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp,
11047ce2de2cSJonas Devlieghere bool cancel_top_handler) {
11057ce2de2cSJonas Devlieghere PushIOHandler(reader_sp, cancel_top_handler);
11067ce2de2cSJonas Devlieghere }
11077ce2de2cSJonas Devlieghere
AdoptTopIOHandlerFilesIfInvalid(FileSP & in,StreamFileSP & out,StreamFileSP & err)11087ca15ba7SLawrence D'Anna void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out,
1109b9c1b51eSKate Stone StreamFileSP &err) {
111005097246SAdrian Prantl // Before an IOHandler runs, it must have in/out/err streams. This function
111105097246SAdrian Prantl // is called when one ore more of the streams are nullptr. We use the top
111205097246SAdrian Prantl // input reader's in/out/err streams, or fall back to the debugger file
111305097246SAdrian Prantl // handles, or we fall back onto stdin/stdout/stderr as a last resort.
111444d93782SGreg Clayton
11157ce2de2cSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
11167ce2de2cSJonas Devlieghere IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
111744d93782SGreg Clayton // If no STDIN has been set, then set it appropriately
1118b07823f3SLawrence D'Anna if (!in || !in->IsValid()) {
111944d93782SGreg Clayton if (top_reader_sp)
11207ca15ba7SLawrence D'Anna in = top_reader_sp->GetInputFileSP();
112144d93782SGreg Clayton else
11227ca15ba7SLawrence D'Anna in = GetInputFileSP();
112344d93782SGreg Clayton // If there is nothing, use stdin
112444d93782SGreg Clayton if (!in)
1125f913fd6eSLawrence D'Anna in = std::make_shared<NativeFile>(stdin, false);
112644d93782SGreg Clayton }
112744d93782SGreg Clayton // If no STDOUT has been set, then set it appropriately
1128b07823f3SLawrence D'Anna if (!out || !out->GetFile().IsValid()) {
112944d93782SGreg Clayton if (top_reader_sp)
11307ca15ba7SLawrence D'Anna out = top_reader_sp->GetOutputStreamFileSP();
113144d93782SGreg Clayton else
11327ca15ba7SLawrence D'Anna out = GetOutputStreamSP();
113344d93782SGreg Clayton // If there is nothing, use stdout
113444d93782SGreg Clayton if (!out)
11352f3df613SZachary Turner out = std::make_shared<StreamFile>(stdout, false);
113644d93782SGreg Clayton }
113744d93782SGreg Clayton // If no STDERR has been set, then set it appropriately
1138b07823f3SLawrence D'Anna if (!err || !err->GetFile().IsValid()) {
113944d93782SGreg Clayton if (top_reader_sp)
11407ca15ba7SLawrence D'Anna err = top_reader_sp->GetErrorStreamFileSP();
114144d93782SGreg Clayton else
11427ca15ba7SLawrence D'Anna err = GetErrorStreamSP();
114344d93782SGreg Clayton // If there is nothing, use stderr
114444d93782SGreg Clayton if (!err)
11457ca15ba7SLawrence D'Anna err = std::make_shared<StreamFile>(stderr, false);
114644d93782SGreg Clayton }
114744d93782SGreg Clayton }
114844d93782SGreg Clayton
PushIOHandler(const IOHandlerSP & reader_sp,bool cancel_top_handler)1149c01783a8SRaphael Isemann void Debugger::PushIOHandler(const IOHandlerSP &reader_sp,
1150c01783a8SRaphael Isemann bool cancel_top_handler) {
115130fdc8d8SChris Lattner if (!reader_sp)
115230fdc8d8SChris Lattner return;
1153b44880caSCaroline Tice
11547ce2de2cSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
11554446487dSPavel Labath
11564446487dSPavel Labath // Get the current top input reader...
11577ce2de2cSJonas Devlieghere IOHandlerSP top_reader_sp(m_io_handler_stack.Top());
1158b44880caSCaroline Tice
1159b4874f1aSGreg Clayton // Don't push the same IO handler twice...
11604446487dSPavel Labath if (reader_sp == top_reader_sp)
11614446487dSPavel Labath return;
11624446487dSPavel Labath
116344d93782SGreg Clayton // Push our new input reader
11647ce2de2cSJonas Devlieghere m_io_handler_stack.Push(reader_sp);
11654446487dSPavel Labath reader_sp->Activate();
116644d93782SGreg Clayton
116705097246SAdrian Prantl // Interrupt the top input reader to it will exit its Run() function and let
116805097246SAdrian Prantl // this new input reader take over
1169b9c1b51eSKate Stone if (top_reader_sp) {
117044d93782SGreg Clayton top_reader_sp->Deactivate();
1171c01783a8SRaphael Isemann if (cancel_top_handler)
11724446487dSPavel Labath top_reader_sp->Cancel();
117330fdc8d8SChris Lattner }
1174b4874f1aSGreg Clayton }
117530fdc8d8SChris Lattner
PopIOHandler(const IOHandlerSP & pop_reader_sp)1176b9c1b51eSKate Stone bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) {
11774446487dSPavel Labath if (!pop_reader_sp)
11784446487dSPavel Labath return false;
117930fdc8d8SChris Lattner
11807ce2de2cSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex());
118144d93782SGreg Clayton
118205097246SAdrian Prantl // The reader on the stop of the stack is done, so let the next read on the
118305097246SAdrian Prantl // stack refresh its prompt and if there is one...
11847ce2de2cSJonas Devlieghere if (m_io_handler_stack.IsEmpty())
11854446487dSPavel Labath return false;
11864446487dSPavel Labath
11877ce2de2cSJonas Devlieghere IOHandlerSP reader_sp(m_io_handler_stack.Top());
118830fdc8d8SChris Lattner
11894446487dSPavel Labath if (pop_reader_sp != reader_sp)
11904446487dSPavel Labath return false;
11914446487dSPavel Labath
119244d93782SGreg Clayton reader_sp->Deactivate();
1193b4874f1aSGreg Clayton reader_sp->Cancel();
11947ce2de2cSJonas Devlieghere m_io_handler_stack.Pop();
119530fdc8d8SChris Lattner
11967ce2de2cSJonas Devlieghere reader_sp = m_io_handler_stack.Top();
119730fdc8d8SChris Lattner if (reader_sp)
119844d93782SGreg Clayton reader_sp->Activate();
119944d93782SGreg Clayton
120044d93782SGreg Clayton return true;
120130fdc8d8SChris Lattner }
12026611103cSGreg Clayton
GetAsyncOutputStream()1203b9c1b51eSKate Stone StreamSP Debugger::GetAsyncOutputStream() {
1204990d0c71SJonas Devlieghere return std::make_shared<StreamAsynchronousIO>(*this, true, GetUseColor());
12055b52f0c7SJim Ingham }
12065b52f0c7SJim Ingham
GetAsyncErrorStream()1207b9c1b51eSKate Stone StreamSP Debugger::GetAsyncErrorStream() {
1208990d0c71SJonas Devlieghere return std::make_shared<StreamAsynchronousIO>(*this, false, GetUseColor());
12095b52f0c7SJim Ingham }
12105b52f0c7SJim Ingham
GetNumDebuggers()1211b9c1b51eSKate Stone size_t Debugger::GetNumDebuggers() {
1212b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
12136c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
12146c42e063SGreg Clayton return g_debugger_list_ptr->size();
1215061858ceSEnrico Granata }
1216c15f55e2SGreg Clayton return 0;
1217c15f55e2SGreg Clayton }
1218061858ceSEnrico Granata
GetDebuggerAtIndex(size_t index)1219b9c1b51eSKate Stone lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) {
1220061858ceSEnrico Granata DebuggerSP debugger_sp;
1221061858ceSEnrico Granata
1222b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
12236c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
12246c42e063SGreg Clayton if (index < g_debugger_list_ptr->size())
12256c42e063SGreg Clayton debugger_sp = g_debugger_list_ptr->at(index);
1226c15f55e2SGreg Clayton }
1227061858ceSEnrico Granata
1228061858ceSEnrico Granata return debugger_sp;
1229061858ceSEnrico Granata }
1230061858ceSEnrico Granata
FindDebuggerWithID(lldb::user_id_t id)1231b9c1b51eSKate Stone DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) {
12324d122c40SGreg Clayton DebuggerSP debugger_sp;
1233ebc1bb27SCaroline Tice
1234b9c1b51eSKate Stone if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
12356c42e063SGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
12366c42e063SGreg Clayton DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
1237b9c1b51eSKate Stone for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) {
1238b9c1b51eSKate Stone if ((*pos)->GetID() == id) {
1239ebc1bb27SCaroline Tice debugger_sp = *pos;
1240ebc1bb27SCaroline Tice break;
1241ebc1bb27SCaroline Tice }
1242ebc1bb27SCaroline Tice }
1243c15f55e2SGreg Clayton }
1244ebc1bb27SCaroline Tice return debugger_sp;
1245ebc1bb27SCaroline Tice }
12463df9a8dfSCaroline Tice
FormatDisassemblerAddress(const FormatEntity::Entry * format,const SymbolContext * sc,const SymbolContext * prev_sc,const ExecutionContext * exe_ctx,const Address * addr,Stream & s)1247b9c1b51eSKate Stone bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format,
1248aff1b357SJason Molenda const SymbolContext *sc,
1249aff1b357SJason Molenda const SymbolContext *prev_sc,
1250aff1b357SJason Molenda const ExecutionContext *exe_ctx,
1251b9c1b51eSKate Stone const Address *addr, Stream &s) {
1252554f68d3SGreg Clayton FormatEntity::Entry format_entry;
1253554f68d3SGreg Clayton
1254b9c1b51eSKate Stone if (format == nullptr) {
1255df370550SEugene Zelenko if (exe_ctx != nullptr && exe_ctx->HasTargetScope())
1256aff1b357SJason Molenda format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat();
1257b9c1b51eSKate Stone if (format == nullptr) {
1258554f68d3SGreg Clayton FormatEntity::Parse("${addr}: ", format_entry);
1259554f68d3SGreg Clayton format = &format_entry;
1260554f68d3SGreg Clayton }
1261aff1b357SJason Molenda }
1262aff1b357SJason Molenda bool function_changed = false;
1263aff1b357SJason Molenda bool initial_function = false;
1264b9c1b51eSKate Stone if (prev_sc && (prev_sc->function || prev_sc->symbol)) {
1265b9c1b51eSKate Stone if (sc && (sc->function || sc->symbol)) {
1266b9c1b51eSKate Stone if (prev_sc->symbol && sc->symbol) {
1267b9c1b51eSKate Stone if (!sc->symbol->Compare(prev_sc->symbol->GetName(),
1268b9c1b51eSKate Stone prev_sc->symbol->GetType())) {
1269aff1b357SJason Molenda function_changed = true;
1270aff1b357SJason Molenda }
1271b9c1b51eSKate Stone } else if (prev_sc->function && sc->function) {
1272b9c1b51eSKate Stone if (prev_sc->function->GetMangled() != sc->function->GetMangled()) {
1273aff1b357SJason Molenda function_changed = true;
1274aff1b357SJason Molenda }
1275aff1b357SJason Molenda }
1276aff1b357SJason Molenda }
1277aff1b357SJason Molenda }
127805097246SAdrian Prantl // The first context on a list of instructions will have a prev_sc that has
127905097246SAdrian Prantl // no Function or Symbol -- if SymbolContext had an IsValid() method, it
1280aff1b357SJason Molenda // would return false. But we do get a prev_sc pointer.
1281b9c1b51eSKate Stone if ((sc && (sc->function || sc->symbol)) && prev_sc &&
1282b9c1b51eSKate Stone (prev_sc->function == nullptr && prev_sc->symbol == nullptr)) {
1283aff1b357SJason Molenda initial_function = true;
1284aff1b357SJason Molenda }
1285b9c1b51eSKate Stone return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr,
1286b9c1b51eSKate Stone function_changed, initial_function);
1287aff1b357SJason Molenda }
1288aff1b357SJason Molenda
SetLoggingCallback(lldb::LogOutputCallback log_callback,void * baton)1289b9c1b51eSKate Stone void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback,
1290b9c1b51eSKate Stone void *baton) {
12914f02b22dSJim Ingham // For simplicity's sake, I am not going to deal with how to close down any
12924f02b22dSJim Ingham // open logging streams, I just redirect everything from here on out to the
12934f02b22dSJim Ingham // callback.
1294de747565SJonas Devlieghere m_callback_handler_sp =
1295de747565SJonas Devlieghere std::make_shared<CallbackLogHandler>(log_callback, baton);
1296228063cdSJim Ingham }
1297228063cdSJim Ingham
PrivateReportProgress(Debugger & debugger,uint64_t progress_id,const std::string & message,uint64_t completed,uint64_t total,bool is_debugger_specific)1298e122877fSGreg Clayton static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id,
1299e122877fSGreg Clayton const std::string &message,
1300e122877fSGreg Clayton uint64_t completed, uint64_t total,
1301e122877fSGreg Clayton bool is_debugger_specific) {
1302e122877fSGreg Clayton // Only deliver progress events if we have any progress listeners.
1303e122877fSGreg Clayton const uint32_t event_type = Debugger::eBroadcastBitProgress;
1304e122877fSGreg Clayton if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type))
1305e122877fSGreg Clayton return;
13065e65e79bSJonas Devlieghere EventSP event_sp(new Event(
13075e65e79bSJonas Devlieghere event_type, new ProgressEventData(progress_id, message, completed, total,
13085e65e79bSJonas Devlieghere is_debugger_specific)));
1309e122877fSGreg Clayton debugger.GetBroadcaster().BroadcastEvent(event_sp);
1310e122877fSGreg Clayton }
1311e122877fSGreg Clayton
ReportProgress(uint64_t progress_id,const std::string & message,uint64_t completed,uint64_t total,llvm::Optional<lldb::user_id_t> debugger_id)1312e122877fSGreg Clayton void Debugger::ReportProgress(uint64_t progress_id, const std::string &message,
1313e122877fSGreg Clayton uint64_t completed, uint64_t total,
1314e122877fSGreg Clayton llvm::Optional<lldb::user_id_t> debugger_id) {
1315e122877fSGreg Clayton // Check if this progress is for a specific debugger.
13165413bf1bSKazu Hirata if (debugger_id) {
1317e122877fSGreg Clayton // It is debugger specific, grab it and deliver the event if the debugger
1318e122877fSGreg Clayton // still exists.
1319e122877fSGreg Clayton DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);
1320e122877fSGreg Clayton if (debugger_sp)
1321e122877fSGreg Clayton PrivateReportProgress(*debugger_sp, progress_id, message, completed,
1322e122877fSGreg Clayton total, /*is_debugger_specific*/ true);
1323e122877fSGreg Clayton return;
1324e122877fSGreg Clayton }
1325e122877fSGreg Clayton // The progress event is not debugger specific, iterate over all debuggers
1326e122877fSGreg Clayton // and deliver a progress event to each one.
1327e122877fSGreg Clayton if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1328e122877fSGreg Clayton std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1329e122877fSGreg Clayton DebuggerList::iterator pos, end = g_debugger_list_ptr->end();
1330e122877fSGreg Clayton for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos)
1331e122877fSGreg Clayton PrivateReportProgress(*(*pos), progress_id, message, completed, total,
1332e122877fSGreg Clayton /*is_debugger_specific*/ false);
1333e122877fSGreg Clayton }
1334e122877fSGreg Clayton }
1335e122877fSGreg Clayton
PrivateReportDiagnostic(Debugger & debugger,DiagnosticEventData::Type type,std::string message,bool debugger_specific)13362fc38b2bSJonas Devlieghere static void PrivateReportDiagnostic(Debugger &debugger,
13372fc38b2bSJonas Devlieghere DiagnosticEventData::Type type,
13382fc38b2bSJonas Devlieghere std::string message,
13392fc38b2bSJonas Devlieghere bool debugger_specific) {
13402fc38b2bSJonas Devlieghere uint32_t event_type = 0;
13412fc38b2bSJonas Devlieghere switch (type) {
13422fc38b2bSJonas Devlieghere case DiagnosticEventData::Type::Warning:
13432fc38b2bSJonas Devlieghere event_type = Debugger::eBroadcastBitWarning;
13442fc38b2bSJonas Devlieghere break;
13452fc38b2bSJonas Devlieghere case DiagnosticEventData::Type::Error:
13462fc38b2bSJonas Devlieghere event_type = Debugger::eBroadcastBitError;
13472fc38b2bSJonas Devlieghere break;
13482fc38b2bSJonas Devlieghere }
13492fc38b2bSJonas Devlieghere
13502fc38b2bSJonas Devlieghere Broadcaster &broadcaster = debugger.GetBroadcaster();
13512fc38b2bSJonas Devlieghere if (!broadcaster.EventTypeHasListeners(event_type)) {
13522fc38b2bSJonas Devlieghere // Diagnostics are too important to drop. If nobody is listening, print the
13532fc38b2bSJonas Devlieghere // diagnostic directly to the debugger's error stream.
13542fc38b2bSJonas Devlieghere DiagnosticEventData event_data(type, std::move(message), debugger_specific);
13552fc38b2bSJonas Devlieghere StreamSP stream = debugger.GetAsyncErrorStream();
13562fc38b2bSJonas Devlieghere event_data.Dump(stream.get());
13572fc38b2bSJonas Devlieghere return;
13582fc38b2bSJonas Devlieghere }
13592fc38b2bSJonas Devlieghere EventSP event_sp = std::make_shared<Event>(
13602fc38b2bSJonas Devlieghere event_type,
13612fc38b2bSJonas Devlieghere new DiagnosticEventData(type, std::move(message), debugger_specific));
13622fc38b2bSJonas Devlieghere broadcaster.BroadcastEvent(event_sp);
13632fc38b2bSJonas Devlieghere }
13642fc38b2bSJonas Devlieghere
ReportDiagnosticImpl(DiagnosticEventData::Type type,std::string message,llvm::Optional<lldb::user_id_t> debugger_id,std::once_flag * once)13652fc38b2bSJonas Devlieghere void Debugger::ReportDiagnosticImpl(DiagnosticEventData::Type type,
13662fc38b2bSJonas Devlieghere std::string message,
13672fc38b2bSJonas Devlieghere llvm::Optional<lldb::user_id_t> debugger_id,
13682fc38b2bSJonas Devlieghere std::once_flag *once) {
13692fc38b2bSJonas Devlieghere auto ReportDiagnosticLambda = [&]() {
13702fc38b2bSJonas Devlieghere // Check if this progress is for a specific debugger.
13712fc38b2bSJonas Devlieghere if (debugger_id) {
13722fc38b2bSJonas Devlieghere // It is debugger specific, grab it and deliver the event if the debugger
13732fc38b2bSJonas Devlieghere // still exists.
13742fc38b2bSJonas Devlieghere DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id);
13752fc38b2bSJonas Devlieghere if (debugger_sp)
13762fc38b2bSJonas Devlieghere PrivateReportDiagnostic(*debugger_sp, type, std::move(message), true);
13772fc38b2bSJonas Devlieghere return;
13782fc38b2bSJonas Devlieghere }
13792fc38b2bSJonas Devlieghere // The progress event is not debugger specific, iterate over all debuggers
13802fc38b2bSJonas Devlieghere // and deliver a progress event to each one.
13812fc38b2bSJonas Devlieghere if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
13822fc38b2bSJonas Devlieghere std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
13832fc38b2bSJonas Devlieghere for (const auto &debugger : *g_debugger_list_ptr)
13842fc38b2bSJonas Devlieghere PrivateReportDiagnostic(*debugger, type, message, false);
13852fc38b2bSJonas Devlieghere }
13862fc38b2bSJonas Devlieghere };
13872fc38b2bSJonas Devlieghere
13882fc38b2bSJonas Devlieghere if (once)
13892fc38b2bSJonas Devlieghere std::call_once(*once, ReportDiagnosticLambda);
13902fc38b2bSJonas Devlieghere else
13912fc38b2bSJonas Devlieghere ReportDiagnosticLambda();
13922fc38b2bSJonas Devlieghere }
13932fc38b2bSJonas Devlieghere
ReportWarning(std::string message,llvm::Optional<lldb::user_id_t> debugger_id,std::once_flag * once)13942fc38b2bSJonas Devlieghere void Debugger::ReportWarning(std::string message,
13952fc38b2bSJonas Devlieghere llvm::Optional<lldb::user_id_t> debugger_id,
13962fc38b2bSJonas Devlieghere std::once_flag *once) {
13972fc38b2bSJonas Devlieghere ReportDiagnosticImpl(DiagnosticEventData::Type::Warning, std::move(message),
13982fc38b2bSJonas Devlieghere debugger_id, once);
13992fc38b2bSJonas Devlieghere }
14002fc38b2bSJonas Devlieghere
ReportError(std::string message,llvm::Optional<lldb::user_id_t> debugger_id,std::once_flag * once)14012fc38b2bSJonas Devlieghere void Debugger::ReportError(std::string message,
14022fc38b2bSJonas Devlieghere llvm::Optional<lldb::user_id_t> debugger_id,
14032fc38b2bSJonas Devlieghere std::once_flag *once) {
14042fc38b2bSJonas Devlieghere
14052fc38b2bSJonas Devlieghere ReportDiagnosticImpl(DiagnosticEventData::Type::Error, std::move(message),
14062fc38b2bSJonas Devlieghere debugger_id, once);
14072fc38b2bSJonas Devlieghere }
14082fc38b2bSJonas Devlieghere
1409be265d25SJonas Devlieghere static std::shared_ptr<LogHandler>
CreateLogHandler(LogHandlerKind log_handler_kind,int fd,bool should_close,size_t buffer_size)1410be265d25SJonas Devlieghere CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,
1411be265d25SJonas Devlieghere size_t buffer_size) {
1412be265d25SJonas Devlieghere switch (log_handler_kind) {
1413be265d25SJonas Devlieghere case eLogHandlerStream:
1414be265d25SJonas Devlieghere return std::make_shared<StreamLogHandler>(fd, should_close, buffer_size);
1415be265d25SJonas Devlieghere case eLogHandlerCircular:
1416be265d25SJonas Devlieghere return std::make_shared<RotatingLogHandler>(buffer_size);
1417be265d25SJonas Devlieghere case eLogHandlerSystem:
1418be265d25SJonas Devlieghere return std::make_shared<SystemLogHandler>();
1419be265d25SJonas Devlieghere case eLogHandlerCallback:
1420be265d25SJonas Devlieghere return {};
1421be265d25SJonas Devlieghere }
1422be265d25SJonas Devlieghere return {};
1423be265d25SJonas Devlieghere }
1424be265d25SJonas Devlieghere
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)14255e336903SPavel Labath bool Debugger::EnableLog(llvm::StringRef channel,
14265e336903SPavel Labath llvm::ArrayRef<const char *> categories,
14275e336903SPavel Labath llvm::StringRef log_file, uint32_t log_options,
1428be265d25SJonas Devlieghere size_t buffer_size, LogHandlerKind log_handler_kind,
1429be265d25SJonas Devlieghere llvm::raw_ostream &error_stream) {
14305fae71c5SPavel Labath
14316ff49af3SJonas Devlieghere std::shared_ptr<LogHandler> log_handler_sp;
14326ff49af3SJonas Devlieghere if (m_callback_handler_sp) {
14336ff49af3SJonas Devlieghere log_handler_sp = m_callback_handler_sp;
1434228063cdSJim Ingham // For now when using the callback mode you always get thread & timestamp.
1435b9c1b51eSKate Stone log_options |=
1436b9c1b51eSKate Stone LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
14375e336903SPavel Labath } else if (log_file.empty()) {
1438be265d25SJonas Devlieghere log_handler_sp =
1439be265d25SJonas Devlieghere CreateLogHandler(log_handler_kind, GetOutputFile().GetDescriptor(),
1440be265d25SJonas Devlieghere /*should_close=*/false, buffer_size);
1441b9c1b51eSKate Stone } else {
14426ff49af3SJonas Devlieghere auto pos = m_stream_handlers.find(log_file);
14436ff49af3SJonas Devlieghere if (pos != m_stream_handlers.end())
14446ff49af3SJonas Devlieghere log_handler_sp = pos->second.lock();
14456ff49af3SJonas Devlieghere if (!log_handler_sp) {
14466b2e6765SJonas Devlieghere File::OpenOptions flags =
144714735cabSMichał Górny File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
14485fae71c5SPavel Labath if (log_options & LLDB_LOG_OPTION_APPEND)
14496b2e6765SJonas Devlieghere flags |= File::eOpenOptionAppend;
14506b2e6765SJonas Devlieghere else
14516b2e6765SJonas Devlieghere flags |= File::eOpenOptionTruncate;
1452867c347cSRaphael Isemann llvm::Expected<FileUP> file = FileSystem::Instance().Open(
14536b2e6765SJonas Devlieghere FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false);
14546b2e6765SJonas Devlieghere if (!file) {
1455867c347cSRaphael Isemann error_stream << "Unable to open log file '" << log_file
1456867c347cSRaphael Isemann << "': " << llvm::toString(file.takeError()) << "\n";
14575fae71c5SPavel Labath return false;
14585fae71c5SPavel Labath }
14596b2e6765SJonas Devlieghere
1460be265d25SJonas Devlieghere log_handler_sp =
1461be265d25SJonas Devlieghere CreateLogHandler(log_handler_kind, (*file)->GetDescriptor(),
1462be265d25SJonas Devlieghere /*should_close=*/true, buffer_size);
14636ff49af3SJonas Devlieghere m_stream_handlers[log_file] = log_handler_sp;
1464228063cdSJim Ingham }
1465228063cdSJim Ingham }
14666ff49af3SJonas Devlieghere assert(log_handler_sp);
1467228063cdSJim Ingham
1468228063cdSJim Ingham if (log_options == 0)
146970841b97SJonas Devlieghere log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
1470228063cdSJim Ingham
14716ff49af3SJonas Devlieghere return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories,
1472b9c1b51eSKate Stone error_stream);
1473228063cdSJim Ingham }
1474228063cdSJim Ingham
1475bbf70c04SJonas Devlieghere ScriptInterpreter *
GetScriptInterpreter(bool can_create,llvm::Optional<lldb::ScriptLanguage> language)1476bbf70c04SJonas Devlieghere Debugger::GetScriptInterpreter(bool can_create,
1477bbf70c04SJonas Devlieghere llvm::Optional<lldb::ScriptLanguage> language) {
14782b29b432SJonas Devlieghere std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex);
1479bbf70c04SJonas Devlieghere lldb::ScriptLanguage script_language =
1480bbf70c04SJonas Devlieghere language ? *language : GetScriptLanguage();
14812b29b432SJonas Devlieghere
1482bbf70c04SJonas Devlieghere if (!m_script_interpreters[script_language]) {
14832b29b432SJonas Devlieghere if (!can_create)
14842b29b432SJonas Devlieghere return nullptr;
1485bbf70c04SJonas Devlieghere m_script_interpreters[script_language] =
1486bbf70c04SJonas Devlieghere PluginManager::GetScriptInterpreterForLanguage(script_language, *this);
14872b29b432SJonas Devlieghere }
14882b29b432SJonas Devlieghere
1489bbf70c04SJonas Devlieghere return m_script_interpreters[script_language].get();
14902b29b432SJonas Devlieghere }
14912b29b432SJonas Devlieghere
GetSourceManager()1492b9c1b51eSKate Stone SourceManager &Debugger::GetSourceManager() {
1493d5b44036SJonas Devlieghere if (!m_source_manager_up)
1494a8f3ae7cSJonas Devlieghere m_source_manager_up = std::make_unique<SourceManager>(shared_from_this());
1495d5b44036SJonas Devlieghere return *m_source_manager_up;
14969585fbfcSGreg Clayton }
14979585fbfcSGreg Clayton
149844d93782SGreg Clayton // This function handles events that were broadcast by the process.
HandleBreakpointEvent(const EventSP & event_sp)1499b9c1b51eSKate Stone void Debugger::HandleBreakpointEvent(const EventSP &event_sp) {
150044d93782SGreg Clayton using namespace lldb;
1501b9c1b51eSKate Stone const uint32_t event_type =
1502b9c1b51eSKate Stone Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent(
1503b9c1b51eSKate Stone event_sp);
150444d93782SGreg Clayton
150544d93782SGreg Clayton // if (event_type & eBreakpointEventTypeAdded
150644d93782SGreg Clayton // || event_type & eBreakpointEventTypeRemoved
150744d93782SGreg Clayton // || event_type & eBreakpointEventTypeEnabled
150844d93782SGreg Clayton // || event_type & eBreakpointEventTypeDisabled
150944d93782SGreg Clayton // || event_type & eBreakpointEventTypeCommandChanged
151044d93782SGreg Clayton // || event_type & eBreakpointEventTypeConditionChanged
151144d93782SGreg Clayton // || event_type & eBreakpointEventTypeIgnoreChanged
151244d93782SGreg Clayton // || event_type & eBreakpointEventTypeLocationsResolved)
151344d93782SGreg Clayton // {
1514b9c1b51eSKate Stone // // Don't do anything about these events, since the breakpoint
1515b9c1b51eSKate Stone // commands already echo these actions.
151644d93782SGreg Clayton // }
151744d93782SGreg Clayton //
1518b9c1b51eSKate Stone if (event_type & eBreakpointEventTypeLocationsAdded) {
1519b9c1b51eSKate Stone uint32_t num_new_locations =
1520b9c1b51eSKate Stone Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent(
1521b9c1b51eSKate Stone event_sp);
1522b9c1b51eSKate Stone if (num_new_locations > 0) {
1523b9c1b51eSKate Stone BreakpointSP breakpoint =
1524b9c1b51eSKate Stone Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp);
15254446487dSPavel Labath StreamSP output_sp(GetAsyncOutputStream());
1526b9c1b51eSKate Stone if (output_sp) {
152744d93782SGreg Clayton output_sp->Printf("%d location%s added to breakpoint %d\n",
1528b9c1b51eSKate Stone num_new_locations, num_new_locations == 1 ? "" : "s",
152944d93782SGreg Clayton breakpoint->GetID());
15304446487dSPavel Labath output_sp->Flush();
153144d93782SGreg Clayton }
153244d93782SGreg Clayton }
153344d93782SGreg Clayton }
153444d93782SGreg Clayton // else if (event_type & eBreakpointEventTypeLocationsRemoved)
153544d93782SGreg Clayton // {
1536b9c1b51eSKate Stone // // These locations just get disabled, not sure it is worth spamming
1537b9c1b51eSKate Stone // folks about this on the command line.
153844d93782SGreg Clayton // }
153944d93782SGreg Clayton // else if (event_type & eBreakpointEventTypeLocationsResolved)
154044d93782SGreg Clayton // {
1541b9c1b51eSKate Stone // // This might be an interesting thing to note, but I'm going to
1542b9c1b51eSKate Stone // leave it quiet for now, it just looked noisy.
154344d93782SGreg Clayton // }
154444d93782SGreg Clayton }
154544d93782SGreg Clayton
FlushProcessOutput(Process & process,bool flush_stdout,bool flush_stderr)1546a9d58436SPavel Labath void Debugger::FlushProcessOutput(Process &process, bool flush_stdout,
1547a9d58436SPavel Labath bool flush_stderr) {
1548a9d58436SPavel Labath const auto &flush = [&](Stream &stream,
1549a9d58436SPavel Labath size_t (Process::*get)(char *, size_t, Status &)) {
155097206d57SZachary Turner Status error;
155144d93782SGreg Clayton size_t len;
1552a9d58436SPavel Labath char buffer[1024];
1553a9d58436SPavel Labath while ((len = (process.*get)(buffer, sizeof(buffer), error)) > 0)
1554a9d58436SPavel Labath stream.Write(buffer, len);
1555a9d58436SPavel Labath stream.Flush();
1556a9d58436SPavel Labath };
155744d93782SGreg Clayton
1558a9d58436SPavel Labath std::lock_guard<std::mutex> guard(m_output_flush_mutex);
1559a9d58436SPavel Labath if (flush_stdout)
1560a9d58436SPavel Labath flush(*GetAsyncOutputStream(), &Process::GetSTDOUT);
1561a9d58436SPavel Labath if (flush_stderr)
1562a9d58436SPavel Labath flush(*GetAsyncErrorStream(), &Process::GetSTDERR);
156344d93782SGreg Clayton }
156444d93782SGreg Clayton
156544d93782SGreg Clayton // This function handles events that were broadcast by the process.
HandleProcessEvent(const EventSP & event_sp)1566b9c1b51eSKate Stone void Debugger::HandleProcessEvent(const EventSP &event_sp) {
156744d93782SGreg Clayton using namespace lldb;
156844d93782SGreg Clayton const uint32_t event_type = event_sp->GetType();
1569b9c1b51eSKate Stone ProcessSP process_sp =
1570b9c1b51eSKate Stone (event_type == Process::eBroadcastBitStructuredData)
157175930019STodd Fiala ? EventDataStructuredData::GetProcessFromEvent(event_sp.get())
157275930019STodd Fiala : Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
157344d93782SGreg Clayton
15744446487dSPavel Labath StreamSP output_stream_sp = GetAsyncOutputStream();
15754446487dSPavel Labath StreamSP error_stream_sp = GetAsyncErrorStream();
157644d93782SGreg Clayton const bool gui_enabled = IsForwardingEvents();
157744d93782SGreg Clayton
1578b9c1b51eSKate Stone if (!gui_enabled) {
1579b4874f1aSGreg Clayton bool pop_process_io_handler = false;
158044d93782SGreg Clayton assert(process_sp);
158144d93782SGreg Clayton
15824446487dSPavel Labath bool state_is_stopped = false;
1583b9c1b51eSKate Stone const bool got_state_changed =
1584b9c1b51eSKate Stone (event_type & Process::eBroadcastBitStateChanged) != 0;
15854446487dSPavel Labath const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0;
15864446487dSPavel Labath const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0;
1587b9c1b51eSKate Stone const bool got_structured_data =
1588b9c1b51eSKate Stone (event_type & Process::eBroadcastBitStructuredData) != 0;
158975930019STodd Fiala
1590b9c1b51eSKate Stone if (got_state_changed) {
1591b9c1b51eSKate Stone StateType event_state =
1592b9c1b51eSKate Stone Process::ProcessEventData::GetStateFromEvent(event_sp.get());
15934446487dSPavel Labath state_is_stopped = StateIsStoppedState(event_state, false);
159444d93782SGreg Clayton }
1595b4874f1aSGreg Clayton
15964446487dSPavel Labath // Display running state changes first before any STDIO
1597b9c1b51eSKate Stone if (got_state_changed && !state_is_stopped) {
1598b9c1b51eSKate Stone Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),
1599b9c1b51eSKate Stone pop_process_io_handler);
160044d93782SGreg Clayton }
1601b4874f1aSGreg Clayton
1602a9d58436SPavel Labath // Now display STDOUT and STDERR
1603a9d58436SPavel Labath FlushProcessOutput(*process_sp, got_stdout || got_state_changed,
1604a9d58436SPavel Labath got_stderr || got_state_changed);
1605b4874f1aSGreg Clayton
160675930019STodd Fiala // Give structured data events an opportunity to display.
1607b9c1b51eSKate Stone if (got_structured_data) {
160875930019STodd Fiala StructuredDataPluginSP plugin_sp =
160975930019STodd Fiala EventDataStructuredData::GetPluginFromEvent(event_sp.get());
1610b9c1b51eSKate Stone if (plugin_sp) {
161175930019STodd Fiala auto structured_data_sp =
161275930019STodd Fiala EventDataStructuredData::GetObjectFromEvent(event_sp.get());
1613b9c1b51eSKate Stone if (output_stream_sp) {
161475930019STodd Fiala StreamString content_stream;
161597206d57SZachary Turner Status error =
1616b9c1b51eSKate Stone plugin_sp->GetDescription(structured_data_sp, content_stream);
1617b9c1b51eSKate Stone if (error.Success()) {
1618b9c1b51eSKate Stone if (!content_stream.GetString().empty()) {
161975930019STodd Fiala // Add newline.
162075930019STodd Fiala content_stream.PutChar('\n');
162175930019STodd Fiala content_stream.Flush();
162275930019STodd Fiala
162375930019STodd Fiala // Print it.
1624771ef6d4SMalcolm Parsons output_stream_sp->PutCString(content_stream.GetString());
162575930019STodd Fiala }
1626b9c1b51eSKate Stone } else {
1627a3939e15SPavel Labath error_stream_sp->Format("Failed to print structured "
1628a3939e15SPavel Labath "data with plugin {0}: {1}",
1629a3939e15SPavel Labath plugin_sp->GetPluginName(), error);
163075930019STodd Fiala }
163175930019STodd Fiala }
163275930019STodd Fiala }
163375930019STodd Fiala }
163475930019STodd Fiala
16354446487dSPavel Labath // Now display any stopped state changes after any STDIO
1636b9c1b51eSKate Stone if (got_state_changed && state_is_stopped) {
1637b9c1b51eSKate Stone Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(),
1638b9c1b51eSKate Stone pop_process_io_handler);
163944d93782SGreg Clayton }
164044d93782SGreg Clayton
16414446487dSPavel Labath output_stream_sp->Flush();
16424446487dSPavel Labath error_stream_sp->Flush();
164344d93782SGreg Clayton
1644b4874f1aSGreg Clayton if (pop_process_io_handler)
1645b4874f1aSGreg Clayton process_sp->PopProcessIOHandler();
1646b4874f1aSGreg Clayton }
1647b4874f1aSGreg Clayton }
1648b4874f1aSGreg Clayton
HandleThreadEvent(const EventSP & event_sp)1649b9c1b51eSKate Stone void Debugger::HandleThreadEvent(const EventSP &event_sp) {
165005097246SAdrian Prantl // At present the only thread event we handle is the Frame Changed event, and
165105097246SAdrian Prantl // all we do for that is just reprint the thread status for that thread.
165244d93782SGreg Clayton using namespace lldb;
165344d93782SGreg Clayton const uint32_t event_type = event_sp->GetType();
16546a9767c7SJim Ingham const bool stop_format = true;
165544d93782SGreg Clayton if (event_type == Thread::eBroadcastBitStackChanged ||
1656b9c1b51eSKate Stone event_type == Thread::eBroadcastBitThreadSelected) {
1657b9c1b51eSKate Stone ThreadSP thread_sp(
1658b9c1b51eSKate Stone Thread::ThreadEventData::GetThreadFromEvent(event_sp.get()));
1659b9c1b51eSKate Stone if (thread_sp) {
16606a9767c7SJim Ingham thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format);
166144d93782SGreg Clayton }
166244d93782SGreg Clayton }
166344d93782SGreg Clayton }
166444d93782SGreg Clayton
IsForwardingEvents()1665b9c1b51eSKate Stone bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; }
166644d93782SGreg Clayton
EnableForwardEvents(const ListenerSP & listener_sp)1667b9c1b51eSKate Stone void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) {
166844d93782SGreg Clayton m_forward_listener_sp = listener_sp;
166944d93782SGreg Clayton }
167044d93782SGreg Clayton
CancelForwardEvents(const ListenerSP & listener_sp)1671b9c1b51eSKate Stone void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) {
167244d93782SGreg Clayton m_forward_listener_sp.reset();
167344d93782SGreg Clayton }
167444d93782SGreg Clayton
DefaultEventHandler()1675d0810779SPavel Labath lldb::thread_result_t Debugger::DefaultEventHandler() {
1676583bbb1dSJim Ingham ListenerSP listener_sp(GetListener());
167744d93782SGreg Clayton ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
167844d93782SGreg Clayton ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());
167944d93782SGreg Clayton ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());
168044d93782SGreg Clayton BroadcastEventSpec target_event_spec(broadcaster_class_target,
168144d93782SGreg Clayton Target::eBroadcastBitBreakpointChanged);
168244d93782SGreg Clayton
1683b9c1b51eSKate Stone BroadcastEventSpec process_event_spec(
1684b9c1b51eSKate Stone broadcaster_class_process,
1685b9c1b51eSKate Stone Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT |
1686b9c1b51eSKate Stone Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData);
168744d93782SGreg Clayton
168844d93782SGreg Clayton BroadcastEventSpec thread_event_spec(broadcaster_class_thread,
168944d93782SGreg Clayton Thread::eBroadcastBitStackChanged |
169044d93782SGreg Clayton Thread::eBroadcastBitThreadSelected);
169144d93782SGreg Clayton
1692b9c1b51eSKate Stone listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
1693b9c1b51eSKate Stone target_event_spec);
1694b9c1b51eSKate Stone listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
1695b9c1b51eSKate Stone process_event_spec);
1696b9c1b51eSKate Stone listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp,
1697b9c1b51eSKate Stone thread_event_spec);
1698b9c1b51eSKate Stone listener_sp->StartListeningForEvents(
1699d5b44036SJonas Devlieghere m_command_interpreter_up.get(),
170044d93782SGreg Clayton CommandInterpreter::eBroadcastBitQuitCommandReceived |
170144d93782SGreg Clayton CommandInterpreter::eBroadcastBitAsynchronousOutputData |
170244d93782SGreg Clayton CommandInterpreter::eBroadcastBitAsynchronousErrorData);
170344d93782SGreg Clayton
17042fc38b2bSJonas Devlieghere listener_sp->StartListeningForEvents(
17052fc38b2bSJonas Devlieghere &m_broadcaster,
17062fc38b2bSJonas Devlieghere eBroadcastBitProgress | eBroadcastBitWarning | eBroadcastBitError);
17075a27b998SJonas Devlieghere
170805097246SAdrian Prantl // Let the thread that spawned us know that we have started up and that we
170905097246SAdrian Prantl // are now listening to all required events so no events get missed
1710afa91e33SGreg Clayton m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening);
1711afa91e33SGreg Clayton
171244d93782SGreg Clayton bool done = false;
1713b9c1b51eSKate Stone while (!done) {
171444d93782SGreg Clayton EventSP event_sp;
1715d35031e1SPavel Labath if (listener_sp->GetEvent(event_sp, llvm::None)) {
1716b9c1b51eSKate Stone if (event_sp) {
171744d93782SGreg Clayton Broadcaster *broadcaster = event_sp->GetBroadcaster();
1718b9c1b51eSKate Stone if (broadcaster) {
171944d93782SGreg Clayton uint32_t event_type = event_sp->GetType();
172044d93782SGreg Clayton ConstString broadcaster_class(broadcaster->GetBroadcasterClass());
1721b9c1b51eSKate Stone if (broadcaster_class == broadcaster_class_process) {
172244d93782SGreg Clayton HandleProcessEvent(event_sp);
1723b9c1b51eSKate Stone } else if (broadcaster_class == broadcaster_class_target) {
1724b9c1b51eSKate Stone if (Breakpoint::BreakpointEventData::GetEventDataFromEvent(
1725b9c1b51eSKate Stone event_sp.get())) {
172644d93782SGreg Clayton HandleBreakpointEvent(event_sp);
172744d93782SGreg Clayton }
1728b9c1b51eSKate Stone } else if (broadcaster_class == broadcaster_class_thread) {
172944d93782SGreg Clayton HandleThreadEvent(event_sp);
1730d5b44036SJonas Devlieghere } else if (broadcaster == m_command_interpreter_up.get()) {
1731b9c1b51eSKate Stone if (event_type &
1732b9c1b51eSKate Stone CommandInterpreter::eBroadcastBitQuitCommandReceived) {
173344d93782SGreg Clayton done = true;
1734b9c1b51eSKate Stone } else if (event_type &
1735b9c1b51eSKate Stone CommandInterpreter::eBroadcastBitAsynchronousErrorData) {
173665fdb342SRaphael Isemann const char *data = static_cast<const char *>(
1737b9c1b51eSKate Stone EventDataBytes::GetBytesFromEvent(event_sp.get()));
1738b9c1b51eSKate Stone if (data && data[0]) {
17394446487dSPavel Labath StreamSP error_sp(GetAsyncErrorStream());
1740b9c1b51eSKate Stone if (error_sp) {
174144d93782SGreg Clayton error_sp->PutCString(data);
174244d93782SGreg Clayton error_sp->Flush();
174344d93782SGreg Clayton }
174444d93782SGreg Clayton }
1745b9c1b51eSKate Stone } else if (event_type & CommandInterpreter::
1746b9c1b51eSKate Stone eBroadcastBitAsynchronousOutputData) {
174765fdb342SRaphael Isemann const char *data = static_cast<const char *>(
1748b9c1b51eSKate Stone EventDataBytes::GetBytesFromEvent(event_sp.get()));
1749b9c1b51eSKate Stone if (data && data[0]) {
17504446487dSPavel Labath StreamSP output_sp(GetAsyncOutputStream());
1751b9c1b51eSKate Stone if (output_sp) {
175244d93782SGreg Clayton output_sp->PutCString(data);
175344d93782SGreg Clayton output_sp->Flush();
175444d93782SGreg Clayton }
175544d93782SGreg Clayton }
175644d93782SGreg Clayton }
17575a27b998SJonas Devlieghere } else if (broadcaster == &m_broadcaster) {
17585a27b998SJonas Devlieghere if (event_type & Debugger::eBroadcastBitProgress)
17595a27b998SJonas Devlieghere HandleProgressEvent(event_sp);
17602fc38b2bSJonas Devlieghere else if (event_type & Debugger::eBroadcastBitWarning)
17612fc38b2bSJonas Devlieghere HandleDiagnosticEvent(event_sp);
17622fc38b2bSJonas Devlieghere else if (event_type & Debugger::eBroadcastBitError)
17632fc38b2bSJonas Devlieghere HandleDiagnosticEvent(event_sp);
176444d93782SGreg Clayton }
176544d93782SGreg Clayton }
176644d93782SGreg Clayton
176744d93782SGreg Clayton if (m_forward_listener_sp)
176844d93782SGreg Clayton m_forward_listener_sp->AddEvent(event_sp);
176944d93782SGreg Clayton }
177044d93782SGreg Clayton }
177144d93782SGreg Clayton }
177285200645SKonrad Kleine return {};
177344d93782SGreg Clayton }
177444d93782SGreg Clayton
StartEventHandlerThread()1775b9c1b51eSKate Stone bool Debugger::StartEventHandlerThread() {
1776b9c1b51eSKate Stone if (!m_event_handler_thread.IsJoinable()) {
177705097246SAdrian Prantl // We must synchronize with the DefaultEventHandler() thread to ensure it
177805097246SAdrian Prantl // is up and running and listening to events before we return from this
177905097246SAdrian Prantl // function. We do this by listening to events for the
1780afa91e33SGreg Clayton // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster
17811a728f66STatyana Krasnukha ConstString full_name("lldb.debugger.event-handler");
17821a728f66STatyana Krasnukha ListenerSP listener_sp(Listener::MakeListener(full_name.AsCString()));
1783b9c1b51eSKate Stone listener_sp->StartListeningForEvents(&m_sync_broadcaster,
1784b9c1b51eSKate Stone eBroadcastBitEventThreadIsListening);
1785afa91e33SGreg Clayton
1786642bc15dSRaphael Isemann llvm::StringRef thread_name =
1787e063ecccSJonas Devlieghere full_name.GetLength() < llvm::get_max_thread_name_length()
1788642bc15dSRaphael Isemann ? full_name.GetStringRef()
1789e063ecccSJonas Devlieghere : "dbg.evt-handler";
17901a728f66STatyana Krasnukha
17917c2896a2SZachary Turner // Use larger 8MB stack for this thread
1792f39c2e18SJonas Devlieghere llvm::Expected<HostThread> event_handler_thread =
1793d0810779SPavel Labath ThreadLauncher::LaunchThread(
1794d0810779SPavel Labath thread_name, [this] { return DefaultEventHandler(); },
1795f39c2e18SJonas Devlieghere g_debugger_event_thread_stack_bytes);
1796f39c2e18SJonas Devlieghere
1797f39c2e18SJonas Devlieghere if (event_handler_thread) {
1798f39c2e18SJonas Devlieghere m_event_handler_thread = *event_handler_thread;
1799f39c2e18SJonas Devlieghere } else {
1800a007a6d8SPavel Labath LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}",
1801f39c2e18SJonas Devlieghere llvm::toString(event_handler_thread.takeError()));
1802f39c2e18SJonas Devlieghere }
1803afa91e33SGreg Clayton
180405097246SAdrian Prantl // Make sure DefaultEventHandler() is running and listening to events
180505097246SAdrian Prantl // before we return from this function. We are only listening for events of
180605097246SAdrian Prantl // type eBroadcastBitEventThreadIsListening so we don't need to check the
180705097246SAdrian Prantl // event, we just need to wait an infinite amount of time for it (nullptr
180805097246SAdrian Prantl // timeout as the first parameter)
1809afa91e33SGreg Clayton lldb::EventSP event_sp;
1810d35031e1SPavel Labath listener_sp->GetEvent(event_sp, llvm::None);
1811807b6b32SGreg Clayton }
1812acee96aeSZachary Turner return m_event_handler_thread.IsJoinable();
181344d93782SGreg Clayton }
181444d93782SGreg Clayton
StopEventHandlerThread()1815b9c1b51eSKate Stone void Debugger::StopEventHandlerThread() {
1816b9c1b51eSKate Stone if (m_event_handler_thread.IsJoinable()) {
1817b9c1b51eSKate Stone GetCommandInterpreter().BroadcastEvent(
1818b9c1b51eSKate Stone CommandInterpreter::eBroadcastBitQuitCommandReceived);
181939de3110SZachary Turner m_event_handler_thread.Join(nullptr);
182044d93782SGreg Clayton }
182144d93782SGreg Clayton }
182244d93782SGreg Clayton
IOHandlerThread()1823d0810779SPavel Labath lldb::thread_result_t Debugger::IOHandlerThread() {
1824d0810779SPavel Labath RunIOHandlers();
1825d0810779SPavel Labath StopEventHandlerThread();
182685200645SKonrad Kleine return {};
182744d93782SGreg Clayton }
182844d93782SGreg Clayton
HandleProgressEvent(const lldb::EventSP & event_sp)18295a27b998SJonas Devlieghere void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
18305e65e79bSJonas Devlieghere auto *data = ProgressEventData::GetEventDataFromEvent(event_sp.get());
18315a27b998SJonas Devlieghere if (!data)
18325a27b998SJonas Devlieghere return;
18335a27b998SJonas Devlieghere
18345a27b998SJonas Devlieghere // Do some bookkeeping for the current event, regardless of whether we're
18355a27b998SJonas Devlieghere // going to show the progress.
18365a27b998SJonas Devlieghere const uint64_t id = data->GetID();
18375a27b998SJonas Devlieghere if (m_current_event_id) {
1838ea8b811bSMed Ismail Bennani Log *log = GetLog(LLDBLog::Events);
1839ea8b811bSMed Ismail Bennani if (log && log->GetVerbose()) {
1840ea8b811bSMed Ismail Bennani StreamString log_stream;
1841ea8b811bSMed Ismail Bennani log_stream.AsRawOstream()
1842ea8b811bSMed Ismail Bennani << static_cast<void *>(this) << " Debugger(" << GetID()
1843ea8b811bSMed Ismail Bennani << ")::HandleProgressEvent( m_current_event_id = "
1844ea8b811bSMed Ismail Bennani << *m_current_event_id << ", data = { ";
1845ea8b811bSMed Ismail Bennani data->Dump(&log_stream);
1846ea8b811bSMed Ismail Bennani log_stream << " } )";
1847ea8b811bSMed Ismail Bennani log->PutString(log_stream.GetString());
1848ea8b811bSMed Ismail Bennani }
18495a27b998SJonas Devlieghere if (id != *m_current_event_id)
18505a27b998SJonas Devlieghere return;
1851ea8b811bSMed Ismail Bennani if (data->GetCompleted() == data->GetTotal())
18525a27b998SJonas Devlieghere m_current_event_id.reset();
18535a27b998SJonas Devlieghere } else {
18545a27b998SJonas Devlieghere m_current_event_id = id;
18555a27b998SJonas Devlieghere }
18565a27b998SJonas Devlieghere
18575a27b998SJonas Devlieghere // Decide whether we actually are going to show the progress. This decision
18585a27b998SJonas Devlieghere // can change between iterations so check it inside the loop.
18595a27b998SJonas Devlieghere if (!GetShowProgress())
18605a27b998SJonas Devlieghere return;
18615a27b998SJonas Devlieghere
18625a27b998SJonas Devlieghere // Determine whether the current output file is an interactive terminal with
18635a27b998SJonas Devlieghere // color support. We assume that if we support ANSI escape codes we support
18645a27b998SJonas Devlieghere // vt100 escape codes.
1865c231deb7SJonas Devlieghere File &file = GetOutputFile();
1866c231deb7SJonas Devlieghere if (!file.GetIsInteractive() || !file.GetIsTerminalWithColors())
18675a27b998SJonas Devlieghere return;
18685a27b998SJonas Devlieghere
1869c231deb7SJonas Devlieghere StreamSP output = GetAsyncOutputStream();
1870c231deb7SJonas Devlieghere
1871e618eb87SJonas Devlieghere // Print over previous line, if any.
1872c231deb7SJonas Devlieghere output->Printf("\r");
1873e618eb87SJonas Devlieghere
1874ea8b811bSMed Ismail Bennani if (data->GetCompleted() == data->GetTotal()) {
18755a27b998SJonas Devlieghere // Clear the current line.
1876c231deb7SJonas Devlieghere output->Printf("\x1B[2K");
1877c231deb7SJonas Devlieghere output->Flush();
18785a27b998SJonas Devlieghere return;
18795a27b998SJonas Devlieghere }
18805a27b998SJonas Devlieghere
1881051a5ae9SMed Ismail Bennani // Trim the progress message if it exceeds the window's width and print it.
1882051a5ae9SMed Ismail Bennani std::string message = data->GetMessage();
1883051a5ae9SMed Ismail Bennani if (data->IsFinite())
1884051a5ae9SMed Ismail Bennani message = llvm::formatv("[{0}/{1}] {2}", data->GetCompleted(),
1885051a5ae9SMed Ismail Bennani data->GetTotal(), message)
1886051a5ae9SMed Ismail Bennani .str();
1887051a5ae9SMed Ismail Bennani
1888051a5ae9SMed Ismail Bennani // Trim the progress message if it exceeds the window's width and print it.
1889051a5ae9SMed Ismail Bennani const uint32_t term_width = GetTerminalWidth();
1890051a5ae9SMed Ismail Bennani const uint32_t ellipsis = 3;
1891051a5ae9SMed Ismail Bennani if (message.size() + ellipsis >= term_width)
1892051a5ae9SMed Ismail Bennani message = message.substr(0, term_width - ellipsis);
1893051a5ae9SMed Ismail Bennani
1894097d46f4SJonas Devlieghere const bool use_color = GetUseColor();
1895097d46f4SJonas Devlieghere llvm::StringRef ansi_prefix = GetShowProgressAnsiPrefix();
1896097d46f4SJonas Devlieghere if (!ansi_prefix.empty())
1897c231deb7SJonas Devlieghere output->Printf(
1898097d46f4SJonas Devlieghere "%s", ansi::FormatAnsiTerminalCodes(ansi_prefix, use_color).c_str());
1899097d46f4SJonas Devlieghere
1900c231deb7SJonas Devlieghere output->Printf("%s...", message.c_str());
19015a27b998SJonas Devlieghere
1902097d46f4SJonas Devlieghere llvm::StringRef ansi_suffix = GetShowProgressAnsiSuffix();
1903097d46f4SJonas Devlieghere if (!ansi_suffix.empty())
1904c231deb7SJonas Devlieghere output->Printf(
1905097d46f4SJonas Devlieghere "%s", ansi::FormatAnsiTerminalCodes(ansi_suffix, use_color).c_str());
1906097d46f4SJonas Devlieghere
19075a27b998SJonas Devlieghere // Clear until the end of the line.
1908c231deb7SJonas Devlieghere output->Printf("\x1B[K\r");
19095a27b998SJonas Devlieghere
19105a27b998SJonas Devlieghere // Flush the output.
1911c231deb7SJonas Devlieghere output->Flush();
19125a27b998SJonas Devlieghere }
19135a27b998SJonas Devlieghere
HandleDiagnosticEvent(const lldb::EventSP & event_sp)19142fc38b2bSJonas Devlieghere void Debugger::HandleDiagnosticEvent(const lldb::EventSP &event_sp) {
19152fc38b2bSJonas Devlieghere auto *data = DiagnosticEventData::GetEventDataFromEvent(event_sp.get());
19162fc38b2bSJonas Devlieghere if (!data)
19172fc38b2bSJonas Devlieghere return;
19182fc38b2bSJonas Devlieghere
19192fc38b2bSJonas Devlieghere StreamSP stream = GetAsyncErrorStream();
19202fc38b2bSJonas Devlieghere data->Dump(stream.get());
19212fc38b2bSJonas Devlieghere }
19222fc38b2bSJonas Devlieghere
HasIOHandlerThread()1923b9c1b51eSKate Stone bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); }
19246681041dSSean Callanan
StartIOHandlerThread()1925b9c1b51eSKate Stone bool Debugger::StartIOHandlerThread() {
1926f39c2e18SJonas Devlieghere if (!m_io_handler_thread.IsJoinable()) {
1927f39c2e18SJonas Devlieghere llvm::Expected<HostThread> io_handler_thread = ThreadLauncher::LaunchThread(
1928d0810779SPavel Labath "lldb.debugger.io-handler", [this] { return IOHandlerThread(); },
1929807b6b32SGreg Clayton 8 * 1024 * 1024); // Use larger 8MB stack for this thread
1930f39c2e18SJonas Devlieghere if (io_handler_thread) {
1931f39c2e18SJonas Devlieghere m_io_handler_thread = *io_handler_thread;
1932f39c2e18SJonas Devlieghere } else {
1933a007a6d8SPavel Labath LLDB_LOG(GetLog(LLDBLog::Host), "failed to launch host thread: {}",
1934f39c2e18SJonas Devlieghere llvm::toString(io_handler_thread.takeError()));
1935f39c2e18SJonas Devlieghere }
1936f39c2e18SJonas Devlieghere }
1937acee96aeSZachary Turner return m_io_handler_thread.IsJoinable();
193844d93782SGreg Clayton }
193944d93782SGreg Clayton
StopIOHandlerThread()1940b9c1b51eSKate Stone void Debugger::StopIOHandlerThread() {
1941b9c1b51eSKate Stone if (m_io_handler_thread.IsJoinable()) {
19427ca15ba7SLawrence D'Anna GetInputFile().Close();
194339de3110SZachary Turner m_io_handler_thread.Join(nullptr);
194444d93782SGreg Clayton }
194544d93782SGreg Clayton }
194644d93782SGreg Clayton
JoinIOHandlerThread()1947b9c1b51eSKate Stone void Debugger::JoinIOHandlerThread() {
1948b9c1b51eSKate Stone if (HasIOHandlerThread()) {
19496681041dSSean Callanan thread_result_t result;
19506681041dSSean Callanan m_io_handler_thread.Join(&result);
19516681041dSSean Callanan m_io_handler_thread = LLDB_INVALID_HOST_THREAD;
19526681041dSSean Callanan }
19536681041dSSean Callanan }
19546681041dSSean Callanan
GetSelectedOrDummyTarget(bool prefer_dummy)1955b2fa3b92SJonas Devlieghere Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) {
1956b9c1b51eSKate Stone if (!prefer_dummy) {
1957b2fa3b92SJonas Devlieghere if (TargetSP target = m_target_list.GetSelectedTarget())
1958b2fa3b92SJonas Devlieghere return *target;
195933df7cd3SJim Ingham }
1960893c932aSJim Ingham return GetDummyTarget();
1961893c932aSJim Ingham }
196244d93782SGreg Clayton
RunREPL(LanguageType language,const char * repl_options)196397206d57SZachary Turner Status Debugger::RunREPL(LanguageType language, const char *repl_options) {
196497206d57SZachary Turner Status err;
19653e7e915dSSean Callanan FileSpec repl_executable;
19663e7e915dSSean Callanan
196746a28a95SJonas Devlieghere if (language == eLanguageTypeUnknown)
196846a28a95SJonas Devlieghere language = GetREPLLanguage();
196946a28a95SJonas Devlieghere
1970b9c1b51eSKate Stone if (language == eLanguageTypeUnknown) {
1971aa97a89dSAdrian Prantl LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
197297f84e87SSean Callanan
1973aa97a89dSAdrian Prantl if (auto single_lang = repl_languages.GetSingularLanguage()) {
1974aa97a89dSAdrian Prantl language = *single_lang;
1975aa97a89dSAdrian Prantl } else if (repl_languages.Empty()) {
197646a28a95SJonas Devlieghere err.SetErrorString(
1977b9c1b51eSKate Stone "LLDB isn't configured with REPL support for any languages.");
197897f84e87SSean Callanan return err;
1979b9c1b51eSKate Stone } else {
198046a28a95SJonas Devlieghere err.SetErrorString(
1981b9c1b51eSKate Stone "Multiple possible REPL languages. Please specify a language.");
198297f84e87SSean Callanan return err;
198397f84e87SSean Callanan }
198497f84e87SSean Callanan }
198597f84e87SSean Callanan
1986b9c1b51eSKate Stone Target *const target =
1987b9c1b51eSKate Stone nullptr; // passing in an empty target means the REPL must create one
19883e7e915dSSean Callanan
19893b682de6SSean Callanan REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options));
19903e7e915dSSean Callanan
1991b9c1b51eSKate Stone if (!err.Success()) {
19923e7e915dSSean Callanan return err;
19933e7e915dSSean Callanan }
19943e7e915dSSean Callanan
1995b9c1b51eSKate Stone if (!repl_sp) {
1996b9c1b51eSKate Stone err.SetErrorStringWithFormat("couldn't find a REPL for %s",
1997b9c1b51eSKate Stone Language::GetNameForLanguageType(language));
19983e7e915dSSean Callanan return err;
19993e7e915dSSean Callanan }
20003e7e915dSSean Callanan
20013e7e915dSSean Callanan repl_sp->SetCompilerOptions(repl_options);
20023e7e915dSSean Callanan repl_sp->RunLoop();
20033e7e915dSSean Callanan
20043e7e915dSSean Callanan return err;
20053e7e915dSSean Callanan }
200620048f31SLuboš Luňák
GetThreadPool()200720048f31SLuboš Luňák llvm::ThreadPool &Debugger::GetThreadPool() {
200820048f31SLuboš Luňák // NOTE: intentional leak to avoid issues with C++ destructor chain
200920048f31SLuboš Luňák static llvm::ThreadPool *g_thread_pool = nullptr;
201020048f31SLuboš Luňák static llvm::once_flag g_once_flag;
201120048f31SLuboš Luňák llvm::call_once(g_once_flag, []() {
201220048f31SLuboš Luňák g_thread_pool = new llvm::ThreadPool(llvm::optimal_concurrency());
201320048f31SLuboš Luňák });
201420048f31SLuboš Luňák return *g_thread_pool;
201520048f31SLuboš Luňák }
2016