mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-26 13:30:30 +00:00
2003-04-23 Andrew Cagney <cagney@redhat.com>
* infcall.c (call_function_by_hand): Make declaration of "i", "sal", "bpt" and "old_sp" more local to their use. Delete #if lint.
This commit is contained in:
parent
d727590f88
commit
ebc7896c3c
@ -1,3 +1,9 @@
|
|||||||
|
2003-04-23 Andrew Cagney <cagney@redhat.com>
|
||||||
|
|
||||||
|
* infcall.c (call_function_by_hand): Make declaration of "i",
|
||||||
|
"sal", "bpt" and "old_sp" more local to their use. Delete #if
|
||||||
|
lint.
|
||||||
|
|
||||||
2003-04-23 Andrew Cagney <cagney@redhat.com>
|
2003-04-23 Andrew Cagney <cagney@redhat.com>
|
||||||
|
|
||||||
* infcall.c (call_function_by_hand): Delete variable
|
* infcall.c (call_function_by_hand): Delete variable
|
||||||
|
241
gdb/infcall.c
241
gdb/infcall.c
@ -237,7 +237,6 @@ struct value *
|
|||||||
call_function_by_hand (struct value *function, int nargs, struct value **args)
|
call_function_by_hand (struct value *function, int nargs, struct value **args)
|
||||||
{
|
{
|
||||||
register CORE_ADDR sp;
|
register CORE_ADDR sp;
|
||||||
register int i;
|
|
||||||
int rc;
|
int rc;
|
||||||
CORE_ADDR start_sp;
|
CORE_ADDR start_sp;
|
||||||
/* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word
|
/* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word
|
||||||
@ -258,7 +257,6 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
int sizeof_dummy1;
|
int sizeof_dummy1;
|
||||||
char *dummy1;
|
char *dummy1;
|
||||||
CORE_ADDR dummy_addr;
|
CORE_ADDR dummy_addr;
|
||||||
CORE_ADDR old_sp;
|
|
||||||
struct type *value_type;
|
struct type *value_type;
|
||||||
unsigned char struct_return;
|
unsigned char struct_return;
|
||||||
CORE_ADDR struct_addr = 0;
|
CORE_ADDR struct_addr = 0;
|
||||||
@ -322,55 +320,56 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
generic_push_dummy_frame ();
|
generic_push_dummy_frame ();
|
||||||
}
|
}
|
||||||
|
|
||||||
old_sp = read_sp ();
|
|
||||||
|
|
||||||
/* Ensure that the initial SP is correctly aligned. */
|
/* Ensure that the initial SP is correctly aligned. */
|
||||||
if (gdbarch_frame_align_p (current_gdbarch))
|
{
|
||||||
{
|
CORE_ADDR old_sp = read_sp ();
|
||||||
/* NOTE: cagney/2002-09-18:
|
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.
|
||||||
|
|
||||||
On a RISC architecture, a void parameterless generic dummy
|
To avoid this problem, the code below always grows the
|
||||||
frame (i.e., no parameters, no result) typically does not
|
stack. That way, two dummy frames can never be identical.
|
||||||
need to push anything the stack and hence can leave SP and
|
It does burn a few bytes of stack but that is a small price
|
||||||
FP. Similarly, a framelss (possibly leaf) function does not
|
to pay :-). */
|
||||||
push anything on the stack and, hence, that too can leave FP
|
sp = gdbarch_frame_align (current_gdbarch, old_sp);
|
||||||
and SP unchanged. As a consequence, a sequence of void
|
if (sp == old_sp)
|
||||||
parameterless generic dummy frame calls to frameless
|
{
|
||||||
functions will create a sequence of effectively identical
|
if (INNER_THAN (1, 2))
|
||||||
frames (SP, FP and TOS and PC the same). This, not
|
/* Stack grows down. */
|
||||||
suprisingly, results in what appears to be a stack in an
|
sp = gdbarch_frame_align (current_gdbarch, old_sp - 1);
|
||||||
infinite loop --- when GDB tries to find a generic dummy
|
else
|
||||||
frame on the internal dummy frame stack, it will always find
|
/* Stack grows up. */
|
||||||
the first one.
|
sp = gdbarch_frame_align (current_gdbarch, old_sp + 1);
|
||||||
|
}
|
||||||
To avoid this problem, the code below always grows the stack.
|
gdb_assert ((INNER_THAN (1, 2) && sp <= old_sp)
|
||||||
That way, two dummy frames can never be identical. It does
|
|| (INNER_THAN (2, 1) && sp >= old_sp));
|
||||||
burn a few bytes of stack but that is a small price to pay
|
}
|
||||||
:-). */
|
else
|
||||||
sp = gdbarch_frame_align (current_gdbarch, old_sp);
|
/* FIXME: cagney/2002-09-18: Hey, you loose! Who knows how
|
||||||
if (sp == old_sp)
|
badly aligned the SP is! Further, per comment above, if the
|
||||||
{
|
generic dummy frame ends up empty (because nothing is pushed)
|
||||||
if (INNER_THAN (1, 2))
|
GDB won't be able to correctly perform back traces. If a
|
||||||
/* Stack grows down. */
|
target is having trouble with backtraces, first thing to do
|
||||||
sp = gdbarch_frame_align (current_gdbarch, old_sp - 1);
|
is add FRAME_ALIGN() to its architecture vector. After that,
|
||||||
else
|
try adding SAVE_DUMMY_FRAME_TOS() and modifying
|
||||||
/* Stack grows up. */
|
DEPRECATED_FRAME_CHAIN so that when the next outer frame is a
|
||||||
sp = gdbarch_frame_align (current_gdbarch, old_sp + 1);
|
generic dummy, it returns the current frame's base. */
|
||||||
}
|
sp = old_sp;
|
||||||
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
|
|
||||||
DEPRECATED_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))
|
if (INNER_THAN (1, 2))
|
||||||
{
|
{
|
||||||
@ -407,10 +406,13 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
|
|
||||||
/* Create a call sequence customized for this function
|
/* Create a call sequence customized for this function
|
||||||
and the number of arguments for it. */
|
and the number of arguments for it. */
|
||||||
for (i = 0; i < (int) (SIZEOF_CALL_DUMMY_WORDS / sizeof (dummy[0])); i++)
|
{
|
||||||
store_unsigned_integer (&dummy1[i * REGISTER_SIZE],
|
int i;
|
||||||
REGISTER_SIZE,
|
for (i = 0; i < (int) (SIZEOF_CALL_DUMMY_WORDS / sizeof (dummy[0])); i++)
|
||||||
(ULONGEST) dummy[i]);
|
store_unsigned_integer (&dummy1[i * REGISTER_SIZE],
|
||||||
|
REGISTER_SIZE,
|
||||||
|
(ULONGEST) dummy[i]);
|
||||||
|
}
|
||||||
|
|
||||||
switch (CALL_DUMMY_LOCATION)
|
switch (CALL_DUMMY_LOCATION)
|
||||||
{
|
{
|
||||||
@ -459,72 +461,74 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
internal_error (__FILE__, __LINE__, "bad switch");
|
internal_error (__FILE__, __LINE__, "bad switch");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef lint
|
|
||||||
sp = old_sp; /* It really is used, for some ifdef's... */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (nargs < TYPE_NFIELDS (ftype))
|
if (nargs < TYPE_NFIELDS (ftype))
|
||||||
error ("too few arguments in function call");
|
error ("too few arguments in function call");
|
||||||
|
|
||||||
for (i = nargs - 1; i >= 0; i--)
|
{
|
||||||
{
|
int i;
|
||||||
int prototyped;
|
for (i = nargs - 1; i >= 0; i--)
|
||||||
struct type *param_type;
|
{
|
||||||
|
int prototyped;
|
||||||
|
struct type *param_type;
|
||||||
|
|
||||||
|
/* FIXME drow/2002-05-31: Should just always mark methods as
|
||||||
|
prototyped. Can we respect TYPE_VARARGS? Probably not. */
|
||||||
|
if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
|
||||||
|
prototyped = 1;
|
||||||
|
else if (i < TYPE_NFIELDS (ftype))
|
||||||
|
prototyped = TYPE_PROTOTYPED (ftype);
|
||||||
|
else
|
||||||
|
prototyped = 0;
|
||||||
|
|
||||||
/* FIXME drow/2002-05-31: Should just always mark methods as
|
if (i < TYPE_NFIELDS (ftype))
|
||||||
prototyped. Can we respect TYPE_VARARGS? Probably not. */
|
param_type = TYPE_FIELD_TYPE (ftype, i);
|
||||||
if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
|
else
|
||||||
prototyped = 1;
|
param_type = NULL;
|
||||||
else if (i < TYPE_NFIELDS (ftype))
|
|
||||||
prototyped = TYPE_PROTOTYPED (ftype);
|
args[i] = value_arg_coerce (args[i], param_type, prototyped);
|
||||||
else
|
|
||||||
prototyped = 0;
|
|
||||||
|
|
||||||
if (i < TYPE_NFIELDS (ftype))
|
/* elz: this code is to handle the case in which the function
|
||||||
param_type = TYPE_FIELD_TYPE (ftype, i);
|
to be called has a pointer to function as parameter and the
|
||||||
else
|
corresponding actual argument is the address of a function
|
||||||
param_type = NULL;
|
and not a pointer to function variable. In aCC compiled
|
||||||
|
code, the calls through pointers to functions (in the body
|
||||||
|
of the function called by hand) are made via
|
||||||
|
$$dyncall_external which requires some registers setting,
|
||||||
|
this is taken care of if we call via a function pointer
|
||||||
|
variable, but not via a function address. In cc this is
|
||||||
|
not a problem. */
|
||||||
|
|
||||||
args[i] = value_arg_coerce (args[i], param_type, prototyped);
|
if (using_gcc == 0)
|
||||||
|
{
|
||||||
/* elz: this code is to handle the case in which the function to
|
if (param_type != NULL && TYPE_CODE (ftype) != TYPE_CODE_METHOD)
|
||||||
be called has a pointer to function as parameter and the
|
{
|
||||||
corresponding actual argument is the address of a function
|
/* if this parameter is a pointer to function. */
|
||||||
and not a pointer to function variable. In aCC compiled
|
if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
|
||||||
code, the calls through pointers to functions (in the body of
|
if (TYPE_CODE (TYPE_TARGET_TYPE (param_type)) == TYPE_CODE_FUNC)
|
||||||
the function called by hand) are made via $$dyncall_external
|
/* elz: FIXME here should go the test about the
|
||||||
which requires some registers setting, this is taken care of
|
compiler used to compile the target. We want to
|
||||||
if we call via a function pointer variable, but not via a
|
issue the error message only if the compiler
|
||||||
function address. In cc this is not a problem. */
|
used was HP's aCC. If we used HP's cc, then
|
||||||
|
there is no problem and no need to return at
|
||||||
if (using_gcc == 0)
|
this point. */
|
||||||
{
|
/* Go see if the actual parameter is a variable of
|
||||||
if (param_type != NULL && TYPE_CODE (ftype) != TYPE_CODE_METHOD)
|
type pointer to function or just a function. */
|
||||||
{
|
if (args[i]->lval == not_lval)
|
||||||
/* if this parameter is a pointer to function. */
|
{
|
||||||
if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
|
char *arg_name;
|
||||||
if (TYPE_CODE (TYPE_TARGET_TYPE (param_type)) == TYPE_CODE_FUNC)
|
if (find_pc_partial_function ((CORE_ADDR) args[i]->aligner.contents[0], &arg_name, NULL, NULL))
|
||||||
/* elz: FIXME here should go the test about the
|
error ("\
|
||||||
compiler used to compile the target. We want to
|
|
||||||
issue the error message only if the compiler used
|
|
||||||
was HP's aCC. If we used HP's cc, then there is
|
|
||||||
no problem and no need to return at this point. */
|
|
||||||
/* Go see if the actual parameter is a variable of
|
|
||||||
type pointer to function or just a function. */
|
|
||||||
if (args[i]->lval == not_lval)
|
|
||||||
{
|
|
||||||
char *arg_name;
|
|
||||||
if (find_pc_partial_function ((CORE_ADDR) args[i]->aligner.contents[0], &arg_name, NULL, NULL))
|
|
||||||
error ("\
|
|
||||||
You cannot use function <%s> as argument. \n\
|
You cannot use function <%s> as argument. \n\
|
||||||
You must use a pointer to function type variable. Command ignored.", arg_name);
|
You must use a pointer to function type variable. Command ignored.", arg_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (REG_STRUCT_HAS_ADDR_P ())
|
if (REG_STRUCT_HAS_ADDR_P ())
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
/* This is a machine like the sparc, where we may need to pass a
|
/* This is a machine like the sparc, where we may need to pass a
|
||||||
pointer to the structure, not the structure itself. */
|
pointer to the structure, not the structure itself. */
|
||||||
for (i = nargs - 1; i >= 0; i--)
|
for (i = nargs - 1; i >= 0; i--)
|
||||||
@ -632,7 +636,7 @@ You must use a pointer to function type variable. Command ignored.", arg_name);
|
|||||||
{
|
{
|
||||||
/* If stack grows down, we must leave a hole at the top. */
|
/* If stack grows down, we must leave a hole at the top. */
|
||||||
int len = 0;
|
int len = 0;
|
||||||
|
int i;
|
||||||
for (i = nargs - 1; i >= 0; i--)
|
for (i = nargs - 1; i >= 0; i--)
|
||||||
len += TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
|
len += TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
|
||||||
if (DEPRECATED_CALL_DUMMY_STACK_ADJUST_P ())
|
if (DEPRECATED_CALL_DUMMY_STACK_ADJUST_P ())
|
||||||
@ -774,24 +778,25 @@ You must use a pointer to function type variable. Command ignored.", arg_name);
|
|||||||
struct regcache *buffer = retbuf;
|
struct regcache *buffer = retbuf;
|
||||||
struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
|
struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
|
||||||
int saved_async = 0;
|
int saved_async = 0;
|
||||||
struct breakpoint *bpt;
|
|
||||||
struct symtab_and_line sal;
|
|
||||||
|
|
||||||
/* Now proceed, having reached the desired place. */
|
/* Now proceed, having reached the desired place. */
|
||||||
clear_proceed_status ();
|
clear_proceed_status ();
|
||||||
|
|
||||||
init_sal (&sal); /* initialize to zeroes */
|
/* Create a momentary breakpoint at the return address of the
|
||||||
sal.pc = bp_addr;
|
inferior. That way it breaks when it returns. */
|
||||||
sal.section = find_pc_overlay (sal.pc);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
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 up a frame ID for the dummy frame so we can pass it to
|
||||||
set_momentary_breakpoint. We need to give the breakpoint a
|
set_momentary_breakpoint. We need to give the breakpoint a
|
||||||
frame ID so that the breakpoint code can correctly
|
frame ID so that the breakpoint code can correctly
|
||||||
re-identify the dummy breakpoint. */
|
re-identify the dummy breakpoint. */
|
||||||
struct frame_id frame = frame_id_build (read_fp (), sal.pc);
|
frame = frame_id_build (read_fp (), sal.pc);
|
||||||
/* Create a momentary breakpoint at the return address of the
|
|
||||||
inferior. That way it breaks when it returns. */
|
|
||||||
bpt = set_momentary_breakpoint (sal, frame, bp_call_dummy);
|
bpt = set_momentary_breakpoint (sal, frame, bp_call_dummy);
|
||||||
bpt->disposition = disp_del;
|
bpt->disposition = disp_del;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user