On 10/08/17 12:08, Pedro Alves wrote:
> On 08/09/2017 01:17 PM, Jiong Wang wrote:
>> +
>> + /* Only DW_CFA_GNU_window_save is expected on AArch64. */
>> + if (op != DW_CFA_GNU_window_save)
>> + return false;
>> +
> Was there any progress in giving this an Aarch64-specific name
> to avoid confusion? FYI, I was confused by this again for a couple
> minutes when I read it, until I remembered the previous discussions.
Hi Pedro,
Yes, We can add DW_CFA_AARCH64_negate_ra_state to dwarf2.def, with the same
number of DW_CFA_GNU_window_save, then need to introduce a new DW_CFA_DUP
to avoid duplicated case value trouble when auto-generate switch/case for
returning CFA name. Will post patch to GCC then can be synced to binutils-gdb
onced approved.
>
>> +/* Implement the execute_dwarf_cfa_vendor_op method. */
>> +
>> +static bool
>> +aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
>> + struct dwarf2_frame_state *fs)
>> +{
>> + struct dwarf2_frame_state_reg *ra_state_column;
>> + static unsigned char exp_0 = 0x30; /* DW_OP_lit0. */
>> + static unsigned char exp_1 = 0x31; /* DW_OP_lit1. */
> Can these be static const? (likewise elsewhere in the patch.)
>
> Also, gdb_byte.
Will fix in the next update.
Thanks.
Regards,
Jiong
@@ -35,6 +35,7 @@
#include "frame-base.h"
#include "trad-frame.h"
#include "objfiles.h"
+#include "dwarf2.h"
#include "dwarf2-frame.h"
#include "gdbtypes.h"
#include "prologue-value.h"
@@ -1046,12 +1047,30 @@ static struct value *
aarch64_dwarf2_prev_register (struct frame_info *this_frame,
void **this_cache, int regnum)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
CORE_ADDR lr;
switch (regnum)
{
case AARCH64_PC_REGNUM:
lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
+ /* Also fetch return address signing status, mask off the signature bits
+ if it's signed. */
+ if (aarch64_tdep_has_pauth_p (gdbarch_tdep (gdbarch)))
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int ra_state_column
+ = tdep->regnum.pauth_ra_state_regnum + gdbarch_num_regs (gdbarch);
+ CORE_ADDR ra_state = frame_unwind_register_unsigned (this_frame,
+ ra_state_column);
+ if (ra_state)
+ {
+ int cmask_num = tdep->regnum.pauth_reg_base + 1;
+ CORE_ADDR cmask
+ = frame_unwind_register_unsigned (this_frame, cmask_num);
+ lr = lr & ~cmask;
+ }
+ }
return frame_unwind_got_constant (this_frame, regnum, lr);
default:
@@ -1067,6 +1086,33 @@ aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
struct dwarf2_frame_state_reg *reg,
struct frame_info *this_frame)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Init pauth registers. */
+ if (aarch64_tdep_has_pauth_p (tdep))
+ {
+ int ra_state_num
+ = tdep->regnum.pauth_ra_state_regnum + gdbarch_num_regs (gdbarch);
+ int dmask_num = tdep->regnum.pauth_reg_base;
+ int cmask_num = tdep->regnum.pauth_reg_base + 1;
+
+ if (regnum == ra_state_num)
+ {
+ /* Initialize RA_STATE column to zero. */
+ static unsigned char exp_0 = 0x30; /* DW_OP_lit0. */
+
+ reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
+ reg->loc.exp = &exp_0;
+ reg->exp_len = 1;
+ return;
+ }
+ else if (regnum == cmask_num || regnum == dmask_num)
+ {
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+ return;
+ }
+ }
+
switch (regnum)
{
case AARCH64_PC_REGNUM:
@@ -1079,6 +1125,40 @@ aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
}
}
+/* Implement the execute_dwarf_cfa_vendor_op method. */
+
+static bool
+aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
+ struct dwarf2_frame_state *fs)
+{
+ struct dwarf2_frame_state_reg *ra_state_column;
+ static unsigned char exp_0 = 0x30; /* DW_OP_lit0. */
+ static unsigned char exp_1 = 0x31; /* DW_OP_lit1. */
+
+ /* Only DW_CFA_GNU_window_save is expected on AArch64. */
+ if (op != DW_CFA_GNU_window_save)
+ return false;
+
+
+ /* Allocate RA_STATE column if it's not allocated yet. */
+ dwarf2_frame_state_alloc_regs (&fs->regs, AARCH64_DWARF_PAUTH_RA_STATE + 1);
+
+ /* Toggle the status of RA_STATE column between 0 and 1. This column is
+ therefore using value expression rule as currently it's the only rule to
+ represent constant. */
+ ra_state_column = &(fs->regs.reg[AARCH64_DWARF_PAUTH_RA_STATE]);
+ ra_state_column->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
+
+ if (ra_state_column->loc.exp == NULL || ra_state_column->loc.exp == &exp_0)
+ ra_state_column->loc.exp = &exp_1;
+ else
+ ra_state_column->loc.exp = &exp_0;
+
+ ra_state_column->exp_len = 1;
+
+ return true;
+}
+
/* When arguments must be pushed onto the stack, they go on in reverse
order. The code below implements a FILO (stack) to do this. */
@@ -1777,6 +1857,8 @@ aarch64_vnb_type (struct gdbarch *gdbarch)
static int
aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
if (reg >= AARCH64_DWARF_X0 && reg <= AARCH64_DWARF_X0 + 30)
return AARCH64_X0_REGNUM + reg - AARCH64_DWARF_X0;
@@ -1786,6 +1868,16 @@ aarch64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
if (reg >= AARCH64_DWARF_V0 && reg <= AARCH64_DWARF_V0 + 31)
return AARCH64_V0_REGNUM + reg - AARCH64_DWARF_V0;
+ if (aarch64_tdep_has_pauth_p (tdep))
+ {
+ if (reg >= AARCH64_DWARF_PAUTH_DMASK && reg <= AARCH64_DWARF_PAUTH_CMASK)
+ return tdep->regnum.pauth_reg_base + reg - AARCH64_DWARF_PAUTH_DMASK;
+
+ if (reg == AARCH64_DWARF_PAUTH_RA_STATE)
+ /* AARCH64_PAUTH_RA_STATE_REGNUM is a pseudo register. */
+ return tdep->regnum.pauth_ra_state_regnum + gdbarch_num_regs (gdbarch);
+ }
+
return -1;
}
@@ -2120,6 +2212,8 @@ aarch64_gen_return_address (struct gdbarch *gdbarch,
static const char *
aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
static const char *const q_name[] =
{
"q0", "q1", "q2", "q3",
@@ -2197,6 +2291,21 @@ aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
return b_name[regnum - AARCH64_B0_REGNUM];
+ if (aarch64_tdep_has_pauth_p (tdep))
+ {
+ /* RA_STATE is the first pseudo register for pointer authentication
+ feature. */
+ int ra_state = tdep->regnum.pauth_ra_state_regnum;
+
+ /* RA_STATE is a pseudo register whose value will be initialized and
+ referenced only during frame unwinding. GDB should not read its
+ value from low level methods. In some functions, GDB will read a
+ register if it has a name. For example, mi_cmd_trace_frame_collected.
+ Therefore, we make RA_STATE anonymous to avoid such reading. */
+ if (regnum == ra_state)
+ return "";
+ }
+
internal_error (__FILE__, __LINE__,
_("aarch64_pseudo_register_name: bad register number %d"),
regnum);
@@ -2207,6 +2316,8 @@ aarch64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
static struct type *
aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
regnum -= gdbarch_num_regs (gdbarch);
if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
@@ -2224,6 +2335,10 @@ aarch64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
return aarch64_vnb_type (gdbarch);
+ if (aarch64_tdep_has_pauth_p (tdep)
+ && regnum == tdep->regnum.pauth_ra_state_regnum)
+ return builtin_type (gdbarch)->builtin_uint64;
+
internal_error (__FILE__, __LINE__,
_("aarch64_pseudo_register_type: bad register number %d"),
regnum);
@@ -2235,6 +2350,8 @@ static int
aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
regnum -= gdbarch_num_regs (gdbarch);
if (regnum >= AARCH64_Q0_REGNUM && regnum < AARCH64_Q0_REGNUM + 32)
@@ -2249,6 +2366,11 @@ aarch64_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
return group == all_reggroup || group == vector_reggroup;
else if (regnum >= AARCH64_B0_REGNUM && regnum < AARCH64_B0_REGNUM + 32)
return group == all_reggroup || group == vector_reggroup;
+ /* Don't assign RA_STATE to any group. This pseudo register is supposed to be
+ used during unwinding only. Don't display it for "info register". */
+ if (aarch64_tdep_has_pauth_p (tdep)
+ && regnum == tdep->regnum.pauth_ra_state_regnum)
+ return 0;
return group == all_reggroup;
}
@@ -2891,6 +3013,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
int num_pseudo_regs = 0;
struct aarch64_optional_regnum *regnum;
int first_pauth_regnum = -1;
+ int pauth_ra_state_regnum = -1;
/* Ensure we always have a target descriptor. */
if (!tdesc_has_registers (tdesc))
@@ -2939,6 +3062,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
if (feature_pauth)
{
first_pauth_regnum = num_regs;
+ pauth_ra_state_regnum = num_pseudo_regs;
/* Validate the descriptor provides the mandatory PAUTH registers
and allocate their numbers. */
for (i = 0; i < ARRAY_SIZE (aarch64_pauth_register_names); i++)
@@ -2948,6 +3072,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
aarch64_pauth_register_names[i]);
num_regs += i;
+ num_pseudo_regs += 1; /* Count RA_STATE pseudo register. */
}
if (!valid_p)
@@ -2988,6 +3113,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->jb_pc = -1; /* Longjump support not enabled by default. */
tdep->jb_elt_size = 8;
tdep->regnum.pauth_reg_base = first_pauth_regnum;
+ tdep->regnum.pauth_ra_state_regnum = pauth_ra_state_regnum;
set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, aarch64_frame_align);
@@ -3059,6 +3185,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
gdbarch_init_osabi (info, gdbarch);
dwarf2_frame_set_init_reg (gdbarch, aarch64_dwarf2_frame_init_reg);
+ /* Register DWARF CFA vendor handler. */
+ set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch,
+ aarch64_execute_dwarf_cfa_vendor_op);
/* Add some default predicates. */
frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);
@@ -29,6 +29,9 @@ struct regset;
/* AArch64 Dwarf register numbering. */
#define AARCH64_DWARF_X0 0
#define AARCH64_DWARF_SP 31
+#define AARCH64_DWARF_PAUTH_RA_STATE 34
+#define AARCH64_DWARF_PAUTH_DMASK 35
+#define AARCH64_DWARF_PAUTH_CMASK 36
#define AARCH64_DWARF_V0 64
/* Register numbers of various important registers. */
@@ -80,6 +83,8 @@ struct aarch64_optional_regnum
{
/* First pauth register number. */
int pauth_reg_base;
+ /* pauth ra_state register number. */
+ int pauth_ra_state_regnum;
};
/* Target-dependent structure in gdbarch. */