Skip to content

handle synthetic frames produced by GDB FrameFilter without a level#1605

Merged
gregg-miskelly merged 6 commits into
microsoft:mainfrom
tzcnt:missing_level_fix
Jul 11, 2026
Merged

handle synthetic frames produced by GDB FrameFilter without a level#1605
gregg-miskelly merged 6 commits into
microsoft:mainfrom
tzcnt:missing_level_fix

Conversation

@tzcnt

@tzcnt tzcnt commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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:

ERROR: Error while trying to enter break state. Debugging will now stop. Unrecognized format of field "level" in result: {addr=0x000055555555fef0,func=[async] main::$_0::operator()(unsigned long) const [clone .destroy],file=<file>,line=80,arch=i386:x86-64}

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.Level nullable and update stack walking/parsing to allow frames without level.
  • 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.

@gregg-miskelly

Copy link
Copy Markdown
Member

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 ThreadContext, make Level a uint? instead of a uint and then fixup the various spots that are checking the level to early out if Level is null.

@gregg-miskelly

Copy link
Copy Markdown
Member

I should have said: thanks for taking the time to send this in!

@tzcnt

tzcnt commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

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):

image

@tzcnt tzcnt force-pushed the missing_level_fix branch from d31a563 to 2ebc72d Compare July 9, 2026 15:21

@gregg-miskelly gregg-miskelly left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Otherwise LGTM. Thanks for doing this!

Comment thread src/MIDebugEngine/AD7.Impl/AD7Thread.cs Outdated
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs Outdated
@tzcnt tzcnt force-pushed the missing_level_fix branch from bea368d to 2a9193e Compare July 10, 2026 17:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.Level nullable and update stack walking/parsing to allow frames without level.
  • 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

Comment thread src/MIDebugEngine/Natvis.Impl/VisualizationCache.cs
Comment thread src/MIDebugEngine/AD7.Impl/AD7Thread.cs
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs
Comment thread src/MIDebugEngine/Engine.Impl/Variables.cs
Comment thread src/MIDebugEngine/AD7.Impl/AD7Thread.cs Outdated

@gregg-miskelly gregg-miskelly left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry, Copilot noticed a few small changes that seem to be worth addressing. Please fix and I will merge this. Thanks again!

@tzcnt

tzcnt commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

All should be addressed in the latest commit.

@gregg-miskelly gregg-miskelly merged commit ca8f423 into microsoft:main Jul 11, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants