https://github.com/python/cpython/commit/4d025a23188e0a8391cac16b264549b50af744ef
commit: 4d025a23188e0a8391cac16b264549b50af744ef
branch: 3.14
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: pablogsal <pablog...@gmail.com>
date: 2025-07-10T00:57:40+01:00
summary:

[3.14] gh-136476: Show the full stack in get_async_stack_trace in 
_remote_debugging (GH-136483) (#136490)

gh-136476: Show the full stack in get_async_stack_trace in _remote_debugging 
(GH-136483)
(cherry picked from commit ea45a2f97cb1d4774a6f88e63c6ce0a487f83031)

Co-authored-by: Pablo Galindo Salgado <pablog...@gmail.com>

files:
A Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst
M Lib/test/test_external_inspection.py
M Modules/_remote_debugging_module.c
M Modules/clinic/_remote_debugging_module.c.h

diff --git a/Lib/test/test_external_inspection.py 
b/Lib/test/test_external_inspection.py
index 44890ebfe5f76d..a709b837161f48 100644
--- a/Lib/test/test_external_inspection.py
+++ b/Lib/test/test_external_inspection.py
@@ -8,7 +8,12 @@
 import time
 from asyncio import staggered, taskgroups, base_events, tasks
 from unittest.mock import ANY
-from test.support import os_helper, SHORT_TIMEOUT, busy_retry, 
requires_gil_enabled
+from test.support import (
+    os_helper,
+    SHORT_TIMEOUT,
+    busy_retry,
+    requires_gil_enabled,
+)
 from test.support.script_helper import make_script
 from test.support.socket_helper import find_unused_port
 
@@ -236,55 +241,162 @@ def new_eager_loop():
                     p.terminate()
                     p.wait(timeout=SHORT_TIMEOUT)
 
-                # sets are unordered, so we want to sort "awaited_by"s
-                stack_trace[2].sort(key=lambda x: x[1])
+                # First check all the tasks are present
+                tasks_names = [
+                    task.task_name for task in stack_trace[0].awaited_by
+                ]
+                for task_name in ["c2_root", "sub_main_1", "sub_main_2"]:
+                    self.assertIn(task_name, tasks_names)
+
+                # Now ensure that the awaited_by_relationships are correct
+                id_to_task = {
+                    task.task_id: task for task in stack_trace[0].awaited_by
+                }
+                task_name_to_awaited_by = {
+                    task.task_name: set(
+                        id_to_task[awaited.task_name].task_name
+                        for awaited in task.awaited_by
+                    )
+                    for task in stack_trace[0].awaited_by
+                }
+                self.assertEqual(
+                    task_name_to_awaited_by,
+                    {
+                        "c2_root": {"Task-1", "sub_main_1", "sub_main_2"},
+                        "Task-1": set(),
+                        "sub_main_1": {"Task-1"},
+                        "sub_main_2": {"Task-1"},
+                    },
+                )
 
-                expected_stack_trace = [
-                    [
-                        FrameInfo([script_name, 10, "c5"]),
-                        FrameInfo([script_name, 14, "c4"]),
-                        FrameInfo([script_name, 17, "c3"]),
-                        FrameInfo([script_name, 20, "c2"]),
-                    ],
-                    "c2_root",
-                    [
-                        CoroInfo(
-                            [
-                                [
-                                    FrameInfo(
+                # Now ensure that the coroutine stacks are correct
+                coroutine_stacks = {
+                    task.task_name: sorted(
+                        tuple(tuple(frame) for frame in coro.call_stack)
+                        for coro in task.coroutine_stack
+                    )
+                    for task in stack_trace[0].awaited_by
+                }
+                self.assertEqual(
+                    coroutine_stacks,
+                    {
+                        "Task-1": [
+                            (
+                                tuple(
+                                    [
+                                        taskgroups.__file__,
+                                        ANY,
+                                        "TaskGroup._aexit",
+                                    ]
+                                ),
+                                tuple(
+                                    [
+                                        taskgroups.__file__,
+                                        ANY,
+                                        "TaskGroup.__aexit__",
+                                    ]
+                                ),
+                                tuple([script_name, 26, "main"]),
+                            )
+                        ],
+                        "c2_root": [
+                            (
+                                tuple([script_name, 10, "c5"]),
+                                tuple([script_name, 14, "c4"]),
+                                tuple([script_name, 17, "c3"]),
+                                tuple([script_name, 20, "c2"]),
+                            )
+                        ],
+                        "sub_main_1": [(tuple([script_name, 23, "c1"]),)],
+                        "sub_main_2": [(tuple([script_name, 23, "c1"]),)],
+                    },
+                )
+
+                # Now ensure the coroutine stacks for the awaited_by 
relationships are correct.
+                awaited_by_coroutine_stacks = {
+                    task.task_name: sorted(
+                        (
+                            id_to_task[coro.task_name].task_name,
+                            tuple(tuple(frame) for frame in coro.call_stack),
+                        )
+                        for coro in task.awaited_by
+                    )
+                    for task in stack_trace[0].awaited_by
+                }
+                self.assertEqual(
+                    awaited_by_coroutine_stacks,
+                    {
+                        "Task-1": [],
+                        "c2_root": [
+                            (
+                                "Task-1",
+                                (
+                                    tuple(
                                         [
                                             taskgroups.__file__,
                                             ANY,
                                             "TaskGroup._aexit",
                                         ]
                                     ),
-                                    FrameInfo(
+                                    tuple(
                                         [
                                             taskgroups.__file__,
                                             ANY,
                                             "TaskGroup.__aexit__",
                                         ]
                                     ),
-                                    FrameInfo([script_name, 26, "main"]),
-                                ],
+                                    tuple([script_name, 26, "main"]),
+                                ),
+                            ),
+                            ("sub_main_1", (tuple([script_name, 23, "c1"]),)),
+                            ("sub_main_2", (tuple([script_name, 23, "c1"]),)),
+                        ],
+                        "sub_main_1": [
+                            (
                                 "Task-1",
-                            ]
-                        ),
-                        CoroInfo(
-                            [
-                                [FrameInfo([script_name, 23, "c1"])],
-                                "sub_main_1",
-                            ]
-                        ),
-                        CoroInfo(
-                            [
-                                [FrameInfo([script_name, 23, "c1"])],
-                                "sub_main_2",
-                            ]
-                        ),
-                    ],
-                ]
-                self.assertEqual(stack_trace, expected_stack_trace)
+                                (
+                                    tuple(
+                                        [
+                                            taskgroups.__file__,
+                                            ANY,
+                                            "TaskGroup._aexit",
+                                        ]
+                                    ),
+                                    tuple(
+                                        [
+                                            taskgroups.__file__,
+                                            ANY,
+                                            "TaskGroup.__aexit__",
+                                        ]
+                                    ),
+                                    tuple([script_name, 26, "main"]),
+                                ),
+                            )
+                        ],
+                        "sub_main_2": [
+                            (
+                                "Task-1",
+                                (
+                                    tuple(
+                                        [
+                                            taskgroups.__file__,
+                                            ANY,
+                                            "TaskGroup._aexit",
+                                        ]
+                                    ),
+                                    tuple(
+                                        [
+                                            taskgroups.__file__,
+                                            ANY,
+                                            "TaskGroup.__aexit__",
+                                        ]
+                                    ),
+                                    tuple([script_name, 26, "main"]),
+                                ),
+                            )
+                        ],
+                    },
+                )
 
     @skip_if_not_supported
     @unittest.skipIf(
@@ -350,19 +462,29 @@ async def main():
                 p.terminate()
                 p.wait(timeout=SHORT_TIMEOUT)
 
-            # sets are unordered, so we want to sort "awaited_by"s
-            stack_trace[2].sort(key=lambda x: x[1])
-
-            expected_stack_trace = [
+            # For this simple asyncgen test, we only expect one task with the 
full coroutine stack
+            self.assertEqual(len(stack_trace[0].awaited_by), 1)
+            task = stack_trace[0].awaited_by[0]
+            self.assertEqual(task.task_name, "Task-1")
+
+            # Check the coroutine stack - based on actual output, only shows 
main
+            coroutine_stack = sorted(
+                tuple(tuple(frame) for frame in coro.call_stack)
+                for coro in task.coroutine_stack
+            )
+            self.assertEqual(
+                coroutine_stack,
                 [
-                    FrameInfo([script_name, 10, "gen_nested_call"]),
-                    FrameInfo([script_name, 16, "gen"]),
-                    FrameInfo([script_name, 19, "main"]),
+                    (
+                        tuple([script_name, 10, "gen_nested_call"]),
+                        tuple([script_name, 16, "gen"]),
+                        tuple([script_name, 19, "main"]),
+                    )
                 ],
-                "Task-1",
-                [],
-            ]
-            self.assertEqual(stack_trace, expected_stack_trace)
+            )
+
+            # No awaited_by relationships expected for this simple case
+            self.assertEqual(task.awaited_by, [])
 
     @skip_if_not_supported
     @unittest.skipIf(
@@ -429,18 +551,73 @@ async def main():
                 p.terminate()
                 p.wait(timeout=SHORT_TIMEOUT)
 
-            # sets are unordered, so we want to sort "awaited_by"s
-            stack_trace[2].sort(key=lambda x: x[1])
-
-            expected_stack_trace = [
-                [
-                    FrameInfo([script_name, 11, "deep"]),
-                    FrameInfo([script_name, 15, "c1"]),
-                ],
-                "Task-2",
-                [CoroInfo([[FrameInfo([script_name, 21, "main"])], "Task-1"])],
+            # First check all the tasks are present
+            tasks_names = [
+                task.task_name for task in stack_trace[0].awaited_by
             ]
-            self.assertEqual(stack_trace, expected_stack_trace)
+            for task_name in ["Task-1", "Task-2"]:
+                self.assertIn(task_name, tasks_names)
+
+            # Now ensure that the awaited_by_relationships are correct
+            id_to_task = {
+                task.task_id: task for task in stack_trace[0].awaited_by
+            }
+            task_name_to_awaited_by = {
+                task.task_name: set(
+                    id_to_task[awaited.task_name].task_name
+                    for awaited in task.awaited_by
+                )
+                for task in stack_trace[0].awaited_by
+            }
+            self.assertEqual(
+                task_name_to_awaited_by,
+                {
+                    "Task-1": set(),
+                    "Task-2": {"Task-1"},
+                },
+            )
+
+            # Now ensure that the coroutine stacks are correct
+            coroutine_stacks = {
+                task.task_name: sorted(
+                    tuple(tuple(frame) for frame in coro.call_stack)
+                    for coro in task.coroutine_stack
+                )
+                for task in stack_trace[0].awaited_by
+            }
+            self.assertEqual(
+                coroutine_stacks,
+                {
+                    "Task-1": [(tuple([script_name, 21, "main"]),)],
+                    "Task-2": [
+                        (
+                            tuple([script_name, 11, "deep"]),
+                            tuple([script_name, 15, "c1"]),
+                        )
+                    ],
+                },
+            )
+
+            # Now ensure the coroutine stacks for the awaited_by relationships 
are correct.
+            awaited_by_coroutine_stacks = {
+                task.task_name: sorted(
+                    (
+                        id_to_task[coro.task_name].task_name,
+                        tuple(tuple(frame) for frame in coro.call_stack),
+                    )
+                    for coro in task.awaited_by
+                )
+                for task in stack_trace[0].awaited_by
+            }
+            self.assertEqual(
+                awaited_by_coroutine_stacks,
+                {
+                    "Task-1": [],
+                    "Task-2": [
+                        ("Task-1", (tuple([script_name, 21, "main"]),))
+                    ],
+                },
+            )
 
     @skip_if_not_supported
     @unittest.skipIf(
@@ -510,36 +687,93 @@ async def main():
                 p.terminate()
                 p.wait(timeout=SHORT_TIMEOUT)
 
-            # sets are unordered, so we want to sort "awaited_by"s
-            stack_trace[2].sort(key=lambda x: x[1])
-            expected_stack_trace = [
-                [
-                    FrameInfo([script_name, 11, "deep"]),
-                    FrameInfo([script_name, 15, "c1"]),
-                    FrameInfo(
-                        [
-                            staggered.__file__,
-                            ANY,
-                            "staggered_race.<locals>.run_one_coro",
-                        ]
-                    ),
-                ],
-                "Task-2",
-                [
-                    CoroInfo(
-                        [
-                            [
-                                FrameInfo(
+            # First check all the tasks are present
+            tasks_names = [
+                task.task_name for task in stack_trace[0].awaited_by
+            ]
+            for task_name in ["Task-1", "Task-2"]:
+                self.assertIn(task_name, tasks_names)
+
+            # Now ensure that the awaited_by_relationships are correct
+            id_to_task = {
+                task.task_id: task for task in stack_trace[0].awaited_by
+            }
+            task_name_to_awaited_by = {
+                task.task_name: set(
+                    id_to_task[awaited.task_name].task_name
+                    for awaited in task.awaited_by
+                )
+                for task in stack_trace[0].awaited_by
+            }
+            self.assertEqual(
+                task_name_to_awaited_by,
+                {
+                    "Task-1": set(),
+                    "Task-2": {"Task-1"},
+                },
+            )
+
+            # Now ensure that the coroutine stacks are correct
+            coroutine_stacks = {
+                task.task_name: sorted(
+                    tuple(tuple(frame) for frame in coro.call_stack)
+                    for coro in task.coroutine_stack
+                )
+                for task in stack_trace[0].awaited_by
+            }
+            self.assertEqual(
+                coroutine_stacks,
+                {
+                    "Task-1": [
+                        (
+                            tuple([staggered.__file__, ANY, "staggered_race"]),
+                            tuple([script_name, 21, "main"]),
+                        )
+                    ],
+                    "Task-2": [
+                        (
+                            tuple([script_name, 11, "deep"]),
+                            tuple([script_name, 15, "c1"]),
+                            tuple(
+                                [
+                                    staggered.__file__,
+                                    ANY,
+                                    "staggered_race.<locals>.run_one_coro",
+                                ]
+                            ),
+                        )
+                    ],
+                },
+            )
+
+            # Now ensure the coroutine stacks for the awaited_by relationships 
are correct.
+            awaited_by_coroutine_stacks = {
+                task.task_name: sorted(
+                    (
+                        id_to_task[coro.task_name].task_name,
+                        tuple(tuple(frame) for frame in coro.call_stack),
+                    )
+                    for coro in task.awaited_by
+                )
+                for task in stack_trace[0].awaited_by
+            }
+            self.assertEqual(
+                awaited_by_coroutine_stacks,
+                {
+                    "Task-1": [],
+                    "Task-2": [
+                        (
+                            "Task-1",
+                            (
+                                tuple(
                                     [staggered.__file__, ANY, "staggered_race"]
                                 ),
-                                FrameInfo([script_name, 21, "main"]),
-                            ],
-                            "Task-1",
-                        ]
-                    )
-                ],
-            ]
-            self.assertEqual(stack_trace, expected_stack_trace)
+                                tuple([script_name, 21, "main"]),
+                            ),
+                        )
+                    ],
+                },
+            )
 
     @skip_if_not_supported
     @unittest.skipIf(
@@ -973,7 +1207,10 @@ def main_work():
                         if not stack:
                             continue
                         current_frame = stack[0]
-                        if current_frame.funcname == "main_work" and 
current_frame.lineno >15:
+                        if (
+                            current_frame.funcname == "main_work"
+                            and current_frame.lineno > 15
+                        ):
                             found = True
 
                     if found:
@@ -981,7 +1218,9 @@ def main_work():
                     # Give a bit of time to take the next sample
                     time.sleep(0.1)
                 else:
-                    self.fail("Main thread did not start its busy work on 
time")
+                    self.fail(
+                        "Main thread did not start its busy work on time"
+                    )
 
                 # Get stack trace with only GIL holder
                 unwinder_gil = RemoteUnwinder(p.pid, only_active_thread=True)
@@ -999,16 +1238,23 @@ def main_work():
                 p.wait(timeout=SHORT_TIMEOUT)
 
             # Verify we got multiple threads in all_traces
-            self.assertGreater(len(all_traces), 1, "Should have multiple 
threads")
+            self.assertGreater(
+                len(all_traces), 1, "Should have multiple threads"
+            )
 
             # Verify we got exactly one thread in gil_traces
-            self.assertEqual(len(gil_traces), 1, "Should have exactly one GIL 
holder")
+            self.assertEqual(
+                len(gil_traces), 1, "Should have exactly one GIL holder"
+            )
 
             # The GIL holder should be in the all_traces list
             gil_thread_id = gil_traces[0][0]
             all_thread_ids = [trace[0] for trace in all_traces]
-            self.assertIn(gil_thread_id, all_thread_ids,
-                         "GIL holder should be among all threads")
+            self.assertIn(
+                gil_thread_id,
+                all_thread_ids,
+                "GIL holder should be among all threads",
+            )
 
 
 if __name__ == "__main__":
diff --git 
a/Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst 
b/Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst
new file mode 100644
index 00000000000000..7634bd3be9346d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-07-09-20-29-30.gh-issue-136476.HyLLzh.rst
@@ -0,0 +1,2 @@
+Fix a bug that was causing the ``get_async_stack_trace`` function to miss
+some frames in the stack trace.
diff --git a/Modules/_remote_debugging_module.c 
b/Modules/_remote_debugging_module.c
index 7b8d272e63b160..0dc797a9da82a0 100644
--- a/Modules/_remote_debugging_module.c
+++ b/Modules/_remote_debugging_module.c
@@ -257,20 +257,25 @@ is_frame_valid(
     uintptr_t code_object_addr
 );
 
-static int
-parse_tasks_in_set(
+typedef int (*thread_processor_func)(
     RemoteUnwinderObject *unwinder,
-    uintptr_t set_addr,
-    PyObject *awaited_by,
-    int recurse_task
+    uintptr_t thread_state_addr,
+    unsigned long tid,
+    void *context
+);
+
+typedef int (*set_entry_processor_func)(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t key_addr,
+    void *context
 );
 
+
 static int
 parse_task(
     RemoteUnwinderObject *unwinder,
     uintptr_t task_address,
-    PyObject *render_to,
-    int recurse_task
+    PyObject *render_to
 );
 
 static int
@@ -285,9 +290,27 @@ static int parse_frame_object(
     RemoteUnwinderObject *unwinder,
     PyObject** result,
     uintptr_t address,
+    uintptr_t* address_of_code_object,
     uintptr_t* previous_frame
 );
 
+static int
+parse_async_frame_chain(
+    RemoteUnwinderObject *unwinder,
+    PyObject *calls,
+    uintptr_t address_of_thread,
+    uintptr_t running_task_code_obj
+);
+
+static int read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, 
uintptr_t *ptr_addr);
+static int read_Py_ssize_t(RemoteUnwinderObject *unwinder, uintptr_t address, 
Py_ssize_t *size);
+
+static int process_task_and_waiters(RemoteUnwinderObject *unwinder, uintptr_t 
task_addr, PyObject *result);
+static int process_task_awaited_by(RemoteUnwinderObject *unwinder, uintptr_t 
task_address, set_entry_processor_func processor, void *context);
+static int find_running_task_in_thread(RemoteUnwinderObject *unwinder, 
uintptr_t thread_state_addr, uintptr_t *running_task_addr);
+static int get_task_code_object(RemoteUnwinderObject *unwinder, uintptr_t 
task_addr, uintptr_t *code_obj_addr);
+static int append_awaited_by(RemoteUnwinderObject *unwinder, unsigned long 
tid, uintptr_t head_addr, PyObject *result);
+
 /* ============================================================================
  * UTILITY FUNCTIONS AND HELPERS
  * 
============================================================================ */
@@ -405,32 +428,149 @@ validate_debug_offsets(struct _Py_DebugOffsets 
*debug_offsets)
     return 0;
 }
 
-/* ============================================================================
- * MEMORY READING FUNCTIONS
- * 
============================================================================ */
+// Generic function to iterate through all threads
+static int
+iterate_threads(
+    RemoteUnwinderObject *unwinder,
+    thread_processor_func processor,
+    void *context
+) {
+    uintptr_t thread_state_addr;
+    unsigned long tid = 0;
 
-static inline int
-read_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t 
*ptr_addr)
-{
-    int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, 
address, sizeof(void*), ptr_addr);
-    if (result < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
pointer from remote memory");
+    if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
+                &unwinder->handle,
+                unwinder->interpreter_addr + 
unwinder->debug_offsets.interpreter_state.threads_main,
+                sizeof(void*),
+                &thread_state_addr))
+    {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read main 
thread state");
         return -1;
     }
+
+    while (thread_state_addr != 0) {
+        if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
+                    &unwinder->handle,
+                    thread_state_addr + 
unwinder->debug_offsets.thread_state.native_thread_id,
+                    sizeof(tid),
+                    &tid))
+        {
+            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
thread ID");
+            return -1;
+        }
+
+        // Call the processor function for this thread
+        if (processor(unwinder, thread_state_addr, tid, context) < 0) {
+            return -1;
+        }
+
+        // Move to next thread
+        if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
+                    &unwinder->handle,
+                    thread_state_addr + 
unwinder->debug_offsets.thread_state.next,
+                    sizeof(void*),
+                    &thread_state_addr))
+        {
+            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
next thread state");
+            return -1;
+        }
+    }
+
     return 0;
 }
 
-static inline int
-read_Py_ssize_t(RemoteUnwinderObject *unwinder, uintptr_t address, Py_ssize_t 
*size)
-{
-    int result = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, 
address, sizeof(Py_ssize_t), size);
-    if (result < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
Py_ssize_t from remote memory");
+// Generic function to iterate through set entries
+static int
+iterate_set_entries(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t set_addr,
+    set_entry_processor_func processor,
+    void *context
+) {
+    char set_object[SIZEOF_SET_OBJ];
+    if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, set_addr,
+                                              SIZEOF_SET_OBJ, set_object) < 0) 
{
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set 
object");
         return -1;
     }
+
+    Py_ssize_t num_els = GET_MEMBER(Py_ssize_t, set_object, 
unwinder->debug_offsets.set_object.used);
+    Py_ssize_t set_len = GET_MEMBER(Py_ssize_t, set_object, 
unwinder->debug_offsets.set_object.mask) + 1;
+    uintptr_t table_ptr = GET_MEMBER(uintptr_t, set_object, 
unwinder->debug_offsets.set_object.table);
+
+    Py_ssize_t i = 0;
+    Py_ssize_t els = 0;
+    while (i < set_len && els < num_els) {
+        uintptr_t key_addr;
+        if (read_py_ptr(unwinder, table_ptr, &key_addr) < 0) {
+            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
set entry key");
+            return -1;
+        }
+
+        if ((void*)key_addr != NULL) {
+            Py_ssize_t ref_cnt;
+            if (read_Py_ssize_t(unwinder, table_ptr, &ref_cnt) < 0) {
+                set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
read set entry ref count");
+                return -1;
+            }
+
+            if (ref_cnt) {
+                // Process this valid set entry
+                if (processor(unwinder, key_addr, context) < 0) {
+                    return -1;
+                }
+                els++;
+            }
+        }
+        table_ptr += sizeof(void*) * 2;
+        i++;
+    }
+
     return 0;
 }
 
+// Processor function for task waiters
+static int
+process_waiter_task(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t key_addr,
+    void *context
+) {
+    PyObject *result = (PyObject *)context;
+    return process_task_and_waiters(unwinder, key_addr, result);
+}
+
+// Processor function for parsing tasks in sets
+static int
+process_task_parser(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t key_addr,
+    void *context
+) {
+    PyObject *awaited_by = (PyObject *)context;
+    return parse_task(unwinder, key_addr, awaited_by);
+}
+
+/* ============================================================================
+ * MEMORY READING FUNCTIONS
+ * 
============================================================================ */
+
+#define DEFINE_MEMORY_READER(type_name, c_type, error_msg) \
+static inline int \
+read_##type_name(RemoteUnwinderObject *unwinder, uintptr_t address, c_type 
*result) \
+{ \
+    int res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, 
address, sizeof(c_type), result); \
+    if (res < 0) { \
+        set_exception_cause(unwinder, PyExc_RuntimeError, error_msg); \
+        return -1; \
+    } \
+    return 0; \
+}
+
+DEFINE_MEMORY_READER(ptr, uintptr_t, "Failed to read pointer from remote 
memory")
+DEFINE_MEMORY_READER(Py_ssize_t, Py_ssize_t, "Failed to read Py_ssize_t from 
remote memory")
+DEFINE_MEMORY_READER(char, char, "Failed to read char from remote memory")
+
 static int
 read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t address, uintptr_t 
*ptr_addr)
 {
@@ -442,17 +582,6 @@ read_py_ptr(RemoteUnwinderObject *unwinder, uintptr_t 
address, uintptr_t *ptr_ad
     return 0;
 }
 
-static int
-read_char(RemoteUnwinderObject *unwinder, uintptr_t address, char *result)
-{
-    int res = _Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, 
address, sizeof(char), result);
-    if (res < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read char 
from remote memory");
-        return -1;
-    }
-    return 0;
-}
-
 /* ============================================================================
  * PYTHON OBJECT READING FUNCTIONS
  * 
============================================================================ */
@@ -799,39 +928,9 @@ parse_task_name(
 static int parse_task_awaited_by(
     RemoteUnwinderObject *unwinder,
     uintptr_t task_address,
-    PyObject *awaited_by,
-    int recurse_task
+    PyObject *awaited_by
 ) {
-    // Read the entire TaskObj at once
-    char task_obj[SIZEOF_TASK_OBJ];
-    if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address,
-                                              
unwinder->async_debug_offsets.asyncio_task_object.size,
-                                              task_obj) < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task 
object in awaited_by parsing");
-        return -1;
-    }
-
-    uintptr_t task_ab_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, 
unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by);
-
-    if ((void*)task_ab_addr == NULL) {
-        return 0;
-    }
-
-    char awaited_by_is_a_set = GET_MEMBER(char, task_obj, 
unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by_is_set);
-
-    if (awaited_by_is_a_set) {
-        if (parse_tasks_in_set(unwinder, task_ab_addr, awaited_by, 
recurse_task)) {
-            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
tasks in awaited_by set");
-            return -1;
-        }
-    } else {
-        if (parse_task(unwinder, task_ab_addr, awaited_by, recurse_task)) {
-            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
single awaited_by task");
-            return -1;
-        }
-    }
-
-    return 0;
+    return process_task_awaited_by(unwinder, task_address, 
process_task_parser, awaited_by);
 }
 
 static int
@@ -940,12 +1039,13 @@ parse_coro_chain(
     // Parse the previous frame using the gi_iframe from local copy
     uintptr_t prev_frame;
     uintptr_t gi_iframe_addr = coro_address + 
unwinder->debug_offsets.gen_object.gi_iframe;
-    if (parse_frame_object(unwinder, &name, gi_iframe_addr, &prev_frame) < 0) {
+    uintptr_t address_of_code_object = 0;
+    if (parse_frame_object(unwinder, &name, gi_iframe_addr, 
&address_of_code_object, &prev_frame) < 0) {
         set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
frame object in coro chain");
         return -1;
     }
 
-    if (name == NULL) {
+    if (!name) {
         return 0;
     }
 
@@ -966,8 +1066,7 @@ parse_coro_chain(
 static PyObject*
 create_task_result(
     RemoteUnwinderObject *unwinder,
-    uintptr_t task_address,
-    int recurse_task
+    uintptr_t task_address
 ) {
     PyObject* result = NULL;
     PyObject *call_stack = NULL;
@@ -983,11 +1082,7 @@ create_task_result(
     }
 
     // Create task name/address for second tuple element
-    if (recurse_task) {
-        tn = parse_task_name(unwinder, task_address);
-    } else {
-        tn = PyLong_FromUnsignedLongLong(task_address);
-    }
+    tn = PyLong_FromUnsignedLongLong(task_address);
     if (tn == NULL) {
         set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create 
task name/address");
         goto error;
@@ -1040,8 +1135,7 @@ static int
 parse_task(
     RemoteUnwinderObject *unwinder,
     uintptr_t task_address,
-    PyObject *render_to,
-    int recurse_task
+    PyObject *render_to
 ) {
     char is_task;
     PyObject* result = NULL;
@@ -1057,7 +1151,7 @@ parse_task(
     }
 
     if (is_task) {
-        result = create_task_result(unwinder, task_address, recurse_task);
+        result = create_task_result(unwinder, task_address);
         if (!result) {
             set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
create task result");
             goto error;
@@ -1084,11 +1178,11 @@ parse_task(
         PyStructSequence_SetItem(result, 0, empty_list);  // This steals the 
reference
         PyStructSequence_SetItem(result, 1, task_name);  // This steals the 
reference
     }
-
     if (PyList_Append(render_to, result)) {
         set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append 
task result to render list");
         goto error;
     }
+
     Py_DECREF(result);
     return 0;
 
@@ -1098,234 +1192,335 @@ parse_task(
 }
 
 static int
-process_set_entry(
+process_single_task_node(
     RemoteUnwinderObject *unwinder,
-    uintptr_t table_ptr,
-    PyObject *awaited_by,
-    int recurse_task
+    uintptr_t task_addr,
+    PyObject **task_info,
+    PyObject *result
 ) {
-    uintptr_t key_addr;
-    if (read_py_ptr(unwinder, table_ptr, &key_addr)) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set 
entry key");
-        return -1;
+    PyObject *tn = NULL;
+    PyObject *current_awaited_by = NULL;
+    PyObject *task_id = NULL;
+    PyObject *result_item = NULL;
+    PyObject *coroutine_stack = NULL;
+
+    tn = parse_task_name(unwinder, task_addr);
+    if (tn == NULL) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
task name in single task node");
+        goto error;
     }
 
-    if ((void*)key_addr != NULL) {
-        Py_ssize_t ref_cnt;
-        if (read_Py_ssize_t(unwinder, table_ptr, &ref_cnt)) {
-            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
set entry reference count");
-            return -1;
-        }
+    current_awaited_by = PyList_New(0);
+    if (current_awaited_by == NULL) {
+        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
awaited_by list in single task node");
+        goto error;
+    }
 
-        if (ref_cnt) {
-            // if 'ref_cnt=0' it's a set dummy marker
-            if (parse_task(unwinder, key_addr, awaited_by, recurse_task)) {
-                set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
parse task in set entry");
-                return -1;
-            }
-            return 1; // Successfully processed a valid entry
-        }
+    // Extract the coroutine stack for this task
+    coroutine_stack = PyList_New(0);
+    if (coroutine_stack == NULL) {
+        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
coroutine stack list in single task node");
+        goto error;
     }
-    return 0; // Entry was NULL or dummy marker
-}
 
-static int
-parse_tasks_in_set(
-    RemoteUnwinderObject *unwinder,
-    uintptr_t set_addr,
-    PyObject *awaited_by,
-    int recurse_task
-) {
-    char set_object[SIZEOF_SET_OBJ];
-    int err = _Py_RemoteDebug_PagedReadRemoteMemory(
-        &unwinder->handle,
-        set_addr,
-        SIZEOF_SET_OBJ,
-        set_object);
-    if (err < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read set 
object");
-        return -1;
+    if (parse_task(unwinder, task_addr, coroutine_stack) < 0) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
task coroutine stack in single task node");
+        goto error;
     }
 
-    Py_ssize_t num_els = GET_MEMBER(Py_ssize_t, set_object, 
unwinder->debug_offsets.set_object.used);
-    Py_ssize_t set_len = GET_MEMBER(Py_ssize_t, set_object, 
unwinder->debug_offsets.set_object.mask) + 1; // The set contains the `mask+1` 
element slots.
-    uintptr_t table_ptr = GET_MEMBER(uintptr_t, set_object, 
unwinder->debug_offsets.set_object.table);
+    task_id = PyLong_FromUnsignedLongLong(task_addr);
+    if (task_id == NULL) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create 
task ID in single task node");
+        goto error;
+    }
 
-    Py_ssize_t i = 0;
-    Py_ssize_t els = 0;
-    while (i < set_len && els < num_els) {
-        int result = process_set_entry(unwinder, table_ptr, awaited_by, 
recurse_task);
+    RemoteDebuggingState *state = 
RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+    result_item = PyStructSequence_New(state->TaskInfo_Type);
+    if (result_item == NULL) {
+        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
TaskInfo in single task node");
+        goto error;
+    }
 
-        if (result < 0) {
-            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
process set entry");
-            return -1;
-        }
-        if (result > 0) {
-            els++;
-        }
+    PyStructSequence_SetItem(result_item, 0, task_id);  // steals ref
+    PyStructSequence_SetItem(result_item, 1, tn);  // steals ref
+    PyStructSequence_SetItem(result_item, 2, coroutine_stack);  // steals ref
+    PyStructSequence_SetItem(result_item, 3, current_awaited_by);  // steals 
ref
 
-        table_ptr += sizeof(void*) * 2;
-        i++;
+    // References transferred to tuple
+    task_id = NULL;
+    tn = NULL;
+    coroutine_stack = NULL;
+    current_awaited_by = NULL;
+
+    if (PyList_Append(result, result_item)) {
+        Py_DECREF(result_item);
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append 
result item in single task node");
+        return -1;
+    }
+    if (task_info != NULL) {
+        *task_info = result_item;
+    }
+    Py_DECREF(result_item);
+
+    // Get back current_awaited_by reference for parse_task_awaited_by
+    current_awaited_by = PyStructSequence_GetItem(result_item, 3);
+    if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by) < 0) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
awaited_by in single task node");
+        // No cleanup needed here since all references were transferred to 
result_item
+        // and result_item was already added to result list and decreffed
+        return -1;
     }
+
     return 0;
+
+error:
+    Py_XDECREF(tn);
+    Py_XDECREF(current_awaited_by);
+    Py_XDECREF(task_id);
+    Py_XDECREF(result_item);
+    Py_XDECREF(coroutine_stack);
+    return -1;
 }
 
+// Thread processor for get_all_awaited_by
+static int
+process_thread_for_awaited_by(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t thread_state_addr,
+    unsigned long tid,
+    void *context
+) {
+    PyObject *result = (PyObject *)context;
+    uintptr_t head_addr = thread_state_addr + 
unwinder->async_debug_offsets.asyncio_thread_state.asyncio_tasks_head;
+    return append_awaited_by(unwinder, tid, head_addr, result);
+}
 
+// Generic function to process task awaited_by
 static int
-setup_async_result_structure(RemoteUnwinderObject *unwinder, PyObject 
**result, PyObject **calls)
-{
-    *result = PyList_New(1);
-    if (*result == NULL) {
-        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
async result structure");
+process_task_awaited_by(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t task_address,
+    set_entry_processor_func processor,
+    void *context
+) {
+    // Read the entire TaskObj at once
+    char task_obj[SIZEOF_TASK_OBJ];
+    if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address,
+                                              
unwinder->async_debug_offsets.asyncio_task_object.size,
+                                              task_obj) < 0) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read task 
object");
         return -1;
     }
 
-    *calls = PyList_New(0);
-    if (*calls == NULL) {
-        Py_DECREF(*result);
-        *result = NULL;
-        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
calls list in async result");
-        return -1;
+    uintptr_t task_ab_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, 
unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by);
+    if ((void*)task_ab_addr == NULL) {
+        return 0;  // No tasks waiting for this one
     }
 
-    if (PyList_SetItem(*result, 0, *calls)) { /* steals ref to 'calls' */
-        Py_DECREF(*calls);
-        Py_DECREF(*result);
-        *result = NULL;
-        *calls = NULL;
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to set calls 
list in async result");
-        return -1;
-    }
+    char awaited_by_is_a_set = GET_MEMBER(char, task_obj, 
unwinder->async_debug_offsets.asyncio_task_object.task_awaited_by_is_set);
 
-    return 0;
+    if (awaited_by_is_a_set) {
+        return iterate_set_entries(unwinder, task_ab_addr, processor, context);
+    } else {
+        // Single task waiting
+        return processor(unwinder, task_ab_addr, context);
+    }
 }
 
 static int
-add_task_info_to_result(
+process_running_task_chain(
     RemoteUnwinderObject *unwinder,
-    PyObject *result,
-    uintptr_t running_task_addr
+    uintptr_t running_task_addr,
+    uintptr_t thread_state_addr,
+    PyObject *result
 ) {
-    PyObject *tn = parse_task_name(unwinder, running_task_addr);
-    if (tn == NULL) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
task name for result");
+    uintptr_t running_task_code_obj = 0;
+    if(get_task_code_object(unwinder, running_task_addr, 
&running_task_code_obj) < 0) {
+        return -1;
+    }
+
+    // First, add this task to the result
+    PyObject *task_info = NULL;
+    if (process_single_task_node(unwinder, running_task_addr, &task_info, 
result) < 0) {
         return -1;
     }
 
-    if (PyList_Append(result, tn)) {
-        Py_DECREF(tn);
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append 
task name to result");
+    // Get the chain from the current frame to this task
+    PyObject *coro_chain = PyStructSequence_GET_ITEM(task_info, 2);
+    assert(coro_chain != NULL);
+    if (PyList_GET_SIZE(coro_chain) != 1) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Coro chain is not a 
single item");
         return -1;
     }
-    Py_DECREF(tn);
+    PyObject *coro_info = PyList_GET_ITEM(coro_chain, 0);
+    assert(coro_info != NULL);
+    PyObject *frame_chain = PyStructSequence_GET_ITEM(coro_info, 0);
+    assert(frame_chain != NULL);
 
-    PyObject* awaited_by = PyList_New(0);
-    if (awaited_by == NULL) {
-        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
awaited_by list for result");
+    // Clear the coro_chain
+    if (PyList_Clear(frame_chain) < 0) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to clear 
coroutine chain");
         return -1;
     }
 
-    if (PyList_Append(result, awaited_by)) {
-        Py_DECREF(awaited_by);
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append 
awaited_by to result");
+    // Add the chain from the current frame to this task
+    if (parse_async_frame_chain(unwinder, frame_chain, thread_state_addr, 
running_task_code_obj) < 0) {
         return -1;
     }
-    Py_DECREF(awaited_by);
 
-    if (parse_task_awaited_by(
-        unwinder, running_task_addr, awaited_by, 1) < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
awaited_by for result");
+    // Now find all tasks that are waiting for this task and process them
+    if (process_task_awaited_by(unwinder, running_task_addr, 
process_waiter_task, result) < 0) {
         return -1;
     }
 
     return 0;
 }
 
+// Thread processor for get_async_stack_trace
 static int
-process_single_task_node(
+process_thread_for_async_stack_trace(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t thread_state_addr,
+    unsigned long tid,
+    void *context
+) {
+    PyObject *result = (PyObject *)context;
+
+    // Find running task in this thread
+    uintptr_t running_task_addr;
+    if (find_running_task_in_thread(unwinder, thread_state_addr, 
&running_task_addr) < 0) {
+        return 0;
+    }
+
+    // If we found a running task, process it and its waiters
+    if ((void*)running_task_addr != NULL) {
+        PyObject *task_list = PyList_New(0);
+        if (task_list == NULL) {
+            set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
task list for thread");
+            return -1;
+        }
+
+        if (process_running_task_chain(unwinder, running_task_addr, 
thread_state_addr, task_list) < 0) {
+            Py_DECREF(task_list);
+            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
process running task chain");
+            return -1;
+        }
+
+        // Create AwaitedInfo structure for this thread
+        PyObject *tid_py = PyLong_FromUnsignedLong(tid);
+        if (tid_py == NULL) {
+            Py_DECREF(task_list);
+            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
create thread ID");
+            return -1;
+        }
+
+        RemoteDebuggingState *state = 
RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+        PyObject *awaited_info = PyStructSequence_New(state->AwaitedInfo_Type);
+        if (awaited_info == NULL) {
+            Py_DECREF(tid_py);
+            Py_DECREF(task_list);
+            set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
AwaitedInfo");
+            return -1;
+        }
+
+        PyStructSequence_SetItem(awaited_info, 0, tid_py);  // steals ref
+        PyStructSequence_SetItem(awaited_info, 1, task_list);  // steals ref
+
+        if (PyList_Append(result, awaited_info)) {
+            Py_DECREF(awaited_info);
+            set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
append AwaitedInfo to result");
+            return -1;
+        }
+        Py_DECREF(awaited_info);
+    }
+
+    return 0;
+}
+
+static int
+process_task_and_waiters(
     RemoteUnwinderObject *unwinder,
     uintptr_t task_addr,
     PyObject *result
 ) {
-    PyObject *tn = NULL;
-    PyObject *current_awaited_by = NULL;
-    PyObject *task_id = NULL;
-    PyObject *result_item = NULL;
-    PyObject *coroutine_stack = NULL;
-
-    tn = parse_task_name(unwinder, task_addr);
-    if (tn == NULL) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
task name in single task node");
-        goto error;
+    // First, add this task to the result
+    if (process_single_task_node(unwinder, task_addr, NULL, result) < 0) {
+        return -1;
     }
 
-    current_awaited_by = PyList_New(0);
-    if (current_awaited_by == NULL) {
-        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
awaited_by list in single task node");
-        goto error;
+    // Now find all tasks that are waiting for this task and process them
+    return process_task_awaited_by(unwinder, task_addr, process_waiter_task, 
result);
+}
+
+static int
+find_running_task_in_thread(
+    RemoteUnwinderObject *unwinder,
+    uintptr_t thread_state_addr,
+    uintptr_t *running_task_addr
+) {
+    *running_task_addr = (uintptr_t)NULL;
+
+    uintptr_t address_of_running_loop;
+    int bytes_read = read_py_ptr(
+        unwinder,
+        thread_state_addr + 
unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_loop,
+        &address_of_running_loop);
+    if (bytes_read == -1) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
running loop address");
+        return -1;
     }
 
-    // Extract the coroutine stack for this task
-    coroutine_stack = PyList_New(0);
-    if (coroutine_stack == NULL) {
-        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
coroutine stack list in single task node");
-        goto error;
+    // no asyncio loop is now running
+    if ((void*)address_of_running_loop == NULL) {
+        return 0;
     }
 
-    if (parse_task(unwinder, task_addr, coroutine_stack, 0) < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
task coroutine stack in single task node");
-        goto error;
+    int err = read_ptr(
+        unwinder,
+        thread_state_addr + 
unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_task,
+        running_task_addr);
+    if (err) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
running task address");
+        return -1;
     }
 
-    task_id = PyLong_FromUnsignedLongLong(task_addr);
-    if (task_id == NULL) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create 
task ID in single task node");
-        goto error;
+    return 0;
+}
+
+static int
+get_task_code_object(RemoteUnwinderObject *unwinder, uintptr_t task_addr, 
uintptr_t *code_obj_addr) {
+    uintptr_t running_coro_addr = 0;
+
+    if(read_py_ptr(
+        unwinder,
+        task_addr + 
unwinder->async_debug_offsets.asyncio_task_object.task_coro,
+        &running_coro_addr) < 0) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro 
read failed");
+        return -1;
     }
 
-    RemoteDebuggingState *state = 
RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
-    result_item = PyStructSequence_New(state->TaskInfo_Type);
-    if (result_item == NULL) {
-        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
TaskInfo in single task node");
-        goto error;
+    if (running_coro_addr == 0) {
+        PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL");
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro 
address is NULL");
+        return -1;
     }
 
-    PyStructSequence_SetItem(result_item, 0, task_id);  // steals ref
-    PyStructSequence_SetItem(result_item, 1, tn);  // steals ref
-    PyStructSequence_SetItem(result_item, 2, coroutine_stack);  // steals ref
-    PyStructSequence_SetItem(result_item, 3, current_awaited_by);  // steals 
ref
-
-    // References transferred to tuple
-    task_id = NULL;
-    tn = NULL;
-    coroutine_stack = NULL;
-    current_awaited_by = NULL;
-
-    if (PyList_Append(result, result_item)) {
-        Py_DECREF(result_item);
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append 
result item in single task node");
+    // note: genobject's gi_iframe is an embedded struct so the address to
+    // the offset leads directly to its first field: f_executable
+    if (read_py_ptr(
+        unwinder,
+        running_coro_addr + unwinder->debug_offsets.gen_object.gi_iframe, 
code_obj_addr) < 0) {
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
running task code object");
         return -1;
     }
-    Py_DECREF(result_item);
 
-    // Get back current_awaited_by reference for parse_task_awaited_by
-    current_awaited_by = PyStructSequence_GetItem(result_item, 3);
-    if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by, 0) < 0) 
{
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
awaited_by in single task node");
-        // No cleanup needed here since all references were transferred to 
result_item
-        // and result_item was already added to result list and decreffed
+    if (*code_obj_addr == 0) {
+        PyErr_SetString(PyExc_RuntimeError, "Running task code object is 
NULL");
+        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task code 
object address is NULL");
         return -1;
     }
 
     return 0;
-
-error:
-    Py_XDECREF(tn);
-    Py_XDECREF(current_awaited_by);
-    Py_XDECREF(task_id);
-    Py_XDECREF(result_item);
-    Py_XDECREF(coroutine_stack);
-    return -1;
 }
 
 /* ============================================================================
@@ -1908,45 +2103,13 @@ populate_initial_state_data(
     return 0;
 }
 
+
 static int
 find_running_frame(
     RemoteUnwinderObject *unwinder,
-    uintptr_t runtime_start_address,
+    uintptr_t address_of_thread,
     uintptr_t *frame
 ) {
-    uint64_t interpreter_state_list_head =
-        unwinder->debug_offsets.runtime_state.interpreters_head;
-
-    uintptr_t address_of_interpreter_state;
-    int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
-            &unwinder->handle,
-            runtime_start_address + interpreter_state_list_head,
-            sizeof(void*),
-            &address_of_interpreter_state);
-    if (bytes_read < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
interpreter state for running frame");
-        return -1;
-    }
-
-    if (address_of_interpreter_state == 0) {
-        PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state 
is NULL in running frame search");
-        return -1;
-    }
-
-    uintptr_t address_of_thread;
-    bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
-            &unwinder->handle,
-            address_of_interpreter_state +
-                unwinder->debug_offsets.interpreter_state.threads_main,
-            sizeof(void*),
-            &address_of_thread);
-    if (bytes_read < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
thread address for running frame");
-        return -1;
-    }
-
-    // No Python frames are available for us (can happen at tear-down).
     if ((void*)address_of_thread != NULL) {
         int err = read_ptr(
             unwinder,
@@ -1963,133 +2126,6 @@ find_running_frame(
     return 0;
 }
 
-static int
-find_running_task(
-    RemoteUnwinderObject *unwinder,
-    uintptr_t *running_task_addr
-) {
-    *running_task_addr = (uintptr_t)NULL;
-
-    uint64_t interpreter_state_list_head =
-        unwinder->debug_offsets.runtime_state.interpreters_head;
-
-    uintptr_t address_of_interpreter_state;
-    int bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
-            &unwinder->handle,
-            unwinder->runtime_start_address + interpreter_state_list_head,
-            sizeof(void*),
-            &address_of_interpreter_state);
-    if (bytes_read < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
interpreter state for running task");
-        return -1;
-    }
-
-    if (address_of_interpreter_state == 0) {
-        PyErr_SetString(PyExc_RuntimeError, "No interpreter state found");
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Interpreter state 
is NULL in running task search");
-        return -1;
-    }
-
-    uintptr_t address_of_thread;
-    bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
-            &unwinder->handle,
-            address_of_interpreter_state +
-                unwinder->debug_offsets.interpreter_state.threads_head,
-            sizeof(void*),
-            &address_of_thread);
-    if (bytes_read < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
thread head for running task");
-        return -1;
-    }
-
-    uintptr_t address_of_running_loop;
-    // No Python frames are available for us (can happen at tear-down).
-    if ((void*)address_of_thread == NULL) {
-        return 0;
-    }
-
-    bytes_read = read_py_ptr(
-        unwinder,
-        address_of_thread
-        + 
unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_loop,
-        &address_of_running_loop);
-    if (bytes_read == -1) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
running loop address");
-        return -1;
-    }
-
-    // no asyncio loop is now running
-    if ((void*)address_of_running_loop == NULL) {
-        return 0;
-    }
-
-    int err = read_ptr(
-        unwinder,
-        address_of_thread
-        + 
unwinder->async_debug_offsets.asyncio_thread_state.asyncio_running_task,
-        running_task_addr);
-    if (err) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
running task address");
-        return -1;
-    }
-
-    return 0;
-}
-
-static int
-find_running_task_and_coro(
-    RemoteUnwinderObject *unwinder,
-    uintptr_t *running_task_addr,
-    uintptr_t *running_coro_addr,
-    uintptr_t *running_task_code_obj
-) {
-    *running_task_addr = (uintptr_t)NULL;
-    if (find_running_task(
-        unwinder, running_task_addr) < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task search 
failed");
-        return -1;
-    }
-
-    if ((void*)*running_task_addr == NULL) {
-        PyErr_SetString(PyExc_RuntimeError, "No running task found");
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task 
address is NULL");
-        return -1;
-    }
-
-    if (read_py_ptr(
-        unwinder,
-        *running_task_addr + 
unwinder->async_debug_offsets.asyncio_task_object.task_coro,
-        running_coro_addr) < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro 
read failed");
-        return -1;
-    }
-
-    if ((void*)*running_coro_addr == NULL) {
-        PyErr_SetString(PyExc_RuntimeError, "Running task coro is NULL");
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task coro 
address is NULL");
-        return -1;
-    }
-
-    // note: genobject's gi_iframe is an embedded struct so the address to
-    // the offset leads directly to its first field: f_executable
-    if (read_py_ptr(
-        unwinder,
-        *running_coro_addr + unwinder->debug_offsets.gen_object.gi_iframe,
-        running_task_code_obj) < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
running task code object");
-        return -1;
-    }
-
-    if ((void*)*running_task_code_obj == NULL) {
-        PyErr_SetString(PyExc_RuntimeError, "Running task code object is 
NULL");
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Running task code 
object address is NULL");
-        return -1;
-    }
-
-    return 0;
-}
-
-
 /* ============================================================================
  * FRAME PARSING FUNCTIONS
  * 
============================================================================ */
@@ -2126,9 +2162,11 @@ parse_frame_object(
     RemoteUnwinderObject *unwinder,
     PyObject** result,
     uintptr_t address,
+    uintptr_t* address_of_code_object,
     uintptr_t* previous_frame
 ) {
     char frame[SIZEOF_INTERP_FRAME];
+    *address_of_code_object = 0;
 
     Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
         &unwinder->handle,
@@ -2158,77 +2196,38 @@ parse_frame_object(
     }
 #endif
 
-    return parse_code_object(unwinder, result, 
code_object,instruction_pointer, previous_frame, tlbc_index);
-}
-
-static int
-parse_async_frame_object(
-    RemoteUnwinderObject *unwinder,
-    PyObject** result,
-    uintptr_t address,
-    uintptr_t* previous_frame,
-    uintptr_t* code_object
-) {
-    char frame[SIZEOF_INTERP_FRAME];
-
-    Py_ssize_t bytes_read = _Py_RemoteDebug_PagedReadRemoteMemory(
-        &unwinder->handle,
-        address,
-        SIZEOF_INTERP_FRAME,
-        frame
-    );
-    if (bytes_read < 0) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read 
async frame");
-        return -1;
-    }
-
-    *previous_frame = GET_MEMBER(uintptr_t, frame, 
unwinder->debug_offsets.interpreter_frame.previous);
-    *code_object = GET_MEMBER_NO_TAG(uintptr_t, frame, 
unwinder->debug_offsets.interpreter_frame.executable);
-    int frame_valid = is_frame_valid(unwinder, (uintptr_t)frame, *code_object);
-    if (frame_valid != 1) {
-        return frame_valid;
-    }
-
-    uintptr_t instruction_pointer = GET_MEMBER(uintptr_t, frame, 
unwinder->debug_offsets.interpreter_frame.instr_ptr);
-
-    // Get tlbc_index for free threading builds
-    int32_t tlbc_index = 0;
-#ifdef Py_GIL_DISABLED
-    if (unwinder->debug_offsets.interpreter_frame.tlbc_index != 0) {
-        tlbc_index = GET_MEMBER(int32_t, frame, 
unwinder->debug_offsets.interpreter_frame.tlbc_index);
-    }
-#endif
-
-    if (parse_code_object(
-        unwinder, result, *code_object, instruction_pointer, previous_frame, 
tlbc_index)) {
-        set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse 
code object in async frame");
-        return -1;
-    }
-
-    return 1;
+    *address_of_code_object = code_object;
+    return parse_code_object(unwinder, result, code_object, 
instruction_pointer, previous_frame, tlbc_index);
 }
 
 static int
-parse_async_frame_chain(
+ parse_async_frame_chain(
     RemoteUnwinderObject *unwinder,
     PyObject *calls,
+    uintptr_t address_of_thread,
     uintptr_t running_task_code_obj
 ) {
     uintptr_t address_of_current_frame;
-    if (find_running_frame(unwinder, unwinder->runtime_start_address, 
&address_of_current_frame) < 0) {
+    if (find_running_frame(unwinder, address_of_thread, 
&address_of_current_frame) < 0) {
         set_exception_cause(unwinder, PyExc_RuntimeError, "Running frame 
search failed in async chain");
         return -1;
     }
 
-    uintptr_t address_of_code_object;
+    PyObject *frames = PyList_New(0);
+    if (frames == NULL) {
+        set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create 
frames list");
+        return -1;
+    }
+
     while ((void*)address_of_current_frame != NULL) {
         PyObject* frame_info = NULL;
-        int res = parse_async_frame_object(
+        uintptr_t address_of_code_object;
+        int res = parse_frame_object(
             unwinder,
             &frame_info,
             address_of_current_frame,
-            &address_of_current_frame,
-            &address_of_code_object
+            &address_of_code_object,
+            &address_of_current_frame
         );
 
         if (res < 0) {
@@ -2294,7 +2293,7 @@ append_awaited_by_for_thread(
         uintptr_t task_addr = (uintptr_t)GET_MEMBER(uintptr_t, task_node, 
unwinder->debug_offsets.llist_node.next)
             - unwinder->async_debug_offsets.asyncio_task_object.task_node;
 
-        if (process_single_task_node(unwinder, task_addr, result) < 0) {
+        if (process_single_task_node(unwinder, task_addr, NULL, result) < 0) {
             set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
process task node in awaited_by");
             return -1;
         }
@@ -2389,7 +2388,8 @@ process_frame_chain(
         // Try chunks first, fallback to direct memory read
         if (parse_frame_from_chunks(unwinder, &frame, frame_addr, 
&next_frame_addr, chunks) < 0) {
             PyErr_Clear();
-            if (parse_frame_object(unwinder, &frame, frame_addr, 
&next_frame_addr) < 0) {
+            uintptr_t address_of_code_object = 0;
+            if (parse_frame_object(unwinder, &frame, frame_addr, 
&address_of_code_object ,&next_frame_addr) < 0) {
                 set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to 
parse frame object in chain");
                 return -1;
             }
@@ -2830,53 +2830,12 @@ 
_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s
         goto result_err;
     }
 
-    uintptr_t thread_state_addr;
-    unsigned long tid = 0;
-    if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
-                &self->handle,
-                self->interpreter_addr
-                + self->debug_offsets.interpreter_state.threads_main,
-                sizeof(void*),
-                &thread_state_addr))
-    {
-        set_exception_cause(self, PyExc_RuntimeError, "Failed to read main 
thread state in get_all_awaited_by");
+    // Process all threads
+    if (iterate_threads(self, process_thread_for_awaited_by, result) < 0) {
         goto result_err;
     }
 
-    uintptr_t head_addr;
-    while (thread_state_addr != 0) {
-        if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
-                    &self->handle,
-                    thread_state_addr
-                    + self->debug_offsets.thread_state.native_thread_id,
-                    sizeof(tid),
-                    &tid))
-        {
-            set_exception_cause(self, PyExc_RuntimeError, "Failed to read 
thread ID in get_all_awaited_by");
-            goto result_err;
-        }
-
-        head_addr = thread_state_addr
-            + 
self->async_debug_offsets.asyncio_thread_state.asyncio_tasks_head;
-
-        if (append_awaited_by(self, tid, head_addr, result))
-        {
-            set_exception_cause(self, PyExc_RuntimeError, "Failed to append 
awaited_by for thread in get_all_awaited_by");
-            goto result_err;
-        }
-
-        if (0 > _Py_RemoteDebug_PagedReadRemoteMemory(
-                    &self->handle,
-                    thread_state_addr + self->debug_offsets.thread_state.next,
-                    sizeof(void*),
-                    &thread_state_addr))
-        {
-            set_exception_cause(self, PyExc_RuntimeError, "Failed to read next 
thread state in get_all_awaited_by");
-            goto result_err;
-        }
-    }
-
-    head_addr = self->interpreter_addr
+    uintptr_t head_addr = self->interpreter_addr
         + 
self->async_debug_offsets.asyncio_interpreter_state.asyncio_tasks_head;
 
     // On top of a per-thread task lists used by default by asyncio to avoid
@@ -2903,32 +2862,50 @@ 
_remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s
 @critical_section
 _remote_debugging.RemoteUnwinder.get_async_stack_trace
 
-Returns information about the currently running async task and its stack trace.
+Get the currently running async tasks and their dependency graphs from the 
remote process.
 
-Returns a tuple of (task_info, stack_frames) where:
-- task_info is a tuple of (task_id, task_name) identifying the task
-- stack_frames is a list of tuples (function_name, filename, line_number) 
representing
-  the Python stack frames for the task, ordered from most recent to oldest
+This returns information about running tasks and all tasks that are waiting 
for them,
+forming a complete dependency graph for each thread's active task.
 
-Example:
-    ((4345585712, 'Task-1'), [
-        ('run_echo_server', 'server.py', 127),
-        ('serve_forever', 'server.py', 45),
-        ('main', 'app.py', 23)
-    ])
+For each thread with a running task, returns the running task plus all tasks 
that
+transitively depend on it (tasks waiting for the running task, tasks waiting 
for
+those tasks, etc.).
+
+Returns a list of per-thread results, where each thread result contains:
+- Thread ID
+- List of task information for the running task and all its waiters
+
+Each task info contains:
+- Task ID (memory address)
+- Task name
+- Call stack frames: List of (func_name, filename, lineno)
+- List of tasks waiting for this task (recursive structure)
 
 Raises:
     RuntimeError: If AsyncioDebug section is not available in the target 
process
-    RuntimeError: If there is an error copying memory from the target process
-    OSError: If there is an error accessing the target process
-    PermissionError: If access to the target process is denied
-    UnicodeDecodeError: If there is an error decoding strings from the target 
process
+    MemoryError: If memory allocation fails
+    OSError: If reading from the remote process fails
+
+Example output (similar structure to get_all_awaited_by but only for running 
tasks):
+[
+    # Thread 140234 results
+    (140234, [
+        # Running task and its complete waiter dependency graph
+        (4345585712, 'main_task',
+         [("run_server", "server.py", 127), ("main", "app.py", 23)],
+         [
+             # Tasks waiting for main_task
+             (4345585800, 'worker_1', [...], [...]),
+             (4345585900, 'worker_2', [...], [...])
+         ])
+    ])
+]
 
 [clinic start generated code]*/
 
 static PyObject *
 
_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject
 *self)
-/*[clinic end generated code: output=6433d52b55e87bbe input=11b7150c59d4c60f]*/
+/*[clinic end generated code: output=6433d52b55e87bbe input=8744b47c9ec2220a]*/
 {
     if (!self->async_debug_offsets_available) {
         PyErr_SetString(PyExc_RuntimeError, "AsyncioDebug section not 
available");
@@ -2936,35 +2913,20 @@ 
_remote_debugging_RemoteUnwinder_get_async_stack_trace_impl(RemoteUnwinderObject
         return NULL;
     }
 
-    PyObject *result = NULL;
-    PyObject *calls = NULL;
-
-    if (setup_async_result_structure(self, &result, &calls) < 0) {
-        set_exception_cause(self, PyExc_RuntimeError, "Failed to setup async 
result structure");
-        goto cleanup;
-    }
-
-    uintptr_t running_task_addr, running_coro_addr, running_task_code_obj;
-    if (find_running_task_and_coro(self, &running_task_addr,
-                                   &running_coro_addr, &running_task_code_obj) 
< 0) {
-        set_exception_cause(self, PyExc_RuntimeError, "Failed to find running 
task and coro");
-        goto cleanup;
-    }
-
-    if (parse_async_frame_chain(self, calls, running_task_code_obj) < 0) {
-        set_exception_cause(self, PyExc_RuntimeError, "Failed to parse async 
frame chain");
-        goto cleanup;
+    PyObject *result = PyList_New(0);
+    if (result == NULL) {
+        set_exception_cause(self, PyExc_MemoryError, "Failed to create result 
list in get_async_stack_trace");
+        return NULL;
     }
 
-    if (add_task_info_to_result(self, result, running_task_addr) < 0) {
-        set_exception_cause(self, PyExc_RuntimeError, "Failed to add task info 
to result");
-        goto cleanup;
+    // Process all threads
+    if (iterate_threads(self, process_thread_for_async_stack_trace, result) < 
0) {
+        goto result_err;
     }
 
     _Py_RemoteDebug_ClearCache(&self->handle);
     return result;
-
-cleanup:
+result_err:
     _Py_RemoteDebug_ClearCache(&self->handle);
     Py_XDECREF(result);
     return NULL;
diff --git a/Modules/clinic/_remote_debugging_module.c.h 
b/Modules/clinic/_remote_debugging_module.c.h
index e80b24b54c0ffa..f6a51cdba6b401 100644
--- a/Modules/clinic/_remote_debugging_module.c.h
+++ b/Modules/clinic/_remote_debugging_module.c.h
@@ -235,26 +235,41 @@ 
PyDoc_STRVAR(_remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__,
 "get_async_stack_trace($self, /)\n"
 "--\n"
 "\n"
-"Returns information about the currently running async task and its stack 
trace.\n"
+"Get the currently running async tasks and their dependency graphs from the 
remote process.\n"
 "\n"
-"Returns a tuple of (task_info, stack_frames) where:\n"
-"- task_info is a tuple of (task_id, task_name) identifying the task\n"
-"- stack_frames is a list of tuples (function_name, filename, line_number) 
representing\n"
-"  the Python stack frames for the task, ordered from most recent to oldest\n"
+"This returns information about running tasks and all tasks that are waiting 
for them,\n"
+"forming a complete dependency graph for each thread\'s active task.\n"
 "\n"
-"Example:\n"
-"    ((4345585712, \'Task-1\'), [\n"
-"        (\'run_echo_server\', \'server.py\', 127),\n"
-"        (\'serve_forever\', \'server.py\', 45),\n"
-"        (\'main\', \'app.py\', 23)\n"
-"    ])\n"
+"For each thread with a running task, returns the running task plus all tasks 
that\n"
+"transitively depend on it (tasks waiting for the running task, tasks waiting 
for\n"
+"those tasks, etc.).\n"
+"\n"
+"Returns a list of per-thread results, where each thread result contains:\n"
+"- Thread ID\n"
+"- List of task information for the running task and all its waiters\n"
+"\n"
+"Each task info contains:\n"
+"- Task ID (memory address)\n"
+"- Task name\n"
+"- Call stack frames: List of (func_name, filename, lineno)\n"
+"- List of tasks waiting for this task (recursive structure)\n"
 "\n"
 "Raises:\n"
 "    RuntimeError: If AsyncioDebug section is not available in the target 
process\n"
-"    RuntimeError: If there is an error copying memory from the target 
process\n"
-"    OSError: If there is an error accessing the target process\n"
-"    PermissionError: If access to the target process is denied\n"
-"    UnicodeDecodeError: If there is an error decoding strings from the target 
process");
+"    MemoryError: If memory allocation fails\n"
+"    OSError: If reading from the remote process fails\n"
+"\n"
+"Example output (similar structure to get_all_awaited_by but only for running 
tasks):\n"
+"[\n"
+"    (140234, [\n"
+"        (4345585712, \'main_task\',\n"
+"         [(\"run_server\", \"server.py\", 127), (\"main\", \"app.py\", 
23)],\n"
+"         [\n"
+"             (4345585800, \'worker_1\', [...], [...]),\n"
+"             (4345585900, \'worker_2\', [...], [...])\n"
+"         ])\n"
+"    ])\n"
+"]");
 
 #define _REMOTE_DEBUGGING_REMOTEUNWINDER_GET_ASYNC_STACK_TRACE_METHODDEF    \
     {"get_async_stack_trace", 
(PyCFunction)_remote_debugging_RemoteUnwinder_get_async_stack_trace, 
METH_NOARGS, _remote_debugging_RemoteUnwinder_get_async_stack_trace__doc__},
@@ -273,4 +288,4 @@ 
_remote_debugging_RemoteUnwinder_get_async_stack_trace(PyObject *self, PyObject
 
     return return_value;
 }
-/*[clinic end generated code: output=a37ab223d5081b16 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=0dd1e6e8bab2a8b1 input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to