/* Low level packing and unpacking of values for GDB, the GNU Debugger.
- Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
- 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005 Free
- Software Foundation, Inc.
+ Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+ 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "gdb_string.h"
declared here. */
union
{
- bfd_byte contents[1];
+ gdb_byte contents[1];
DOUBLEST force_doublest_align;
LONGEST force_longest_align;
CORE_ADDR force_core_addr_align;
value->bitsize = bit;
}
-bfd_byte *
+gdb_byte *
value_contents_raw (struct value *value)
{
return value->aligner.contents + value->embedded_offset;
}
-bfd_byte *
+gdb_byte *
value_contents_all_raw (struct value *value)
{
return value->aligner.contents;
return value->enclosing_type;
}
-const bfd_byte *
+const gdb_byte *
value_contents_all (struct value *value)
{
if (value->lazy)
value->lazy = val;
}
-const bfd_byte *
+const gdb_byte *
value_contents (struct value *value)
{
return value_contents_writeable (value);
}
-bfd_byte *
+gdb_byte *
value_contents_writeable (struct value *value)
{
if (value->lazy)
value_fetch_lazy (value);
- return value->aligner.contents;
+ return value_contents_raw (value);
+}
+
+/* Return non-zero if VAL1 and VAL2 have the same contents. Note that
+ this function is different from value_equal; in C the operator ==
+ can return 0 even if the two values being compared are equal. */
+
+int
+value_contents_equal (struct value *val1, struct value *val2)
+{
+ struct type *type1;
+ struct type *type2;
+ int len;
+
+ type1 = check_typedef (value_type (val1));
+ type2 = check_typedef (value_type (val2));
+ len = TYPE_LENGTH (type1);
+ if (len != TYPE_LENGTH (type2))
+ return 0;
+
+ return (memcmp (value_contents (val1), value_contents (val2), len) == 0);
}
int
return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]);
}
-/* Clear the value history entirely.
- Must be done when new symbol tables are loaded,
- because the type pointers become invalid. */
-
-void
-clear_value_history (void)
-{
- struct value_history_chunk *next;
- int i;
- struct value *val;
-
- while (value_history_chain)
- {
- for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
- if ((val = value_history_chain->values[i]) != NULL)
- xfree (val);
- next = value_history_chain->next;
- xfree (value_history_chain);
- value_history_chain = next;
- }
- value_history_count = 0;
-}
-
static void
show_values (char *num_exp, int from_tty)
{
static struct internalvar *internalvars;
+/* If the variable does not already exist create it and give it the value given.
+ If no value is given then the default is zero. */
+static void
+init_if_undefined_command (char* args, int from_tty)
+{
+ struct internalvar* intvar;
+
+ /* Parse the expression - this is taken from set_command(). */
+ struct expression *expr = parse_expression (args);
+ register struct cleanup *old_chain =
+ make_cleanup (free_current_contents, &expr);
+
+ /* Validate the expression.
+ Was the expression an assignment?
+ Or even an expression at all? */
+ if (expr->nelts == 0 || expr->elts[0].opcode != BINOP_ASSIGN)
+ error (_("Init-if-undefined requires an assignment expression."));
+
+ /* Extract the variable from the parsed expression.
+ In the case of an assign the lvalue will be in elts[1] and elts[2]. */
+ if (expr->elts[1].opcode != OP_INTERNALVAR)
+ error (_("The first parameter to init-if-undefined should be a GDB variable."));
+ intvar = expr->elts[2].internalvar;
+
+ /* Only evaluate the expression if the lvalue is void.
+ This may still fail if the expresssion is invalid. */
+ if (TYPE_CODE (value_type (intvar->value)) == TYPE_CODE_VOID)
+ evaluate_expression (expr);
+
+ do_cleanups (old_chain);
+}
+
+
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.
return var;
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
- var->name = concat (name, NULL);
+ var->name = concat (name, (char *)NULL);
var->value = allocate_value (builtin_type_void);
+ var->endian = TARGET_BYTE_ORDER;
release_value (var->value);
var->next = internalvars;
internalvars = var;
value_of_internalvar (struct internalvar *var)
{
struct value *val;
+ int i, j;
+ gdb_byte temp;
val = value_copy (var->value);
if (value_lazy (val))
value_fetch_lazy (val);
VALUE_LVAL (val) = lval_internalvar;
VALUE_INTERNALVAR (val) = var;
+
+ /* Values are always stored in the target's byte order. When connected to a
+ target this will most likely always be correct, so there's normally no
+ need to worry about it.
+
+ However, internal variables can be set up before the target endian is
+ known and so may become out of date. Fix it up before anybody sees.
+
+ Internal variables usually hold simple scalar values, and we can
+ correct those. More complex values (e.g. structures and floating
+ point types) are left alone, because they would be too complicated
+ to correct. */
+
+ if (var->endian != TARGET_BYTE_ORDER)
+ {
+ gdb_byte *array = value_contents_raw (val);
+ struct type *type = check_typedef (value_enclosing_type (val));
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_INT:
+ case TYPE_CODE_PTR:
+ /* Reverse the bytes. */
+ for (i = 0, j = TYPE_LENGTH (type) - 1; i < j; i++, j--)
+ {
+ temp = array[j];
+ array[j] = array[i];
+ array[i] = temp;
+ }
+ break;
+ }
+ }
+
return val;
}
set_internalvar_component (struct internalvar *var, int offset, int bitpos,
int bitsize, struct value *newval)
{
- bfd_byte *addr = value_contents_writeable (var->value) + offset;
+ gdb_byte *addr = value_contents_writeable (var->value) + offset;
if (bitsize)
modify_field (addr, value_as_long (newval),
long. */
xfree (var->value);
var->value = newval;
+ var->endian = TARGET_BYTE_ORDER;
release_value (newval);
/* End code which must not call error(). */
}
return var->name;
}
-/* Free all internalvars. Done when new symtabs are loaded,
- because that makes the values invalid. */
+/* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to
+ prevent cycles / duplicates. */
+
+static void
+preserve_one_value (struct value *value, struct objfile *objfile,
+ htab_t copied_types)
+{
+ if (TYPE_OBJFILE (value->type) == objfile)
+ value->type = copy_type_recursive (objfile, value->type, copied_types);
+
+ if (TYPE_OBJFILE (value->enclosing_type) == objfile)
+ value->enclosing_type = copy_type_recursive (objfile,
+ value->enclosing_type,
+ copied_types);
+}
+
+/* Update the internal variables and value history when OBJFILE is
+ discarded; we must copy the types out of the objfile. New global types
+ will be created for every convenience variable which currently points to
+ this objfile's types, and the convenience variables will be adjusted to
+ use the new global types. */
void
-clear_internalvars (void)
+preserve_values (struct objfile *objfile)
{
+ htab_t copied_types;
+ struct value_history_chunk *cur;
struct internalvar *var;
+ int i;
- while (internalvars)
- {
- var = internalvars;
- internalvars = var->next;
- xfree (var->name);
- xfree (var->value);
- xfree (var);
- }
+ /* Create the hash table. We allocate on the objfile's obstack, since
+ it is soon to be deleted. */
+ copied_types = create_copied_types_hash (objfile);
+
+ for (cur = value_history_chain; cur; cur = cur->next)
+ for (i = 0; i < VALUE_HISTORY_CHUNK; i++)
+ if (cur->values[i])
+ preserve_one_value (cur->values[i], objfile, copied_types);
+
+ for (var = internalvars; var; var = var->next)
+ preserve_one_value (var->value, objfile, copied_types);
+
+ htab_delete (copied_types);
}
static void
varseen = 1;
}
printf_filtered (("$%s = "), var->name);
- value_print (var->value, gdb_stdout, 0, Val_pretty_default);
+ value_print (value_of_internalvar (var), gdb_stdout,
+ 0, Val_pretty_default);
printf_filtered (("\n"));
}
if (!varseen)
to an INT (or some size). After all, it is only an offset. */
LONGEST
-unpack_long (struct type *type, const char *valaddr)
+unpack_long (struct type *type, const gdb_byte *valaddr)
{
enum type_code code = TYPE_CODE (type);
int len = TYPE_LENGTH (type);
case TYPE_CODE_TYPEDEF:
return unpack_long (check_typedef (type), valaddr);
case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLAGS:
case TYPE_CODE_BOOL:
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
format, result is in host format. */
DOUBLEST
-unpack_double (struct type *type, const char *valaddr, int *invp)
+unpack_double (struct type *type, const gdb_byte *valaddr, int *invp)
{
enum type_code code;
int len;
to an INT (or some size). After all, it is only an offset. */
CORE_ADDR
-unpack_pointer (struct type *type, const char *valaddr)
+unpack_pointer (struct type *type, const gdb_byte *valaddr)
{
/* Assume a CORE_ADDR can fit in a LONGEST (for now). Not sure
whether we want this to be true eventually. */
If the field is signed, we also do sign extension. */
LONGEST
-unpack_field_as_long (struct type *type, const char *valaddr, int fieldno)
+unpack_field_as_long (struct type *type, const gdb_byte *valaddr, int fieldno)
{
ULONGEST val;
ULONGEST valmask;
0 <= BITPOS, where lbits is the size of a LONGEST in bits. */
void
-modify_field (char *addr, LONGEST fieldval, int bitpos, int bitsize)
+modify_field (gdb_byte *addr, LONGEST fieldval, int bitpos, int bitsize)
{
ULONGEST oword;
ULONGEST mask = (ULONGEST) -1 >> (8 * sizeof (ULONGEST) - bitsize);
case TYPE_CODE_INT:
case TYPE_CODE_CHAR:
case TYPE_CODE_ENUM:
+ case TYPE_CODE_FLAGS:
case TYPE_CODE_BOOL:
case TYPE_CODE_RANGE:
store_signed_integer (value_contents_raw (val), len, num);
add_cmd ("values", no_class, show_values,
_("Elements of value history around item number IDX (or last ten)."),
&showlist);
+
+ add_com ("init-if-undefined", class_vars, init_if_undefined_command, _("\
+Initialize a convenience variable if necessary.\n\
+init-if-undefined VARIABLE = EXPRESSION\n\
+Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\
+exist or does not contain a value. The EXPRESSION is not evaluated if the\n\
+VARIABLE is already initialized."));
}