/* Map the symbol table registers which live in the range [1 *
NUM_REGS .. 2 * NUM_REGS) back onto the corresponding raw
- registers. */
+ registers. Take care of alignment and size problems. */
static void
mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int cookednum, void *buf)
{
+ int rawnum = cookednum % NUM_REGS;
gdb_assert (cookednum >= NUM_REGS && cookednum < 2 * NUM_REGS);
- return regcache_raw_read (regcache, cookednum % NUM_REGS, buf);
+ if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+ return regcache_raw_read (regcache, rawnum, buf);
+ else if (register_size (gdbarch, rawnum) > register_size (gdbarch, cookednum))
+ {
+ if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
+ || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
+ else
+ regcache_raw_read_part (regcache, rawnum, 4, 4, buf);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "bad register size");
}
static void
mips_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int cookednum, const void *buf)
{
+ int rawnum = cookednum % NUM_REGS;
gdb_assert (cookednum >= NUM_REGS && cookednum < 2 * NUM_REGS);
- return regcache_raw_write (regcache, cookednum % NUM_REGS, buf);
+ if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
+ return regcache_raw_write (regcache, rawnum, buf);
+ else if (register_size (gdbarch, rawnum) > register_size (gdbarch, cookednum))
+ {
+ if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
+ || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+ regcache_raw_write_part (regcache, rawnum, 0, 4, buf);
+ else
+ regcache_raw_write_part (regcache, rawnum, 4, 4, buf);
+ }
+ else
+ internal_error (__FILE__, __LINE__, "bad register size");
}
/* Table to translate MIPS16 register field to actual register number. */
}
}
-/* Convert between RAW and VIRTUAL registers. The RAW register size
- defines the remote-gdb packet. */
-
-static int
-mips_register_convertible (int reg_nr)
-{
- if (gdbarch_tdep (current_gdbarch)->mips64_transfers_32bit_regs_p)
- return 0;
- else
- return (register_size (current_gdbarch, reg_nr) > register_size (current_gdbarch, reg_nr));
-}
-
-static void
-mips_register_convert_to_virtual (int n, struct type *virtual_type,
- char *raw_buf, char *virt_buf)
-{
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (virt_buf,
- raw_buf + (register_size (current_gdbarch, n) - TYPE_LENGTH (virtual_type)),
- TYPE_LENGTH (virtual_type));
- else
- memcpy (virt_buf,
- raw_buf,
- TYPE_LENGTH (virtual_type));
-}
-
-static void
-mips_register_convert_to_raw (struct type *virtual_type, int n,
- const char *virt_buf, char *raw_buf)
-{
- memset (raw_buf, 0, register_size (current_gdbarch, n));
- if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
- memcpy (raw_buf + (register_size (current_gdbarch, n) - TYPE_LENGTH (virtual_type)),
- virt_buf,
- TYPE_LENGTH (virtual_type));
- else
- memcpy (raw_buf,
- virt_buf,
- TYPE_LENGTH (virtual_type));
-}
+/* Convert to/from a register and the corresponding memory value. */
static int
mips_convert_register_p (int regnum, struct type *type)
return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
}
-static int
-mips_n32n64_use_struct_convention (int gcc_p, struct type *type)
-{
- return (TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE);
-}
-
/* Should call_function pass struct by reference?
For each architecture, structs are passed either by
value or by reference, depending on their size. */
#define SIGFRAME_REGSAVE_OFF (SIGFRAME_BASE + 3 * mips_regsize (current_gdbarch))
#define SIGFRAME_FPREGSAVE_OFF \
(SIGFRAME_REGSAVE_OFF + MIPS_NUMREGS * mips_regsize (current_gdbarch) + 3 * mips_regsize (current_gdbarch))
-#endif
-#ifndef SIGFRAME_REG_SIZE
- /* FIXME! Is this correct?? */
-#define SIGFRAME_REG_SIZE mips_regsize (current_gdbarch)
#endif
if ((get_frame_type (fci) == SIGTRAMP_FRAME))
{
for (ireg = 0; ireg < MIPS_NUMREGS; ireg++)
{
CORE_ADDR reg_position = (get_frame_base (fci) + SIGFRAME_REGSAVE_OFF
- + ireg * SIGFRAME_REG_SIZE);
+ + ireg * mips_regsize (current_gdbarch));
set_reg_offset (saved_regs, ireg, reg_position);
}
for (ireg = 0; ireg < MIPS_NUMREGS; ireg++)
{
CORE_ADDR reg_position = (get_frame_base (fci)
+ SIGFRAME_FPREGSAVE_OFF
- + ireg * SIGFRAME_REG_SIZE);
+ + ireg * mips_regsize (current_gdbarch));
set_reg_offset (saved_regs, mips_regnum (current_gdbarch)->fp0 + ireg, reg_position);
}
if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame), 0, 0))
{
- LONGEST tmp;
/* Always unwind the cooked PC register value. */
- frame_unwind_signed_register (frame, NUM_REGS + PC_REGNUM, &tmp);
- saved_pc = tmp;
+ saved_pc = frame_unwind_register_signed (frame, NUM_REGS + PC_REGNUM);
}
else
{
CORE_ADDR tmp;
CORE_ADDR saved_pc = DEPRECATED_FRAME_SAVED_PC (frame);
- if (saved_pc == 0 || deprecated_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 = SKIP_TRAMPOLINE_CODE (saved_pc)) != 0)
frame_extra_info_zalloc (fci, sizeof (struct frame_extra_info));
- deprecated_set_frame_saved_regs_hack (fci, NULL);
get_frame_extra_info (fci)->proc_desc =
proc_desc == &temp_proc_desc ? 0 : proc_desc;
if (proc_desc)
}
+/* Given PC at the function's start address, attempt to find the
+ prologue end using SAL information. Return zero if the skip fails.
+
+ A non-optimized prologue traditionally has one SAL for the function
+ and a second for the function body. A single line function has
+ them both pointing at the same line.
+
+ An optimized prologue is similar but the prologue may contain
+ instructions (SALs) from the instruction body. Need to skip those
+ while not getting into the function body.
+
+ The functions end point and an increasing SAL line are used as
+ indicators of the prologue's endpoint.
+
+ This code is based on the function refine_prologue_limit (versions
+ found in both ia64 and ppc). */
+
+static CORE_ADDR
+skip_prologue_using_sal (CORE_ADDR func_addr)
+{
+ struct symtab_and_line prologue_sal;
+ CORE_ADDR start_pc;
+ CORE_ADDR end_pc;
+
+ /* Get an initial range for the function. */
+ find_pc_partial_function (func_addr, NULL, &start_pc, &end_pc);
+ start_pc += FUNCTION_START_OFFSET;
+
+ prologue_sal = find_pc_line (start_pc, 0);
+ if (prologue_sal.line != 0)
+ {
+ while (prologue_sal.end < end_pc)
+ {
+ struct symtab_and_line sal;
+
+ sal = find_pc_line (prologue_sal.end, 0);
+ if (sal.line == 0)
+ break;
+ /* Assume that a consecutive SAL for the same (or larger)
+ line mark the prologue -> body transition. */
+ if (sal.line >= prologue_sal.line)
+ break;
+ /* The case in which compiler's optimizer/scheduler has
+ moved instructions into the prologue. We look ahead in
+ the function looking for address ranges whose
+ corresponding line number is less the first one that we
+ found for the function. This is more conservative then
+ refine_prologue_limit which scans a large number of SALs
+ looking for any in the prologue */
+ prologue_sal = sal;
+ }
+ }
+ return prologue_sal.end;
+}
+
/* Skip the PC past function prologue instructions (32-bit version).
This is a helper function for mips_skip_prologue. */
int seen_sp_adjust = 0;
int load_immediate_bytes = 0;
+ /* Find an upper bound on the prologue. */
+ end_pc = skip_prologue_using_sal (pc);
+ if (end_pc == 0)
+ end_pc = pc + 100; /* Magic. */
+
/* Skip the typical prologue instructions. These are the stack adjustment
instruction and the instructions that save registers on the stack
or in the gcc frame. */
- for (end_pc = pc + 100; pc < end_pc; pc += MIPS_INSTLEN)
+ for (; pc < end_pc; pc += MIPS_INSTLEN)
{
unsigned long high_word;
} /* end of table marker */
};
+ /* Find an upper bound on the prologue. */
+ end_pc = skip_prologue_using_sal (pc);
+ if (end_pc == 0)
+ end_pc = pc + 100; /* Magic. */
+
/* Skip the typical prologue instructions. These are the stack adjustment
instruction and the instructions that save registers on the stack
or in the gcc frame. */
- for (end_pc = pc + 100; pc < end_pc; pc += MIPS16_INSTLEN)
+ for (; pc < end_pc; pc += MIPS16_INSTLEN)
{
unsigned short inst;
int i;
return_value_location (valtype, &hi, &lo);
memcpy (valbuf + lo.buf_offset,
- regbuf + DEPRECATED_REGISTER_BYTE (lo.reg) + lo.reg_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + lo.reg) + lo.reg_offset,
lo.len);
if (hi.len > 0)
memcpy (valbuf + hi.buf_offset,
- regbuf + DEPRECATED_REGISTER_BYTE (hi.reg) + hi.reg_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + hi.reg) + hi.reg_offset,
hi.len);
}
return_value_location (valtype, &hi, &lo);
memcpy (valbuf + lo.buf_offset,
- regbuf + DEPRECATED_REGISTER_BYTE (lo.reg) + lo.reg_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + lo.reg) + lo.reg_offset,
lo.len);
if (hi.len > 0)
memcpy (valbuf + hi.buf_offset,
- regbuf + DEPRECATED_REGISTER_BYTE (hi.reg) + hi.reg_offset,
+ regbuf + DEPRECATED_REGISTER_BYTE (NUM_REGS + hi.reg) + hi.reg_offset,
hi.len);
}
/* O32 ABI stuff. */
-static void
-mips_o32_xfer_return_value (struct type *type,
- struct regcache *regcache,
- bfd_byte *in, const bfd_byte *out)
+static enum return_value_convention
+mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache,
+ void *readbuf, const void *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- if (TYPE_CODE (type) == TYPE_CODE_FLT
- && TYPE_LENGTH (type) == 4
- && tdep->mips_fpu_type != MIPS_FPU_NONE)
+
+ if (TYPE_CODE (type)== TYPE_CODE_STRUCT
+ || TYPE_CODE (type)== TYPE_CODE_UNION
+ || TYPE_CODE (type)== TYPE_CODE_ARRAY)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && TYPE_LENGTH (type) == 4
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
{
/* A single-precision floating-point value. It fits in the
least significant part of FP0. */
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
- mips_xfer_register (regcache, NUM_REGS + mips_regnum (current_gdbarch)->fp0, TYPE_LENGTH (type),
- TARGET_BYTE_ORDER, in, out, 0);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0,
+ TYPE_LENGTH (type),
+ TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
else if (TYPE_CODE (type) == TYPE_CODE_FLT
&& TYPE_LENGTH (type) == 8
switch (TARGET_BYTE_ORDER)
{
case BFD_ENDIAN_LITTLE:
- mips_xfer_register (regcache, NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 0, 4,
- TARGET_BYTE_ORDER, in, out, 0);
- mips_xfer_register (regcache, NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 1, 4,
- TARGET_BYTE_ORDER, in, out, 4);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 0,
+ 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 1,
+ 4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
break;
case BFD_ENDIAN_BIG:
- mips_xfer_register (regcache, NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 1, 4,
- TARGET_BYTE_ORDER, in, out, 0);
- mips_xfer_register (regcache, NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 0, 4,
- TARGET_BYTE_ORDER, in, out, 4);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 1,
+ 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0 + 0,
+ 4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
break;
default:
internal_error (__FILE__, __LINE__, "bad switch");
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
#if 0
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n", offset);
mips_xfer_register (regcache, NUM_REGS + regnum,
TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
- TARGET_BYTE_ORDER, in, out, offset);
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
#endif
#if 0
fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
- BFD_ENDIAN_UNKNOWN, in, out, offset);
+ BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
#endif
else
fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
- TARGET_BYTE_ORDER, in, out, offset);
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
}
-static void
-mips_o32_extract_return_value (struct type *type,
- struct regcache *regcache,
- void *valbuf)
-{
- mips_o32_xfer_return_value (type, regcache, valbuf, NULL);
-}
-
-static void
-mips_o32_store_return_value (struct type *type, char *valbuf)
-{
- mips_o32_xfer_return_value (type, current_regcache, NULL, valbuf);
-}
-
/* N32/N44 ABI stuff. */
-static void
-mips_n32n64_xfer_return_value (struct type *type,
- struct regcache *regcache,
- bfd_byte *in, const bfd_byte *out)
+static enum return_value_convention
+mips_n32n64_return_value (struct gdbarch *gdbarch,
+ struct type *type, struct regcache *regcache,
+ void *readbuf, const void *writebuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- if (TYPE_CODE (type) == TYPE_CODE_FLT
- && tdep->mips_fpu_type != MIPS_FPU_NONE)
+ if (TYPE_CODE (type)== TYPE_CODE_STRUCT
+ || TYPE_CODE (type)== TYPE_CODE_UNION
+ || TYPE_CODE (type)== TYPE_CODE_ARRAY
+ || TYPE_LENGTH (type) > 2 * MIPS_SAVED_REGSIZE)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else if (TYPE_CODE (type) == TYPE_CODE_FLT
+ && tdep->mips_fpu_type != MIPS_FPU_NONE)
{
/* A floating-point value belongs in the least significant part
of FP0. */
if (mips_debug)
fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
- mips_xfer_register (regcache, NUM_REGS + mips_regnum (current_gdbarch)->fp0, TYPE_LENGTH (type),
- TARGET_BYTE_ORDER, in, out, 0);
+ mips_xfer_register (regcache,
+ NUM_REGS + mips_regnum (current_gdbarch)->fp0,
+ TYPE_LENGTH (type),
+ TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) <= 2
fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n", offset);
mips_xfer_register (regcache, NUM_REGS + regnum,
TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
- TARGET_BYTE_ORDER, in, out, offset);
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
|| TYPE_CODE (type) == TYPE_CODE_UNION)
fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
- BFD_ENDIAN_UNKNOWN, in, out, offset);
+ BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
else
{
fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
offset, xfer, regnum);
mips_xfer_register (regcache, NUM_REGS + regnum, xfer,
- TARGET_BYTE_ORDER, in, out, offset);
+ TARGET_BYTE_ORDER, readbuf, writebuf, offset);
}
+ return RETURN_VALUE_REGISTER_CONVENTION;
}
}
-static void
-mips_n32n64_extract_return_value (struct type *type,
- struct regcache *regcache,
- void *valbuf)
-{
- mips_n32n64_xfer_return_value (type, regcache, valbuf, NULL);
-}
-
-static void
-mips_n32n64_store_return_value (struct type *type, char *valbuf)
-{
- mips_n32n64_xfer_return_value (type, current_regcache, NULL, valbuf);
-}
-
static CORE_ADDR
mips_extract_struct_value_address (struct regcache *regcache)
{
{
case MIPS_ABI_O32:
set_gdbarch_push_dummy_call (gdbarch, mips_o32_push_dummy_call);
- set_gdbarch_deprecated_store_return_value (gdbarch, mips_o32_store_return_value);
- set_gdbarch_extract_return_value (gdbarch, mips_o32_extract_return_value);
+ set_gdbarch_return_value (gdbarch, mips_o32_return_value);
tdep->mips_default_saved_regsize = 4;
tdep->mips_default_stack_argsize = 4;
tdep->mips_fp_register_double = 0;
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_deprecated_reg_struct_has_addr
(gdbarch, mips_o32_reg_struct_has_addr);
- set_gdbarch_use_struct_convention (gdbarch,
- always_use_struct_convention);
break;
case MIPS_ABI_O64:
set_gdbarch_push_dummy_call (gdbarch, mips_o64_push_dummy_call);
break;
case MIPS_ABI_N32:
set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
- set_gdbarch_deprecated_store_return_value (gdbarch, mips_n32n64_store_return_value);
- set_gdbarch_extract_return_value (gdbarch, mips_n32n64_extract_return_value);
+ set_gdbarch_return_value (gdbarch, mips_n32n64_return_value);
tdep->mips_default_saved_regsize = 8;
tdep->mips_default_stack_argsize = 8;
tdep->mips_fp_register_double = 1;
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_ptr_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
- set_gdbarch_use_struct_convention (gdbarch,
- mips_n32n64_use_struct_convention);
set_gdbarch_deprecated_reg_struct_has_addr
(gdbarch, mips_n32n64_reg_struct_has_addr);
break;
case MIPS_ABI_N64:
set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
- set_gdbarch_deprecated_store_return_value (gdbarch, mips_n32n64_store_return_value);
- set_gdbarch_extract_return_value (gdbarch, mips_n32n64_extract_return_value);
+ set_gdbarch_return_value (gdbarch, mips_n32n64_return_value);
tdep->mips_default_saved_regsize = 8;
tdep->mips_default_stack_argsize = 8;
tdep->mips_fp_register_double = 1;
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
- set_gdbarch_use_struct_convention (gdbarch,
- mips_n32n64_use_struct_convention);
set_gdbarch_deprecated_reg_struct_has_addr
(gdbarch, mips_n32n64_reg_struct_has_addr);
break;
set_gdbarch_deprecated_pop_frame (gdbarch, mips_pop_frame);
set_gdbarch_frame_align (gdbarch, mips_frame_align);
set_gdbarch_deprecated_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
- set_gdbarch_deprecated_register_convertible (gdbarch, mips_register_convertible);
- set_gdbarch_deprecated_register_convert_to_virtual (gdbarch, mips_register_convert_to_virtual);
- set_gdbarch_deprecated_register_convert_to_raw (gdbarch, mips_register_convert_to_raw);
set_gdbarch_deprecated_frame_chain (gdbarch, mips_frame_chain);
set_gdbarch_frameless_function_invocation (gdbarch,
fprintf_unfiltered (file,
"mips_dump_tdep: SIGFRAME_REGSAVE_OFF = %d\n",
SIGFRAME_REGSAVE_OFF);
- fprintf_unfiltered (file,
- "mips_dump_tdep: SIGFRAME_REG_SIZE = %d\n",
- SIGFRAME_REG_SIZE);
fprintf_unfiltered (file,
"mips_dump_tdep: SKIP_TRAMPOLINE_CODE # %s\n",
XSTRING (SKIP_TRAMPOLINE_CODE (PC)));