public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
From: Adrian Vogelsgesang <vogelsgesang@gmail.com>
To: gcc@gcc.gnu.org
Subject: RFC: Debug info for coroutine suspension locations
Date: Fri, 10 Oct 2025 04:16:55 +0200	[thread overview]
Message-ID: <CAB6OZBHVoqDyT+KD+x_u6mM96Brr82+1L0pSBy8y+d-wu2DZGA@mail.gmail.com> (raw)

Hi gcc-devs!

TLDR: For debugging C++ coroutines, I patched clang to emit artificial
DW_TAG_labels, mapping suspension point ids to the corresponding
source location. Looking for alignment re debugging info between clang
and gcc.

(Finally following up on Iain Sandoe's request to send this email)

~~~~~~~~~
Background
~~~~~~~~~

When using coroutines for asynchronous programming, the physical stack
only tells part of the truth. One also wants to see the chain of
"awaiting" coroutines, i.e. the coroutines which initiated the current
coroutine frame and are waiting for its completion.

I published a gdb debugger script which provides a FrameFilter to
inject those async stack frames. With this script, the `bt` command
now returns

> #0  write_output(...) at ...
> [async] greet() at ...
> [async] [noop_coroutine] at ...
> #1  coroutine_handle<task::promise_type>::resume() const at ...
> #2  task::syncStart() at ...

However, this script currently doesn't work for gcc-compiled binaries,
yet, due to missing debug information.

~~~~~~~~~
Current state of gcc-generated debug info
~~~~~~~~~

There are two reasons the script doesn't work for g++:
1. g++ does not emit a `__promise` variable inside the destroy
function - that can be worked around by changing the script, though
2. g++ provides no way to map the compiler-assigned suspension point
IDs back to line numbers - i.e., the topic of this email

In clang, I solved this issue by emitting DW_TAG labels like

> 0x00000f71:     DW_TAG_label
>                   DW_AT_name    ("__coro_resume_17")
>                   DW_AT_decl_file       ("generator-example.cpp")
>                   DW_AT_decl_line       (5)
>                   DW_AT_decl_column     (3)
>                   DW_AT_artificial      (true)
>                   DW_AT_LLVM_coro_suspend_idx   (0x11)
>                   DW_AT_low_pc  (0x00000000000019be)

The debugging script can lookup the DW_TAG_label for a given
suspension point either by name or via DW_AT_LLVM_coro_suspend_idx and
retrieve the line, column and address (for setting breakpoints) from
that label.

gcc emits similar information:

> 0x0000297c:     DW_TAG_label
>                  DW_AT_name    ("resume.17")
>
> 0x00002981:     DW_TAG_label
>                 DW_AT_name    ("destroy.17")

Unfortunately, this information is not useful because it lacks file,
line, column and address information. It would be great if g++ could
also emit file, line, column and address information for those labels.

~~~~~~~~~
Can gcc also emit useful DW_TAG debug information for coroutines?
~~~~~~~~~

What do you think about the approach of using DW_TAG_label for
debugging coroutines? Would you be willing to adopt the same approach
also for g++? (I would also be happy to adjust clang, in case we come
to a different alignment between both compilers).

Adding the file, line, column and address would probably be pretty
fundamental for a good debugging experience. Also it would be nice
(although completely optional) if we could use the same naming
convention (`__coro_resume_x`) and you might want to set the
DW_AT_artificial tag. I chose `__coro_resume_x` for clang, because
this is a reserved name which is still easily writeable in debugger
commands. Using the DW_AT_artificial for those labels also seems to
make semantically sense (although it is strictly speaking not blessed
by the DWARF standard).

~~~~~~~~~
Further Reading
~~~~~~~~~

RFC for LLVM/clang:
https://discourse.llvm.org/t/rfc-debug-info-for-coroutine-suspension-locations-take-2/86606

Corresponding clang commit: https://github.com/llvm/llvm-project/pull/141937

Background on debugging of coroutines, both from the user's point of
view and toolchain implementation details, such as the approach for
devirtualizing the coroutine frame's state:
https://clang.llvm.org/docs/DebuggingCoroutines.html

Best,
Adrian

             reply	other threads:[~2025-10-10  2:17 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-10  2:16 Adrian Vogelsgesang [this message]
2025-10-10  6:18 ` Iain Sandoe
2025-11-03 11:24   ` Adrian Vogelsgesang
2025-11-03 14:18     ` Jason Merrill
2025-11-03 15:53       ` Iain Sandoe
2025-11-03 21:47         ` Iain Sandoe
2025-11-10 22:34           ` Adrian Vogelsgesang
2025-11-10 23:04             ` Iain Sandoe
2025-11-03 20:36       ` Michael Welsh Duggan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAB6OZBHVoqDyT+KD+x_u6mM96Brr82+1L0pSBy8y+d-wu2DZGA@mail.gmail.com \
    --to=vogelsgesang@gmail.com \
    --cc=gcc@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).