[PATCH v4 3/5] gdb: Migrate frame unwinders to use C++ classes

Thiago Jung Bauermann thiago.bauermann@linaro.org
Fri Sep 27 15:57:34 GMT 2024


Guinevere Larsen <guinevere@redhat.com> writes:

> On 9/27/24 12:51 AM, Thiago Jung Bauermann wrote:
>> Hello Guinevere,
>>
>> Great patch! I got carried away with it, and implemented all of the
>> suggestions I made to see whether they were feasible. If you want to
>> check how they affect the code, they're available in branch
>> 'review/modernize-frame-unwinders' on this repo:
>>
>> https://git.linaro.org/people/thiago.bauermann/binutils-gdb.git/
>>
>> Some of them IMHO can be incorporated in this patch, but some of them
>> would be better as separate patches. If you want, you can cherry-pick
>> them into your series, or I can post them later after it gets
>> in. Whichever way you prefer.
>
> Thank you for the thorough review!

No problem. Thanks for the patch series!

I forgot to mention: of course also feel free to squash any commit from
my branch into your patches. They're just small adjustments, so no need
to add 'co-authored-by' or anything.

>> Guinevere Larsen <blarsen@redhat.com> writes:
>>
>>> +/* This method just passes the parameters to the callback pointer.  */
>>> +int
>>> +frame_unwind_legacy::sniffer (const struct frame_unwind *self,
>>> +			      const frame_info_ptr &this_frame,
>>> +			      void **this_prologue_cache) const
>>> +{
>>> +  return sniffer_p (self, this_frame, this_prologue_cache);
>>> +}
>> Many frame_unwind_legacy instances use default_frame_sniffer, which
>> simply returns 1. Since this patch already defines an equivalent
>> frame_unwind::sniffer (), it's possible to remove the need of specifying
>> default_frame_sniffer in the declarations of many
>> frame_uwnind_legacy instances if this method is made to call the parent
>> class' implementation if sniffer_p is nullptr:
>>
>> /* This method just passes the parameters to the callback pointer.  */
>> int
>> frame_unwind_legacy::sniffer (const frame_info_ptr &this_frame,
>> 			      void **this_prologue_cache) const
>> {
>>    if (sniffer_p == nullptr)
>>      return frame_unwind::sniffer (this_frame, this_prologue_cache);
>>    return sniffer_p (this, this_frame, this_prologue_cache);
>> }
> Same as above, I agree that this is a great change but I worried it would make for a
> harder review.

That's true. It could be a follow-on patch. Like I said, I don't mind
posting one after your series goes in if you prefer.

>>> +  /* The following methods are here mostly for interface functionality.  They
>>> +     all throw an error when called, as a safe way to check if an unwinder has
>>> +     implemented the desired functionality.  */
>> Rather than throwing an error at runtime to check if an unwinder has
>> implemented the desired functionality, I believe it's better to do the
>> check at compile time by making these methods pure virtual.
>>
>> This can be done to this_id () and prev_register (). prev_arch () can be
>> turned into a useful default implementation by making it call
>> get_frame_arch () as I mentioned before.
>>
>> This leaves just dealloc_cache (), so this comment can be moved to it.
>
> I remember trying to make the methods pure-virtual and getting linker errors when testing
> locally.
>
> I know that after that I found one unwinder that didn't set one of the pointers, so maybe
> that was fixed... If you managed to build with --enable-targets=all, I think we're safe.

Yes, I build-tested with --enable-targets=all. The only caveat is that I
don't have liunwind-ia64 so some of the unwinders in ia64-tdep.c are
untested — though I don't see how they could go wrong (famous last words).

>>> +/* This is a legacy version of the frame unwinder.  The original struct
>>> +   used function pointers for callbacks, this updated version has a
>>> +   method that just passes the parameters along to the callback
>>> +   pointer.
>>> +   Do not use this class for new unwinders.  Instead, see other classes
>>> +   that inherit from frame_unwind, such as the python unwinder.  */
>>> +class frame_unwind_legacy : public frame_unwind
>>> +{
>>> +private:
>>>     /* Should an attribute indicating the frame's address-in-block go
>>>        here?  */
>>> -  frame_unwind_stop_reason_ftype *stop_reason;
>>> -  frame_this_id_ftype *this_id;
>>> -  frame_prev_register_ftype *prev_register;
>>> -  const struct frame_data *unwind_data;
>>> -  frame_sniffer_ftype *sniffer;
>>> -  frame_dealloc_cache_ftype *dealloc_cache;
>>> -  frame_prev_arch_ftype *prev_arch;
>>> +  frame_unwind_stop_reason_ftype *stop_reason_p;
>>> +  frame_this_id_ftype *this_id_p;
>>> +  frame_prev_register_ftype *prev_register_p;
>>> +  frame_sniffer_ftype *sniffer_p;
>>> +  frame_dealloc_cache_ftype *dealloc_cache_p;
>>> +  frame_prev_arch_ftype *prev_arch_p;
>>> +public:
>>> +  frame_unwind_legacy (const char *n, frame_type t, frame_unwind_class c,
>>> +		       frame_unwind_stop_reason_ftype *sr,
>> As mentioned before, if this argument is moved later, it can be made
>> optional. Probably best done in a separate patch, if you agree with the
>> change.
>
> Makes sense
>
>>> +		       frame_this_id_ftype *ti,
>>> +		       frame_prev_register_ftype *pr,
>>> +		       const struct frame_data *ud,
>> It turns out that no frame_unwind_legacy instance passes a frame_data
>> object, so this argument can simply be removed and nullptr can be passed
>> to the parent class' constructor. Not sure if this is better done as a
>> separate patch, or as part of this patch.
>
> Oh, thanks for noticing that!
>
> I think it's  better to have it separate so we minimize things that can go wrong in one
> single change...

Agreed.

-- 
Thiago


More information about the Gdb-patches mailing list