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.

Change-Id: I0c23ba56310174a2f8e539be72a11ac554efcaca
This commit is contained in:
Zoran Zaric
2020-12-07 19:00:28 +00:00
committed by Simon Marchi
parent 07089eff99
commit a6491910ec
2 changed files with 61 additions and 29 deletions

View File

@@ -235,16 +235,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);
struct value *init_value = value_at_lazy (type, initial);
struct value *init_value = value_at_lazy (init_type, initial);
std::vector<struct value *> init_values;
set_value_stack (init_value, initial_in_stack_memory);
@@ -254,10 +255,15 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
= dwarf2_eval_exp (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);
}
@@ -988,10 +994,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:
@@ -1189,24 +1199,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

View File

@@ -1567,25 +1567,49 @@ 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;
if (curr_len == register_size (gdbarch, regnum))
/* Compute value is a special new case. The problem is that
the computed callback mechanism only supports a struct
value arguments, so we need to make one. */
if (value != NULL && VALUE_LVAL (value) == lval_computed)
{
struct value *from_value;
const struct lval_funcs *funcs = value_computed_funcs (value);
struct type * reg_type = register_type (gdbarch, regnum);
if (funcs->write == NULL)
error (_("Attempt to assign to an unmodifiable 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);
memcpy ((char *) value_contents_writeable (value) + offset, myaddr,
curr_len);
memcpy ((char *) value_contents_writeable (value) + offset,
myaddr, curr_len);
put_frame_register (frame, regnum, value_contents_raw (value));
release_value (value);
}
if (value != NULL)
release_value (value);
myaddr += curr_len;
len -= curr_len;
offset = 0;