From: Zoran Zaric Date: Mon, 7 Dec 2020 19:00:28 +0000 (+0000) Subject: Add support for any location description in CFI X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a6491910ec6b5a53709ef648cc219d2df451b49a;p=thirdparty%2Fbinutils-gdb.git 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 --- diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c index 1469621133f..e83031d1a55 100644 --- a/gdb/dwarf2/frame.c +++ b/gdb/dwarf2/frame.c @@ -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 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 diff --git a/gdb/frame.c b/gdb/frame.c index 4618da6c81e..0068bf84555 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -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;