Skip to content

Commit

Permalink
[lldb] Add --gdb-format flag to dwim-print
Browse files Browse the repository at this point in the history
Add support for the `--gdb-format`/`-G` flag to `dwim-print`.

The gdb-format flag allows users to alias `p` to `dwim-print`.

Differential Revision: https://reviews.llvm.org/D141425
  • Loading branch information
kastiglione committed Feb 9, 2023
1 parent c49941b commit d160873
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 23 deletions.
54 changes: 43 additions & 11 deletions lldb/source/Commands/CommandObjectDWIMPrint.cpp
Expand Up @@ -9,13 +9,19 @@
#include "CommandObjectDWIMPrint.h"

#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatVariadic.h"

using namespace llvm;
using namespace lldb;
Expand All @@ -26,28 +32,49 @@ CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)
"Print a variable or expression.",
"dwim-print [<variable-name> | <expression>]",
eCommandProcessMustBePaused | eCommandTryTargetAPILock) {
m_option_group.Append(&m_format_options,
OptionGroupFormat::OPTION_GROUP_FORMAT |
OptionGroupFormat::OPTION_GROUP_GDB_FMT,
LLDB_OPT_SET_1);
m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
m_option_group.Finalize();
}

bool CommandObjectDWIMPrint::DoExecute(StringRef expr,
Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; }

bool CommandObjectDWIMPrint::DoExecute(StringRef command,
CommandReturnObject &result) {
// Ignore leading and trailing whitespace.
expr = expr.trim();
m_option_group.NotifyOptionParsingStarting(&m_exe_ctx);
OptionsWithRaw args{command};
StringRef expr = args.GetRawPart();

if (expr.empty()) {
if (args.HasArgs()) {
if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
m_exe_ctx))
return false;
} else if (command.empty()) {
result.AppendErrorWithFormatv("'{0}' takes a variable or expression",
m_cmd_name);
return false;
}

auto verbosity = GetDebugger().GetDWIMPrintVerbosity();

DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions(
eLanguageRuntimeDescriptionDisplayVerbosityFull,
m_format_options.GetFormat());

// First, try `expr` as the name of a frame variable.
if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
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());
if (verbosity == eDWIMPrintVerbosityFull) {
StringRef flags;
if (args.HasArgs())
flags = args.GetArgString();
result.AppendMessageWithFormatv("note: ran `frame variable {0}{1}`",
flags, expr);
}
valobj_sp->Dump(result.GetOutputStream(), dump_options);
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
}
Expand All @@ -63,9 +90,14 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef expr,
ValueObjectSP valobj_sp;
if (target.EvaluateExpression(expr, exe_scope, valobj_sp) ==
eExpressionCompleted) {
if (verbosity != eDWIMPrintVerbosityNone)
result.AppendMessageWithFormatv("note: ran `expression -- {0}`", expr);
valobj_sp->Dump(result.GetOutputStream());
if (verbosity != eDWIMPrintVerbosityNone) {
StringRef flags;
if (args.HasArgs())
flags = args.GetArgStringWithDelimiter();
result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags,
expr);
}
valobj_sp->Dump(result.GetOutputStream(), dump_options);
result.SetStatus(eReturnStatusSuccessFinishResult);
return true;
} else {
Expand Down
9 changes: 9 additions & 0 deletions lldb/source/Commands/CommandObjectDWIMPrint.h
Expand Up @@ -10,6 +10,9 @@
#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H

#include "lldb/Interpreter/CommandObject.h"
#include "lldb/Interpreter/OptionGroupFormat.h"
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
#include "lldb/Interpreter/OptionValueFormat.h"

namespace lldb_private {

Expand All @@ -31,8 +34,14 @@ class CommandObjectDWIMPrint : public CommandObjectRaw {

~CommandObjectDWIMPrint() override = default;

Options *GetOptions() override;

private:
bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override;

OptionGroupOptions m_option_group;
OptionGroupFormat m_format_options = lldb::eFormatDefault;
OptionGroupValueObjectDisplay m_varobj_options;
};

} // namespace lldb_private
Expand Down
56 changes: 44 additions & 12 deletions lldb/test/API/commands/dwim-print/TestDWIMPrint.py
Expand Up @@ -27,47 +27,79 @@ def _mask_persistent_var(self, string: str) -> str:
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:
def _expect_cmd(
self,
dwim_cmd: str,
actual_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)
# Resolve the dwim-print command to either `expression` or `frame variable`.
substitute_cmd = dwim_cmd.replace("dwim-print", actual_cmd, 1)
interp = self.dbg.GetCommandInterpreter()
result = lldb.SBCommandReturnObject()
interp.ResolveCommand(substitute_cmd, result)
self.assertTrue(result.Succeeded(), result.GetError())

resolved_cmd = result.GetOutput()
if actual_cmd == "frame variable":
resolved_cmd = resolved_cmd.replace(" -- ", " ", 1)

expected_output = self._run_cmd(resolved_cmd)

# Verify dwim-print chose the expected command.
self.runCmd("settings set dwim-print-verbosity full")
substrs = [f"note: ran `{cmd}`"]
substrs = [f"note: ran `{resolved_cmd}`"]
patterns = []

if base_cmd == "expression --" and self.PERSISTENT_VAR.search(cmd_output):
patterns.append(self._mask_persistent_var(cmd_output))
if actual_cmd == "expression" and self.PERSISTENT_VAR.search(expected_output):
patterns.append(self._mask_persistent_var(expected_output))
else:
substrs.append(cmd_output)
substrs.append(expected_output)

self.expect(f"dwim-print {expr}", substrs=substrs, patterns=patterns)
self.expect(dwim_cmd, substrs=substrs, patterns=patterns)

def test_variables(self):
"""Test dwim-print with variables."""
self.build()
lldbutil.run_to_name_breakpoint(self, "main")
vars = ("argc", "argv")
for var in vars:
self._expect_cmd(var, "frame variable")
self._expect_cmd(f"dwim-print {var}", "frame variable")

def test_variable_paths(self):
"""Test dwim-print with variable path expressions."""
self.build()
lldbutil.run_to_name_breakpoint(self, "main")
exprs = ("&argc", "*argv", "argv[0]")
for expr in exprs:
self._expect_cmd(expr, "expression --")
self._expect_cmd(f"dwim-print {expr}", "expression")

def test_expressions(self):
"""Test dwim-print with expressions."""
self.build()
lldbutil.run_to_name_breakpoint(self, "main")
exprs = ("argc + 1", "(void)argc", "(int)abs(argc)")
for expr in exprs:
self._expect_cmd(expr, "expression --")
self._expect_cmd(f"dwim-print {expr}", "expression")

def test_dummy_target_expressions(self):
"""Test dwim-print's ability to evaluate expressions without a target."""
self._expect_cmd("1 + 2", "expression --")
self._expect_cmd("dwim-print 1 + 2", "expression")

def test_gdb_format(self):
self.build()
lldbutil.run_to_name_breakpoint(self, "main")
self._expect_cmd(f"dwim-print/x argc", "frame variable")
self._expect_cmd(f"dwim-print/x argc + 1", "expression")

def test_format_flags(self):
self.build()
lldbutil.run_to_name_breakpoint(self, "main")
self._expect_cmd(f"dwim-print -fx -- argc", "frame variable")
self._expect_cmd(f"dwim-print -fx -- argc + 1", "expression")

def test_display_flags(self):
self.build()
lldbutil.run_to_name_breakpoint(self, "main")
self._expect_cmd(f"dwim-print -T -- argc", "frame variable")
self._expect_cmd(f"dwim-print -T -- argc + 1", "expression")

0 comments on commit d160873

Please sign in to comment.