* alpha-tdep.c (INSN_OPCODE, MEM_RA, MEM_RB, MEM_DISP, BR_RA)
(OPR_FUNCTION, OPR_HAS_IMMEDIATE, OPR_RA, OPR_RC, OPR_LIT): New macros. (lda_opcode, stq_opcode, bne_opcode, subq_opcode, subq_function): New constants. (alpha_heuristic_analyze_probing_loop): New function. (alpha_heuristic_frame_unwind_cache): In the prologue analysis, detect and handle cases when a stack probe loop is generated. * alpha-mdebug-tdep.c (alpha_mdebug_frameless): New function. (alpha_mdebug_max_frame_size_exceeded): New function. (alpha_mdebug_after_prologue): Use alpha_mdebug_frameless. (alpha_mdebug_frame_sniffer, alpha_mdebug_frame_base_sniffer): Return 0 when the maximum debuggable frame size has been exceeded.
This commit is contained in:
parent
e4166a49ea
commit
3a48e6ff66
@ -1,3 +1,18 @@
|
||||
2010-04-23 Jerome Guitton <guitton@adacore.com>
|
||||
|
||||
* alpha-tdep.c (INSN_OPCODE, MEM_RA, MEM_RB, MEM_DISP, BR_RA)
|
||||
(OPR_FUNCTION, OPR_HAS_IMMEDIATE, OPR_RA, OPR_RC, OPR_LIT): New macros.
|
||||
(lda_opcode, stq_opcode, bne_opcode, subq_opcode, subq_function):
|
||||
New constants.
|
||||
(alpha_heuristic_analyze_probing_loop): New function.
|
||||
(alpha_heuristic_frame_unwind_cache): In the prologue analysis, detect
|
||||
and handle cases when a stack probe loop is generated.
|
||||
* alpha-mdebug-tdep.c (alpha_mdebug_frameless): New function.
|
||||
(alpha_mdebug_max_frame_size_exceeded): New function.
|
||||
(alpha_mdebug_after_prologue): Use alpha_mdebug_frameless.
|
||||
(alpha_mdebug_frame_sniffer, alpha_mdebug_frame_base_sniffer):
|
||||
Return 0 when the maximum debuggable frame size has been exceeded.
|
||||
|
||||
2010-04-23 Joel Brobecker <brobecker@adacore.com>
|
||||
|
||||
Fix ARI warning.
|
||||
|
@ -136,6 +136,15 @@ find_proc_desc (CORE_ADDR pc)
|
||||
return proc_desc;
|
||||
}
|
||||
|
||||
/* Return a non-zero result if the function is frameless; zero otherwise. */
|
||||
|
||||
static int
|
||||
alpha_mdebug_frameless (struct mdebug_extra_func_info *proc_desc)
|
||||
{
|
||||
return (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM
|
||||
&& PROC_FRAME_OFFSET (proc_desc) == 0);
|
||||
}
|
||||
|
||||
/* This returns the PC of the first inst after the prologue. If we can't
|
||||
find the prologue, then return 0. */
|
||||
|
||||
@ -146,8 +155,7 @@ alpha_mdebug_after_prologue (CORE_ADDR pc, struct mdebug_extra_func_info *proc_d
|
||||
{
|
||||
/* If function is frameless, then we need to do it the hard way. I
|
||||
strongly suspect that frameless always means prologueless... */
|
||||
if (PROC_FRAME_REG (proc_desc) == ALPHA_SP_REGNUM
|
||||
&& PROC_FRAME_OFFSET (proc_desc) == 0)
|
||||
if (alpha_mdebug_frameless (proc_desc))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -283,6 +291,20 @@ alpha_mdebug_frame_prev_register (struct frame_info *this_frame,
|
||||
return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
|
||||
}
|
||||
|
||||
/* Return a non-zero result if the size of the stack frame exceeds the
|
||||
maximum debuggable frame size (512 Kbytes); zero otherwise. */
|
||||
|
||||
static int
|
||||
alpha_mdebug_max_frame_size_exceeded (struct mdebug_extra_func_info *proc_desc)
|
||||
{
|
||||
/* If frame offset is null, we can be in two cases: either the
|
||||
function is frameless (the stack frame is null) or its
|
||||
frame exceeds the maximum debuggable frame size (512 Kbytes). */
|
||||
|
||||
return (PROC_FRAME_OFFSET (proc_desc) == 0
|
||||
&& !alpha_mdebug_frameless (proc_desc));
|
||||
}
|
||||
|
||||
static int
|
||||
alpha_mdebug_frame_sniffer (const struct frame_unwind *self,
|
||||
struct frame_info *this_frame,
|
||||
@ -302,6 +324,11 @@ alpha_mdebug_frame_sniffer (const struct frame_unwind *self,
|
||||
if (alpha_mdebug_in_prologue (pc, proc_desc))
|
||||
return 0;
|
||||
|
||||
/* If the maximum debuggable frame size has been exceeded, the
|
||||
proc desc is bogus. Fall back on the heuristic unwinder. */
|
||||
if (alpha_mdebug_max_frame_size_exceeded (proc_desc))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -362,6 +389,11 @@ alpha_mdebug_frame_base_sniffer (struct frame_info *this_frame)
|
||||
if (proc_desc == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If the maximum debuggable frame size has been exceeded, the
|
||||
proc desc is bogus. Fall back on the heuristic unwinder. */
|
||||
if (alpha_mdebug_max_frame_size_exceeded (proc_desc))
|
||||
return 0;
|
||||
|
||||
return &alpha_mdebug_frame_base;
|
||||
}
|
||||
|
||||
|
134
gdb/alpha-tdep.c
134
gdb/alpha-tdep.c
@ -46,6 +46,36 @@
|
||||
|
||||
#include "alpha-tdep.h"
|
||||
|
||||
/* Instruction decoding. The notations for registers, immediates and
|
||||
opcodes are the same as the one used in Compaq's Alpha architecture
|
||||
handbook. */
|
||||
|
||||
#define INSN_OPCODE(insn) ((insn & 0xfc000000) >> 26)
|
||||
|
||||
/* Memory instruction format */
|
||||
#define MEM_RA(insn) ((insn & 0x03e00000) >> 21)
|
||||
#define MEM_RB(insn) ((insn & 0x001f0000) >> 16)
|
||||
#define MEM_DISP(insn) \
|
||||
(((insn & 0x8000) == 0) ? (insn & 0xffff) : -((-insn) & 0xffff))
|
||||
|
||||
static const int lda_opcode = 0x08;
|
||||
static const int stq_opcode = 0x2d;
|
||||
|
||||
/* Branch instruction format */
|
||||
#define BR_RA(insn) MEM_RA(insn)
|
||||
|
||||
static const int bne_opcode = 0x3d;
|
||||
|
||||
/* Operate instruction format */
|
||||
#define OPR_FUNCTION(insn) ((insn & 0xfe0) >> 5)
|
||||
#define OPR_HAS_IMMEDIATE(insn) ((insn & 0x1000) == 0x1000)
|
||||
#define OPR_RA(insn) MEM_RA(insn)
|
||||
#define OPR_RC(insn) ((insn & 0x1f))
|
||||
#define OPR_LIT(insn) ((insn & 0x1fe000) >> 13)
|
||||
|
||||
static const int subq_opcode = 0x10;
|
||||
static const int subq_function = 0x29;
|
||||
|
||||
|
||||
/* Return the name of the REGNO register.
|
||||
|
||||
@ -1000,6 +1030,108 @@ struct alpha_heuristic_unwind_cache
|
||||
int return_reg;
|
||||
};
|
||||
|
||||
/* If a probing loop sequence starts at PC, simulate it and compute
|
||||
FRAME_SIZE and PC after its execution. Otherwise, return with PC and
|
||||
FRAME_SIZE unchanged. */
|
||||
|
||||
static void
|
||||
alpha_heuristic_analyze_probing_loop (struct gdbarch *gdbarch, CORE_ADDR *pc,
|
||||
int *frame_size)
|
||||
{
|
||||
CORE_ADDR cur_pc = *pc;
|
||||
int cur_frame_size = *frame_size;
|
||||
int nb_of_iterations, reg_index, reg_probe;
|
||||
unsigned int insn;
|
||||
|
||||
/* The following pattern is recognized as a probing loop:
|
||||
|
||||
lda REG_INDEX,NB_OF_ITERATIONS
|
||||
lda REG_PROBE,<immediate>(sp)
|
||||
|
||||
LOOP_START:
|
||||
stq zero,<immediate>(REG_PROBE)
|
||||
subq REG_INDEX,0x1,REG_INDEX
|
||||
lda REG_PROBE,<immediate>(REG_PROBE)
|
||||
bne REG_INDEX, LOOP_START
|
||||
|
||||
lda sp,<immediate>(REG_PROBE)
|
||||
|
||||
If anything different is found, the function returns without
|
||||
changing PC and FRAME_SIZE. Otherwise, PC will point immediately
|
||||
after this sequence, and FRAME_SIZE will be updated.
|
||||
*/
|
||||
|
||||
/* lda REG_INDEX,NB_OF_ITERATIONS */
|
||||
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != lda_opcode)
|
||||
return;
|
||||
reg_index = MEM_RA (insn);
|
||||
nb_of_iterations = MEM_DISP (insn);
|
||||
|
||||
/* lda REG_PROBE,<immediate>(sp) */
|
||||
|
||||
cur_pc += ALPHA_INSN_SIZE;
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != lda_opcode
|
||||
|| MEM_RB (insn) != ALPHA_SP_REGNUM)
|
||||
return;
|
||||
reg_probe = MEM_RA (insn);
|
||||
cur_frame_size -= MEM_DISP (insn);
|
||||
|
||||
/* stq zero,<immediate>(REG_PROBE) */
|
||||
|
||||
cur_pc += ALPHA_INSN_SIZE;
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != stq_opcode
|
||||
|| MEM_RA (insn) != 0x1f
|
||||
|| MEM_RB (insn) != reg_probe)
|
||||
return;
|
||||
|
||||
/* subq REG_INDEX,0x1,REG_INDEX */
|
||||
|
||||
cur_pc += ALPHA_INSN_SIZE;
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != subq_opcode
|
||||
|| !OPR_HAS_IMMEDIATE (insn)
|
||||
|| OPR_FUNCTION (insn) != subq_function
|
||||
|| OPR_LIT(insn) != 1
|
||||
|| OPR_RA (insn) != reg_index
|
||||
|| OPR_RC (insn) != reg_index)
|
||||
return;
|
||||
|
||||
/* lda REG_PROBE,<immediate>(REG_PROBE) */
|
||||
|
||||
cur_pc += ALPHA_INSN_SIZE;
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != lda_opcode
|
||||
|| MEM_RA (insn) != reg_probe
|
||||
|| MEM_RB (insn) != reg_probe)
|
||||
return;
|
||||
cur_frame_size -= MEM_DISP (insn) * nb_of_iterations;
|
||||
|
||||
/* bne REG_INDEX, LOOP_START */
|
||||
|
||||
cur_pc += ALPHA_INSN_SIZE;
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != bne_opcode
|
||||
|| MEM_RA (insn) != reg_index)
|
||||
return;
|
||||
|
||||
/* lda sp,<immediate>(REG_PROBE) */
|
||||
|
||||
cur_pc += ALPHA_INSN_SIZE;
|
||||
insn = alpha_read_insn (gdbarch, cur_pc);
|
||||
if (INSN_OPCODE (insn) != lda_opcode
|
||||
|| MEM_RA (insn) != ALPHA_SP_REGNUM
|
||||
|| MEM_RB (insn) != reg_probe)
|
||||
return;
|
||||
cur_frame_size -= MEM_DISP (insn);
|
||||
|
||||
*pc = cur_pc;
|
||||
*frame_size = cur_frame_size;
|
||||
}
|
||||
|
||||
static struct alpha_heuristic_unwind_cache *
|
||||
alpha_heuristic_frame_unwind_cache (struct frame_info *this_frame,
|
||||
void **this_prologue_cache,
|
||||
@ -1116,6 +1248,8 @@ alpha_heuristic_frame_unwind_cache (struct frame_info *this_frame,
|
||||
frame_reg = ALPHA_GCC_FP_REGNUM;
|
||||
else if (word == 0x47fe040f) /* bis zero,sp,fp */
|
||||
frame_reg = ALPHA_GCC_FP_REGNUM;
|
||||
|
||||
alpha_heuristic_analyze_probing_loop (gdbarch, &cur_pc, &frame_size);
|
||||
}
|
||||
|
||||
/* If we haven't found a valid return address register yet, keep
|
||||
|
Loading…
Reference in New Issue
Block a user