#include "user-regs.h"
#include "language.h"
#include "infcall.h"
+#include "ax.h"
+#include "ax-gdb.h"
#include "aarch64-tdep.h"
/* AArch64 prologue cache structure. */
struct aarch64_prologue_cache
{
+ /* The program counter at the start of the function. It is used to
+ identify this frame as a prologue frame. */
+ CORE_ADDR func;
+
+ /* The program counter at the time this frame was created; i.e. where
+ this function was called from. It is used to identify this frame as a
+ stub frame. */
+ CORE_ADDR prev_pc;
+
/* The stack pointer at the time this frame was created; i.e. the
caller's stack pointer when this function was called. It is used
to identify this frame. */
CORE_ADDR prev_sp;
+ /* Is the target available to read from? */
+ int available_p;
+
/* The frame base for this frame is just prev_sp - frame size.
FRAMESIZE is the distance from the frame pointer to the
initial stack pointer. */
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
- LINK receives the 'link' bit from the decoded instruction.
+ IS_BL receives the 'op' bit from the decoded instruction.
OFFSET receives the immediate offset from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
-decode_b (CORE_ADDR addr, uint32_t insn, unsigned *link, int32_t *offset)
+decode_b (CORE_ADDR addr, uint32_t insn, int *is_bl, int32_t *offset)
{
/* b 0001 01ii iiii iiii iiii iiii iiii iiii */
/* bl 1001 01ii iiii iiii iiii iiii iiii iiii */
if (decode_masked_match (insn, 0x7c000000, 0x14000000))
{
- *link = insn >> 31;
+ *is_bl = (insn >> 31) & 0x1;
*offset = extract_signed_bitfield (insn, 26, 0) << 2;
if (aarch64_debug)
fprintf_unfiltered (gdb_stdlog,
"decode: 0x%s 0x%x %s 0x%s\n",
core_addr_to_string_nz (addr), insn,
- *link ? "bl" : "b",
+ *is_bl ? "bl" : "b",
core_addr_to_string_nz (addr + *offset));
return 1;
static int
decode_bcond (CORE_ADDR addr, uint32_t insn, unsigned *cond, int32_t *offset)
{
- if (decode_masked_match (insn, 0xfe000000, 0x54000000))
+ /* b.cond 0101 0100 iiii iiii iiii iiii iii0 cccc */
+ if (decode_masked_match (insn, 0xff000010, 0x54000000))
{
*cond = (insn >> 0) & 0xf;
*offset = extract_signed_bitfield (insn, 19, 5) << 2;
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
- LINK receives the 'link' bit from the decoded instruction.
+ IS_BLR receives the 'op' bit from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
-decode_br (CORE_ADDR addr, uint32_t insn, unsigned *link, unsigned *rn)
+decode_br (CORE_ADDR addr, uint32_t insn, int *is_blr, unsigned *rn)
{
/* 8 4 0 6 2 8 4 0 */
/* blr 110101100011111100000000000rrrrr */
/* br 110101100001111100000000000rrrrr */
if (decode_masked_match (insn, 0xffdffc1f, 0xd61f0000))
{
- *link = (insn >> 21) & 1;
+ *is_blr = (insn >> 21) & 1;
*rn = (insn >> 5) & 0x1f;
if (aarch64_debug)
fprintf_unfiltered (gdb_stdlog,
"decode: 0x%s 0x%x %s 0x%x\n",
core_addr_to_string_nz (addr), insn,
- *link ? "blr" : "br", *rn);
+ *is_blr ? "blr" : "br", *rn);
return 1;
}
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
IS64 receives the 'sf' field from the decoded instruction.
- OP receives the 'op' field from the decoded instruction.
+ IS_CBNZ receives the 'op' field from the decoded instruction.
RN receives the 'rn' field from the decoded instruction.
OFFSET receives the 'imm19' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
-decode_cb (CORE_ADDR addr,
- uint32_t insn, int *is64, unsigned *op, unsigned *rn,
- int32_t *offset)
+decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, int *is_cbnz,
+ unsigned *rn, int32_t *offset)
{
+ /* cbz T011 010o iiii iiii iiii iiii iiir rrrr */
+ /* cbnz T011 010o iiii iiii iiii iiii iiir rrrr */
if (decode_masked_match (insn, 0x7e000000, 0x34000000))
{
- /* cbz T011 010o iiii iiii iiii iiii iiir rrrr */
- /* cbnz T011 010o iiii iiii iiii iiii iiir rrrr */
-
*rn = (insn >> 0) & 0x1f;
*is64 = (insn >> 31) & 0x1;
- *op = (insn >> 24) & 0x1;
+ *is_cbnz = (insn >> 24) & 0x1;
*offset = extract_signed_bitfield (insn, 19, 5) << 2;
if (aarch64_debug)
fprintf_unfiltered (gdb_stdlog,
"decode: 0x%s 0x%x %s 0x%s\n",
core_addr_to_string_nz (addr), insn,
- *op ? "cbnz" : "cbz",
+ *is_cbnz ? "cbnz" : "cbz",
core_addr_to_string_nz (addr + *offset));
return 1;
}
return 0;
}
-/* Decode an opcode if it represents a TB or TBNZ instruction.
+/* Decode an opcode if it represents a TBZ or TBNZ instruction.
ADDR specifies the address of the opcode.
INSN specifies the opcode to test.
- OP receives the 'op' field from the decoded instruction.
+ IS_TBNZ receives the 'op' field from the decoded instruction.
BIT receives the bit position field from the decoded instruction.
RT receives 'rt' field from the decoded instruction.
IMM receives 'imm' field from the decoded instruction.
Return 1 if the opcodes matches and is decoded, otherwise 0. */
static int
-decode_tb (CORE_ADDR addr,
- uint32_t insn, unsigned *op, unsigned *bit, unsigned *rt,
- int32_t *imm)
+decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz, unsigned *bit,
+ unsigned *rt, int32_t *imm)
{
+ /* tbz b011 0110 bbbb biii iiii iiii iiir rrrr */
+ /* tbnz B011 0111 bbbb biii iiii iiii iiir rrrr */
if (decode_masked_match (insn, 0x7e000000, 0x36000000))
{
- /* tbz b011 0110 bbbb biii iiii iiii iiir rrrr */
- /* tbnz B011 0111 bbbb biii iiii iiii iiir rrrr */
-
*rt = (insn >> 0) & 0x1f;
- *op = insn & (1 << 24);
+ *is_tbnz = (insn >> 24) & 0x1;
*bit = ((insn >> (31 - 4)) & 0x20) | ((insn >> 19) & 0x1f);
*imm = extract_signed_bitfield (insn, 14, 5) << 2;
fprintf_unfiltered (gdb_stdlog,
"decode: 0x%s 0x%x %s x%u, #%u, 0x%s\n",
core_addr_to_string_nz (addr), insn,
- *op ? "tbnz" : "tbz", *rt, *bit,
+ *is_tbnz ? "tbnz" : "tbz", *rt, *bit,
core_addr_to_string_nz (addr + *imm));
return 1;
}
int32_t imm;
unsigned cond;
int is64;
- unsigned is_link;
- unsigned op;
+ int is_link;
+ int is_cbnz;
+ int is_tbnz;
unsigned bit;
int32_t offset;
/* Stop analysis on branch. */
break;
}
- else if (decode_cb (start, insn, &is64, &op, &rn, &offset))
+ else if (decode_cb (start, insn, &is64, &is_cbnz, &rn, &offset))
{
/* Stop analysis on branch. */
break;
regs[rt2]);
regs[rn] = pv_add_constant (regs[rn], imm);
}
- else if (decode_tb (start, insn, &op, &bit, &rn, &offset))
+ else if (decode_tb (start, insn, &is_tbnz, &bit, &rn, &offset))
{
/* Stop analysis on branch. */
break;
CORE_ADDR prev_pc = get_frame_pc (this_frame);
struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ cache->prev_pc = prev_pc;
+
/* Assume we do not find a frame. */
cache->framereg = -1;
cache->framesize = 0;
}
}
+/* Fill in *CACHE with information about the prologue of *THIS_FRAME. This
+ function may throw an exception if the inferior's registers or memory is
+ not available. */
+
+static void
+aarch64_make_prologue_cache_1 (struct frame_info *this_frame,
+ struct aarch64_prologue_cache *cache)
+{
+ CORE_ADDR unwound_fp;
+ int reg;
+
+ aarch64_scan_prologue (this_frame, cache);
+
+ if (cache->framereg == -1)
+ return;
+
+ unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg);
+ if (unwound_fp == 0)
+ return;
+
+ cache->prev_sp = unwound_fp + cache->framesize;
+
+ /* Calculate actual addresses of saved registers using offsets
+ determined by aarch64_analyze_prologue. */
+ for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
+ if (trad_frame_addr_p (cache->saved_regs, reg))
+ cache->saved_regs[reg].addr += cache->prev_sp;
+
+ cache->func = get_frame_func (this_frame);
+
+ cache->available_p = 1;
+}
+
/* Allocate and fill in *THIS_CACHE with information about the prologue of
*THIS_FRAME. Do not do this is if *THIS_CACHE was already allocated.
Return a pointer to the current aarch64_prologue_cache in
aarch64_make_prologue_cache (struct frame_info *this_frame, void **this_cache)
{
struct aarch64_prologue_cache *cache;
- CORE_ADDR unwound_fp;
- int reg;
if (*this_cache != NULL)
return *this_cache;
cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
*this_cache = cache;
- aarch64_scan_prologue (this_frame, cache);
+ TRY
+ {
+ aarch64_make_prologue_cache_1 (this_frame, cache);
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
+ }
+ END_CATCH
- if (cache->framereg == -1)
- return cache;
+ return cache;
+}
- unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg);
- if (unwound_fp == 0)
- return cache;
+/* Implement the "stop_reason" frame_unwind method. */
- cache->prev_sp = unwound_fp + cache->framesize;
+static enum unwind_stop_reason
+aarch64_prologue_frame_unwind_stop_reason (struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct aarch64_prologue_cache *cache
+ = aarch64_make_prologue_cache (this_frame, this_cache);
- /* Calculate actual addresses of saved registers using offsets
- determined by aarch64_analyze_prologue. */
- for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++)
- if (trad_frame_addr_p (cache->saved_regs, reg))
- cache->saved_regs[reg].addr += cache->prev_sp;
+ if (!cache->available_p)
+ return UNWIND_UNAVAILABLE;
- return cache;
+ /* Halt the backtrace at "_start". */
+ if (cache->prev_pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
+ return UNWIND_OUTERMOST;
+
+ /* We've hit a wall, stop. */
+ if (cache->prev_sp == 0)
+ return UNWIND_OUTERMOST;
+
+ return UNWIND_NO_REASON;
}
/* Our frame ID for a normal frame is the current function's starting
{
struct aarch64_prologue_cache *cache
= aarch64_make_prologue_cache (this_frame, this_cache);
- struct frame_id id;
- CORE_ADDR pc, func;
- /* This is meant to halt the backtrace at "_start". */
- pc = get_frame_pc (this_frame);
- if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc)
- return;
-
- /* If we've hit a wall, stop. */
- if (cache->prev_sp == 0)
- return;
-
- func = get_frame_func (this_frame);
- id = frame_id_build (cache->prev_sp, func);
- *this_id = id;
+ if (!cache->available_p)
+ *this_id = frame_id_build_unavailable_stack (cache->func);
+ else
+ *this_id = frame_id_build (cache->prev_sp, cache->func);
}
/* Implement the "prev_register" frame_unwind method. */
struct frame_unwind aarch64_prologue_unwind =
{
NORMAL_FRAME,
- default_frame_unwind_stop_reason,
+ aarch64_prologue_frame_unwind_stop_reason,
aarch64_prologue_this_id,
aarch64_prologue_prev_register,
NULL,
cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
*this_cache = cache;
- cache->prev_sp
- = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
+ TRY
+ {
+ cache->prev_sp = get_frame_register_unsigned (this_frame,
+ AARCH64_SP_REGNUM);
+ cache->prev_pc = get_frame_pc (this_frame);
+ cache->available_p = 1;
+ }
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
+ }
+ END_CATCH
return cache;
}
+/* Implement the "stop_reason" frame_unwind method. */
+
+static enum unwind_stop_reason
+aarch64_stub_frame_unwind_stop_reason (struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct aarch64_prologue_cache *cache
+ = aarch64_make_stub_cache (this_frame, this_cache);
+
+ if (!cache->available_p)
+ return UNWIND_UNAVAILABLE;
+
+ return UNWIND_NO_REASON;
+}
+
/* Our frame ID for a stub frame is the current SP and LR. */
static void
struct aarch64_prologue_cache *cache
= aarch64_make_stub_cache (this_frame, this_cache);
- *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame));
+ if (cache->available_p)
+ *this_id = frame_id_build (cache->prev_sp, cache->prev_pc);
+ else
+ *this_id = frame_id_build_unavailable_stack (cache->prev_pc);
}
/* Implement the "sniffer" frame_unwind method. */
struct frame_unwind aarch64_stub_unwind =
{
NORMAL_FRAME,
- default_frame_unwind_stop_reason,
+ aarch64_stub_frame_unwind_stop_reason,
aarch64_stub_this_id,
aarch64_prologue_prev_register,
NULL,
int nRc;
enum type_code code;
- CHECK_TYPEDEF (type);
+ type = check_typedef (type);
/* In the AArch64 ABI, "integer" like aggregate types are returned
in registers. For an aggregate type to be integer like, its size
*pc = extract_unsigned_integer (buf, X_REGISTER_SIZE, byte_order);
return 1;
}
+
+/* Implement the "gen_return_address" gdbarch method. */
+
+static void
+aarch64_gen_return_address (struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value,
+ CORE_ADDR scope)
+{
+ value->type = register_type (gdbarch, AARCH64_LR_REGNUM);
+ value->kind = axs_lvalue_register;
+ value->u.reg = AARCH64_LR_REGNUM;
+}
\f
/* Return the pseudo register name corresponding to register regnum. */
v_regnum = AARCH64_V0_REGNUM + regnum - AARCH64_S0_REGNUM;
status = regcache_raw_read (regcache, v_regnum, reg_buf);
- memcpy (buf, reg_buf, S_REGISTER_SIZE);
+ if (status != REG_VALID)
+ mark_value_bytes_unavailable (result_value, 0,
+ TYPE_LENGTH (value_type (result_value)));
+ else
+ memcpy (buf, reg_buf, S_REGISTER_SIZE);
return result_value;
}
return best_arch->gdbarch;
}
- tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
/* This should be low enough for everything. */
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, aarch64_get_longjmp_target);
+ set_gdbarch_gen_return_address (gdbarch, aarch64_gen_return_address);
+
tdesc_use_registers (gdbarch, tdesc, tdesc_data);
/* Add standard register aliases. */