-/* Target-machine dependent code for Hitachi H8/300, for GDB.
+/* Target-machine dependent code for Renesas H8/300, for GDB.
- Copyright 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+ 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/*
Contributed by Steve Chamberlain
#include "defs.h"
#include "value.h"
-#include "inferior.h"
-#include "symfile.h"
#include "arch-utils.h"
#include "regcache.h"
#include "gdbcore.h"
#include "objfiles.h"
-#include "gdbcmd.h"
#include "gdb_assert.h"
#include "dis-asm.h"
-
-/* Extra info which is saved in each frame_info. */
-struct frame_extra_info
-{
- CORE_ADDR from_pc;
-};
-
-enum
-{
- h8300_reg_size = 2,
- h8300h_reg_size = 4,
- h8300_max_reg_size = 4,
-};
-#define BINWORD (h8300hmode ? h8300h_reg_size : h8300_reg_size)
+#include "dwarf2-frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
enum gdb_regnum
{
E_R0_REGNUM, E_ER0_REGNUM = E_R0_REGNUM, E_ARG0_REGNUM = E_R0_REGNUM,
- E_RET0_REGNUM = E_R0_REGNUM,
+ E_RET0_REGNUM = E_R0_REGNUM,
E_R1_REGNUM, E_ER1_REGNUM = E_R1_REGNUM, E_RET1_REGNUM = E_R1_REGNUM,
E_R2_REGNUM, E_ER2_REGNUM = E_R2_REGNUM, E_ARGLAST_REGNUM = E_R2_REGNUM,
E_R3_REGNUM, E_ER3_REGNUM = E_R3_REGNUM,
E_VBR_REGNUM
};
+#define H8300_MAX_NUM_REGS 18
+
#define E_PSEUDO_CCR_REGNUM (NUM_REGS)
#define E_PSEUDO_EXR_REGNUM (NUM_REGS+1)
-#define UNSIGNED_SHORT(X) ((X) & 0xffff)
+struct h8300_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR sp_offset;
+ CORE_ADDR pc;
+
+ /* Flag showing that a frame has been created in the prologue code. */
+ int uses_fp;
+
+ /* Saved registers. */
+ CORE_ADDR saved_regs[H8300_MAX_NUM_REGS];
+ CORE_ADDR saved_sp;
+};
+
+enum
+{
+ h8300_reg_size = 2,
+ h8300h_reg_size = 4,
+ h8300_max_reg_size = 4,
+};
+
+static int is_h8300hmode (struct gdbarch *gdbarch);
+static int is_h8300smode (struct gdbarch *gdbarch);
+static int is_h8300sxmode (struct gdbarch *gdbarch);
+static int is_h8300_normal_mode (struct gdbarch *gdbarch);
+
+#define BINWORD ((is_h8300hmode (current_gdbarch) \
+ && !is_h8300_normal_mode (current_gdbarch)) \
+ ? h8300h_reg_size : h8300_reg_size)
+
+static CORE_ADDR
+h8300_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_PC_REGNUM);
+}
+
+static CORE_ADDR
+h8300_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_SP_REGNUM);
+}
+
+static struct frame_id
+h8300_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (h8300_unwind_sp (gdbarch, next_frame),
+ frame_pc_unwind (next_frame));
+}
+
+/* Normal frames. */
+
+/* Allocate and initialize a frame cache. */
+
+static void
+h8300_init_frame_cache (struct h8300_frame_cache *cache)
+{
+ int i;
+
+ /* Base address. */
+ cache->base = 0;
+ cache->sp_offset = 0;
+ cache->pc = 0;
-#define IS_PUSH(x) ((x & 0xfff0)==0x6df0)
-#define IS_PUSH_FP(x) (x == 0x6df6)
-#define IS_MOVE_FP(x) (x == 0x0d76 || x == 0x0ff6)
-#define IS_MOV_SP_FP(x) (x == 0x0d76 || x == 0x0ff6)
-#define IS_SUB2_SP(x) (x==0x1b87)
-#define IS_SUB4_SP(x) (x==0x1b97)
-#define IS_SUBL_SP(x) (x==0x7a37)
-#define IS_MOVK_R5(x) (x==0x7905)
-#define IS_SUB_R5SP(x) (x==0x1957)
+ /* Frameless until proven otherwise. */
+ cache->uses_fp = 0;
+
+ /* Saved registers. We initialize these to -1 since zero is a valid
+ offset (that's where %fp is supposed to be stored). */
+ for (i = 0; i < NUM_REGS; i++)
+ cache->saved_regs[i] = -1;
+}
+
+#define IS_MOVB_RnRm(x) (((x) & 0xff88) == 0x0c88)
+#define IS_MOVW_RnRm(x) (((x) & 0xff88) == 0x0d00)
+#define IS_MOVL_RnRm(x) (((x) & 0xff88) == 0x0f80)
+#define IS_MOVB_Rn16_SP(x) (((x) & 0xfff0) == 0x6ee0)
+#define IS_MOVB_EXT(x) ((x) == 0x7860)
+#define IS_MOVB_Rn24_SP(x) (((x) & 0xfff0) == 0x6aa0)
+#define IS_MOVW_Rn16_SP(x) (((x) & 0xfff0) == 0x6fe0)
+#define IS_MOVW_EXT(x) ((x) == 0x78e0)
+#define IS_MOVW_Rn24_SP(x) (((x) & 0xfff0) == 0x6ba0)
+/* Same instructions as mov.w, just prefixed with 0x0100 */
+#define IS_MOVL_PRE(x) ((x) == 0x0100)
+#define IS_MOVL_Rn16_SP(x) (((x) & 0xfff0) == 0x6fe0)
+#define IS_MOVL_EXT(x) ((x) == 0x78e0)
+#define IS_MOVL_Rn24_SP(x) (((x) & 0xfff0) == 0x6ba0)
+
+#define IS_PUSHFP_MOVESPFP(x) ((x) == 0x6df60d76)
+#define IS_PUSH_FP(x) ((x) == 0x01006df6)
+#define IS_MOV_SP_FP(x) ((x) == 0x0ff6)
+#define IS_SUB2_SP(x) ((x) == 0x1b87)
+#define IS_SUB4_SP(x) ((x) == 0x1b97)
+#define IS_ADD_IMM_SP(x) ((x) == 0x7a1f)
+#define IS_SUB_IMM_SP(x) ((x) == 0x7a3f)
+#define IS_SUBL4_SP(x) ((x) == 0x1acf)
+#define IS_MOV_IMM_Rn(x) (((x) & 0xfff0) == 0x7905)
+#define IS_SUB_RnSP(x) (((x) & 0xff0f) == 0x1907)
+#define IS_ADD_RnSP(x) (((x) & 0xff0f) == 0x0907)
+#define IS_PUSH(x) (((x) & 0xfff0) == 0x6df0)
/* If the instruction at PC is an argument register spill, return its
length. Otherwise, return zero.
{
int w = read_memory_unsigned_integer (pc, 2);
- if (((w & 0xff88) == 0x0c88 /* mov.b Rsl, Rdl */
- || (w & 0xff88) == 0x0d00 /* mov.w Rs, Rd */
- || (w & 0xff88) == 0x0f80) /* mov.l Rs, Rd */
- && (w & 0x70) <= 0x20 /* Rs is R0, R1 or R2 */
- && (w & 0x7) >= 0x3 && (w & 0x7) <= 0x5)/* Rd is R3, R4 or R5 */
+ if ((IS_MOVB_RnRm (w) || IS_MOVW_RnRm (w) || IS_MOVL_RnRm (w))
+ && (w & 0x70) <= 0x20 /* Rs is R0, R1 or R2 */
+ && (w & 0x7) >= 0x3 && (w & 0x7) <= 0x5) /* Rd is R3, R4 or R5 */
return 2;
- if ((w & 0xfff0) == 0x6ee0 /* mov.b Rs,@(d:16,er6) */
- && 8 <= (w & 0xf) && (w & 0xf) <= 10) /* Rs is R0L, R1L, or R2L */
+ if (IS_MOVB_Rn16_SP (w)
+ && 8 <= (w & 0xf) && (w & 0xf) <= 10) /* Rs is R0L, R1L, or R2L */
{
- int w2 = read_memory_integer (pc + 2, 2);
-
- /* ... and d:16 is negative. */
- if (w2 < 0)
- return 4;
+ if (read_memory_integer (pc + 2, 2) < 0) /* ... and d:16 is negative. */
+ return 4;
}
- else if (w == 0x7860)
+ else if (IS_MOVB_EXT (w))
{
- int w2 = read_memory_integer (pc + 2, 2);
-
- if ((w2 & 0xfff0) == 0x6aa0) /* mov.b Rs, @(d:24,er6) */
- {
- LONGEST disp = read_memory_integer (pc + 4, 4);
+ if (IS_MOVB_Rn24_SP (read_memory_unsigned_integer (pc + 2, 2)))
+ {
+ LONGEST disp = read_memory_integer (pc + 4, 4);
- /* ... and d:24 is negative. */
- if (disp < 0 && disp > 0xffffff)
- return 8;
- }
+ /* ... and d:24 is negative. */
+ if (disp < 0 && disp > 0xffffff)
+ return 8;
+ }
}
- else if ((w & 0xfff0) == 0x6fe0 /* mov.w Rs,@(d:16,er6) */
- && (w & 0xf) <= 2) /* Rs is R0, R1, or R2 */
+ else if (IS_MOVW_Rn16_SP (w)
+ && (w & 0xf) <= 2) /* Rs is R0, R1, or R2 */
{
- int w2 = read_memory_integer (pc + 2, 2);
-
/* ... and d:16 is negative. */
- if (w2 < 0)
- return 4;
+ if (read_memory_integer (pc + 2, 2) < 0)
+ return 4;
}
- else if (w == 0x78e0)
+ else if (IS_MOVW_EXT (w))
{
- int w2 = read_memory_integer (pc + 2, 2);
-
- if ((w2 & 0xfff0) == 0x6ba0) /* mov.b Rs, @(d:24,er6) */
- {
- LONGEST disp = read_memory_integer (pc + 4, 4);
+ if (IS_MOVW_Rn24_SP (read_memory_unsigned_integer (pc + 2, 2)))
+ {
+ LONGEST disp = read_memory_integer (pc + 4, 4);
- /* ... and d:24 is negative. */
- if (disp < 0 && disp > 0xffffff)
- return 8;
- }
+ /* ... and d:24 is negative. */
+ if (disp < 0 && disp > 0xffffff)
+ return 8;
+ }
}
- else if (w == 0x0100)
+ else if (IS_MOVL_PRE (w))
{
int w2 = read_memory_integer (pc + 2, 2);
- if ((w2 & 0xfff0) == 0x6fe0 /* mov.l Rs,@(d:16,er6) */
- && (w2 & 0xf) <= 2) /* Rs is ER0, ER1, or ER2 */
- {
- int w3 = read_memory_integer (pc + 4, 2);
-
- /* ... and d:16 is negative. */
- if (w3 < 0)
- return 6;
- }
- else if (w2 == 0x78e0)
- {
- int w3 = read_memory_integer (pc + 4, 2);
-
- if ((w3 & 0xfff0) == 0x6ba0) /* mov.l Rs, @(d:24,er6) */
- {
- LONGEST disp = read_memory_integer (pc + 6, 4);
-
- /* ... and d:24 is negative. */
- if (disp < 0 && disp > 0xffffff)
- return 10;
- }
- }
- }
-
- return 0;
-}
-
-static CORE_ADDR
-h8300_skip_prologue (CORE_ADDR start_pc)
-{
- short int w;
- int adjust = 0;
-
- /* Skip past all push and stm insns. */
- while (1)
- {
- w = read_memory_unsigned_integer (start_pc, 2);
- /* First look for push insns. */
- if (w == 0x0100 || w == 0x0110 || w == 0x0120 || w == 0x0130)
+ if (IS_MOVL_Rn16_SP (w2)
+ && (w2 & 0xf) <= 2) /* Rs is ER0, ER1, or ER2 */
{
- w = read_memory_unsigned_integer (start_pc + 2, 2);
- adjust = 2;
+ /* ... and d:16 is negative. */
+ if (read_memory_integer (pc + 4, 2) < 0)
+ return 6;
}
-
- if (IS_PUSH (w))
+ else if (IS_MOVL_EXT (w2))
{
- start_pc += 2 + adjust;
- w = read_memory_unsigned_integer (start_pc, 2);
- continue;
- }
- adjust = 0;
- break;
- }
+ int w3 = read_memory_integer (pc + 4, 2);
- /* Skip past a move to FP, either word or long sized */
- w = read_memory_unsigned_integer (start_pc, 2);
- if (w == 0x0100)
- {
- w = read_memory_unsigned_integer (start_pc + 2, 2);
- adjust += 2;
- }
+ if (IS_MOVL_Rn24_SP (read_memory_integer (pc + 4, 2)))
+ {
+ LONGEST disp = read_memory_integer (pc + 6, 4);
- if (IS_MOVE_FP (w))
- {
- start_pc += 2 + adjust;
- w = read_memory_unsigned_integer (start_pc, 2);
+ /* ... and d:24 is negative. */
+ if (disp < 0 && disp > 0xffffff)
+ return 10;
+ }
+ }
}
- /* Check for loading either a word constant into r5;
- long versions are handled by the SUBL_SP below. */
- if (IS_MOVK_R5 (w))
- {
- start_pc += 2;
- w = read_memory_unsigned_integer (start_pc, 2);
- }
+ return 0;
+}
- /* Now check for subtracting r5 from sp, word sized only. */
- if (IS_SUB_R5SP (w))
- {
- start_pc += 2 + adjust;
- w = read_memory_unsigned_integer (start_pc, 2);
- }
+/* Do a full analysis of the prologue at PC and update CACHE
+ accordingly. Bail out early if CURRENT_PC is reached. Return the
+ address where the analysis stopped.
- /* Check for subs #2 and subs #4. */
- while (IS_SUB2_SP (w) || IS_SUB4_SP (w))
- {
- start_pc += 2 + adjust;
- w = read_memory_unsigned_integer (start_pc, 2);
- }
+ We handle all cases that can be generated by gcc.
- /* Check for a 32bit subtract. */
- if (IS_SUBL_SP (w))
- start_pc += 6 + adjust;
+ For allocating a stack frame:
- /* Skip past another possible stm insn for registers R3 to R5 (possibly used
- for register qualified arguments. */
- w = read_memory_unsigned_integer (start_pc, 2);
- /* First look for push insns. */
- if (w == 0x0110 || w == 0x0120 || w == 0x0130)
- {
- w = read_memory_unsigned_integer (start_pc + 2, 2);
- if (IS_PUSH (w) && (w & 0xf) >= 0x3 && (w & 0xf) <= 0x5)
- start_pc += 4;
- }
+ mov.w r6,@-sp
+ mov.w sp,r6
+ mov.w #-n,rN
+ add.w rN,sp
- /* Check for spilling an argument register to the stack frame.
- This could also be an initializing store from non-prologue code,
- but I don't think there's any harm in skipping that. */
- for (;;)
- {
- int spill_size = h8300_is_argument_spill (start_pc);
- if (spill_size == 0)
- break;
- start_pc += spill_size;
- }
+ mov.w r6,@-sp
+ mov.w sp,r6
+ subs #2,sp
+ (repeat)
- return start_pc;
-}
+ mov.l er6,@-sp
+ mov.l sp,er6
+ add.l #-n,sp
-/* Fetch the instruction at ADDR, returning 0 if ADDR is beyond LIM or
- is not the address of a valid instruction, the address of the next
- instruction beyond ADDR otherwise. *PWORD1 receives the first word
- of the instruction. */
+ mov.w r6,@-sp
+ mov.w sp,r6
+ subs #4,sp
+ (repeat)
-static CORE_ADDR
-h8300_next_prologue_insn (CORE_ADDR addr,
- CORE_ADDR lim,
- unsigned short* pword1)
-{
- char buf[2];
- if (addr < lim + 8)
- {
- read_memory (addr, buf, 2);
- *pword1 = extract_signed_integer (buf, 2);
+ For saving registers:
- return addr + 2;
- }
- return 0;
-}
+ mov.w rN,@-sp
+ mov.l erN,@-sp
+ stm.l reglist,@-sp
-/* Examine the prologue of a function. `ip' points to the first instruction.
- `limit' is the limit of the prologue (e.g. the addr of the first
- linenumber, or perhaps the program counter if we're stepping through).
- `frame_sp' is the stack pointer value in use in this frame.
- `fsr' is a pointer to a frame_saved_regs structure into which we put
- info about the registers saved by this frame.
- `fi' is a struct frame_info pointer; we fill in various fields in it
- to reflect the offsets of the arg pointer and the locals pointer. */
-
-/* Any function with a frame looks like this
- SECOND ARG
- FIRST ARG
- RET PC
- SAVED R2
- SAVED R3
- SAVED FP <-FP POINTS HERE
- LOCALS0
- LOCALS1 <-SP POINTS HERE
- */
+ */
static CORE_ADDR
-h8300_examine_prologue (register CORE_ADDR ip, register CORE_ADDR limit,
- CORE_ADDR after_prolog_fp, CORE_ADDR *fsr,
- struct frame_info *fi)
+h8300_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct h8300_frame_cache *cache)
{
- register CORE_ADDR next_ip;
- int r;
- int have_fp = 0;
- unsigned short insn_word;
- /* Number of things pushed onto stack, starts at 2/4, 'cause the
- PC is already there */
- unsigned int reg_save_depth = BINWORD;
-
- unsigned int auto_depth = 0; /* Number of bytes of autos */
-
- char in_frame[11]; /* One for each reg */
-
- int adjust = 0;
-
- memset (in_frame, 1, 11);
- for (r = 0; r < 8; r++)
- {
- fsr[r] = 0;
- }
- if (after_prolog_fp == 0)
- {
- after_prolog_fp = read_register (E_SP_REGNUM);
- }
+ unsigned int op;
+ int regno, i, spill_size;
- /* If the PC isn't valid, quit now. */
- if (ip == 0 || ip & (h8300hmode ? ~0xffffff : ~0xffff))
- return 0;
+ cache->sp_offset = 0;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
+ if (pc >= current_pc)
+ return current_pc;
- if (insn_word == 0x0100) /* mov.l */
- {
- insn_word = read_memory_unsigned_integer (ip + 2, 2);
- adjust = 2;
- }
+ op = read_memory_unsigned_integer (pc, 4);
- /* Skip over any fp push instructions */
- fsr[E_FP_REGNUM] = after_prolog_fp;
- while (next_ip && IS_PUSH_FP (insn_word))
+ if (IS_PUSHFP_MOVESPFP (op))
{
- ip = next_ip + adjust;
-
- in_frame[insn_word & 0x7] = reg_save_depth;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
- reg_save_depth += 2 + adjust;
+ cache->saved_regs[E_FP_REGNUM] = 0;
+ cache->uses_fp = 1;
+ pc += 4;
}
-
- /* Is this a move into the fp */
- if (next_ip && IS_MOV_SP_FP (insn_word))
+ else if (IS_PUSH_FP (op))
{
- ip = next_ip;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
- have_fp = 1;
+ cache->saved_regs[E_FP_REGNUM] = 0;
+ pc += 4;
+ if (pc >= current_pc)
+ return current_pc;
+ op = read_memory_unsigned_integer (pc, 2);
+ if (IS_MOV_SP_FP (op))
+ {
+ cache->uses_fp = 1;
+ pc += 2;
+ }
}
- /* Skip over any stack adjustment, happens either with a number of
- sub#2,sp or a mov #x,r5 sub r5,sp */
-
- if (next_ip && (IS_SUB2_SP (insn_word) || IS_SUB4_SP (insn_word)))
+ while (pc < current_pc)
{
- while (next_ip && (IS_SUB2_SP (insn_word) || IS_SUB4_SP (insn_word)))
+ op = read_memory_unsigned_integer (pc, 2);
+ if (IS_SUB2_SP (op))
{
- auto_depth += IS_SUB2_SP (insn_word) ? 2 : 4;
- ip = next_ip;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
+ cache->sp_offset += 2;
+ pc += 2;
}
- }
- else
- {
- if (next_ip && IS_MOVK_R5 (insn_word))
+ else if (IS_SUB4_SP (op))
{
- ip = next_ip;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
- auto_depth += insn_word;
-
- next_ip = h8300_next_prologue_insn (next_ip, limit, &insn_word);
- auto_depth += insn_word;
+ cache->sp_offset += 4;
+ pc += 2;
}
- if (next_ip && IS_SUBL_SP (insn_word))
+ else if (IS_ADD_IMM_SP (op))
{
- ip = next_ip;
- auto_depth += read_memory_unsigned_integer (ip, 4);
- ip += 4;
-
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
+ cache->sp_offset += -read_memory_integer (pc + 2, 2);
+ pc += 4;
}
- }
-
- /* Now examine the push insns to determine where everything lives
- on the stack. */
- while (1)
- {
- adjust = 0;
- if (!next_ip)
- break;
-
- if (insn_word == 0x0100)
+ else if (IS_SUB_IMM_SP (op))
{
- ip = next_ip;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
- adjust = 2;
+ cache->sp_offset += read_memory_integer (pc + 2, 2);
+ pc += 4;
}
-
- if (IS_PUSH (insn_word))
+ else if (IS_SUBL4_SP (op))
{
- auto_depth += 2 + adjust;
- fsr[insn_word & 0x7] = after_prolog_fp - auto_depth;
- ip = next_ip;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
- continue;
+ cache->sp_offset += 4;
+ pc += 2;
}
-
- /* Now check for push multiple insns. */
- if (insn_word == 0x0110 || insn_word == 0x0120 || insn_word == 0x0130)
+ else if (IS_MOV_IMM_Rn (op))
+ {
+ int offset = read_memory_integer (pc + 2, 2);
+ regno = op & 0x000f;
+ op = read_memory_unsigned_integer (pc + 4, 2);
+ if (IS_ADD_RnSP (op) && (op & 0x00f0) == regno)
+ {
+ cache->sp_offset -= offset;
+ pc += 6;
+ }
+ else if (IS_SUB_RnSP (op) && (op & 0x00f0) == regno)
+ {
+ cache->sp_offset += offset;
+ pc += 6;
+ }
+ else
+ break;
+ }
+ else if (IS_PUSH (op))
{
- int count = ((insn_word >> 4) & 0xf) + 1;
- int start, i;
-
- ip = next_ip;
- next_ip = h8300_next_prologue_insn (ip, limit, &insn_word);
- start = insn_word & 0x7;
-
- for (i = start; i < start + count; i++)
+ regno = op & 0x000f;
+ cache->sp_offset += 2;
+ cache->saved_regs[regno] = cache->sp_offset;
+ pc += 2;
+ }
+ else if (op == 0x0100)
+ {
+ op = read_memory_unsigned_integer (pc + 2, 2);
+ if (IS_PUSH (op))
{
- auto_depth += 4;
- fsr[i] = after_prolog_fp - auto_depth;
+ regno = op & 0x000f;
+ cache->sp_offset += 4;
+ cache->saved_regs[regno] = cache->sp_offset;
+ pc += 4;
}
+ else
+ break;
}
- break;
+ else if ((op & 0xffcf) == 0x0100)
+ {
+ int op1;
+ op1 = read_memory_unsigned_integer (pc + 2, 2);
+ if (IS_PUSH (op1))
+ {
+ /* Since the prefix is 0x01x0, this is not a simple pushm but a
+ stm.l reglist,@-sp */
+ i = ((op & 0x0030) >> 4) + 1;
+ regno = op1 & 0x000f;
+ for (; i > 0; regno++, --i)
+ {
+ cache->sp_offset += 4;
+ cache->saved_regs[regno] = cache->sp_offset;
+ }
+ pc += 4;
+ }
+ else
+ break;
+ }
+ else
+ break;
}
- /* The PC is at a known place */
- get_frame_extra_info (fi)->from_pc =
- read_memory_unsigned_integer (after_prolog_fp + BINWORD, BINWORD);
+ /* Check for spilling an argument register to the stack frame.
+ This could also be an initializing store from non-prologue code,
+ but I don't think there's any harm in skipping that. */
+ while ((spill_size = h8300_is_argument_spill (pc)) > 0
+ && pc + spill_size <= current_pc)
+ pc += spill_size;
+
+ return pc;
+}
+
+static struct h8300_frame_cache *
+h8300_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+ struct h8300_frame_cache *cache;
+ char buf[4];
+ int i;
+ CORE_ADDR current_pc;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct h8300_frame_cache);
+ h8300_init_frame_cache (cache);
+ *this_cache = cache;
+
+ /* In principle, for normal frames, %fp holds the frame pointer,
+ which holds the base address for the current stack frame.
+ However, for functions that don't need it, the frame pointer is
+ optional. For these "frameless" functions the frame pointer is
+ actually the frame pointer of the calling frame. */
+
+ cache->base = frame_unwind_register_unsigned (next_frame, E_FP_REGNUM);
+ if (cache->base == 0)
+ return cache;
+
+ cache->saved_regs[E_PC_REGNUM] = -BINWORD;
- /* Rememeber any others too */
- in_frame[E_PC_REGNUM] = 0;
+ cache->pc = frame_func_unwind (next_frame);
+ current_pc = frame_pc_unwind (next_frame);
+ if (cache->pc != 0)
+ h8300_analyze_prologue (cache->pc, current_pc, cache);
- if (have_fp)
- /* We keep the old FP in the SP spot */
- fsr[E_SP_REGNUM] = read_memory_unsigned_integer (fsr[E_FP_REGNUM],
- BINWORD);
+ if (!cache->uses_fp)
+ {
+ /* We didn't find a valid frame, which means that CACHE->base
+ currently holds the frame pointer for our calling frame. If
+ we're at the start of a function, or somewhere half-way its
+ prologue, the function's frame probably hasn't been fully
+ setup yet. Try to reconstruct the base address for the stack
+ frame by looking at the stack pointer. For truly "frameless"
+ functions this might work too. */
+
+ cache->base = frame_unwind_register_unsigned (next_frame, E_SP_REGNUM)
+ + cache->sp_offset;
+ cache->saved_sp = cache->base + BINWORD;
+ cache->saved_regs[E_PC_REGNUM] = 0;
+ }
else
- fsr[E_SP_REGNUM] = after_prolog_fp + auto_depth;
+ {
+ cache->saved_sp = cache->base + 2 * BINWORD;
+ cache->saved_regs[E_PC_REGNUM] = -BINWORD;
+ }
+
+ /* Adjust all the saved registers such that they contain addresses
+ instead of offsets. */
+ for (i = 0; i < NUM_REGS; i++)
+ if (cache->saved_regs[i] != -1)
+ cache->saved_regs[i] = cache->base - cache->saved_regs[i];
- return (ip);
+ return cache;
}
static void
-h8300_frame_init_saved_regs (struct frame_info *fi)
+h8300_frame_this_id (struct frame_info *next_frame, void **this_cache,
+ struct frame_id *this_id)
{
- CORE_ADDR func_addr, func_end;
+ struct h8300_frame_cache *cache =
+ h8300_frame_cache (next_frame, this_cache);
- if (!get_frame_saved_regs (fi))
- {
- frame_saved_regs_zalloc (fi);
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
- /* Find the beginning of this function, so we can analyze its
- prologue. */
- if (find_pc_partial_function (get_frame_pc (fi), NULL,
- &func_addr, &func_end))
- {
- struct symtab_and_line sal = find_pc_line (func_addr, 0);
- CORE_ADDR limit = (sal.end && sal.end < get_frame_pc (fi))
- ? sal.end : get_frame_pc (fi);
- /* This will fill in fields in fi. */
- h8300_examine_prologue (func_addr, limit, get_frame_base (fi),
- get_frame_saved_regs (fi), fi);
- }
- /* Else we're out of luck (can't debug completely stripped code).
- FIXME. */
- }
+ *this_id = frame_id_build (cache->saved_sp, cache->pc);
}
-/* Given a GDB frame, determine the address of the calling function's
- frame. This will be used to create a new GDB frame struct, and
- then DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_INIT_FRAME_PC
- will be called for the new frame.
+static void
+h8300_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+ int regnum, int *optimizedp,
+ enum lval_type *lvalp, CORE_ADDR *addrp,
+ int *realnump, gdb_byte *valuep)
+{
+ struct h8300_frame_cache *cache =
+ h8300_frame_cache (next_frame, this_cache);
- For us, the frame address is its stack pointer value, so we look up
- the function prologue to determine the caller's sp value, and
- return it. */
+ gdb_assert (regnum >= 0);
-static CORE_ADDR
-h8300_frame_chain (struct frame_info *thisframe)
-{
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (thisframe),
- get_frame_base (thisframe),
- get_frame_base (thisframe)))
- { /* initialize the from_pc now */
- get_frame_extra_info (thisframe)->from_pc =
- deprecated_read_register_dummy (get_frame_pc (thisframe),
- get_frame_base (thisframe),
- E_PC_REGNUM);
- return get_frame_base (thisframe);
+ if (regnum == E_SP_REGNUM && cache->saved_sp)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ store_unsigned_integer (valuep, BINWORD, cache->saved_sp);
+ return;
+ }
+
+ if (regnum < NUM_REGS && cache->saved_regs[regnum] != -1)
+ {
+ *optimizedp = 0;
+ *lvalp = lval_memory;
+ *addrp = cache->saved_regs[regnum];
+ *realnump = -1;
+ if (valuep)
+ read_memory (*addrp, valuep, register_size (current_gdbarch, regnum));
+ return;
}
- return get_frame_saved_regs (thisframe)[E_SP_REGNUM];
+
+ frame_register_unwind (next_frame, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
}
-/* Return the saved PC from this frame.
+static const struct frame_unwind h8300_frame_unwind = {
+ NORMAL_FRAME,
+ h8300_frame_this_id,
+ h8300_frame_prev_register
+};
- If the frame has a memory copy of SRP_REGNUM, use that. If not,
- just use the register SRP_REGNUM itself. */
+static const struct frame_unwind *
+h8300_frame_sniffer (struct frame_info *next_frame)
+{
+ return &h8300_frame_unwind;
+}
static CORE_ADDR
-h8300_frame_saved_pc (struct frame_info *frame)
+h8300_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
- get_frame_base (frame),
- get_frame_base (frame)))
- return deprecated_read_register_dummy (get_frame_pc (frame),
- get_frame_base (frame),
- E_PC_REGNUM);
- else
- return get_frame_extra_info (frame)->from_pc;
+ struct h8300_frame_cache *cache = h8300_frame_cache (next_frame, this_cache);
+ return cache->base;
}
-static void
-h8300_init_extra_frame_info (int fromleaf, struct frame_info *fi)
+static const struct frame_base h8300_frame_base = {
+ &h8300_frame_unwind,
+ h8300_frame_base_address,
+ h8300_frame_base_address,
+ h8300_frame_base_address
+};
+
+static CORE_ADDR
+h8300_skip_prologue (CORE_ADDR pc)
{
- if (!get_frame_extra_info (fi))
+ CORE_ADDR func_addr = 0 , func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
{
- frame_extra_info_zalloc (fi, sizeof (struct frame_extra_info));
- get_frame_extra_info (fi)->from_pc = 0;
-
- if (!get_frame_pc (fi))
- {
- if (get_next_frame (fi))
- deprecated_update_frame_pc_hack (fi, h8300_frame_saved_pc (get_next_frame (fi)));
- }
- h8300_frame_init_saved_regs (fi);
+ struct symtab_and_line sal;
+ struct h8300_frame_cache cache;
+
+ /* Found a function. */
+ sal = find_pc_line (func_addr, 0);
+ if (sal.end && sal.end < func_end)
+ /* Found a line number, use it as end of prologue. */
+ return sal.end;
+
+ /* No useable line symbol. Use prologue parsing method. */
+ h8300_init_frame_cache (&cache);
+ return h8300_analyze_prologue (func_addr, func_end, &cache);
}
-}
-/* Round N up or down to the nearest multiple of UNIT.
- Evaluate N only once, UNIT several times.
- UNIT must be a power of two. */
-#define round_up(n, unit) (((n) + (unit) - 1) & -(unit))
-#define round_down(n, unit) ((n) & -(unit))
+ /* No function symbol -- just return the PC. */
+ return (CORE_ADDR) pc;
+}
/* Function: push_dummy_call
Setup the function arguments for calling a function in the inferior.
to begin with. */
static CORE_ADDR
-h8300_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
- struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp, int struct_return,
- CORE_ADDR struct_addr)
+h8300_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)
{
int stack_alloc = 0, stack_offset = 0;
int wordsize = BINWORD;
int argument;
/* First, make sure the stack is properly aligned. */
- sp = round_down (sp, wordsize);
+ sp = align_down (sp, wordsize);
/* Now make sure there's space on the stack for the arguments. We
may over-allocate a little here, but that won't hurt anything. */
for (argument = 0; argument < nargs; argument++)
- stack_alloc += round_up (TYPE_LENGTH (VALUE_TYPE (args[argument])),
- wordsize);
+ stack_alloc += align_up (TYPE_LENGTH (value_type (args[argument])),
+ wordsize);
sp -= stack_alloc;
/* Now load as many arguments as possible into registers, and push
for (argument = 0; argument < nargs; argument++)
{
- struct type *type = VALUE_TYPE (args[argument]);
+ struct type *type = value_type (args[argument]);
int len = TYPE_LENGTH (type);
- char *contents = (char *) VALUE_CONTENTS (args[argument]);
+ char *contents = (char *) value_contents (args[argument]);
/* Pad the argument appropriately. */
- int padded_len = round_up (len, wordsize);
- char *padded = alloca (padded_len);
+ int padded_len = align_up (len, wordsize);
+ gdb_byte *padded = alloca (padded_len);
memset (padded, 0, padded_len);
memcpy (len < wordsize ? padded + padded_len - len : padded,
- contents, len);
+ contents, len);
/* Could the argument fit in the remaining registers? */
if (padded_len <= (E_ARGLAST_REGNUM - reg + 1) * wordsize)
- {
- /* Are we going to pass it on the stack anyway, for no good
- reason? */
- if (len > wordsize && len % wordsize)
- {
- /* I feel so unclean. */
- write_memory (sp + stack_offset, padded, padded_len);
- stack_offset += padded_len;
-
- /* That's right --- even though we passed the argument
- on the stack, we consume the registers anyway! Love
- me, love my dog. */
- reg += padded_len / wordsize;
- }
- else
- {
- /* Heavens to Betsy --- it's really going in registers!
- It would be nice if we could use write_register_bytes
- here, but on the h8/300s, there are gaps between
- the registers in the register file. */
- int offset;
-
- for (offset = 0; offset < padded_len; offset += wordsize)
- {
- ULONGEST word = extract_unsigned_integer (padded + offset,
+ {
+ /* Are we going to pass it on the stack anyway, for no good
+ reason? */
+ if (len > wordsize && len % wordsize)
+ {
+ /* I feel so unclean. */
+ write_memory (sp + stack_offset, padded, padded_len);
+ stack_offset += padded_len;
+
+ /* That's right --- even though we passed the argument
+ on the stack, we consume the registers anyway! Love
+ me, love my dog. */
+ reg += padded_len / wordsize;
+ }
+ else
+ {
+ /* Heavens to Betsy --- it's really going in registers!
+ It would be nice if we could use write_register_bytes
+ here, but on the h8/300s, there are gaps between
+ the registers in the register file. */
+ int offset;
+
+ for (offset = 0; offset < padded_len; offset += wordsize)
+ {
+ ULONGEST word = extract_unsigned_integer (padded + offset,
wordsize);
regcache_cooked_write_unsigned (regcache, reg++, word);
- }
- }
- }
+ }
+ }
+ }
else
- {
- /* It doesn't fit in registers! Onto the stack it goes. */
- write_memory (sp + stack_offset, padded, padded_len);
- stack_offset += padded_len;
-
- /* Once one argument has spilled onto the stack, all
- subsequent arguments go on the stack. */
- reg = E_ARGLAST_REGNUM + 1;
- }
+ {
+ /* It doesn't fit in registers! Onto the stack it goes. */
+ write_memory (sp + stack_offset, padded, padded_len);
+ stack_offset += padded_len;
+
+ /* Once one argument has spilled onto the stack, all
+ subsequent arguments go on the stack. */
+ reg = E_ARGLAST_REGNUM + 1;
+ }
}
/* Store return address. */
/* Update stack pointer. */
regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, sp);
- return sp;
-}
-
-/* Function: h8300_pop_frame
- Restore the machine to the state it had before the current frame
- was created. Usually used either by the "RETURN" command, or by
- call_function_by_hand after the dummy_frame is finished. */
-
-static void
-h8300_pop_frame (void)
-{
- unsigned regno;
- struct frame_info *frame = get_current_frame ();
-
- if (DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (frame),
- get_frame_base (frame),
- get_frame_base (frame)))
- {
- generic_pop_dummy_frame ();
- }
- else
- {
- for (regno = 0; regno < 8; regno++)
- {
- /* Don't forget E_SP_REGNUM is a frame_saved_regs struct is the
- actual value we want, not the address of the value we want. */
- if (get_frame_saved_regs (frame)[regno] && regno != E_SP_REGNUM)
- write_register (regno,
- read_memory_integer
- (get_frame_saved_regs (frame)[regno], BINWORD));
- else if (get_frame_saved_regs (frame)[regno] && regno == E_SP_REGNUM)
- write_register (regno, get_frame_base (frame) + 2 * BINWORD);
- }
-
- /* Don't forget to update the PC too! */
- write_register (E_PC_REGNUM, get_frame_extra_info (frame)->from_pc);
- }
- flush_cached_frames ();
+ /* Return the new stack pointer minus the return address slot since
+ that's what DWARF2/GCC uses as the frame's CFA. */
+ return sp + wordsize;
}
/* Function: extract_return_value
switch (len)
{
- case 1:
- case 2:
- regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
- store_unsigned_integer (valbuf, len, c);
- break;
- case 4: /* Needs two registers on plain H8/300 */
- regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
- store_unsigned_integer (valbuf, 2, c);
- regcache_cooked_read_unsigned (regcache, E_RET1_REGNUM, &c);
- store_unsigned_integer ((void*)((char *)valbuf + 2), 2, c);
- break;
- case 8: /* long long is now 8 bytes. */
- if (TYPE_CODE (type) == TYPE_CODE_INT)
- {
- regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &addr);
- c = read_memory_unsigned_integer ((CORE_ADDR) addr, len);
- store_unsigned_integer (valbuf, len, c);
- }
- else
- {
- error ("I don't know how this 8 byte value is returned.");
- }
- break;
+ case 1:
+ case 2:
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
+ store_unsigned_integer (valbuf, len, c);
+ break;
+ case 4: /* Needs two registers on plain H8/300 */
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
+ store_unsigned_integer (valbuf, 2, c);
+ regcache_cooked_read_unsigned (regcache, E_RET1_REGNUM, &c);
+ store_unsigned_integer ((void *) ((char *) valbuf + 2), 2, c);
+ break;
+ case 8: /* long long is now 8 bytes. */
+ if (TYPE_CODE (type) == TYPE_CODE_INT)
+ {
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &addr);
+ c = read_memory_unsigned_integer ((CORE_ADDR) addr, len);
+ store_unsigned_integer (valbuf, len, c);
+ }
+ else
+ {
+ error ("I don't know how this 8 byte value is returned.");
+ }
+ break;
}
}
static void
h8300h_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
+ void *valbuf)
{
int len = TYPE_LENGTH (type);
ULONGEST c, addr;
switch (len)
{
- case 1:
- case 2:
- case 4:
- regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
- store_unsigned_integer (valbuf, len, c);
- break;
- case 8: /* long long is now 8 bytes. */
- if (TYPE_CODE (type) == TYPE_CODE_INT)
- {
- regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &addr);
- c = read_memory_unsigned_integer ((CORE_ADDR) addr, len);
- store_unsigned_integer (valbuf, len, c);
- }
- else
- {
- error ("I don't know how this 8 byte value is returned.");
- }
- break;
+ case 1:
+ case 2:
+ case 4:
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
+ store_unsigned_integer (valbuf, len, c);
+ break;
+ case 8: /* long long is now 8 bytes. */
+ if (TYPE_CODE (type) == TYPE_CODE_INT)
+ {
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
+ store_unsigned_integer (valbuf, 4, c);
+ regcache_cooked_read_unsigned (regcache, E_RET1_REGNUM, &c);
+ store_unsigned_integer ((void *) ((char *) valbuf + 4), 4, c);
+ }
+ else
+ {
+ error ("I don't know how this 8 byte value is returned.");
+ }
+ break;
}
}
+int
+h8300_use_struct_convention (struct type *value_type)
+{
+ /* Types of 1, 2 or 4 bytes are returned in R0/R1, everything else on the
+ stack. */
+
+ if (TYPE_CODE (value_type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (value_type) == TYPE_CODE_UNION)
+ return 1;
+ return !(TYPE_LENGTH (value_type) == 1
+ || TYPE_LENGTH (value_type) == 2
+ || TYPE_LENGTH (value_type) == 4);
+}
+
+int
+h8300h_use_struct_convention (struct type *value_type)
+{
+ /* Types of 1, 2 or 4 bytes are returned in R0, INT types of 8 bytes are
+ returned in R0/R1, everything else on the stack. */
+ if (TYPE_CODE (value_type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (value_type) == TYPE_CODE_UNION)
+ return 1;
+ return !(TYPE_LENGTH (value_type) == 1
+ || TYPE_LENGTH (value_type) == 2
+ || TYPE_LENGTH (value_type) == 4
+ || (TYPE_LENGTH (value_type) == 8
+ && TYPE_CODE (value_type) == TYPE_CODE_INT));
+}
/* Function: store_return_value
Place the appropriate value in the appropriate registers.
switch (len)
{
- case 1:
- case 2: /* short... */
- val = extract_unsigned_integer (valbuf, len);
- regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM, val);
- break;
- case 4: /* long, float */
- val = extract_unsigned_integer (valbuf, len);
- regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM,
- (val >> 16) &0xffff);
- regcache_cooked_write_unsigned (regcache, E_RET1_REGNUM, val & 0xffff);
- break;
- case 8: /* long long, double and long double are all defined
- as 4 byte types so far so this shouldn't happen. */
- error ("I don't know how to return an 8 byte value.");
- break;
+ case 1:
+ case 2: /* short... */
+ val = extract_unsigned_integer (valbuf, len);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM, val);
+ break;
+ case 4: /* long, float */
+ val = extract_unsigned_integer (valbuf, len);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM,
+ (val >> 16) & 0xffff);
+ regcache_cooked_write_unsigned (regcache, E_RET1_REGNUM, val & 0xffff);
+ break;
+ case 8: /* long long, double and long double are all defined
+ as 4 byte types so far so this shouldn't happen. */
+ error ("I don't know how to return an 8 byte value.");
+ break;
}
}
switch (len)
{
- case 1:
- case 2:
- case 4: /* long, float */
- val = extract_unsigned_integer (valbuf, len);
- regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM, val);
- break;
- case 8: /* long long, double and long double are all defined
- as 4 byte types so far so this shouldn't happen. */
- error ("I don't know how to return an 8 byte value.");
- break;
+ case 1:
+ case 2:
+ case 4: /* long, float */
+ val = extract_unsigned_integer (valbuf, len);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM, val);
+ break;
+ case 8:
+ val = extract_unsigned_integer (valbuf, len);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM,
+ (val >> 32) & 0xffffffff);
+ regcache_cooked_write_unsigned (regcache, E_RET1_REGNUM,
+ val & 0xffffffff);
+ break;
}
}
+static enum return_value_convention
+h8300_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (h8300_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ h8300_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ h8300_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+static enum return_value_convention
+h8300h_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (h8300h_use_struct_convention (type))
+ {
+ if (readbuf)
+ {
+ ULONGEST addr;
+
+ regcache_raw_read_unsigned (regcache, E_R0_REGNUM, &addr);
+ read_memory (addr, readbuf, TYPE_LENGTH (type));
+ }
+
+ return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+ }
+ if (writebuf)
+ h8300h_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ h8300h_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
static struct cmd_list_element *setmachinelist;
static const char *
type is selected. */
static char *register_names[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6",
- "sp", "","pc","cycles", "tick", "inst",
- "ccr", /* pseudo register */
+ "sp", "", "pc", "cycles", "tick", "inst",
+ "ccr", /* pseudo register */
};
if (regno < 0
|| regno >= (sizeof (register_names) / sizeof (*register_names)))
internal_error (__FILE__, __LINE__,
- "h8300_register_name: illegal register number %d", regno);
+ "h8300_register_name: illegal register number %d", regno);
else
return register_names[regno];
}
"er0", "er1", "er2", "er3", "er4", "er5", "er6",
"sp", "", "pc", "cycles", "", "tick", "inst",
"mach", "macl",
- "ccr", "exr" /* pseudo registers */
+ "ccr", "exr" /* pseudo registers */
};
if (regno < 0
|| regno >= (sizeof (register_names) / sizeof (*register_names)))
internal_error (__FILE__, __LINE__,
- "h8300s_register_name: illegal register number %d", regno);
+ "h8300s_register_name: illegal register number %d",
+ regno);
else
return register_names[regno];
}
"er0", "er1", "er2", "er3", "er4", "er5", "er6",
"sp", "", "pc", "cycles", "", "tick", "inst",
"mach", "macl", "sbr", "vbr",
- "ccr", "exr" /* pseudo registers */
+ "ccr", "exr" /* pseudo registers */
};
if (regno < 0
|| regno >= (sizeof (register_names) / sizeof (*register_names)))
internal_error (__FILE__, __LINE__,
- "h8300sx_register_name: illegal register number %d", regno);
+ "h8300sx_register_name: illegal register number %d",
+ regno);
else
return register_names[regno];
}
if (!name || !*name)
return;
- frame_read_signed_register (frame, regno, &rval);
+ rval = get_frame_register_signed (frame, regno);
fprintf_filtered (file, "%-14s ", name);
- if (regno == E_PSEUDO_CCR_REGNUM || (regno == E_PSEUDO_EXR_REGNUM && h8300smode))
+ if ((regno == E_PSEUDO_CCR_REGNUM) || \
+ (regno == E_PSEUDO_EXR_REGNUM && is_h8300smode (current_gdbarch)))
{
- fprintf_filtered (file, "0x%02x ", (unsigned char)rval);
+ fprintf_filtered (file, "0x%02x ", (unsigned char) rval);
print_longest (file, 'u', 1, rval);
}
else
{
- fprintf_filtered (file, "0x%s ", phex ((ULONGEST)rval, BINWORD));
+ fprintf_filtered (file, "0x%s ", phex ((ULONGEST) rval, BINWORD));
print_longest (file, 'd', 1, rval);
}
if (regno == E_PSEUDO_CCR_REGNUM)
if ((Z | (N ^ V)) == 1)
fprintf_filtered (file, "<= ");
}
- else if (regno == E_PSEUDO_EXR_REGNUM && h8300smode)
+ else if (regno == E_PSEUDO_EXR_REGNUM && is_h8300smode (current_gdbarch))
{
/* EXR register */
unsigned char l = rval & 0xff;
h8300_print_register (gdbarch, file, frame, regno);
h8300_print_register (gdbarch, file, frame, E_PSEUDO_CCR_REGNUM);
h8300_print_register (gdbarch, file, frame, E_PC_REGNUM);
- if (h8300smode)
- {
+ if (is_h8300smode (current_gdbarch))
+ {
h8300_print_register (gdbarch, file, frame, E_PSEUDO_EXR_REGNUM);
- if (h8300sxmode)
+ if (is_h8300sxmode (current_gdbarch))
{
h8300_print_register (gdbarch, file, frame, E_SBR_REGNUM);
h8300_print_register (gdbarch, file, frame, E_VBR_REGNUM);
h8300_print_register (gdbarch, file, frame, E_INSTS_REGNUM);
}
else
- {
+ {
h8300_print_register (gdbarch, file, frame, E_CYCLES_REGNUM);
h8300_print_register (gdbarch, file, frame, E_TICK_REGNUM);
h8300_print_register (gdbarch, file, frame, E_INST_REGNUM);
else
{
if (regno == E_CCR_REGNUM)
- h8300_print_register (gdbarch, file, frame, E_PSEUDO_CCR_REGNUM);
- else if (regno == E_PSEUDO_EXR_REGNUM && h8300smode)
+ h8300_print_register (gdbarch, file, frame, E_PSEUDO_CCR_REGNUM);
+ else if (regno == E_PSEUDO_EXR_REGNUM
+ && is_h8300smode (current_gdbarch))
h8300_print_register (gdbarch, file, frame, E_PSEUDO_EXR_REGNUM);
else
h8300_print_register (gdbarch, file, frame, regno);
}
}
-static CORE_ADDR
-h8300_saved_pc_after_call (struct frame_info *ignore)
-{
- return read_memory_unsigned_integer (read_register (E_SP_REGNUM), BINWORD);
-}
-
static struct type *
h8300_register_type (struct gdbarch *gdbarch, int regno)
{
if (regno < 0 || regno >= NUM_REGS + NUM_PSEUDO_REGS)
internal_error (__FILE__, __LINE__,
- "h8300_register_type: illegal register number %d",
- regno);
+ "h8300_register_type: illegal register number %d", regno);
else
{
switch (regno)
- {
- case E_PC_REGNUM:
- return builtin_type_void_func_ptr;
- case E_SP_REGNUM:
- case E_FP_REGNUM:
- return builtin_type_void_data_ptr;
- default:
- if (regno == E_PSEUDO_CCR_REGNUM)
- return builtin_type_uint8;
- else if (regno == E_PSEUDO_EXR_REGNUM)
- return builtin_type_uint8;
- else if (h8300hmode)
- return builtin_type_int32;
- else
- return builtin_type_int16;
- }
+ {
+ case E_PC_REGNUM:
+ return builtin_type_void_func_ptr;
+ case E_SP_REGNUM:
+ case E_FP_REGNUM:
+ return builtin_type_void_data_ptr;
+ default:
+ if (regno == E_PSEUDO_CCR_REGNUM)
+ return builtin_type_uint8;
+ else if (regno == E_PSEUDO_EXR_REGNUM)
+ return builtin_type_uint8;
+ else if (is_h8300hmode (current_gdbarch))
+ return builtin_type_int32;
+ else
+ return builtin_type_int16;
+ }
}
}
static void
-h8300_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
- int regno, void *buf)
+h8300_pseudo_register_read (struct gdbarch *gdbarch,
+ struct regcache *regcache, int regno,
+ gdb_byte *buf)
{
if (regno == E_PSEUDO_CCR_REGNUM)
regcache_raw_read (regcache, E_CCR_REGNUM, buf);
}
static void
-h8300_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regno, const void *buf)
+h8300_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache, int regno,
+ const gdb_byte *buf)
{
if (regno == E_PSEUDO_CCR_REGNUM)
regcache_raw_write (regcache, E_CCR_REGNUM, buf);
return regno;
}
-static CORE_ADDR
-h8300_extract_struct_value_address (struct regcache *regcache)
-{
- ULONGEST addr;
- regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &addr);
- return addr;
-}
-
const static unsigned char *
h8300_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
{
- /*static unsigned char breakpoint[] = { 0x7A, 0xFF };*/ /* ??? */
- static unsigned char breakpoint[] = { 0x01, 0x80 }; /* Sleep */
+ /*static unsigned char breakpoint[] = { 0x7A, 0xFF }; *//* ??? */
+ static unsigned char breakpoint[] = { 0x01, 0x80 }; /* Sleep */
*lenptr = sizeof (breakpoint);
return breakpoint;
}
-static CORE_ADDR
-h8300_push_dummy_code (struct gdbarch *gdbarch,
- CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
- struct value **args, int nargs,
- struct type *value_type,
- CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
-{
- /* Allocate space sufficient for a breakpoint. */
- sp = (sp - 2) & ~1;
- /* Store the address of that breakpoint */
- *bp_addr = sp;
- /* h8300 always starts the call at the callee's entry point. */
- *real_pc = funaddr;
- return sp;
-}
-
static void
h8300_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
struct frame_info *frame, const char *args)
switch (info.bfd_arch_info->mach)
{
case bfd_mach_h8300:
- h8300sxmode = 0;
- h8300smode = 0;
- h8300hmode = 0;
set_gdbarch_num_regs (gdbarch, 13);
set_gdbarch_num_pseudo_regs (gdbarch, 1);
set_gdbarch_ecoff_reg_to_regnum (gdbarch, h8300_dbg_reg_to_regnum);
set_gdbarch_register_name (gdbarch, h8300_register_name);
set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_addr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
- set_gdbarch_extract_return_value (gdbarch, h8300_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, h8300_store_return_value);
+ set_gdbarch_return_value (gdbarch, h8300_return_value);
set_gdbarch_print_insn (gdbarch, print_insn_h8300);
break;
case bfd_mach_h8300h:
case bfd_mach_h8300hn:
- h8300sxmode = 0;
- h8300smode = 0;
- h8300hmode = 1;
set_gdbarch_num_regs (gdbarch, 13);
set_gdbarch_num_pseudo_regs (gdbarch, 1);
set_gdbarch_ecoff_reg_to_regnum (gdbarch, h8300_dbg_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, h8300_dbg_reg_to_regnum);
set_gdbarch_stab_reg_to_regnum (gdbarch, h8300_dbg_reg_to_regnum);
set_gdbarch_register_name (gdbarch, h8300_register_name);
- set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- set_gdbarch_extract_return_value (gdbarch, h8300h_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, h8300h_store_return_value);
+ if (info.bfd_arch_info->mach != bfd_mach_h8300hn)
+ {
+ set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ }
+ else
+ {
+ set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ }
+ set_gdbarch_return_value (gdbarch, h8300h_return_value);
set_gdbarch_print_insn (gdbarch, print_insn_h8300h);
break;
case bfd_mach_h8300s:
case bfd_mach_h8300sn:
- h8300sxmode = 0;
- h8300smode = 1;
- h8300hmode = 1;
set_gdbarch_num_regs (gdbarch, 16);
set_gdbarch_num_pseudo_regs (gdbarch, 2);
set_gdbarch_ecoff_reg_to_regnum (gdbarch, h8300s_dbg_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, h8300s_dbg_reg_to_regnum);
set_gdbarch_stab_reg_to_regnum (gdbarch, h8300s_dbg_reg_to_regnum);
set_gdbarch_register_name (gdbarch, h8300s_register_name);
- set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- set_gdbarch_extract_return_value (gdbarch, h8300h_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, h8300h_store_return_value);
+ if (info.bfd_arch_info->mach != bfd_mach_h8300sn)
+ {
+ set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ }
+ else
+ {
+ set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ }
+ set_gdbarch_return_value (gdbarch, h8300h_return_value);
set_gdbarch_print_insn (gdbarch, print_insn_h8300s);
break;
case bfd_mach_h8300sx:
case bfd_mach_h8300sxn:
- h8300sxmode = 1;
- h8300smode = 1;
- h8300hmode = 1;
set_gdbarch_num_regs (gdbarch, 18);
set_gdbarch_num_pseudo_regs (gdbarch, 2);
set_gdbarch_ecoff_reg_to_regnum (gdbarch, h8300s_dbg_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, h8300s_dbg_reg_to_regnum);
set_gdbarch_stab_reg_to_regnum (gdbarch, h8300s_dbg_reg_to_regnum);
set_gdbarch_register_name (gdbarch, h8300sx_register_name);
- set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- set_gdbarch_extract_return_value (gdbarch, h8300h_extract_return_value);
- set_gdbarch_store_return_value (gdbarch, h8300h_store_return_value);
+ if (info.bfd_arch_info->mach != bfd_mach_h8300sxn)
+ {
+ set_gdbarch_ptr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ }
+ else
+ {
+ set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ }
+ set_gdbarch_return_value (gdbarch, h8300h_return_value);
set_gdbarch_print_insn (gdbarch, print_insn_h8300s);
break;
}
set_gdbarch_pseudo_register_read (gdbarch, h8300_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, h8300_pseudo_register_write);
- /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
- ready to unwind the PC first (see frame.c:get_prev_frame()). */
- set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
-
/*
* Basic register fields and methods.
*/
set_gdbarch_sp_regnum (gdbarch, E_SP_REGNUM);
- set_gdbarch_deprecated_fp_regnum (gdbarch, E_FP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, E_PC_REGNUM);
set_gdbarch_register_type (gdbarch, h8300_register_type);
set_gdbarch_print_registers_info (gdbarch, h8300_print_registers_info);
*/
set_gdbarch_skip_prologue (gdbarch, h8300_skip_prologue);
- set_gdbarch_deprecated_frame_init_saved_regs (gdbarch,
- h8300_frame_init_saved_regs);
- set_gdbarch_deprecated_init_extra_frame_info (gdbarch,
- h8300_init_extra_frame_info);
- set_gdbarch_deprecated_frame_chain (gdbarch, h8300_frame_chain);
- set_gdbarch_deprecated_saved_pc_after_call (gdbarch,
- h8300_saved_pc_after_call);
- set_gdbarch_deprecated_frame_saved_pc (gdbarch, h8300_frame_saved_pc);
- set_gdbarch_deprecated_pop_frame (gdbarch, h8300_pop_frame);
+ /* Frame unwinder. */
+ set_gdbarch_unwind_pc (gdbarch, h8300_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, h8300_unwind_sp);
+ set_gdbarch_unwind_dummy_id (gdbarch, h8300_unwind_dummy_id);
+ frame_base_set_default (gdbarch, &h8300_frame_base);
/*
* Miscelany
*/
/* Stack grows up. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- /* PC stops zero byte after a trap instruction
- (which means: exactly on trap instruction). */
- set_gdbarch_decr_pc_after_break (gdbarch, 0);
- /* This value is almost never non-zero... */
- set_gdbarch_function_start_offset (gdbarch, 0);
- /* This value is almost never non-zero... */
- set_gdbarch_frame_args_skip (gdbarch, 0);
- set_gdbarch_frameless_function_invocation (gdbarch,
- frameless_look_for_prologue);
-
- set_gdbarch_extract_struct_value_address (gdbarch,
- h8300_extract_struct_value_address);
- set_gdbarch_use_struct_convention (gdbarch, always_use_struct_convention);
+
set_gdbarch_breakpoint_from_pc (gdbarch, h8300_breakpoint_from_pc);
- set_gdbarch_push_dummy_code (gdbarch, h8300_push_dummy_code);
set_gdbarch_push_dummy_call (gdbarch, h8300_push_dummy_call);
+ set_gdbarch_char_signed (gdbarch, 0);
set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT);
set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
set_gdbarch_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
- /* set_gdbarch_stack_align (gdbarch, SOME_stack_align); */
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
- /* Char is unsigned. */
- set_gdbarch_char_signed (gdbarch, 0);
+ /* Hook in the DWARF CFI frame unwinder. */
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, h8300_frame_sniffer);
return gdbarch;
+
}
-extern initialize_file_ftype _initialize_h8300_tdep; /* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_h8300_tdep; /* -Wmissing-prototypes */
void
_initialize_h8300_tdep (void)
{
register_gdbarch_init (bfd_arch_h8300, h8300_gdbarch_init);
}
+
+static int
+is_h8300hmode (struct gdbarch *gdbarch)
+{
+ return gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sx
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sxn
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300s
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sn
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300h
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300hn;
+}
+
+static int
+is_h8300smode (struct gdbarch *gdbarch)
+{
+ return gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sx
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sxn
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300s
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sn;
+}
+
+static int
+is_h8300sxmode (struct gdbarch *gdbarch)
+{
+ return gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sx
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sxn;
+}
+
+static int
+is_h8300_normal_mode (struct gdbarch *gdbarch)
+{
+ return gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sxn
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300sn
+ || gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_h8300hn;
+}