Line 80... |
Line 80... |
#include "trad-frame.h"
|
#include "trad-frame.h"
|
|
|
#include <inttypes.h>
|
#include <inttypes.h>
|
|
|
|
|
/* Forward declarations of support functions for the architecture definition */
|
|
|
|
static unsigned long int
|
|
or1k_fetch_instruction (struct frame_info *next_frame,
|
|
CORE_ADDR addr);
|
|
static void or1k_store_instruction( struct frame_info *next_frame,
|
|
CORE_ADDR addr,
|
|
unsigned long int insn);
|
|
|
|
/* Forward declaration of support functions for frame handling */
|
|
|
|
static int or1k_frame_size (struct frame_info *next_frame,
|
|
CORE_ADDR func_start_addr);
|
|
static int or1k_frame_fp_loc (struct frame_info *next_frame,
|
|
CORE_ADDR func_start_addr);
|
|
static int or1k_frame_size_check (struct frame_info *next_frame,
|
|
CORE_ADDR func_start_addr);
|
|
static int or1k_link_address (struct frame_info *next_frame,
|
|
CORE_ADDR func_start_addr);
|
|
static int or1k_get_saved_reg (struct frame_info *next_frame,
|
|
CORE_ADDR instr_start_addr,
|
|
int *reg_offset);
|
|
static struct trad_frame_cache
|
|
*or1k_frame_unwind_cache (struct frame_info *next_frame,
|
|
void **this_prologue_cache);
|
|
static void or1k_frame_this_id (struct frame_info *next_frame,
|
|
void **this_prologue_cache,
|
|
struct frame_id *this_id);
|
|
static void or1k_frame_prev_register (struct frame_info *next_frame,
|
|
void **this_prologue_cache,
|
|
int regnum,
|
|
int *optimizedp,
|
|
enum lval_type *lvalp,
|
|
CORE_ADDR *addrp,
|
|
int *realregp,
|
|
gdb_byte *bufferp);
|
|
static CORE_ADDR
|
|
or1k_frame_base_address (struct frame_info *next_frame,
|
|
void **this_prologue_cache);
|
|
|
|
/* Forward declarations of functions which define the architecture */
|
|
|
|
static enum return_value_convention
|
|
or1k_return_value (struct gdbarch *gdbarch,
|
|
struct type *type,
|
|
struct regcache *regcache,
|
|
gdb_byte *readbuf,
|
|
const gdb_byte *writebuf);
|
|
static const gdb_byte *or1k_breakpoint_from_pc (struct gdbarch *gdbarch,
|
|
CORE_ADDR *bp_addr,
|
|
int *bp_size);
|
|
static int or1k_single_step_through_delay (struct gdbarch *gdbarch,
|
|
struct frame_info *this_frame);
|
|
static void or1k_pseudo_register_read (struct gdbarch *gdbarch,
|
|
struct regcache *regcache,
|
|
int regnum,
|
|
gdb_byte *buf);
|
|
static void or1k_pseudo_register_write (struct gdbarch *gdbarch,
|
|
struct regcache *regcache,
|
|
int regnum,
|
|
const gdb_byte *buf);
|
|
static const char *or1k_register_name (struct gdbarch *gdbarch,
|
|
int regnum);
|
|
static struct type *or1k_register_type (struct gdbarch *arch,
|
|
int regnum);
|
|
static void or1k_registers_info (struct gdbarch *gdbarch,
|
|
struct ui_file *file,
|
|
struct frame_info *frame,
|
|
int regnum,
|
|
int all);
|
|
static int or1k_register_reggroup_p (struct gdbarch *gdbarch,
|
|
int regnum,
|
|
struct reggroup *group);
|
|
static CORE_ADDR or1k_skip_prologue (struct gdbarch *gdbarch,
|
|
CORE_ADDR pc);
|
|
static CORE_ADDR or1k_frame_align (struct gdbarch *gdbarch,
|
|
CORE_ADDR sp);
|
|
static CORE_ADDR or1k_unwind_pc (struct gdbarch *gdbarch,
|
|
struct frame_info *next_frame);
|
|
static CORE_ADDR or1k_unwind_sp (struct gdbarch *gdbarch,
|
|
struct frame_info *next_frame);
|
|
static CORE_ADDR or1k_push_dummy_call (struct gdbarch *gdbarch,
|
|
struct value *function,
|
|
struct regcache *regcache,
|
|
CORE_ADDR bp_addr,
|
|
int nargs,
|
|
struct value **args,
|
|
CORE_ADDR sp,
|
|
int struct_return,
|
|
CORE_ADDR struct_addr);
|
|
static struct frame_id or1k_unwind_dummy_id (struct gdbarch *gdbarch,
|
|
struct frame_info *next_frame);
|
|
static const struct frame_unwind *
|
|
or1k_frame_sniffer (struct frame_info *next_frame);
|
|
|
|
/* Forward declaration of architecture set up functions */
|
|
|
|
static struct gdbarch *or1k_gdbarch_init (struct gdbarch_info info,
|
|
struct gdbarch_list *arches);
|
|
|
|
static void or1k_dump_tdep (struct gdbarch *gdbarch,
|
|
struct ui_file *file);
|
|
|
|
/* Forward declarations of functions which extend GDB */
|
|
|
|
static const char *or1k_spr_group_name (int group);
|
|
static char *or1k_spr_register_name (int group,
|
|
int index,
|
|
char *name);
|
|
static int or1k_groupnum_from_name (char *group_name);
|
|
static int or1k_regnum_from_name (int group,
|
|
char *name);
|
|
static int or1k_tokenize (char *str,
|
|
char **tok);
|
|
static char *or1k_parse_spr_params (char *args,
|
|
int *group,
|
|
int *index,
|
|
int is_set);
|
|
static ULONGEST or1k_read_spr (unsigned int regnum);
|
|
static void or1k_write_spr (unsigned int regnum,
|
|
ULONGEST data);
|
|
static void info_spr_command (char *args,
|
|
int from_tty);
|
|
static void or1k_spr_command (char *args,
|
|
int from_tty);
|
|
static void info_matchpoints_command (char *args,
|
|
int from_tty);
|
|
|
|
|
|
|
|
/* Support functions for the architecture definition */
|
/* Support functions for the architecture definition */
|
|
|
|
|
Line 238... |
Line 110... |
{
|
{
|
char buf[OR1K_INSTLEN];
|
char buf[OR1K_INSTLEN];
|
int status;
|
int status;
|
|
|
struct frame_info *this_frame = get_prev_frame (next_frame);
|
struct frame_info *this_frame = get_prev_frame (next_frame);
|
if (NULL != this_frame)
|
|
|
if (NULL == this_frame)
|
{
|
{
|
status = !(safe_frame_unwind_memory (this_frame, addr, buf,
|
status = read_memory_nobpt (addr, buf, OR1K_INSTLEN);
|
OR1K_INSTLEN));
|
|
}
|
}
|
else
|
else
|
{
|
{
|
status = read_memory_nobpt (addr, buf, OR1K_INSTLEN);
|
status = !(safe_frame_unwind_memory (this_frame, addr, buf,
|
|
OR1K_INSTLEN));
|
}
|
}
|
|
|
if (0 != status)
|
if (0 != status)
|
{
|
{
|
memory_error (status, addr);
|
memory_error (status, addr);
|
Line 283... |
Line 156... |
write_memory_unsigned_integer( addr, sizeof( insn ), insn );
|
write_memory_unsigned_integer( addr, sizeof( insn ), insn );
|
|
|
} /* or1k_store_instruction() */
|
} /* or1k_store_instruction() */
|
|
|
|
|
|
|
|
|
|
|
/* Support functions for frame handling */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Return the size of the new stack frame
|
|
|
|
Given the function start address, find the size of the stack frame. We are
|
|
looking for the instruction
|
|
|
|
@verbatim
|
|
l.addi r1,r1,-<frame_size>
|
|
@endverbatim
|
|
|
|
If this is not found at the start address, then this must be frameless
|
|
invocation, for which we return size 0.
|
|
|
|
@see or1k_frame_unwind_cache() for details of the OR1K prolog
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the one
|
|
THIS frame called), or NULL if this
|
|
information is not available.
|
|
@param[in] instr_addr Function start address
|
|
|
|
@return The size of the new stack frame, or zero if this is frameless */
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
|
/*!Generic function to read bits from an instruction
|
|
|
static int
|
printf style. Basic syntax
|
or1k_frame_size (struct frame_info *next_frame,
|
|
CORE_ADDR instr_addr)
|
|
{
|
|
uint32_t instr = or1k_fetch_instruction (next_frame, instr_addr);
|
|
int opcode = OR1K_OPCODE1 (instr);
|
|
int rd;
|
|
int ra;
|
|
int imm;
|
|
|
|
if (OR1K_OP_ADDI != opcode)
|
or1k_analyse_inst (inst, format, &arg1, &arg2 ...)
|
{
|
|
return 0;
|
|
}
|
|
|
|
rd = OR1K_D_REG (instr);
|
Format string can contain the following characters:
|
ra = OR1K_A_REG (instr);
|
|
imm = OR1K_IMM (instr);
|
|
|
|
if((OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra))
|
- SPACE: Ignored, just for layout
|
{
|
- 0: Match with a zero bit
|
return -imm; /* Falling stack */
|
- 1: Match with a one bit
|
}
|
- %<n>b: Match <n> bits to the next argument (n decimal)
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
} /* or1k_frame_size() */
|
|
|
|
|
If the arg corresponding to a bit field is non-null, the value will be
|
|
assigned to that argument (using NULL allows fields to be skipped).
|
|
|
/*----------------------------------------------------------------------------*/
|
Any bad string will cause a fatal error. These are constant strings, so
|
/*!Return the offset from the stack pointer of the saved FP location
|
should be correct.
|
|
|
Given the function start address, find the size of the stack frame. We are
|
The bit field must be 32 bits long. A failure here will cause a fatal error
|
looking for the instruction
|
for the same reason.
|
|
|
@verbatim
|
@note The format string is presented MS field to LS field, left to
|
l.sw <save_loc>(r1),r2
|
right. This means that it is read lowest numbered char first.
|
@endverbatim
|
|
|
|
If this is not found at the start address + 4, then this is an error.
|
@note Some of the arg fields may be populated, even if recognition
|
|
ultimately fails.
|
|
|
@see or1k_frame_unwind_cache() for details of the OR1K prolog
|
@param[in] inst The instruction to analyse
|
|
@param[in] format The format string
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the one THIS
|
@param[out] ... Argument fields
|
frame called), or NULL if this information is not
|
|
available.
|
|
@param[in] instr_addr Address where we find this instruction (function
|
|
start + OR1K_INSTLEN)
|
|
|
|
@return The offset from the stack pointer where the old frame pointer is
|
|
saved or -1 if we don't find this instruction. */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
|
@return 1 (TRUE) if the instruction matches, 0 (FALSE) otherwise. */
|
|
/*---------------------------------------------------------------------------*/
|
static int
|
static int
|
or1k_frame_fp_loc (struct frame_info *next_frame,
|
or1k_analyse_inst (uint32_t inst,
|
CORE_ADDR instr_addr)
|
const char *format,
|
|
...)
|
{
|
{
|
uint32_t instr = or1k_fetch_instruction (next_frame, instr_addr);
|
/* Break out each field in turn, validating as we go. */
|
int opcode = OR1K_OPCODE1 (instr);
|
va_list ap;
|
int ra;
|
|
int rb;
|
|
int imm;
|
|
|
|
if (OR1K_OP_SW != opcode)
|
int i;
|
{
|
int iptr = 0; /* Instruction pointer */
|
return -1;
|
|
}
|
|
|
|
ra = OR1K_A_REG (instr);
|
va_start (ap, format);
|
rb = OR1K_B_REG (instr);
|
|
imm = OR1K_IMM2 (instr);
|
|
|
|
if((OR1K_SP_REGNUM != ra) || (OR1K_FP_REGNUM != rb))
|
for (i = 0; 0 != format[i];)
|
{
|
{
|
return -1;
|
const char *start_ptr;
|
}
|
char *end_ptr;
|
|
|
return imm;
|
|
|
|
} /* or1k_frame_fp_loc() */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Check the frame size is what expected
|
|
|
|
Given the function start address, find the setting of the frame
|
|
pointer. This should choose a frame size matching that used earlier to set
|
|
the stack pointer. We look for the instruction:
|
|
|
|
@verbatim
|
|
l.addi r2,r1,<frame_size>
|
|
@endverbatim
|
|
|
|
If this is not found at the start address + 8, with the expected frame size
|
|
then this is an error.
|
|
|
|
There is no return value - the function raises an error if the instruction
|
|
is not found.
|
|
|
|
@see or1k_frame_unwind_cache() for details of the OR1K prolog
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the one THIS
|
uint32_t bits; /* Bit substring of interest */
|
frame called), or NULL if this information is not
|
uint32_t width; /* Substring width */
|
available.
|
uint32_t *arg_ptr;
|
@param[in] instr_addr Address where we find this instruction (function
|
|
start + 2*OR1K_INSTLEN)
|
|
|
|
@return The frame size found, or -1 if the instruction was not there. */
|
switch (format[i])
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
or1k_frame_size_check (struct frame_info *next_frame,
|
|
CORE_ADDR instr_addr)
|
|
{
|
{
|
uint32_t instr = or1k_fetch_instruction (next_frame, instr_addr);
|
case ' ': i++; break; /* Formatting: ignored */
|
int opcode = OR1K_OPCODE1 (instr);
|
|
int rd;
|
|
int ra;
|
|
int imm;
|
|
|
|
if (OR1K_OP_ADDI != opcode)
|
case '0': case '1': /* Constant bit field */
|
{
|
bits = (inst >> (OR1K_INSTBITLEN - iptr - 1)) & 0x1;
|
return -1;
|
|
}
|
|
|
|
rd = OR1K_D_REG (instr);
|
|
ra = OR1K_A_REG (instr);
|
|
imm = OR1K_IMM (instr);
|
|
|
|
if((OR1K_SP_REGNUM != ra) || (OR1K_FP_REGNUM != rd))
|
if ((format[i] - '0') != bits)
|
{
|
{
|
return -1;
|
return 0;
|
}
|
}
|
|
|
return imm;
|
iptr++;
|
|
i++;
|
} /* or1k_frame_size_check() */
|
break;
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!See if the link (return) address is saved as expected
|
|
|
|
Given the function start address, find the saving of the link address. The
|
|
location (as an offset from the stack pointer) should be 4 less than the
|
|
offset where the frame pointer was saved. We look for the instruction:
|
|
|
|
@verbatim
|
|
l.sw <save_loc-4>(r1),r9
|
|
@endverbatim
|
|
|
|
This instruction may be missing - leaf functions do not necessarily save
|
|
the return address on the stack.
|
|
|
|
@see or1k_frame_unwind_cache() for details of the OR1K prolog
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the one THIS
|
|
frame called), or NULL if this information is not
|
|
available.
|
|
@param[in] instr_addr Address where we find this instruction (function
|
|
start + 12)
|
|
|
|
@return The link offset if the instruction was found, -1 otherwise */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
case '%': /* Bit field */
|
or1k_link_address (struct frame_info *next_frame,
|
i++;
|
CORE_ADDR instr_addr)
|
start_ptr = &(format[i]);
|
{
|
width = strtoul (start_ptr, &end_ptr, 10);
|
uint32_t instr = or1k_fetch_instruction (next_frame, instr_addr);
|
|
int opcode = OR1K_OPCODE1 (instr);
|
|
int ra;
|
|
int rb;
|
|
int imm;
|
|
|
|
if (OR1K_OP_SW != opcode)
|
/* Check we got something, and if so skip on */
|
|
if (start_ptr == end_ptr)
|
{
|
{
|
return -1;
|
fatal ("bitstring \"%s\" at offset %d has no length field.\n",
|
|
format, i);
|
}
|
}
|
|
|
ra = OR1K_A_REG (instr);
|
i += end_ptr - start_ptr;
|
rb = OR1K_B_REG (instr);
|
|
imm = OR1K_IMM2 (instr);
|
|
|
|
if((OR1K_SP_REGNUM != ra) || (OR1K_LR_REGNUM != rb))
|
/* Look for and skip the terminating 'b'. If it's not there, we
|
|
still give a fatal error, because these are fixed strings that
|
|
just should not be wrong. */
|
|
if ('b' != format[i++])
|
{
|
{
|
return -1;
|
fatal ("bitstring \"%s\" at offset %d has no terminating 'b'.\n",
|
|
format, i);
|
}
|
}
|
|
|
return imm;
|
/* Break out the field. There is a special case with a bit width of
|
|
32. */
|
} /* or1k_link_address() */
|
if (32 == width)
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Get a saved register's details
|
|
|
|
Given an address, see if it contains an instruction to save a register with
|
|
the specified offset from the stack pointer. The locations increment by 4
|
|
from the location where the FP was saved for each callee saved register. We
|
|
look for the instruction:
|
|
|
|
@verbatim
|
|
l.sw x(r1),ry
|
|
@endverbatim
|
|
|
|
If this is found with the expected offset (x), then the register number
|
|
(y) is returned. If not -1 is returned (not a register). The register
|
|
must be one of the 10 callee saved registers (r10, r12, r14, r16, r18, r20,
|
|
r22, r24, r26, r28, r30).
|
|
|
|
@see or1k_frame_unwind_cache() for details of the OR1K prolog
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the one THIS
|
|
frame called), or NULL if this information is not
|
|
available.
|
|
@param[in] instr_addr Location of this instruction
|
|
@param[out] reg_offset Offset where the register is saved
|
|
|
|
@return The register number if this instruction is found, otherwise -1 */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static int
|
|
or1k_get_saved_reg (struct frame_info *next_frame,
|
|
CORE_ADDR instr_addr,
|
|
int *reg_offset)
|
|
{
|
{
|
uint32_t instr = or1k_fetch_instruction (next_frame, instr_addr);
|
bits = inst;
|
int opcode = OR1K_OPCODE1 (instr);
|
}
|
int ra;
|
else
|
int rb;
|
|
int imm;
|
|
|
|
if (OR1K_OP_SW != opcode)
|
|
{
|
{
|
return -1;
|
bits = (inst >> (OR1K_INSTBITLEN - iptr - width)) & ((1 << width) - 1);
|
}
|
}
|
|
|
ra = OR1K_A_REG (instr);
|
arg_ptr = va_arg (ap, uint32_t *);
|
rb = OR1K_B_REG (instr);
|
*arg_ptr = bits;
|
imm = OR1K_IMM2 (instr);
|
iptr += width;
|
|
break;
|
|
|
if(OR1K_SP_REGNUM != ra)
|
default:
|
{
|
fatal ("invalid character in bitstring \"%s\" at offset %d.\n",
|
return -1;
|
format, i);
|
|
break;
|
}
|
}
|
|
|
if ((1 == (rb % 2)) || rb < 10)
|
|
{
|
|
return -1; /* Not a callee saved register */
|
|
}
|
}
|
|
|
*reg_offset = imm;
|
/* Is the length OK? */
|
return rb;
|
gdb_assert (OR1K_INSTBITLEN == iptr);
|
|
|
} /* or1k_get_saved_reg() */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
return 1; /* We succeeded */
|
/*!Initialize a prologue (unwind) cache
|
|
|
|
Build up the information (saved registers etc) for the given frame if it
|
} /* or1k_analyse_inst () */
|
does not already exist.
|
|
|
|
The OR1K has a falling stack frame and a simple prolog. The Stack pointer
|
|
is R1 and the frame pointer R2. The frame base is therefore the address
|
|
held in R2 and the stack pointer (R1) is the frame base of the NEXT frame.
|
|
|
|
@verbatim
|
|
l.addi r1,r1,-frame_size # SP now points to end of new stack frame
|
|
l.sw save_loc(r1),r2 # old FP saved in new stack frame
|
|
l.addi r2,r1,frame_size # FP now points to base of new stack frame
|
|
l.sw save_loc-4(r1),r9 # Link (return) address
|
|
l.sw x(r1),ry # Save any callee saved regs
|
|
@endverbatim
|
|
|
|
The frame pointer is not necessarily saved right at the end of the stack
|
|
frame - OR1K saves enough space for any args to called functions right at
|
|
the end. The offsets x for the various registers saved always rise in
|
|
increments of 4, starting at save_loc+4.
|
|
|
|
This prolog is used, even for -O3 with GCC.
|
|
|
|
All this analysis must allow for the possibility that the PC is in the
|
|
middle of the prologue. Data should only be set up insofar as it has been
|
|
computed.
|
|
|
|
A suite of "helper" routines are used, allowing reuse for
|
|
or1k_skip_prologue().
|
|
|
|
Reportedly, this is only valid for frames less than 0x7fff in size.
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here,
|
|
the one THIS frame called)
|
|
@param[in,out] this_prologue_cache The prologue cache. If not supplied, we
|
|
build it.
|
|
|
|
@return The prolog cache (duplicates the return through the argument) */
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
|
/*!Analyse a l.addi instruction
|
|
|
static struct trad_frame_cache *
|
General form is:
|
or1k_frame_unwind_cache (struct frame_info *next_frame,
|
|
void **this_prologue_cache)
|
|
{
|
|
struct gdbarch *gdbarch;
|
|
struct trad_frame_cache *info;
|
|
|
|
CORE_ADDR this_pc;
|
l.addi rD,rA,I
|
CORE_ADDR this_sp;
|
|
int frame_size;
|
|
int fp_save_offset;
|
|
int tmp;
|
|
|
|
CORE_ADDR start_iaddr;
|
|
CORE_ADDR saved_regs_iaddr;
|
|
CORE_ADDR prologue_end_iaddr;
|
|
CORE_ADDR end_iaddr;
|
|
|
|
int regnum;
|
Makes use of the generic analysis function (@see or1k_analyse_inst ()).
|
|
|
/* Nothing to do if we already have this info */
|
@param[in] inst The instruction to analyse.
|
if (NULL != *this_prologue_cache)
|
@param[out] rd_ptr Pointer to the rD value.
|
{
|
@param[out] ra_ptr Pointer to the rA value.
|
return *this_prologue_cache;
|
@param[out] simm_ptr Pointer to the signed immediate value.
|
}
|
|
|
|
gdbarch = get_frame_arch (next_frame);
|
|
|
|
/* Get a new prologue cache and populate it with default values */
|
@return 1 (TRUE) if the instruction matches, 0 (FALSE) otherwise. */
|
info = trad_frame_cache_zalloc (next_frame);
|
/*---------------------------------------------------------------------------*/
|
*this_prologue_cache = info;
|
static int
|
|
or1k_analyse_l_addi (uint32_t inst,
|
/* Find the start address of THIS function (which is a NORMAL frame, even if
|
unsigned int *rd_ptr,
|
the NEXT frame is the sentinel frame) and the end of its prologue. */
|
unsigned int *ra_ptr,
|
start_iaddr = frame_func_unwind (next_frame, NORMAL_FRAME);
|
int *simm_ptr)
|
prologue_end_iaddr = skip_prologue_using_sal (start_iaddr);
|
|
|
|
/* Return early if GDB couldn't find the function. */
|
|
if (start_iaddr == 0)
|
|
{
|
|
return info;
|
|
}
|
|
|
|
/* Unwind key registers for THIS frame. */
|
|
this_pc = or1k_unwind_pc (gdbarch, next_frame);
|
|
this_sp = or1k_unwind_sp (gdbarch, next_frame);
|
|
|
|
/* The frame base of THIS frame is its stack pointer. This is the same
|
|
whether we are frameless or not. */
|
|
trad_frame_set_this_base (info, this_sp);
|
|
|
|
/* We should only examine code that is in the prologue and which has been
|
|
executed. This is all code up to (but not including) end_iaddr. */
|
|
end_iaddr = (this_pc > prologue_end_iaddr) ? prologue_end_iaddr : this_pc;
|
|
|
|
/* The default is to find the PC of the PREVIOUS frame in the link register
|
|
of this frame. This may be changed if we find the link register was saved
|
|
on the stack. */
|
|
trad_frame_set_reg_realreg (info, OR1K_NPC_REGNUM, OR1K_LR_REGNUM);
|
|
|
|
/* All the following analysis only occurs if we are in the prologue and have
|
|
executed the code. Get THIS frame size (which implies framelessness if
|
|
zero) */
|
|
|
|
if (end_iaddr > start_iaddr)
|
|
{
|
|
frame_size = or1k_frame_size (next_frame, start_iaddr);
|
|
}
|
|
else
|
|
{
|
|
frame_size = 0;
|
|
}
|
|
|
|
/* If we are not frameless, check the other standard components are present
|
|
as expected */
|
|
if ((0 != frame_size) && (end_iaddr > (start_iaddr + OR1K_INSTLEN)))
|
|
{
|
|
int i;
|
|
|
|
/* If we are not frameless, the frame pointer of the PREVIOUS frame can
|
|
be found at offset fp_save_offset from the stack pointer in THIS
|
|
frame. */
|
|
fp_save_offset = or1k_frame_fp_loc (next_frame,
|
|
start_iaddr + OR1K_INSTLEN);
|
|
if (-1 == fp_save_offset)
|
|
{
|
|
error ("or1k_frame_unwind_cache: "
|
|
"invalid frame pointer save instruction at address %08llx\n",
|
|
(long long unsigned int)(ULONGEST)(start_iaddr + OR1K_INSTLEN));
|
|
}
|
|
else
|
|
{
|
{
|
trad_frame_set_reg_addr (info, OR1K_FP_REGNUM,
|
/* Instruction fields */
|
this_sp + fp_save_offset);
|
uint32_t rd, ra, i;
|
}
|
|
|
|
/* The frame pointer should be set up to match the allocated stack
|
if (or1k_analyse_inst (inst, "10 0111 %5b %5b %16b", &rd, &ra, &i))
|
size */
|
|
if (end_iaddr > (start_iaddr + (2 * OR1K_INSTLEN)))
|
|
{
|
{
|
tmp = or1k_frame_size_check (next_frame,
|
/* Found it. Construct the result fields */
|
start_iaddr + (2 * OR1K_INSTLEN));
|
*rd_ptr = (unsigned int) rd;
|
|
*ra_ptr = (unsigned int) ra;
|
|
*simm_ptr = (int) (((i & 0x8000) == 0x8000) ? 0xffff0000 | i : i);
|
|
|
if (-1 == tmp)
|
return 1; /* Success */
|
{
|
|
error ("or1k_frame_unwind_cache: "
|
|
"no frame pointer set up instruction at address %08llx\n",
|
|
(long long unsigned int)(ULONGEST)(start_iaddr + (2 * OR1K_INSTLEN)));
|
|
}
|
|
else if (frame_size != tmp)
|
|
{
|
|
error ("or1k_frame_unwind_cache: "
|
|
"frame pointer set to wrong size at address %08llx: "
|
|
"expected %d, got %d\n",
|
|
(long long unsigned int)(ULONGEST)(start_iaddr + (2* OR1K_INSTLEN)), frame_size,
|
|
tmp);
|
|
}
|
|
else
|
|
{
|
|
/* If we have got this far, the stack pointer of the PREVIOUS
|
|
frame is the frame pointer of THIS frame. */
|
|
trad_frame_set_reg_realreg (info, OR1K_SP_REGNUM, OR1K_FP_REGNUM);
|
|
}
|
|
}
|
|
/* If the link register is saved in the THIS frame, it holds the value
|
|
of the PC in the PREVIOUS frame. This overwrites the previous
|
|
information about finding the PC in the link register. */
|
|
if (end_iaddr > (start_iaddr + (2 * OR1K_INSTLEN)))
|
|
{
|
|
tmp = or1k_link_address (next_frame,
|
|
start_iaddr + (3 * OR1K_INSTLEN));
|
|
if ((-1 != tmp) && (tmp == (fp_save_offset - OR1K_INSTLEN)))
|
|
{
|
|
trad_frame_set_reg_addr (info, OR1K_LR_REGNUM, this_sp + tmp);
|
|
trad_frame_set_reg_addr (info, OR1K_NPC_REGNUM, this_sp + tmp);
|
|
saved_regs_iaddr = start_iaddr + (3 * OR1K_INSTLEN);
|
|
}
|
}
|
else
|
else
|
{
|
{
|
saved_regs_iaddr = start_iaddr + (2 * OR1K_INSTLEN);
|
return 0; /* Failure */
|
}
|
|
|
|
/* Retrieve any saved register information */
|
|
for (i = OR1K_INSTLEN;
|
|
saved_regs_iaddr + i < end_iaddr;
|
|
i += OR1K_INSTLEN)
|
|
{
|
|
regnum = or1k_get_saved_reg (next_frame, saved_regs_iaddr + i,
|
|
&tmp);
|
|
|
|
if ((regnum < 0) || (tmp != (fp_save_offset + i)))
|
|
{
|
|
break; /* End of register saves */
|
|
}
|
}
|
|
} /* or1k_analyse_l_addi () */
|
|
|
/* The register in the PREVIOUS frame can be found at this
|
|
location in THIS frame */
|
|
trad_frame_set_reg_addr (info, regnum,
|
|
this_sp + fp_save_offset + i);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Build the frame ID */
|
|
trad_frame_set_id (info, frame_id_build (this_sp, start_iaddr));
|
|
|
|
return info;
|
/*---------------------------------------------------------------------------*/
|
|
/*!Analyse a l.sw instruction
|
|
|
} /* or1k_frame_unwind_cache() */
|
General form is:
|
|
|
|
l.sw I(rA),rB
|
|
|
/*----------------------------------------------------------------------------*/
|
Makes use of the generic analysis function (@see or1k_analyse_inst ()).
|
/*!Find the frame ID of this frame
|
|
|
|
Given a GDB frame (called by THIS frame), determine the address of oru
|
@param[in] inst The instruction to analyse.
|
frame and from this create a new GDB frame struct. The info required is
|
@param[out] simm_ptr Pointer to the signed immediate value.
|
obtained from the prologue cache for THIS frame.
|
@param[out] ra_ptr Pointer to the rA value.
|
|
@param[out] rb_ptr Pointer to the rB value.
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the
|
|
one THIS frame called)
|
|
@param[in] this_prologue_cache Any cached prologue for THIS function.
|
|
@param[out] this_id Frame ID of our own frame.
|
|
|
|
@return Frame ID for THIS frame */
|
@return 1 (TRUE) if the instruction matches, 0 (FALSE) otherwise. */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
|
static int
|
static void
|
or1k_analyse_l_sw (uint32_t inst,
|
or1k_frame_this_id (struct frame_info *next_frame,
|
int *simm_ptr,
|
void **this_prologue_cache,
|
unsigned int *ra_ptr,
|
struct frame_id *this_id)
|
unsigned int *rb_ptr)
|
{
|
{
|
struct trad_frame_cache *info =
|
/* Instruction fields */
|
or1k_frame_unwind_cache (next_frame, this_prologue_cache);
|
uint32_t ihi, ilo, ra, rb;
|
|
|
trad_frame_get_id (info, this_id);
|
if (or1k_analyse_inst (inst, "11 0101 %5b %5b %5b %11b", &ihi, &ra, &rb,
|
|
&ilo))
|
|
|
} /* or1k_frame_this_id() */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Get a register from THIS frame
|
|
|
|
Given a pointer to the NEXT frame, return the details of a register in the
|
|
PREVIOUS frame.
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the
|
|
one THIS frame called)
|
|
@param[in] this_prologue_cache Any cached prologue associated with THIS
|
|
frame, which may therefore tell us about
|
|
registers in the PREVIOUS frame.
|
|
@param[in] regnum The register of interest in the PREVIOUS
|
|
frame
|
|
@param[out] optimizedp True (1) if the register has been
|
|
optimized out.
|
|
@param[out] lvalp What sort of l-value (if any) does the
|
|
register represent
|
|
@param[out] addrp Address in THIS frame where the register's
|
|
value may be found (-1 if not available)
|
|
@param[out] realregp Register in this frame where the
|
|
register's value may be found (-1 if not
|
|
available)
|
|
@param[out] bufferp If non-NULL, buffer where the value held
|
|
in the register may be put */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
or1k_frame_prev_register (struct frame_info *next_frame,
|
|
void **this_prologue_cache,
|
|
int regnum,
|
|
int *optimizedp,
|
|
enum lval_type *lvalp,
|
|
CORE_ADDR *addrp,
|
|
int *realregp,
|
|
gdb_byte *bufferp)
|
|
{
|
{
|
struct trad_frame_cache *info =
|
/* Found it. Construct the result fields */
|
or1k_frame_unwind_cache (next_frame, this_prologue_cache);
|
*simm_ptr = (int) ((ihi << 11) | ilo);
|
|
*simm_ptr |= ((ihi & 0x10) == 0x10) ? 0xffff0000 : 0;
|
trad_frame_get_register (info, next_frame, regnum, optimizedp, lvalp, addrp,
|
|
realregp, bufferp);
|
|
|
|
} /* or1k_frame_prev_register() */
|
*ra_ptr = (unsigned int) ra;
|
|
*rb_ptr = (unsigned int) rb;
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Return the base address of the frame
|
|
|
|
The commenting in the GDB source code could mean our stack pointer or our
|
|
frame pointer, since we have a falling stack, but index within the frame
|
|
using negative offsets from the FP.
|
|
|
|
This seems to be the function used to determine the value of $fp, but the
|
return 1; /* Success */
|
value required seems to be the stack pointer, so we return that, even if
|
}
|
the value of $fp will be wrong.
|
else
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the
|
|
one THIS frame called)
|
|
@param[in] this_prologue_cache Any cached prologue for THIS function.
|
|
|
|
@return The frame base address */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static CORE_ADDR
|
|
or1k_frame_base_address (struct frame_info *next_frame,
|
|
void **this_prologue_cache)
|
|
{
|
{
|
return frame_unwind_register_unsigned (next_frame, OR1K_SP_REGNUM);
|
return 0; /* Failure */
|
|
}
|
} /* or1k_frame_base_address() */
|
} /* or1k_analyse_l_sw () */
|
|
|
|
|
|
|
|
|
/* Functions defining the architecture */
|
/* Functions defining the architecture */
|
Line 1299... |
Line 785... |
|
|
@see For details of the stack frame, see the function
|
@see For details of the stack frame, see the function
|
or1k_frame_unwind_cache().
|
or1k_frame_unwind_cache().
|
|
|
This function reuses the helper functions from or1k_frame_unwind_cache() to
|
This function reuses the helper functions from or1k_frame_unwind_cache() to
|
locate the various parts of the prolog.
|
locate the various parts of the prolog, any or all of which may be missing.
|
|
|
This is very tricky. Essentially we look for the parts of a prolog. If we
|
|
get a mismatch, we never know if it is because we are not in prolog, or
|
|
because the prolog is broken.
|
|
|
|
@param[in] gdbarch The GDB architecture being used
|
@param[in] gdbarch The GDB architecture being used
|
@param[in] pc Current program counter
|
@param[in] pc Current program counter
|
|
|
@return The address of the end of the prolog if the PC is in a function
|
@return The address of the end of the prolog if the PC is in a function
|
prologue, otherwise the input address. */
|
prologue, otherwise the input address. */
|
/*--------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
|
|
static CORE_ADDR
|
static CORE_ADDR
|
or1k_skip_prologue (struct gdbarch *gdbarch,
|
or1k_skip_prologue (struct gdbarch *gdbarch,
|
CORE_ADDR pc)
|
CORE_ADDR pc)
|
{
|
{
|
enum {
|
CORE_ADDR addr;
|
OR1K_FRAME_SIZE,
|
uint32_t inst;
|
OR1K_FP_SAVED,
|
|
OR1K_NEW_FP,
|
|
OR1K_LR_SAVE,
|
|
OR1K_REG_SAVE,
|
|
OR1K_NO_PROLOGUE
|
|
} start_pos = OR1K_NO_PROLOGUE;
|
|
|
|
CORE_ADDR addr = pc;
|
|
int frame_size;
|
|
int fp_save_offset;
|
|
int tmp;
|
|
int i;
|
|
|
|
CORE_ADDR start_addr;
|
unsigned int ra, rb, rd; /* For instruction analysis */
|
CORE_ADDR end_addr;
|
int simm;
|
|
|
|
int frame_size = 0;
|
|
|
/* Try using SAL first */
|
/* Try using SAL first if we have symbolic information available. */
|
if (find_pc_partial_function (pc, NULL, &start_addr, &end_addr))
|
if (find_pc_partial_function (pc, NULL, NULL, NULL))
|
{
|
{
|
CORE_ADDR prologue_end = skip_prologue_using_sal( pc );
|
CORE_ADDR prologue_end = skip_prologue_using_sal( pc );
|
|
|
if (prologue_end > pc)
|
return (prologue_end > pc) ? prologue_end : pc;
|
{
|
|
return prologue_end;
|
|
}
|
|
else
|
|
{
|
|
return pc;
|
|
}
|
|
}
|
}
|
|
|
frame_size = or1k_frame_size (NULL, addr);
|
/* Look to see if we can find any of the standard prologue sequence. All
|
|
quite difficult, since any or all of it may be missing. So this is just a
|
|
best guess! */
|
|
addr = pc; /* Where we have got to */
|
|
inst = or1k_fetch_instruction (NULL, addr);
|
|
|
if (0 != frame_size)
|
/* Look for the new stack pointer being set up. */
|
|
if (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
|
|
(OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
|
|
(simm < 0) && (0 == (simm % 4)))
|
{
|
{
|
/* We seem to have the start of a prolog */
|
frame_size = -simm;
|
start_pos = OR1K_FRAME_SIZE;
|
|
addr += OR1K_INSTLEN;
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (NULL, addr);
|
}
|
}
|
|
|
/* Look for the previous frame pointer being saved. If we are in a frame,
|
/* Look for the frame pointer being manipulated. */
|
then this must be here. */
|
if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
|
fp_save_offset = or1k_frame_fp_loc (NULL, addr);
|
(OR1K_SP_REGNUM == ra) && (OR1K_FP_REGNUM == rb) &&
|
|
(simm >= 0) && (0 == (simm % 4)))
|
switch (start_pos)
|
|
{
|
|
case OR1K_FRAME_SIZE:
|
|
if (-1 == fp_save_offset)
|
|
{
|
|
error ("or1k_skip_prolog: "
|
|
"old frame pointer not saved at address %08llx: giving up\n",
|
|
(long long unsigned int)(ULONGEST)addr);
|
|
}
|
|
else
|
|
{
|
{
|
addr += OR1K_INSTLEN;
|
addr += OR1K_INSTLEN;
|
}
|
inst = or1k_fetch_instruction (NULL, addr);
|
|
|
break;
|
gdb_assert (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
|
|
(OR1K_FP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
|
|
(simm == frame_size));
|
|
|
default:
|
|
start_pos = OR1K_FP_SAVED;
|
|
addr += OR1K_INSTLEN;
|
addr += OR1K_INSTLEN;
|
break;
|
inst = or1k_fetch_instruction (NULL, addr);
|
}
|
}
|
|
|
/* Look for new FP being set up. This must match the frame_size if that is
|
/* Look for the link register being saved */
|
known. */
|
if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
|
tmp = or1k_frame_size_check (NULL, addr);
|
(OR1K_SP_REGNUM == ra) && (OR1K_LR_REGNUM == rb) &&
|
switch (start_pos)
|
(simm >= 0) && (0 == (simm % 4)))
|
{
|
|
case OR1K_FRAME_SIZE:
|
|
if (frame_size != tmp)
|
|
{
|
|
error ("or1k_skip_prolog: "
|
|
"frame pointer set to wrong size at address %08llx: "
|
|
"expected %d, got %d\n", (long long unsigned int)(ULONGEST)addr, frame_size, tmp);
|
|
}
|
|
else
|
|
{
|
{
|
addr += OR1K_INSTLEN;
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (NULL, addr);
|
}
|
}
|
|
|
break;
|
/* Look for callee-saved register being saved. The register must be one
|
|
of the 10 callee saved registers (r10, r12, r14, r16, r18, r20, r22,
|
case OR1K_FP_SAVED:
|
r24, r26, r28, r30).*/
|
if (-1 == tmp)
|
while (1)
|
{
|
{
|
error ("or1k_skip_prolog: "
|
if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
|
"no frame pointer set up instruction at address %08llx\n",
|
(OR1K_SP_REGNUM == ra) && (rb >= OR1K_FIRST_SAVED_REGNUM) &&
|
(long long unsigned int)(ULONGEST)addr);
|
(0 == rb % 2) && (simm >= 0) && (0 == (simm % 4)))
|
}
|
|
else
|
|
{
|
{
|
addr += OR1K_INSTLEN;
|
addr += OR1K_INSTLEN;
|
}
|
inst = or1k_fetch_instruction (NULL, addr);
|
|
|
break;
|
|
|
|
default:
|
|
if (-1 != tmp)
|
|
{
|
|
start_pos = OR1K_NEW_FP;
|
|
addr += OR1K_INSTLEN;
|
|
}
|
|
}
|
|
|
|
/* Look for the link register being saved. If we are in a prolog sequence,
|
|
and is there then it should save to a particular location. */
|
|
tmp = or1k_link_address (NULL, addr);
|
|
switch (start_pos)
|
|
{
|
|
case OR1K_FRAME_SIZE:
|
|
case OR1K_FP_SAVED:
|
|
if ((-1 != tmp) && (tmp != fp_save_offset - OR1K_INSTLEN))
|
|
{
|
|
error ("or1k_skip_prolog: "
|
|
"link address saved to wrong offset at address %08llx: "
|
|
"expected %d, got %d\n", (long long unsigned int)(ULONGEST)addr,
|
|
fp_save_offset - OR1K_INSTLEN, tmp);
|
|
}
|
|
else
|
|
{
|
|
addr += OR1K_INSTLEN;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
if (-1 != tmp)
|
|
{
|
|
start_pos = OR1K_LR_SAVE;
|
|
addr += OR1K_INSTLEN;
|
|
}
|
|
}
|
|
|
|
/* Skip saved registers */
|
|
for (i = 0;; i += OR1K_INSTLEN)
|
|
{
|
|
int regnum = or1k_get_saved_reg (NULL, addr, &tmp);
|
|
|
|
switch (start_pos)
|
|
{
|
|
case OR1K_FRAME_SIZE:
|
|
case OR1K_FP_SAVED:
|
|
if (-1 != regnum)
|
|
{
|
|
if (tmp != fp_save_offset + ((i - 1) * OR1K_INSTLEN))
|
|
{
|
|
error ("or1k_skip_prolog: callee register saved to wrong "
|
|
"offset at address %08llx: "
|
|
"expected %d, got %d\n", (long long unsigned int)(ULONGEST)addr,
|
|
fp_save_offset + ((i - 1) * OR1K_INSTLEN), tmp);
|
|
}
|
|
else
|
|
{
|
|
addr += 4;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return addr;
|
|
}
|
|
|
|
break;
|
|
|
|
case OR1K_NEW_FP:
|
|
case OR1K_LR_SAVE:
|
|
case OR1K_REG_SAVE:
|
|
if (-1 != regnum)
|
|
{
|
|
addr += 4;
|
|
}
|
}
|
else
|
else
|
{
|
{
|
|
/* Nothing else to look for. We have found the end of the prologue. */
|
return addr;
|
return addr;
|
}
|
}
|
|
|
default:
|
|
if (-1 != regnum)
|
|
{
|
|
start_pos = OR1K_REG_SAVE;
|
|
addr += 4;
|
|
}
|
|
else
|
|
{
|
|
return pc; /* Not in a prolog */
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
}
|
} /* or1k_skip_prologue() */
|
} /* or1k_skip_prologue() */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
Line 1549... |
Line 912... |
|
|
static CORE_ADDR
|
static CORE_ADDR
|
or1k_unwind_pc (struct gdbarch *gdbarch,
|
or1k_unwind_pc (struct gdbarch *gdbarch,
|
struct frame_info *next_frame)
|
struct frame_info *next_frame)
|
{
|
{
|
return frame_unwind_register_unsigned (next_frame, OR1K_NPC_REGNUM);
|
CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, OR1K_NPC_REGNUM);
|
|
|
|
return pc;
|
|
|
} /* or1k_unwind_pc() */
|
} /* or1k_unwind_pc() */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
Line 1569... |
Line 934... |
|
|
static CORE_ADDR
|
static CORE_ADDR
|
or1k_unwind_sp (struct gdbarch *gdbarch,
|
or1k_unwind_sp (struct gdbarch *gdbarch,
|
struct frame_info *next_frame)
|
struct frame_info *next_frame)
|
{
|
{
|
return frame_unwind_register_unsigned (next_frame, OR1K_SP_REGNUM);
|
CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, OR1K_SP_REGNUM);
|
|
|
|
return sp;
|
|
|
} /* or1k_unwind_sp() */
|
} /* or1k_unwind_sp() */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
Line 1795... |
Line 1162... |
}
|
}
|
|
|
} /* or1k_unwind_dummy_id() */
|
} /* or1k_unwind_dummy_id() */
|
|
|
|
|
|
|
|
|
|
|
|
/* Support functions for frame handling */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Initialize a prologue (unwind) cache
|
|
|
|
Build up the information (saved registers etc) for the given frame if it
|
|
does not already exist.
|
|
|
|
STACK FORMAT
|
|
============
|
|
|
|
The OR1K has a falling stack frame and a simple prolog. The Stack pointer
|
|
is R1 and the frame pointer R2. The frame base is therefore the address
|
|
held in R2 and the stack pointer (R1) is the frame base of the NEXT frame.
|
|
|
|
@verbatim
|
|
l.addi r1,r1,-frame_size # SP now points to end of new stack frame
|
|
@endverbatim
|
|
|
|
The stack pointer may not be set up in a frameless function (e.g. a simple
|
|
leaf function).
|
|
|
|
@verbatim
|
|
l.sw fp_loc(r1),r2 # old FP saved in new stack frame
|
|
l.addi r2,r1,frame_size # FP now points to base of new stack frame
|
|
@endverbatim
|
|
|
|
The frame pointer is not necessarily saved right at the end of the stack
|
|
frame - OR1K saves enough space for any args to called functions right at
|
|
the end (this is a difference from the Architecture Manual).
|
|
|
|
@verbatim
|
|
l.sw lr_loc(r1),r9 # Link (return) address
|
|
@endverbatim
|
|
|
|
The link register is usally saved at fp_loc - 4. It may not be saved at all
|
|
in a leaf function.
|
|
|
|
@verbatim
|
|
l.sw reg_loc(r1),ry # Save any callee saved regs
|
|
@endverbatim
|
|
|
|
The offsets x for the callee saved registers generally (always?) rise in
|
|
increments of 4, starting at fp_loc + 4. If the frame pointer is omitted
|
|
(an option to GCC), then it may not be saved at all. There may be no callee
|
|
saved registers.
|
|
|
|
So in summary none of this may be present. However what is present seems
|
|
always to follow this fixed order, and occur before any substantive code
|
|
(it is possible for GCC to have more flexible scheduling of the prologue,
|
|
but this does not seem to occur for OR1K).
|
|
|
|
ANALYSIS
|
|
========
|
|
|
|
This prolog is used, even for -O3 with GCC.
|
|
|
|
All this analysis must allow for the possibility that the PC is in the
|
|
middle of the prologue. Data should only be set up insofar as it has been
|
|
computed.
|
|
|
|
A suite of "helper" routines are used, allowing reuse for
|
|
or1k_skip_prologue().
|
|
|
|
Reportedly, this is only valid for frames less than 0x7fff in size.
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here,
|
|
the one THIS frame called)
|
|
@param[in,out] this_prologue_cache The prologue cache. If not supplied, we
|
|
build it.
|
|
|
|
@return The prolog cache (duplicates the return through the argument) */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static struct trad_frame_cache *
|
|
or1k_frame_unwind_cache (struct frame_info *next_frame,
|
|
void **this_prologue_cache)
|
|
{
|
|
struct gdbarch *gdbarch;
|
|
struct trad_frame_cache *info;
|
|
|
|
CORE_ADDR this_pc;
|
|
CORE_ADDR this_sp;
|
|
int frame_size = 0;
|
|
|
|
CORE_ADDR start_addr;
|
|
CORE_ADDR end_addr;
|
|
|
|
/* Nothing to do if we already have this info */
|
|
if (NULL != *this_prologue_cache)
|
|
{
|
|
return *this_prologue_cache;
|
|
}
|
|
|
|
/* Get a new prologue cache and populate it with default values */
|
|
info = trad_frame_cache_zalloc (next_frame);
|
|
*this_prologue_cache = info;
|
|
|
|
/* Find the start address of THIS function (which is a NORMAL frame, even if
|
|
the NEXT frame is the sentinel frame) and the end of its prologue. */
|
|
start_addr = frame_func_unwind (next_frame, NORMAL_FRAME);
|
|
|
|
/* Return early if GDB couldn't find the function. */
|
|
if (start_addr == 0)
|
|
{
|
|
return info;
|
|
}
|
|
|
|
/* Unwind key registers for THIS frame. */
|
|
gdbarch = get_frame_arch (next_frame);
|
|
this_pc = or1k_unwind_pc (gdbarch, next_frame);
|
|
this_sp = or1k_unwind_sp (gdbarch, next_frame);
|
|
|
|
/* The frame base of THIS frame is its stack pointer. This is the same
|
|
whether we are frameless or not. */
|
|
trad_frame_set_this_base (info, this_sp);
|
|
|
|
/* The default is to find the PC of the PREVIOUS frame in the link register
|
|
of this frame. This may be changed if we find the link register was saved
|
|
on the stack. */
|
|
trad_frame_set_reg_realreg (info, OR1K_NPC_REGNUM, OR1K_LR_REGNUM);
|
|
|
|
/* We should only examine code that is in the prologue and which has been
|
|
executed. This is all code up to (but not including) end_addr or the PC,
|
|
whichever is first. */
|
|
end_addr = or1k_skip_prologue (gdbarch, start_addr);
|
|
end_addr = (this_pc > end_addr) ? end_addr : this_pc;
|
|
|
|
/* All the following analysis only occurs if we are in the prologue and have
|
|
executed the code. Check we have a sane prologue size, and if zero we
|
|
are frameless and can give up here. */
|
|
if (end_addr < start_addr)
|
|
{
|
|
fatal ("end addr 0x%08x is less than start addr 0x%08x\n",
|
|
(unsigned int) end_addr, (unsigned int) start_addr);
|
|
}
|
|
|
|
if (end_addr == start_addr)
|
|
{
|
|
frame_size = 0;
|
|
}
|
|
else
|
|
{
|
|
/* have a frame. Look for the various components */
|
|
CORE_ADDR addr = start_addr; /* Where we have got to */
|
|
uint32_t inst = or1k_fetch_instruction (next_frame, addr);
|
|
|
|
unsigned int ra, rb, rd; /* For instruction analysis */
|
|
int simm;
|
|
|
|
/* Look for the new stack pointer being set up. */
|
|
if (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
|
|
(OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
|
|
(simm < 0) && (0 == (simm % 4)))
|
|
{
|
|
frame_size = -simm;
|
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (next_frame, addr);
|
|
|
|
/* The stack pointer of the PREVIOUS frame is frame_size greater
|
|
than the stack pointer of THIS frame. */
|
|
trad_frame_set_reg_value (info, OR1K_SP_REGNUM,
|
|
this_sp + frame_size);
|
|
}
|
|
|
|
/* Look for the frame pointer being manipulated. */
|
|
if ((addr < end_addr) &&
|
|
or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
|
|
(OR1K_SP_REGNUM == ra) && (OR1K_FP_REGNUM == rb) &&
|
|
(simm >= 0) && (0 == (simm % 4)))
|
|
{
|
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (next_frame, addr);
|
|
|
|
/* At this stage, we can find the frame pointer of the PREVIOUS
|
|
frame on the stack of the current frame. */
|
|
trad_frame_set_reg_addr (info, OR1K_FP_REGNUM, this_sp + simm);
|
|
|
|
/* Look for the new frame pointer being set up */
|
|
if (addr < end_addr)
|
|
{
|
|
gdb_assert (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
|
|
(OR1K_FP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
|
|
(simm == frame_size));
|
|
|
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (next_frame, addr);
|
|
|
|
/* If we have got this far, the stack pointer of the PREVIOUS
|
|
frame is the frame pointer of THIS frame. */
|
|
trad_frame_set_reg_realreg (info, OR1K_SP_REGNUM, OR1K_FP_REGNUM);
|
|
}
|
|
}
|
|
|
|
/* Look for the link register being saved */
|
|
if ((addr < end_addr) &&
|
|
or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
|
|
(OR1K_SP_REGNUM == ra) && (OR1K_LR_REGNUM == rb) &&
|
|
(simm >= 0) && (0 == (simm % 4)))
|
|
{
|
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (next_frame, addr);
|
|
|
|
/* If the link register is saved in the THIS frame, it holds the
|
|
value of the PC in the PREVIOUS frame. This overwrites the
|
|
previous information about finding the PC in the link
|
|
register. */
|
|
trad_frame_set_reg_addr (info, OR1K_NPC_REGNUM, this_sp + simm);
|
|
}
|
|
|
|
/* Look for callee-saved register being save. The register must be one
|
|
of the 10 callee saved registers (r10, r12, r14, r16, r18, r20, r22,
|
|
r24, r26, r28, r30).*/
|
|
while (addr < end_addr)
|
|
{
|
|
if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
|
|
(OR1K_SP_REGNUM == ra) && (rb >= OR1K_FIRST_SAVED_REGNUM) &&
|
|
(0 == rb % 2) && (simm >= 0) && (0 == (simm % 4)))
|
|
{
|
|
addr += OR1K_INSTLEN;
|
|
inst = or1k_fetch_instruction (next_frame, addr);
|
|
|
|
/* The register in the PREVIOUS frame can be found at this
|
|
location in THIS frame */
|
|
trad_frame_set_reg_addr (info, rb, this_sp + simm);
|
|
}
|
|
else
|
|
{
|
|
break; /* Not a register save instruction */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Build the frame ID */
|
|
trad_frame_set_id (info, frame_id_build (this_sp, start_addr));
|
|
|
|
return info;
|
|
|
|
} /* or1k_frame_unwind_cache() */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Find the frame ID of this frame
|
|
|
|
Given a GDB frame (called by THIS frame), determine the address of oru
|
|
frame and from this create a new GDB frame struct. The info required is
|
|
obtained from the prologue cache for THIS frame.
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the
|
|
one THIS frame called)
|
|
@param[in] this_prologue_cache Any cached prologue for THIS function.
|
|
@param[out] this_id Frame ID of our own frame.
|
|
|
|
@return Frame ID for THIS frame */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
or1k_frame_this_id (struct frame_info *next_frame,
|
|
void **this_prologue_cache,
|
|
struct frame_id *this_id)
|
|
{
|
|
struct trad_frame_cache *info =
|
|
or1k_frame_unwind_cache (next_frame, this_prologue_cache);
|
|
|
|
trad_frame_get_id (info, this_id);
|
|
|
|
} /* or1k_frame_this_id() */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Get a register from THIS frame
|
|
|
|
Given a pointer to the NEXT frame, return the details of a register in the
|
|
PREVIOUS frame.
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the
|
|
one THIS frame called)
|
|
@param[in] this_prologue_cache Any cached prologue associated with THIS
|
|
frame, which may therefore tell us about
|
|
registers in the PREVIOUS frame.
|
|
@param[in] regnum The register of interest in the PREVIOUS
|
|
frame
|
|
@param[out] optimizedp True (1) if the register has been
|
|
optimized out.
|
|
@param[out] lvalp What sort of l-value (if any) does the
|
|
register represent
|
|
@param[out] addrp Address in THIS frame where the register's
|
|
value may be found (-1 if not available)
|
|
@param[out] realregp Register in this frame where the
|
|
register's value may be found (-1 if not
|
|
available)
|
|
@param[out] bufferp If non-NULL, buffer where the value held
|
|
in the register may be put */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
static void
|
|
or1k_frame_prev_register (struct frame_info *next_frame,
|
|
void **this_prologue_cache,
|
|
int regnum,
|
|
int *optimizedp,
|
|
enum lval_type *lvalp,
|
|
CORE_ADDR *addrp,
|
|
int *realregp,
|
|
gdb_byte *bufferp)
|
|
{
|
|
struct trad_frame_cache *info =
|
|
or1k_frame_unwind_cache (next_frame, this_prologue_cache);
|
|
|
|
trad_frame_get_register (info, next_frame, regnum, optimizedp, lvalp, addrp,
|
|
realregp, bufferp);
|
|
|
|
} /* or1k_frame_prev_register() */
|
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/*!Return the base address of the frame
|
|
|
|
The commenting in the GDB source code could mean our stack pointer or our
|
|
frame pointer, since we have a falling stack, but index within the frame
|
|
using negative offsets from the FP.
|
|
|
|
This seems to be the function used to determine the value of $fp, but the
|
|
value required seems to be the stack pointer, so we return that, even if
|
|
the value of $fp will be wrong.
|
|
|
|
@param[in] next_frame The NEXT frame (i.e. inner from here, the
|
|
one THIS frame called)
|
|
@param[in] this_prologue_cache Any cached prologue for THIS function.
|
|
|
|
@return The frame base address */
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
static CORE_ADDR
|
|
or1k_frame_base_address (struct frame_info *next_frame,
|
|
void **this_prologue_cache)
|
|
{
|
|
return frame_unwind_register_unsigned (next_frame, OR1K_SP_REGNUM);
|
|
|
|
} /* or1k_frame_base_address() */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
/*!The OpenRISC 1000 registered frame sniffer
|
/*!The OpenRISC 1000 registered frame sniffer
|
|
|
This function just identifies our family of frame sniffing functions.
|
This function just identifies our family of frame sniffing functions.
|
|
|