diff options
author | Andrew Cagney <cagney@redhat.com> | 2002-09-18 15:37:18 +0000 |
---|---|---|
committer | Andrew Cagney <cagney@redhat.com> | 2002-09-18 15:37:18 +0000 |
commit | dc60453953d816e84c32b10bcc187100ec090206 (patch) | |
tree | 4ebb3131ab59d027361b42aa01174a3911a506a0 /gdb/valops.c | |
parent | 11350d2a6f73a4a510fa335553e1363857f8b84f (diff) | |
download | gdb-dc60453953d816e84c32b10bcc187100ec090206.zip gdb-dc60453953d816e84c32b10bcc187100ec090206.tar.gz gdb-dc60453953d816e84c32b10bcc187100ec090206.tar.bz2 |
2002-09-18 Andrew Cagney <ac131313@redhat.com>
* valops.c (hand_function_call): Align the initial stack pointer
and STRUCT_ADDR using frame_align. When STRUCT_RETURN and
FRAME_ALIGN_P, use STRUCT_ADDR to obtain the called function's
return value.
* mips-tdep.c (mips_frame_align): New function.
(mips_gdbarch_init): Set frame_align.
* gdbarch.sh (FRAME_ALIGN): New method.
* gdbarch.h, gdbarch.c: Re-generate.
Diffstat (limited to 'gdb/valops.c')
-rw-r--r-- | gdb/valops.c | 111 |
1 files changed, 93 insertions, 18 deletions
diff --git a/gdb/valops.c b/gdb/valops.c index 2e61e88..eaf4295 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -1351,7 +1351,55 @@ hand_function_call (struct value *function, int nargs, struct value **args) they are saved on the stack in the inferior. */ PUSH_DUMMY_FRAME; - old_sp = sp = read_sp (); + old_sp = read_sp (); + + /* Ensure that the initial SP is correctly aligned. */ + if (gdbarch_frame_align_p (current_gdbarch)) + { + /* NOTE: cagney/2002-09-18: + + On a RISC architecture, a void parameterless generic dummy + frame (i.e., no parameters, no result) typically does not + need to push anything the stack and hence can leave SP and + FP. Similarly, a framelss (possibly leaf) function does not + push anything on the stack and, hence, that too can leave FP + and SP unchanged. As a consequence, a sequence of void + parameterless generic dummy frame calls to frameless + functions will create a sequence of effectively identical + frames (SP, FP and TOS and PC the same). This, not + suprisingly, results in what appears to be a stack in an + infinite loop --- when GDB tries to find a generic dummy + frame on the internal dummy frame stack, it will always find + the first one. + + To avoid this problem, the code below always grows the stack. + That way, two dummy frames can never be identical. It does + burn a few bytes of stack but that is a small price to pay + :-). */ + sp = gdbarch_frame_align (current_gdbarch, old_sp); + if (sp == old_sp) + { + if (INNER_THAN (1, 2)) + /* Stack grows down. */ + sp = gdbarch_frame_align (current_gdbarch, old_sp - 1); + else + /* Stack grows up. */ + sp = gdbarch_frame_align (current_gdbarch, old_sp + 1); + } + gdb_assert ((INNER_THAN (1, 2) && sp <= old_sp) + || (INNER_THAN (2, 1) && sp >= old_sp)); + } + else + /* FIXME: cagney/2002-09-18: Hey, you loose! Who knows how badly + aligned the SP is! Further, per comment above, if the generic + dummy frame ends up empty (because nothing is pushed) GDB won't + be able to correctly perform back traces. If a target is + having trouble with backtraces, first thing to do is add + FRAME_ALIGN() to its architecture vector. After that, try + adding SAVE_DUMMY_FRAME_TOS() and modifying FRAME_CHAIN so that + when the next outer frame is a generic dummy, it returns the + current frame's base. */ + sp = old_sp; if (INNER_THAN (1, 2)) { @@ -1366,6 +1414,11 @@ hand_function_call (struct value *function, int nargs, struct value **args) sp += sizeof_dummy1; } + /* NOTE: cagney/2002-09-10: Don't bother re-adjusting the stack + after allocating space for the call dummy. A target can specify + a SIZEOF_DUMMY1 (via SIZEOF_CALL_DUMMY_WORDS) such that all local + alignment requirements are met. */ + funaddr = find_function_addr (function, &value_type); CHECK_TYPEDEF (value_type); @@ -1562,7 +1615,8 @@ You must use a pointer to function type variable. Command ignored.", arg_name); /* Reserve space for the return structure to be written on the - stack, if necessary */ + stack, if necessary. Make certain that the value is correctly + aligned. */ if (struct_return) { @@ -1574,15 +1628,23 @@ You must use a pointer to function type variable. Command ignored.", arg_name); len = STACK_ALIGN (len); if (INNER_THAN (1, 2)) { - /* stack grows downward */ + /* Stack grows downward. Align STRUCT_ADDR and SP after + making space for the return value. */ sp -= len; + if (gdbarch_frame_align_p (current_gdbarch)) + sp = gdbarch_frame_align (current_gdbarch, sp); struct_addr = sp; } else { - /* stack grows upward */ + /* Stack grows upward. Align the frame, allocate space, and + then again, re-align the frame??? */ + if (gdbarch_frame_align_p (current_gdbarch)) + sp = gdbarch_frame_align (current_gdbarch, sp); struct_addr = sp; sp += len; + if (gdbarch_frame_align_p (current_gdbarch)) + sp = gdbarch_frame_align (current_gdbarch, sp); } } @@ -1778,14 +1840,13 @@ the function call).", name); do_cleanups (inf_status_cleanup); /* Figure out the value returned by the function. */ -/* elz: I defined this new macro for the hppa architecture only. - this gives us a way to get the value returned by the function from the stack, - at the same address we told the function to put it. - We cannot assume on the pa that r28 still contains the address of the returned - structure. Usually this will be overwritten by the callee. - I don't know about other architectures, so I defined this macro - */ - + /* elz: I defined this new macro for the hppa architecture only. + this gives us a way to get the value returned by the function + from the stack, at the same address we told the function to put + it. We cannot assume on the pa that r28 still contains the + address of the returned structure. Usually this will be + overwritten by the callee. I don't know about other + architectures, so I defined this macro */ #ifdef VALUE_RETURNED_FROM_STACK if (struct_return) { @@ -1793,12 +1854,26 @@ the function call).", name); return VALUE_RETURNED_FROM_STACK (value_type, struct_addr); } #endif - - { - struct value *retval = value_being_returned (value_type, retbuf, struct_return); - do_cleanups (retbuf_cleanup); - return retval; - } + /* NOTE: cagney/2002-09-10: Only when the stack has been correctly + aligned (using frame_align()) do we can trust STRUCT_ADDR and + fetch the return value direct from the stack. This lack of + trust comes about because legacy targets have a nasty habit of + silently, and local to PUSH_ARGUMENTS(), moving STRUCT_ADDR. + For such targets, just hope that value_being_returned() can + find the adjusted value. */ + if (struct_return && gdbarch_frame_align_p (current_gdbarch)) + { + struct value *retval = value_at (value_type, struct_addr, NULL); + do_cleanups (retbuf_cleanup); + return retval; + } + else + { + struct value *retval = value_being_returned (value_type, retbuf, + struct_return); + do_cleanups (retbuf_cleanup); + return retval; + } } } |