* [PATCH] gdb: z80: Fix endless backtrace loop and assertion crashes
@ 2026-06-05 18:56 Ronald Hecht
2026-06-06 19:40 ` Kevin Buettner
0 siblings, 1 reply; 10+ messages in thread
From: Ronald Hecht @ 2026-06-05 18:56 UTC (permalink / raw)
To: gdb-patches; +Cc: Ronald Hecht
This patch fixes two distinct issues in the Z80 frame unwind cache:
1. An infinite loop in the stack pointer wrapping logic. The `for (;; ++sp)`
loop could run endlessly if the overflow condition `sp < this_base` was
never met due to 16-bit address space wrapping. Introduced a `loop_count`
to break out after 4 iterations as a sensible heuristic for Z80.
2. A potential internal GDB assertion failure. The code previously called
`.addr()` directly on saved registers without verifying if they actually
held an address, causing crashes when encountering unexpected register
states (e.g. REG_UNKNOWN). Added a check for `.is_addr()` beforehand.
gdb/ChangeLog:
* z80-tdep.c (z80_frame_unwind_cache): Prevent infinite loop by
adding loop_count. Check is_addr() before calling addr().
---
gdb/z80-tdep.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
index 3a0d5f7e393..5e1c3a877b3 100644
--- a/gdb/z80-tdep.c
+++ b/gdb/z80-tdep.c
@@ -597,6 +597,7 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
CORE_ADDR sp;
CORE_ADDR sp_mask = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int loop_count = 0;
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
this_base = get_frame_register_unsigned (this_frame, Z80_SP_REGNUM);
@@ -604,7 +605,7 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
for (;; ++sp)
{
sp &= sp_mask;
- if (sp < this_base)
+ if (++loop_count > 4 || sp < this_base)
{ /* overflow, looks like end of stack */
sp = this_base + info->size;
break;
@@ -644,9 +645,14 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
/* Adjust all the saved registers so that they contain addresses and not
offsets. */
for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
- if (info->saved_regs[i].addr () > 0)
- info->saved_regs[i].set_addr
- (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+ {
+ if (info->saved_regs[i].is_addr ())
+ {
+ if (info->saved_regs[i].addr () > 0)
+ info->saved_regs[i].set_addr
+ (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+ }
+ }
/* Except for the startup code, the return PC is always saved on
the stack and is at the base of the frame. */
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH] gdb: z80: Fix endless backtrace loop and assertion crashes
2026-06-05 18:56 [PATCH] gdb: z80: Fix endless backtrace loop and assertion crashes Ronald Hecht
@ 2026-06-06 19:40 ` Kevin Buettner
2026-06-07 7:36 ` Ronald Hecht
2026-06-07 7:48 ` [PATCH v2] " Ronald Hecht
0 siblings, 2 replies; 10+ messages in thread
From: Kevin Buettner @ 2026-06-06 19:40 UTC (permalink / raw)
To: Ronald Hecht; +Cc: gdb-patches
Hi Ronald,
On Fri, 5 Jun 2026 20:56:47 +0200
Ronald Hecht <ronald.hecht@gmx.de> wrote:
> This patch fixes two distinct issues in the Z80 frame unwind cache:
>
> 1. An infinite loop in the stack pointer wrapping logic. The `for (;;
> ++sp)` loop could run endlessly if the overflow condition `sp <
> this_base` was never met due to 16-bit address space wrapping. Introduced
> a `loop_count` to break out after 4 iterations as a sensible heuristic
> for Z80.
>
> 2. A potential internal GDB assertion failure. The code previously called
> `.addr()` directly on saved registers without verifying if they
> actually held an address, causing crashes when encountering unexpected
> register states (e.g. REG_UNKNOWN). Added a check for `.is_addr()`
> beforehand.
>
> gdb/ChangeLog:
> * z80-tdep.c (z80_frame_unwind_cache): Prevent infinite loop by
> adding loop_count. Check is_addr() before calling addr().
> ---
> gdb/z80-tdep.c | 14 ++++++++++----
> 1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
> index 3a0d5f7e393..5e1c3a877b3 100644
> --- a/gdb/z80-tdep.c
> +++ b/gdb/z80-tdep.c
> @@ -597,6 +597,7 @@ z80_frame_unwind_cache (const frame_info_ptr
> &this_frame, CORE_ADDR sp;
> CORE_ADDR sp_mask = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
> enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + int loop_count = 0;
> /* Assume that the FP is this frame's SP but with that pushed
> stack space added back. */
> this_base = get_frame_register_unsigned (this_frame,
> Z80_SP_REGNUM); @@ -604,7 +605,7 @@ z80_frame_unwind_cache (const
> frame_info_ptr &this_frame, for (;; ++sp)
> {
> sp &= sp_mask;
> - if (sp < this_base)
> + if (++loop_count > 4 || sp < this_base)
I'm wondering if there's a better way to handle this? It seems to me
that we should be able come up with a comparison against the unmasked
'sp' value which detects bottom of stack (or end of address space). I
think that perhaps this might work:
...
for (;; ++sp)
{
if (sp > sp_mask)
{ /* overflow, looks like end of stack */
sp = this_base + info->size;
break;
}
/* find return address */
read_memory (sp, buf, addr_len);
...
Note that I got rid of the masking operation; It's no longer needed with
that 'sp > sp_mask' test. But you might want to rename 'sp_mask' to
be 'addr_space_max' or some such.
Can you test this version?
It may still be desirable to place a limit on the number of stack
slots that are checked in this code. I have no objection to doing
this. I only ask that you document the constant chosen ('4' perhaps)
and that you explain why it's likely enough for the z80 architecture.
(Put the explanation in a code comment, instead of only the commit
log.)
Kevin
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH] gdb: z80: Fix endless backtrace loop and assertion crashes
2026-06-06 19:40 ` Kevin Buettner
@ 2026-06-07 7:36 ` Ronald Hecht
2026-06-07 7:48 ` [PATCH v2] " Ronald Hecht
1 sibling, 0 replies; 10+ messages in thread
From: Ronald Hecht @ 2026-06-07 7:36 UTC (permalink / raw)
To: Kevin Buettner, gdb-patches
Hi,
Thank you for the review and the constructive feedback!
You are completely right about dropping the masking operation and
checking for |sp > sp_mask| (or |addr_space_max|). I tested your
suggested change and it indeed makes the logic much cleaner and works
perfectly.
Regarding the limit on the stack slots (|loop_count|): I did a test run
without my abort condition to see exactly what happens under the hood
when the unwinder gets confused (e.g. due to a slightly corrupt stack or
unpopped arguments) and fails to find the return address immediately.
Here is a snippet from my remote debug log:
(gdb) bt
[remote] Sending packet: $m1ae,2#c2
[remote] Received Ack
[remote] Packet received: D8E3
[remote] Sending packet: $me3d5,3#fd
[remote] Received Ack
[remote] Packet received: CDCAE3
[remote] Sending packet: $m1af,2#c3
[remote] Received Ack
...
[remote] Sending packet: $m1b0,2#8e
...
[remote] Sending packet: $m1b1,2#8f
As you can see, the Stack Pointer started at |0x01ae|. Because it
couldn't find a matching |CALL| instruction, it started creeping up the
memory byte-by-byte (|1ae|, |1af|, |1b0|, |1b1|...).
Without a hard limit, this loop will iterate all the way up to |0xffff|.
That is over 65,000 iterations. Since each iteration triggers two
|read_memory()| calls (one for the SP, one to check for the |CALL|
instruction), GDB ends up sending over 130,000 remote packets over a
slow serial or JTAG connection. This effectively hangs the debugger
session for minutes.
As for why the limit is specifically set to |4| iterations: The Z80
heavily relies on 16-bit register pairs (2 bytes). A limit of 4 bytes
perfectly covers typical small stack offsets, such as two unpopped
16-bit arguments or a temporary 32-bit push (which SDCC sometimes
generates). Scanning further (e.g. 8+ bytes) drastically increases the
risk of false positives. We would wander deeply into the caller's local
variables, where hitting a random |0xCD| (CALL opcode) byte is quite
likely. This would cause GDB to hallucinate a corrupted backtrace. A
limit of 4 comfortably pulls the emergency brake before that happens.
I will prepare and send a |v2| patch shortly. It will include your clean
|sp > addr_space_max| refactoring, keep the |loop_count| limit, and add
a detailed code comment explaining this exact rationale for the magic
number '4' as requested.
Thanks again for your guidance!
Best regards,
Ronald
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2] gdb: z80: Fix endless backtrace loop and assertion crashes
2026-06-06 19:40 ` Kevin Buettner
2026-06-07 7:36 ` Ronald Hecht
@ 2026-06-07 7:48 ` Ronald Hecht
2026-06-14 22:06 ` Kevin Buettner
1 sibling, 1 reply; 10+ messages in thread
From: Ronald Hecht @ 2026-06-07 7:48 UTC (permalink / raw)
To: gdb-patches; +Cc: Ronald Hecht
This patch fixes two distinct issues in the Z80 frame unwind cache:
1. An infinite loop in the stack pointer wrapping logic. The `for (;; ++sp)`
loop could run endlessly if the overflow condition `sp < this_base` was
never met due to 16-bit address space wrapping. This is fixed by
checking for `sp > addr_space_max` instead of masking the address.
Additionally, a `loop_count` is introduced to break out after 4 iterations.
This prevents severe slow-downs on remote targets caused by scanning
large portions of the address space when the stack is corrupt.
2. A potential internal GDB assertion failure. The code previously called
`.addr()` directly on saved registers without verifying if they actually
held an address, causing crashes when encountering unexpected register
states (e.g. REG_UNKNOWN). Added a check for `.is_addr()` beforehand.
gdb/ChangeLog:
* z80-tdep.c (z80_frame_unwind_cache): Prevent infinite loop by
checking addr_space_max and adding loop_count. Check is_addr()
before calling addr().
---
gdb/z80-tdep.c | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
index 3a0d5f7e393..832433f05cb 100644
--- a/gdb/z80-tdep.c
+++ b/gdb/z80-tdep.c
@@ -595,16 +595,28 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
{
CORE_ADDR addr;
CORE_ADDR sp;
- CORE_ADDR sp_mask = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
+ CORE_ADDR addr_space_max = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int loop_count = 0;
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
this_base = get_frame_register_unsigned (this_frame, Z80_SP_REGNUM);
sp = this_base + info->size;
for (;; ++sp)
{
- sp &= sp_mask;
- if (sp < this_base)
+ /* Limit the scan to 4 iterations. If the unwinder's frame
+ size calculation is slightly off (e.g. due to unpopped
+ 16-bit arguments or temporary pushes like SDCC sometimes
+ generates), the return address might be hidden a few
+ bytes deeper. Scanning up to 4 bytes comfortably covers
+ one 32-bit or two 16-bit misplaced values. Scanning
+ further (e.g. 8+ bytes) drastically increases the risk of
+ false positives: we might wander into the caller's local
+ variables, hit a random 0xCD (CALL) byte, and generate a
+ corrupted backtrace. It also prevents massive slow-downs
+ on remote serial targets if the stack is severely
+ corrupted. */
+ if (++loop_count > 4 || sp > addr_space_max)
{ /* overflow, looks like end of stack */
sp = this_base + info->size;
break;
@@ -644,9 +656,14 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
/* Adjust all the saved registers so that they contain addresses and not
offsets. */
for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
- if (info->saved_regs[i].addr () > 0)
- info->saved_regs[i].set_addr
- (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+ {
+ if (info->saved_regs[i].is_addr ())
+ {
+ if (info->saved_regs[i].addr () > 0)
+ info->saved_regs[i].set_addr
+ (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+ }
+ }
/* Except for the startup code, the return PC is always saved on
the stack and is at the base of the frame. */
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] gdb: z80: Fix endless backtrace loop and assertion crashes
2026-06-07 7:48 ` [PATCH v2] " Ronald Hecht
@ 2026-06-14 22:06 ` Kevin Buettner
2026-06-15 6:49 ` Ronald Hecht
2026-06-15 7:04 ` [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types Ronald Hecht
0 siblings, 2 replies; 10+ messages in thread
From: Kevin Buettner @ 2026-06-14 22:06 UTC (permalink / raw)
To: Ronald Hecht; +Cc: gdb-patches
Hi Ronald,
Just a few nits...
On Sun, 7 Jun 2026 09:48:01 +0200
Ronald Hecht <ronald.hecht@gmx.de> wrote:
> This patch fixes two distinct issues in the Z80 frame unwind cache:
>
> 1. An infinite loop in the stack pointer wrapping logic. The `for (;; ++sp)`
> loop could run endlessly if the overflow condition `sp < this_base` was
> never met due to 16-bit address space wrapping. This is fixed by
> checking for `sp > addr_space_max` instead of masking the address.
> Additionally, a `loop_count` is introduced to break out after 4 iterations.
> This prevents severe slow-downs on remote targets caused by scanning
> large portions of the address space when the stack is corrupt.
>
> 2. A potential internal GDB assertion failure. The code previously called
> `.addr()` directly on saved registers without verifying if they actually
> held an address, causing crashes when encountering unexpected register
> states (e.g. REG_UNKNOWN). Added a check for `.is_addr()` beforehand.
>
> gdb/ChangeLog:
> * z80-tdep.c (z80_frame_unwind_cache): Prevent infinite loop by
> checking addr_space_max and adding loop_count. Check is_addr()
> before calling addr().
> ---
> gdb/z80-tdep.c | 29 +++++++++++++++++++++++------
> 1 file changed, 23 insertions(+), 6 deletions(-)
>
> diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
> index 3a0d5f7e393..832433f05cb 100644
> --- a/gdb/z80-tdep.c
> +++ b/gdb/z80-tdep.c
> @@ -595,16 +595,28 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
> {
> CORE_ADDR addr;
> CORE_ADDR sp;
> - CORE_ADDR sp_mask = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
> + CORE_ADDR addr_space_max = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
> enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + int loop_count = 0;
> /* Assume that the FP is this frame's SP but with that pushed
> stack space added back. */
> this_base = get_frame_register_unsigned (this_frame, Z80_SP_REGNUM);
> sp = this_base + info->size;
> for (;; ++sp)
> {
> - sp &= sp_mask;
> - if (sp < this_base)
> + /* Limit the scan to 4 iterations. If the unwinder's frame
> + size calculation is slightly off (e.g. due to unpopped
> + 16-bit arguments or temporary pushes like SDCC sometimes
> + generates), the return address might be hidden a few
> + bytes deeper. Scanning up to 4 bytes comfortably covers
> + one 32-bit or two 16-bit misplaced values. Scanning
> + further (e.g. 8+ bytes) drastically increases the risk of
> + false positives: we might wander into the caller's local
> + variables, hit a random 0xCD (CALL) byte, and generate a
> + corrupted backtrace. It also prevents massive slow-downs
> + on remote serial targets if the stack is severely
> + corrupted. */
There's a whitespace problem in the above comment. Our whitespace
conventions use tabs in the place of (multiples of) 8 leading spaces.
You've used spaces here with no tabs on the continuation lines. (The
first line is correct.)
Another coding convention nit: GNU coding conventions have two spaces
following a period.
Also, I believe that the CALL matching code also matches conditional
call instructions, but you mention only the unconditional case. Not
sure if it's worth changing the comment to cover this, but I thought
I'd mention it.
> + if (++loop_count > 4 || sp > addr_space_max)
> { /* overflow, looks like end of stack */
> sp = this_base + info->size;
> break;
I'm wondering if 4 is enough to handle the eZ80 which has 24 bit addresses
in extended mode? Should the limit change depending on the architecture?
Or, alternately, maybe make the limit depend on the address width?
It occurs to me too that the disjunct which matters most now is the
loop_count check. The comparison against addr_space_max will rarely
if ever be triggered. OTOH, I suppose it still could be when working
at the very end/bottom of the stack. Regardless, it seems to me that
the "overflow, looks like end of stack" comment should be revised as
well.
Kevin
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2] gdb: z80: Fix endless backtrace loop and assertion crashes
2026-06-14 22:06 ` Kevin Buettner
@ 2026-06-15 6:49 ` Ronald Hecht
2026-06-15 7:04 ` [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types Ronald Hecht
1 sibling, 0 replies; 10+ messages in thread
From: Ronald Hecht @ 2026-06-15 6:49 UTC (permalink / raw)
To: Kevin Buettner; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 713 bytes --]
|Hi |Kevin,
Thanks for taking the time to review the patch.
|You are right that a hardcoded 4 is perfect for the 16-bit Z80
(covering two pushed register pairs), but it would fall short for the
eZ80 ADL mode where two pushed registers take up six bytes. Making the
limit dependent on the architecture's address width is a reasonable
solution. Since `addr_len` is already available in the function, I will
change it to `2 * addr_len`. What do you think? I will update the
comments as you suggested: 1. Mentioned conditional CALLs alongside the
unconditional ones. 2. Updated the old "overflow" comment inside the
break block to accurately reflect both exit conditions. Best regards, Ronald|
[-- Attachment #2: Type: text/html, Size: 1301 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types
2026-06-14 22:06 ` Kevin Buettner
2026-06-15 6:49 ` Ronald Hecht
@ 2026-06-15 7:04 ` Ronald Hecht
2026-06-20 20:11 ` Kevin Buettner
1 sibling, 1 reply; 10+ messages in thread
From: Ronald Hecht @ 2026-06-15 7:04 UTC (permalink / raw)
To: gdb-patches; +Cc: Ronald Hecht
In z80_frame_unwind_cache, the loop scanning for the frame base pointer
(for (;; ++sp)) could run into an endless loop or scan too far if the
termination condition (sp < this_base) was not met due to corrupted
or unexpected stack layouts. This patch introduces a loop_count to
limit the scan to a maximum of 2 * addr_len iterations.
Additionally, when iterating through saved registers to adjust their
offsets into concrete addresses, the code now explicitly checks if
the register actually holds an address using is_addr() before calling
addr(). This prevents potential assertions or undefined behavior for
registers that do not contain valid address data.
gdb/ChangeLog:
* z80-tdep.c (z80_frame_unwind_cache): Limit stack scanning
to 2 * addr_len iterations to prevent endless loops. Check
is_addr() before adjusting saved register addresses.
---
gdb/z80-tdep.c | 29 ++++++++++++++++++++++-------
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/gdb/z80-tdep.c b/gdb/z80-tdep.c
index 3a0d5f7e..6828894f 100644
--- a/gdb/z80-tdep.c
+++ b/gdb/z80-tdep.c
@@ -595,17 +595,27 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
{
CORE_ADDR addr;
CORE_ADDR sp;
- CORE_ADDR sp_mask = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
+ CORE_ADDR addr_space_max = (1 << gdbarch_ptr_bit(gdbarch)) - 1;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int loop_count = 0;
/* Assume that the FP is this frame's SP but with that pushed
stack space added back. */
this_base = get_frame_register_unsigned (this_frame, Z80_SP_REGNUM);
sp = this_base + info->size;
for (;; ++sp)
{
- sp &= sp_mask;
- if (sp < this_base)
- { /* overflow, looks like end of stack */
+ /* Limit the scan to 2 * addr_len iterations. If the unwinder's
+ frame size calculation is slightly off (e.g. due to unpopped
+ arguments or temporary pushes), the return address might be
+ hidden a few bytes deeper. Scanning up to 2 * addr_len bytes
+ comfortably covers two misplaced pointer-sized values.
+ Scanning further drastically increases the risk of false
+ positives: we might wander into the caller's local variables,
+ hit a random CALL or conditional CALL opcode, and generate a
+ corrupted backtrace. It also prevents massive slow-downs on
+ remote serial targets if the stack is severely corrupted. */
+ if (++loop_count > 2 * addr_len || sp > addr_space_max)
+ { /* Limit reached or end of address space, assume end of stack. */
sp = this_base + info->size;
break;
}
@@ -644,9 +654,14 @@ z80_frame_unwind_cache (const frame_info_ptr &this_frame,
/* Adjust all the saved registers so that they contain addresses and not
offsets. */
for (i = 0; i < gdbarch_num_regs (gdbarch) - 1; i++)
- if (info->saved_regs[i].addr () > 0)
- info->saved_regs[i].set_addr
- (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+ {
+ if (info->saved_regs[i].is_addr ())
+ {
+ if (info->saved_regs[i].addr () > 0)
+ info->saved_regs[i].set_addr
+ (info->prev_sp - info->saved_regs[i].addr () * addr_len);
+ }
+ }
/* Except for the startup code, the return PC is always saved on
the stack and is at the base of the frame. */
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types
2026-06-15 7:04 ` [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types Ronald Hecht
@ 2026-06-20 20:11 ` Kevin Buettner
2026-06-23 7:16 ` Ronald Hecht
0 siblings, 1 reply; 10+ messages in thread
From: Kevin Buettner @ 2026-06-20 20:11 UTC (permalink / raw)
To: Ronald Hecht; +Cc: gdb-patches
Hi Ronald,
This looks great! Thanks for making the changes I requested.
On Mon, 15 Jun 2026 09:04:01 +0200
Ronald Hecht <ronald.hecht@gmx.de> wrote:
> In z80_frame_unwind_cache, the loop scanning for the frame base pointer
> (for (;; ++sp)) could run into an endless loop or scan too far if the
> termination condition (sp < this_base) was not met due to corrupted
> or unexpected stack layouts. This patch introduces a loop_count to
> limit the scan to a maximum of 2 * addr_len iterations.
>
> Additionally, when iterating through saved registers to adjust their
> offsets into concrete addresses, the code now explicitly checks if
> the register actually holds an address using is_addr() before calling
> addr(). This prevents potential assertions or undefined behavior for
> registers that do not contain valid address data.
>
> gdb/ChangeLog:
>
> * z80-tdep.c (z80_frame_unwind_cache): Limit stack scanning
> to 2 * addr_len iterations to prevent endless loops. Check
> is_addr() before adjusting saved register addresses.
The ChangeLog entry isn't required, but there's no harm in having it in
the commit log. Regardless, don't add it to any ChangeLog files prior
to pushing it.
Approved-By: Kevin Buettner <kevinb@redhat.com>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types
2026-06-20 20:11 ` Kevin Buettner
@ 2026-06-23 7:16 ` Ronald Hecht
2026-07-09 3:52 ` Kevin Buettner
0 siblings, 1 reply; 10+ messages in thread
From: Ronald Hecht @ 2026-06-23 7:16 UTC (permalink / raw)
To: Kevin Buettner; +Cc: gdb-patches
Hi Kevin,
Thank you for the review and the approval! Since I do not have write
access to the GDB repository, could you please push the patch on my behalf?
Best regards,
Ronald
On 6/20/26 22:11, Kevin Buettner wrote:
> Hi Ronald,
>
> This looks great! Thanks for making the changes I requested.
>
> On Mon, 15 Jun 2026 09:04:01 +0200
> Ronald Hecht <ronald.hecht@gmx.de> wrote:
>
>> In z80_frame_unwind_cache, the loop scanning for the frame base pointer
>> (for (;; ++sp)) could run into an endless loop or scan too far if the
>> termination condition (sp < this_base) was not met due to corrupted
>> or unexpected stack layouts. This patch introduces a loop_count to
>> limit the scan to a maximum of 2 * addr_len iterations.
>>
>> Additionally, when iterating through saved registers to adjust their
>> offsets into concrete addresses, the code now explicitly checks if
>> the register actually holds an address using is_addr() before calling
>> addr(). This prevents potential assertions or undefined behavior for
>> registers that do not contain valid address data.
>>
>> gdb/ChangeLog:
>>
>> * z80-tdep.c (z80_frame_unwind_cache): Limit stack scanning
>> to 2 * addr_len iterations to prevent endless loops. Check
>> is_addr() before adjusting saved register addresses.
> The ChangeLog entry isn't required, but there's no harm in having it in
> the commit log. Regardless, don't add it to any ChangeLog files prior
> to pushing it.
>
> Approved-By: Kevin Buettner <kevinb@redhat.com>
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types
2026-06-23 7:16 ` Ronald Hecht
@ 2026-07-09 3:52 ` Kevin Buettner
0 siblings, 0 replies; 10+ messages in thread
From: Kevin Buettner @ 2026-07-09 3:52 UTC (permalink / raw)
To: Ronald Hecht; +Cc: gdb-patches
On Tue, 23 Jun 2026 09:16:28 +0200
Ronald Hecht <ronald.hecht@gmx.de> wrote:
> Thank you for the review and the approval! Since I do not have write
> access to the GDB repository, could you please push the patch on my behalf?
Done. I've pushed your commit:
32a7e94f84a gdb: z80: Fix endless loop in frame unwinder and validate saved register types
Thanks for those z80 cleanups!
Kevin
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-09 3:52 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-05 18:56 [PATCH] gdb: z80: Fix endless backtrace loop and assertion crashes Ronald Hecht
2026-06-06 19:40 ` Kevin Buettner
2026-06-07 7:36 ` Ronald Hecht
2026-06-07 7:48 ` [PATCH v2] " Ronald Hecht
2026-06-14 22:06 ` Kevin Buettner
2026-06-15 6:49 ` Ronald Hecht
2026-06-15 7:04 ` [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types Ronald Hecht
2026-06-20 20:11 ` Kevin Buettner
2026-06-23 7:16 ` Ronald Hecht
2026-07-09 3:52 ` Kevin Buettner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox