diff -ruN usrc/gdb/configure.tgt src/gdb/configure.tgt --- usrc/gdb/configure.tgt 2009-04-17 10:22:25.000000000 -0400 +++ src/gdb/configure.tgt 2009-04-23 07:29:18.000000000 -0400 @@ -114,6 +114,11 @@ gdb_sim=../sim/frv/libsim.a ;; +moxie-*-elf) + gdb_target_obs="moxie-tdep.o" + gdb_sim=../sim/moxie/libsim.a + ;; + h8300-*-*) # Target: H8300 with HMS monitor and H8 simulator gdb_target_obs="h8300-tdep.o monitor.o dsrec.o" diff -ruN usrc/gdb/moxie-tdep.c src/gdb/moxie-tdep.c --- usrc/gdb/moxie-tdep.c 1969-12-31 19:00:00.000000000 -0500 +++ src/gdb/moxie-tdep.c 2009-04-23 07:18:09.000000000 -0400 @@ -0,0 +1,500 @@ +/* Target-dependent code for Moxie + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + 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. + + 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 . */ + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "gdb_string.h" +#include "value.h" +#include "inferior.h" +#include "symfile.h" +#include "objfiles.h" +#include "osabi.h" +#include "language.h" +#include "arch-utils.h" +#include "regcache.h" +#include "trad-frame.h" +#include "dis-asm.h" + +#include "gdb_assert.h" + +#include "moxie-tdep.h" + +/* Local functions */ + +extern void _initialize_moxie_tdep (void); + +/* Use an invalid address value as 'not available' marker. */ +enum { REG_UNAVAIL = (CORE_ADDR) -1 }; + +struct moxie_frame_cache +{ + /* Base address. */ + CORE_ADDR base; + CORE_ADDR pc; + LONGEST framesize; + CORE_ADDR saved_regs[MOXIE_NUM_REGS]; + CORE_ADDR saved_sp; +}; + +static CORE_ADDR +moxie_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) +{ + /* Align to the size of an instruction (so that they can safely be + pushed onto the stack. */ + return sp & ~1; +} + +const static unsigned char * +moxie_breakpoint_from_pc (struct gdbarch *gdbarch, + CORE_ADDR *pcptr, int *lenptr) +{ + static unsigned char breakpoint[] = { 0x35, 0x00 }; + *lenptr = sizeof (breakpoint); + return breakpoint; +} + +char *moxie_register_names[] = { + "$fp", "$sp", "$r0", "$r1", "$r2", + "$r3", "$r4", "$r5", "$r6", "$r7", + "$r8", "$r9", "$r10", "$r11", "$r12", + "$r13", "$pc", "$cc" }; + +static const char * +moxie_register_name (struct gdbarch *gdbarch, int reg_nr) +{ + if (reg_nr < 0) + return NULL; + if (reg_nr >= MOXIE_NUM_REGS) + return NULL; + return moxie_register_names[reg_nr]; +} + + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +static struct type * +moxie_register_type (struct gdbarch *gdbarch, int reg_nr) +{ + if (reg_nr == MOXIE_PC_REGNUM) + return builtin_type (gdbarch)->builtin_func_ptr; + else if (reg_nr == MOXIE_SP_REGNUM || reg_nr == MOXIE_FP_REGNUM) + return builtin_type (gdbarch)->builtin_data_ptr; + else + return builtin_type_int32; +} + + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. + + Things always get returned in RET1_REGNUM, RET2_REGNUM. */ + +static void +moxie_store_return_value (struct type *type, struct regcache *regcache, + const void *valbuf) +{ + CORE_ADDR regval; + int len = TYPE_LENGTH (type); + + regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len); + regcache_cooked_write_unsigned (regcache, RET1_REGNUM, regval); + + if (len > 4) + { + regval = extract_unsigned_integer ((gdb_byte *) valbuf + 4, len - 4); + regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval); + } +} + +/* Function: moxie_scan_prologue + Decode the instructions within the given address range. + Decide when we must have reached the end of the function prologue. + If a frame_info pointer is provided, fill in its saved_regs etc. + + Returns the address of the first instruction after the prologue. */ + +static CORE_ADDR +moxie_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr, + struct moxie_frame_cache *cache, + struct frame_info *this_frame) +{ + CORE_ADDR next_addr; + ULONGEST inst, inst2; + LONGEST offset; + int regnum; + + /* Record where the jsra instruction saves the PC and FP */ + cache->saved_regs[MOXIE_PC_REGNUM] = -4; + cache->saved_regs[MOXIE_FP_REGNUM] = 0; + cache->framesize = 0; + + if (start_addr >= end_addr) + return end_addr; + + for (next_addr = start_addr; + next_addr < end_addr; ) + { + inst = read_memory_unsigned_integer (next_addr, 2); + + if (inst >= 0x0614 && inst <= 0x061f) /* push %r2 .. push %r13 */ + { + regnum = inst & 0x000f; + cache->framesize += 4; + cache->saved_regs[regnum] = cache->framesize; + next_addr += 2; + } + + /* optional stack allocation for args and local vars <= 4 byte */ + else if (inst == 0x01f0) /* ldi.l $r13, X */ + { + offset = read_memory_integer (next_addr + 2, 4); + inst2 = read_memory_unsigned_integer (next_addr + 6, 2); + + if (inst2 == 0x051f) /* add.l $sp, $r13 */ + { + cache->framesize += offset; + } + + return (next_addr + 8); + } + else /* Not a prologue instruction. */ + break; + } + + return next_addr; +} + +/* Function: skip_prologue + Find end of function prologue */ + +#define DEFAULT_SEARCH_LIMIT 128 + +CORE_ADDR +moxie_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR func_addr = 0, func_end = 0; + char *func_name; + + if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end)) + { + struct symtab_and_line sal; + struct symbol *sym; + struct moxie_frame_cache cache; + CORE_ADDR plg_end; + + memset (&cache, 0, sizeof cache); + + plg_end = moxie_analyze_prologue (func_addr, func_end, &cache, NULL); + + /* Found a function. */ + sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL); + /* Don't use line number debug info for assembly source files. */ + if (sym && SYMBOL_LANGUAGE (sym) != language_asm) + { + 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 result of prologue parsing method. */ + return plg_end; + } + + /* No function symbol -- just return the PC. */ + + return (CORE_ADDR) pc; +} + +struct moxie_unwind_cache +{ + /* The previous frame's inner most stack address. Used as this + frame ID's stack_addr. */ + CORE_ADDR prev_sp; + /* The frame's base, optionally used by the high-level debug info. */ + CORE_ADDR base; + int size; + /* How far the SP and r13 (FP) have been offset from the start of + the stack frame (as defined by the previous frame's stack + pointer). */ + LONGEST sp_offset; + LONGEST r13_offset; + int uses_frame; + /* Table indicating the location of each and every register. */ + struct trad_frame_saved_reg *saved_regs; +}; + +static CORE_ADDR +moxie_read_pc (struct regcache *regcache) +{ + ULONGEST pc; + regcache_cooked_read_unsigned (regcache, MOXIE_PC_REGNUM, &pc); + return pc; +} + +static void +moxie_write_pc (struct regcache *regcache, CORE_ADDR val) +{ + regcache_cooked_write_unsigned (regcache, MOXIE_PC_REGNUM, val); +} + +static CORE_ADDR +moxie_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_unwind_register_unsigned (next_frame, MOXIE_SP_REGNUM); +} + + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ + +static void +moxie_extract_return_value (struct type *type, struct regcache *regcache, + void *dst) +{ + bfd_byte *valbuf = dst; + int len = TYPE_LENGTH (type); + ULONGEST tmp; + + /* By using store_unsigned_integer we avoid having to do + anything special for small big-endian values. */ + regcache_cooked_read_unsigned (regcache, RET1_REGNUM, &tmp); + store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), tmp); + + /* Ignore return values more than 8 bytes in size because the moxie + returns anything more than 8 bytes in the stack. */ + if (len > 4) + { + regcache_cooked_read_unsigned (regcache, RET1_REGNUM + 1, &tmp); + store_unsigned_integer (valbuf + len - 4, 4, tmp); + } +} + +enum return_value_convention +moxie_return_value (struct gdbarch *gdbarch, struct type *func_type, + struct type *valtype, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + if (TYPE_LENGTH (valtype) > 8) + return RETURN_VALUE_STRUCT_CONVENTION; + else + { + if (readbuf != NULL) + moxie_extract_return_value (valtype, regcache, readbuf); + if (writebuf != NULL) + moxie_store_return_value (valtype, regcache, writebuf); + return RETURN_VALUE_REGISTER_CONVENTION; + } +} + +static struct moxie_frame_cache * +moxie_alloc_frame_cache (void) +{ + struct moxie_frame_cache *cache; + int i; + + cache = FRAME_OBSTACK_ZALLOC (struct moxie_frame_cache); + + cache->base = 0; + cache->saved_sp = 0; + cache->pc = 0; + cache->framesize = 0; + for (i = 0; i < MOXIE_NUM_REGS; ++i) + cache->saved_regs[i] = REG_UNAVAIL; + + return cache; +} + +static struct moxie_frame_cache * +moxie_frame_cache (struct frame_info *this_frame, void **this_cache) +{ + struct moxie_frame_cache *cache; + CORE_ADDR current_pc; + int i; + + if (*this_cache) + return *this_cache; + + cache = moxie_alloc_frame_cache (); + *this_cache = cache; + + cache->base = get_frame_register_unsigned (this_frame, MOXIE_FP_REGNUM); + if (cache->base == 0) + return cache; + + cache->pc = get_frame_func (this_frame); + current_pc = get_frame_pc (this_frame); + if (cache->pc) + moxie_analyze_prologue (cache->pc, current_pc, cache, this_frame); + + cache->saved_sp = cache->base - cache->framesize; + + for (i = 0; i < MOXIE_NUM_REGS; ++i) + if (cache->saved_regs[i] != REG_UNAVAIL) + cache->saved_regs[i] = cache->base - cache->saved_regs[i]; + + return cache; +} + +static CORE_ADDR +moxie_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_unwind_register_unsigned (next_frame, MOXIE_PC_REGNUM); +} + +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + +static void +moxie_frame_this_id (struct frame_info *this_frame, + void **this_prologue_cache, struct frame_id *this_id) +{ + struct moxie_frame_cache *cache = moxie_frame_cache (this_frame, + this_prologue_cache); + + /* This marks the outermost frame. */ + if (cache->base == 0) + return; + + *this_id = frame_id_build (cache->saved_sp, cache->pc); +} + +static struct value * +moxie_frame_prev_register (struct frame_info *this_frame, + void **this_prologue_cache, int regnum) +{ + struct moxie_frame_cache *cache = moxie_frame_cache (this_frame, + this_prologue_cache); + gdb_assert (regnum >= 0); + + if (regnum == MOXIE_SP_REGNUM && cache->saved_sp) + return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp); + + if (regnum < MOXIE_NUM_REGS && cache->saved_regs[regnum] != REG_UNAVAIL) + return frame_unwind_got_memory (this_frame, regnum, + cache->saved_regs[regnum]); + + return frame_unwind_got_register (this_frame, regnum, regnum); +} + +static const struct frame_unwind moxie_frame_unwind = { + NORMAL_FRAME, + moxie_frame_this_id, + moxie_frame_prev_register, + NULL, + default_frame_sniffer +}; + +static CORE_ADDR +moxie_frame_base_address (struct frame_info *this_frame, void **this_cache) +{ + struct moxie_frame_cache *cache = moxie_frame_cache (this_frame, + this_cache); + return cache->base; +} + +static const struct frame_base moxie_frame_base = { + &moxie_frame_unwind, + moxie_frame_base_address, + moxie_frame_base_address, + moxie_frame_base_address +}; + +/* Assuming THIS_FRAME is a dummy, return the frame ID of that dummy + frame. The frame ID's base needs to match the TOS value saved by + save_dummy_frame_tos(), and the PC match the dummy frame's breakpoint. */ + +static struct frame_id +moxie_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + CORE_ADDR sp = get_frame_register_unsigned (this_frame, MOXIE_SP_REGNUM); + return frame_id_build (sp, get_frame_pc (this_frame)); +} + + +static gdbarch_init_ftype moxie_gdbarch_init; + +static struct gdbarch * +moxie_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + + /* If there is already a candidate, use it. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + return arches->gdbarch; + + /* Allocate space for the new architecture. */ + tdep = XMALLOC (struct gdbarch_tdep); + gdbarch = gdbarch_alloc (&info, tdep); + + set_gdbarch_read_pc (gdbarch, moxie_read_pc); + set_gdbarch_write_pc (gdbarch, moxie_write_pc); + set_gdbarch_unwind_sp (gdbarch, moxie_unwind_sp); + + set_gdbarch_num_regs (gdbarch, MOXIE_NUM_REGS); + set_gdbarch_sp_regnum (gdbarch, MOXIE_SP_REGNUM); + set_gdbarch_register_name (gdbarch, moxie_register_name); + set_gdbarch_register_type (gdbarch, moxie_register_type); + + set_gdbarch_return_value (gdbarch, moxie_return_value); + + set_gdbarch_skip_prologue (gdbarch, moxie_skip_prologue); + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_breakpoint_from_pc (gdbarch, moxie_breakpoint_from_pc); + set_gdbarch_frame_align (gdbarch, moxie_frame_align); + + frame_base_set_default (gdbarch, &moxie_frame_base); + + /* Methods for saving / extracting a dummy frame's ID. The ID's + stack address must match the SP value returned by + PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */ + set_gdbarch_dummy_id (gdbarch, moxie_dummy_id); + + /* Return the unwound PC value. */ + set_gdbarch_unwind_pc (gdbarch, moxie_unwind_pc); + + set_gdbarch_print_insn (gdbarch, print_insn_moxie); + + /* Hook in ABI-specific overrides, if they have been registered. */ + gdbarch_init_osabi (info, gdbarch); + + /* Hook in the default unwinders. */ + frame_unwind_append_unwinder (gdbarch, &moxie_frame_unwind); + + /* Support simple overlay manager. */ + set_gdbarch_overlay_update (gdbarch, simple_overlay_update); + + return gdbarch; +} + +void +_initialize_moxie_tdep (void) +{ + register_gdbarch_init (bfd_arch_moxie, moxie_gdbarch_init); +} diff -ruN usrc/gdb/moxie-tdep.h src/gdb/moxie-tdep.h --- usrc/gdb/moxie-tdep.h 1969-12-31 19:00:00.000000000 -0500 +++ src/gdb/moxie-tdep.h 2009-04-23 07:18:18.000000000 -0400 @@ -0,0 +1,45 @@ +/* Target-dependent code for Moxie + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + 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. + + 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 . */ + +#ifndef MOXIE_TDEP_H +#define MOXIE_TDEP_H + +struct gdbarch_tdep +{ + /* gdbarch target dependent data here. Currently unused for MOXIE. */ +}; + +/* moxie register names. */ + +enum moxie_regnum +{ + MOXIE_FP_REGNUM = 0, + MOXIE_SP_REGNUM = 1, + R0_REGNUM = 2, + R1_REGNUM = 3, + MOXIE_PC_REGNUM = 16, + MOXIE_CC_REGNUM = 17, + RET1_REGNUM = R0_REGNUM, + ARG1_REGNUM = R0_REGNUM, + ARGN_REGNUM = R1_REGNUM, +}; + +#define MOXIE_NUM_REGS 18 + +#endif /* moxie-tdep.h */