diff options
author | Maciej W. Rozycki <macro@embecosm.com> | 2023-02-10 23:49:19 +0000 |
---|---|---|
committer | Maciej W. Rozycki <macro@embecosm.com> | 2023-02-10 23:49:19 +0000 |
commit | aaab5fce4f25e0d3b1a85edc7d6ac8f7d06f599c (patch) | |
tree | 27e8bf3de78fc774e0318806087240c8dffd86ac /gdb/value.c | |
parent | 4f82620cc9fd1ef630b6b732a9d939d4e529a07f (diff) | |
download | binutils-aaab5fce4f25e0d3b1a85edc7d6ac8f7d06f599c.zip binutils-aaab5fce4f25e0d3b1a85edc7d6ac8f7d06f599c.tar.gz binutils-aaab5fce4f25e0d3b1a85edc7d6ac8f7d06f599c.tar.bz2 |
GDB: Only make data actually retrieved into value history available
While it makes sense to allow accessing out-of-bounds elements in the
debuggee and see whatever there might happen to be there in memory (we
are a debugger and not a programming rules enforcement facility and we
want to make people's life easier in chasing bugs), e.g.:
(gdb) print one_hundred[-1]
$1 = 0
(gdb) print one_hundred[100]
$2 = 0
(gdb)
we shouldn't really pretend that we have any meaningful data around
values recorded in history (what these commands really retrieve are
current debuggee memory contents outside the original data accessed,
really confusing in my opinion). Mark values recorded in history as
such then and verify accesses to be in-range for them:
(gdb) print one_hundred[-1]
$1 = <unavailable>
(gdb) print one_hundred[100]
$2 = <unavailable>
Add a suitable test case, which also covers integer overflows in data
location calculation.
Approved-By: Tom Tromey <tom@tromey.com>
Diffstat (limited to 'gdb/value.c')
-rw-r--r-- | gdb/value.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/gdb/value.c b/gdb/value.c index 57625b0..fbdb079 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -185,6 +185,7 @@ struct value initialized (1), stack (0), is_zero (false), + in_history (false), type (type_), enclosing_type (type_) { @@ -239,6 +240,9 @@ struct value otherwise. */ bool is_zero : 1; + /* True if this a value recorded in value history; false otherwise. */ + bool in_history : 1; + /* Location of value (if lval). */ union { @@ -385,7 +389,13 @@ value_bits_available (const struct value *value, { gdb_assert (!value->lazy); - return !ranges_contain (value->unavailable, offset, length); + /* Don't pretend we have anything available there in the history beyond + the boundaries of the value recorded. It's not like inferior memory + where there is actual stuff underneath. */ + ULONGEST val_len = TARGET_CHAR_BIT * value_enclosing_type (value)->length (); + return !((value->in_history + && (offset < 0 || offset + length > val_len)) + || ranges_contain (value->unavailable, offset, length)); } int @@ -1797,6 +1807,7 @@ value_copy (const value *arg) val->modifiable = arg->modifiable; val->stack = arg->stack; val->is_zero = arg->is_zero; + val->in_history = arg->in_history; val->initialized = arg->initialized; val->unavailable = arg->unavailable; val->optimized_out = arg->optimized_out; @@ -1950,6 +1961,10 @@ record_latest_value (struct value *val) a value on the value history never changes. */ if (value_lazy (val)) value_fetch_lazy (val); + + /* Mark the value as recorded in the history for the availability check. */ + val->in_history = true; + /* We preserve VALUE_LVAL so that the user can find out where it was fetched from. This is a bit dubious, because then *&$1 does not just return $1 but the current contents of that location. c'est la vie... */ |