@@ -886,11 +886,15 @@ dwarf2_frame_find_quirks (struct dwarf2_frame_state *fs,
}
-void
-dwarf2_compile_cfa_to_ax (struct agent_expr *expr, struct axs_value *loc,
- struct gdbarch *gdbarch,
- CORE_ADDR pc,
- struct dwarf2_per_cu_data *data)
+/* See dwarf2-frame.h. */
+
+int
+dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
+ struct dwarf2_per_cu_data *data,
+ int *regnum_out, LONGEST *offset_out,
+ CORE_ADDR *text_offset_out,
+ const gdb_byte **cfa_start_out,
+ const gdb_byte **cfa_end_out)
{
struct dwarf2_fde *fde;
CORE_ADDR text_offset;
@@ -936,26 +940,20 @@ dwarf2_compile_cfa_to_ax (struct agent_expr *expr, struct axs_value *loc,
if (regnum == -1)
error (_("Unable to access DWARF register number %d"),
(int) fs.regs.cfa_reg); /* FIXME */
- ax_reg (expr, regnum);
- if (fs.regs.cfa_offset != 0)
- {
- if (fs.armcc_cfa_offsets_reversed)
- ax_const_l (expr, -fs.regs.cfa_offset);
- else
- ax_const_l (expr, fs.regs.cfa_offset);
- ax_simple (expr, aop_add);
- }
+ *regnum_out = regnum;
+ if (fs.armcc_cfa_offsets_reversed)
+ *offset_out = -fs.regs.cfa_offset;
+ else
+ *offset_out = fs.regs.cfa_offset;
+ return 1;
}
- break;
case CFA_EXP:
- ax_const_l (expr, text_offset);
- dwarf2_compile_expr_to_ax (expr, loc, gdbarch, addr_size,
- fs.regs.cfa_exp,
- fs.regs.cfa_exp + fs.regs.cfa_exp_len,
- data);
- break;
+ *text_offset_out = text_offset;
+ *cfa_start_out = fs.regs.cfa_exp;
+ *cfa_end_out = fs.regs.cfa_exp + fs.regs.cfa_exp_len;
+ return 0;
default:
internal_error (__FILE__, __LINE__, _("Unknown CFA rule."));
@@ -120,15 +120,26 @@ extern const struct frame_base *
CORE_ADDR dwarf2_frame_cfa (struct frame_info *this_frame);
-/* Update the agent expression EXPR with code to compute the CFA for a
- frame at PC. GDBARCH is the architecture of the function at PC.
- This function may call dwarf2_compile_expr_to_ax; DATA is passed
- through to that function if needed. */
-
-extern void dwarf2_compile_cfa_to_ax (struct agent_expr *expr,
- struct axs_value *loc,
- struct gdbarch *gdbarch,
- CORE_ADDR pc,
- struct dwarf2_per_cu_data *data);
+/* Find the CFA information for PC.
+
+ Return 1 if a register is used for the CFA, or 0 if another
+ expression is used. Throw an exception on error.
+
+ GDBARCH is the architecture to use.
+ DATA is the per-CU data.
+
+ REGNUM_OUT is an out parameter that is set to the register number.
+ OFFSET_OUT is the offset to use from this register.
+ These are only filled in when 1 is returned.
+
+ TEXT_OFFSET_OUT, CFA_START_OUT, and CFA_END_OUT describe the CFA
+ in other cases. These are only used when 0 is returned. */
+
+extern int dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
+ struct dwarf2_per_cu_data *data,
+ int *regnum_out, LONGEST *offset_out,
+ CORE_ADDR *text_offset_out,
+ const gdb_byte **cfa_start_out,
+ const gdb_byte **cfa_end_out);
#endif /* dwarf2-frame.h */
@@ -3308,8 +3308,34 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
break;
case DW_OP_call_frame_cfa:
- dwarf2_compile_cfa_to_ax (expr, loc, arch, expr->scope, per_cu);
- loc->kind = axs_lvalue_memory;
+ {
+ int regnum;
+ CORE_ADDR text_offset;
+ LONGEST off;
+ const gdb_byte *cfa_start, *cfa_end;
+
+ if (dwarf2_fetch_cfa_info (arch, expr->scope, per_cu,
+ ®num, &off,
+ &text_offset, &cfa_start, &cfa_end))
+ {
+ /* Register. */
+ ax_reg (expr, regnum);
+ if (off != 0)
+ {
+ ax_const_l (expr, off);
+ ax_simple (expr, aop_add);
+ }
+ }
+ else
+ {
+ /* Another expression. */
+ ax_const_l (expr, text_offset);
+ dwarf2_compile_expr_to_ax (expr, loc, arch, addr_size,
+ cfa_start, cfa_end, per_cu);
+ }
+
+ loc->kind = axs_lvalue_memory;
+ }
break;
case DW_OP_GNU_push_tls_address: