OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-6.8/] [gdb/] [arm-tdep.c] - Diff between revs 157 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 157 Rev 816
/* Common target dependent code for GDB on ARM systems.
/* Common target dependent code for GDB on ARM systems.
 
 
   Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
   Copyright (C) 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1998, 1999, 2000,
   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   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
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include <ctype.h>              /* XXX for isupper () */
#include <ctype.h>              /* XXX for isupper () */
 
 
#include "defs.h"
#include "defs.h"
#include "frame.h"
#include "frame.h"
#include "inferior.h"
#include "inferior.h"
#include "gdbcmd.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "gdbcore.h"
#include "gdb_string.h"
#include "gdb_string.h"
#include "dis-asm.h"            /* For register styles. */
#include "dis-asm.h"            /* For register styles. */
#include "regcache.h"
#include "regcache.h"
#include "doublest.h"
#include "doublest.h"
#include "value.h"
#include "value.h"
#include "arch-utils.h"
#include "arch-utils.h"
#include "osabi.h"
#include "osabi.h"
#include "frame-unwind.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "frame-base.h"
#include "trad-frame.h"
#include "trad-frame.h"
#include "objfiles.h"
#include "objfiles.h"
#include "dwarf2-frame.h"
#include "dwarf2-frame.h"
#include "gdbtypes.h"
#include "gdbtypes.h"
#include "prologue-value.h"
#include "prologue-value.h"
#include "target-descriptions.h"
#include "target-descriptions.h"
#include "user-regs.h"
#include "user-regs.h"
 
 
#include "arm-tdep.h"
#include "arm-tdep.h"
#include "gdb/sim-arm.h"
#include "gdb/sim-arm.h"
 
 
#include "elf-bfd.h"
#include "elf-bfd.h"
#include "coff/internal.h"
#include "coff/internal.h"
#include "elf/arm.h"
#include "elf/arm.h"
 
 
#include "gdb_assert.h"
#include "gdb_assert.h"
 
 
static int arm_debug;
static int arm_debug;
 
 
/* Macros for setting and testing a bit in a minimal symbol that marks
/* Macros for setting and testing a bit in a minimal symbol that marks
   it as Thumb function.  The MSB of the minimal symbol's "info" field
   it as Thumb function.  The MSB of the minimal symbol's "info" field
   is used for this purpose.
   is used for this purpose.
 
 
   MSYMBOL_SET_SPECIAL  Actually sets the "special" bit.
   MSYMBOL_SET_SPECIAL  Actually sets the "special" bit.
   MSYMBOL_IS_SPECIAL   Tests the "special" bit in a minimal symbol.  */
   MSYMBOL_IS_SPECIAL   Tests the "special" bit in a minimal symbol.  */
 
 
#define MSYMBOL_SET_SPECIAL(msym)                                       \
#define MSYMBOL_SET_SPECIAL(msym)                                       \
        MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym))    \
        MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym))    \
                                        | 0x80000000)
                                        | 0x80000000)
 
 
#define MSYMBOL_IS_SPECIAL(msym)                                \
#define MSYMBOL_IS_SPECIAL(msym)                                \
        (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
        (((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
 
 
/* The list of available "set arm ..." and "show arm ..." commands.  */
/* The list of available "set arm ..." and "show arm ..." commands.  */
static struct cmd_list_element *setarmcmdlist = NULL;
static struct cmd_list_element *setarmcmdlist = NULL;
static struct cmd_list_element *showarmcmdlist = NULL;
static struct cmd_list_element *showarmcmdlist = NULL;
 
 
/* The type of floating-point to use.  Keep this in sync with enum
/* The type of floating-point to use.  Keep this in sync with enum
   arm_float_model, and the help string in _initialize_arm_tdep.  */
   arm_float_model, and the help string in _initialize_arm_tdep.  */
static const char *fp_model_strings[] =
static const char *fp_model_strings[] =
{
{
  "auto",
  "auto",
  "softfpa",
  "softfpa",
  "fpa",
  "fpa",
  "softvfp",
  "softvfp",
  "vfp",
  "vfp",
  NULL
  NULL
};
};
 
 
/* A variable that can be configured by the user.  */
/* A variable that can be configured by the user.  */
static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
static enum arm_float_model arm_fp_model = ARM_FLOAT_AUTO;
static const char *current_fp_model = "auto";
static const char *current_fp_model = "auto";
 
 
/* The ABI to use.  Keep this in sync with arm_abi_kind.  */
/* The ABI to use.  Keep this in sync with arm_abi_kind.  */
static const char *arm_abi_strings[] =
static const char *arm_abi_strings[] =
{
{
  "auto",
  "auto",
  "APCS",
  "APCS",
  "AAPCS",
  "AAPCS",
  NULL
  NULL
};
};
 
 
/* A variable that can be configured by the user.  */
/* A variable that can be configured by the user.  */
static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
static enum arm_abi_kind arm_abi_global = ARM_ABI_AUTO;
static const char *arm_abi_string = "auto";
static const char *arm_abi_string = "auto";
 
 
/* Number of different reg name sets (options).  */
/* Number of different reg name sets (options).  */
static int num_disassembly_options;
static int num_disassembly_options;
 
 
/* The standard register names, and all the valid aliases for them.  */
/* The standard register names, and all the valid aliases for them.  */
static const struct
static const struct
{
{
  const char *name;
  const char *name;
  int regnum;
  int regnum;
} arm_register_aliases[] = {
} arm_register_aliases[] = {
  /* Basic register numbers.  */
  /* Basic register numbers.  */
  { "r0", 0 },
  { "r0", 0 },
  { "r1", 1 },
  { "r1", 1 },
  { "r2", 2 },
  { "r2", 2 },
  { "r3", 3 },
  { "r3", 3 },
  { "r4", 4 },
  { "r4", 4 },
  { "r5", 5 },
  { "r5", 5 },
  { "r6", 6 },
  { "r6", 6 },
  { "r7", 7 },
  { "r7", 7 },
  { "r8", 8 },
  { "r8", 8 },
  { "r9", 9 },
  { "r9", 9 },
  { "r10", 10 },
  { "r10", 10 },
  { "r11", 11 },
  { "r11", 11 },
  { "r12", 12 },
  { "r12", 12 },
  { "r13", 13 },
  { "r13", 13 },
  { "r14", 14 },
  { "r14", 14 },
  { "r15", 15 },
  { "r15", 15 },
  /* Synonyms (argument and variable registers).  */
  /* Synonyms (argument and variable registers).  */
  { "a1", 0 },
  { "a1", 0 },
  { "a2", 1 },
  { "a2", 1 },
  { "a3", 2 },
  { "a3", 2 },
  { "a4", 3 },
  { "a4", 3 },
  { "v1", 4 },
  { "v1", 4 },
  { "v2", 5 },
  { "v2", 5 },
  { "v3", 6 },
  { "v3", 6 },
  { "v4", 7 },
  { "v4", 7 },
  { "v5", 8 },
  { "v5", 8 },
  { "v6", 9 },
  { "v6", 9 },
  { "v7", 10 },
  { "v7", 10 },
  { "v8", 11 },
  { "v8", 11 },
  /* Other platform-specific names for r9.  */
  /* Other platform-specific names for r9.  */
  { "sb", 9 },
  { "sb", 9 },
  { "tr", 9 },
  { "tr", 9 },
  /* Special names.  */
  /* Special names.  */
  { "ip", 12 },
  { "ip", 12 },
  { "sp", 13 },
  { "sp", 13 },
  { "lr", 14 },
  { "lr", 14 },
  { "pc", 15 },
  { "pc", 15 },
  /* Names used by GCC (not listed in the ARM EABI).  */
  /* Names used by GCC (not listed in the ARM EABI).  */
  { "sl", 10 },
  { "sl", 10 },
  { "fp", 11 },
  { "fp", 11 },
  /* A special name from the older ATPCS.  */
  /* A special name from the older ATPCS.  */
  { "wr", 7 },
  { "wr", 7 },
};
};
 
 
static const char *const arm_register_names[] =
static const char *const arm_register_names[] =
{"r0",  "r1",  "r2",  "r3",     /*  0  1  2  3 */
{"r0",  "r1",  "r2",  "r3",     /*  0  1  2  3 */
 "r4",  "r5",  "r6",  "r7",     /*  4  5  6  7 */
 "r4",  "r5",  "r6",  "r7",     /*  4  5  6  7 */
 "r8",  "r9",  "r10", "r11",    /*  8  9 10 11 */
 "r8",  "r9",  "r10", "r11",    /*  8  9 10 11 */
 "r12", "sp",  "lr",  "pc",     /* 12 13 14 15 */
 "r12", "sp",  "lr",  "pc",     /* 12 13 14 15 */
 "f0",  "f1",  "f2",  "f3",     /* 16 17 18 19 */
 "f0",  "f1",  "f2",  "f3",     /* 16 17 18 19 */
 "f4",  "f5",  "f6",  "f7",     /* 20 21 22 23 */
 "f4",  "f5",  "f6",  "f7",     /* 20 21 22 23 */
 "fps", "cpsr" };               /* 24 25       */
 "fps", "cpsr" };               /* 24 25       */
 
 
/* Valid register name styles.  */
/* Valid register name styles.  */
static const char **valid_disassembly_styles;
static const char **valid_disassembly_styles;
 
 
/* Disassembly style to use. Default to "std" register names.  */
/* Disassembly style to use. Default to "std" register names.  */
static const char *disassembly_style;
static const char *disassembly_style;
 
 
/* This is used to keep the bfd arch_info in sync with the disassembly
/* This is used to keep the bfd arch_info in sync with the disassembly
   style.  */
   style.  */
static void set_disassembly_style_sfunc(char *, int,
static void set_disassembly_style_sfunc(char *, int,
                                         struct cmd_list_element *);
                                         struct cmd_list_element *);
static void set_disassembly_style (void);
static void set_disassembly_style (void);
 
 
static void convert_from_extended (const struct floatformat *, const void *,
static void convert_from_extended (const struct floatformat *, const void *,
                                   void *, int);
                                   void *, int);
static void convert_to_extended (const struct floatformat *, void *,
static void convert_to_extended (const struct floatformat *, void *,
                                 const void *, int);
                                 const void *, int);
 
 
struct arm_prologue_cache
struct arm_prologue_cache
{
{
  /* The stack pointer at the time this frame was created; i.e. the
  /* The stack pointer at the time this frame was created; i.e. the
     caller's stack pointer when this function was called.  It is used
     caller's stack pointer when this function was called.  It is used
     to identify this frame.  */
     to identify this frame.  */
  CORE_ADDR prev_sp;
  CORE_ADDR prev_sp;
 
 
  /* The frame base for this frame is just prev_sp - frame size.
  /* The frame base for this frame is just prev_sp - frame size.
     FRAMESIZE is the distance from the frame pointer to the
     FRAMESIZE is the distance from the frame pointer to the
     initial stack pointer.  */
     initial stack pointer.  */
 
 
  int framesize;
  int framesize;
 
 
  /* The register used to hold the frame pointer for this frame.  */
  /* The register used to hold the frame pointer for this frame.  */
  int framereg;
  int framereg;
 
 
  /* Saved register offsets.  */
  /* Saved register offsets.  */
  struct trad_frame_saved_reg *saved_regs;
  struct trad_frame_saved_reg *saved_regs;
};
};
 
 
/* Addresses for calling Thumb functions have the bit 0 set.
/* Addresses for calling Thumb functions have the bit 0 set.
   Here are some macros to test, set, or clear bit 0 of addresses.  */
   Here are some macros to test, set, or clear bit 0 of addresses.  */
#define IS_THUMB_ADDR(addr)     ((addr) & 1)
#define IS_THUMB_ADDR(addr)     ((addr) & 1)
#define MAKE_THUMB_ADDR(addr)   ((addr) | 1)
#define MAKE_THUMB_ADDR(addr)   ((addr) | 1)
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)
 
 
/* Set to true if the 32-bit mode is in use.  */
/* Set to true if the 32-bit mode is in use.  */
 
 
int arm_apcs_32 = 1;
int arm_apcs_32 = 1;
 
 
/* Determine if the program counter specified in MEMADDR is in a Thumb
/* Determine if the program counter specified in MEMADDR is in a Thumb
   function.  */
   function.  */
 
 
static int
static int
arm_pc_is_thumb (CORE_ADDR memaddr)
arm_pc_is_thumb (CORE_ADDR memaddr)
{
{
  struct minimal_symbol *sym;
  struct minimal_symbol *sym;
 
 
  /* If bit 0 of the address is set, assume this is a Thumb address.  */
  /* If bit 0 of the address is set, assume this is a Thumb address.  */
  if (IS_THUMB_ADDR (memaddr))
  if (IS_THUMB_ADDR (memaddr))
    return 1;
    return 1;
 
 
  /* Thumb functions have a "special" bit set in minimal symbols.  */
  /* Thumb functions have a "special" bit set in minimal symbols.  */
  sym = lookup_minimal_symbol_by_pc (memaddr);
  sym = lookup_minimal_symbol_by_pc (memaddr);
  if (sym)
  if (sym)
    {
    {
      return (MSYMBOL_IS_SPECIAL (sym));
      return (MSYMBOL_IS_SPECIAL (sym));
    }
    }
  else
  else
    {
    {
      return 0;
      return 0;
    }
    }
}
}
 
 
/* Remove useless bits from addresses in a running program.  */
/* Remove useless bits from addresses in a running program.  */
static CORE_ADDR
static CORE_ADDR
arm_addr_bits_remove (CORE_ADDR val)
arm_addr_bits_remove (CORE_ADDR val)
{
{
  if (arm_apcs_32)
  if (arm_apcs_32)
    return UNMAKE_THUMB_ADDR (val);
    return UNMAKE_THUMB_ADDR (val);
  else
  else
    return (val & 0x03fffffc);
    return (val & 0x03fffffc);
}
}
 
 
/* When reading symbols, we need to zap the low bit of the address,
/* When reading symbols, we need to zap the low bit of the address,
   which may be set to 1 for Thumb functions.  */
   which may be set to 1 for Thumb functions.  */
static CORE_ADDR
static CORE_ADDR
arm_smash_text_address (CORE_ADDR val)
arm_smash_text_address (CORE_ADDR val)
{
{
  return val & ~1;
  return val & ~1;
}
}
 
 
/* Analyze a Thumb prologue, looking for a recognizable stack frame
/* Analyze a Thumb prologue, looking for a recognizable stack frame
   and frame pointer.  Scan until we encounter a store that could
   and frame pointer.  Scan until we encounter a store that could
   clobber the stack frame unexpectedly, or an unknown instruction.  */
   clobber the stack frame unexpectedly, or an unknown instruction.  */
 
 
static CORE_ADDR
static CORE_ADDR
thumb_analyze_prologue (struct gdbarch *gdbarch,
thumb_analyze_prologue (struct gdbarch *gdbarch,
                        CORE_ADDR start, CORE_ADDR limit,
                        CORE_ADDR start, CORE_ADDR limit,
                        struct arm_prologue_cache *cache)
                        struct arm_prologue_cache *cache)
{
{
  int i;
  int i;
  pv_t regs[16];
  pv_t regs[16];
  struct pv_area *stack;
  struct pv_area *stack;
  struct cleanup *back_to;
  struct cleanup *back_to;
  CORE_ADDR offset;
  CORE_ADDR offset;
 
 
  for (i = 0; i < 16; i++)
  for (i = 0; i < 16; i++)
    regs[i] = pv_register (i, 0);
    regs[i] = pv_register (i, 0);
  stack = make_pv_area (ARM_SP_REGNUM);
  stack = make_pv_area (ARM_SP_REGNUM);
  back_to = make_cleanup_free_pv_area (stack);
  back_to = make_cleanup_free_pv_area (stack);
 
 
  /* The call instruction saved PC in LR, and the current PC is not
  /* The call instruction saved PC in LR, and the current PC is not
     interesting.  Due to this file's conventions, we want the value
     interesting.  Due to this file's conventions, we want the value
     of LR at this function's entry, not at the call site, so we do
     of LR at this function's entry, not at the call site, so we do
     not record the save of the PC - when the ARM prologue analyzer
     not record the save of the PC - when the ARM prologue analyzer
     has also been converted to the pv mechanism, we could record the
     has also been converted to the pv mechanism, we could record the
     save here and remove the hack in prev_register.  */
     save here and remove the hack in prev_register.  */
  regs[ARM_PC_REGNUM] = pv_unknown ();
  regs[ARM_PC_REGNUM] = pv_unknown ();
 
 
  while (start < limit)
  while (start < limit)
    {
    {
      unsigned short insn;
      unsigned short insn;
 
 
      insn = read_memory_unsigned_integer (start, 2);
      insn = read_memory_unsigned_integer (start, 2);
 
 
      if ((insn & 0xfe00) == 0xb400)            /* push { rlist } */
      if ((insn & 0xfe00) == 0xb400)            /* push { rlist } */
        {
        {
          int regno;
          int regno;
          int mask;
          int mask;
 
 
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
            break;
            break;
 
 
          /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
          /* Bits 0-7 contain a mask for registers R0-R7.  Bit 8 says
             whether to save LR (R14).  */
             whether to save LR (R14).  */
          mask = (insn & 0xff) | ((insn & 0x100) << 6);
          mask = (insn & 0xff) | ((insn & 0x100) << 6);
 
 
          /* Calculate offsets of saved R0-R7 and LR.  */
          /* Calculate offsets of saved R0-R7 and LR.  */
          for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
          for (regno = ARM_LR_REGNUM; regno >= 0; regno--)
            if (mask & (1 << regno))
            if (mask & (1 << regno))
              {
              {
                regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                                                       -4);
                                                       -4);
                pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
                pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
              }
              }
        }
        }
      else if ((insn & 0xff00) == 0xb000)       /* add sp, #simm  OR
      else if ((insn & 0xff00) == 0xb000)       /* add sp, #simm  OR
                                                   sub sp, #simm */
                                                   sub sp, #simm */
        {
        {
          offset = (insn & 0x7f) << 2;          /* get scaled offset */
          offset = (insn & 0x7f) << 2;          /* get scaled offset */
          if (insn & 0x80)                      /* Check for SUB.  */
          if (insn & 0x80)                      /* Check for SUB.  */
            regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
            regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                                                   -offset);
                                                   -offset);
          else
          else
            regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
            regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                                                   offset);
                                                   offset);
        }
        }
      else if ((insn & 0xff00) == 0xaf00)       /* add r7, sp, #imm */
      else if ((insn & 0xff00) == 0xaf00)       /* add r7, sp, #imm */
        regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
        regs[THUMB_FP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM],
                                                 (insn & 0xff) << 2);
                                                 (insn & 0xff) << 2);
      else if ((insn & 0xff00) == 0x4600)       /* mov hi, lo or mov lo, hi */
      else if ((insn & 0xff00) == 0x4600)       /* mov hi, lo or mov lo, hi */
        {
        {
          int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
          int dst_reg = (insn & 0x7) + ((insn & 0x80) >> 4);
          int src_reg = (insn & 0x78) >> 3;
          int src_reg = (insn & 0x78) >> 3;
          regs[dst_reg] = regs[src_reg];
          regs[dst_reg] = regs[src_reg];
        }
        }
      else if ((insn & 0xf800) == 0x9000)       /* str rd, [sp, #off] */
      else if ((insn & 0xf800) == 0x9000)       /* str rd, [sp, #off] */
        {
        {
          /* Handle stores to the stack.  Normally pushes are used,
          /* Handle stores to the stack.  Normally pushes are used,
             but with GCC -mtpcs-frame, there may be other stores
             but with GCC -mtpcs-frame, there may be other stores
             in the prologue to create the frame.  */
             in the prologue to create the frame.  */
          int regno = (insn >> 8) & 0x7;
          int regno = (insn >> 8) & 0x7;
          pv_t addr;
          pv_t addr;
 
 
          offset = (insn & 0xff) << 2;
          offset = (insn & 0xff) << 2;
          addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
          addr = pv_add_constant (regs[ARM_SP_REGNUM], offset);
 
 
          if (pv_area_store_would_trash (stack, addr))
          if (pv_area_store_would_trash (stack, addr))
            break;
            break;
 
 
          pv_area_store (stack, addr, 4, regs[regno]);
          pv_area_store (stack, addr, 4, regs[regno]);
        }
        }
      else
      else
        {
        {
          /* We don't know what this instruction is.  We're finished
          /* We don't know what this instruction is.  We're finished
             scanning.  NOTE: Recognizing more safe-to-ignore
             scanning.  NOTE: Recognizing more safe-to-ignore
             instructions here will improve support for optimized
             instructions here will improve support for optimized
             code.  */
             code.  */
          break;
          break;
        }
        }
 
 
      start += 2;
      start += 2;
    }
    }
 
 
  if (cache == NULL)
  if (cache == NULL)
    {
    {
      do_cleanups (back_to);
      do_cleanups (back_to);
      return start;
      return start;
    }
    }
 
 
  if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
  if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
    {
    {
      /* Frame pointer is fp.  Frame size is constant.  */
      /* Frame pointer is fp.  Frame size is constant.  */
      cache->framereg = ARM_FP_REGNUM;
      cache->framereg = ARM_FP_REGNUM;
      cache->framesize = -regs[ARM_FP_REGNUM].k;
      cache->framesize = -regs[ARM_FP_REGNUM].k;
    }
    }
  else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM))
  else if (pv_is_register (regs[THUMB_FP_REGNUM], ARM_SP_REGNUM))
    {
    {
      /* Frame pointer is r7.  Frame size is constant.  */
      /* Frame pointer is r7.  Frame size is constant.  */
      cache->framereg = THUMB_FP_REGNUM;
      cache->framereg = THUMB_FP_REGNUM;
      cache->framesize = -regs[THUMB_FP_REGNUM].k;
      cache->framesize = -regs[THUMB_FP_REGNUM].k;
    }
    }
  else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
  else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
    {
    {
      /* Try the stack pointer... this is a bit desperate.  */
      /* Try the stack pointer... this is a bit desperate.  */
      cache->framereg = ARM_SP_REGNUM;
      cache->framereg = ARM_SP_REGNUM;
      cache->framesize = -regs[ARM_SP_REGNUM].k;
      cache->framesize = -regs[ARM_SP_REGNUM].k;
    }
    }
  else
  else
    {
    {
      /* We're just out of luck.  We don't know where the frame is.  */
      /* We're just out of luck.  We don't know where the frame is.  */
      cache->framereg = -1;
      cache->framereg = -1;
      cache->framesize = 0;
      cache->framesize = 0;
    }
    }
 
 
  for (i = 0; i < 16; i++)
  for (i = 0; i < 16; i++)
    if (pv_area_find_reg (stack, gdbarch, i, &offset))
    if (pv_area_find_reg (stack, gdbarch, i, &offset))
      cache->saved_regs[i].addr = offset;
      cache->saved_regs[i].addr = offset;
 
 
  do_cleanups (back_to);
  do_cleanups (back_to);
  return start;
  return start;
}
}
 
 
/* Advance the PC across any function entry prologue instructions to
/* Advance the PC across any function entry prologue instructions to
   reach some "real" code.
   reach some "real" code.
 
 
   The APCS (ARM Procedure Call Standard) defines the following
   The APCS (ARM Procedure Call Standard) defines the following
   prologue:
   prologue:
 
 
   mov          ip, sp
   mov          ip, sp
   [stmfd       sp!, {a1,a2,a3,a4}]
   [stmfd       sp!, {a1,a2,a3,a4}]
   stmfd        sp!, {...,fp,ip,lr,pc}
   stmfd        sp!, {...,fp,ip,lr,pc}
   [stfe        f7, [sp, #-12]!]
   [stfe        f7, [sp, #-12]!]
   [stfe        f6, [sp, #-12]!]
   [stfe        f6, [sp, #-12]!]
   [stfe        f5, [sp, #-12]!]
   [stfe        f5, [sp, #-12]!]
   [stfe        f4, [sp, #-12]!]
   [stfe        f4, [sp, #-12]!]
   sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn */
   sub fp, ip, #nn @@ nn == 20 or 4 depending on second insn */
 
 
static CORE_ADDR
static CORE_ADDR
arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
arm_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
{
  unsigned long inst;
  unsigned long inst;
  CORE_ADDR skip_pc;
  CORE_ADDR skip_pc;
  CORE_ADDR func_addr, func_end = 0;
  CORE_ADDR func_addr, func_end = 0;
  char *func_name;
  char *func_name;
  struct symtab_and_line sal;
  struct symtab_and_line sal;
 
 
  /* If we're in a dummy frame, don't even try to skip the prologue.  */
  /* If we're in a dummy frame, don't even try to skip the prologue.  */
  if (deprecated_pc_in_call_dummy (pc))
  if (deprecated_pc_in_call_dummy (pc))
    return pc;
    return pc;
 
 
  /* See what the symbol table says.  */
  /* See what the symbol table says.  */
 
 
  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
  if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
    {
    {
      struct symbol *sym;
      struct symbol *sym;
 
 
      /* Found a function.  */
      /* Found a function.  */
      sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
      sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
      if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
      if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
        {
        {
          /* Don't use this trick for assembly source files.  */
          /* Don't use this trick for assembly source files.  */
          sal = find_pc_line (func_addr, 0);
          sal = find_pc_line (func_addr, 0);
          if ((sal.line != 0) && (sal.end < func_end))
          if ((sal.line != 0) && (sal.end < func_end))
            return sal.end;
            return sal.end;
        }
        }
    }
    }
 
 
  /* Can't find the prologue end in the symbol table, try it the hard way
  /* Can't find the prologue end in the symbol table, try it the hard way
     by disassembling the instructions.  */
     by disassembling the instructions.  */
 
 
  /* Like arm_scan_prologue, stop no later than pc + 64. */
  /* Like arm_scan_prologue, stop no later than pc + 64. */
  if (func_end == 0 || func_end > pc + 64)
  if (func_end == 0 || func_end > pc + 64)
    func_end = pc + 64;
    func_end = pc + 64;
 
 
  /* Check if this is Thumb code.  */
  /* Check if this is Thumb code.  */
  if (arm_pc_is_thumb (pc))
  if (arm_pc_is_thumb (pc))
    return thumb_analyze_prologue (gdbarch, pc, func_end, NULL);
    return thumb_analyze_prologue (gdbarch, pc, func_end, NULL);
 
 
  for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
  for (skip_pc = pc; skip_pc < func_end; skip_pc += 4)
    {
    {
      inst = read_memory_unsigned_integer (skip_pc, 4);
      inst = read_memory_unsigned_integer (skip_pc, 4);
 
 
      /* "mov ip, sp" is no longer a required part of the prologue.  */
      /* "mov ip, sp" is no longer a required part of the prologue.  */
      if (inst == 0xe1a0c00d)                   /* mov ip, sp */
      if (inst == 0xe1a0c00d)                   /* mov ip, sp */
        continue;
        continue;
 
 
      if ((inst & 0xfffff000) == 0xe28dc000)    /* add ip, sp #n */
      if ((inst & 0xfffff000) == 0xe28dc000)    /* add ip, sp #n */
        continue;
        continue;
 
 
      if ((inst & 0xfffff000) == 0xe24dc000)    /* sub ip, sp #n */
      if ((inst & 0xfffff000) == 0xe24dc000)    /* sub ip, sp #n */
        continue;
        continue;
 
 
      /* Some prologues begin with "str lr, [sp, #-4]!".  */
      /* Some prologues begin with "str lr, [sp, #-4]!".  */
      if (inst == 0xe52de004)                   /* str lr, [sp, #-4]! */
      if (inst == 0xe52de004)                   /* str lr, [sp, #-4]! */
        continue;
        continue;
 
 
      if ((inst & 0xfffffff0) == 0xe92d0000)    /* stmfd sp!,{a1,a2,a3,a4} */
      if ((inst & 0xfffffff0) == 0xe92d0000)    /* stmfd sp!,{a1,a2,a3,a4} */
        continue;
        continue;
 
 
      if ((inst & 0xfffff800) == 0xe92dd800)    /* stmfd sp!,{fp,ip,lr,pc} */
      if ((inst & 0xfffff800) == 0xe92dd800)    /* stmfd sp!,{fp,ip,lr,pc} */
        continue;
        continue;
 
 
      /* Any insns after this point may float into the code, if it makes
      /* Any insns after this point may float into the code, if it makes
         for better instruction scheduling, so we skip them only if we
         for better instruction scheduling, so we skip them only if we
         find them, but still consider the function to be frame-ful.  */
         find them, but still consider the function to be frame-ful.  */
 
 
      /* We may have either one sfmfd instruction here, or several stfe
      /* We may have either one sfmfd instruction here, or several stfe
         insns, depending on the version of floating point code we
         insns, depending on the version of floating point code we
         support.  */
         support.  */
      if ((inst & 0xffbf0fff) == 0xec2d0200)    /* sfmfd fn, <cnt>, [sp]! */
      if ((inst & 0xffbf0fff) == 0xec2d0200)    /* sfmfd fn, <cnt>, [sp]! */
        continue;
        continue;
 
 
      if ((inst & 0xffff8fff) == 0xed6d0103)    /* stfe fn, [sp, #-12]! */
      if ((inst & 0xffff8fff) == 0xed6d0103)    /* stfe fn, [sp, #-12]! */
        continue;
        continue;
 
 
      if ((inst & 0xfffff000) == 0xe24cb000)    /* sub fp, ip, #nn */
      if ((inst & 0xfffff000) == 0xe24cb000)    /* sub fp, ip, #nn */
        continue;
        continue;
 
 
      if ((inst & 0xfffff000) == 0xe24dd000)    /* sub sp, sp, #nn */
      if ((inst & 0xfffff000) == 0xe24dd000)    /* sub sp, sp, #nn */
        continue;
        continue;
 
 
      if ((inst & 0xffffc000) == 0xe54b0000 ||  /* strb r(0123),[r11,#-nn] */
      if ((inst & 0xffffc000) == 0xe54b0000 ||  /* strb r(0123),[r11,#-nn] */
          (inst & 0xffffc0f0) == 0xe14b00b0 ||  /* strh r(0123),[r11,#-nn] */
          (inst & 0xffffc0f0) == 0xe14b00b0 ||  /* strh r(0123),[r11,#-nn] */
          (inst & 0xffffc000) == 0xe50b0000)    /* str  r(0123),[r11,#-nn] */
          (inst & 0xffffc000) == 0xe50b0000)    /* str  r(0123),[r11,#-nn] */
        continue;
        continue;
 
 
      if ((inst & 0xffffc000) == 0xe5cd0000 ||  /* strb r(0123),[sp,#nn] */
      if ((inst & 0xffffc000) == 0xe5cd0000 ||  /* strb r(0123),[sp,#nn] */
          (inst & 0xffffc0f0) == 0xe1cd00b0 ||  /* strh r(0123),[sp,#nn] */
          (inst & 0xffffc0f0) == 0xe1cd00b0 ||  /* strh r(0123),[sp,#nn] */
          (inst & 0xffffc000) == 0xe58d0000)    /* str  r(0123),[sp,#nn] */
          (inst & 0xffffc000) == 0xe58d0000)    /* str  r(0123),[sp,#nn] */
        continue;
        continue;
 
 
      /* Un-recognized instruction; stop scanning.  */
      /* Un-recognized instruction; stop scanning.  */
      break;
      break;
    }
    }
 
 
  return skip_pc;               /* End of prologue */
  return skip_pc;               /* End of prologue */
}
}
 
 
/* *INDENT-OFF* */
/* *INDENT-OFF* */
/* Function: thumb_scan_prologue (helper function for arm_scan_prologue)
/* Function: thumb_scan_prologue (helper function for arm_scan_prologue)
   This function decodes a Thumb function prologue to determine:
   This function decodes a Thumb function prologue to determine:
     1) the size of the stack frame
     1) the size of the stack frame
     2) which registers are saved on it
     2) which registers are saved on it
     3) the offsets of saved regs
     3) the offsets of saved regs
     4) the offset from the stack pointer to the frame pointer
     4) the offset from the stack pointer to the frame pointer
 
 
   A typical Thumb function prologue would create this stack frame
   A typical Thumb function prologue would create this stack frame
   (offsets relative to FP)
   (offsets relative to FP)
     old SP ->  24  stack parameters
     old SP ->  24  stack parameters
                20  LR
                20  LR
                16  R7
                16  R7
     R7 ->       0  local variables (16 bytes)
     R7 ->       0  local variables (16 bytes)
     SP ->     -12  additional stack space (12 bytes)
     SP ->     -12  additional stack space (12 bytes)
   The frame size would thus be 36 bytes, and the frame offset would be
   The frame size would thus be 36 bytes, and the frame offset would be
   12 bytes.  The frame register is R7.
   12 bytes.  The frame register is R7.
 
 
   The comments for thumb_skip_prolog() describe the algorithm we use
   The comments for thumb_skip_prolog() describe the algorithm we use
   to detect the end of the prolog.  */
   to detect the end of the prolog.  */
/* *INDENT-ON* */
/* *INDENT-ON* */
 
 
static void
static void
thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
thumb_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR prev_pc,
                     struct arm_prologue_cache *cache)
                     struct arm_prologue_cache *cache)
{
{
  CORE_ADDR prologue_start;
  CORE_ADDR prologue_start;
  CORE_ADDR prologue_end;
  CORE_ADDR prologue_end;
  CORE_ADDR current_pc;
  CORE_ADDR current_pc;
  /* Which register has been copied to register n?  */
  /* Which register has been copied to register n?  */
  int saved_reg[16];
  int saved_reg[16];
  /* findmask:
  /* findmask:
     bit 0 - push { rlist }
     bit 0 - push { rlist }
     bit 1 - mov r7, sp  OR  add r7, sp, #imm  (setting of r7)
     bit 1 - mov r7, sp  OR  add r7, sp, #imm  (setting of r7)
     bit 2 - sub sp, #simm  OR  add sp, #simm  (adjusting of sp)
     bit 2 - sub sp, #simm  OR  add sp, #simm  (adjusting of sp)
  */
  */
  int findmask = 0;
  int findmask = 0;
  int i;
  int i;
 
 
  if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
  if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
    {
    {
      struct symtab_and_line sal = find_pc_line (prologue_start, 0);
      struct symtab_and_line sal = find_pc_line (prologue_start, 0);
 
 
      if (sal.line == 0)         /* no line info, use current PC  */
      if (sal.line == 0)         /* no line info, use current PC  */
        prologue_end = prev_pc;
        prologue_end = prev_pc;
      else if (sal.end < prologue_end)  /* next line begins after fn end */
      else if (sal.end < prologue_end)  /* next line begins after fn end */
        prologue_end = sal.end;         /* (probably means no prologue)  */
        prologue_end = sal.end;         /* (probably means no prologue)  */
    }
    }
  else
  else
    /* We're in the boondocks: we have no idea where the start of the
    /* We're in the boondocks: we have no idea where the start of the
       function is.  */
       function is.  */
    return;
    return;
 
 
  prologue_end = min (prologue_end, prev_pc);
  prologue_end = min (prologue_end, prev_pc);
 
 
  thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
  thumb_analyze_prologue (gdbarch, prologue_start, prologue_end, cache);
}
}
 
 
/* This function decodes an ARM function prologue to determine:
/* This function decodes an ARM function prologue to determine:
   1) the size of the stack frame
   1) the size of the stack frame
   2) which registers are saved on it
   2) which registers are saved on it
   3) the offsets of saved regs
   3) the offsets of saved regs
   4) the offset from the stack pointer to the frame pointer
   4) the offset from the stack pointer to the frame pointer
   This information is stored in the "extra" fields of the frame_info.
   This information is stored in the "extra" fields of the frame_info.
 
 
   There are two basic forms for the ARM prologue.  The fixed argument
   There are two basic forms for the ARM prologue.  The fixed argument
   function call will look like:
   function call will look like:
 
 
   mov    ip, sp
   mov    ip, sp
   stmfd  sp!, {fp, ip, lr, pc}
   stmfd  sp!, {fp, ip, lr, pc}
   sub    fp, ip, #4
   sub    fp, ip, #4
   [sub sp, sp, #4]
   [sub sp, sp, #4]
 
 
   Which would create this stack frame (offsets relative to FP):
   Which would create this stack frame (offsets relative to FP):
   IP ->   4    (caller's stack)
   IP ->   4    (caller's stack)
   FP ->   0    PC (points to address of stmfd instruction + 8 in callee)
   FP ->   0    PC (points to address of stmfd instruction + 8 in callee)
   -4   LR (return address in caller)
   -4   LR (return address in caller)
   -8   IP (copy of caller's SP)
   -8   IP (copy of caller's SP)
   -12  FP (caller's FP)
   -12  FP (caller's FP)
   SP -> -28    Local variables
   SP -> -28    Local variables
 
 
   The frame size would thus be 32 bytes, and the frame offset would be
   The frame size would thus be 32 bytes, and the frame offset would be
   28 bytes.  The stmfd call can also save any of the vN registers it
   28 bytes.  The stmfd call can also save any of the vN registers it
   plans to use, which increases the frame size accordingly.
   plans to use, which increases the frame size accordingly.
 
 
   Note: The stored PC is 8 off of the STMFD instruction that stored it
   Note: The stored PC is 8 off of the STMFD instruction that stored it
   because the ARM Store instructions always store PC + 8 when you read
   because the ARM Store instructions always store PC + 8 when you read
   the PC register.
   the PC register.
 
 
   A variable argument function call will look like:
   A variable argument function call will look like:
 
 
   mov    ip, sp
   mov    ip, sp
   stmfd  sp!, {a1, a2, a3, a4}
   stmfd  sp!, {a1, a2, a3, a4}
   stmfd  sp!, {fp, ip, lr, pc}
   stmfd  sp!, {fp, ip, lr, pc}
   sub    fp, ip, #20
   sub    fp, ip, #20
 
 
   Which would create this stack frame (offsets relative to FP):
   Which would create this stack frame (offsets relative to FP):
   IP ->  20    (caller's stack)
   IP ->  20    (caller's stack)
   16  A4
   16  A4
   12  A3
   12  A3
   8  A2
   8  A2
   4  A1
   4  A1
   FP ->   0    PC (points to address of stmfd instruction + 8 in callee)
   FP ->   0    PC (points to address of stmfd instruction + 8 in callee)
   -4   LR (return address in caller)
   -4   LR (return address in caller)
   -8   IP (copy of caller's SP)
   -8   IP (copy of caller's SP)
   -12  FP (caller's FP)
   -12  FP (caller's FP)
   SP -> -28    Local variables
   SP -> -28    Local variables
 
 
   The frame size would thus be 48 bytes, and the frame offset would be
   The frame size would thus be 48 bytes, and the frame offset would be
   28 bytes.
   28 bytes.
 
 
   There is another potential complication, which is that the optimizer
   There is another potential complication, which is that the optimizer
   will try to separate the store of fp in the "stmfd" instruction from
   will try to separate the store of fp in the "stmfd" instruction from
   the "sub fp, ip, #NN" instruction.  Almost anything can be there, so
   the "sub fp, ip, #NN" instruction.  Almost anything can be there, so
   we just key on the stmfd, and then scan for the "sub fp, ip, #NN"...
   we just key on the stmfd, and then scan for the "sub fp, ip, #NN"...
 
 
   Also, note, the original version of the ARM toolchain claimed that there
   Also, note, the original version of the ARM toolchain claimed that there
   should be an
   should be an
 
 
   instruction at the end of the prologue.  I have never seen GCC produce
   instruction at the end of the prologue.  I have never seen GCC produce
   this, and the ARM docs don't mention it.  We still test for it below in
   this, and the ARM docs don't mention it.  We still test for it below in
   case it happens...
   case it happens...
 
 
 */
 */
 
 
static void
static void
arm_scan_prologue (struct frame_info *next_frame,
arm_scan_prologue (struct frame_info *next_frame,
                   struct arm_prologue_cache *cache)
                   struct arm_prologue_cache *cache)
{
{
  struct gdbarch *gdbarch = get_frame_arch (next_frame);
  struct gdbarch *gdbarch = get_frame_arch (next_frame);
  int regno;
  int regno;
  CORE_ADDR prologue_start, prologue_end, current_pc;
  CORE_ADDR prologue_start, prologue_end, current_pc;
  CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
  CORE_ADDR prev_pc = frame_pc_unwind (next_frame);
  pv_t regs[ARM_FPS_REGNUM];
  pv_t regs[ARM_FPS_REGNUM];
  struct pv_area *stack;
  struct pv_area *stack;
  struct cleanup *back_to;
  struct cleanup *back_to;
  CORE_ADDR offset;
  CORE_ADDR offset;
 
 
  /* Assume there is no frame until proven otherwise.  */
  /* Assume there is no frame until proven otherwise.  */
  cache->framereg = ARM_SP_REGNUM;
  cache->framereg = ARM_SP_REGNUM;
  cache->framesize = 0;
  cache->framesize = 0;
 
 
  /* Check for Thumb prologue.  */
  /* Check for Thumb prologue.  */
  if (arm_pc_is_thumb (prev_pc))
  if (arm_pc_is_thumb (prev_pc))
    {
    {
      thumb_scan_prologue (gdbarch, prev_pc, cache);
      thumb_scan_prologue (gdbarch, prev_pc, cache);
      return;
      return;
    }
    }
 
 
  /* Find the function prologue.  If we can't find the function in
  /* Find the function prologue.  If we can't find the function in
     the symbol table, peek in the stack frame to find the PC.  */
     the symbol table, peek in the stack frame to find the PC.  */
  if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
  if (find_pc_partial_function (prev_pc, NULL, &prologue_start, &prologue_end))
    {
    {
      /* One way to find the end of the prologue (which works well
      /* One way to find the end of the prologue (which works well
         for unoptimized code) is to do the following:
         for unoptimized code) is to do the following:
 
 
            struct symtab_and_line sal = find_pc_line (prologue_start, 0);
            struct symtab_and_line sal = find_pc_line (prologue_start, 0);
 
 
            if (sal.line == 0)
            if (sal.line == 0)
              prologue_end = prev_pc;
              prologue_end = prev_pc;
            else if (sal.end < prologue_end)
            else if (sal.end < prologue_end)
              prologue_end = sal.end;
              prologue_end = sal.end;
 
 
         This mechanism is very accurate so long as the optimizer
         This mechanism is very accurate so long as the optimizer
         doesn't move any instructions from the function body into the
         doesn't move any instructions from the function body into the
         prologue.  If this happens, sal.end will be the last
         prologue.  If this happens, sal.end will be the last
         instruction in the first hunk of prologue code just before
         instruction in the first hunk of prologue code just before
         the first instruction that the scheduler has moved from
         the first instruction that the scheduler has moved from
         the body to the prologue.
         the body to the prologue.
 
 
         In order to make sure that we scan all of the prologue
         In order to make sure that we scan all of the prologue
         instructions, we use a slightly less accurate mechanism which
         instructions, we use a slightly less accurate mechanism which
         may scan more than necessary.  To help compensate for this
         may scan more than necessary.  To help compensate for this
         lack of accuracy, the prologue scanning loop below contains
         lack of accuracy, the prologue scanning loop below contains
         several clauses which'll cause the loop to terminate early if
         several clauses which'll cause the loop to terminate early if
         an implausible prologue instruction is encountered.
         an implausible prologue instruction is encountered.
 
 
         The expression
         The expression
 
 
              prologue_start + 64
              prologue_start + 64
 
 
         is a suitable endpoint since it accounts for the largest
         is a suitable endpoint since it accounts for the largest
         possible prologue plus up to five instructions inserted by
         possible prologue plus up to five instructions inserted by
         the scheduler.  */
         the scheduler.  */
 
 
      if (prologue_end > prologue_start + 64)
      if (prologue_end > prologue_start + 64)
        {
        {
          prologue_end = prologue_start + 64;   /* See above.  */
          prologue_end = prologue_start + 64;   /* See above.  */
        }
        }
    }
    }
  else
  else
    {
    {
      /* We have no symbol information.  Our only option is to assume this
      /* We have no symbol information.  Our only option is to assume this
         function has a standard stack frame and the normal frame register.
         function has a standard stack frame and the normal frame register.
         Then, we can find the value of our frame pointer on entrance to
         Then, we can find the value of our frame pointer on entrance to
         the callee (or at the present moment if this is the innermost frame).
         the callee (or at the present moment if this is the innermost frame).
         The value stored there should be the address of the stmfd + 8.  */
         The value stored there should be the address of the stmfd + 8.  */
      CORE_ADDR frame_loc;
      CORE_ADDR frame_loc;
      LONGEST return_value;
      LONGEST return_value;
 
 
      frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
      frame_loc = frame_unwind_register_unsigned (next_frame, ARM_FP_REGNUM);
      if (!safe_read_memory_integer (frame_loc, 4, &return_value))
      if (!safe_read_memory_integer (frame_loc, 4, &return_value))
        return;
        return;
      else
      else
        {
        {
          prologue_start = gdbarch_addr_bits_remove
          prologue_start = gdbarch_addr_bits_remove
                             (gdbarch, return_value) - 8;
                             (gdbarch, return_value) - 8;
          prologue_end = prologue_start + 64;   /* See above.  */
          prologue_end = prologue_start + 64;   /* See above.  */
        }
        }
    }
    }
 
 
  if (prev_pc < prologue_end)
  if (prev_pc < prologue_end)
    prologue_end = prev_pc;
    prologue_end = prev_pc;
 
 
  /* Now search the prologue looking for instructions that set up the
  /* Now search the prologue looking for instructions that set up the
     frame pointer, adjust the stack pointer, and save registers.
     frame pointer, adjust the stack pointer, and save registers.
 
 
     Be careful, however, and if it doesn't look like a prologue,
     Be careful, however, and if it doesn't look like a prologue,
     don't try to scan it.  If, for instance, a frameless function
     don't try to scan it.  If, for instance, a frameless function
     begins with stmfd sp!, then we will tell ourselves there is
     begins with stmfd sp!, then we will tell ourselves there is
     a frame, which will confuse stack traceback, as well as "finish"
     a frame, which will confuse stack traceback, as well as "finish"
     and other operations that rely on a knowledge of the stack
     and other operations that rely on a knowledge of the stack
     traceback.
     traceback.
 
 
     In the APCS, the prologue should start with  "mov ip, sp" so
     In the APCS, the prologue should start with  "mov ip, sp" so
     if we don't see this as the first insn, we will stop.
     if we don't see this as the first insn, we will stop.
 
 
     [Note: This doesn't seem to be true any longer, so it's now an
     [Note: This doesn't seem to be true any longer, so it's now an
     optional part of the prologue.  - Kevin Buettner, 2001-11-20]
     optional part of the prologue.  - Kevin Buettner, 2001-11-20]
 
 
     [Note further: The "mov ip,sp" only seems to be missing in
     [Note further: The "mov ip,sp" only seems to be missing in
     frameless functions at optimization level "-O2" or above,
     frameless functions at optimization level "-O2" or above,
     in which case it is often (but not always) replaced by
     in which case it is often (but not always) replaced by
     "str lr, [sp, #-4]!".  - Michael Snyder, 2002-04-23]  */
     "str lr, [sp, #-4]!".  - Michael Snyder, 2002-04-23]  */
 
 
  for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
  for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
    regs[regno] = pv_register (regno, 0);
    regs[regno] = pv_register (regno, 0);
  stack = make_pv_area (ARM_SP_REGNUM);
  stack = make_pv_area (ARM_SP_REGNUM);
  back_to = make_cleanup_free_pv_area (stack);
  back_to = make_cleanup_free_pv_area (stack);
 
 
  regs[ARM_PC_REGNUM] = pv_unknown ();
  regs[ARM_PC_REGNUM] = pv_unknown ();
 
 
  for (current_pc = prologue_start;
  for (current_pc = prologue_start;
       current_pc < prologue_end;
       current_pc < prologue_end;
       current_pc += 4)
       current_pc += 4)
    {
    {
      unsigned int insn = read_memory_unsigned_integer (current_pc, 4);
      unsigned int insn = read_memory_unsigned_integer (current_pc, 4);
 
 
      if (insn == 0xe1a0c00d)           /* mov ip, sp */
      if (insn == 0xe1a0c00d)           /* mov ip, sp */
        {
        {
          regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
          regs[ARM_IP_REGNUM] = regs[ARM_SP_REGNUM];
          continue;
          continue;
        }
        }
      else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
      else if ((insn & 0xfffff000) == 0xe28dc000) /* add ip, sp #n */
        {
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
          imm = (imm >> rot) | (imm << (32 - rot));
          regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], imm);
          regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], imm);
          continue;
          continue;
        }
        }
      else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
      else if ((insn & 0xfffff000) == 0xe24dc000) /* sub ip, sp #n */
        {
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
          imm = (imm >> rot) | (imm << (32 - rot));
          regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
          regs[ARM_IP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
          continue;
          continue;
        }
        }
      else if (insn == 0xe52de004)      /* str lr, [sp, #-4]! */
      else if (insn == 0xe52de004)      /* str lr, [sp, #-4]! */
        {
        {
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
            break;
            break;
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
          pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[ARM_LR_REGNUM]);
          pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[ARM_LR_REGNUM]);
          continue;
          continue;
        }
        }
      else if ((insn & 0xffff0000) == 0xe92d0000)
      else if ((insn & 0xffff0000) == 0xe92d0000)
        /* stmfd sp!, {..., fp, ip, lr, pc}
        /* stmfd sp!, {..., fp, ip, lr, pc}
           or
           or
           stmfd sp!, {a1, a2, a3, a4}  */
           stmfd sp!, {a1, a2, a3, a4}  */
        {
        {
          int mask = insn & 0xffff;
          int mask = insn & 0xffff;
 
 
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
            break;
            break;
 
 
          /* Calculate offsets of saved registers.  */
          /* Calculate offsets of saved registers.  */
          for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
          for (regno = ARM_PC_REGNUM; regno >= 0; regno--)
            if (mask & (1 << regno))
            if (mask & (1 << regno))
              {
              {
                regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
                regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -4);
                pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
                pv_area_store (stack, regs[ARM_SP_REGNUM], 4, regs[regno]);
              }
              }
        }
        }
      else if ((insn & 0xffffc000) == 0xe54b0000 ||     /* strb rx,[r11,#-n] */
      else if ((insn & 0xffffc000) == 0xe54b0000 ||     /* strb rx,[r11,#-n] */
               (insn & 0xffffc0f0) == 0xe14b00b0 ||     /* strh rx,[r11,#-n] */
               (insn & 0xffffc0f0) == 0xe14b00b0 ||     /* strh rx,[r11,#-n] */
               (insn & 0xffffc000) == 0xe50b0000)       /* str  rx,[r11,#-n] */
               (insn & 0xffffc000) == 0xe50b0000)       /* str  rx,[r11,#-n] */
        {
        {
          /* No need to add this to saved_regs -- it's just an arg reg.  */
          /* No need to add this to saved_regs -- it's just an arg reg.  */
          continue;
          continue;
        }
        }
      else if ((insn & 0xffffc000) == 0xe5cd0000 ||     /* strb rx,[sp,#n] */
      else if ((insn & 0xffffc000) == 0xe5cd0000 ||     /* strb rx,[sp,#n] */
               (insn & 0xffffc0f0) == 0xe1cd00b0 ||     /* strh rx,[sp,#n] */
               (insn & 0xffffc0f0) == 0xe1cd00b0 ||     /* strh rx,[sp,#n] */
               (insn & 0xffffc000) == 0xe58d0000)       /* str  rx,[sp,#n] */
               (insn & 0xffffc000) == 0xe58d0000)       /* str  rx,[sp,#n] */
        {
        {
          /* No need to add this to saved_regs -- it's just an arg reg.  */
          /* No need to add this to saved_regs -- it's just an arg reg.  */
          continue;
          continue;
        }
        }
      else if ((insn & 0xfffff000) == 0xe24cb000)       /* sub fp, ip #n */
      else if ((insn & 0xfffff000) == 0xe24cb000)       /* sub fp, ip #n */
        {
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
          imm = (imm >> rot) | (imm << (32 - rot));
          regs[ARM_FP_REGNUM] = pv_add_constant (regs[ARM_IP_REGNUM], -imm);
          regs[ARM_FP_REGNUM] = pv_add_constant (regs[ARM_IP_REGNUM], -imm);
        }
        }
      else if ((insn & 0xfffff000) == 0xe24dd000)       /* sub sp, sp #n */
      else if ((insn & 0xfffff000) == 0xe24dd000)       /* sub sp, sp #n */
        {
        {
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned imm = insn & 0xff;                   /* immediate value */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          unsigned rot = (insn & 0xf00) >> 7;           /* rotate amount */
          imm = (imm >> rot) | (imm << (32 - rot));
          imm = (imm >> rot) | (imm << (32 - rot));
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -imm);
        }
        }
      else if ((insn & 0xffff7fff) == 0xed6d0103        /* stfe f?, [sp, -#c]! */
      else if ((insn & 0xffff7fff) == 0xed6d0103        /* stfe f?, [sp, -#c]! */
               && gdbarch_tdep (gdbarch)->have_fpa_registers)
               && gdbarch_tdep (gdbarch)->have_fpa_registers)
        {
        {
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
            break;
            break;
 
 
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
          regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
          regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
          regno = ARM_F0_REGNUM + ((insn >> 12) & 0x07);
          pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]);
          pv_area_store (stack, regs[ARM_SP_REGNUM], 12, regs[regno]);
        }
        }
      else if ((insn & 0xffbf0fff) == 0xec2d0200        /* sfmfd f0, 4, [sp!] */
      else if ((insn & 0xffbf0fff) == 0xec2d0200        /* sfmfd f0, 4, [sp!] */
               && gdbarch_tdep (gdbarch)->have_fpa_registers)
               && gdbarch_tdep (gdbarch)->have_fpa_registers)
        {
        {
          int n_saved_fp_regs;
          int n_saved_fp_regs;
          unsigned int fp_start_reg, fp_bound_reg;
          unsigned int fp_start_reg, fp_bound_reg;
 
 
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
          if (pv_area_store_would_trash (stack, regs[ARM_SP_REGNUM]))
            break;
            break;
 
 
          if ((insn & 0x800) == 0x800)          /* N0 is set */
          if ((insn & 0x800) == 0x800)          /* N0 is set */
            {
            {
              if ((insn & 0x40000) == 0x40000)  /* N1 is set */
              if ((insn & 0x40000) == 0x40000)  /* N1 is set */
                n_saved_fp_regs = 3;
                n_saved_fp_regs = 3;
              else
              else
                n_saved_fp_regs = 1;
                n_saved_fp_regs = 1;
            }
            }
          else
          else
            {
            {
              if ((insn & 0x40000) == 0x40000)  /* N1 is set */
              if ((insn & 0x40000) == 0x40000)  /* N1 is set */
                n_saved_fp_regs = 2;
                n_saved_fp_regs = 2;
              else
              else
                n_saved_fp_regs = 4;
                n_saved_fp_regs = 4;
            }
            }
 
 
          fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
          fp_start_reg = ARM_F0_REGNUM + ((insn >> 12) & 0x7);
          fp_bound_reg = fp_start_reg + n_saved_fp_regs;
          fp_bound_reg = fp_start_reg + n_saved_fp_regs;
          for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
          for (; fp_start_reg < fp_bound_reg; fp_start_reg++)
            {
            {
              regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
              regs[ARM_SP_REGNUM] = pv_add_constant (regs[ARM_SP_REGNUM], -12);
              pv_area_store (stack, regs[ARM_SP_REGNUM], 12,
              pv_area_store (stack, regs[ARM_SP_REGNUM], 12,
                             regs[fp_start_reg++]);
                             regs[fp_start_reg++]);
            }
            }
        }
        }
      else if ((insn & 0xf0000000) != 0xe0000000)
      else if ((insn & 0xf0000000) != 0xe0000000)
        break;                  /* Condition not true, exit early */
        break;                  /* Condition not true, exit early */
      else if ((insn & 0xfe200000) == 0xe8200000)       /* ldm? */
      else if ((insn & 0xfe200000) == 0xe8200000)       /* ldm? */
        break;                  /* Don't scan past a block load */
        break;                  /* Don't scan past a block load */
      else
      else
        /* The optimizer might shove anything into the prologue,
        /* The optimizer might shove anything into the prologue,
           so we just skip what we don't recognize.  */
           so we just skip what we don't recognize.  */
        continue;
        continue;
    }
    }
 
 
  /* The frame size is just the distance from the frame register
  /* The frame size is just the distance from the frame register
     to the original stack pointer.  */
     to the original stack pointer.  */
  if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
  if (pv_is_register (regs[ARM_FP_REGNUM], ARM_SP_REGNUM))
    {
    {
      /* Frame pointer is fp.  */
      /* Frame pointer is fp.  */
      cache->framereg = ARM_FP_REGNUM;
      cache->framereg = ARM_FP_REGNUM;
      cache->framesize = -regs[ARM_FP_REGNUM].k;
      cache->framesize = -regs[ARM_FP_REGNUM].k;
    }
    }
  else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
  else if (pv_is_register (regs[ARM_SP_REGNUM], ARM_SP_REGNUM))
    {
    {
      /* Try the stack pointer... this is a bit desperate.  */
      /* Try the stack pointer... this is a bit desperate.  */
      cache->framereg = ARM_SP_REGNUM;
      cache->framereg = ARM_SP_REGNUM;
      cache->framesize = -regs[ARM_SP_REGNUM].k;
      cache->framesize = -regs[ARM_SP_REGNUM].k;
    }
    }
  else
  else
    {
    {
      /* We're just out of luck.  We don't know where the frame is.  */
      /* We're just out of luck.  We don't know where the frame is.  */
      cache->framereg = -1;
      cache->framereg = -1;
      cache->framesize = 0;
      cache->framesize = 0;
    }
    }
 
 
  for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
  for (regno = 0; regno < ARM_FPS_REGNUM; regno++)
    if (pv_area_find_reg (stack, gdbarch, regno, &offset))
    if (pv_area_find_reg (stack, gdbarch, regno, &offset))
      cache->saved_regs[regno].addr = offset;
      cache->saved_regs[regno].addr = offset;
 
 
  do_cleanups (back_to);
  do_cleanups (back_to);
}
}
 
 
static struct arm_prologue_cache *
static struct arm_prologue_cache *
arm_make_prologue_cache (struct frame_info *next_frame)
arm_make_prologue_cache (struct frame_info *next_frame)
{
{
  int reg;
  int reg;
  struct arm_prologue_cache *cache;
  struct arm_prologue_cache *cache;
  CORE_ADDR unwound_fp;
  CORE_ADDR unwound_fp;
 
 
  cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
  cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
 
  arm_scan_prologue (next_frame, cache);
  arm_scan_prologue (next_frame, cache);
 
 
  unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
  unwound_fp = frame_unwind_register_unsigned (next_frame, cache->framereg);
  if (unwound_fp == 0)
  if (unwound_fp == 0)
    return cache;
    return cache;
 
 
  cache->prev_sp = unwound_fp + cache->framesize;
  cache->prev_sp = unwound_fp + cache->framesize;
 
 
  /* Calculate actual addresses of saved registers using offsets
  /* Calculate actual addresses of saved registers using offsets
     determined by arm_scan_prologue.  */
     determined by arm_scan_prologue.  */
  for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (next_frame)); reg++)
  for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (next_frame)); reg++)
    if (trad_frame_addr_p (cache->saved_regs, reg))
    if (trad_frame_addr_p (cache->saved_regs, reg))
      cache->saved_regs[reg].addr += cache->prev_sp;
      cache->saved_regs[reg].addr += cache->prev_sp;
 
 
  return cache;
  return cache;
}
}
 
 
/* Our frame ID for a normal frame is the current function's starting PC
/* Our frame ID for a normal frame is the current function's starting PC
   and the caller's SP when we were called.  */
   and the caller's SP when we were called.  */
 
 
static void
static void
arm_prologue_this_id (struct frame_info *next_frame,
arm_prologue_this_id (struct frame_info *next_frame,
                      void **this_cache,
                      void **this_cache,
                      struct frame_id *this_id)
                      struct frame_id *this_id)
{
{
  struct arm_prologue_cache *cache;
  struct arm_prologue_cache *cache;
  struct frame_id id;
  struct frame_id id;
  CORE_ADDR func;
  CORE_ADDR func;
 
 
  if (*this_cache == NULL)
  if (*this_cache == NULL)
    *this_cache = arm_make_prologue_cache (next_frame);
    *this_cache = arm_make_prologue_cache (next_frame);
  cache = *this_cache;
  cache = *this_cache;
 
 
  func = frame_func_unwind (next_frame, NORMAL_FRAME);
  func = frame_func_unwind (next_frame, NORMAL_FRAME);
 
 
  /* This is meant to halt the backtrace at "_start".  Make sure we
  /* This is meant to halt the backtrace at "_start".  Make sure we
     don't halt it at a generic dummy frame. */
     don't halt it at a generic dummy frame. */
  if (func <= gdbarch_tdep (get_frame_arch (next_frame))->lowest_pc)
  if (func <= gdbarch_tdep (get_frame_arch (next_frame))->lowest_pc)
    return;
    return;
 
 
  /* If we've hit a wall, stop.  */
  /* If we've hit a wall, stop.  */
  if (cache->prev_sp == 0)
  if (cache->prev_sp == 0)
    return;
    return;
 
 
  id = frame_id_build (cache->prev_sp, func);
  id = frame_id_build (cache->prev_sp, func);
  *this_id = id;
  *this_id = id;
}
}
 
 
static void
static void
arm_prologue_prev_register (struct frame_info *next_frame,
arm_prologue_prev_register (struct frame_info *next_frame,
                            void **this_cache,
                            void **this_cache,
                            int prev_regnum,
                            int prev_regnum,
                            int *optimized,
                            int *optimized,
                            enum lval_type *lvalp,
                            enum lval_type *lvalp,
                            CORE_ADDR *addrp,
                            CORE_ADDR *addrp,
                            int *realnump,
                            int *realnump,
                            gdb_byte *valuep)
                            gdb_byte *valuep)
{
{
  struct arm_prologue_cache *cache;
  struct arm_prologue_cache *cache;
 
 
  if (*this_cache == NULL)
  if (*this_cache == NULL)
    *this_cache = arm_make_prologue_cache (next_frame);
    *this_cache = arm_make_prologue_cache (next_frame);
  cache = *this_cache;
  cache = *this_cache;
 
 
  /* If we are asked to unwind the PC, then we need to return the LR
  /* If we are asked to unwind the PC, then we need to return the LR
     instead.  The saved value of PC points into this frame's
     instead.  The saved value of PC points into this frame's
     prologue, not the next frame's resume location.  */
     prologue, not the next frame's resume location.  */
  if (prev_regnum == ARM_PC_REGNUM)
  if (prev_regnum == ARM_PC_REGNUM)
    prev_regnum = ARM_LR_REGNUM;
    prev_regnum = ARM_LR_REGNUM;
 
 
  /* SP is generally not saved to the stack, but this frame is
  /* SP is generally not saved to the stack, but this frame is
     identified by NEXT_FRAME's stack pointer at the time of the call.
     identified by NEXT_FRAME's stack pointer at the time of the call.
     The value was already reconstructed into PREV_SP.  */
     The value was already reconstructed into PREV_SP.  */
  if (prev_regnum == ARM_SP_REGNUM)
  if (prev_regnum == ARM_SP_REGNUM)
    {
    {
      *lvalp = not_lval;
      *lvalp = not_lval;
      if (valuep)
      if (valuep)
        store_unsigned_integer (valuep, 4, cache->prev_sp);
        store_unsigned_integer (valuep, 4, cache->prev_sp);
      return;
      return;
    }
    }
 
 
  trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
  trad_frame_get_prev_register (next_frame, cache->saved_regs, prev_regnum,
                                optimized, lvalp, addrp, realnump, valuep);
                                optimized, lvalp, addrp, realnump, valuep);
}
}
 
 
struct frame_unwind arm_prologue_unwind = {
struct frame_unwind arm_prologue_unwind = {
  NORMAL_FRAME,
  NORMAL_FRAME,
  arm_prologue_this_id,
  arm_prologue_this_id,
  arm_prologue_prev_register
  arm_prologue_prev_register
};
};
 
 
static const struct frame_unwind *
static const struct frame_unwind *
arm_prologue_unwind_sniffer (struct frame_info *next_frame)
arm_prologue_unwind_sniffer (struct frame_info *next_frame)
{
{
  return &arm_prologue_unwind;
  return &arm_prologue_unwind;
}
}
 
 
static struct arm_prologue_cache *
static struct arm_prologue_cache *
arm_make_stub_cache (struct frame_info *next_frame)
arm_make_stub_cache (struct frame_info *next_frame)
{
{
  int reg;
  int reg;
  struct arm_prologue_cache *cache;
  struct arm_prologue_cache *cache;
  CORE_ADDR unwound_fp;
  CORE_ADDR unwound_fp;
 
 
  cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
  cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache);
  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
  cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
 
  cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
  cache->prev_sp = frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM);
 
 
  return cache;
  return cache;
}
}
 
 
/* Our frame ID for a stub frame is the current SP and LR.  */
/* Our frame ID for a stub frame is the current SP and LR.  */
 
 
static void
static void
arm_stub_this_id (struct frame_info *next_frame,
arm_stub_this_id (struct frame_info *next_frame,
                  void **this_cache,
                  void **this_cache,
                  struct frame_id *this_id)
                  struct frame_id *this_id)
{
{
  struct arm_prologue_cache *cache;
  struct arm_prologue_cache *cache;
 
 
  if (*this_cache == NULL)
  if (*this_cache == NULL)
    *this_cache = arm_make_stub_cache (next_frame);
    *this_cache = arm_make_stub_cache (next_frame);
  cache = *this_cache;
  cache = *this_cache;
 
 
  *this_id = frame_id_build (cache->prev_sp,
  *this_id = frame_id_build (cache->prev_sp,
                             frame_pc_unwind (next_frame));
                             frame_pc_unwind (next_frame));
}
}
 
 
struct frame_unwind arm_stub_unwind = {
struct frame_unwind arm_stub_unwind = {
  NORMAL_FRAME,
  NORMAL_FRAME,
  arm_stub_this_id,
  arm_stub_this_id,
  arm_prologue_prev_register
  arm_prologue_prev_register
};
};
 
 
static const struct frame_unwind *
static const struct frame_unwind *
arm_stub_unwind_sniffer (struct frame_info *next_frame)
arm_stub_unwind_sniffer (struct frame_info *next_frame)
{
{
  CORE_ADDR addr_in_block;
  CORE_ADDR addr_in_block;
  char dummy[4];
  char dummy[4];
 
 
  addr_in_block = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
  addr_in_block = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
  if (in_plt_section (addr_in_block, NULL)
  if (in_plt_section (addr_in_block, NULL)
      || target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
      || target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
    return &arm_stub_unwind;
    return &arm_stub_unwind;
 
 
  return NULL;
  return NULL;
}
}
 
 
static CORE_ADDR
static CORE_ADDR
arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
arm_normal_frame_base (struct frame_info *next_frame, void **this_cache)
{
{
  struct arm_prologue_cache *cache;
  struct arm_prologue_cache *cache;
 
 
  if (*this_cache == NULL)
  if (*this_cache == NULL)
    *this_cache = arm_make_prologue_cache (next_frame);
    *this_cache = arm_make_prologue_cache (next_frame);
  cache = *this_cache;
  cache = *this_cache;
 
 
  return cache->prev_sp - cache->framesize;
  return cache->prev_sp - cache->framesize;
}
}
 
 
struct frame_base arm_normal_base = {
struct frame_base arm_normal_base = {
  &arm_prologue_unwind,
  &arm_prologue_unwind,
  arm_normal_frame_base,
  arm_normal_frame_base,
  arm_normal_frame_base,
  arm_normal_frame_base,
  arm_normal_frame_base
  arm_normal_frame_base
};
};
 
 
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
   dummy frame.  The frame ID's base needs to match the TOS value
   dummy frame.  The frame ID's base needs to match the TOS value
   saved by save_dummy_frame_tos() and returned from
   saved by save_dummy_frame_tos() and returned from
   arm_push_dummy_call, and the PC needs to match the dummy frame's
   arm_push_dummy_call, and the PC needs to match the dummy frame's
   breakpoint.  */
   breakpoint.  */
 
 
static struct frame_id
static struct frame_id
arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
arm_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
{
  return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
  return frame_id_build (frame_unwind_register_unsigned (next_frame, ARM_SP_REGNUM),
                         frame_pc_unwind (next_frame));
                         frame_pc_unwind (next_frame));
}
}
 
 
/* Given THIS_FRAME, find the previous frame's resume PC (which will
/* Given THIS_FRAME, find the previous frame's resume PC (which will
   be used to construct the previous frame's ID, after looking up the
   be used to construct the previous frame's ID, after looking up the
   containing function).  */
   containing function).  */
 
 
static CORE_ADDR
static CORE_ADDR
arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
arm_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
{
  CORE_ADDR pc;
  CORE_ADDR pc;
  pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
  pc = frame_unwind_register_unsigned (this_frame, ARM_PC_REGNUM);
  return arm_addr_bits_remove (pc);
  return arm_addr_bits_remove (pc);
}
}
 
 
static CORE_ADDR
static CORE_ADDR
arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
arm_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
{
  return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
  return frame_unwind_register_unsigned (this_frame, ARM_SP_REGNUM);
}
}
 
 
/* When arguments must be pushed onto the stack, they go on in reverse
/* When arguments must be pushed onto the stack, they go on in reverse
   order.  The code below implements a FILO (stack) to do this.  */
   order.  The code below implements a FILO (stack) to do this.  */
 
 
struct stack_item
struct stack_item
{
{
  int len;
  int len;
  struct stack_item *prev;
  struct stack_item *prev;
  void *data;
  void *data;
};
};
 
 
static struct stack_item *
static struct stack_item *
push_stack_item (struct stack_item *prev, void *contents, int len)
push_stack_item (struct stack_item *prev, void *contents, int len)
{
{
  struct stack_item *si;
  struct stack_item *si;
  si = xmalloc (sizeof (struct stack_item));
  si = xmalloc (sizeof (struct stack_item));
  si->data = xmalloc (len);
  si->data = xmalloc (len);
  si->len = len;
  si->len = len;
  si->prev = prev;
  si->prev = prev;
  memcpy (si->data, contents, len);
  memcpy (si->data, contents, len);
  return si;
  return si;
}
}
 
 
static struct stack_item *
static struct stack_item *
pop_stack_item (struct stack_item *si)
pop_stack_item (struct stack_item *si)
{
{
  struct stack_item *dead = si;
  struct stack_item *dead = si;
  si = si->prev;
  si = si->prev;
  xfree (dead->data);
  xfree (dead->data);
  xfree (dead);
  xfree (dead);
  return si;
  return si;
}
}
 
 
 
 
/* Return the alignment (in bytes) of the given type.  */
/* Return the alignment (in bytes) of the given type.  */
 
 
static int
static int
arm_type_align (struct type *t)
arm_type_align (struct type *t)
{
{
  int n;
  int n;
  int align;
  int align;
  int falign;
  int falign;
 
 
  t = check_typedef (t);
  t = check_typedef (t);
  switch (TYPE_CODE (t))
  switch (TYPE_CODE (t))
    {
    {
    default:
    default:
      /* Should never happen.  */
      /* Should never happen.  */
      internal_error (__FILE__, __LINE__, _("unknown type alignment"));
      internal_error (__FILE__, __LINE__, _("unknown type alignment"));
      return 4;
      return 4;
 
 
    case TYPE_CODE_PTR:
    case TYPE_CODE_PTR:
    case TYPE_CODE_ENUM:
    case TYPE_CODE_ENUM:
    case TYPE_CODE_INT:
    case TYPE_CODE_INT:
    case TYPE_CODE_FLT:
    case TYPE_CODE_FLT:
    case TYPE_CODE_SET:
    case TYPE_CODE_SET:
    case TYPE_CODE_RANGE:
    case TYPE_CODE_RANGE:
    case TYPE_CODE_BITSTRING:
    case TYPE_CODE_BITSTRING:
    case TYPE_CODE_REF:
    case TYPE_CODE_REF:
    case TYPE_CODE_CHAR:
    case TYPE_CODE_CHAR:
    case TYPE_CODE_BOOL:
    case TYPE_CODE_BOOL:
      return TYPE_LENGTH (t);
      return TYPE_LENGTH (t);
 
 
    case TYPE_CODE_ARRAY:
    case TYPE_CODE_ARRAY:
    case TYPE_CODE_COMPLEX:
    case TYPE_CODE_COMPLEX:
      /* TODO: What about vector types?  */
      /* TODO: What about vector types?  */
      return arm_type_align (TYPE_TARGET_TYPE (t));
      return arm_type_align (TYPE_TARGET_TYPE (t));
 
 
    case TYPE_CODE_STRUCT:
    case TYPE_CODE_STRUCT:
    case TYPE_CODE_UNION:
    case TYPE_CODE_UNION:
      align = 1;
      align = 1;
      for (n = 0; n < TYPE_NFIELDS (t); n++)
      for (n = 0; n < TYPE_NFIELDS (t); n++)
        {
        {
          falign = arm_type_align (TYPE_FIELD_TYPE (t, n));
          falign = arm_type_align (TYPE_FIELD_TYPE (t, n));
          if (falign > align)
          if (falign > align)
            align = falign;
            align = falign;
        }
        }
      return align;
      return align;
    }
    }
}
}
 
 
/* We currently only support passing parameters in integer registers.  This
/* We currently only support passing parameters in integer registers.  This
   conforms with GCC's default model.  Several other variants exist and
   conforms with GCC's default model.  Several other variants exist and
   we should probably support some of them based on the selected ABI.  */
   we should probably support some of them based on the selected ABI.  */
 
 
static CORE_ADDR
static CORE_ADDR
arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
arm_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
                     struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
                     struct value **args, CORE_ADDR sp, int struct_return,
                     struct value **args, CORE_ADDR sp, int struct_return,
                     CORE_ADDR struct_addr)
                     CORE_ADDR struct_addr)
{
{
  int argnum;
  int argnum;
  int argreg;
  int argreg;
  int nstack;
  int nstack;
  struct stack_item *si = NULL;
  struct stack_item *si = NULL;
 
 
  /* Set the return address.  For the ARM, the return breakpoint is
  /* Set the return address.  For the ARM, the return breakpoint is
     always at BP_ADDR.  */
     always at BP_ADDR.  */
  /* XXX Fix for Thumb.  */
  /* XXX Fix for Thumb.  */
  regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
  regcache_cooked_write_unsigned (regcache, ARM_LR_REGNUM, bp_addr);
 
 
  /* Walk through the list of args and determine how large a temporary
  /* Walk through the list of args and determine how large a temporary
     stack is required.  Need to take care here as structs may be
     stack is required.  Need to take care here as structs may be
     passed on the stack, and we have to to push them.  */
     passed on the stack, and we have to to push them.  */
  nstack = 0;
  nstack = 0;
 
 
  argreg = ARM_A1_REGNUM;
  argreg = ARM_A1_REGNUM;
  nstack = 0;
  nstack = 0;
 
 
  /* The struct_return pointer occupies the first parameter
  /* The struct_return pointer occupies the first parameter
     passing register.  */
     passing register.  */
  if (struct_return)
  if (struct_return)
    {
    {
      if (arm_debug)
      if (arm_debug)
        fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
        fprintf_unfiltered (gdb_stdlog, "struct return in %s = 0x%s\n",
                            gdbarch_register_name (gdbarch, argreg),
                            gdbarch_register_name (gdbarch, argreg),
                            paddr (struct_addr));
                            paddr (struct_addr));
      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
      regcache_cooked_write_unsigned (regcache, argreg, struct_addr);
      argreg++;
      argreg++;
    }
    }
 
 
  for (argnum = 0; argnum < nargs; argnum++)
  for (argnum = 0; argnum < nargs; argnum++)
    {
    {
      int len;
      int len;
      struct type *arg_type;
      struct type *arg_type;
      struct type *target_type;
      struct type *target_type;
      enum type_code typecode;
      enum type_code typecode;
      bfd_byte *val;
      bfd_byte *val;
      int align;
      int align;
 
 
      arg_type = check_typedef (value_type (args[argnum]));
      arg_type = check_typedef (value_type (args[argnum]));
      len = TYPE_LENGTH (arg_type);
      len = TYPE_LENGTH (arg_type);
      target_type = TYPE_TARGET_TYPE (arg_type);
      target_type = TYPE_TARGET_TYPE (arg_type);
      typecode = TYPE_CODE (arg_type);
      typecode = TYPE_CODE (arg_type);
      val = value_contents_writeable (args[argnum]);
      val = value_contents_writeable (args[argnum]);
 
 
      align = arm_type_align (arg_type);
      align = arm_type_align (arg_type);
      /* Round alignment up to a whole number of words.  */
      /* Round alignment up to a whole number of words.  */
      align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
      align = (align + INT_REGISTER_SIZE - 1) & ~(INT_REGISTER_SIZE - 1);
      /* Different ABIs have different maximum alignments.  */
      /* Different ABIs have different maximum alignments.  */
      if (gdbarch_tdep (gdbarch)->arm_abi == ARM_ABI_APCS)
      if (gdbarch_tdep (gdbarch)->arm_abi == ARM_ABI_APCS)
        {
        {
          /* The APCS ABI only requires word alignment.  */
          /* The APCS ABI only requires word alignment.  */
          align = INT_REGISTER_SIZE;
          align = INT_REGISTER_SIZE;
        }
        }
      else
      else
        {
        {
          /* The AAPCS requires at most doubleword alignment.  */
          /* The AAPCS requires at most doubleword alignment.  */
          if (align > INT_REGISTER_SIZE * 2)
          if (align > INT_REGISTER_SIZE * 2)
            align = INT_REGISTER_SIZE * 2;
            align = INT_REGISTER_SIZE * 2;
        }
        }
 
 
      /* Push stack padding for dowubleword alignment.  */
      /* Push stack padding for dowubleword alignment.  */
      if (nstack & (align - 1))
      if (nstack & (align - 1))
        {
        {
          si = push_stack_item (si, val, INT_REGISTER_SIZE);
          si = push_stack_item (si, val, INT_REGISTER_SIZE);
          nstack += INT_REGISTER_SIZE;
          nstack += INT_REGISTER_SIZE;
        }
        }
 
 
      /* Doubleword aligned quantities must go in even register pairs.  */
      /* Doubleword aligned quantities must go in even register pairs.  */
      if (argreg <= ARM_LAST_ARG_REGNUM
      if (argreg <= ARM_LAST_ARG_REGNUM
          && align > INT_REGISTER_SIZE
          && align > INT_REGISTER_SIZE
          && argreg & 1)
          && argreg & 1)
        argreg++;
        argreg++;
 
 
      /* If the argument is a pointer to a function, and it is a
      /* If the argument is a pointer to a function, and it is a
         Thumb function, create a LOCAL copy of the value and set
         Thumb function, create a LOCAL copy of the value and set
         the THUMB bit in it.  */
         the THUMB bit in it.  */
      if (TYPE_CODE_PTR == typecode
      if (TYPE_CODE_PTR == typecode
          && target_type != NULL
          && target_type != NULL
          && TYPE_CODE_FUNC == TYPE_CODE (target_type))
          && TYPE_CODE_FUNC == TYPE_CODE (target_type))
        {
        {
          CORE_ADDR regval = extract_unsigned_integer (val, len);
          CORE_ADDR regval = extract_unsigned_integer (val, len);
          if (arm_pc_is_thumb (regval))
          if (arm_pc_is_thumb (regval))
            {
            {
              val = alloca (len);
              val = alloca (len);
              store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
              store_unsigned_integer (val, len, MAKE_THUMB_ADDR (regval));
            }
            }
        }
        }
 
 
      /* Copy the argument to general registers or the stack in
      /* Copy the argument to general registers or the stack in
         register-sized pieces.  Large arguments are split between
         register-sized pieces.  Large arguments are split between
         registers and stack.  */
         registers and stack.  */
      while (len > 0)
      while (len > 0)
        {
        {
          int partial_len = len < INT_REGISTER_SIZE ? len : INT_REGISTER_SIZE;
          int partial_len = len < INT_REGISTER_SIZE ? len : INT_REGISTER_SIZE;
 
 
          if (argreg <= ARM_LAST_ARG_REGNUM)
          if (argreg <= ARM_LAST_ARG_REGNUM)
            {
            {
              /* The argument is being passed in a general purpose
              /* The argument is being passed in a general purpose
                 register.  */
                 register.  */
              CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
              CORE_ADDR regval = extract_unsigned_integer (val, partial_len);
              if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
              if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
                regval <<= (INT_REGISTER_SIZE - partial_len) * 8;
                regval <<= (INT_REGISTER_SIZE - partial_len) * 8;
              if (arm_debug)
              if (arm_debug)
                fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
                fprintf_unfiltered (gdb_stdlog, "arg %d in %s = 0x%s\n",
                                    argnum,
                                    argnum,
                                    gdbarch_register_name
                                    gdbarch_register_name
                                      (gdbarch, argreg),
                                      (gdbarch, argreg),
                                    phex (regval, INT_REGISTER_SIZE));
                                    phex (regval, INT_REGISTER_SIZE));
              regcache_cooked_write_unsigned (regcache, argreg, regval);
              regcache_cooked_write_unsigned (regcache, argreg, regval);
              argreg++;
              argreg++;
            }
            }
          else
          else
            {
            {
              /* Push the arguments onto the stack.  */
              /* Push the arguments onto the stack.  */
              if (arm_debug)
              if (arm_debug)
                fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
                fprintf_unfiltered (gdb_stdlog, "arg %d @ sp + %d\n",
                                    argnum, nstack);
                                    argnum, nstack);
              si = push_stack_item (si, val, INT_REGISTER_SIZE);
              si = push_stack_item (si, val, INT_REGISTER_SIZE);
              nstack += INT_REGISTER_SIZE;
              nstack += INT_REGISTER_SIZE;
            }
            }
 
 
          len -= partial_len;
          len -= partial_len;
          val += partial_len;
          val += partial_len;
        }
        }
    }
    }
  /* If we have an odd number of words to push, then decrement the stack
  /* If we have an odd number of words to push, then decrement the stack
     by one word now, so first stack argument will be dword aligned.  */
     by one word now, so first stack argument will be dword aligned.  */
  if (nstack & 4)
  if (nstack & 4)
    sp -= 4;
    sp -= 4;
 
 
  while (si)
  while (si)
    {
    {
      sp -= si->len;
      sp -= si->len;
      write_memory (sp, si->data, si->len);
      write_memory (sp, si->data, si->len);
      si = pop_stack_item (si);
      si = pop_stack_item (si);
    }
    }
 
 
  /* Finally, update teh SP register.  */
  /* Finally, update teh SP register.  */
  regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
  regcache_cooked_write_unsigned (regcache, ARM_SP_REGNUM, sp);
 
 
  return sp;
  return sp;
}
}
 
 
 
 
/* Always align the frame to an 8-byte boundary.  This is required on
/* Always align the frame to an 8-byte boundary.  This is required on
   some platforms and harmless on the rest.  */
   some platforms and harmless on the rest.  */
 
 
static CORE_ADDR
static CORE_ADDR
arm_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
arm_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
{
  /* Align the stack to eight bytes.  */
  /* Align the stack to eight bytes.  */
  return sp & ~ (CORE_ADDR) 7;
  return sp & ~ (CORE_ADDR) 7;
}
}
 
 
static void
static void
print_fpu_flags (int flags)
print_fpu_flags (int flags)
{
{
  if (flags & (1 << 0))
  if (flags & (1 << 0))
    fputs ("IVO ", stdout);
    fputs ("IVO ", stdout);
  if (flags & (1 << 1))
  if (flags & (1 << 1))
    fputs ("DVZ ", stdout);
    fputs ("DVZ ", stdout);
  if (flags & (1 << 2))
  if (flags & (1 << 2))
    fputs ("OFL ", stdout);
    fputs ("OFL ", stdout);
  if (flags & (1 << 3))
  if (flags & (1 << 3))
    fputs ("UFL ", stdout);
    fputs ("UFL ", stdout);
  if (flags & (1 << 4))
  if (flags & (1 << 4))
    fputs ("INX ", stdout);
    fputs ("INX ", stdout);
  putchar ('\n');
  putchar ('\n');
}
}
 
 
/* Print interesting information about the floating point processor
/* Print interesting information about the floating point processor
   (if present) or emulator.  */
   (if present) or emulator.  */
static void
static void
arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
arm_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
                      struct frame_info *frame, const char *args)
                      struct frame_info *frame, const char *args)
{
{
  unsigned long status = get_frame_register_unsigned (frame, ARM_FPS_REGNUM);
  unsigned long status = get_frame_register_unsigned (frame, ARM_FPS_REGNUM);
  int type;
  int type;
 
 
  type = (status >> 24) & 127;
  type = (status >> 24) & 127;
  if (status & (1 << 31))
  if (status & (1 << 31))
    printf (_("Hardware FPU type %d\n"), type);
    printf (_("Hardware FPU type %d\n"), type);
  else
  else
    printf (_("Software FPU type %d\n"), type);
    printf (_("Software FPU type %d\n"), type);
  /* i18n: [floating point unit] mask */
  /* i18n: [floating point unit] mask */
  fputs (_("mask: "), stdout);
  fputs (_("mask: "), stdout);
  print_fpu_flags (status >> 16);
  print_fpu_flags (status >> 16);
  /* i18n: [floating point unit] flags */
  /* i18n: [floating point unit] flags */
  fputs (_("flags: "), stdout);
  fputs (_("flags: "), stdout);
  print_fpu_flags (status);
  print_fpu_flags (status);
}
}
 
 
/* Return the GDB type object for the "standard" data type of data in
/* Return the GDB type object for the "standard" data type of data in
   register N.  */
   register N.  */
 
 
static struct type *
static struct type *
arm_register_type (struct gdbarch *gdbarch, int regnum)
arm_register_type (struct gdbarch *gdbarch, int regnum)
{
{
  if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
  if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
    return builtin_type_arm_ext;
    return builtin_type_arm_ext;
  else if (regnum == ARM_SP_REGNUM)
  else if (regnum == ARM_SP_REGNUM)
    return builtin_type_void_data_ptr;
    return builtin_type_void_data_ptr;
  else if (regnum == ARM_PC_REGNUM)
  else if (regnum == ARM_PC_REGNUM)
    return builtin_type_void_func_ptr;
    return builtin_type_void_func_ptr;
  else if (regnum >= ARRAY_SIZE (arm_register_names))
  else if (regnum >= ARRAY_SIZE (arm_register_names))
    /* These registers are only supported on targets which supply
    /* These registers are only supported on targets which supply
       an XML description.  */
       an XML description.  */
    return builtin_type_int0;
    return builtin_type_int0;
  else
  else
    return builtin_type_uint32;
    return builtin_type_uint32;
}
}
 
 
/* Map a DWARF register REGNUM onto the appropriate GDB register
/* Map a DWARF register REGNUM onto the appropriate GDB register
   number.  */
   number.  */
 
 
static int
static int
arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
arm_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
{
  /* Core integer regs.  */
  /* Core integer regs.  */
  if (reg >= 0 && reg <= 15)
  if (reg >= 0 && reg <= 15)
    return reg;
    return reg;
 
 
  /* Legacy FPA encoding.  These were once used in a way which
  /* Legacy FPA encoding.  These were once used in a way which
     overlapped with VFP register numbering, so their use is
     overlapped with VFP register numbering, so their use is
     discouraged, but GDB doesn't support the ARM toolchain
     discouraged, but GDB doesn't support the ARM toolchain
     which used them for VFP.  */
     which used them for VFP.  */
  if (reg >= 16 && reg <= 23)
  if (reg >= 16 && reg <= 23)
    return ARM_F0_REGNUM + reg - 16;
    return ARM_F0_REGNUM + reg - 16;
 
 
  /* New assignments for the FPA registers.  */
  /* New assignments for the FPA registers.  */
  if (reg >= 96 && reg <= 103)
  if (reg >= 96 && reg <= 103)
    return ARM_F0_REGNUM + reg - 96;
    return ARM_F0_REGNUM + reg - 96;
 
 
  /* WMMX register assignments.  */
  /* WMMX register assignments.  */
  if (reg >= 104 && reg <= 111)
  if (reg >= 104 && reg <= 111)
    return ARM_WCGR0_REGNUM + reg - 104;
    return ARM_WCGR0_REGNUM + reg - 104;
 
 
  if (reg >= 112 && reg <= 127)
  if (reg >= 112 && reg <= 127)
    return ARM_WR0_REGNUM + reg - 112;
    return ARM_WR0_REGNUM + reg - 112;
 
 
  if (reg >= 192 && reg <= 199)
  if (reg >= 192 && reg <= 199)
    return ARM_WC0_REGNUM + reg - 192;
    return ARM_WC0_REGNUM + reg - 192;
 
 
  return -1;
  return -1;
}
}
 
 
/* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
/* Map GDB internal REGNUM onto the Arm simulator register numbers.  */
static int
static int
arm_register_sim_regno (struct gdbarch *gdbarch, int regnum)
arm_register_sim_regno (struct gdbarch *gdbarch, int regnum)
{
{
  int reg = regnum;
  int reg = regnum;
  gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch));
  gdb_assert (reg >= 0 && reg < gdbarch_num_regs (gdbarch));
 
 
  if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM)
  if (regnum >= ARM_WR0_REGNUM && regnum <= ARM_WR15_REGNUM)
    return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM;
    return regnum - ARM_WR0_REGNUM + SIM_ARM_IWMMXT_COP0R0_REGNUM;
 
 
  if (regnum >= ARM_WC0_REGNUM && regnum <= ARM_WC7_REGNUM)
  if (regnum >= ARM_WC0_REGNUM && regnum <= ARM_WC7_REGNUM)
    return regnum - ARM_WC0_REGNUM + SIM_ARM_IWMMXT_COP1R0_REGNUM;
    return regnum - ARM_WC0_REGNUM + SIM_ARM_IWMMXT_COP1R0_REGNUM;
 
 
  if (regnum >= ARM_WCGR0_REGNUM && regnum <= ARM_WCGR7_REGNUM)
  if (regnum >= ARM_WCGR0_REGNUM && regnum <= ARM_WCGR7_REGNUM)
    return regnum - ARM_WCGR0_REGNUM + SIM_ARM_IWMMXT_COP1R8_REGNUM;
    return regnum - ARM_WCGR0_REGNUM + SIM_ARM_IWMMXT_COP1R8_REGNUM;
 
 
  if (reg < NUM_GREGS)
  if (reg < NUM_GREGS)
    return SIM_ARM_R0_REGNUM + reg;
    return SIM_ARM_R0_REGNUM + reg;
  reg -= NUM_GREGS;
  reg -= NUM_GREGS;
 
 
  if (reg < NUM_FREGS)
  if (reg < NUM_FREGS)
    return SIM_ARM_FP0_REGNUM + reg;
    return SIM_ARM_FP0_REGNUM + reg;
  reg -= NUM_FREGS;
  reg -= NUM_FREGS;
 
 
  if (reg < NUM_SREGS)
  if (reg < NUM_SREGS)
    return SIM_ARM_FPS_REGNUM + reg;
    return SIM_ARM_FPS_REGNUM + reg;
  reg -= NUM_SREGS;
  reg -= NUM_SREGS;
 
 
  internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
  internal_error (__FILE__, __LINE__, _("Bad REGNUM %d"), regnum);
}
}
 
 
/* NOTE: cagney/2001-08-20: Both convert_from_extended() and
/* NOTE: cagney/2001-08-20: Both convert_from_extended() and
   convert_to_extended() use floatformat_arm_ext_littlebyte_bigword.
   convert_to_extended() use floatformat_arm_ext_littlebyte_bigword.
   It is thought that this is is the floating-point register format on
   It is thought that this is is the floating-point register format on
   little-endian systems.  */
   little-endian systems.  */
 
 
static void
static void
convert_from_extended (const struct floatformat *fmt, const void *ptr,
convert_from_extended (const struct floatformat *fmt, const void *ptr,
                       void *dbl, int endianess)
                       void *dbl, int endianess)
{
{
  DOUBLEST d;
  DOUBLEST d;
 
 
  if (endianess == BFD_ENDIAN_BIG)
  if (endianess == BFD_ENDIAN_BIG)
    floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
    floatformat_to_doublest (&floatformat_arm_ext_big, ptr, &d);
  else
  else
    floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
    floatformat_to_doublest (&floatformat_arm_ext_littlebyte_bigword,
                             ptr, &d);
                             ptr, &d);
  floatformat_from_doublest (fmt, &d, dbl);
  floatformat_from_doublest (fmt, &d, dbl);
}
}
 
 
static void
static void
convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
                     int endianess)
                     int endianess)
{
{
  DOUBLEST d;
  DOUBLEST d;
 
 
  floatformat_to_doublest (fmt, ptr, &d);
  floatformat_to_doublest (fmt, ptr, &d);
  if (endianess == BFD_ENDIAN_BIG)
  if (endianess == BFD_ENDIAN_BIG)
    floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
    floatformat_from_doublest (&floatformat_arm_ext_big, &d, dbl);
  else
  else
    floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
    floatformat_from_doublest (&floatformat_arm_ext_littlebyte_bigword,
                               &d, dbl);
                               &d, dbl);
}
}
 
 
static int
static int
condition_true (unsigned long cond, unsigned long status_reg)
condition_true (unsigned long cond, unsigned long status_reg)
{
{
  if (cond == INST_AL || cond == INST_NV)
  if (cond == INST_AL || cond == INST_NV)
    return 1;
    return 1;
 
 
  switch (cond)
  switch (cond)
    {
    {
    case INST_EQ:
    case INST_EQ:
      return ((status_reg & FLAG_Z) != 0);
      return ((status_reg & FLAG_Z) != 0);
    case INST_NE:
    case INST_NE:
      return ((status_reg & FLAG_Z) == 0);
      return ((status_reg & FLAG_Z) == 0);
    case INST_CS:
    case INST_CS:
      return ((status_reg & FLAG_C) != 0);
      return ((status_reg & FLAG_C) != 0);
    case INST_CC:
    case INST_CC:
      return ((status_reg & FLAG_C) == 0);
      return ((status_reg & FLAG_C) == 0);
    case INST_MI:
    case INST_MI:
      return ((status_reg & FLAG_N) != 0);
      return ((status_reg & FLAG_N) != 0);
    case INST_PL:
    case INST_PL:
      return ((status_reg & FLAG_N) == 0);
      return ((status_reg & FLAG_N) == 0);
    case INST_VS:
    case INST_VS:
      return ((status_reg & FLAG_V) != 0);
      return ((status_reg & FLAG_V) != 0);
    case INST_VC:
    case INST_VC:
      return ((status_reg & FLAG_V) == 0);
      return ((status_reg & FLAG_V) == 0);
    case INST_HI:
    case INST_HI:
      return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C);
      return ((status_reg & (FLAG_C | FLAG_Z)) == FLAG_C);
    case INST_LS:
    case INST_LS:
      return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
      return ((status_reg & (FLAG_C | FLAG_Z)) != FLAG_C);
    case INST_GE:
    case INST_GE:
      return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
      return (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0));
    case INST_LT:
    case INST_LT:
      return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0));
      return (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0));
    case INST_GT:
    case INST_GT:
      return (((status_reg & FLAG_Z) == 0) &&
      return (((status_reg & FLAG_Z) == 0) &&
              (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)));
              (((status_reg & FLAG_N) == 0) == ((status_reg & FLAG_V) == 0)));
    case INST_LE:
    case INST_LE:
      return (((status_reg & FLAG_Z) != 0) ||
      return (((status_reg & FLAG_Z) != 0) ||
              (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0)));
              (((status_reg & FLAG_N) == 0) != ((status_reg & FLAG_V) == 0)));
    }
    }
  return 1;
  return 1;
}
}
 
 
/* Support routines for single stepping.  Calculate the next PC value.  */
/* Support routines for single stepping.  Calculate the next PC value.  */
#define submask(x) ((1L << ((x) + 1)) - 1)
#define submask(x) ((1L << ((x) + 1)) - 1)
#define bit(obj,st) (((obj) >> (st)) & 1)
#define bit(obj,st) (((obj) >> (st)) & 1)
#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
#define bits(obj,st,fn) (((obj) >> (st)) & submask ((fn) - (st)))
#define sbits(obj,st,fn) \
#define sbits(obj,st,fn) \
  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
  ((long) (bits(obj,st,fn) | ((long) bit(obj,fn) * ~ submask (fn - st))))
#define BranchDest(addr,instr) \
#define BranchDest(addr,instr) \
  ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
  ((CORE_ADDR) (((long) (addr)) + 8 + (sbits (instr, 0, 23) << 2)))
#define ARM_PC_32 1
#define ARM_PC_32 1
 
 
static unsigned long
static unsigned long
shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
                 unsigned long pc_val, unsigned long status_reg)
                 unsigned long pc_val, unsigned long status_reg)
{
{
  unsigned long res, shift;
  unsigned long res, shift;
  int rm = bits (inst, 0, 3);
  int rm = bits (inst, 0, 3);
  unsigned long shifttype = bits (inst, 5, 6);
  unsigned long shifttype = bits (inst, 5, 6);
 
 
  if (bit (inst, 4))
  if (bit (inst, 4))
    {
    {
      int rs = bits (inst, 8, 11);
      int rs = bits (inst, 8, 11);
      shift = (rs == 15 ? pc_val + 8
      shift = (rs == 15 ? pc_val + 8
                        : get_frame_register_unsigned (frame, rs)) & 0xFF;
                        : get_frame_register_unsigned (frame, rs)) & 0xFF;
    }
    }
  else
  else
    shift = bits (inst, 7, 11);
    shift = bits (inst, 7, 11);
 
 
  res = (rm == 15
  res = (rm == 15
         ? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
         ? ((pc_val | (ARM_PC_32 ? 0 : status_reg))
            + (bit (inst, 4) ? 12 : 8))
            + (bit (inst, 4) ? 12 : 8))
         : get_frame_register_unsigned (frame, rm));
         : get_frame_register_unsigned (frame, rm));
 
 
  switch (shifttype)
  switch (shifttype)
    {
    {
    case 0:                      /* LSL */
    case 0:                      /* LSL */
      res = shift >= 32 ? 0 : res << shift;
      res = shift >= 32 ? 0 : res << shift;
      break;
      break;
 
 
    case 1:                     /* LSR */
    case 1:                     /* LSR */
      res = shift >= 32 ? 0 : res >> shift;
      res = shift >= 32 ? 0 : res >> shift;
      break;
      break;
 
 
    case 2:                     /* ASR */
    case 2:                     /* ASR */
      if (shift >= 32)
      if (shift >= 32)
        shift = 31;
        shift = 31;
      res = ((res & 0x80000000L)
      res = ((res & 0x80000000L)
             ? ~((~res) >> shift) : res >> shift);
             ? ~((~res) >> shift) : res >> shift);
      break;
      break;
 
 
    case 3:                     /* ROR/RRX */
    case 3:                     /* ROR/RRX */
      shift &= 31;
      shift &= 31;
      if (shift == 0)
      if (shift == 0)
        res = (res >> 1) | (carry ? 0x80000000L : 0);
        res = (res >> 1) | (carry ? 0x80000000L : 0);
      else
      else
        res = (res >> shift) | (res << (32 - shift));
        res = (res >> shift) | (res << (32 - shift));
      break;
      break;
    }
    }
 
 
  return res & 0xffffffff;
  return res & 0xffffffff;
}
}
 
 
/* Return number of 1-bits in VAL.  */
/* Return number of 1-bits in VAL.  */
 
 
static int
static int
bitcount (unsigned long val)
bitcount (unsigned long val)
{
{
  int nbits;
  int nbits;
  for (nbits = 0; val != 0; nbits++)
  for (nbits = 0; val != 0; nbits++)
    val &= val - 1;             /* delete rightmost 1-bit in val */
    val &= val - 1;             /* delete rightmost 1-bit in val */
  return nbits;
  return nbits;
}
}
 
 
static CORE_ADDR
static CORE_ADDR
thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
thumb_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
{
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  unsigned long pc_val = ((unsigned long) pc) + 4;      /* PC after prefetch */
  unsigned long pc_val = ((unsigned long) pc) + 4;      /* PC after prefetch */
  unsigned short inst1 = read_memory_unsigned_integer (pc, 2);
  unsigned short inst1 = read_memory_unsigned_integer (pc, 2);
  CORE_ADDR nextpc = pc + 2;            /* default is next instruction */
  CORE_ADDR nextpc = pc + 2;            /* default is next instruction */
  unsigned long offset;
  unsigned long offset;
 
 
  if ((inst1 & 0xff00) == 0xbd00)       /* pop {rlist, pc} */
  if ((inst1 & 0xff00) == 0xbd00)       /* pop {rlist, pc} */
    {
    {
      CORE_ADDR sp;
      CORE_ADDR sp;
 
 
      /* Fetch the saved PC from the stack.  It's stored above
      /* Fetch the saved PC from the stack.  It's stored above
         all of the other registers.  */
         all of the other registers.  */
      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
      offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
      sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
      sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
      nextpc = (CORE_ADDR) read_memory_unsigned_integer (sp + offset, 4);
      nextpc = (CORE_ADDR) read_memory_unsigned_integer (sp + offset, 4);
      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
      if (nextpc == pc)
      if (nextpc == pc)
        error (_("Infinite loop detected"));
        error (_("Infinite loop detected"));
    }
    }
  else if ((inst1 & 0xf000) == 0xd000)  /* conditional branch */
  else if ((inst1 & 0xf000) == 0xd000)  /* conditional branch */
    {
    {
      unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
      unsigned long status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
      unsigned long cond = bits (inst1, 8, 11);
      unsigned long cond = bits (inst1, 8, 11);
      if (cond != 0x0f && condition_true (cond, status))    /* 0x0f = SWI */
      if (cond != 0x0f && condition_true (cond, status))    /* 0x0f = SWI */
        nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
        nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
    }
    }
  else if ((inst1 & 0xf800) == 0xe000)  /* unconditional branch */
  else if ((inst1 & 0xf800) == 0xe000)  /* unconditional branch */
    {
    {
      nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
      nextpc = pc_val + (sbits (inst1, 0, 10) << 1);
    }
    }
  else if ((inst1 & 0xf800) == 0xf000)  /* long branch with link, and blx */
  else if ((inst1 & 0xf800) == 0xf000)  /* long branch with link, and blx */
    {
    {
      unsigned short inst2 = read_memory_unsigned_integer (pc + 2, 2);
      unsigned short inst2 = read_memory_unsigned_integer (pc + 2, 2);
      offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
      offset = (sbits (inst1, 0, 10) << 12) + (bits (inst2, 0, 10) << 1);
      nextpc = pc_val + offset;
      nextpc = pc_val + offset;
      /* For BLX make sure to clear the low bits.  */
      /* For BLX make sure to clear the low bits.  */
      if (bits (inst2, 11, 12) == 1)
      if (bits (inst2, 11, 12) == 1)
        nextpc = nextpc & 0xfffffffc;
        nextpc = nextpc & 0xfffffffc;
    }
    }
  else if ((inst1 & 0xff00) == 0x4700)  /* bx REG, blx REG */
  else if ((inst1 & 0xff00) == 0x4700)  /* bx REG, blx REG */
    {
    {
      if (bits (inst1, 3, 6) == 0x0f)
      if (bits (inst1, 3, 6) == 0x0f)
        nextpc = pc_val;
        nextpc = pc_val;
      else
      else
        nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
        nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
 
 
      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
      nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
      if (nextpc == pc)
      if (nextpc == pc)
        error (_("Infinite loop detected"));
        error (_("Infinite loop detected"));
    }
    }
 
 
  return nextpc;
  return nextpc;
}
}
 
 
CORE_ADDR
CORE_ADDR
arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
{
{
  struct gdbarch *gdbarch = get_frame_arch (frame);
  struct gdbarch *gdbarch = get_frame_arch (frame);
  unsigned long pc_val;
  unsigned long pc_val;
  unsigned long this_instr;
  unsigned long this_instr;
  unsigned long status;
  unsigned long status;
  CORE_ADDR nextpc;
  CORE_ADDR nextpc;
 
 
  if (arm_pc_is_thumb (pc))
  if (arm_pc_is_thumb (pc))
    return thumb_get_next_pc (frame, pc);
    return thumb_get_next_pc (frame, pc);
 
 
  pc_val = (unsigned long) pc;
  pc_val = (unsigned long) pc;
  this_instr = read_memory_unsigned_integer (pc, 4);
  this_instr = read_memory_unsigned_integer (pc, 4);
  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
  status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
  nextpc = (CORE_ADDR) (pc_val + 4);    /* Default case */
  nextpc = (CORE_ADDR) (pc_val + 4);    /* Default case */
 
 
  if (bits (this_instr, 28, 31) == INST_NV)
  if (bits (this_instr, 28, 31) == INST_NV)
    switch (bits (this_instr, 24, 27))
    switch (bits (this_instr, 24, 27))
      {
      {
      case 0xa:
      case 0xa:
      case 0xb:
      case 0xb:
        {
        {
          /* Branch with Link and change to Thumb.  */
          /* Branch with Link and change to Thumb.  */
          nextpc = BranchDest (pc, this_instr);
          nextpc = BranchDest (pc, this_instr);
          nextpc |= bit (this_instr, 24) << 1;
          nextpc |= bit (this_instr, 24) << 1;
 
 
          nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
          nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
          if (nextpc == pc)
          if (nextpc == pc)
            error (_("Infinite loop detected"));
            error (_("Infinite loop detected"));
          break;
          break;
        }
        }
      case 0xc:
      case 0xc:
      case 0xd:
      case 0xd:
      case 0xe:
      case 0xe:
        /* Coprocessor register transfer.  */
        /* Coprocessor register transfer.  */
        if (bits (this_instr, 12, 15) == 15)
        if (bits (this_instr, 12, 15) == 15)
          error (_("Invalid update to pc in instruction"));
          error (_("Invalid update to pc in instruction"));
        break;
        break;
      }
      }
  else if (condition_true (bits (this_instr, 28, 31), status))
  else if (condition_true (bits (this_instr, 28, 31), status))
    {
    {
      switch (bits (this_instr, 24, 27))
      switch (bits (this_instr, 24, 27))
        {
        {
        case 0x0:
        case 0x0:
        case 0x1:                       /* data processing */
        case 0x1:                       /* data processing */
        case 0x2:
        case 0x2:
        case 0x3:
        case 0x3:
          {
          {
            unsigned long operand1, operand2, result = 0;
            unsigned long operand1, operand2, result = 0;
            unsigned long rn;
            unsigned long rn;
            int c;
            int c;
 
 
            if (bits (this_instr, 12, 15) != 15)
            if (bits (this_instr, 12, 15) != 15)
              break;
              break;
 
 
            if (bits (this_instr, 22, 25) == 0
            if (bits (this_instr, 22, 25) == 0
                && bits (this_instr, 4, 7) == 9)        /* multiply */
                && bits (this_instr, 4, 7) == 9)        /* multiply */
              error (_("Invalid update to pc in instruction"));
              error (_("Invalid update to pc in instruction"));
 
 
            /* BX <reg>, BLX <reg> */
            /* BX <reg>, BLX <reg> */
            if (bits (this_instr, 4, 27) == 0x12fff1
            if (bits (this_instr, 4, 27) == 0x12fff1
                || bits (this_instr, 4, 27) == 0x12fff3)
                || bits (this_instr, 4, 27) == 0x12fff3)
              {
              {
                rn = bits (this_instr, 0, 3);
                rn = bits (this_instr, 0, 3);
                result = (rn == 15) ? pc_val + 8
                result = (rn == 15) ? pc_val + 8
                                    : get_frame_register_unsigned (frame, rn);
                                    : get_frame_register_unsigned (frame, rn);
                nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
                nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
                                       (gdbarch, result);
                                       (gdbarch, result);
 
 
                if (nextpc == pc)
                if (nextpc == pc)
                  error (_("Infinite loop detected"));
                  error (_("Infinite loop detected"));
 
 
                return nextpc;
                return nextpc;
              }
              }
 
 
            /* Multiply into PC */
            /* Multiply into PC */
            c = (status & FLAG_C) ? 1 : 0;
            c = (status & FLAG_C) ? 1 : 0;
            rn = bits (this_instr, 16, 19);
            rn = bits (this_instr, 16, 19);
            operand1 = (rn == 15) ? pc_val + 8
            operand1 = (rn == 15) ? pc_val + 8
                                  : get_frame_register_unsigned (frame, rn);
                                  : get_frame_register_unsigned (frame, rn);
 
 
            if (bit (this_instr, 25))
            if (bit (this_instr, 25))
              {
              {
                unsigned long immval = bits (this_instr, 0, 7);
                unsigned long immval = bits (this_instr, 0, 7);
                unsigned long rotate = 2 * bits (this_instr, 8, 11);
                unsigned long rotate = 2 * bits (this_instr, 8, 11);
                operand2 = ((immval >> rotate) | (immval << (32 - rotate)))
                operand2 = ((immval >> rotate) | (immval << (32 - rotate)))
                  & 0xffffffff;
                  & 0xffffffff;
              }
              }
            else                /* operand 2 is a shifted register */
            else                /* operand 2 is a shifted register */
              operand2 = shifted_reg_val (frame, this_instr, c, pc_val, status);
              operand2 = shifted_reg_val (frame, this_instr, c, pc_val, status);
 
 
            switch (bits (this_instr, 21, 24))
            switch (bits (this_instr, 21, 24))
              {
              {
              case 0x0: /*and */
              case 0x0: /*and */
                result = operand1 & operand2;
                result = operand1 & operand2;
                break;
                break;
 
 
              case 0x1: /*eor */
              case 0x1: /*eor */
                result = operand1 ^ operand2;
                result = operand1 ^ operand2;
                break;
                break;
 
 
              case 0x2: /*sub */
              case 0x2: /*sub */
                result = operand1 - operand2;
                result = operand1 - operand2;
                break;
                break;
 
 
              case 0x3: /*rsb */
              case 0x3: /*rsb */
                result = operand2 - operand1;
                result = operand2 - operand1;
                break;
                break;
 
 
              case 0x4: /*add */
              case 0x4: /*add */
                result = operand1 + operand2;
                result = operand1 + operand2;
                break;
                break;
 
 
              case 0x5: /*adc */
              case 0x5: /*adc */
                result = operand1 + operand2 + c;
                result = operand1 + operand2 + c;
                break;
                break;
 
 
              case 0x6: /*sbc */
              case 0x6: /*sbc */
                result = operand1 - operand2 + c;
                result = operand1 - operand2 + c;
                break;
                break;
 
 
              case 0x7: /*rsc */
              case 0x7: /*rsc */
                result = operand2 - operand1 + c;
                result = operand2 - operand1 + c;
                break;
                break;
 
 
              case 0x8:
              case 0x8:
              case 0x9:
              case 0x9:
              case 0xa:
              case 0xa:
              case 0xb: /* tst, teq, cmp, cmn */
              case 0xb: /* tst, teq, cmp, cmn */
                result = (unsigned long) nextpc;
                result = (unsigned long) nextpc;
                break;
                break;
 
 
              case 0xc: /*orr */
              case 0xc: /*orr */
                result = operand1 | operand2;
                result = operand1 | operand2;
                break;
                break;
 
 
              case 0xd: /*mov */
              case 0xd: /*mov */
                /* Always step into a function.  */
                /* Always step into a function.  */
                result = operand2;
                result = operand2;
                break;
                break;
 
 
              case 0xe: /*bic */
              case 0xe: /*bic */
                result = operand1 & ~operand2;
                result = operand1 & ~operand2;
                break;
                break;
 
 
              case 0xf: /*mvn */
              case 0xf: /*mvn */
                result = ~operand2;
                result = ~operand2;
                break;
                break;
              }
              }
            nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
            nextpc = (CORE_ADDR) gdbarch_addr_bits_remove
                                   (gdbarch, result);
                                   (gdbarch, result);
 
 
            if (nextpc == pc)
            if (nextpc == pc)
              error (_("Infinite loop detected"));
              error (_("Infinite loop detected"));
            break;
            break;
          }
          }
 
 
        case 0x4:
        case 0x4:
        case 0x5:               /* data transfer */
        case 0x5:               /* data transfer */
        case 0x6:
        case 0x6:
        case 0x7:
        case 0x7:
          if (bit (this_instr, 20))
          if (bit (this_instr, 20))
            {
            {
              /* load */
              /* load */
              if (bits (this_instr, 12, 15) == 15)
              if (bits (this_instr, 12, 15) == 15)
                {
                {
                  /* rd == pc */
                  /* rd == pc */
                  unsigned long rn;
                  unsigned long rn;
                  unsigned long base;
                  unsigned long base;
 
 
                  if (bit (this_instr, 22))
                  if (bit (this_instr, 22))
                    error (_("Invalid update to pc in instruction"));
                    error (_("Invalid update to pc in instruction"));
 
 
                  /* byte write to PC */
                  /* byte write to PC */
                  rn = bits (this_instr, 16, 19);
                  rn = bits (this_instr, 16, 19);
                  base = (rn == 15) ? pc_val + 8
                  base = (rn == 15) ? pc_val + 8
                                    : get_frame_register_unsigned (frame, rn);
                                    : get_frame_register_unsigned (frame, rn);
                  if (bit (this_instr, 24))
                  if (bit (this_instr, 24))
                    {
                    {
                      /* pre-indexed */
                      /* pre-indexed */
                      int c = (status & FLAG_C) ? 1 : 0;
                      int c = (status & FLAG_C) ? 1 : 0;
                      unsigned long offset =
                      unsigned long offset =
                      (bit (this_instr, 25)
                      (bit (this_instr, 25)
                       ? shifted_reg_val (frame, this_instr, c, pc_val, status)
                       ? shifted_reg_val (frame, this_instr, c, pc_val, status)
                       : bits (this_instr, 0, 11));
                       : bits (this_instr, 0, 11));
 
 
                      if (bit (this_instr, 23))
                      if (bit (this_instr, 23))
                        base += offset;
                        base += offset;
                      else
                      else
                        base -= offset;
                        base -= offset;
                    }
                    }
                  nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
                  nextpc = (CORE_ADDR) read_memory_integer ((CORE_ADDR) base,
                                                            4);
                                                            4);
 
 
                  nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
                  nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
 
 
                  if (nextpc == pc)
                  if (nextpc == pc)
                    error (_("Infinite loop detected"));
                    error (_("Infinite loop detected"));
                }
                }
            }
            }
          break;
          break;
 
 
        case 0x8:
        case 0x8:
        case 0x9:               /* block transfer */
        case 0x9:               /* block transfer */
          if (bit (this_instr, 20))
          if (bit (this_instr, 20))
            {
            {
              /* LDM */
              /* LDM */
              if (bit (this_instr, 15))
              if (bit (this_instr, 15))
                {
                {
                  /* loading pc */
                  /* loading pc */
                  int offset = 0;
                  int offset = 0;
 
 
                  if (bit (this_instr, 23))
                  if (bit (this_instr, 23))
                    {
                    {
                      /* up */
                      /* up */
                      unsigned long reglist = bits (this_instr, 0, 14);
                      unsigned long reglist = bits (this_instr, 0, 14);
                      offset = bitcount (reglist) * 4;
                      offset = bitcount (reglist) * 4;
                      if (bit (this_instr, 24))         /* pre */
                      if (bit (this_instr, 24))         /* pre */
                        offset += 4;
                        offset += 4;
                    }
                    }
                  else if (bit (this_instr, 24))
                  else if (bit (this_instr, 24))
                    offset = -4;
                    offset = -4;
 
 
                  {
                  {
                    unsigned long rn_val =
                    unsigned long rn_val =
                    get_frame_register_unsigned (frame,
                    get_frame_register_unsigned (frame,
                                                 bits (this_instr, 16, 19));
                                                 bits (this_instr, 16, 19));
                    nextpc =
                    nextpc =
                      (CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val
                      (CORE_ADDR) read_memory_integer ((CORE_ADDR) (rn_val
                                                                  + offset),
                                                                  + offset),
                                                       4);
                                                       4);
                  }
                  }
                  nextpc = gdbarch_addr_bits_remove
                  nextpc = gdbarch_addr_bits_remove
                             (gdbarch, nextpc);
                             (gdbarch, nextpc);
                  if (nextpc == pc)
                  if (nextpc == pc)
                    error (_("Infinite loop detected"));
                    error (_("Infinite loop detected"));
                }
                }
            }
            }
          break;
          break;
 
 
        case 0xb:               /* branch & link */
        case 0xb:               /* branch & link */
        case 0xa:               /* branch */
        case 0xa:               /* branch */
          {
          {
            nextpc = BranchDest (pc, this_instr);
            nextpc = BranchDest (pc, this_instr);
 
 
            nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
            nextpc = gdbarch_addr_bits_remove (gdbarch, nextpc);
            if (nextpc == pc)
            if (nextpc == pc)
              error (_("Infinite loop detected"));
              error (_("Infinite loop detected"));
            break;
            break;
          }
          }
 
 
        case 0xc:
        case 0xc:
        case 0xd:
        case 0xd:
        case 0xe:               /* coproc ops */
        case 0xe:               /* coproc ops */
        case 0xf:               /* SWI */
        case 0xf:               /* SWI */
          break;
          break;
 
 
        default:
        default:
          fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n"));
          fprintf_filtered (gdb_stderr, _("Bad bit-field extraction\n"));
          return (pc);
          return (pc);
        }
        }
    }
    }
 
 
  return nextpc;
  return nextpc;
}
}
 
 
/* single_step() is called just before we want to resume the inferior,
/* single_step() is called just before we want to resume the inferior,
   if we want to single-step it but there is no hardware or kernel
   if we want to single-step it but there is no hardware or kernel
   single-step support.  We find the target of the coming instruction
   single-step support.  We find the target of the coming instruction
   and breakpoint it.  */
   and breakpoint it.  */
 
 
int
int
arm_software_single_step (struct frame_info *frame)
arm_software_single_step (struct frame_info *frame)
{
{
  /* NOTE: This may insert the wrong breakpoint instruction when
  /* NOTE: This may insert the wrong breakpoint instruction when
     single-stepping over a mode-changing instruction, if the
     single-stepping over a mode-changing instruction, if the
     CPSR heuristics are used.  */
     CPSR heuristics are used.  */
 
 
  CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
  CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
  insert_single_step_breakpoint (next_pc);
  insert_single_step_breakpoint (next_pc);
 
 
  return 1;
  return 1;
}
}
 
 
#include "bfd-in2.h"
#include "bfd-in2.h"
#include "libcoff.h"
#include "libcoff.h"
 
 
static int
static int
gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
gdb_print_insn_arm (bfd_vma memaddr, disassemble_info *info)
{
{
  if (arm_pc_is_thumb (memaddr))
  if (arm_pc_is_thumb (memaddr))
    {
    {
      static asymbol *asym;
      static asymbol *asym;
      static combined_entry_type ce;
      static combined_entry_type ce;
      static struct coff_symbol_struct csym;
      static struct coff_symbol_struct csym;
      static struct bfd fake_bfd;
      static struct bfd fake_bfd;
      static bfd_target fake_target;
      static bfd_target fake_target;
 
 
      if (csym.native == NULL)
      if (csym.native == NULL)
        {
        {
          /* Create a fake symbol vector containing a Thumb symbol.
          /* Create a fake symbol vector containing a Thumb symbol.
             This is solely so that the code in print_insn_little_arm()
             This is solely so that the code in print_insn_little_arm()
             and print_insn_big_arm() in opcodes/arm-dis.c will detect
             and print_insn_big_arm() in opcodes/arm-dis.c will detect
             the presence of a Thumb symbol and switch to decoding
             the presence of a Thumb symbol and switch to decoding
             Thumb instructions.  */
             Thumb instructions.  */
 
 
          fake_target.flavour = bfd_target_coff_flavour;
          fake_target.flavour = bfd_target_coff_flavour;
          fake_bfd.xvec = &fake_target;
          fake_bfd.xvec = &fake_target;
          ce.u.syment.n_sclass = C_THUMBEXTFUNC;
          ce.u.syment.n_sclass = C_THUMBEXTFUNC;
          csym.native = &ce;
          csym.native = &ce;
          csym.symbol.the_bfd = &fake_bfd;
          csym.symbol.the_bfd = &fake_bfd;
          csym.symbol.name = "fake";
          csym.symbol.name = "fake";
          asym = (asymbol *) & csym;
          asym = (asymbol *) & csym;
        }
        }
 
 
      memaddr = UNMAKE_THUMB_ADDR (memaddr);
      memaddr = UNMAKE_THUMB_ADDR (memaddr);
      info->symbols = &asym;
      info->symbols = &asym;
    }
    }
  else
  else
    info->symbols = NULL;
    info->symbols = NULL;
 
 
  if (info->endian == BFD_ENDIAN_BIG)
  if (info->endian == BFD_ENDIAN_BIG)
    return print_insn_big_arm (memaddr, info);
    return print_insn_big_arm (memaddr, info);
  else
  else
    return print_insn_little_arm (memaddr, info);
    return print_insn_little_arm (memaddr, info);
}
}
 
 
/* The following define instruction sequences that will cause ARM
/* The following define instruction sequences that will cause ARM
   cpu's to take an undefined instruction trap.  These are used to
   cpu's to take an undefined instruction trap.  These are used to
   signal a breakpoint to GDB.
   signal a breakpoint to GDB.
 
 
   The newer ARMv4T cpu's are capable of operating in ARM or Thumb
   The newer ARMv4T cpu's are capable of operating in ARM or Thumb
   modes.  A different instruction is required for each mode.  The ARM
   modes.  A different instruction is required for each mode.  The ARM
   cpu's can also be big or little endian.  Thus four different
   cpu's can also be big or little endian.  Thus four different
   instructions are needed to support all cases.
   instructions are needed to support all cases.
 
 
   Note: ARMv4 defines several new instructions that will take the
   Note: ARMv4 defines several new instructions that will take the
   undefined instruction trap.  ARM7TDMI is nominally ARMv4T, but does
   undefined instruction trap.  ARM7TDMI is nominally ARMv4T, but does
   not in fact add the new instructions.  The new undefined
   not in fact add the new instructions.  The new undefined
   instructions in ARMv4 are all instructions that had no defined
   instructions in ARMv4 are all instructions that had no defined
   behaviour in earlier chips.  There is no guarantee that they will
   behaviour in earlier chips.  There is no guarantee that they will
   raise an exception, but may be treated as NOP's.  In practice, it
   raise an exception, but may be treated as NOP's.  In practice, it
   may only safe to rely on instructions matching:
   may only safe to rely on instructions matching:
 
 
   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
   C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x
   C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x
 
 
   Even this may only true if the condition predicate is true. The
   Even this may only true if the condition predicate is true. The
   following use a condition predicate of ALWAYS so it is always TRUE.
   following use a condition predicate of ALWAYS so it is always TRUE.
 
 
   There are other ways of forcing a breakpoint.  GNU/Linux, RISC iX,
   There are other ways of forcing a breakpoint.  GNU/Linux, RISC iX,
   and NetBSD all use a software interrupt rather than an undefined
   and NetBSD all use a software interrupt rather than an undefined
   instruction to force a trap.  This can be handled by by the
   instruction to force a trap.  This can be handled by by the
   abi-specific code during establishment of the gdbarch vector.  */
   abi-specific code during establishment of the gdbarch vector.  */
 
 
#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
#define THUMB_LE_BREAKPOINT {0xbe,0xbe}
#define THUMB_LE_BREAKPOINT {0xbe,0xbe}
#define THUMB_BE_BREAKPOINT {0xbe,0xbe}
#define THUMB_BE_BREAKPOINT {0xbe,0xbe}
 
 
static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
static const char arm_default_arm_le_breakpoint[] = ARM_LE_BREAKPOINT;
static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
static const char arm_default_arm_be_breakpoint[] = ARM_BE_BREAKPOINT;
static const char arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
static const char arm_default_thumb_le_breakpoint[] = THUMB_LE_BREAKPOINT;
static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
static const char arm_default_thumb_be_breakpoint[] = THUMB_BE_BREAKPOINT;
 
 
/* Determine the type and size of breakpoint to insert at PCPTR.  Uses
/* Determine the type and size of breakpoint to insert at PCPTR.  Uses
   the program counter value to determine whether a 16-bit or 32-bit
   the program counter value to determine whether a 16-bit or 32-bit
   breakpoint should be used.  It returns a pointer to a string of
   breakpoint should be used.  It returns a pointer to a string of
   bytes that encode a breakpoint instruction, stores the length of
   bytes that encode a breakpoint instruction, stores the length of
   the string to *lenptr, and adjusts the program counter (if
   the string to *lenptr, and adjusts the program counter (if
   necessary) to point to the actual memory location where the
   necessary) to point to the actual memory location where the
   breakpoint should be inserted.  */
   breakpoint should be inserted.  */
 
 
static const unsigned char *
static const unsigned char *
arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
arm_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
 
  if (arm_pc_is_thumb (*pcptr))
  if (arm_pc_is_thumb (*pcptr))
    {
    {
      *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
      *pcptr = UNMAKE_THUMB_ADDR (*pcptr);
      *lenptr = tdep->thumb_breakpoint_size;
      *lenptr = tdep->thumb_breakpoint_size;
      return tdep->thumb_breakpoint;
      return tdep->thumb_breakpoint;
    }
    }
  else
  else
    {
    {
      *lenptr = tdep->arm_breakpoint_size;
      *lenptr = tdep->arm_breakpoint_size;
      return tdep->arm_breakpoint;
      return tdep->arm_breakpoint;
    }
    }
}
}
 
 
/* Extract from an array REGBUF containing the (raw) register state a
/* Extract from an array REGBUF containing the (raw) register state a
   function return value of type TYPE, and copy that, in virtual
   function return value of type TYPE, and copy that, in virtual
   format, into VALBUF.  */
   format, into VALBUF.  */
 
 
static void
static void
arm_extract_return_value (struct type *type, struct regcache *regs,
arm_extract_return_value (struct type *type, struct regcache *regs,
                          gdb_byte *valbuf)
                          gdb_byte *valbuf)
{
{
  struct gdbarch *gdbarch = get_regcache_arch (regs);
  struct gdbarch *gdbarch = get_regcache_arch (regs);
 
 
  if (TYPE_CODE_FLT == TYPE_CODE (type))
  if (TYPE_CODE_FLT == TYPE_CODE (type))
    {
    {
      switch (gdbarch_tdep (gdbarch)->fp_model)
      switch (gdbarch_tdep (gdbarch)->fp_model)
        {
        {
        case ARM_FLOAT_FPA:
        case ARM_FLOAT_FPA:
          {
          {
            /* The value is in register F0 in internal format.  We need to
            /* The value is in register F0 in internal format.  We need to
               extract the raw value and then convert it to the desired
               extract the raw value and then convert it to the desired
               internal type.  */
               internal type.  */
            bfd_byte tmpbuf[FP_REGISTER_SIZE];
            bfd_byte tmpbuf[FP_REGISTER_SIZE];
 
 
            regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
            regcache_cooked_read (regs, ARM_F0_REGNUM, tmpbuf);
            convert_from_extended (floatformat_from_type (type), tmpbuf,
            convert_from_extended (floatformat_from_type (type), tmpbuf,
                                   valbuf, gdbarch_byte_order (gdbarch));
                                   valbuf, gdbarch_byte_order (gdbarch));
          }
          }
          break;
          break;
 
 
        case ARM_FLOAT_SOFT_FPA:
        case ARM_FLOAT_SOFT_FPA:
        case ARM_FLOAT_SOFT_VFP:
        case ARM_FLOAT_SOFT_VFP:
          regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
          regcache_cooked_read (regs, ARM_A1_REGNUM, valbuf);
          if (TYPE_LENGTH (type) > 4)
          if (TYPE_LENGTH (type) > 4)
            regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
            regcache_cooked_read (regs, ARM_A1_REGNUM + 1,
                                  valbuf + INT_REGISTER_SIZE);
                                  valbuf + INT_REGISTER_SIZE);
          break;
          break;
 
 
        default:
        default:
          internal_error
          internal_error
            (__FILE__, __LINE__,
            (__FILE__, __LINE__,
             _("arm_extract_return_value: Floating point model not supported"));
             _("arm_extract_return_value: Floating point model not supported"));
          break;
          break;
        }
        }
    }
    }
  else if (TYPE_CODE (type) == TYPE_CODE_INT
  else if (TYPE_CODE (type) == TYPE_CODE_INT
           || TYPE_CODE (type) == TYPE_CODE_CHAR
           || TYPE_CODE (type) == TYPE_CODE_CHAR
           || TYPE_CODE (type) == TYPE_CODE_BOOL
           || TYPE_CODE (type) == TYPE_CODE_BOOL
           || TYPE_CODE (type) == TYPE_CODE_PTR
           || TYPE_CODE (type) == TYPE_CODE_PTR
           || TYPE_CODE (type) == TYPE_CODE_REF
           || TYPE_CODE (type) == TYPE_CODE_REF
           || TYPE_CODE (type) == TYPE_CODE_ENUM)
           || TYPE_CODE (type) == TYPE_CODE_ENUM)
    {
    {
      /* If the the type is a plain integer, then the access is
      /* If the the type is a plain integer, then the access is
         straight-forward.  Otherwise we have to play around a bit more.  */
         straight-forward.  Otherwise we have to play around a bit more.  */
      int len = TYPE_LENGTH (type);
      int len = TYPE_LENGTH (type);
      int regno = ARM_A1_REGNUM;
      int regno = ARM_A1_REGNUM;
      ULONGEST tmp;
      ULONGEST tmp;
 
 
      while (len > 0)
      while (len > 0)
        {
        {
          /* By using store_unsigned_integer we avoid having to do
          /* By using store_unsigned_integer we avoid having to do
             anything special for small big-endian values.  */
             anything special for small big-endian values.  */
          regcache_cooked_read_unsigned (regs, regno++, &tmp);
          regcache_cooked_read_unsigned (regs, regno++, &tmp);
          store_unsigned_integer (valbuf,
          store_unsigned_integer (valbuf,
                                  (len > INT_REGISTER_SIZE
                                  (len > INT_REGISTER_SIZE
                                   ? INT_REGISTER_SIZE : len),
                                   ? INT_REGISTER_SIZE : len),
                                  tmp);
                                  tmp);
          len -= INT_REGISTER_SIZE;
          len -= INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
        }
        }
    }
    }
  else
  else
    {
    {
      /* For a structure or union the behaviour is as if the value had
      /* For a structure or union the behaviour is as if the value had
         been stored to word-aligned memory and then loaded into
         been stored to word-aligned memory and then loaded into
         registers with 32-bit load instruction(s).  */
         registers with 32-bit load instruction(s).  */
      int len = TYPE_LENGTH (type);
      int len = TYPE_LENGTH (type);
      int regno = ARM_A1_REGNUM;
      int regno = ARM_A1_REGNUM;
      bfd_byte tmpbuf[INT_REGISTER_SIZE];
      bfd_byte tmpbuf[INT_REGISTER_SIZE];
 
 
      while (len > 0)
      while (len > 0)
        {
        {
          regcache_cooked_read (regs, regno++, tmpbuf);
          regcache_cooked_read (regs, regno++, tmpbuf);
          memcpy (valbuf, tmpbuf,
          memcpy (valbuf, tmpbuf,
                  len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
                  len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
          len -= INT_REGISTER_SIZE;
          len -= INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
        }
        }
    }
    }
}
}
 
 
 
 
/* Will a function return an aggregate type in memory or in a
/* Will a function return an aggregate type in memory or in a
   register?  Return 0 if an aggregate type can be returned in a
   register?  Return 0 if an aggregate type can be returned in a
   register, 1 if it must be returned in memory.  */
   register, 1 if it must be returned in memory.  */
 
 
static int
static int
arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
{
{
  int nRc;
  int nRc;
  enum type_code code;
  enum type_code code;
 
 
  CHECK_TYPEDEF (type);
  CHECK_TYPEDEF (type);
 
 
  /* In the ARM ABI, "integer" like aggregate types are returned in
  /* In the ARM ABI, "integer" like aggregate types are returned in
     registers.  For an aggregate type to be integer like, its size
     registers.  For an aggregate type to be integer like, its size
     must be less than or equal to INT_REGISTER_SIZE and the
     must be less than or equal to INT_REGISTER_SIZE and the
     offset of each addressable subfield must be zero.  Note that bit
     offset of each addressable subfield must be zero.  Note that bit
     fields are not addressable, and all addressable subfields of
     fields are not addressable, and all addressable subfields of
     unions always start at offset zero.
     unions always start at offset zero.
 
 
     This function is based on the behaviour of GCC 2.95.1.
     This function is based on the behaviour of GCC 2.95.1.
     See: gcc/arm.c: arm_return_in_memory() for details.
     See: gcc/arm.c: arm_return_in_memory() for details.
 
 
     Note: All versions of GCC before GCC 2.95.2 do not set up the
     Note: All versions of GCC before GCC 2.95.2 do not set up the
     parameters correctly for a function returning the following
     parameters correctly for a function returning the following
     structure: struct { float f;}; This should be returned in memory,
     structure: struct { float f;}; This should be returned in memory,
     not a register.  Richard Earnshaw sent me a patch, but I do not
     not a register.  Richard Earnshaw sent me a patch, but I do not
     know of any way to detect if a function like the above has been
     know of any way to detect if a function like the above has been
     compiled with the correct calling convention.  */
     compiled with the correct calling convention.  */
 
 
  /* All aggregate types that won't fit in a register must be returned
  /* All aggregate types that won't fit in a register must be returned
     in memory.  */
     in memory.  */
  if (TYPE_LENGTH (type) > INT_REGISTER_SIZE)
  if (TYPE_LENGTH (type) > INT_REGISTER_SIZE)
    {
    {
      return 1;
      return 1;
    }
    }
 
 
  /* The AAPCS says all aggregates not larger than a word are returned
  /* The AAPCS says all aggregates not larger than a word are returned
     in a register.  */
     in a register.  */
  if (gdbarch_tdep (gdbarch)->arm_abi != ARM_ABI_APCS)
  if (gdbarch_tdep (gdbarch)->arm_abi != ARM_ABI_APCS)
    return 0;
    return 0;
 
 
  /* The only aggregate types that can be returned in a register are
  /* The only aggregate types that can be returned in a register are
     structs and unions.  Arrays must be returned in memory.  */
     structs and unions.  Arrays must be returned in memory.  */
  code = TYPE_CODE (type);
  code = TYPE_CODE (type);
  if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code))
  if ((TYPE_CODE_STRUCT != code) && (TYPE_CODE_UNION != code))
    {
    {
      return 1;
      return 1;
    }
    }
 
 
  /* Assume all other aggregate types can be returned in a register.
  /* Assume all other aggregate types can be returned in a register.
     Run a check for structures, unions and arrays.  */
     Run a check for structures, unions and arrays.  */
  nRc = 0;
  nRc = 0;
 
 
  if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
  if ((TYPE_CODE_STRUCT == code) || (TYPE_CODE_UNION == code))
    {
    {
      int i;
      int i;
      /* Need to check if this struct/union is "integer" like.  For
      /* Need to check if this struct/union is "integer" like.  For
         this to be true, its size must be less than or equal to
         this to be true, its size must be less than or equal to
         INT_REGISTER_SIZE and the offset of each addressable
         INT_REGISTER_SIZE and the offset of each addressable
         subfield must be zero.  Note that bit fields are not
         subfield must be zero.  Note that bit fields are not
         addressable, and unions always start at offset zero.  If any
         addressable, and unions always start at offset zero.  If any
         of the subfields is a floating point type, the struct/union
         of the subfields is a floating point type, the struct/union
         cannot be an integer type.  */
         cannot be an integer type.  */
 
 
      /* For each field in the object, check:
      /* For each field in the object, check:
         1) Is it FP? --> yes, nRc = 1;
         1) Is it FP? --> yes, nRc = 1;
         2) Is it addressable (bitpos != 0) and
         2) Is it addressable (bitpos != 0) and
         not packed (bitsize == 0)?
         not packed (bitsize == 0)?
         --> yes, nRc = 1
         --> yes, nRc = 1
       */
       */
 
 
      for (i = 0; i < TYPE_NFIELDS (type); i++)
      for (i = 0; i < TYPE_NFIELDS (type); i++)
        {
        {
          enum type_code field_type_code;
          enum type_code field_type_code;
          field_type_code = TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, i)));
          field_type_code = TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, i)));
 
 
          /* Is it a floating point type field?  */
          /* Is it a floating point type field?  */
          if (field_type_code == TYPE_CODE_FLT)
          if (field_type_code == TYPE_CODE_FLT)
            {
            {
              nRc = 1;
              nRc = 1;
              break;
              break;
            }
            }
 
 
          /* If bitpos != 0, then we have to care about it.  */
          /* If bitpos != 0, then we have to care about it.  */
          if (TYPE_FIELD_BITPOS (type, i) != 0)
          if (TYPE_FIELD_BITPOS (type, i) != 0)
            {
            {
              /* Bitfields are not addressable.  If the field bitsize is
              /* Bitfields are not addressable.  If the field bitsize is
                 zero, then the field is not packed.  Hence it cannot be
                 zero, then the field is not packed.  Hence it cannot be
                 a bitfield or any other packed type.  */
                 a bitfield or any other packed type.  */
              if (TYPE_FIELD_BITSIZE (type, i) == 0)
              if (TYPE_FIELD_BITSIZE (type, i) == 0)
                {
                {
                  nRc = 1;
                  nRc = 1;
                  break;
                  break;
                }
                }
            }
            }
        }
        }
    }
    }
 
 
  return nRc;
  return nRc;
}
}
 
 
/* Write into appropriate registers a function return value of type
/* Write into appropriate registers a function return value of type
   TYPE, given in virtual format.  */
   TYPE, given in virtual format.  */
 
 
static void
static void
arm_store_return_value (struct type *type, struct regcache *regs,
arm_store_return_value (struct type *type, struct regcache *regs,
                        const gdb_byte *valbuf)
                        const gdb_byte *valbuf)
{
{
  struct gdbarch *gdbarch = get_regcache_arch (regs);
  struct gdbarch *gdbarch = get_regcache_arch (regs);
 
 
  if (TYPE_CODE (type) == TYPE_CODE_FLT)
  if (TYPE_CODE (type) == TYPE_CODE_FLT)
    {
    {
      char buf[MAX_REGISTER_SIZE];
      char buf[MAX_REGISTER_SIZE];
 
 
      switch (gdbarch_tdep (gdbarch)->fp_model)
      switch (gdbarch_tdep (gdbarch)->fp_model)
        {
        {
        case ARM_FLOAT_FPA:
        case ARM_FLOAT_FPA:
 
 
          convert_to_extended (floatformat_from_type (type), buf, valbuf,
          convert_to_extended (floatformat_from_type (type), buf, valbuf,
                               gdbarch_byte_order (gdbarch));
                               gdbarch_byte_order (gdbarch));
          regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
          regcache_cooked_write (regs, ARM_F0_REGNUM, buf);
          break;
          break;
 
 
        case ARM_FLOAT_SOFT_FPA:
        case ARM_FLOAT_SOFT_FPA:
        case ARM_FLOAT_SOFT_VFP:
        case ARM_FLOAT_SOFT_VFP:
          regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
          regcache_cooked_write (regs, ARM_A1_REGNUM, valbuf);
          if (TYPE_LENGTH (type) > 4)
          if (TYPE_LENGTH (type) > 4)
            regcache_cooked_write (regs, ARM_A1_REGNUM + 1,
            regcache_cooked_write (regs, ARM_A1_REGNUM + 1,
                                   valbuf + INT_REGISTER_SIZE);
                                   valbuf + INT_REGISTER_SIZE);
          break;
          break;
 
 
        default:
        default:
          internal_error
          internal_error
            (__FILE__, __LINE__,
            (__FILE__, __LINE__,
             _("arm_store_return_value: Floating point model not supported"));
             _("arm_store_return_value: Floating point model not supported"));
          break;
          break;
        }
        }
    }
    }
  else if (TYPE_CODE (type) == TYPE_CODE_INT
  else if (TYPE_CODE (type) == TYPE_CODE_INT
           || TYPE_CODE (type) == TYPE_CODE_CHAR
           || TYPE_CODE (type) == TYPE_CODE_CHAR
           || TYPE_CODE (type) == TYPE_CODE_BOOL
           || TYPE_CODE (type) == TYPE_CODE_BOOL
           || TYPE_CODE (type) == TYPE_CODE_PTR
           || TYPE_CODE (type) == TYPE_CODE_PTR
           || TYPE_CODE (type) == TYPE_CODE_REF
           || TYPE_CODE (type) == TYPE_CODE_REF
           || TYPE_CODE (type) == TYPE_CODE_ENUM)
           || TYPE_CODE (type) == TYPE_CODE_ENUM)
    {
    {
      if (TYPE_LENGTH (type) <= 4)
      if (TYPE_LENGTH (type) <= 4)
        {
        {
          /* Values of one word or less are zero/sign-extended and
          /* Values of one word or less are zero/sign-extended and
             returned in r0.  */
             returned in r0.  */
          bfd_byte tmpbuf[INT_REGISTER_SIZE];
          bfd_byte tmpbuf[INT_REGISTER_SIZE];
          LONGEST val = unpack_long (type, valbuf);
          LONGEST val = unpack_long (type, valbuf);
 
 
          store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
          store_signed_integer (tmpbuf, INT_REGISTER_SIZE, val);
          regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
          regcache_cooked_write (regs, ARM_A1_REGNUM, tmpbuf);
        }
        }
      else
      else
        {
        {
          /* Integral values greater than one word are stored in consecutive
          /* Integral values greater than one word are stored in consecutive
             registers starting with r0.  This will always be a multiple of
             registers starting with r0.  This will always be a multiple of
             the regiser size.  */
             the regiser size.  */
          int len = TYPE_LENGTH (type);
          int len = TYPE_LENGTH (type);
          int regno = ARM_A1_REGNUM;
          int regno = ARM_A1_REGNUM;
 
 
          while (len > 0)
          while (len > 0)
            {
            {
              regcache_cooked_write (regs, regno++, valbuf);
              regcache_cooked_write (regs, regno++, valbuf);
              len -= INT_REGISTER_SIZE;
              len -= INT_REGISTER_SIZE;
              valbuf += INT_REGISTER_SIZE;
              valbuf += INT_REGISTER_SIZE;
            }
            }
        }
        }
    }
    }
  else
  else
    {
    {
      /* For a structure or union the behaviour is as if the value had
      /* For a structure or union the behaviour is as if the value had
         been stored to word-aligned memory and then loaded into
         been stored to word-aligned memory and then loaded into
         registers with 32-bit load instruction(s).  */
         registers with 32-bit load instruction(s).  */
      int len = TYPE_LENGTH (type);
      int len = TYPE_LENGTH (type);
      int regno = ARM_A1_REGNUM;
      int regno = ARM_A1_REGNUM;
      bfd_byte tmpbuf[INT_REGISTER_SIZE];
      bfd_byte tmpbuf[INT_REGISTER_SIZE];
 
 
      while (len > 0)
      while (len > 0)
        {
        {
          memcpy (tmpbuf, valbuf,
          memcpy (tmpbuf, valbuf,
                  len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
                  len > INT_REGISTER_SIZE ? INT_REGISTER_SIZE : len);
          regcache_cooked_write (regs, regno++, tmpbuf);
          regcache_cooked_write (regs, regno++, tmpbuf);
          len -= INT_REGISTER_SIZE;
          len -= INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
          valbuf += INT_REGISTER_SIZE;
        }
        }
    }
    }
}
}
 
 
 
 
/* Handle function return values.  */
/* Handle function return values.  */
 
 
static enum return_value_convention
static enum return_value_convention
arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
arm_return_value (struct gdbarch *gdbarch, struct type *valtype,
                  struct regcache *regcache, gdb_byte *readbuf,
                  struct regcache *regcache, gdb_byte *readbuf,
                  const gdb_byte *writebuf)
                  const gdb_byte *writebuf)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
 
  if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
  if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
      || TYPE_CODE (valtype) == TYPE_CODE_UNION
      || TYPE_CODE (valtype) == TYPE_CODE_UNION
      || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
      || TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
    {
    {
      if (tdep->struct_return == pcc_struct_return
      if (tdep->struct_return == pcc_struct_return
          || arm_return_in_memory (gdbarch, valtype))
          || arm_return_in_memory (gdbarch, valtype))
        return RETURN_VALUE_STRUCT_CONVENTION;
        return RETURN_VALUE_STRUCT_CONVENTION;
    }
    }
 
 
  if (writebuf)
  if (writebuf)
    arm_store_return_value (valtype, regcache, writebuf);
    arm_store_return_value (valtype, regcache, writebuf);
 
 
  if (readbuf)
  if (readbuf)
    arm_extract_return_value (valtype, regcache, readbuf);
    arm_extract_return_value (valtype, regcache, readbuf);
 
 
  return RETURN_VALUE_REGISTER_CONVENTION;
  return RETURN_VALUE_REGISTER_CONVENTION;
}
}
 
 
 
 
static int
static int
arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
arm_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
{
  CORE_ADDR jb_addr;
  CORE_ADDR jb_addr;
  char buf[INT_REGISTER_SIZE];
  char buf[INT_REGISTER_SIZE];
  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
 
 
  jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
  jb_addr = get_frame_register_unsigned (frame, ARM_A1_REGNUM);
 
 
  if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
  if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
                          INT_REGISTER_SIZE))
                          INT_REGISTER_SIZE))
    return 0;
    return 0;
 
 
  *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
  *pc = extract_unsigned_integer (buf, INT_REGISTER_SIZE);
  return 1;
  return 1;
}
}
 
 
/* Recognize GCC and GNU ld's trampolines.  If we are in a trampoline,
/* Recognize GCC and GNU ld's trampolines.  If we are in a trampoline,
   return the target PC.  Otherwise return 0.  */
   return the target PC.  Otherwise return 0.  */
 
 
CORE_ADDR
CORE_ADDR
arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
arm_skip_stub (struct frame_info *frame, CORE_ADDR pc)
{
{
  char *name;
  char *name;
  int namelen;
  int namelen;
  CORE_ADDR start_addr;
  CORE_ADDR start_addr;
 
 
  /* Find the starting address and name of the function containing the PC.  */
  /* Find the starting address and name of the function containing the PC.  */
  if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
  if (find_pc_partial_function (pc, &name, &start_addr, NULL) == 0)
    return 0;
    return 0;
 
 
  /* If PC is in a Thumb call or return stub, return the address of the
  /* If PC is in a Thumb call or return stub, return the address of the
     target PC, which is in a register.  The thunk functions are called
     target PC, which is in a register.  The thunk functions are called
     _call_via_xx, where x is the register name.  The possible names
     _call_via_xx, where x is the register name.  The possible names
     are r0-r9, sl, fp, ip, sp, and lr.  */
     are r0-r9, sl, fp, ip, sp, and lr.  */
  if (strncmp (name, "_call_via_", 10) == 0)
  if (strncmp (name, "_call_via_", 10) == 0)
    {
    {
      /* Use the name suffix to determine which register contains the
      /* Use the name suffix to determine which register contains the
         target PC.  */
         target PC.  */
      static char *table[15] =
      static char *table[15] =
      {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
      {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
       "r8", "r9", "sl", "fp", "ip", "sp", "lr"
       "r8", "r9", "sl", "fp", "ip", "sp", "lr"
      };
      };
      int regno;
      int regno;
      int offset = strlen (name) - 2;
      int offset = strlen (name) - 2;
 
 
      for (regno = 0; regno <= 14; regno++)
      for (regno = 0; regno <= 14; regno++)
        if (strcmp (&name[offset], table[regno]) == 0)
        if (strcmp (&name[offset], table[regno]) == 0)
          return get_frame_register_unsigned (frame, regno);
          return get_frame_register_unsigned (frame, regno);
    }
    }
 
 
  /* GNU ld generates __foo_from_arm or __foo_from_thumb for
  /* GNU ld generates __foo_from_arm or __foo_from_thumb for
     non-interworking calls to foo.  We could decode the stubs
     non-interworking calls to foo.  We could decode the stubs
     to find the target but it's easier to use the symbol table.  */
     to find the target but it's easier to use the symbol table.  */
  namelen = strlen (name);
  namelen = strlen (name);
  if (name[0] == '_' && name[1] == '_'
  if (name[0] == '_' && name[1] == '_'
      && ((namelen > 2 + strlen ("_from_thumb")
      && ((namelen > 2 + strlen ("_from_thumb")
           && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
           && strncmp (name + namelen - strlen ("_from_thumb"), "_from_thumb",
                       strlen ("_from_thumb")) == 0)
                       strlen ("_from_thumb")) == 0)
          || (namelen > 2 + strlen ("_from_arm")
          || (namelen > 2 + strlen ("_from_arm")
              && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
              && strncmp (name + namelen - strlen ("_from_arm"), "_from_arm",
                          strlen ("_from_arm")) == 0)))
                          strlen ("_from_arm")) == 0)))
    {
    {
      char *target_name;
      char *target_name;
      int target_len = namelen - 2;
      int target_len = namelen - 2;
      struct minimal_symbol *minsym;
      struct minimal_symbol *minsym;
      struct objfile *objfile;
      struct objfile *objfile;
      struct obj_section *sec;
      struct obj_section *sec;
 
 
      if (name[namelen - 1] == 'b')
      if (name[namelen - 1] == 'b')
        target_len -= strlen ("_from_thumb");
        target_len -= strlen ("_from_thumb");
      else
      else
        target_len -= strlen ("_from_arm");
        target_len -= strlen ("_from_arm");
 
 
      target_name = alloca (target_len + 1);
      target_name = alloca (target_len + 1);
      memcpy (target_name, name + 2, target_len);
      memcpy (target_name, name + 2, target_len);
      target_name[target_len] = '\0';
      target_name[target_len] = '\0';
 
 
      sec = find_pc_section (pc);
      sec = find_pc_section (pc);
      objfile = (sec == NULL) ? NULL : sec->objfile;
      objfile = (sec == NULL) ? NULL : sec->objfile;
      minsym = lookup_minimal_symbol (target_name, NULL, objfile);
      minsym = lookup_minimal_symbol (target_name, NULL, objfile);
      if (minsym != NULL)
      if (minsym != NULL)
        return SYMBOL_VALUE_ADDRESS (minsym);
        return SYMBOL_VALUE_ADDRESS (minsym);
      else
      else
        return 0;
        return 0;
    }
    }
 
 
  return 0;                      /* not a stub */
  return 0;                      /* not a stub */
}
}
 
 
static void
static void
set_arm_command (char *args, int from_tty)
set_arm_command (char *args, int from_tty)
{
{
  printf_unfiltered (_("\
  printf_unfiltered (_("\
\"set arm\" must be followed by an apporpriate subcommand.\n"));
\"set arm\" must be followed by an apporpriate subcommand.\n"));
  help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout);
  help_list (setarmcmdlist, "set arm ", all_commands, gdb_stdout);
}
}
 
 
static void
static void
show_arm_command (char *args, int from_tty)
show_arm_command (char *args, int from_tty)
{
{
  cmd_show_list (showarmcmdlist, from_tty, "");
  cmd_show_list (showarmcmdlist, from_tty, "");
}
}
 
 
static void
static void
arm_update_current_architecture (void)
arm_update_current_architecture (void)
{
{
  struct gdbarch_info info;
  struct gdbarch_info info;
 
 
  /* If the current architecture is not ARM, we have nothing to do.  */
  /* If the current architecture is not ARM, we have nothing to do.  */
  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_arm)
  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_arm)
    return;
    return;
 
 
  /* Update the architecture.  */
  /* Update the architecture.  */
  gdbarch_info_init (&info);
  gdbarch_info_init (&info);
 
 
  if (!gdbarch_update_p (info))
  if (!gdbarch_update_p (info))
    internal_error (__FILE__, __LINE__, "could not update architecture");
    internal_error (__FILE__, __LINE__, "could not update architecture");
}
}
 
 
static void
static void
set_fp_model_sfunc (char *args, int from_tty,
set_fp_model_sfunc (char *args, int from_tty,
                    struct cmd_list_element *c)
                    struct cmd_list_element *c)
{
{
  enum arm_float_model fp_model;
  enum arm_float_model fp_model;
 
 
  for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
  for (fp_model = ARM_FLOAT_AUTO; fp_model != ARM_FLOAT_LAST; fp_model++)
    if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
    if (strcmp (current_fp_model, fp_model_strings[fp_model]) == 0)
      {
      {
        arm_fp_model = fp_model;
        arm_fp_model = fp_model;
        break;
        break;
      }
      }
 
 
  if (fp_model == ARM_FLOAT_LAST)
  if (fp_model == ARM_FLOAT_LAST)
    internal_error (__FILE__, __LINE__, _("Invalid fp model accepted: %s."),
    internal_error (__FILE__, __LINE__, _("Invalid fp model accepted: %s."),
                    current_fp_model);
                    current_fp_model);
 
 
  arm_update_current_architecture ();
  arm_update_current_architecture ();
}
}
 
 
static void
static void
show_fp_model (struct ui_file *file, int from_tty,
show_fp_model (struct ui_file *file, int from_tty,
               struct cmd_list_element *c, const char *value)
               struct cmd_list_element *c, const char *value)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
 
  if (arm_fp_model == ARM_FLOAT_AUTO
  if (arm_fp_model == ARM_FLOAT_AUTO
      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
    fprintf_filtered (file, _("\
    fprintf_filtered (file, _("\
The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
The current ARM floating point model is \"auto\" (currently \"%s\").\n"),
                      fp_model_strings[tdep->fp_model]);
                      fp_model_strings[tdep->fp_model]);
  else
  else
    fprintf_filtered (file, _("\
    fprintf_filtered (file, _("\
The current ARM floating point model is \"%s\".\n"),
The current ARM floating point model is \"%s\".\n"),
                      fp_model_strings[arm_fp_model]);
                      fp_model_strings[arm_fp_model]);
}
}
 
 
static void
static void
arm_set_abi (char *args, int from_tty,
arm_set_abi (char *args, int from_tty,
             struct cmd_list_element *c)
             struct cmd_list_element *c)
{
{
  enum arm_abi_kind arm_abi;
  enum arm_abi_kind arm_abi;
 
 
  for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
  for (arm_abi = ARM_ABI_AUTO; arm_abi != ARM_ABI_LAST; arm_abi++)
    if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
    if (strcmp (arm_abi_string, arm_abi_strings[arm_abi]) == 0)
      {
      {
        arm_abi_global = arm_abi;
        arm_abi_global = arm_abi;
        break;
        break;
      }
      }
 
 
  if (arm_abi == ARM_ABI_LAST)
  if (arm_abi == ARM_ABI_LAST)
    internal_error (__FILE__, __LINE__, _("Invalid ABI accepted: %s."),
    internal_error (__FILE__, __LINE__, _("Invalid ABI accepted: %s."),
                    arm_abi_string);
                    arm_abi_string);
 
 
  arm_update_current_architecture ();
  arm_update_current_architecture ();
}
}
 
 
static void
static void
arm_show_abi (struct ui_file *file, int from_tty,
arm_show_abi (struct ui_file *file, int from_tty,
             struct cmd_list_element *c, const char *value)
             struct cmd_list_element *c, const char *value)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
 
 
  if (arm_abi_global == ARM_ABI_AUTO
  if (arm_abi_global == ARM_ABI_AUTO
      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
      && gdbarch_bfd_arch_info (current_gdbarch)->arch == bfd_arch_arm)
    fprintf_filtered (file, _("\
    fprintf_filtered (file, _("\
The current ARM ABI is \"auto\" (currently \"%s\").\n"),
The current ARM ABI is \"auto\" (currently \"%s\").\n"),
                      arm_abi_strings[tdep->arm_abi]);
                      arm_abi_strings[tdep->arm_abi]);
  else
  else
    fprintf_filtered (file, _("The current ARM ABI is \"%s\".\n"),
    fprintf_filtered (file, _("The current ARM ABI is \"%s\".\n"),
                      arm_abi_string);
                      arm_abi_string);
}
}
 
 
/* If the user changes the register disassembly style used for info
/* If the user changes the register disassembly style used for info
   register and other commands, we have to also switch the style used
   register and other commands, we have to also switch the style used
   in opcodes for disassembly output.  This function is run in the "set
   in opcodes for disassembly output.  This function is run in the "set
   arm disassembly" command, and does that.  */
   arm disassembly" command, and does that.  */
 
 
static void
static void
set_disassembly_style_sfunc (char *args, int from_tty,
set_disassembly_style_sfunc (char *args, int from_tty,
                              struct cmd_list_element *c)
                              struct cmd_list_element *c)
{
{
  set_disassembly_style ();
  set_disassembly_style ();
}
}


/* Return the ARM register name corresponding to register I.  */
/* Return the ARM register name corresponding to register I.  */
static const char *
static const char *
arm_register_name (struct gdbarch *gdbarch, int i)
arm_register_name (struct gdbarch *gdbarch, int i)
{
{
  if (i >= ARRAY_SIZE (arm_register_names))
  if (i >= ARRAY_SIZE (arm_register_names))
    /* These registers are only supported on targets which supply
    /* These registers are only supported on targets which supply
       an XML description.  */
       an XML description.  */
    return "";
    return "";
 
 
  return arm_register_names[i];
  return arm_register_names[i];
}
}
 
 
static void
static void
set_disassembly_style (void)
set_disassembly_style (void)
{
{
  int current;
  int current;
 
 
  /* Find the style that the user wants.  */
  /* Find the style that the user wants.  */
  for (current = 0; current < num_disassembly_options; current++)
  for (current = 0; current < num_disassembly_options; current++)
    if (disassembly_style == valid_disassembly_styles[current])
    if (disassembly_style == valid_disassembly_styles[current])
      break;
      break;
  gdb_assert (current < num_disassembly_options);
  gdb_assert (current < num_disassembly_options);
 
 
  /* Synchronize the disassembler.  */
  /* Synchronize the disassembler.  */
  set_arm_regname_option (current);
  set_arm_regname_option (current);
}
}
 
 
/* Test whether the coff symbol specific value corresponds to a Thumb
/* Test whether the coff symbol specific value corresponds to a Thumb
   function.  */
   function.  */
 
 
static int
static int
coff_sym_is_thumb (int val)
coff_sym_is_thumb (int val)
{
{
  return (val == C_THUMBEXT ||
  return (val == C_THUMBEXT ||
          val == C_THUMBSTAT ||
          val == C_THUMBSTAT ||
          val == C_THUMBEXTFUNC ||
          val == C_THUMBEXTFUNC ||
          val == C_THUMBSTATFUNC ||
          val == C_THUMBSTATFUNC ||
          val == C_THUMBLABEL);
          val == C_THUMBLABEL);
}
}
 
 
/* arm_coff_make_msymbol_special()
/* arm_coff_make_msymbol_special()
   arm_elf_make_msymbol_special()
   arm_elf_make_msymbol_special()
 
 
   These functions test whether the COFF or ELF symbol corresponds to
   These functions test whether the COFF or ELF symbol corresponds to
   an address in thumb code, and set a "special" bit in a minimal
   an address in thumb code, and set a "special" bit in a minimal
   symbol to indicate that it does.  */
   symbol to indicate that it does.  */
 
 
static void
static void
arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
arm_elf_make_msymbol_special(asymbol *sym, struct minimal_symbol *msym)
{
{
  /* Thumb symbols are of type STT_LOPROC, (synonymous with
  /* Thumb symbols are of type STT_LOPROC, (synonymous with
     STT_ARM_TFUNC).  */
     STT_ARM_TFUNC).  */
  if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info)
  if (ELF_ST_TYPE (((elf_symbol_type *)sym)->internal_elf_sym.st_info)
      == STT_LOPROC)
      == STT_LOPROC)
    MSYMBOL_SET_SPECIAL (msym);
    MSYMBOL_SET_SPECIAL (msym);
}
}
 
 
static void
static void
arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
arm_coff_make_msymbol_special(int val, struct minimal_symbol *msym)
{
{
  if (coff_sym_is_thumb (val))
  if (coff_sym_is_thumb (val))
    MSYMBOL_SET_SPECIAL (msym);
    MSYMBOL_SET_SPECIAL (msym);
}
}
 
 
static void
static void
arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
arm_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
{
  regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc);
  regcache_cooked_write_unsigned (regcache, ARM_PC_REGNUM, pc);
 
 
  /* If necessary, set the T bit.  */
  /* If necessary, set the T bit.  */
  if (arm_apcs_32)
  if (arm_apcs_32)
    {
    {
      ULONGEST val;
      ULONGEST val;
      regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
      regcache_cooked_read_unsigned (regcache, ARM_PS_REGNUM, &val);
      if (arm_pc_is_thumb (pc))
      if (arm_pc_is_thumb (pc))
        regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | 0x20);
        regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM, val | 0x20);
      else
      else
        regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
        regcache_cooked_write_unsigned (regcache, ARM_PS_REGNUM,
                                        val & ~(ULONGEST) 0x20);
                                        val & ~(ULONGEST) 0x20);
    }
    }
}
}
 
 
static struct value *
static struct value *
value_of_arm_user_reg (struct frame_info *frame, const void *baton)
value_of_arm_user_reg (struct frame_info *frame, const void *baton)
{
{
  const int *reg_p = baton;
  const int *reg_p = baton;
  return value_of_register (*reg_p, frame);
  return value_of_register (*reg_p, frame);
}
}


static enum gdb_osabi
static enum gdb_osabi
arm_elf_osabi_sniffer (bfd *abfd)
arm_elf_osabi_sniffer (bfd *abfd)
{
{
  unsigned int elfosabi;
  unsigned int elfosabi;
  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
 
 
  elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
  elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
 
 
  if (elfosabi == ELFOSABI_ARM)
  if (elfosabi == ELFOSABI_ARM)
    /* GNU tools use this value.  Check note sections in this case,
    /* GNU tools use this value.  Check note sections in this case,
       as well.  */
       as well.  */
    bfd_map_over_sections (abfd,
    bfd_map_over_sections (abfd,
                           generic_elf_osabi_sniff_abi_tag_sections,
                           generic_elf_osabi_sniff_abi_tag_sections,
                           &osabi);
                           &osabi);
 
 
  /* Anything else will be handled by the generic ELF sniffer.  */
  /* Anything else will be handled by the generic ELF sniffer.  */
  return osabi;
  return osabi;
}
}
 
 


/* Initialize the current architecture based on INFO.  If possible,
/* Initialize the current architecture based on INFO.  If possible,
   re-use an architecture from ARCHES, which is a list of
   re-use an architecture from ARCHES, which is a list of
   architectures already created during this debugging session.
   architectures already created during this debugging session.
 
 
   Called e.g. at program startup, when reading a core file, and when
   Called e.g. at program startup, when reading a core file, and when
   reading a binary file.  */
   reading a binary file.  */
 
 
static struct gdbarch *
static struct gdbarch *
arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
{
  struct gdbarch_tdep *tdep;
  struct gdbarch_tdep *tdep;
  struct gdbarch *gdbarch;
  struct gdbarch *gdbarch;
  struct gdbarch_list *best_arch;
  struct gdbarch_list *best_arch;
  enum arm_abi_kind arm_abi = arm_abi_global;
  enum arm_abi_kind arm_abi = arm_abi_global;
  enum arm_float_model fp_model = arm_fp_model;
  enum arm_float_model fp_model = arm_fp_model;
  struct tdesc_arch_data *tdesc_data = NULL;
  struct tdesc_arch_data *tdesc_data = NULL;
  int i;
  int i;
  int have_fpa_registers = 1;
  int have_fpa_registers = 1;
 
 
  /* Check any target description for validity.  */
  /* Check any target description for validity.  */
  if (tdesc_has_registers (info.target_desc))
  if (tdesc_has_registers (info.target_desc))
    {
    {
      /* For most registers we require GDB's default names; but also allow
      /* For most registers we require GDB's default names; but also allow
         the numeric names for sp / lr / pc, as a convenience.  */
         the numeric names for sp / lr / pc, as a convenience.  */
      static const char *const arm_sp_names[] = { "r13", "sp", NULL };
      static const char *const arm_sp_names[] = { "r13", "sp", NULL };
      static const char *const arm_lr_names[] = { "r14", "lr", NULL };
      static const char *const arm_lr_names[] = { "r14", "lr", NULL };
      static const char *const arm_pc_names[] = { "r15", "pc", NULL };
      static const char *const arm_pc_names[] = { "r15", "pc", NULL };
 
 
      const struct tdesc_feature *feature;
      const struct tdesc_feature *feature;
      int i, valid_p;
      int i, valid_p;
 
 
      feature = tdesc_find_feature (info.target_desc,
      feature = tdesc_find_feature (info.target_desc,
                                    "org.gnu.gdb.arm.core");
                                    "org.gnu.gdb.arm.core");
      if (feature == NULL)
      if (feature == NULL)
        return NULL;
        return NULL;
 
 
      tdesc_data = tdesc_data_alloc ();
      tdesc_data = tdesc_data_alloc ();
 
 
      valid_p = 1;
      valid_p = 1;
      for (i = 0; i < ARM_SP_REGNUM; i++)
      for (i = 0; i < ARM_SP_REGNUM; i++)
        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
                                            arm_register_names[i]);
                                            arm_register_names[i]);
      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
                                                  ARM_SP_REGNUM,
                                                  ARM_SP_REGNUM,
                                                  arm_sp_names);
                                                  arm_sp_names);
      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
                                                  ARM_LR_REGNUM,
                                                  ARM_LR_REGNUM,
                                                  arm_lr_names);
                                                  arm_lr_names);
      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
      valid_p &= tdesc_numbered_register_choices (feature, tdesc_data,
                                                  ARM_PC_REGNUM,
                                                  ARM_PC_REGNUM,
                                                  arm_pc_names);
                                                  arm_pc_names);
      valid_p &= tdesc_numbered_register (feature, tdesc_data,
      valid_p &= tdesc_numbered_register (feature, tdesc_data,
                                          ARM_PS_REGNUM, "cpsr");
                                          ARM_PS_REGNUM, "cpsr");
 
 
      if (!valid_p)
      if (!valid_p)
        {
        {
          tdesc_data_cleanup (tdesc_data);
          tdesc_data_cleanup (tdesc_data);
          return NULL;
          return NULL;
        }
        }
 
 
      feature = tdesc_find_feature (info.target_desc,
      feature = tdesc_find_feature (info.target_desc,
                                    "org.gnu.gdb.arm.fpa");
                                    "org.gnu.gdb.arm.fpa");
      if (feature != NULL)
      if (feature != NULL)
        {
        {
          valid_p = 1;
          valid_p = 1;
          for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
          for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
            valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
            valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
                                                arm_register_names[i]);
                                                arm_register_names[i]);
          if (!valid_p)
          if (!valid_p)
            {
            {
              tdesc_data_cleanup (tdesc_data);
              tdesc_data_cleanup (tdesc_data);
              return NULL;
              return NULL;
            }
            }
        }
        }
      else
      else
        have_fpa_registers = 0;
        have_fpa_registers = 0;
 
 
      feature = tdesc_find_feature (info.target_desc,
      feature = tdesc_find_feature (info.target_desc,
                                    "org.gnu.gdb.xscale.iwmmxt");
                                    "org.gnu.gdb.xscale.iwmmxt");
      if (feature != NULL)
      if (feature != NULL)
        {
        {
          static const char *const iwmmxt_names[] = {
          static const char *const iwmmxt_names[] = {
            "wR0", "wR1", "wR2", "wR3", "wR4", "wR5", "wR6", "wR7",
            "wR0", "wR1", "wR2", "wR3", "wR4", "wR5", "wR6", "wR7",
            "wR8", "wR9", "wR10", "wR11", "wR12", "wR13", "wR14", "wR15",
            "wR8", "wR9", "wR10", "wR11", "wR12", "wR13", "wR14", "wR15",
            "wCID", "wCon", "wCSSF", "wCASF", "", "", "", "",
            "wCID", "wCon", "wCSSF", "wCASF", "", "", "", "",
            "wCGR0", "wCGR1", "wCGR2", "wCGR3", "", "", "", "",
            "wCGR0", "wCGR1", "wCGR2", "wCGR3", "", "", "", "",
          };
          };
 
 
          valid_p = 1;
          valid_p = 1;
          for (i = ARM_WR0_REGNUM; i <= ARM_WR15_REGNUM; i++)
          for (i = ARM_WR0_REGNUM; i <= ARM_WR15_REGNUM; i++)
            valid_p
            valid_p
              &= tdesc_numbered_register (feature, tdesc_data, i,
              &= tdesc_numbered_register (feature, tdesc_data, i,
                                          iwmmxt_names[i - ARM_WR0_REGNUM]);
                                          iwmmxt_names[i - ARM_WR0_REGNUM]);
 
 
          /* Check for the control registers, but do not fail if they
          /* Check for the control registers, but do not fail if they
             are missing.  */
             are missing.  */
          for (i = ARM_WC0_REGNUM; i <= ARM_WCASF_REGNUM; i++)
          for (i = ARM_WC0_REGNUM; i <= ARM_WCASF_REGNUM; i++)
            tdesc_numbered_register (feature, tdesc_data, i,
            tdesc_numbered_register (feature, tdesc_data, i,
                                     iwmmxt_names[i - ARM_WR0_REGNUM]);
                                     iwmmxt_names[i - ARM_WR0_REGNUM]);
 
 
          for (i = ARM_WCGR0_REGNUM; i <= ARM_WCGR3_REGNUM; i++)
          for (i = ARM_WCGR0_REGNUM; i <= ARM_WCGR3_REGNUM; i++)
            valid_p
            valid_p
              &= tdesc_numbered_register (feature, tdesc_data, i,
              &= tdesc_numbered_register (feature, tdesc_data, i,
                                          iwmmxt_names[i - ARM_WR0_REGNUM]);
                                          iwmmxt_names[i - ARM_WR0_REGNUM]);
 
 
          if (!valid_p)
          if (!valid_p)
            {
            {
              tdesc_data_cleanup (tdesc_data);
              tdesc_data_cleanup (tdesc_data);
              return NULL;
              return NULL;
            }
            }
        }
        }
    }
    }
 
 
  /* If we have an object to base this architecture on, try to determine
  /* If we have an object to base this architecture on, try to determine
     its ABI.  */
     its ABI.  */
 
 
  if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
  if (arm_abi == ARM_ABI_AUTO && info.abfd != NULL)
    {
    {
      int ei_osabi, e_flags;
      int ei_osabi, e_flags;
 
 
      switch (bfd_get_flavour (info.abfd))
      switch (bfd_get_flavour (info.abfd))
        {
        {
        case bfd_target_aout_flavour:
        case bfd_target_aout_flavour:
          /* Assume it's an old APCS-style ABI.  */
          /* Assume it's an old APCS-style ABI.  */
          arm_abi = ARM_ABI_APCS;
          arm_abi = ARM_ABI_APCS;
          break;
          break;
 
 
        case bfd_target_coff_flavour:
        case bfd_target_coff_flavour:
          /* Assume it's an old APCS-style ABI.  */
          /* Assume it's an old APCS-style ABI.  */
          /* XXX WinCE?  */
          /* XXX WinCE?  */
          arm_abi = ARM_ABI_APCS;
          arm_abi = ARM_ABI_APCS;
          break;
          break;
 
 
        case bfd_target_elf_flavour:
        case bfd_target_elf_flavour:
          ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
          ei_osabi = elf_elfheader (info.abfd)->e_ident[EI_OSABI];
          e_flags = elf_elfheader (info.abfd)->e_flags;
          e_flags = elf_elfheader (info.abfd)->e_flags;
 
 
          if (ei_osabi == ELFOSABI_ARM)
          if (ei_osabi == ELFOSABI_ARM)
            {
            {
              /* GNU tools used to use this value, but do not for EABI
              /* GNU tools used to use this value, but do not for EABI
                 objects.  There's nowhere to tag an EABI version
                 objects.  There's nowhere to tag an EABI version
                 anyway, so assume APCS.  */
                 anyway, so assume APCS.  */
              arm_abi = ARM_ABI_APCS;
              arm_abi = ARM_ABI_APCS;
            }
            }
          else if (ei_osabi == ELFOSABI_NONE)
          else if (ei_osabi == ELFOSABI_NONE)
            {
            {
              int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
              int eabi_ver = EF_ARM_EABI_VERSION (e_flags);
 
 
              switch (eabi_ver)
              switch (eabi_ver)
                {
                {
                case EF_ARM_EABI_UNKNOWN:
                case EF_ARM_EABI_UNKNOWN:
                  /* Assume GNU tools.  */
                  /* Assume GNU tools.  */
                  arm_abi = ARM_ABI_APCS;
                  arm_abi = ARM_ABI_APCS;
                  break;
                  break;
 
 
                case EF_ARM_EABI_VER4:
                case EF_ARM_EABI_VER4:
                case EF_ARM_EABI_VER5:
                case EF_ARM_EABI_VER5:
                  arm_abi = ARM_ABI_AAPCS;
                  arm_abi = ARM_ABI_AAPCS;
                  /* EABI binaries default to VFP float ordering.  */
                  /* EABI binaries default to VFP float ordering.  */
                  if (fp_model == ARM_FLOAT_AUTO)
                  if (fp_model == ARM_FLOAT_AUTO)
                    fp_model = ARM_FLOAT_SOFT_VFP;
                    fp_model = ARM_FLOAT_SOFT_VFP;
                  break;
                  break;
 
 
                default:
                default:
                  /* Leave it as "auto".  */
                  /* Leave it as "auto".  */
                  warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
                  warning (_("unknown ARM EABI version 0x%x"), eabi_ver);
                  break;
                  break;
                }
                }
            }
            }
 
 
          if (fp_model == ARM_FLOAT_AUTO)
          if (fp_model == ARM_FLOAT_AUTO)
            {
            {
              int e_flags = elf_elfheader (info.abfd)->e_flags;
              int e_flags = elf_elfheader (info.abfd)->e_flags;
 
 
              switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
              switch (e_flags & (EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT))
                {
                {
                case 0:
                case 0:
                  /* Leave it as "auto".  Strictly speaking this case
                  /* Leave it as "auto".  Strictly speaking this case
                     means FPA, but almost nobody uses that now, and
                     means FPA, but almost nobody uses that now, and
                     many toolchains fail to set the appropriate bits
                     many toolchains fail to set the appropriate bits
                     for the floating-point model they use.  */
                     for the floating-point model they use.  */
                  break;
                  break;
                case EF_ARM_SOFT_FLOAT:
                case EF_ARM_SOFT_FLOAT:
                  fp_model = ARM_FLOAT_SOFT_FPA;
                  fp_model = ARM_FLOAT_SOFT_FPA;
                  break;
                  break;
                case EF_ARM_VFP_FLOAT:
                case EF_ARM_VFP_FLOAT:
                  fp_model = ARM_FLOAT_VFP;
                  fp_model = ARM_FLOAT_VFP;
                  break;
                  break;
                case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
                case EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT:
                  fp_model = ARM_FLOAT_SOFT_VFP;
                  fp_model = ARM_FLOAT_SOFT_VFP;
                  break;
                  break;
                }
                }
            }
            }
          break;
          break;
 
 
        default:
        default:
          /* Leave it as "auto".  */
          /* Leave it as "auto".  */
          break;
          break;
        }
        }
    }
    }
 
 
  /* If there is already a candidate, use it.  */
  /* If there is already a candidate, use it.  */
  for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
  for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
       best_arch != NULL;
       best_arch != NULL;
       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
    {
    {
      if (arm_abi != ARM_ABI_AUTO
      if (arm_abi != ARM_ABI_AUTO
          && arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
          && arm_abi != gdbarch_tdep (best_arch->gdbarch)->arm_abi)
        continue;
        continue;
 
 
      if (fp_model != ARM_FLOAT_AUTO
      if (fp_model != ARM_FLOAT_AUTO
          && fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
          && fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
        continue;
        continue;
 
 
      /* Found a match.  */
      /* Found a match.  */
      break;
      break;
    }
    }
 
 
  if (best_arch != NULL)
  if (best_arch != NULL)
    {
    {
      if (tdesc_data != NULL)
      if (tdesc_data != NULL)
        tdesc_data_cleanup (tdesc_data);
        tdesc_data_cleanup (tdesc_data);
      return best_arch->gdbarch;
      return best_arch->gdbarch;
    }
    }
 
 
  tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
  tdep = xcalloc (1, sizeof (struct gdbarch_tdep));
  gdbarch = gdbarch_alloc (&info, tdep);
  gdbarch = gdbarch_alloc (&info, tdep);
 
 
  /* Record additional information about the architecture we are defining.
  /* Record additional information about the architecture we are defining.
     These are gdbarch discriminators, like the OSABI.  */
     These are gdbarch discriminators, like the OSABI.  */
  tdep->arm_abi = arm_abi;
  tdep->arm_abi = arm_abi;
  tdep->fp_model = fp_model;
  tdep->fp_model = fp_model;
  tdep->have_fpa_registers = have_fpa_registers;
  tdep->have_fpa_registers = have_fpa_registers;
 
 
  /* Breakpoints.  */
  /* Breakpoints.  */
  switch (info.byte_order)
  switch (info.byte_order)
    {
    {
    case BFD_ENDIAN_BIG:
    case BFD_ENDIAN_BIG:
      tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
      tdep->arm_breakpoint = arm_default_arm_be_breakpoint;
      tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint);
      tdep->arm_breakpoint_size = sizeof (arm_default_arm_be_breakpoint);
      tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint;
      tdep->thumb_breakpoint = arm_default_thumb_be_breakpoint;
      tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint);
      tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_be_breakpoint);
 
 
      break;
      break;
 
 
    case BFD_ENDIAN_LITTLE:
    case BFD_ENDIAN_LITTLE:
      tdep->arm_breakpoint = arm_default_arm_le_breakpoint;
      tdep->arm_breakpoint = arm_default_arm_le_breakpoint;
      tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint);
      tdep->arm_breakpoint_size = sizeof (arm_default_arm_le_breakpoint);
      tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint;
      tdep->thumb_breakpoint = arm_default_thumb_le_breakpoint;
      tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint);
      tdep->thumb_breakpoint_size = sizeof (arm_default_thumb_le_breakpoint);
 
 
      break;
      break;
 
 
    default:
    default:
      internal_error (__FILE__, __LINE__,
      internal_error (__FILE__, __LINE__,
                      _("arm_gdbarch_init: bad byte order for float format"));
                      _("arm_gdbarch_init: bad byte order for float format"));
    }
    }
 
 
  /* On ARM targets char defaults to unsigned.  */
  /* On ARM targets char defaults to unsigned.  */
  set_gdbarch_char_signed (gdbarch, 0);
  set_gdbarch_char_signed (gdbarch, 0);
 
 
  /* This should be low enough for everything.  */
  /* This should be low enough for everything.  */
  tdep->lowest_pc = 0x20;
  tdep->lowest_pc = 0x20;
  tdep->jb_pc = -1;     /* Longjump support not enabled by default.  */
  tdep->jb_pc = -1;     /* Longjump support not enabled by default.  */
 
 
  /* The default, for both APCS and AAPCS, is to return small
  /* The default, for both APCS and AAPCS, is to return small
     structures in registers.  */
     structures in registers.  */
  tdep->struct_return = reg_struct_return;
  tdep->struct_return = reg_struct_return;
 
 
  set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
  set_gdbarch_push_dummy_call (gdbarch, arm_push_dummy_call);
  set_gdbarch_frame_align (gdbarch, arm_frame_align);
  set_gdbarch_frame_align (gdbarch, arm_frame_align);
 
 
  set_gdbarch_write_pc (gdbarch, arm_write_pc);
  set_gdbarch_write_pc (gdbarch, arm_write_pc);
 
 
  /* Frame handling.  */
  /* Frame handling.  */
  set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
  set_gdbarch_unwind_dummy_id (gdbarch, arm_unwind_dummy_id);
  set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
  set_gdbarch_unwind_pc (gdbarch, arm_unwind_pc);
  set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
  set_gdbarch_unwind_sp (gdbarch, arm_unwind_sp);
 
 
  frame_base_set_default (gdbarch, &arm_normal_base);
  frame_base_set_default (gdbarch, &arm_normal_base);
 
 
  /* Address manipulation.  */
  /* Address manipulation.  */
  set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
  set_gdbarch_smash_text_address (gdbarch, arm_smash_text_address);
  set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
  set_gdbarch_addr_bits_remove (gdbarch, arm_addr_bits_remove);
 
 
  /* Advance PC across function entry code.  */
  /* Advance PC across function entry code.  */
  set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
  set_gdbarch_skip_prologue (gdbarch, arm_skip_prologue);
 
 
  /* Skip trampolines.  */
  /* Skip trampolines.  */
  set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
  set_gdbarch_skip_trampoline_code (gdbarch, arm_skip_stub);
 
 
  /* The stack grows downward.  */
  /* The stack grows downward.  */
  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
 
 
  /* Breakpoint manipulation.  */
  /* Breakpoint manipulation.  */
  set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
  set_gdbarch_breakpoint_from_pc (gdbarch, arm_breakpoint_from_pc);
 
 
  /* Information about registers, etc.  */
  /* Information about registers, etc.  */
  set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM);    /* ??? */
  set_gdbarch_deprecated_fp_regnum (gdbarch, ARM_FP_REGNUM);    /* ??? */
  set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
  set_gdbarch_sp_regnum (gdbarch, ARM_SP_REGNUM);
  set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
  set_gdbarch_pc_regnum (gdbarch, ARM_PC_REGNUM);
  set_gdbarch_num_regs (gdbarch, ARM_NUM_REGS);
  set_gdbarch_num_regs (gdbarch, ARM_NUM_REGS);
  set_gdbarch_register_type (gdbarch, arm_register_type);
  set_gdbarch_register_type (gdbarch, arm_register_type);
 
 
  /* This "info float" is FPA-specific.  Use the generic version if we
  /* This "info float" is FPA-specific.  Use the generic version if we
     do not have FPA.  */
     do not have FPA.  */
  if (gdbarch_tdep (gdbarch)->have_fpa_registers)
  if (gdbarch_tdep (gdbarch)->have_fpa_registers)
    set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
    set_gdbarch_print_float_info (gdbarch, arm_print_float_info);
 
 
  /* Internal <-> external register number maps.  */
  /* Internal <-> external register number maps.  */
  set_gdbarch_dwarf_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
  set_gdbarch_dwarf_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arm_dwarf_reg_to_regnum);
  set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
  set_gdbarch_register_sim_regno (gdbarch, arm_register_sim_regno);
 
 
  set_gdbarch_register_name (gdbarch, arm_register_name);
  set_gdbarch_register_name (gdbarch, arm_register_name);
 
 
  /* Returning results.  */
  /* Returning results.  */
  set_gdbarch_return_value (gdbarch, arm_return_value);
  set_gdbarch_return_value (gdbarch, arm_return_value);
 
 
  /* Disassembly.  */
  /* Disassembly.  */
  set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
  set_gdbarch_print_insn (gdbarch, gdb_print_insn_arm);
 
 
  /* Minsymbol frobbing.  */
  /* Minsymbol frobbing.  */
  set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special);
  set_gdbarch_elf_make_msymbol_special (gdbarch, arm_elf_make_msymbol_special);
  set_gdbarch_coff_make_msymbol_special (gdbarch,
  set_gdbarch_coff_make_msymbol_special (gdbarch,
                                         arm_coff_make_msymbol_special);
                                         arm_coff_make_msymbol_special);
 
 
  /* Virtual tables.  */
  /* Virtual tables.  */
  set_gdbarch_vbit_in_delta (gdbarch, 1);
  set_gdbarch_vbit_in_delta (gdbarch, 1);
 
 
  /* Hook in the ABI-specific overrides, if they have been registered.  */
  /* Hook in the ABI-specific overrides, if they have been registered.  */
  gdbarch_init_osabi (info, gdbarch);
  gdbarch_init_osabi (info, gdbarch);
 
 
  /* Add some default predicates.  */
  /* Add some default predicates.  */
  frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
  frame_unwind_append_sniffer (gdbarch, arm_stub_unwind_sniffer);
  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
  frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
  frame_unwind_append_sniffer (gdbarch, arm_prologue_unwind_sniffer);
 
 
  /* Now we have tuned the configuration, set a few final things,
  /* Now we have tuned the configuration, set a few final things,
     based on what the OS ABI has told us.  */
     based on what the OS ABI has told us.  */
 
 
  /* If the ABI is not otherwise marked, assume the old GNU APCS.  EABI
  /* If the ABI is not otherwise marked, assume the old GNU APCS.  EABI
     binaries are always marked.  */
     binaries are always marked.  */
  if (tdep->arm_abi == ARM_ABI_AUTO)
  if (tdep->arm_abi == ARM_ABI_AUTO)
    tdep->arm_abi = ARM_ABI_APCS;
    tdep->arm_abi = ARM_ABI_APCS;
 
 
  /* We used to default to FPA for generic ARM, but almost nobody
  /* We used to default to FPA for generic ARM, but almost nobody
     uses that now, and we now provide a way for the user to force
     uses that now, and we now provide a way for the user to force
     the model.  So default to the most useful variant.  */
     the model.  So default to the most useful variant.  */
  if (tdep->fp_model == ARM_FLOAT_AUTO)
  if (tdep->fp_model == ARM_FLOAT_AUTO)
    tdep->fp_model = ARM_FLOAT_SOFT_FPA;
    tdep->fp_model = ARM_FLOAT_SOFT_FPA;
 
 
  if (tdep->jb_pc >= 0)
  if (tdep->jb_pc >= 0)
    set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
    set_gdbarch_get_longjmp_target (gdbarch, arm_get_longjmp_target);
 
 
  /* Floating point sizes and format.  */
  /* Floating point sizes and format.  */
  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
  if (tdep->fp_model == ARM_FLOAT_SOFT_FPA || tdep->fp_model == ARM_FLOAT_FPA)
  if (tdep->fp_model == ARM_FLOAT_SOFT_FPA || tdep->fp_model == ARM_FLOAT_FPA)
    {
    {
      set_gdbarch_double_format
      set_gdbarch_double_format
        (gdbarch, floatformats_ieee_double_littlebyte_bigword);
        (gdbarch, floatformats_ieee_double_littlebyte_bigword);
      set_gdbarch_long_double_format
      set_gdbarch_long_double_format
        (gdbarch, floatformats_ieee_double_littlebyte_bigword);
        (gdbarch, floatformats_ieee_double_littlebyte_bigword);
    }
    }
  else
  else
    {
    {
      set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
      set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
      set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
      set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
    }
    }
 
 
  if (tdesc_data)
  if (tdesc_data)
    tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
    tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
 
 
  /* Add standard register aliases.  We add aliases even for those
  /* Add standard register aliases.  We add aliases even for those
     nanes which are used by the current architecture - it's simpler,
     nanes which are used by the current architecture - it's simpler,
     and does no harm, since nothing ever lists user registers.  */
     and does no harm, since nothing ever lists user registers.  */
  for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
  for (i = 0; i < ARRAY_SIZE (arm_register_aliases); i++)
    user_reg_add (gdbarch, arm_register_aliases[i].name,
    user_reg_add (gdbarch, arm_register_aliases[i].name,
                  value_of_arm_user_reg, &arm_register_aliases[i].regnum);
                  value_of_arm_user_reg, &arm_register_aliases[i].regnum);
 
 
  return gdbarch;
  return gdbarch;
}
}
 
 
static void
static void
arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
arm_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
{
{
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
 
  if (tdep == NULL)
  if (tdep == NULL)
    return;
    return;
 
 
  fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%lx"),
  fprintf_unfiltered (file, _("arm_dump_tdep: Lowest pc = 0x%lx"),
                      (unsigned long) tdep->lowest_pc);
                      (unsigned long) tdep->lowest_pc);
}
}
 
 
extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
extern initialize_file_ftype _initialize_arm_tdep; /* -Wmissing-prototypes */
 
 
void
void
_initialize_arm_tdep (void)
_initialize_arm_tdep (void)
{
{
  struct ui_file *stb;
  struct ui_file *stb;
  long length;
  long length;
  struct cmd_list_element *new_set, *new_show;
  struct cmd_list_element *new_set, *new_show;
  const char *setname;
  const char *setname;
  const char *setdesc;
  const char *setdesc;
  const char *const *regnames;
  const char *const *regnames;
  int numregs, i, j;
  int numregs, i, j;
  static char *helptext;
  static char *helptext;
  char regdesc[1024], *rdptr = regdesc;
  char regdesc[1024], *rdptr = regdesc;
  size_t rest = sizeof (regdesc);
  size_t rest = sizeof (regdesc);
 
 
  gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
  gdbarch_register (bfd_arch_arm, arm_gdbarch_init, arm_dump_tdep);
 
 
  /* Register an ELF OS ABI sniffer for ARM binaries.  */
  /* Register an ELF OS ABI sniffer for ARM binaries.  */
  gdbarch_register_osabi_sniffer (bfd_arch_arm,
  gdbarch_register_osabi_sniffer (bfd_arch_arm,
                                  bfd_target_elf_flavour,
                                  bfd_target_elf_flavour,
                                  arm_elf_osabi_sniffer);
                                  arm_elf_osabi_sniffer);
 
 
  /* Get the number of possible sets of register names defined in opcodes.  */
  /* Get the number of possible sets of register names defined in opcodes.  */
  num_disassembly_options = get_arm_regname_num_options ();
  num_disassembly_options = get_arm_regname_num_options ();
 
 
  /* Add root prefix command for all "set arm"/"show arm" commands.  */
  /* Add root prefix command for all "set arm"/"show arm" commands.  */
  add_prefix_cmd ("arm", no_class, set_arm_command,
  add_prefix_cmd ("arm", no_class, set_arm_command,
                  _("Various ARM-specific commands."),
                  _("Various ARM-specific commands."),
                  &setarmcmdlist, "set arm ", 0, &setlist);
                  &setarmcmdlist, "set arm ", 0, &setlist);
 
 
  add_prefix_cmd ("arm", no_class, show_arm_command,
  add_prefix_cmd ("arm", no_class, show_arm_command,
                  _("Various ARM-specific commands."),
                  _("Various ARM-specific commands."),
                  &showarmcmdlist, "show arm ", 0, &showlist);
                  &showarmcmdlist, "show arm ", 0, &showlist);
 
 
  /* Sync the opcode insn printer with our register viewer.  */
  /* Sync the opcode insn printer with our register viewer.  */
  parse_arm_disassembler_option ("reg-names-std");
  parse_arm_disassembler_option ("reg-names-std");
 
 
  /* Initialize the array that will be passed to
  /* Initialize the array that will be passed to
     add_setshow_enum_cmd().  */
     add_setshow_enum_cmd().  */
  valid_disassembly_styles
  valid_disassembly_styles
    = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
    = xmalloc ((num_disassembly_options + 1) * sizeof (char *));
  for (i = 0; i < num_disassembly_options; i++)
  for (i = 0; i < num_disassembly_options; i++)
    {
    {
      numregs = get_arm_regnames (i, &setname, &setdesc, &regnames);
      numregs = get_arm_regnames (i, &setname, &setdesc, &regnames);
      valid_disassembly_styles[i] = setname;
      valid_disassembly_styles[i] = setname;
      length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
      length = snprintf (rdptr, rest, "%s - %s\n", setname, setdesc);
      rdptr += length;
      rdptr += length;
      rest -= length;
      rest -= length;
      /* When we find the default names, tell the disassembler to use
      /* When we find the default names, tell the disassembler to use
         them.  */
         them.  */
      if (!strcmp (setname, "std"))
      if (!strcmp (setname, "std"))
        {
        {
          disassembly_style = setname;
          disassembly_style = setname;
          set_arm_regname_option (i);
          set_arm_regname_option (i);
        }
        }
    }
    }
  /* Mark the end of valid options.  */
  /* Mark the end of valid options.  */
  valid_disassembly_styles[num_disassembly_options] = NULL;
  valid_disassembly_styles[num_disassembly_options] = NULL;
 
 
  /* Create the help text.  */
  /* Create the help text.  */
  stb = mem_fileopen ();
  stb = mem_fileopen ();
  fprintf_unfiltered (stb, "%s%s%s",
  fprintf_unfiltered (stb, "%s%s%s",
                      _("The valid values are:\n"),
                      _("The valid values are:\n"),
                      regdesc,
                      regdesc,
                      _("The default is \"std\"."));
                      _("The default is \"std\"."));
  helptext = ui_file_xstrdup (stb, &length);
  helptext = ui_file_xstrdup (stb, &length);
  ui_file_delete (stb);
  ui_file_delete (stb);
 
 
  add_setshow_enum_cmd("disassembler", no_class,
  add_setshow_enum_cmd("disassembler", no_class,
                       valid_disassembly_styles, &disassembly_style,
                       valid_disassembly_styles, &disassembly_style,
                       _("Set the disassembly style."),
                       _("Set the disassembly style."),
                       _("Show the disassembly style."),
                       _("Show the disassembly style."),
                       helptext,
                       helptext,
                       set_disassembly_style_sfunc,
                       set_disassembly_style_sfunc,
                       NULL, /* FIXME: i18n: The disassembly style is \"%s\".  */
                       NULL, /* FIXME: i18n: The disassembly style is \"%s\".  */
                       &setarmcmdlist, &showarmcmdlist);
                       &setarmcmdlist, &showarmcmdlist);
 
 
  add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
  add_setshow_boolean_cmd ("apcs32", no_class, &arm_apcs_32,
                           _("Set usage of ARM 32-bit mode."),
                           _("Set usage of ARM 32-bit mode."),
                           _("Show usage of ARM 32-bit mode."),
                           _("Show usage of ARM 32-bit mode."),
                           _("When off, a 26-bit PC will be used."),
                           _("When off, a 26-bit PC will be used."),
                           NULL,
                           NULL,
                           NULL, /* FIXME: i18n: Usage of ARM 32-bit mode is %s.  */
                           NULL, /* FIXME: i18n: Usage of ARM 32-bit mode is %s.  */
                           &setarmcmdlist, &showarmcmdlist);
                           &setarmcmdlist, &showarmcmdlist);
 
 
  /* Add a command to allow the user to force the FPU model.  */
  /* Add a command to allow the user to force the FPU model.  */
  add_setshow_enum_cmd ("fpu", no_class, fp_model_strings, &current_fp_model,
  add_setshow_enum_cmd ("fpu", no_class, fp_model_strings, &current_fp_model,
                        _("Set the floating point type."),
                        _("Set the floating point type."),
                        _("Show the floating point type."),
                        _("Show the floating point type."),
                        _("auto - Determine the FP typefrom the OS-ABI.\n\
                        _("auto - Determine the FP typefrom the OS-ABI.\n\
softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n\
softfpa - Software FP, mixed-endian doubles on little-endian ARMs.\n\
fpa - FPA co-processor (GCC compiled).\n\
fpa - FPA co-processor (GCC compiled).\n\
softvfp - Software FP with pure-endian doubles.\n\
softvfp - Software FP with pure-endian doubles.\n\
vfp - VFP co-processor."),
vfp - VFP co-processor."),
                        set_fp_model_sfunc, show_fp_model,
                        set_fp_model_sfunc, show_fp_model,
                        &setarmcmdlist, &showarmcmdlist);
                        &setarmcmdlist, &showarmcmdlist);
 
 
  /* Add a command to allow the user to force the ABI.  */
  /* Add a command to allow the user to force the ABI.  */
  add_setshow_enum_cmd ("abi", class_support, arm_abi_strings, &arm_abi_string,
  add_setshow_enum_cmd ("abi", class_support, arm_abi_strings, &arm_abi_string,
                        _("Set the ABI."),
                        _("Set the ABI."),
                        _("Show the ABI."),
                        _("Show the ABI."),
                        NULL, arm_set_abi, arm_show_abi,
                        NULL, arm_set_abi, arm_show_abi,
                        &setarmcmdlist, &showarmcmdlist);
                        &setarmcmdlist, &showarmcmdlist);
 
 
  /* Debugging flag.  */
  /* Debugging flag.  */
  add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
  add_setshow_boolean_cmd ("arm", class_maintenance, &arm_debug,
                           _("Set ARM debugging."),
                           _("Set ARM debugging."),
                           _("Show ARM debugging."),
                           _("Show ARM debugging."),
                           _("When on, arm-specific debugging is enabled."),
                           _("When on, arm-specific debugging is enabled."),
                           NULL,
                           NULL,
                           NULL, /* FIXME: i18n: "ARM debugging is %s.  */
                           NULL, /* FIXME: i18n: "ARM debugging is %s.  */
                           &setdebuglist, &showdebuglist);
                           &setdebuglist, &showdebuglist);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.