infcall, c++: allow more info to be computed for pass-by-reference values

In C++, call-by-value arguments that cannot be trivially copied are
implicitly passed by reference.  When making an infcall, GDB needs to
find out if an argument is pass-by-reference or not, so that the
correct semantics can be followed.  This patch enriches the
information computed by the language ops for pass-by-reference
arguments.  Instead of a plain binary result, the computed information
now includes whether the argument is

  - copy constructible
  - destructible
  - trivially copyable
  - trivially copy constructible
  - trivially destructible

This information is stored in a struct named 'language_pass_by_ref_info'.

This patch paves the way for GDB's infcall mechanism to call the copy
ctor and the destructor of a pass-by-ref argument appropriately.

gdb/ChangeLog:
2019-12-20  Tankut Baris Aktemur  <tankut.baris.aktemur@intel.com>

	* language.h (struct language_pass_by_ref_info): New struct.
	(struct language_defn)<la_pass_by_reference>: Change the signature
	to return a language_pass_by_ref_info instead of an int.
	(language_pass_by_reference): Ditto.
	(default_pass_by_reference): Ditto.
	Adjust the users listed below.
	* arch-utils.c (default_return_in_first_hidden_param_p):
	Update.
	* cp-abi.c (cp_pass_by_reference): Update.
	* cp-abi.h (cp_pass_by_reference): Update declaration.
	(struct cp_abi_ops)<pass_by_reference>: Update.
	* gnu-v3-abi.c (gnuv3_pass_by_reference): Update.
	* infcall.c (call_function_by_hand_dummy): Update.
	* language.c (language_pass_by_reference): Update.
	(default_pass_by_reference): Update.
	* tic6x-tdep.c (tic6x_return_value): Update.

Change-Id: Ib1c1f87f2490a5737c469f7b7185ddc7f6a164cb
This commit is contained in:
Tankut Baris Aktemur 2019-12-20 17:43:06 +01:00
parent e35000a7f8
commit 9d084466d7
9 changed files with 131 additions and 40 deletions

View File

@ -1,3 +1,22 @@
2019-12-20 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* language.h (struct language_pass_by_ref_info): New struct.
(struct language_defn)<la_pass_by_reference>: Change the signature
to return a language_pass_by_ref_info instead of an int.
(language_pass_by_reference): Ditto.
(default_pass_by_reference): Ditto.
Adjust the users listed below.
* arch-utils.c (default_return_in_first_hidden_param_p):
Update.
* cp-abi.c (cp_pass_by_reference): Update.
* cp-abi.h (cp_pass_by_reference): Update declaration.
(struct cp_abi_ops)<pass_by_reference>: Update.
* gnu-v3-abi.c (gnuv3_pass_by_reference): Update.
* infcall.c (call_function_by_hand_dummy): Update.
* language.c (language_pass_by_reference): Update.
(default_pass_by_reference): Update.
* tic6x-tdep.c (tic6x_return_value): Update.
2019-12-20 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> 2019-12-20 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com>
* dwarf2read.c (dwarf2_add_member_fn): Read the DW_AT_defaulted * dwarf2read.c (dwarf2_add_member_fn): Read the DW_AT_defaulted

View File

@ -858,7 +858,7 @@ default_return_in_first_hidden_param_p (struct gdbarch *gdbarch,
/* Usually, the return value's address is stored the in the "first hidden" /* Usually, the return value's address is stored the in the "first hidden"
parameter if the return value should be passed by reference, as parameter if the return value should be passed by reference, as
specified in ABI. */ specified in ABI. */
return language_pass_by_reference (type); return !(language_pass_by_reference (type).trivially_copyable);
} }
int default_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr) int default_insn_is_call (struct gdbarch *gdbarch, CORE_ADDR addr)

View File

@ -220,11 +220,13 @@ cplus_typename_from_type_info (struct value *value)
return (*current_cp_abi.get_typename_from_type_info) (value); return (*current_cp_abi.get_typename_from_type_info) (value);
} }
int /* See cp-abi.h. */
struct language_pass_by_ref_info
cp_pass_by_reference (struct type *type) cp_pass_by_reference (struct type *type)
{ {
if ((current_cp_abi.pass_by_reference) == NULL) if ((current_cp_abi.pass_by_reference) == NULL)
return 0; return default_pass_by_reference (type);
return (*current_cp_abi.pass_by_reference) (type); return (*current_cp_abi.pass_by_reference) (type);
} }

View File

@ -207,9 +207,11 @@ extern std::string cplus_typename_from_type_info (struct value *value);
CORE_ADDR cplus_skip_trampoline (struct frame_info *frame, CORE_ADDR cplus_skip_trampoline (struct frame_info *frame,
CORE_ADDR stop_pc); CORE_ADDR stop_pc);
/* Return non-zero if an argument of type TYPE should be passed by /* Return a struct that provides pass-by-reference information
reference instead of value. */ about the given TYPE. */
extern int cp_pass_by_reference (struct type *type);
extern struct language_pass_by_ref_info cp_pass_by_reference
(struct type *type);
struct cp_abi_ops struct cp_abi_ops
{ {
@ -246,7 +248,7 @@ struct cp_abi_ops
struct type *(*get_type_from_type_info) (struct value *value); struct type *(*get_type_from_type_info) (struct value *value);
std::string (*get_typename_from_type_info) (struct value *value); std::string (*get_typename_from_type_info) (struct value *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); struct language_pass_by_ref_info (*pass_by_reference) (struct type *type);
}; };

View File

@ -1230,7 +1230,7 @@ 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. /* Return pass-by-reference information for the given TYPE.
The rule in the v3 ABI document comes from section 3.1.1. If the 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 type has a non-trivial copy constructor or destructor, then the
@ -1248,22 +1248,33 @@ gnuv3_skip_trampoline (struct frame_info *frame, CORE_ADDR stop_pc)
We don't do anything with the constructors or destructors, We don't do anything with the constructors or destructors,
but we have to get the argument passing right anyway. */ but we have to get the argument passing right anyway. */
static int
static struct language_pass_by_ref_info
gnuv3_pass_by_reference (struct type *type) gnuv3_pass_by_reference (struct type *type)
{ {
int fieldnum, fieldelem; int fieldnum, fieldelem;
type = check_typedef (type); type = check_typedef (type);
/* Start with the default values. */
struct language_pass_by_ref_info info
= default_pass_by_reference (type);
/* FIXME: Currently, this implementation only fills in the
'trivially-copyable' field to preserve GDB's existing behavior. */
/* We're only interested in things that can have methods. */ /* We're only interested in things that can have methods. */
if (TYPE_CODE (type) != TYPE_CODE_STRUCT if (TYPE_CODE (type) != TYPE_CODE_STRUCT
&& TYPE_CODE (type) != TYPE_CODE_UNION) && TYPE_CODE (type) != TYPE_CODE_UNION)
return 0; return info;
/* A dynamic class has a non-trivial copy constructor. /* A dynamic class has a non-trivial copy constructor.
See c++98 section 12.8 Copying class objects [class.copy]. */ See c++98 section 12.8 Copying class objects [class.copy]. */
if (gnuv3_dynamic_class (type)) if (gnuv3_dynamic_class (type))
return 1; {
info.trivially_copyable = false;
return info;
}
for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++) for (fieldnum = 0; fieldnum < TYPE_NFN_FIELDS (type); fieldnum++)
for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum); for (fieldelem = 0; fieldelem < TYPE_FN_FIELDLIST_LENGTH (type, fieldnum);
@ -1280,7 +1291,10 @@ gnuv3_pass_by_reference (struct type *type)
/* If we've found a destructor, we must pass this by reference. */ /* If we've found a destructor, we must pass this by reference. */
if (name[0] == '~') if (name[0] == '~')
return 1; {
info.trivially_copyable = false;
return info;
}
/* If the mangled name of this method doesn't indicate that it /* If the mangled name of this method doesn't indicate that it
is a constructor, we're not interested. is a constructor, we're not interested.
@ -1302,11 +1316,13 @@ gnuv3_pass_by_reference (struct type *type)
if (TYPE_CODE (arg_type) == TYPE_CODE_REF) if (TYPE_CODE (arg_type) == TYPE_CODE_REF)
{ {
struct type *arg_target_type; struct type *arg_target_type
= check_typedef (TYPE_TARGET_TYPE (arg_type));
arg_target_type = check_typedef (TYPE_TARGET_TYPE (arg_type));
if (class_types_same_p (arg_target_type, type)) if (class_types_same_p (arg_target_type, type))
return 1; {
info.trivially_copyable = false;
return info;
}
} }
} }
} }
@ -1319,11 +1335,18 @@ gnuv3_pass_by_reference (struct type *type)
about recursive loops here, since we are only looking at members about recursive loops here, since we are only looking at members
of complete class type. Also ignore any static members. */ of complete class type. Also ignore any static members. */
for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++) for (fieldnum = 0; fieldnum < TYPE_NFIELDS (type); fieldnum++)
if (! field_is_static (&TYPE_FIELD (type, fieldnum)) if (!field_is_static (&TYPE_FIELD (type, fieldnum)))
&& gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum))) {
return 1; struct language_pass_by_ref_info field_info
= gnuv3_pass_by_reference (TYPE_FIELD_TYPE (type, fieldnum));
if (!field_info.trivially_copyable)
{
info.trivially_copyable = false;
return info;
}
}
return 0; return info;
} }
static void static void

View File

@ -1020,7 +1020,8 @@ call_function_by_hand_dummy (struct value *function,
args[i] = value_arg_coerce (gdbarch, args[i], args[i] = value_arg_coerce (gdbarch, args[i],
param_type, prototyped); param_type, prototyped);
if (param_type != NULL && language_pass_by_reference (param_type)) if (param_type != NULL
&& !(language_pass_by_reference (param_type).trivially_copyable))
args[i] = value_addr (args[i]); args[i] = value_addr (args[i]);
} }

View File

@ -652,21 +652,23 @@ language_class_name_from_physname (const struct language_defn *lang,
return NULL; return NULL;
} }
/* Return non-zero if TYPE should be passed (and returned) by /* Return information about whether TYPE should be passed
reference at the language level. */ (and returned) by reference at the language level. */
int
struct language_pass_by_ref_info
language_pass_by_reference (struct type *type) language_pass_by_reference (struct type *type)
{ {
return current_language->la_pass_by_reference (type); return current_language->la_pass_by_reference (type);
} }
/* Return zero; by default, types are passed by value at the language /* Return a default struct that provides pass-by-reference information
level. The target ABI may pass or return some structs by reference about the given TYPE. Languages should update the default values
independent of this. */ as appropriate. */
int
struct language_pass_by_ref_info
default_pass_by_reference (struct type *type) default_pass_by_reference (struct type *type)
{ {
return 0; return {};
} }
/* Return the default string containing the list of characters /* Return the default string containing the list of characters

View File

@ -128,6 +128,47 @@ struct language_arch_info
struct type *bool_type_default; struct type *bool_type_default;
}; };
/* In a language (particularly C++) a function argument of an aggregate
type (i.e. class/struct/union) may be implicitly passed by reference
even though it is declared a call-by-value argument in the source.
The struct below puts together necessary information for GDB to be
able to detect and carry out pass-by-reference semantics for a
particular type. This type is referred as T in the inlined comments
below.
The default values of the fields are chosen to give correct semantics
for primitive types and for simple aggregate types, such as
class T {
int x;
}; */
struct language_pass_by_ref_info
{
/* True if an argument of type T can be passed to a function by value
(i.e. not through an implicit reference). False, otherwise. */
bool trivially_copyable = true;
/* True if a copy of a value of type T can be initialized by
memcpy'ing the value bit-by-bit. False, otherwise.
E.g. If T has a user-defined copy ctor, this should be false. */
bool trivially_copy_constructible = true;
/* True if a value of type T can be destructed simply by reclaiming
the memory area occupied by the value. False, otherwise.
E.g. If T has a user-defined destructor, this should be false. */
bool trivially_destructible = true;
/* True if it is allowed to create a copy of a value of type T.
False, otherwise.
E.g. If T has a deleted copy ctor, this should be false. */
bool copy_constructible = true;
/* True if a value of type T can be destructed. False, otherwise.
E.g. If T has a deleted destructor, this should be false. */
bool destructible = true;
};
/* Structure tying together assorted information about a language. */ /* Structure tying together assorted information about a language. */
struct language_defn struct language_defn
@ -356,9 +397,10 @@ struct language_defn
struct ui_file *stream, struct ui_file *stream,
const struct value_print_options *options); const struct value_print_options *options);
/* Return non-zero if TYPE should be passed (and returned) by /* Return information about whether TYPE should be passed
reference at the language level. */ (and returned) by reference at the language level. */
int (*la_pass_by_reference) (struct type *type); struct language_pass_by_ref_info (*la_pass_by_reference)
(struct type *type);
/* Return an expression that can be used for a location /* Return an expression that can be used for a location
watchpoint. TYPE is a pointer type that points to the memory watchpoint. TYPE is a pointer type that points to the memory
@ -613,14 +655,14 @@ extern void default_print_array_index (struct value *index_value,
struct ui_file *stream, struct ui_file *stream,
const struct value_print_options *options); const struct value_print_options *options);
/* Return non-zero if TYPE should be passed (and returned) by /* Return information about whether TYPE should be passed
reference at the language level. */ (and returned) by reference at the language level. */
int language_pass_by_reference (struct type *type); struct language_pass_by_ref_info language_pass_by_reference (struct type *type);
/* Return zero; by default, types are passed by value at the language /* Return a default struct that provides pass-by-reference information
level. The target ABI may pass or return some structs by reference about the given TYPE. Languages should update the default values
independent of this. */ as appropriate. */
int default_pass_by_reference (struct type *type); struct language_pass_by_ref_info default_pass_by_reference (struct type *type);
/* The default implementation of la_print_typedef. */ /* The default implementation of la_print_typedef. */
void default_print_typedef (struct type *type, struct symbol *new_symbol, void default_print_typedef (struct type *type, struct symbol *new_symbol,

View File

@ -784,7 +784,7 @@ tic6x_return_value (struct gdbarch *gdbarch, struct value *function,
if (type != NULL) if (type != NULL)
{ {
type = check_typedef (type); type = check_typedef (type);
if (language_pass_by_reference (type)) if (!(language_pass_by_reference (type).trivially_copyable))
return RETURN_VALUE_STRUCT_CONVENTION; return RETURN_VALUE_STRUCT_CONVENTION;
} }
} }