[PING][PATCH] gdb/python: Allow SIGTRAMP_FRAME python unwinders to be created.

Rémi Bernon rbernon@codeweavers.com
Thu Feb 29 08:17:26 GMT 2024


Ping,

Thanks,

On 2/14/24 22:58, Rémi Bernon wrote:
> Wine now executes Win32 code on a separate stack for its Unix code. It
> switches from one stack to another on through specific functions, and
> without any custom unwinders, debugging Wine in Gdb will only let you
> see the frames of either the Win32 side, or the Unix side.
> 
> The Win32 and Unix call stacks are actually interleaved, with Unix code
> sometimes calling back into Win32. Using a custom Python frame unwinder
> we can provide Gdb with the information it needs to join both toghether
> and show a complete interleaved call stack. However, Gdb will often stop
> unwinding as it will see the frames from one stack as inner the frames
> from the other stack.
> 
> This allows to write custom unwinders to produce SIGTRAMP_FRAME typed
> frames, which bypasses this restriction and will show the Win32 / Unix
> gate as a signal frame.
> ---
>   gdb/python/lib/gdb/__init__.py |  8 ++++----
>   gdb/python/lib/gdb/unwinder.py |  7 ++++++-
>   gdb/python/py-unwind.c         | 16 +++++++++++++++-
>   3 files changed, 25 insertions(+), 6 deletions(-)
> 
> diff --git a/gdb/python/lib/gdb/__init__.py b/gdb/python/lib/gdb/__init__.py
> index b3124369fe8..d9226440cbc 100644
> --- a/gdb/python/lib/gdb/__init__.py
> +++ b/gdb/python/lib/gdb/__init__.py
> @@ -86,7 +86,7 @@ frame_filters = {}
>   frame_unwinders = []
>   
>   
> -def _execute_unwinders(pending_frame):
> +def _execute_unwinders(pending_frame, frame_type):
>       """Internal function called from GDB to execute all unwinders.
>   
>       Runs each currently enabled unwinder until it finds the one that
> @@ -105,19 +105,19 @@ def _execute_unwinders(pending_frame):
>       """
>       for objfile in objfiles():
>           for unwinder in objfile.frame_unwinders:
> -            if unwinder.enabled:
> +            if unwinder.enabled and unwinder.frame_type == frame_type:
>                   unwind_info = unwinder(pending_frame)
>                   if unwind_info is not None:
>                       return (unwind_info, unwinder.name)
>   
>       for unwinder in current_progspace().frame_unwinders:
> -        if unwinder.enabled:
> +        if unwinder.enabled and unwinder.frame_type == frame_type:
>               unwind_info = unwinder(pending_frame)
>               if unwind_info is not None:
>                   return (unwind_info, unwinder.name)
>   
>       for unwinder in frame_unwinders:
> -        if unwinder.enabled:
> +        if unwinder.enabled and unwinder.frame_type == frame_type:
>               unwind_info = unwinder(pending_frame)
>               if unwind_info is not None:
>                   return (unwind_info, unwinder.name)
> diff --git a/gdb/python/lib/gdb/unwinder.py b/gdb/python/lib/gdb/unwinder.py
> index 140b84d3374..7e23a662a32 100644
> --- a/gdb/python/lib/gdb/unwinder.py
> +++ b/gdb/python/lib/gdb/unwinder.py
> @@ -29,7 +29,7 @@ class Unwinder(object):
>           enabled: A boolean indicating whether the unwinder is enabled.
>       """
>   
> -    def __init__(self, name):
> +    def __init__(self, name, frame_type=gdb.NORMAL_FRAME):
>           """Constructor.
>   
>           Args:
> @@ -39,9 +39,14 @@ class Unwinder(object):
>           if not isinstance(name, str):
>               raise TypeError("incorrect type for name: %s" % type(name))
>   
> +        self._frame_type = frame_type
>           self._name = name
>           self._enabled = True
>   
> +    @property
> +    def frame_type(self):
> +        return self._frame_type
> +
>       @property
>       def name(self):
>           return self._name
> diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
> index 1856e41e2a1..2d36c43d342 100644
> --- a/gdb/python/py-unwind.c
> +++ b/gdb/python/py-unwind.c
> @@ -844,7 +844,8 @@ pyuw_sniffer (const struct frame_unwind *self, frame_info_ptr this_frame,
>     /* A (gdb.UnwindInfo, str) tuple, or None.  */
>     gdbpy_ref<> pyo_execute_ret
>       (PyObject_CallFunctionObjArgs (pyo_execute.get (),
> -				   pyo_pending_frame.get (), NULL));
> +				   pyo_pending_frame.get (),
> +				   PyLong_FromLong(self->type), NULL));
>     if (pyo_execute_ret == nullptr)
>       {
>         /* If the unwinder is cancelled due to a Ctrl-C, then propagate
> @@ -965,6 +966,19 @@ pyuw_on_new_gdbarch (struct gdbarch *newarch)
>         unwinder->sniffer = pyuw_sniffer;
>         unwinder->dealloc_cache = pyuw_dealloc_cache;
>         frame_unwind_prepend_unwinder (newarch, unwinder);
> +
> +      struct frame_unwind *unwinder_signals
> +	  = GDBARCH_OBSTACK_ZALLOC (newarch, struct frame_unwind);
> +
> +      unwinder_signals->name = "python-sigtramp";
> +      unwinder_signals->type = SIGTRAMP_FRAME;
> +      unwinder_signals->stop_reason = default_frame_unwind_stop_reason;
> +      unwinder_signals->this_id = pyuw_this_id;
> +      unwinder_signals->prev_register = pyuw_prev_register;
> +      unwinder_signals->unwind_data = (const struct frame_data *) newarch;
> +      unwinder_signals->sniffer = pyuw_sniffer;
> +      unwinder_signals->dealloc_cache = pyuw_dealloc_cache;
> +      frame_unwind_prepend_unwinder (newarch, unwinder_signals);
>         data->unwinder_registered = 1;
>       }
>   }

-- 
Rémi Bernon <rbernon@codeweavers.com>



More information about the Gdb-patches mailing list