-/* Target-machine dependent code for Hitachi H8/300, for GDB.
- Copyright (C) 1988, 1990, 1991 Free Software Foundation, Inc.
+/* Target-machine dependent code for Renesas H8/300, for GDB.
-This file is part of GDB.
+ Copyright (C) 1988-2014 Free Software Foundation, Inc.
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ This file is part of GDB.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
-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. */
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/*
- Contributed by Steve Chamberlain
- sac@cygnus.com
+ Contributed by Steve Chamberlain
+ sac@cygnus.com
*/
#include "defs.h"
-#include "frame.h"
-#include "obstack.h"
-#include "symtab.h"
+#include "value.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "gdbcore.h"
+#include "objfiles.h"
+#include "gdb_assert.h"
#include "dis-asm.h"
-#include "gdbcmd.h"
-#include "gdbtypes.h"
+#include "dwarf2-frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
-#undef NUM_REGS
-#define NUM_REGS 11
+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_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_R4_REGNUM, E_ER4_REGNUM = E_R4_REGNUM,
+ E_R5_REGNUM, E_ER5_REGNUM = E_R5_REGNUM,
+ E_R6_REGNUM, E_ER6_REGNUM = E_R6_REGNUM, E_FP_REGNUM = E_R6_REGNUM,
+ E_SP_REGNUM,
+ E_CCR_REGNUM,
+ E_PC_REGNUM,
+ E_CYCLES_REGNUM,
+ E_TICK_REGNUM, E_EXR_REGNUM = E_TICK_REGNUM,
+ E_INST_REGNUM, E_TICKS_REGNUM = E_INST_REGNUM,
+ E_INSTS_REGNUM,
+ E_MACH_REGNUM,
+ E_MACL_REGNUM,
+ E_SBR_REGNUM,
+ E_VBR_REGNUM
+};
+
+#define H8300_MAX_NUM_REGS 18
+
+#define E_PSEUDO_CCR_REGNUM(gdbarch) (gdbarch_num_regs (gdbarch))
+#define E_PSEUDO_EXR_REGNUM(gdbarch) (gdbarch_num_regs (gdbarch)+1)
+
+struct h8300_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR sp_offset;
+ CORE_ADDR pc;
-#define UNSIGNED_SHORT(X) ((X) & 0xffff)
+ /* Flag showing that a frame has been created in the prologue code. */
+ int uses_fp;
-/* an easy to debug H8 stack frame looks like:
-0x6df6 push r6
-0x0d76 mov.w r7,r6
-0x6dfn push reg
-0x7905 nnnn mov.w #n,r5 or 0x1b87 subs #2,sp
-0x1957 sub.w r5,sp
+ /* 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,
+};
-#define IS_PUSH(x) ((x & 0xff00)==0x6d00)
-#define IS_PUSH_FP(x) (x == 0x6df6)
-#define IS_MOVE_FP(x) (x == 0x0d76)
-#define IS_MOV_SP_FP(x) (x == 0x0d76)
-#define IS_SUB2_SP(x) (x==0x1b87)
-#define IS_MOVK_R5(x) (x==0x7905)
-#define IS_SUB_R5SP(x) (x==0x1957)
+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);
-static CORE_ADDR examine_prologue ();
+#define BINWORD(gdbarch) ((is_h8300hmode (gdbarch) \
+ && !is_h8300_normal_mode (gdbarch)) \
+ ? h8300h_reg_size : h8300_reg_size)
-void frame_find_saved_regs ();
-CORE_ADDR
-h8300_skip_prologue (start_pc)
- CORE_ADDR start_pc;
+static CORE_ADDR
+h8300_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- short int w;
+ return frame_unwind_register_unsigned (next_frame, E_PC_REGNUM);
+}
- w = read_memory_unsigned_integer (start_pc, 2);
- /* Skip past all push insns */
- while (IS_PUSH_FP (w))
- {
- start_pc += 2;
- w = read_memory_unsigned_integer (start_pc, 2);
- }
+static CORE_ADDR
+h8300_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_SP_REGNUM);
+}
- /* Skip past a move to FP */
- if (IS_MOVE_FP (w))
- {
- start_pc += 2;
- w = read_memory_unsigned_integer (start_pc, 2);
- }
+static struct frame_id
+h8300_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
- /* Skip the stack adjust */
+/* Normal frames. */
- if (IS_MOVK_R5 (w))
+/* Allocate and initialize a frame cache. */
+
+static void
+h8300_init_frame_cache (struct gdbarch *gdbarch,
+ struct h8300_frame_cache *cache)
+{
+ int i;
+
+ /* Base address. */
+ cache->base = 0;
+ cache->sp_offset = 0;
+ cache->pc = 0;
+
+ /* 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 < gdbarch_num_regs (gdbarch); 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.
+
+ An argument register spill is an instruction that moves an argument
+ from the register in which it was passed to the stack slot in which
+ it really lives. It is a byte, word, or longword move from an
+ argument register to a negative offset from the frame pointer.
+
+ CV, 2003-06-16: Or, in optimized code or when the `register' qualifier
+ is used, it could be a byte, word or long move to registers r3-r5. */
+
+static int
+h8300_is_argument_spill (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int w = read_memory_unsigned_integer (pc, 2, byte_order);
+
+ 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 (IS_MOVB_Rn16_SP (w)
+ && 8 <= (w & 0xf) && (w & 0xf) <= 10) /* Rs is R0L, R1L, or R2L */
{
- start_pc += 2;
- w = read_memory_unsigned_integer (start_pc, 2);
+ /* ... and d:16 is negative. */
+ if (read_memory_integer (pc + 2, 2, byte_order) < 0)
+ return 4;
}
- if (IS_SUB_R5SP (w))
+ else if (IS_MOVB_EXT (w))
{
- start_pc += 2;
- w = read_memory_unsigned_integer (start_pc, 2);
+ if (IS_MOVB_Rn24_SP (read_memory_unsigned_integer (pc + 2,
+ 2, byte_order)))
+ {
+ LONGEST disp = read_memory_integer (pc + 4, 4, byte_order);
+
+ /* ... and d:24 is negative. */
+ if (disp < 0 && disp > 0xffffff)
+ return 8;
+ }
}
- while (IS_SUB2_SP (w))
+ else if (IS_MOVW_Rn16_SP (w)
+ && (w & 0xf) <= 2) /* Rs is R0, R1, or R2 */
{
- start_pc += 2;
- w = read_memory_unsigned_integer (start_pc, 2);
+ /* ... and d:16 is negative. */
+ if (read_memory_integer (pc + 2, 2, byte_order) < 0)
+ return 4;
}
+ else if (IS_MOVW_EXT (w))
+ {
+ if (IS_MOVW_Rn24_SP (read_memory_unsigned_integer (pc + 2,
+ 2, byte_order)))
+ {
+ LONGEST disp = read_memory_integer (pc + 4, 4, byte_order);
- return start_pc;
-}
+ /* ... and d:24 is negative. */
+ if (disp < 0 && disp > 0xffffff)
+ return 8;
+ }
+ }
+ else if (IS_MOVL_PRE (w))
+ {
+ int w2 = read_memory_integer (pc + 2, 2, byte_order);
-int
-gdb_print_insn_h8300 (memaddr, info)
- bfd_vma memaddr;
- disassemble_info *info;
-{
- if (h8300hmode)
- return print_insn_h8300h (memaddr, info);
- else
- return print_insn_h8300 (memaddr, info);
-}
+ if (IS_MOVL_Rn16_SP (w2)
+ && (w2 & 0xf) <= 2) /* Rs is ER0, ER1, or ER2 */
+ {
+ /* ... and d:16 is negative. */
+ if (read_memory_integer (pc + 4, 2, byte_order) < 0)
+ return 6;
+ }
+ else if (IS_MOVL_EXT (w2))
+ {
+ int w3 = read_memory_integer (pc + 4, 2, byte_order);
-/* 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
- INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame.
+ if (IS_MOVL_Rn24_SP (read_memory_integer (pc + 4, 2, byte_order)))
+ {
+ LONGEST disp = read_memory_integer (pc + 6, 4, byte_order);
- 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. */
+ /* ... and d:24 is negative. */
+ if (disp < 0 && disp > 0xffffff)
+ return 10;
+ }
+ }
+ }
-CORE_ADDR
-h8300_frame_chain (thisframe)
- struct frame_info *thisframe;
-{
- frame_find_saved_regs (thisframe, (struct frame_saved_regs *) 0);
- return thisframe->fsr->regs[SP_REGNUM];
+ return 0;
}
-/* Put here the code to store, into a struct frame_saved_regs,
- the addresses of the saved registers of frame described by FRAME_INFO.
- This includes special registers such as pc and fp saved in special
- ways in the stack frame. sp is even more special:
- the address we return for it IS the sp for the next frame.
-
- We cache the result of doing this in the frame_cache_obstack, since
- it is fairly expensive. */
+/* 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.
-void
-frame_find_saved_regs (fi, fsr)
- struct frame_info *fi;
- struct frame_saved_regs *fsr;
-{
- register CORE_ADDR next_addr;
- register CORE_ADDR *saved_regs;
- register int regnum;
- register struct frame_saved_regs *cache_fsr;
- extern struct obstack frame_cache_obstack;
- CORE_ADDR ip;
- struct symtab_and_line sal;
- CORE_ADDR limit;
-
- if (!fi->fsr)
- {
- cache_fsr = (struct frame_saved_regs *)
- obstack_alloc (&frame_cache_obstack,
- sizeof (struct frame_saved_regs));
- memset (cache_fsr, '\0', sizeof (struct frame_saved_regs));
+ We handle all cases that can be generated by gcc.
- fi->fsr = cache_fsr;
+ For allocating a stack frame:
- /* Find the start and end of the function prologue. If the PC
- is in the function prologue, we only consider the part that
- has executed already. */
+ mov.w r6,@-sp
+ mov.w sp,r6
+ mov.w #-n,rN
+ add.w rN,sp
- ip = get_pc_function_start (fi->pc);
- sal = find_pc_line (ip, 0);
- limit = (sal.end && sal.end < fi->pc) ? sal.end : fi->pc;
-
- /* This will fill in fields in *fi as well as in cache_fsr. */
- examine_prologue (ip, limit, fi->frame, cache_fsr, fi);
- }
+ mov.w r6,@-sp
+ mov.w sp,r6
+ subs #2,sp
+ (repeat)
- if (fsr)
- *fsr = *fi->fsr;
-}
+ 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)
-CORE_ADDR
-NEXT_PROLOGUE_INSN (addr, lim, pword1)
- CORE_ADDR addr;
- CORE_ADDR lim;
- INSN_WORD *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. */
+ */
static CORE_ADDR
-examine_prologue (ip, limit, after_prolog_fp, fsr, fi)
- register CORE_ADDR ip;
- register CORE_ADDR limit;
- CORE_ADDR after_prolog_fp;
- struct frame_saved_regs *fsr;
- struct frame_info *fi;
-{
- register CORE_ADDR next_ip;
- int r;
- int i;
- int have_fp = 0;
- register int src;
- register struct pic_prologue_code *pcode;
- INSN_WORD insn_word;
- int size, offset;
- /* Number of things pushed onto stack, starts at 2/4, 'cause the
- PC is already there */
- unsigned int reg_save_depth = h8300hmode ? 4 : 2;
+h8300_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR pc, CORE_ADDR current_pc,
+ struct h8300_frame_cache *cache)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ unsigned int op;
+ int regno, i, spill_size;
+
+ cache->sp_offset = 0;
- unsigned int auto_depth = 0; /* Number of bytes of autos */
+ if (pc >= current_pc)
+ return current_pc;
- char in_frame[11]; /* One for each reg */
+ op = read_memory_unsigned_integer (pc, 4, byte_order);
- memset (in_frame, 1, 11);
- for (r = 0; r < 8; r++)
+ if (IS_PUSHFP_MOVESPFP (op))
{
- fsr->regs[r] = 0;
+ cache->saved_regs[E_FP_REGNUM] = 0;
+ cache->uses_fp = 1;
+ pc += 4;
}
- if (after_prolog_fp == 0)
+ else if (IS_PUSH_FP (op))
{
- after_prolog_fp = read_register (SP_REGNUM);
+ cache->saved_regs[E_FP_REGNUM] = 0;
+ pc += 4;
+ if (pc >= current_pc)
+ return current_pc;
+ op = read_memory_unsigned_integer (pc, 2, byte_order);
+ if (IS_MOV_SP_FP (op))
+ {
+ cache->uses_fp = 1;
+ pc += 2;
+ }
}
- if (ip == 0 || ip & (h8300hmode ? ~0xffff : ~0xffff))
- return 0;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
-
- /* Skip over any fp push instructions */
- fsr->regs[6] = after_prolog_fp;
- while (next_ip && IS_PUSH_FP (insn_word))
+ while (pc < current_pc)
{
- ip = next_ip;
-
- in_frame[insn_word & 0x7] = reg_save_depth;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- reg_save_depth += 2;
+ op = read_memory_unsigned_integer (pc, 2, byte_order);
+ if (IS_SUB2_SP (op))
+ {
+ cache->sp_offset += 2;
+ pc += 2;
+ }
+ else if (IS_SUB4_SP (op))
+ {
+ cache->sp_offset += 4;
+ pc += 2;
+ }
+ else if (IS_ADD_IMM_SP (op))
+ {
+ cache->sp_offset += -read_memory_integer (pc + 2, 2, byte_order);
+ pc += 4;
+ }
+ else if (IS_SUB_IMM_SP (op))
+ {
+ cache->sp_offset += read_memory_integer (pc + 2, 2, byte_order);
+ pc += 4;
+ }
+ else if (IS_SUBL4_SP (op))
+ {
+ cache->sp_offset += 4;
+ pc += 2;
+ }
+ else if (IS_MOV_IMM_Rn (op))
+ {
+ int offset = read_memory_integer (pc + 2, 2, byte_order);
+ regno = op & 0x000f;
+ op = read_memory_unsigned_integer (pc + 4, 2, byte_order);
+ 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))
+ {
+ 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, byte_order);
+ if (IS_PUSH (op))
+ {
+ regno = op & 0x000f;
+ cache->sp_offset += 4;
+ cache->saved_regs[regno] = cache->sp_offset;
+ pc += 4;
+ }
+ else
+ break;
+ }
+ else if ((op & 0xffcf) == 0x0100)
+ {
+ int op1;
+ op1 = read_memory_unsigned_integer (pc + 2, 2, byte_order);
+ 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;
}
- /* Is this a move into the fp */
- if (next_ip && IS_MOV_SP_FP (insn_word))
- {
- ip = next_ip;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- have_fp = 1;
- }
+ /* 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 (gdbarch, pc)) > 0
+ && pc + spill_size <= current_pc)
+ pc += spill_size;
+
+ return pc;
+}
- /* Skip over any stack adjustment, happens either with a number of
- sub#2,sp or a mov #x,r5 sub r5,sp */
+static struct h8300_frame_cache *
+h8300_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct h8300_frame_cache *cache;
+ int i;
+ CORE_ADDR current_pc;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct h8300_frame_cache);
+ h8300_init_frame_cache (gdbarch, 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. */
- if (next_ip && IS_SUB2_SP (insn_word))
+ cache->base = get_frame_register_unsigned (this_frame, E_FP_REGNUM);
+ if (cache->base == 0)
+ return cache;
+
+ cache->saved_regs[E_PC_REGNUM] = -BINWORD (gdbarch);
+
+ cache->pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+ if (cache->pc != 0)
+ h8300_analyze_prologue (gdbarch, cache->pc, current_pc, cache);
+
+ if (!cache->uses_fp)
{
- while (next_ip && IS_SUB2_SP (insn_word))
- {
- auto_depth += 2;
- ip = next_ip;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- }
+ /* 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 = get_frame_register_unsigned (this_frame, E_SP_REGNUM)
+ + cache->sp_offset;
+ cache->saved_sp = cache->base + BINWORD (gdbarch);
+ cache->saved_regs[E_PC_REGNUM] = 0;
}
else
{
- if (next_ip && IS_MOVK_R5 (insn_word))
- {
- ip = next_ip;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- auto_depth += insn_word;
-
- next_ip = NEXT_PROLOGUE_INSN (next_ip, limit, &insn_word);
- auto_depth += insn_word;
- }
- }
- /* Work out which regs are stored where */
- while (next_ip && IS_PUSH (insn_word))
- {
- ip = next_ip;
- next_ip = NEXT_PROLOGUE_INSN (ip, limit, &insn_word);
- fsr->regs[r] = after_prolog_fp + auto_depth;
- auto_depth += 2;
+ cache->saved_sp = cache->base + 2 * BINWORD (gdbarch);
+ cache->saved_regs[E_PC_REGNUM] = -BINWORD (gdbarch);
}
- /* The args are always reffed based from the stack pointer */
- fi->args_pointer = after_prolog_fp;
- /* Locals are always reffed based from the fp */
- fi->locals_pointer = after_prolog_fp;
- /* The PC is at a known place */
- fi->from_pc = read_memory_unsigned_integer (after_prolog_fp + 2, BINWORD);
+ /* Adjust all the saved registers such that they contain addresses
+ instead of offsets. */
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
+ if (cache->saved_regs[i] != -1)
+ cache->saved_regs[i] = cache->base - cache->saved_regs[i];
- /* Rememeber any others too */
- in_frame[PC_REGNUM] = 0;
+ return cache;
+}
- if (have_fp)
- /* We keep the old FP in the SP spot */
- fsr->regs[SP_REGNUM] = read_memory_unsigned_integer (fsr->regs[6], BINWORD);
- else
- fsr->regs[SP_REGNUM] = after_prolog_fp + auto_depth;
+static void
+h8300_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct h8300_frame_cache *cache =
+ h8300_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
- return (ip);
+ *this_id = frame_id_build (cache->saved_sp, cache->pc);
}
-void
-init_extra_frame_info (fromleaf, fi)
- int fromleaf;
- struct frame_info *fi;
+static struct value *
+h8300_frame_prev_register (struct frame_info *this_frame, void **this_cache,
+ int regnum)
{
- fi->fsr = 0; /* Not yet allocated */
- fi->args_pointer = 0; /* Unknown */
- fi->locals_pointer = 0; /* Unknown */
- fi->from_pc = 0;
-}
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct h8300_frame_cache *cache =
+ h8300_frame_cache (this_frame, this_cache);
-/* Return the saved PC from this frame.
+ gdb_assert (regnum >= 0);
- If the frame has a memory copy of SRP_REGNUM, use that. If not,
- just use the register SRP_REGNUM itself. */
+ if (regnum == E_SP_REGNUM && cache->saved_sp)
+ return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
-CORE_ADDR
-frame_saved_pc (frame)
- struct frame_info *frame;
-{
- return frame->from_pc;
+ if (regnum < gdbarch_num_regs (gdbarch)
+ && cache->saved_regs[regnum] != -1)
+ return frame_unwind_got_memory (this_frame, regnum,
+ cache->saved_regs[regnum]);
+
+ return frame_unwind_got_register (this_frame, regnum, regnum);
}
-CORE_ADDR
-frame_locals_address (fi)
- struct frame_info *fi;
+static const struct frame_unwind h8300_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ h8300_frame_this_id,
+ h8300_frame_prev_register,
+ NULL,
+ default_frame_sniffer
+};
+
+static CORE_ADDR
+h8300_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
- if (!fi->locals_pointer)
- {
- struct frame_saved_regs ignore;
+ struct h8300_frame_cache *cache = h8300_frame_cache (this_frame, this_cache);
+ return cache->base;
+}
- get_frame_saved_regs (fi, &ignore);
+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 (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0 , func_end = 0;
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ 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 (gdbarch, &cache);
+ return h8300_analyze_prologue (gdbarch, func_addr, func_end, &cache);
}
- return fi->locals_pointer;
+
+ /* No function symbol -- just return the PC. */
+ return (CORE_ADDR) pc;
}
-/* Return the address of the argument block for the frame
- described by FI. Returns 0 if the address is unknown. */
+/* Function: push_dummy_call
+ Setup the function arguments for calling a function in the inferior.
+ In this discussion, a `word' is 16 bits on the H8/300s, and 32 bits
+ on the H8/300H.
+
+ There are actually two ABI's here: -mquickcall (the default) and
+ -mno-quickcall. With -mno-quickcall, all arguments are passed on
+ the stack after the return address, word-aligned. With
+ -mquickcall, GCC tries to use r0 -- r2 to pass registers. Since
+ GCC doesn't indicate in the object file which ABI was used to
+ compile it, GDB only supports the default --- -mquickcall.
+
+ Here are the rules for -mquickcall, in detail:
+
+ Each argument, whether scalar or aggregate, is padded to occupy a
+ whole number of words. Arguments smaller than a word are padded at
+ the most significant end; those larger than a word are padded at
+ the least significant end.
+
+ The initial arguments are passed in r0 -- r2. Earlier arguments go in
+ lower-numbered registers. Multi-word arguments are passed in
+ consecutive registers, with the most significant end in the
+ lower-numbered register.
+
+ If an argument doesn't fit entirely in the remaining registers, it
+ is passed entirely on the stack. Stack arguments begin just after
+ the return address. Once an argument has overflowed onto the stack
+ this way, all subsequent arguments are passed on the stack.
+
+ The above rule has odd consequences. For example, on the h8/300s,
+ if a function takes two longs and an int as arguments:
+ - the first long will be passed in r0/r1,
+ - the second long will be passed entirely on the stack, since it
+ doesn't fit in r2,
+ - and the int will be passed on the stack, even though it could fit
+ in r2.
+
+ A weird exception: if an argument is larger than a word, but not a
+ whole number of words in length (before padding), it is passed on
+ the stack following the rules for stack arguments above, even if
+ there are sufficient registers available to hold it. Stranger
+ still, the argument registers are still `used up' --- even though
+ there's nothing in them.
+
+ So, for example, on the h8/300s, if a function expects a three-byte
+ structure and an int, the structure will go on the stack, and the
+ int will go in r2, not r0.
+
+ If the function returns an aggregate type (struct, union, or class)
+ by value, the caller must allocate space to hold the return value,
+ and pass the callee a pointer to this space as an invisible first
+ argument, in R0.
+
+ For varargs functions, the last fixed argument and all the variable
+ arguments are always passed on the stack. This means that calls to
+ varargs functions don't work properly unless there is a prototype
+ in scope.
+
+ Basically, this ABI is not good, for the following reasons:
+ - You can't call vararg functions properly unless a prototype is in scope.
+ - Structure passing is inconsistent, to no purpose I can see.
+ - It often wastes argument registers, of which there are only three
+ to begin with. */
-CORE_ADDR
-frame_args_address (fi)
- struct frame_info *fi;
+static CORE_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)
{
- if (!fi->args_pointer)
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int stack_alloc = 0, stack_offset = 0;
+ int wordsize = BINWORD (gdbarch);
+ int reg = E_ARG0_REGNUM;
+ int argument;
+
+ /* First, make sure the stack is properly aligned. */
+ 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 += align_up (TYPE_LENGTH (value_type (args[argument])),
+ wordsize);
+ sp -= stack_alloc;
+
+ /* Now load as many arguments as possible into registers, and push
+ the rest onto the stack.
+ If we're returning a structure by value, then we must pass a
+ pointer to the buffer for the return value as an invisible first
+ argument. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, reg++, struct_addr);
+
+ for (argument = 0; argument < nargs; argument++)
{
- struct frame_saved_regs ignore;
+ struct cleanup *back_to;
+ struct type *type = value_type (args[argument]);
+ int len = TYPE_LENGTH (type);
+ char *contents = (char *) value_contents (args[argument]);
+
+ /* Pad the argument appropriately. */
+ int padded_len = align_up (len, wordsize);
+ gdb_byte *padded = xmalloc (padded_len);
+ back_to = make_cleanup (xfree, padded);
+
+ memset (padded, 0, padded_len);
+ memcpy (len < wordsize ? padded + padded_len - len : padded,
+ 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!
+ Note that 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, byte_order);
+ 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;
- get_frame_saved_regs (fi, &ignore);
+ /* Once one argument has spilled onto the stack, all
+ subsequent arguments go on the stack. */
+ reg = E_ARGLAST_REGNUM + 1;
+ }
+ do_cleanups (back_to);
}
- return fi->args_pointer;
+ /* Store return address. */
+ sp -= wordsize;
+ write_memory_unsigned_integer (sp, wordsize, byte_order, bp_addr);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, sp);
+
+ /* 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;
}
-void
-h8300_pop_frame ()
-{
- unsigned regnum;
- struct frame_saved_regs fsr;
- struct frame_info *frame = get_current_frame ();
+/* Function: extract_return_value
+ Figure out where in REGBUF the called function has left its return value.
+ Copy that into VALBUF. Be sure to account for CPU type. */
- get_frame_saved_regs (frame, &fsr);
+static void
+h8300_extract_return_value (struct type *type, struct regcache *regcache,
+ void *valbuf)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int len = TYPE_LENGTH (type);
+ ULONGEST c, addr;
- for (regnum = 0; regnum < 8; regnum++)
+ switch (len)
{
- if (fsr.regs[regnum])
- write_register (regnum, read_memory_integer(fsr.regs[regnum]), BINWORD);
+ case 1:
+ case 2:
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
+ store_unsigned_integer (valbuf, len, byte_order, 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, byte_order, c);
+ regcache_cooked_read_unsigned (regcache, E_RET1_REGNUM, &c);
+ store_unsigned_integer ((void *)((char *) valbuf + 2), 2, byte_order, 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, byte_order);
+ store_unsigned_integer (valbuf, len, byte_order, c);
+ }
+ else
+ {
+ error (_("I don't know how this 8 byte value is returned."));
+ }
+ break;
+ }
+}
- flush_cached_frames ();
+static void
+h8300h_extract_return_value (struct type *type, struct regcache *regcache,
+ void *valbuf)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ ULONGEST c;
+
+ switch (TYPE_LENGTH (type))
+ {
+ case 1:
+ case 2:
+ case 4:
+ regcache_cooked_read_unsigned (regcache, E_RET0_REGNUM, &c);
+ store_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order, 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, byte_order, c);
+ regcache_cooked_read_unsigned (regcache, E_RET1_REGNUM, &c);
+ store_unsigned_integer ((void *) ((char *) valbuf + 4), 4,
+ byte_order, c);
+ }
+ else
+ {
+ error (_("I don't know how this 8 byte value is returned."));
+ }
+ break;
}
}
+static 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);
+}
-struct cmd_list_element *setmemorylist;
+static 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.
+ Primarily used by the RETURN command. */
static void
-h8300_command(args, from_tty)
+h8300_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
{
- extern int h8300hmode;
- h8300hmode = 0;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ ULONGEST val;
+
+ switch (TYPE_LENGTH (type))
+ {
+ case 1:
+ case 2: /* short... */
+ val = extract_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM, val);
+ break;
+ case 4: /* long, float */
+ val = extract_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order);
+ 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;
+ }
}
static void
-h8300h_command(args, from_tty)
+h8300h_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
{
- extern int h8300hmode;
- h8300hmode = 1;
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ ULONGEST val;
+
+ switch (TYPE_LENGTH (type))
+ {
+ case 1:
+ case 2:
+ case 4: /* long, float */
+ val = extract_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM, val);
+ break;
+ case 8:
+ val = extract_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order);
+ regcache_cooked_write_unsigned (regcache, E_RET0_REGNUM,
+ (val >> 32) & 0xffffffff);
+ regcache_cooked_write_unsigned (regcache, E_RET1_REGNUM,
+ val & 0xffffffff);
+ break;
+ }
}
-static void
-set_machine (args, from_tty)
- char *args;
- int from_tty;
+static enum return_value_convention
+h8300_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
- printf_unfiltered ("\"set machine\" must be followed by h8300 or h8300h.\n");
- help_list (setmemorylist, "set memory ", -1, gdb_stdout);
+ 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;
}
-void
-_initialize_h8300m ()
+static enum return_value_convention
+h8300h_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
- add_prefix_cmd ("machine", no_class, set_machine,
- "set the machine type", &setmemorylist, "set machine ", 0,
- &setlist);
+ if (h8300h_use_struct_convention (type))
+ {
+ if (readbuf)
+ {
+ ULONGEST addr;
- add_cmd ("h8300", class_support, h8300_command,
- "Set machine to be H8/300.", &setmemorylist);
+ regcache_raw_read_unsigned (regcache, E_R0_REGNUM, &addr);
+ read_memory (addr, readbuf, TYPE_LENGTH (type));
+ }
- add_cmd ("h8300h", class_support, h8300h_command,
- "Set machine to be H8/300H.", &setmemorylist);
+ 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 *
+h8300_register_name (struct gdbarch *gdbarch, int regno)
+{
+ /* The register names change depending on which h8300 processor
+ type is selected. */
+ static char *register_names[] = {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6",
+ "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);
+ else
+ return register_names[regno];
+}
-void
-print_register_hook (regno)
+static const char *
+h8300s_register_name (struct gdbarch *gdbarch, int regno)
+{
+ static char *register_names[] = {
+ "er0", "er1", "er2", "er3", "er4", "er5", "er6",
+ "sp", "", "pc", "cycles", "", "tick", "inst",
+ "mach", "macl",
+ "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);
+ else
+ return register_names[regno];
+}
+
+static const char *
+h8300sx_register_name (struct gdbarch *gdbarch, int regno)
+{
+ static char *register_names[] = {
+ "er0", "er1", "er2", "er3", "er4", "er5", "er6",
+ "sp", "", "pc", "cycles", "", "tick", "inst",
+ "mach", "macl", "sbr", "vbr",
+ "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);
+ else
+ return register_names[regno];
+}
+
+static void
+h8300_print_register (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, int regno)
{
- if (regno == 8)
+ LONGEST rval;
+ const char *name = gdbarch_register_name (gdbarch, regno);
+
+ if (!name || !*name)
+ return;
+
+ rval = get_frame_register_signed (frame, regno);
+
+ fprintf_filtered (file, "%-14s ", name);
+ if ((regno == E_PSEUDO_CCR_REGNUM (gdbarch)) || \
+ (regno == E_PSEUDO_EXR_REGNUM (gdbarch) && is_h8300smode (gdbarch)))
+ {
+ fprintf_filtered (file, "0x%02x ", (unsigned char) rval);
+ print_longest (file, 'u', 1, rval);
+ }
+ else
+ {
+ fprintf_filtered (file, "0x%s ", phex ((ULONGEST) rval,
+ BINWORD (gdbarch)));
+ print_longest (file, 'd', 1, rval);
+ }
+ if (regno == E_PSEUDO_CCR_REGNUM (gdbarch))
{
/* CCR register */
int C, Z, N, V;
- unsigned char b[4];
- unsigned char l;
- read_relative_register_raw_bytes (regno, b);
- l = b[REGISTER_VIRTUAL_SIZE(8) -1];
- printf_unfiltered ("\t");
- printf_unfiltered ("I-%d - ", (l & 0x80) != 0);
- printf_unfiltered ("H-%d - ", (l & 0x20) != 0);
+ unsigned char l = rval & 0xff;
+ fprintf_filtered (file, "\t");
+ fprintf_filtered (file, "I-%d ", (l & 0x80) != 0);
+ fprintf_filtered (file, "UI-%d ", (l & 0x40) != 0);
+ fprintf_filtered (file, "H-%d ", (l & 0x20) != 0);
+ fprintf_filtered (file, "U-%d ", (l & 0x10) != 0);
N = (l & 0x8) != 0;
Z = (l & 0x4) != 0;
V = (l & 0x2) != 0;
C = (l & 0x1) != 0;
- printf_unfiltered ("N-%d ", N);
- printf_unfiltered ("Z-%d ", Z);
- printf_unfiltered ("V-%d ", V);
- printf_unfiltered ("C-%d ", C);
+ fprintf_filtered (file, "N-%d ", N);
+ fprintf_filtered (file, "Z-%d ", Z);
+ fprintf_filtered (file, "V-%d ", V);
+ fprintf_filtered (file, "C-%d ", C);
if ((C | Z) == 0)
- printf_unfiltered ("u> ");
+ fprintf_filtered (file, "u> ");
if ((C | Z) == 1)
- printf_unfiltered ("u<= ");
+ fprintf_filtered (file, "u<= ");
if ((C == 0))
- printf_unfiltered ("u>= ");
+ fprintf_filtered (file, "u>= ");
if (C == 1)
- printf_unfiltered ("u< ");
+ fprintf_filtered (file, "u< ");
if (Z == 0)
- printf_unfiltered ("!= ");
+ fprintf_filtered (file, "!= ");
if (Z == 1)
- printf_unfiltered ("== ");
+ fprintf_filtered (file, "== ");
if ((N ^ V) == 0)
- printf_unfiltered (">= ");
+ fprintf_filtered (file, ">= ");
if ((N ^ V) == 1)
- printf_unfiltered ("< ");
+ fprintf_filtered (file, "< ");
if ((Z | (N ^ V)) == 0)
- printf_unfiltered ("> ");
+ fprintf_filtered (file, "> ");
if ((Z | (N ^ V)) == 1)
- printf_unfiltered ("<= ");
+ fprintf_filtered (file, "<= ");
+ }
+ else if (regno == E_PSEUDO_EXR_REGNUM (gdbarch) && is_h8300smode (gdbarch))
+ {
+ /* EXR register */
+ unsigned char l = rval & 0xff;
+ fprintf_filtered (file, "\t");
+ fprintf_filtered (file, "T-%d - - - ", (l & 0x80) != 0);
+ fprintf_filtered (file, "I2-%d ", (l & 4) != 0);
+ fprintf_filtered (file, "I1-%d ", (l & 2) != 0);
+ fprintf_filtered (file, "I0-%d", (l & 1) != 0);
+ }
+ fprintf_filtered (file, "\n");
+}
+
+static void
+h8300_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, int regno, int cpregs)
+{
+ if (regno < 0)
+ {
+ for (regno = E_R0_REGNUM; regno <= E_SP_REGNUM; ++regno)
+ h8300_print_register (gdbarch, file, frame, regno);
+ h8300_print_register (gdbarch, file, frame,
+ E_PSEUDO_CCR_REGNUM (gdbarch));
+ h8300_print_register (gdbarch, file, frame, E_PC_REGNUM);
+ if (is_h8300smode (gdbarch))
+ {
+ h8300_print_register (gdbarch, file, frame,
+ E_PSEUDO_EXR_REGNUM (gdbarch));
+ if (is_h8300sxmode (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_MACH_REGNUM);
+ h8300_print_register (gdbarch, file, frame, E_MACL_REGNUM);
+ h8300_print_register (gdbarch, file, frame, E_CYCLES_REGNUM);
+ h8300_print_register (gdbarch, file, frame, E_TICKS_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 (gdbarch));
+ else if (regno == E_PSEUDO_EXR_REGNUM (gdbarch)
+ && is_h8300smode (gdbarch))
+ h8300_print_register (gdbarch, file, frame,
+ E_PSEUDO_EXR_REGNUM (gdbarch));
+ else
+ h8300_print_register (gdbarch, file, frame, regno);
+ }
+}
+
+static struct type *
+h8300_register_type (struct gdbarch *gdbarch, int regno)
+{
+ if (regno < 0 || regno >= gdbarch_num_regs (gdbarch)
+ + gdbarch_num_pseudo_regs (gdbarch))
+ internal_error (__FILE__, __LINE__,
+ _("h8300_register_type: illegal register number %d"),
+ regno);
+ else
+ {
+ switch (regno)
+ {
+ case E_PC_REGNUM:
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ case E_SP_REGNUM:
+ case E_FP_REGNUM:
+ return builtin_type (gdbarch)->builtin_data_ptr;
+ default:
+ if (regno == E_PSEUDO_CCR_REGNUM (gdbarch))
+ return builtin_type (gdbarch)->builtin_uint8;
+ else if (regno == E_PSEUDO_EXR_REGNUM (gdbarch))
+ return builtin_type (gdbarch)->builtin_uint8;
+ else if (is_h8300hmode (gdbarch))
+ return builtin_type (gdbarch)->builtin_int32;
+ else
+ return builtin_type (gdbarch)->builtin_int16;
+ }
+ }
+}
+
+static enum register_status
+h8300_pseudo_register_read (struct gdbarch *gdbarch,
+ struct regcache *regcache, int regno,
+ gdb_byte *buf)
+{
+ if (regno == E_PSEUDO_CCR_REGNUM (gdbarch))
+ return regcache_raw_read (regcache, E_CCR_REGNUM, buf);
+ else if (regno == E_PSEUDO_EXR_REGNUM (gdbarch))
+ return regcache_raw_read (regcache, E_EXR_REGNUM, buf);
+ else
+ return regcache_raw_read (regcache, regno, buf);
+}
+
+static void
+h8300_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache, int regno,
+ const gdb_byte *buf)
+{
+ if (regno == E_PSEUDO_CCR_REGNUM (gdbarch))
+ regcache_raw_write (regcache, E_CCR_REGNUM, buf);
+ else if (regno == E_PSEUDO_EXR_REGNUM (gdbarch))
+ regcache_raw_write (regcache, E_EXR_REGNUM, buf);
+ else
+ regcache_raw_write (regcache, regno, buf);
+}
+
+static int
+h8300_dbg_reg_to_regnum (struct gdbarch *gdbarch, int regno)
+{
+ if (regno == E_CCR_REGNUM)
+ return E_PSEUDO_CCR_REGNUM (gdbarch);
+ return regno;
+}
+
+static int
+h8300s_dbg_reg_to_regnum (struct gdbarch *gdbarch, int regno)
+{
+ if (regno == E_CCR_REGNUM)
+ return E_PSEUDO_CCR_REGNUM (gdbarch);
+ if (regno == E_EXR_REGNUM)
+ return E_PSEUDO_EXR_REGNUM (gdbarch);
+ return regno;
+}
+
+static const unsigned char *
+h8300_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+ int *lenptr)
+{
+ /*static unsigned char breakpoint[] = { 0x7A, 0xFF }; *//* ??? */
+ static unsigned char breakpoint[] = { 0x01, 0x80 }; /* Sleep */
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+static void
+h8300_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+ struct frame_info *frame, const char *args)
+{
+ fprintf_filtered (file, "\
+No floating-point info available for this processor.\n");
+}
+
+static struct gdbarch *
+h8300_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep = NULL;
+ struct gdbarch *gdbarch;
+
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (arches != NULL)
+ return arches->gdbarch;
+
+#if 0
+ tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+#endif
+
+ if (info.bfd_arch_info->arch != bfd_arch_h8300)
+ return NULL;
+
+ gdbarch = gdbarch_alloc (&info, 0);
+
+ switch (info.bfd_arch_info->mach)
+ {
+ case bfd_mach_h8300:
+ 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, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_addr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ 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:
+ 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);
+ 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:
+ 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);
+ 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:
+ 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);
+ 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);
+
+ /*
+ * Basic register fields and methods.
+ */
+
+ set_gdbarch_sp_regnum (gdbarch, E_SP_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_print_float_info (gdbarch, h8300_print_float_info);
+
+ /*
+ * Frame Info
+ */
+ set_gdbarch_skip_prologue (gdbarch, h8300_skip_prologue);
+
+ /* Frame unwinder. */
+ set_gdbarch_unwind_pc (gdbarch, h8300_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, h8300_unwind_sp);
+ set_gdbarch_dummy_id (gdbarch, h8300_dummy_id);
+ frame_base_set_default (gdbarch, &h8300_frame_base);
+
+ /*
+ * Miscelany
+ */
+ /* Stack grows up. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ set_gdbarch_breakpoint_from_pc (gdbarch, h8300_breakpoint_from_pc);
+ 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_double_format (gdbarch, floatformats_ieee_single);
+ set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_single);
+
+ set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+ /* Hook in the DWARF CFI frame unwinder. */
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &h8300_frame_unwind);
+
+ return gdbarch;
+
}
+extern initialize_file_ftype _initialize_h8300_tdep; /* -Wmissing-prototypes */
+
void
-_initialize_h8300_tdep ()
+_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)
{
- tm_print_insn = gdb_print_insn_h8300;
+ 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;
}