* infcall.c (call_function_by_hand): Handle language-specific
pass and return by reference. * cp-abi.c (cp_pass_by_reference): New. * cp-abi.h (cp_pass_by_reference): Declare. (struct cp_abi_ops): Add pass_by_reference. * gnu-v3-abi.c (gnuv3_pass_by_reference): New. (init_gnuv3_ops): Set pass_by_reference. * language.c (language_pass_by_reference): New. (default_pass_by_reference): New. (unknown_language_defn, auto_language_defn, local_language_defn): Add default_pass_by_reference. * langauge.h (struct language_defn): Add la_pass_by_reference. (language_pass_by_reference, default_pass_by_reference): Declare. * ada-lang.c (ada_language_defn): Add default_pass_by_reference. * c-lang.c (c_language_defn, asm_language_defn) (minimal_language_defn): Likewise. (cplus_language_defn): Add cp_pass_by_reference. * f-lang.c (f_language_defn): Add default_pass_by_reference. * jv-lang.c (java_language_defn): Likewise. * m2-lang.c (m2_language_defn): Likewise. * objc-lang.c (objc_language_defn): Likewise. * p-lang.c (pascal_language_defn): Likewise. * scm-lang.c (scm_language_defn): Likewise * gdb.cp/pass-by-ref.cc, gdb.cp/pass-by-ref.exp: New files.
This commit is contained in:
parent
3f213f78ed
commit
41f1b6975d
@ -1,3 +1,31 @@
|
|||||||
|
2007-09-23 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
|
* infcall.c (call_function_by_hand): Handle language-specific
|
||||||
|
pass and return by reference.
|
||||||
|
|
||||||
|
* cp-abi.c (cp_pass_by_reference): New.
|
||||||
|
* cp-abi.h (cp_pass_by_reference): Declare.
|
||||||
|
(struct cp_abi_ops): Add pass_by_reference.
|
||||||
|
* gnu-v3-abi.c (gnuv3_pass_by_reference): New.
|
||||||
|
(init_gnuv3_ops): Set pass_by_reference.
|
||||||
|
|
||||||
|
* language.c (language_pass_by_reference): New.
|
||||||
|
(default_pass_by_reference): New.
|
||||||
|
(unknown_language_defn, auto_language_defn, local_language_defn): Add
|
||||||
|
default_pass_by_reference.
|
||||||
|
* langauge.h (struct language_defn): Add la_pass_by_reference.
|
||||||
|
(language_pass_by_reference, default_pass_by_reference): Declare.
|
||||||
|
* ada-lang.c (ada_language_defn): Add default_pass_by_reference.
|
||||||
|
* c-lang.c (c_language_defn, asm_language_defn)
|
||||||
|
(minimal_language_defn): Likewise.
|
||||||
|
(cplus_language_defn): Add cp_pass_by_reference.
|
||||||
|
* f-lang.c (f_language_defn): Add default_pass_by_reference.
|
||||||
|
* jv-lang.c (java_language_defn): Likewise.
|
||||||
|
* m2-lang.c (m2_language_defn): Likewise.
|
||||||
|
* objc-lang.c (objc_language_defn): Likewise.
|
||||||
|
* p-lang.c (pascal_language_defn): Likewise.
|
||||||
|
* scm-lang.c (scm_language_defn): Likewise
|
||||||
|
|
||||||
2007-09-23 Vladimir Prus <vladimir@codesourcery.com>
|
2007-09-23 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
Allow a code breakpoint to have several locations
|
Allow a code breakpoint to have several locations
|
||||||
|
@ -10441,6 +10441,7 @@ const struct language_defn ada_language_defn = {
|
|||||||
ada_get_gdb_completer_word_break_characters,
|
ada_get_gdb_completer_word_break_characters,
|
||||||
ada_language_arch_info,
|
ada_language_arch_info,
|
||||||
ada_print_array_index,
|
ada_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -606,6 +606,7 @@ const struct language_defn c_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
c_language_arch_info,
|
c_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -711,6 +712,7 @@ const struct language_defn cplus_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
cplus_language_arch_info,
|
cplus_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
cp_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -747,6 +749,7 @@ const struct language_defn asm_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
c_language_arch_info, /* FIXME: la_language_arch_info. */
|
c_language_arch_info, /* FIXME: la_language_arch_info. */
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -788,6 +791,7 @@ const struct language_defn minimal_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
c_language_arch_info,
|
c_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -135,6 +135,14 @@ cplus_method_ptr_to_value (struct value **this_p, struct value *method_ptr)
|
|||||||
return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr);
|
return (*current_cp_abi.method_ptr_to_value) (this_p, method_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
cp_pass_by_reference (struct type *type)
|
||||||
|
{
|
||||||
|
if ((current_cp_abi.pass_by_reference) == NULL)
|
||||||
|
return 0;
|
||||||
|
return (*current_cp_abi.pass_by_reference) (type);
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the current C++ ABI to SHORT_NAME. */
|
/* Set the current C++ ABI to SHORT_NAME. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -172,6 +172,10 @@ void cplus_make_method_ptr (gdb_byte *CONTENTS, CORE_ADDR address,
|
|||||||
|
|
||||||
CORE_ADDR cplus_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc);
|
CORE_ADDR cplus_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc);
|
||||||
|
|
||||||
|
/* Return non-zero if an argument of type TYPE should be passed by reference
|
||||||
|
instead of value. */
|
||||||
|
extern int cp_pass_by_reference (struct type *type);
|
||||||
|
|
||||||
struct cp_abi_ops
|
struct cp_abi_ops
|
||||||
{
|
{
|
||||||
const char *shortname;
|
const char *shortname;
|
||||||
@ -195,6 +199,7 @@ struct cp_abi_ops
|
|||||||
void (*make_method_ptr) (gdb_byte *, CORE_ADDR, int);
|
void (*make_method_ptr) (gdb_byte *, CORE_ADDR, int);
|
||||||
struct value * (*method_ptr_to_value) (struct value **, struct value *);
|
struct value * (*method_ptr_to_value) (struct value **, struct value *);
|
||||||
CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR);
|
CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR);
|
||||||
|
int (*pass_by_reference) (struct type *type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -503,6 +503,7 @@ const struct language_defn f_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
f_language_arch_info,
|
f_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -716,6 +716,87 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
|
|||||||
return real_stop_pc;
|
return real_stop_pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return nonzero if a type should be passed by reference.
|
||||||
|
|
||||||
|
The rule in the v3 ABI document comes from section 3.1.1. If the
|
||||||
|
type has a non-trivial copy constructor or destructor, then the
|
||||||
|
caller must make a copy (by calling the copy constructor if there
|
||||||
|
is one or perform the copy itself otherwise), pass the address of
|
||||||
|
the copy, and then destroy the temporary (if necessary).
|
||||||
|
|
||||||
|
For return values with non-trivial copy constructors or
|
||||||
|
destructors, space will be allocated in the caller, and a pointer
|
||||||
|
will be passed as the first argument (preceding "this").
|
||||||
|
|
||||||
|
We don't have a bulletproof mechanism for determining whether a
|
||||||
|
constructor or destructor is trivial. For GCC and DWARF2 debug
|
||||||
|
information, we can check the artificial flag.
|
||||||
|
|
||||||
|
We don't do anything with the constructors or destructors,
|
||||||
|
but we have to get the argument passing right anyway. */
|
||||||
|
static int
|
||||||
|
gnuv3_pass_by_reference (struct type *type)
|
||||||
|
{
|
||||||
|
int fieldnum, fieldelem;
|
||||||
|
|
||||||
|
CHECK_TYPEDEF (type);
|
||||||
|
|
||||||
|
/* We're only interested in things that can have methods. */
|
||||||
|
if (TYPE_CODE (type) != TYPE_CODE_STRUCT
|
||||||
|
&& TYPE_CODE (type) != TYPE_CODE_CLASS
|
||||||
|
&& TYPE_CODE (type) != TYPE_CODE_UNION)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
|
||||||
|
for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
|
||||||
|
fieldelem++)
|
||||||
|
{
|
||||||
|
struct fn_field *fn = TYPE_FN_FIELDLIST1 (type, fieldnum);
|
||||||
|
char *name = TYPE_FN_FIELDLIST_NAME (type, fieldnum);
|
||||||
|
struct type *fieldtype = TYPE_FN_FIELD_TYPE (fn, fieldelem);
|
||||||
|
|
||||||
|
/* If this function is marked as artificial, it is compiler-generated,
|
||||||
|
and we assume it is trivial. */
|
||||||
|
if (TYPE_FN_FIELD_ARTIFICIAL (fn, fieldelem))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If we've found a destructor, we must pass this by reference. */
|
||||||
|
if (name[0] == '~')
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* If the mangled name of this method doesn't indicate that it
|
||||||
|
is a constructor, we're not interested.
|
||||||
|
|
||||||
|
FIXME drow/2007-09-23: We could do this using the name of
|
||||||
|
the method and the name of the class instead of dealing
|
||||||
|
with the mangled name. We don't have a convenient function
|
||||||
|
to strip off both leading scope qualifiers and trailing
|
||||||
|
template arguments yet. */
|
||||||
|
if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If this method takes two arguments, and the second argument is
|
||||||
|
a reference to this class, then it is a copy constructor. */
|
||||||
|
if (TYPE_NFIELDS (fieldtype) == 2
|
||||||
|
&& TYPE_CODE (TYPE_FIELD_TYPE (fieldtype, 1)) == TYPE_CODE_REF
|
||||||
|
&& check_typedef (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (fieldtype, 1))) == type)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Even if all the constructors and destructors were artificial, one
|
||||||
|
of them may have invoked a non-artificial constructor or
|
||||||
|
destructor in a base class. If any base class needs to be passed
|
||||||
|
by reference, so does this class. Similarly for members, which
|
||||||
|
are constructed whenever this class is. We do not need to worry
|
||||||
|
about recursive loops here, since we are only looking at members
|
||||||
|
of complete class type. */
|
||||||
|
for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++)
|
||||||
|
if (gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_gnuv3_ops (void)
|
init_gnuv3_ops (void)
|
||||||
{
|
{
|
||||||
@ -738,6 +819,7 @@ init_gnuv3_ops (void)
|
|||||||
gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr;
|
gnu_v3_abi_ops.make_method_ptr = gnuv3_make_method_ptr;
|
||||||
gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value;
|
gnu_v3_abi_ops.method_ptr_to_value = gnuv3_method_ptr_to_value;
|
||||||
gnu_v3_abi_ops.skip_trampoline = gnuv3_skip_trampoline;
|
gnu_v3_abi_ops.skip_trampoline = gnuv3_skip_trampoline;
|
||||||
|
gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */
|
extern initialize_file_ftype _initialize_gnu_v3_abi; /* -Wmissing-prototypes */
|
||||||
|
@ -339,8 +339,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
{
|
{
|
||||||
CORE_ADDR sp;
|
CORE_ADDR sp;
|
||||||
CORE_ADDR dummy_addr;
|
CORE_ADDR dummy_addr;
|
||||||
struct type *values_type;
|
struct type *values_type, *target_values_type;
|
||||||
unsigned char struct_return;
|
unsigned char struct_return = 0, lang_struct_return = 0;
|
||||||
CORE_ADDR struct_addr = 0;
|
CORE_ADDR struct_addr = 0;
|
||||||
struct regcache *retbuf;
|
struct regcache *retbuf;
|
||||||
struct cleanup *retbuf_cleanup;
|
struct cleanup *retbuf_cleanup;
|
||||||
@ -354,6 +354,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
struct regcache *caller_regcache;
|
struct regcache *caller_regcache;
|
||||||
struct cleanup *caller_regcache_cleanup;
|
struct cleanup *caller_regcache_cleanup;
|
||||||
struct frame_id dummy_id;
|
struct frame_id dummy_id;
|
||||||
|
struct cleanup *args_cleanup;
|
||||||
|
|
||||||
if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
|
if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
|
||||||
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
|
ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
|
||||||
@ -460,10 +461,30 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
|
using_gcc = (b == NULL ? 2 : BLOCK_GCC_COMPILED (b));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Are we returning a value using a structure return or a normal
|
/* Are we returning a value using a structure return (passing a
|
||||||
value return? */
|
hidden argument pointing to storage) or a normal value return?
|
||||||
|
There are two cases: language-mandated structure return and
|
||||||
|
target ABI structure return. The variable STRUCT_RETURN only
|
||||||
|
describes the latter. The language version is handled by passing
|
||||||
|
the return location as the first parameter to the function,
|
||||||
|
even preceding "this". This is different from the target
|
||||||
|
ABI version, which is target-specific; for instance, on ia64
|
||||||
|
the first argument is passed in out0 but the hidden structure
|
||||||
|
return pointer would normally be passed in r8. */
|
||||||
|
|
||||||
struct_return = using_struct_return (values_type, using_gcc);
|
if (language_pass_by_reference (values_type))
|
||||||
|
{
|
||||||
|
lang_struct_return = 1;
|
||||||
|
|
||||||
|
/* Tell the target specific argument pushing routine not to
|
||||||
|
expect a value. */
|
||||||
|
target_values_type = builtin_type_void;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct_return = using_struct_return (values_type, using_gcc);
|
||||||
|
target_values_type = values_type;
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine the location of the breakpoint (and possibly other
|
/* Determine the location of the breakpoint (and possibly other
|
||||||
stuff) that the called function will return to. The SPARC, for a
|
stuff) that the called function will return to. The SPARC, for a
|
||||||
@ -482,7 +503,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
if (gdbarch_inner_than (current_gdbarch, 1, 2))
|
if (gdbarch_inner_than (current_gdbarch, 1, 2))
|
||||||
{
|
{
|
||||||
sp = push_dummy_code (current_gdbarch, sp, funaddr,
|
sp = push_dummy_code (current_gdbarch, sp, funaddr,
|
||||||
using_gcc, args, nargs, values_type,
|
using_gcc, args, nargs, target_values_type,
|
||||||
&real_pc, &bp_addr, get_current_regcache ());
|
&real_pc, &bp_addr, get_current_regcache ());
|
||||||
dummy_addr = sp;
|
dummy_addr = sp;
|
||||||
}
|
}
|
||||||
@ -490,7 +511,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
{
|
{
|
||||||
dummy_addr = sp;
|
dummy_addr = sp;
|
||||||
sp = push_dummy_code (current_gdbarch, sp, funaddr,
|
sp = push_dummy_code (current_gdbarch, sp, funaddr,
|
||||||
using_gcc, args, nargs, values_type,
|
using_gcc, args, nargs, target_values_type,
|
||||||
&real_pc, &bp_addr, get_current_regcache ());
|
&real_pc, &bp_addr, get_current_regcache ());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -557,9 +578,12 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
|
|||||||
param_type = TYPE_FIELD_TYPE (ftype, i);
|
param_type = TYPE_FIELD_TYPE (ftype, i);
|
||||||
else
|
else
|
||||||
param_type = NULL;
|
param_type = NULL;
|
||||||
|
|
||||||
args[i] = value_arg_coerce (args[i], param_type, prototyped);
|
args[i] = value_arg_coerce (args[i], param_type, prototyped);
|
||||||
|
|
||||||
|
if (param_type != NULL && language_pass_by_reference (param_type))
|
||||||
|
args[i] = value_addr (args[i]);
|
||||||
|
|
||||||
/* elz: this code is to handle the case in which the function
|
/* elz: this code is to handle the case in which the function
|
||||||
to be called has a pointer to function as parameter and the
|
to be called has a pointer to function as parameter and the
|
||||||
corresponding actual argument is the address of a function
|
corresponding actual argument is the address of a function
|
||||||
@ -659,7 +683,7 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
|
|||||||
stack, if necessary. Make certain that the value is correctly
|
stack, if necessary. Make certain that the value is correctly
|
||||||
aligned. */
|
aligned. */
|
||||||
|
|
||||||
if (struct_return)
|
if (struct_return || lang_struct_return)
|
||||||
{
|
{
|
||||||
int len = TYPE_LENGTH (values_type);
|
int len = TYPE_LENGTH (values_type);
|
||||||
if (gdbarch_inner_than (current_gdbarch, 1, 2))
|
if (gdbarch_inner_than (current_gdbarch, 1, 2))
|
||||||
@ -684,6 +708,22 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lang_struct_return)
|
||||||
|
{
|
||||||
|
struct value **new_args;
|
||||||
|
|
||||||
|
/* Add the new argument to the front of the argument list. */
|
||||||
|
new_args = xmalloc (sizeof (struct value *) * (nargs + 1));
|
||||||
|
new_args[0] = value_from_pointer (lookup_pointer_type (values_type),
|
||||||
|
struct_addr);
|
||||||
|
memcpy (&new_args[1], &args[0], sizeof (struct value *) * nargs);
|
||||||
|
args = new_args;
|
||||||
|
nargs++;
|
||||||
|
args_cleanup = make_cleanup (xfree, args);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
args_cleanup = make_cleanup (null_cleanup, NULL);
|
||||||
|
|
||||||
/* Create the dummy stack frame. Pass in the call dummy address as,
|
/* Create the dummy stack frame. Pass in the call dummy address as,
|
||||||
presumably, the ABI code knows where, in the call dummy, the
|
presumably, the ABI code knows where, in the call dummy, the
|
||||||
return address should be pointed. */
|
return address should be pointed. */
|
||||||
@ -691,6 +731,8 @@ You must use a pointer to function type variable. Command ignored."), arg_name);
|
|||||||
get_current_regcache (), bp_addr, nargs, args,
|
get_current_regcache (), bp_addr, nargs, args,
|
||||||
sp, struct_return, struct_addr);
|
sp, struct_return, struct_addr);
|
||||||
|
|
||||||
|
do_cleanups (args_cleanup);
|
||||||
|
|
||||||
/* 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 frame
|
set_momentary_breakpoint. We need to give the breakpoint a frame
|
||||||
ID so that the breakpoint code can correctly re-identify the
|
ID so that the breakpoint code can correctly re-identify the
|
||||||
@ -882,7 +924,9 @@ the function call)."), name);
|
|||||||
{
|
{
|
||||||
struct value *retval = NULL;
|
struct value *retval = NULL;
|
||||||
|
|
||||||
if (TYPE_CODE (values_type) == TYPE_CODE_VOID)
|
if (lang_struct_return)
|
||||||
|
retval = value_at (values_type, struct_addr);
|
||||||
|
else if (TYPE_CODE (target_values_type) == TYPE_CODE_VOID)
|
||||||
{
|
{
|
||||||
/* If the function returns void, don't bother fetching the
|
/* If the function returns void, don't bother fetching the
|
||||||
return value. */
|
return value. */
|
||||||
@ -892,7 +936,7 @@ the function call)."), name);
|
|||||||
{
|
{
|
||||||
struct gdbarch *arch = current_gdbarch;
|
struct gdbarch *arch = current_gdbarch;
|
||||||
|
|
||||||
switch (gdbarch_return_value (arch, values_type, NULL, NULL, NULL))
|
switch (gdbarch_return_value (arch, target_values_type, NULL, NULL, NULL))
|
||||||
{
|
{
|
||||||
case RETURN_VALUE_REGISTER_CONVENTION:
|
case RETURN_VALUE_REGISTER_CONVENTION:
|
||||||
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
|
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
|
||||||
|
@ -1115,6 +1115,7 @@ const struct language_defn java_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
c_language_arch_info,
|
c_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1045,6 +1045,23 @@ language_class_name_from_physname (const struct language_defn *current_language,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return non-zero if TYPE should be passed (and returned) by
|
||||||
|
reference at the language level. */
|
||||||
|
int
|
||||||
|
language_pass_by_reference (struct type *type)
|
||||||
|
{
|
||||||
|
return current_language->la_pass_by_reference (type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return zero; by default, types are passed by value at the language
|
||||||
|
level. The target ABI may pass or return some structs by reference
|
||||||
|
independent of this. */
|
||||||
|
int
|
||||||
|
default_pass_by_reference (struct type *type)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the default string containing the list of characters
|
/* Return the default string containing the list of characters
|
||||||
delimiting words. This is a reasonable default value that
|
delimiting words. This is a reasonable default value that
|
||||||
most languages should be able to use. */
|
most languages should be able to use. */
|
||||||
@ -1191,6 +1208,7 @@ const struct language_defn unknown_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
unknown_language_arch_info, /* la_language_arch_info. */
|
unknown_language_arch_info, /* la_language_arch_info. */
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1228,6 +1246,7 @@ const struct language_defn auto_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
unknown_language_arch_info, /* la_language_arch_info. */
|
unknown_language_arch_info, /* la_language_arch_info. */
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1264,6 +1283,7 @@ const struct language_defn local_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
unknown_language_arch_info, /* la_language_arch_info. */
|
unknown_language_arch_info, /* la_language_arch_info. */
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -280,6 +280,10 @@ struct language_defn
|
|||||||
int format,
|
int format,
|
||||||
enum val_prettyprint pretty);
|
enum val_prettyprint pretty);
|
||||||
|
|
||||||
|
/* Return non-zero if TYPE should be passed (and returned) by
|
||||||
|
reference at the language level. */
|
||||||
|
int (*la_pass_by_reference) (struct type *type);
|
||||||
|
|
||||||
/* Add fields above this point, so the magic number is always last. */
|
/* Add fields above this point, so the magic number is always last. */
|
||||||
/* Magic number for compat checking */
|
/* Magic number for compat checking */
|
||||||
|
|
||||||
@ -471,4 +475,13 @@ extern void default_print_array_index (struct value *index_value,
|
|||||||
int format,
|
int format,
|
||||||
enum val_prettyprint pretty);
|
enum val_prettyprint pretty);
|
||||||
|
|
||||||
|
/* Return non-zero if TYPE should be passed (and returned) by
|
||||||
|
reference at the language level. */
|
||||||
|
int language_pass_by_reference (struct type *type);
|
||||||
|
|
||||||
|
/* Return zero; by default, types are passed by value at the language
|
||||||
|
level. The target ABI may pass or return some structs by reference
|
||||||
|
independent of this. */
|
||||||
|
int default_pass_by_reference (struct type *type);
|
||||||
|
|
||||||
#endif /* defined (LANGUAGE_H) */
|
#endif /* defined (LANGUAGE_H) */
|
||||||
|
@ -459,6 +459,7 @@ const struct language_defn m2_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
m2_language_arch_info,
|
m2_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -668,6 +668,7 @@ const struct language_defn objc_language_defn = {
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
c_language_arch_info,
|
c_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -525,6 +525,7 @@ const struct language_defn pascal_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
pascal_language_arch_info,
|
pascal_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -267,6 +267,7 @@ const struct language_defn scm_language_defn =
|
|||||||
default_word_break_characters,
|
default_word_break_characters,
|
||||||
c_language_arch_info,
|
c_language_arch_info,
|
||||||
default_print_array_index,
|
default_print_array_index,
|
||||||
|
default_pass_by_reference,
|
||||||
LANG_MAGIC
|
LANG_MAGIC
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2007-09-23 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
|
* gdb.cp/pass-by-ref.cc, gdb.cp/pass-by-ref.exp: New files.
|
||||||
|
|
||||||
2007-09-23 Pedro Alves <pedro_alves@portugalmail.pt>
|
2007-09-23 Pedro Alves <pedro_alves@portugalmail.pt>
|
||||||
|
|
||||||
* configure.ac: Do gdb.stabs tests by default on Cygwin and MinGW
|
* configure.ac: Do gdb.stabs tests by default on Cygwin and MinGW
|
||||||
|
79
gdb/testsuite/gdb.cp/pass-by-ref.cc
Normal file
79
gdb/testsuite/gdb.cp/pass-by-ref.cc
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/* This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright 2007 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
class Obj {
|
||||||
|
public:
|
||||||
|
Obj ();
|
||||||
|
Obj (const Obj &);
|
||||||
|
~Obj ();
|
||||||
|
int var[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
int foo (Obj arg)
|
||||||
|
{
|
||||||
|
return arg.var[0] + arg.var[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj::Obj ()
|
||||||
|
{
|
||||||
|
var[0] = 1;
|
||||||
|
var[1] = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj::Obj (const Obj &obj)
|
||||||
|
{
|
||||||
|
var[0] = obj.var[0];
|
||||||
|
var[1] = obj.var[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj::~Obj ()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Derived : public Obj
|
||||||
|
{
|
||||||
|
int other;
|
||||||
|
};
|
||||||
|
|
||||||
|
int blap (Derived arg)
|
||||||
|
{
|
||||||
|
return foo (arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Container
|
||||||
|
{
|
||||||
|
Obj obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
int blip (Container arg)
|
||||||
|
{
|
||||||
|
return foo (arg.obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
Obj global_obj;
|
||||||
|
Derived global_derived;
|
||||||
|
Container global_container;
|
||||||
|
|
||||||
|
int
|
||||||
|
main ()
|
||||||
|
{
|
||||||
|
int bar = foo (global_obj);
|
||||||
|
blap (global_derived);
|
||||||
|
blip (global_container);
|
||||||
|
return bar;
|
||||||
|
}
|
41
gdb/testsuite/gdb.cp/pass-by-ref.exp
Normal file
41
gdb/testsuite/gdb.cp/pass-by-ref.exp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# Copyright 2007 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# Check that GDB can call C++ functions whose parameters have
|
||||||
|
# object type, but are passed by reference.
|
||||||
|
|
||||||
|
if { [skip_cplus_tests] } { continue }
|
||||||
|
|
||||||
|
set testfile "pass-by-ref"
|
||||||
|
set srcfile ${testfile}.cc
|
||||||
|
set binfile ${objdir}/${subdir}/${testfile}
|
||||||
|
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
|
||||||
|
executable {debug c++}] != "" } {
|
||||||
|
untested pass-by-ref.exp
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_exit
|
||||||
|
gdb_start
|
||||||
|
gdb_reinitialize_dir $srcdir/$subdir
|
||||||
|
gdb_load ${binfile}
|
||||||
|
|
||||||
|
if ![runto_main] then {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
gdb_test "print foo (global_obj)" " = 3" "call function in obj"
|
||||||
|
gdb_test "print blap (global_derived)" " = 3" "call function in derived"
|
||||||
|
gdb_test "print blip (global_container)" " = 3" "call function in container"
|
Loading…
Reference in New Issue
Block a user