-
-/* Functions to use for the COERCE_FLOAT_TO_DOUBLE gdbarch method.
-
- How you should pass arguments to a function depends on whether it
- was defined in K&R style or prototype style. If you define a
- function using the K&R syntax that takes a `float' argument, then
- callers must pass that argument as a `double'. If you define the
- function using the prototype syntax, then you must pass the
- argument as a `float', with no promotion.
-
- Unfortunately, on certain older platforms, the debug info doesn't
- indicate reliably how each function was defined. A function type's
- TYPE_FLAG_PROTOTYPED flag may be clear, even if the function was
- defined in prototype style. When calling a function whose
- TYPE_FLAG_PROTOTYPED flag is clear, GDB consults the
- COERCE_FLOAT_TO_DOUBLE gdbarch method to decide what to do.
-
- For modern targets, it is proper to assume that, if the prototype
- flag is clear, that can be trusted: `float' arguments should be
- promoted to `double'. You should register the function
- `standard_coerce_float_to_double' to get this behavior.
-
- For some older targets, if the prototype flag is clear, that
- doesn't tell us anything. So we guess that, if we don't have a
- type for the formal parameter (i.e., the first argument to
- COERCE_FLOAT_TO_DOUBLE is null), then we should promote it;
- otherwise, we should leave it alone. The function
- `default_coerce_float_to_double' provides this behavior; it is the
- default value, for compatibility with older configurations. */
-int
-default_coerce_float_to_double (struct type *formal, struct type *actual)
-{
- return formal == NULL;
-}
-
-
-int
-standard_coerce_float_to_double (struct type *formal, struct type *actual)
-{
- return 1;
-}
-
-
-/* Perform the standard coercions that are specified
- for arguments to be passed to C functions.
-
- If PARAM_TYPE is non-NULL, it is the expected parameter type.
- IS_PROTOTYPED is non-zero if the function declaration is prototyped. */
-
-static value_ptr
-value_arg_coerce (value_ptr arg, struct type *param_type, int is_prototyped)
-{
- register struct type *arg_type = check_typedef (VALUE_TYPE (arg));
- register struct type *type
- = param_type ? check_typedef (param_type) : arg_type;
-
- switch (TYPE_CODE (type))
- {
- case TYPE_CODE_REF:
- if (TYPE_CODE (arg_type) != TYPE_CODE_REF)
- {
- arg = value_addr (arg);
- VALUE_TYPE (arg) = param_type;
- return arg;
- }
- break;
- case TYPE_CODE_INT:
- case TYPE_CODE_CHAR:
- case TYPE_CODE_BOOL:
- case TYPE_CODE_ENUM:
- /* If we don't have a prototype, coerce to integer type if necessary. */
- if (!is_prototyped)
- {
- if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
- type = builtin_type_int;
- }
- /* Currently all target ABIs require at least the width of an integer
- type for an argument. We may have to conditionalize the following
- type coercion for future targets. */
- if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_int))
- type = builtin_type_int;
- break;
- case TYPE_CODE_FLT:
- /* FIXME: We should always convert floats to doubles in the
- non-prototyped case. As many debugging formats include
- no information about prototyping, we have to live with
- COERCE_FLOAT_TO_DOUBLE for now. */
- if (!is_prototyped && COERCE_FLOAT_TO_DOUBLE (param_type, arg_type))
- {
- if (TYPE_LENGTH (type) < TYPE_LENGTH (builtin_type_double))
- type = builtin_type_double;
- else if (TYPE_LENGTH (type) > TYPE_LENGTH (builtin_type_double))
- type = builtin_type_long_double;
- }
- break;
- case TYPE_CODE_FUNC:
- type = lookup_pointer_type (type);
- break;
- case TYPE_CODE_ARRAY:
- if (current_language->c_style_arrays)
- type = lookup_pointer_type (TYPE_TARGET_TYPE (type));
- break;
- case TYPE_CODE_UNDEF:
- case TYPE_CODE_PTR:
- case TYPE_CODE_STRUCT:
- case TYPE_CODE_UNION:
- case TYPE_CODE_VOID:
- case TYPE_CODE_SET:
- case TYPE_CODE_RANGE:
- case TYPE_CODE_STRING:
- case TYPE_CODE_BITSTRING:
- case TYPE_CODE_ERROR:
- case TYPE_CODE_MEMBER:
- case TYPE_CODE_METHOD:
- case TYPE_CODE_COMPLEX:
- default:
- break;
- }
-
- return value_cast (type, arg);
-}
-
-/* Determine a function's address and its return type from its value.
- Calls error() if the function is not valid for calling. */
-
-static CORE_ADDR
-find_function_addr (value_ptr function, struct type **retval_type)
-{
- register struct type *ftype = check_typedef (VALUE_TYPE (function));
- register enum type_code code = TYPE_CODE (ftype);
- struct type *value_type;
- CORE_ADDR funaddr;
-
- /* If it's a member function, just look at the function
- part of it. */
-
- /* Determine address to call. */
- if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD)
- {
- funaddr = VALUE_ADDRESS (function);
- value_type = TYPE_TARGET_TYPE (ftype);
- }
- else if (code == TYPE_CODE_PTR)
- {
- funaddr = value_as_address (function);
- ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
- if (TYPE_CODE (ftype) == TYPE_CODE_FUNC
- || TYPE_CODE (ftype) == TYPE_CODE_METHOD)
- {
- funaddr = CONVERT_FROM_FUNC_PTR_ADDR (funaddr);
- value_type = TYPE_TARGET_TYPE (ftype);
- }
- else
- value_type = builtin_type_int;
- }
- else if (code == TYPE_CODE_INT)
- {
- /* Handle the case of functions lacking debugging info.
- Their values are characters since their addresses are char */
- if (TYPE_LENGTH (ftype) == 1)
- funaddr = value_as_address (value_addr (function));
- else
- /* Handle integer used as address of a function. */
- funaddr = (CORE_ADDR) value_as_long (function);
-
- value_type = builtin_type_int;
- }
- else
- error ("Invalid data type for function to be called.");
-
- *retval_type = value_type;
- return funaddr;
-}
-
-/* All this stuff with a dummy frame may seem unnecessarily complicated
- (why not just save registers in GDB?). The purpose of pushing a dummy
- frame which looks just like a real frame is so that if you call a
- function and then hit a breakpoint (get a signal, etc), "backtrace"
- will look right. Whether the backtrace needs to actually show the
- stack at the time the inferior function was called is debatable, but
- it certainly needs to not display garbage. So if you are contemplating
- making dummy frames be different from normal frames, consider that. */
-
-/* Perform a function call in the inferior.
- ARGS is a vector of values of arguments (NARGS of them).
- FUNCTION is a value, the function to be called.
- Returns a value representing what the function returned.
- May fail to return, if a breakpoint or signal is hit
- during the execution of the function.
-
- ARGS is modified to contain coerced values. */
-
-static value_ptr hand_function_call (value_ptr function, int nargs,
- value_ptr * args);
-static value_ptr
-hand_function_call (value_ptr function, int nargs, value_ptr *args)
-{
- register CORE_ADDR sp;
- register int i;
- int rc;
- CORE_ADDR start_sp;
- /* CALL_DUMMY is an array of words (REGISTER_SIZE), but each word
- is in host byte order. Before calling FIX_CALL_DUMMY, we byteswap it
- and remove any extra bytes which might exist because ULONGEST is
- bigger than REGISTER_SIZE.
-
- NOTE: This is pretty wierd, as the call dummy is actually a
- sequence of instructions. But CISC machines will have
- to pack the instructions into REGISTER_SIZE units (and
- so will RISC machines for which INSTRUCTION_SIZE is not
- REGISTER_SIZE).
-
- NOTE: This is pretty stupid. CALL_DUMMY should be in strict
- target byte order. */
-
- static ULONGEST *dummy;
- int sizeof_dummy1;
- char *dummy1;
- CORE_ADDR old_sp;
- struct type *value_type;
- unsigned char struct_return;
- CORE_ADDR struct_addr = 0;
- struct inferior_status *inf_status;
- struct cleanup *old_chain;
- CORE_ADDR funaddr;
- int using_gcc; /* Set to version of gcc in use, or zero if not gcc */
- CORE_ADDR real_pc;
- struct type *param_type = NULL;
- struct type *ftype = check_typedef (SYMBOL_TYPE (function));
- int n_method_args = 0;
-
- dummy = alloca (SIZEOF_CALL_DUMMY_WORDS);
- sizeof_dummy1 = REGISTER_SIZE * SIZEOF_CALL_DUMMY_WORDS / sizeof (ULONGEST);
- dummy1 = alloca (sizeof_dummy1);
- memcpy (dummy, CALL_DUMMY_WORDS, SIZEOF_CALL_DUMMY_WORDS);
-
- if (!target_has_execution)
- noprocess ();
-
- inf_status = save_inferior_status (1);
- old_chain = make_cleanup_restore_inferior_status (inf_status);
-
- /* PUSH_DUMMY_FRAME is responsible for saving the inferior registers
- (and POP_FRAME for restoring them). (At least on most machines)
- they are saved on the stack in the inferior. */
- PUSH_DUMMY_FRAME;
-
- old_sp = sp = read_sp ();
-
- if (INNER_THAN (1, 2))
- {
- /* Stack grows down */
- sp -= sizeof_dummy1;
- start_sp = sp;
- }
- else
- {
- /* Stack grows up */
- start_sp = sp;
- sp += sizeof_dummy1;
- }
-
- funaddr = find_function_addr (function, &value_type);
- CHECK_TYPEDEF (value_type);
-
- {
- struct block *b = block_for_pc (funaddr);
- /* If compiled without -g, assume GCC 2. */
- using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
- }
-
- /* Are we returning a value using a structure return or a normal
- value return? */
-
- struct_return = using_struct_return (function, funaddr, value_type,
- using_gcc);
-
- /* Create a call sequence customized for this function
- 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],
- REGISTER_SIZE,
- (ULONGEST) dummy[i]);
-
-#ifdef GDB_TARGET_IS_HPPA
- real_pc = FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
- value_type, using_gcc);
-#else
- FIX_CALL_DUMMY (dummy1, start_sp, funaddr, nargs, args,
- value_type, using_gcc);
- real_pc = start_sp;
-#endif
-
- if (CALL_DUMMY_LOCATION == ON_STACK)
- {
- write_memory (start_sp, (char *) dummy1, sizeof_dummy1);
- }
-
- if (CALL_DUMMY_LOCATION == BEFORE_TEXT_END)
- {
- /* Convex Unix prohibits executing in the stack segment. */
- /* Hope there is empty room at the top of the text segment. */
- extern CORE_ADDR text_end;
- static int checked = 0;
- if (!checked)
- for (start_sp = text_end - sizeof_dummy1; start_sp < text_end; ++start_sp)
- if (read_memory_integer (start_sp, 1) != 0)
- error ("text segment full -- no place to put call");
- checked = 1;
- sp = old_sp;
- real_pc = text_end - sizeof_dummy1;
- write_memory (real_pc, (char *) dummy1, sizeof_dummy1);
- }
-
- if (CALL_DUMMY_LOCATION == AFTER_TEXT_END)
- {
- extern CORE_ADDR text_end;
- int errcode;
- sp = old_sp;
- real_pc = text_end;
- errcode = target_write_memory (real_pc, (char *) dummy1, sizeof_dummy1);
- if (errcode != 0)
- error ("Cannot write text segment -- call_function failed");
- }
-
- if (CALL_DUMMY_LOCATION == AT_ENTRY_POINT)
- {
- real_pc = funaddr;
- }
-
-#ifdef lint
- sp = old_sp; /* It really is used, for some ifdef's... */
-#endif
-
- if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
- {
- i = 0;
- while (TYPE_CODE (TYPE_ARG_TYPES (ftype)[i]) != TYPE_CODE_VOID)
- i++;
- n_method_args = i;
- if (nargs < i)
- error ("too few arguments in method call");
- }
- else if (nargs < TYPE_NFIELDS (ftype))
- error ("too few arguments in function call");
-
- for (i = nargs - 1; i >= 0; i--)
- {
- /* Assume that methods are always prototyped, unless they are off the
- end (which we should only be allowing if there is a ``...'').
- FIXME. */
- if (TYPE_CODE (ftype) == TYPE_CODE_METHOD)
- {
- if (i < n_method_args)
- args[i] = value_arg_coerce (args[i], TYPE_ARG_TYPES (ftype)[i], 1);
- else
- args[i] = value_arg_coerce (args[i], NULL, 0);
- }
-
- /* If we're off the end of the known arguments, do the standard
- promotions. FIXME: if we had a prototype, this should only
- be allowed if ... were present. */
- if (i >= TYPE_NFIELDS (ftype))
- args[i] = value_arg_coerce (args[i], NULL, 0);
-
- else
- {
- param_type = TYPE_FIELD_TYPE (ftype, i);
- args[i] = value_arg_coerce (args[i], param_type, TYPE_PROTOTYPED (ftype));
- }
-
- /*elz: this code is to handle the case in which the function to be called
- has a pointer to function as parameter and the corresponding actual argument
- is the address of a function 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. */
-
- if (using_gcc == 0)
- if (param_type)
- /* if this parameter is a pointer to function */
- if (TYPE_CODE (param_type) == TYPE_CODE_PTR)
- if (TYPE_CODE (param_type->target_type) == TYPE_CODE_FUNC)
- /* elz: FIXME here should go the test about the 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 */
- if (using_gcc == 0) /* && compiler == aCC */
- /* 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 must use a pointer to function type variable. Command ignored.", arg_name);
- }
- }
-
- if (REG_STRUCT_HAS_ADDR_P ())
- {
- /* This is a machine like the sparc, where we may need to pass a
- pointer to the structure, not the structure itself. */
- for (i = nargs - 1; i >= 0; i--)
- {
- struct type *arg_type = check_typedef (VALUE_TYPE (args[i]));
- if ((TYPE_CODE (arg_type) == TYPE_CODE_STRUCT
- || TYPE_CODE (arg_type) == TYPE_CODE_UNION
- || TYPE_CODE (arg_type) == TYPE_CODE_ARRAY
- || TYPE_CODE (arg_type) == TYPE_CODE_STRING
- || TYPE_CODE (arg_type) == TYPE_CODE_BITSTRING
- || TYPE_CODE (arg_type) == TYPE_CODE_SET
- || (TYPE_CODE (arg_type) == TYPE_CODE_FLT
- && TYPE_LENGTH (arg_type) > 8)
- )
- && REG_STRUCT_HAS_ADDR (using_gcc, arg_type))
- {
- CORE_ADDR addr;
- int len; /* = TYPE_LENGTH (arg_type); */
- int aligned_len;
- arg_type = check_typedef (VALUE_ENCLOSING_TYPE (args[i]));
- len = TYPE_LENGTH (arg_type);
-
- if (STACK_ALIGN_P ())
- /* MVS 11/22/96: I think at least some of this
- stack_align code is really broken. Better to let
- PUSH_ARGUMENTS adjust the stack in a target-defined
- manner. */
- aligned_len = STACK_ALIGN (len);
- else
- aligned_len = len;
- if (INNER_THAN (1, 2))
- {
- /* stack grows downward */
- sp -= aligned_len;
- /* ... so the address of the thing we push is the
- stack pointer after we push it. */
- addr = sp;
- }
- else
- {
- /* The stack grows up, so the address of the thing
- we push is the stack pointer before we push it. */
- addr = sp;
- sp += aligned_len;
- }
- /* Push the structure. */
- write_memory (addr, VALUE_CONTENTS_ALL (args[i]), len);
- /* The value we're going to pass is the address of the
- thing we just pushed. */
- /*args[i] = value_from_longest (lookup_pointer_type (value_type),
- (LONGEST) addr); */
- args[i] = value_from_pointer (lookup_pointer_type (arg_type),
- addr);
- }
- }
- }
-
-
- /* Reserve space for the return structure to be written on the
- stack, if necessary */
-
- if (struct_return)
- {
- int len = TYPE_LENGTH (value_type);
- if (STACK_ALIGN_P ())
- /* MVS 11/22/96: I think at least some of this stack_align
- code is really broken. Better to let PUSH_ARGUMENTS adjust
- the stack in a target-defined manner. */
- len = STACK_ALIGN (len);
- if (INNER_THAN (1, 2))
- {
- /* stack grows downward */
- sp -= len;
- struct_addr = sp;
- }
- else
- {
- /* stack grows upward */
- struct_addr = sp;
- sp += len;
- }
- }
-
- /* elz: on HPPA no need for this extra alignment, maybe it is needed
- on other architectures. This is because all the alignment is
- taken care of in the above code (ifdef REG_STRUCT_HAS_ADDR) and
- in hppa_push_arguments */
- if (EXTRA_STACK_ALIGNMENT_NEEDED)
- {
- /* MVS 11/22/96: I think at least some of this stack_align code
- is really broken. Better to let PUSH_ARGUMENTS adjust the
- stack in a target-defined manner. */
- if (STACK_ALIGN_P () && INNER_THAN (1, 2))
- {
- /* If stack grows down, we must leave a hole at the top. */
- int len = 0;
-
- for (i = nargs - 1; i >= 0; i--)
- len += TYPE_LENGTH (VALUE_ENCLOSING_TYPE (args[i]));
- if (CALL_DUMMY_STACK_ADJUST_P)
- len += CALL_DUMMY_STACK_ADJUST;
- sp -= STACK_ALIGN (len) - len;
- }
- }
-
- sp = PUSH_ARGUMENTS (nargs, args, sp, struct_return, struct_addr);
-
- if (PUSH_RETURN_ADDRESS_P ())
- /* for targets that use no CALL_DUMMY */
- /* There are a number of targets now which actually don't write
- any CALL_DUMMY instructions into the target, but instead just
- save the machine state, push the arguments, and jump directly
- to the callee function. Since this doesn't actually involve
- executing a JSR/BSR instruction, the return address must be set
- up by hand, either by pushing onto the stack or copying into a
- return-address register as appropriate. Formerly this has been
- done in PUSH_ARGUMENTS, but that's overloading its
- functionality a bit, so I'm making it explicit to do it here. */
- sp = PUSH_RETURN_ADDRESS (real_pc, sp);
-
- if (STACK_ALIGN_P () && !INNER_THAN (1, 2))
- {
- /* If stack grows up, we must leave a hole at the bottom, note
- that sp already has been advanced for the arguments! */
- if (CALL_DUMMY_STACK_ADJUST_P)
- sp += CALL_DUMMY_STACK_ADJUST;
- sp = STACK_ALIGN (sp);
- }
-
-/* XXX This seems wrong. For stacks that grow down we shouldn't do
- anything here! */
- /* MVS 11/22/96: I think at least some of this stack_align code is
- really broken. Better to let PUSH_ARGUMENTS adjust the stack in
- a target-defined manner. */
- if (CALL_DUMMY_STACK_ADJUST_P)
- if (INNER_THAN (1, 2))
- {
- /* stack grows downward */
- sp -= CALL_DUMMY_STACK_ADJUST;
- }
-
- /* Store the address at which the structure is supposed to be
- written. Note that this (and the code which reserved the space
- above) assumes that gcc was used to compile this function. Since
- it doesn't cost us anything but space and if the function is pcc
- it will ignore this value, we will make that assumption.
-
- Also note that on some machines (like the sparc) pcc uses a
- convention like gcc's. */
-
- if (struct_return)
- STORE_STRUCT_RETURN (struct_addr, sp);
-
- /* Write the stack pointer. This is here because the statements above
- might fool with it. On SPARC, this write also stores the register
- window into the right place in the new stack frame, which otherwise
- wouldn't happen. (See store_inferior_registers in sparc-nat.c.) */
- write_sp (sp);
-
- if (SAVE_DUMMY_FRAME_TOS_P ())
- SAVE_DUMMY_FRAME_TOS (sp);
-
- {
- char *retbuf = (char*) alloca (REGISTER_BYTES);
- char *name;
- struct symbol *symbol;
-
- name = NULL;
- symbol = find_pc_function (funaddr);
- if (symbol)
- {
- name = SYMBOL_SOURCE_NAME (symbol);
- }
- else
- {
- /* Try the minimal symbols. */
- struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (funaddr);
-
- if (msymbol)
- {
- name = SYMBOL_SOURCE_NAME (msymbol);
- }
- }
- if (name == NULL)
- {
- char format[80];
- sprintf (format, "at %s", local_hex_format ());
- name = alloca (80);
- /* FIXME-32x64: assumes funaddr fits in a long. */
- sprintf (name, format, (unsigned long) funaddr);
- }
-
- /* Execute the stack dummy routine, calling FUNCTION.
- When it is done, discard the empty frame
- after storing the contents of all regs into retbuf. */
- rc = run_stack_dummy (real_pc + CALL_DUMMY_START_OFFSET, retbuf);
-
- if (rc == 1)
- {
- /* We stopped inside the FUNCTION because of a random signal.
- Further execution of the FUNCTION is not allowed. */
-
- if (unwind_on_signal_p)
- {
- /* The user wants the context restored. */
-
- /* We must get back to the frame we were before the dummy call. */
- POP_FRAME;
-
- /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
- a C++ name with arguments and stuff. */
- error ("\
-The program being debugged was signaled while in a function called from GDB.\n\
-GDB has restored the context to what it was before the call.\n\
-To change this behavior use \"set unwindonsignal off\"\n\
-Evaluation of the expression containing the function (%s) will be abandoned.",
- name);
- }
- else
- {
- /* The user wants to stay in the frame where we stopped (default).*/
-
- /* If we did the cleanups, we would print a spurious error
- message (Unable to restore previously selected frame),
- would write the registers from the inf_status (which is
- wrong), and would do other wrong things. */
- discard_cleanups (old_chain);
- discard_inferior_status (inf_status);
-
- /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
- a C++ name with arguments and stuff. */
- error ("\
-The program being debugged was signaled while in a function called from GDB.\n\
-GDB remains in the frame where the signal was received.\n\
-To change this behavior use \"set unwindonsignal on\"\n\
-Evaluation of the expression containing the function (%s) will be abandoned.",
- name);
- }
- }
-
- if (rc == 2)
- {
- /* We hit a breakpoint inside the FUNCTION. */
-
- /* If we did the cleanups, we would print a spurious error
- message (Unable to restore previously selected frame),
- would write the registers from the inf_status (which is
- wrong), and would do other wrong things. */
- discard_cleanups (old_chain);
- discard_inferior_status (inf_status);
-
- /* The following error message used to say "The expression
- which contained the function call has been discarded." It
- is a hard concept to explain in a few words. Ideally, GDB
- would be able to resume evaluation of the expression when
- the function finally is done executing. Perhaps someday
- this will be implemented (it would not be easy). */
-
- /* FIXME: Insert a bunch of wrap_here; name can be very long if it's
- a C++ name with arguments and stuff. */
- error ("\
-The program being debugged stopped while in a function called from GDB.\n\
-When the function (%s) is done executing, GDB will silently\n\
-stop (instead of continuing to evaluate the expression containing\n\
-the function call).", name);
- }
-
- /* If we get here the called FUNCTION run to completion. */
- do_cleanups (old_chain);
-
- /* 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
- */
-
-#ifdef VALUE_RETURNED_FROM_STACK
- if (struct_return)
- return (value_ptr) VALUE_RETURNED_FROM_STACK (value_type, struct_addr);
-#endif
-
- return value_being_returned (value_type, retbuf, struct_return);
- }
-}
-
-value_ptr
-call_function_by_hand (value_ptr function, int nargs, value_ptr *args)
-{
- if (CALL_DUMMY_P)
- {
- return hand_function_call (function, nargs, args);
- }
- else
- {
- error ("Cannot invoke functions on this machine.");
- }
-}
-\f
-
-