2011-03-10 Maxim Grigoriev <maxim2405@gmail.com>
* xtensa-tdep.c (xtensa_c0reg_t): Update comments. (xtensa_call0_frame_cache_t): Update comments. New fields added. (xtensa_alloc_frame_cache): Add initialization for new fields. (xtensa_frame_cache): Change the way how call0_frame_cache () is called. (warning_once): New function. (xtensa_insn_kind): New item c0opc_and. (call0_classify_opcode): Add the case for AND instruction. (call0_track_op): Change arguments. New local variable litbase. Add the case to handle c0opc_and. Update algorithms for c0opc_mov, c0opc_l32r, c0opc_s32i to take into account dynamic stack adjustments in prologue. Add cases for c0opc_l32e, c0opc_s32e, c0opc_rfwo, c0opc_rfwu. (call0_analyze_prologue): Update the comments. Change arguments. Add the variety of updates to handle extended prologues, which now can conduct dynamic stack adjustments. (call0_frame_cache): Likewise. (xtensa_skip_prologue): Update call0_analyze_prologue () function call. (xtensa_gdbarch_init): Initialize xtensa_session_once_reported.
This commit is contained in:
parent
a00888a47b
commit
dbab50deda
2 changed files with 222 additions and 101 deletions
|
@ -1,3 +1,23 @@
|
||||||
|
2011-03-10 Maxim Grigoriev <maxim2405@gmail.com>
|
||||||
|
|
||||||
|
* xtensa-tdep.c (xtensa_c0reg_t): Update comments.
|
||||||
|
(xtensa_call0_frame_cache_t): Update comments. New fields added.
|
||||||
|
(xtensa_alloc_frame_cache): Add initialization for new fields.
|
||||||
|
(xtensa_frame_cache): Change the way how call0_frame_cache () is called.
|
||||||
|
(warning_once): New function.
|
||||||
|
(xtensa_insn_kind): New item c0opc_and.
|
||||||
|
(call0_classify_opcode): Add the case for AND instruction.
|
||||||
|
(call0_track_op): Change arguments. New local variable litbase. Add the
|
||||||
|
case to handle c0opc_and. Update algorithms for c0opc_mov, c0opc_l32r,
|
||||||
|
c0opc_s32i to take into account dynamic stack adjustments in prologue.
|
||||||
|
Add cases for c0opc_l32e, c0opc_s32e, c0opc_rfwo, c0opc_rfwu.
|
||||||
|
(call0_analyze_prologue): Update the comments. Change arguments.
|
||||||
|
Add the variety of updates to handle extended prologues, which now can
|
||||||
|
conduct dynamic stack adjustments.
|
||||||
|
(call0_frame_cache): Likewise.
|
||||||
|
(xtensa_skip_prologue): Update call0_analyze_prologue () function call.
|
||||||
|
(xtensa_gdbarch_init): Initialize xtensa_session_once_reported.
|
||||||
|
|
||||||
2011-03-10 Michael Snyder <msnyder@vmware.com>
|
2011-03-10 Michael Snyder <msnyder@vmware.com>
|
||||||
|
|
||||||
* tracepoint.c (cmd_qtv): Discard unused value 'packet'.
|
* tracepoint.c (cmd_qtv): Discard unused value 'packet'.
|
||||||
|
@ -57,7 +77,7 @@
|
||||||
|
|
||||||
2011-03-09 Maxim Grigoriev <maxim2405@gmail.com>
|
2011-03-09 Maxim Grigoriev <maxim2405@gmail.com>
|
||||||
|
|
||||||
* xtensa-tdep.c (xtensa_read_register: Add comment.
|
* xtensa-tdep.c (xtensa_read_register): Add comment.
|
||||||
(xtensa_write_register): Likewise.
|
(xtensa_write_register): Likewise.
|
||||||
(xtensa_hextochar): Add comment and update to match coding conventions.
|
(xtensa_hextochar): Add comment and update to match coding conventions.
|
||||||
(xtensa_frame_cache, xtensa_return_value): Follow coding conventions.
|
(xtensa_frame_cache, xtensa_return_value): Follow coding conventions.
|
||||||
|
|
|
@ -982,24 +982,30 @@ extern xtensa_isa xtensa_default_isa;
|
||||||
|
|
||||||
typedef struct xtensa_c0reg
|
typedef struct xtensa_c0reg
|
||||||
{
|
{
|
||||||
int fr_reg; /* original register from which register content
|
int fr_reg; /* original register from which register content
|
||||||
is derived, or C0_CONST, or C0_INEXP. */
|
is derived, or C0_CONST, or C0_INEXP. */
|
||||||
int fr_ofs; /* constant offset from reg, or immediate value. */
|
int fr_ofs; /* constant offset from reg, or immediate value. */
|
||||||
int to_stk; /* offset from original SP to register (4-byte
|
int to_stk; /* offset from original SP to register (4-byte aligned),
|
||||||
aligned), or C0_NOSTK if register has not
|
or C0_NOSTK if register has not been saved. */
|
||||||
been saved. */
|
|
||||||
} xtensa_c0reg_t;
|
} xtensa_c0reg_t;
|
||||||
|
|
||||||
|
|
||||||
/* Frame cache part for Call0 ABI. */
|
/* Frame cache part for Call0 ABI. */
|
||||||
typedef struct xtensa_call0_frame_cache
|
typedef struct xtensa_call0_frame_cache
|
||||||
{
|
{
|
||||||
int c0_frmsz; /* Stack frame size. */
|
int c0_frmsz; /* Stack frame size. */
|
||||||
int c0_hasfp; /* Current frame uses frame
|
int c0_hasfp; /* Current frame uses frame pointer. */
|
||||||
pointer. */
|
int fp_regnum; /* A-register used as FP. */
|
||||||
int fp_regnum; /* A-register used as FP. */
|
int c0_fp; /* Actual value of frame pointer. */
|
||||||
int c0_fp; /* Actual value of frame pointer. */
|
int c0_fpalign; /* Dinamic adjustment for the stack
|
||||||
xtensa_c0reg_t c0_rt[C0_NREGS]; /* Register tracking information. */
|
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;
|
} xtensa_call0_frame_cache_t;
|
||||||
|
|
||||||
typedef struct xtensa_frame_cache
|
typedef struct xtensa_frame_cache
|
||||||
|
@ -1040,6 +1046,9 @@ xtensa_alloc_frame_cache (int windowed)
|
||||||
cache->c0.c0_hasfp = 0;
|
cache->c0.c0_hasfp = 0;
|
||||||
cache->c0.fp_regnum = -1;
|
cache->c0.fp_regnum = -1;
|
||||||
cache->c0.c0_fp = -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++)
|
for (i = 0; i < C0_NREGS; i++)
|
||||||
{
|
{
|
||||||
|
@ -1261,8 +1270,7 @@ done:
|
||||||
|
|
||||||
static void
|
static void
|
||||||
call0_frame_cache (struct frame_info *this_frame,
|
call0_frame_cache (struct frame_info *this_frame,
|
||||||
xtensa_frame_cache_t *cache,
|
xtensa_frame_cache_t *cache, CORE_ADDR pc);
|
||||||
CORE_ADDR pc, CORE_ADDR litbase);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xtensa_window_interrupt_frame_cache (struct frame_info *this_frame,
|
xtensa_window_interrupt_frame_cache (struct frame_info *this_frame,
|
||||||
|
@ -1408,11 +1416,7 @@ xtensa_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||||
}
|
}
|
||||||
else /* Call0 framework. */
|
else /* Call0 framework. */
|
||||||
{
|
{
|
||||||
unsigned int litbase_regnum = gdbarch_tdep (gdbarch)->litbase_regnum;
|
call0_frame_cache (this_frame, cache, pc);
|
||||||
CORE_ADDR litbase = (litbase_regnum == -1)
|
|
||||||
? 0 : get_frame_register_unsigned (this_frame, litbase_regnum);
|
|
||||||
|
|
||||||
call0_frame_cache (this_frame, cache, pc, litbase);
|
|
||||||
fp_regnum = cache->c0.fp_regnum;
|
fp_regnum = cache->c0.fp_regnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1421,6 +1425,22 @@ xtensa_frame_cache (struct frame_info *this_frame, void **this_cache)
|
||||||
return cache;
|
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 inline void warning_once ()
|
||||||
|
{
|
||||||
|
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
|
static void
|
||||||
xtensa_frame_this_id (struct frame_info *this_frame,
|
xtensa_frame_this_id (struct frame_info *this_frame,
|
||||||
void **this_cache,
|
void **this_cache,
|
||||||
|
@ -2088,6 +2108,7 @@ typedef enum
|
||||||
c0opc_break, /* Debugger software breakpoints. */
|
c0opc_break, /* Debugger software breakpoints. */
|
||||||
c0opc_add, /* Adding two registers. */
|
c0opc_add, /* Adding two registers. */
|
||||||
c0opc_addi, /* Adding a register and an immediate. */
|
c0opc_addi, /* Adding a register and an immediate. */
|
||||||
|
c0opc_and, /* Bitwise "and"-ing two registers. */
|
||||||
c0opc_sub, /* Subtracting a register from a register. */
|
c0opc_sub, /* Subtracting a register from a register. */
|
||||||
c0opc_mov, /* Moving a register to a register. */
|
c0opc_mov, /* Moving a register to a register. */
|
||||||
c0opc_movi, /* Moving an immediate to a register. */
|
c0opc_movi, /* Moving an immediate to a register. */
|
||||||
|
@ -2159,6 +2180,8 @@ call0_classify_opcode (xtensa_isa isa, xtensa_opcode opc)
|
||||||
else if (strcasecmp (opcname, "add") == 0
|
else if (strcasecmp (opcname, "add") == 0
|
||||||
|| strcasecmp (opcname, "add.n") == 0)
|
|| strcasecmp (opcname, "add.n") == 0)
|
||||||
opclass = c0opc_add;
|
opclass = c0opc_add;
|
||||||
|
else if (strcasecmp (opcname, "and") == 0)
|
||||||
|
opclass = c0opc_and;
|
||||||
else if (strcasecmp (opcname, "addi") == 0
|
else if (strcasecmp (opcname, "addi") == 0
|
||||||
|| strcasecmp (opcname, "addi.n") == 0
|
|| strcasecmp (opcname, "addi.n") == 0
|
||||||
|| strcasecmp (opcname, "addmi") == 0)
|
|| strcasecmp (opcname, "addmi") == 0)
|
||||||
|
@ -2190,16 +2213,16 @@ call0_classify_opcode (xtensa_isa isa, xtensa_opcode opc)
|
||||||
be within a bundle. Updates the destination register tracking info
|
be within a bundle. Updates the destination register tracking info
|
||||||
accordingly. The pc is needed only for pc-relative load instructions
|
accordingly. The pc is needed only for pc-relative load instructions
|
||||||
(eg. l32r). The SP register number is needed to identify stores to
|
(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
|
static int
|
||||||
call0_track_op (struct gdbarch *gdbarch,
|
call0_track_op (struct gdbarch *gdbarch, xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
|
||||||
xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
|
|
||||||
xtensa_insn_kind opclass, int nods, unsigned odv[],
|
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);
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||||
unsigned litaddr, litval;
|
unsigned litbase, litaddr, litval;
|
||||||
|
|
||||||
switch (opclass)
|
switch (opclass)
|
||||||
{
|
{
|
||||||
|
@ -2224,6 +2247,39 @@ call0_track_op (struct gdbarch *gdbarch,
|
||||||
}
|
}
|
||||||
else dst[odv[0]].fr_reg = C0_INEXP;
|
else dst[odv[0]].fr_reg = C0_INEXP;
|
||||||
break;
|
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:
|
case c0opc_sub:
|
||||||
/* 3 operands: dst, src1, src2. */
|
/* 3 operands: dst, src1, src2. */
|
||||||
gdb_assert (nods == 3);
|
gdb_assert (nods == 3);
|
||||||
|
@ -2237,6 +2293,13 @@ call0_track_op (struct gdbarch *gdbarch,
|
||||||
case c0opc_mov:
|
case c0opc_mov:
|
||||||
/* 2 operands: dst, src [, src]. */
|
/* 2 operands: dst, src [, src]. */
|
||||||
gdb_assert (nods == 2);
|
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_reg = src[odv[1]].fr_reg;
|
||||||
dst[odv[0]].fr_ofs = src[odv[1]].fr_ofs;
|
dst[odv[0]].fr_ofs = src[odv[1]].fr_ofs;
|
||||||
break;
|
break;
|
||||||
|
@ -2249,6 +2312,10 @@ call0_track_op (struct gdbarch *gdbarch,
|
||||||
case c0opc_l32r:
|
case c0opc_l32r:
|
||||||
/* 2 operands: dst, literal offset. */
|
/* 2 operands: dst, literal offset. */
|
||||||
gdb_assert (nods == 2);
|
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
|
litaddr = litbase & 1
|
||||||
? (litbase & ~1) + (signed)odv[1]
|
? (litbase & ~1) + (signed)odv[1]
|
||||||
: (pc + 3 + (signed)odv[1]) & ~3;
|
: (pc + 3 + (signed)odv[1]) & ~3;
|
||||||
|
@ -2259,6 +2326,13 @@ call0_track_op (struct gdbarch *gdbarch,
|
||||||
case c0opc_s32i:
|
case c0opc_s32i:
|
||||||
/* 3 operands: value, base, offset. */
|
/* 3 operands: value, base, offset. */
|
||||||
gdb_assert (nods == 3 && spreg >= 0 && spreg < C0_NREGS);
|
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. */
|
if (src[odv[1]].fr_reg == spreg /* Store to stack frame. */
|
||||||
&& (src[odv[1]].fr_ofs & 3) == 0 /* Alignment preserved. */
|
&& (src[odv[1]].fr_ofs & 3) == 0 /* Alignment preserved. */
|
||||||
&& src[odv[0]].fr_reg >= 0 /* Value is from a register. */
|
&& src[odv[0]].fr_reg >= 0 /* Value is from a register. */
|
||||||
|
@ -2270,20 +2344,29 @@ call0_track_op (struct gdbarch *gdbarch,
|
||||||
dst[src[odv[0]].fr_reg].to_stk = src[odv[1]].fr_ofs + odv[2];
|
dst[src[odv[0]].fr_reg].to_stk = src[odv[1]].fr_ofs + odv[2];
|
||||||
}
|
}
|
||||||
break;
|
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:
|
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
|
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.
|
in the prologue up to the PC or just beyond the prologue, whichever is
|
||||||
An 'entry' instruction indicates non-Call0 ABI and the end of the prologue.
|
first. An 'entry' instruction indicates non-Call0 ABI and the end of the
|
||||||
The prologue may overlap non-prologue instructions but is guaranteed to end
|
prologue. The prologue may overlap non-prologue instructions but is
|
||||||
by the first flow-control instruction (jump, branch, call or return).
|
guaranteed to end by the first flow-control instruction (jump, branch,
|
||||||
Since an optimized function may move information around and change the
|
call or return). Since an optimized function may move information around
|
||||||
stack frame arbitrarily during the prologue, the information is guaranteed
|
and change the stack frame arbitrarily during the prologue, the information
|
||||||
valid only at the point in the function indicated by the PC.
|
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.
|
May be used to skip the prologue or identify the ABI, w/o tracking.
|
||||||
|
|
||||||
Returns: Address of first instruction after prologue, or PC (whichever
|
Returns: Address of first instruction after prologue, or PC (whichever
|
||||||
|
@ -2293,21 +2376,17 @@ call0_track_op (struct gdbarch *gdbarch,
|
||||||
pc Program counter to stop at. Use 0 to continue to end of prologue.
|
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
|
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.
|
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:
|
InOut args:
|
||||||
rt[] Array[nregs] of xtensa_c0reg structures for register tracking info.
|
cache Xtensa frame cache.
|
||||||
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).
|
|
||||||
|
|
||||||
Note that these may produce useful results even if decoding fails
|
Note that these may produce useful results even if decoding fails
|
||||||
because they begin with default assumptions that analysis may change. */
|
because they begin with default assumptions that analysis may change. */
|
||||||
|
|
||||||
static CORE_ADDR
|
static CORE_ADDR
|
||||||
call0_analyze_prologue (struct gdbarch *gdbarch,
|
call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
CORE_ADDR start, CORE_ADDR pc, CORE_ADDR litbase,
|
CORE_ADDR start, CORE_ADDR pc,
|
||||||
int nregs, xtensa_c0reg_t rt[], int *call0)
|
int nregs, xtensa_frame_cache_t *cache)
|
||||||
{
|
{
|
||||||
CORE_ADDR ia; /* Current insn address in prologue. */
|
CORE_ADDR ia; /* Current insn address in prologue. */
|
||||||
CORE_ADDR ba = 0; /* Current address at base of insn buffer. */
|
CORE_ADDR ba = 0; /* Current address at base of insn buffer. */
|
||||||
|
@ -2359,15 +2438,8 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
else
|
else
|
||||||
body_pc = min (pc, body_pc);
|
body_pc = min (pc, body_pc);
|
||||||
|
|
||||||
if (call0 != NULL)
|
cache->call0 = 1;
|
||||||
*call0 = 1;
|
rtmp = (xtensa_c0reg_t*) alloca(nregs * sizeof(xtensa_c0reg_t));
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!xtensa_default_isa)
|
if (!xtensa_default_isa)
|
||||||
xtensa_default_isa = xtensa_isa_init (0, 0);
|
xtensa_default_isa = xtensa_isa_init (0, 0);
|
||||||
|
@ -2386,9 +2458,8 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
{
|
{
|
||||||
ba = ia;
|
ba = ia;
|
||||||
bt = (ba + XTENSA_ISA_BSZ) < body_pc ? ba + XTENSA_ISA_BSZ : body_pc;
|
bt = (ba + XTENSA_ISA_BSZ) < body_pc ? ba + XTENSA_ISA_BSZ : body_pc;
|
||||||
read_memory (ba, ibuf, bt - ba);
|
if (target_read_memory (ba, ibuf, bt - ba) != 0 )
|
||||||
/* If there is a memory reading error read_memory () will report it
|
error (_("Unable to read target memory ..."));
|
||||||
and then throw an exception, stopping command execution. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode format information. */
|
/* Decode format information. */
|
||||||
|
@ -2418,7 +2489,7 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
register changes do not take effect within this bundle. */
|
register changes do not take effect within this bundle. */
|
||||||
|
|
||||||
for (j = 0; j < nregs; ++j)
|
for (j = 0; j < nregs; ++j)
|
||||||
rtmp[j] = rt[j];
|
rtmp[j] = cache->c0.c0_rt[j];
|
||||||
|
|
||||||
for (is = 0; is < islots; ++is)
|
for (is = 0; is < islots; ++is)
|
||||||
{
|
{
|
||||||
|
@ -2429,8 +2500,7 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
opc = xtensa_opcode_decode (isa, ifmt, is, slot);
|
opc = xtensa_opcode_decode (isa, ifmt, is, slot);
|
||||||
DEBUGVERB ("[call0_analyze_prologue] instr "
|
DEBUGVERB ("[call0_analyze_prologue] instr addr = 0x%08x, opc = %d\n",
|
||||||
"addr = 0x%08x, opc = %d\n",
|
|
||||||
(unsigned)ia, opc);
|
(unsigned)ia, opc);
|
||||||
if (opc == XTENSA_UNDEFINED)
|
if (opc == XTENSA_UNDEFINED)
|
||||||
opclass = c0opc_illegal;
|
opclass = c0opc_illegal;
|
||||||
|
@ -2449,23 +2519,20 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
case c0opc_uninteresting:
|
case c0opc_uninteresting:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case c0opc_flow:
|
case c0opc_flow: /* Flow control instructions stop analysis. */
|
||||||
|
case c0opc_rwxsr: /* RSR, WSR, XSR instructions stop analysis. */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
case c0opc_entry:
|
case c0opc_entry:
|
||||||
if (call0 != NULL)
|
cache->call0 = 0;
|
||||||
*call0 = 0;
|
|
||||||
ia += ilen; /* Skip over 'entry' insn. */
|
ia += ilen; /* Skip over 'entry' insn. */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (call0 != NULL)
|
cache->call0 = 1;
|
||||||
*call0 = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only expected opcodes should get this far. */
|
/* Only expected opcodes should get this far. */
|
||||||
if (rt == NULL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Extract and decode the operands. */
|
/* Extract and decode the operands. */
|
||||||
nods = xtensa_opcode_num_operands (isa, opc);
|
nods = xtensa_opcode_num_operands (isa, opc);
|
||||||
|
@ -2491,7 +2558,13 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
if (opclass == c0opc_mov && nods == 3)
|
if (opclass == c0opc_mov && nods == 3)
|
||||||
{
|
{
|
||||||
if (odv[2] == odv[1])
|
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
|
else
|
||||||
{
|
{
|
||||||
opclass = c0opc_uninteresting;
|
opclass = c0opc_uninteresting;
|
||||||
|
@ -2500,8 +2573,10 @@ call0_analyze_prologue (struct gdbarch *gdbarch,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Track register movement and modification for this operation. */
|
/* Track register movement and modification for this operation. */
|
||||||
call0_track_op (gdbarch, rt, rtmp, opclass,
|
fail = call0_track_op (gdbarch, cache->c0.c0_rt, rtmp,
|
||||||
nods, odv, ia, litbase, 1);
|
opclass, nods, odv, ia, 1, cache);
|
||||||
|
if (fail)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
@ -2516,39 +2591,38 @@ done:
|
||||||
|
|
||||||
static void
|
static void
|
||||||
call0_frame_cache (struct frame_info *this_frame,
|
call0_frame_cache (struct frame_info *this_frame,
|
||||||
xtensa_frame_cache_t *cache,
|
xtensa_frame_cache_t *cache, CORE_ADDR pc)
|
||||||
CORE_ADDR pc, CORE_ADDR litbase)
|
|
||||||
{
|
{
|
||||||
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||||
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||||
CORE_ADDR start_pc; /* The beginning of the function. */
|
CORE_ADDR start_pc; /* The beginning of the function. */
|
||||||
CORE_ADDR body_pc=UINT_MAX; /* PC, where prologue analysis stopped. */
|
CORE_ADDR body_pc=UINT_MAX; /* PC, where prologue analysis stopped. */
|
||||||
CORE_ADDR sp, fp, ra;
|
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
|
/* 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. */
|
and analyze it up to the PC or the end of the prologue. */
|
||||||
|
|
||||||
if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
|
if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
|
||||||
{
|
{
|
||||||
body_pc = call0_analyze_prologue (gdbarch, start_pc, pc, litbase,
|
body_pc = call0_analyze_prologue (gdbarch, start_pc, pc, C0_NREGS, cache);
|
||||||
C0_NREGS,
|
|
||||||
&cache->c0.c0_rt[0],
|
|
||||||
&cache->call0);
|
|
||||||
|
|
||||||
if (body_pc == XTENSA_ISA_BADPC)
|
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.
|
/* Get the frame information and FP (if used) at the current PC.
|
||||||
If PC is in the prologue, the prologue analysis is more reliable
|
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,
|
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
|
but we do know no calls have yet taken place, so we can almost
|
||||||
certainly rely on the prologue analysis. */
|
certainly rely on the prologue analysis. */
|
||||||
|
|
||||||
if (body_pc <= pc)
|
if (body_pc <= pc)
|
||||||
|
@ -2571,7 +2645,35 @@ analysis failed in this frame. GDB command execution stopped."));
|
||||||
start_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
|
/* Frame size from debug info or prologue tracking does not account for
|
||||||
alloca() and other dynamic allocations. Adjust frame size by FP - SP. */
|
alloca() and other dynamic allocations. Adjust frame size by FP - SP. */
|
||||||
|
@ -2579,8 +2681,6 @@ analysis failed in this frame. GDB command execution stopped."));
|
||||||
{
|
{
|
||||||
fp = get_frame_register_unsigned (this_frame, fp_regnum);
|
fp = get_frame_register_unsigned (this_frame, fp_regnum);
|
||||||
|
|
||||||
/* Recalculate previous SP. */
|
|
||||||
prev_sp = fp + c0_frmsz;
|
|
||||||
/* Update the stack frame size. */
|
/* Update the stack frame size. */
|
||||||
c0_frmsz += fp - sp;
|
c0_frmsz += fp - sp;
|
||||||
}
|
}
|
||||||
|
@ -2597,23 +2697,21 @@ analysis failed in this frame. GDB command execution stopped."));
|
||||||
else if (cache->c0.c0_rt[C0_RA].fr_reg == C0_CONST
|
else if (cache->c0.c0_rt[C0_RA].fr_reg == C0_CONST
|
||||||
&& cache->c0.c0_rt[C0_RA].fr_ofs == 0)
|
&& cache->c0.c0_rt[C0_RA].fr_ofs == 0)
|
||||||
{
|
{
|
||||||
/* Special case for terminating backtrace at a function that
|
/* Special case for terminating backtrace at a function that wants to
|
||||||
wants to be seen as the outermost. Such a function will
|
be seen as the outermost one. Such a function will clear it's RA (A0)
|
||||||
clear it's RA (A0) register to 0 in the prologue instead of
|
register to 0 in the prologue instead of saving its original value. */
|
||||||
saving its original value. */
|
|
||||||
ra = 0;
|
ra = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* RA was copied to another register or (before any function
|
/* RA was copied to another register or (before any function call) may
|
||||||
call) may still be in the original RA register. This is not
|
still be in the original RA register. This is not always reliable:
|
||||||
always reliable: even in a leaf function, register tracking
|
even in a leaf function, register tracking stops after prologue, and
|
||||||
stops after prologue, and even in prologue, non-prologue
|
even in prologue, non-prologue instructions (not tracked) may overwrite
|
||||||
instructions (not tracked) may overwrite RA or any register
|
RA or any register it was copied to. If likely in prologue or before
|
||||||
it was copied to. If likely in prologue or before any call,
|
any call, use retracking info and hope for the best (compiler should
|
||||||
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,
|
||||||
have saved RA in stack if not in a leaf function). If not in
|
too bad. */
|
||||||
prologue, too bad. */
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
|
@ -2631,6 +2729,7 @@ analysis failed in this frame. GDB command execution stopped."));
|
||||||
else ra = 0;
|
else ra = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finish_frame_analysis:
|
||||||
cache->pc = start_pc;
|
cache->pc = start_pc;
|
||||||
cache->ra = ra;
|
cache->ra = ra;
|
||||||
/* RA == 0 marks the outermost frame. Do not go past it. */
|
/* RA == 0 marks the outermost frame. Do not go past it. */
|
||||||
|
@ -2971,7 +3070,8 @@ xtensa_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No debug line info. Analyze prologue for Call0 or simply skip ENTRY. */
|
/* 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;
|
return body_pc != 0 ? body_pc : start_pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3122,6 +3222,7 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
||||||
|
|
||||||
/* Verify our configuration. */
|
/* Verify our configuration. */
|
||||||
xtensa_verify_config (gdbarch);
|
xtensa_verify_config (gdbarch);
|
||||||
|
xtensa_session_once_reported = 0;
|
||||||
|
|
||||||
/* Pseudo-Register read/write. */
|
/* Pseudo-Register read/write. */
|
||||||
set_gdbarch_pseudo_register_read (gdbarch, xtensa_pseudo_register_read);
|
set_gdbarch_pseudo_register_read (gdbarch, xtensa_pseudo_register_read);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue