Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH] [gdb/testsuite] Fix gdb.base/inline-frame-cycle-unwind.exp for s390x (alternative)
Date: Wed, 21 Jan 2026 14:32:13 +0100	[thread overview]
Message-ID: <5e904db2-8fe3-42a3-b8ac-32255471b2b5@suse.de> (raw)
In-Reply-To: <87a4y8qru0.fsf@redhat.com>

On 1/20/26 3:30 PM, Andrew Burgess wrote:
> Tom de Vries<tdevries@suse.de> writes:
> 
>> With test-case gdb.base/inline-frame-cycle-unwind.exp on s390x-linux, I run
>> into:
>> ...
>>   (gdb) bt^M
>>   #0  inline_func () at inline-frame-cycle-unwind.c:49^M
>>   #1  normal_func () at inline-frame-cycle-unwind.c:32^M
>>   #2  0x000000000100065c in inline_func () at inline-frame-cycle-unwind.c:45^M
>>   #3  normal_func () at inline-frame-cycle-unwind.c:32^M
>>   Backtrace stopped: previous frame identical to this frame (corrupt stack?)^M
>>   (gdb) FAIL: $exp: bt: cycle at level 5: backtrace when the unwind is broken \
>>     at frame 5
>> ...
>>
>> In contrast, on x86_64-linux, I get:
>> ...
>>   (gdb) bt^M
>>   #0  inline_func () at inline-frame-cycle-unwind.c:49^M
>>   #1  normal_func () at inline-frame-cycle-unwind.c:32^M
>>   #2  0x0000000000401157 in inline_func () at inline-frame-cycle-unwind.c:45^M
>>   #3  normal_func () at inline-frame-cycle-unwind.c:32^M
>>   #4  0x0000000000401157 in inline_func () at inline-frame-cycle-unwind.c:45^M
>>   #5  normal_func () at inline-frame-cycle-unwind.c:32^M
>>   Backtrace stopped: previous frame identical to this frame (corrupt stack?)^M
>>   (gdb) PASS: $exp: bt: cycle at level 5: backtrace when the unwind is broken \
>>     at frame 5
>> ...
>>
>> AFAIU, the mechanism of the test is as follows: the custom unwinder produces the
>> frame-id for frame #5 at frame #4.  Consequently, when arriving at frame #5, a
>> cycle is detected.
> I don't believe this is how it works.  See below for what I think happens.
> 
>> [ It took me a while to understand this because of the following off-by-one
>> confusion: for frame #0, we get pending_frame.level() == 1.  So when
>> stop_at_level == 5, the custom unwinder calculates a frame-id for frame #4,
>> not frame #5.  But the frame-id it calculates is the one for frame #5, so
>> unwinding will stop at frame #5 because the frame-ids for frame #4 and
>> frame #5 are identical. ]
> I went back and looked at the unpatched test again, and I don't believe
> this "off-by-one" issue is a thing, at least, I don't see one based on
> your description.
> 
> It does appear that for frame #0 we get pending_frame.level() == 1, but
> this isn't what's really happening.
> 
> Frame #0 is inline, so the Python frame unwinder is never run for this
> frame.  The first frame for which the Python frame unwinder is run is
> frame #1, hence pending_frame.level() == 1.
> 
> The frame-id calculated within TestUnwinder.__call__ is the frame-id for
> the previous (outer, older) frame.  So, when pending_frame.level() == 5
> we are calculating the frame-id for frame #6.  As frame #6 then appears
> to be identical to frame #5, a cycle is detected and the backtrace ends.

After reading the documentation ( 
https://www.sourceware.org/gdb/current/onlinedocs/gdb.html/Unwinding-Frames-in-Python.html 
):
...
For the frames it can sniff an unwinder provides two additional methods: 
it can return frame’s ID, and it can fetch registers from the previous 
frame.

   ...

You implement a frame unwinder in Python as a class with which has two 
attributes, name and enabled, with obvious meanings, and a single method 
__call__, which examines a given frame and returns an object (an 
instance of gdb.UnwindInfo class) describing it. If an unwinder does not 
recognize a frame, it should return None. The code in GDB that enables 
writing unwinders in Python uses this object to return frame’s ID and 
previous frame registers when GDB core asks for them.
...
my understanding is that for pending_frame.level() == 5, we calculate 
the frame-id for frame #5.

On x86_64-linux, indeed that's the case, the output of maint print 
frame-id 5 matches the sp/pc calculated for pending_frame.level() == 5. 
This is shown in more detail in the commit message of the v2 I've submitted.

Thanks,
- Tom

  parent reply	other threads:[~2026-01-21 13:33 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-11 13:39 Tom de Vries
2026-01-03 15:12 ` [PING][PATCH] " Tom de Vries
2026-01-19 18:36   ` [PING^2][PATCH] " Tom de Vries
2026-01-20 10:38 ` [PATCH] " Andrew Burgess
2026-01-20 14:30 ` Andrew Burgess
2026-01-20 20:38   ` Andrew Burgess
2026-01-21 13:09     ` Tom de Vries
2026-01-21 13:32   ` Tom de Vries [this message]
2026-01-21 16:50     ` Andrew Burgess
2026-01-24 23:19 ` Kevin Buettner

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=5e904db2-8fe3-42a3-b8ac-32255471b2b5@suse.de \
    --to=tdevries@suse.de \
    --cc=aburgess@redhat.com \
    --cc=gdb-patches@sourceware.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