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>
|
||||
|
||||
* 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 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 *);
|
||||
|
||||
|
@ -1777,7 +1778,8 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
|||
else if (within_current_scope && b->exp)
|
||||
{
|
||||
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;
|
||||
|
||||
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));
|
||||
|
||||
/* 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
|
||||
its contents to evaluate the expression, then we
|
||||
must watch it. If the first value returned is
|
||||
still lazy, that means an error occurred reading it;
|
||||
watch it anyway in case it becomes readable. */
|
||||
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));
|
||||
|
||||
|
@ -1962,13 +1967,6 @@ update_watchpoint (struct watchpoint *b, int reparse)
|
|||
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
|
||||
above left it without any location set up. But,
|
||||
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. */
|
||||
|
||||
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;
|
||||
struct value *head = v;
|
||||
|
||||
/* Did the user specifically forbid us to use hardware watchpoints? */
|
||||
if (!can_use_hw_watchpoints)
|
||||
return 0;
|
||||
|
||||
gdb_assert (!vals.empty ());
|
||||
struct value *head = vals[0].get ();
|
||||
|
||||
/* Make sure that the value of the expression depends only upon
|
||||
memory contents, and values computed from them within GDB. If we
|
||||
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
|
||||
notice that an expression involving an inferior function call
|
||||
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 (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.
|
||||
This is the value which we store in struct breakpoint.
|
||||
|
||||
If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the
|
||||
value chain. The caller must free the values individually. If
|
||||
VAL_CHAIN is NULL, all generated values will be left on the value
|
||||
chain. */
|
||||
If VAL_CHAIN is non-NULL, the values put into *VAL_CHAIN will be
|
||||
released from the value chain. If VAL_CHAIN is NULL, all generated
|
||||
values will be left on the value chain. */
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
struct value *mark, *new_mark, *result;
|
||||
|
@ -195,7 +195,7 @@ fetch_subexp_value (struct expression *exp, int *pc, struct value **valp,
|
|||
if (resultp)
|
||||
*resultp = NULL;
|
||||
if (val_chain)
|
||||
*val_chain = NULL;
|
||||
val_chain->clear ();
|
||||
|
||||
/* Evaluate the expression. */
|
||||
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
|
||||
decide which addresses to watch. */
|
||||
*val_chain = new_mark;
|
||||
value_release_to_mark (mark);
|
||||
*val_chain = 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
|
||||
expression (e.g., lval_computed or lval_internalvar). */
|
||||
static int
|
||||
num_memory_accesses (struct value *v)
|
||||
num_memory_accesses (const std::vector<value_ref_ptr> &chain)
|
||||
{
|
||||
int found_memory_cnt = 0;
|
||||
struct value *head = v;
|
||||
|
||||
/* The idea here is that evaluating an expression generates a series
|
||||
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.
|
||||
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. */
|
||||
if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
|
||||
continue;
|
||||
|
@ -1892,7 +1893,8 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
|
|||
CORE_ADDR *data_value, int *len)
|
||||
{
|
||||
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)
|
||||
return 0;
|
||||
|
@ -1901,22 +1903,13 @@ check_condition (CORE_ADDR watch_addr, struct expression *cond,
|
|||
num_accesses_left = num_memory_accesses (left_chain);
|
||||
|
||||
if (left_val == NULL || num_accesses_left < 0)
|
||||
{
|
||||
free_value_chain (left_chain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, 0);
|
||||
num_accesses_right = num_memory_accesses (right_chain);
|
||||
|
||||
if (right_val == NULL || num_accesses_right < 0)
|
||||
{
|
||||
free_value_chain (left_chain);
|
||||
free_value_chain (right_chain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (num_accesses_left == 1 && num_accesses_right == 0
|
||||
&& 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)));
|
||||
}
|
||||
else
|
||||
{
|
||||
free_value_chain (left_chain);
|
||||
free_value_chain (right_chain);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
free_value_chain (left_chain);
|
||||
free_value_chain (right_chain);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
so it will not be freed automatically. */
|
||||
|
||||
|
@ -1695,25 +1681,30 @@ release_value (struct value *val)
|
|||
return value_ref_ptr (val);
|
||||
}
|
||||
|
||||
/* Release all values up to mark */
|
||||
struct value *
|
||||
/* See value.h. */
|
||||
|
||||
std::vector<value_ref_ptr>
|
||||
value_release_to_mark (const struct value *mark)
|
||||
{
|
||||
struct value *val;
|
||||
std::vector<value_ref_ptr> result;
|
||||
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)
|
||||
{
|
||||
all_values = next->next;
|
||||
struct value *save = next->next;
|
||||
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.
|
||||
|
|
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,
|
||||
struct value **valp, struct value **resultp,
|
||||
struct value **val_chain,
|
||||
std::vector<value_ref_ptr> *val_chain,
|
||||
int preserve_errors);
|
||||
|
||||
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 void free_value_chain (struct value *v);
|
||||
|
||||
extern value_ref_ptr release_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,
|
||||
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,
|
||||
LONGEST embedded_offset, CORE_ADDR address,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue