Open tmandry opened 4 years ago
Another missing piece: Debuggers need the ability to identify the local variable currently being awaited. This could be as simple as a special symbol name (something that can't be spelled in normal Rust, like $awaitee
). And/or maybe there's a special designation we can make on the local in DWARF.
My understanding from this thread is that if using Apple's libdispatch as an executor, it's possible to encode the dispatch stack trace as part of the executor. This could be useful for macOS/iOS, albeit a bit specific. Though probably not quite as good or general-purpose a DWARF approach would be.
On Windows I've found that MSVC provides a built-in way to debug multi-threaded code (ref). If we can find out which symbols they're using to instrument their libraries, perhaps we can employ the same mechanism for our builds too. I would imagine this one to be a bit more similar to the DWARF proposal.
It would be nice if debuggers supported printing a backtrace of await points within an async stack machine. In particular, if I have a reference to an async task, my debugger should be able to read the state of all (nested) generators compiled into that object, and turn that into something that looks like a stack trace (except, of course, there is no actual stack).
See #73522 for a more general discussion of debugger support for async/await.
Prior art
Javascript has async stack traces, but AIUI, it is really solving a different problem. In Javascript, awaiting something is the equivalent of spawning an async task in Rust and then awaiting completion of that task: if you set and hit breakpoint inside an async function, you won't have any context on what's calling that function from a "normal" stack backtrace.
This is not the case for Rust: the stack trace from inside a poll function shows you all the futures that polled you inside your task. (However, such a technique would be useful for seeing across task boundaries.)
The problem we are really trying to solve in this issue is an external backtrace: I should be able to peer into the state of an async task that isn't running and inspect the "stack" of Futures in it (both async fns and hand-rolled futures, ideally).
Trees, not stacks
A complication with the backtrace analogy is that in general, we are dealing with trees of futures (think
select!()
), not stacks. This means that in addition to making sure the debugger has all the information it needs, we'll need to experiment with different ways of presenting that information in the various debugging environments. I hope some prior art will be informative here.Implementation history