/* Target-dependent code for the Toshiba MeP for GDB, the GNU debugger.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Red Hat, 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
+ 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,
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, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "frame.h"
#include "elf-bfd.h"
#include "elf/mep.h"
#include "prologue-value.h"
-#include "opcode/cgen-bitset.h"
+#include "cgen/bitset.h"
#include "infcall.h"
#include "gdb_assert.h"
mask contains any of the me_module's coprocessor ISAs,
specifically excluding the generic coprocessor register sets. */
- CGEN_CPU_DESC desc = gdbarch_tdep (current_gdbarch)->cpu_desc;
+ CGEN_CPU_DESC desc = gdbarch_tdep (target_gdbarch)->cpu_desc;
const CGEN_HW_ENTRY *hw;
if (me_module == CONFIG_NONE)
static int
-mep_debug_reg_to_regnum (int debug_reg)
+mep_debug_reg_to_regnum (struct gdbarch *gdbarch, int debug_reg)
{
/* The debug info uses the raw register numbers. */
return mep_raw_to_pseudo[debug_reg];
return regval;
}
else
- return gdbarch_tdep (current_gdbarch)->me_module;
+ return gdbarch_tdep (target_gdbarch)->me_module;
}
static const char *
-mep_register_name (int regnr)
+mep_register_name (struct gdbarch *gdbarch, int regnr)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* General-purpose registers. */
static const char *gpr_names[] = {
{
/* Filter reserved or unused register numbers. */
{
- const char *name = mep_register_name (regnum);
+ const char *name = mep_register_name (gdbarch, regnum);
if (! name || name[0] == '\0')
return 0;
keep the 'g' packet format fixed), and the pseudoregisters vary
in length. */
if (IS_RAW_CR_REGNUM (reg_nr))
- return builtin_type_uint64;
+ return builtin_type (gdbarch)->builtin_uint64;
/* Since GDB doesn't allow registers to change type, we have two
banks of pseudoregisters for the coprocessor general-purpose
if (size == 32)
{
if (mep_pseudo_cr_is_float (reg_nr))
- return builtin_type_float;
+ return builtin_type (gdbarch)->builtin_float;
else
- return builtin_type_uint32;
+ return builtin_type (gdbarch)->builtin_uint32;
}
else if (size == 64)
{
if (mep_pseudo_cr_is_float (reg_nr))
- return builtin_type_double;
+ return builtin_type (gdbarch)->builtin_double;
else
- return builtin_type_uint64;
+ return builtin_type (gdbarch)->builtin_uint64;
}
else
gdb_assert (0);
/* All other registers are 32 bits long. */
else
- return builtin_type_uint32;
+ return builtin_type (gdbarch)->builtin_uint32;
}
int cookednum,
void *buf)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* Read the raw register into a 64-bit buffer, and then return the
appropriate end of that buffer. */
int rawnum = mep_pseudo_to_raw[cookednum];
gdb_assert (TYPE_LENGTH (register_type (gdbarch, cookednum)) == 4);
regcache_raw_read (regcache, rawnum, buf64);
/* Slow, but legible. */
- store_unsigned_integer (buf, 4, extract_unsigned_integer (buf64, 8));
+ store_unsigned_integer (buf, 4, byte_order,
+ extract_unsigned_integer (buf64, 8, byte_order));
}
int cookednum,
const void *buf)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int size = register_size (gdbarch, cookednum);
struct mep_csr_register *r
= &mep_csr_registers[cookednum - MEP_FIRST_CSR_REGNUM];
ULONGEST mixed_bits;
regcache_raw_read_unsigned (regcache, r->raw, &old_bits);
- new_bits = extract_unsigned_integer (buf, size);
+ new_bits = extract_unsigned_integer (buf, size, byte_order);
mixed_bits = ((r->writeable_bits & new_bits)
| (~r->writeable_bits & old_bits));
regcache_raw_write_unsigned (regcache, r->raw, mixed_bits);
int cookednum,
const void *buf)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* Expand the 32-bit value into a 64-bit value, and write that to
the pseudoregister. */
int rawnum = mep_pseudo_to_raw[cookednum];
gdb_assert (TYPE_LENGTH (register_type (gdbarch, rawnum)) == sizeof (buf64));
gdb_assert (TYPE_LENGTH (register_type (gdbarch, cookednum)) == 4);
/* Slow, but legible. */
- store_unsigned_integer (buf64, 8, extract_unsigned_integer (buf, 4));
+ store_unsigned_integer (buf64, 8, byte_order,
+ extract_unsigned_integer (buf, 4, byte_order));
regcache_raw_write (regcache, rawnum, buf64);
}
/* The mep disassembler needs to know about the section in order to
work correctly. */
-int
+static int
mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
{
struct obj_section * s = find_pc_section (pc);
anyway. */
static CORE_ADDR
-mep_get_insn (CORE_ADDR pc, long *insn)
+mep_get_insn (struct gdbarch *gdbarch, CORE_ADDR pc, long *insn)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int pc_in_vliw_section;
int vliw_mode;
int insn_len;
vliw_mode = 0;
read_memory (pc, buf, sizeof (buf));
- *insn = extract_unsigned_integer (buf, 2) << 16;
+ *insn = extract_unsigned_integer (buf, 2, byte_order) << 16;
/* The major opcode --- the top four bits of the first 16-bit
part --- indicates whether this instruction is 16 or 32 bits
{
/* Fetch the second 16-bit part of the instruction. */
read_memory (pc + 2, buf, sizeof (buf));
- *insn = *insn | extract_unsigned_integer (buf, 2);
+ *insn = *insn | extract_unsigned_integer (buf, 2, byte_order);
}
/* If we're in VLIW code, then the VLIW width determines the address
/* This structure holds the results of a prologue analysis. */
struct mep_prologue
{
+ /* The architecture for which we generated this prologue info. */
+ struct gdbarch *gdbarch;
+
/* The offset from the frame base to the stack pointer --- always
zero or negative.
- ADDR is a stack slot's address (e.g., relative to the original
value of the SP). */
static int
-is_arg_spill (pv_t value, pv_t addr, struct pv_area *stack)
+is_arg_spill (struct gdbarch *gdbarch, pv_t value, pv_t addr,
+ struct pv_area *stack)
{
return (is_arg_reg (value)
&& pv_is_register (addr, MEP_SP_REGNUM)
- && ! pv_area_find_reg (stack, current_gdbarch, value.reg, 0));
+ && ! pv_area_find_reg (stack, gdbarch, value.reg, 0));
}
if (value.kind == pvk_register
&& value.k == 0
&& pv_is_register (addr, MEP_SP_REGNUM)
- && size == register_size (current_gdbarch, value.reg))
+ && size == register_size (result->gdbarch, value.reg))
result->reg_offset[value.reg] = addr.k;
}
/* Analyze a prologue starting at START_PC, going no further than
LIMIT_PC. Fill in RESULT as appropriate. */
static void
-mep_analyze_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+mep_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR start_pc, CORE_ADDR limit_pc,
struct mep_prologue *result)
{
CORE_ADDR pc;
CORE_ADDR after_last_frame_setup_insn = start_pc;
memset (result, 0, sizeof (*result));
+ result->gdbarch = gdbarch;
for (rn = 0; rn < MEP_NUM_REGS; rn++)
{
result->reg_offset[rn] = 1;
}
- stack = make_pv_area (MEP_SP_REGNUM);
+ stack = make_pv_area (MEP_SP_REGNUM, gdbarch_addr_bit (gdbarch));
back_to = make_cleanup_free_pv_area (stack);
pc = start_pc;
CORE_ADDR next_pc;
pv_t pre_insn_fp, pre_insn_sp;
- next_pc = mep_get_insn (pc, &insn);
+ next_pc = mep_get_insn (gdbarch, pc, &insn);
/* A zero return from mep_get_insn means that either we weren't
able to read the instruction from memory, or that we don't
if (pv_area_store_would_trash (stack, reg[rm]))
break;
- if (is_arg_spill (reg[rn], reg[rm], stack))
+ if (is_arg_spill (gdbarch, reg[rn], reg[rm], stack))
after_last_frame_setup_insn = next_pc;
pv_area_store (stack, reg[rm], 4, reg[rn]);
if (pv_area_store_would_trash (stack, addr))
break;
- if (is_arg_spill (reg[rn], addr, stack))
+ if (is_arg_spill (gdbarch, reg[rn], addr, stack))
after_last_frame_setup_insn = next_pc;
pv_area_store (stack, addr, 4, reg[rn]);
if (pv_area_store_would_trash (stack, addr))
break;
- if (is_arg_spill (reg[rn], addr, stack))
+ if (is_arg_spill (gdbarch, reg[rn], addr, stack))
after_last_frame_setup_insn = next_pc;
pv_area_store (stack, addr, size, reg[rn]);
}
else if (IS_BRA (insn) && BRA_DISP (insn) > 0)
{
- /* When a loop appears as the first statement as a function
+ /* When a loop appears as the first statement of a function
body, gcc 4.x will use a BRA instruction to branch to the
loop condition checking code. This BRA instruction is
marked as part of the prologue. We therefore set next_pc
to this branch target and also stop the prologue scan.
The instructions at and beyond the branch target should
- no longer be associated with the prologue. */
+ no longer be associated with the prologue.
+
+ Note that we only consider forward branches here. We
+ presume that a forward branch is being used to skip over
+ a loop body.
+
+ A backwards branch is covered by the default case below.
+ If we were to encounter a backwards branch, that would
+ most likely mean that we've scanned through a loop body.
+ We definitely want to stop the prologue scan when this
+ happens and that is precisely what is done by the default
+ case below. */
next_pc = pc + BRA_DISP (insn);
after_last_frame_setup_insn = next_pc;
break;
static CORE_ADDR
-mep_skip_prologue (CORE_ADDR pc)
+mep_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
char *name;
CORE_ADDR func_addr, func_end;
if (! find_pc_partial_function (pc, &name, &func_addr, &func_end))
return pc;
- mep_analyze_prologue (pc, func_end, &p);
+ mep_analyze_prologue (gdbarch, pc, func_end, &p);
return p.prologue_end;
}
/* Breakpoints. */
static const unsigned char *
-mep_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
+mep_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr, int *lenptr)
{
static unsigned char breakpoint[] = { 0x70, 0x32 };
*lenptr = sizeof (breakpoint);
static struct mep_prologue *
-mep_analyze_frame_prologue (struct frame_info *next_frame,
+mep_analyze_frame_prologue (struct frame_info *this_frame,
void **this_prologue_cache)
{
if (! *this_prologue_cache)
*this_prologue_cache
= FRAME_OBSTACK_ZALLOC (struct mep_prologue);
- func_start = frame_func_unwind (next_frame, NORMAL_FRAME);
- stop_addr = frame_pc_unwind (next_frame);
+ func_start = get_frame_func (this_frame);
+ stop_addr = get_frame_pc (this_frame);
/* If we couldn't find any function containing the PC, then
just initialize the prologue cache, but don't do anything. */
if (! func_start)
stop_addr = func_start;
- mep_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+ mep_analyze_prologue (get_frame_arch (this_frame),
+ func_start, stop_addr, *this_prologue_cache);
}
return *this_prologue_cache;
/* Given the next frame and a prologue cache, return this frame's
base. */
static CORE_ADDR
-mep_frame_base (struct frame_info *next_frame,
+mep_frame_base (struct frame_info *this_frame,
void **this_prologue_cache)
{
struct mep_prologue *p
- = mep_analyze_frame_prologue (next_frame, this_prologue_cache);
+ = mep_analyze_frame_prologue (this_frame, this_prologue_cache);
/* In functions that use alloca, the distance between the stack
pointer and the frame base varies dynamically, so we can't use
if (p->has_frame_ptr)
{
CORE_ADDR fp
- = frame_unwind_register_unsigned (next_frame, MEP_FP_REGNUM);
+ = get_frame_register_unsigned (this_frame, MEP_FP_REGNUM);
return fp - p->frame_ptr_offset;
}
else
{
CORE_ADDR sp
- = frame_unwind_register_unsigned (next_frame, MEP_SP_REGNUM);
+ = get_frame_register_unsigned (this_frame, MEP_SP_REGNUM);
return sp - p->frame_size;
}
}
static void
-mep_frame_this_id (struct frame_info *next_frame,
+mep_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
- *this_id = frame_id_build (mep_frame_base (next_frame, this_prologue_cache),
- frame_func_unwind (next_frame, NORMAL_FRAME));
+ *this_id = frame_id_build (mep_frame_base (this_frame, this_prologue_cache),
+ get_frame_func (this_frame));
}
-static void
-mep_frame_prev_register (struct frame_info *next_frame,
- void **this_prologue_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, gdb_byte *bufferp)
+static struct value *
+mep_frame_prev_register (struct frame_info *this_frame,
+ void **this_prologue_cache, int regnum)
{
struct mep_prologue *p
- = mep_analyze_frame_prologue (next_frame, this_prologue_cache);
+ = mep_analyze_frame_prologue (this_frame, this_prologue_cache);
/* There are a number of complications in unwinding registers on the
MeP, having to do with core functions calling VLIW functions and
do this. */
if (regnum == MEP_PC_REGNUM)
{
- mep_frame_prev_register (next_frame, this_prologue_cache, MEP_LP_REGNUM,
- optimizedp, lvalp, addrp, realnump, bufferp);
- store_unsigned_integer (bufferp, MEP_LP_SIZE,
- (extract_unsigned_integer (bufferp, MEP_LP_SIZE)
- & ~1));
- *lvalp = not_lval;
+ struct value *value;
+ CORE_ADDR lp;
+ value = mep_frame_prev_register (this_frame, this_prologue_cache,
+ MEP_LP_REGNUM);
+ lp = value_as_long (value);
+ release_value (value);
+ value_free (value);
+
+ return frame_unwind_got_constant (this_frame, regnum, lp & ~1);
}
else
{
- CORE_ADDR frame_base = mep_frame_base (next_frame, this_prologue_cache);
- int reg_size = register_size (get_frame_arch (next_frame), regnum);
+ CORE_ADDR frame_base = mep_frame_base (this_frame, this_prologue_cache);
+ struct value *value;
/* Our caller's SP is our frame base. */
if (regnum == MEP_SP_REGNUM)
- {
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (bufferp)
- store_unsigned_integer (bufferp, reg_size, frame_base);
- }
+ return frame_unwind_got_constant (this_frame, regnum, frame_base);
/* If prologue analysis says we saved this register somewhere,
return a description of the stack slot holding it. */
- else if (p->reg_offset[regnum] != 1)
- {
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = frame_base + p->reg_offset[regnum];
- *realnump = -1;
- if (bufferp)
- get_frame_memory (next_frame, *addrp, bufferp, reg_size);
- }
+ if (p->reg_offset[regnum] != 1)
+ value = frame_unwind_got_memory (this_frame, regnum,
+ frame_base + p->reg_offset[regnum]);
/* Otherwise, presume we haven't changed the value of this
register, and get it from the next frame. */
else
- frame_register_unwind (next_frame, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ value = frame_unwind_got_register (this_frame, regnum, regnum);
/* If we need to toggle the operating mode, do so. */
if (regnum == MEP_PSW_REGNUM)
{
- int lp_optimized;
- enum lval_type lp_lval;
- CORE_ADDR lp_addr;
- int lp_realnum;
- char lp_buffer[MEP_LP_SIZE];
+ CORE_ADDR psw, lp;
+
+ psw = value_as_long (value);
+ release_value (value);
+ value_free (value);
/* Get the LP's value, too. */
- frame_register_unwind (next_frame, MEP_LP_REGNUM,
- &lp_optimized, &lp_lval, &lp_addr,
- &lp_realnum, lp_buffer);
+ value = get_frame_register_value (this_frame, MEP_LP_REGNUM);
+ lp = value_as_long (value);
+ release_value (value);
+ value_free (value);
/* If LP.LTOM is set, then toggle PSW.OM. */
- if (extract_unsigned_integer (lp_buffer, MEP_LP_SIZE) & 0x1)
- store_unsigned_integer
- (bufferp, MEP_PSW_SIZE,
- (extract_unsigned_integer (bufferp, MEP_PSW_SIZE) ^ 0x1000));
- *lvalp = not_lval;
+ if (lp & 0x1)
+ psw ^= 0x1000;
+
+ return frame_unwind_got_constant (this_frame, regnum, psw);
}
+
+ return value;
}
}
static const struct frame_unwind mep_frame_unwind = {
NORMAL_FRAME,
mep_frame_this_id,
- mep_frame_prev_register
+ mep_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-static const struct frame_unwind *
-mep_frame_sniffer (struct frame_info *next_frame)
-{
- return &mep_frame_unwind;
-}
-
-
/* Our general unwinding function can handle unwinding the PC. */
static CORE_ADDR
mep_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
"Try using the 'return' command with no argument.");
}
-enum return_value_convention
-mep_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, gdb_byte *readbuf,
- const gdb_byte *writebuf)
+static enum return_value_convention
+mep_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
if (mep_use_struct_convention (type))
{
int struct_return,
CORE_ADDR struct_addr)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR *copy = (CORE_ADDR *) alloca (argc * sizeof (copy[0]));
CORE_ADDR func_addr = find_function_addr (function, NULL);
int i;
/* Arguments that fit in a GPR get expanded to fill the GPR. */
if (arg_size <= MEP_GPR_SIZE)
value = extract_unsigned_integer (value_contents (argv[i]),
- TYPE_LENGTH (value_type (argv[i])));
+ TYPE_LENGTH (value_type (argv[i])),
+ byte_order);
/* Arguments too large to fit in a GPR get copied to the stack,
and we pass a pointer to the copy. */
else
{
char buf[MEP_GPR_SIZE];
- store_unsigned_integer (buf, MEP_GPR_SIZE, value);
+ store_unsigned_integer (buf, MEP_GPR_SIZE, byte_order, value);
write_memory (arg_stack, buf, MEP_GPR_SIZE);
arg_stack += MEP_GPR_SIZE;
}
static struct frame_id
-mep_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+mep_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
- return frame_id_build (mep_unwind_sp (gdbarch, next_frame),
- frame_pc_unwind (next_frame));
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, MEP_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
}
set_gdbarch_skip_prologue (gdbarch, mep_skip_prologue);
/* Frames and frame unwinding. */
- frame_unwind_append_sniffer (gdbarch, mep_frame_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &mep_frame_unwind);
set_gdbarch_unwind_pc (gdbarch, mep_unwind_pc);
set_gdbarch_unwind_sp (gdbarch, mep_unwind_sp);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
/* Inferior function calls. */
set_gdbarch_frame_align (gdbarch, mep_frame_align);
set_gdbarch_push_dummy_call (gdbarch, mep_push_dummy_call);
- set_gdbarch_unwind_dummy_id (gdbarch, mep_unwind_dummy_id);
+ set_gdbarch_dummy_id (gdbarch, mep_dummy_id);
return gdbarch;
}
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_mep_tdep;
void
_initialize_mep_tdep (void)