Skip to content

[lldb] Update dwim-print to support limited variable expression paths #117452

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions lldb/source/Commands/CommandObjectDWIMPrint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,24 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
result.SetStatus(eReturnStatusSuccessFinishResult);
};

// First, try `expr` as the name of a frame variable.
if (frame) {
auto valobj_sp = frame->FindVariable(ConstString(expr));
if (valobj_sp && valobj_sp->GetError().Success()) {
// First, try `expr` as a _limited_ frame variable expression path: only the
// dot operator (`.`) is permitted for this case.
//
// This is limited to support only unambiguous expression paths. Of note,
// expression paths are not attempted if the expression contain either the
// arrow operator (`->`) or the subscript operator (`[]`). This is because
// both operators can be overloaded in C++, and could result in ambiguity in
// how the expression is handled. Additionally, `*` and `&` are not supported.
const bool try_variable_path =
expr.find_first_of("*&->[]") == StringRef::npos;
if (frame && try_variable_path) {
VariableSP var_sp;
Status status;
auto valobj_sp = frame->GetValueForVariableExpressionPath(
expr, eval_options.GetUseDynamic(),
StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp,
status);
if (valobj_sp && status.Success() && valobj_sp->GetError().Success()) {
if (!suppress_result) {
if (auto persisted_valobj = valobj_sp->Persist())
valobj_sp = persisted_valobj;
Expand Down
2 changes: 1 addition & 1 deletion lldb/test/API/commands/dwim-print/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
C_SOURCES := main.c
CXX_SOURCES := main.cpp

include Makefile.rules
43 changes: 36 additions & 7 deletions lldb/test/API/commands/dwim-print/TestDWIMPrint.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def _run_cmd(self, cmd: str) -> str:
self.ci.HandleCommand(cmd, result)
return result.GetOutput().rstrip()

VAR_IDENT = re.compile(r"(?:\$\d+|\w+) = ")
VAR_IDENT = re.compile(r"(?:\$\d+|[\w.]+) = ")

def _strip_result_var(self, string: str) -> str:
"""
Expand Down Expand Up @@ -121,30 +121,39 @@ def test_empty_expression(self):
def test_nested_values(self):
"""Test dwim-print with nested values (structs, etc)."""
self.build()
lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
self.runCmd("settings set auto-one-line-summaries false")
self._expect_cmd(f"dwim-print s", "frame variable")
self._expect_cmd(f"dwim-print (struct Structure)s", "expression")

def test_summary_strings(self):
"""Test dwim-print with nested values (structs, etc)."""
"""Test dwim-print with type summaries."""
self.build()
lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
self.runCmd("settings set auto-one-line-summaries false")
self.runCmd("type summary add -e -s 'stub summary' Structure")
self._expect_cmd(f"dwim-print s", "frame variable")
self._expect_cmd(f"dwim-print (struct Structure)s", "expression")
self.runCmd("type summary delete Structure")

def test_void_result(self):
"""Test dwim-print does not surface an error message for void expressions."""
self.build()
lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
self.expect("dwim-print (void)15", matching=False, patterns=["(?i)error"])

def test_preserves_persistent_variables(self):
"""Test dwim-print does not delete persistent variables."""
self.build()
lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
self.expect("dwim-print int $i = 15")
# Run the same expression twice and verify success. This ensures the
# first command does not delete the persistent variable.
Expand All @@ -154,5 +163,25 @@ def test_preserves_persistent_variables(self):
def test_missing_type(self):
"""The expected output of po opaque is its address (no error)"""
self.build()
lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
self.expect("dwim-print -O -- opaque", substrs=["0x"])

def test_variable_expression_path(self):
"""Test dwim-print supports certain variable expression paths."""
self.build()
lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.cpp")
)
self.runCmd("settings set auto-one-line-summaries false")
self._expect_cmd("dwim-print w.s", "frame variable")
self._expect_cmd("dwim-print wp->s", "expression")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also add cases for */[]/&? Or are those tested elsewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are tests for those in test_variable_paths


def test_direct_child_access(self):
"""Test dwim-print supports accessing members/ivars without qualification."""
self.build()
lldbutil.run_to_source_breakpoint(
self, "break inside", lldb.SBFileSpec("main.cpp")
)
self._expect_cmd("dwim-print number", "frame variable")
14 changes: 0 additions & 14 deletions lldb/test/API/commands/dwim-print/main.c

This file was deleted.

22 changes: 22 additions & 0 deletions lldb/test/API/commands/dwim-print/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
extern "C" int puts(const char *s);

struct Structure {
int number = 30;
void f() { puts("break inside"); }
};

struct Wrapper {
Structure s;
};

struct Opaque;

int main(int argc, char **argv) {
Structure s;
Wrapper w;
Wrapper *wp = &w;
Opaque *opaque = (Opaque *)(void *)&s;
puts("break here");
s.f();
return 0;
}
Loading