diff options
Diffstat (limited to 'source/Core/Debugger.cpp')
-rw-r--r-- | source/Core/Debugger.cpp | 224 |
1 files changed, 125 insertions, 99 deletions
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index 972d0bc0a6d7..765b59c8865e 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -9,67 +9,71 @@ #include "lldb/Core/Debugger.h" -#include "lldb/Breakpoint/Breakpoint.h" // for Breakpoint, Brea... -#include "lldb/Core/Event.h" // for Event, EventData... +#include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Core/FormatEntity.h" -#include "lldb/Core/Listener.h" // for Listener -#include "lldb/Core/Mangled.h" // for Mangled -#include "lldb/Core/ModuleList.h" // for Mangled +#include "lldb/Core/Mangled.h" +#include "lldb/Core/ModuleList.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Core/State.h" #include "lldb/Core/StreamAsynchronousIO.h" #include "lldb/Core/StreamFile.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Expression/REPL.h" -#include "lldb/Host/File.h" // for File, File::kInv... +#include "lldb/Host/File.h" +#include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/Terminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/OptionValue.h" // for OptionValue, Opt... +#include "lldb/Interpreter/OptionValue.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/OptionValueSInt64.h" #include "lldb/Interpreter/OptionValueString.h" -#include "lldb/Interpreter/Property.h" // for PropertyDefinition -#include "lldb/Interpreter/ScriptInterpreter.h" // for ScriptInterpreter +#include "lldb/Interpreter/Property.h" +#include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" -#include "lldb/Symbol/SymbolContext.h" // for SymbolContext +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/StructuredDataPlugin.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/Thread.h" -#include "lldb/Target/ThreadList.h" // for ThreadList +#include "lldb/Target/ThreadList.h" #include "lldb/Utility/AnsiTerminal.h" -#include "lldb/Utility/Log.h" // for LLDB_LOG_OPTION_... -#include "lldb/Utility/Stream.h" // for Stream +#include "lldb/Utility/Event.h" +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/State.h" +#include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamCallback.h" #include "lldb/Utility/StreamString.h" #if defined(_WIN32) -#include "lldb/Host/windows/PosixApi.h" // for PATH_MAX +#include "lldb/Host/windows/PosixApi.h" +#include "lldb/Host/windows/windows.h" #endif -#include "llvm/ADT/None.h" // for None -#include "llvm/ADT/STLExtras.h" // for make_unique +#include "llvm/ADT/None.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/iterator.h" // for iterator_facade_... +#include "llvm/ADT/iterator.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Threading.h" -#include "llvm/Support/raw_ostream.h" // for raw_fd_ostream +#include "llvm/Support/raw_ostream.h" -#include <list> // for list -#include <memory> // for make_shared +#include <list> +#include <memory> #include <mutex> -#include <set> // for set -#include <stdio.h> // for size_t, NULL -#include <stdlib.h> // for getenv -#include <string.h> // for strcmp -#include <string> // for string -#include <system_error> // for error_code +#include <set> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <string> +#include <system_error> namespace lldb_private { class Address; @@ -89,7 +93,7 @@ static std::recursive_mutex *g_debugger_list_mutex_ptr = static DebuggerList *g_debugger_list_ptr = nullptr; // NOTE: intentional leak to avoid issues with C++ destructor chain -OptionEnumValueElement g_show_disassembly_enum_values[] = { +static constexpr OptionEnumValueElement g_show_disassembly_enum_values[] = { {Debugger::eStopDisassemblyTypeNever, "never", "Never show disassembly when displaying a stop context."}, {Debugger::eStopDisassemblyTypeNoDebugInfo, "no-debuginfo", @@ -98,16 +102,14 @@ OptionEnumValueElement g_show_disassembly_enum_values[] = { "Show disassembly when there is no source information, or the source file " "is missing when displaying a stop context."}, {Debugger::eStopDisassemblyTypeAlways, "always", - "Always show disassembly when displaying a stop context."}, - {0, nullptr, nullptr}}; + "Always show disassembly when displaying a stop context."} }; -OptionEnumValueElement g_language_enumerators[] = { +static constexpr OptionEnumValueElement g_language_enumerators[] = { {eScriptLanguageNone, "none", "Disable scripting languages."}, {eScriptLanguagePython, "python", "Select python as the default scripting language."}, {eScriptLanguageDefault, "default", - "Select the lldb default as the default scripting language."}, - {0, nullptr, nullptr}}; + "Select the lldb default as the default scripting language."} }; #define MODULE_WITH_FUNC \ "{ " \ @@ -119,9 +121,12 @@ OptionEnumValueElement g_language_enumerators[] = { "${module.file.basename}{`${function.name-without-args}" \ "{${frame.no-debug}${function.pc-offset}}}}" -#define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}" +#define FILE_AND_LINE \ + "{ at ${line.file.basename}:${line.number}{:${line.column}}}" #define IS_OPTIMIZED "{${function.is-optimized} [opt]}" +#define IS_ARTIFICIAL "{${frame.is-artificial} [artificial]}" + #define DEFAULT_THREAD_FORMAT \ "thread #${thread.index}: tid = ${thread.id%tid}" \ "{, ${frame.pc}}" MODULE_WITH_FUNC FILE_AND_LINE \ @@ -146,11 +151,11 @@ OptionEnumValueElement g_language_enumerators[] = { #define DEFAULT_FRAME_FORMAT \ "frame #${frame.index}: ${frame.pc}" MODULE_WITH_FUNC FILE_AND_LINE \ - IS_OPTIMIZED "\\n" + IS_OPTIMIZED IS_ARTIFICIAL "\\n" #define DEFAULT_FRAME_FORMAT_NO_ARGS \ "frame #${frame.index}: ${frame.pc}" MODULE_WITH_FUNC_NO_ARGS FILE_AND_LINE \ - IS_OPTIMIZED "\\n" + IS_OPTIMIZED IS_ARTIFICIAL "\\n" // Three parts to this disassembly format specification: // 1. If this is a new function/symbol (no previous symbol/function), print @@ -162,8 +167,8 @@ OptionEnumValueElement g_language_enumerators[] = { // address <+offset>: #define DEFAULT_DISASSEMBLY_FORMAT \ "{${function.initial-function}{${module.file.basename}`}{${function.name-" \ - "without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${" \ - "function.name-without-args}}:\n}{${current-pc-arrow} " \ + "without-args}}:\\n}{${function.changed}\\n{${module.file.basename}`}{${" \ + "function.name-without-args}}:\\n}{${current-pc-arrow} " \ "}${addr-file-or-load}{ " \ "<${function.concrete-only-addr-offset-no-padding}>}: " @@ -177,10 +182,7 @@ OptionEnumValueElement g_language_enumerators[] = { // args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name- // without-args}}:\n}{${current-pc-arrow} }{${addr-file-or-load}}: -#define DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX "${ansi.underline}" -#define DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX "${ansi.normal}" - -static OptionEnumValueElement s_stop_show_column_values[] = { +static constexpr OptionEnumValueElement s_stop_show_column_values[] = { {eStopShowColumnAnsiOrCaret, "ansi-or-caret", "Highlight the stop column with ANSI terminal codes when color/ANSI mode " "is enabled; otherwise, fall back to using a text-only caret (^) as if " @@ -192,98 +194,95 @@ static OptionEnumValueElement s_stop_show_column_values[] = { "Highlight the stop column with a caret character (^) underneath the stop " "column. This method introduces a new line in source listings that " "display thread stop locations."}, - {eStopShowColumnNone, "none", "Do not highlight the stop column."}, - {0, nullptr, nullptr}}; + {eStopShowColumnNone, "none", "Do not highlight the stop column."}}; -static PropertyDefinition g_properties[] = { - {"auto-confirm", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, +static constexpr PropertyDefinition g_properties[] = { + {"auto-confirm", OptionValue::eTypeBoolean, true, false, nullptr, {}, "If true all confirmation prompts will receive their default reply."}, {"disassembly-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_DISASSEMBLY_FORMAT, nullptr, + DEFAULT_DISASSEMBLY_FORMAT, {}, "The default disassembly format " "string to use when disassembling " "instruction sequences."}, {"frame-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_FRAME_FORMAT, nullptr, + DEFAULT_FRAME_FORMAT, {}, "The default frame format string to use " "when displaying stack frame information " "for threads."}, - {"notify-void", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, + {"notify-void", OptionValue::eTypeBoolean, true, false, nullptr, {}, "Notify the user explicitly if an expression returns void (default: " "false)."}, {"prompt", OptionValue::eTypeString, true, - OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", - nullptr, "The debugger command line prompt displayed for the user."}, + OptionValueString::eOptionEncodeCharacterEscapeSequences, "(lldb) ", {}, + "The debugger command line prompt displayed for the user."}, {"script-lang", OptionValue::eTypeEnum, true, eScriptLanguagePython, - nullptr, g_language_enumerators, + nullptr, OptionEnumValues(g_language_enumerators), "The script language to be used for evaluating user-written scripts."}, - {"stop-disassembly-count", OptionValue::eTypeSInt64, true, 4, nullptr, - nullptr, + {"stop-disassembly-count", OptionValue::eTypeSInt64, true, 4, nullptr, {}, "The number of disassembly lines to show when displaying a " "stopped context."}, {"stop-disassembly-display", OptionValue::eTypeEnum, true, Debugger::eStopDisassemblyTypeNoDebugInfo, nullptr, - g_show_disassembly_enum_values, + OptionEnumValues(g_show_disassembly_enum_values), "Control when to display disassembly when displaying a stopped context."}, - {"stop-line-count-after", OptionValue::eTypeSInt64, true, 3, nullptr, - nullptr, + {"stop-line-count-after", OptionValue::eTypeSInt64, true, 3, nullptr, {}, "The number of sources lines to display that come after the " "current source line when displaying a stopped context."}, - {"stop-line-count-before", OptionValue::eTypeSInt64, true, 3, nullptr, - nullptr, + {"stop-line-count-before", OptionValue::eTypeSInt64, true, 3, nullptr, {}, "The number of sources lines to display that come before the " "current source line when displaying a stopped context."}, + {"highlight-source", OptionValue::eTypeBoolean, true, true, nullptr, {}, + "If true, LLDB will highlight the displayed source code."}, {"stop-show-column", OptionValue::eTypeEnum, false, - eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values, + eStopShowColumnAnsiOrCaret, nullptr, OptionEnumValues(s_stop_show_column_values), "If true, LLDB will use the column information from the debug info to " "mark the current position when displaying a stopped context."}, - {"stop-show-column-ansi-prefix", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX, nullptr, + {"stop-show-column-ansi-prefix", OptionValue::eTypeString, true, 0, + "${ansi.underline}", {}, "When displaying the column marker in a color-enabled (i.e. ANSI) " "terminal, use the ANSI terminal code specified in this format at the " "immediately before the column to be marked."}, - {"stop-show-column-ansi-suffix", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX, nullptr, + {"stop-show-column-ansi-suffix", OptionValue::eTypeString, true, 0, + "${ansi.normal}", {}, "When displaying the column marker in a color-enabled (i.e. ANSI) " "terminal, use the ANSI terminal code specified in this format " "immediately after the column to be marked."}, - {"term-width", OptionValue::eTypeSInt64, true, 80, nullptr, nullptr, + {"term-width", OptionValue::eTypeSInt64, true, 80, nullptr, {}, "The maximum number of columns to use for displaying text."}, {"thread-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_THREAD_FORMAT, nullptr, + DEFAULT_THREAD_FORMAT, {}, "The default thread format string to use " "when displaying thread information."}, {"thread-stop-format", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_THREAD_STOP_FORMAT, nullptr, + DEFAULT_THREAD_STOP_FORMAT, {}, "The default thread format " "string to use when displaying thread " "information as part of the stop display."}, - {"use-external-editor", OptionValue::eTypeBoolean, true, false, nullptr, - nullptr, "Whether to use an external editor or not."}, - {"use-color", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, + {"use-external-editor", OptionValue::eTypeBoolean, true, false, nullptr, {}, + "Whether to use an external editor or not."}, + {"use-color", OptionValue::eTypeBoolean, true, true, nullptr, {}, "Whether to use Ansi color codes or not."}, {"auto-one-line-summaries", OptionValue::eTypeBoolean, true, true, nullptr, - nullptr, + {}, "If true, LLDB will automatically display small structs in " "one-liner format (default: true)."}, - {"auto-indent", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, + {"auto-indent", OptionValue::eTypeBoolean, true, true, nullptr, {}, "If true, LLDB will auto indent/outdent code. Currently only supported in " "the REPL (default: true)."}, - {"print-decls", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, + {"print-decls", OptionValue::eTypeBoolean, true, true, nullptr, {}, "If true, LLDB will print the values of variables declared in an " "expression. Currently only supported in the REPL (default: true)."}, - {"tab-size", OptionValue::eTypeUInt64, true, 4, nullptr, nullptr, + {"tab-size", OptionValue::eTypeUInt64, true, 4, nullptr, {}, "The tab size to use when indenting code in multi-line input mode " "(default: 4)."}, {"escape-non-printables", OptionValue::eTypeBoolean, true, true, nullptr, - nullptr, + {}, "If true, LLDB will automatically escape non-printable and " "escape characters when formatting strings."}, {"frame-format-unique", OptionValue::eTypeFormatEntity, true, 0, - DEFAULT_FRAME_FORMAT_NO_ARGS, nullptr, + DEFAULT_FRAME_FORMAT_NO_ARGS, {}, "The default frame format string to use when displaying stack frame" - "information for threads from thread backtrace unique."}, - {nullptr, OptionValue::eTypeInvalid, true, 0, nullptr, nullptr, nullptr}}; + "information for threads from thread backtrace unique."}}; enum { ePropertyAutoConfirm = 0, @@ -296,6 +295,7 @@ enum { ePropertyStopDisassemblyDisplay, ePropertyStopLineCountAfter, ePropertyStopLineCountBefore, + ePropertyHighlightSource, ePropertyStopShowColumn, ePropertyStopShowColumnAnsiPrefix, ePropertyStopShowColumnAnsiSuffix, @@ -413,6 +413,11 @@ void Debugger::SetPrompt(llvm::StringRef p) { GetCommandInterpreter().UpdatePrompt(new_prompt); } +llvm::StringRef Debugger::GetReproducerPath() const { + auto &r = repro::Reproducer::Instance(); + return r.GetReproducerPath().GetCString(); +} + const FormatEntity::Entry *Debugger::GetThreadFormat() const { const uint32_t idx = ePropertyThreadFormat; return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); @@ -470,20 +475,26 @@ bool Debugger::SetUseColor(bool b) { return ret; } +bool Debugger::GetHighlightSource() const { + const uint32_t idx = ePropertyHighlightSource; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value); +} + StopShowColumn Debugger::GetStopShowColumn() const { const uint32_t idx = ePropertyStopShowColumn; return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration( nullptr, idx, g_properties[idx].default_uint_value); } -const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiPrefix() const { +llvm::StringRef Debugger::GetStopShowColumnAnsiPrefix() const { const uint32_t idx = ePropertyStopShowColumnAnsiPrefix; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); + return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, ""); } -const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiSuffix() const { +llvm::StringRef Debugger::GetStopShowColumnAnsiSuffix() const { const uint32_t idx = ePropertyStopShowColumnAnsiSuffix; - return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); + return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, ""); } uint32_t Debugger::GetStopSourceLineCount(bool before) const { @@ -600,16 +611,16 @@ bool Debugger::LoadPlugin(const FileSpec &spec, Status &error) { return false; } -static FileSpec::EnumerateDirectoryResult +static FileSystem::EnumerateDirectoryResult LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft, - const FileSpec &file_spec) { + llvm::StringRef path) { Status error; static ConstString g_dylibext(".dylib"); static ConstString g_solibext(".so"); if (!baton) - return FileSpec::eEnumerateDirectoryResultQuit; + return FileSystem::eEnumerateDirectoryResultQuit; Debugger *debugger = (Debugger *)baton; @@ -620,18 +631,18 @@ LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft, // file type information. if (ft == fs::file_type::regular_file || ft == fs::file_type::symlink_file || ft == fs::file_type::type_unknown) { - FileSpec plugin_file_spec(file_spec); - plugin_file_spec.ResolvePath(); + FileSpec plugin_file_spec(path); + FileSystem::Instance().Resolve(plugin_file_spec); if (plugin_file_spec.GetFileNameExtension() != g_dylibext && plugin_file_spec.GetFileNameExtension() != g_solibext) { - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } Status plugin_load_error; debugger->LoadPlugin(plugin_file_spec, plugin_load_error); - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } else if (ft == fs::file_type::directory_file || ft == fs::file_type::symlink_file || ft == fs::file_type::type_unknown) { @@ -639,10 +650,10 @@ LoadPluginCallback(void *baton, llvm::sys::fs::file_type ft, // also do this for unknown as sometimes the directory enumeration might be // enumerating a file system that doesn't have correct file type // information. - return FileSpec::eEnumerateDirectoryResultEnter; + return FileSystem::eEnumerateDirectoryResultEnter; } - return FileSpec::eEnumerateDirectoryResultNext; + return FileSystem::eEnumerateDirectoryResultNext; } void Debugger::InstanceInitialize() { @@ -651,16 +662,20 @@ void Debugger::InstanceInitialize() { const bool find_other = true; char dir_path[PATH_MAX]; if (FileSpec dir_spec = HostInfo::GetSystemPluginDir()) { - if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { - FileSpec::EnumerateDirectory(dir_path, find_directories, find_files, - find_other, LoadPluginCallback, this); + if (FileSystem::Instance().Exists(dir_spec) && + dir_spec.GetPath(dir_path, sizeof(dir_path))) { + FileSystem::Instance().EnumerateDirectory(dir_path, find_directories, + find_files, find_other, + LoadPluginCallback, this); } } if (FileSpec dir_spec = HostInfo::GetUserPluginDir()) { - if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path))) { - FileSpec::EnumerateDirectory(dir_path, find_directories, find_files, - find_other, LoadPluginCallback, this); + if (FileSystem::Instance().Exists(dir_spec) && + dir_spec.GetPath(dir_path, sizeof(dir_path))) { + FileSystem::Instance().EnumerateDirectory(dir_path, find_directories, + find_files, find_other, + LoadPluginCallback, this); } } @@ -795,6 +810,15 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) const char *term = getenv("TERM"); if (term && !strcmp(term, "dumb")) SetUseColor(false); + // Turn off use-color if we don't write to a terminal with color support. + if (!m_output_file_sp->GetFile().GetIsTerminalWithColors()) + SetUseColor(false); + +#if defined(_WIN32) && defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING) + // Enabling use of ANSI color codes because LLDB is using them to highlight + // text. + llvm::sys::Process::UseANSIEscapeCodes(true); +#endif } Debugger::~Debugger() { Clear(); } @@ -1068,7 +1092,8 @@ void Debugger::AdoptTopIOHandlerFilesIfInvalid(StreamFileSP &in, } } -void Debugger::PushIOHandler(const IOHandlerSP &reader_sp) { +void Debugger::PushIOHandler(const IOHandlerSP &reader_sp, + bool cancel_top_handler) { if (!reader_sp) return; @@ -1089,7 +1114,8 @@ void Debugger::PushIOHandler(const IOHandlerSP &reader_sp) { // this new input reader take over if (top_reader_sp) { top_reader_sp->Deactivate(); - top_reader_sp->Cancel(); + if (cancel_top_handler) + top_reader_sp->Cancel(); } } |