/* FIXME: Put this declaration in frame.h. */
extern struct obstack frame_cache_obstack;
-/* FIXME! this code assumes 4-byte instructions. */
-#define MIPS_INSTLEN 4 /* Length of an instruction */
-#define MIPS16_INSTLEN 2 /* Length of an instruction on MIPS16*/
-#define MIPS_NUMREGS 32 /* Number of integer or float registers */
-typedef unsigned long t_inst; /* Integer big enough to hold an instruction */
-
-/* MIPS16 function addresses are odd (bit 0 is set). Here are some
- macros to test, set, or clear bit 0 of addresses. */
-#define IS_MIPS16_ADDR(addr) ((addr) & 1)
-#define MAKE_MIPS16_ADDR(addr) ((addr) | 1)
-#define UNMAKE_MIPS16_ADDR(addr) ((addr) & ~1)
-
#if 0
static int mips_in_lenient_prologue PARAMS ((CORE_ADDR, CORE_ADDR));
#endif
*gen_mask |= (1 << 31);
}
+
+/* Fetch and return instruction from the specified location. If the PC
+ is odd, assume it's a MIPS16 instruction; otherwise MIPS32. */
+
+static t_inst
+mips_fetch_instruction (addr)
+ CORE_ADDR addr;
+{
+ char buf[MIPS_INSTLEN];
+ int instlen;
+ int status;
+
+ if (IS_MIPS16_ADDR (addr))
+ {
+ instlen = MIPS16_INSTLEN;
+ addr = UNMAKE_MIPS16_ADDR (addr);
+ }
+ else
+ instlen = MIPS_INSTLEN;
+ status = read_memory_nobpt (addr, buf, instlen);
+ if (status)
+ memory_error (status, addr);
+ return extract_unsigned_integer (buf, instlen);
+}
+
+
/* Guaranteed to set fci->saved_regs to some values (it never leaves it
NULL). */
/* What registers have been saved? Bitmasks. */
unsigned long gen_mask, float_mask;
mips_extra_func_info_t proc_desc;
+ t_inst inst;
fci->saved_regs = (struct frame_saved_regs *)
obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs));
claims are saved have been saved yet. */
CORE_ADDR addr;
- int status;
- char buf[MIPS_INSTLEN];
- t_inst inst;
- int instlen;
/* Bitmasks; set if we have found a save for the register. */
unsigned long gen_save_found = 0;
unsigned long float_save_found = 0;
+ int instlen;
/* If the address is odd, assume this is MIPS16 code. */
addr = PROC_LOW_ADDR (proc_desc);
- if (IS_MIPS16_ADDR (addr))
- {
- instlen = MIPS16_INSTLEN;
- addr = UNMAKE_MIPS16_ADDR (addr);
- }
- else
- instlen = MIPS_INSTLEN;
+ instlen = IS_MIPS16_ADDR (addr) ? MIPS16_INSTLEN : MIPS_INSTLEN;
/* Scan through this function's instructions preceding the current
PC, and look for those that save registers. */
while (addr < fci->pc)
{
- status = read_memory_nobpt (addr, buf, instlen);
- if (status)
- memory_error (status, addr);
- inst = extract_unsigned_integer (buf, instlen);
- if (instlen == MIPS16_INSTLEN)
+ inst = mips_fetch_instruction (addr);
+ if (IS_MIPS16_ADDR (addr))
mips16_decode_reg_save (inst, &gen_save_found);
else
mips32_decode_reg_save (inst, &gen_save_found, &float_save_found);
fci->saved_regs->regs[ireg] = reg_position;
reg_position -= MIPS_REGSIZE;
}
+
+ /* The MIPS16 entry instruction saves $s0 and $s1 in the reverse order
+ of that normally used by gcc. Therefore, we have to fetch the first
+ instruction of the function, and if it's an entry instruction that
+ saves $s0 or $s1, correct their saved addresses. */
+ if (IS_MIPS16_ADDR (PROC_LOW_ADDR (proc_desc)))
+ {
+ inst = mips_fetch_instruction (PROC_LOW_ADDR (proc_desc));
+ if ((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */
+ {
+ int reg;
+ int sreg_count = (inst >> 6) & 3;
+
+ /* Check if the ra register was pushed on the stack. */
+ reg_position = fci->frame + PROC_REG_OFFSET (proc_desc);
+ if (inst & 0x20)
+ reg_position -= MIPS_REGSIZE;
+
+ /* Check if the s0 and s1 registers were pushed on the stack. */
+ for (reg = 16; reg < sreg_count+16; reg++)
+ {
+ fci->saved_regs->regs[reg] = reg_position;
+ reg_position -= MIPS_REGSIZE;
+ }
+ }
+ }
+
/* Fill in the offsets for the registers which float_mask says
were saved. */
reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc);
/* The freg_offset points to where the first *double* register
is saved. So skip to the high-order word. */
if (! GDB_TARGET_IS_MIPS64)
- reg_position += 4;
+ reg_position += MIPS_REGSIZE;
/* Fill in the offsets for the float registers which float_mask says
were saved. */
{
#if GDB_TARGET_IS_MIPS64
if ((addr >> 32 == (CORE_ADDR)0xffffffff)
- && (strcmp(target_shortname,"pmon")==0
- || strcmp(target_shortname,"ddb")==0
- || strcmp(target_shortname,"sim")==0))
+ && (strcmp (target_shortname,"pmon")==0
+ || strcmp (target_shortname,"ddb")==0
+ || strcmp (target_shortname,"sim")==0))
{
/* This hack is a work-around for existing boards using PMON,
the simulator, and any other 64-bit targets that doesn't have
return addr;
}
+void
+mips_init_frame_pc_first (fromleaf, prev)
+ int fromleaf;
+ struct frame_info *prev;
+{
+ CORE_ADDR pc, tmp;
+
+ pc = ((fromleaf) ? SAVED_PC_AFTER_CALL (prev->next) :
+ prev->next ? FRAME_SAVED_PC (prev->next) : read_pc ());
+ tmp = mips_skip_stub (pc);
+ prev->pc = tmp ? tmp : pc;
+}
+
+
CORE_ADDR
mips_frame_saved_pc(frame)
struct frame_info *frame;
else
warning("Hit heuristic-fence-post without finding");
- warning("enclosing function for address 0x%s", paddr (pc));
+ warning("enclosing function for address 0x%s", paddr_nz (pc));
if (!blurb_printed)
{
printf_filtered ("\
addiu sp,-n
daddiu sp,-n
extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n' */
- inst = read_memory_integer (UNMAKE_MIPS16_ADDR (start_pc), 2);
+ inst = mips_fetch_instruction (start_pc);
if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */
|| (inst & 0xff80) == 0x6380 /* addiu sp,-n */
|| (inst & 0xff80) == 0xfb80 /* daddiu sp,-n */
return start_pc;
}
-/* Fetch the immediate value from the current instruction.
+/* Fetch the immediate value from a MIPS16 instruction.
If the previous instruction was an EXTEND, use it to extend
the upper bits of the immediate value. This is a helper function
for mips16_heuristic_proc_desc. */
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS16_INSTLEN)
{
- char buf[MIPS16_INSTLEN];
- int status, reg, offset;
+ int reg, offset;
/* Save the previous instruction. If it's an EXTEND, we'll extract
the immediate offset extension from it in mips16_get_imm. */
prev_inst = inst;
- /* Fetch the instruction. */
- status = read_memory_nobpt (UNMAKE_MIPS16_ADDR (cur_pc), buf,
- MIPS16_INSTLEN);
- if (status) memory_error (status, cur_pc);
- inst = (unsigned short) extract_unsigned_integer (buf, MIPS16_INSTLEN);
-
+ /* Fetch and decode the instruction. */
+ inst = (unsigned short) mips_fetch_instruction (cur_pc);
if ((inst & 0xff00) == 0x6300 /* addiu sp */
|| (inst & 0xff00) == 0xfb00) /* daddiu sp */
{
PROC_FRAME_OFFSET(&temp_proc_desc) += 32;
/* Check if a0-a3 were saved in the caller's argument save area. */
- for (reg = 4, offset = 32; reg < areg_count+4; reg++, offset += 4)
+ for (reg = 4, offset = 32; reg < areg_count+4; reg++)
{
PROC_REG_MASK(&temp_proc_desc) |= 1 << reg;
temp_saved_regs.regs[reg] = sp + offset;
+ offset -= MIPS_REGSIZE;
}
/* Check if the ra register was pushed on the stack. */
{
PROC_REG_MASK(&temp_proc_desc) |= 1 << 31;
temp_saved_regs.regs[31] = sp + offset;
- offset -= 4;
+ offset -= MIPS_REGSIZE;
}
/* Check if the s0 and s1 registers were pushed on the stack. */
- for (reg = 16; reg < sreg_count+16; reg++, offset -= 4)
+ for (reg = 16; reg < sreg_count+16; reg++)
{
PROC_REG_MASK(&temp_proc_desc) |= 1 << reg;
temp_saved_regs.regs[reg] = sp + offset;
+ offset -= MIPS_REGSIZE;
}
}
else if ((inst & 0xf800) == 0x1800) /* jal(x) */
PROC_FRAME_OFFSET(&temp_proc_desc) = 0;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSTLEN)
{
- char buf[MIPS_INSTLEN];
unsigned long inst, high_word, low_word;
- int status, reg;
+ int reg;
/* Fetch the instruction. */
- status = (unsigned long) read_memory_nobpt (cur_pc, buf, MIPS_INSTLEN);
- if (status) memory_error (status, cur_pc);
- inst = (unsigned long) extract_unsigned_integer (buf, MIPS_INSTLEN);
+ inst = (unsigned long) mips_fetch_instruction (cur_pc);
/* Save some code by pre-extracting some useful fields. */
high_word = (inst >> 16) & 0xffff;
mips_frame_chain(frame)
struct frame_info *frame;
{
- mips_extra_func_info_t proc_desc;
- CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
-
- if (saved_pc == 0 || inside_entry_file (saved_pc))
- return 0;
-
- proc_desc = find_proc_desc(saved_pc, frame);
- if (!proc_desc)
- return 0;
-
- cached_proc_desc = proc_desc;
-
- /* If no frame pointer and frame size is zero, we must be at end
- of stack (or otherwise hosed). If we don't check frame size,
- we loop forever if we see a zero size frame. */
- if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
- && PROC_FRAME_OFFSET (proc_desc) == 0
- /* The previous frame from a sigtramp frame might be frameless
- and have frame size zero. */
- && !frame->signal_handler_caller)
- return 0;
- else
- return get_frame_pointer (frame, proc_desc);
+ mips_extra_func_info_t proc_desc;
+ CORE_ADDR tmp;
+ CORE_ADDR saved_pc = FRAME_SAVED_PC(frame);
+
+ if (saved_pc == 0 || inside_entry_file (saved_pc))
+ return 0;
+
+ /* Check if the PC is inside a call stub. If it is, fetch the
+ PC of the caller of that stub. */
+ if ((tmp = mips_skip_stub (saved_pc)) != 0)
+ saved_pc = tmp;
+
+ /* Look up the procedure descriptor for this PC. */
+ proc_desc = find_proc_desc(saved_pc, frame);
+ if (!proc_desc)
+ return 0;
+
+ cached_proc_desc = proc_desc;
+
+ /* If no frame pointer and frame size is zero, we must be at end
+ of stack (or otherwise hosed). If we don't check frame size,
+ we loop forever if we see a zero size frame. */
+ if (PROC_FRAME_REG (proc_desc) == SP_REGNUM
+ && PROC_FRAME_OFFSET (proc_desc) == 0
+ /* The previous frame from a sigtramp frame might be frameless
+ and have frame size zero. */
+ && !frame->signal_handler_caller)
+ return 0;
+ else
+ return get_frame_pointer (frame, proc_desc);
}
void
int float_argreg;
int argnum;
int len = 0;
- int stack_offset;
+ int stack_offset = 0;
/* Macros to round N up or down to the next A boundary; A must be
a power of two. */
if (struct_return)
write_register (argreg++, struct_addr);
- /* The offset onto the stack at which we will start copying parameters
- (after the registers are used up) begins at 16 in the old ABI.
- This leaves room for the "home" area for register parameters. */
- stack_offset = MIPS_EABI ? 0 : MIPS_REGSIZE * 4;
-
/* Now load as many as possible of the first arguments into
registers, and push the rest onto the stack. Loop thru args
from first to last. */
/* The EABI passes structures that do not fit in a register by
reference. In all other cases, pass the structure by value. */
- if (typecode == TYPE_CODE_STRUCT && MIPS_EABI && len > MIPS_REGSIZE)
+ if (MIPS_EABI && len > MIPS_REGSIZE &&
+ (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
{
store_address (valbuf, MIPS_REGSIZE, VALUE_ADDRESS (arg));
+ typecode = TYPE_CODE_PTR;
len = MIPS_REGSIZE;
val = valbuf;
}
/* Floating point arguments passed in registers have to be
treated specially. On 32-bit architectures, doubles
are passed in register pairs; the even register gets
- the low word, and the odd register gets the high word. */
+ the low word, and the odd register gets the high word.
+ On non-EABI processors, the first two floating point arguments are
+ also copied to general registers, because MIPS16 functions
+ don't use float registers for arguments. This duplication of
+ arguments in general registers can't hurt non-MIPS16 functions
+ because those registers are normally skipped. */
if (typecode == TYPE_CODE_FLT
&& float_argreg <= MIPS_LAST_FP_ARG_REGNUM
&& mips_fpu != MIPS_FPU_NONE)
int low_offset = TARGET_BYTE_ORDER == BIG_ENDIAN ? 4 : 0;
unsigned long regval;
+ /* Write the low word of the double to the even register(s). */
regval = extract_unsigned_integer (val+low_offset, 4);
- write_register (float_argreg++, regval); /* low word */
+ write_register (float_argreg++, regval);
+ if (!MIPS_EABI)
+ write_register (argreg+1, regval);
+
+ /* Write the high word of the double to the odd register(s). */
regval = extract_unsigned_integer (val+4-low_offset, 4);
- write_register (float_argreg++, regval); /* high word */
+ write_register (float_argreg++, regval);
+ if (!MIPS_EABI)
+ {
+ write_register (argreg, regval);
+ argreg += 2;
+ }
}
else
{
+ /* This is a floating point value that fits entirely
+ in a single register. */
CORE_ADDR regval = extract_address (val, len);
write_register (float_argreg++, regval);
+ if (!MIPS_EABI)
+ {
+ write_register (argreg, regval);
+ argreg += GDB_TARGET_IS_MIPS64 ? 1 : 2;
+ }
}
-
- /* If this is the old ABI, skip one or two general registers. */
- if (!MIPS_EABI)
- argreg += GDB_TARGET_IS_MIPS64 ? 1 : 2;
}
else
{
/* Copy the argument to general registers or the stack in
register-sized pieces. Large arguments are split between
registers and stack. */
+ /* Note: structs whose size is not a multiple of MIPS_REGSIZE
+ are treated specially: Irix cc passes them in registers
+ where gcc sometimes puts them on the stack. For maximum
+ compatibility, we will put them in both places. */
+
+ int odd_sized_struct = ((len > MIPS_REGSIZE) &&
+ (len % MIPS_REGSIZE != 0));
while (len > 0)
{
int partial_len = len < MIPS_REGSIZE ? len : MIPS_REGSIZE;
+ if (argreg > MIPS_LAST_ARG_REGNUM || odd_sized_struct)
+ {
+ /* Write this portion of the argument to the stack. */
+ int longword_offset;
+
+ longword_offset = 0;
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ if (MIPS_REGSIZE == 8 &&
+ (typecode == TYPE_CODE_INT ||
+ typecode == TYPE_CODE_PTR ||
+ typecode == TYPE_CODE_FLT) && len <= 4)
+ longword_offset = 4;
+ else if ((typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION) &&
+ TYPE_LENGTH (arg_type) < MIPS_REGSIZE)
+ longword_offset = MIPS_REGSIZE - len;
+
+ write_memory (sp + stack_offset + longword_offset,
+ val, partial_len);
+ }
+
+ /* Note!!! This is NOT an else clause.
+ Odd sized structs may go thru BOTH paths. */
if (argreg <= MIPS_LAST_ARG_REGNUM)
{
CORE_ADDR regval = extract_address (val, partial_len);
- /* It's a simple argument being passed in a general
- register.
- If the argument length is smaller than the register size,
- we have to adjust the argument on big endian targets.
- But don't do this adjustment on EABI targets. */
- if (TARGET_BYTE_ORDER == BIG_ENDIAN
- && partial_len < MIPS_REGSIZE
- && !MIPS_EABI)
- regval <<= ((MIPS_REGSIZE - partial_len) * TARGET_CHAR_BIT);
+ /* A non-floating-point argument being passed in a
+ general register. If a struct or union, and if
+ small enough for a single register, we have to
+ adjust the alignment.
+
+ It does not seem to be necessary to do the
+ same for integral types.
+
+ Also don't do this adjustment on EABI targets. */
+
+ if (!MIPS_EABI &&
+ TYPE_LENGTH (arg_type) < MIPS_REGSIZE &&
+ (typecode == TYPE_CODE_STRUCT ||
+ typecode == TYPE_CODE_UNION))
+ regval <<= ((MIPS_REGSIZE - partial_len) *
+ TARGET_CHAR_BIT);
+
write_register (argreg, regval);
argreg++;
if (!MIPS_EABI)
float_argreg = MIPS_LAST_FP_ARG_REGNUM + 1;
}
- else
- {
- /* Write this portion of the argument to the stack. */
- partial_len = len;
- write_memory (sp + stack_offset, val, partial_len);
- stack_offset += ROUND_UP (partial_len, MIPS_REGSIZE);
- }
len -= partial_len;
val += partial_len;
+
+ /* The offset onto the stack at which we will start
+ copying parameters (after the registers are used up)
+ begins at (4 * MIPS_REGSIZE) in the old ABI. This
+ leaves room for the "home" area for register parameters.
+
+ In the new EABI, the 8 register parameters do not
+ have "home" stack space reserved for them, so the
+ stack offset does not get incremented until after
+ we have used up the 8 parameter registers. */
+ if (!(MIPS_EABI && argnum < 8))
+ stack_offset += ROUND_UP (partial_len, MIPS_REGSIZE);
}
}
}
return sp;
}
-void
+static void
mips_push_register(CORE_ADDR *sp, int regno)
{
char buffer[MAX_REGISTER_RAW_SIZE];
return;
}
- /* If an even floating pointer register, also print as double. */
+ /* If an even floating point register, also print as double. */
if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM+MIPS_NUMREGS
&& !((regnum-FP0_REGNUM) & 1))
{
- char dbuffer[MAX_REGISTER_RAW_SIZE];
+ char dbuffer[2 * MAX_REGISTER_RAW_SIZE];
read_relative_register_raw_bytes (regnum, dbuffer);
- read_relative_register_raw_bytes (regnum+1, dbuffer+4); /* FIXME!! */
-#ifdef REGISTER_CONVERT_TO_TYPE
- REGISTER_CONVERT_TO_TYPE(regnum, builtin_type_double, dbuffer);
-#endif
+ read_relative_register_raw_bytes (regnum+1, dbuffer+MIPS_REGSIZE);
+ REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer);
+
printf_filtered ("(d%d: ", regnum-FP0_REGNUM);
val_print (builtin_type_double, dbuffer, 0,
gdb_stdout, 0, 1, 0, Val_pretty_default);
or in the gcc frame. */
for (end_pc = pc + 100; pc < end_pc; pc += MIPS_INSTLEN)
{
- char buf[MIPS_INSTLEN];
- int status;
unsigned long high_word;
- status = read_memory_nobpt (pc, buf, MIPS_INSTLEN);
- if (status)
- memory_error (status, pc);
- inst = (unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN);
+ inst = mips_fetch_instruction (pc);
high_word = (inst >> 16) & 0xffff;
#if 0
int lenient;
{
CORE_ADDR end_pc;
+ int extend_bytes = 0;
+ int prev_extend_bytes;
/* Table of instructions likely to be found in a function prologue. */
static struct
or in the gcc frame. */
for (end_pc = pc + 100; pc < end_pc; pc += MIPS16_INSTLEN)
{
- char buf[MIPS16_INSTLEN];
- int status;
unsigned short inst;
- int extend_bytes = 0;
- int prev_extend_bytes;
int i;
- status = read_memory_nobpt (UNMAKE_MIPS16_ADDR (pc), buf,
- MIPS16_INSTLEN);
- if (status)
- memory_error (status, pc);
- inst = (unsigned long)extract_unsigned_integer (buf, MIPS16_INSTLEN);
-
-#if 0
- if (lenient && is_delayed (inst))
- continue;
-#endif
+ inst = mips_fetch_instruction (pc);
/* Normally we ignore an extend instruction. However, if it is
not followed by a valid prologue instruction, we must adjust
{
int regnum;
int offset = 0;
+ int len = TYPE_LENGTH (valtype);
regnum = 2;
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
- && (mips_fpu == MIPS_FPU_DOUBLE
- || (mips_fpu == MIPS_FPU_SINGLE && TYPE_LENGTH (valtype) <= 4))) /* FIXME!! */
+ && (mips_fpu == MIPS_FPU_DOUBLE
+ || (mips_fpu == MIPS_FPU_SINGLE && len <= MIPS_REGSIZE)))
regnum = FP0_REGNUM;
- if (TARGET_BYTE_ORDER == BIG_ENDIAN
- && TYPE_CODE (valtype) != TYPE_CODE_FLT
- && TYPE_LENGTH (valtype) < REGISTER_RAW_SIZE (regnum))
- offset = REGISTER_RAW_SIZE (regnum) - TYPE_LENGTH (valtype);
-
- memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset,
- TYPE_LENGTH (valtype));
-#ifdef REGISTER_CONVERT_TO_TYPE
- REGISTER_CONVERT_TO_TYPE(regnum, valtype, valbuf);
-#endif
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ { /* "un-left-justify" the value from the register */
+ if (len < REGISTER_RAW_SIZE (regnum))
+ offset = REGISTER_RAW_SIZE (regnum) - len;
+ if (len > REGISTER_RAW_SIZE (regnum) && /* odd-size structs */
+ len < REGISTER_RAW_SIZE (regnum) * 2 &&
+ (TYPE_CODE (valtype) == TYPE_CODE_STRUCT ||
+ TYPE_CODE (valtype) == TYPE_CODE_UNION))
+ offset = 2 * REGISTER_RAW_SIZE (regnum) - len;
+ }
+ memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset, len);
+ REGISTER_CONVERT_TO_TYPE (regnum, valtype, valbuf);
}
/* Given a return value in `regbuf' with a type `valtype',
char *valbuf;
{
int regnum;
+ int offset = 0;
+ int len = TYPE_LENGTH (valtype);
char raw_buffer[MAX_REGISTER_RAW_SIZE];
regnum = 2;
if (TYPE_CODE (valtype) == TYPE_CODE_FLT
- && (mips_fpu == MIPS_FPU_DOUBLE
- || (mips_fpu == MIPS_FPU_SINGLE && TYPE_LENGTH (valtype) <= 4))) /* FIXME!! */
+ && (mips_fpu == MIPS_FPU_DOUBLE
+ || (mips_fpu == MIPS_FPU_SINGLE && len <= MIPS_REGSIZE)))
regnum = FP0_REGNUM;
- memcpy(raw_buffer, valbuf, TYPE_LENGTH (valtype));
-
-#ifdef REGISTER_CONVERT_FROM_TYPE
+ if (TARGET_BYTE_ORDER == BIG_ENDIAN)
+ { /* "left-justify" the value in the register */
+ if (len < REGISTER_RAW_SIZE (regnum))
+ offset = REGISTER_RAW_SIZE (regnum) - len;
+ if (len > REGISTER_RAW_SIZE (regnum) && /* odd-size structs */
+ len < REGISTER_RAW_SIZE (regnum) * 2 &&
+ (TYPE_CODE (valtype) == TYPE_CODE_STRUCT ||
+ TYPE_CODE (valtype) == TYPE_CODE_UNION))
+ offset = 2 * REGISTER_RAW_SIZE (regnum) - len;
+ }
+ memcpy(raw_buffer + offset, valbuf, len);
REGISTER_CONVERT_FROM_TYPE(regnum, valtype, raw_buffer);
-#endif
-
- write_register_bytes(REGISTER_BYTE (regnum), raw_buffer, TYPE_LENGTH (valtype));
+ write_register_bytes(REGISTER_BYTE (regnum), raw_buffer,
+ len > REGISTER_RAW_SIZE (regnum) ?
+ len : REGISTER_RAW_SIZE (regnum));
}
/* Exported procedure: Is PC in the signal trampoline code */
else
{
static char big_breakpoint[] = BIG_BREAKPOINT;
+ static char pmon_big_breakpoint[] = PMON_BIG_BREAKPOINT;
+ static char idt_big_breakpoint[] = IDT_BIG_BREAKPOINT;
+
*lenptr = sizeof(big_breakpoint);
- return big_breakpoint;
+
+ if (strcmp (target_shortname, "mips") == 0)
+ return idt_big_breakpoint;
+ else if (strcmp (target_shortname, "ddb") == 0
+ || strcmp (target_shortname, "pmon") == 0
+ || strcmp (target_shortname, "lsi") == 0)
+ return pmon_big_breakpoint;
+ else
+ return big_breakpoint;
}
}
else
else
{
static char little_breakpoint[] = LITTLE_BREAKPOINT;
+ static char pmon_little_breakpoint[] = PMON_LITTLE_BREAKPOINT;
+ static char idt_little_breakpoint[] = IDT_LITTLE_BREAKPOINT;
+
*lenptr = sizeof(little_breakpoint);
- return little_breakpoint;
+
+ if (strcmp (target_shortname, "mips") == 0)
+ return idt_little_breakpoint;
+ else if (strcmp (target_shortname, "ddb") == 0
+ || strcmp (target_shortname, "pmon") == 0
+ || strcmp (target_shortname, "lsi") == 0)
+ return pmon_little_breakpoint;
+ else
+ return little_breakpoint;
}
}
}
as $a3), then a "jr" using that register. This second case
is almost impossible to distinguish from an indirect jump
used for switch statements, so we don't even try. */
- return read_memory_integer (UNMAKE_MIPS16_ADDR (pc), 2) == 0xe820; /* jr $ra */
+ return mips_fetch_instruction (pc) == 0xe820; /* jr $ra */
else
- return read_memory_integer (pc, 4) == 0x3e00008; /* jr $ra */
+ return mips_fetch_instruction (pc) == 0x3e00008; /* jr $ra */
+}
+
+
+/* If PC is in a mips16 call or return stub, return the address of the target
+ PC, which is either the callee or the caller. There are several
+ cases which must be handled:
+
+ * If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
+ target PC is in $31 ($ra).
+ * If the PC is in __mips16_call_stub_{1..10}, this is a call stub
+ and the target PC is in $2.
+ * If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub
+ and the the target PC is in $2. Otherwise this is effectively
+ a return stub and the target PC is in $18.
+
+ See the source code for the stubs in gcc/config/mips/mips16.S for
+ gory details.
+
+ This function implements the SKIP_TRAMPOLINE_CODE macro.
+*/
+
+CORE_ADDR
+mips_skip_stub (pc)
+ CORE_ADDR pc;
+{
+ char *name;
+ CORE_ADDR start_addr;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a return stub and the
+ target PC is in $31 ($ra). */
+ if (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0)
+ return read_register (RA_REGNUM);
+
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+ {
+ /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
+ and the target PC is in $2. */
+ if (name[19] >= '0' && name[19] <= '9')
+ return read_register (2);
+
+ /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub
+ and the the target PC is in $2. Otherwise this is effectively
+ a return stub and the target PC is in $18. */
+ else if (name[19] == 's' || name[19] == 'd')
+ {
+ if (pc == start_addr)
+ {
+ /* Check if the target of the stub is a compiler-generated
+ stub. Such a stub for a function bar might have a name
+ like __fn_stub_bar, and might look like this:
+ mfc1 $4,$f13
+ mfc1 $5,$f12
+ mfc1 $6,$f15
+ mfc1 $7,$f14
+ la $1,bar (becomes a lui/addiu pair)
+ jr $1
+ So scan down to the lui/addi and extract the target
+ address from those two instructions. */
+
+ CORE_ADDR target_pc = read_register (2);
+ t_inst inst;
+ int i;
+
+ /* See if the name of the target function is __fn_stub_*. */
+ if (find_pc_partial_function (target_pc, &name, NULL, NULL) == 0)
+ return target_pc;
+ if (strncmp (name, "__fn_stub_", 10) != 0
+ && strcmp (name, "etext") != 0
+ && strcmp (name, "_etext") != 0)
+ return target_pc;
+
+ /* Scan through this _fn_stub_ code for the lui/addiu pair.
+ The limit on the search is arbitrarily set to 20
+ instructions. FIXME. */
+ for (i = 0, pc = 0; i < 20; i++, target_pc += MIPS_INSTLEN)
+ {
+ inst = mips_fetch_instruction (target_pc);
+ if ((inst & 0xffff0000) == 0x3c010000) /* lui $at */
+ pc = (inst << 16) & 0xffff0000; /* high word */
+ else if ((inst & 0xffff0000) == 0x24210000) /* addiu $at */
+ return pc | (inst & 0xffff); /* low word */
+ }
+
+ /* Couldn't find the lui/addui pair, so return stub address. */
+ return target_pc;
+ }
+ else
+ /* This is the 'return' part of a call stub. The return
+ address is in $r18. */
+ return read_register (18);
+ }
+ }
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is inside a call thunk (aka stub or trampoline).
+ This implements the IN_SOLIB_CALL_TRAMPOLINE macro. */
+
+int
+mips_in_call_stub (pc, name)
+ CORE_ADDR pc;
+ char *name;
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. If the
+ caller didn't give us a name, look it up at the same time. */
+ if (find_pc_partial_function (pc, name ? NULL : &name, &start_addr, NULL) == 0)
+ return 0;
+
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0)
+ {
+ /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub. */
+ if (name[19] >= '0' && name[19] <= '9')
+ return 1;
+ /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
+ before the jal instruction, this is effectively a call stub. */
+ else if (name[19] == 's' || name[19] == 'd')
+ return pc == start_addr;
+ }
+
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is inside a return thunk (aka stub or trampoline).
+ This implements the IN_SOLIB_RETURN_TRAMPOLINE macro. */
+
+int
+mips_in_return_stub (pc, name)
+ CORE_ADDR pc;
+ char *name;
+{
+ CORE_ADDR start_addr;
+
+ /* Find the starting address of the function containing the PC. */
+ if (find_pc_partial_function (pc, NULL, &start_addr, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a return stub. */
+ if (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0)
+ return 1;
+
+ /* If the PC is in __mips16_call_stub_{s,d}f_{0..10} but not at the start,
+ i.e. after the jal instruction, this is effectively a return stub. */
+ if (strncmp (name, "__mips16_call_stub_", 19) == 0
+ && (name[19] == 's' || name[19] == 'd')
+ && pc != start_addr)
+ return 1;
+
+ return 0; /* not a stub */
+}
+
+
+/* Return non-zero if the PC is in a library helper function that should
+ be ignored. This implements the IGNORE_HELPER_CALL macro. */
+
+int
+mips_ignore_helper (pc)
+ CORE_ADDR pc;
+{
+ char *name;
+
+ /* Find the starting address and name of the function containing the PC. */
+ if (find_pc_partial_function (pc, &name, NULL, NULL) == 0)
+ return 0;
+
+ /* If the PC is in __mips16_ret_{d,s}f, this is a library helper function
+ that we want to ignore. */
+ return (strcmp (name, "__mips16_ret_sf") == 0
+ || strcmp (name, "__mips16_ret_df") == 0);
}