diff options
Diffstat (limited to 'lldb/source/Interpreter')
| -rw-r--r-- | lldb/source/Interpreter/CommandInterpreter.cpp | 117 | ||||
| -rw-r--r-- | lldb/source/Interpreter/CommandObject.cpp | 18 | ||||
| -rw-r--r-- | lldb/source/Interpreter/CommandReturnObject.cpp | 8 | ||||
| -rw-r--r-- | lldb/source/Interpreter/InterpreterProperties.td | 4 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionGroupMemoryTag.cpp | 60 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionGroupPlatform.cpp | 27 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp | 12 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionValueDictionary.cpp | 25 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionValueFileColonLine.cpp | 5 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionValueFileSpec.cpp | 4 | ||||
| -rw-r--r-- | lldb/source/Interpreter/OptionValueProperties.cpp | 11 | ||||
| -rw-r--r-- | lldb/source/Interpreter/Options.cpp | 192 | ||||
| -rw-r--r-- | lldb/source/Interpreter/Property.cpp | 7 | ||||
| -rw-r--r-- | lldb/source/Interpreter/ScriptInterpreter.cpp | 8 | ||||
| -rw-r--r-- | lldb/source/Interpreter/embedded_interpreter.py | 73 |
15 files changed, 332 insertions, 239 deletions
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 59c23716bf89..6ef209b20fc6 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -45,6 +45,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/State.h" @@ -83,6 +84,10 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/ScopedPrinter.h" +#if defined(__APPLE__) +#include <TargetConditionals.h> +#endif + using namespace lldb; using namespace lldb_private; @@ -123,7 +128,8 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger, m_debugger(debugger), m_synchronous_execution(true), m_skip_lldbinit_files(false), m_skip_app_init_files(false), m_comment_char('#'), m_batch_command_mode(false), - m_truncation_warning(eNoTruncation), m_command_source_depth(0) { + m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission), + m_command_source_depth(0) { SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit"); SetEventName(eBroadcastBitResetPrompt, "reset-prompt"); SetEventName(eBroadcastBitQuitCommandReceived, "quit"); @@ -206,7 +212,7 @@ bool CommandInterpreter::SetQuitExitCode(int exit_code) { } int CommandInterpreter::GetQuitExitCode(bool &exited) const { - exited = m_quit_exit_code.hasValue(); + exited = m_quit_exit_code.has_value(); if (exited) return *m_quit_exit_code; return 0; @@ -239,6 +245,12 @@ bool CommandInterpreter::GetRepeatPreviousCommand() const { nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } +bool CommandInterpreter::GetRequireCommandOverwrite() const { + const uint32_t idx = ePropertyRequireCommandOverwrite; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); +} + void CommandInterpreter::Initialize() { LLDB_SCOPED_TIMER(); @@ -433,7 +445,7 @@ void CommandInterpreter::Initialize() { if (cmd_obj_sp) { alias_arguments_vector_sp = std::make_shared<OptionArgVector>(); #if defined(__APPLE__) -#if defined(TARGET_OS_IPHONE) +#if TARGET_OS_IPHONE AddAlias("r", cmd_obj_sp, "--"); AddAlias("run", cmd_obj_sp, "--"); #else @@ -1434,7 +1446,7 @@ void CommandInterpreter::GetHelp(CommandReturnObject &result, result.AppendMessage("Current user-defined container commands:"); result.AppendMessage(""); max_len = FindLongestCommandWord(m_user_mw_dict); - for (pos = m_user_dict.begin(); pos != m_user_mw_dict.end(); ++pos) { + for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) { OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--", pos->second->GetHelp(), max_len); } @@ -1825,7 +1837,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line, std::string command_string(command_line); std::string original_command_string(command_line); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS)); + Log *log = GetLog(LLDBLog::Commands); llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")", command_line); @@ -1943,16 +1955,21 @@ bool CommandInterpreter::HandleCommand(const char *command_line, // arguments. if (cmd_obj != nullptr) { - if (add_to_history) { + // If we got here when empty_command was true, then this command is a + // stored "repeat command" which we should give a chance to produce it's + // repeat command, even though we don't add repeat commands to the history. + if (add_to_history || empty_command) { Args command_args(command_string); - const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0); - if (repeat_command != nullptr) - m_repeat_command.assign(repeat_command); + llvm::Optional<std::string> repeat_command = + cmd_obj->GetRepeatCommand(command_args, 0); + if (repeat_command) + m_repeat_command.assign(*repeat_command); else m_repeat_command.assign(original_command_string); + } + if (add_to_history) m_command_history.AppendString(original_command_string); - } std::string remainder; const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size(); @@ -2374,6 +2391,21 @@ void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result, SourceInitFile(FileSpec(init_file.str()), result); } +void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) { +#ifdef LLDB_GLOBAL_INIT_DIRECTORY + if (!m_skip_lldbinit_files) { + FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY); + if (init_file) + init_file.MakeAbsolute(HostInfo::GetShlibDir()); + + init_file.AppendPathComponent("lldbinit"); + SourceInitFile(init_file, result); + return; + } +#endif + result.SetStatus(eReturnStatusSuccessFinishNoResult); +} + const char *CommandInterpreter::GetCommandPrefix() { const char *prefix = GetDebugger().GetIOHandlerCommandPrefix(); return prefix == nullptr ? "" : prefix; @@ -2950,28 +2982,27 @@ bool CommandInterpreter::WasInterrupted() const { return was_interrupted; } -void CommandInterpreter::PrintCommandOutput(Stream &stream, - llvm::StringRef str) { +void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler, + llvm::StringRef str, + bool is_stdout) { + + lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP() + : io_handler.GetErrorStreamFileSP(); // Split the output into lines and poll for interrupt requests - const char *data = str.data(); - size_t size = str.size(); - while (size > 0 && !WasInterrupted()) { - size_t chunk_size = 0; - for (; chunk_size < size; ++chunk_size) { - lldbassert(data[chunk_size] != '\0'); - if (data[chunk_size] == '\n') { - ++chunk_size; - break; - } + while (!str.empty() && !WasInterrupted()) { + llvm::StringRef line; + std::tie(line, str) = str.split('\n'); + { + std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); + stream->Write(line.data(), line.size()); + stream->Write("\n", 1); } - chunk_size = stream.Write(data, chunk_size); - lldbassert(size >= chunk_size); - data += chunk_size; - size -= chunk_size; - } - if (size > 0) { - stream.Printf("\n... Interrupted.\n"); } + + std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); + if (!str.empty()) + stream->Printf("\n... Interrupted.\n"); + stream->Flush(); } bool CommandInterpreter::EchoCommandNonInteractive( @@ -3007,16 +3038,24 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, // When using a non-interactive file handle (like when sourcing commands // from a file) we need to echo the command out so we don't just see the // command output and no command... - if (EchoCommandNonInteractive(line, io_handler.GetFlags())) + if (EchoCommandNonInteractive(line, io_handler.GetFlags())) { + std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex()); io_handler.GetOutputStreamFileSP()->Printf( "%s%s\n", io_handler.GetPrompt(), line.c_str()); + } } StartHandlingCommand(); - OverrideExecutionContext(m_debugger.GetSelectedExecutionContext()); - auto finalize = llvm::make_scope_exit([this]() { - RestoreExecutionContext(); + ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext(); + bool pushed_exe_ctx = false; + if (exe_ctx.HasTargetScope()) { + OverrideExecutionContext(exe_ctx); + pushed_exe_ctx = true; + } + auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() { + if (pushed_exe_ctx) + RestoreExecutionContext(); }); lldb_private::CommandReturnObject result(m_debugger.GetUseColor()); @@ -3031,13 +3070,13 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, if (!result.GetImmediateOutputStream()) { llvm::StringRef output = result.GetOutputData(); - PrintCommandOutput(*io_handler.GetOutputStreamFileSP(), output); + PrintCommandOutput(io_handler, output, true); } // Now emit the command error text from the command we just executed if (!result.GetImmediateErrorStream()) { llvm::StringRef error = result.GetErrorData(); - PrintCommandOutput(*io_handler.GetErrorStreamFileSP(), error); + PrintCommandOutput(io_handler, error, false); } } @@ -3122,8 +3161,8 @@ bool CommandInterpreter::SaveTranscript( } auto error_out = [&](llvm::StringRef error_message, std::string description) { - LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS), "{0} ({1}:{2})", - error_message, output_file, description); + LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message, + output_file, description); result.AppendErrorWithFormatv( "Failed to save session's transcripts to {0}!", *output_file); return false; @@ -3156,6 +3195,10 @@ bool CommandInterpreter::SaveTranscript( return true; } +bool CommandInterpreter::IsInteractive() { + return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false); +} + FileSpec CommandInterpreter::GetCurrentSourceDir() { if (m_command_source_dirs.empty()) return {}; diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index dcae27ff5479..c92fec53a55e 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -132,7 +132,7 @@ bool CommandObject::ParseOptions(Args &args, CommandReturnObject &result) { } else { // No error string, output the usage information into result options->GenerateOptionUsage( - result.GetErrorStream(), this, + result.GetErrorStream(), *this, GetCommandInterpreter().GetDebugger().GetTerminalWidth()); } } @@ -326,7 +326,7 @@ bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word, if (!found_word && search_options && GetOptions() != nullptr) { StreamString usage_help; GetOptions()->GenerateOptionUsage( - usage_help, this, + usage_help, *this, GetCommandInterpreter().GetDebugger().GetTerminalWidth()); if (!usage_help.Empty()) { llvm::StringRef usage_text = usage_help.GetString(); @@ -863,7 +863,7 @@ void CommandObject::GenerateHelpText(Stream &output_strm) { Options *options = GetOptions(); if (options != nullptr) { options->GenerateOptionUsage( - output_strm, this, + output_strm, *this, GetCommandInterpreter().GetDebugger().GetTerminalWidth()); } llvm::StringRef long_help = GetHelpLong(); @@ -995,6 +995,11 @@ bool CommandObjectParsed::Execute(const char *args_string, if (ParseOptions(cmd_args, result)) { // Call the command-specific version of 'Execute', passing it the // already processed arguments. + if (cmd_args.GetArgumentCount() != 0 && m_arguments.empty()) { + result.AppendErrorWithFormatv("'{0}' doesn't take any arguments.", + GetCommandName()); + return false; + } handled = DoExecute(cmd_args, result); } } @@ -1126,7 +1131,12 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypeCommand, "command", CommandCompletions::eNoCompletion, { nullptr, false }, "An LLDB Command line command element." }, { eArgTypeColumnNum, "column", CommandCompletions::eNoCompletion, { nullptr, false }, "Column number in a source file." }, { eArgTypeModuleUUID, "module-uuid", CommandCompletions::eModuleUUIDCompletion, { nullptr, false }, "A module UUID value." }, - { eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." } + { eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." }, + { eArgTypeLogHandler, "log-handler", CommandCompletions::eNoCompletion, { nullptr, false }, "The log handle that will be used to write out log messages." }, + { eArgTypeSEDStylePair, "substitution-pair", CommandCompletions::eNoCompletion, { nullptr, false }, "A sed-style pattern and target pair." }, + { eArgTypeConnectURL, "process-connect-url", CommandCompletions::eNoCompletion, { nullptr, false }, "A URL-style specification for a remote connection." }, + { eArgTypeTargetID, "target-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The index ID for an lldb Target." }, + { eArgTypeStopHookID, "stop-hook-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The ID you receive when you create a stop-hook." } // clang-format on }; diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp index 1b1e6996764c..4433c43ff6d4 100644 --- a/lldb/source/Interpreter/CommandReturnObject.cpp +++ b/lldb/source/Interpreter/CommandReturnObject.cpp @@ -106,7 +106,13 @@ void CommandReturnObject::AppendError(llvm::StringRef in_string) { void CommandReturnObject::SetError(const Status &error, const char *fallback_error_cstr) { - AppendError(error.AsCString(fallback_error_cstr)); + if (error.Fail()) + AppendError(error.AsCString(fallback_error_cstr)); +} + +void CommandReturnObject::SetError(llvm::Error error) { + if (error) + AppendError(llvm::toString(std::move(error))); } // Similar to AppendError, but do not prepend 'Status: ' to message, and don't diff --git a/lldb/source/Interpreter/InterpreterProperties.td b/lldb/source/Interpreter/InterpreterProperties.td index 1c6f0206c489..c0acc044fb7f 100644 --- a/lldb/source/Interpreter/InterpreterProperties.td +++ b/lldb/source/Interpreter/InterpreterProperties.td @@ -36,4 +36,8 @@ let Definition = "interpreter" in { Global, DefaultTrue, Desc<"If true, LLDB will repeat the previous command if no command was passed to the interpreter. If false, LLDB won't repeat the previous command but only return a new prompt.">; + def RequireCommandOverwrite: Property<"require-overwrite", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, require --overwrite in 'command script add' before overwriting existing user commands.">; } diff --git a/lldb/source/Interpreter/OptionGroupMemoryTag.cpp b/lldb/source/Interpreter/OptionGroupMemoryTag.cpp new file mode 100644 index 000000000000..6752b6c8acf2 --- /dev/null +++ b/lldb/source/Interpreter/OptionGroupMemoryTag.cpp @@ -0,0 +1,60 @@ +//===-- OptionGroupMemoryTag.cpp -----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/OptionGroupMemoryTag.h" + +#include "lldb/Host/OptionParser.h" + +using namespace lldb; +using namespace lldb_private; + +static const uint32_t SHORT_OPTION_SHOW_TAGS = 0x54414753; // 'tags' + +OptionGroupMemoryTag::OptionGroupMemoryTag(bool note_binary /*=false*/) + : m_show_tags(false, false), m_option_definition{ + LLDB_OPT_SET_1, + false, + "show-tags", + SHORT_OPTION_SHOW_TAGS, + OptionParser::eNoArgument, + nullptr, + {}, + 0, + eArgTypeNone, + note_binary + ? "Include memory tags in output " + "(does not apply to binary output)." + : "Include memory tags in output."} {} + +llvm::ArrayRef<OptionDefinition> OptionGroupMemoryTag::GetDefinitions() { + return llvm::makeArrayRef(m_option_definition); +} + +Status +OptionGroupMemoryTag::SetOptionValue(uint32_t option_idx, + llvm::StringRef option_arg, + ExecutionContext *execution_context) { + assert(option_idx == 0 && "Only one option in memory tag group!"); + + switch (m_option_definition.short_option) { + case SHORT_OPTION_SHOW_TAGS: + m_show_tags.SetCurrentValue(true); + m_show_tags.SetOptionWasSet(); + break; + + default: + llvm_unreachable("Unimplemented option"); + } + + return {}; +} + +void OptionGroupMemoryTag::OptionParsingStarting( + ExecutionContext *execution_context) { + m_show_tags.Clear(); +} diff --git a/lldb/source/Interpreter/OptionGroupPlatform.cpp b/lldb/source/Interpreter/OptionGroupPlatform.cpp index 4242e010fa64..acdf3f293496 100644 --- a/lldb/source/Interpreter/OptionGroupPlatform.cpp +++ b/lldb/source/Interpreter/OptionGroupPlatform.cpp @@ -18,27 +18,34 @@ using namespace lldb_private; PlatformSP OptionGroupPlatform::CreatePlatformWithOptions( CommandInterpreter &interpreter, const ArchSpec &arch, bool make_selected, Status &error, ArchSpec &platform_arch) const { + PlatformList &platforms = interpreter.GetDebugger().GetPlatformList(); + PlatformSP platform_sp; if (!m_platform_name.empty()) { - platform_sp = Platform::Create(ConstString(m_platform_name.c_str()), error); + platform_sp = platforms.Create(m_platform_name); + if (!platform_sp) { + error.SetErrorStringWithFormatv( + "unable to find a plug-in for the platform named \"{0}\"", + m_platform_name); + } if (platform_sp) { - if (platform_arch.IsValid() && - !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) { - error.SetErrorStringWithFormat("platform '%s' doesn't support '%s'", - platform_sp->GetName().GetCString(), - arch.GetTriple().getTriple().c_str()); + if (platform_arch.IsValid() && !platform_sp->IsCompatibleArchitecture( + arch, {}, false, &platform_arch)) { + error.SetErrorStringWithFormatv("platform '{0}' doesn't support '{1}'", + platform_sp->GetPluginName(), + arch.GetTriple().getTriple()); platform_sp.reset(); return platform_sp; } } } else if (arch.IsValid()) { - platform_sp = Platform::Create(arch, &platform_arch, error); + platform_sp = platforms.GetOrCreate(arch, {}, &platform_arch, error); } if (platform_sp) { - interpreter.GetDebugger().GetPlatformList().Append(platform_sp, - make_selected); + if (make_selected) + platforms.SetSelectedPlatform(platform_sp); if (!m_os_version.empty()) platform_sp->SetOSVersion(m_os_version); @@ -122,7 +129,7 @@ bool OptionGroupPlatform::PlatformMatches( const lldb::PlatformSP &platform_sp) const { if (platform_sp) { if (!m_platform_name.empty()) { - if (platform_sp->GetName() != ConstString(m_platform_name.c_str())) + if (platform_sp->GetName() != m_platform_name) return false; } diff --git a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp index 04861b539650..57b593020b14 100644 --- a/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -104,6 +104,8 @@ Status OptionGroupValueObjectDisplay::SetOptionValue( max_depth = UINT32_MAX; error.SetErrorStringWithFormat("invalid max depth '%s'", option_arg.str().c_str()); + } else { + max_depth_is_default = false; } break; @@ -163,6 +165,7 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting( flat_output = false; use_objc = false; max_depth = UINT32_MAX; + max_depth_is_default = true; ptr_depth = 0; elem_count = 0; use_synth = true; @@ -172,9 +175,12 @@ void OptionGroupValueObjectDisplay::OptionParsingStarting( TargetSP target_sp = execution_context ? execution_context->GetTargetSP() : TargetSP(); - if (target_sp) + if (target_sp) { use_dynamic = target_sp->GetPreferDynamicValue(); - else { + auto max_depth_config = target_sp->GetMaximumDepthOfChildrenToDisplay(); + max_depth = std::get<uint32_t>(max_depth_config); + max_depth_is_default = std::get<bool>(max_depth_config); + } else { // If we don't have any targets, then dynamic values won't do us much good. use_dynamic = lldb::eNoDynamicValues; } @@ -190,7 +196,7 @@ DumpValueObjectOptions OptionGroupValueObjectDisplay::GetAsDumpOptions( options.SetShowSummary(false); else options.SetOmitSummaryDepth(no_summary_depth); - options.SetMaximumDepth(max_depth) + options.SetMaximumDepth(max_depth, max_depth_is_default) .SetShowTypes(show_types) .SetShowLocation(show_location) .SetUseObjectiveC(use_objc) diff --git a/lldb/source/Interpreter/OptionValueDictionary.cpp b/lldb/source/Interpreter/OptionValueDictionary.cpp index 26fed4a987e1..6baafc9213e1 100644 --- a/lldb/source/Interpreter/OptionValueDictionary.cpp +++ b/lldb/source/Interpreter/OptionValueDictionary.cpp @@ -8,11 +8,12 @@ #include "lldb/Interpreter/OptionValueDictionary.h" -#include "llvm/ADT/StringRef.h" #include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/OptionValueEnumeration.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/State.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; @@ -161,16 +162,26 @@ Status OptionValueDictionary::SetArgs(const Args &args, return error; } - lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( - value.str().c_str(), m_type_mask, error)); - if (value_sp) { + if (m_type_mask == 1u << eTypeEnum) { + auto enum_value = + std::make_shared<OptionValueEnumeration>(m_enum_values, 0); + error = enum_value->SetValueFromString(value); if (error.Fail()) return error; m_value_was_set = true; - SetValueForKey(ConstString(key), value_sp, true); + SetValueForKey(ConstString(key), enum_value, true); } else { - error.SetErrorString("dictionaries that can contain multiple types " - "must subclass OptionValueArray"); + lldb::OptionValueSP value_sp(CreateValueFromCStringForTypeMask( + value.str().c_str(), m_type_mask, error)); + if (value_sp) { + if (error.Fail()) + return error; + m_value_was_set = true; + SetValueForKey(ConstString(key), value_sp, true); + } else { + error.SetErrorString("dictionaries that can contain multiple types " + "must subclass OptionValueArray"); + } } } break; diff --git a/lldb/source/Interpreter/OptionValueFileColonLine.cpp b/lldb/source/Interpreter/OptionValueFileColonLine.cpp index fb0b516c8616..e500005a815d 100644 --- a/lldb/source/Interpreter/OptionValueFileColonLine.cpp +++ b/lldb/source/Interpreter/OptionValueFileColonLine.cpp @@ -24,9 +24,8 @@ using namespace lldb_private; OptionValueFileColonLine::OptionValueFileColonLine() = default; OptionValueFileColonLine::OptionValueFileColonLine(llvm::StringRef input) - : m_line_number(LLDB_INVALID_LINE_NUMBER), - m_column_number(LLDB_INVALID_COLUMN_NUMBER), - m_completion_mask(CommandCompletions::eSourceFileCompletion) { + +{ SetValueFromString(input, eVarSetOperationAssign); } diff --git a/lldb/source/Interpreter/OptionValueFileSpec.cpp b/lldb/source/Interpreter/OptionValueFileSpec.cpp index 3987a36b1b65..f35a6b886f98 100644 --- a/lldb/source/Interpreter/OptionValueFileSpec.cpp +++ b/lldb/source/Interpreter/OptionValueFileSpec.cpp @@ -22,14 +22,14 @@ OptionValueFileSpec::OptionValueFileSpec(bool resolve) : m_resolve(resolve) {} OptionValueFileSpec::OptionValueFileSpec(const FileSpec &value, bool resolve) : m_current_value(value), m_default_value(value), - m_completion_mask(CommandCompletions::eDiskFileCompletion), + m_resolve(resolve) {} OptionValueFileSpec::OptionValueFileSpec(const FileSpec ¤t_value, const FileSpec &default_value, bool resolve) : m_current_value(current_value), m_default_value(default_value), - m_completion_mask(CommandCompletions::eDiskFileCompletion), + m_resolve(resolve) {} void OptionValueFileSpec::DumpValue(const ExecutionContext *exe_ctx, diff --git a/lldb/source/Interpreter/OptionValueProperties.cpp b/lldb/source/Interpreter/OptionValueProperties.cpp index 6e6580574edf..b216557b808f 100644 --- a/lldb/source/Interpreter/OptionValueProperties.cpp +++ b/lldb/source/Interpreter/OptionValueProperties.cpp @@ -412,6 +412,17 @@ OptionValueSInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64( return nullptr; } +OptionValueUInt64 *OptionValueProperties::GetPropertyAtIndexAsOptionValueUInt64( + const ExecutionContext *exe_ctx, uint32_t idx) const { + const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); + if (property) { + OptionValue *value = property->GetValue().get(); + if (value) + return value->GetAsUInt64(); + } + return nullptr; +} + int64_t OptionValueProperties::GetPropertyAtIndexAsSInt64( const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const { const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp index feebe338bc9a..26d9d2a17867 100644 --- a/lldb/source/Interpreter/Options.cpp +++ b/lldb/source/Interpreter/Options.cpp @@ -20,6 +20,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Target.h" #include "lldb/Utility/StreamString.h" +#include "llvm/ADT/STLExtras.h" using namespace lldb; using namespace lldb_private; @@ -223,21 +224,25 @@ Option *Options::GetLongOptions() { option_seen.find(short_opt); StreamString strm; if (defs[i].HasShortOption()) - Host::SystemLog(Host::eSystemLogError, - "option[%u] --%s has a short option -%c that " - "conflicts with option[%u] --%s, short option won't " - "be used for --%s\n", - (int)i, defs[i].long_option, short_opt, pos->second, - m_getopt_table[pos->second].definition->long_option, - defs[i].long_option); + Debugger::ReportError( + llvm::formatv( + "option[{0}] --{1} has a short option -{2} that " + "conflicts with option[{3}] --{4}, short option won't " + "be used for --{5}", + i, defs[i].long_option, short_opt, pos->second, + m_getopt_table[pos->second].definition->long_option, + defs[i].long_option) + .str()); else - Host::SystemLog(Host::eSystemLogError, - "option[%u] --%s has a short option 0x%x that " - "conflicts with option[%u] --%s, short option won't " - "be used for --%s\n", - (int)i, defs[i].long_option, short_opt, pos->second, - m_getopt_table[pos->second].definition->long_option, - defs[i].long_option); + Debugger::ReportError( + llvm::formatv( + "option[{0}] --{1} has a short option {2:x} that " + "conflicts with option[{3}] --{4}, short option won't " + "be used for --{5}n", + (int)i, defs[i].long_option, short_opt, pos->second, + m_getopt_table[pos->second].definition->long_option, + defs[i].long_option) + .str()); } } @@ -387,26 +392,19 @@ static bool PrintOption(const OptionDefinition &opt_def, return true; } -void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, +void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd, uint32_t screen_width) { - const bool only_print_args = cmd->IsDashDashCommand(); - auto opt_defs = GetDefinitions(); const uint32_t save_indent_level = strm.GetIndentLevel(); - llvm::StringRef name; - + llvm::StringRef name = cmd.GetCommandName(); StreamString arguments_str; - - if (cmd) { - name = cmd->GetCommandName(); - cmd->GetFormattedCommandArguments(arguments_str); - } else - name = ""; + cmd.GetFormattedCommandArguments(arguments_str); const uint32_t num_options = NumCommandOptions(); if (num_options == 0) return; + const bool only_print_args = cmd.IsDashDashCommand(); if (!only_print_args) strm.PutCString("\nCommand Options Usage:\n"); @@ -418,113 +416,73 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, // [options-for-level-1] // etc. - uint32_t num_option_sets = GetRequiredOptions().size(); - - uint32_t i; - if (!only_print_args) { + uint32_t num_option_sets = GetRequiredOptions().size(); for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) { - uint32_t opt_set_mask; - - opt_set_mask = 1 << opt_set; if (opt_set > 0) strm.Printf("\n"); strm.Indent(name); // Different option sets may require different args. StreamString args_str; - if (cmd) - cmd->GetFormattedCommandArguments(args_str, opt_set_mask); + uint32_t opt_set_mask = 1 << opt_set; + cmd.GetFormattedCommandArguments(args_str, opt_set_mask); // First go through and print all options that take no arguments as a // single string. If a command has "-a" "-b" and "-c", this will show up // as [-abc] - std::set<int> options; - std::set<int>::const_iterator options_pos, options_end; - for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask && def.HasShortOption()) { - // Add current option to the end of out_stream. + // We use a set here so that they will be sorted. + std::set<int> required_options; + std::set<int> optional_options; - if (def.required && def.option_has_arg == OptionParser::eNoArgument) { - options.insert(def.short_option); + for (auto &def : opt_defs) { + if (def.usage_mask & opt_set_mask && def.HasShortOption() && + def.option_has_arg == OptionParser::eNoArgument) { + if (def.required) { + required_options.insert(def.short_option); + } else { + optional_options.insert(def.short_option); } } } - if (!options.empty()) { - // We have some required options with no arguments + if (!required_options.empty()) { strm.PutCString(" -"); - for (i = 0; i < 2; ++i) - for (options_pos = options.begin(), options_end = options.end(); - options_pos != options_end; ++options_pos) { - if (i == 0 && ::islower(*options_pos)) - continue; - if (i == 1 && ::isupper(*options_pos)) - continue; - strm << (char)*options_pos; - } - } - - options.clear(); - for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask && def.HasShortOption()) { - // Add current option to the end of out_stream. - - if (!def.required && - def.option_has_arg == OptionParser::eNoArgument) { - options.insert(def.short_option); - } - } + for (int short_option : required_options) + strm.PutChar(short_option); } - if (!options.empty()) { - // We have some required options with no arguments + if (!optional_options.empty()) { strm.PutCString(" [-"); - for (i = 0; i < 2; ++i) - for (options_pos = options.begin(), options_end = options.end(); - options_pos != options_end; ++options_pos) { - if (i == 0 && ::islower(*options_pos)) - continue; - if (i == 1 && ::isupper(*options_pos)) - continue; - strm << (char)*options_pos; - } + for (int short_option : optional_options) + strm.PutChar(short_option); strm.PutChar(']'); } // First go through and print the required options (list them up front). - for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask && def.HasShortOption()) { - if (def.required && def.option_has_arg != OptionParser::eNoArgument) - PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); - } + if (def.usage_mask & opt_set_mask && def.HasShortOption() && + def.required && def.option_has_arg != OptionParser::eNoArgument) + PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); } // Now go through again, and this time only print the optional options. - for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask) { - // Add current option to the end of out_stream. - - if (!def.required && def.option_has_arg != OptionParser::eNoArgument) - PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); - } + if (def.usage_mask & opt_set_mask && !def.required && + def.option_has_arg != OptionParser::eNoArgument) + PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); } if (args_str.GetSize() > 0) { - if (cmd->WantsRawCommandString() && !only_print_args) + if (cmd.WantsRawCommandString()) strm.Printf(" --"); - strm << " " << args_str.GetString(); - if (only_print_args) - break; } } } - if (cmd && (only_print_args || cmd->WantsRawCommandString()) && + if ((only_print_args || cmd.WantsRawCommandString()) && arguments_str.GetSize() > 0) { if (!only_print_args) strm.PutChar('\n'); @@ -540,63 +498,49 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, // -short <argument> ( --long_name <argument> ) // help text - // This variable is used to keep track of which options' info we've printed - // out, because some options can be in more than one usage level, but we - // only want to print the long form of its information once. - - std::multimap<int, uint32_t> options_seen; strm.IndentMore(5); - // Put the unique command options in a vector & sort it, so we can output - // them alphabetically (by short_option) when writing out detailed help for - // each option. - - i = 0; - for (auto &def : opt_defs) - options_seen.insert(std::make_pair(def.short_option, i++)); + // Put the command options in a sorted container, so we can output + // them alphabetically by short_option. + std::multimap<int, uint32_t> options_ordered; + for (auto def : llvm::enumerate(opt_defs)) + options_ordered.insert( + std::make_pair(def.value().short_option, def.index())); - // Go through the unique'd and alphabetically sorted vector of options, - // find the table entry for each option and write out the detailed help - // information for that option. + // Go through each option, find the table entry and write out the detailed + // help information for that option. bool first_option_printed = false; - for (auto pos : options_seen) { - i = pos.second; - // Print out the help information for this option. - + for (auto pos : options_ordered) { // Put a newline separation between arguments if (first_option_printed) strm.EOL(); else first_option_printed = true; - CommandArgumentType arg_type = opt_defs[i].argument_type; - - StreamString arg_name_str; - arg_name_str.Printf("<%s>", CommandObject::GetArgumentName(arg_type)); + OptionDefinition opt_def = opt_defs[pos.second]; strm.Indent(); - if (opt_defs[i].short_option && opt_defs[i].HasShortOption()) { - PrintOption(opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, + if (opt_def.short_option && opt_def.HasShortOption()) { + PrintOption(opt_def, eDisplayShortOption, nullptr, nullptr, false, strm); - PrintOption(opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); + PrintOption(opt_def, eDisplayLongOption, " ( ", " )", false, strm); } else { // Short option is not printable, just print long option - PrintOption(opt_defs[i], eDisplayLongOption, nullptr, nullptr, false, - strm); + PrintOption(opt_def, eDisplayLongOption, nullptr, nullptr, false, strm); } strm.EOL(); strm.IndentMore(5); - if (opt_defs[i].usage_text) - OutputFormattedUsageText(strm, opt_defs[i], screen_width); - if (!opt_defs[i].enum_values.empty()) { + if (opt_def.usage_text) + OutputFormattedUsageText(strm, opt_def, screen_width); + if (!opt_def.enum_values.empty()) { strm.Indent(); strm.Printf("Values: "); bool is_first = true; - for (const auto &enum_value : opt_defs[i].enum_values) { + for (const auto &enum_value : opt_def.enum_values) { if (is_first) { strm.Printf("%s", enum_value.string_value); is_first = false; diff --git a/lldb/source/Interpreter/Property.cpp b/lldb/source/Interpreter/Property.cpp index fe3a8a31394b..681596224d31 100644 --- a/lldb/source/Interpreter/Property.cpp +++ b/lldb/source/Interpreter/Property.cpp @@ -68,9 +68,10 @@ Property::Property(const PropertyDefinition &definition) } case OptionValue::eTypeDictionary: // "definition.default_uint_value" is always a OptionValue::Type - m_value_sp = - std::make_shared<OptionValueDictionary>(OptionValue::ConvertTypeToMask( - (OptionValue::Type)definition.default_uint_value)); + m_value_sp = std::make_shared<OptionValueDictionary>( + OptionValue::ConvertTypeToMask( + (OptionValue::Type)definition.default_uint_value), + definition.enum_values); break; case OptionValue::eTypeEnum: diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index fbdcbb8da868..bc8a542afc87 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -109,13 +109,13 @@ ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { Status ScriptInterpreter::SetBreakpointCommandCallback( std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec, const char *callback_text) { - Status return_error; + Status error; for (BreakpointOptions &bp_options : bp_options_vec) { - return_error = SetBreakpointCommandCallback(bp_options, callback_text); - if (return_error.Success()) + error = SetBreakpointCommandCallback(bp_options, callback_text); + if (!error.Success()) break; } - return return_error; + return error; } Status ScriptInterpreter::SetBreakpointCommandCallbackFunction( diff --git a/lldb/source/Interpreter/embedded_interpreter.py b/lldb/source/Interpreter/embedded_interpreter.py index 9312dbfaca4e..fd2cc06bc286 100644 --- a/lldb/source/Interpreter/embedded_interpreter.py +++ b/lldb/source/Interpreter/embedded_interpreter.py @@ -1,4 +1,4 @@ -import sys +import sys if sys.version_info[0] < 3: import __builtin__ as builtins else: @@ -23,36 +23,6 @@ else: else: readline.parse_and_bind('tab: complete') -g_builtin_override_called = False - - -class LLDBQuitter(object): - - def __init__(self, name): - self.name = name - - def __repr__(self): - self() - - def __call__(self, code=None): - global g_builtin_override_called - g_builtin_override_called = True - raise SystemExit(-1) - - -def setquit(): - '''Redefine builtin functions 'quit()' and 'exit()' to print a message and raise an EOFError exception.''' - # This function will be called prior to each interactive - # interpreter loop or each single line, so we set the global - # g_builtin_override_called to False so we know if a SystemExit - # is thrown, we can catch it and tell the difference between - # a call to "quit()" or "exit()" and something like - # "sys.exit(123)" - global g_builtin_override_called - g_builtin_override_called = False - builtins.quit = LLDBQuitter('quit') - builtins.exit = LLDBQuitter('exit') - # When running one line, we might place the string to run in this string # in case it would be hard to correctly escape a string's contents @@ -70,6 +40,22 @@ def get_terminal_size(fd): return hw +class LLDBExit(SystemExit): + pass + + +def strip_and_check_exit(line): + line = line.rstrip() + if line in ('exit', 'quit'): + raise LLDBExit + return line + + +def readfunc(prompt): + line = input(prompt) + return strip_and_check_exit(line) + + def readfunc_stdio(prompt): sys.stdout.write(prompt) sys.stdout.flush() @@ -78,12 +64,11 @@ def readfunc_stdio(prompt): # ends with an incomplete line. An empty line indicates EOF. if not line: raise EOFError - return line.rstrip() + return strip_and_check_exit(line) def run_python_interpreter(local_dict): # Pass in the dictionary, for continuity from one session to the next. - setquit() try: fd = sys.stdin.fileno() interacted = False @@ -116,24 +101,30 @@ def run_python_interpreter(local_dict): # We have a real interactive terminal code.interact( banner="Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.", + readfunc=readfunc, local=local_dict) + except LLDBExit: + pass except SystemExit as e: - global g_builtin_override_called - if not g_builtin_override_called: - print('Script exited with %s' % (e)) + if e.code: + print('Script exited with code %s' % e.code) def run_one_line(local_dict, input_string): global g_run_one_line_str - setquit() try: + input_string = strip_and_check_exit(input_string) repl = code.InteractiveConsole(local_dict) if input_string: + # A newline is appended to support one-line statements containing + # control flow. For example "if True: print(1)" silently does + # nothing, but works with a newline: "if True: print(1)\n". + input_string += "\n" repl.runsource(input_string) elif g_run_one_line_str: repl.runsource(g_run_one_line_str) - + except LLDBExit: + pass except SystemExit as e: - global g_builtin_override_called - if not g_builtin_override_called: - print('Script exited with %s' % (e)) + if e.code: + print('Script exited with code %s' % e.code) |
