From: Ronald Hecht <ronald.hecht@gmx.de>
To: gdb-patches@sourceware.org
Cc: Ronald Hecht <ronald.hecht@gmx.de>
Subject: [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types
Date: Mon, 15 Jun 2026 09:04:01 +0200 [thread overview]
Message-ID: <20260615070401.8671-1-ronald.hecht@gmx.de> (raw)
In-Reply-To: <20260614150230.2fd33d6e@f44-mesa-1>
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
next prev parent reply other threads:[~2026-06-15 7:10 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Ronald Hecht [this message]
2026-06-20 20:11 ` [PATCH v3] gdb: z80: Fix endless loop in frame unwinder and validate saved register types Kevin Buettner
2026-06-23 7:16 ` Ronald Hecht
2026-07-09 3:52 ` 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=20260615070401.8671-1-ronald.hecht@gmx.de \
--to=ronald.hecht@gmx.de \
--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