Skip to content

[lldb] Make print delegate to synthetic frames.#178602

Closed
bzcheeseman wants to merge 1 commit intomainfrom
users/bzcheeseman/stack/7
Closed

[lldb] Make print delegate to synthetic frames.#178602
bzcheeseman wants to merge 1 commit intomainfrom
users/bzcheeseman/stack/7

Conversation

@bzcheeseman
Copy link
Contributor

@bzcheeseman bzcheeseman commented Jan 29, 2026

Stacked PRs:


[lldb] Make print delegate to synthetic frames.

This patch is more of a proposal in that it's a pretty dramatic change to the way that print works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier " or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from 67e37e2 to f6f858b Compare January 29, 2026 06:20
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@llvmbot llvmbot added the lldb label Jan 29, 2026
@llvmbot
Copy link
Member

llvmbot commented Jan 29, 2026

@llvm/pr-subscribers-lldb

Author: Aman LaChapelle (bzcheeseman)

Changes

Stacked PRs:

  • ->#178602
  • #178575
  • #178574
  • #178573

[lldb] Make print delegate to synthetic frames.

This patch is more of a proposal in that it's a pretty dramatic change to the way that print works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.


Full diff: https://github.com/llvm/llvm-project/pull/178602.diff

1 Files Affected:

  • (modified) lldb/source/Commands/CommandObjectDWIMPrint.cpp (+23-2)
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index 40f00c90bbbfb..68bb87221ed03 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -143,8 +143,7 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
       maybe_add_hint(output);
       result.GetOutputStream() << output;
     } else {
-      llvm::Error error =
-        valobj.Dump(result.GetOutputStream(), dump_options);
+      llvm::Error error = valobj.Dump(result.GetOutputStream(), dump_options);
       if (error) {
         result.AppendError(toString(std::move(error)));
         return;
@@ -155,6 +154,28 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command,
     result.SetStatus(eReturnStatusSuccessFinishResult);
   };
 
+  // If the frame is synthetic, then we handle all printing through the
+  // GetValueForVariableExpressionPath. This is so that the synthetic frame has
+  // the ability to take over anything it needs to.
+  if (frame && frame->IsSynthetic()) {
+    VariableSP var_sp;
+    Status status;
+    auto valobj_sp = frame->GetValueForVariableExpressionPath(
+        expr, eval_options.GetUseDynamic(),
+        StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, var_sp,
+        status);
+
+    // Something failed, print the error and return immediately.
+    if (!status.Success()) {
+      result.AppendError(status.AsCString());
+      return;
+    }
+
+    // Otherwise, simply print the object.
+    dump_val_object(*valobj_sp);
+    return;
+  }
+
   // First, try `expr` as a _limited_ frame variable expression path: only the
   // dot operator (`.`) is permitted for this case.
   //

@bzcheeseman bzcheeseman marked this pull request as draft January 29, 2026 16:31
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 29, 2026 16:31
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from f6f858b to 596163d Compare January 29, 2026 16:31
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 29, 2026 16:31
@bzcheeseman bzcheeseman marked this pull request as ready for review January 29, 2026 16:32
@bzcheeseman bzcheeseman marked this pull request as draft January 29, 2026 16:33
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 29, 2026 16:33
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from 596163d to ea2ba05 Compare January 29, 2026 16:33
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 29, 2026 16:33
@bzcheeseman bzcheeseman marked this pull request as ready for review January 29, 2026 16:33
@bzcheeseman bzcheeseman marked this pull request as draft January 29, 2026 18:30
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 29, 2026 18:30
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from ea2ba05 to a2fbf87 Compare January 29, 2026 18:30
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 29, 2026 18:30
@bzcheeseman bzcheeseman marked this pull request as ready for review January 29, 2026 18:30
@bzcheeseman bzcheeseman marked this pull request as draft January 29, 2026 19:53
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 29, 2026 19:53
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from 9c57d52 to d29da9f Compare January 29, 2026 19:53
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 29, 2026 19:54
@bzcheeseman bzcheeseman marked this pull request as ready for review January 29, 2026 19:54
@bzcheeseman bzcheeseman marked this pull request as draft January 29, 2026 19:58
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 29, 2026 19:58
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from d29da9f to ef725a4 Compare January 29, 2026 19:58
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 29, 2026 19:58
@bzcheeseman bzcheeseman marked this pull request as ready for review January 29, 2026 19:58
@bzcheeseman bzcheeseman marked this pull request as draft January 29, 2026 21:18
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 29, 2026 21:18
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from ef725a4 to 0cd04e7 Compare January 29, 2026 21:18
bzcheeseman added a commit that referenced this pull request Jan 29, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 29, 2026 21:18
@bzcheeseman bzcheeseman marked this pull request as ready for review January 29, 2026 21:18
@jimingham
Copy link
Collaborator

jimingham commented Jan 29, 2026

This doesn't seem like the right way to do this to me. What should be happening fundamentally is that when anybody asks "can you find the variable foo" for a synthetic frame, the frame's synthetic provider's variable list should be queried, rather than (or along with depending on what policy we're going to choose for access to synthetic variables) the "native" variable list from the frame. You would want that to work not just in dwim-print but anywhere that variables get looked up in a frame.

Once you've handed out the right root variable, the parsing of child nodes for an expression will happen naturally since that's just querying the root's type, so if you get the right root variable, you get the appropriate children. That shows that properly the task is "hand out the right variables from the frame when asked".

The one thing that dwim-print and expr should probably do is warn or error out if the user tries to running expressions in a frame with synthetic variables. Even that wouldn't be necessary if we take the extra step of materializing the synthetic values into the inferior when the frame makes them. But that's probably going to be tricky and seems like a "version 2" kind of effort. In the case of StackFrame::EvaluateExpression and expr you should be able to do this at the top of the command (except expr --top-level which explicitly forces a different scope). For dwim-print, you would error out if the frame var lookup failed and before it falls back to running expressions.

But note, if you said frame var (Foo *) synthesized_var_name with the new DIL support, you would first want the DIL parser to parse this to the point where it sees a name it has to ask for. If you handed out the right variable when the DIL asked for it by name, then the rest of this would all fall out naturally.

So while we probably want to put some "can't run expressions that have to run in the target in a frame with synthesized variables" warning when in a frame with synthesized variables, the actual lookup into the synthesized variables list needs to happen at a lower layer in the lookup.

@bzcheeseman bzcheeseman marked this pull request as draft January 30, 2026 01:53
@bzcheeseman bzcheeseman changed the base branch from users/bzcheeseman/stack/6 to main January 30, 2026 01:53
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from 0cd04e7 to b6e6837 Compare January 30, 2026 01:54
bzcheeseman added a commit that referenced this pull request Jan 30, 2026
This patch is more of a proposal in that it's a pretty dramatic change to the way that `print` works. It completely delegates getting values to the frame if the frame is synthetic, and does not redirect at all if the frame fails.

For this patch, the main goal was to allow the synthetic frame to bubble up its own errors in expression evaluation, rather than having errors come back with an extra "could not find identifier <blah>" or worse, simply get swallowed. If there's a better way to handle this, I'm more than happy to change this as long as the core goals of 'delegate variable/value extraction to the synthetic frame', and 'allow the synthetic frame to give back errors that are displayed to the user' can be met.

stack-info: PR: #178602, branch: users/bzcheeseman/stack/7
@bzcheeseman bzcheeseman changed the base branch from main to users/bzcheeseman/stack/6 January 30, 2026 01:54
@bzcheeseman bzcheeseman marked this pull request as ready for review January 30, 2026 01:54
Base automatically changed from users/bzcheeseman/stack/6 to main January 30, 2026 05:24
@bzcheeseman bzcheeseman force-pushed the users/bzcheeseman/stack/7 branch from b6e6837 to a9894b2 Compare January 30, 2026 05:24
@bzcheeseman
Copy link
Contributor Author

This doesn't seem like the right way to do this to me. What should be happening fundamentally is that when anybody asks "can you find the variable foo" for a synthetic frame, the frame's synthetic provider's variable list should be queried, rather than (or along with depending on what policy we're going to choose for access to synthetic variables) the "native" variable list from the frame. You would want that to work not just in dwim-print but anywhere that variables get looked up in a frame.

Yes that does seem much more correct. I think the issue I was running into was understanding where that change should be made!

Once you've handed out the right root variable, the parsing of child nodes for an expression will happen naturally since that's just querying the root's type, so if you get the right root variable, you get the appropriate children. That shows that properly the task is "hand out the right variables from the frame when asked".

That makes sense. I hope that works with Values as well, since we can't produce variables at this point 😅 My reading of the code is that you're right, it should, but I'm not as confident as I'd like to be.

The one thing that dwim-print and expr should probably do is warn or error out if the user tries to running expressions in a frame with synthetic variables. Even that wouldn't be necessary if we take the extra step of materializing the synthetic values into the inferior when the frame makes them. But that's probably going to be tricky and seems like a "version 2" kind of effort. In the case of StackFrame::EvaluateExpression and expr you should be able to do this at the top of the command (except expr --top-level which explicitly forces a different scope). For dwim-print, you would error out if the frame var lookup failed and before it falls back to running expressions.

Do you mean in the context of something like "I have provided a synthetic variable from my interpreter, and now I want to run an expression on it"? Wouldn't you just have the interpreter itself run that expression? Or not, I guess, depending on the thing being interpreted.

But note, if you said frame var (Foo *) synthesized_var_name with the new DIL support, you would first want the DIL parser to parse this to the point where it sees a name it has to ask for. If you handed out the right variable when the DIL asked for it by name, then the rest of this would all fall out naturally.

Sorry what's the DIL here? That sounds promising, but I don't know enough to evaluate. The main blocker I encountered was finding things/methods that required VariableSP (hard to create) vs ValueObjectSP (easy to create).

So while we probably want to put some "can't run expressions that have to run in the target in a frame with synthesized variables" warning when in a frame with synthesized variables, the actual lookup into the synthesized variables list needs to happen at a lower layer in the lookup.

Got it, makes sense. Do you have a sense for where something like that should be done? It kind of sounds like you're shooting for putting some of this stuff into the expression evaluation machinery? I'm happy to try and put some more time into it, I will just need your guidance :) I would also like to see if there's a good way for the plugin to propagate errors back up to the user through the print/expression evaluation.

In the meantime I'll close this PR since it sounds like, and I agree, there's a better way to do the thing I'm trying to do.

@github-actions github-actions bot deleted the users/bzcheeseman/stack/7 branch February 25, 2026 08:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants