[patch rfc] generic POP_FRAME
Mark Kettenis
kettenis@chello.nl
Sat Mar 15 20:11:00 GMT 2003
Andrew Cagney <ac131313@redhat.com> writes:
> I'll look to commit this in a few days.
>
> 2003-03-10 Andrew Cagney <cagney@redhat.com>
>
> Eliminate the need for POP_FRAME.
> * frame-unwind.h (frame_unwind_pop_ftype): Delete definition.
> (struct frame_unwind): Update.
> * frame.c (do_frame_unwind_register): New function.
> (frame_pop): When no POP_FRAME, pop the frame using register
> unwind and a scratch regcache.
> (frame_saved_regs_pop): Delete function.
> (trad_frame_unwinder): Update.
> * d10v-tdep.c (d10v_frame_pop): Delete function.
> (d10v_frame_unwind): Update.
> * sentinel-frame.c (sentinel_frame_pop): Delete function.
> (sentinel_frame_unwinder): Update.
> * dummy-frame.c (dummy_frame_pop): Delete function.
> (dummy_frame_unwind): Update.
Andrew,
This patch has a serious problem:
> Index: frame.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/frame.c,v
> retrieving revision 1.75
> diff -u -r1.75 frame.c
> --- frame.c 10 Mar 2003 15:28:40 -0000 1.75
> +++ frame.c 10 Mar 2003 20:08:38 -0000
> @@ -185,16 +185,44 @@
> return this_frame->pc_unwind_cache;
> }
>
> +static int
> +do_frame_unwind_register (void *src, int regnum, void *buf)
> +{
> + frame_unwind_register (src, regnum, buf);
> + return 1;
> +}
> +
> void
> frame_pop (struct frame_info *frame)
> {
> - /* FIXME: cagney/2003-01-18: There is probably a chicken-egg problem
> - with passing in current_regcache. The pop function needs to be
> - written carefully so as to not overwrite registers whose [old]
> - values are needed to restore other registers. Instead, this code
> - should pass in a scratch cache and, as a second step, restore the
> - registers using that. */
> - frame->unwind->pop (frame, &frame->unwind_cache, current_regcache);
> + struct regcache *scratch_regcache;
> + struct cleanup *cleanups;
> +
> + if (POP_FRAME_P ())
> + {
> + /* A legacy architecture that has implemented a custom pop
> + function. All new architectures should instead be using the
> + generic code below. */
> + POP_FRAME;
> + }
> + else
> + {
> + /* Make a copy of all the register values unwound from this
> + frame. Save them in a scratch buffer so that there isn't a
> + race betweening trying to extract the old values from the
> + current_regcache while, at the same time writing new values
> + into that same cache. */
> + struct regcache *scratch = regcache_xmalloc (current_gdbarch);
> + struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
> + regcache_save (scratch, do_frame_unwind_register, frame);
> + /* Now copy those saved registers into the current regcache.
> + Here, regcache_cpy() calls regcache_restore(). */
> + regcache_cpy (current_regcache, scratch);
> + do_cleanups (cleanups);
> + }
> + /* We've made right mess of GDB's local state, just discard
> + everything. */
> + target_store_registers (-1);
> flush_cached_frames ();
> }
The call to target_store_registers you introduced here, writes back
all registers, including those registers that weren't in the register
cache at all. As a result, on the i386, this typically makes us write
bogus values into the floating-point registers. This makes several
tests in gdb.base/return2.exp fail on my i386-unknown-freebsd4.7
system, since executing a floating-point instruction with the thrashed
floating-point state generates a SIGFPE. I'd expect to see these same
failures on i686-pc-linux-gnu, but I assume that was the target you
tested on. Therefore I suspect that the Linux kernel doesn't let you
write to the floating-point registers since the floating-point state
wasn't initialized yet[1].
Moving the call to target_store_registers() call into the
!POP_FRAME_P() block solves the problem. Do you agree that's the
right approach?
Mark
[1] Initialization of the floating-point state usually happens in a
"lazy" fashion on most i386 OS'es, i.e. upon execution of the first
floating-point rinstruction.
More information about the Gdb-patches
mailing list