Remove free_value_chain
This patch changes value_release_to_mark and fetch_subexp_value to return a std::vector of value references, rather than relying on the "next" field that is contained in a struct value. This makes it simpler to reason about the returned values, and also allows for the removal of free_value_chain. gdb/ChangeLog 2018-04-06 Tom Tromey <tom@tromey.com> * value.h (fetch_subexp_value, value_release_to_mark): Update. (free_value_chain): Remove. * value.c (free_value_chain): Remove. (value_release_to_mark): Return a std::vector. * ppc-linux-nat.c (num_memory_accesses): Change "chain" to a std::vector. (check_condition): Update. * eval.c (fetch_subexp_value): Change "val_chain" to a std::vector. * breakpoint.c (update_watchpoint): Update. (can_use_hardware_watchpoint): Change "vals" to a std::vector.
This commit is contained in:
parent
b562120198
commit
a6535de190
6 changed files with 69 additions and 73 deletions
|
@ -1,3 +1,17 @@
|
||||||
|
2018-04-06 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
|
* value.h (fetch_subexp_value, value_release_to_mark): Update.
|
||||||
|
(free_value_chain): Remove.
|
||||||
|
* value.c (free_value_chain): Remove.
|
||||||
|
(value_release_to_mark): Return a std::vector.
|
||||||
|
* ppc-linux-nat.c (num_memory_accesses): Change "chain" to a
|
||||||
|
std::vector.
|
||||||
|
(check_condition): Update.
|
||||||
|
* eval.c (fetch_subexp_value): Change "val_chain" to a
|
||||||
|
std::vector.
|
||||||
|
* breakpoint.c (update_watchpoint): Update.
|
||||||
|
(can_use_hardware_watchpoint): Change "vals" to a std::vector.
|
||||||
|
|
||||||
2018-04-06 Tom Tromey <tom@tromey.com>
|
2018-04-06 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
* value.h (free_all_values): Remove.
|
* value.h (free_all_values): Remove.
|
||||||
|
|
|
@ -117,7 +117,8 @@ static std::vector<symtab_and_line> decode_location_default
|
||||||
(struct breakpoint *b, const struct event_location *location,
|
(struct breakpoint *b, const struct event_location *location,
|
||||||
struct program_space *search_pspace);
|
struct program_space *search_pspace);
|
||||||
|
|
||||||
static int can_use_hardware_watchpoint (struct value *);
|
static int can_use_hardware_watchpoint
|
||||||
|
(const std::vector<value_ref_ptr> &vals);
|
||||||
|
|
||||||
static void mention (struct breakpoint *);
|
static void mention (struct breakpoint *);
|
||||||
|
|
||||||
|
@ -1777,7 +1778,8 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
||||||
else if (within_current_scope && b->exp)
|
else if (within_current_scope && b->exp)
|
||||||
{
|
{
|
||||||
int pc = 0;
|
int pc = 0;
|
||||||
struct value *val_chain, *v, *result, *next;
|
std::vector<value_ref_ptr> val_chain;
|
||||||
|
struct value *v, *result, *next;
|
||||||
struct program_space *frame_pspace;
|
struct program_space *frame_pspace;
|
||||||
|
|
||||||
fetch_subexp_value (b->exp.get (), &pc, &v, &result, &val_chain, 0);
|
fetch_subexp_value (b->exp.get (), &pc, &v, &result, &val_chain, 0);
|
||||||
|
@ -1799,15 +1801,18 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
||||||
frame_pspace = get_frame_program_space (get_selected_frame (NULL));
|
frame_pspace = get_frame_program_space (get_selected_frame (NULL));
|
||||||
|
|
||||||
/* Look at each value on the value chain. */
|
/* Look at each value on the value chain. */
|
||||||
for (v = val_chain; v; v = value_next (v))
|
gdb_assert (!val_chain.empty ());
|
||||||
|
for (const value_ref_ptr &iter : val_chain)
|
||||||
{
|
{
|
||||||
|
v = iter.get ();
|
||||||
|
|
||||||
/* If it's a memory location, and GDB actually needed
|
/* If it's a memory location, and GDB actually needed
|
||||||
its contents to evaluate the expression, then we
|
its contents to evaluate the expression, then we
|
||||||
must watch it. If the first value returned is
|
must watch it. If the first value returned is
|
||||||
still lazy, that means an error occurred reading it;
|
still lazy, that means an error occurred reading it;
|
||||||
watch it anyway in case it becomes readable. */
|
watch it anyway in case it becomes readable. */
|
||||||
if (VALUE_LVAL (v) == lval_memory
|
if (VALUE_LVAL (v) == lval_memory
|
||||||
&& (v == val_chain || ! value_lazy (v)))
|
&& (v == val_chain[0] || ! value_lazy (v)))
|
||||||
{
|
{
|
||||||
struct type *vtype = check_typedef (value_type (v));
|
struct type *vtype = check_typedef (value_type (v));
|
||||||
|
|
||||||
|
@ -1962,13 +1967,6 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
||||||
bl->loc_type = loc_type;
|
bl->loc_type = loc_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (v = val_chain; v; v = next)
|
|
||||||
{
|
|
||||||
next = value_next (v);
|
|
||||||
if (v != b->val)
|
|
||||||
value_decref (v);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If a software watchpoint is not watching any memory, then the
|
/* If a software watchpoint is not watching any memory, then the
|
||||||
above left it without any location set up. But,
|
above left it without any location set up. But,
|
||||||
bpstat_stop_status requires a location to be able to report
|
bpstat_stop_status requires a location to be able to report
|
||||||
|
@ -10875,15 +10873,17 @@ watch_command_1 (const char *arg, int accessflag, int from_tty,
|
||||||
If the watchpoint cannot be handled in hardware return zero. */
|
If the watchpoint cannot be handled in hardware return zero. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
can_use_hardware_watchpoint (struct value *v)
|
can_use_hardware_watchpoint (const std::vector<value_ref_ptr> &vals)
|
||||||
{
|
{
|
||||||
int found_memory_cnt = 0;
|
int found_memory_cnt = 0;
|
||||||
struct value *head = v;
|
|
||||||
|
|
||||||
/* Did the user specifically forbid us to use hardware watchpoints? */
|
/* Did the user specifically forbid us to use hardware watchpoints? */
|
||||||
if (!can_use_hw_watchpoints)
|
if (!can_use_hw_watchpoints)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
gdb_assert (!vals.empty ());
|
||||||
|
struct value *head = vals[0].get ();
|
||||||
|
|
||||||
/* Make sure that the value of the expression depends only upon
|
/* Make sure that the value of the expression depends only upon
|
||||||
memory contents, and values computed from them within GDB. If we
|
memory contents, and values computed from them within GDB. If we
|
||||||
find any register references or function calls, we can't use a
|
find any register references or function calls, we can't use a
|
||||||
|
@ -10903,8 +10903,10 @@ can_use_hardware_watchpoint (struct value *v)
|
||||||
function calls are special in any way. So this function may not
|
function calls are special in any way. So this function may not
|
||||||
notice that an expression involving an inferior function call
|
notice that an expression involving an inferior function call
|
||||||
can't be watched with hardware watchpoints. FIXME. */
|
can't be watched with hardware watchpoints. FIXME. */
|
||||||
for (; v; v = value_next (v))
|
for (const value_ref_ptr &iter : vals)
|
||||||
{
|
{
|
||||||
|
struct value *v = iter.get ();
|
||||||
|
|
||||||
if (VALUE_LVAL (v) == lval_memory)
|
if (VALUE_LVAL (v) == lval_memory)
|
||||||
{
|
{
|
||||||
if (v != head && value_lazy (v))
|
if (v != head && value_lazy (v))
|
||||||
|
|
15
gdb/eval.c
15
gdb/eval.c
|
@ -179,14 +179,14 @@ evaluate_subexpression_type (struct expression *exp, int subexp)
|
||||||
set to any referenced values. *VALP will never be a lazy value.
|
set to any referenced values. *VALP will never be a lazy value.
|
||||||
This is the value which we store in struct breakpoint.
|
This is the value which we store in struct breakpoint.
|
||||||
|
|
||||||
If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
|
If VAL_CHAIN is non-NULL, the values put into *VAL_CHAIN will be
|
||||||
value chain. The caller must free the values individually. If
|
released from the value chain. If VAL_CHAIN is NULL, all generated
|
||||||
VAL_CHAIN is NULL, all generated values will be left on the value
|
values will be left on the value chain. */
|
||||||
chain. */
|
|
||||||
|
|
||||||
void
|
void
|
||||||
fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
|
fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
|
||||||
struct value **resultp, struct value **val_chain,
|
struct value **resultp,
|
||||||
|
std::vector<value_ref_ptr> *val_chain,
|
||||||
int preserve_errors)
|
int preserve_errors)
|
||||||
{
|
{
|
||||||
struct value *mark, *new_mark, *result;
|
struct value *mark, *new_mark, *result;
|
||||||
|
@ -195,7 +195,7 @@ fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
|
||||||
if (resultp)
|
if (resultp)
|
||||||
*resultp = NULL;
|
*resultp = NULL;
|
||||||
if (val_chain)
|
if (val_chain)
|
||||||
*val_chain = NULL;
|
val_chain->clear ();
|
||||||
|
|
||||||
/* Evaluate the expression. */
|
/* Evaluate the expression. */
|
||||||
mark = value_mark ();
|
mark = value_mark ();
|
||||||
|
@ -253,8 +253,7 @@ fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
|
||||||
{
|
{
|
||||||
/* Return the chain of intermediate values. We use this to
|
/* Return the chain of intermediate values. We use this to
|
||||||
decide which addresses to watch. */
|
decide which addresses to watch. */
|
||||||
*val_chain = new_mark;
|
*val_chain = value_release_to_mark (mark);
|
||||||
value_release_to_mark (mark);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1840,10 +1840,9 @@ calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
|
||||||
other kinds of values which are not acceptable in a condition
|
other kinds of values which are not acceptable in a condition
|
||||||
expression (e.g., lval_computed or lval_internalvar). */
|
expression (e.g., lval_computed or lval_internalvar). */
|
||||||
static int
|
static int
|
||||||
num_memory_accesses (struct value *v)
|
num_memory_accesses (const std::vector<value_ref_ptr> &chain)
|
||||||
{
|
{
|
||||||
int found_memory_cnt = 0;
|
int found_memory_cnt = 0;
|
||||||
struct value *head = v;
|
|
||||||
|
|
||||||
/* The idea here is that evaluating an expression generates a series
|
/* The idea here is that evaluating an expression generates a series
|
||||||
of values, one holding the value of every subexpression. (The
|
of values, one holding the value of every subexpression. (The
|
||||||
|
@ -1860,8 +1859,10 @@ num_memory_accesses (struct value *v)
|
||||||
notice that an expression contains an inferior function call.
|
notice that an expression contains an inferior function call.
|
||||||
FIXME. */
|
FIXME. */
|
||||||
|
|
||||||
for (; v; v = value_next (v))
|
for (const value_ref_ptr &iter : chain)
|
||||||
{
|
{
|
||||||
|
struct value *v = iter.get ();
|
||||||
|
|
||||||
/* Constants and values from the history are fine. */
|
/* Constants and values from the history are fine. */
|
||||||
if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
|
if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -1892,7 +1893,8 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
|
||||||
CORE_ADDR *data_value, int *len)
|
CORE_ADDR *data_value, int *len)
|
||||||
{
|
{
|
||||||
int pc = 1, num_accesses_left, num_accesses_right;
|
int pc = 1, num_accesses_left, num_accesses_right;
|
||||||
struct value *left_val, *right_val, *left_chain, *right_chain;
|
struct value *left_val, *right_val;
|
||||||
|
std::vector<value_ref_ptr> left_chain, right_chain;
|
||||||
|
|
||||||
if (cond->elts[0].opcode != BINOP_EQUAL)
|
if (cond->elts[0].opcode != BINOP_EQUAL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1901,22 +1903,13 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
|
||||||
num_accesses_left = num_memory_accesses (left_chain);
|
num_accesses_left = num_memory_accesses (left_chain);
|
||||||
|
|
||||||
if (left_val == NULL || num_accesses_left < 0)
|
if (left_val == NULL || num_accesses_left < 0)
|
||||||
{
|
|
||||||
free_value_chain (left_chain);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, 0);
|
fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, 0);
|
||||||
num_accesses_right = num_memory_accesses (right_chain);
|
num_accesses_right = num_memory_accesses (right_chain);
|
||||||
|
|
||||||
if (right_val == NULL || num_accesses_right < 0)
|
if (right_val == NULL || num_accesses_right < 0)
|
||||||
{
|
|
||||||
free_value_chain (left_chain);
|
|
||||||
free_value_chain (right_chain);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
if (num_accesses_left == 1 && num_accesses_right == 0
|
if (num_accesses_left == 1 && num_accesses_right == 0
|
||||||
&& VALUE_LVAL (left_val) == lval_memory
|
&& VALUE_LVAL (left_val) == lval_memory
|
||||||
|
@ -1939,15 +1932,7 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
|
||||||
*len = TYPE_LENGTH (check_typedef (value_type (right_val)));
|
*len = TYPE_LENGTH (check_typedef (value_type (right_val)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
free_value_chain (left_chain);
|
|
||||||
free_value_chain (right_chain);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
free_value_chain (left_chain);
|
|
||||||
free_value_chain (right_chain);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
37
gdb/value.c
37
gdb/value.c
|
@ -1638,20 +1638,6 @@ value_free_to_mark (const struct value *mark)
|
||||||
all_values = val;
|
all_values = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Frees all the elements in a chain of values. */
|
|
||||||
|
|
||||||
void
|
|
||||||
free_value_chain (struct value *v)
|
|
||||||
{
|
|
||||||
struct value *next;
|
|
||||||
|
|
||||||
for (; v; v = next)
|
|
||||||
{
|
|
||||||
next = value_next (v);
|
|
||||||
value_decref (v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove VAL from the chain all_values
|
/* Remove VAL from the chain all_values
|
||||||
so it will not be freed automatically. */
|
so it will not be freed automatically. */
|
||||||
|
|
||||||
|
@ -1695,25 +1681,30 @@ release_value (struct value *val)
|
||||||
return value_ref_ptr (val);
|
return value_ref_ptr (val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release all values up to mark */
|
/* See value.h. */
|
||||||
struct value *
|
|
||||||
|
std::vector<value_ref_ptr>
|
||||||
value_release_to_mark (const struct value *mark)
|
value_release_to_mark (const struct value *mark)
|
||||||
{
|
{
|
||||||
struct value *val;
|
std::vector<value_ref_ptr> result;
|
||||||
struct value *next;
|
struct value *next;
|
||||||
|
|
||||||
for (val = next = all_values; next; next = next->next)
|
for (next = all_values; next; next = next->next)
|
||||||
{
|
{
|
||||||
|
next->released = 1;
|
||||||
|
result.emplace_back (next);
|
||||||
|
|
||||||
if (next->next == mark)
|
if (next->next == mark)
|
||||||
{
|
{
|
||||||
all_values = next->next;
|
struct value *save = next->next;
|
||||||
next->next = NULL;
|
next->next = NULL;
|
||||||
return val;
|
next = save;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
next->released = 1;
|
|
||||||
}
|
}
|
||||||
all_values = 0;
|
|
||||||
return val;
|
all_values = next;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a copy of the value ARG.
|
/* Return a copy of the value ARG.
|
||||||
|
|
13
gdb/value.h
13
gdb/value.h
|
@ -915,7 +915,7 @@ extern value *eval_skip_value (expression *exp);
|
||||||
|
|
||||||
extern void fetch_subexp_value (struct expression *exp, int *pc,
|
extern void fetch_subexp_value (struct expression *exp, int *pc,
|
||||||
struct value **valp, struct value **resultp,
|
struct value **valp, struct value **resultp,
|
||||||
struct value **val_chain,
|
std::vector<value_ref_ptr> *val_chain,
|
||||||
int preserve_errors);
|
int preserve_errors);
|
||||||
|
|
||||||
extern const char *extract_field_op (struct expression *exp, int *subexp);
|
extern const char *extract_field_op (struct expression *exp, int *subexp);
|
||||||
|
@ -1053,8 +1053,6 @@ extern int unop_user_defined_p (enum exp_opcode op, struct value *arg1);
|
||||||
|
|
||||||
extern int destructor_name_p (const char *name, struct type *type);
|
extern int destructor_name_p (const char *name, struct type *type);
|
||||||
|
|
||||||
extern void free_value_chain (struct value *v);
|
|
||||||
|
|
||||||
extern value_ref_ptr release_value (struct value *val);
|
extern value_ref_ptr release_value (struct value *val);
|
||||||
|
|
||||||
extern int record_latest_value (struct value *val);
|
extern int record_latest_value (struct value *val);
|
||||||
|
@ -1084,7 +1082,14 @@ extern void value_print_array_elements (struct value *val,
|
||||||
struct ui_file *stream, int format,
|
struct ui_file *stream, int format,
|
||||||
enum val_prettyformat pretty);
|
enum val_prettyformat pretty);
|
||||||
|
|
||||||
extern struct value *value_release_to_mark (const struct value *mark);
|
/* Release values from the value chain and return them. Values
|
||||||
|
created after MARK are released. If MARK is nullptr, or if MARK is
|
||||||
|
not found on the value chain, then all values are released. Values
|
||||||
|
are returned in reverse order of creation; that is, newest
|
||||||
|
first. */
|
||||||
|
|
||||||
|
extern std::vector<value_ref_ptr> value_release_to_mark
|
||||||
|
(const struct value *mark);
|
||||||
|
|
||||||
extern void val_print (struct type *type,
|
extern void val_print (struct type *type,
|
||||||
LONGEST embedded_offset, CORE_ADDR address,
|
LONGEST embedded_offset, CORE_ADDR address,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue