From 96860204a5b8c68b406f7b44793d57183c10d2fb Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Mon, 2 Aug 2004 17:39:53 +0000 Subject: [PATCH] 2004-08-02 Andrew Cagney * dummy-frame.c: Include "gdb_string.h". (generic_save_call_dummy_addr, generic_push_dummy_frame) (generic_save_dummy_frame_tos): Delete. (dummy_frame_push): New function, replaces above. * dummy-frame.h: Update copyright. (dummy_frame_push): Declare. * frame.h (generic_save_dummy_frame_tos, generic_push_dummy_frame) (generic_save_call_dummy_addr): Delete declarations. * infcall.c: Include "dummy-frame.h". (call_function_by_hand): Add locals caller_regcache, caller_regcache_cleanup and dummy_id. Replace push_dummy_frame with call to frame_save_as_regcache plus cleanup. Delete calls to generic_save_call_dummy_addr and generic_save_dummy_frame_tos. Move clear_proceed_status to just before the resume, add call to dummy_frame_push (discard cleanup). * Makefile.in (infcall.o): Add $(dummy_frame_h). (dummy-frame.o): Add $(gdb_string_h). --- gdb/ChangeLog | 20 ++++++++++++++++ gdb/Makefile.in | 5 ++-- gdb/dummy-frame.c | 56 ++++++++++++++++--------------------------- gdb/dummy-frame.h | 18 +++++++++++++- gdb/frame.h | 6 ----- gdb/infcall.c | 61 ++++++++++++++++++++++------------------------- 6 files changed, 90 insertions(+), 76 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b42caa5188..b80d61a75d 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +2004-08-02 Andrew Cagney + + * dummy-frame.c: Include "gdb_string.h". + (generic_save_call_dummy_addr, generic_push_dummy_frame) + (generic_save_dummy_frame_tos): Delete. + (dummy_frame_push): New function, replaces above. + * dummy-frame.h: Update copyright. + (dummy_frame_push): Declare. + * frame.h (generic_save_dummy_frame_tos, generic_push_dummy_frame) + (generic_save_call_dummy_addr): Delete declarations. + * infcall.c: Include "dummy-frame.h". + (call_function_by_hand): Add locals caller_regcache, + caller_regcache_cleanup and dummy_id. Replace push_dummy_frame + with call to frame_save_as_regcache plus cleanup. Delete calls to + generic_save_call_dummy_addr and generic_save_dummy_frame_tos. + Move clear_proceed_status to just before the resume, add call to + dummy_frame_push (discard cleanup). + * Makefile.in (infcall.o): Add $(dummy_frame_h). + (dummy-frame.o): Add $(gdb_string_h). + 2004-08-01 Andrew Cagney * dummy-frame.h (dummy_frame_unwind): Replace dummy_frame_sniffer. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 865d3a915f..56d9ef6225 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1828,7 +1828,7 @@ dsrec.o: dsrec.c $(defs_h) $(serial_h) $(srec_h) $(gdb_assert_h) \ $(gdb_string_h) dummy-frame.o: dummy-frame.c $(defs_h) $(dummy_frame_h) $(regcache_h) \ $(frame_h) $(inferior_h) $(gdb_assert_h) $(frame_unwind_h) \ - $(command_h) $(gdbcmd_h) + $(command_h) $(gdbcmd_h) $(gdb_string_h) dve3900-rom.o: dve3900-rom.c $(defs_h) $(gdbcore_h) $(target_h) $(monitor_h) \ $(serial_h) $(inferior_h) $(command_h) $(gdb_string_h) $(regcache_h) \ $(mips_tdep_h) @@ -2043,7 +2043,8 @@ ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(gdbcore_h) \ $(libunwind_frame_h) $(libunwind_ia64_h) infcall.o: infcall.c $(defs_h) $(breakpoint_h) $(target_h) $(regcache_h) \ $(inferior_h) $(gdb_assert_h) $(block_h) $(gdbcore_h) $(language_h) \ - $(objfiles_h) $(gdbcmd_h) $(command_h) $(gdb_string_h) $(infcall_h) + $(objfiles_h) $(gdbcmd_h) $(command_h) $(gdb_string_h) $(infcall_h) \ + $(dummy_frame_h) infcmd.o: infcmd.c $(defs_h) $(gdb_string_h) $(symtab_h) $(gdbtypes_h) \ $(frame_h) $(inferior_h) $(environ_h) $(value_h) $(gdbcmd_h) \ $(symfile_h) $(gdbcore_h) $(target_h) $(language_h) $(symfile_h) \ diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c index 1945a00d96..53365f4169 100644 --- a/gdb/dummy-frame.c +++ b/gdb/dummy-frame.c @@ -31,6 +31,7 @@ #include "frame-unwind.h" #include "command.h" #include "gdbcmd.h" +#include "gdb_string.h" static int pc_in_dummy_frame (CORE_ADDR pc); @@ -94,27 +95,24 @@ pc_in_dummy_frame (CORE_ADDR pc) return 0; } -/* Save all the registers on the dummy frame stack. Most ports save the - registers on the target stack. This results in lots of unnecessary memory - references, which are slow when debugging via a serial line. Instead, we - save all the registers internally, and never write them to the stack. The - registers get restored when the called function returns to the entry point, - where a breakpoint is laying in wait. */ +/* Push the caller's state, along with the dummy frame info, onto a + dummy-frame stack. */ void -generic_push_dummy_frame (void) +dummy_frame_push (struct regcache *caller_regcache, + const struct frame_id *dummy_id) { struct dummy_frame *dummy_frame; - CORE_ADDR fp = get_frame_base (get_current_frame ()); - - /* check to see if there are stale dummy frames, - perhaps left over from when a longjump took us out of a - function that was called by the debugger */ + /* Check to see if there are stale dummy frames, perhaps left over + from when a longjump took us out of a function that was called by + the debugger. */ dummy_frame = dummy_frame_stack; while (dummy_frame) - if (gdbarch_inner_than (current_gdbarch, dummy_frame->top, fp)) - /* stale -- destroy! */ + /* FIXME: cagney/2004-08-02: Should just test IDs. */ + if (gdbarch_inner_than (current_gdbarch, dummy_frame->top, + dummy_id->stack_addr)) + /* Stale -- destroy! */ { dummy_frame_stack = dummy_frame->next; regcache_xfree (dummy_frame->regcache); @@ -124,31 +122,19 @@ generic_push_dummy_frame (void) else dummy_frame = dummy_frame->next; - dummy_frame = xmalloc (sizeof (struct dummy_frame)); - dummy_frame->regcache = frame_save_as_regcache (get_current_frame ()); - - dummy_frame->pc = read_pc (); - dummy_frame->top = 0; - dummy_frame->id = get_frame_id (get_current_frame ()); + dummy_frame = XZALLOC (struct dummy_frame); + dummy_frame->regcache = caller_regcache; + dummy_frame->id = (*dummy_id); + /* FIXME: cagney/2004-08-02: Retain for compatibility - trust the + ID. */ + dummy_frame->pc = dummy_id->code_addr; + dummy_frame->top = dummy_id->stack_addr; + dummy_frame->call_lo = dummy_id->code_addr + 0; + dummy_frame->call_hi = dummy_id->code_addr + 1; dummy_frame->next = dummy_frame_stack; dummy_frame_stack = dummy_frame; } -void -generic_save_dummy_frame_tos (CORE_ADDR sp) -{ - dummy_frame_stack->top = sp; -} - -/* Record the upper/lower bounds on the address of the call dummy. */ - -void -generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi) -{ - dummy_frame_stack->call_lo = lo; - dummy_frame_stack->call_hi = hi; -} - /* Return the dummy frame cache, it contains both the ID, and a pointer to the regcache. */ struct dummy_frame_cache diff --git a/gdb/dummy-frame.h b/gdb/dummy-frame.h index 26c2522a7c..7ce7973f0a 100644 --- a/gdb/dummy-frame.h +++ b/gdb/dummy-frame.h @@ -1,6 +1,6 @@ /* Code dealing with dummy stack frames, for GDB, the GNU debugger. - Copyright 2002 Free Software Foundation, Inc. + Copyright 2002, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -27,6 +27,22 @@ struct regcache; struct frame_unwind; struct frame_id; +/* Push the information needed to identify, and unwind from, a dummy + frame onto the dummy frame stack. */ + +/* NOTE: cagney/2004-08-02: This interface will eventually need to be + parameterized with the caller's thread - that will allow per-thread + dummy-frame stacks and, hence, per-thread inferior function + calls. */ + +/* NOTE: cagney/2004-08-02: In the case of ABIs using push_dummy_code + containing more than one instruction, this interface many need to + be expanded so that it knowns the lower/upper extent of the dummy + frame's code. */ + +extern void dummy_frame_push (struct regcache *regcache, + const struct frame_id *dummy_id); + /* If the PC falls in a dummy frame, return a dummy frame unwinder. */ diff --git a/gdb/frame.h b/gdb/frame.h index 75b0c9e00f..942f7b197e 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -521,8 +521,6 @@ extern void *frame_obstack_zalloc (unsigned long size); /* Create a regcache, and copy the frame's registers into it. */ struct regcache *frame_save_as_regcache (struct frame_info *this_frame); -extern void generic_save_dummy_frame_tos (CORE_ADDR sp); - extern struct block *get_frame_block (struct frame_info *, CORE_ADDR *addr_in_block); @@ -575,12 +573,8 @@ extern void print_frame_info (struct frame_info *, int print_level, extern struct frame_info *block_innermost_frame (struct block *); -extern void generic_push_dummy_frame (void); - extern int deprecated_pc_in_call_dummy (CORE_ADDR pc); -extern void generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi); - /* FIXME: cagney/2003-02-02: Should be deprecated or replaced with a function called get_frame_register_p(). This slightly weird (and older) variant of get_frame_register() returns zero (indicating the diff --git a/gdb/infcall.c b/gdb/infcall.c index fce9cc0cf4..ade9943337 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -35,6 +35,7 @@ #include "command.h" #include "gdb_string.h" #include "infcall.h" +#include "dummy-frame.h" /* NOTE: cagney/2003-04-16: What's the future of this code? @@ -308,6 +309,9 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) CORE_ADDR real_pc; struct type *ftype = check_typedef (SYMBOL_TYPE (function)); CORE_ADDR bp_addr; + struct regcache *caller_regcache; + struct cleanup *caller_regcache_cleanup; + struct frame_id dummy_id; if (!target_has_execution) noprocess (); @@ -325,23 +329,12 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) inf_status = save_inferior_status (1); inf_status_cleanup = make_cleanup_restore_inferior_status (inf_status); - /* FIXME: cagney/2003-02-26: Step zero of this little tinker is to - extract the generic dummy frame code from the architecture - vector. Hence this direct call. - - A follow-on change is to modify this interface so that it takes - thread OR frame OR ptid as a parameter, and returns a dummy frame - handle. The handle can then be used further down as a parameter - to generic_save_dummy_frame_tos(). Hmm, thinking about it, since - everything is ment to be using generic dummy frames, why not even - use some of the dummy frame code to here - do a regcache dup and - then pass the duped regcache, along with all the other stuff, at - one single point. - - In fact, you can even save the structure's return address in the - dummy frame and fix one of those nasty lost struct return edge - conditions. */ - generic_push_dummy_frame (); + /* Save the caller's registers so that they can be restored once the + callee returns. To allow nested calls the registers are (further + down) pushed onto a dummy frame stack. Include a cleanup (which + is tossed once the regcache has been pushed). */ + caller_regcache = frame_save_as_regcache (get_current_frame ()); + caller_regcache_cleanup = make_cleanup_regcache_xfree (caller_regcache); /* Ensure that the initial SP is correctly aligned. */ { @@ -491,10 +484,6 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) internal_error (__FILE__, __LINE__, "bad switch"); } - /* Save where the breakpoint is going to be inserted so that the - dummy-frame code is later able to re-identify it. */ - generic_save_call_dummy_addr (bp_addr, bp_addr + 1); - if (nargs < TYPE_NFIELDS (ftype)) error ("too few arguments in function call"); @@ -660,36 +649,44 @@ You must use a pointer to function type variable. Command ignored.", arg_name); else error ("This target does not support function calls"); + /* Set up a frame ID for the dummy frame so we can pass it to + set_momentary_breakpoint. We need to give the breakpoint a frame + ID so that the breakpoint code can correctly re-identify the + dummy breakpoint. */ /* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by unwind_dummy_id to form the frame ID's stack address. */ - generic_save_dummy_frame_tos (sp); + dummy_id = frame_id_build (sp, bp_addr); - /* Now proceed, having reached the desired place. */ - clear_proceed_status (); - /* Create a momentary breakpoint at the return address of the inferior. That way it breaks when it returns. */ { struct breakpoint *bpt; struct symtab_and_line sal; - struct frame_id frame; init_sal (&sal); /* initialize to zeroes */ sal.pc = bp_addr; sal.section = find_pc_overlay (sal.pc); - /* Set up a frame ID for the dummy frame so we can pass it to - set_momentary_breakpoint. We need to give the breakpoint a - frame ID so that the breakpoint code can correctly re-identify - the dummy breakpoint. */ /* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by unwind_dummy_id to form the frame ID's stack address. */ - frame = frame_id_build (sp, sal.pc); - bpt = set_momentary_breakpoint (sal, frame, bp_call_dummy); + bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy); bpt->disposition = disp_del; } + /* Everything's ready, push all the info needed to restore the + caller (and identify the dummy-frame) onto the dummy-frame + stack. */ + dummy_frame_push (caller_regcache, &dummy_id); + discard_cleanups (caller_regcache_cleanup); + + /* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - + If you're looking to implement asynchronous dummy-frames, then + just below is the place to chop this function in two.. */ + + /* Now proceed, having reached the desired place. */ + clear_proceed_status (); + /* Execute a "stack dummy", a piece of code stored in the stack by the debugger to be executed in the inferior.