gdb/
[deliverable/binutils-gdb.git] / gdb / xtensa-tdep.c
index c5c62f927245253c13e1efb7282f926254697e31..c3ed28327b4d4f12d1d5bcb599d72ea7cf7185d6 100644 (file)
@@ -1,12 +1,13 @@
 /* Target-dependent code for the Xtensa port of GDB, the GNU debugger.
 
-   Copyright (C) 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "frame.h"
+#include "solib-svr4.h"
 #include "symtab.h"
 #include "symfile.h"
 #include "objfiles.h"
@@ -35,7 +35,7 @@
 #include "regset.h"
 
 #include "dummy-frame.h"
-#include "elf/dwarf2.h"
+#include "dwarf2.h"
 #include "dwarf2-frame.h"
 #include "dwarf2loc.h"
 #include "frame.h"
@@ -53,6 +53,7 @@
 
 #include "xtensa-isa.h"
 #include "xtensa-tdep.h"
+#include "xtensa-config.h"
 
 
 static int xtensa_debug_level = 0;
@@ -80,7 +81,6 @@ static int xtensa_debug_level = 0;
 
 /* On Windowed ABI, we use a6 through a11 for passing arguments
    to a function called by GDB because CALL4 is used.  */
-#define ARGS_FIRST_REG         A6_REGNUM
 #define ARGS_NUM_REGS          6
 #define REGISTER_SIZE          4
 
@@ -91,25 +91,20 @@ static int xtensa_debug_level = 0;
 #define CALLINC(ps)            (((ps) & PS_CALLINC_MASK) >> PS_CALLINC_SHIFT)
 #define WINSIZE(ra)            (4 * (( (ra) >> 30) & 0x3))
 
-
-/* Convert a live Ax register number to the corresponding Areg number.  */
-#define AREG_NUMBER(r, wb) \
-  ((((r) - A0_REGNUM + (((wb) & WB_MASK) << WB_SHIFT)) & AREGS_MASK) + AR_BASE)
-
 /* ABI-independent macros.  */
-#define ARG_NOF            (CALL_ABI == CallAbiCall0Only ? C0_NARGS : (ARGS_NUM_REGS))
-#define ARG_1ST            (CALL_ABI == CallAbiCall0Only \
-                    ? (A0_REGNUM) + C0_ARGS : (ARGS_FIRST_REG))
-
-extern struct gdbarch_tdep *xtensa_config_tdep (struct gdbarch_info *);
-extern int xtensa_config_byte_order (struct gdbarch_info *);
-
+#define ARG_NOF(gdbarch) \
+  (gdbarch_tdep (gdbarch)->call_abi \
+   == CallAbiCall0Only ? C0_NARGS : (ARGS_NUM_REGS))
+#define ARG_1ST(gdbarch) \
+  (gdbarch_tdep (gdbarch)->call_abi  == CallAbiCall0Only \
+   ? (gdbarch_tdep (gdbarch)->a0_base + C0_ARGS) \
+   : (gdbarch_tdep (gdbarch)->a0_base + 6))
 
 /* XTENSA_IS_ENTRY tests whether the first byte of an instruction
    indicates that the instruction is an ENTRY instruction.  */
 
-#define XTENSA_IS_ENTRY(op1) \
-  ((gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) \
+#define XTENSA_IS_ENTRY(gdbarch, op1) \
+  ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) \
    ? ((op1) == 0x6c) : ((op1) == 0x36))
 
 #define XTENSA_ENTRY_LENGTH    3
@@ -121,6 +116,36 @@ extern int xtensa_config_byte_order (struct gdbarch_info *);
 #define PS_WOE                 (1<<18)
 #define PS_EXC                 (1<<4)
 
+/* Convert a live A-register number to the corresponding AR-register
+   number.  */
+static int
+arreg_number (struct gdbarch *gdbarch, int a_regnum, ULONGEST wb)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int arreg;
+
+  arreg = a_regnum - tdep->a0_base;
+  arreg += (wb & ((tdep->num_aregs - 1) >> 2)) << WB_SHIFT;
+  arreg &= tdep->num_aregs - 1;
+
+  return arreg + tdep->ar_base;
+}
+
+/* Convert a live AR-register number to the corresponding A-register order
+   number in a range [0..15].  Return -1, if AR_REGNUM is out of WB window.  */
+static int
+areg_number (struct gdbarch *gdbarch, int ar_regnum, unsigned int wb)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int areg;
+
+  areg = ar_regnum - tdep->ar_base;
+  if (areg < 0 || areg >= tdep->num_aregs)
+    return -1;
+  areg = (areg - wb * 4) & (tdep->num_aregs - 1);
+  return (areg > 15) ? -1 : areg;
+}
+
 static inline int
 windowing_enabled (CORE_ADDR ps)
 {
@@ -139,8 +164,9 @@ windowing_enabled (CORE_ADDR ps)
    method to call the inferior function.  */
 
 static int
-extract_call_winsize (CORE_ADDR pc)
+extract_call_winsize (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int winsize = 4;
   int insn;
   gdb_byte buf[4];
@@ -149,7 +175,7 @@ extract_call_winsize (CORE_ADDR pc)
 
   /* Read the previous instruction (should be a call[x]{4|8|12}.  */
   read_memory (pc-3, buf, 3);
-  insn = extract_unsigned_integer (buf, 3);
+  insn = extract_unsigned_integer (buf, 3, byte_order);
 
   /* Decode call instruction:
      Little Endian
@@ -159,7 +185,7 @@ extract_call_winsize (CORE_ADDR pc)
        call{0,4,8,12}   0101 || {00,01,10,11} || OFFSET
        callx{0,4,8,12}  0000 || {00,01,10,11} || 11 || OFFSET.  */
 
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+  if (byte_order == BFD_ENDIAN_LITTLE)
     {
       if (((insn & 0xf) == 0x5) || ((insn & 0xcf) == 0xc0))
        winsize = (insn & 0x30) >> 2;   /* 0, 4, 8, 12.  */
@@ -177,51 +203,40 @@ extract_call_winsize (CORE_ADDR pc)
 
 /* Returns the name of a register.  */
 static const char *
-xtensa_register_name (int regnum)
+xtensa_register_name (struct gdbarch *gdbarch, int regnum)
 {
   /* Return the name stored in the register map.  */
-  if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch)
-                             + gdbarch_num_pseudo_regs (current_gdbarch))
-    return REGMAP[regnum].name;
+  if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)
+                             + gdbarch_num_pseudo_regs (gdbarch))
+    return gdbarch_tdep (gdbarch)->regmap[regnum].name;
 
   internal_error (__FILE__, __LINE__, _("invalid register %d"), regnum);
   return 0;
 }
 
-static unsigned long
-xtensa_read_register (int regnum)
-{
-  ULONGEST value;
-
-  regcache_raw_read_unsigned (get_current_regcache (), regnum, &value);
-  return (unsigned long) value;
-}
-
 /* Return the type of a register.  Create a new type, if necessary.  */
 
-static struct ctype_cache
-{
-  struct ctype_cache *next;
-  int size;
-  struct type *virtual_type;
-} *type_entries = NULL;
-
 static struct type *
 xtensa_register_type (struct gdbarch *gdbarch, int regnum)
 {
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
   /* Return signed integer for ARx and Ax registers.  */
-  if ((regnum >= AR_BASE && regnum < AR_BASE + NUM_AREGS)
-      || (regnum >= A0_BASE && regnum < A0_BASE + 16))
-    return builtin_type_int;
+  if ((regnum >= tdep->ar_base
+       && regnum < tdep->ar_base + tdep->num_aregs)
+      || (regnum >= tdep->a0_base
+         && regnum < tdep->a0_base + 16))
+    return builtin_type (gdbarch)->builtin_int;
 
-  if (regnum == gdbarch_pc_regnum (current_gdbarch) || regnum == A1_REGNUM)
-    return lookup_pointer_type (builtin_type_void);
+  if (regnum == gdbarch_pc_regnum (gdbarch)
+      || regnum == tdep->a0_base + 1)
+    return builtin_type (gdbarch)->builtin_data_ptr;
 
   /* Return the stored type for all other registers.  */
-  else if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch)
-                                  + gdbarch_num_pseudo_regs (current_gdbarch))
+  else if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch)
+                                  + gdbarch_num_pseudo_regs (gdbarch))
     {
-      xtensa_register_t* reg = &REGMAP[regnum];
+      xtensa_register_t* reg = &tdep->regmap[regnum];
 
       /* Set ctype for this register (only the first time).  */
 
@@ -235,27 +250,27 @@ xtensa_register_type (struct gdbarch *gdbarch, int regnum)
          switch (size)
            {
            case 1:
-             reg->ctype = builtin_type_uint8;
+             reg->ctype = builtin_type (gdbarch)->builtin_uint8;
              break;
 
            case 2:
-             reg->ctype = builtin_type_uint16;
+             reg->ctype = builtin_type (gdbarch)->builtin_uint16;
              break;
 
            case 4:
-             reg->ctype = builtin_type_uint32;
+             reg->ctype = builtin_type (gdbarch)->builtin_uint32;
              break;
 
            case 8:
-             reg->ctype = builtin_type_uint64;
+             reg->ctype = builtin_type (gdbarch)->builtin_uint64;
              break;
 
            case 16:
-             reg->ctype = builtin_type_uint128;
+             reg->ctype = builtin_type (gdbarch)->builtin_uint128;
              break;
 
            default:
-             for (tp = type_entries; tp != NULL; tp = tp->next)
+             for (tp = tdep->type_entries; tp != NULL; tp = tp->next)
                if (tp->size == size)
                  break;
 
@@ -263,14 +278,13 @@ xtensa_register_type (struct gdbarch *gdbarch, int regnum)
                {
                  char *name = xmalloc (16);
                  tp = xmalloc (sizeof (struct ctype_cache));
-                 tp->next = type_entries;
-                 type_entries = tp;
+                 tp->next = tdep->type_entries;
+                 tdep->type_entries = tp;
                  tp->size = size;
 
                  sprintf (name, "int%d", size * 8);
-                 tp->virtual_type = init_type (TYPE_CODE_INT, size,
-                                               TYPE_FLAG_UNSIGNED, name,
-                                               NULL);
+                 tp->virtual_type
+                   = arch_integer_type (gdbarch, size * 8, 1, xstrdup (name));
                }
 
              reg->ctype = tp->virtual_type;
@@ -289,18 +303,17 @@ xtensa_register_type (struct gdbarch *gdbarch, int regnum)
    to n for An.  So, we only have to add the base number for A0.  */
 
 static int
-xtensa_reg_to_regnum (int regnum)
+xtensa_reg_to_regnum (struct gdbarch *gdbarch, int regnum)
 {
   int i;
 
   if (regnum >= 0 && regnum < 16)
-    return A0_BASE + regnum;
+    return gdbarch_tdep (gdbarch)->a0_base + regnum;
 
   for (i = 0;
-       i < gdbarch_num_regs (current_gdbarch)
-          + gdbarch_num_pseudo_regs (current_gdbarch);
+       i < gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
        i++)
-    if (regnum == REGMAP[i].target_number)
+    if (regnum == gdbarch_tdep (gdbarch)->regmap[i].target_number)
       return i;
 
   internal_error (__FILE__, __LINE__,
@@ -334,7 +347,7 @@ xtensa_register_write_masked (struct regcache *regcache,
   DEBUGTRACE ("xtensa_register_write_masked ()\n");
 
   /* Copy the masked register to host byte-order.  */
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (get_regcache_arch (regcache)) == BFD_ENDIAN_BIG)
     for (i = 0; i < bytesize; i++)
       {
        mem >>= 8;
@@ -464,7 +477,7 @@ xtensa_register_read_masked (struct regcache *regcache,
   ptr = value;
   mem = *ptr;
 
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (get_regcache_arch (regcache)) == BFD_ENDIAN_BIG)
     for (i = 0; i < bytesize; i++)
       {
        if ((i & 3) == 0)
@@ -491,34 +504,50 @@ xtensa_pseudo_register_read (struct gdbarch *gdbarch,
                             int regnum,
                             gdb_byte *buffer)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
   DEBUGTRACE ("xtensa_pseudo_register_read (... regnum = %d (%s) ...)\n",
-             regnum, xtensa_register_name (regnum));
+             regnum, xtensa_register_name (gdbarch, regnum));
 
-  if (regnum == FP_ALIAS)
-     regnum = A1_REGNUM;
+  if (regnum == gdbarch_num_regs (gdbarch)
+               + gdbarch_num_pseudo_regs (gdbarch) - 1)
+     regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
 
   /* Read aliases a0..a15, if this is a Windowed ABI.  */
-  if (ISA_USE_WINDOWED_REGISTERS
-      && (regnum >= A0_REGNUM) && (regnum <= A15_REGNUM))
+  if (gdbarch_tdep (gdbarch)->isa_use_windowed_registers
+      && (regnum >= gdbarch_tdep (gdbarch)->a0_base)
+      && (regnum <= gdbarch_tdep (gdbarch)->a0_base + 15))
     {
       gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
 
-      regcache_raw_read (regcache, WB_REGNUM, buf);
-      regnum = AREG_NUMBER (regnum, extract_unsigned_integer (buf, 4));
+      regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf);
+      regnum = arreg_number (gdbarch, regnum,
+                            extract_unsigned_integer (buf, 4, byte_order));
     }
 
   /* We can always read non-pseudo registers.  */
-  if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch))
+  if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch))
     regcache_raw_read (regcache, regnum, buffer);
 
+
+  /* We have to find out how to deal with priveleged registers.
+     Let's treat them as pseudo-registers, but we cannot read/write them.  */
+     
+  else if (regnum < gdbarch_tdep (gdbarch)->a0_base)
+    {
+      buffer[0] = (gdb_byte)0;
+      buffer[1] = (gdb_byte)0;
+      buffer[2] = (gdb_byte)0;
+      buffer[3] = (gdb_byte)0;
+    }
   /* Pseudo registers.  */
   else if (regnum >= 0
-           && regnum < gdbarch_num_regs (current_gdbarch)
-                       + gdbarch_num_pseudo_regs (current_gdbarch))
+           && regnum < gdbarch_num_regs (gdbarch)
+                       + gdbarch_num_pseudo_regs (gdbarch))
     {
-      xtensa_register_t *reg = &REGMAP[regnum];
+      xtensa_register_t *reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
       xtensa_register_type_t type = reg->type;
-      int flags = XTENSA_TARGET_FLAGS;
+      int flags = gdbarch_tdep (gdbarch)->target_flags;
 
       /* We cannot read Unknown or Unmapped registers.  */
       if (type == xtRegisterTypeUnmapped || type == xtRegisterTypeUnknown)
@@ -526,7 +555,7 @@ xtensa_pseudo_register_read (struct gdbarch *gdbarch,
          if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
            {
              warning (_("cannot read register %s"),
-                      xtensa_register_name (regnum));
+                      xtensa_register_name (gdbarch, regnum));
              return;
            }
        }
@@ -573,36 +602,49 @@ xtensa_pseudo_register_write (struct gdbarch *gdbarch,
                              int regnum,
                              const gdb_byte *buffer)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
   DEBUGTRACE ("xtensa_pseudo_register_write (... regnum = %d (%s) ...)\n",
-             regnum, xtensa_register_name (regnum));
+             regnum, xtensa_register_name (gdbarch, regnum));
 
-  if (regnum == FP_ALIAS)
-     regnum = A1_REGNUM;
+  if (regnum == gdbarch_num_regs (gdbarch)
+               + gdbarch_num_pseudo_regs (gdbarch) -1)
+     regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
 
   /* Renumber register, if aliase a0..a15 on Windowed ABI.  */
-  if (ISA_USE_WINDOWED_REGISTERS
-      && (regnum >= A0_REGNUM) && (regnum <= A15_REGNUM))
+  if (gdbarch_tdep (gdbarch)->isa_use_windowed_registers
+      && (regnum >= gdbarch_tdep (gdbarch)->a0_base)
+      && (regnum <= gdbarch_tdep (gdbarch)->a0_base + 15))
     {
       gdb_byte *buf = (gdb_byte *) alloca (MAX_REGISTER_SIZE);
       unsigned int wb;
 
-      regcache_raw_read (regcache, WB_REGNUM, buf);
-      regnum = AREG_NUMBER (regnum, extract_unsigned_integer (buf, 4));
+      regcache_raw_read (regcache,
+                        gdbarch_tdep (gdbarch)->wb_regnum, buf);
+      regnum = arreg_number (gdbarch, regnum,
+                            extract_unsigned_integer (buf, 4, byte_order));
     }
 
   /* We can always write 'core' registers.
      Note: We might have converted Ax->ARy.  */
-  if (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch))
+  if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch))
     regcache_raw_write (regcache, regnum, buffer);
 
+  /* We have to find out how to deal with priveleged registers.
+     Let's treat them as pseudo-registers, but we cannot read/write them.  */
+
+  else if (regnum < gdbarch_tdep (gdbarch)->a0_base)
+    {
+      return;
+    }
   /* Pseudo registers.  */
   else if (regnum >= 0
-          && regnum < gdbarch_num_regs (current_gdbarch)
-                      + gdbarch_num_pseudo_regs (current_gdbarch))
+          && regnum < gdbarch_num_regs (gdbarch)
+                      + gdbarch_num_pseudo_regs (gdbarch))
     {
-      xtensa_register_t *reg = &REGMAP[regnum];
+      xtensa_register_t *reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
       xtensa_register_type_t type = reg->type;
-      int flags = XTENSA_TARGET_FLAGS;
+      int flags = gdbarch_tdep (gdbarch)->target_flags;
 
       /* On most targets, we cannot write registers
         of type "Unknown" or "Unmapped".  */
@@ -611,7 +653,7 @@ xtensa_pseudo_register_write (struct gdbarch *gdbarch,
          if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
            {
              warning (_("cannot write register %s"),
-                      xtensa_register_name (regnum));
+                      xtensa_register_name (gdbarch, regnum));
              return;
            }
        }
@@ -719,7 +761,7 @@ xtensa_register_reggroup_p (struct gdbarch *gdbarch,
                            int regnum,
                            struct reggroup *group)
 {
-  xtensa_register_t* reg = &REGMAP[regnum];
+  xtensa_register_t* reg = &gdbarch_tdep (gdbarch)->regmap[regnum];
   xtensa_register_type_t type = reg->type;
   xtensa_register_group_t rg = reg->group;
   int cp_number;
@@ -746,7 +788,7 @@ xtensa_register_reggroup_p (struct gdbarch *gdbarch,
   if (group == vector_reggroup || group == xtensa_vectra_reggroup)
     return rg & xtRegisterGroupVectra;
   if (group == save_reggroup || group == restore_reggroup)
-    return (regnum < gdbarch_num_regs (current_gdbarch)
+    return (regnum < gdbarch_num_regs (gdbarch)
            && (reg->flags & SAVE_REST_FLAGS) == SAVE_REST_VALID);
   if ((cp_number = xtensa_coprocessor_register_group (group)) >= 0)
     return rg & (xtRegisterGroupCP0 << cp_number);
@@ -767,39 +809,44 @@ xtensa_supply_gregset (const struct regset *regset,
                       size_t len)
 {
   const xtensa_elf_gregset_t *regs = gregs;
+  struct gdbarch *gdbarch = get_regcache_arch (rc);
   int i;
 
-  DEBUGTRACE ("xtensa_supply_gregset (..., regnum==%d, ...) \n", regnum);
-
-  if (regnum == gdbarch_pc_regnum (current_gdbarch) || regnum == -1)
-    regcache_raw_supply (rc,
-                        gdbarch_pc_regnum (current_gdbarch),
-                        (char *) &regs->pc);
-  if (regnum == gdbarch_ps_regnum (current_gdbarch) || regnum == -1)
-    regcache_raw_supply (rc, gdbarch_ps_regnum (current_gdbarch),
-                        (char *) &regs->ps);
-  if (regnum == WB_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, WB_REGNUM, (char *) &regs->windowbase);
-  if (regnum == WS_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, WS_REGNUM, (char *) &regs->windowstart);
-  if (regnum == LBEG_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, LBEG_REGNUM, (char *) &regs->lbeg);
-  if (regnum == LEND_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, LEND_REGNUM, (char *) &regs->lend);
-  if (regnum == LCOUNT_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, LCOUNT_REGNUM, (char *) &regs->lcount);
-  if (regnum == SAR_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, SAR_REGNUM, (char *) &regs->sar);
-  if (regnum == EXCCAUSE_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, EXCCAUSE_REGNUM, (char *) &regs->exccause);
-  if (regnum == EXCVADDR_REGNUM || regnum == -1)
-    regcache_raw_supply (rc, EXCVADDR_REGNUM, (char *) &regs->excvaddr);
-  if (regnum >= AR_BASE && regnum < AR_BASE + NUM_AREGS)
-    regcache_raw_supply (rc, regnum, (char *) &regs->ar[regnum - AR_BASE]);
+  DEBUGTRACE ("xtensa_supply_gregset (..., regnum==%d, ...)\n", regnum);
+
+  if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_pc_regnum (gdbarch), (char *) &regs->pc);
+  if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_ps_regnum (gdbarch), (char *) &regs->ps);
+  if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->wb_regnum,
+                        (char *) &regs->windowbase);
+  if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->ws_regnum,
+                        (char *) &regs->windowstart);
+  if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->lbeg_regnum,
+                        (char *) &regs->lbeg);
+  if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->lend_regnum,
+                        (char *) &regs->lend);
+  if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->lcount_regnum,
+                        (char *) &regs->lcount);
+  if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1)
+    regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->sar_regnum,
+                        (char *) &regs->sar);
+  if (regnum >=gdbarch_tdep (gdbarch)->ar_base
+      && regnum < gdbarch_tdep (gdbarch)->ar_base
+                   + gdbarch_tdep (gdbarch)->num_aregs)
+    regcache_raw_supply (rc, regnum,
+                        (char *) &regs->ar[regnum - gdbarch_tdep
+                          (gdbarch)->ar_base]);
   else if (regnum == -1)
     {
-      for (i = 0; i < NUM_AREGS; ++i)
-       regcache_raw_supply (rc, AR_BASE + i, (char *) &regs->ar[i]);
+      for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i)
+       regcache_raw_supply (rc, gdbarch_tdep (gdbarch)->ar_base + i,
+                            (char *) &regs->ar[i]);
     }
 }
 
@@ -823,8 +870,8 @@ xtensa_regset_from_core_section (struct gdbarch *core_arch,
                                 size_t sect_size)
 {
   DEBUGTRACE ("xtensa_regset_from_core_section "
-             "(..., sect_name==\"%s\", sect_size==%x) \n",
-             sect_name, sect_size);
+             "(..., sect_name==\"%s\", sect_size==%x)\n",
+             sect_name, (unsigned int) sect_size);
 
   if (strcmp (sect_name, ".reg") == 0
       && sect_size >= sizeof(xtensa_elf_gregset_t))
@@ -842,15 +889,23 @@ xtensa_regset_from_core_section (struct gdbarch *core_arch,
 /* Frame cache part for Windowed ABI.  */
 typedef struct xtensa_windowed_frame_cache
 {
-  int wb;              /* Base for this frame; -1 if not in regfile.  */
-  int callsize;                /* Call size to next frame.  */
-  int ws;
+  int wb;              /* WINDOWBASE of the previous frame.  */
+  int callsize;                /* Call size of this frame.  */
+  int ws;              /* WINDOWSTART of the previous frame.  It
+                          keeps track of life windows only.  If there
+                          is no bit set for the window, that means it
+                          had been already spilled because of window
+                          overflow.  */
+
+  /* Spilled A-registers from the previous frame.
+     AREGS[i] == -1, if corresponding AR is alive.  */
   CORE_ADDR aregs[XTENSA_NUM_SAVED_AREGS];
 } xtensa_windowed_frame_cache_t;
 
 /* Call0 ABI Definitions.  */
 
-#define C0_MAXOPDS  3  /* Maximum number of operands for prologue analysis.  */
+#define C0_MAXOPDS  3  /* Maximum number of operands for prologue
+                          analysis.  */
 #define C0_NREGS   16  /* Number of A-registers to track.  */
 #define C0_CLESV   12  /* Callee-saved registers are here and up.  */
 #define C0_SP      1   /* Register used as SP.  */
@@ -877,8 +932,9 @@ typedef struct xtensa_c0reg
     int            fr_reg;     /* original register from which register content
                           is derived, or C0_CONST, or C0_INEXP.  */
     int            fr_ofs;     /* constant offset from reg, or immediate value.  */
-    int            to_stk;     /* offset from original SP to register (4-byte aligned),
-                          or C0_NOSTK if register has not been saved.  */
+    int            to_stk;     /* offset from original SP to register (4-byte
+                          aligned), or C0_NOSTK if register has not
+                          been saved.  */
 } xtensa_c0reg_t;
 
 
@@ -886,7 +942,8 @@ typedef struct xtensa_c0reg
 typedef struct xtensa_call0_frame_cache
 {
   int c0_frmsz;                                /* Stack frame size.  */
-  int c0_hasfp;                                /* Current frame uses frame pointer.  */
+  int c0_hasfp;                                /* Current frame uses frame
+                                          pointer.  */
   int fp_regnum;                       /* A-register used as FP.  */
   int c0_fp;                           /* Actual value of frame pointer.  */
   xtensa_c0reg_t c0_rt[C0_NREGS];      /* Register tracking information.  */
@@ -894,11 +951,11 @@ typedef struct xtensa_call0_frame_cache
 
 typedef struct xtensa_frame_cache
 {
-  CORE_ADDR base;      /* Stack pointer of the next frame.  */
+  CORE_ADDR base;      /* Stack pointer of this frame.  */
   CORE_ADDR pc;                /* PC at the entry point to the function.  */
-  CORE_ADDR ra;                /* The raw return address.  */
-  CORE_ADDR ps;                /* The PS register of the frame.  */
-  CORE_ADDR prev_sp;   /* Stack Pointer of the frame.  */
+  CORE_ADDR ra;                /* The raw return address (without CALLINC).  */
+  CORE_ADDR ps;                /* The PS register of this frame.  */
+  CORE_ADDR prev_sp;   /* Stack Pointer of the previous frame.  */
   int call0;           /* It's a call0 framework (else windowed).  */
   union
     {
@@ -941,6 +998,7 @@ xtensa_alloc_frame_cache (int windowed)
   else
     {
       cache->wd.wb = 0;
+      cache->wd.ws = 0;
       cache->wd.callsize = -1;
 
       for (i = 0; i < XTENSA_NUM_SAVED_AREGS; i++)
@@ -961,113 +1019,247 @@ static CORE_ADDR
 xtensa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   gdb_byte buf[8];
+  CORE_ADDR pc;
 
-  DEBUGTRACE ("xtensa_unwind_pc (next_frame = %p)\n", next_frame);
+  DEBUGTRACE ("xtensa_unwind_pc (next_frame = %s)\n", 
+               host_address_to_string (next_frame));
 
-  frame_unwind_register (next_frame, gdbarch_pc_regnum (current_gdbarch), buf);
+  frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
+  pc = extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr);
 
-  DEBUGINFO ("[xtensa_unwind_pc] pc = 0x%08x\n", (unsigned int)
-            extract_typed_address (buf, builtin_type_void_func_ptr));
+  DEBUGINFO ("[xtensa_unwind_pc] pc = 0x%08x\n", (unsigned int) pc);
 
-  return extract_typed_address (buf, builtin_type_void_func_ptr);
+  return pc;
 }
 
 
 static struct frame_id
-xtensa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+xtensa_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 {
   CORE_ADDR pc, fp;
 
-  /* next_frame->prev is a dummy frame.  Return a frame ID of that frame.  */
-
-  DEBUGTRACE ("xtensa_unwind_dummy_id ()\n");
+  /* THIS-FRAME is a dummy frame.  Return a frame ID of that frame.  */
 
-  pc = frame_pc_unwind (next_frame);
-  fp = frame_unwind_register_unsigned (next_frame, A1_REGNUM);
+  pc = get_frame_pc (this_frame);
+  fp = get_frame_register_unsigned
+        (this_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
 
   /* Make dummy frame ID unique by adding a constant.  */
   return frame_id_build (fp + SP_ALIGNMENT, pc);
 }
 
+/* Returns the best guess about which register is a frame pointer
+   for the function containing CURRENT_PC.  */
+
+#define XTENSA_ISA_BSZ         32              /* Instruction buffer size.  */
+#define XTENSA_ISA_BADPC       ((CORE_ADDR)0)  /* Bad PC value.  */
+
+static unsigned int
+xtensa_scan_prologue (struct gdbarch *gdbarch, CORE_ADDR current_pc)
+{
+#define RETURN_FP goto done
+
+  unsigned int fp_regnum = gdbarch_tdep (gdbarch)->a0_base + 1;
+  CORE_ADDR start_addr;
+  xtensa_isa isa;
+  xtensa_insnbuf ins, slot;
+  char ibuf[XTENSA_ISA_BSZ];
+  CORE_ADDR ia, bt, ba;
+  xtensa_format ifmt;
+  int ilen, islots, is;
+  xtensa_opcode opc;
+  const char *opcname;
+
+  find_pc_partial_function (current_pc, NULL, &start_addr, NULL);
+  if (start_addr == 0)
+    return fp_regnum;
+
+  if (!xtensa_default_isa)
+    xtensa_default_isa = xtensa_isa_init (0, 0);
+  isa = xtensa_default_isa;
+  gdb_assert (XTENSA_ISA_BSZ >= xtensa_isa_maxlength (isa));
+  ins = xtensa_insnbuf_alloc (isa);
+  slot = xtensa_insnbuf_alloc (isa);
+  ba = 0;
+
+  for (ia = start_addr, bt = ia; ia < current_pc ; ia += ilen)
+    {
+      if (ia + xtensa_isa_maxlength (isa) > bt)
+        {
+         ba = ia;
+         bt = (ba + XTENSA_ISA_BSZ) < current_pc
+           ? ba + XTENSA_ISA_BSZ : current_pc;
+         if (target_read_memory (ba, ibuf, bt - ba) != 0)
+           RETURN_FP;
+       }
+
+      xtensa_insnbuf_from_chars (isa, ins, &ibuf[ia-ba], 0);
+      ifmt = xtensa_format_decode (isa, ins);
+      if (ifmt == XTENSA_UNDEFINED)
+       RETURN_FP;
+      ilen = xtensa_format_length (isa, ifmt);
+      if (ilen == XTENSA_UNDEFINED)
+       RETURN_FP;
+      islots = xtensa_format_num_slots (isa, ifmt);
+      if (islots == XTENSA_UNDEFINED)
+       RETURN_FP;
+      
+      for (is = 0; is < islots; ++is)
+       {
+         if (xtensa_format_get_slot (isa, ifmt, is, ins, slot))
+           RETURN_FP;
+         
+         opc = xtensa_opcode_decode (isa, ifmt, is, slot);
+         if (opc == XTENSA_UNDEFINED) 
+           RETURN_FP;
+         
+         opcname = xtensa_opcode_name (isa, opc);
+
+         if (strcasecmp (opcname, "mov.n") == 0
+             || strcasecmp (opcname, "or") == 0)
+           {
+             unsigned int register_operand;
+
+             /* Possible candidate for setting frame pointer
+                from A1.  This is what we are looking for.  */
+
+             if (xtensa_operand_get_field (isa, opc, 1, ifmt, 
+                                           is, slot, &register_operand) != 0)
+               RETURN_FP;
+             if (xtensa_operand_decode (isa, opc, 1, &register_operand) != 0)
+               RETURN_FP;
+             if (register_operand == 1)  /* Mov{.n} FP A1.  */
+               {
+                 if (xtensa_operand_get_field (isa, opc, 0, ifmt, is, slot, 
+                                               &register_operand) != 0)
+                   RETURN_FP;
+                 if (xtensa_operand_decode (isa, opc, 0,
+                                            &register_operand) != 0)
+                   RETURN_FP;
+
+                 fp_regnum
+                   = gdbarch_tdep (gdbarch)->a0_base + register_operand;
+                 RETURN_FP;
+               }
+           }
+
+         if (
+             /* We have problems decoding the memory.  */
+             opcname == NULL 
+             || strcasecmp (opcname, "ill") == 0
+             || strcasecmp (opcname, "ill.n") == 0
+             /* Hit planted breakpoint.  */
+             || strcasecmp (opcname, "break") == 0
+             || strcasecmp (opcname, "break.n") == 0
+             /* Flow control instructions finish prologue.  */
+             || xtensa_opcode_is_branch (isa, opc) > 0
+             || xtensa_opcode_is_jump   (isa, opc) > 0
+             || xtensa_opcode_is_loop   (isa, opc) > 0
+             || xtensa_opcode_is_call   (isa, opc) > 0
+             || strcasecmp (opcname, "simcall") == 0
+             || strcasecmp (opcname, "syscall") == 0)
+           /* Can not continue analysis.  */
+           RETURN_FP;
+       }
+    }
+done:
+  xtensa_insnbuf_free(isa, slot);
+  xtensa_insnbuf_free(isa, ins);
+  return fp_regnum;
+}
+
 /* The key values to identify the frame using "cache" are 
 
-       cache->base    = SP of this frame;
+       cache->base    = SP (or best guess about FP) of this frame;
        cache->pc      = entry-PC (entry point of the frame function);
-       cache->prev_sp = SP of the previous frame.
-*/
+       cache->prev_sp = SP of the previous frame.  */
 
 static void
-call0_frame_cache (struct frame_info *next_frame,
+call0_frame_cache (struct frame_info *this_frame,
                   xtensa_frame_cache_t *cache,
-                  CORE_ADDR pc);
+                  CORE_ADDR pc, CORE_ADDR litbase);
 
 static struct xtensa_frame_cache *
-xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
+xtensa_frame_cache (struct frame_info *this_frame, void **this_cache)
 {
   xtensa_frame_cache_t *cache;
   CORE_ADDR ra, wb, ws, pc, sp, ps;
-  unsigned int ps_regnum = gdbarch_ps_regnum (current_gdbarch);
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  unsigned int fp_regnum;
   char op1;
   int  windowed;
 
-  DEBUGTRACE ("xtensa_frame_cache (next_frame %p, *this_cache %p)\n",
-             next_frame, this_cache ? *this_cache : (void*)0xdeadbeef);
-
   if (*this_cache)
     return *this_cache;
 
-  windowed = windowing_enabled (xtensa_read_register (ps_regnum));
+  ps = get_frame_register_unsigned (this_frame, gdbarch_ps_regnum (gdbarch));
+  windowed = windowing_enabled (ps);
 
   /* Get pristine xtensa-frame.  */
   cache = xtensa_alloc_frame_cache (windowed);
   *this_cache = cache;
 
-  pc = frame_unwind_register_unsigned (next_frame,
-                                      gdbarch_pc_regnum (current_gdbarch));
+  pc = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
 
   if (windowed)
     {
       /* Get WINDOWBASE, WINDOWSTART, and PS registers.  */
-      wb = frame_unwind_register_unsigned (next_frame, WB_REGNUM);
-      ws = frame_unwind_register_unsigned (next_frame, WS_REGNUM);
-      ps = frame_unwind_register_unsigned (next_frame, ps_regnum);
+      wb = get_frame_register_unsigned (this_frame, 
+                                       gdbarch_tdep (gdbarch)->wb_regnum);
+      ws = get_frame_register_unsigned (this_frame,
+                                       gdbarch_tdep (gdbarch)->ws_regnum);
 
-      op1 = read_memory_integer (pc, 1);
-      if (XTENSA_IS_ENTRY (op1))
+      op1 = read_memory_integer (pc, 1, byte_order);
+      if (XTENSA_IS_ENTRY (gdbarch, op1))
        {
          int callinc = CALLINC (ps);
-         ra = frame_unwind_register_unsigned (next_frame,
-                                              A0_REGNUM + callinc * 4);
-         
-         DEBUGINFO("[xtensa_frame_cache] 'entry' at 0x%08x\n (callinc = %d)",
-                   (int)pc, callinc);
+         ra = get_frame_register_unsigned
+           (this_frame, gdbarch_tdep (gdbarch)->a0_base + callinc * 4);
          
          /* ENTRY hasn't been executed yet, therefore callsize is still 0.  */
          cache->wd.callsize = 0;
          cache->wd.wb = wb;
          cache->wd.ws = ws;
-         cache->prev_sp = frame_unwind_register_unsigned (next_frame,
-                                                          A1_REGNUM);
+         cache->prev_sp = get_frame_register_unsigned
+                            (this_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+
+         /* This only can be the outermost frame since we are
+            just about to execute ENTRY.  SP hasn't been set yet.
+            We can assume any frame size, because it does not
+            matter, and, let's fake frame base in cache.  */
+         cache->base = cache->prev_sp + 16;
+
+         cache->pc = pc;
+         cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
+         cache->ps = (ps & ~PS_CALLINC_MASK)
+           | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+
+         return cache;
        }
       else
        {
-         ra = frame_unwind_register_unsigned (next_frame, A0_REGNUM);
+         fp_regnum = xtensa_scan_prologue (gdbarch, pc);
+         ra = get_frame_register_unsigned (this_frame,
+                                           gdbarch_tdep (gdbarch)->a0_base);
          cache->wd.callsize = WINSIZE (ra);
-         cache->wd.wb = (wb - cache->wd.callsize / 4) & (NUM_AREGS / 4 - 1);
+         cache->wd.wb = (wb - cache->wd.callsize / 4)
+                         & (gdbarch_tdep (gdbarch)->num_aregs / 4 - 1);
          cache->wd.ws = ws & ~(1 << wb);
-       }
 
-      cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
-      cache->ra = (cache->pc & 0xc0000000) | (ra & 0x3fffffff);
-      cache->ps = (ps & ~PS_CALLINC_MASK)
-       | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+         cache->pc = get_frame_func (this_frame);
+         cache->ra = (pc & 0xc0000000) | (ra & 0x3fffffff);
+         cache->ps = (ps & ~PS_CALLINC_MASK)
+           | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+       }
 
       if (cache->wd.ws == 0)
        {
          int i;
 
          /* Set A0...A3.  */
-         sp = frame_unwind_register_unsigned (next_frame, A1_REGNUM) - 16;
+         sp = get_frame_register_unsigned
+           (this_frame, gdbarch_tdep (gdbarch)->a0_base + 1) - 16;
          
          for (i = 0; i < 4; i++, sp += 4)
            {
@@ -1077,11 +1269,13 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
          if (cache->wd.callsize > 4)
            {
              /* Set A4...A7/A11.  */
-             /* Read an SP of the previous frame.  */
-             sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
+             /* Get the SP of the frame previous to the previous one.
+                To achieve this, we have to dereference SP twice.  */
+             sp = (CORE_ADDR) read_memory_integer (sp - 12, 4, byte_order);
+             sp = (CORE_ADDR) read_memory_integer (sp - 12, 4, byte_order);
              sp -= cache->wd.callsize * 4;
 
-             for ( /* i=4  */ ; i < cache->wd.callsize; i++, sp += 4)
+             for ( i = 4; i < cache->wd.callsize; i++, sp += 4)
                {
                  cache->wd.aregs[i] = sp;
                }
@@ -1089,146 +1283,84 @@ xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
        }
 
       if ((cache->prev_sp == 0) && ( ra != 0 ))
-       /* If RA is equal to 0 this frame is an outermost frame.  Leave
-          cache->prev_sp unchanged marking the boundary of the frame stack.  */
+       /* If RA is equal to 0 this frame is an outermost frame.
+          Leave cache->prev_sp unchanged marking the boundary of the
+          frame stack.  */
        {
-         if (cache->wd.ws == 0)
+         if ((cache->wd.ws & (1 << cache->wd.wb)) == 0)
            {
              /* Register window overflow already happened.
                 We can read caller's SP from the proper spill loction.  */
-             cache->prev_sp =
-               read_memory_integer (cache->wd.aregs[1],
-                                    register_size (current_gdbarch,
-                                                   A1_REGNUM));
+             sp = get_frame_register_unsigned
+               (this_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
+             cache->prev_sp = read_memory_integer (sp - 12, 4, byte_order);
            }
          else
            {
              /* Read caller's frame SP directly from the previous window.  */
-             int regnum = AREG_NUMBER (A1_REGNUM, cache->wd.wb);
+             int regnum = arreg_number
+                            (gdbarch, gdbarch_tdep (gdbarch)->a0_base + 1,
+                             cache->wd.wb);
 
-             cache->prev_sp = xtensa_read_register (regnum);
+             cache->prev_sp = get_frame_register_unsigned (this_frame,
+                                                           regnum);
            }
        }
     }
   else /* Call0 framework.  */
     {
-      call0_frame_cache (next_frame, cache, pc);
+      unsigned int litbase_regnum = gdbarch_tdep (gdbarch)->litbase_regnum;
+      CORE_ADDR litbase = (litbase_regnum == -1)
+       ? 0 : get_frame_register_unsigned (this_frame, litbase_regnum);
+
+      call0_frame_cache (this_frame, cache, pc, litbase);
+      fp_regnum = cache->c0.fp_regnum;
     }
 
-  cache->base = frame_unwind_register_unsigned (next_frame,A1_REGNUM);
+  cache->base = get_frame_register_unsigned (this_frame, fp_regnum);
 
   return cache;
 }
 
 static void
-xtensa_frame_this_id (struct frame_info *next_frame,
+xtensa_frame_this_id (struct frame_info *this_frame,
                      void **this_cache,
                      struct frame_id *this_id)
 {
   struct xtensa_frame_cache *cache =
-    xtensa_frame_cache (next_frame, this_cache);
-  struct frame_id id;
-
-  DEBUGTRACE ("xtensa_frame_this_id (next 0x%08x, *this 0x%08x)\n",
-             (unsigned int) next_frame, (unsigned int) *this_cache);
+    xtensa_frame_cache (this_frame, this_cache);
 
   if (cache->prev_sp == 0)
     return;
 
-  id = frame_id_build (cache->prev_sp, cache->pc);
-  if (frame_id_eq (id, get_frame_id(next_frame)))
-    {
-      warning(_("\
-Frame stack is corrupted. That could happen because of \
-setting register(s) from GDB or stopping execution \
-inside exception handler. Frame backtracing has stopped. \
-It can make some GDB commands work inappropriately.\n"));
-      cache->prev_sp = 0;
-      return;
-    }
-  (*this_id) = id;
-}
-
-static int
-call0_frame_get_reg_at_entry (struct frame_info *next_frame,
-                             struct xtensa_frame_cache *cache,
-                             int regnum, 
-                             CORE_ADDR *addrp,
-                             enum lval_type *lval,
-                             gdb_byte *valuep)
-{
-  CORE_ADDR fp, spe;
-  int stkofs;
-  int reg = (regnum >= AR_BASE && regnum <= (AR_BASE + C0_NREGS))
-               ? regnum - AR_BASE : regnum;
-
-  /* Determine stack pointer on entry to this function, based on FP.  */
-  spe = cache->c0.c0_fp - cache->c0.c0_rt[cache->c0.fp_regnum].fr_ofs;
-
-  /* If register was saved to the stack frame in the prologue, retrieve it.  */
-  stkofs = cache->c0.c0_rt[reg].to_stk;
-  if (stkofs != C0_NOSTK)
-    {
-      *lval = lval_memory;
-      *addrp = spe + stkofs;
-
-      if (valuep)
-       read_memory (*addrp, valuep, register_size (current_gdbarch, regnum));
-
-      return 1;
-    }
-
-  /* If not callee-saved or if known to have been overwritten, give up.  */
-  if (reg < C0_CLESV 
-      || cache->c0.c0_rt[reg].fr_reg != reg
-      || cache->c0.c0_rt[reg].fr_ofs != 0)
-    return 0;
-
-  if (get_frame_type (next_frame) != NORMAL_FRAME)
-    /* TODO: Do we need a special case for DUMMY_FRAME here?  */
-    return 0;
-
-  return call0_frame_get_reg_at_entry (get_next_frame(next_frame),
-                                      cache, regnum, addrp, lval, valuep);
+  (*this_id) = frame_id_build (cache->prev_sp, cache->pc);
 }
 
-static void
-xtensa_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+xtensa_frame_prev_register (struct frame_info *this_frame,
                            void **this_cache,
-                           int regnum,
-                           int *optimizedp,
-                           enum lval_type *lvalp,
-                           CORE_ADDR *addrp,
-                           int *realnump,
-                           gdb_byte *valuep)
+                           int regnum)
 {
-  struct xtensa_frame_cache *cache =
-    xtensa_frame_cache (next_frame, this_cache);
-  CORE_ADDR saved_reg = 0;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct xtensa_frame_cache *cache;
+  ULONGEST saved_reg = 0;
   int done = 1;
 
-  DEBUGTRACE ("xtensa_frame_prev_register (next 0x%08x, "
-             "*this 0x%08x, regnum %d (%s), ...)\n",
-             (unsigned int) next_frame,
-             *this_cache ? (unsigned int) *this_cache : 0, regnum,
-             xtensa_register_name (regnum));
+  if (*this_cache == NULL)
+    *this_cache = xtensa_frame_cache (this_frame, this_cache);
+  cache = *this_cache;
 
-  if (regnum ==gdbarch_pc_regnum (current_gdbarch))
+  if (regnum ==gdbarch_pc_regnum (gdbarch))
     saved_reg = cache->ra;
-  else if (regnum == A1_REGNUM)
+  else if (regnum == gdbarch_tdep (gdbarch)->a0_base + 1)
     saved_reg = cache->prev_sp;
   else if (!cache->call0)
     {
-      if (regnum == WS_REGNUM)
-       {
-         if (cache->wd.ws != 0)
-           saved_reg = cache->wd.ws;
-         else
-           saved_reg = 1 << cache->wd.wb;
-       }
-      else if (regnum == WB_REGNUM)
+      if (regnum == gdbarch_tdep (gdbarch)->ws_regnum)
+       saved_reg = cache->wd.ws;
+      else if (regnum == gdbarch_tdep (gdbarch)->wb_regnum)
        saved_reg = cache->wd.wb;
-      else if (regnum == gdbarch_ps_regnum (current_gdbarch))
+      else if (regnum == gdbarch_ps_regnum (gdbarch))
        saved_reg = cache->ps;
       else
        done = 0;
@@ -1237,50 +1369,36 @@ xtensa_frame_prev_register (struct frame_info *next_frame,
     done = 0;
 
   if (done)
-    {
-      *optimizedp = 0;
-      *lvalp = not_lval;
-      *addrp = 0;
-      *realnump = -1;
-      if (valuep)
-       store_unsigned_integer (valuep, 4, saved_reg);
-
-      return;
-    }
+    return frame_unwind_got_constant (this_frame, regnum, saved_reg);
 
   if (!cache->call0) /* Windowed ABI.  */
     {
-      /* Convert A-register numbers to AR-register numbers.  */
-      if (regnum >= A0_REGNUM && regnum <= A15_REGNUM)
-       regnum = AREG_NUMBER (regnum, cache->wd.wb);
-
-      /* Check if AR-register has been saved to stack.  */
-      if (regnum >= AR_BASE && regnum <= (AR_BASE + NUM_AREGS))
+      /* Convert A-register numbers to AR-register numbers,
+        if we deal with A-register.  */
+      if (regnum >= gdbarch_tdep (gdbarch)->a0_base
+          && regnum <= gdbarch_tdep (gdbarch)->a0_base + 15)
+       regnum = arreg_number (gdbarch, regnum, cache->wd.wb);
+
+      /* Check, if we deal with AR-register saved on stack.  */
+      if (regnum >= gdbarch_tdep (gdbarch)->ar_base
+         && regnum <= (gdbarch_tdep (gdbarch)->ar_base
+                        + gdbarch_tdep (gdbarch)->num_aregs))
        {
-         int areg = regnum - AR_BASE - (cache->wd.wb * 4);
+         int areg = areg_number (gdbarch, regnum, cache->wd.wb);
 
          if (areg >= 0
              && areg < XTENSA_NUM_SAVED_AREGS
              && cache->wd.aregs[areg] != -1)
-           {
-             *optimizedp = 0;
-             *lvalp = lval_memory;
-             *addrp = cache->wd.aregs[areg];
-             *realnump = -1;
-
-             if (valuep)
-               read_memory (*addrp, valuep,
-                            register_size (current_gdbarch, regnum));
-
-             DEBUGINFO ("[xtensa_frame_prev_register] register on stack\n");
-             return;
-           }
+           return frame_unwind_got_memory (this_frame, regnum,
+                                           cache->wd.aregs[areg]);
        }
     }
   else /* Call0 ABI.  */
     {
-      int reg = (regnum >= AR_BASE && regnum <= (AR_BASE + C0_NREGS))
-                       ? regnum - AR_BASE : regnum;
+      int reg = (regnum >= gdbarch_tdep (gdbarch)->ar_base
+               && regnum <= (gdbarch_tdep (gdbarch)->ar_base
+                              + C0_NREGS))
+                 ? regnum - gdbarch_tdep (gdbarch)->ar_base : regnum;
 
       if (reg < C0_NREGS)
        {
@@ -1294,17 +1412,9 @@ xtensa_frame_prev_register (struct frame_info *next_frame,
              /* Determine SP on entry based on FP.  */
              spe = cache->c0.c0_fp
                - cache->c0.c0_rt[cache->c0.fp_regnum].fr_ofs;
-             *optimizedp = 0;
-             *lvalp = lval_memory;
-             *addrp = spe + stkofs;
-             *realnump = -1;
-         
-             if (valuep)
-               read_memory (*addrp, valuep,
-                            register_size (current_gdbarch, regnum));
-         
-             DEBUGINFO ("[xtensa_frame_prev_register] register on stack\n");
-             return;
+
+             return frame_unwind_got_memory (this_frame, regnum,
+                                             spe + stkofs);
            }
        }
     }
@@ -1312,34 +1422,25 @@ xtensa_frame_prev_register (struct frame_info *next_frame,
   /* All other registers have been either saved to
      the stack or are still alive in the processor.  */
 
-  *optimizedp = 0;
-  *lvalp = lval_register;
-  *addrp = 0;
-  *realnump = regnum;
-  if (valuep)
-    frame_unwind_register (next_frame, (*realnump), valuep);
+  return frame_unwind_got_register (this_frame, regnum, regnum);
 }
 
 
 static const struct frame_unwind
-xtensa_frame_unwind =
+xtensa_unwind =
 {
   NORMAL_FRAME,
   xtensa_frame_this_id,
-  xtensa_frame_prev_register
+  xtensa_frame_prev_register,
+  NULL,
+  default_frame_sniffer
 };
 
-static const struct frame_unwind *
-xtensa_frame_sniffer (struct frame_info *next_frame)
-{
-  return &xtensa_frame_unwind;
-}
-
 static CORE_ADDR
-xtensa_frame_base_address (struct frame_info *next_frame, void **this_cache)
+xtensa_frame_base_address (struct frame_info *this_frame, void **this_cache)
 {
   struct xtensa_frame_cache *cache =
-    xtensa_frame_cache (next_frame, this_cache);
+    xtensa_frame_cache (this_frame, this_cache);
 
   return cache->base;
 }
@@ -1347,7 +1448,7 @@ xtensa_frame_base_address (struct frame_info *next_frame, void **this_cache)
 static const struct frame_base
 xtensa_frame_base =
 {
-  &xtensa_frame_unwind,
+  &xtensa_unwind,
   xtensa_frame_base_address,
   xtensa_frame_base_address,
   xtensa_frame_base_address
@@ -1359,6 +1460,7 @@ xtensa_extract_return_value (struct type *type,
                             struct regcache *regcache,
                             void *dst)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   bfd_byte *valbuf = dst;
   int len = TYPE_LENGTH (type);
   ULONGEST pc, wb;
@@ -1369,32 +1471,34 @@ xtensa_extract_return_value (struct type *type,
 
   gdb_assert(len > 0);
 
-  if (CALL_ABI != CallAbiCall0Only)
+  if (gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
     {
       /* First, we have to find the caller window in the register file.  */
-      regcache_raw_read_unsigned (regcache,
-                             gdbarch_pc_regnum (current_gdbarch), &pc);
-      callsize = extract_call_winsize (pc);
+      regcache_raw_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch), &pc);
+      callsize = extract_call_winsize (gdbarch, pc);
 
       /* On Xtensa, we can return up to 4 words (or 2 for call12).  */
       if (len > (callsize > 8 ? 8 : 16))
        internal_error (__FILE__, __LINE__,
-                       _("cannot extract return value of %d bytes long"), len);
+                       _("cannot extract return value of %d bytes long"),
+                       len);
 
       /* Get the register offset of the return
         register (A2) in the caller window.  */
-      regcache_raw_read_unsigned (regcache, WB_REGNUM, &wb);
-      areg = AREG_NUMBER(A2_REGNUM + callsize, wb);
+      regcache_raw_read_unsigned
+       (regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb);
+      areg = arreg_number (gdbarch,
+                         gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
     }
   else
     {
       /* No windowing hardware - Call0 ABI.  */
-      areg = A0_REGNUM + C0_ARGS;
+      areg = gdbarch_tdep (gdbarch)->a0_base + C0_ARGS;
     }
 
   DEBUGINFO ("[xtensa_extract_return_value] areg %d len %d\n", areg, len);
 
-  if (len < 4 && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (len < 4 && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     offset = 4 - len;
 
   for (; len > 0; len -= 4, areg++, valbuf += 4)
@@ -1412,6 +1516,7 @@ xtensa_store_return_value (struct type *type,
                           struct regcache *regcache,
                           const void *dst)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   const bfd_byte *valbuf = dst;
   unsigned int areg;
   ULONGEST pc, wb;
@@ -1421,28 +1526,29 @@ xtensa_store_return_value (struct type *type,
 
   DEBUGTRACE ("xtensa_store_return_value (...)\n");
 
-  if (CALL_ABI != CallAbiCall0Only)
+  if (gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
     {
-      regcache_raw_read_unsigned (regcache, WB_REGNUM, &wb);
-  regcache_raw_read_unsigned (regcache,
-                             gdbarch_pc_regnum (current_gdbarch), &pc);
-      callsize = extract_call_winsize (pc);
+      regcache_raw_read_unsigned 
+       (regcache, gdbarch_tdep (gdbarch)->wb_regnum, &wb);
+      regcache_raw_read_unsigned (regcache, gdbarch_pc_regnum (gdbarch), &pc);
+      callsize = extract_call_winsize (gdbarch, pc);
 
       if (len > (callsize > 8 ? 8 : 16))
        internal_error (__FILE__, __LINE__,
                        _("unimplemented for this length: %d"),
                        TYPE_LENGTH (type));
-      areg = AREG_NUMBER (A2_REGNUM + callsize, wb);
+      areg = arreg_number (gdbarch,
+                          gdbarch_tdep (gdbarch)->a0_base + 2 + callsize, wb);
 
       DEBUGTRACE ("[xtensa_store_return_value] callsize %d wb %d\n",
               callsize, (int) wb);
     }
   else
     {
-      areg = A0_REGNUM + C0_ARGS;
+      areg = gdbarch_tdep (gdbarch)->a0_base + C0_ARGS;
     }
 
-  if (len < 4 && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (len < 4 && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     offset = 4 - len;
 
   for (; len > 0; len -= 4, areg++, valbuf += 4)
@@ -1457,6 +1563,7 @@ xtensa_store_return_value (struct type *type,
 
 static enum return_value_convention
 xtensa_return_value (struct gdbarch *gdbarch,
+                    struct type *func_type,
                     struct type *valtype,
                     struct regcache *regcache,
                     gdb_byte *readbuf,
@@ -1501,6 +1608,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
                        int struct_return,
                        CORE_ADDR struct_addr)
 {
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int i;
   int size, onstack_size;
   gdb_byte *buf = (gdb_byte *) alloca (16);
@@ -1513,8 +1621,8 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
     int align;                 /* alignment */
     union
     {
-      int offset;              /* stack offset if on stack */
-      int regno;               /* regno if in register */
+      int offset;              /* stack offset if on stack */
+      int regno;               /* regno if in register */
     } u;
   };
 
@@ -1537,8 +1645,9 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
         {
          struct value *arg = args[i];
          struct type *arg_type = check_typedef (value_type (arg));
-         fprintf_unfiltered (gdb_stdlog, "%2d: 0x%08x %3d ",
-                             i, (int) arg, TYPE_LENGTH (arg_type));
+         fprintf_unfiltered (gdb_stdlog, "%2d: %s %3d ", i,
+                             host_address_to_string (arg),
+                             TYPE_LENGTH (arg_type));
          switch (TYPE_CODE (arg_type))
            {
            case TYPE_CODE_INT:
@@ -1551,8 +1660,8 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
              fprintf_unfiltered (gdb_stdlog, "%3d", TYPE_CODE (arg_type));
              break;
            }
-         fprintf_unfiltered (gdb_stdlog, " 0x%08x\n",
-                             (unsigned int) value_contents (arg));
+         fprintf_unfiltered (gdb_stdlog, " %s\n",
+                             host_address_to_string (value_contents (arg)));
        }
     }
 
@@ -1583,9 +1692,10 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
        case TYPE_CODE_ENUM:
 
          /* Cast argument to long if necessary as the mask does it too.  */
-         if (TYPE_LENGTH (arg_type) < TYPE_LENGTH (builtin_type_long))
+         if (TYPE_LENGTH (arg_type)
+             < TYPE_LENGTH (builtin_type (gdbarch)->builtin_long))
            {
-             arg_type = builtin_type_long;
+             arg_type = builtin_type (gdbarch)->builtin_long;
              arg = value_cast (arg_type, arg);
            }
          /* Aligment is equal to the type length for the basic types.  */
@@ -1595,15 +1705,16 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
        case TYPE_CODE_FLT:
 
          /* Align doubles correctly.  */
-         if (TYPE_LENGTH (arg_type) == TYPE_LENGTH (builtin_type_double))
-           info->align = TYPE_LENGTH (builtin_type_double);
+         if (TYPE_LENGTH (arg_type)
+             == TYPE_LENGTH (builtin_type (gdbarch)->builtin_double))
+           info->align = TYPE_LENGTH (builtin_type (gdbarch)->builtin_double);
          else
-           info->align = TYPE_LENGTH (builtin_type_long);
+           info->align = TYPE_LENGTH (builtin_type (gdbarch)->builtin_long);
          break;
 
        case TYPE_CODE_STRUCT:
        default:
-         info->align = TYPE_LENGTH (builtin_type_long);
+         info->align = TYPE_LENGTH (builtin_type (gdbarch)->builtin_long);
          break;
        }
       info->length = TYPE_LENGTH (arg_type);
@@ -1613,7 +1724,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
       size = (size + info->align - 1) & ~(info->align - 1);
       onstack_size = (onstack_size + info->align - 1) & ~(info->align - 1);
 
-      if (size + info->length > REGISTER_SIZE * ARG_NOF)
+      if (size + info->length > REGISTER_SIZE * ARG_NOF (gdbarch))
        {
          info->onstack = 1;
          info->u.offset = onstack_size;
@@ -1622,7 +1733,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
       else
        {
          info->onstack = 0;
-         info->u.regno = ARG_1ST + size / REGISTER_SIZE;
+         info->u.regno = ARG_1ST (gdbarch) + size / REGISTER_SIZE;
        }
       size += info->length;
     }
@@ -1631,7 +1742,8 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
   sp = align_down (sp - onstack_size, SP_ALIGNMENT);
 
   /* Simulate MOVSP, if Windowed ABI.  */
-  if ((CALL_ABI != CallAbiCall0Only) && (sp != osp))
+  if ((gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
+      && (sp != osp))
     {
       read_memory (osp - 16, buf, 16);
       write_memory (sp - 16, buf, 16);
@@ -1641,8 +1753,8 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
 
   if (struct_return)
     {
-      store_unsigned_integer (buf, REGISTER_SIZE, struct_addr);
-      regcache_cooked_write (regcache, ARG_1ST, buf);
+      store_unsigned_integer (buf, REGISTER_SIZE, byte_order, struct_addr);
+      regcache_cooked_write (regcache, ARG_1ST (gdbarch), buf);
     }
 
   for (i = 0; i < nargs; i++)
@@ -1659,7 +1771,7 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
             applies for structures smaller than one word.  */
 
          if (n < REGISTER_SIZE
-             && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+             && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
            offset += (REGISTER_SIZE - n);
 
          write_memory (offset, info->contents, info->length);
@@ -1677,13 +1789,13 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
             than REGISTER_SIZE; for larger odd-sized structures the excess
             will be left-aligned in the register on both endiannesses.  */
 
-         if (n < REGISTER_SIZE
-             && gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+         if (n < REGISTER_SIZE && byte_order == BFD_ENDIAN_BIG)
            {
-             ULONGEST v = extract_unsigned_integer (cp, REGISTER_SIZE);
+             ULONGEST v;
+             v = extract_unsigned_integer (cp, REGISTER_SIZE, byte_order);
              v = v >> ((REGISTER_SIZE - n) * TARGET_CHAR_BIT);
 
-             store_unsigned_integer (buf, REGISTER_SIZE, v);
+             store_unsigned_integer (buf, REGISTER_SIZE, byte_order, v);
              regcache_cooked_write (regcache, r, buf);
 
              cp += REGISTER_SIZE;
@@ -1706,24 +1818,37 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
      The return address for the current function (in A0) is
      saved in the dummy frame, so we can savely overwrite A0 here.  */
 
-  if (CALL_ABI != CallAbiCall0Only)
+  if (gdbarch_tdep (gdbarch)->call_abi != CallAbiCall0Only)
     {
       ra = (bp_addr & 0x3fffffff) | 0x40000000;
-      regcache_raw_read (regcache, gdbarch_ps_regnum (current_gdbarch), buf);
-      ps = extract_unsigned_integer (buf, 4) & ~0x00030000;
-      regcache_cooked_write_unsigned (regcache, A4_REGNUM, ra);
+      regcache_raw_read (regcache, gdbarch_ps_regnum (gdbarch), buf);
+      ps = extract_unsigned_integer (buf, 4, byte_order) & ~0x00030000;
+      regcache_cooked_write_unsigned
+       (regcache, gdbarch_tdep (gdbarch)->a0_base + 4, ra);
       regcache_cooked_write_unsigned (regcache,
-                                     gdbarch_ps_regnum (current_gdbarch),
+                                     gdbarch_ps_regnum (gdbarch),
                                      ps | 0x00010000);
+
+      /* All the registers have been saved.  After executing
+        dummy call, they all will be restored.  So it's safe
+        to modify WINDOWSTART register to make it look like there
+        is only one register window corresponding to WINDOWEBASE.  */
+
+      regcache_raw_read (regcache, gdbarch_tdep (gdbarch)->wb_regnum, buf);
+      regcache_cooked_write_unsigned
+       (regcache, gdbarch_tdep (gdbarch)->ws_regnum,
+        1 << extract_unsigned_integer (buf, 4, byte_order));
     }
   else
     {
       /* Simulate CALL0: write RA into A0 register.  */
-      regcache_cooked_write_unsigned (regcache, A0_REGNUM, bp_addr);
+      regcache_cooked_write_unsigned
+       (regcache, gdbarch_tdep (gdbarch)->a0_base, bp_addr);
     }
 
   /* Set new stack pointer and return it.  */
-  regcache_cooked_write_unsigned (regcache, A1_REGNUM, sp);
+  regcache_cooked_write_unsigned (regcache,
+                                 gdbarch_tdep (gdbarch)->a0_base + 1, sp);
   /* Make dummy frame ID unique by adding a constant.  */
   return sp + SP_ALIGNMENT;
 }
@@ -1739,7 +1864,8 @@ xtensa_push_dummy_call (struct gdbarch *gdbarch,
 #define DENSITY_LITTLE_BREAKPOINT { 0x2d, 0xf0 }
 
 static const unsigned char *
-xtensa_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+xtensa_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+                          int *lenptr)
 {
   static unsigned char big_breakpoint[] = BIG_BREAKPOINT;
   static unsigned char little_breakpoint[] = LITTLE_BREAKPOINT;
@@ -1748,9 +1874,9 @@ xtensa_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 
   DEBUGTRACE ("xtensa_breakpoint_from_pc (pc = 0x%08x)\n", (int) *pcptr);
 
-  if (ISA_USE_DENSITY_INSTRUCTIONS)
+  if (gdbarch_tdep (gdbarch)->isa_use_density_instructions)
     {
-      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
        {
          *lenptr = sizeof (density_big_breakpoint);
          return density_big_breakpoint;
@@ -1763,7 +1889,7 @@ xtensa_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
     }
   else
     {
-      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
        {
          *lenptr = sizeof (big_breakpoint);
          return big_breakpoint;
@@ -1795,7 +1921,8 @@ typedef enum {
   c0opc_mov,          /* Moving a register to a register.  */
   c0opc_movi,         /* Moving an immediate to a register.  */
   c0opc_l32r,         /* Loading a literal.  */
-  c0opc_s32i,         /* Storing word at fixed offset from a base register.  */
+  c0opc_s32i,         /* Storing word at fixed offset from a base
+                         register.  */
   c0opc_NrOf          /* Number of opcode classifications.  */
 } xtensa_insn_kind;
 
@@ -1863,11 +1990,13 @@ call0_classify_opcode (xtensa_isa isa, xtensa_opcode opc)
    the stack frame.  */
 
 static void
-call0_track_op (xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
+call0_track_op (struct gdbarch *gdbarch,
+               xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
                xtensa_insn_kind opclass, int nods, unsigned odv[],
-               CORE_ADDR pc, int spreg)
+               CORE_ADDR pc, CORE_ADDR litbase, int spreg)
 {
-  unsigned litbase, litaddr, litval;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  unsigned litaddr, litval;
 
   switch (opclass)
     {
@@ -1917,13 +2046,10 @@ call0_track_op (xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
     case c0opc_l32r:
       /* 2 operands: dst, literal offset.  */
       gdb_assert (nods == 2);
-      /* litbase = xtensa_get_litbase (pc); can be also used.  */
-      litbase = (LITBASE_REGNUM == -1)
-       ? 0 : xtensa_read_register (LITBASE_REGNUM);
       litaddr = litbase & 1
                  ? (litbase & ~1) + (signed)odv[1]
                  : (pc + 3  + (signed)odv[1]) & ~3;
-      litval = read_memory_integer(litaddr, 4);
+      litval = read_memory_integer (litaddr, 4, byte_order);
       dst[odv[0]].fr_reg = C0_CONST;
       dst[odv[0]].fr_ofs = litval;
       break;
@@ -1942,7 +2068,7 @@ call0_track_op (xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
        }
       break;
     default:
-       gdb_assert (0);
+       gdb_assert_not_reached ("unexpected instruction kind");
     }
 }
 
@@ -1976,14 +2102,14 @@ call0_track_op (xtensa_c0reg_t dst[], xtensa_c0reg_t src[],
       because they begin with default assumptions that analysis may change.  */
 
 static CORE_ADDR
-call0_analyze_prologue (CORE_ADDR start, CORE_ADDR pc,
+call0_analyze_prologue (struct gdbarch *gdbarch,
+                       CORE_ADDR start, CORE_ADDR pc, CORE_ADDR litbase,
                        int nregs, xtensa_c0reg_t rt[], int *call0)
 {
   CORE_ADDR ia;                    /* Current insn address in prologue.  */
   CORE_ADDR ba = 0;        /* Current address at base of insn buffer.  */
   CORE_ADDR bt;                    /* Current address at top+1 of insn buffer.  */
-  #define BSZ 32           /* Instruction buffer size.  */
-  char ibuf[BSZ];          /* Instruction buffer for decoding prologue.  */
+  char ibuf[XTENSA_ISA_BSZ];/* Instruction buffer for decoding prologue.  */
   xtensa_isa isa;          /* libisa ISA handle.  */
   xtensa_insnbuf ins, slot; /* libisa handle to decoded insn, slot.  */
   xtensa_format ifmt;      /* libisa instruction format.  */
@@ -2012,7 +2138,7 @@ call0_analyze_prologue (CORE_ADDR start, CORE_ADDR pc,
      Assume we may be in the prologue until we hit a flow control instr.  */
 
   rtmp = NULL;
-  body_pc = INT_MAX;
+  body_pc = UINT_MAX;
   end_pc = 0;
 
   /* Find out, if we have an information about the prologue from DWARF.  */
@@ -2040,8 +2166,10 @@ call0_analyze_prologue (CORE_ADDR start, CORE_ADDR pc,
     }
   else nregs = 0;
 
+  if (!xtensa_default_isa)
+    xtensa_default_isa = xtensa_isa_init (0, 0);
   isa = xtensa_default_isa;
-  gdb_assert (BSZ >= xtensa_isa_maxlength (isa));
+  gdb_assert (XTENSA_ISA_BSZ >= xtensa_isa_maxlength (isa));
   ins = xtensa_insnbuf_alloc (isa);
   slot = xtensa_insnbuf_alloc (isa);
 
@@ -2054,8 +2182,10 @@ call0_analyze_prologue (CORE_ADDR start, CORE_ADDR pc,
       if (ia + xtensa_isa_maxlength (isa) > bt)
         {
          ba = ia;
-         bt = (ba + BSZ) < body_pc ? ba + BSZ : body_pc;
+         bt = (ba + XTENSA_ISA_BSZ) < body_pc ? ba + XTENSA_ISA_BSZ : body_pc;
          read_memory (ba, ibuf, bt - ba);
+         /* If there is a memory reading error read_memory () will report it
+            and then throw an exception, stopping command execution.  */
        }
 
       /* Decode format information.  */
@@ -2096,7 +2226,8 @@ call0_analyze_prologue (CORE_ADDR start, CORE_ADDR pc,
            goto done;
 
          opc = xtensa_opcode_decode (isa, ifmt, is, slot);
-         DEBUGVERB ("[call0_analyze_prologue] instr addr = 0x%08x, opc = %d\n", 
+         DEBUGVERB ("[call0_analyze_prologue] instr "
+                    "addr = 0x%08x, opc = %d\n", 
                     (unsigned)ia, opc);
          if (opc == XTENSA_UNDEFINED) 
            opclass = c0opc_illegal;
@@ -2166,7 +2297,8 @@ call0_analyze_prologue (CORE_ADDR start, CORE_ADDR pc,
            }
 
          /* Track register movement and modification for this operation.  */
-         call0_track_op (rt, rtmp, opclass, nods, odv, ia, 1);
+         call0_track_op (gdbarch, rt, rtmp, opclass,
+                         nods, odv, ia, litbase, 1);
        }
     }
 done:
@@ -2174,17 +2306,18 @@ done:
             (unsigned)ia, fail ? "failed" : "succeeded");
   xtensa_insnbuf_free(isa, slot);
   xtensa_insnbuf_free(isa, ins);
-  return fail ? 0 : ia;
+  return fail ? XTENSA_ISA_BADPC : ia;
 }
 
-/* Initialize frame cache for the current frame.  The "next_frame" is the next
-   one relative to current frame.  "cache" is the pointer to the data structure
-   we have to initialize.  "pc" is curretnt PC.  */
+/* Initialize frame cache for the current frame in CALL0 ABI.  */
 
 static void
-call0_frame_cache (struct frame_info *next_frame,
-                  xtensa_frame_cache_t *cache, CORE_ADDR pc)
+call0_frame_cache (struct frame_info *this_frame,
+                  xtensa_frame_cache_t *cache,
+                  CORE_ADDR pc, CORE_ADDR litbase)
 {
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR start_pc;          /* The beginning of the function.  */
   CORE_ADDR body_pc=UINT_MAX;  /* PC, where prologue analysis stopped.  */
   CORE_ADDR sp, fp, ra;
@@ -2195,12 +2328,18 @@ call0_frame_cache (struct frame_info *next_frame,
 
   if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
     {
-      body_pc = call0_analyze_prologue (start_pc, pc, C0_NREGS,
+      body_pc = call0_analyze_prologue (gdbarch, start_pc, pc, litbase,
+                                       C0_NREGS,
                                        &cache->c0.c0_rt[0],
                                        &cache->call0);
+
+      if (body_pc == XTENSA_ISA_BADPC)
+       error (_("Xtensa-specific internal error: CALL0 prologue \
+analysis failed in this frame. GDB command execution stopped."));
     }
   
-  sp = frame_unwind_register_unsigned (next_frame, A1_REGNUM);
+  sp = get_frame_register_unsigned
+    (this_frame, gdbarch_tdep (gdbarch)->a0_base + 1);
   fp = sp; /* Assume FP == SP until proven otherwise.  */
 
   /* Get the frame information and FP (if used) at the current PC.
@@ -2219,12 +2358,12 @@ call0_frame_cache (struct frame_info *next_frame,
         was derived from SP.  Otherwise, it would be C0_FP.  */
       fp_regnum = c0_hasfp ? C0_FP : C0_SP;
       c0_frmsz = - cache->c0.c0_rt[fp_regnum].fr_ofs;
-      fp_regnum += A0_BASE;
+      fp_regnum += gdbarch_tdep (gdbarch)->a0_base;
     }
   else  /* No data from the prologue analysis.  */
     {
       c0_hasfp = 0;
-      fp_regnum = A0_BASE + C0_SP;
+      fp_regnum = gdbarch_tdep (gdbarch)->a0_base + C0_SP;
       c0_frmsz = 0;
       start_pc = pc;
    }
@@ -2235,7 +2374,7 @@ call0_frame_cache (struct frame_info *next_frame,
      alloca() and other dynamic allocations.  Adjust frame size by FP - SP.  */
   if (c0_hasfp)
     {
-      fp = frame_unwind_register_unsigned (next_frame, fp_regnum);
+      fp = get_frame_register_unsigned (this_frame, fp_regnum);
 
       /* Recalculate previous SP.  */
       prev_sp = fp + c0_frmsz;
@@ -2249,26 +2388,29 @@ call0_frame_cache (struct frame_info *next_frame,
   to_stk = cache->c0.c0_rt[C0_RA].to_stk;
   if (to_stk != C0_NOSTK)
     ra = (CORE_ADDR) 
-      read_memory_integer (sp + c0_frmsz + cache->c0.c0_rt[C0_RA].to_stk, 4);
+      read_memory_integer (sp + c0_frmsz + cache->c0.c0_rt[C0_RA].to_stk,
+                          4, byte_order);
 
   else if (cache->c0.c0_rt[C0_RA].fr_reg == C0_CONST
           && cache->c0.c0_rt[C0_RA].fr_ofs == 0)
     {
-      /* Special case for terminating backtrace at a function that wants to
-        be seen as the outermost.  Such a function will clear it's RA (A0)
-        register to 0 in the prologue instead of saving its original value.  */
+      /* Special case for terminating backtrace at a function that
+        wants to be seen as the outermost.  Such a function will
+        clear it's RA (A0) register to 0 in the prologue instead of
+        saving its original value.  */
       ra = 0;
     }
   else
     {
-      /* RA was copied to another register or (before any function call) may
-        still be in the original RA register.  This is not always reliable:
-        even in a leaf function, register tracking stops after prologue, and
-        even in prologue, non-prologue instructions (not tracked) may overwrite
-        RA or any register it was copied to.  If likely in prologue or before
-        any call, use retracking info and hope for the best (compiler should
-        have saved RA in stack if not in a leaf function).  If not in prologue,
-        too bad.  */
+      /* RA was copied to another register or (before any function
+        call) may still be in the original RA register.  This is not
+        always reliable: even in a leaf function, register tracking
+        stops after prologue, and even in prologue, non-prologue
+        instructions (not tracked) may overwrite RA or any register
+        it was copied to.  If likely in prologue or before any call,
+        use retracking info and hope for the best (compiler should
+        have saved RA in stack if not in a leaf function).  If not in
+        prologue, too bad.  */
 
       int i;
       for (i = 0; 
@@ -2277,10 +2419,11 @@ call0_frame_cache (struct frame_info *next_frame,
           ++i);
       if (i >= C0_NREGS && cache->c0.c0_rt[C0_RA].fr_reg == C0_RA)
        i = C0_RA;
-      if (i < C0_NREGS) /* Read from the next_frame.  */
+      if (i < C0_NREGS)
        {
-         ra = frame_unwind_register_unsigned (next_frame,
-                                              A0_REGNUM + cache->c0.c0_rt[i].fr_reg);
+         ra = get_frame_register_unsigned
+           (this_frame,
+            gdbarch_tdep (gdbarch)->a0_base + cache->c0.c0_rt[i].fr_reg);
        }
       else ra = 0;
     }
@@ -2333,8 +2476,8 @@ call0_frame_cache (struct frame_info *next_frame,
 
 /* #define DONT_SKIP_PROLOGUE  */
 
-CORE_ADDR
-xtensa_skip_prologue (CORE_ADDR start_pc)
+static CORE_ADDR
+xtensa_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
 {
   struct symtab_and_line prologue_sal;
   CORE_ADDR body_pc;
@@ -2367,7 +2510,7 @@ xtensa_skip_prologue (CORE_ADDR start_pc)
     }
 
   /* No debug line info.  Analyze prologue for Call0 or simply skip ENTRY.  */
-  body_pc = call0_analyze_prologue(start_pc, 0, 0, NULL, NULL);
+  body_pc = call0_analyze_prologue (gdbarch, start_pc, 0, 0, 0, NULL, NULL);
   return body_pc != 0 ? body_pc : start_pc;
 }
 
@@ -2378,7 +2521,7 @@ xtensa_verify_config (struct gdbarch *gdbarch)
   struct ui_file *log;
   struct cleanup *cleanups;
   struct gdbarch_tdep *tdep;
-  long dummy;
+  long length;
   char *buf;
 
   tdep = gdbarch_tdep (gdbarch);
@@ -2411,16 +2554,95 @@ xtensa_verify_config (struct gdbarch *gdbarch)
   if (tdep->a0_base == -1)
     fprintf_unfiltered (log, _("\n\ta0_base: No Ax registers"));
 
-  buf = ui_file_xstrdup (log, &dummy);
+  buf = ui_file_xstrdup (log, &length);
   make_cleanup (xfree, buf);
-  if (strlen (buf) > 0)
+  if (length > 0)
     internal_error (__FILE__, __LINE__,
                    _("the following are invalid: %s"), buf);
   do_cleanups (cleanups);
 }
 
+
+/* Derive specific register numbers from the array of registers.  */
+
+static void
+xtensa_derive_tdep (struct gdbarch_tdep *tdep)
+{
+  xtensa_register_t* rmap;
+  int n, max_size = 4;
+
+  tdep->num_regs = 0;
+  tdep->num_nopriv_regs = 0;
+
+/* Special registers 0..255 (core).  */
+#define XTENSA_DBREGN_SREG(n)  (0x0200+(n))
+
+  for (rmap = tdep->regmap, n = 0; rmap->target_number != -1; n++, rmap++)
+    {
+      if (rmap->target_number == 0x0020)
+       tdep->pc_regnum = n;
+      else if (rmap->target_number == 0x0100)
+       tdep->ar_base = n;
+      else if (rmap->target_number == 0x0000)
+       tdep->a0_base = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(72))
+       tdep->wb_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(73))
+       tdep->ws_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(233))
+       tdep->debugcause_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(232))
+       tdep->exccause_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(238))
+       tdep->excvaddr_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(0))
+       tdep->lbeg_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(1))
+       tdep->lend_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(2))
+       tdep->lcount_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(3))
+       tdep->sar_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(5))
+       tdep->litbase_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(230))
+       tdep->ps_regnum = n;
+#if 0
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(226))
+       tdep->interrupt_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(227))
+       tdep->interrupt2_regnum = n;
+      else if (rmap->target_number == XTENSA_DBREGN_SREG(224))
+       tdep->cpenable_regnum = n;
+#endif
+
+      if (rmap->byte_size > max_size)
+       max_size = rmap->byte_size;
+      if (rmap->mask != 0 && tdep->num_regs == 0)
+       tdep->num_regs = n;
+      /* Find out out how to deal with priveleged registers.
+
+         if ((rmap->flags & XTENSA_REGISTER_FLAGS_PRIVILEGED) != 0
+              && tdep->num_nopriv_regs == 0)
+           tdep->num_nopriv_regs = n;
+      */
+      if ((rmap->flags & XTENSA_REGISTER_FLAGS_PRIVILEGED) != 0
+         && tdep->num_regs == 0)
+       tdep->num_regs = n;
+    }
+
+  /* Number of pseudo registers.  */
+  tdep->num_pseudo_regs = n - tdep->num_regs;
+
+  /* Empirically determined maximum sizes.  */
+  tdep->max_register_raw_size = max_size;
+  tdep->max_register_virtual_size = max_size;
+}
+
 /* Module "constructor" function.  */
 
+extern struct gdbarch_tdep xtensa_tdep;
+
 static struct gdbarch *
 xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -2431,10 +2653,11 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   DEBUGTRACE ("gdbarch_init()\n");
 
   /* We have to set the byte order before we call gdbarch_alloc.  */
-  info.byte_order = xtensa_config_byte_order (&info);
+  info.byte_order = XCHAL_HAVE_BE ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
 
-  tdep = xtensa_config_tdep (&info);
+  tdep = &xtensa_tdep;
   gdbarch = gdbarch_alloc (&info, tdep);
+  xtensa_derive_tdep (tdep);
 
   /* Verify our configuration.  */
   xtensa_verify_config (gdbarch);
@@ -2450,16 +2673,15 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_pc_regnum (gdbarch, tdep->pc_regnum);
   set_gdbarch_ps_regnum (gdbarch, tdep->ps_regnum);
 
-  /* Renumber registers for known formats (stab, dwarf, and dwarf2).  */
+  /* Renumber registers for known formats (stabs and dwarf2).  */
   set_gdbarch_stab_reg_to_regnum (gdbarch, xtensa_reg_to_regnum);
-  set_gdbarch_dwarf_reg_to_regnum (gdbarch, xtensa_reg_to_regnum);
   set_gdbarch_dwarf2_reg_to_regnum (gdbarch, xtensa_reg_to_regnum);
 
   /* We provide our own function to get register information.  */
   set_gdbarch_register_name (gdbarch, xtensa_register_name);
   set_gdbarch_register_type (gdbarch, xtensa_register_type);
 
-  /* To call functions from GDB using dummy frame */
+  /* To call functions from GDB using dummy frame */
   set_gdbarch_push_dummy_call (gdbarch, xtensa_push_dummy_call);
 
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
@@ -2486,11 +2708,12 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_frame_align (gdbarch, xtensa_frame_align);
 
-  set_gdbarch_unwind_dummy_id (gdbarch, xtensa_unwind_dummy_id);
+  set_gdbarch_dummy_id (gdbarch, xtensa_dummy_id);
 
   /* Frame handling.  */
   frame_base_set_default (gdbarch, &xtensa_frame_base);
-  frame_unwind_append_sniffer (gdbarch, xtensa_frame_sniffer);
+  frame_unwind_append_unwinder (gdbarch, &xtensa_unwind);
+  dwarf2_append_unwinders (gdbarch);
 
   set_gdbarch_print_insn (gdbarch, print_insn_xtensa);
 
@@ -2502,15 +2725,21 @@ xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_regset_from_core_section (gdbarch,
                                        xtensa_regset_from_core_section);
 
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+
   return gdbarch;
 }
 
 static void
-xtensa_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+xtensa_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 {
   error (_("xtensa_dump_tdep(): not implemented"));
 }
 
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_xtensa_tdep;
+
 void
 _initialize_xtensa_tdep (void)
 {
@@ -2521,9 +2750,9 @@ _initialize_xtensa_tdep (void)
 
   add_setshow_zinteger_cmd ("xtensa",
                            class_maintenance,
-                           &xtensa_debug_level, _("\
-Set Xtensa debugging."), _("\
-Show Xtensa debugging."), _("\
+                           &xtensa_debug_level,
+                           _("Set Xtensa debugging."),
+                           _("Show Xtensa debugging."), _("\
 When non-zero, Xtensa-specific debugging is enabled. \
 Can be 1, 2, 3, or 4 indicating the level of debugging."),
                            NULL,
This page took 0.053976 seconds and 4 git commands to generate.