/* 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.
#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;
== CallAbiCall0Only ? C0_NARGS : (ARGS_NUM_REGS))
#define ARG_1ST(gdbarch) \
(gdbarch_tdep (gdbarch)->call_abi == CallAbiCall0Only \
- ? (gdbarch_tdep (gdbarch)->a0_base + 0) + C0_ARGS \
+ ? (gdbarch_tdep (gdbarch)->a0_base + C0_ARGS) \
: (gdbarch_tdep (gdbarch)->a0_base + 6))
-extern struct gdbarch_tdep *xtensa_config_tdep (struct gdbarch_info *);
-extern int xtensa_config_byte_order (struct gdbarch_info *);
-
-
/* XTENSA_IS_ENTRY tests whether the first byte of an instruction
indicates that the instruction is an ENTRY instruction. */
#define PS_WOE (1<<18)
#define PS_EXC (1<<4)
-/* Convert a live Ax register number to the corresponding Areg number. */
+/* Convert a live A-register number to the corresponding AR-register number. */
static int
-areg_number (struct gdbarch *gdbarch, int regnum, ULONGEST wb)
+arreg_number (struct gdbarch *gdbarch, int a_regnum, ULONGEST wb)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int areg;
+ 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;
+}
- areg = regnum - tdep->a0_base;
- areg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT;
- areg &= tdep->num_aregs - 1;
+/* 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;
- return areg + tdep->ar_base;
+ 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
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 gdbarch_tdep (current_gdbarch)->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 == gdbarch_tdep (current_gdbarch)->regmap[i].target_number)
+ if (regnum == gdbarch_tdep (gdbarch)->regmap[i].target_number)
return i;
internal_error (__FILE__, __LINE__,
regnum, xtensa_register_name (gdbarch, regnum));
if (regnum == gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_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 (gdbarch_tdep (gdbarch)->isa_use_windowed_registers
- && (regnum >= gdbarch_tdep (gdbarch)->a0_base + 0)
+ && (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, gdbarch_tdep (gdbarch)->wb_regnum, buf);
- regnum = areg_number (gdbarch, regnum, extract_unsigned_integer (buf, 4));
+ regnum = arreg_number (gdbarch, regnum,
+ extract_unsigned_integer (buf, 4));
}
/* We can always read non-pseudo registers. */
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 (gdbarch)
regnum, xtensa_register_name (gdbarch, regnum));
if (regnum == gdbarch_num_regs (gdbarch)
- + gdbarch_num_pseudo_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 (gdbarch_tdep (gdbarch)->isa_use_windowed_registers
- && (regnum >= gdbarch_tdep (gdbarch)->a0_base + 0)
+ && (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,
gdbarch_tdep (gdbarch)->wb_regnum, buf);
- regnum = areg_number (gdbarch, regnum, extract_unsigned_integer (buf, 4));
+ regnum = arreg_number (gdbarch, regnum,
+ extract_unsigned_integer (buf, 4));
}
/* We can always write 'core' registers.
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 (gdbarch)
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)->exccause_regnum || regnum == -1)
- regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->exccause_regnum,
- (char *) ®s->exccause);
- if (regnum == gdbarch_tdep (gdbarch)->excvaddr_regnum || regnum == -1)
- regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->excvaddr_regnum,
- (char *) ®s->excvaddr);
if (regnum >=gdbarch_tdep (gdbarch)->ar_base
&& regnum < gdbarch_tdep (gdbarch)->ar_base
+ gdbarch_tdep (gdbarch)->num_aregs)
{
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++)
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.
*/
CORE_ADDR ra, wb, ws, pc, sp, ps;
struct gdbarch *gdbarch = get_frame_arch (next_frame);
unsigned int ps_regnum = gdbarch_ps_regnum (gdbarch);
+ unsigned int fp_regnum;
char op1;
int windowed;
{
int callinc = CALLINC (ps);
ra = frame_unwind_register_unsigned
- (next_frame, gdbarch_tdep (gdbarch)->a0_base + 0 + callinc * 4);
+ (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.ws = ws;
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
{
+ fp_regnum = xtensa_scan_prologue (gdbarch, pc);
ra = frame_unwind_register_unsigned
- (next_frame, gdbarch_tdep (gdbarch)->a0_base + 0);
+ (next_frame, gdbarch_tdep (gdbarch)->a0_base);
cache->wd.callsize = WINSIZE (ra);
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)
{
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 (gdbarch,
- gdbarch_tdep (gdbarch)->a0_base + 1));
+ 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
+ int regnum = arreg_number
(gdbarch, gdbarch_tdep (gdbarch)->a0_base + 1,
cache->wd.wb);
else /* Call0 framework. */
{
call0_frame_cache (next_frame, cache, pc);
+ fp_regnum = cache->c0.fp_regnum;
}
- cache->base = frame_unwind_register_unsigned
- (next_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+ 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 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,
+ 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 (gdbarch))
else if (!cache->call0)
{
if (regnum == gdbarch_tdep (gdbarch)->ws_regnum)
- {
- if (cache->wd.ws != 0)
- saved_reg = cache->wd.ws;
- else
- saved_reg = 1 << cache->wd.wb;
- }
+ saved_reg = cache->wd.ws;
else if (regnum == gdbarch_tdep (gdbarch)->wb_regnum)
saved_reg = cache->wd.wb;
else if (regnum == gdbarch_ps_regnum (gdbarch))
if (!cache->call0) /* Windowed ABI. */
{
- /* Convert A-register numbers to AR-register numbers. */
- if (regnum >= gdbarch_tdep (gdbarch)->a0_base + 0
+ /* 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 = areg_number (gdbarch, regnum, cache->wd.wb);
+ regnum = arreg_number (gdbarch, regnum, cache->wd.wb);
- /* Check if AR-register has been saved to stack. */
+ /* 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 - gdbarch_tdep (gdbarch)->ar_base
- - (cache->wd.wb * 4);
+ int areg = areg_number (gdbarch, regnum, cache->wd.wb);
if (areg >= 0
&& areg < XTENSA_NUM_SAVED_AREGS
register (A2) in the caller window. */
regcache_raw_read_unsigned
(regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb);
- areg = areg_number (gdbarch,
+ areg = arreg_number (gdbarch,
gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
}
else
{
/* No windowing hardware - Call0 ABI. */
- areg = gdbarch_tdep (gdbarch)->a0_base + 0 + C0_ARGS;
+ areg = gdbarch_tdep (gdbarch)->a0_base + C0_ARGS;
}
DEBUGINFO ("[xtensa_extract_return_value] areg %d len %d\n", areg, len);
internal_error (__FILE__, __LINE__,
_("unimplemented for this length: %d"),
TYPE_LENGTH (type));
- areg = areg_number (gdbarch,
- gdbarch_tdep (gdbarch)->a0_base + 2 + 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 = gdbarch_tdep (gdbarch)->a0_base + 0 + C0_ARGS;
+ areg = gdbarch_tdep (gdbarch)->a0_base + C0_ARGS;
}
if (len < 4 && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
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));
}
}
regcache_cooked_write_unsigned (regcache,
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, gdbarch_tdep (gdbarch)->a0_base + 0, bp_addr);
+ (regcache, gdbarch_tdep (gdbarch)->a0_base, bp_addr);
}
/* Set new stack pointer and return it. */
}
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);
{
ra = frame_unwind_register_unsigned
(next_frame,
- gdbarch_tdep (gdbarch)->a0_base + 0
- + cache->c0.c0_rt[i].fr_reg);
+ 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;
}