2011-03-08 Maxim Grigoriev <maxim2405@gmail.com>
* xtensa-tdep.c (xtensa_read_register): New function. (xtensa_write_register): New function. (xtensa_find_register_by_name): New function. (xtensa_windowed_frame_cache): Update comments in type description. (xtensa_frame_cache): Likewise. (xtensa_window_interrupt_insn): New function. (xtensa_frame_cache): Add analysis for Xtensa Window Exception frames. (xtensa_insn_kind): Add new instructions. (rwx_special_register): New function. (call0_classify_opcode): Add new instructions to the analysis. (a0_saved, a7_saved, a11_saved): New variables. (a0_was_saved, a7_was_saved, a11_was_saved): New variables. (execute_l32e): New function. (execute_s32e): New function. (xtensa_exception_handler_t): New type. (execute_code): New function. (xtensa_window_interrupt_frame_cache): New function to conduct frame analysis for Xtensa Window Exception handlers.
This commit is contained in:
parent
ecb351e919
commit
08b9c608aa
|
@ -1,3 +1,24 @@
|
|||
2011-03-08 Maxim Grigoriev <maxim2405@gmail.com>
|
||||
|
||||
* xtensa-tdep.c (xtensa_read_register): New function.
|
||||
(xtensa_write_register): New function.
|
||||
(xtensa_find_register_by_name): New function.
|
||||
(xtensa_windowed_frame_cache): Update comments in type description.
|
||||
(xtensa_frame_cache): Likewise.
|
||||
(xtensa_window_interrupt_insn): New function.
|
||||
(xtensa_frame_cache): Add analysis for Xtensa Window Exception frames.
|
||||
(xtensa_insn_kind): Add new instructions.
|
||||
(rwx_special_register): New function.
|
||||
(call0_classify_opcode): Add new instructions to the analysis.
|
||||
(a0_saved, a7_saved, a11_saved): New variables.
|
||||
(a0_was_saved, a7_was_saved, a11_was_saved): New variables.
|
||||
(execute_l32e): New function.
|
||||
(execute_s32e): New function.
|
||||
(xtensa_exception_handler_t): New type.
|
||||
(execute_code): New function.
|
||||
(xtensa_window_interrupt_frame_cache): New function to conduct frame
|
||||
analysis for Xtensa Window Exception handlers.
|
||||
|
||||
2011-03-08 Maxim Grigoriev <maxim2405@gmail.com>
|
||||
|
||||
* xtensa-tdep.c (TX_PS): New.
|
||||
|
|
|
@ -161,6 +161,21 @@ areg_number (struct gdbarch *gdbarch, int ar_regnum, unsigned int wb)
|
|||
return (areg > 15) ? -1 : areg;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
xtensa_read_register (int regnum)
|
||||
{
|
||||
ULONGEST value;
|
||||
|
||||
regcache_raw_read_unsigned (get_current_regcache (), regnum, &value);
|
||||
return (unsigned long) value;
|
||||
}
|
||||
|
||||
static inline void
|
||||
xtensa_write_register (int regnum, ULONGEST value)
|
||||
{
|
||||
regcache_raw_write_unsigned (get_current_regcache (), regnum, value);
|
||||
}
|
||||
|
||||
/* Return the window size of the previous call to the function from which we
|
||||
have just returned.
|
||||
|
||||
|
@ -210,6 +225,22 @@ extract_call_winsize (struct gdbarch *gdbarch, CORE_ADDR pc)
|
|||
|
||||
/* REGISTER INFORMATION */
|
||||
|
||||
/* Find register by name. */
|
||||
static int
|
||||
xtensa_find_register_by_name (struct gdbarch *gdbarch, char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < gdbarch_num_regs (gdbarch)
|
||||
+ gdbarch_num_pseudo_regs (gdbarch);
|
||||
i++)
|
||||
|
||||
if (strcasecmp (gdbarch_tdep (gdbarch)->regmap[i].name, name) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Returns the name of a register. */
|
||||
static const char *
|
||||
xtensa_register_name (struct gdbarch *gdbarch, int regnum)
|
||||
|
@ -907,14 +938,13 @@ typedef struct xtensa_windowed_frame_cache
|
|||
{
|
||||
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. */
|
||||
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. */
|
||||
/* Addresses of spilled A-registers.
|
||||
AREGS[i] == -1, if corresponding AR is alive. */
|
||||
CORE_ADDR aregs[XTENSA_NUM_SAVED_AREGS];
|
||||
} xtensa_windowed_frame_cache_t;
|
||||
|
||||
|
@ -968,10 +998,10 @@ typedef struct xtensa_call0_frame_cache
|
|||
typedef struct xtensa_frame_cache
|
||||
{
|
||||
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 (without CALLINC). */
|
||||
CORE_ADDR ps; /* The PS register of this frame. */
|
||||
CORE_ADDR prev_sp; /* Stack Pointer of the previous frame. */
|
||||
CORE_ADDR pc; /* PC of this frame at the function entry point. */
|
||||
CORE_ADDR ra; /* The raw return address of this frame. */
|
||||
CORE_ADDR ps; /* The PS register of the previous (older) frame. */
|
||||
CORE_ADDR prev_sp; /* Stack Pointer of the previous (older) frame. */
|
||||
int call0; /* It's a call0 framework (else windowed). */
|
||||
union
|
||||
{
|
||||
|
@ -1064,6 +1094,38 @@ xtensa_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
|
|||
return frame_id_build (fp + SP_ALIGNMENT, pc);
|
||||
}
|
||||
|
||||
/* Returns true, if instruction to execute next is unique to Xtensa Window
|
||||
Interrupt Handlers. It can only be one of L32E, S32E, RFWO, or RFWU. */
|
||||
|
||||
static int
|
||||
xtensa_window_interrupt_insn (struct gdbarch *gdbarch, CORE_ADDR pc)
|
||||
{
|
||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||
unsigned int insn = read_memory_integer (pc, 4, byte_order);
|
||||
unsigned int code;
|
||||
|
||||
if (byte_order == BFD_ENDIAN_BIG)
|
||||
{
|
||||
/* Check, if this is L32E or S32E. */
|
||||
code = insn & 0xf000ff00;
|
||||
if ((code == 0x00009000) || (code == 0x00009400))
|
||||
return 1;
|
||||
/* Check, if this is RFWU or RFWO. */
|
||||
code = insn & 0xffffff00;
|
||||
return ((code == 0x00430000) || (code == 0x00530000));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check, if this is L32E or S32E. */
|
||||
code = insn & 0x00ff000f;
|
||||
if ((code == 0x090000) || (code == 0x490000))
|
||||
return 1;
|
||||
/* Check, if this is RFWU or RFWO. */
|
||||
code = insn & 0x00ffffff;
|
||||
return ((code == 0x00003400) || (code == 0x00003500));
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the best guess about which register is a frame pointer
|
||||
for the function containing CURRENT_PC. */
|
||||
|
||||
|
@ -1195,6 +1257,11 @@ call0_frame_cache (struct frame_info *this_frame,
|
|||
xtensa_frame_cache_t *cache,
|
||||
CORE_ADDR pc, CORE_ADDR litbase);
|
||||
|
||||
static void
|
||||
xtensa_window_interrupt_frame_cache (struct frame_info *this_frame,
|
||||
xtensa_frame_cache_t *cache,
|
||||
CORE_ADDR pc);
|
||||
|
||||
static struct xtensa_frame_cache *
|
||||
xtensa_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||
{
|
||||
|
@ -1302,9 +1369,8 @@ xtensa_frame_cache (struct frame_info *this_frame, void **this_cache)
|
|||
}
|
||||
|
||||
if ((cache->prev_sp == 0) && ( ra != 0 ))
|
||||
/* 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 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 & (1 << cache->wd.wb)) == 0)
|
||||
{
|
||||
|
@ -1321,11 +1387,18 @@ xtensa_frame_cache (struct frame_info *this_frame, void **this_cache)
|
|||
(gdbarch, gdbarch_tdep (gdbarch)->a0_base + 1,
|
||||
cache->wd.wb);
|
||||
|
||||
cache->prev_sp = get_frame_register_unsigned (this_frame,
|
||||
regnum);
|
||||
cache->prev_sp = xtensa_read_register (regnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (xtensa_window_interrupt_insn (gdbarch, pc))
|
||||
{
|
||||
/* Execution stopped inside Xtensa Window Interrupt Handler. */
|
||||
|
||||
xtensa_window_interrupt_frame_cache (this_frame, cache, pc);
|
||||
/* Everything was set already, including cache->base. */
|
||||
return cache;
|
||||
}
|
||||
else /* Call0 framework. */
|
||||
{
|
||||
unsigned int litbase_regnum = gdbarch_tdep (gdbarch)->litbase_regnum;
|
||||
|
@ -1941,11 +2014,33 @@ typedef enum {
|
|||
c0opc_mov, /* Moving a register to a register. */
|
||||
c0opc_movi, /* Moving an immediate to a register. */
|
||||
c0opc_l32r, /* Loading a literal. */
|
||||
c0opc_s32i, /* Storing word at fixed offset from a base
|
||||
register. */
|
||||
c0opc_s32i, /* Storing word at fixed offset from a base register. */
|
||||
c0opc_rwxsr, /* RSR, WRS, or XSR instructions. */
|
||||
c0opc_l32e, /* L32E instruction. */
|
||||
c0opc_s32e, /* S32E instruction. */
|
||||
c0opc_rfwo, /* RFWO instruction. */
|
||||
c0opc_rfwu, /* RFWU instruction. */
|
||||
c0opc_NrOf /* Number of opcode classifications. */
|
||||
} xtensa_insn_kind;
|
||||
|
||||
/* Return true, if OPCNAME is RSR, WRS, or XSR instruction. */
|
||||
|
||||
static int
|
||||
rwx_special_register (const char *opcname)
|
||||
{
|
||||
char ch = *opcname++;
|
||||
|
||||
if ((ch != 'r') && (ch != 'w') && (ch != 'x'))
|
||||
return 0;
|
||||
if (*opcname++ != 's')
|
||||
return 0;
|
||||
if (*opcname++ != 'r')
|
||||
return 0;
|
||||
if (*opcname++ != '.')
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Classify an opcode based on what it means for Call0 prologue analysis. */
|
||||
|
||||
|
@ -1970,6 +2065,10 @@ call0_classify_opcode (xtensa_isa isa, xtensa_opcode opc)
|
|||
opclass = c0opc_break;
|
||||
else if (strcasecmp (opcname, "entry") == 0)
|
||||
opclass = c0opc_entry;
|
||||
else if (strcasecmp (opcname, "rfwo") == 0)
|
||||
opclass = c0opc_rfwo;
|
||||
else if (strcasecmp (opcname, "rfwu") == 0)
|
||||
opclass = c0opc_rfwu;
|
||||
else if (xtensa_opcode_is_branch (isa, opc) > 0
|
||||
|| xtensa_opcode_is_jump (isa, opc) > 0
|
||||
|| xtensa_opcode_is_loop (isa, opc) > 0
|
||||
|
@ -1999,6 +2098,12 @@ call0_classify_opcode (xtensa_isa isa, xtensa_opcode opc)
|
|||
else if (strcasecmp (opcname, "s32i") == 0
|
||||
|| strcasecmp (opcname, "s32i.n") == 0)
|
||||
opclass = c0opc_s32i;
|
||||
else if (strcasecmp (opcname, "l32e") == 0)
|
||||
opclass = c0opc_l32e;
|
||||
else if (strcasecmp (opcname, "s32e") == 0)
|
||||
opclass = c0opc_s32e;
|
||||
else if (rwx_special_register (opcname))
|
||||
opclass = c0opc_rwxsr;
|
||||
|
||||
return opclass;
|
||||
}
|
||||
|
@ -2028,7 +2133,7 @@ call0_track_op (struct gdbarch *gdbarch,
|
|||
break;
|
||||
case c0opc_add:
|
||||
/* 3 operands: dst, src1, src2. */
|
||||
gdb_assert (nods == 3);
|
||||
gdb_assert (nods == 3);
|
||||
if (src[odv[1]].fr_reg == C0_CONST)
|
||||
{
|
||||
dst[odv[0]].fr_reg = src[odv[2]].fr_reg;
|
||||
|
@ -2458,6 +2563,258 @@ analysis failed in this frame. GDB command execution stopped."));
|
|||
cache->c0.c0_fp = fp;
|
||||
}
|
||||
|
||||
static CORE_ADDR a0_saved;
|
||||
static CORE_ADDR a7_saved;
|
||||
static CORE_ADDR a11_saved;
|
||||
static int a0_was_saved;
|
||||
static int a7_was_saved;
|
||||
static int a11_was_saved;
|
||||
|
||||
/* Simulate L32E insn: AT <-- ref (AS + offset). */
|
||||
static void
|
||||
execute_l32e (struct gdbarch *gdbarch, int at, int as, int offset, CORE_ADDR wb)
|
||||
{
|
||||
int atreg = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base + at, wb);
|
||||
int asreg = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base + as, wb);
|
||||
CORE_ADDR addr = xtensa_read_register (asreg) + offset;
|
||||
unsigned int spilled_value
|
||||
= read_memory_unsigned_integer (addr, 4, gdbarch_byte_order (gdbarch));
|
||||
|
||||
if ((at == 0) && !a0_was_saved)
|
||||
{
|
||||
a0_saved = xtensa_read_register (atreg);
|
||||
a0_was_saved = 1;
|
||||
}
|
||||
else if ((at == 7) && !a7_was_saved)
|
||||
{
|
||||
a7_saved = xtensa_read_register (atreg);
|
||||
a7_was_saved = 1;
|
||||
}
|
||||
else if ((at == 11) && !a11_was_saved)
|
||||
{
|
||||
a11_saved = xtensa_read_register (atreg);
|
||||
a11_was_saved = 1;
|
||||
}
|
||||
|
||||
xtensa_write_register (atreg, spilled_value);
|
||||
}
|
||||
|
||||
/* Simulate S32E insn: AT --> ref (AS + offset). */
|
||||
static void
|
||||
execute_s32e (struct gdbarch *gdbarch, int at, int as, int offset, CORE_ADDR wb)
|
||||
{
|
||||
int atreg = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base + at, wb);
|
||||
int asreg = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base + as, wb);
|
||||
CORE_ADDR addr = xtensa_read_register (asreg) + offset;
|
||||
ULONGEST spilled_value = xtensa_read_register (atreg);
|
||||
|
||||
write_memory_unsigned_integer (addr, 4,
|
||||
gdbarch_byte_order (gdbarch),
|
||||
spilled_value);
|
||||
}
|
||||
|
||||
#define XTENSA_MAX_WINDOW_INTERRUPT_HANDLER_LEN 200
|
||||
|
||||
typedef enum {
|
||||
xtWindowOverflow,
|
||||
xtWindowUnderflow,
|
||||
xtNoExceptionHandler
|
||||
} xtensa_exception_handler_t;
|
||||
|
||||
/* Execute insn stream from current PC until hitting RFWU or RFWO.
|
||||
Return type of Xtensa Window Interrupt Handler on success. */
|
||||
static xtensa_exception_handler_t
|
||||
execute_code (struct gdbarch *gdbarch, CORE_ADDR current_pc, CORE_ADDR wb)
|
||||
{
|
||||
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;
|
||||
int insn_num = 0;
|
||||
int fail = 0;
|
||||
void (*func) (struct gdbarch *, int, int, int, CORE_ADDR);
|
||||
|
||||
int at, as, offset;
|
||||
int num_operands;
|
||||
|
||||
/* WindowUnderflow12 = true, when inside _WindowUnderflow12. */
|
||||
int WindowUnderflow12 = (current_pc & 0x1ff) >= 0x140;
|
||||
|
||||
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;
|
||||
ia = current_pc;
|
||||
bt = ia;
|
||||
|
||||
a0_was_saved = 0;
|
||||
a7_was_saved = 0;
|
||||
a11_was_saved = 0;
|
||||
|
||||
while (insn_num++ < XTENSA_MAX_WINDOW_INTERRUPT_HANDLER_LEN)
|
||||
{
|
||||
if (ia + xtensa_isa_maxlength (isa) > bt)
|
||||
{
|
||||
ba = ia;
|
||||
bt = (ba + XTENSA_ISA_BSZ);
|
||||
if (target_read_memory (ba, ibuf, bt - ba) != 0)
|
||||
return xtNoExceptionHandler;
|
||||
}
|
||||
xtensa_insnbuf_from_chars (isa, ins, &ibuf[ia-ba], 0);
|
||||
ifmt = xtensa_format_decode (isa, ins);
|
||||
if (ifmt == XTENSA_UNDEFINED)
|
||||
return xtNoExceptionHandler;
|
||||
ilen = xtensa_format_length (isa, ifmt);
|
||||
if (ilen == XTENSA_UNDEFINED)
|
||||
return xtNoExceptionHandler;
|
||||
islots = xtensa_format_num_slots (isa, ifmt);
|
||||
if (islots == XTENSA_UNDEFINED)
|
||||
return xtNoExceptionHandler;
|
||||
for (is = 0; is < islots; ++is)
|
||||
{
|
||||
if (xtensa_format_get_slot (isa, ifmt, is, ins, slot))
|
||||
return xtNoExceptionHandler;
|
||||
opc = xtensa_opcode_decode (isa, ifmt, is, slot);
|
||||
if (opc == XTENSA_UNDEFINED)
|
||||
return xtNoExceptionHandler;
|
||||
switch (call0_classify_opcode (isa, opc))
|
||||
{
|
||||
case c0opc_illegal:
|
||||
case c0opc_flow:
|
||||
case c0opc_entry:
|
||||
case c0opc_break:
|
||||
/* We expect none of them here. */
|
||||
return xtNoExceptionHandler;
|
||||
case c0opc_l32e:
|
||||
func = execute_l32e;
|
||||
break;
|
||||
case c0opc_s32e:
|
||||
func = execute_s32e;
|
||||
break;
|
||||
case c0opc_rfwo: /* RFWO. */
|
||||
/* Here, we return from WindowOverflow handler and,
|
||||
if we stopped at the very beginning, which means
|
||||
A0 was saved, we have to restore it now. */
|
||||
if (a0_was_saved)
|
||||
{
|
||||
int arreg = arreg_number (gdbarch,
|
||||
gdbarch_tdep (gdbarch)->a0_base,
|
||||
wb);
|
||||
xtensa_write_register (arreg, a0_saved);
|
||||
}
|
||||
return xtWindowOverflow;
|
||||
case c0opc_rfwu: /* RFWU. */
|
||||
/* Here, we return from WindowUnderflow handler.
|
||||
Let's see if either A7 or A11 has to be restored. */
|
||||
if (WindowUnderflow12)
|
||||
{
|
||||
if (a11_was_saved)
|
||||
{
|
||||
int arreg = arreg_number (gdbarch,
|
||||
gdbarch_tdep (gdbarch)->a0_base + 11,
|
||||
wb);
|
||||
xtensa_write_register (arreg, a11_saved);
|
||||
}
|
||||
}
|
||||
else if (a7_was_saved)
|
||||
{
|
||||
int arreg = arreg_number (gdbarch,
|
||||
gdbarch_tdep (gdbarch)->a0_base + 7,
|
||||
wb);
|
||||
xtensa_write_register (arreg, a7_saved);
|
||||
}
|
||||
return xtWindowUnderflow;
|
||||
default: /* Simply skip this insns. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Decode arguments for L32E / S32E and simulate their execution. */
|
||||
if ( xtensa_opcode_num_operands (isa, opc) != 3 )
|
||||
return xtNoExceptionHandler;
|
||||
if (xtensa_operand_get_field (isa, opc, 0, ifmt, is, slot, &at))
|
||||
return xtNoExceptionHandler;
|
||||
if (xtensa_operand_decode (isa, opc, 0, &at))
|
||||
return xtNoExceptionHandler;
|
||||
if (xtensa_operand_get_field (isa, opc, 1, ifmt, is, slot, &as))
|
||||
return xtNoExceptionHandler;
|
||||
if (xtensa_operand_decode (isa, opc, 1, &as))
|
||||
return xtNoExceptionHandler;
|
||||
if (xtensa_operand_get_field (isa, opc, 2, ifmt, is, slot, &offset))
|
||||
return xtNoExceptionHandler;
|
||||
if (xtensa_operand_decode (isa, opc, 2, &offset))
|
||||
return xtNoExceptionHandler;
|
||||
|
||||
(*func) (gdbarch, at, as, offset, wb);
|
||||
}
|
||||
|
||||
ia += ilen;
|
||||
}
|
||||
return xtNoExceptionHandler;
|
||||
}
|
||||
|
||||
/* Handle Window Overflow / Underflow exception frames. */
|
||||
|
||||
static void
|
||||
xtensa_window_interrupt_frame_cache (struct frame_info *this_frame,
|
||||
xtensa_frame_cache_t *cache,
|
||||
CORE_ADDR pc)
|
||||
{
|
||||
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||
CORE_ADDR ps, wb, ws, ra;
|
||||
int epc1_regnum, i, regnum;
|
||||
xtensa_exception_handler_t eh_type;
|
||||
|
||||
/* Read PS, WB, and WS from the hardware. Note that PS register
|
||||
must be present, if Windowed ABI is supported. */
|
||||
ps = xtensa_read_register (gdbarch_ps_regnum (gdbarch));
|
||||
wb = xtensa_read_register (gdbarch_tdep (gdbarch)->wb_regnum);
|
||||
ws = xtensa_read_register (gdbarch_tdep (gdbarch)->ws_regnum);
|
||||
|
||||
/* Execute all the remaining instructions from Window Interrupt Handler
|
||||
by simulating them on the remote protocol level. On return, set the
|
||||
type of Xtensa Window Interrupt Handler, or report an error. */
|
||||
eh_type = execute_code (gdbarch, pc, wb);
|
||||
if (eh_type == xtNoExceptionHandler)
|
||||
error (_("\
|
||||
Unable to decode Xtensa Window Interrupt Handler's code."));
|
||||
|
||||
cache->ps = ps ^ PS_EXC; /* Clear the exception bit in PS. */
|
||||
cache->call0 = 0; /* It's Windowed ABI. */
|
||||
|
||||
/* All registers for the cached frame will be alive. */
|
||||
for (i = 0; i < XTENSA_NUM_SAVED_AREGS; i++)
|
||||
cache->wd.aregs[i] = -1;
|
||||
|
||||
if (eh_type == xtWindowOverflow)
|
||||
cache->wd.ws = ws ^ (1 << wb);
|
||||
else /* eh_type == xtWindowUnderflow. */
|
||||
cache->wd.ws = ws | (1 << wb);
|
||||
|
||||
cache->wd.wb = (ps & 0xf00) >> 8; /* Set WB to OWB. */
|
||||
regnum = arreg_number (gdbarch, gdbarch_tdep (gdbarch)->a0_base,
|
||||
cache->wd.wb);
|
||||
ra = xtensa_read_register (regnum);
|
||||
cache->wd.callsize = WINSIZE (ra);
|
||||
cache->prev_sp = xtensa_read_register (regnum + 1);
|
||||
/* Set regnum to a frame pointer of the frame being cached. */
|
||||
regnum = xtensa_scan_prologue (gdbarch, pc);
|
||||
regnum = arreg_number (gdbarch,
|
||||
gdbarch_tdep (gdbarch)->a0_base + regnum,
|
||||
cache->wd.wb);
|
||||
cache->base = get_frame_register_unsigned (this_frame, regnum);
|
||||
|
||||
/* Read PC of interrupted function from EPC1 register. */
|
||||
epc1_regnum = xtensa_find_register_by_name (gdbarch,"epc1");
|
||||
if (epc1_regnum < 0)
|
||||
error(_("Unable to read Xtensa register EPC1"));
|
||||
cache->ra = xtensa_read_register (epc1_regnum);
|
||||
cache->pc = get_frame_func (this_frame);
|
||||
}
|
||||
|
||||
|
||||
/* Skip function prologue.
|
||||
|
||||
|
|
Loading…
Reference in New Issue