/* Target-dependent code for the Xtensa port of GDB, the GNU debugger.
- Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011
- Free Software Foundation, Inc.
+ Copyright (C) 2003-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "dwarf2.h"
#include "dwarf2-frame.h"
#include "dwarf2loc.h"
-#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "xtensa-config.h"
-static int xtensa_debug_level = 0;
+static unsigned int xtensa_debug_level = 0;
#define DEBUGWARN(args...) \
if (xtensa_debug_level > 0) \
#define PS_WOE (1<<18)
#define PS_EXC (1<<4)
-static inline int
+static int
windowing_enabled (struct gdbarch *gdbarch, unsigned int ps)
{
/* If we know CALL0 ABI is set explicitly, say it is Call0. */
}
/* Read Xtensa register directly from the hardware. */
-static inline unsigned long
+static unsigned long
xtensa_read_register (int regnum)
{
ULONGEST value;
}
/* Write Xtensa register directly to the hardware. */
-static inline void
+static void
xtensa_write_register (int regnum, ULONGEST value)
{
regcache_raw_write_unsigned (get_current_regcache (), regnum, value);
if (tp == NULL)
{
- char *name = xmalloc (16);
+ char *name = xstrprintf ("int%d", size * 8);
tp = xmalloc (sizeof (struct ctype_cache));
tp->next = tdep->type_entries;
tdep->type_entries = tp;
tp->size = size;
-
- sprintf (name, "int%d", size * 8);
tp->virtual_type
- = arch_integer_type (gdbarch, size * 8, 1, xstrdup (name));
+ = arch_integer_type (gdbarch, size * 8, 1, name);
+ xfree (name);
}
reg->ctype = tp->virtual_type;
/* Read a tie state or mapped registers. Read the masked areas
of the registers and assemble them into a single value. */
-static void
+static enum register_status
xtensa_register_read_masked (struct regcache *regcache,
xtensa_register_t *reg, gdb_byte *buffer)
{
int r = mask->mask[i].reg_num;
if (r >= 0)
{
+ enum register_status status;
ULONGEST val;
- regcache_cooked_read_unsigned (regcache, r, &val);
+
+ status = regcache_cooked_read_unsigned (regcache, r, &val);
+ if (status != REG_VALID)
+ return status;
regval = (unsigned int) val;
}
else
buffer[i] = mem & 0xff;
mem >>= 8;
}
+
+ return REG_VALID;
}
/* Read pseudo registers. */
-static void
+static enum register_status
xtensa_pseudo_register_read (struct gdbarch *gdbarch,
struct regcache *regcache,
int regnum,
&& (regnum <= gdbarch_tdep (gdbarch)->a0_base + 15))
{
gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
+ enum register_status status;
- regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf);
+ status = regcache_raw_read (regcache,
+ gdbarch_tdep (gdbarch)->wb_regnum,
+ buf);
+ if (status != REG_VALID)
+ return status;
regnum = arreg_number (gdbarch, regnum,
extract_unsigned_integer (buf, 4, byte_order));
}
/* We can always read non-pseudo registers. */
if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch))
- regcache_raw_read (regcache, regnum, buffer);
-
+ return 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. */
buffer[1] = (gdb_byte)0;
buffer[2] = (gdb_byte)0;
buffer[3] = (gdb_byte)0;
+ return REG_VALID;
}
/* Pseudo registers. */
else if (regnum >= 0
{
warning (_("cannot read register %s"),
xtensa_register_name (gdbarch, regnum));
- return;
+ return REG_VALID;
}
}
if (flags & xtTargetFlagsUseFetchStore)
{
warning (_("cannot read register"));
- return;
+ return REG_VALID;
}
/* On some targets (esp. simulators), we can always read the reg. */
else if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
{
warning (_("cannot read register"));
- return;
+ return REG_VALID;
}
}
/* We can always read mapped registers. */
else if (type == xtRegisterTypeMapped || type == xtRegisterTypeTieState)
- {
- xtensa_register_read_masked (regcache, reg, buffer);
- return;
- }
+ return xtensa_register_read_masked (regcache, reg, buffer);
/* Assume that we can read the register. */
- regcache_raw_read (regcache, regnum, buffer);
+ return regcache_raw_read (regcache, regnum, buffer);
}
else
internal_error (__FILE__, __LINE__,
&& (regnum <= gdbarch_tdep (gdbarch)->a0_base + 15))
{
gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
- unsigned int wb;
regcache_raw_read (regcache,
gdbarch_tdep (gdbarch)->wb_regnum, buf);
_("invalid register number %d"), regnum);
}
-/* Return a character representation of a hex-decimal digit.
- The value of "xdigit" is assumed to be in a range [0..15]. */
-
-static inline
-char xtensa_hextochar (int xdigit)
-{
- return '0' + xdigit;
-}
-
static struct reggroup *xtensa_ar_reggroup;
static struct reggroup *xtensa_user_reggroup;
static struct reggroup *xtensa_vectra_reggroup;
for (i = 0; i < XTENSA_MAX_COPROCESSOR; i++)
{
- cpname[2] = xtensa_hextochar (i);
+ cpname[2] = '0' + i;
xtensa_cp[i] = reggroup_new (cpname, USER_REGGROUP);
}
}
if (group == restore_reggroup)
return (regnum < gdbarch_num_regs (gdbarch)
&& (reg->flags & SAVE_REST_FLAGS) == SAVE_REST_VALID);
- if ((cp_number = xtensa_coprocessor_register_group (group)) >= 0)
+ cp_number = xtensa_coprocessor_register_group (group);
+ if (cp_number >= 0)
return rg & (xtRegisterGroupCP0 << cp_number);
else
return 1;
typedef struct xtensa_c0reg
{
- int fr_reg; /* original register from which register content
- is derived, or C0_CONST, or C0_INEXP. */
- int fr_ofs; /* constant offset from reg, or immediate value. */
- int to_stk; /* offset from original SP to register (4-byte
- aligned), or C0_NOSTK if register has not
- been saved. */
+ int fr_reg; /* original register from which register content
+ is derived, or C0_CONST, or C0_INEXP. */
+ int fr_ofs; /* constant offset from reg, or immediate value. */
+ int to_stk; /* offset from original SP to register (4-byte aligned),
+ or C0_NOSTK if register has not been saved. */
} xtensa_c0reg_t;
-
/* Frame cache part for Call0 ABI. */
typedef struct xtensa_call0_frame_cache
{
- int c0_frmsz; /* Stack frame size. */
- int c0_hasfp; /* Current frame uses frame
- pointer. */
- int fp_regnum; /* A-register used as FP. */
- int c0_fp; /* Actual value of frame pointer. */
- xtensa_c0reg_t c0_rt[C0_NREGS]; /* Register tracking information. */
+ int c0_frmsz; /* Stack frame size. */
+ int c0_hasfp; /* Current frame uses frame pointer. */
+ int fp_regnum; /* A-register used as FP. */
+ int c0_fp; /* Actual value of frame pointer. */
+ int c0_fpalign; /* Dinamic adjustment for the stack
+ pointer. It's an AND mask. Zero,
+ if alignment was not adjusted. */
+ int c0_old_sp; /* In case of dynamic adjustment, it is
+ a register holding unaligned sp.
+ C0_INEXP, when undefined. */
+ int c0_sp_ofs; /* If "c0_old_sp" was spilled it's a
+ stack offset. C0_NOSTK otherwise. */
+
+ xtensa_c0reg_t c0_rt[C0_NREGS]; /* Register tracking information. */
} xtensa_call0_frame_cache_t;
typedef struct xtensa_frame_cache
cache->c0.c0_hasfp = 0;
cache->c0.fp_regnum = -1;
cache->c0.c0_fp = -1;
+ cache->c0.c0_fpalign = 0;
+ cache->c0.c0_old_sp = C0_INEXP;
+ cache->c0.c0_sp_ofs = C0_NOSTK;
for (i = 0; i < C0_NREGS; i++)
{
CORE_ADDR start_addr;
xtensa_isa isa;
xtensa_insnbuf ins, slot;
- char ibuf[XTENSA_ISA_BSZ];
+ gdb_byte ibuf[XTENSA_ISA_BSZ];
CORE_ADDR ia, bt, ba;
xtensa_format ifmt;
int ilen, islots, is;
static void
call0_frame_cache (struct frame_info *this_frame,
- xtensa_frame_cache_t *cache,
- CORE_ADDR pc, CORE_ADDR litbase);
+ xtensa_frame_cache_t *cache, CORE_ADDR pc);
static void
xtensa_window_interrupt_frame_cache (struct frame_info *this_frame,
}
else /* Call0 framework. */
{
- unsigned int litbase_regnum = gdbarch_tdep (gdbarch)->litbase_regnum;
- CORE_ADDR litbase = (litbase_regnum == -1)
- ? 0 : get_frame_register_unsigned (this_frame, litbase_regnum);
-
- call0_frame_cache (this_frame, cache, pc, litbase);
+ call0_frame_cache (this_frame, cache, pc);
fp_regnum = cache->c0.fp_regnum;
}
return cache;
}
+static int xtensa_session_once_reported = 1;
+
+/* Report a problem with prologue analysis while doing backtracing.
+ But, do it only once to avoid annoyng repeated messages. */
+
+static void
+warning_once (void)
+{
+ if (xtensa_session_once_reported == 0)
+ warning (_("\
+\nUnrecognised function prologue. Stack trace cannot be resolved. \
+This message will not be repeated in this session.\n"));
+
+ xtensa_session_once_reported = 1;
+}
+
+
static void
xtensa_frame_this_id (struct frame_info *this_frame,
void **this_cache,
xtensa_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
xtensa_frame_this_id,
xtensa_frame_prev_register,
NULL,
static enum return_value_convention
xtensa_return_value (struct gdbarch *gdbarch,
- struct type *func_type,
+ struct value *function,
struct type *valtype,
struct regcache *regcache,
gdb_byte *readbuf,
#define RETURN_RET goto done
xtensa_isa isa;
xtensa_insnbuf ins, slot;
- char ibuf[XTENSA_ISA_BSZ];
+ gdb_byte ibuf[XTENSA_ISA_BSZ];
CORE_ADDR ia, bt, ba;
xtensa_format ifmt;
int ilen, islots, is;
c0opc_break, /* Debugger software breakpoints. */
c0opc_add, /* Adding two registers. */
c0opc_addi, /* Adding a register and an immediate. */
+ c0opc_and, /* Bitwise "and"-ing two registers. */
c0opc_sub, /* Subtracting a register from a register. */
c0opc_mov, /* Moving a register to a register. */
c0opc_movi, /* Moving an immediate to a register. */
else if (strcasecmp (opcname, "add") == 0
|| strcasecmp (opcname, "add.n") == 0)
opclass = c0opc_add;
+ else if (strcasecmp (opcname, "and") == 0)
+ opclass = c0opc_and;
else if (strcasecmp (opcname, "addi") == 0
|| strcasecmp (opcname, "addi.n") == 0
|| strcasecmp (opcname, "addmi") == 0)
be within a bundle. Updates the destination register tracking info
accordingly. The pc is needed only for pc-relative load instructions
(eg. l32r). The SP register number is needed to identify stores to
- the stack frame. */
+ the stack frame. Returns 0, if analysis was succesfull, non-zero
+ otherwise. */
-static void
-call0_track_op (struct gdbarch *gdbarch,
- xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
+static int
+call0_track_op (struct gdbarch *gdbarch, xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
xtensa_insn_kind opclass, int nods, unsigned odv[],
- CORE_ADDR pc, CORE_ADDR litbase, int spreg)
+ CORE_ADDR pc, int spreg, xtensa_frame_cache_t *cache)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- unsigned litaddr, litval;
+ unsigned litbase, litaddr, litval;
switch (opclass)
{
}
else dst[odv[0]].fr_reg = C0_INEXP;
break;
+ case c0opc_and:
+ /* 3 operands: dst, src1, src2. */
+ gdb_assert (nods == 3);
+ if (cache->c0.c0_fpalign == 0)
+ {
+ /* Handle dynamic stack alignment. */
+ if ((src[odv[0]].fr_reg == spreg) && (src[odv[1]].fr_reg == spreg))
+ {
+ if (src[odv[2]].fr_reg == C0_CONST)
+ cache->c0.c0_fpalign = src[odv[2]].fr_ofs;
+ break;
+ }
+ else if ((src[odv[0]].fr_reg == spreg)
+ && (src[odv[2]].fr_reg == spreg))
+ {
+ if (src[odv[1]].fr_reg == C0_CONST)
+ cache->c0.c0_fpalign = src[odv[1]].fr_ofs;
+ break;
+ }
+ /* else fall through. */
+ }
+ if (src[odv[1]].fr_reg == C0_CONST)
+ {
+ dst[odv[0]].fr_reg = src[odv[2]].fr_reg;
+ dst[odv[0]].fr_ofs = src[odv[2]].fr_ofs & src[odv[1]].fr_ofs;
+ }
+ else if (src[odv[2]].fr_reg == C0_CONST)
+ {
+ dst[odv[0]].fr_reg = src[odv[1]].fr_reg;
+ dst[odv[0]].fr_ofs = src[odv[1]].fr_ofs & src[odv[2]].fr_ofs;
+ }
+ else dst[odv[0]].fr_reg = C0_INEXP;
+ break;
case c0opc_sub:
/* 3 operands: dst, src1, src2. */
gdb_assert (nods == 3);
case c0opc_mov:
/* 2 operands: dst, src [, src]. */
gdb_assert (nods == 2);
+ /* First, check if it's a special case of saving unaligned SP
+ to a spare register in case of dynamic stack adjustment.
+ But, only do it one time. The second time could be initializing
+ frame pointer. We don't want to overwrite the first one. */
+ if ((odv[1] == spreg) && (cache->c0.c0_old_sp == C0_INEXP))
+ cache->c0.c0_old_sp = odv[0];
+
dst[odv[0]].fr_reg = src[odv[1]].fr_reg;
dst[odv[0]].fr_ofs = src[odv[1]].fr_ofs;
break;
case c0opc_l32r:
/* 2 operands: dst, literal offset. */
gdb_assert (nods == 2);
+ /* litbase = xtensa_get_litbase (pc); can be also used. */
+ litbase = (gdbarch_tdep (gdbarch)->litbase_regnum == -1)
+ ? 0 : xtensa_read_register
+ (gdbarch_tdep (gdbarch)->litbase_regnum);
litaddr = litbase & 1
? (litbase & ~1) + (signed)odv[1]
: (pc + 3 + (signed)odv[1]) & ~3;
case c0opc_s32i:
/* 3 operands: value, base, offset. */
gdb_assert (nods == 3 && spreg >= 0 && spreg < C0_NREGS);
+ /* First, check if it's a spill for saved unaligned SP,
+ when dynamic stack adjustment was applied to this frame. */
+ if ((cache->c0.c0_fpalign != 0) /* Dynamic stack adjustment. */
+ && (odv[1] == spreg) /* SP usage indicates spill. */
+ && (odv[0] == cache->c0.c0_old_sp)) /* Old SP register spilled. */
+ cache->c0.c0_sp_ofs = odv[2];
+
if (src[odv[1]].fr_reg == spreg /* Store to stack frame. */
&& (src[odv[1]].fr_ofs & 3) == 0 /* Alignment preserved. */
&& src[odv[0]].fr_reg >= 0 /* Value is from a register. */
dst[src[odv[0]].fr_reg].to_stk = src[odv[1]].fr_ofs + odv[2];
}
break;
+ /* If we end up inside Window Overflow / Underflow interrupt handler
+ report an error because these handlers should have been handled
+ already in a different way. */
+ case c0opc_l32e:
+ case c0opc_s32e:
+ case c0opc_rfwo:
+ case c0opc_rfwu:
+ return 1;
default:
- gdb_assert_not_reached ("unexpected instruction kind");
+ return 1;
}
+ return 0;
}
-/* Analyze prologue of the function at start address to determine if it uses
+/* Analyze prologue of the function at start address to determine if it uses
the Call0 ABI, and if so track register moves and linear modifications
- in the prologue up to the PC or just beyond the prologue, whichever is first.
- An 'entry' instruction indicates non-Call0 ABI and the end of the prologue.
- The prologue may overlap non-prologue instructions but is guaranteed to end
- by the first flow-control instruction (jump, branch, call or return).
- Since an optimized function may move information around and change the
- stack frame arbitrarily during the prologue, the information is guaranteed
- valid only at the point in the function indicated by the PC.
+ in the prologue up to the PC or just beyond the prologue, whichever is
+ first. An 'entry' instruction indicates non-Call0 ABI and the end of the
+ prologue. The prologue may overlap non-prologue instructions but is
+ guaranteed to end by the first flow-control instruction (jump, branch,
+ call or return). Since an optimized function may move information around
+ and change the stack frame arbitrarily during the prologue, the information
+ is guaranteed valid only at the point in the function indicated by the PC.
May be used to skip the prologue or identify the ABI, w/o tracking.
Returns: Address of first instruction after prologue, or PC (whichever
pc Program counter to stop at. Use 0 to continue to end of prologue.
If 0, avoids infinite run-on in corrupt code memory by bounding
the scan to the end of the function if that can be determined.
- nregs Number of general registers to track (size of rt[] array).
+ nregs Number of general registers to track.
InOut args:
- rt[] Array[nregs] of xtensa_c0reg structures for register tracking info.
- If NULL, registers are not tracked.
- Output args:
- call0 If != NULL, *call0 is set non-zero if Call0 ABI used, else 0
- (more accurately, non-zero until 'entry' insn is encountered).
+ cache Xtensa frame cache.
Note that these may produce useful results even if decoding fails
because they begin with default assumptions that analysis may change. */
static CORE_ADDR
call0_analyze_prologue (struct gdbarch *gdbarch,
- CORE_ADDR start, CORE_ADDR pc, CORE_ADDR litbase,
- int nregs, xtensa_c0reg_t rt[], int *call0)
+ CORE_ADDR start, CORE_ADDR pc,
+ int nregs, xtensa_frame_cache_t *cache)
{
CORE_ADDR ia; /* Current insn address in prologue. */
CORE_ADDR ba = 0; /* Current address at base of insn buffer. */
CORE_ADDR bt; /* Current address at top+1 of insn buffer. */
- char ibuf[XTENSA_ISA_BSZ];/* Instruction buffer for decoding prologue. */
+ gdb_byte ibuf[XTENSA_ISA_BSZ];/* Instruction buffer for decoding prologue. */
xtensa_isa isa; /* libisa ISA handle. */
xtensa_insnbuf ins, slot; /* libisa handle to decoded insn, slot. */
xtensa_format ifmt; /* libisa instruction format. */
else
body_pc = min (pc, body_pc);
- if (call0 != NULL)
- *call0 = 1;
-
- if (rt != NULL)
- {
- rtmp = (xtensa_c0reg_t*) alloca(nregs * sizeof(xtensa_c0reg_t));
- /* rt is already initialized in xtensa_alloc_frame_cache(). */
- }
- else nregs = 0;
+ cache->call0 = 1;
+ rtmp = (xtensa_c0reg_t*) alloca(nregs * sizeof(xtensa_c0reg_t));
if (!xtensa_default_isa)
xtensa_default_isa = xtensa_isa_init (0, 0);
{
ba = ia;
bt = (ba + XTENSA_ISA_BSZ) < body_pc ? ba + XTENSA_ISA_BSZ : body_pc;
- read_memory (ba, ibuf, bt - ba);
- /* If there is a memory reading error read_memory () will report it
- and then throw an exception, stopping command execution. */
+ if (target_read_memory (ba, ibuf, bt - ba) != 0 )
+ error (_("Unable to read target memory ..."));
}
/* Decode format information. */
register changes do not take effect within this bundle. */
for (j = 0; j < nregs; ++j)
- rtmp[j] = rt[j];
+ rtmp[j] = cache->c0.c0_rt[j];
for (is = 0; is < islots; ++is)
{
goto done;
opc = xtensa_opcode_decode (isa, ifmt, is, slot);
- DEBUGVERB ("[call0_analyze_prologue] instr "
- "addr = 0x%08x, opc = %d\n",
+ DEBUGVERB ("[call0_analyze_prologue] instr addr = 0x%08x, opc = %d\n",
(unsigned)ia, opc);
if (opc == XTENSA_UNDEFINED)
opclass = c0opc_illegal;
case c0opc_uninteresting:
continue;
- case c0opc_flow:
+ case c0opc_flow: /* Flow control instructions stop analysis. */
+ case c0opc_rwxsr: /* RSR, WSR, XSR instructions stop analysis. */
goto done;
case c0opc_entry:
- if (call0 != NULL)
- *call0 = 0;
+ cache->call0 = 0;
ia += ilen; /* Skip over 'entry' insn. */
goto done;
default:
- if (call0 != NULL)
- *call0 = 1;
+ cache->call0 = 1;
}
/* Only expected opcodes should get this far. */
- if (rt == NULL)
- continue;
/* Extract and decode the operands. */
nods = xtensa_opcode_num_operands (isa, opc);
if (opclass == c0opc_mov && nods == 3)
{
if (odv[2] == odv[1])
- nods = 2;
+ {
+ nods = 2;
+ if ((odv[0] == 1) && (odv[1] != 1))
+ /* OR A1, An, An , where n != 1.
+ This means we are inside epilogue already. */
+ goto done;
+ }
else
{
opclass = c0opc_uninteresting;
}
/* Track register movement and modification for this operation. */
- call0_track_op (gdbarch, rt, rtmp, opclass,
- nods, odv, ia, litbase, 1);
+ fail = call0_track_op (gdbarch, cache->c0.c0_rt, rtmp,
+ opclass, nods, odv, ia, 1, cache);
+ if (fail)
+ goto done;
}
}
done:
static void
call0_frame_cache (struct frame_info *this_frame,
- xtensa_frame_cache_t *cache,
- CORE_ADDR pc, CORE_ADDR litbase)
+ xtensa_frame_cache_t *cache, CORE_ADDR pc)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
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;
- int fp_regnum, c0_hasfp, c0_frmsz, prev_sp, to_stk;
+ int fp_regnum = C0_SP, c0_hasfp = 0, c0_frmsz = 0, prev_sp = 0, to_stk;
+ sp = get_frame_register_unsigned
+ (this_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+ fp = sp; /* Assume FP == SP until proven otherwise. */
+
/* Find the beginning of the prologue of the function containing the PC
and analyze it up to the PC or the end of the prologue. */
if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
{
- body_pc = call0_analyze_prologue (gdbarch, start_pc, pc, litbase,
- C0_NREGS,
- &cache->c0.c0_rt[0],
- &cache->call0);
+ body_pc = call0_analyze_prologue (gdbarch, start_pc, pc, C0_NREGS, cache);
if (body_pc == XTENSA_ISA_BADPC)
- error (_("Xtensa-specific internal error: CALL0 prologue \
-analysis failed in this frame. GDB command execution stopped."));
+ {
+ warning_once ();
+ ra = 0;
+ goto finish_frame_analysis;
+ }
}
- sp = get_frame_register_unsigned
- (this_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.
If PC is in the prologue, the prologue analysis is more reliable
- than DWARF info. We don't not know for sure if PC is in the prologue,
- but we know no calls have yet taken place, so we can almost
+ than DWARF info. We don't not know for sure, if PC is in the prologue,
+ but we do know no calls have yet taken place, so we can almost
certainly rely on the prologue analysis. */
if (body_pc <= pc)
start_pc = pc;
}
- prev_sp = fp + c0_frmsz;
+ if (cache->c0.c0_fpalign)
+ {
+ /* This frame has a special prologue with a dynamic stack adjustment
+ to force an alignment, which is bigger than standard 16 bytes. */
+
+ CORE_ADDR unaligned_sp;
+
+ if (cache->c0.c0_old_sp == C0_INEXP)
+ /* This can't be. Prologue code should be consistent.
+ Unaligned stack pointer should be saved in a spare register. */
+ {
+ warning_once ();
+ ra = 0;
+ goto finish_frame_analysis;
+ }
+
+ if (cache->c0.c0_sp_ofs == C0_NOSTK)
+ /* Saved unaligned value of SP is kept in a register. */
+ unaligned_sp = get_frame_register_unsigned
+ (this_frame, gdbarch_tdep (gdbarch)->a0_base + cache->c0.c0_old_sp);
+ else
+ /* Get the value from stack. */
+ unaligned_sp = (CORE_ADDR)
+ read_memory_integer (fp + cache->c0.c0_sp_ofs, 4, byte_order);
+
+ prev_sp = unaligned_sp + c0_frmsz;
+ }
+ else
+ prev_sp = fp + c0_frmsz;
/* Frame size from debug info or prologue tracking does not account for
alloca() and other dynamic allocations. Adjust frame size by FP - SP. */
{
fp = get_frame_register_unsigned (this_frame, fp_regnum);
- /* Recalculate previous SP. */
- prev_sp = fp + c0_frmsz;
/* Update the stack frame size. */
c0_frmsz += fp - sp;
}
else if (cache->c0.c0_rt[C0_RA].fr_reg == C0_CONST
&& cache->c0.c0_rt[C0_RA].fr_ofs == 0)
{
- /* Special case for terminating backtrace at a function that
- wants to be seen as the outermost. Such a function will
- clear it's RA (A0) register to 0 in the prologue instead of
- saving its original value. */
+ /* Special case for terminating backtrace at a function that wants to
+ be seen as the outermost one. Such a function will clear it's RA (A0)
+ register to 0 in the prologue instead of saving its original value. */
ra = 0;
}
else
{
- /* RA was copied to another register or (before any function
- call) may still be in the original RA register. This is not
- always reliable: even in a leaf function, register tracking
- stops after prologue, and even in prologue, non-prologue
- instructions (not tracked) may overwrite RA or any register
- it was copied to. If likely in prologue or before any call,
- use retracking info and hope for the best (compiler should
- have saved RA in stack if not in a leaf function). If not in
- prologue, too bad. */
+ /* RA was copied to another register or (before any function call) may
+ still be in the original RA register. This is not always reliable:
+ even in a leaf function, register tracking stops after prologue, and
+ even in prologue, non-prologue instructions (not tracked) may overwrite
+ RA or any register it was copied to. If likely in prologue or before
+ any call, use retracking info and hope for the best (compiler should
+ have saved RA in stack if not in a leaf function). If not in prologue,
+ too bad. */
int i;
- for (i = 0;
- (i < C0_NREGS) &&
- (i == C0_RA || cache->c0.c0_rt[i].fr_reg != C0_RA);
+ for (i = 0;
+ (i < C0_NREGS)
+ && (i == C0_RA || cache->c0.c0_rt[i].fr_reg != C0_RA);
++i);
if (i >= C0_NREGS && cache->c0.c0_rt[C0_RA].fr_reg == C0_RA)
i = C0_RA;
else ra = 0;
}
+ finish_frame_analysis:
cache->pc = start_pc;
cache->ra = ra;
/* RA == 0 marks the outermost frame. Do not go past it. */
{
xtensa_isa isa;
xtensa_insnbuf ins, slot;
- char ibuf[XTENSA_ISA_BSZ];
+ gdb_byte ibuf[XTENSA_ISA_BSZ];
CORE_ADDR ia, bt, ba;
xtensa_format ifmt;
int ilen, islots, is;
int fail = 0;
void (*func) (struct gdbarch *, int, int, int, CORE_ADDR);
- int at, as, offset;
- int num_operands;
+ uint32_t at, as, offset;
/* WindowUnderflow12 = true, when inside _WindowUnderflow12. */
int WindowUnderflow12 = (current_pc & 0x1ff) >= 0x140;
}
/* No debug line info. Analyze prologue for Call0 or simply skip ENTRY. */
- body_pc = call0_analyze_prologue (gdbarch, start_pc, 0, 0, 0, NULL, NULL);
+ body_pc = call0_analyze_prologue (gdbarch, start_pc, 0, 0,
+ xtensa_alloc_frame_cache (0));
return body_pc != 0 ? body_pc : start_pc;
}
/* Verify our configuration. */
xtensa_verify_config (gdbarch);
+ xtensa_session_once_reported = 0;
/* Pseudo-Register read/write. */
set_gdbarch_pseudo_register_read (gdbarch, xtensa_pseudo_register_read);
gdbarch_register (bfd_arch_xtensa, xtensa_gdbarch_init, xtensa_dump_tdep);
xtensa_init_reggroups ();
- add_setshow_zinteger_cmd ("xtensa",
- class_maintenance,
- &xtensa_debug_level,
+ add_setshow_zuinteger_cmd ("xtensa",
+ class_maintenance,
+ &xtensa_debug_level,
_("Set Xtensa debugging."),
_("Show Xtensa debugging."), _("\
When non-zero, Xtensa-specific debugging is enabled. \
Can be 1, 2, 3, or 4 indicating the level of debugging."),
- NULL,
- NULL,
- &setdebuglist, &showdebuglist);
+ NULL,
+ NULL,
+ &setdebuglist, &showdebuglist);
}