* value.h (struct internalvar): Remove.
(get_internalvar_integer): Add prototype. (set_internalvar_integer): Add prototype. (clear_internalvar): Add prototype. * value.c (struct internalvar): Move here. Add type member. Remove endian member. Add union_internalvar member instead of value member. (init_if_undefined_command): Use intvar->type. (create_internalvar): Do not initialize value/endian, but type. (create_internalvar_type_lazy): Call create_internalvar. (value_of_internalvar): Handle host-side internalvar contents. (set_internalvar_component): Likewise. (set_internalvar): Likewise. (get_internalvar_integer): New function. (clear_internalvar): Likewise. (set_internalvar_integer): Likewise. (preserve_values): Handle host-side internalvar contents. * breakpoint.c (set_breakpoint_count, set_tracepoint_count): Call set_internalvar_integer instead of set_internalvar. * findcmd.c (find_command): Likewise. * infrun.c (handle_inferior_event): Likewise. * source.c (forward_search_command, reverse_search_command): Likewise. * tracepoint.c (set_traceframe_num, set_tracepoint_num, set_traceframe_context): Likewise. * printcmd.c (x_command): Call clear_internalvar instead of set_internalvar. * tracepoint.c (set_traceframe_context): Likewise. * breakpoint.c (get_number_trailer): Call get_internalvar_integer instead of value_of_internalvar. * linespec.c (decode_dollar): Likewise. * expprint.c (dump_subexp_body_standard): Use internalvar_name instead of accessing internalvar private elements. * valops.c (value_assign): Copy from original source instead of accessing internalvar private elements.
This commit is contained in:
parent
6ceaaae577
commit
4fa6249465
@ -1,3 +1,44 @@
|
||||
2009-06-03 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* value.h (struct internalvar): Remove.
|
||||
(get_internalvar_integer): Add prototype.
|
||||
(set_internalvar_integer): Add prototype.
|
||||
(clear_internalvar): Add prototype.
|
||||
|
||||
* value.c (struct internalvar): Move here. Add type member. Remove
|
||||
endian member. Add union_internalvar member instead of value member.
|
||||
(init_if_undefined_command): Use intvar->type.
|
||||
(create_internalvar): Do not initialize value/endian, but type.
|
||||
(create_internalvar_type_lazy): Call create_internalvar.
|
||||
(value_of_internalvar): Handle host-side internalvar contents.
|
||||
(set_internalvar_component): Likewise.
|
||||
(set_internalvar): Likewise.
|
||||
(get_internalvar_integer): New function.
|
||||
(clear_internalvar): Likewise.
|
||||
(set_internalvar_integer): Likewise.
|
||||
(preserve_values): Handle host-side internalvar contents.
|
||||
|
||||
* breakpoint.c (set_breakpoint_count, set_tracepoint_count): Call
|
||||
set_internalvar_integer instead of set_internalvar.
|
||||
* findcmd.c (find_command): Likewise.
|
||||
* infrun.c (handle_inferior_event): Likewise.
|
||||
* source.c (forward_search_command, reverse_search_command): Likewise.
|
||||
* tracepoint.c (set_traceframe_num, set_tracepoint_num,
|
||||
set_traceframe_context): Likewise.
|
||||
|
||||
* printcmd.c (x_command): Call clear_internalvar instead of
|
||||
set_internalvar.
|
||||
* tracepoint.c (set_traceframe_context): Likewise.
|
||||
|
||||
* breakpoint.c (get_number_trailer): Call get_internalvar_integer
|
||||
instead of value_of_internalvar.
|
||||
* linespec.c (decode_dollar): Likewise.
|
||||
|
||||
* expprint.c (dump_subexp_body_standard): Use internalvar_name
|
||||
instead of accessing internalvar private elements.
|
||||
* valops.c (value_assign): Copy from original source instead of
|
||||
accessing internalvar private elements.
|
||||
|
||||
2009-06-03 Ulrich Weigand <uweigand@de.ibm.com>
|
||||
|
||||
* scm-lang.c (builtin_type_scm): Remove.
|
||||
|
@ -368,8 +368,7 @@ void
|
||||
set_breakpoint_count (int num)
|
||||
{
|
||||
breakpoint_count = num;
|
||||
set_internalvar (lookup_internalvar ("bpnum"),
|
||||
value_from_longest (builtin_type_int32, (LONGEST) num));
|
||||
set_internalvar_integer (lookup_internalvar ("bpnum"), num);
|
||||
}
|
||||
|
||||
/* Used in run_command to zero the hit count when a new run starts. */
|
||||
@ -421,16 +420,15 @@ get_number_trailer (char **pp, int trailer)
|
||||
to pass to lookup_internalvar(). */
|
||||
char *varname;
|
||||
char *start = ++p;
|
||||
struct value *val;
|
||||
LONGEST val;
|
||||
|
||||
while (isalnum (*p) || *p == '_')
|
||||
p++;
|
||||
varname = (char *) alloca (p - start + 1);
|
||||
strncpy (varname, start, p - start);
|
||||
varname[p - start] = '\0';
|
||||
val = value_of_internalvar (lookup_internalvar (varname));
|
||||
if (TYPE_CODE (value_type (val)) == TYPE_CODE_INT)
|
||||
retval = (int) value_as_long (val);
|
||||
if (get_internalvar_integer (lookup_internalvar (varname), &val))
|
||||
retval = (int) val;
|
||||
else
|
||||
{
|
||||
printf_filtered (_("Convenience variable must have integer value.\n"));
|
||||
@ -8275,8 +8273,7 @@ static void
|
||||
set_tracepoint_count (int num)
|
||||
{
|
||||
tracepoint_count = num;
|
||||
set_internalvar (lookup_internalvar ("tpnum"),
|
||||
value_from_longest (builtin_type_int32, (LONGEST) num));
|
||||
set_internalvar_integer (lookup_internalvar ("tpnum"), num);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1002,7 +1002,7 @@ dump_subexp_body_standard (struct expression *exp,
|
||||
fprintf_filtered (stream, "Internal var @");
|
||||
gdb_print_host_address (exp->elts[elt].internalvar, stream);
|
||||
fprintf_filtered (stream, " (%s)",
|
||||
exp->elts[elt].internalvar->name);
|
||||
internalvar_name (exp->elts[elt].internalvar));
|
||||
elt += 2;
|
||||
break;
|
||||
case OP_FUNCALL:
|
||||
|
@ -291,9 +291,7 @@ find_command (char *args, int from_tty)
|
||||
|
||||
/* Record and print the results. */
|
||||
|
||||
set_internalvar (lookup_internalvar ("numfound"),
|
||||
value_from_longest (builtin_type_int32,
|
||||
(LONGEST) found_count));
|
||||
set_internalvar_integer (lookup_internalvar ("numfound"), found_count);
|
||||
if (found_count > 0)
|
||||
{
|
||||
struct gdbarch *gdbarch = current_gdbarch;
|
||||
|
@ -2512,9 +2512,8 @@ handle_inferior_event (struct execution_control_state *ecs)
|
||||
|
||||
/* Record the exit code in the convenience variable $_exitcode, so
|
||||
that the user can inspect this again later. */
|
||||
set_internalvar (lookup_internalvar ("_exitcode"),
|
||||
value_from_longest (builtin_type_int32,
|
||||
(LONGEST) ecs->ws.value.integer));
|
||||
set_internalvar_integer (lookup_internalvar ("_exitcode"),
|
||||
(LONGEST) ecs->ws.value.integer);
|
||||
gdb_flush (gdb_stdout);
|
||||
target_mourn_inferior ();
|
||||
singlestep_breakpoints_inserted_p = 0;
|
||||
|
@ -1669,7 +1669,7 @@ static struct symtabs_and_lines
|
||||
decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
|
||||
char ***canonical, struct symtab *file_symtab)
|
||||
{
|
||||
struct value *valx;
|
||||
LONGEST valx;
|
||||
int index = 0;
|
||||
int need_canonical = 0;
|
||||
struct symtabs_and_lines values;
|
||||
@ -1684,10 +1684,12 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
|
||||
if (!*p) /* Reached end of token without hitting non-digit. */
|
||||
{
|
||||
/* We have a value history reference. */
|
||||
struct value *val_history;
|
||||
sscanf ((copy[1] == '$') ? copy + 2 : copy + 1, "%d", &index);
|
||||
valx = access_value_history ((copy[1] == '$') ? -index : index);
|
||||
if (TYPE_CODE (value_type (valx)) != TYPE_CODE_INT)
|
||||
val_history = access_value_history ((copy[1] == '$') ? -index : index);
|
||||
if (TYPE_CODE (value_type (val_history)) != TYPE_CODE_INT)
|
||||
error (_("History values used in line specs must have integer values."));
|
||||
valx = value_as_long (val_history);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1709,8 +1711,7 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
|
||||
return minsym_found (funfirstline, msymbol);
|
||||
|
||||
/* Not a user variable or function -- must be convenience variable. */
|
||||
valx = value_of_internalvar (lookup_internalvar (copy + 1));
|
||||
if (TYPE_CODE (value_type (valx)) != TYPE_CODE_INT)
|
||||
if (!get_internalvar_integer (lookup_internalvar (copy + 1), &valx))
|
||||
error (_("Convenience variables used in line specs must have integer values."));
|
||||
}
|
||||
|
||||
@ -1718,7 +1719,7 @@ decode_dollar (char *copy, int funfirstline, struct symtab *default_symtab,
|
||||
|
||||
/* Either history value or convenience value from above, in valx. */
|
||||
val.symtab = file_symtab ? file_symtab : default_symtab;
|
||||
val.line = value_as_long (valx);
|
||||
val.line = valx;
|
||||
val.pc = 0;
|
||||
|
||||
values.sals = (struct symtab_and_line *) xmalloc (sizeof val);
|
||||
|
@ -1369,8 +1369,7 @@ x_command (char *exp, int from_tty)
|
||||
then don't fetch it now; instead mark it by voiding the $__
|
||||
variable. */
|
||||
if (value_lazy (last_examine_value))
|
||||
set_internalvar (lookup_internalvar ("__"),
|
||||
allocate_value (builtin_type_void));
|
||||
clear_internalvar (lookup_internalvar ("__"));
|
||||
else
|
||||
set_internalvar (lookup_internalvar ("__"), last_examine_value);
|
||||
}
|
||||
|
@ -1615,9 +1615,7 @@ forward_search_command (char *regex, int from_tty)
|
||||
/* Match! */
|
||||
fclose (stream);
|
||||
print_source_lines (current_source_symtab, line, line + 1, 0);
|
||||
set_internalvar (lookup_internalvar ("_"),
|
||||
value_from_longest (builtin_type_int32,
|
||||
(LONGEST) line));
|
||||
set_internalvar_integer (lookup_internalvar ("_"), line);
|
||||
current_source_line = max (line - lines_to_list / 2, 1);
|
||||
return;
|
||||
}
|
||||
@ -1695,9 +1693,7 @@ reverse_search_command (char *regex, int from_tty)
|
||||
/* Match! */
|
||||
fclose (stream);
|
||||
print_source_lines (current_source_symtab, line, line + 1, 0);
|
||||
set_internalvar (lookup_internalvar ("_"),
|
||||
value_from_longest (builtin_type_int32,
|
||||
(LONGEST) line));
|
||||
set_internalvar_integer (lookup_internalvar ("_"), line);
|
||||
current_source_line = max (line - lines_to_list / 2, 1);
|
||||
return;
|
||||
}
|
||||
|
@ -208,8 +208,7 @@ static void
|
||||
set_traceframe_num (int num)
|
||||
{
|
||||
traceframe_number = num;
|
||||
set_internalvar (lookup_internalvar ("trace_frame"),
|
||||
value_from_longest (builtin_type_int32, (LONGEST) num));
|
||||
set_internalvar_integer (lookup_internalvar ("trace_frame"), num);
|
||||
}
|
||||
|
||||
/* Set tracepoint number to NUM. */
|
||||
@ -217,8 +216,7 @@ static void
|
||||
set_tracepoint_num (int num)
|
||||
{
|
||||
tracepoint_number = num;
|
||||
set_internalvar (lookup_internalvar ("tracepoint"),
|
||||
value_from_longest (builtin_type_int32, (LONGEST) num));
|
||||
set_internalvar_integer (lookup_internalvar ("tracepoint"), num);
|
||||
}
|
||||
|
||||
/* Set externally visible debug variables for querying/printing
|
||||
@ -240,13 +238,9 @@ set_traceframe_context (struct frame_info *trace_frame)
|
||||
traceframe_fun = 0;
|
||||
traceframe_sal.pc = traceframe_sal.line = 0;
|
||||
traceframe_sal.symtab = NULL;
|
||||
set_internalvar (lookup_internalvar ("trace_func"),
|
||||
allocate_value (builtin_type_void));
|
||||
set_internalvar (lookup_internalvar ("trace_file"),
|
||||
allocate_value (builtin_type_void));
|
||||
set_internalvar (lookup_internalvar ("trace_line"),
|
||||
value_from_longest (builtin_type_int32,
|
||||
(LONGEST) - 1));
|
||||
clear_internalvar (lookup_internalvar ("trace_func"));
|
||||
clear_internalvar (lookup_internalvar ("trace_file"));
|
||||
set_internalvar_integer (lookup_internalvar ("trace_line"), -1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -257,16 +251,14 @@ set_traceframe_context (struct frame_info *trace_frame)
|
||||
|
||||
/* Save linenumber as "$trace_line", a debugger variable visible to
|
||||
users. */
|
||||
set_internalvar (lookup_internalvar ("trace_line"),
|
||||
value_from_longest (builtin_type_int32,
|
||||
(LONGEST) traceframe_sal.line));
|
||||
set_internalvar_integer (lookup_internalvar ("trace_line"),
|
||||
traceframe_sal.line);
|
||||
|
||||
/* Save func name as "$trace_func", a debugger variable visible to
|
||||
users. */
|
||||
if (traceframe_fun == NULL ||
|
||||
SYMBOL_LINKAGE_NAME (traceframe_fun) == NULL)
|
||||
set_internalvar (lookup_internalvar ("trace_func"),
|
||||
allocate_value (builtin_type_void));
|
||||
if (traceframe_fun == NULL
|
||||
|| SYMBOL_LINKAGE_NAME (traceframe_fun) == NULL)
|
||||
clear_internalvar (lookup_internalvar ("trace_func"));
|
||||
else
|
||||
{
|
||||
len = strlen (SYMBOL_LINKAGE_NAME (traceframe_fun));
|
||||
@ -285,10 +277,9 @@ set_traceframe_context (struct frame_info *trace_frame)
|
||||
|
||||
/* Save file name as "$trace_file", a debugger variable visible to
|
||||
users. */
|
||||
if (traceframe_sal.symtab == NULL ||
|
||||
traceframe_sal.symtab->filename == NULL)
|
||||
set_internalvar (lookup_internalvar ("trace_file"),
|
||||
allocate_value (builtin_type_void));
|
||||
if (traceframe_sal.symtab == NULL
|
||||
|| traceframe_sal.symtab->filename == NULL)
|
||||
clear_internalvar (lookup_internalvar ("trace_file"));
|
||||
else
|
||||
{
|
||||
len = strlen (traceframe_sal.symtab->filename);
|
||||
|
@ -774,7 +774,7 @@ value_assign (struct value *toval, struct value *fromval)
|
||||
{
|
||||
case lval_internalvar:
|
||||
set_internalvar (VALUE_INTERNALVAR (toval), fromval);
|
||||
val = value_copy (VALUE_INTERNALVAR (toval)->value);
|
||||
val = value_copy (fromval);
|
||||
val = value_change_enclosing_type (val,
|
||||
value_enclosing_type (fromval));
|
||||
set_value_embedded_offset (val, value_embedded_offset (fromval));
|
||||
|
314
gdb/value.c
314
gdb/value.c
@ -878,6 +878,32 @@ show_values (char *num_exp, int from_tty)
|
||||
The user refers to them with a '$' prefix
|
||||
that does not appear in the variable names stored internally. */
|
||||
|
||||
struct internalvar
|
||||
{
|
||||
struct internalvar *next;
|
||||
char *name;
|
||||
struct type *type;
|
||||
|
||||
/* True if this internalvar is the canonical name for a convenience
|
||||
function. */
|
||||
int canonical;
|
||||
|
||||
/* If this function is non-NULL, it is used to compute a fresh value
|
||||
on every access to the internalvar. */
|
||||
internalvar_make_value make_value;
|
||||
|
||||
/* To reduce dependencies on target properties (like byte order) that
|
||||
may change during the lifetime of an internal variable, we store
|
||||
simple scalar values as host objects. */
|
||||
union internalvar_data
|
||||
{
|
||||
struct value *v;
|
||||
struct internal_function *f;
|
||||
LONGEST l;
|
||||
CORE_ADDR a;
|
||||
} u;
|
||||
};
|
||||
|
||||
static struct internalvar *internalvars;
|
||||
|
||||
/* If the variable does not already exist create it and give it the value given.
|
||||
@ -906,7 +932,7 @@ init_if_undefined_command (char* args, int from_tty)
|
||||
|
||||
/* 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)
|
||||
if (TYPE_CODE (intvar->type) == TYPE_CODE_VOID)
|
||||
evaluate_expression (expr);
|
||||
|
||||
do_cleanups (old_chain);
|
||||
@ -941,11 +967,9 @@ create_internalvar (const char *name)
|
||||
struct internalvar *var;
|
||||
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
|
||||
var->name = concat (name, (char *)NULL);
|
||||
var->value = allocate_value (builtin_type_void);
|
||||
var->endian = gdbarch_byte_order (current_gdbarch);
|
||||
var->type = builtin_type_void;
|
||||
var->make_value = NULL;
|
||||
var->canonical = 0;
|
||||
release_value (var->value);
|
||||
var->next = internalvars;
|
||||
internalvars = var;
|
||||
return var;
|
||||
@ -959,14 +983,8 @@ create_internalvar (const char *name)
|
||||
struct internalvar *
|
||||
create_internalvar_type_lazy (char *name, internalvar_make_value fun)
|
||||
{
|
||||
struct internalvar *var;
|
||||
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
|
||||
var->name = concat (name, (char *)NULL);
|
||||
var->value = NULL;
|
||||
struct internalvar *var = create_internalvar (name);
|
||||
var->make_value = fun;
|
||||
var->endian = gdbarch_byte_order (current_gdbarch);
|
||||
var->next = internalvars;
|
||||
internalvars = var;
|
||||
return var;
|
||||
}
|
||||
|
||||
@ -992,14 +1010,31 @@ struct value *
|
||||
value_of_internalvar (struct internalvar *var)
|
||||
{
|
||||
struct value *val;
|
||||
int i, j;
|
||||
gdb_byte temp;
|
||||
|
||||
if (var->make_value != NULL)
|
||||
val = (*var->make_value) (var);
|
||||
else
|
||||
{
|
||||
val = value_copy (var->value);
|
||||
switch (TYPE_CODE (var->type))
|
||||
{
|
||||
case TYPE_CODE_VOID:
|
||||
case TYPE_CODE_INTERNAL_FUNCTION:
|
||||
val = allocate_value (var->type);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_INT:
|
||||
val = value_from_longest (var->type, var->u.l);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_PTR:
|
||||
val = value_from_pointer (var->type, var->u.a);
|
||||
break;
|
||||
|
||||
default:
|
||||
val = value_copy (var->u.v);
|
||||
break;
|
||||
}
|
||||
|
||||
if (value_lazy (val))
|
||||
value_fetch_lazy (val);
|
||||
|
||||
@ -1013,127 +1048,210 @@ value_of_internalvar (struct internalvar *var)
|
||||
assignments to them don't just replace the previous value
|
||||
altogether. At the moment, this seems like the behavior we
|
||||
want. */
|
||||
if (var->value->lval == lval_computed)
|
||||
VALUE_LVAL (val) = lval_computed;
|
||||
else
|
||||
if (val->lval != lval_computed)
|
||||
{
|
||||
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 != gdbarch_byte_order (current_gdbarch))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
int
|
||||
get_internalvar_integer (struct internalvar *var, LONGEST *result)
|
||||
{
|
||||
switch (TYPE_CODE (var->type))
|
||||
{
|
||||
case TYPE_CODE_INT:
|
||||
*result = var->u.l;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
get_internalvar_function (struct internalvar *var,
|
||||
struct internal_function **result)
|
||||
{
|
||||
switch (TYPE_CODE (var->type))
|
||||
{
|
||||
case TYPE_CODE_INTERNAL_FUNCTION:
|
||||
*result = var->u.f;
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_internalvar_component (struct internalvar *var, int offset, int bitpos,
|
||||
int bitsize, struct value *newval)
|
||||
{
|
||||
gdb_byte *addr = value_contents_writeable (var->value) + offset;
|
||||
gdb_byte *addr;
|
||||
|
||||
if (bitsize)
|
||||
modify_field (addr, value_as_long (newval),
|
||||
bitpos, bitsize);
|
||||
else
|
||||
memcpy (addr, value_contents (newval), TYPE_LENGTH (value_type (newval)));
|
||||
switch (TYPE_CODE (var->type))
|
||||
{
|
||||
case TYPE_CODE_VOID:
|
||||
case TYPE_CODE_INTERNAL_FUNCTION:
|
||||
case TYPE_CODE_INT:
|
||||
case TYPE_CODE_PTR:
|
||||
/* We can never get a component of a basic type. */
|
||||
internal_error (__FILE__, __LINE__, "set_internalvar_component");
|
||||
|
||||
default:
|
||||
addr = value_contents_writeable (var->u.v);
|
||||
|
||||
if (bitsize)
|
||||
modify_field (addr + offset,
|
||||
value_as_long (newval), bitpos, bitsize);
|
||||
else
|
||||
memcpy (addr + offset, value_contents (newval),
|
||||
TYPE_LENGTH (value_type (newval)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_internalvar (struct internalvar *var, struct value *val)
|
||||
{
|
||||
struct value *newval;
|
||||
struct type *new_type = check_typedef (value_type (val));
|
||||
union internalvar_data new_data = { 0 };
|
||||
|
||||
if (var->canonical)
|
||||
error (_("Cannot overwrite convenience function %s"), var->name);
|
||||
|
||||
newval = value_copy (val);
|
||||
newval->modifiable = 1;
|
||||
/* Prepare new contents. */
|
||||
switch (TYPE_CODE (new_type))
|
||||
{
|
||||
case TYPE_CODE_VOID:
|
||||
break;
|
||||
|
||||
/* Force the value to be fetched from the target now, to avoid problems
|
||||
later when this internalvar is referenced and the target is gone or
|
||||
has changed. */
|
||||
if (value_lazy (newval))
|
||||
value_fetch_lazy (newval);
|
||||
case TYPE_CODE_INTERNAL_FUNCTION:
|
||||
gdb_assert (VALUE_LVAL (val) == lval_internalvar);
|
||||
get_internalvar_function (VALUE_INTERNALVAR (val), &new_data.f);
|
||||
break;
|
||||
|
||||
/* Begin code which must not call error(). If var->value points to
|
||||
something free'd, an error() obviously leaves a dangling pointer.
|
||||
But we also get a dangling pointer if var->value points to
|
||||
something in the value chain (i.e., before release_value is
|
||||
called), because after the error free_all_values will get called before
|
||||
long. */
|
||||
value_free (var->value);
|
||||
var->value = newval;
|
||||
var->endian = gdbarch_byte_order (current_gdbarch);
|
||||
release_value (newval);
|
||||
case TYPE_CODE_INT:
|
||||
new_data.l = value_as_long (val);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_PTR:
|
||||
new_data.a = value_as_address (val);
|
||||
break;
|
||||
|
||||
default:
|
||||
new_data.v = value_copy (val);
|
||||
new_data.v->modifiable = 1;
|
||||
|
||||
/* Force the value to be fetched from the target now, to avoid problems
|
||||
later when this internalvar is referenced and the target is gone or
|
||||
has changed. */
|
||||
if (value_lazy (new_data.v))
|
||||
value_fetch_lazy (new_data.v);
|
||||
|
||||
/* Release the value from the value chain to prevent it from being
|
||||
deleted by free_all_values. From here on this function should not
|
||||
call error () until new_data is installed into the var->u to avoid
|
||||
leaking memory. */
|
||||
release_value (new_data.v);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clean up old contents. */
|
||||
clear_internalvar (var);
|
||||
|
||||
/* Switch over. */
|
||||
var->type = new_type;
|
||||
var->u = new_data;
|
||||
/* End code which must not call error(). */
|
||||
}
|
||||
|
||||
void
|
||||
set_internalvar_integer (struct internalvar *var, LONGEST l)
|
||||
{
|
||||
/* Clean up old contents. */
|
||||
clear_internalvar (var);
|
||||
|
||||
/* Use a platform-independent 32-bit integer type. */
|
||||
var->type = builtin_type_int32;
|
||||
var->u.l = l;
|
||||
}
|
||||
|
||||
static void
|
||||
set_internalvar_function (struct internalvar *var, struct internal_function *f)
|
||||
{
|
||||
/* Clean up old contents. */
|
||||
clear_internalvar (var);
|
||||
|
||||
var->type = internal_fn_type;
|
||||
var->u.f = f;
|
||||
}
|
||||
|
||||
void
|
||||
clear_internalvar (struct internalvar *var)
|
||||
{
|
||||
/* Clean up old contents. */
|
||||
switch (TYPE_CODE (var->type))
|
||||
{
|
||||
case TYPE_CODE_VOID:
|
||||
case TYPE_CODE_INTERNAL_FUNCTION:
|
||||
case TYPE_CODE_INT:
|
||||
case TYPE_CODE_PTR:
|
||||
break;
|
||||
|
||||
default:
|
||||
value_free (var->u.v);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set to void type. */
|
||||
var->type = builtin_type_void;
|
||||
}
|
||||
|
||||
char *
|
||||
internalvar_name (struct internalvar *var)
|
||||
{
|
||||
return var->name;
|
||||
}
|
||||
|
||||
static struct value *
|
||||
value_create_internal_function (const char *name,
|
||||
internal_function_fn handler,
|
||||
void *cookie)
|
||||
static struct internal_function *
|
||||
create_internal_function (const char *name,
|
||||
internal_function_fn handler, void *cookie)
|
||||
{
|
||||
struct value *result = allocate_value (internal_fn_type);
|
||||
gdb_byte *addr = value_contents_writeable (result);
|
||||
struct internal_function **fnp = (struct internal_function **) addr;
|
||||
struct internal_function *ifn = XNEW (struct internal_function);
|
||||
ifn->name = xstrdup (name);
|
||||
ifn->handler = handler;
|
||||
ifn->cookie = cookie;
|
||||
*fnp = ifn;
|
||||
return result;
|
||||
return ifn;
|
||||
}
|
||||
|
||||
char *
|
||||
value_internal_function_name (struct value *val)
|
||||
{
|
||||
gdb_byte *addr = value_contents_writeable (val);
|
||||
struct internal_function *ifn = * (struct internal_function **) addr;
|
||||
struct internal_function *ifn;
|
||||
int result;
|
||||
|
||||
gdb_assert (VALUE_LVAL (val) == lval_internalvar);
|
||||
result = get_internalvar_function (VALUE_INTERNALVAR (val), &ifn);
|
||||
gdb_assert (result);
|
||||
|
||||
return ifn->name;
|
||||
}
|
||||
|
||||
struct value *
|
||||
call_internal_function (struct value *func, int argc, struct value **argv)
|
||||
{
|
||||
gdb_byte *addr = value_contents_writeable (func);
|
||||
struct internal_function *ifn = * (struct internal_function **) addr;
|
||||
struct internal_function *ifn;
|
||||
int result;
|
||||
|
||||
gdb_assert (VALUE_LVAL (func) == lval_internalvar);
|
||||
result = get_internalvar_function (VALUE_INTERNALVAR (func), &ifn);
|
||||
gdb_assert (result);
|
||||
|
||||
return (*ifn->handler) (ifn->cookie, argc, argv);
|
||||
}
|
||||
|
||||
@ -1165,9 +1283,11 @@ add_internal_function (const char *name, const char *doc,
|
||||
internal_function_fn handler, void *cookie)
|
||||
{
|
||||
struct cmd_list_element *cmd;
|
||||
struct internal_function *ifn;
|
||||
struct internalvar *var = lookup_internalvar (name);
|
||||
struct value *fnval = value_create_internal_function (name, handler, cookie);
|
||||
set_internalvar (var, fnval);
|
||||
|
||||
ifn = create_internal_function (name, handler, cookie);
|
||||
set_internalvar_function (var, ifn);
|
||||
var->canonical = 1;
|
||||
|
||||
cmd = add_cmd (xstrdup (name), no_class, function_command, (char *) doc,
|
||||
@ -1216,8 +1336,23 @@ preserve_values (struct objfile *objfile)
|
||||
preserve_one_value (cur->values[i], objfile, copied_types);
|
||||
|
||||
for (var = internalvars; var; var = var->next)
|
||||
if (var->value)
|
||||
preserve_one_value (var->value, objfile, copied_types);
|
||||
{
|
||||
if (TYPE_OBJFILE (var->type) == objfile)
|
||||
var->type = copy_type_recursive (objfile, var->type, copied_types);
|
||||
|
||||
switch (TYPE_CODE (var->type))
|
||||
{
|
||||
case TYPE_CODE_VOID:
|
||||
case TYPE_CODE_INTERNAL_FUNCTION:
|
||||
case TYPE_CODE_INT:
|
||||
case TYPE_CODE_PTR:
|
||||
break;
|
||||
|
||||
default:
|
||||
preserve_one_value (var->u.v, objfile, copied_types);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (val = values_in_python; val; val = val->next)
|
||||
preserve_one_value (val, objfile, copied_types);
|
||||
@ -2067,6 +2202,5 @@ Placeholder command for showing help on convenience functions."),
|
||||
|
||||
internal_fn_type = alloc_type (NULL);
|
||||
TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION;
|
||||
TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *);
|
||||
TYPE_NAME (internal_fn_type) = "<internal function>";
|
||||
}
|
||||
|
25
gdb/value.h
25
gdb/value.h
@ -309,23 +309,6 @@ extern struct value *coerce_ref (struct value *value);
|
||||
|
||||
extern struct value *coerce_array (struct value *value);
|
||||
|
||||
/* Internal variables (variables for convenience of use of debugger)
|
||||
are recorded as a chain of these structures. */
|
||||
|
||||
typedef struct value * (*internalvar_make_value) (struct internalvar *);
|
||||
|
||||
struct internalvar
|
||||
{
|
||||
struct internalvar *next;
|
||||
char *name;
|
||||
struct value *value;
|
||||
internalvar_make_value make_value;
|
||||
int endian;
|
||||
/* True if this internalvar is the canonical name for a convenience
|
||||
function. */
|
||||
int canonical;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#include "symtab.h"
|
||||
@ -538,8 +521,14 @@ extern struct value *access_value_history (int num);
|
||||
|
||||
extern struct value *value_of_internalvar (struct internalvar *var);
|
||||
|
||||
extern int get_internalvar_integer (struct internalvar *var, LONGEST *l);
|
||||
|
||||
extern void set_internalvar (struct internalvar *var, struct value *val);
|
||||
|
||||
extern void set_internalvar_integer (struct internalvar *var, LONGEST l);
|
||||
|
||||
extern void clear_internalvar (struct internalvar *var);
|
||||
|
||||
extern void set_internalvar_component (struct internalvar *var,
|
||||
int offset,
|
||||
int bitpos, int bitsize,
|
||||
@ -549,6 +538,8 @@ extern struct internalvar *lookup_only_internalvar (const char *name);
|
||||
|
||||
extern struct internalvar *create_internalvar (const char *name);
|
||||
|
||||
typedef struct value * (*internalvar_make_value) (struct internalvar *);
|
||||
|
||||
extern struct internalvar *
|
||||
create_internalvar_type_lazy (char *name, internalvar_make_value fun);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user