summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZoran Zaric <Zoran.Zaric@amd.com>2020-10-14 10:48:00 +0100
committerZoran Zaric <zoran.zaric@amd.com>2021-11-05 11:46:38 +0000
commitedb4cff0d8ae5d7d9534963a9d364721bb4a882d (patch)
tree92ed4a147be384b23844a80a26a1057e706f5f71
parent087ced679c2644f893966d814a1efd2f84baee03 (diff)
downloadbinutils-gdb-edb4cff0d8ae5d7d9534963a9d364721bb4a882d.tar.gz
Add support for any location description in CFI
One of the main benefits of allowing location description to be on the DWARF stack is that now CFI expression based register rules can be defined using a location description operations. This allows a register of one frame to be saved in any location, including any composite location. To fully support this feature, the execute_stack_op function in dwarf2/frame.c needs to return a single struct value object instead of just an address. Function put_frame_register_bytes also needs to change to support any location description. This support is a one of the key features to truly support optimized code. gdb/ChangeLog: * dwarf2/frame.c (execute_stack_op): Change to return a struct value object. (dwarf2_frame_cache): Change to call new execute_stack_op definition. (dwarf2_frame_prev_register): Change to call new execute_stack_op definition. * frame.c (put_frame_register_bytes): Add support for writing to composite location description.
-rw-r--r--gdb/dwarf2/frame.c54
-rw-r--r--gdb/frame.c31
2 files changed, 58 insertions, 27 deletions
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index e17b36e243b..e70dcd5a86e 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -236,16 +236,17 @@ register %s (#%d) at %s"),
}
}
-static CORE_ADDR
+static value *
execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
struct frame_info *this_frame, CORE_ADDR initial,
- int initial_in_stack_memory, dwarf2_per_objfile *per_objfile)
+ int initial_in_stack_memory, dwarf2_per_objfile *per_objfile,
+ struct type* type = nullptr, bool as_lval = true)
{
scoped_value_mark free_values;
- struct type *type = address_type (per_objfile->objfile->arch (),
- addr_size);
+ struct type *init_type = address_type (per_objfile->objfile->arch (),
+ addr_size);
- value *init_value = value_at_lazy (type, initial);
+ value *init_value = value_at_lazy (init_type, initial);
std::vector<value *> init_values;
set_value_stack (init_value, initial_in_stack_memory);
@@ -255,10 +256,15 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
= dwarf2_evaluate (exp, len, true, per_objfile, nullptr,
this_frame, addr_size, &init_values, nullptr);
- if (VALUE_LVAL (result_val) == lval_memory)
- return value_address (result_val);
- else
- return value_as_address (result_val);
+ /* We need to clean up all the values that are not needed any more.
+ The problem with a value_ref_ptr class is that it disconnects the
+ RETVAL from the value garbage collection, so we need to make
+ a copy of that value on the stack to keep everything consistent.
+ The value_ref_ptr will clean up after itself at the end of this block. */
+ value_ref_ptr value_holder = value_ref_ptr::new_reference (result_val);
+ free_values.free_to_mark ();
+
+ return value_copy (result_val);
}
@@ -989,10 +995,14 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
break;
case CFA_EXP:
- cache->cfa =
- execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
- cache->addr_size, this_frame, 0, 0,
- cache->per_objfile);
+ {
+ struct value *value
+ = execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
+ cache->addr_size, this_frame, 0, 0,
+ cache->per_objfile);
+ cache->cfa = value_address (value);
+ }
+
break;
default:
@@ -1190,24 +1200,22 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
return frame_unwind_got_register (this_frame, regnum, realnum);
case DWARF2_FRAME_REG_SAVED_EXP:
- addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
+ return execute_stack_op (cache->reg[regnum].loc.exp.start,
cache->reg[regnum].loc.exp.len,
- cache->addr_size,
- this_frame, cache->cfa, 1,
- cache->per_objfile);
- return frame_unwind_got_memory (this_frame, regnum, addr);
+ cache->addr_size, this_frame,
+ cache->cfa, 1, cache->per_objfile,
+ register_type (gdbarch, regnum));
case DWARF2_FRAME_REG_SAVED_VAL_OFFSET:
addr = cache->cfa + cache->reg[regnum].loc.offset;
return frame_unwind_got_constant (this_frame, regnum, addr);
case DWARF2_FRAME_REG_SAVED_VAL_EXP:
- addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
+ return execute_stack_op (cache->reg[regnum].loc.exp.start,
cache->reg[regnum].loc.exp.len,
- cache->addr_size,
- this_frame, cache->cfa, 1,
- cache->per_objfile);
- return frame_unwind_got_constant (this_frame, regnum, addr);
+ cache->addr_size, this_frame,
+ cache->cfa, 1, cache->per_objfile,
+ register_type (gdbarch, regnum), false);
case DWARF2_FRAME_REG_UNSPECIFIED:
/* GCC, in its infinite wisdom decided to not provide unwind
diff --git a/gdb/frame.c b/gdb/frame.c
index 2a899fc494f..3dd6c799847 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1534,19 +1534,42 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
{
int curr_len = register_size (gdbarch, regnum) - offset;
+ struct value *value = frame_unwind_register_value (frame->next,
+ regnum);
+
if (curr_len > len)
curr_len = len;
const gdb_byte *myaddr = buffer.data ();
- if (curr_len == register_size (gdbarch, regnum))
+
+ /* Computed value is a special case. The computed callback
+ mechanism requires a strut value argument, so we need to
+ make one. */
+ if (value != nullptr && VALUE_LVAL (value) == lval_computed)
+ {
+ const lval_funcs *funcs = value_computed_funcs (value);
+
+ if (funcs->write == nullptr)
+ error (_("Attempt to assign to an unmodifiable value."));
+
+ type * reg_type = register_type (gdbarch, regnum);
+
+ struct value *from_value = allocate_value (reg_type);
+ memcpy (value_contents_raw (from_value), myaddr,
+ TYPE_LENGTH (reg_type));
+
+ set_value_offset (value, offset);
+
+ funcs->write (value, from_value);
+ release_value (from_value);
+ }
+ else if (curr_len == register_size (gdbarch, regnum))
{
put_frame_register (frame, regnum, myaddr);
}
else
{
- struct value *value = frame_unwind_register_value (frame->next,
- regnum);
- gdb_assert (value != NULL);
+ gdb_assert (value != nullptr);
memcpy ((char *) value_contents_writeable (value).data () + offset,
myaddr, curr_len);