summaryrefslogtreecommitdiff
path: root/gdb/valops.c
diff options
context:
space:
mode:
authorgdb-2.5.1 <gdb@fsf.org>1988-05-02 01:00:00 +0100
committerPedro Alves <palves@redhat.com>2012-06-03 15:36:30 +0100
commit632ea0ccc5c4c3f9fc06881bfedfc4b075873941 (patch)
tree96f152433c41c5f51fe57307b287eb85865a43e2 /gdb/valops.c
parent7b4ac7e1ed2c4616bce56d1760807798be87ac9e (diff)
downloadbinutils-gdb-632ea0ccc5c4c3f9fc06881bfedfc4b075873941.tar.gz
gdb-2.5.1
Diffstat (limited to 'gdb/valops.c')
-rw-r--r--gdb/valops.c452
1 files changed, 438 insertions, 14 deletions
diff --git a/gdb/valops.c b/gdb/valops.c
index 9f0e3cced9f..c9629320d86 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -17,7 +17,7 @@ notice and this notice must be preserved on all copies.
In other words, go ahead and share GDB, but don't try to stop
anyone else from sharing it farther. Help stamp out software hoarding!
*/
-
+#include "stdio.h"
#include "defs.h"
#include "initialize.h"
#include "param.h"
@@ -56,11 +56,19 @@ value_cast (type, arg2)
return value_from_long (type, value_as_long (arg2));
else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2)))
{
+ if ((code1 == TYPE_CODE_MPTR) ^ (code2 == TYPE_CODE_MPTR))
+ printf ("warning: assignment between pointer-to-member and non pointer-to-member types\n");
+
VALUE_TYPE (arg2) = type;
return arg2;
}
else if (VALUE_LVAL (arg2) == lval_memory)
- return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2));
+ {
+ if ((code1 == TYPE_CODE_MPTR) ^ (code2 == TYPE_CODE_MPTR))
+ printf ("warning: assignment between pointer-to-member and non pointer-to-member types\n");
+
+ return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2));
+ }
else
error ("Invalid cast.");
}
@@ -278,6 +286,9 @@ value_ind (arg1)
{
COERCE_ARRAY (arg1);
+ if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_MPTR)
+ error ("not implemented: member pointers in value_ind");
+
/* Allow * on an integer so we can cast it to whatever we want. */
if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT)
return value_at (builtin_type_long,
@@ -285,6 +296,9 @@ value_ind (arg1)
else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR)
return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
(CORE_ADDR) value_as_long (arg1));
+ else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_REF)
+ return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)),
+ (CORE_ADDR) value_as_long (arg1));
error ("Attempt to take contents of a non-pointer value.");
}
@@ -411,6 +425,9 @@ call_function (function, nargs, args)
register struct type *ftype = VALUE_TYPE (function);
register enum type_code code = TYPE_CODE (ftype);
+ if (code == TYPE_CODE_MPTR)
+ error ("not implemented: member pointer to call_function");
+
/* Determine address to call. */
if (code == TYPE_CODE_FUNC)
{
@@ -552,16 +569,24 @@ value_string (ptr, len)
/* Given ARG1, a value of type (pointer to a)* structure/union,
extract the component named NAME from the ultimate target structure/union
and return it as a value with its appropriate type.
- ERR is used in the error message if ARG1's type is wrong. */
+ ERR is used in the error message if ARG1's type is wrong.
+
+ C++: ARGS is a list of argument types to aid in the selection of
+ an appropriate method. Also, handle derived types.
+
+ ERR is an error message to be printed in case the field is not found. */
value
-value_struct_elt (arg1, name, err)
- register value arg1;
+value_struct_elt (arg1, args, name, err)
+ register value arg1, *args;
char *name;
char *err;
{
register struct type *t;
register int i;
+ int found = 0;
+
+ struct type *baseclass;
COERCE_ARRAY (arg1);
@@ -569,28 +594,427 @@ value_struct_elt (arg1, name, err)
/* Follow pointers until we get to a non-pointer. */
- while (TYPE_CODE (t) == TYPE_CODE_PTR)
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
{
arg1 = value_ind (arg1);
COERCE_ARRAY (arg1);
t = VALUE_TYPE (arg1);
}
+ if (TYPE_CODE (t) == TYPE_CODE_MPTR)
+ error ("not implemented: member pointers in value_struct_elt");
+
if (TYPE_CODE (t) != TYPE_CODE_STRUCT
- &&
- TYPE_CODE (t) != TYPE_CODE_UNION)
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
error ("Attempt to extract a component of a value that is not a %s.", err);
- for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ baseclass = t;
+
+ if (!args)
+ {
+ /* if there are no arguments ...do this... */
+
+ /* Try as a variable first, because if we succeed, there
+ is less work to be done. */
+ while (t)
+ {
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ {
+ if (!strcmp (TYPE_FIELD_NAME (t, i), name))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (i >= 0)
+ return TYPE_FIELD_STATIC (t, i)
+ ? value_static_field (t, name, i) : value_field (arg1, i);
+
+ t = TYPE_BASECLASS (t);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+ t = baseclass;
+ VALUE_TYPE (arg1) = t; /* side effect! */
+
+ if (destructor_name_p (name, t))
+ error ("use `info method' command to print out value of destructor");
+
+ while (t)
+ {
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (! strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ {
+ error ("use `info method' command to print value of method \"%s\"", name);
+ }
+ }
+ t = TYPE_BASECLASS (t);
+ }
+
+ if (found == 0)
+ error("there is no field named %s", name);
+ return 0;
+ }
+
+ if (destructor_name_p (name, t))
+ {
+ if (!args[1])
+ {
+ /* destructors are a special case. */
+ return (value)value_fn_field (arg1, 0, TYPE_FN_FIELDLIST_LENGTH (t, 0));
+ }
+ else
+ {
+ error ("destructor should not have any argument");
+ }
+ }
+
+ /* This following loop is for methods with arguments. */
+ while (t)
+ {
+ /* Look up as method first, because that is where we
+ expect to find it first. */
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; i--)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ {
+ int j;
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ found = 1;
+ for (j = TYPE_FN_FIELDLIST_LENGTH (t, i) - 1; j >= 0; --j)
+ {
+ if (!typecmp (TYPE_FN_FIELD_ARGS (f, j), args))
+ {
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ {
+ /* First, get the virtual function table pointer.
+ That comes with a strange type, so cast
+ it to type `pointer to long' (which
+ should serve just fine as a function type).
+ Then, index into the table, and convert
+ final value to appropriate function type. */
+ value vfn, vtbl;
+ value vi = value_from_long (builtin_type_int,
+ TYPE_FN_FIELD_VOFFSET (f, j));
+ VALUE_TYPE (arg1) = TYPE_VPTR_BASETYPE (t);
+
+ if (TYPE_VPTR_FIELDNO (t) < 0)
+ TYPE_VPTR_FIELDNO (t)
+ = fill_in_vptr_fieldno (t);
+
+ vtbl = value_field (arg1, TYPE_VPTR_FIELDNO (t));
+ vfn = value_subscript (vtbl, vi);
+ VALUE_TYPE (vfn) = lookup_pointer_type (TYPE_FN_FIELD_TYPE (f, j));
+ return vfn;
+ }
+ else
+ return (value)value_fn_field (arg1, i, j);
+ }
+ }
+ }
+ }
+ t = TYPE_BASECLASS (t);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+
+ if (found)
+ {
+ error ("Structure method %s not defined for arglist.", name);
+ return 0;
+ }
+ else
+ {
+ /* See if user tried to invoke data as function */
+ t = baseclass;
+ while (t)
+ {
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ {
+ if (!strcmp (TYPE_FIELD_NAME (t, i), name))
+ {
+ found = 1;
+ break;
+ }
+ }
+
+ if (i >= 0)
+ return TYPE_FIELD_STATIC (t, i)
+ ? value_static_field (t, name, i) : value_field (arg1, i);
+
+ t = TYPE_BASECLASS (t);
+ VALUE_TYPE (arg1) = t; /* side effect! */
+ }
+ error ("Structure has no component named %s.", name);
+ }
+}
+
+/* C++: return 1 is NAME is a legitimate name for the destructor
+ of type TYPE. If TYPE does not have a destructor, or
+ if NAME is inappropriate for TYPE, an error is signaled. */
+int
+destructor_name_p (name, type)
+ char *name;
+ struct type *type;
+{
+ /* destructors are a special case. */
+ char *dname = TYPE_NAME (type);
+
+ if (name[0] == '~')
+ {
+ if (! TYPE_HAS_DESTRUCTOR (type))
+ error ("type `%s' does not have destructor defined",
+ TYPE_NAME (type));
+ /* Skip past the "struct " at the front. */
+ while (*dname++ != ' ') ;
+ if (strcmp (dname, name+1))
+ error ("destructor specification error");
+ else
+ return 1;
+ }
+ return 0;
+}
+
+/* C++: Given ARG1, a value of type (pointer to a)* structure/union,
+ return 1 if the component named NAME from the ultimate
+ target structure/union is defined, otherwise, return 0. */
+
+int
+check_field (arg1, name)
+ register value arg1;
+ char *name;
+{
+ register struct type *t;
+ register int i;
+ int found = 0;
+
+ struct type *baseclass;
+
+ COERCE_ARRAY (arg1);
+
+ t = VALUE_TYPE (arg1);
+
+ /* Follow pointers until we get to a non-pointer. */
+
+ while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+ {
+ arg1 = value_ind (arg1);
+ COERCE_ARRAY (arg1);
+ t = VALUE_TYPE (arg1);
+ }
+
+ if (TYPE_CODE (t) == TYPE_CODE_MPTR)
+ error ("not implemented: member pointers in check_field");
+
+ if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: `this' is not an aggregate");
+
+ baseclass = t;
+
+ while (t)
{
- if (!strcmp (TYPE_FIELD_NAME (t, i), name))
- break;
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ {
+ if (!strcmp (TYPE_FIELD_NAME (t, i), name))
+ {
+ return 1;
+ }
+ }
+ t = TYPE_BASECLASS (t);
+ VALUE_TYPE (arg1) = t; /* side effect! */
}
- if (i < 0)
- error ("Structure has no component named %s.", name);
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+ t = baseclass;
+ VALUE_TYPE (arg1) = t; /* side effect! */
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, t))
+ return 1;
+
+ while (t)
+ {
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ return 1;
+ }
+ t = TYPE_BASECLASS (t);
+ }
+ return 0;
+}
- return value_field (arg1, i);
+/* C++: Given an aggregate type DOMAIN, and a member name NAME,
+ return the address of this member as a pointer to member
+ type. If INTYPE is non-null, then it will be the type
+ of the member we are looking for. This will help us resolve
+ pointers to member functions. */
+
+value
+value_struct_elt_for_address (domain, intype, name)
+ struct type *domain, *intype;
+ char *name;
+{
+ register struct type *t = domain;
+ register int i;
+ int found = 0;
+ value v;
+
+ struct type *baseclass;
+
+ if (TYPE_CODE (t) != TYPE_CODE_STRUCT
+ && TYPE_CODE (t) != TYPE_CODE_UNION)
+ error ("Internal error: non-aggregate type to value_struct_elt_for_address");
+
+ baseclass = t;
+
+ while (t)
+ {
+ for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--)
+ {
+ if (!strcmp (TYPE_FIELD_NAME (t, i), name))
+ {
+ if (TYPE_FIELD_PACKED (t, i))
+ error ("pointers to bitfield members not allowed");
+
+ v = value_from_long (builtin_type_int, TYPE_FIELD_BITPOS (t, i) >> 3);
+ VALUE_TYPE (v) = lookup_member_pointer_type (TYPE_FIELD_TYPE (t, i), baseclass);
+ return v;
+ }
+ }
+ t = TYPE_BASECLASS (t);
+ }
+
+ /* C++: If it was not found as a data field, then try to
+ return it as a pointer to a method. */
+ t = baseclass;
+
+ /* Destructors are a special case. */
+ if (destructor_name_p (name, t))
+ {
+ error ("pointers to destructors not implemented yet");
+ }
+
+ while (t)
+ {
+ for (i = TYPE_NFN_FIELDS (t) - 1; i >= 0; --i)
+ {
+ if (!strcmp (TYPE_FN_FIELDLIST_NAME (t, i), name))
+ {
+ int j = TYPE_FN_FIELDLIST_LENGTH (t, i);
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (t, i);
+
+ if (intype == 0 && j > 1)
+ error ("non-unique member `%s' requires type instantiation", name);
+ if (intype)
+ {
+ while (j--)
+ if (TYPE_FN_FIELD_TYPE (f, j) == intype)
+ break;
+ if (j < 0)
+ error ("no member function matches that type instantiation");
+ }
+ else
+ j = 0;
+
+ if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
+ {
+ v = value_from_long (builtin_type_long,
+ TYPE_FN_FIELD_VOFFSET (f, j));
+ }
+ else
+ {
+ struct symbol *s = lookup_symbol (TYPE_FN_FIELD_PHYSNAME (f, j),
+ 0, VAR_NAMESPACE);
+ v = locate_var_value (s, 0);
+ }
+ VALUE_TYPE (v) = lookup_member_pointer_type (TYPE_FN_FIELD_TYPE (f, j), baseclass);
+ return v;
+ }
+ }
+ t = TYPE_BASECLASS (t);
+ }
+ return 0;
+}
+
+/* Compare two argument lists and return the position in which they differ,
+ or zero if equal. Note that we ignore the first argument, which is
+ the type of the instance variable. This is because we want to handle
+ derived classes. This is not entirely correct: we should actually
+ check to make sure that a requested operation is type secure,
+ shouldn't we? */
+int typecmp(t1, t2)
+ struct type *t1[];
+ value t2[];
+{
+ int i;
+
+ if (t1[0]->code == TYPE_CODE_VOID) return 0;
+ if (!t1[1])return 0;
+ for (i = 1; t1[i]->code != TYPE_CODE_VOID; i++)
+ {
+ if (! t2[i]
+ || t1[i]->code != t2[i]->type->code
+ || t1[i]->target_type != t2[i]->type->target_type)
+ {
+ return i+1;
+ }
+ }
+ return t2[i] ? i+1 : 0;
+}
+
+#ifndef FRAME
+#include "frame.h"
+#endif
+
+/* C++: return the value of the class instance variable, if one exists.
+ Flag COMPLAIN signals an error if the request is made in an
+ inappropriate context. */
+value
+value_of_this (complain)
+ int complain;
+{
+ extern FRAME selected_frame;
+ struct symbol *func, *sym;
+ char *funname = 0;
+ struct block *b;
+ int i;
+
+ if (selected_frame == 0)
+ if (complain)
+ error ("no frame selected");
+ else return 0;
+
+ func = get_frame_function (selected_frame);
+ if (func)
+ funname = SYMBOL_NAME (func);
+ else
+ if (complain)
+ error ("no `this' in nameless context");
+ else return 0;
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ i = BLOCK_NSYMS (b);
+ if (i <= 0)
+ if (complain)
+ error ("no args, no `this'");
+ else return 0;
+
+ sym = BLOCK_SYM (b, 0);
+ if (strncmp ("$this", SYMBOL_NAME (sym), 5))
+ if (complain)
+ error ("current stack frame not in method");
+ else return 0;
+
+ return read_var_value (sym, selected_frame);
}
static