/* Target-dependent code for the Xtensa port of GDB, the GNU debugger.
- Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "frame.h"
+#include "solib-svr4.h"
#include "symtab.h"
#include "symfile.h"
#include "objfiles.h"
#include "xtensa-isa.h"
#include "xtensa-tdep.h"
+#include "xtensa-config.h"
static int xtensa_debug_level = 0;
/* On Windowed ABI, we use a6 through a11 for passing arguments
to a function called by GDB because CALL4 is used. */
-#define ARGS_FIRST_REG A6_REGNUM
#define ARGS_NUM_REGS 6
#define REGISTER_SIZE 4
#define CALLINC(ps) (((ps) & PS_CALLINC_MASK) >> PS_CALLINC_SHIFT)
#define WINSIZE(ra) (4 * (( (ra) >> 30) & 0x3))
-
-/* Convert a live Ax register number to the corresponding Areg number. */
-#define AREG_NUMBER(r, wb) \
- ((((r) - A0_REGNUM + (((wb) & WB_MASK) << WB_SHIFT)) & AREGS_MASK) + AR_BASE)
-
/* ABI-independent macros. */
-#define ARG_NOF (CALL_ABI == CallAbiCall0Only ? C0_NARGS : (ARGS_NUM_REGS))
-#define ARG_1ST (CALL_ABI == CallAbiCall0Only \
- ? (A0_REGNUM) + C0_ARGS : (ARGS_FIRST_REG))
-
-extern struct gdbarch_tdep *xtensa_config_tdep (struct gdbarch_info *);
-extern int xtensa_config_byte_order (struct gdbarch_info *);
-
+#define ARG_NOF(gdbarch) \
+ (gdbarch_tdep (gdbarch)->call_abi \
+ == CallAbiCall0Only ? C0_NARGS : (ARGS_NUM_REGS))
+#define ARG_1ST(gdbarch) \
+ (gdbarch_tdep (gdbarch)->call_abi == CallAbiCall0Only \
+ ? (gdbarch_tdep (gdbarch)->a0_base + C0_ARGS) \
+ : (gdbarch_tdep (gdbarch)->a0_base + 6))
/* XTENSA_IS_ENTRY tests whether the first byte of an instruction
indicates that the instruction is an ENTRY instruction. */
-#define XTENSA_IS_ENTRY(op1) \
- ((gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) \
+#define XTENSA_IS_ENTRY(gdbarch, op1) \
+ ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) \
? ((op1) == 0x6c) : ((op1) == 0x36))
#define XTENSA_ENTRY_LENGTH 3
#define PS_WOE (1<<18)
#define PS_EXC (1<<4)
+/* Convert a live A-register number to the corresponding AR-register number. */
+static int
+arreg_number (struct gdbarch *gdbarch, int a_regnum, ULONGEST wb)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int arreg;
+
+ arreg = a_regnum - tdep->a0_base;
+ arreg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT;
+ arreg &= tdep->num_aregs - 1;
+
+ return arreg + tdep->ar_base;
+}
+
+/* Convert a live AR-register number to the corresponding A-register order
+ number in a range [0..15]. Return -1, if AR_REGNUM is out of WB window. */
+static int
+areg_number (struct gdbarch *gdbarch, int ar_regnum, unsigned int wb)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int areg;
+
+ areg = ar_regnum - tdep->ar_base;
+ if (areg < 0 || areg >= tdep->num_aregs)
+ return -1;
+ areg = (areg - wb * 4) & (tdep->num_aregs - 1);
+ return (areg > 15) ? -1 : areg;
+}
+
static inline int
windowing_enabled (CORE_ADDR ps)
{
method to call the inferior function. */
static int
-extract_call_winsize (CORE_ADDR pc)
+extract_call_winsize (struct gdbarch *gdbarch, CORE_ADDR pc)
{
int winsize = 4;
int insn;
call{0,4,8,12} 0101 || {00,01,10,11} || OFFSET
callx{0,4,8,12} 0000 || {00,01,10,11} || 11 || OFFSET. */
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
{
if (((insn & 0xf) == 0x5) || ((insn & 0xcf) == 0xc0))
winsize = (insn & 0x30) >> 2; /* 0, 4, 8, 12. */
/* Returns the name of a register. */
static const char *
-xtensa_register_name (int regnum)
+xtensa_register_name (struct gdbarch *gdbarch, int regnum)
{
/* Return the name stored in the register map. */
- if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch)
- + gdbarch_num_pseudo_regs (current_gdbarch))
- return REGMAP[regnum].name;
+ if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch))
+ return gdbarch_tdep (gdbarch)->regmap[regnum].name;
internal_error (__FILE__, __LINE__, _("invalid register %d"), regnum);
return 0;
xtensa_register_type (struct gdbarch *gdbarch, int regnum)
{
/* Return signed integer for ARx and Ax registers. */
- if ((regnum >= AR_BASE && regnum < AR_BASE + NUM_AREGS)
- || (regnum >= A0_BASE && regnum < A0_BASE + 16))
+ if ((regnum >= gdbarch_tdep (gdbarch)->ar_base
+ && regnum < gdbarch_tdep (gdbarch)->ar_base
+ + gdbarch_tdep (gdbarch)->num_aregs)
+ || (regnum >= gdbarch_tdep (gdbarch)->a0_base
+ && regnum < gdbarch_tdep (gdbarch)->a0_base + 16))
return builtin_type_int;
- if (regnum == gdbarch_pc_regnum (current_gdbarch) || regnum == A1_REGNUM)
+ if (regnum == gdbarch_pc_regnum (gdbarch)
+ || regnum == gdbarch_tdep (gdbarch)->a0_base + 1)
return lookup_pointer_type (builtin_type_void);
/* Return the stored type for all other registers. */
- else if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch)
- + gdbarch_num_pseudo_regs (current_gdbarch))
+ else if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch))
{
- xtensa_register_t* reg = ®MAP[regnum];
+ xtensa_register_t* reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
/* Set ctype for this register (only the first time). */
to n for An. So, we only have to add the base number for A0. */
static int
-xtensa_reg_to_regnum (int regnum)
+xtensa_reg_to_regnum (struct gdbarch *gdbarch, int regnum)
{
int i;
if (regnum >= 0 && regnum < 16)
- return A0_BASE + regnum;
+ return gdbarch_tdep (gdbarch)->a0_base + regnum;
for (i = 0;
- i < gdbarch_num_regs (current_gdbarch)
- + gdbarch_num_pseudo_regs (current_gdbarch);
+ i < gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
i++)
- if (regnum == REGMAP[i].target_number)
+ if (regnum == gdbarch_tdep (gdbarch)->regmap[i].target_number)
return i;
internal_error (__FILE__, __LINE__,
DEBUGTRACE ("xtensa_register_write_masked ()\n");
/* Copy the masked register to host byte-order. */
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (get_regcache_arch (regcache)) == BFD_ENDIAN_BIG)
for (i = 0; i < bytesize; i++)
{
mem >>= 8;
ptr = value;
mem = *ptr;
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (get_regcache_arch (regcache)) == BFD_ENDIAN_BIG)
for (i = 0; i < bytesize; i++)
{
if ((i & 3) == 0)
gdb_byte *buffer)
{
DEBUGTRACE ("xtensa_pseudo_register_read (... regnum = %d (%s) ...)\n",
- regnum, xtensa_register_name (regnum));
+ regnum, xtensa_register_name (gdbarch, regnum));
- if (regnum == FP_ALIAS)
- regnum = A1_REGNUM;
+ if (regnum == gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch) - 1)
+ regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
/* Read aliases a0..a15, if this is a Windowed ABI. */
- if (ISA_USE_WINDOWED_REGISTERS
- && (regnum >= A0_REGNUM) && (regnum <= A15_REGNUM))
+ if (gdbarch_tdep (gdbarch)->isa_use_windowed_registers
+ && (regnum >= gdbarch_tdep (gdbarch)->a0_base)
+ && (regnum <= gdbarch_tdep (gdbarch)->a0_base + 15))
{
gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
- regcache_raw_read (regcache, WB_REGNUM, buf);
- regnum = AREG_NUMBER (regnum, extract_unsigned_integer (buf, 4));
+ regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf);
+ regnum = arreg_number (gdbarch, regnum,
+ extract_unsigned_integer (buf, 4));
}
/* We can always read non-pseudo registers. */
- if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch))
+ if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch))
regcache_raw_read (regcache, regnum, buffer);
+
+ /* We have to find out how to deal with priveleged registers.
+ Let's treat them as pseudo-registers, but we cannot read/write them. */
+
+ else if (regnum < gdbarch_tdep (gdbarch)->a0_base)
+ {
+ buffer[0] = (gdb_byte)0;
+ buffer[1] = (gdb_byte)0;
+ buffer[2] = (gdb_byte)0;
+ buffer[3] = (gdb_byte)0;
+ }
/* Pseudo registers. */
else if (regnum >= 0
- && regnum < gdbarch_num_regs (current_gdbarch)
- + gdbarch_num_pseudo_regs (current_gdbarch))
+ && regnum < gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch))
{
- xtensa_register_t *reg = ®MAP[regnum];
+ xtensa_register_t *reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
xtensa_register_type_t type = reg->type;
- int flags = XTENSA_TARGET_FLAGS;
+ int flags = gdbarch_tdep (gdbarch)->target_flags;
/* We cannot read Unknown or Unmapped registers. */
if (type == xtRegisterTypeUnmapped || type == xtRegisterTypeUnknown)
if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
{
warning (_("cannot read register %s"),
- xtensa_register_name (regnum));
+ xtensa_register_name (gdbarch, regnum));
return;
}
}
const gdb_byte *buffer)
{
DEBUGTRACE ("xtensa_pseudo_register_write (... regnum = %d (%s) ...)\n",
- regnum, xtensa_register_name (regnum));
+ regnum, xtensa_register_name (gdbarch, regnum));
- if (regnum == FP_ALIAS)
- regnum = A1_REGNUM;
+ if (regnum == gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch) -1)
+ regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
/* Renumber register, if aliase a0..a15 on Windowed ABI. */
- if (ISA_USE_WINDOWED_REGISTERS
- && (regnum >= A0_REGNUM) && (regnum <= A15_REGNUM))
+ if (gdbarch_tdep (gdbarch)->isa_use_windowed_registers
+ && (regnum >= gdbarch_tdep (gdbarch)->a0_base)
+ && (regnum <= gdbarch_tdep (gdbarch)->a0_base + 15))
{
gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
unsigned int wb;
- regcache_raw_read (regcache, WB_REGNUM, buf);
- regnum = AREG_NUMBER (regnum, extract_unsigned_integer (buf, 4));
+ regcache_raw_read (regcache,
+ gdbarch_tdep (gdbarch)->wb_regnum, buf);
+ regnum = arreg_number (gdbarch, regnum,
+ extract_unsigned_integer (buf, 4));
}
/* We can always write 'core' registers.
Note: We might have converted Ax->ARy. */
- if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch))
+ if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch))
regcache_raw_write (regcache, regnum, buffer);
+ /* We have to find out how to deal with priveleged registers.
+ Let's treat them as pseudo-registers, but we cannot read/write them. */
+
+ else if (regnum < gdbarch_tdep (gdbarch)->a0_base)
+ {
+ return;
+ }
/* Pseudo registers. */
else if (regnum >= 0
- && regnum < gdbarch_num_regs (current_gdbarch)
- + gdbarch_num_pseudo_regs (current_gdbarch))
+ && regnum < gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch))
{
- xtensa_register_t *reg = ®MAP[regnum];
+ xtensa_register_t *reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
xtensa_register_type_t type = reg->type;
- int flags = XTENSA_TARGET_FLAGS;
+ int flags = gdbarch_tdep (gdbarch)->target_flags;
/* On most targets, we cannot write registers
of type "Unknown" or "Unmapped". */
if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
{
warning (_("cannot write register %s"),
- xtensa_register_name (regnum));
+ xtensa_register_name (gdbarch, regnum));
return;
}
}
int regnum,
struct reggroup *group)
{
- xtensa_register_t* reg = ®MAP[regnum];
+ xtensa_register_t* reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
xtensa_register_type_t type = reg->type;
xtensa_register_group_t rg = reg->group;
int cp_number;
if (group == vector_reggroup || group == xtensa_vectra_reggroup)
return rg & xtRegisterGroupVectra;
if (group == save_reggroup || group == restore_reggroup)
- return (regnum < gdbarch_num_regs (current_gdbarch)
+ return (regnum < gdbarch_num_regs (gdbarch)
&& (reg->flags & SAVE_REST_FLAGS) == SAVE_REST_VALID);
if ((cp_number = xtensa_coprocessor_register_group (group)) >= 0)
return rg & (xtRegisterGroupCP0 << cp_number);
size_t len)
{
const xtensa_elf_gregset_t *regs = gregs;
+ struct gdbarch *gdbarch = get_regcache_arch (rc);
int i;
DEBUGTRACE ("xtensa_supply_gregset (..., regnum==%d, ...) \n", regnum);
- if (regnum == gdbarch_pc_regnum (current_gdbarch) || regnum == -1)
- regcache_raw_supply (rc,
- gdbarch_pc_regnum (current_gdbarch),
- (char *) ®s->pc);
- if (regnum == gdbarch_ps_regnum (current_gdbarch) || regnum == -1)
- regcache_raw_supply (rc, gdbarch_ps_regnum (current_gdbarch),
- (char *) ®s->ps);
- if (regnum == WB_REGNUM || regnum == -1)
- regcache_raw_supply (rc, WB_REGNUM, (char *) ®s->windowbase);
- if (regnum == WS_REGNUM || regnum == -1)
- regcache_raw_supply (rc, WS_REGNUM, (char *) ®s->windowstart);
- if (regnum == LBEG_REGNUM || regnum == -1)
- regcache_raw_supply (rc, LBEG_REGNUM, (char *) ®s->lbeg);
- if (regnum == LEND_REGNUM || regnum == -1)
- regcache_raw_supply (rc, LEND_REGNUM, (char *) ®s->lend);
- if (regnum == LCOUNT_REGNUM || regnum == -1)
- regcache_raw_supply (rc, LCOUNT_REGNUM, (char *) ®s->lcount);
- if (regnum == SAR_REGNUM || regnum == -1)
- regcache_raw_supply (rc, SAR_REGNUM, (char *) ®s->sar);
- if (regnum == EXCCAUSE_REGNUM || regnum == -1)
- regcache_raw_supply (rc, EXCCAUSE_REGNUM, (char *) ®s->exccause);
- if (regnum == EXCVADDR_REGNUM || regnum == -1)
- regcache_raw_supply (rc, EXCVADDR_REGNUM, (char *) ®s->excvaddr);
- if (regnum >= AR_BASE && regnum < AR_BASE + NUM_AREGS)
- regcache_raw_supply (rc, regnum, (char *) ®s->ar[regnum - AR_BASE]);
+ if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_pc_regnum (gdbarch), (char *) ®s->pc);
+ if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_ps_regnum (gdbarch), (char *) ®s->ps);
+ if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->wb_regnum,
+ (char *) ®s->windowbase);
+ if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->ws_regnum,
+ (char *) ®s->windowstart);
+ if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->lbeg_regnum,
+ (char *) ®s->lbeg);
+ if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->lend_regnum,
+ (char *) ®s->lend);
+ if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->lcount_regnum,
+ (char *) ®s->lcount);
+ if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->sar_regnum,
+ (char *) ®s->sar);
+ if (regnum >=gdbarch_tdep (gdbarch)->ar_base
+ && regnum < gdbarch_tdep (gdbarch)->ar_base
+ + gdbarch_tdep (gdbarch)->num_aregs)
+ regcache_raw_supply (rc, regnum,
+ (char *) ®s->ar[regnum - gdbarch_tdep
+ (gdbarch)->ar_base]);
else if (regnum == -1)
{
- for (i = 0; i < NUM_AREGS; ++i)
- regcache_raw_supply (rc, AR_BASE + i, (char *) ®s->ar[i]);
+ for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i)
+ regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->ar_base + i,
+ (char *) ®s->ar[i]);
}
}
{
DEBUGTRACE ("xtensa_regset_from_core_section "
"(..., sect_name==\"%s\", sect_size==%x) \n",
- sect_name, sect_size);
+ sect_name, (unsigned int) sect_size);
if (strcmp (sect_name, ".reg") == 0
&& sect_size >= sizeof(xtensa_elf_gregset_t))
/* Frame cache part for Windowed ABI. */
typedef struct xtensa_windowed_frame_cache
{
- int wb; /* Base for this frame; -1 if not in regfile. */
- int callsize; /* Call size to next frame. */
- int ws;
+ int wb; /* WINDOWBASE of the previous frame. */
+ int callsize; /* Call size of this frame. */
+ int ws; /* WINDOWSTART of the previous frame. It keeps track of
+ life windows only. If there is no bit set for the
+ window, that means it had been already spilled
+ because of window overflow. */
+
+ /* Spilled A-registers from the previous frame.
+ AREGS[i] == -1, if corresponding AR is alive. */
CORE_ADDR aregs[XTENSA_NUM_SAVED_AREGS];
} xtensa_windowed_frame_cache_t;
typedef struct xtensa_frame_cache
{
- CORE_ADDR base; /* Stack pointer of the next frame. */
+ CORE_ADDR base; /* Stack pointer of this frame. */
CORE_ADDR pc; /* PC at the entry point to the function. */
- CORE_ADDR ra; /* The raw return address. */
- CORE_ADDR ps; /* The PS register of the frame. */
- CORE_ADDR prev_sp; /* Stack Pointer of the frame. */
+ CORE_ADDR ra; /* The raw return address (without CALLINC). */
+ CORE_ADDR ps; /* The PS register of the previous frame. */
+ CORE_ADDR prev_sp; /* Stack Pointer of the previous frame. */
int call0; /* It's a call0 framework (else windowed). */
union
{
else
{
cache->wd.wb = 0;
+ cache->wd.ws = 0;
cache->wd.callsize = -1;
for (i = 0; i < XTENSA_NUM_SAVED_AREGS; i++)
DEBUGTRACE ("xtensa_unwind_pc (next_frame = %p)\n", next_frame);
- frame_unwind_register (next_frame, gdbarch_pc_regnum (current_gdbarch), buf);
+ frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
DEBUGINFO ("[xtensa_unwind_pc] pc = 0x%08x\n", (unsigned int)
extract_typed_address (buf, builtin_type_void_func_ptr));
DEBUGTRACE ("xtensa_unwind_dummy_id ()\n");
pc = frame_pc_unwind (next_frame);
- fp = frame_unwind_register_unsigned (next_frame, A1_REGNUM);
+ fp = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
/* Make dummy frame ID unique by adding a constant. */
return frame_id_build (fp + SP_ALIGNMENT, pc);
}
+/* Returns the best guess about which register is a frame pointer
+ for the function containing CURRENT_PC. */
+
+#define XTENSA_ISA_BSZ 32 /* Instruction buffer size. */
+
+static unsigned int
+xtensa_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR current_pc)
+{
+#define RETURN_FP goto done
+
+ unsigned int fp_regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
+ CORE_ADDR start_addr;
+ xtensa_isa isa;
+ xtensa_insnbuf ins, slot;
+ char ibuf[XTENSA_ISA_BSZ];
+ CORE_ADDR ia, bt, ba;
+ xtensa_format ifmt;
+ int ilen, islots, is;
+ xtensa_opcode opc;
+ const char *opcname;
+
+ find_pc_partial_function (current_pc, NULL, &start_addr, NULL);
+ if (start_addr == 0)
+ return fp_regnum;
+
+ if (!xtensa_default_isa)
+ xtensa_default_isa = xtensa_isa_init (0, 0);
+ isa = xtensa_default_isa;
+ gdb_assert (XTENSA_ISA_BSZ >= xtensa_isa_maxlength (isa));
+ ins = xtensa_insnbuf_alloc (isa);
+ slot = xtensa_insnbuf_alloc (isa);
+ ba = 0;
+
+ for (ia = start_addr, bt = ia; ia < current_pc ; ia += ilen)
+ {
+ if (ia + xtensa_isa_maxlength (isa) > bt)
+ {
+ ba = ia;
+ bt = (ba + XTENSA_ISA_BSZ) < current_pc
+ ? ba + XTENSA_ISA_BSZ : current_pc;
+ read_memory (ba, ibuf, bt - ba);
+ }
+
+ xtensa_insnbuf_from_chars (isa, ins, &ibuf[ia-ba], 0);
+ ifmt = xtensa_format_decode (isa, ins);
+ if (ifmt == XTENSA_UNDEFINED)
+ RETURN_FP;
+ ilen = xtensa_format_length (isa, ifmt);
+ if (ilen == XTENSA_UNDEFINED)
+ RETURN_FP;
+ islots = xtensa_format_num_slots (isa, ifmt);
+ if (islots == XTENSA_UNDEFINED)
+ RETURN_FP;
+
+ for (is = 0; is < islots; ++is)
+ {
+ if (xtensa_format_get_slot (isa, ifmt, is, ins, slot))
+ RETURN_FP;
+
+ opc = xtensa_opcode_decode (isa, ifmt, is, slot);
+ if (opc == XTENSA_UNDEFINED)
+ RETURN_FP;
+
+ opcname = xtensa_opcode_name (isa, opc);
+
+ if (strcasecmp (opcname, "mov.n") == 0
+ || strcasecmp (opcname, "or") == 0)
+ {
+ unsigned int register_operand;
+
+ /* Possible candidate for setting frame pointer
+ from A1. This is what we are looking for. */
+
+ if (xtensa_operand_get_field (isa, opc, 1, ifmt,
+ is, slot, ®ister_operand) != 0)
+ RETURN_FP;
+ if (xtensa_operand_decode (isa, opc, 1, ®ister_operand) != 0)
+ RETURN_FP;
+ if (register_operand == 1) /* Mov{.n} FP A1. */
+ {
+ if (xtensa_operand_get_field (isa, opc, 0, ifmt, is, slot,
+ ®ister_operand) != 0)
+ RETURN_FP;
+ if (xtensa_operand_decode (isa, opc, 0,
+ ®ister_operand) != 0)
+ RETURN_FP;
+
+ fp_regnum = gdbarch_tdep (gdbarch)->a0_base + register_operand;
+ RETURN_FP;
+ }
+ }
+
+ if (
+ /* We have problems decoding the memory. */
+ opcname == NULL
+ || strcasecmp (opcname, "ill") == 0
+ || strcasecmp (opcname, "ill.n") == 0
+ /* Hit planted breakpoint. */
+ || strcasecmp (opcname, "break") == 0
+ || strcasecmp (opcname, "break.n") == 0
+ /* Flow control instructions finish prologue. */
+ || xtensa_opcode_is_branch (isa, opc) > 0
+ || xtensa_opcode_is_jump (isa, opc) > 0
+ || xtensa_opcode_is_loop (isa, opc) > 0
+ || xtensa_opcode_is_call (isa, opc) > 0
+ || strcasecmp (opcname, "simcall") == 0
+ || strcasecmp (opcname, "syscall") == 0)
+ /* Can not continue analysis. */
+ RETURN_FP;
+ }
+ }
+done:
+ xtensa_insnbuf_free(isa, slot);
+ xtensa_insnbuf_free(isa, ins);
+ return fp_regnum;
+}
+
/* The key values to identify the frame using "cache" are
- cache->base = SP of this frame;
+ cache->base = SP (or best guess about FP) of this frame;
cache->pc = entry-PC (entry point of the frame function);
cache->prev_sp = SP of the previous frame.
*/
{
xtensa_frame_cache_t *cache;
CORE_ADDR ra, wb, ws, pc, sp, ps;
- unsigned int ps_regnum = gdbarch_ps_regnum (current_gdbarch);
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ unsigned int ps_regnum = gdbarch_ps_regnum (gdbarch);
+ unsigned int fp_regnum;
char op1;
int windowed;
*this_cache = cache;
pc = frame_unwind_register_unsigned (next_frame,
- gdbarch_pc_regnum (current_gdbarch));
+ gdbarch_pc_regnum (gdbarch));
if (windowed)
{
/* Get WINDOWBASE, WINDOWSTART, and PS registers. */
- wb = frame_unwind_register_unsigned (next_frame, WB_REGNUM);
- ws = frame_unwind_register_unsigned (next_frame, WS_REGNUM);
+ wb = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->wb_regnum);
+ ws = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->ws_regnum);
ps = frame_unwind_register_unsigned (next_frame, ps_regnum);
op1 = read_memory_integer (pc, 1);
- if (XTENSA_IS_ENTRY (op1))
+ if (XTENSA_IS_ENTRY (gdbarch, op1))
{
int callinc = CALLINC (ps);
- ra = frame_unwind_register_unsigned (next_frame,
- A0_REGNUM + callinc * 4);
+ ra = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base + callinc * 4);
DEBUGINFO("[xtensa_frame_cache] 'entry' at 0x%08x\n (callinc = %d)",
(int)pc, callinc);
cache->wd.callsize = 0;
cache->wd.wb = wb;
cache->wd.ws = ws;
- cache->prev_sp = frame_unwind_register_unsigned (next_frame,
- A1_REGNUM);
+ cache->prev_sp = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+
+ /* This only can be the outermost frame since we are
+ just about to execute ENTRY. SP hasn't been set yet.
+ We can assume any frame size, because it does not
+ matter, and, let's fake frame base in cache. */
+ cache->base = cache->prev_sp + 16;
+
+ cache->pc = pc;
+ cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
+ cache->ps = (ps & ~PS_CALLINC_MASK)
+ | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+
+ return cache;
}
else
{
- ra = frame_unwind_register_unsigned (next_frame, A0_REGNUM);
+ fp_regnum = xtensa_scan_prologue (gdbarch, pc);
+ ra = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base);
cache->wd.callsize = WINSIZE (ra);
- cache->wd.wb = (wb - cache->wd.callsize / 4) & (NUM_AREGS / 4 - 1);
+ cache->wd.wb = (wb - cache->wd.callsize / 4)
+ & (gdbarch_tdep (gdbarch)->num_aregs / 4 - 1);
cache->wd.ws = ws & ~(1 << wb);
- }
- cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
- cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
- cache->ps = (ps & ~PS_CALLINC_MASK)
- | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+ cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
+ cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
+ cache->ps = (ps & ~PS_CALLINC_MASK)
+ | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+ }
if (cache->wd.ws == 0)
{
int i;
/* Set A0...A3. */
- sp = frame_unwind_register_unsigned (next_frame, A1_REGNUM) - 16;
+ sp = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1) - 16;
for (i = 0; i < 4; i++, sp += 4)
{
if (cache->wd.callsize > 4)
{
/* Set A4...A7/A11. */
- /* Read an SP of the previous frame. */
+ /* Get the SP of the frame previous to the previous one.
+ To achieve this, we have to dereference SP twice. */
+ sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
sp -= cache->wd.callsize * 4;
- for ( /* i=4 */ ; i < cache->wd.callsize; i++, sp += 4)
+ for ( i = 4; i < cache->wd.callsize; i++, sp += 4)
{
cache->wd.aregs[i] = sp;
}
/* If RA is equal to 0 this frame is an outermost frame. Leave
cache->prev_sp unchanged marking the boundary of the frame stack. */
{
- if (cache->wd.ws == 0)
+ if ((cache->wd.ws & (1 << cache->wd.wb)) == 0)
{
/* Register window overflow already happened.
We can read caller's SP from the proper spill loction. */
- cache->prev_sp =
- read_memory_integer (cache->wd.aregs[1],
- register_size (current_gdbarch,
- A1_REGNUM));
+ sp = frame_unwind_register_unsigned (next_frame,
+ gdbarch_tdep (gdbarch)->a0_base + 1);
+ cache->prev_sp = read_memory_integer (sp - 12, 4);
}
else
{
/* Read caller's frame SP directly from the previous window. */
- int regnum = AREG_NUMBER (A1_REGNUM, cache->wd.wb);
+ int regnum = arreg_number
+ (gdbarch, gdbarch_tdep (gdbarch)->a0_base + 1,
+ cache->wd.wb);
cache->prev_sp = xtensa_read_register (regnum);
}
else /* Call0 framework. */
{
call0_frame_cache (next_frame, cache, pc);
+ fp_regnum = cache->c0.fp_regnum;
}
- cache->base = frame_unwind_register_unsigned (next_frame,A1_REGNUM);
+ cache->base = frame_unwind_register_unsigned (next_frame, fp_regnum);
return cache;
}
xtensa_frame_cache (next_frame, this_cache);
struct frame_id id;
- DEBUGTRACE ("xtensa_frame_this_id (next 0x%08x, *this 0x%08x)\n",
- (unsigned int) next_frame, (unsigned int) *this_cache);
+ DEBUGTRACE ("xtensa_frame_this_id (next 0x%lx, *this 0x%lx)\n",
+ (unsigned long) next_frame, (unsigned long) *this_cache);
if (cache->prev_sp == 0)
return;
{
CORE_ADDR fp, spe;
int stkofs;
- int reg = (regnum >= AR_BASE && regnum <= (AR_BASE + C0_NREGS))
- ? regnum - AR_BASE : regnum;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ int reg = (regnum >= gdbarch_tdep (gdbarch)->ar_base
+ && regnum <= (gdbarch_tdep (gdbarch)->ar_base + C0_NREGS))
+ ? regnum - gdbarch_tdep (gdbarch)->ar_base : regnum;
/* Determine stack pointer on entry to this function, based on FP. */
spe = cache->c0.c0_fp - cache->c0.c0_rt[cache->c0.fp_regnum].fr_ofs;
*addrp = spe + stkofs;
if (valuep)
- read_memory (*addrp, valuep, register_size (current_gdbarch, regnum));
+ read_memory (*addrp, valuep, register_size (gdbarch, regnum));
return 1;
}
int *realnump,
gdb_byte *valuep)
{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
struct xtensa_frame_cache *cache =
xtensa_frame_cache (next_frame, this_cache);
CORE_ADDR saved_reg = 0;
int done = 1;
- DEBUGTRACE ("xtensa_frame_prev_register (next 0x%08x, "
- "*this 0x%08x, regnum %d (%s), ...)\n",
- (unsigned int) next_frame,
- *this_cache ? (unsigned int) *this_cache : 0, regnum,
- xtensa_register_name (regnum));
+ DEBUGTRACE ("xtensa_frame_prev_register (next 0x%lx, "
+ "*this 0x%lx, regnum %d (%s), ...)\n",
+ (unsigned long) next_frame,
+ *this_cache ? (unsigned long) *this_cache : 0, regnum,
+ xtensa_register_name (gdbarch, regnum));
- if (regnum ==gdbarch_pc_regnum (current_gdbarch))
+ if (regnum ==gdbarch_pc_regnum (gdbarch))
saved_reg = cache->ra;
- else if (regnum == A1_REGNUM)
+ else if (regnum == gdbarch_tdep (gdbarch)->a0_base + 1)
saved_reg = cache->prev_sp;
else if (!cache->call0)
{
- if (regnum == WS_REGNUM)
- {
- if (cache->wd.ws != 0)
- saved_reg = cache->wd.ws;
- else
- saved_reg = 1 << cache->wd.wb;
- }
- else if (regnum == WB_REGNUM)
+ if (regnum == gdbarch_tdep (gdbarch)->ws_regnum)
+ saved_reg = cache->wd.ws;
+ else if (regnum == gdbarch_tdep (gdbarch)->wb_regnum)
saved_reg = cache->wd.wb;
- else if (regnum == gdbarch_ps_regnum (current_gdbarch))
+ else if (regnum == gdbarch_ps_regnum (gdbarch))
saved_reg = cache->ps;
else
done = 0;
if (!cache->call0) /* Windowed ABI. */
{
- /* Convert A-register numbers to AR-register numbers. */
- if (regnum >= A0_REGNUM && regnum <= A15_REGNUM)
- regnum = AREG_NUMBER (regnum, cache->wd.wb);
-
- /* Check if AR-register has been saved to stack. */
- if (regnum >= AR_BASE && regnum <= (AR_BASE + NUM_AREGS))
+ /* Convert A-register numbers to AR-register numbers,
+ if we deal with A-register. */
+ if (regnum >= gdbarch_tdep (gdbarch)->a0_base
+ && regnum <= gdbarch_tdep (gdbarch)->a0_base + 15)
+ regnum = arreg_number (gdbarch, regnum, cache->wd.wb);
+
+ /* Check, if we deal with AR-register saved on stack. */
+ if (regnum >= gdbarch_tdep (gdbarch)->ar_base
+ && regnum <= (gdbarch_tdep (gdbarch)->ar_base
+ + gdbarch_tdep (gdbarch)->num_aregs))
{
- int areg = regnum - AR_BASE - (cache->wd.wb * 4);
+ int areg = areg_number (gdbarch, regnum, cache->wd.wb);
if (areg >= 0
&& areg < XTENSA_NUM_SAVED_AREGS
if (valuep)
read_memory (*addrp, valuep,
- register_size (current_gdbarch, regnum));
+ register_size (gdbarch, regnum));
DEBUGINFO ("[xtensa_frame_prev_register] register on stack\n");
return;
}
else /* Call0 ABI. */
{
- int reg = (regnum >= AR_BASE && regnum <= (AR_BASE + C0_NREGS))
- ? regnum - AR_BASE : regnum;
+ int reg = (regnum >= gdbarch_tdep (gdbarch)->ar_base
+ && regnum <= (gdbarch_tdep (gdbarch)->ar_base
+ + C0_NREGS))
+ ? regnum - gdbarch_tdep (gdbarch)->ar_base : regnum;
if (reg < C0_NREGS)
{
if (valuep)
read_memory (*addrp, valuep,
- register_size (current_gdbarch, regnum));
+ register_size (gdbarch, regnum));
DEBUGINFO ("[xtensa_frame_prev_register] register on stack\n");
return;
struct regcache *regcache,
void *dst)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
bfd_byte *valbuf = dst;
int len = TYPE_LENGTH (type);
ULONGEST pc, wb;
gdb_assert(len > 0);
- if (CALL_ABI != CallAbiCall0Only)
+ if (gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
{
/* First, we have to find the caller window in the register file. */
- regcache_raw_read_unsigned (regcache,
- gdbarch_pc_regnum (current_gdbarch), &pc);
- callsize = extract_call_winsize (pc);
+ regcache_raw_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch), &pc);
+ callsize = extract_call_winsize (gdbarch, pc);
/* On Xtensa, we can return up to 4 words (or 2 for call12). */
if (len > (callsize > 8 ? 8 : 16))
/* Get the register offset of the return
register (A2) in the caller window. */
- regcache_raw_read_unsigned (regcache, WB_REGNUM, &wb);
- areg = AREG_NUMBER(A2_REGNUM + callsize, wb);
+ regcache_raw_read_unsigned
+ (regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb);
+ areg = arreg_number (gdbarch,
+ gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
}
else
{
/* No windowing hardware - Call0 ABI. */
- areg = A0_REGNUM + C0_ARGS;
+ areg = gdbarch_tdep (gdbarch)->a0_base + C0_ARGS;
}
DEBUGINFO ("[xtensa_extract_return_value] areg %d len %d\n", areg, len);
- if (len < 4 && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (len < 4 && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
offset = 4 - len;
for (; len > 0; len -= 4, areg++, valbuf += 4)
struct regcache *regcache,
const void *dst)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
const bfd_byte *valbuf = dst;
unsigned int areg;
ULONGEST pc, wb;
DEBUGTRACE ("xtensa_store_return_value (...)\n");
- if (CALL_ABI != CallAbiCall0Only)
+ if (gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
{
- regcache_raw_read_unsigned (regcache, WB_REGNUM, &wb);
- regcache_raw_read_unsigned (regcache,
- gdbarch_pc_regnum (current_gdbarch), &pc);
- callsize = extract_call_winsize (pc);
+ regcache_raw_read_unsigned
+ (regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb);
+ regcache_raw_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch), &pc);
+ callsize = extract_call_winsize (gdbarch, pc);
if (len > (callsize > 8 ? 8 : 16))
internal_error (__FILE__, __LINE__,
_("unimplemented for this length: %d"),
TYPE_LENGTH (type));
- areg = AREG_NUMBER (A2_REGNUM + callsize, wb);
+ areg = arreg_number (gdbarch,
+ gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
DEBUGTRACE ("[xtensa_store_return_value] callsize %d wb %d\n",
callsize, (int) wb);
}
else
{
- areg = A0_REGNUM + C0_ARGS;
+ areg = gdbarch_tdep (gdbarch)->a0_base + C0_ARGS;
}
- if (len < 4 && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (len < 4 && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
offset = 4 - len;
for (; len > 0; len -= 4, areg++, valbuf += 4)
static enum return_value_convention
xtensa_return_value (struct gdbarch *gdbarch,
+ struct type *func_type,
struct type *valtype,
struct regcache *regcache,
gdb_byte *readbuf,
{
struct value *arg = args[i];
struct type *arg_type = check_typedef (value_type (arg));
- fprintf_unfiltered (gdb_stdlog, "%2d: 0x%08x %3d ",
- i, (int) arg, TYPE_LENGTH (arg_type));
+ fprintf_unfiltered (gdb_stdlog, "%2d: 0x%lx %3d ",
+ i, (unsigned long) arg, TYPE_LENGTH (arg_type));
switch (TYPE_CODE (arg_type))
{
case TYPE_CODE_INT:
fprintf_unfiltered (gdb_stdlog, "%3d", TYPE_CODE (arg_type));
break;
}
- fprintf_unfiltered (gdb_stdlog, " 0x%08x\n",
- (unsigned int) value_contents (arg));
+ fprintf_unfiltered (gdb_stdlog, " 0x%lx\n",
+ (unsigned long) value_contents (arg));
}
}
size = (size + info->align - 1) & ~(info->align - 1);
onstack_size = (onstack_size + info->align - 1) & ~(info->align - 1);
- if (size + info->length > REGISTER_SIZE * ARG_NOF)
+ if (size + info->length > REGISTER_SIZE * ARG_NOF (gdbarch))
{
info->onstack = 1;
info->u.offset = onstack_size;
else
{
info->onstack = 0;
- info->u.regno = ARG_1ST + size / REGISTER_SIZE;
+ info->u.regno = ARG_1ST (gdbarch) + size / REGISTER_SIZE;
}
size += info->length;
}
sp = align_down (sp - onstack_size, SP_ALIGNMENT);
/* Simulate MOVSP, if Windowed ABI. */
- if ((CALL_ABI != CallAbiCall0Only) && (sp != osp))
+ if ((gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
+ && (sp != osp))
{
read_memory (osp - 16, buf, 16);
write_memory (sp - 16, buf, 16);
if (struct_return)
{
store_unsigned_integer (buf, REGISTER_SIZE, struct_addr);
- regcache_cooked_write (regcache, ARG_1ST, buf);
+ regcache_cooked_write (regcache, ARG_1ST (gdbarch), buf);
}
for (i = 0; i < nargs; i++)
applies for structures smaller than one word. */
if (n < REGISTER_SIZE
- && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
offset += (REGISTER_SIZE - n);
write_memory (offset, info->contents, info->length);
will be left-aligned in the register on both endiannesses. */
if (n < REGISTER_SIZE
- && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
ULONGEST v = extract_unsigned_integer (cp, REGISTER_SIZE);
v = v >> ((REGISTER_SIZE - n) * TARGET_CHAR_BIT);
The return address for the current function (in A0) is
saved in the dummy frame, so we can savely overwrite A0 here. */
- if (CALL_ABI != CallAbiCall0Only)
+ if (gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
{
ra = (bp_addr & 0x3fffffff) | 0x40000000;
- regcache_raw_read (regcache, gdbarch_ps_regnum (current_gdbarch), buf);
+ regcache_raw_read (regcache, gdbarch_ps_regnum (gdbarch), buf);
ps = extract_unsigned_integer (buf, 4) & ~0x00030000;
- regcache_cooked_write_unsigned (regcache, A4_REGNUM, ra);
+ regcache_cooked_write_unsigned
+ (regcache, gdbarch_tdep (gdbarch)->a0_base + 4, ra);
regcache_cooked_write_unsigned (regcache,
- gdbarch_ps_regnum (current_gdbarch),
+ gdbarch_ps_regnum (gdbarch),
ps | 0x00010000);
+
+ /* All the registers have been saved. After executing
+ dummy call, they all will be restored. So it's safe
+ to modify WINDOWSTART register to make it look like there
+ is only one register window corresponding to WINDOWEBASE. */
+
+ regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf);
+ regcache_cooked_write_unsigned (regcache,
+ gdbarch_tdep (gdbarch)->ws_regnum,
+ 1 << extract_unsigned_integer (buf, 4));
}
else
{
/* Simulate CALL0: write RA into A0 register. */
- regcache_cooked_write_unsigned (regcache, A0_REGNUM, bp_addr);
+ regcache_cooked_write_unsigned
+ (regcache, gdbarch_tdep (gdbarch)->a0_base, bp_addr);
}
/* Set new stack pointer and return it. */
- regcache_cooked_write_unsigned (regcache, A1_REGNUM, sp);
+ regcache_cooked_write_unsigned (regcache,
+ gdbarch_tdep (gdbarch)->a0_base + 1, sp);
/* Make dummy frame ID unique by adding a constant. */
return sp + SP_ALIGNMENT;
}
#define DENSITY_LITTLE_BREAKPOINT { 0x2d, 0xf0 }
static const unsigned char *
-xtensa_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+xtensa_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+ int *lenptr)
{
static unsigned char big_breakpoint[] = BIG_BREAKPOINT;
static unsigned char little_breakpoint[] = LITTLE_BREAKPOINT;
DEBUGTRACE ("xtensa_breakpoint_from_pc (pc = 0x%08x)\n", (int) *pcptr);
- if (ISA_USE_DENSITY_INSTRUCTIONS)
+ if (gdbarch_tdep (gdbarch)->isa_use_density_instructions)
{
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
*lenptr = sizeof (density_big_breakpoint);
return density_big_breakpoint;
}
else
{
- if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
{
*lenptr = sizeof (big_breakpoint);
return big_breakpoint;
/* 2 operands: dst, literal offset. */
gdb_assert (nods == 2);
/* litbase = xtensa_get_litbase (pc); can be also used. */
- litbase = (LITBASE_REGNUM == -1)
- ? 0 : xtensa_read_register (LITBASE_REGNUM);
+ litbase = (gdbarch_tdep (current_gdbarch)->litbase_regnum == -1)
+ ? 0 : xtensa_read_register
+ (gdbarch_tdep (current_gdbarch)->litbase_regnum);
litaddr = litbase & 1
? (litbase & ~1) + (signed)odv[1]
: (pc + 3 + (signed)odv[1]) & ~3;
}
else nregs = 0;
+ if (!xtensa_default_isa)
+ xtensa_default_isa = xtensa_isa_init (0, 0);
isa = xtensa_default_isa;
gdb_assert (BSZ >= xtensa_isa_maxlength (isa));
ins = xtensa_insnbuf_alloc (isa);
call0_frame_cache (struct frame_info *next_frame,
xtensa_frame_cache_t *cache, CORE_ADDR pc)
{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
CORE_ADDR start_pc; /* The beginning of the function. */
CORE_ADDR body_pc=UINT_MAX; /* PC, where prologue analysis stopped. */
CORE_ADDR sp, fp, ra;
&cache->call0);
}
- sp = frame_unwind_register_unsigned (next_frame, A1_REGNUM);
+ sp = frame_unwind_register_unsigned
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
fp = sp; /* Assume FP == SP until proven otherwise. */
/* Get the frame information and FP (if used) at the current PC.
was derived from SP. Otherwise, it would be C0_FP. */
fp_regnum = c0_hasfp ? C0_FP : C0_SP;
c0_frmsz = - cache->c0.c0_rt[fp_regnum].fr_ofs;
- fp_regnum += A0_BASE;
+ fp_regnum += gdbarch_tdep (gdbarch)->a0_base;
}
else /* No data from the prologue analysis. */
{
c0_hasfp = 0;
- fp_regnum = A0_BASE + C0_SP;
+ fp_regnum = gdbarch_tdep (gdbarch)->a0_base + C0_SP;
c0_frmsz = 0;
start_pc = pc;
}
i = C0_RA;
if (i < C0_NREGS) /* Read from the next_frame. */
{
- ra = frame_unwind_register_unsigned (next_frame,
- A0_REGNUM + cache->c0.c0_rt[i].fr_reg);
+ ra = frame_unwind_register_unsigned
+ (next_frame,
+ gdbarch_tdep (gdbarch)->a0_base + cache->c0.c0_rt[i].fr_reg);
}
else ra = 0;
}
/* #define DONT_SKIP_PROLOGUE */
CORE_ADDR
-xtensa_skip_prologue (CORE_ADDR start_pc)
+xtensa_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
struct symtab_and_line prologue_sal;
CORE_ADDR body_pc;
do_cleanups (cleanups);
}
+
+/* Derive specific register numbers from the array of registers. */
+
+void
+xtensa_derive_tdep (struct gdbarch_tdep *tdep)
+{
+ xtensa_register_t* rmap;
+ int n, max_size = 4;
+
+ tdep->num_regs = 0;
+ tdep->num_nopriv_regs = 0;
+
+/* Special registers 0..255 (core). */
+#define XTENSA_DBREGN_SREG(n) (0x0200+(n))
+
+ for (rmap = tdep->regmap, n = 0; rmap->target_number != -1; n++, rmap++)
+ {
+ if (rmap->target_number == 0x0020)
+ tdep->pc_regnum = n;
+ else if (rmap->target_number == 0x0100)
+ tdep->ar_base = n;
+ else if (rmap->target_number == 0x0000)
+ tdep->a0_base = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(72))
+ tdep->wb_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(73))
+ tdep->ws_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(233))
+ tdep->debugcause_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(232))
+ tdep->exccause_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(238))
+ tdep->excvaddr_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(0))
+ tdep->lbeg_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(1))
+ tdep->lend_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(2))
+ tdep->lcount_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(3))
+ tdep->sar_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(5))
+ tdep->litbase_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(230))
+ tdep->ps_regnum = n;
+#if 0
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(226))
+ tdep->interrupt_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(227))
+ tdep->interrupt2_regnum = n;
+ else if (rmap->target_number == XTENSA_DBREGN_SREG(224))
+ tdep->cpenable_regnum = n;
+#endif
+
+ if (rmap->byte_size > max_size)
+ max_size = rmap->byte_size;
+ if (rmap->mask != 0 && tdep->num_regs == 0)
+ tdep->num_regs = n;
+ /* Find out out how to deal with priveleged registers.
+
+ if ((rmap->flags & XTENSA_REGISTER_FLAGS_PRIVILEGED) != 0
+ && tdep->num_nopriv_regs == 0)
+ tdep->num_nopriv_regs = n;
+ */
+ if ((rmap->flags & XTENSA_REGISTER_FLAGS_PRIVILEGED) != 0
+ && tdep->num_regs == 0)
+ tdep->num_regs = n;
+ }
+
+ /* Number of pseudo registers. */
+ tdep->num_pseudo_regs = n - tdep->num_regs;
+
+ /* Empirically determined maximum sizes. */
+ tdep->max_register_raw_size = max_size;
+ tdep->max_register_virtual_size = max_size;
+}
+
/* Module "constructor" function. */
+extern struct gdbarch_tdep xtensa_tdep;
+
static struct gdbarch *
xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
DEBUGTRACE ("gdbarch_init()\n");
/* We have to set the byte order before we call gdbarch_alloc. */
- info.byte_order = xtensa_config_byte_order (&info);
+ info.byte_order = XCHAL_HAVE_BE ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
- tdep = xtensa_config_tdep (&info);
+ tdep = &xtensa_tdep;
gdbarch = gdbarch_alloc (&info, tdep);
+ xtensa_derive_tdep (tdep);
/* Verify our configuration. */
xtensa_verify_config (gdbarch);
set_gdbarch_regset_from_core_section (gdbarch,
xtensa_regset_from_core_section);
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
return gdbarch;
}
static void
-xtensa_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+xtensa_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
{
error (_("xtensa_dump_tdep(): not implemented"));
}