kastiglione updated this revision to Diff 476549.
kastiglione added a comment.
Add license.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D138315/new/
https://reviews.llvm.org/D138315
Files:
lldb/include/lldb/Core/Debugger.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/Commands/CMakeLists.txt
lldb/source/Commands/CommandObjectDWIMPrint.cpp
lldb/source/Commands/CommandObjectDWIMPrint.h
lldb/source/Core/CoreProperties.td
lldb/source/Core/Debugger.cpp
lldb/source/Interpreter/CommandInterpreter.cpp
lldb/test/API/commands/dwim-print/Makefile
lldb/test/API/commands/dwim-print/TestDWIMPrint.py
lldb/test/API/commands/dwim-print/main.c
Index: lldb/test/API/commands/dwim-print/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/commands/dwim-print/main.c
@@ -0,0 +1,3 @@
+int main(int argc, char **argv) {
+ return 0;
+}
Index: lldb/test/API/commands/dwim-print/TestDWIMPrint.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/dwim-print/TestDWIMPrint.py
@@ -0,0 +1,68 @@
+"""
+Test dwim-print with variables, variable paths, and expressions.
+"""
+
+import re
+import lldb
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test.decorators import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class TestCase(TestBase):
+ def setUp(self):
+ TestBase.setUp(self)
+ self.build()
+ lldbutil.run_to_name_breakpoint(self, "main")
+
+ def _run_cmd(self, cmd: str) -> str:
+ """Run the given lldb command and return its output."""
+ result = lldb.SBCommandReturnObject()
+ self.ci.HandleCommand(cmd, result)
+ return result.GetOutput().rstrip()
+
+ PERSISTENT_VAR = re.compile(r"\$\d+")
+
+ def _mask_persistent_var(self, string: str) -> str:
+ """
+ Replace persistent result variables (ex '$0', '$1', etc) with a regex
+ that matches any persistent result (r'\$\d+'). The returned string can
+ be matched against other `expression` results.
+ """
+ before, after = self.PERSISTENT_VAR.split(string, maxsplit=1)
+ return re.escape(before) + r"\$\d+" + re.escape(after)
+
+ def _expect_cmd(self, expr: str, base_cmd: str) -> None:
+ """Run dwim-print and verify the output against the expected command."""
+ cmd = f"{base_cmd} {expr}"
+ cmd_output = self._run_cmd(cmd)
+
+ # Verify dwim-print chose the expected command.
+ self.runCmd("settings set dwim-print-verbosity full")
+ substrs = [f"note: ran `{cmd}`"]
+ patterns = []
+
+ if base_cmd == "expression" and self.PERSISTENT_VAR.search(cmd_output):
+ patterns.append(self._mask_persistent_var(cmd_output))
+ else:
+ substrs.append(cmd_output)
+
+ self.expect(f"dwim-print {expr}", substrs=substrs, patterns=patterns)
+
+ def test_variables(self):
+ """Test dwim-print with variables."""
+ vars = ("argc", "argv")
+ for var in vars:
+ self._expect_cmd(var, "frame variable")
+
+ def test_variable_paths(self):
+ """Test dwim-print with variable path expressions."""
+ exprs = ("&argc", "*argv", "argv[0]")
+ for expr in exprs:
+ self._expect_cmd(expr, "expression")
+
+ def test_expressions(self):
+ """Test dwim-print with expressions."""
+ exprs = ("argc + 1", "(void)argc", "(int)abs(argc)")
+ for expr in exprs:
+ self._expect_cmd(expr, "expression")
Index: lldb/test/API/commands/dwim-print/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/commands/dwim-print/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/source/Interpreter/CommandInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/CommandInterpreter.cpp
+++ lldb/source/Interpreter/CommandInterpreter.cpp
@@ -15,6 +15,7 @@
#include "Commands/CommandObjectApropos.h"
#include "Commands/CommandObjectBreakpoint.h"
#include "Commands/CommandObjectCommands.h"
+#include "Commands/CommandObjectDWIMPrint.h"
#include "Commands/CommandObjectDiagnostics.h"
#include "Commands/CommandObjectDisassemble.h"
#include "Commands/CommandObjectExpression.h"
@@ -532,6 +533,7 @@
REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
+ REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
Index: lldb/source/Core/Debugger.cpp
===================================================================
--- lldb/source/Core/Debugger.cpp
+++ lldb/source/Core/Debugger.cpp
@@ -52,6 +52,7 @@
#include "lldb/Utility/State.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-enumerations.h"
#if defined(_WIN32)
#include "lldb/Host/windows/PosixApi.h"
@@ -149,6 +150,16 @@
},
};
+static constexpr OptionEnumValueElement g_dwim_print_verbosities[] = {
+ {eDWIMPrintVerbosityNone, "none",
+ "Use no verbosity when running dwim-print."},
+ {eDWIMPrintVerbosityExpression, "expression",
+ "Use partial verbosity when running dwim-print - display a message when "
+ "`expression` evaluation is used."},
+ {eDWIMPrintVerbosityFull, "full",
+ "Use full verbosity when running dwim-print."},
+};
+
static constexpr OptionEnumValueElement s_stop_show_column_values[] = {
{
eStopShowColumnAnsiOrCaret,
@@ -520,6 +531,13 @@
return m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, tab_size);
}
+lldb::DWIMPrintVerbosity Debugger::GetDWIMPrintVerbosity() const {
+ const uint32_t idx = ePropertyDWIMPrintVerbosity;
+ return (lldb::DWIMPrintVerbosity)
+ m_collection_sp->GetPropertyAtIndexAsEnumeration(
+ nullptr, idx, g_debugger_properties[idx].default_uint_value);
+}
+
#pragma mark Debugger
// const DebuggerPropertiesSP &
Index: lldb/source/Core/CoreProperties.td
===================================================================
--- lldb/source/Core/CoreProperties.td
+++ lldb/source/Core/CoreProperties.td
@@ -191,4 +191,9 @@
Global,
DefaultStringValue<"${ansi.normal}">,
Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">;
+ def DWIMPrintVerbosity: Property<"dwim-print-verbosity", "Enum">,
+ Global,
+ DefaultEnumValue<"eDWIMPrintVerbosityExpression">,
+ EnumValues<"OptionEnumValues(g_dwim_print_verbosities)">,
+ Desc<"The verbosity level used by dwim-print.">;
}
Index: lldb/source/Commands/CommandObjectDWIMPrint.h
===================================================================
--- /dev/null
+++ lldb/source/Commands/CommandObjectDWIMPrint.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectDWIMPrint.h --------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H
+#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H
+
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+/// Implements `dwim-print`, a printing command that chooses the most direct,
+/// efficient, and resilient means of printing a given expression.
+///
+/// DWIM is an acronym for Do What I Mean. From Wikipedia, DWIM is described as:
+///
+/// > attempt to anticipate what users intend to do, correcting trivial errors
+/// > automatically rather than blindly executing users' explicit but
+/// > potentially incorrect input
+///
+/// The `dwim-print` command serves as a single print command for users who
+/// don't yet know, or perfer not to know, the various lldb commands that can be
+/// used to print, and when to use them.
+class CommandObjectDWIMPrint : public CommandObjectRaw {
+public:
+ CommandObjectDWIMPrint(CommandInterpreter &interpreter);
+
+ ~CommandObjectDWIMPrint() override = default;
+
+private:
+ bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override;
+};
+
+} // namespace lldb_private
+
+#endif
Index: lldb/source/Commands/CommandObjectDWIMPrint.cpp
===================================================================
--- /dev/null
+++ lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -0,0 +1,76 @@
+#include "CommandObjectDWIMPrint.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "llvm/Analysis/ValueLattice.h"
+
+using namespace llvm;
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)
+ : CommandObjectRaw(
+ interpreter, "dwim-print", "Print a variable or expression.",
+ "dwim-print [<variable-name> | <expression>]",
+ eCommandProcessMustBePaused | eCommandTryTargetAPILock |
+ eCommandRequiresFrame | eCommandProcessMustBeLaunched |
+ eCommandRequiresProcess) {}
+
+bool CommandObjectDWIMPrint::DoExecute(StringRef expr,
+ CommandReturnObject &result) {
+ // Ignore leading and trailing whitespace.
+ expr = expr.trim();
+
+ if (expr.empty()) {
+ result.AppendErrorWithFormatv("'{0}' takes a variable or expression",
+ m_cmd_name);
+ return false;
+ }
+
+ // No need to check "frame" for validity as eCommandRequiresFrame ensures
+ // it is valid
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ auto verbosity = GetDebugger().GetDWIMPrintVerbosity();
+
+ // First, try `expr` as the name of a variable.
+ {
+ auto valobj_sp = frame->FindVariable(ConstString(expr));
+ if (valobj_sp && valobj_sp->GetError().Success()) {
+ if (verbosity == eDWIMPrintVerbosityFull)
+ result.AppendMessageWithFormatv("note: ran `frame variable {0}`", expr);
+ valobj_sp->Dump(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+
+ // Second, also lastly, try `expr` as a source expression to evaluate.
+ {
+ ExecutionContext exe_ctx = m_interpreter.GetExecutionContext();
+ Target *target_ptr = exe_ctx.GetTargetPtr();
+ Target &target = target_ptr ? *target_ptr : GetDummyTarget();
+
+ ValueObjectSP valobj_sp;
+ if (target.EvaluateExpression(expr, frame, valobj_sp) ==
+ eExpressionCompleted) {
+ if (verbosity != eDWIMPrintVerbosityNone)
+ result.AppendMessageWithFormatv("note: ran `expression {0}`", expr);
+ valobj_sp->Dump(result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ } else {
+ if (valobj_sp)
+ result.SetError(valobj_sp->GetError());
+ else
+ result.AppendErrorWithFormatv(
+ "unknown error evaluating expression `{0}`", expr);
+ return false;
+ }
+ }
+}
Index: lldb/source/Commands/CMakeLists.txt
===================================================================
--- lldb/source/Commands/CMakeLists.txt
+++ lldb/source/Commands/CMakeLists.txt
@@ -10,6 +10,7 @@
CommandObjectCommands.cpp
CommandObjectDiagnostics.cpp
CommandObjectDisassemble.cpp
+ CommandObjectDWIMPrint.cpp
CommandObjectExpression.cpp
CommandObjectFrame.cpp
CommandObjectGUI.cpp
Index: lldb/include/lldb/lldb-enumerations.h
===================================================================
--- lldb/include/lldb/lldb-enumerations.h
+++ lldb/include/lldb/lldb-enumerations.h
@@ -1203,6 +1203,16 @@
eTraceCursorSeekTypeEnd
};
+/// Enum to control the verbosity level of `dwim-print` execution.
+enum DWIMPrintVerbosity {
+ /// Run `dwim-print` with no verbosity.
+ eDWIMPrintVerbosityNone,
+ /// Print a message when `dwim-print` uses `expression` evaluation.
+ eDWIMPrintVerbosityExpression,
+ /// Always print a message indicating how `dwim-print` is evaluating its
+ /// expression.
+ eDWIMPrintVerbosityFull,
+};
} // namespace lldb
Index: lldb/include/lldb/Core/Debugger.h
===================================================================
--- lldb/include/lldb/Core/Debugger.h
+++ lldb/include/lldb/Core/Debugger.h
@@ -348,6 +348,8 @@
bool SetTabSize(uint32_t tab_size);
+ lldb::DWIMPrintVerbosity GetDWIMPrintVerbosity() const;
+
bool GetEscapeNonPrintables() const;
bool GetNotifyVoid() const;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits