Skip to content

Commit 11e1b75

Browse files
committed
AArch64: DWARF unwinder support for signed return addresses
Pauth address signing is enabled at binary compile time. When enabled the return addresses for functions may be mangled. This patch adds functionality to restore the original address for use in the DWARF unwinder. DW_CFA_AARCH64_negate_ra_state in a binary indicates the toggling of address signing between enabled and disabled. Ensure the state is stored in the DWARF register ra_state. Ensure the pauth DWARF registers are initialised. gdb/ChangeLog: * aarch64-tdep.c (aarch64_frame_unmask_address): New function. (aarch64_dwarf2_prev_register): Unmask PC value. (aarch64_dwarf2_frame_init_reg): Init pauth registers. (aarch64_execute_dwarf_cfa_vendor_op): Check for DW_CFA_AARCH64_negate_ra_state. (aarch64_gdbarch_init): Add aarch64_execute_dwarf_cfa_vendor_op.
1 parent 34dcc7c commit 11e1b75

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

gdb/ChangeLog

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2019-03-22 Alan Hayward <alan.hayward@arm.com>
2+
Jiong Wang <jiong.wang@arm.com>
3+
4+
* aarch64-tdep.c (aarch64_frame_unmask_address): New function.
5+
(aarch64_dwarf2_prev_register): Unmask PC value.
6+
(aarch64_dwarf2_frame_init_reg): Init pauth registers.
7+
(aarch64_execute_dwarf_cfa_vendor_op): Check for
8+
DW_CFA_AARCH64_negate_ra_state.
9+
(aarch64_gdbarch_init): Add aarch64_execute_dwarf_cfa_vendor_op.
10+
111
2019-03-22 Alan Hayward <alan.hayward@arm.com>
212
Jiong Wang <jiong.wang@arm.com>
313

gdb/aarch64-tdep.c

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "frame-base.h"
3535
#include "trad-frame.h"
3636
#include "objfiles.h"
37+
#include "dwarf2.h"
3738
#include "dwarf2-frame.h"
3839
#include "gdbtypes.h"
3940
#include "prologue-value.h"
@@ -248,6 +249,26 @@ class instruction_reader : public abstract_instruction_reader
248249

249250
} // namespace
250251

252+
/* If address signing is enabled, mask off the signature bits from ADDR, using
253+
the register values in THIS_FRAME. */
254+
255+
static CORE_ADDR
256+
aarch64_frame_unmask_address (struct gdbarch_tdep *tdep,
257+
struct frame_info *this_frame,
258+
CORE_ADDR addr)
259+
{
260+
if (tdep->has_pauth ()
261+
&& frame_unwind_register_unsigned (this_frame,
262+
tdep->pauth_ra_state_regnum))
263+
{
264+
int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base);
265+
CORE_ADDR cmask = frame_unwind_register_unsigned (this_frame, cmask_num);
266+
addr = addr & ~cmask;
267+
}
268+
269+
return addr;
270+
}
271+
251272
/* Analyze a prologue, looking for a recognizable stack frame
252273
and frame pointer. Scan until we encounter a store that could
253274
clobber the stack frame unexpectedly, or an unknown instruction. */
@@ -1013,12 +1034,14 @@ static struct value *
10131034
aarch64_dwarf2_prev_register (struct frame_info *this_frame,
10141035
void **this_cache, int regnum)
10151036
{
1037+
struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
10161038
CORE_ADDR lr;
10171039

10181040
switch (regnum)
10191041
{
10201042
case AARCH64_PC_REGNUM:
10211043
lr = frame_unwind_register_unsigned (this_frame, AARCH64_LR_REGNUM);
1044+
lr = aarch64_frame_unmask_address (tdep, this_frame, lr);
10221045
return frame_unwind_got_constant (this_frame, regnum, lr);
10231046

10241047
default:
@@ -1027,25 +1050,82 @@ aarch64_dwarf2_prev_register (struct frame_info *this_frame,
10271050
}
10281051
}
10291052

1053+
static const unsigned char op_lit0 = DW_OP_lit0;
1054+
static const unsigned char op_lit1 = DW_OP_lit1;
1055+
10301056
/* Implement the "init_reg" dwarf2_frame_ops method. */
10311057

10321058
static void
10331059
aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
10341060
struct dwarf2_frame_state_reg *reg,
10351061
struct frame_info *this_frame)
10361062
{
1063+
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1064+
10371065
switch (regnum)
10381066
{
10391067
case AARCH64_PC_REGNUM:
10401068
reg->how = DWARF2_FRAME_REG_FN;
10411069
reg->loc.fn = aarch64_dwarf2_prev_register;
1042-
break;
1070+
return;
1071+
10431072
case AARCH64_SP_REGNUM:
10441073
reg->how = DWARF2_FRAME_REG_CFA;
1045-
break;
1074+
return;
1075+
}
1076+
1077+
/* Init pauth registers. */
1078+
if (tdep->has_pauth ())
1079+
{
1080+
if (regnum == tdep->pauth_ra_state_regnum)
1081+
{
1082+
/* Initialize RA_STATE to zero. */
1083+
reg->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
1084+
reg->loc.exp.start = &op_lit0;
1085+
reg->loc.exp.len = 1;
1086+
return;
1087+
}
1088+
else if (regnum == AARCH64_PAUTH_DMASK_REGNUM (tdep->pauth_reg_base)
1089+
|| regnum == AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base))
1090+
{
1091+
reg->how = DWARF2_FRAME_REG_SAME_VALUE;
1092+
return;
1093+
}
10461094
}
10471095
}
10481096

1097+
/* Implement the execute_dwarf_cfa_vendor_op method. */
1098+
1099+
static bool
1100+
aarch64_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
1101+
struct dwarf2_frame_state *fs)
1102+
{
1103+
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1104+
struct dwarf2_frame_state_reg *ra_state;
1105+
1106+
if (tdep->has_pauth () && op == DW_CFA_AARCH64_negate_ra_state)
1107+
{
1108+
/* Allocate RA_STATE column if it's not allocated yet. */
1109+
fs->regs.alloc_regs (AARCH64_DWARF_PAUTH_RA_STATE + 1);
1110+
1111+
/* Toggle the status of RA_STATE between 0 and 1. */
1112+
ra_state = &(fs->regs.reg[AARCH64_DWARF_PAUTH_RA_STATE]);
1113+
ra_state->how = DWARF2_FRAME_REG_SAVED_VAL_EXP;
1114+
1115+
if (ra_state->loc.exp.start == nullptr
1116+
|| ra_state->loc.exp.start == &op_lit0)
1117+
ra_state->loc.exp.start = &op_lit1;
1118+
else
1119+
ra_state->loc.exp.start = &op_lit0;
1120+
1121+
ra_state->loc.exp.len = 1;
1122+
1123+
return true;
1124+
}
1125+
1126+
return false;
1127+
}
1128+
10491129
/* When arguments must be pushed onto the stack, they go on in reverse
10501130
order. The code below implements a FILO (stack) to do this. */
10511131

@@ -3192,6 +3272,9 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
31923272
gdbarch_init_osabi (info, gdbarch);
31933273

31943274
dwarf2_frame_set_init_reg (gdbarch, aarch64_dwarf2_frame_init_reg);
3275+
/* Register DWARF CFA vendor handler. */
3276+
set_gdbarch_execute_dwarf_cfa_vendor_op (gdbarch,
3277+
aarch64_execute_dwarf_cfa_vendor_op);
31953278

31963279
/* Add some default predicates. */
31973280
frame_unwind_append_unwinder (gdbarch, &aarch64_stub_unwind);

0 commit comments

Comments
 (0)