/* Target-dependent code for the Toshiba MeP for GDB, the GNU debugger.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ Copyright (C) 2001-2021 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 "gdbtypes.h"
#include "gdbcmd.h"
#include "gdbcore.h"
-#include "gdb_string.h"
#include "value.h"
#include "inferior.h"
#include "dis-asm.h"
#include "arch-utils.h"
#include "regcache.h"
#include "remote.h"
-#include "floatformat.h"
#include "sim-regno.h"
#include "disasm.h"
#include "trad-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"
-
/* Get the user's customized MeP coprocessor register names from
libopcodes. */
#include "opcodes/mep-desc.h"
return zero. */
static const CGEN_HW_ENTRY *
find_hw_entry_by_prefix_and_isa (CGEN_CPU_DESC desc,
- const char *prefix,
- CGEN_BITSET *copro_isa_mask,
- CGEN_BITSET *generic_isa_mask)
+ const char *prefix,
+ CGEN_BITSET *copro_isa_mask,
+ CGEN_BITSET *generic_isa_mask)
{
int prefix_len = strlen (prefix);
int i;
{
const CGEN_HW_ENTRY *hw = desc->hw_table.entries[i];
if (strncmp (prefix, hw->name, prefix_len) == 0)
- {
- CGEN_BITSET *hw_isa_mask
- = ((CGEN_BITSET *)
- &CGEN_ATTR_CGEN_HW_ISA_VALUE (CGEN_HW_ATTRS (hw)));
-
- if (cgen_bitset_intersect_p (hw_isa_mask, copro_isa_mask)
- && ! cgen_bitset_intersect_p (hw_isa_mask, generic_isa_mask))
- return hw;
- }
+ {
+ CGEN_BITSET *hw_isa_mask
+ = ((CGEN_BITSET *)
+ &CGEN_ATTR_CGEN_HW_ISA_VALUE (CGEN_HW_ATTRS (hw)));
+
+ if (cgen_bitset_intersect_p (hw_isa_mask, copro_isa_mask)
+ && ! cgen_bitset_intersect_p (hw_isa_mask, generic_isa_mask))
+ return hw;
+ }
}
return 0;
const CGEN_HW_ENTRY *hw = desc->hw_table.entries[i];
if (hw->type == type)
- return hw;
+ return hw;
}
return 0;
whose hardware type is GENERIC_TYPE. */
static const CGEN_HW_ENTRY *
me_module_register_set (CONFIG_ATTR me_module,
- const char *prefix,
- CGEN_HW_TYPE generic_type)
+ const char *prefix,
+ CGEN_HW_TYPE generic_type)
{
/* This is kind of tricky, because the hardware table is constructed
in a way that isn't very helpful. Perhaps we can fix that, but
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)
/* Given a hardware table entry HW representing a register set, return
a pointer to the keyword table with all the register names. If HW
- is NULL, return NULL, to propage the "no such register set" info
+ is NULL, return NULL, to propagate the "no such register set" info
along. */
static CGEN_KEYWORD *
register_set_keyword_table (const CGEN_HW_ENTRY *hw)
/* Given a keyword table KEYWORD and a register number REGNUM, return
the name of the register, or "" if KEYWORD contains no register
whose number is REGNUM. */
-static char *
+static const char *
register_name_from_keyword (CGEN_KEYWORD *keyword_table, int regnum)
{
const CGEN_KEYWORD_ENTRY *entry
char *name = entry->name;
/* The CGEN keyword entries for register names include the
- leading $, which appears in MeP assembly as well as in GDB.
- But we don't want to return that; GDB core code adds that
- itself. */
+ leading $, which appears in MeP assembly as well as in GDB.
+ But we don't want to return that; GDB core code adds that
+ itself. */
if (name[0] == '$')
- name++;
+ name++;
return name;
}
#define IS_CR64_REGNUM(n) (IN_SET (CR64, (n)))
#define IS_FP_CR64_REGNUM(n) (IN_SET (FP_CR64, (n)))
#define IS_CR_REGNUM(n) (IS_CR32_REGNUM (n) || IS_FP_CR32_REGNUM (n) \
- || IS_CR64_REGNUM (n) || IS_FP_CR64_REGNUM (n))
+ || IS_CR64_REGNUM (n) || IS_FP_CR64_REGNUM (n))
#define IS_CCR_REGNUM(n) (IN_SET (CCR, (n)))
#define IS_RAW_REGNUM(n) (IN_SET (RAW, (n)))
We just list the register numbers here explicitly to help catch
typos. */
#define CSR(name) MEP_RAW_ ## name ## _REGNUM, MEP_ ## name ## _REGNUM
-struct mep_csr_register mep_csr_registers[] = {
+static mep_csr_register mep_csr_registers[] = {
{ CSR(PC), 0xffffffff }, /* manual says r/o, but we can write it */
{ CSR(LP), 0xffffffff },
{ CSR(SAR), 0x0000003f },
int pseudofp64 = MEP_FIRST_FP_CR64_REGNUM + i;
/* Truly, the raw->pseudo mapping depends on the current module.
- But we use the raw->pseudo mapping when we read the debugging
- info; at that point, we don't know what module we'll actually
- be running yet. So, we always supply the 64-bit register
- numbers; GDB knows how to pick a smaller value out of a
- larger register properly. */
+ But we use the raw->pseudo mapping when we read the debugging
+ info; at that point, we don't know what module we'll actually
+ be running yet. So, we always supply the 64-bit register
+ numbers; GDB knows how to pick a smaller value out of a
+ larger register properly. */
mep_raw_to_pseudo[raw] = pseudo64;
mep_pseudo_to_raw[pseudo32] = raw;
mep_pseudo_to_raw[pseudofp32] = raw;
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];
+ if (debug_reg >= 0 && debug_reg < ARRAY_SIZE (mep_raw_to_pseudo))
+ return mep_raw_to_pseudo[debug_reg];
+ return -1;
}
|| IS_FP_CR32_REGNUM (pseudo))
return 32;
else if (IS_CR64_REGNUM (pseudo)
- || IS_FP_CR64_REGNUM (pseudo))
+ || IS_FP_CR64_REGNUM (pseudo))
return 64;
else
- gdb_assert (0);
+ gdb_assert_not_reached ("unexpected coprocessor pseudo register");
}
mep_pseudo_cr_is_float (int pseudo)
{
return (IS_FP_CR32_REGNUM (pseudo)
- || IS_FP_CR64_REGNUM (pseudo));
+ || IS_FP_CR64_REGNUM (pseudo));
}
else if (IS_FP_CR64_REGNUM (pseudo))
return pseudo - MEP_FIRST_FP_CR64_REGNUM;
else
- gdb_assert (0);
+ gdb_assert_not_reached ("unexpected coprocessor pseudo register");
}
from the ELF header's e_flags field of the current executable
file. */
static CONFIG_ATTR
-current_me_module ()
+current_me_module (void)
{
- if (target_has_registers)
- return read_register (MEP_MODULE_REGNUM);
+ if (target_has_registers ())
+ {
+ ULONGEST regval;
+ regcache_cooked_read_unsigned (get_current_regcache (),
+ MEP_MODULE_REGNUM, ®val);
+ return (CONFIG_ATTR) regval;
+ }
else
- return gdbarch_tdep (current_gdbarch)->me_module;
+ return gdbarch_tdep (target_gdbarch ())->me_module;
}
then use the 'module_opt' field we computed when we build the
gdbarch object for this module. */
static unsigned int
-current_options ()
+current_options (void)
{
- if (target_has_registers)
- return read_register (MEP_OPT_REGNUM);
+ if (target_has_registers ())
+ {
+ ULONGEST regval;
+ regcache_cooked_read_unsigned (get_current_regcache (),
+ MEP_OPT_REGNUM, ®val);
+ return regval;
+ }
else
return me_module_opt (current_me_module ());
}
/* Return the width of the current me_module's coprocessor data bus,
in bits. This is either 32 or 64. */
static int
-current_cop_data_bus_width ()
+current_cop_data_bus_width (void)
{
return me_module_cop_data_bus_width (current_me_module ());
}
/* Return the keyword table of coprocessor general-purpose register
names appropriate for the me_module we're dealing with. */
static CGEN_KEYWORD *
-current_cr_names ()
+current_cr_names (void)
{
const CGEN_HW_ENTRY *hw
= me_module_register_set (current_me_module (), "h-cr-", HW_H_CR);
/* Return non-zero if the coprocessor general-purpose registers are
floating-point values, zero otherwise. */
static int
-current_cr_is_float ()
+current_cr_is_float (void)
{
const CGEN_HW_ENTRY *hw
= me_module_register_set (current_me_module (), "h-cr-", HW_H_CR);
/* Return the keyword table of coprocessor control register names
appropriate for the me_module we're dealing with. */
static CGEN_KEYWORD *
-current_ccr_names ()
+current_ccr_names (void)
{
const CGEN_HW_ENTRY *hw
= me_module_register_set (current_me_module (), "h-ccr-", HW_H_CCR);
static const char *
-mep_register_name (int regnr)
+mep_register_name (struct gdbarch *gdbarch, int regnr)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
/* General-purpose registers. */
static const char *gpr_names[] = {
"r0", "r1", "r2", "r3", /* 0 */
else if (IS_CSR_REGNUM (regnr))
{
/* The 'hi' and 'lo' registers are only present on processors
- that have the 'MUL' or 'DIV' instructions enabled. */
+ that have the 'MUL' or 'DIV' instructions enabled. */
if ((regnr == MEP_HI_REGNUM || regnr == MEP_LO_REGNUM)
- && (! (current_options () & (MEP_OPT_MUL | MEP_OPT_DIV))))
- return "";
+ && (! (current_options () & (MEP_OPT_MUL | MEP_OPT_DIV))))
+ return "";
return csr_names[regnr - MEP_FIRST_CSR_REGNUM];
}
/* Does this module have a coprocessor at all? */
if (! (current_options () & MEP_OPT_COP))
- return "";
+ return "";
names = current_cr_names ();
if (! names)
- /* This module's coprocessor has no general-purpose registers. */
- return "";
+ /* This module's coprocessor has no general-purpose registers. */
+ return "";
cr_size = current_cop_data_bus_width ();
if (cr_size != mep_pseudo_cr_size (regnr))
- /* This module's coprocessor's GPR's are of a different size. */
- return "";
+ /* This module's coprocessor's GPR's are of a different size. */
+ return "";
cr_is_float = current_cr_is_float ();
/* The extra ! operators ensure we get boolean equality, not
- numeric equality. */
+ numeric equality. */
if (! cr_is_float != ! mep_pseudo_cr_is_float (regnr))
- /* This module's coprocessor's GPR's are of a different type. */
- return "";
+ /* This module's coprocessor's GPR's are of a different type. */
+ return "";
return register_name_from_keyword (names, mep_pseudo_cr_index (regnr));
}
{
/* Does this module have a coprocessor at all? */
if (! (current_options () & MEP_OPT_COP))
- return "";
+ return "";
{
- CGEN_KEYWORD *names = current_ccr_names ();
+ CGEN_KEYWORD *names = current_ccr_names ();
- if (! names)
- /* This me_module's coprocessor has no control registers. */
- return "";
+ if (! names)
+ /* This me_module's coprocessor has no control registers. */
+ return "";
- return register_name_from_keyword (names, regnr-MEP_FIRST_CCR_REGNUM);
+ return register_name_from_keyword (names, regnr-MEP_FIRST_CCR_REGNUM);
}
}
static int
mep_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
- struct reggroup *group)
+ struct reggroup *group)
{
/* 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;
the existing behavior, so we'd want to run that by them. */
if (group == general_reggroup)
return (IS_GPR_REGNUM (regnum)
- || IS_CSR_REGNUM (regnum));
+ || IS_CSR_REGNUM (regnum));
/* Everything is in the 'all' reggroup, except for the raw CSR's. */
else if (group == all_reggroup)
return (IS_GPR_REGNUM (regnum)
- || IS_CSR_REGNUM (regnum)
- || IS_CR_REGNUM (regnum)
- || IS_CCR_REGNUM (regnum));
+ || IS_CSR_REGNUM (regnum)
+ || IS_CR_REGNUM (regnum)
+ || IS_CCR_REGNUM (regnum));
/* All registers should be saved and restored, except for the raw
CSR's.
hardware engine, perhaps. */
else if (group == save_reggroup || group == restore_reggroup)
return (IS_GPR_REGNUM (regnum)
- || IS_CSR_REGNUM (regnum)
- || IS_CR_REGNUM (regnum)
- || IS_CCR_REGNUM (regnum));
+ || IS_CSR_REGNUM (regnum)
+ || IS_CR_REGNUM (regnum)
+ || IS_CCR_REGNUM (regnum));
else if (group == mep_csr_reggroup)
return IS_CSR_REGNUM (regnum);
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
{
int size = mep_pseudo_cr_size (reg_nr);
if (size == 32)
- {
- if (mep_pseudo_cr_is_float (reg_nr))
- return builtin_type_float;
- else
- return builtin_type_uint32;
- }
+ {
+ if (mep_pseudo_cr_is_float (reg_nr))
+ return builtin_type (gdbarch)->builtin_float;
+ else
+ return builtin_type (gdbarch)->builtin_uint32;
+ }
else if (size == 64)
- {
- if (mep_pseudo_cr_is_float (reg_nr))
- return builtin_type_double;
- else
- return builtin_type_uint64;
- }
+ {
+ if (mep_pseudo_cr_is_float (reg_nr))
+ return builtin_type (gdbarch)->builtin_double;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+ }
else
- gdb_assert (0);
+ gdb_assert_not_reached ("unexpected cr size");
}
/* All other registers are 32 bits long. */
else
- return builtin_type_uint32;
+ return builtin_type (gdbarch)->builtin_uint32;
}
-
-static CORE_ADDR
-mep_read_pc (ptid_t ptid)
-{
- ptid_t saved_ptid;
- CORE_ADDR pc;
-
- saved_ptid = inferior_ptid;
- inferior_ptid = ptid;
-
- pc = read_register (MEP_PC_REGNUM);
-
- inferior_ptid = saved_ptid;
- return pc;
-}
-
-static void
-mep_write_pc (CORE_ADDR pc, ptid_t ptid)
-{
- ptid_t saved_ptid;
-
- saved_ptid = inferior_ptid;
- inferior_ptid = ptid;
-
- write_register (MEP_PC_REGNUM, pc);
-
- inferior_ptid = saved_ptid;
-}
-
-
-static void
+static enum register_status
mep_pseudo_cr32_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- void *buf)
+ readable_regcache *regcache,
+ int cookednum,
+ gdb_byte *buf)
{
+ enum register_status status;
+ 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];
- char buf64[8];
+ gdb_byte buf64[8];
gdb_assert (TYPE_LENGTH (register_type (gdbarch, rawnum)) == sizeof (buf64));
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));
+ status = regcache->raw_read (rawnum, buf64);
+ if (status == REG_VALID)
+ {
+ /* Slow, but legible. */
+ store_unsigned_integer (buf, 4, byte_order,
+ extract_unsigned_integer (buf64, 8, byte_order));
+ }
+ return status;
}
-static void
+static enum register_status
mep_pseudo_cr64_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- void *buf)
+ readable_regcache *regcache,
+ int cookednum,
+ gdb_byte *buf)
{
- regcache_raw_read (regcache, mep_pseudo_to_raw[cookednum], buf);
+ return regcache->raw_read (mep_pseudo_to_raw[cookednum], buf);
}
-static void
+static enum register_status
mep_pseudo_register_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- gdb_byte *buf)
+ readable_regcache *regcache,
+ int cookednum,
+ gdb_byte *buf)
{
if (IS_CSR_REGNUM (cookednum)
|| IS_CCR_REGNUM (cookednum))
- regcache_raw_read (regcache, mep_pseudo_to_raw[cookednum], buf);
+ return regcache->raw_read (mep_pseudo_to_raw[cookednum], buf);
else if (IS_CR32_REGNUM (cookednum)
- || IS_FP_CR32_REGNUM (cookednum))
- mep_pseudo_cr32_read (gdbarch, regcache, cookednum, buf);
+ || IS_FP_CR32_REGNUM (cookednum))
+ return mep_pseudo_cr32_read (gdbarch, regcache, cookednum, buf);
else if (IS_CR64_REGNUM (cookednum)
- || IS_FP_CR64_REGNUM (cookednum))
- mep_pseudo_cr64_read (gdbarch, regcache, cookednum, buf);
+ || IS_FP_CR64_REGNUM (cookednum))
+ return mep_pseudo_cr64_read (gdbarch, regcache, cookednum, buf);
else
- gdb_assert (0);
+ gdb_assert_not_reached ("unexpected pseudo register");
}
static void
mep_pseudo_csr_write (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- const void *buf)
+ struct regcache *regcache,
+ int cookednum,
+ const gdb_byte *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 old_bits;
ULONGEST new_bits;
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));
+ | (~r->writeable_bits & old_bits));
regcache_raw_write_unsigned (regcache, r->raw, mixed_bits);
}
}
-
+
static void
mep_pseudo_cr32_write (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- const void *buf)
+ struct regcache *regcache,
+ int cookednum,
+ const gdb_byte *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];
- char buf64[8];
+ gdb_byte buf64[8];
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));
- regcache_raw_write (regcache, rawnum, buf64);
+ store_unsigned_integer (buf64, 8, byte_order,
+ extract_unsigned_integer (buf, 4, byte_order));
+ regcache->raw_write (rawnum, buf64);
}
static void
mep_pseudo_cr64_write (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- const void *buf)
+ struct regcache *regcache,
+ int cookednum,
+ const gdb_byte *buf)
{
- regcache_raw_write (regcache, mep_pseudo_to_raw[cookednum], buf);
+ regcache->raw_write (mep_pseudo_to_raw[cookednum], buf);
}
static void
mep_pseudo_register_write (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- const gdb_byte *buf)
+ struct regcache *regcache,
+ int cookednum,
+ const gdb_byte *buf)
{
if (IS_CSR_REGNUM (cookednum))
mep_pseudo_csr_write (gdbarch, regcache, cookednum, buf);
else if (IS_CR32_REGNUM (cookednum)
- || IS_FP_CR32_REGNUM (cookednum))
+ || IS_FP_CR32_REGNUM (cookednum))
mep_pseudo_cr32_write (gdbarch, regcache, cookednum, buf);
else if (IS_CR64_REGNUM (cookednum)
- || IS_FP_CR64_REGNUM (cookednum))
+ || IS_FP_CR64_REGNUM (cookednum))
mep_pseudo_cr64_write (gdbarch, regcache, cookednum, buf);
else if (IS_CCR_REGNUM (cookednum))
- regcache_raw_write (regcache, mep_pseudo_to_raw[cookednum], buf);
+ regcache->raw_write (mep_pseudo_to_raw[cookednum], buf);
else
- gdb_assert (0);
+ gdb_assert_not_reached ("unexpected pseudo register");
}
\f
/* Disassembly. */
-/* 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);
+ info->arch = bfd_arch_mep;
if (s)
{
/* The libopcodes disassembly code uses the section to find the
- BFD, the BFD to find the ELF header, the ELF header to find
- the me_module index, and the me_module index to select the
- right instructions to print. */
+ BFD, the BFD to find the ELF header, the ELF header to find
+ the me_module index, and the me_module index to select the
+ right instructions to print. */
info->section = s->the_bfd_section;
- info->arch = bfd_arch_mep;
-
- return print_insn_mep (pc, info);
}
-
- return 0;
+
+ return print_insn_mep (pc, info);
}
\f
Every bundle is four bytes long, and naturally aligned, and can hold
one or two instructions:
- 16-bit core instruction; 16-bit coprocessor instruction
- These execute in parallel.
+ These execute in parallel.
- 32-bit core instruction
- 32-bit coprocessor instruction
Every bundle is eight bytes long, and naturally aligned, and can hold
one or two instructions:
- 16-bit core instruction; 48-bit (!) coprocessor instruction
- These execute in parallel.
+ These execute in parallel.
- 32-bit core instruction; 32-bit coprocessor instruction
- These execute in parallel.
+ These execute in parallel.
- 64-bit coprocessor instruction
Now, the MeP manual doesn't define any 48- or 64-bit coprocessor
void
foo (void)
{
- asm ("movu $1, 0x123456");
- asm ("sb $1,0x5678($2)");
- asm ("clip $1, 19");
+ asm ("movu $1, 0x123456");
+ asm ("sb $1,0x5678($2)");
+ asm ("clip $1, 19");
}
compiles to this big-endian code:
anyway. */
static CORE_ADDR
-mep_get_insn (CORE_ADDR pc, long *insn)
+mep_get_insn (struct gdbarch *gdbarch, CORE_ADDR pc, unsigned long *insn)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int pc_in_vliw_section;
int vliw_mode;
int insn_len;
- char buf[2];
+ gdb_byte buf[2];
*insn = 0;
vliw_mode = current_options () & (MEP_OPT_VL32 | MEP_OPT_VL64);
/* If PC is in a VLIW section, but the current core doesn't say
- that it supports either VLIW mode, then we don't have enough
- information to parse the instruction stream it contains.
- Since the "undifferentiated" standard core doesn't have
- either VLIW mode bit set, this could happen.
+ that it supports either VLIW mode, then we don't have enough
+ information to parse the instruction stream it contains.
+ Since the "undifferentiated" standard core doesn't have
+ either VLIW mode bit set, this could happen.
- But it shouldn't be an error to (say) set a breakpoint in a
- VLIW section, if you know you'll never reach it. (Perhaps
- you have a script that sets a bunch of standard breakpoints.)
+ But it shouldn't be an error to (say) set a breakpoint in a
+ VLIW section, if you know you'll never reach it. (Perhaps
+ you have a script that sets a bunch of standard breakpoints.)
- So we'll just return zero here, and hope for the best. */
+ So we'll just return zero here, and hope for the best. */
if (! (vliw_mode & (MEP_OPT_VL32 | MEP_OPT_VL64)))
- return 0;
+ return 0;
/* If both VL32 and VL64 are set, that's bogus, too. */
if (vliw_mode == (MEP_OPT_VL32 | MEP_OPT_VL64))
- return 0;
+ return 0;
}
else
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
if (vliw_mode)
{
/* In 32-bit VLIW code, all bundles are 32 bits long. We ignore the
- coprocessor half of a core / copro bundle. */
+ coprocessor half of a core / copro bundle. */
if (vliw_mode == MEP_OPT_VL32)
- insn_len = 4;
+ insn_len = 4;
/* In 64-bit VLIW code, all bundles are 64 bits long. We ignore the
- coprocessor half of a core / copro bundle. */
+ coprocessor half of a core / copro bundle. */
else if (vliw_mode == MEP_OPT_VL64)
- insn_len = 8;
+ insn_len = 8;
/* We'd better be in either core, 32-bit VLIW, or 64-bit VLIW mode. */
else
- gdb_assert (0);
+ gdb_assert_not_reached ("unexpected vliw mode");
}
/* Otherwise, the top two bits of the major opcode are (again) what
#define ADD_OFFSET(i) (SFIELD (i, 18, 6))
/* LDC Rn,imm5 0111_nnnn_iiii_101I xxxx_xxxx_xxxx_xxxx
- imm5 = I||i[7:4] */
+ imm5 = I||i[7:4] */
#define IS_LDC(i) (((i) & 0xf00e0000) == 0x700a0000)
#define LDC_IMM(i) ((FIELD (i, 16, 1) << 4) | FIELD (i, 20, 4))
#define LDC_TARGET(i) (FIELD (i, 24, 4))
#define MOV_TARGET(i) (FIELD (i, 24, 4))
#define MOV_SOURCE(i) (FIELD (i, 20, 4))
+/* BRA disp12.align2 1011_dddd_dddd_ddd0 xxxx_xxxx_xxxx_xxxx */
+#define IS_BRA(i) (((i) & 0xf0010000) == 0xb0000000)
+#define BRA_DISP(i) (SFIELD (i, 17, 11) << 1)
+
/* 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.
is_arg_reg (pv_t value)
{
return (value.kind == pvk_register
- && MEP_R1_REGNUM <= value.reg && value.reg <= MEP_R4_REGNUM
- && value.k == 0);
+ && MEP_R1_REGNUM <= value.reg && value.reg <= MEP_R4_REGNUM
+ && value.k == 0);
}
/* Return non-zero if a store of REG's current value VALUE to ADDR is
- 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_is_register (addr, MEP_SP_REGNUM)
+ && ! stack->find_reg (gdbarch, value.reg, 0));
}
/* Function for finding saved registers in a 'struct pv_area'; we pass
- this to pv_area_scan.
+ this to pv_area::scan.
If VALUE is a saved register, ADDR says it was saved at a constant
offset from the frame base, and SIZE indicates that the whole
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,
- struct mep_prologue *result)
+mep_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR start_pc, CORE_ADDR limit_pc,
+ struct mep_prologue *result)
{
CORE_ADDR pc;
unsigned long insn;
- int rn;
- int found_lp = 0;
pv_t reg[MEP_NUM_REGS];
- struct pv_area *stack;
- struct cleanup *back_to;
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++)
+ for (int rn = 0; rn < MEP_NUM_REGS; rn++)
{
reg[rn] = pv_register (rn, 0);
result->reg_offset[rn] = 1;
}
- stack = make_pv_area (MEP_SP_REGNUM);
- back_to = make_cleanup_free_pv_area (stack);
+ pv_area stack (MEP_SP_REGNUM, gdbarch_addr_bit (gdbarch));
pc = start_pc;
while (pc < limit_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
- have enough information to be able to reliably decode it. So
- we'll store here and hope for the best. */
+ able to read the instruction from memory, or that we don't
+ have enough information to be able to reliably decode it. So
+ we'll store here and hope for the best. */
if (! next_pc)
- break;
+ break;
/* Note the current values of the SP and FP, so we can tell if
- this instruction changed them, below. */
+ this instruction changed them, below. */
pre_insn_fp = reg[MEP_FP_REGNUM];
pre_insn_sp = reg[MEP_SP_REGNUM];
if (IS_ADD (insn))
- {
- int rn = ADD_TARGET (insn);
- CORE_ADDR imm6 = ADD_OFFSET (insn);
+ {
+ int rn = ADD_TARGET (insn);
+ CORE_ADDR imm6 = ADD_OFFSET (insn);
- reg[rn] = pv_add_constant (reg[rn], imm6);
- }
+ reg[rn] = pv_add_constant (reg[rn], imm6);
+ }
else if (IS_ADD3_16 (insn))
{
- int rn = ADD3_16_TARGET (insn);
- int imm7 = ADD3_16_OFFSET (insn);
+ int rn = ADD3_16_TARGET (insn);
+ int imm7 = ADD3_16_OFFSET (insn);
- reg[rn] = pv_add_constant (reg[MEP_SP_REGNUM], imm7);
- }
+ reg[rn] = pv_add_constant (reg[MEP_SP_REGNUM], imm7);
+ }
else if (IS_ADD3_32 (insn))
{
- int rn = ADD3_32_TARGET (insn);
- int rm = ADD3_32_SOURCE (insn);
- int imm16 = ADD3_32_OFFSET (insn);
+ int rn = ADD3_32_TARGET (insn);
+ int rm = ADD3_32_SOURCE (insn);
+ int imm16 = ADD3_32_OFFSET (insn);
- reg[rn] = pv_add_constant (reg[rm], imm16);
+ reg[rn] = pv_add_constant (reg[rm], imm16);
}
else if (IS_SW_REG (insn))
- {
- int rn = SW_REG_SOURCE (insn);
- int rm = SW_REG_BASE (insn);
-
- /* If simulating this store would require us to forget
- everything we know about the stack frame in the name of
- accuracy, it would be better to just quit now. */
- if (pv_area_store_would_trash (stack, reg[rm]))
- break;
-
- if (is_arg_spill (reg[rn], reg[rm], stack))
- after_last_frame_setup_insn = next_pc;
-
- pv_area_store (stack, reg[rm], 4, reg[rn]);
- }
+ {
+ int rn = SW_REG_SOURCE (insn);
+ int rm = SW_REG_BASE (insn);
+
+ /* If simulating this store would require us to forget
+ everything we know about the stack frame in the name of
+ accuracy, it would be better to just quit now. */
+ if (stack.store_would_trash (reg[rm]))
+ break;
+
+ if (is_arg_spill (gdbarch, reg[rn], reg[rm], &stack))
+ after_last_frame_setup_insn = next_pc;
+
+ stack.store (reg[rm], 4, reg[rn]);
+ }
else if (IS_SW_IMMD (insn))
- {
- int rn = SW_IMMD_SOURCE (insn);
- int offset = SW_IMMD_OFFSET (insn);
- pv_t addr = pv_add_constant (reg[MEP_SP_REGNUM], offset);
-
- /* If simulating this store would require us to forget
- everything we know about the stack frame in the name of
- accuracy, it would be better to just quit now. */
- if (pv_area_store_would_trash (stack, addr))
- break;
-
- if (is_arg_spill (reg[rn], addr, stack))
- after_last_frame_setup_insn = next_pc;
-
- pv_area_store (stack, addr, 4, reg[rn]);
- }
+ {
+ int rn = SW_IMMD_SOURCE (insn);
+ int offset = SW_IMMD_OFFSET (insn);
+ pv_t addr = pv_add_constant (reg[MEP_SP_REGNUM], offset);
+
+ /* If simulating this store would require us to forget
+ everything we know about the stack frame in the name of
+ accuracy, it would be better to just quit now. */
+ if (stack.store_would_trash (addr))
+ break;
+
+ if (is_arg_spill (gdbarch, reg[rn], addr, &stack))
+ after_last_frame_setup_insn = next_pc;
+
+ stack.store (addr, 4, reg[rn]);
+ }
else if (IS_MOV (insn))
{
- int rn = MOV_TARGET (insn);
- int rm = MOV_SOURCE (insn);
+ int rn = MOV_TARGET (insn);
+ int rm = MOV_SOURCE (insn);
- reg[rn] = reg[rm];
+ reg[rn] = reg[rm];
if (pv_is_register (reg[rm], rm) && is_arg_reg (reg[rm]))
after_last_frame_setup_insn = next_pc;
}
else if (IS_SB (insn) || IS_SH (insn) || IS_SW (insn))
{
- int rn = SWBH_32_SOURCE (insn);
- int rm = SWBH_32_BASE (insn);
- int disp = SWBH_32_OFFSET (insn);
- int size = (IS_SB (insn) ? 1
- : IS_SH (insn) ? 2
- : IS_SW (insn) ? 4
- : (gdb_assert (0), 1));
- pv_t addr = pv_add_constant (reg[rm], disp);
-
- if (pv_area_store_would_trash (stack, addr))
- break;
-
- if (is_arg_spill (reg[rn], addr, stack))
- after_last_frame_setup_insn = next_pc;
-
- pv_area_store (stack, addr, size, reg[rn]);
+ int rn = SWBH_32_SOURCE (insn);
+ int rm = SWBH_32_BASE (insn);
+ int disp = SWBH_32_OFFSET (insn);
+ int size = (IS_SB (insn) ? 1
+ : IS_SH (insn) ? 2
+ : (gdb_assert (IS_SW (insn)), 4));
+ pv_t addr = pv_add_constant (reg[rm], disp);
+
+ if (stack.store_would_trash (addr))
+ break;
+
+ if (is_arg_spill (gdbarch, reg[rn], addr, &stack))
+ after_last_frame_setup_insn = next_pc;
+
+ stack.store (addr, size, reg[rn]);
}
else if (IS_LDC (insn))
{
- int rn = LDC_TARGET (insn);
- int cr = LDC_IMM (insn) + MEP_FIRST_CSR_REGNUM;
+ int rn = LDC_TARGET (insn);
+ int cr = LDC_IMM (insn) + MEP_FIRST_CSR_REGNUM;
- reg[rn] = reg[cr];
+ reg[rn] = reg[cr];
}
else if (IS_LW (insn))
- {
- int rn = LW_TARGET (insn);
- int rm = LW_BASE (insn);
- int offset = LW_OFFSET (insn);
- pv_t addr = pv_add_constant (reg[rm], offset);
-
- reg[rn] = pv_area_fetch (stack, addr, 4);
- }
+ {
+ int rn = LW_TARGET (insn);
+ int rm = LW_BASE (insn);
+ int offset = LW_OFFSET (insn);
+ pv_t addr = pv_add_constant (reg[rm], offset);
+
+ reg[rn] = stack.fetch (addr, 4);
+ }
+ else if (IS_BRA (insn) && BRA_DISP (insn) > 0)
+ {
+ /* 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.
+
+ 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;
+ }
else
- /* We've hit some instruction we don't know how to simulate.
- Strictly speaking, we should set every value we're
- tracking to "unknown". But we'll be optimistic, assume
- that we have enough information already, and stop
- analysis here. */
- break;
+ /* We've hit some instruction we don't know how to simulate.
+ Strictly speaking, we should set every value we're
+ tracking to "unknown". But we'll be optimistic, assume
+ that we have enough information already, and stop
+ analysis here. */
+ break;
/* If this instruction changed the FP or decreased the SP (i.e.,
- allocated more stack space), then this may be a good place to
- declare the prologue finished. However, there are some
- exceptions:
+ allocated more stack space), then this may be a good place to
+ declare the prologue finished. However, there are some
+ exceptions:
- - If the instruction just changed the FP back to its original
- value, then that's probably a restore instruction. The
- prologue should definitely end before that.
+ - If the instruction just changed the FP back to its original
+ value, then that's probably a restore instruction. The
+ prologue should definitely end before that.
- - If the instruction increased the value of the SP (that is,
- shrunk the frame), then it's probably part of a frame
- teardown sequence, and the prologue should end before that. */
+ - If the instruction increased the value of the SP (that is,
+ shrunk the frame), then it's probably part of a frame
+ teardown sequence, and the prologue should end before that. */
if (! pv_is_identical (reg[MEP_FP_REGNUM], pre_insn_fp))
- {
- if (! pv_is_register_k (reg[MEP_FP_REGNUM], MEP_FP_REGNUM, 0))
- after_last_frame_setup_insn = next_pc;
- }
+ {
+ if (! pv_is_register_k (reg[MEP_FP_REGNUM], MEP_FP_REGNUM, 0))
+ after_last_frame_setup_insn = next_pc;
+ }
else if (! pv_is_identical (reg[MEP_SP_REGNUM], pre_insn_sp))
- {
- /* The comparison of constants looks odd, there, because .k
- is unsigned. All it really means is that the new value
- is lower than it was before the instruction. */
- if (pv_is_register (pre_insn_sp, MEP_SP_REGNUM)
- && pv_is_register (reg[MEP_SP_REGNUM], MEP_SP_REGNUM)
- && ((pre_insn_sp.k - reg[MEP_SP_REGNUM].k)
- < (reg[MEP_SP_REGNUM].k - pre_insn_sp.k)))
- after_last_frame_setup_insn = next_pc;
- }
+ {
+ /* The comparison of constants looks odd, there, because .k
+ is unsigned. All it really means is that the new value
+ is lower than it was before the instruction. */
+ if (pv_is_register (pre_insn_sp, MEP_SP_REGNUM)
+ && pv_is_register (reg[MEP_SP_REGNUM], MEP_SP_REGNUM)
+ && ((pre_insn_sp.k - reg[MEP_SP_REGNUM].k)
+ < (reg[MEP_SP_REGNUM].k - pre_insn_sp.k)))
+ after_last_frame_setup_insn = next_pc;
+ }
pc = next_pc;
}
}
/* Record where all the registers were saved. */
- pv_area_scan (stack, check_for_saved, (void *) result);
+ stack.scan (check_for_saved, (void *) result);
result->prologue_end = after_last_frame_setup_insn;
-
- do_cleanups (back_to);
}
static CORE_ADDR
-mep_skip_prologue (CORE_ADDR pc)
+mep_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
- char *name;
+ const char *name;
CORE_ADDR func_addr, func_end;
struct mep_prologue p;
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;
}
\f
/* Breakpoints. */
+constexpr gdb_byte mep_break_insn[] = { 0x70, 0x32 };
-static const unsigned char *
-mep_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
-{
- static unsigned char breakpoint[] = { 0x70, 0x32 };
- *lenptr = sizeof (breakpoint);
- return breakpoint;
-}
-
+typedef BP_MANIPULATION (mep_break_insn) mep_breakpoint;
\f
/* Frames and frame unwinding. */
static struct mep_prologue *
-mep_analyze_frame_prologue (struct frame_info *next_frame,
- void **this_prologue_cache)
+mep_analyze_frame_prologue (struct frame_info *this_frame,
+ void **this_prologue_cache)
{
if (! *this_prologue_cache)
{
CORE_ADDR func_start, stop_addr;
*this_prologue_cache
- = FRAME_OBSTACK_ZALLOC (struct mep_prologue);
+ = 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. */
+ just initialize the prologue cache, but don't do anything. */
if (! func_start)
- stop_addr = 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,
+ (struct mep_prologue *) *this_prologue_cache);
}
- return *this_prologue_cache;
+ return (struct mep_prologue *) *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,
- void **this_prologue_cache)
+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,
- void **this_prologue_cache,
- struct frame_id *this_id)
+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);
+
+ 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);
- }
+ return a description of the stack slot holding it. */
+ 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. */
+ 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];
-
- /* Get the LP's value, too. */
- frame_register_unwind (next_frame, MEP_LP_REGNUM,
- &lp_optimized, &lp_lval, &lp_addr,
- &lp_realnum, lp_buffer);
-
- /* 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;
- }
- }
-}
-
+ {
+ CORE_ADDR psw, lp;
-static const struct frame_unwind mep_frame_unwind = {
- NORMAL_FRAME,
- mep_frame_this_id,
- mep_frame_prev_register
-};
+ psw = value_as_long (value);
+ release_value (value);
+ /* Get the LP's value, too. */
+ value = get_frame_register_value (this_frame, MEP_LP_REGNUM);
+ lp = value_as_long (value);
+ release_value (value);
-static const struct frame_unwind *
-mep_frame_sniffer (struct frame_info *next_frame)
-{
- return &mep_frame_unwind;
-}
+ /* If LP.LTOM is set, then toggle PSW.OM. */
+ if (lp & 0x1)
+ psw ^= 0x1000;
+ return frame_unwind_got_constant (this_frame, regnum, psw);
+ }
-/* Our general unwinding function can handle unwinding the PC. */
-static CORE_ADDR
-mep_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_unwind_register_unsigned (next_frame, MEP_PC_REGNUM);
+ return value;
+ }
}
-/* Our general unwinding function can handle unwinding the SP. */
-static CORE_ADDR
-mep_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_unwind_register_unsigned (next_frame, MEP_SP_REGNUM);
-}
-
+static const struct frame_unwind mep_frame_unwind = {
+ "mep prologue",
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ mep_frame_this_id,
+ mep_frame_prev_register,
+ NULL,
+ default_frame_sniffer
+};
\f
/* Return values. */
static void
mep_extract_return_value (struct gdbarch *arch,
- struct type *type,
- struct regcache *regcache,
- gdb_byte *valbuf)
+ struct type *type,
+ struct regcache *regcache,
+ gdb_byte *valbuf)
{
int byte_order = gdbarch_byte_order (arch);
else
offset = 0;
- /* Return values that do fit in a single register are returned in R0. */
- regcache_cooked_read_part (regcache, MEP_R0_REGNUM,
- offset, TYPE_LENGTH (type),
- valbuf);
+ /* Return values that do fit in a single register are returned in R0. */
+ regcache->cooked_read_part (MEP_R0_REGNUM, offset, TYPE_LENGTH (type),
+ valbuf);
}
static void
mep_store_return_value (struct gdbarch *arch,
- struct type *type,
- struct regcache *regcache,
- const gdb_byte *valbuf)
+ struct type *type,
+ struct regcache *regcache,
+ const gdb_byte *valbuf)
{
int byte_order = gdbarch_byte_order (arch);
if (TYPE_LENGTH (type) <= MEP_GPR_SIZE)
{
/* Values that don't occupy a full register appear at the least
- significant end of the value. This is the offset to where the
- value starts. */
+ significant end of the value. This is the offset to where the
+ value starts. */
int offset;
if (byte_order == BFD_ENDIAN_BIG)
- offset = MEP_GPR_SIZE - TYPE_LENGTH (type);
+ offset = MEP_GPR_SIZE - TYPE_LENGTH (type);
else
- offset = 0;
+ offset = 0;
- regcache_cooked_write_part (regcache, MEP_R0_REGNUM,
- offset, TYPE_LENGTH (type),
- valbuf);
+ regcache->cooked_write_part (MEP_R0_REGNUM, offset, TYPE_LENGTH (type),
+ valbuf);
}
/* Return values larger than a single register are returned in
memory, pointed to by R0. Unfortunately, we can't count on R0
- pointing to the return buffer, so we raise an error here. */
+ pointing to the return buffer, so we raise an error here. */
else
- error ("GDB cannot set return values larger than four bytes; "
- "the Media Processor's\n"
- "calling conventions do not provide enough information "
- "to do this.\n"
- "Try using the 'return' command with no argument.");
+ error (_("\
+GDB cannot set return values larger than four bytes; the Media Processor's\n\
+calling conventions do not provide enough information to do this.\n\
+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 value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
if (mep_use_struct_convention (type))
{
{
/* Return values larger than a single register are returned in
memory, pointed to by R0. Unfortunately, we can't count on R0
- pointing to the return buffer, so we raise an error here. */
- error ("GDB cannot set return values larger than four bytes; "
- "the Media Processor's\n"
- "calling conventions do not provide enough information "
- "to do this.\n"
- "Try using the 'return' command with no argument.");
+ pointing to the return buffer, so we raise an error here. */
+ error (_("\
+GDB cannot set return values larger than four bytes; the Media Processor's\n\
+calling conventions do not provide enough information to do this.\n\
+Try using the 'return' command with no argument."));
}
return RETURN_VALUE_ABI_RETURNS_ADDRESS;
}
4.2.1 Core register conventions
- Parameters should be evaluated from left to right, and they
- should be held in $1,$2,$3,$4 in order. The fifth parameter or
- after should be held in the stack. If the size is larger than 4
+ should be held in $1,$2,$3,$4 in order. The fifth parameter or
+ after should be held in the stack. If the size is larger than 4
bytes in the first four parameters, the pointer should be held in
- the registers instead. If the size is larger than 4 bytes in the
+ the registers instead. If the size is larger than 4 bytes in the
fifth parameter or after, the pointer should be held in the stack.
- - Return value of a function should be held in register $0. If the
+ - Return value of a function should be held in register $0. If the
size of return value is larger than 4 bytes, $1 should hold the
- pointer pointing memory that would hold the return value. In this
+ pointer pointing memory that would hold the return value. In this
case, the first parameter should be held in $2, the second one in
$3, and the third one in $4, and the forth parameter or after
should be held in the stack.
new stack pointer. */
static CORE_ADDR
push_large_arguments (CORE_ADDR sp, int argc, struct value **argv,
- CORE_ADDR copy[])
+ CORE_ADDR copy[])
{
int i;
unsigned arg_len = TYPE_LENGTH (value_type (argv[i]));
if (arg_len > MEP_GPR_SIZE)
- {
- /* Reserve space for the copy, and then round the SP down, to
- make sure it's all aligned properly. */
- sp = (sp - arg_len) & -4;
- write_memory (sp, value_contents (argv[i]), arg_len);
- copy[i] = sp;
- }
+ {
+ /* Reserve space for the copy, and then round the SP down, to
+ make sure it's all aligned properly. */
+ sp = (sp - arg_len) & -4;
+ write_memory (sp, value_contents (argv[i]), arg_len);
+ copy[i] = sp;
+ }
}
return sp;
static CORE_ADDR
mep_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr,
- int argc, struct value **argv, CORE_ADDR sp,
- int struct_return,
- CORE_ADDR struct_addr)
+ struct regcache *regcache, CORE_ADDR bp_addr,
+ int argc, struct value **argv, CORE_ADDR sp,
+ function_call_return_method return_method,
+ 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;
/* The number of the next register available to hold an argument. */
/* If we're returning a structure by value, push the pointer to the
buffer as the first argument. */
- if (struct_return)
+ if (return_method == return_method_struct)
{
regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
arg_reg++;
for (i = 0; i < argc; i++)
{
- unsigned arg_size = TYPE_LENGTH (value_type (argv[i]));
ULONGEST value;
/* 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])));
+ if (TYPE_LENGTH (value_type (argv[i])) <= MEP_GPR_SIZE)
+ value = extract_unsigned_integer (value_contents (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. */
+ and we pass a pointer to the copy. */
else
- value = copy[i];
+ value = copy[i];
/* We use $1 -- $4 for passing arguments, then use the stack. */
if (arg_reg <= MEP_R4_REGNUM)
- {
- regcache_cooked_write_unsigned (regcache, arg_reg, value);
- arg_reg++;
- }
+ {
+ regcache_cooked_write_unsigned (regcache, arg_reg, value);
+ arg_reg++;
+ }
else
- {
- char buf[MEP_GPR_SIZE];
- store_unsigned_integer (buf, MEP_GPR_SIZE, value);
- write_memory (arg_stack, buf, MEP_GPR_SIZE);
- arg_stack += MEP_GPR_SIZE;
- }
+ {
+ gdb_byte buf[MEP_GPR_SIZE];
+ store_unsigned_integer (buf, MEP_GPR_SIZE, byte_order, value);
+ write_memory (arg_stack, buf, MEP_GPR_SIZE);
+ arg_stack += MEP_GPR_SIZE;
+ }
}
gdb_assert (arg_stack <= arg_stack_end);
return sp;
}
-
-static struct frame_id
-mep_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_id_build (mep_unwind_sp (gdbarch, next_frame),
- frame_pc_unwind (next_frame));
-}
-
-
\f
/* Initialization. */
if (info.abfd)
{
/* The way to get the me_module code depends on the object file
- format. At the moment, we only know how to handle ELF. */
+ format. At the moment, we only know how to handle ELF. */
if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
- me_module = elf_elfheader (info.abfd)->e_flags & EF_MEP_INDEX_MASK;
+ {
+ int flag = elf_elfheader (info.abfd)->e_flags & EF_MEP_INDEX_MASK;
+ me_module = (CONFIG_ATTR) flag;
+ }
else
- me_module = CONFIG_NONE;
+ me_module = CONFIG_NONE;
}
else
me_module = CONFIG_NONE;
if (info.abfd)
{
/* The negations on either side make the comparison treat all
- non-zero (true) values as equal. */
+ non-zero (true) values as equal. */
if (! bfd_big_endian (info.abfd) != ! me_module_big_endian (me_module))
- {
- const char *module_name = me_module_name (me_module);
- const char *module_endianness
- = me_module_big_endian (me_module) ? "big" : "little";
- const char *file_name = bfd_get_filename (info.abfd);
- const char *file_endianness
- = bfd_big_endian (info.abfd) ? "big" : "little";
-
- fputc_unfiltered ('\n', gdb_stderr);
- if (module_name)
- warning ("the MeP module '%s' is %s-endian, but the executable\n"
- "%s is %s-endian.",
- module_name, module_endianness,
- file_name, file_endianness);
- else
- warning ("the selected MeP module is %s-endian, but the "
- "executable\n"
- "%s is %s-endian.",
- module_endianness, file_name, file_endianness);
- }
+ {
+ const char *module_name = me_module_name (me_module);
+ const char *module_endianness
+ = me_module_big_endian (me_module) ? "big" : "little";
+ const char *file_name = bfd_get_filename (info.abfd);
+ const char *file_endianness
+ = bfd_big_endian (info.abfd) ? "big" : "little";
+
+ fputc_unfiltered ('\n', gdb_stderr);
+ if (module_name)
+ warning (_("the MeP module '%s' is %s-endian, but the executable\n"
+ "%s is %s-endian."),
+ module_name, module_endianness,
+ file_name, file_endianness);
+ else
+ warning (_("the selected MeP module is %s-endian, but the "
+ "executable\n"
+ "%s is %s-endian."),
+ module_endianness, file_name, file_endianness);
+ }
}
/* Find a candidate among the list of architectures we've created
if (gdbarch_tdep (arches->gdbarch)->me_module == me_module)
return arches->gdbarch;
- tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+ tdep = XCNEW (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
/* Get a CGEN CPU descriptor for this architecture. */
{
const char *mach_name = info.bfd_arch_info->printable_name;
enum cgen_endian endian = (info.byte_order == BFD_ENDIAN_BIG
- ? CGEN_ENDIAN_BIG
- : CGEN_ENDIAN_LITTLE);
+ ? CGEN_ENDIAN_BIG
+ : CGEN_ENDIAN_LITTLE);
tdep->cpu_desc = mep_cgen_cpu_open (CGEN_CPU_OPEN_BFDMACH, mach_name,
- CGEN_CPU_OPEN_ENDIAN, endian,
- CGEN_CPU_OPEN_END);
+ CGEN_CPU_OPEN_ENDIAN, endian,
+ CGEN_CPU_OPEN_END);
}
tdep->me_module = me_module;
/* Register set. */
- set_gdbarch_read_pc (gdbarch, mep_read_pc);
- set_gdbarch_write_pc (gdbarch, mep_write_pc);
set_gdbarch_num_regs (gdbarch, MEP_NUM_RAW_REGS);
+ set_gdbarch_pc_regnum (gdbarch, MEP_PC_REGNUM);
set_gdbarch_sp_regnum (gdbarch, MEP_SP_REGNUM);
set_gdbarch_register_name (gdbarch, mep_register_name);
set_gdbarch_register_type (gdbarch, mep_register_type);
set_gdbarch_print_insn (gdbarch, mep_gdb_print_insn);
/* Breakpoints. */
- set_gdbarch_breakpoint_from_pc (gdbarch, mep_breakpoint_from_pc);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, mep_breakpoint::kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch, mep_breakpoint::bp_from_kind);
set_gdbarch_decr_pc_after_break (gdbarch, 0);
set_gdbarch_skip_prologue (gdbarch, mep_skip_prologue);
/* Frames and frame unwinding. */
- frame_unwind_append_sniffer (gdbarch, mep_frame_sniffer);
- set_gdbarch_unwind_pc (gdbarch, mep_unwind_pc);
- set_gdbarch_unwind_sp (gdbarch, mep_unwind_sp);
+ frame_unwind_append_unwinder (gdbarch, &mep_frame_unwind);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_frame_args_skip (gdbarch, 0);
/* 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);
return gdbarch;
}
-
+void _initialize_mep_tdep ();
void
-_initialize_mep_tdep (void)
+_initialize_mep_tdep ()
{
mep_csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
mep_cr_reggroup = reggroup_new ("cr", USER_REGGROUP);