1 | //===-- Debugger.cpp ------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Core/Debugger.h" |
10 | |
11 | #include "lldb/Breakpoint/Breakpoint.h" |
12 | #include "lldb/Core/FormatEntity.h" |
13 | #include "lldb/Core/Mangled.h" |
14 | #include "lldb/Core/ModuleList.h" |
15 | #include "lldb/Core/PluginManager.h" |
16 | #include "lldb/Core/StreamAsynchronousIO.h" |
17 | #include "lldb/Core/StreamFile.h" |
18 | #include "lldb/DataFormatters/DataVisualization.h" |
19 | #include "lldb/Expression/REPL.h" |
20 | #include "lldb/Host/File.h" |
21 | #include "lldb/Host/FileSystem.h" |
22 | #include "lldb/Host/HostInfo.h" |
23 | #include "lldb/Host/Terminal.h" |
24 | #include "lldb/Host/ThreadLauncher.h" |
25 | #include "lldb/Interpreter/CommandInterpreter.h" |
26 | #include "lldb/Interpreter/OptionValue.h" |
27 | #include "lldb/Interpreter/OptionValueProperties.h" |
28 | #include "lldb/Interpreter/OptionValueSInt64.h" |
29 | #include "lldb/Interpreter/OptionValueString.h" |
30 | #include "lldb/Interpreter/Property.h" |
31 | #include "lldb/Interpreter/ScriptInterpreter.h" |
32 | #include "lldb/Symbol/Function.h" |
33 | #include "lldb/Symbol/Symbol.h" |
34 | #include "lldb/Symbol/SymbolContext.h" |
35 | #include "lldb/Target/Language.h" |
36 | #include "lldb/Target/Process.h" |
37 | #include "lldb/Target/StructuredDataPlugin.h" |
38 | #include "lldb/Target/Target.h" |
39 | #include "lldb/Target/TargetList.h" |
40 | #include "lldb/Target/Thread.h" |
41 | #include "lldb/Target/ThreadList.h" |
42 | #include "lldb/Utility/AnsiTerminal.h" |
43 | #include "lldb/Utility/Event.h" |
44 | #include "lldb/Utility/Listener.h" |
45 | #include "lldb/Utility/Log.h" |
46 | #include "lldb/Utility/Reproducer.h" |
47 | #include "lldb/Utility/State.h" |
48 | #include "lldb/Utility/Stream.h" |
49 | #include "lldb/Utility/StreamCallback.h" |
50 | #include "lldb/Utility/StreamString.h" |
51 | |
52 | #if defined(_WIN32) |
53 | #include "lldb/Host/windows/PosixApi.h" |
54 | #include "lldb/Host/windows/windows.h" |
55 | #endif |
56 | |
57 | #include "llvm/ADT/None.h" |
58 | #include "llvm/ADT/STLExtras.h" |
59 | #include "llvm/ADT/StringRef.h" |
60 | #include "llvm/ADT/iterator.h" |
61 | #include "llvm/Support/DynamicLibrary.h" |
62 | #include "llvm/Support/FileSystem.h" |
63 | #include "llvm/Support/Process.h" |
64 | #include "llvm/Support/Threading.h" |
65 | #include "llvm/Support/raw_ostream.h" |
66 | |
67 | #include <list> |
68 | #include <memory> |
69 | #include <mutex> |
70 | #include <set> |
71 | #include <stdio.h> |
72 | #include <stdlib.h> |
73 | #include <string.h> |
74 | #include <string> |
75 | #include <system_error> |
76 | |
77 | namespace lldb_private { |
78 | class Address; |
79 | } |
80 | |
81 | using namespace lldb; |
82 | using namespace lldb_private; |
83 | |
84 | static lldb::user_id_t g_unique_id = 1; |
85 | static size_t g_debugger_event_thread_stack_bytes = 8 * 1024 * 1024; |
86 | |
87 | #pragma mark Static Functions |
88 | |
89 | typedef std::vector<DebuggerSP> DebuggerList; |
90 | static std::recursive_mutex *g_debugger_list_mutex_ptr = |
91 | nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain |
92 | static DebuggerList *g_debugger_list_ptr = |
93 | nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain |
94 | |
95 | static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = { |
96 | { |
97 | Debugger::eStopDisassemblyTypeNever, |
98 | "never" , |
99 | "Never show disassembly when displaying a stop context." , |
100 | }, |
101 | { |
102 | Debugger::eStopDisassemblyTypeNoDebugInfo, |
103 | "no-debuginfo" , |
104 | "Show disassembly when there is no debug information." , |
105 | }, |
106 | { |
107 | Debugger::eStopDisassemblyTypeNoSource, |
108 | "no-source" , |
109 | "Show disassembly when there is no source information, or the source " |
110 | "file " |
111 | "is missing when displaying a stop context." , |
112 | }, |
113 | { |
114 | Debugger::eStopDisassemblyTypeAlways, |
115 | "always" , |
116 | "Always show disassembly when displaying a stop context." , |
117 | }, |
118 | }; |
119 | |
120 | static constexpr OptionEnumValueElement g_language_enumerators[] = { |
121 | { |
122 | eScriptLanguageNone, |
123 | "none" , |
124 | "Disable scripting languages." , |
125 | }, |
126 | { |
127 | eScriptLanguagePython, |
128 | "python" , |
129 | "Select python as the default scripting language." , |
130 | }, |
131 | { |
132 | eScriptLanguageDefault, |
133 | "default" , |
134 | "Select the lldb default as the default scripting language." , |
135 | }, |
136 | }; |
137 | |
138 | static constexpr OptionEnumValueElement s_stop_show_column_values[] = { |
139 | { |
140 | eStopShowColumnAnsiOrCaret, |
141 | "ansi-or-caret" , |
142 | "Highlight the stop column with ANSI terminal codes when color/ANSI " |
143 | "mode is enabled; otherwise, fall back to using a text-only caret (^) " |
144 | "as if \"caret-only\" mode was selected." , |
145 | }, |
146 | { |
147 | eStopShowColumnAnsi, |
148 | "ansi" , |
149 | "Highlight the stop column with ANSI terminal codes when running LLDB " |
150 | "with color/ANSI enabled." , |
151 | }, |
152 | { |
153 | eStopShowColumnCaret, |
154 | "caret" , |
155 | "Highlight the stop column with a caret character (^) underneath the " |
156 | "stop column. This method introduces a new line in source listings " |
157 | "that display thread stop locations." , |
158 | }, |
159 | { |
160 | eStopShowColumnNone, |
161 | "none" , |
162 | "Do not highlight the stop column." , |
163 | }, |
164 | }; |
165 | |
166 | #define LLDB_PROPERTIES_debugger |
167 | #include "CoreProperties.inc" |
168 | |
169 | enum { |
170 | #define LLDB_PROPERTIES_debugger |
171 | #include "CorePropertiesEnum.inc" |
172 | }; |
173 | |
174 | LoadPluginCallbackType Debugger::g_load_plugin_callback = nullptr; |
175 | |
176 | Status Debugger::SetPropertyValue(const ExecutionContext *exe_ctx, |
177 | VarSetOperationType op, |
178 | llvm::StringRef property_path, |
179 | llvm::StringRef value) { |
180 | bool is_load_script = |
181 | (property_path == "target.load-script-from-symbol-file" ); |
182 | // These properties might change how we visualize data. |
183 | bool invalidate_data_vis = (property_path == "escape-non-printables" ); |
184 | invalidate_data_vis |= |
185 | (property_path == "target.max-zero-padding-in-float-format" ); |
186 | if (invalidate_data_vis) { |
187 | DataVisualization::ForceUpdate(); |
188 | } |
189 | |
190 | TargetSP target_sp; |
191 | LoadScriptFromSymFile load_script_old_value; |
192 | if (is_load_script && exe_ctx->GetTargetSP()) { |
193 | target_sp = exe_ctx->GetTargetSP(); |
194 | load_script_old_value = |
195 | target_sp->TargetProperties::GetLoadScriptFromSymbolFile(); |
196 | } |
197 | Status error(Properties::SetPropertyValue(exe_ctx, op, property_path, value)); |
198 | if (error.Success()) { |
199 | // FIXME it would be nice to have "on-change" callbacks for properties |
200 | if (property_path == g_debugger_properties[ePropertyPrompt].name) { |
201 | llvm::StringRef new_prompt = GetPrompt(); |
202 | std::string str = lldb_private::ansi::FormatAnsiTerminalCodes( |
203 | new_prompt, GetUseColor()); |
204 | if (str.length()) |
205 | new_prompt = str; |
206 | GetCommandInterpreter().UpdatePrompt(new_prompt); |
207 | auto bytes = std::make_unique<EventDataBytes>(new_prompt); |
208 | auto prompt_change_event_sp = std::make_shared<Event>( |
209 | CommandInterpreter::eBroadcastBitResetPrompt, bytes.release()); |
210 | GetCommandInterpreter().BroadcastEvent(prompt_change_event_sp); |
211 | } else if (property_path == g_debugger_properties[ePropertyUseColor].name) { |
212 | // use-color changed. Ping the prompt so it can reset the ansi terminal |
213 | // codes. |
214 | SetPrompt(GetPrompt()); |
215 | } else if (property_path == g_debugger_properties[ePropertyUseSourceCache].name) { |
216 | // use-source-cache changed. Wipe out the cache contents if it was disabled. |
217 | if (!GetUseSourceCache()) { |
218 | m_source_file_cache.Clear(); |
219 | } |
220 | } else if (is_load_script && target_sp && |
221 | load_script_old_value == eLoadScriptFromSymFileWarn) { |
222 | if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() == |
223 | eLoadScriptFromSymFileTrue) { |
224 | std::list<Status> errors; |
225 | StreamString feedback_stream; |
226 | if (!target_sp->LoadScriptingResources(errors, &feedback_stream)) { |
227 | Stream &s = GetErrorStream(); |
228 | for (auto error : errors) { |
229 | s.Printf("%s\n" , error.AsCString()); |
230 | } |
231 | if (feedback_stream.GetSize()) |
232 | s.PutCString(feedback_stream.GetString()); |
233 | } |
234 | } |
235 | } |
236 | } |
237 | return error; |
238 | } |
239 | |
240 | bool Debugger::GetAutoConfirm() const { |
241 | const uint32_t idx = ePropertyAutoConfirm; |
242 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
243 | nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); |
244 | } |
245 | |
246 | const FormatEntity::Entry *Debugger::GetDisassemblyFormat() const { |
247 | const uint32_t idx = ePropertyDisassemblyFormat; |
248 | return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); |
249 | } |
250 | |
251 | const FormatEntity::Entry *Debugger::GetFrameFormat() const { |
252 | const uint32_t idx = ePropertyFrameFormat; |
253 | return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); |
254 | } |
255 | |
256 | const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const { |
257 | const uint32_t idx = ePropertyFrameFormatUnique; |
258 | return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); |
259 | } |
260 | |
261 | uint32_t Debugger::GetStopDisassemblyMaxSize() const { |
262 | const uint32_t idx = ePropertyStopDisassemblyMaxSize; |
263 | return m_collection_sp->GetPropertyAtIndexAsUInt64( |
264 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
265 | } |
266 | |
267 | bool Debugger::GetNotifyVoid() const { |
268 | const uint32_t idx = ePropertyNotiftVoid; |
269 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
270 | nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); |
271 | } |
272 | |
273 | llvm::StringRef Debugger::GetPrompt() const { |
274 | const uint32_t idx = ePropertyPrompt; |
275 | return m_collection_sp->GetPropertyAtIndexAsString( |
276 | nullptr, idx, g_debugger_properties[idx].default_cstr_value); |
277 | } |
278 | |
279 | void Debugger::SetPrompt(llvm::StringRef p) { |
280 | const uint32_t idx = ePropertyPrompt; |
281 | m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); |
282 | llvm::StringRef new_prompt = GetPrompt(); |
283 | std::string str = |
284 | lldb_private::ansi::FormatAnsiTerminalCodes(new_prompt, GetUseColor()); |
285 | if (str.length()) |
286 | new_prompt = str; |
287 | GetCommandInterpreter().UpdatePrompt(new_prompt); |
288 | } |
289 | |
290 | llvm::StringRef Debugger::GetReproducerPath() const { |
291 | auto &r = repro::Reproducer::Instance(); |
292 | return r.GetReproducerPath().GetCString(); |
293 | } |
294 | |
295 | const FormatEntity::Entry *Debugger::GetThreadFormat() const { |
296 | const uint32_t idx = ePropertyThreadFormat; |
297 | return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); |
298 | } |
299 | |
300 | const FormatEntity::Entry *Debugger::GetThreadStopFormat() const { |
301 | const uint32_t idx = ePropertyThreadStopFormat; |
302 | return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); |
303 | } |
304 | |
305 | lldb::ScriptLanguage Debugger::GetScriptLanguage() const { |
306 | const uint32_t idx = ePropertyScriptLanguage; |
307 | return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration( |
308 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
309 | } |
310 | |
311 | bool Debugger::SetScriptLanguage(lldb::ScriptLanguage script_lang) { |
312 | const uint32_t idx = ePropertyScriptLanguage; |
313 | return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, |
314 | script_lang); |
315 | } |
316 | |
317 | uint32_t Debugger::GetTerminalWidth() const { |
318 | const uint32_t idx = ePropertyTerminalWidth; |
319 | return m_collection_sp->GetPropertyAtIndexAsSInt64( |
320 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
321 | } |
322 | |
323 | bool Debugger::SetTerminalWidth(uint32_t term_width) { |
324 | if (auto handler_sp = m_io_handler_stack.Top()) |
325 | handler_sp->TerminalSizeChanged(); |
326 | |
327 | const uint32_t idx = ePropertyTerminalWidth; |
328 | return m_collection_sp->SetPropertyAtIndexAsSInt64(nullptr, idx, term_width); |
329 | } |
330 | |
331 | bool Debugger::GetUseExternalEditor() const { |
332 | const uint32_t idx = ePropertyUseExternalEditor; |
333 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
334 | nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); |
335 | } |
336 | |
337 | bool Debugger::SetUseExternalEditor(bool b) { |
338 | const uint32_t idx = ePropertyUseExternalEditor; |
339 | return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); |
340 | } |
341 | |
342 | bool Debugger::GetUseColor() const { |
343 | const uint32_t idx = ePropertyUseColor; |
344 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
345 | nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); |
346 | } |
347 | |
348 | bool Debugger::SetUseColor(bool b) { |
349 | const uint32_t idx = ePropertyUseColor; |
350 | bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); |
351 | SetPrompt(GetPrompt()); |
352 | return ret; |
353 | } |
354 | |
355 | bool Debugger::GetUseAutosuggestion() const { |
356 | const uint32_t idx = ePropertyShowAutosuggestion; |
357 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
358 | nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); |
359 | } |
360 | |
361 | bool Debugger::GetUseSourceCache() const { |
362 | const uint32_t idx = ePropertyUseSourceCache; |
363 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
364 | nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); |
365 | } |
366 | |
367 | bool Debugger::SetUseSourceCache(bool b) { |
368 | const uint32_t idx = ePropertyUseSourceCache; |
369 | bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); |
370 | if (!ret) { |
371 | m_source_file_cache.Clear(); |
372 | } |
373 | return ret; |
374 | } |
375 | bool Debugger::GetHighlightSource() const { |
376 | const uint32_t idx = ePropertyHighlightSource; |
377 | return m_collection_sp->GetPropertyAtIndexAsBoolean( |
378 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
379 | } |
380 | |
381 | StopShowColumn Debugger::GetStopShowColumn() const { |
382 | const uint32_t idx = ePropertyStopShowColumn; |
383 | return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration( |
384 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
385 | } |
386 | |
387 | llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const { |
388 | const uint32_t idx = ePropertyStopShowColumnAnsiPrefix; |
389 | return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "" ); |
390 | } |
391 | |
392 | llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const { |
393 | const uint32_t idx = ePropertyStopShowColumnAnsiSuffix; |
394 | return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "" ); |
395 | } |
396 | |
397 | llvm::StringRef Debugger::GetStopShowLineMarkerAnsiPrefix() const { |
398 | const uint32_t idx = ePropertyStopShowLineMarkerAnsiPrefix; |
399 | return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "" ); |
400 | } |
401 | |
402 | llvm::StringRef Debugger::GetStopShowLineMarkerAnsiSuffix() const { |
403 | const uint32_t idx = ePropertyStopShowLineMarkerAnsiSuffix; |
404 | return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, "" ); |
405 | } |
406 | |
407 | uint32_t Debugger::GetStopSourceLineCount(bool before) const { |
408 | const uint32_t idx = |
409 | before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter; |
410 | return m_collection_sp->GetPropertyAtIndexAsSInt64( |
411 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
412 | } |
413 | |
414 | Debugger::StopDisassemblyType Debugger::GetStopDisassemblyDisplay() const { |
415 | const uint32_t idx = ePropertyStopDisassemblyDisplay; |
416 | return (Debugger::StopDisassemblyType) |
417 | m_collection_sp->GetPropertyAtIndexAsEnumeration( |
418 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
419 | } |
420 | |
421 | uint32_t Debugger::GetDisassemblyLineCount() const { |
422 | const uint32_t idx = ePropertyStopDisassemblyCount; |
423 | return m_collection_sp->GetPropertyAtIndexAsSInt64( |
424 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
425 | } |
426 | |
427 | bool Debugger::GetAutoOneLineSummaries() const { |
428 | const uint32_t idx = ePropertyAutoOneLineSummaries; |
429 | return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); |
430 | } |
431 | |
432 | bool Debugger::GetEscapeNonPrintables() const { |
433 | const uint32_t idx = ePropertyEscapeNonPrintables; |
434 | return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); |
435 | } |
436 | |
437 | bool Debugger::GetAutoIndent() const { |
438 | const uint32_t idx = ePropertyAutoIndent; |
439 | return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); |
440 | } |
441 | |
442 | bool Debugger::SetAutoIndent(bool b) { |
443 | const uint32_t idx = ePropertyAutoIndent; |
444 | return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); |
445 | } |
446 | |
447 | bool Debugger::GetPrintDecls() const { |
448 | const uint32_t idx = ePropertyPrintDecls; |
449 | return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, true); |
450 | } |
451 | |
452 | bool Debugger::SetPrintDecls(bool b) { |
453 | const uint32_t idx = ePropertyPrintDecls; |
454 | return m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); |
455 | } |
456 | |
457 | uint32_t Debugger::GetTabSize() const { |
458 | const uint32_t idx = ePropertyTabSize; |
459 | return m_collection_sp->GetPropertyAtIndexAsUInt64( |
460 | nullptr, idx, g_debugger_properties[idx].default_uint_value); |
461 | } |
462 | |
463 | bool Debugger::SetTabSize(uint32_t tab_size) { |
464 | const uint32_t idx = ePropertyTabSize; |
465 | return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size); |
466 | } |
467 | |
468 | #pragma mark Debugger |
469 | |
470 | // const DebuggerPropertiesSP & |
471 | // Debugger::GetSettings() const |
472 | //{ |
473 | // return m_properties_sp; |
474 | //} |
475 | // |
476 | |
477 | void Debugger::Initialize(LoadPluginCallbackType load_plugin_callback) { |
478 | assert(g_debugger_list_ptr == nullptr && |
479 | "Debugger::Initialize called more than once!" ); |
480 | g_debugger_list_mutex_ptr = new std::recursive_mutex(); |
481 | g_debugger_list_ptr = new DebuggerList(); |
482 | g_load_plugin_callback = load_plugin_callback; |
483 | } |
484 | |
485 | void Debugger::Terminate() { |
486 | assert(g_debugger_list_ptr && |
487 | "Debugger::Terminate called without a matching Debugger::Initialize!" ); |
488 | |
489 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
490 | // Clear our master list of debugger objects |
491 | { |
492 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
493 | for (const auto &debugger : *g_debugger_list_ptr) |
494 | debugger->Clear(); |
495 | g_debugger_list_ptr->clear(); |
496 | } |
497 | } |
498 | } |
499 | |
500 | void Debugger::SettingsInitialize() { Target::SettingsInitialize(); } |
501 | |
502 | void Debugger::SettingsTerminate() { Target::SettingsTerminate(); } |
503 | |
504 | bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) { |
505 | if (g_load_plugin_callback) { |
506 | llvm::sys::DynamicLibrary dynlib = |
507 | g_load_plugin_callback(shared_from_this(), spec, error); |
508 | if (dynlib.isValid()) { |
509 | m_loaded_plugins.push_back(dynlib); |
510 | return true; |
511 | } |
512 | } else { |
513 | // The g_load_plugin_callback is registered in SBDebugger::Initialize() and |
514 | // if the public API layer isn't available (code is linking against all of |
515 | // the internal LLDB static libraries), then we can't load plugins |
516 | error.SetErrorString("Public API layer is not available" ); |
517 | } |
518 | return false; |
519 | } |
520 | |
521 | static FileSystem::EnumerateDirectoryResult |
522 | LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft, |
523 | llvm::StringRef path) { |
524 | Status error; |
525 | |
526 | static ConstString g_dylibext(".dylib" ); |
527 | static ConstString g_solibext(".so" ); |
528 | |
529 | if (!baton) |
530 | return FileSystem::eEnumerateDirectoryResultQuit; |
531 | |
532 | Debugger *debugger = (Debugger *)baton; |
533 | |
534 | namespace fs = llvm::sys::fs; |
535 | // If we have a regular file, a symbolic link or unknown file type, try and |
536 | // process the file. We must handle unknown as sometimes the directory |
537 | // enumeration might be enumerating a file system that doesn't have correct |
538 | // file type information. |
539 | if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file || |
540 | ft == fs::file_type::type_unknown) { |
541 | FileSpec plugin_file_spec(path); |
542 | FileSystem::Instance().Resolve(plugin_file_spec); |
543 | |
544 | if (plugin_file_spec.GetFileNameExtension() != g_dylibext && |
545 | plugin_file_spec.GetFileNameExtension() != g_solibext) { |
546 | return FileSystem::eEnumerateDirectoryResultNext; |
547 | } |
548 | |
549 | Status plugin_load_error; |
550 | debugger->LoadPlugin(plugin_file_spec, plugin_load_error); |
551 | |
552 | return FileSystem::eEnumerateDirectoryResultNext; |
553 | } else if (ft == fs::file_type::directory_file || |
554 | ft == fs::file_type::symlink_file || |
555 | ft == fs::file_type::type_unknown) { |
556 | // Try and recurse into anything that a directory or symbolic link. We must |
557 | // also do this for unknown as sometimes the directory enumeration might be |
558 | // enumerating a file system that doesn't have correct file type |
559 | // information. |
560 | return FileSystem::eEnumerateDirectoryResultEnter; |
561 | } |
562 | |
563 | return FileSystem::eEnumerateDirectoryResultNext; |
564 | } |
565 | |
566 | void Debugger::InstanceInitialize() { |
567 | const bool find_directories = true; |
568 | const bool find_files = true; |
569 | const bool find_other = true; |
570 | char dir_path[PATH_MAX]; |
571 | if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) { |
572 | if (FileSystem::Instance().Exists(dir_spec) && |
573 | dir_spec.GetPath(dir_path, sizeof(dir_path))) { |
574 | FileSystem::Instance().EnumerateDirectory(dir_path, find_directories, |
575 | find_files, find_other, |
576 | LoadPluginCallback, this); |
577 | } |
578 | } |
579 | |
580 | if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) { |
581 | if (FileSystem::Instance().Exists(dir_spec) && |
582 | dir_spec.GetPath(dir_path, sizeof(dir_path))) { |
583 | FileSystem::Instance().EnumerateDirectory(dir_path, find_directories, |
584 | find_files, find_other, |
585 | LoadPluginCallback, this); |
586 | } |
587 | } |
588 | |
589 | PluginManager::DebuggerInitialize(*this); |
590 | } |
591 | |
592 | DebuggerSP Debugger::CreateInstance(lldb::LogOutputCallback log_callback, |
593 | void *baton) { |
594 | DebuggerSP debugger_sp(new Debugger(log_callback, baton)); |
595 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
596 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
597 | g_debugger_list_ptr->push_back(debugger_sp); |
598 | } |
599 | debugger_sp->InstanceInitialize(); |
600 | return debugger_sp; |
601 | } |
602 | |
603 | void Debugger::Destroy(DebuggerSP &debugger_sp) { |
604 | if (!debugger_sp) |
605 | return; |
606 | |
607 | debugger_sp->Clear(); |
608 | |
609 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
610 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
611 | DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); |
612 | for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) { |
613 | if ((*pos).get() == debugger_sp.get()) { |
614 | g_debugger_list_ptr->erase(pos); |
615 | return; |
616 | } |
617 | } |
618 | } |
619 | } |
620 | |
621 | DebuggerSP Debugger::FindDebuggerWithInstanceName(ConstString instance_name) { |
622 | DebuggerSP debugger_sp; |
623 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
624 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
625 | DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); |
626 | for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) { |
627 | if ((*pos)->m_instance_name == instance_name) { |
628 | debugger_sp = *pos; |
629 | break; |
630 | } |
631 | } |
632 | } |
633 | return debugger_sp; |
634 | } |
635 | |
636 | TargetSP Debugger::FindTargetWithProcessID(lldb::pid_t pid) { |
637 | TargetSP target_sp; |
638 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
639 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
640 | DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); |
641 | for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) { |
642 | target_sp = (*pos)->GetTargetList().FindTargetWithProcessID(pid); |
643 | if (target_sp) |
644 | break; |
645 | } |
646 | } |
647 | return target_sp; |
648 | } |
649 | |
650 | TargetSP Debugger::FindTargetWithProcess(Process *process) { |
651 | TargetSP target_sp; |
652 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
653 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
654 | DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); |
655 | for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) { |
656 | target_sp = (*pos)->GetTargetList().FindTargetWithProcess(process); |
657 | if (target_sp) |
658 | break; |
659 | } |
660 | } |
661 | return target_sp; |
662 | } |
663 | |
664 | ConstString Debugger::GetStaticBroadcasterClass() { |
665 | static ConstString class_name("lldb.debugger" ); |
666 | return class_name; |
667 | } |
668 | |
669 | Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) |
670 | : UserID(g_unique_id++), |
671 | Properties(std::make_shared<OptionValueProperties>()), |
672 | m_input_file_sp(std::make_shared<NativeFile>(stdin, false)), |
673 | m_output_stream_sp(std::make_shared<StreamFile>(stdout, false)), |
674 | m_error_stream_sp(std::make_shared<StreamFile>(stderr, false)), |
675 | m_input_recorder(nullptr), |
676 | m_broadcaster_manager_sp(BroadcasterManager::MakeBroadcasterManager()), |
677 | m_terminal_state(), m_target_list(*this), m_platform_list(), |
678 | m_listener_sp(Listener::MakeListener("lldb.Debugger" )), |
679 | m_source_manager_up(), m_source_file_cache(), |
680 | m_command_interpreter_up( |
681 | std::make_unique<CommandInterpreter>(*this, false)), |
682 | m_io_handler_stack(), m_instance_name(), m_loaded_plugins(), |
683 | m_event_handler_thread(), m_io_handler_thread(), |
684 | m_sync_broadcaster(nullptr, "lldb.debugger.sync" ), |
685 | m_broadcaster(m_broadcaster_manager_sp, |
686 | GetStaticBroadcasterClass().AsCString()), |
687 | m_forward_listener_sp(), m_clear_once() { |
688 | m_instance_name.SetString(llvm::formatv("debugger_{0}" , GetID()).str()); |
689 | if (log_callback) |
690 | m_log_callback_stream_sp = |
691 | std::make_shared<StreamCallback>(log_callback, baton); |
692 | m_command_interpreter_up->Initialize(); |
693 | // Always add our default platform to the platform list |
694 | PlatformSP default_platform_sp(Platform::GetHostPlatform()); |
695 | assert(default_platform_sp); |
696 | m_platform_list.Append(default_platform_sp, true); |
697 | |
698 | // Create the dummy target. |
699 | { |
700 | ArchSpec arch(Target::GetDefaultArchitecture()); |
701 | if (!arch.IsValid()) |
702 | arch = HostInfo::GetArchitecture(); |
703 | assert(arch.IsValid() && "No valid default or host archspec" ); |
704 | const bool is_dummy_target = true; |
705 | m_dummy_target_sp.reset( |
706 | new Target(*this, arch, default_platform_sp, is_dummy_target)); |
707 | } |
708 | assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?" ); |
709 | |
710 | m_collection_sp->Initialize(g_debugger_properties); |
711 | m_collection_sp->AppendProperty( |
712 | ConstString("target" ), |
713 | ConstString("Settings specify to debugging targets." ), true, |
714 | Target::GetGlobalProperties()->GetValueProperties()); |
715 | m_collection_sp->AppendProperty( |
716 | ConstString("platform" ), ConstString("Platform settings." ), true, |
717 | Platform::GetGlobalPlatformProperties()->GetValueProperties()); |
718 | m_collection_sp->AppendProperty( |
719 | ConstString("symbols" ), ConstString("Symbol lookup and cache settings." ), |
720 | true, ModuleList::GetGlobalModuleListProperties().GetValueProperties()); |
721 | if (m_command_interpreter_up) { |
722 | m_collection_sp->AppendProperty( |
723 | ConstString("interpreter" ), |
724 | ConstString("Settings specify to the debugger's command interpreter." ), |
725 | true, m_command_interpreter_up->GetValueProperties()); |
726 | } |
727 | OptionValueSInt64 *term_width = |
728 | m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64( |
729 | nullptr, ePropertyTerminalWidth); |
730 | term_width->SetMinimumValue(10); |
731 | term_width->SetMaximumValue(1024); |
732 | |
733 | // Turn off use-color if this is a dumb terminal. |
734 | const char *term = getenv("TERM" ); |
735 | if (term && !strcmp(term, "dumb" )) |
736 | SetUseColor(false); |
737 | // Turn off use-color if we don't write to a terminal with color support. |
738 | if (!GetOutputFile().GetIsTerminalWithColors()) |
739 | SetUseColor(false); |
740 | |
741 | #if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) |
742 | // Enabling use of ANSI color codes because LLDB is using them to highlight |
743 | // text. |
744 | llvm::sys::Process::UseANSIEscapeCodes(true); |
745 | #endif |
746 | } |
747 | |
748 | Debugger::~Debugger() { Clear(); } |
749 | |
750 | void Debugger::Clear() { |
751 | // Make sure we call this function only once. With the C++ global destructor |
752 | // chain having a list of debuggers and with code that can be running on |
753 | // other threads, we need to ensure this doesn't happen multiple times. |
754 | // |
755 | // The following functions call Debugger::Clear(): |
756 | // Debugger::~Debugger(); |
757 | // static void Debugger::Destroy(lldb::DebuggerSP &debugger_sp); |
758 | // static void Debugger::Terminate(); |
759 | llvm::call_once(m_clear_once, [this]() { |
760 | ClearIOHandlers(); |
761 | StopIOHandlerThread(); |
762 | StopEventHandlerThread(); |
763 | m_listener_sp->Clear(); |
764 | int num_targets = m_target_list.GetNumTargets(); |
765 | for (int i = 0; i < num_targets; i++) { |
766 | TargetSP target_sp(m_target_list.GetTargetAtIndex(i)); |
767 | if (target_sp) { |
768 | ProcessSP process_sp(target_sp->GetProcessSP()); |
769 | if (process_sp) |
770 | process_sp->Finalize(); |
771 | target_sp->Destroy(); |
772 | } |
773 | } |
774 | m_broadcaster_manager_sp->Clear(); |
775 | |
776 | // Close the input file _before_ we close the input read communications |
777 | // class as it does NOT own the input file, our m_input_file does. |
778 | m_terminal_state.Clear(); |
779 | GetInputFile().Close(); |
780 | |
781 | m_command_interpreter_up->Clear(); |
782 | }); |
783 | } |
784 | |
785 | bool Debugger::GetCloseInputOnEOF() const { |
786 | // return m_input_comm.GetCloseOnEOF(); |
787 | return false; |
788 | } |
789 | |
790 | void Debugger::SetCloseInputOnEOF(bool b) { |
791 | // m_input_comm.SetCloseOnEOF(b); |
792 | } |
793 | |
794 | bool Debugger::GetAsyncExecution() { |
795 | return !m_command_interpreter_up->GetSynchronous(); |
796 | } |
797 | |
798 | void Debugger::SetAsyncExecution(bool async_execution) { |
799 | m_command_interpreter_up->SetSynchronous(!async_execution); |
800 | } |
801 | |
802 | repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; } |
803 | |
804 | void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) { |
805 | assert(file_sp && file_sp->IsValid()); |
806 | m_input_recorder = recorder; |
807 | m_input_file_sp = std::move(file_sp); |
808 | // Save away the terminal state if that is relevant, so that we can restore |
809 | // it in RestoreInputState. |
810 | SaveInputTerminalState(); |
811 | } |
812 | |
813 | void Debugger::SetOutputFile(FileSP file_sp) { |
814 | assert(file_sp && file_sp->IsValid()); |
815 | m_output_stream_sp = std::make_shared<StreamFile>(file_sp); |
816 | } |
817 | |
818 | void Debugger::SetErrorFile(FileSP file_sp) { |
819 | assert(file_sp && file_sp->IsValid()); |
820 | m_error_stream_sp = std::make_shared<StreamFile>(file_sp); |
821 | } |
822 | |
823 | void Debugger::SaveInputTerminalState() { |
824 | int fd = GetInputFile().GetDescriptor(); |
825 | if (fd != File::kInvalidDescriptor) |
826 | m_terminal_state.Save(fd, true); |
827 | } |
828 | |
829 | void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); } |
830 | |
831 | ExecutionContext Debugger::GetSelectedExecutionContext() { |
832 | bool adopt_selected = true; |
833 | ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected); |
834 | return ExecutionContext(exe_ctx_ref); |
835 | } |
836 | |
837 | void Debugger::DispatchInputInterrupt() { |
838 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex()); |
839 | IOHandlerSP reader_sp(m_io_handler_stack.Top()); |
840 | if (reader_sp) |
841 | reader_sp->Interrupt(); |
842 | } |
843 | |
844 | void Debugger::DispatchInputEndOfFile() { |
845 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex()); |
846 | IOHandlerSP reader_sp(m_io_handler_stack.Top()); |
847 | if (reader_sp) |
848 | reader_sp->GotEOF(); |
849 | } |
850 | |
851 | void Debugger::ClearIOHandlers() { |
852 | // The bottom input reader should be the main debugger input reader. We do |
853 | // not want to close that one here. |
854 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex()); |
855 | while (m_io_handler_stack.GetSize() > 1) { |
856 | IOHandlerSP reader_sp(m_io_handler_stack.Top()); |
857 | if (reader_sp) |
858 | PopIOHandler(reader_sp); |
859 | } |
860 | } |
861 | |
862 | void Debugger::RunIOHandlers() { |
863 | IOHandlerSP reader_sp = m_io_handler_stack.Top(); |
864 | while (true) { |
865 | if (!reader_sp) |
866 | break; |
867 | |
868 | reader_sp->Run(); |
869 | { |
870 | std::lock_guard<std::recursive_mutex> guard( |
871 | m_io_handler_synchronous_mutex); |
872 | |
873 | // Remove all input readers that are done from the top of the stack |
874 | while (true) { |
875 | IOHandlerSP top_reader_sp = m_io_handler_stack.Top(); |
876 | if (top_reader_sp && top_reader_sp->GetIsDone()) |
877 | PopIOHandler(top_reader_sp); |
878 | else |
879 | break; |
880 | } |
881 | reader_sp = m_io_handler_stack.Top(); |
882 | } |
883 | } |
884 | ClearIOHandlers(); |
885 | } |
886 | |
887 | void Debugger::RunIOHandlerSync(const IOHandlerSP &reader_sp) { |
888 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_synchronous_mutex); |
889 | |
890 | PushIOHandler(reader_sp); |
891 | IOHandlerSP top_reader_sp = reader_sp; |
892 | |
893 | while (top_reader_sp) { |
894 | if (!top_reader_sp) |
895 | break; |
896 | |
897 | top_reader_sp->Run(); |
898 | |
899 | // Don't unwind past the starting point. |
900 | if (top_reader_sp.get() == reader_sp.get()) { |
901 | if (PopIOHandler(reader_sp)) |
902 | break; |
903 | } |
904 | |
905 | // If we pushed new IO handlers, pop them if they're done or restart the |
906 | // loop to run them if they're not. |
907 | while (true) { |
908 | top_reader_sp = m_io_handler_stack.Top(); |
909 | if (top_reader_sp && top_reader_sp->GetIsDone()) { |
910 | PopIOHandler(top_reader_sp); |
911 | // Don't unwind past the starting point. |
912 | if (top_reader_sp.get() == reader_sp.get()) |
913 | return; |
914 | } else { |
915 | break; |
916 | } |
917 | } |
918 | } |
919 | } |
920 | |
921 | bool Debugger::IsTopIOHandler(const lldb::IOHandlerSP &reader_sp) { |
922 | return m_io_handler_stack.IsTop(reader_sp); |
923 | } |
924 | |
925 | bool Debugger::CheckTopIOHandlerTypes(IOHandler::Type top_type, |
926 | IOHandler::Type second_top_type) { |
927 | return m_io_handler_stack.CheckTopIOHandlerTypes(top_type, second_top_type); |
928 | } |
929 | |
930 | void Debugger::PrintAsync(const char *s, size_t len, bool is_stdout) { |
931 | lldb_private::StreamFile &stream = |
932 | is_stdout ? GetOutputStream() : GetErrorStream(); |
933 | m_io_handler_stack.PrintAsync(&stream, s, len); |
934 | } |
935 | |
936 | ConstString Debugger::GetTopIOHandlerControlSequence(char ch) { |
937 | return m_io_handler_stack.GetTopIOHandlerControlSequence(ch); |
938 | } |
939 | |
940 | const char *Debugger::GetIOHandlerCommandPrefix() { |
941 | return m_io_handler_stack.GetTopIOHandlerCommandPrefix(); |
942 | } |
943 | |
944 | const char *Debugger::GetIOHandlerHelpPrologue() { |
945 | return m_io_handler_stack.GetTopIOHandlerHelpPrologue(); |
946 | } |
947 | |
948 | bool Debugger::RemoveIOHandler(const IOHandlerSP &reader_sp) { |
949 | return PopIOHandler(reader_sp); |
950 | } |
951 | |
952 | void Debugger::RunIOHandlerAsync(const IOHandlerSP &reader_sp, |
953 | bool cancel_top_handler) { |
954 | PushIOHandler(reader_sp, cancel_top_handler); |
955 | } |
956 | |
957 | void Debugger::AdoptTopIOHandlerFilesIfInvalid(FileSP &in, StreamFileSP &out, |
958 | StreamFileSP &err) { |
959 | // Before an IOHandler runs, it must have in/out/err streams. This function |
960 | // is called when one ore more of the streams are nullptr. We use the top |
961 | // input reader's in/out/err streams, or fall back to the debugger file |
962 | // handles, or we fall back onto stdin/stdout/stderr as a last resort. |
963 | |
964 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex()); |
965 | IOHandlerSP top_reader_sp(m_io_handler_stack.Top()); |
966 | // If no STDIN has been set, then set it appropriately |
967 | if (!in || !in->IsValid()) { |
968 | if (top_reader_sp) |
969 | in = top_reader_sp->GetInputFileSP(); |
970 | else |
971 | in = GetInputFileSP(); |
972 | // If there is nothing, use stdin |
973 | if (!in) |
974 | in = std::make_shared<NativeFile>(stdin, false); |
975 | } |
976 | // If no STDOUT has been set, then set it appropriately |
977 | if (!out || !out->GetFile().IsValid()) { |
978 | if (top_reader_sp) |
979 | out = top_reader_sp->GetOutputStreamFileSP(); |
980 | else |
981 | out = GetOutputStreamSP(); |
982 | // If there is nothing, use stdout |
983 | if (!out) |
984 | out = std::make_shared<StreamFile>(stdout, false); |
985 | } |
986 | // If no STDERR has been set, then set it appropriately |
987 | if (!err || !err->GetFile().IsValid()) { |
988 | if (top_reader_sp) |
989 | err = top_reader_sp->GetErrorStreamFileSP(); |
990 | else |
991 | err = GetErrorStreamSP(); |
992 | // If there is nothing, use stderr |
993 | if (!err) |
994 | err = std::make_shared<StreamFile>(stderr, false); |
995 | } |
996 | } |
997 | |
998 | void Debugger::PushIOHandler(const IOHandlerSP &reader_sp, |
999 | bool cancel_top_handler) { |
1000 | if (!reader_sp) |
1001 | return; |
1002 | |
1003 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex()); |
1004 | |
1005 | // Get the current top input reader... |
1006 | IOHandlerSP top_reader_sp(m_io_handler_stack.Top()); |
1007 | |
1008 | // Don't push the same IO handler twice... |
1009 | if (reader_sp == top_reader_sp) |
1010 | return; |
1011 | |
1012 | // Push our new input reader |
1013 | m_io_handler_stack.Push(reader_sp); |
1014 | reader_sp->Activate(); |
1015 | |
1016 | // Interrupt the top input reader to it will exit its Run() function and let |
1017 | // this new input reader take over |
1018 | if (top_reader_sp) { |
1019 | top_reader_sp->Deactivate(); |
1020 | if (cancel_top_handler) |
1021 | top_reader_sp->Cancel(); |
1022 | } |
1023 | } |
1024 | |
1025 | bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) { |
1026 | if (!pop_reader_sp) |
1027 | return false; |
1028 | |
1029 | std::lock_guard<std::recursive_mutex> guard(m_io_handler_stack.GetMutex()); |
1030 | |
1031 | // The reader on the stop of the stack is done, so let the next read on the |
1032 | // stack refresh its prompt and if there is one... |
1033 | if (m_io_handler_stack.IsEmpty()) |
1034 | return false; |
1035 | |
1036 | IOHandlerSP reader_sp(m_io_handler_stack.Top()); |
1037 | |
1038 | if (pop_reader_sp != reader_sp) |
1039 | return false; |
1040 | |
1041 | reader_sp->Deactivate(); |
1042 | reader_sp->Cancel(); |
1043 | m_io_handler_stack.Pop(); |
1044 | |
1045 | reader_sp = m_io_handler_stack.Top(); |
1046 | if (reader_sp) |
1047 | reader_sp->Activate(); |
1048 | |
1049 | return true; |
1050 | } |
1051 | |
1052 | StreamSP Debugger::GetAsyncOutputStream() { |
1053 | return std::make_shared<StreamAsynchronousIO>(*this, true); |
1054 | } |
1055 | |
1056 | StreamSP Debugger::GetAsyncErrorStream() { |
1057 | return std::make_shared<StreamAsynchronousIO>(*this, false); |
1058 | } |
1059 | |
1060 | size_t Debugger::GetNumDebuggers() { |
1061 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
1062 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
1063 | return g_debugger_list_ptr->size(); |
1064 | } |
1065 | return 0; |
1066 | } |
1067 | |
1068 | lldb::DebuggerSP Debugger::GetDebuggerAtIndex(size_t index) { |
1069 | DebuggerSP debugger_sp; |
1070 | |
1071 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
1072 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
1073 | if (index < g_debugger_list_ptr->size()) |
1074 | debugger_sp = g_debugger_list_ptr->at(index); |
1075 | } |
1076 | |
1077 | return debugger_sp; |
1078 | } |
1079 | |
1080 | DebuggerSP Debugger::FindDebuggerWithID(lldb::user_id_t id) { |
1081 | DebuggerSP debugger_sp; |
1082 | |
1083 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
1084 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
1085 | DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); |
1086 | for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) { |
1087 | if ((*pos)->GetID() == id) { |
1088 | debugger_sp = *pos; |
1089 | break; |
1090 | } |
1091 | } |
1092 | } |
1093 | return debugger_sp; |
1094 | } |
1095 | |
1096 | bool Debugger::FormatDisassemblerAddress(const FormatEntity::Entry *format, |
1097 | const SymbolContext *sc, |
1098 | const SymbolContext *prev_sc, |
1099 | const ExecutionContext *exe_ctx, |
1100 | const Address *addr, Stream &s) { |
1101 | FormatEntity::Entry format_entry; |
1102 | |
1103 | if (format == nullptr) { |
1104 | if (exe_ctx != nullptr && exe_ctx->HasTargetScope()) |
1105 | format = exe_ctx->GetTargetRef().GetDebugger().GetDisassemblyFormat(); |
1106 | if (format == nullptr) { |
1107 | FormatEntity::Parse("${addr}: " , format_entry); |
1108 | format = &format_entry; |
1109 | } |
1110 | } |
1111 | bool function_changed = false; |
1112 | bool initial_function = false; |
1113 | if (prev_sc && (prev_sc->function || prev_sc->symbol)) { |
1114 | if (sc && (sc->function || sc->symbol)) { |
1115 | if (prev_sc->symbol && sc->symbol) { |
1116 | if (!sc->symbol->Compare(prev_sc->symbol->GetName(), |
1117 | prev_sc->symbol->GetType())) { |
1118 | function_changed = true; |
1119 | } |
1120 | } else if (prev_sc->function && sc->function) { |
1121 | if (prev_sc->function->GetMangled() != sc->function->GetMangled()) { |
1122 | function_changed = true; |
1123 | } |
1124 | } |
1125 | } |
1126 | } |
1127 | // The first context on a list of instructions will have a prev_sc that has |
1128 | // no Function or Symbol -- if SymbolContext had an IsValid() method, it |
1129 | // would return false. But we do get a prev_sc pointer. |
1130 | if ((sc && (sc->function || sc->symbol)) && prev_sc && |
1131 | (prev_sc->function == nullptr && prev_sc->symbol == nullptr)) { |
1132 | initial_function = true; |
1133 | } |
1134 | return FormatEntity::Format(*format, s, sc, exe_ctx, addr, nullptr, |
1135 | function_changed, initial_function); |
1136 | } |
1137 | |
1138 | void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback, |
1139 | void *baton) { |
1140 | // For simplicity's sake, I am not going to deal with how to close down any |
1141 | // open logging streams, I just redirect everything from here on out to the |
1142 | // callback. |
1143 | m_log_callback_stream_sp = |
1144 | std::make_shared<StreamCallback>(log_callback, baton); |
1145 | } |
1146 | |
1147 | ConstString Debugger::ProgressEventData::GetFlavorString() { |
1148 | static ConstString g_flavor("Debugger::ProgressEventData" ); |
1149 | return g_flavor; |
1150 | } |
1151 | |
1152 | ConstString Debugger::ProgressEventData::GetFlavor() const { |
1153 | return Debugger::ProgressEventData::GetFlavorString(); |
1154 | } |
1155 | |
1156 | void Debugger::ProgressEventData::Dump(Stream *s) const { |
1157 | s->Printf(" id = %" PRIu64 ", message = \"%s\"" , m_id, m_message.c_str()); |
1158 | if (m_completed == 0 || m_completed == m_total) |
1159 | s->Printf(", type = %s" , m_completed == 0 ? "start" : "end" ); |
1160 | else |
1161 | s->PutCString(", type = update" ); |
1162 | // If m_total is UINT64_MAX, there is no progress to report, just "start" |
1163 | // and "end". If it isn't we will show the completed and total amounts. |
1164 | if (m_total != UINT64_MAX) |
1165 | s->Printf(", progress = %" PRIu64 " of %" PRIu64, m_completed, m_total); |
1166 | } |
1167 | |
1168 | const Debugger::ProgressEventData * |
1169 | Debugger::ProgressEventData::GetEventDataFromEvent(const Event *event_ptr) { |
1170 | if (event_ptr) |
1171 | if (const EventData *event_data = event_ptr->GetData()) |
1172 | if (event_data->GetFlavor() == ProgressEventData::GetFlavorString()) |
1173 | return static_cast<const ProgressEventData *>(event_ptr->GetData()); |
1174 | return nullptr; |
1175 | } |
1176 | |
1177 | static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, |
1178 | const std::string &message, |
1179 | uint64_t completed, uint64_t total, |
1180 | bool is_debugger_specific) { |
1181 | // Only deliver progress events if we have any progress listeners. |
1182 | const uint32_t event_type = Debugger::eBroadcastBitProgress; |
1183 | if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type)) |
1184 | return; |
1185 | EventSP event_sp(new Event(event_type, new Debugger::ProgressEventData( |
1186 | progress_id, message, completed, |
1187 | total, is_debugger_specific))); |
1188 | debugger.GetBroadcaster().BroadcastEvent(event_sp); |
1189 | } |
1190 | |
1191 | void Debugger::ReportProgress(uint64_t progress_id, const std::string &message, |
1192 | uint64_t completed, uint64_t total, |
1193 | llvm::Optional<lldb::user_id_t> debugger_id) { |
1194 | // Check if this progress is for a specific debugger. |
1195 | if (debugger_id.hasValue()) { |
1196 | // It is debugger specific, grab it and deliver the event if the debugger |
1197 | // still exists. |
1198 | DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id); |
1199 | if (debugger_sp) |
1200 | PrivateReportProgress(*debugger_sp, progress_id, message, completed, |
1201 | total, /*is_debugger_specific*/ true); |
1202 | return; |
1203 | } |
1204 | // The progress event is not debugger specific, iterate over all debuggers |
1205 | // and deliver a progress event to each one. |
1206 | if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { |
1207 | std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr); |
1208 | DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); |
1209 | for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) |
1210 | PrivateReportProgress(*(*pos), progress_id, message, completed, total, |
1211 | /*is_debugger_specific*/ false); |
1212 | } |
1213 | } |
1214 | |
1215 | bool Debugger::EnableLog(llvm::StringRef channel, |
1216 | llvm::ArrayRef<const char *> categories, |
1217 | llvm::StringRef log_file, uint32_t log_options, |
1218 | llvm::raw_ostream &error_stream) { |
1219 | const bool should_close = true; |
1220 | const bool unbuffered = true; |
1221 | |
1222 | std::shared_ptr<llvm::raw_ostream> log_stream_sp; |
1223 | if (m_log_callback_stream_sp) { |
1224 | log_stream_sp = m_log_callback_stream_sp; |
1225 | // For now when using the callback mode you always get thread & timestamp. |
1226 | log_options |= |
1227 | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; |
1228 | } else if (log_file.empty()) { |
1229 | log_stream_sp = std::make_shared<llvm::raw_fd_ostream>( |
1230 | GetOutputFile().GetDescriptor(), !should_close, unbuffered); |
1231 | } else { |
1232 | auto pos = m_log_streams.find(log_file); |
1233 | if (pos != m_log_streams.end()) |
1234 | log_stream_sp = pos->second.lock(); |
1235 | if (!log_stream_sp) { |
1236 | File::OpenOptions flags = |
1237 | File::eOpenOptionWrite | File::eOpenOptionCanCreate; |
1238 | if (log_options & LLDB_LOG_OPTION_APPEND) |
1239 | flags |= File::eOpenOptionAppend; |
1240 | else |
1241 | flags |= File::eOpenOptionTruncate; |
1242 | llvm::Expected<FileUP> file = FileSystem::Instance().Open( |
1243 | FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false); |
1244 | if (!file) { |
1245 | error_stream << "Unable to open log file '" << log_file |
1246 | << "': " << llvm::toString(file.takeError()) << "\n" ; |
1247 | return false; |
1248 | } |
1249 | |
1250 | log_stream_sp = std::make_shared<llvm::raw_fd_ostream>( |
1251 | (*file)->GetDescriptor(), should_close, unbuffered); |
1252 | m_log_streams[log_file] = log_stream_sp; |
1253 | } |
1254 | } |
1255 | assert(log_stream_sp); |
1256 | |
1257 | if (log_options == 0) |
1258 | log_options = |
1259 | LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; |
1260 | |
1261 | return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, |
1262 | error_stream); |
1263 | } |
1264 | |
1265 | ScriptInterpreter * |
1266 | Debugger::GetScriptInterpreter(bool can_create, |
1267 | llvm::Optional<lldb::ScriptLanguage> language) { |
1268 | std::lock_guard<std::recursive_mutex> locker(m_script_interpreter_mutex); |
1269 | lldb::ScriptLanguage script_language = |
1270 | language ? *language : GetScriptLanguage(); |
1271 | |
1272 | if (!m_script_interpreters[script_language]) { |
1273 | if (!can_create) |
1274 | return nullptr; |
1275 | m_script_interpreters[script_language] = |
1276 | PluginManager::GetScriptInterpreterForLanguage(script_language, *this); |
1277 | } |
1278 | |
1279 | return m_script_interpreters[script_language].get(); |
1280 | } |
1281 | |
1282 | SourceManager &Debugger::GetSourceManager() { |
1283 | if (!m_source_manager_up) |
1284 | m_source_manager_up = std::make_unique<SourceManager>(shared_from_this()); |
1285 | return *m_source_manager_up; |
1286 | } |
1287 | |
1288 | // This function handles events that were broadcast by the process. |
1289 | void Debugger::HandleBreakpointEvent(const EventSP &event_sp) { |
1290 | using namespace lldb; |
1291 | const uint32_t event_type = |
1292 | Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent( |
1293 | event_sp); |
1294 | |
1295 | // if (event_type & eBreakpointEventTypeAdded |
1296 | // || event_type & eBreakpointEventTypeRemoved |
1297 | // || event_type & eBreakpointEventTypeEnabled |
1298 | // || event_type & eBreakpointEventTypeDisabled |
1299 | // || event_type & eBreakpointEventTypeCommandChanged |
1300 | // || event_type & eBreakpointEventTypeConditionChanged |
1301 | // || event_type & eBreakpointEventTypeIgnoreChanged |
1302 | // || event_type & eBreakpointEventTypeLocationsResolved) |
1303 | // { |
1304 | // // Don't do anything about these events, since the breakpoint |
1305 | // commands already echo these actions. |
1306 | // } |
1307 | // |
1308 | if (event_type & eBreakpointEventTypeLocationsAdded) { |
1309 | uint32_t num_new_locations = |
1310 | Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent( |
1311 | event_sp); |
1312 | if (num_new_locations > 0) { |
1313 | BreakpointSP breakpoint = |
1314 | Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp); |
1315 | StreamSP output_sp(GetAsyncOutputStream()); |
1316 | if (output_sp) { |
1317 | output_sp->Printf("%d location%s added to breakpoint %d\n" , |
1318 | num_new_locations, num_new_locations == 1 ? "" : "s" , |
1319 | breakpoint->GetID()); |
1320 | output_sp->Flush(); |
1321 | } |
1322 | } |
1323 | } |
1324 | // else if (event_type & eBreakpointEventTypeLocationsRemoved) |
1325 | // { |
1326 | // // These locations just get disabled, not sure it is worth spamming |
1327 | // folks about this on the command line. |
1328 | // } |
1329 | // else if (event_type & eBreakpointEventTypeLocationsResolved) |
1330 | // { |
1331 | // // This might be an interesting thing to note, but I'm going to |
1332 | // leave it quiet for now, it just looked noisy. |
1333 | // } |
1334 | } |
1335 | |
1336 | void Debugger::FlushProcessOutput(Process &process, bool flush_stdout, |
1337 | bool flush_stderr) { |
1338 | const auto &flush = [&](Stream &stream, |
1339 | size_t (Process::*get)(char *, size_t, Status &)) { |
1340 | Status error; |
1341 | size_t len; |
1342 | char buffer[1024]; |
1343 | while ((len = (process.*get)(buffer, sizeof(buffer), error)) > 0) |
1344 | stream.Write(buffer, len); |
1345 | stream.Flush(); |
1346 | }; |
1347 | |
1348 | std::lock_guard<std::mutex> guard(m_output_flush_mutex); |
1349 | if (flush_stdout) |
1350 | flush(*GetAsyncOutputStream(), &Process::GetSTDOUT); |
1351 | if (flush_stderr) |
1352 | flush(*GetAsyncErrorStream(), &Process::GetSTDERR); |
1353 | } |
1354 | |
1355 | // This function handles events that were broadcast by the process. |
1356 | void Debugger::HandleProcessEvent(const EventSP &event_sp) { |
1357 | using namespace lldb; |
1358 | const uint32_t event_type = event_sp->GetType(); |
1359 | ProcessSP process_sp = |
1360 | (event_type == Process::eBroadcastBitStructuredData) |
1361 | ? EventDataStructuredData::GetProcessFromEvent(event_sp.get()) |
1362 | : Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); |
1363 | |
1364 | StreamSP output_stream_sp = GetAsyncOutputStream(); |
1365 | StreamSP error_stream_sp = GetAsyncErrorStream(); |
1366 | const bool gui_enabled = IsForwardingEvents(); |
1367 | |
1368 | if (!gui_enabled) { |
1369 | bool pop_process_io_handler = false; |
1370 | assert(process_sp); |
1371 | |
1372 | bool state_is_stopped = false; |
1373 | const bool got_state_changed = |
1374 | (event_type & Process::eBroadcastBitStateChanged) != 0; |
1375 | const bool got_stdout = (event_type & Process::eBroadcastBitSTDOUT) != 0; |
1376 | const bool got_stderr = (event_type & Process::eBroadcastBitSTDERR) != 0; |
1377 | const bool got_structured_data = |
1378 | (event_type & Process::eBroadcastBitStructuredData) != 0; |
1379 | |
1380 | if (got_state_changed) { |
1381 | StateType event_state = |
1382 | Process::ProcessEventData::GetStateFromEvent(event_sp.get()); |
1383 | state_is_stopped = StateIsStoppedState(event_state, false); |
1384 | } |
1385 | |
1386 | // Display running state changes first before any STDIO |
1387 | if (got_state_changed && !state_is_stopped) { |
1388 | Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(), |
1389 | pop_process_io_handler); |
1390 | } |
1391 | |
1392 | // Now display STDOUT and STDERR |
1393 | FlushProcessOutput(*process_sp, got_stdout || got_state_changed, |
1394 | got_stderr || got_state_changed); |
1395 | |
1396 | // Give structured data events an opportunity to display. |
1397 | if (got_structured_data) { |
1398 | StructuredDataPluginSP plugin_sp = |
1399 | EventDataStructuredData::GetPluginFromEvent(event_sp.get()); |
1400 | if (plugin_sp) { |
1401 | auto structured_data_sp = |
1402 | EventDataStructuredData::GetObjectFromEvent(event_sp.get()); |
1403 | if (output_stream_sp) { |
1404 | StreamString content_stream; |
1405 | Status error = |
1406 | plugin_sp->GetDescription(structured_data_sp, content_stream); |
1407 | if (error.Success()) { |
1408 | if (!content_stream.GetString().empty()) { |
1409 | // Add newline. |
1410 | content_stream.PutChar('\n'); |
1411 | content_stream.Flush(); |
1412 | |
1413 | // Print it. |
1414 | output_stream_sp->PutCString(content_stream.GetString()); |
1415 | } |
1416 | } else { |
1417 | error_stream_sp->Printf("Failed to print structured " |
1418 | "data with plugin %s: %s" , |
1419 | plugin_sp->GetPluginName().AsCString(), |
1420 | error.AsCString()); |
1421 | } |
1422 | } |
1423 | } |
1424 | } |
1425 | |
1426 | // Now display any stopped state changes after any STDIO |
1427 | if (got_state_changed && state_is_stopped) { |
1428 | Process::HandleProcessStateChangedEvent(event_sp, output_stream_sp.get(), |
1429 | pop_process_io_handler); |
1430 | } |
1431 | |
1432 | output_stream_sp->Flush(); |
1433 | error_stream_sp->Flush(); |
1434 | |
1435 | if (pop_process_io_handler) |
1436 | process_sp->PopProcessIOHandler(); |
1437 | } |
1438 | } |
1439 | |
1440 | void Debugger::HandleThreadEvent(const EventSP &event_sp) { |
1441 | // At present the only thread event we handle is the Frame Changed event, and |
1442 | // all we do for that is just reprint the thread status for that thread. |
1443 | using namespace lldb; |
1444 | const uint32_t event_type = event_sp->GetType(); |
1445 | const bool stop_format = true; |
1446 | if (event_type == Thread::eBroadcastBitStackChanged || |
1447 | event_type == Thread::eBroadcastBitThreadSelected) { |
1448 | ThreadSP thread_sp( |
1449 | Thread::ThreadEventData::GetThreadFromEvent(event_sp.get())); |
1450 | if (thread_sp) { |
1451 | thread_sp->GetStatus(*GetAsyncOutputStream(), 0, 1, 1, stop_format); |
1452 | } |
1453 | } |
1454 | } |
1455 | |
1456 | bool Debugger::IsForwardingEvents() { return (bool)m_forward_listener_sp; } |
1457 | |
1458 | void Debugger::EnableForwardEvents(const ListenerSP &listener_sp) { |
1459 | m_forward_listener_sp = listener_sp; |
1460 | } |
1461 | |
1462 | void Debugger::CancelForwardEvents(const ListenerSP &listener_sp) { |
1463 | m_forward_listener_sp.reset(); |
1464 | } |
1465 | |
1466 | void Debugger::DefaultEventHandler() { |
1467 | ListenerSP listener_sp(GetListener()); |
1468 | ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); |
1469 | ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); |
1470 | ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); |
1471 | BroadcastEventSpec target_event_spec(broadcaster_class_target, |
1472 | Target::eBroadcastBitBreakpointChanged); |
1473 | |
1474 | BroadcastEventSpec process_event_spec( |
1475 | broadcaster_class_process, |
1476 | Process::eBroadcastBitStateChanged | Process::eBroadcastBitSTDOUT | |
1477 | Process::eBroadcastBitSTDERR | Process::eBroadcastBitStructuredData); |
1478 | |
1479 | BroadcastEventSpec thread_event_spec(broadcaster_class_thread, |
1480 | Thread::eBroadcastBitStackChanged | |
1481 | Thread::eBroadcastBitThreadSelected); |
1482 | |
1483 | listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp, |
1484 | target_event_spec); |
1485 | listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp, |
1486 | process_event_spec); |
1487 | listener_sp->StartListeningForEventSpec(m_broadcaster_manager_sp, |
1488 | thread_event_spec); |
1489 | listener_sp->StartListeningForEvents( |
1490 | m_command_interpreter_up.get(), |
1491 | CommandInterpreter::eBroadcastBitQuitCommandReceived | |
1492 | CommandInterpreter::eBroadcastBitAsynchronousOutputData | |
1493 | CommandInterpreter::eBroadcastBitAsynchronousErrorData); |
1494 | |
1495 | // Let the thread that spawned us know that we have started up and that we |
1496 | // are now listening to all required events so no events get missed |
1497 | m_sync_broadcaster.BroadcastEvent(eBroadcastBitEventThreadIsListening); |
1498 | |
1499 | bool done = false; |
1500 | while (!done) { |
1501 | EventSP event_sp; |
1502 | if (listener_sp->GetEvent(event_sp, llvm::None)) { |
1503 | if (event_sp) { |
1504 | Broadcaster *broadcaster = event_sp->GetBroadcaster(); |
1505 | if (broadcaster) { |
1506 | uint32_t event_type = event_sp->GetType(); |
1507 | ConstString broadcaster_class(broadcaster->GetBroadcasterClass()); |
1508 | if (broadcaster_class == broadcaster_class_process) { |
1509 | HandleProcessEvent(event_sp); |
1510 | } else if (broadcaster_class == broadcaster_class_target) { |
1511 | if (Breakpoint::BreakpointEventData::GetEventDataFromEvent( |
1512 | event_sp.get())) { |
1513 | HandleBreakpointEvent(event_sp); |
1514 | } |
1515 | } else if (broadcaster_class == broadcaster_class_thread) { |
1516 | HandleThreadEvent(event_sp); |
1517 | } else if (broadcaster == m_command_interpreter_up.get()) { |
1518 | if (event_type & |
1519 | CommandInterpreter::eBroadcastBitQuitCommandReceived) { |
1520 | done = true; |
1521 | } else if (event_type & |
1522 | CommandInterpreter::eBroadcastBitAsynchronousErrorData) { |
1523 | const char *data = static_cast<const char *>( |
1524 | EventDataBytes::GetBytesFromEvent(event_sp.get())); |
1525 | if (data && data[0]) { |
1526 | StreamSP error_sp(GetAsyncErrorStream()); |
1527 | if (error_sp) { |
1528 | error_sp->PutCString(data); |
1529 | error_sp->Flush(); |
1530 | } |
1531 | } |
1532 | } else if (event_type & CommandInterpreter:: |
1533 | eBroadcastBitAsynchronousOutputData) { |
1534 | const char *data = static_cast<const char *>( |
1535 | EventDataBytes::GetBytesFromEvent(event_sp.get())); |
1536 | if (data && data[0]) { |
1537 | StreamSP output_sp(GetAsyncOutputStream()); |
1538 | if (output_sp) { |
1539 | output_sp->PutCString(data); |
1540 | output_sp->Flush(); |
1541 | } |
1542 | } |
1543 | } |
1544 | } |
1545 | } |
1546 | |
1547 | if (m_forward_listener_sp) |
1548 | m_forward_listener_sp->AddEvent(event_sp); |
1549 | } |
1550 | } |
1551 | } |
1552 | } |
1553 | |
1554 | lldb::thread_result_t Debugger::EventHandlerThread(lldb::thread_arg_t arg) { |
1555 | ((Debugger *)arg)->DefaultEventHandler(); |
1556 | return {}; |
1557 | } |
1558 | |
1559 | bool Debugger::StartEventHandlerThread() { |
1560 | if (!m_event_handler_thread.IsJoinable()) { |
1561 | // We must synchronize with the DefaultEventHandler() thread to ensure it |
1562 | // is up and running and listening to events before we return from this |
1563 | // function. We do this by listening to events for the |
1564 | // eBroadcastBitEventThreadIsListening from the m_sync_broadcaster |
1565 | ConstString full_name("lldb.debugger.event-handler" ); |
1566 | ListenerSP listener_sp(Listener::MakeListener(full_name.AsCString())); |
1567 | listener_sp->StartListeningForEvents(&m_sync_broadcaster, |
1568 | eBroadcastBitEventThreadIsListening); |
1569 | |
1570 | llvm::StringRef thread_name = |
1571 | full_name.GetLength() < llvm::get_max_thread_name_length() |
1572 | ? full_name.GetStringRef() |
1573 | : "dbg.evt-handler" ; |
1574 | |
1575 | // Use larger 8MB stack for this thread |
1576 | llvm::Expected<HostThread> event_handler_thread = |
1577 | ThreadLauncher::LaunchThread(thread_name, EventHandlerThread, this, |
1578 | g_debugger_event_thread_stack_bytes); |
1579 | |
1580 | if (event_handler_thread) { |
1581 | m_event_handler_thread = *event_handler_thread; |
1582 | } else { |
1583 | LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), |
1584 | "failed to launch host thread: {}" , |
1585 | llvm::toString(event_handler_thread.takeError())); |
1586 | } |
1587 | |
1588 | // Make sure DefaultEventHandler() is running and listening to events |
1589 | // before we return from this function. We are only listening for events of |
1590 | // type eBroadcastBitEventThreadIsListening so we don't need to check the |
1591 | // event, we just need to wait an infinite amount of time for it (nullptr |
1592 | // timeout as the first parameter) |
1593 | lldb::EventSP event_sp; |
1594 | listener_sp->GetEvent(event_sp, llvm::None); |
1595 | } |
1596 | return m_event_handler_thread.IsJoinable(); |
1597 | } |
1598 | |
1599 | void Debugger::StopEventHandlerThread() { |
1600 | if (m_event_handler_thread.IsJoinable()) { |
1601 | GetCommandInterpreter().BroadcastEvent( |
1602 | CommandInterpreter::eBroadcastBitQuitCommandReceived); |
1603 | m_event_handler_thread.Join(nullptr); |
1604 | } |
1605 | } |
1606 | |
1607 | lldb::thread_result_t Debugger::IOHandlerThread(lldb::thread_arg_t arg) { |
1608 | Debugger *debugger = (Debugger *)arg; |
1609 | debugger->RunIOHandlers(); |
1610 | debugger->StopEventHandlerThread(); |
1611 | return {}; |
1612 | } |
1613 | |
1614 | bool Debugger::HasIOHandlerThread() { return m_io_handler_thread.IsJoinable(); } |
1615 | |
1616 | bool Debugger::StartIOHandlerThread() { |
1617 | if (!m_io_handler_thread.IsJoinable()) { |
1618 | llvm::Expected<HostThread> io_handler_thread = ThreadLauncher::LaunchThread( |
1619 | "lldb.debugger.io-handler" , IOHandlerThread, this, |
1620 | 8 * 1024 * 1024); // Use larger 8MB stack for this thread |
1621 | if (io_handler_thread) { |
1622 | m_io_handler_thread = *io_handler_thread; |
1623 | } else { |
1624 | LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), |
1625 | "failed to launch host thread: {}" , |
1626 | llvm::toString(io_handler_thread.takeError())); |
1627 | } |
1628 | } |
1629 | return m_io_handler_thread.IsJoinable(); |
1630 | } |
1631 | |
1632 | void Debugger::StopIOHandlerThread() { |
1633 | if (m_io_handler_thread.IsJoinable()) { |
1634 | GetInputFile().Close(); |
1635 | m_io_handler_thread.Join(nullptr); |
1636 | } |
1637 | } |
1638 | |
1639 | void Debugger::JoinIOHandlerThread() { |
1640 | if (HasIOHandlerThread()) { |
1641 | thread_result_t result; |
1642 | m_io_handler_thread.Join(&result); |
1643 | m_io_handler_thread = LLDB_INVALID_HOST_THREAD; |
1644 | } |
1645 | } |
1646 | |
1647 | Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { |
1648 | if (!prefer_dummy) { |
1649 | if (TargetSP target = m_target_list.GetSelectedTarget()) |
1650 | return *target; |
1651 | } |
1652 | return GetDummyTarget(); |
1653 | } |
1654 | |
1655 | Status Debugger::RunREPL(LanguageType language, const char *repl_options) { |
1656 | Status err; |
1657 | FileSpec repl_executable; |
1658 | |
1659 | if (language == eLanguageTypeUnknown) { |
1660 | LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs(); |
1661 | |
1662 | if (auto single_lang = repl_languages.GetSingularLanguage()) { |
1663 | language = *single_lang; |
1664 | } else if (repl_languages.Empty()) { |
1665 | err.SetErrorStringWithFormat( |
1666 | "LLDB isn't configured with REPL support for any languages." ); |
1667 | return err; |
1668 | } else { |
1669 | err.SetErrorStringWithFormat( |
1670 | "Multiple possible REPL languages. Please specify a language." ); |
1671 | return err; |
1672 | } |
1673 | } |
1674 | |
1675 | Target *const target = |
1676 | nullptr; // passing in an empty target means the REPL must create one |
1677 | |
1678 | REPLSP repl_sp(REPL::Create(err, language, this, target, repl_options)); |
1679 | |
1680 | if (!err.Success()) { |
1681 | return err; |
1682 | } |
1683 | |
1684 | if (!repl_sp) { |
1685 | err.SetErrorStringWithFormat("couldn't find a REPL for %s" , |
1686 | Language::GetNameForLanguageType(language)); |
1687 | return err; |
1688 | } |
1689 | |
1690 | repl_sp->SetCompilerOptions(repl_options); |
1691 | repl_sp->RunLoop(); |
1692 | |
1693 | return err; |
1694 | } |
1695 | |