Skip to content

Commit 7f026ca

Browse files
committed
[lldb] Add --gdb-format flag to dwim-print
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 (cherry picked from commit d160873)
1 parent f761a3a commit 7f026ca

File tree

3 files changed

+96
-23
lines changed

3 files changed

+96
-23
lines changed

lldb/source/Commands/CommandObjectDWIMPrint.cpp

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,19 @@
99
#include "CommandObjectDWIMPrint.h"
1010

1111
#include "lldb/Core/ValueObject.h"
12+
#include "lldb/DataFormatters/DumpValueObjectOptions.h"
1213
#include "lldb/Interpreter/CommandInterpreter.h"
1314
#include "lldb/Interpreter/CommandObject.h"
1415
#include "lldb/Interpreter/CommandReturnObject.h"
16+
#include "lldb/Interpreter/OptionGroupFormat.h"
17+
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
1518
#include "lldb/Target/StackFrame.h"
1619
#include "lldb/Utility/ConstString.h"
20+
#include "lldb/lldb-defines.h"
1721
#include "lldb/lldb-enumerations.h"
1822
#include "lldb/lldb-forward.h"
23+
#include "llvm/ADT/StringRef.h"
24+
#include "llvm/Support/FormatVariadic.h"
1925

2026
using namespace llvm;
2127
using namespace lldb;
@@ -26,28 +32,49 @@ CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)
2632
"Print a variable or expression.",
2733
"dwim-print [<variable-name> | <expression>]",
2834
eCommandProcessMustBePaused | eCommandTryTargetAPILock) {
35+
m_option_group.Append(&m_format_options,
36+
OptionGroupFormat::OPTION_GROUP_FORMAT |
37+
OptionGroupFormat::OPTION_GROUP_GDB_FMT,
38+
LLDB_OPT_SET_1);
39+
m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
40+
m_option_group.Finalize();
2941
}
3042

31-
bool CommandObjectDWIMPrint::DoExecute(StringRef expr,
43+
Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; }
44+
45+
bool CommandObjectDWIMPrint::DoExecute(StringRef command,
3246
CommandReturnObject &result) {
33-
// Ignore leading and trailing whitespace.
34-
expr = expr.trim();
47+
m_option_group.NotifyOptionParsingStarting(&m_exe_ctx);
48+
OptionsWithRaw args{command};
49+
StringRef expr = args.GetRawPart();
3550

36-
if (expr.empty()) {
51+
if (args.HasArgs()) {
52+
if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
53+
m_exe_ctx))
54+
return false;
55+
} else if (command.empty()) {
3756
result.AppendErrorWithFormatv("'{0}' takes a variable or expression",
3857
m_cmd_name);
3958
return false;
4059
}
41-
4260
auto verbosity = GetDebugger().GetDWIMPrintVerbosity();
4361

62+
DumpValueObjectOptions dump_options = m_varobj_options.GetAsDumpOptions(
63+
eLanguageRuntimeDescriptionDisplayVerbosityFull,
64+
m_format_options.GetFormat());
65+
4466
// First, try `expr` as the name of a frame variable.
4567
if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
4668
auto valobj_sp = frame->FindVariable(ConstString(expr));
4769
if (valobj_sp && valobj_sp->GetError().Success()) {
48-
if (verbosity == eDWIMPrintVerbosityFull)
49-
result.AppendMessageWithFormatv("note: ran `frame variable {0}`", expr);
50-
valobj_sp->Dump(result.GetOutputStream());
70+
if (verbosity == eDWIMPrintVerbosityFull) {
71+
StringRef flags;
72+
if (args.HasArgs())
73+
flags = args.GetArgString();
74+
result.AppendMessageWithFormatv("note: ran `frame variable {0}{1}`",
75+
flags, expr);
76+
}
77+
valobj_sp->Dump(result.GetOutputStream(), dump_options);
5178
result.SetStatus(eReturnStatusSuccessFinishResult);
5279
return true;
5380
}
@@ -63,9 +90,14 @@ bool CommandObjectDWIMPrint::DoExecute(StringRef expr,
6390
ValueObjectSP valobj_sp;
6491
if (target.EvaluateExpression(expr, exe_scope, valobj_sp) ==
6592
eExpressionCompleted) {
66-
if (verbosity != eDWIMPrintVerbosityNone)
67-
result.AppendMessageWithFormatv("note: ran `expression -- {0}`", expr);
68-
valobj_sp->Dump(result.GetOutputStream());
93+
if (verbosity != eDWIMPrintVerbosityNone) {
94+
StringRef flags;
95+
if (args.HasArgs())
96+
flags = args.GetArgStringWithDelimiter();
97+
result.AppendMessageWithFormatv("note: ran `expression {0}{1}`", flags,
98+
expr);
99+
}
100+
valobj_sp->Dump(result.GetOutputStream(), dump_options);
69101
result.SetStatus(eReturnStatusSuccessFinishResult);
70102
return true;
71103
} else {

lldb/source/Commands/CommandObjectDWIMPrint.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTDWIMPRINT_H
1111

1212
#include "lldb/Interpreter/CommandObject.h"
13+
#include "lldb/Interpreter/OptionGroupFormat.h"
14+
#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
15+
#include "lldb/Interpreter/OptionValueFormat.h"
1316

1417
namespace lldb_private {
1518

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

3235
~CommandObjectDWIMPrint() override = default;
3336

37+
Options *GetOptions() override;
38+
3439
private:
3540
bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override;
41+
42+
OptionGroupOptions m_option_group;
43+
OptionGroupFormat m_format_options = lldb::eFormatDefault;
44+
OptionGroupValueObjectDisplay m_varobj_options;
3645
};
3746

3847
} // namespace lldb_private

lldb/test/API/commands/dwim-print/TestDWIMPrint.py

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,47 +27,79 @@ def _mask_persistent_var(self, string: str) -> str:
2727
before, after = self.PERSISTENT_VAR.split(string, maxsplit=1)
2828
return re.escape(before) + r"\$\d+" + re.escape(after)
2929

30-
def _expect_cmd(self, expr: str, base_cmd: str) -> None:
30+
def _expect_cmd(
31+
self,
32+
dwim_cmd: str,
33+
actual_cmd: str,
34+
) -> None:
3135
"""Run dwim-print and verify the output against the expected command."""
32-
cmd = f"{base_cmd} {expr}"
33-
cmd_output = self._run_cmd(cmd)
36+
# Resolve the dwim-print command to either `expression` or `frame variable`.
37+
substitute_cmd = dwim_cmd.replace("dwim-print", actual_cmd, 1)
38+
interp = self.dbg.GetCommandInterpreter()
39+
result = lldb.SBCommandReturnObject()
40+
interp.ResolveCommand(substitute_cmd, result)
41+
self.assertTrue(result.Succeeded(), result.GetError())
42+
43+
resolved_cmd = result.GetOutput()
44+
if actual_cmd == "frame variable":
45+
resolved_cmd = resolved_cmd.replace(" -- ", " ", 1)
46+
47+
expected_output = self._run_cmd(resolved_cmd)
3448

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

40-
if base_cmd == "expression --" and self.PERSISTENT_VAR.search(cmd_output):
41-
patterns.append(self._mask_persistent_var(cmd_output))
54+
if actual_cmd == "expression" and self.PERSISTENT_VAR.search(expected_output):
55+
patterns.append(self._mask_persistent_var(expected_output))
4256
else:
43-
substrs.append(cmd_output)
57+
substrs.append(expected_output)
4458

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

4761
def test_variables(self):
4862
"""Test dwim-print with variables."""
4963
self.build()
5064
lldbutil.run_to_name_breakpoint(self, "main")
5165
vars = ("argc", "argv")
5266
for var in vars:
53-
self._expect_cmd(var, "frame variable")
67+
self._expect_cmd(f"dwim-print {var}", "frame variable")
5468

5569
def test_variable_paths(self):
5670
"""Test dwim-print with variable path expressions."""
5771
self.build()
5872
lldbutil.run_to_name_breakpoint(self, "main")
5973
exprs = ("&argc", "*argv", "argv[0]")
6074
for expr in exprs:
61-
self._expect_cmd(expr, "expression --")
75+
self._expect_cmd(f"dwim-print {expr}", "expression")
6276

6377
def test_expressions(self):
6478
"""Test dwim-print with expressions."""
6579
self.build()
6680
lldbutil.run_to_name_breakpoint(self, "main")
6781
exprs = ("argc + 1", "(void)argc", "(int)abs(argc)")
6882
for expr in exprs:
69-
self._expect_cmd(expr, "expression --")
83+
self._expect_cmd(f"dwim-print {expr}", "expression")
7084

7185
def test_dummy_target_expressions(self):
7286
"""Test dwim-print's ability to evaluate expressions without a target."""
73-
self._expect_cmd("1 + 2", "expression --")
87+
self._expect_cmd("dwim-print 1 + 2", "expression")
88+
89+
def test_gdb_format(self):
90+
self.build()
91+
lldbutil.run_to_name_breakpoint(self, "main")
92+
self._expect_cmd(f"dwim-print/x argc", "frame variable")
93+
self._expect_cmd(f"dwim-print/x argc + 1", "expression")
94+
95+
def test_format_flags(self):
96+
self.build()
97+
lldbutil.run_to_name_breakpoint(self, "main")
98+
self._expect_cmd(f"dwim-print -fx -- argc", "frame variable")
99+
self._expect_cmd(f"dwim-print -fx -- argc + 1", "expression")
100+
101+
def test_display_flags(self):
102+
self.build()
103+
lldbutil.run_to_name_breakpoint(self, "main")
104+
self._expect_cmd(f"dwim-print -T -- argc", "frame variable")
105+
self._expect_cmd(f"dwim-print -T -- argc + 1", "expression")

0 commit comments

Comments
 (0)