handle synthetic frames produced by GDB FrameFilter without a level#1605
Conversation
|
To make sure I understand correctly, it isn't possible to evaluate anything in these frames without levels correct? If so, I would suggest a slightly different fix -- in |
|
I should have said: thanks for taking the time to send this in! |
|
Synthetic frames from the Python frame filter have no underlying debugger frame so GDB emits no level for them (the original crash), and they can never be selected via --frame N for the target of an MI command (-stack-list-variables, -stack-list-arguments, registers, etc). The only thing you can do with them is show the actively executing line in each one, and show them in the stack trace. Note that LLDB does not have this problem. LLDB synthetic frames get levels, and after llvm/llvm-project#178575 they should be able to render the frame variables as well without any further MIEngine patch (I need to update my LLDB and test). I've made the update as you suggested. As a result, querying a GDB synthetic async frame now returns 0 locals / 0 registers, rather than a neighboring real frame's data. Here's an example of the resulting display, with one of the synthetic async frames selected (no locals / no registers):
|
gregg-miskelly
left a comment
There was a problem hiding this comment.
Otherwise LGTM. Thanks for doing this!
There was a problem hiding this comment.
Pull request overview
This PR updates MIEngine’s callstack and expression-evaluation paths to tolerate GDB FrameFilter “synthetic” frames that omit the level field, avoiding stack-walk failures and guarding frame-relative MI commands (locals/args/registers/eval) when the frame is not addressable by level.
Changes:
- Make
ThreadContext.Levelnullable and update stack walking/parsing to allow frames withoutlevel. - Add defensive guards across locals/args/registers/expression evaluation paths when
Level == null. - Introduce a user-facing resource string for unsupported evaluation scenarios in non-level-bearing frames.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/MIDebugEngine/ResourceStrings.resx | Adds a new localized message for evaluation being unsupported in the current frame. |
| src/MIDebugEngine/ResourceStrings.Designer.cs | Adds the strongly-typed accessor for the new resource string. |
| src/MIDebugEngine/Natvis.Impl/VisualizationCache.cs | Avoids exceptions when a variable’s ThreadContext.Level is null (synthetic frames). |
| src/MIDebugEngine/Engine.Impl/Variables.cs | Blocks/short-circuits expression evaluation and assignment when Level == null; uses the new error string. |
| src/MIDebugEngine/Engine.Impl/Structures.cs | Makes ThreadContext.Level nullable and documents semantics of null levels for synthetic frames. |
| src/MIDebugEngine/Engine.Impl/DebuggedThread.cs | Parses stack frames using TryFindUint("level") to support missing level fields. |
| src/MIDebugEngine/Engine.Impl/DebuggedProcess.cs | Skips locals/args retrieval for frames without a level to avoid failing the full stack walk. |
| src/MIDebugEngine/AD7.Impl/AD7Thread.cs | Adjusts callstack argument querying logic to cope with synthetic frames / missing levels. |
| src/MIDebugEngine/AD7.Impl/AD7StackFrame.cs | Avoids register/eval MI calls for synthetic frames by guarding on Level == null. |
Files not reviewed (1)
- src/MIDebugEngine/ResourceStrings.Designer.cs: Generated file
gregg-miskelly
left a comment
There was a problem hiding this comment.
Sorry, Copilot noticed a few small changes that seem to be worth addressing. Please fix and I will merge this. Thanks again!
|
All should be addressed in the latest commit. |

Synthetic frames produced by GDB's FrameFilter, e.g. async stack backtraces for C++20 coroutines produced by a GDB script do not have a Level, and cannot be assigned a Level with the current version of GDB. Attempting to set a breakpoint inside of an async stack then causes an error when walking the synthetic backtrace:
This PR updates MIEngine’s callstack and expression-evaluation paths to tolerate GDB FrameFilter “synthetic” frames that omit the
levelfield, avoiding stack-walk failures and guarding frame-relative MI commands (locals/args/registers/eval) when the frame is not addressable by level.Changes:
ThreadContext.Levelnullable and update stack walking/parsing to allow frames withoutlevel.Level == null.