This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Xtensa GDB port -- revised patch


Hi Daniel and GDB maintainers,

Can you use the previous frame's stack pointer instead?
Is that going to work?

Yes, it works fine.


I've attached a modified patch.

CHANGELOG:

gdb/

2006-10-05 Maxim Grigoriev <maxim@tensilica.com>

  * NEWS: New port to Xtensa.
  * Makefile.in: Add dependencies for Xtensa files.
  * configure.tgt (xtensa*, xtensa*-*-elf*): New.
  * configure.host (xtensa*-*-elf*): New.
  * config/xtensa/xtensa.mt: New file.
  * xtensa-config.c: New file.
  * xtensa-tdep.h: New file.
  * xtensa-tdep.c: New file.

gdb/doc/

2006-10-05 Maxim Grigoriev <maxim@tensilica.com>

* gdb.texinfo: (Contributors): Add contributors of Xtensa port.

Maxim Grigoriev
Tensilica, Inc.
3255-6 Scott Boulevard
Santa Clara, CA 95054-3013
(w) 408-566-1770


Daniel Jacobowitz wrote:
On Wed, Sep 27, 2006 at 06:06:52PM -0700, Maxim Grigoriev wrote:
After some investigation, it turns out that the get_fp_num() function, which was "grubbing around in the private data structures of the symbol reader", is not needed at all. Perhaps that code was left over from an earlier version of GDB. Stack unwinding on Xtensa can be done using the register windows -- it requires neither prologue analysis to find the frame pointer nor DWARF unwind info. The only thing the get_fp_num() function was used for was identifying frames, but it seems like we can just use the stack pointer for the frame ID. (Is that right?) I've changed the code to do this and it appears to work fine: no DejaGnu regression has been detected, and manual testing on alloca-tests hasn't exposed anything.

I'm not entirely sure, but I think you're off by one frame. The goal is to use a long-lived value which will never change during a single execution of a function. So we normally use the DWARF concept of a "Call Frame Address" - the stack pointer at the time of the call. If you use the current stack pointer for the frame, then you are liable to change the ID during execution of a function, while single stepping. Normally this isn't a big problem; I don't remember offhand what the usual symptoms are.

Can you use the previous frame's stack pointer instead?  Is that going
to work?


Index: gdb/xtensa-config.c
===================================================================
@@ -0,0 +1,563 @@
+/* Configuration for the Xtensa architecture for GDB, the GNU debugger.
+
+   Copyright (C) 2003, 2005, 2006 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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "xtensa-config.h"
+#include "defs.h"
+#include "gdbarch.h"
+#include "xtensa-tdep.h"
+#include "gdbtypes.h"
+
+/* Check version of configuration file.  */
+#define XTENSA_CONFIG_VERSION 0x60
+#if XTENSA_TDEP_VERSION != XTENSA_CONFIG_VERSION
+#warning "xtensa-config.c version mismatch!"
+#endif
+
+
+/* Return the byte order from the configuration.
+   We need this function, because the byte order is needed even
+   before the target structure (tdep) has been set up.  */
+
+int
+xtensa_config_byte_order (void)
+{
+  return XCHAL_HAVE_BE ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE;
+}
+
+
+/* This routine returns the predefined architecture-dependent
+   parameter structure (tdep) and register map.  */
+
+struct gdbarch_tdep xtensa_tdep;
+
+struct gdbarch_tdep *
+xtensa_config_tdep (struct gdbarch_info *info)
+{
+  return &xtensa_tdep;
+}
+
+
+/* Masked registers.  */
+const int mask0[] = { 1, 96, 0, 4  };
+const int mask1[] = { 1, 96, 5, 1  };
+const int mask2[] = { 1, 96, 18, 1  };
+const int mask3[] = { 1, 96, 6, 2  };
+const int mask4[] = { 1, 96, 4, 1  };
+const int mask5[] = { 1, 96, 16, 2  };
+const int mask6[] = { 1, 96, 8, 4  };
+const int mask7[] = { 1, 95, 12, 20  };
+const int mask8[] = { 1, 95, 0, 1  };
+const int mask9[] = { 1, 108, 8, 4  };
+const int mask10[] = { 1, 109, 24, 8  };
+const int mask11[] = { 1, 109, 16, 8  };
+const int mask12[] = { 1, 109, 8, 8  };
+const int mask13[] = { 1, 110, 16, 2  };
+const int mask14[] = { 1, 111, 16, 2  };
+const int mask15[] = { 1, 67, 22, 10  };
+
+
+/* Register map.  */
+xtensa_register_t rmap[] = 
+{
+  { /* 0000 */ "ar0", 0, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000100, 0x0006, 0, 
+    0, 0 },
+  { /* 0001 */ "ar1", 4, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000101, 0x0006, 0, 
+    0, 0 },
+  { /* 0002 */ "ar2", 8, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000102, 0x0006, 0, 
+    0, 0 },
+  { /* 0003 */ "ar3", 12, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000103, 0x0006, 0, 
+    0, 0 },
+  { /* 0004 */ "ar4", 16, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000104, 0x0006, 0, 
+    0, 0 },
+  { /* 0005 */ "ar5", 20, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000105, 0x0006, 0, 
+    0, 0 },
+  { /* 0006 */ "ar6", 24, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000106, 0x0006, 0, 
+    0, 0 },
+  { /* 0007 */ "ar7", 28, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000107, 0x0006, 0, 
+    0, 0 },
+  { /* 0008 */ "ar8", 32, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000108, 0x0006, 0, 
+    0, 0 },
+  { /* 0009 */ "ar9", 36, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000109, 0x0006, 0, 
+    0, 0 },
+  { /* 0010 */ "ar10", 40, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000010a, 0x0006, 0, 
+    0, 0 },
+  { /* 0011 */ "ar11", 44, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000010b, 0x0006, 0, 
+    0, 0 },
+  { /* 0012 */ "ar12", 48, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000010c, 0x0006, 0, 
+    0, 0 },
+  { /* 0013 */ "ar13", 52, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000010d, 0x0006, 0, 
+    0, 0 },
+  { /* 0014 */ "ar14", 56, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000010e, 0x0006, 0, 
+    0, 0 },
+  { /* 0015 */ "ar15", 60, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000010f, 0x0006, 0, 
+    0, 0 },
+  { /* 0016 */ "ar16", 64, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000110, 0x0006, 0, 
+    0, 0 },
+  { /* 0017 */ "ar17", 68, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000111, 0x0006, 0, 
+    0, 0 },
+  { /* 0018 */ "ar18", 72, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000112, 0x0006, 0, 
+    0, 0 },
+  { /* 0019 */ "ar19", 76, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000113, 0x0006, 0, 
+    0, 0 },
+  { /* 0020 */ "ar20", 80, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000114, 0x0006, 0, 
+    0, 0 },
+  { /* 0021 */ "ar21", 84, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000115, 0x0006, 0, 
+    0, 0 },
+  { /* 0022 */ "ar22", 88, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000116, 0x0006, 0, 
+    0, 0 },
+  { /* 0023 */ "ar23", 92, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000117, 0x0006, 0, 
+    0, 0 },
+  { /* 0024 */ "ar24", 96, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000118, 0x0006, 0, 
+    0, 0 },
+  { /* 0025 */ "ar25", 100, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000119, 0x0006, 0, 
+    0, 0 },
+  { /* 0026 */ "ar26", 104, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000011a, 0x0006, 0, 
+    0, 0 },
+  { /* 0027 */ "ar27", 108, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000011b, 0x0006, 0, 
+    0, 0 },
+  { /* 0028 */ "ar28", 112, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000011c, 0x0006, 0, 
+    0, 0 },
+  { /* 0029 */ "ar29", 116, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000011d, 0x0006, 0, 
+    0, 0 },
+  { /* 0030 */ "ar30", 120, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000011e, 0x0006, 0, 
+    0, 0 },
+  { /* 0031 */ "ar31", 124, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000011f, 0x0006, 0, 
+    0, 0 },
+  { /* 0032 */ "ar32", 128, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000120, 0x0006, 0, 
+    0, 0 },
+  { /* 0033 */ "ar33", 132, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000121, 0x0006, 0, 
+    0, 0 },
+  { /* 0034 */ "ar34", 136, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000122, 0x0006, 0, 
+    0, 0 },
+  { /* 0035 */ "ar35", 140, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000123, 0x0006, 0, 
+    0, 0 },
+  { /* 0036 */ "ar36", 144, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000124, 0x0006, 0, 
+    0, 0 },
+  { /* 0037 */ "ar37", 148, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000125, 0x0006, 0, 
+    0, 0 },
+  { /* 0038 */ "ar38", 152, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000126, 0x0006, 0, 
+    0, 0 },
+  { /* 0039 */ "ar39", 156, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000127, 0x0006, 0, 
+    0, 0 },
+  { /* 0040 */ "ar40", 160, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000128, 0x0006, 0, 
+    0, 0 },
+  { /* 0041 */ "ar41", 164, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000129, 0x0006, 0, 
+    0, 0 },
+  { /* 0042 */ "ar42", 168, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000012a, 0x0006, 0, 
+    0, 0 },
+  { /* 0043 */ "ar43", 172, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000012b, 0x0006, 0, 
+    0, 0 },
+  { /* 0044 */ "ar44", 176, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000012c, 0x0006, 0, 
+    0, 0 },
+  { /* 0045 */ "ar45", 180, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000012d, 0x0006, 0, 
+    0, 0 },
+  { /* 0046 */ "ar46", 184, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000012e, 0x0006, 0, 
+    0, 0 },
+  { /* 0047 */ "ar47", 188, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000012f, 0x0006, 0, 
+    0, 0 },
+  { /* 0048 */ "ar48", 192, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000130, 0x0006, 0, 
+    0, 0 },
+  { /* 0049 */ "ar49", 196, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000131, 0x0006, 0, 
+    0, 0 },
+  { /* 0050 */ "ar50", 200, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000132, 0x0006, 0, 
+    0, 0 },
+  { /* 0051 */ "ar51", 204, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000133, 0x0006, 0, 
+    0, 0 },
+  { /* 0052 */ "ar52", 208, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000134, 0x0006, 0, 
+    0, 0 },
+  { /* 0053 */ "ar53", 212, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000135, 0x0006, 0, 
+    0, 0 },
+  { /* 0054 */ "ar54", 216, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000136, 0x0006, 0, 
+    0, 0 },
+  { /* 0055 */ "ar55", 220, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000137, 0x0006, 0, 
+    0, 0 },
+  { /* 0056 */ "ar56", 224, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000138, 0x0006, 0, 
+    0, 0 },
+  { /* 0057 */ "ar57", 228, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x00000139, 0x0006, 0, 
+    0, 0 },
+  { /* 0058 */ "ar58", 232, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000013a, 0x0006, 0, 
+    0, 0 },
+  { /* 0059 */ "ar59", 236, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000013b, 0x0006, 0, 
+    0, 0 },
+  { /* 0060 */ "ar60", 240, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000013c, 0x0006, 0, 
+    0, 0 },
+  { /* 0061 */ "ar61", 244, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000013d, 0x0006, 0, 
+    0, 0 },
+  { /* 0062 */ "ar62", 248, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000013e, 0x0006, 0, 
+    0, 0 },
+  { /* 0063 */ "ar63", 252, xtRegisterTypeArRegfile, 0x2, 0, 
+    32, 4, 4, 0x0000013f, 0x0006, 0, 
+    0, 0 },
+  { /* 0064 */ "lbeg", 256, xtRegisterTypeSpecialReg, 0x1100, 0, 
+    32, 4, 4, 0x00000200, 0x0006, 0, 
+    0, 0 },
+  { /* 0065 */ "lend", 260, xtRegisterTypeSpecialReg, 0x1100, 0, 
+    32, 4, 4, 0x00000201, 0x0006, 0, 
+    0, 0 },
+  { /* 0066 */ "lcount", 264, xtRegisterTypeSpecialReg, 0x1100, 0, 
+    32, 4, 4, 0x00000202, 0x0006, 0, 
+    0, 0 },
+  { /* 0067 */ "ptevaddr", 268, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x00000253, 0x0007, 0, 
+    0, 0 },
+  { /* 0068 */ "ddr", 272, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x00000268, 0x0007, 0, 
+    0, 0 },
+  { /* 0069 */ "interrupt", 276, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    17, 4, 4, 0x000002e2, 0x000b, 0, 
+    0, 0 },
+  { /* 0070 */ "intset", 280, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    17, 4, 4, 0x000002e2, 0x000d, 0, 
+    0, 0 },
+  { /* 0071 */ "intclear", 284, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    17, 4, 4, 0x000002e3, 0x000d, 0, 
+    0, 0 },
+  { /* 0072 */ "ccount", 288, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002ea, 0x000f, 0, 
+    0, 0 },
+  { /* 0073 */ "prid", 292, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002eb, 0x0003, 0, 
+    0, 0 },
+  { /* 0074 */ "icount", 296, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002ec, 0x000f, 0, 
+    0, 0 },
+  { /* 0075 */ "ccompare0", 300, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002f0, 0x000f, 0, 
+    0, 0 },
+  { /* 0076 */ "ccompare1", 304, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002f1, 0x000f, 0, 
+    0, 0 },
+  { /* 0077 */ "ccompare2", 308, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002f2, 0x000f, 0, 
+    0, 0 },
+  { /* 0078 */ "epc1", 312, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002b1, 0x0007, 0, 
+    0, 0 },
+  { /* 0079 */ "epc2", 316, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002b2, 0x0007, 0, 
+    0, 0 },
+  { /* 0080 */ "epc3", 320, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002b3, 0x0007, 0, 
+    0, 0 },
+  { /* 0081 */ "epc4", 324, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002b4, 0x0007, 0, 
+    0, 0 },
+  { /* 0082 */ "excsave1", 328, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002d1, 0x0007, 0, 
+    0, 0 },
+  { /* 0083 */ "excsave2", 332, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002d2, 0x0007, 0, 
+    0, 0 },
+  { /* 0084 */ "excsave3", 336, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002d3, 0x0007, 0, 
+    0, 0 },
+  { /* 0085 */ "excsave4", 340, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002d4, 0x0007, 0, 
+    0, 0 },
+  { /* 0086 */ "eps2", 344, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    19, 4, 4, 0x000002c2, 0x0007, 0, 
+    0, 0 },
+  { /* 0087 */ "eps3", 348, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    19, 4, 4, 0x000002c3, 0x0007, 0, 
+    0, 0 },
+  { /* 0088 */ "eps4", 352, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    19, 4, 4, 0x000002c4, 0x0007, 0, 
+    0, 0 },
+  { /* 0089 */ "exccause", 356, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    6, 4, 4, 0x000002e8, 0x0007, 0, 
+    0, 0 },
+  { /* 0090 */ "depc", 360, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002c0, 0x0007, 0, 
+    0, 0 },
+  { /* 0091 */ "excvaddr", 364, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002ee, 0x0007, 0, 
+    0, 0 },
+  { /* 0092 */ "windowbase", 368, xtRegisterTypeSpecialReg, 0x1002, 0, 
+    4, 4, 4, 0x00000248, 0x0007, 0, 
+    0, 0 },
+  { /* 0093 */ "windowstart", 372, xtRegisterTypeSpecialReg, 0x1002, 0, 
+    16, 4, 4, 0x00000249, 0x0007, 0, 
+    0, 0 },
+  { /* 0094 */ "sar", 376, xtRegisterTypeSpecialReg, 0x1100, 0, 
+    6, 4, 4, 0x00000203, 0x0006, 0, 
+    0, 0 },
+  { /* 0095 */ "litbase", 380, xtRegisterTypeSpecialReg, 0x1100, 0, 
+    32, 4, 4, 0x00000205, 0x0006, 0, 
+    0, 0 },
+  { /* 0096 */ "ps", 384, xtRegisterTypeSpecialReg, 0x1100, 0, 
+    19, 4, 4, 0x000002e6, 0x0007, 0, 
+    0, 0 },
+  { /* 0097 */ "misc0", 388, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002f4, 0x0007, 0, 
+    0, 0 },
+  { /* 0098 */ "misc1", 392, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002f5, 0x0007, 0, 
+    0, 0 },
+  { /* 0099 */ "intenable", 396, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    17, 4, 4, 0x000002e4, 0x0007, 0, 
+    0, 0 },
+  { /* 0100 */ "dbreaka0", 400, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x00000290, 0x0007, 0, 
+    0, 0 },
+  { /* 0101 */ "dbreakc0", 404, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002a0, 0x0007, 0, 
+    0, 0 },
+  { /* 0102 */ "dbreaka1", 408, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x00000291, 0x0007, 0, 
+    0, 0 },
+  { /* 0103 */ "dbreakc1", 412, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x000002a1, 0x0007, 0, 
+    0, 0 },
+  { /* 0104 */ "ibreaka0", 416, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x00000280, 0x0007, 0, 
+    0, 0 },
+  { /* 0105 */ "ibreaka1", 420, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x00000281, 0x0007, 0, 
+    0, 0 },
+  { /* 0106 */ "ibreakenable", 424, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    2, 4, 4, 0x00000260, 0x0007, 0, 
+    0, 0 },
+  { /* 0107 */ "icountlevel", 428, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    4, 4, 4, 0x000002ed, 0x0007, 0, 
+    0, 0 },
+  { /* 0108 */ "debugcause", 432, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    12, 4, 4, 0x000002e9, 0x0003, 0, 
+    0, 0 },
+  { /* 0109 */ "rasid", 436, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    32, 4, 4, 0x0000025a, 0x0007, 0, 
+    0, 0 },
+  { /* 0110 */ "itlbcfg", 440, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    18, 4, 4, 0x0000025b, 0x0007, 0, 
+    0, 0 },
+  { /* 0111 */ "dtlbcfg", 444, xtRegisterTypeSpecialReg, 0x1000, 0, 
+    18, 4, 4, 0x0000025c, 0x0007, 0, 
+    0, 0 },
+  { /* 0112 */ "threadptr", 448, xtRegisterTypeUserReg, 0x110, 0, 
+    32, 4, 4, 0x000003e7, 0x0006, 0, 
+    0, 0 },
+  { /* 0113 */ "pc", 452, xtRegisterTypeVirtual, 0x100, 0, 
+    32, 4, 4, 0x00000020, 0x0006, 0, 
+    0, 0 },
+  { /* 0114 */ "a0", 456, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000000, 0x0006, 0, 
+    0, 0 },
+  { /* 0115 */ "a1", 460, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000001, 0x0006, 0, 
+    0, 0 },
+  { /* 0116 */ "a2", 464, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000002, 0x0006, 0, 
+    0, 0 },
+  { /* 0117 */ "a3", 468, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000003, 0x0006, 0, 
+    0, 0 },
+  { /* 0118 */ "a4", 472, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000004, 0x0006, 0, 
+    0, 0 },
+  { /* 0119 */ "a5", 476, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000005, 0x0006, 0, 
+    0, 0 },
+  { /* 0120 */ "a6", 480, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000006, 0x0006, 0, 
+    0, 0 },
+  { /* 0121 */ "a7", 484, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000007, 0x0006, 0, 
+    0, 0 },
+  { /* 0122 */ "a8", 488, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000008, 0x0006, 0, 
+    0, 0 },
+  { /* 0123 */ "a9", 492, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x00000009, 0x0006, 0, 
+    0, 0 },
+  { /* 0124 */ "a10", 496, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x0000000a, 0x0006, 0, 
+    0, 0 },
+  { /* 0125 */ "a11", 500, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x0000000b, 0x0006, 0, 
+    0, 0 },
+  { /* 0126 */ "a12", 504, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x0000000c, 0x0006, 0, 
+    0, 0 },
+  { /* 0127 */ "a13", 508, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x0000000d, 0x0006, 0, 
+    0, 0 },
+  { /* 0128 */ "a14", 512, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x0000000e, 0x0006, 0, 
+    0, 0 },
+  { /* 0129 */ "a15", 516, xtRegisterTypeWindow, 0x100, 0, 
+    32, 4, 4, 0x0000000f, 0x0006, 0, 
+    0, 0 },
+  { /* 0130 */ "psintlevel", 520, xtRegisterTypeMapped, 0x1010, 0, 
+    4, 4, 4, 0x00002004, 0x0006, (xtensa_mask_t *) mask0, 
+    0, 0 },
+  { /* 0131 */ "psum", 524, xtRegisterTypeMapped, 0x1010, 0, 
+    1, 4, 4, 0x00002005, 0x0006, (xtensa_mask_t *) mask1, 
+    0, 0 },
+  { /* 0132 */ "pswoe", 528, xtRegisterTypeMapped, 0x1010, 0, 
+    1, 4, 4, 0x00002006, 0x0006, (xtensa_mask_t *) mask2, 
+    0, 0 },
+  { /* 0133 */ "psring", 532, xtRegisterTypeMapped, 0x1010, 0, 
+    2, 4, 4, 0x00002007, 0x0006, (xtensa_mask_t *) mask3, 
+    0, 0 },
+  { /* 0134 */ "psexcm", 536, xtRegisterTypeMapped, 0x1010, 0, 
+    1, 4, 4, 0x00002008, 0x0006, (xtensa_mask_t *) mask4, 
+    0, 0 },
+  { /* 0135 */ "pscallinc", 540, xtRegisterTypeMapped, 0x1010, 0, 
+    2, 4, 4, 0x00002009, 0x0006, (xtensa_mask_t *) mask5, 
+    0, 0 },
+  { /* 0136 */ "psowb", 544, xtRegisterTypeMapped, 0x1010, 0, 
+    4, 4, 4, 0x0000200a, 0x0006, (xtensa_mask_t *) mask6, 
+    0, 0 },
+  { /* 0137 */ "litbaddr", 548, xtRegisterTypeMapped, 0x1010, 0, 
+    20, 4, 4, 0x0000200b, 0x0006, (xtensa_mask_t *) mask7, 
+    0, 0 },
+  { /* 0138 */ "litben", 552, xtRegisterTypeMapped, 0x1010, 0, 
+    1, 4, 4, 0x0000200c, 0x0006, (xtensa_mask_t *) mask8, 
+    0, 0 },
+  { /* 0139 */ "dbnum", 556, xtRegisterTypeMapped, 0x1010, 0, 
+    4, 4, 4, 0x00002011, 0x0006, (xtensa_mask_t *) mask9, 
+    0, 0 },
+  { /* 0140 */ "asid3", 560, xtRegisterTypeMapped, 0x1010, 0, 
+    8, 4, 4, 0x00002012, 0x0006, (xtensa_mask_t *) mask10, 
+    0, 0 },
+  { /* 0141 */ "asid2", 564, xtRegisterTypeMapped, 0x1010, 0, 
+    8, 4, 4, 0x00002013, 0x0006, (xtensa_mask_t *) mask11, 
+    0, 0 },
+  { /* 0142 */ "asid1", 568, xtRegisterTypeMapped, 0x1010, 0, 
+    8, 4, 4, 0x00002014, 0x0006, (xtensa_mask_t *) mask12, 
+    0, 0 },
+  { /* 0143 */ "instpgszid4", 572, xtRegisterTypeMapped, 0x1010, 0, 
+    2, 4, 4, 0x00002015, 0x0006, (xtensa_mask_t *) mask13, 
+    0, 0 },
+  { /* 0144 */ "datapgszid4", 576, xtRegisterTypeMapped, 0x1010, 0, 
+    2, 4, 4, 0x00002016, 0x0006, (xtensa_mask_t *) mask14, 
+    0, 0 },
+  { /* 0145 */ "ptbase", 580, xtRegisterTypeMapped, 0x1010, 0, 
+    10, 4, 4, 0x00002017, 0x0006, (xtensa_mask_t *) mask15, 
+    0, 0 },
+};
+
+
+struct gdbarch_tdep xtensa_tdep =
+{
+  /* target_flags */			0,
+  /* spill_location */			-1,
+  /* spill_size */			0,
+  /* unused */				0,
+  /* call_abi */			0,
+  /* debug_interrupt_level */		XCHAL_DEBUGLEVEL,
+  /* icache_line_bytes */		XCHAL_ICACHE_LINESIZE,
+  /* dcache_line_bytes */		XCHAL_DCACHE_LINESIZE,
+  /* dcache_writeback */		XCHAL_DCACHE_IS_WRITEBACK,
+  /* isa_use_windowed_registers */	XCHAL_HAVE_WINDOWED,
+  /* isa_use_density_instructions */	XCHAL_HAVE_DENSITY,
+  /* isa_use_exceptions */		1,
+  /* isa_use_ext_l32r */		0 /* XCHAL_USE_ABSOLUTE_LITERALS */,
+  /* isa_max_insn_size */		3,
+  /* debug_num_ibreaks */		XCHAL_NUM_IBREAK,
+  /* debug_num_dbreaks */		XCHAL_NUM_DBREAK,
+  /* rmap */				rmap,
+  /* num_regs */			114,
+  /* num_pseudo_regs */			32,
+  /* num_aregs */			64,
+  /* num_contexts */			0,
+  /* ar_base */				0,
+  /* a0_base */				114,
+  /* wb_regnum */			92,
+  /* ws_regnum */			93,
+  /* pc_regnum */			113,
+  /* ps_regnum */			96,
+  /* lbeg_regnum */			64,
+  /* lend_regnum */			65,
+  /* lcount_regnum */			66,
+  /* sar_regnum */			94,
+  /* litbase_regnum */			0,
+  /* debugcause_regnum */		108,
+  /* exccause_regnum */			89,
+  /* excvaddr_regnum */			91,
+  /* max_register_raw_size */		4,
+  /* max_register_virtual_size */	4,
+  /* fp_layout */			0,
+  /* fp_layout_bytes */			0,
+  /* gregmap */				0
+};
Index: gdb/xtensa-tdep.h
===================================================================
@@ -0,0 +1,298 @@
+/* Target-dependent code for the Xtensa port of GDB, the GNU debugger.
+
+   Copyright (C) 2003, 2005, 2006 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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+
+/* XTENSA_TDEP_VERSION can/should be changed along with XTENSA_CONFIG_VERSION
+   whenever the "tdep" structure changes in an incompatible way.  */
+
+#define XTENSA_TDEP_VERSION 0x60
+
+/*  Xtensa register type.  */
+
+typedef enum 
+{
+  xtRegisterTypeArRegfile = 1,	/* Register File ar0..arXX.  */
+  xtRegisterTypeSpecialReg,	/* CPU states, such as PS, Booleans, (rsr).  */
+  xtRegisterTypeUserReg,	/* User defined registers (rur).  */
+  xtRegisterTypeTieRegfile,	/* User define register files.  */
+  xtRegisterTypeTieState,	/* TIE States (mapped on user regs).  */
+  xtRegisterTypeMapped,		/* Mapped on Special Registers.  */
+  xtRegisterTypeUnmapped,	/* Special case of masked registers.  */
+  xtRegisterTypeWindow,		/* Live window registers (a0..a15).  */
+  xtRegisterTypeVirtual,	/* PC, FP.  */
+  xtRegisterTypeUnknown
+} xtensa_register_type_t;
+
+
+/*  Xtensa register group.  */
+
+typedef enum 
+{
+  xtRegisterGroupUnknown = 0,
+  xtRegisterGroupRegFile	= 0x0001,    /* Register files without ARx.  */
+  xtRegisterGroupAddrReg	= 0x0002,    /* ARx.  */
+  xtRegisterGroupSpecialReg	= 0x0004,    /* SRxx.  */
+  xtRegisterGroupUserReg	= 0x0008,    /* URxx.  */
+  xtRegisterGroupState 		= 0x0010,    /* States.  */
+
+  xtRegisterGroupGeneral	= 0x0100,    /* General registers, Ax, SR.  */
+  xtRegisterGroupUser		= 0x0200,    /* User registers.  */
+  xtRegisterGroupFloat		= 0x0400,    /* Floating Point.  */
+  xtRegisterGroupVectra		= 0x0800,    /* Vectra.  */
+  xtRegisterGroupSystem		= 0x1000,    /* System.  */
+} xtensa_register_group_t;
+
+
+/*  Xtensa target flags.  */
+
+typedef enum 
+{
+  xtTargetFlagsNonVisibleRegs	= 0x0001,
+  xtTargetFlagsUseFetchStore	= 0x0002,
+} xtensa_target_flags_t;
+
+
+/* Xtensa ELF core file register set representation ('.reg' section). 
+   Copied from target-side ELF header <xtensa/elf.h>.  */
+
+typedef unsigned long xtensa_elf_greg_t;
+
+typedef struct
+{
+  xtensa_elf_greg_t xchal_config_id0;
+  xtensa_elf_greg_t xchal_config_id1;
+  xtensa_elf_greg_t cpux;
+  xtensa_elf_greg_t cpuy;
+  xtensa_elf_greg_t pc;
+  xtensa_elf_greg_t ps;
+  xtensa_elf_greg_t exccause;
+  xtensa_elf_greg_t excvaddr;
+  xtensa_elf_greg_t windowbase;
+  xtensa_elf_greg_t windowstart;
+  xtensa_elf_greg_t lbeg;
+  xtensa_elf_greg_t lend;
+  xtensa_elf_greg_t lcount;
+  xtensa_elf_greg_t sar;
+  xtensa_elf_greg_t syscall;
+  xtensa_elf_greg_t ar[0];	/* variable size (per config).  */
+} xtensa_elf_gregset_t;
+
+#define SIZEOF_GREGSET (sizeof (xtensa_elf_gregset_t) + NUM_AREGS * 4)
+#define XTENSA_ELF_NGREG (SIZEOF_GREGSET / sizeof(xtensa_elf_greg_t))
+
+
+/*  Mask.  */
+
+typedef struct 
+{
+  int count;
+  struct 
+  {
+    int reg_num;
+    int bit_start;
+    int bit_size;
+  } mask[0];
+} xtensa_mask_t;
+
+
+/*  Xtensa register representation.  */
+
+typedef struct 
+{
+  char* name;             	/* Register name.  */
+  int offset;             	/* Offset.  */
+  xtensa_register_type_t type;  /* Register type.  */
+  xtensa_register_group_t group;/* Register group.  */
+  struct type* ctype;		/* C-type.  */
+  int bit_size;  		/* The actual bit size in the target.  */
+  int byte_size;          	/* Actual space allocated in registers[].  */
+  int align;			/* Alignment for this register.  */
+
+  unsigned int target_number;	/* Register target number.  */
+
+  int flags;			/* Flags.  */
+
+  const xtensa_mask_t *mask;	/* Register is a compilation of other regs.  */
+  const char *fetch;		/* Instruction sequence to fetch register.  */
+  const char *store;		/* Instruction sequence to store register.  */
+} xtensa_register_t;
+
+
+#define XTENSA_REGISTER_FLAGS_PRIVILEDGED	0x0001
+#define XTENSA_REGISTER_FLAGS_READABLE		0x0002
+#define XTENSA_REGISTER_FLAGS_WRITABLE		0x0004
+#define XTENSA_REGISTER_FLAGS_VOLATILE		0x0008
+
+
+/*  Call-ABI for stack frame.  */
+
+typedef enum 
+{
+  CallAbiDefault = 0,		/* Any 'callX' instructions; default stack.  */
+  CallAbiCall0Only,		/* Only 'call0' instructions; flat stack.  */
+} call_abi_t;
+
+
+/*  Xtensa-specific target dependencies.  */
+
+struct gdbarch_tdep
+{
+  unsigned int target_flags;
+
+  /* Spill location for TIE register files under ocd.  */
+
+  unsigned int spill_location;
+  unsigned int spill_size;
+
+  char *unused;				/* Placeholder for compatibility.  */
+  call_abi_t call_abi;			/* Calling convention.  */
+
+  /* CPU configuration.  */
+
+  unsigned int debug_interrupt_level;
+
+  unsigned int icache_line_bytes;
+  unsigned int dcache_line_bytes;
+  unsigned int dcache_writeback;
+
+  unsigned int isa_use_windowed_registers;
+  unsigned int isa_use_density_instructions;
+  unsigned int isa_use_exceptions;
+  unsigned int isa_use_ext_l32r;
+  unsigned int isa_max_insn_size;	/* Maximum instruction length.  */
+  unsigned int debug_num_ibreaks;	/* Number of IBREAKs.  */
+  unsigned int debug_num_dbreaks;
+
+  /* Register map.  */
+
+  xtensa_register_t* regmap;
+
+  unsigned int num_regs;	/* Number of registers in regmap.  */
+  unsigned int num_pseudo_regs;	/* Number of pseudo registers.  */
+  unsigned int num_aregs;	/* Size of register file.  */
+  unsigned int num_contexts;
+
+  int ar_base;			/* Register number for AR0.  */
+  int a0_base;			/* Register number for A0 (pseudo).  */
+  int wb_regnum;		/* Register number for WB.  */
+  int ws_regnum;		/* Register number for WS.  */
+  int pc_regnum;		/* Register number for PC.  */
+  int ps_regnum;		/* Register number for PS.  */
+  int lbeg_regnum;		/* Register numbers for count regs.  */
+  int lend_regnum;
+  int lcount_regnum;
+  int sar_regnum;		/* Register number of SAR.  */
+  int litbase_regnum;		/* Register number of LITBASE.  */
+
+  int interrupt_regnum;		/* Register number for interrupt.  */
+  int interrupt2_regnum;	/* Register number for interrupt2.  */
+  int cpenable_regnum;		/* Register number for cpenable.  */
+  int debugcause_regnum;	/* Register number for debugcause.  */
+  int exccause_regnum;		/* Register number for exccause.  */
+  int excvaddr_regnum;		/* Register number for excvaddr.  */
+
+  int max_register_raw_size;
+  int max_register_virtual_size;
+  unsigned long *fp_layout;	/* Layout of custom/TIE regs in 'FP' area.  */
+  unsigned int fp_layout_bytes;	/* Size of layout information (in bytes).  */
+  unsigned long *gregmap;
+};
+
+
+/* Define macros to access some of the gdbarch entries.  */
+#define XTENSA_TARGET_FLAGS \
+  (gdbarch_tdep (current_gdbarch)->target_flags)
+#define SPILL_LOCATION \
+  (gdbarch_tdep (current_gdbarch)->spill_location)
+#define SPILL_SIZE \
+  (gdbarch_tdep (current_gdbarch)->spill_size)
+#define CALL_ABI		\
+  (gdbarch_tdep (current_gdbarch)->call_abi)
+#define ISA_USE_WINDOWED_REGISTERS \
+  (gdbarch_tdep (current_gdbarch)->isa_use_windowed_registers)
+#define ISA_USE_DENSITY_INSTRUCTIONS \
+  (gdbarch_tdep (current_gdbarch)->isa_use_density_instructions)
+#define ISA_USE_EXCEPTIONS \
+  (gdbarch_tdep (current_gdbarch)->isa_use_exceptions)
+#define ISA_USE_EXT_L32R \
+  (gdbarch_tdep (current_gdbarch)->isa_use_ext_l32r)
+#define DEBUG_DATA_VADDR_TRAP_COUNT \
+  (gdbarch_tdep (current_gdbarch)->debug_data_vaddr_trap_count)
+#define DEBUG_INST_VADDR_TRAP_COUNT \
+  (gdbarch_tdep (current_gdbarch)->debug_inst_vaddr_trap_count)
+#define ISA_MAX_INSN_SIZE \
+  (gdbarch_tdep (current_gdbarch)->isa_max_insn_size)
+#define DEBUG_NUM_IBREAKS \
+  (gdbarch_tdep (current_gdbarch)->debug_num_ibreaks)
+#define DEBUG_NUM_DBREAKS \
+  (gdbarch_tdep (current_gdbarch)->debug_num_dbreaks)
+
+#define NUM_AREGS         (gdbarch_tdep (current_gdbarch)->num_aregs)
+#define WB_REGNUM         (gdbarch_tdep (current_gdbarch)->wb_regnum)
+#define WS_REGNUM         (gdbarch_tdep (current_gdbarch)->ws_regnum)
+#define LBEG_REGNUM       (gdbarch_tdep (current_gdbarch)->lbeg_regnum)
+#define LEND_REGNUM       (gdbarch_tdep (current_gdbarch)->lend_regnum)
+#define LCOUNT_REGNUM     (gdbarch_tdep (current_gdbarch)->lcount_regnum)
+#define SAR_REGNUM        (gdbarch_tdep (current_gdbarch)->sar_regnum)
+#define REGMAP            (gdbarch_tdep (current_gdbarch)->regmap)
+
+#define LITBASE_REGNUM    (gdbarch_tdep (current_gdbarch)->litbase_regnum)
+#define DEBUGCAUSE_REGNUM (gdbarch_tdep (current_gdbarch)->debugcause_regnum)
+#define EXCCAUSE_REGNUM   (gdbarch_tdep (current_gdbarch)->exccause_regnum)
+#define EXCVADDR_REGNUM   (gdbarch_tdep (current_gdbarch)->excvaddr_regnum)
+#define NUM_IBREAKS       (gdbarch_tdep (current_gdbarch)->num_ibreaks)
+#define REGMAP_BYTES      (gdbarch_tdep (current_gdbarch)->regmap_bytes)
+#define A0_BASE           (gdbarch_tdep (current_gdbarch)->a0_base)
+#define AR_BASE           (gdbarch_tdep (current_gdbarch)->ar_base)
+#define FP_ALIAS	  (NUM_REGS + NUM_PSEUDO_REGS)
+#define CALL_ABI          (gdbarch_tdep (current_gdbarch)->call_abi)
+#define NUM_CONTEXTS      (gdbarch_tdep (current_gdbarch)->num_contexts)
+  
+#define FP_LAYOUT         (gdbarch_tdep (current_gdbarch)->fp_layout)
+#define FP_LAYOUT_BYTES   (gdbarch_tdep (current_gdbarch)->fp_layout_bytes)
+#define GREGMAP           (gdbarch_tdep (current_gdbarch)->gregmap)
+
+#define AREGS_MASK	  (NUM_AREGS - 1)
+#define WB_MASK		  (AREGS_MASK >> 2)
+#define WB_SHIFT	  2
+
+/* We assign fixed numbers to the registers of the "current" window 
+   (i.e., relative to WB).  The registers get remapped via the reg_map 
+   data structure to their corresponding register in the AR register 
+   file (see xtensa-tdep.c).  */
+
+#define A0_REGNUM  (A0_BASE + 0)
+#define A1_REGNUM  (A0_BASE + 1)
+#define A2_REGNUM  (A0_BASE + 2)
+#define A3_REGNUM  (A0_BASE + 3)
+#define A4_REGNUM  (A0_BASE + 4)
+#define A5_REGNUM  (A0_BASE + 5)
+#define A6_REGNUM  (A0_BASE + 6)
+#define A7_REGNUM  (A0_BASE + 7)
+#define A8_REGNUM  (A0_BASE + 8)
+#define A9_REGNUM  (A0_BASE + 9)
+#define A10_REGNUM (A0_BASE + 10)
+#define A11_REGNUM (A0_BASE + 11)
+#define A12_REGNUM (A0_BASE + 12)
+#define A13_REGNUM (A0_BASE + 13)
+#define A14_REGNUM (A0_BASE + 14)
+#define A15_REGNUM (A0_BASE + 15)
+
Index: gdb/xtensa-tdep.c
===================================================================
@@ -0,0 +1,1735 @@
+/* Target-dependent code for the Xtensa port of GDB, the GNU debugger.
+
+   Copyright (C) 2003, 2005, 2006 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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "regset.h"
+
+#include "dummy-frame.h"
+#include "elf/dwarf2.h"
+#include "dwarf2-frame.h"
+#include "dwarf2loc.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+
+#include "arch-utils.h"
+#include "gdbarch.h"
+#include "remote.h"
+#include "serial.h"
+
+#include "command.h"
+#include "gdbcmd.h"
+#include "gdb_assert.h"
+
+#include "xtensa-tdep.h"
+
+
+static int xtensa_debug_level = 0;
+
+#define DEBUGWARN(args...) \
+  if (xtensa_debug_level > 0) \
+    fprintf_unfiltered (gdb_stdlog, "(warn ) " args)
+
+#define DEBUGINFO(args...) \
+  if (xtensa_debug_level > 1) \
+    fprintf_unfiltered (gdb_stdlog, "(info ) " args)
+
+#define DEBUGTRACE(args...) \
+  if (xtensa_debug_level > 2) \
+    fprintf_unfiltered (gdb_stdlog, "(trace) " args)
+
+#define DEBUGVERB(args...) \
+  if (xtensa_debug_level > 3) \
+    fprintf_unfiltered (gdb_stdlog, "(verb ) " args)
+
+
+/* According to the ABI, the SP must be aligned to 16-byte boundaries.  */
+
+#define SP_ALIGNMENT 16
+
+
+/* We use a6 through a11 for passing arguments to a function called by GDB.  */
+
+#define ARGS_FIRST_REG    A6_REGNUM
+#define ARGS_NUM_REGS     6
+#define REGISTER_SIZE	  4
+
+
+/* Extract the call size from the return address or ps register.  */
+
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_MASK 0x00030000
+#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)
+
+
+/* Define prototypes.  */
+
+extern struct gdbarch_tdep *xtensa_config_tdep (struct gdbarch_info *);
+extern int xtensa_config_byte_order (struct gdbarch_info *);
+
+
+/* XTENSA_IS_ENTRY tests whether the first byte of an instruction
+   indicates that the instruction is an ENTRY instruction.  */
+
+#define XTENSA_IS_ENTRY(op1) \
+  ((TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) ? ((op1)==0x6c) : ((op1)==0x36))
+
+#define XTENSA_ENTRY_LENGTH  3
+
+
+/* windowing_enabled() returns true, if windowing is enabled.
+   WOE must be set to 1; EXCM to 0.
+   Note: We assume that EXCM is always 0 for XEA1.  */
+
+static inline int
+windowing_enabled (CORE_ADDR ps)
+{
+  return ((ps & (1 << 4)) == 0 && (ps & (1 << 18)) != 0);
+}
+
+/* Return the window size of the previous call to the function from which we
+   have just returned.
+
+   This function is used to extract the return value after a called function
+   has returned to the callee.  On Xtensa, the register that holds the return
+   value (from the perspective of the caller) depends on what call
+   instruction was used.  For now, we are assuming that the call instruction
+   precedes the current address, so we simply analyze the call instruction.
+   If we are in a dummy frame, we simply return 4 as we used a 'pseudo-call4'
+   method to call the inferior function.  */
+
+static int
+extract_call_winsize (CORE_ADDR pc)
+{
+  int winsize = 4;	/* Default: No call, e.g. dummy frame.  */
+  int insn;
+  char buf[4];
+
+  DEBUGTRACE ("extract_call_winsize (pc = 0x%08x)\n", (int) 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);
+
+  /* Decode call instruction:
+     Little Endian
+       call{0,4,8,12}   OFFSET || {00,01,10,11} || 0101
+       callx{0,4,8,12}  OFFSET || 11 || {00,01,10,11} || 0000
+     Big Endian
+       call{0,4,8,12}   0101 || {00,01,10,11} || OFFSET
+       callx{0,4,8,12}  0000 || {00,01,10,11} || 11 || OFFSET.  */
+
+  /* Lookup call insn.
+     (Return the default value (4) if we can't find a valid call insn.  */
+
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+    {
+      if (((insn & 0xf) == 0x5) || ((insn & 0xcf) == 0xc0))
+	winsize = (insn & 0x30) >> 2;   /* 0, 4, 8, 12  */
+    }
+  else
+    {
+      if (((insn >> 20) == 0x5) || (((insn >> 16) & 0xf3) == 0x03))
+	winsize = (insn >> 16) & 0xc;   /* 0, 4, 8, 12  */
+    }
+  return winsize;
+}
+
+
+/* REGISTER INFORMATION */
+
+/* Returns the name of a register.  */
+
+static const char *
+xtensa_register_name (int regnum)
+{
+  /* Return the name stored in the register map.  */
+  if (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS)
+    return REGMAP[regnum].name;
+
+  /* Invalid register number.  */
+  internal_error (__FILE__, __LINE__, _("invalid register %d"), regnum);
+  return 0;
+}
+
+
+/* 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)
+{
+  /* 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 == PC_REGNUM || regnum == A1_REGNUM)
+    return lookup_pointer_type (builtin_type_void);
+
+  /* Return the stored type for all other registers.  */
+  else if (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS)
+    {
+      xtensa_register_t* reg = &REGMAP[regnum];
+
+      /* Set ctype for this register (only the first time we ask for it).  */
+
+      if (reg->ctype == 0)
+	{
+	  struct ctype_cache *tp;
+	  int size = reg->byte_size;
+
+	  /* We always use the memory representation, even if the register
+	     width is smaller.  */
+	  switch (size)
+	    {
+	    case 1:
+	      reg->ctype = builtin_type_uint8;
+	      break;
+
+	    case 2:
+	      reg->ctype = builtin_type_uint16;
+	      break;
+
+	    case 4:
+	      reg->ctype = builtin_type_uint32;
+	      break;
+
+	    case 8:
+	      reg->ctype = builtin_type_uint64;
+	      break;
+
+	    case 16:
+	      reg->ctype = builtin_type_uint128;
+	      break;
+
+	    default:
+	      for (tp = type_entries; tp != NULL; tp = tp->next)
+		if (tp->size == size)
+		  break;
+
+	      if (tp == NULL)
+		{
+		  char *name = xmalloc (16);
+		  tp = xmalloc (sizeof (struct ctype_cache));
+		  tp->next = type_entries;
+		  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);
+		}
+
+	      reg->ctype = tp->virtual_type;
+	    }
+	}
+      return reg->ctype;
+    }
+
+  /* Invalid register number.  */
+  internal_error (__FILE__, __LINE__, _("invalid register number %d"), regnum);
+  return 0;
+}
+
+
+/* Returns the 'local' register number for stubs, dwarf2, etc.
+   The debugging information enumerates registers starting from 0 for A0
+   to n for An.  So, we only have to add the base number for A0.  */
+
+static int
+xtensa_reg_to_regnum (int regnum)
+{
+  int i;
+
+  if (regnum >= 0 && regnum < 16)
+    return A0_BASE + regnum;
+
+  for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
+    if (regnum == REGMAP[i].target_number)
+      return i;
+
+  /* Invalid register number.  */
+  internal_error (__FILE__, __LINE__,
+		  _("invalid dwarf/stabs register number %d"), regnum);
+  return 0;
+}
+
+
+/* Handle the special case of masked registers.  */
+
+/* Write the bits of a masked register to the various registers that
+   are combined into this register.  Only the masked areas of these
+   registers are modified; the other fields are untouched.
+   (Note: The size of masked registers is always less or equal 32 bits.)  */
+
+static void
+xtensa_register_write_masked (xtensa_register_t *reg, unsigned char *buffer)
+{
+  unsigned int value[(MAX_REGISTER_SIZE + 3) / 4];
+
+  const xtensa_mask_t *mask = reg->mask;
+
+  int shift = 0;		/* Shift for next mask (mod 32).  */
+  int start, size;		/* Start bit and size of current mask.  */
+
+  unsigned int *ptr = value;
+  unsigned int regval, m, mem = 0;
+
+  int bytesize = reg->byte_size;
+  int bitsize = bytesize * 8;
+  int i, r;
+
+  DEBUGTRACE ("xtensa_register_write_masked ()\n");
+
+  /* Copy the masked register to host byte-order.  */
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    for (i = 0; i < bytesize; i++)
+      {
+	mem >>= 8;
+	mem |= (buffer[bytesize - i - 1] << 24);
+	if ((i & 3) == 3)
+	  *ptr++ = mem;
+      }
+  else
+    for (i = 0; i < bytesize; i++)
+      {
+	mem >>= 8;
+	mem |= (buffer[i] << 24);
+	if ((i & 3) == 3)
+	  *ptr++ = mem;
+      }
+
+  /* We might have to shift the final value:
+     bytesize & 3 == 0 -> nothing to do, we use the full 32 bits,
+     bytesize & 3 == x -> shift (4-x) * 8.  */
+
+  *ptr = mem >> (((0 - bytesize) & 3) * 8);
+  ptr = value;
+  mem = *ptr;
+
+  /* Write the bits to the masked areas of the other registers.  */
+  for (i = 0; i < mask->count; i++)
+    {
+      start = mask->mask[i].bit_start;
+      size = mask->mask[i].bit_size;
+      regval = mem >> shift;
+
+      if ((shift += size) > bitsize)
+	error (_("size of all masks is larger than the register"));
+
+      if (shift >= 32)
+	{
+	  mem = *(++ptr);
+	  shift -= 32;
+	  bitsize -= 32;
+
+	  if (shift > 0)
+	    regval |= mem << (size - shift);
+	}
+
+      /* Make sure we have a valid register.  */
+      r = mask->mask[i].reg_num;
+      if (r >= 0 && size > 0)
+	{
+	  /* Don't overwrite the unmasked areas.  */
+	  m = 0xffffffff >> (32 - size) << start;
+	  regval <<= start;
+	  regval = (regval & m) | (read_register (r) & ~m);
+	  write_register (r, regval);
+	}
+    }
+}
+
+
+/* Read the masked areas of the registers and assemble it into a single
+   register.  */
+
+static void
+xtensa_register_read_masked (xtensa_register_t *reg, unsigned char *buffer)
+{
+  unsigned int value[(MAX_REGISTER_SIZE + 3) / 4];
+
+  const xtensa_mask_t *mask = reg->mask;
+
+  int shift = 0;
+  int start, size;
+
+  unsigned int *ptr = value;
+  unsigned int regval, mem = 0;
+
+  int bytesize = reg->byte_size;
+  int bitsize = bytesize * 8;
+  int i;
+
+  DEBUGTRACE ("xtensa_register_read_masked (reg \"%s\", ...)\n",
+	      reg->name == 0 ? "" : reg->name);
+
+  /* Assemble the register from the masked areas of other registers.  */
+  for (i = 0; i < mask->count; i++)
+    {
+      int r = mask->mask[i].reg_num;
+      regval = (r >= 0) ? read_register (r) : 0;
+      start = mask->mask[i].bit_start;
+      size = mask->mask[i].bit_size;
+
+      regval >>= start;
+
+      if (size < 32)
+	regval &= (0xffffffff >> (32 - size));
+
+      mem |= regval << shift;
+
+      if ((shift += size) > bitsize)
+	error (_("size of all masks is larger than the register"));
+
+      if (shift >= 32)
+	{
+	  *ptr++ = mem;
+	  bitsize -= 32;
+	  shift -= 32;
+
+	  if (shift == 0)
+	    mem = 0;
+	  else
+	    mem = regval >> (size - shift);
+	}
+    }
+
+  if (shift > 0)
+    *ptr = mem;
+
+  /* Copy value to target byte order.  */
+  ptr = value;
+  mem = *ptr;
+
+  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    for (i = 0; i < bytesize; i++)
+      {
+	if ((i & 3) == 0)
+	  mem = *ptr++;
+	buffer[bytesize - i - 1] = mem & 0xff;
+	mem >>= 8;
+      }
+  else
+    for (i = 0; i < bytesize; i++)
+      {
+	if ((i & 3) == 0)
+	  mem = *ptr++;
+	buffer[i] = mem & 0xff;
+	mem >>= 8;
+      }
+}
+
+
+/* Read pseudo registers.  */
+
+static void
+xtensa_pseudo_register_read (struct gdbarch *gdbarch,
+			     struct regcache *regcache,
+			     int regnum,
+			     gdb_byte *buffer)
+{
+  DEBUGTRACE ("xtensa_pseudo_register_read (... regnum = %d (%s) ...)\n",
+	      regnum, xtensa_register_name (regnum));
+
+  /* Check if it is FP (renumber it in this case -> A0...A15).  */
+  if (regnum == FP_ALIAS)
+    error (_("trying to read FP"));
+
+  /* Read aliases a0..a15.  */
+  if (regnum >= A0_REGNUM && regnum <= A15_REGNUM)
+    {
+      char *buf = (char *) alloca (MAX_REGISTER_SIZE);
+
+      regcache_raw_read (regcache, WB_REGNUM, buf);
+      regnum = AREG_NUMBER (regnum, extract_unsigned_integer (buf, 4));
+    }
+
+  /* We can always read 'regular' registers.  */
+  if (regnum >= 0 && regnum < NUM_REGS)
+    regcache_raw_read (regcache, regnum, buffer);
+
+  /* Pseudo registers.  */
+  else if (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS)
+    {
+      xtensa_register_t *reg = &REGMAP[regnum];
+      xtensa_register_type_t type = reg->type;
+      int flags = XTENSA_TARGET_FLAGS;
+
+      /* Can we read Unknown or Unmapped registers?  */
+      if (type == xtRegisterTypeUnmapped || type == xtRegisterTypeUnknown)
+	{
+	  if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
+	    {
+	      warning (_("cannot read register %s"),
+		       xtensa_register_name (regnum));
+	      return;
+	    }
+	}
+
+      /* Some targets cannot read TIE register files.  */
+      else if (type == xtRegisterTypeTieRegfile)
+        {
+	  /* Use 'fetch' to get register?  */
+	  if (flags & xtTargetFlagsUseFetchStore)
+	    {
+	      warning (_("cannot read register"));
+	      return;
+	    }
+
+	  /* On some targets (esp. simulators), we can always read the reg.  */
+	  else if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
+	    {
+	      warning (_("cannot read register"));
+	      return;
+	    }
+	}
+
+      /* We can always read mapped registers.  */
+      else if (type == xtRegisterTypeMapped || type == xtRegisterTypeTieState)
+        {
+	  xtensa_register_read_masked (reg, (unsigned char *) buffer);
+	  return;
+	}
+
+      /* Assume that we can read the register.  */
+      regcache_raw_read (regcache, regnum, buffer);
+    }
+
+  else
+    internal_error (__FILE__, __LINE__,
+		    _("invalid register number %d"), regnum);
+}
+
+
+/* Write pseudo registers.  */
+
+static void
+xtensa_pseudo_register_write (struct gdbarch *gdbarch,
+			      struct regcache *regcache,
+			      int regnum,
+			      const gdb_byte *buffer)
+{
+  DEBUGTRACE ("xtensa_pseudo_register_write (... regnum = %d (%s) ...)\n",
+	      regnum, xtensa_register_name (regnum));
+
+  /* Check if this is FP.  */
+  if (regnum == FP_ALIAS)
+    error (_("trying to write FP"));
+
+  /* Renumber register, if aliase a0..a15.  */
+  if (regnum >= A0_REGNUM && regnum <= A15_REGNUM)
+    {
+      char *buf = (char *) alloca (MAX_REGISTER_SIZE);
+      unsigned int wb;
+
+      regcache_raw_read (regcache, WB_REGNUM, buf);
+      regnum = AREG_NUMBER (regnum, extract_unsigned_integer (buf, 4));
+    }
+
+  /* We can always write 'core' registers.
+     Note: We might have converted Ax->ARy.  */
+  if (regnum >= 0 && regnum < NUM_REGS)
+    regcache_raw_write (regcache, regnum, buffer);
+
+  /* Pseudo registers.  */
+  else if (regnum >= 0 && regnum < NUM_REGS + NUM_PSEUDO_REGS)
+    {
+      xtensa_register_t *reg = &REGMAP[regnum];
+      xtensa_register_type_t type = reg->type;
+      int flags = XTENSA_TARGET_FLAGS;
+
+      /* On most targets, we can't write registers of type "Unknown"
+	 or "Unmapped".  */
+      if (type == xtRegisterTypeUnmapped || type == xtRegisterTypeUnknown)
+        {
+	  if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
+	    {
+	      warning (_("cannot write register %s"),
+		       xtensa_register_name (regnum));
+	      return;
+	    }
+	}
+
+      /* Some targets cannot read TIE register files.  */
+      else if (type == xtRegisterTypeTieRegfile)
+        {
+	  /* Use 'store' to get register?  */
+	  if (flags & xtTargetFlagsUseFetchStore)
+	    {
+	      warning (_("cannot write register"));
+	      return;
+	    }
+
+	  /* On some targets (esp. simulators), we can always write
+	     the register.  */
+
+	  else if ((flags & xtTargetFlagsNonVisibleRegs) == 0)
+	    {
+	      warning (_("cannot write register"));
+	      return;
+	    }
+	}
+
+      /* We can always write mapped registers.  */
+      else if (type == xtRegisterTypeMapped || type == xtRegisterTypeTieState)
+        {
+	  xtensa_register_write_masked (reg, (unsigned char *) buffer);
+	  return;
+	}
+
+      /* Assume that we can write the register.  */
+      regcache_raw_write (regcache, regnum, buffer);
+    }
+
+  else
+    internal_error (__FILE__, __LINE__,
+		    _("invalid register number %d"), regnum);
+}
+
+
+static struct reggroup *xtensa_ar_reggroup;
+static struct reggroup *xtensa_user_reggroup;
+static struct reggroup *xtensa_vectra_reggroup;
+
+static void
+xtensa_init_reggroups (void)
+{
+  xtensa_ar_reggroup = reggroup_new ("ar", USER_REGGROUP);
+  xtensa_user_reggroup = reggroup_new ("user", USER_REGGROUP);
+  xtensa_vectra_reggroup = reggroup_new ("vectra", USER_REGGROUP);
+}
+
+
+static void
+xtensa_add_reggroups (struct gdbarch *gdbarch)
+{
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, save_reggroup);
+  reggroup_add (gdbarch, restore_reggroup);
+  reggroup_add (gdbarch, system_reggroup);
+  reggroup_add (gdbarch, vector_reggroup);		/* vectra */
+  reggroup_add (gdbarch, general_reggroup);		/* core */
+  reggroup_add (gdbarch, float_reggroup);		/* float */
+
+  reggroup_add (gdbarch, xtensa_ar_reggroup);		/* ar */
+  reggroup_add (gdbarch, xtensa_user_reggroup);		/* user */
+  reggroup_add (gdbarch, xtensa_vectra_reggroup);	/* vectra */
+}
+
+
+#define SAVE_REST_FLAGS	(XTENSA_REGISTER_FLAGS_READABLE \
+			| XTENSA_REGISTER_FLAGS_WRITABLE \
+			| XTENSA_REGISTER_FLAGS_VOLATILE)
+
+#define SAVE_REST_VALID	(XTENSA_REGISTER_FLAGS_READABLE \
+			| XTENSA_REGISTER_FLAGS_WRITABLE)
+
+static int
+xtensa_register_reggroup_p (struct gdbarch *gdbarch,
+			    int regnum,
+    			    struct reggroup *group)
+{
+  xtensa_register_t* reg = &REGMAP[regnum];
+  xtensa_register_type_t type = reg->type;
+  xtensa_register_group_t rg = reg->group;
+
+  /* First, skip registers that are not visible to this target
+     (unknown and unmapped registers when not using ISS).  */
+
+  if (type == xtRegisterTypeUnmapped || type == xtRegisterTypeUnknown)
+    return 0;
+  if (group == all_reggroup)
+    return 1;
+  if (group == xtensa_ar_reggroup)
+    return rg & xtRegisterGroupAddrReg;
+  if (group == xtensa_user_reggroup)
+    return rg & xtRegisterGroupUser;
+  if (group == float_reggroup)
+    return rg & xtRegisterGroupFloat;
+  if (group == general_reggroup)
+    return rg & xtRegisterGroupGeneral;
+  if (group == float_reggroup)
+    return rg & xtRegisterGroupFloat;
+  if (group == system_reggroup)
+    return rg & xtRegisterGroupState;
+  if (group == vector_reggroup || group == xtensa_vectra_reggroup)
+    return rg & xtRegisterGroupVectra;
+  if (group == save_reggroup || group == restore_reggroup)
+    return (regnum < NUM_REGS
+	    && (reg->flags & SAVE_REST_FLAGS) == SAVE_REST_VALID);
+  else
+    return 1;
+}
+
+
+/* CORE FILE SUPPORT */
+
+/* Supply register REGNUM from the buffer specified by GREGS and LEN
+   in the general-purpose register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+static void
+xtensa_supply_gregset (const struct regset *regset,
+		       struct regcache *rc,
+		       int regnum,
+		       const void *gregs,
+		       size_t len)
+{
+  const xtensa_elf_gregset_t *regs = gregs;
+  int i;
+
+  DEBUGTRACE ("xtensa_supply_gregset (..., regnum==%d, ...) \n", regnum);
+
+  if (regnum == PC_REGNUM || regnum == -1)
+    regcache_raw_supply (rc, PC_REGNUM, (char *) &regs->pc);
+  if (regnum == PS_REGNUM || regnum == -1)
+    regcache_raw_supply (rc, PS_REGNUM, (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]);
+  else if (regnum == -1)
+    {
+      for (i = 0; i < NUM_AREGS; ++i)
+	regcache_raw_supply (rc, AR_BASE + i, (char *) &regs->ar[i]);
+    }
+}
+
+
+/* Xtensa register set.  */
+
+static struct regset
+xtensa_gregset =
+{
+  NULL,
+  xtensa_supply_gregset
+};
+
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+xtensa_regset_from_core_section (struct gdbarch *core_arch,
+				 const char *sect_name,
+				 size_t sect_size)
+{
+  DEBUGTRACE ("xtensa_regset_from_core_section "
+	      "(..., sect_name==\"%s\", sect_size==%x) \n",
+	      sect_name, sect_size);
+
+  if (strcmp (sect_name, ".reg") == 0
+      && sect_size >= sizeof(xtensa_elf_gregset_t))
+    return &xtensa_gregset;
+
+  return NULL;
+}
+
+
+/* F R A M E */
+
+/* We currently don't support the call0-abi, so we have at max. 12 registers
+   saved on the stack.  */
+
+#define XTENSA_NUM_SAVED_AREGS 12
+
+typedef struct xtensa_frame_cache
+{
+  CORE_ADDR base;
+  CORE_ADDR pc;
+  CORE_ADDR ra;		/* The raw return address; use to compute call_inc.  */
+  CORE_ADDR ps;
+  int wb;		/* Base for this frame; -1 if not in regfile.  */
+  int callsize;		/* Call size to next frame.  */
+  int ws;
+  CORE_ADDR aregs[XTENSA_NUM_SAVED_AREGS];
+  CORE_ADDR prev_sp;
+} xtensa_frame_cache_t;
+
+
+static struct xtensa_frame_cache *
+xtensa_alloc_frame_cache (void)
+{
+  xtensa_frame_cache_t *cache;
+  int i;
+
+  DEBUGTRACE ("xtensa_alloc_frame_cache ()\n");
+
+  cache = FRAME_OBSTACK_ZALLOC (xtensa_frame_cache_t);
+
+  cache->base = 0;
+  cache->pc = 0;
+  cache->ra = 0;
+  cache->wb = 0;
+  cache->ps = 0;
+  cache->callsize = -1;
+  cache->prev_sp = 0;
+
+  for (i = 0; i < XTENSA_NUM_SAVED_AREGS; i++)
+    cache->aregs[i] = -1;
+
+  return cache;
+}
+
+
+static CORE_ADDR
+xtensa_frame_align (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+  return address & ~15;
+}
+
+
+static CORE_ADDR
+xtensa_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  char buf[8];
+
+  DEBUGTRACE ("xtensa_unwind_pc (next_frame = %p)\n", next_frame);
+
+  frame_unwind_register (next_frame, PC_REGNUM, buf);
+
+  DEBUGINFO ("[xtensa_unwind_pc] pc = 0x%08x\n", (unsigned int)
+	     extract_typed_address (buf, builtin_type_void_func_ptr));
+
+  return extract_typed_address (buf, builtin_type_void_func_ptr);
+}
+
+
+static struct frame_id
+xtensa_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  CORE_ADDR pc, fp;
+  char buf[4];
+
+  /* next_frame->prev is a dummy frame. Return a frame ID of that frame.  */
+
+  DEBUGTRACE ("xtensa_unwind_dummy_id ()\n");
+
+  pc = frame_pc_unwind (next_frame);
+  frame_unwind_register (next_frame, A1_REGNUM, buf);
+  fp = extract_unsigned_integer (buf, 4);
+
+  /* Make dummy frame ID unique by adding a constant.  */
+  return frame_id_build (fp+SP_ALIGNMENT, pc);
+}
+
+
+static struct xtensa_frame_cache *
+xtensa_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  xtensa_frame_cache_t *cache;
+  char buf[4];
+  CORE_ADDR ra, wb, ws, pc, sp, ps;
+  char op1;
+
+  DEBUGTRACE ("xtensa_frame_cache (next_frame %p, *this_cache %p)\n",
+	      next_frame, this_cache ? *this_cache : (void*)0xdeadbeef);
+
+  /* Already cached?  */
+  if (*this_cache)
+    return *this_cache;
+
+  /* Get pristine xtensa-frame.  */
+  cache = xtensa_alloc_frame_cache ();
+  *this_cache = cache;
+
+  /* Get windowbase, windowstart, ps, and pc.  */
+  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);
+  pc = frame_unwind_register_unsigned (next_frame, PC_REGNUM);
+
+  op1 = read_memory_integer (pc, 1);
+  if (XTENSA_IS_ENTRY (op1) || !windowing_enabled (read_register (PS_REGNUM)))
+    {
+      int callinc = CALLINC (frame_unwind_register_unsigned (next_frame,
+							     PS_REGNUM));
+      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);
+
+      /* ENTRY hasn't been executed yet, therefore callsize is still 0.  */
+      cache->callsize = 0;
+      cache->wb = wb;
+      cache->ws = ws;
+      cache->prev_sp = read_register (A1_REGNUM);
+    }
+  else
+    {
+      ra = frame_unwind_register_unsigned (next_frame, A0_REGNUM);
+      cache->callsize = WINSIZE (ra);
+      cache->wb = (wb - (cache->callsize / 4)) & ((NUM_AREGS / 4) - 1);
+      cache->ws = ws & ~(1 << wb);
+    }
+
+  cache->pc = ((frame_func_unwind (next_frame) & 0xc0000000)
+	       | (ra & 0x3fffffff));
+  cache->ps = (ps & ~PS_CALLINC_MASK) | ((WINSIZE(ra)/4) << PS_CALLINC_SHIFT);
+
+
+  /* Note: We could also calculate the location on stack when we actually
+     access the register.  However, this approach, saving the location
+     in the cache frame, is probably easier to support the call0 ABI.  */
+
+  if (cache->ws == 0)
+    {
+      int i;
+
+      /* Set A0...A3.  */
+      sp = frame_unwind_register_unsigned (next_frame, A1_REGNUM) - 16;
+
+      for (i = 0; i < 4; i++, sp += 4)
+	{
+	  cache->aregs[i] = sp;
+	}
+
+      if (cache->callsize > 4)
+	{
+	  /* Set A4...A7/A11.  */
+
+	  sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
+	  sp = (CORE_ADDR) read_memory_integer (sp - 12, 4);
+	  sp -= cache->callsize * 4;
+
+	  for ( /* i=4  */ ; i < cache->callsize; i++, sp += 4)
+	    {
+	      cache->aregs[i] = sp;
+	    }
+	}
+    }
+
+  if (cache->prev_sp == 0) 
+    {
+      if (cache->ws == 0)
+	{
+	  /* Register window overflow already happened.
+	     We can read caller's frame SP from the proper spill loction.  */
+	  cache->prev_sp =
+		  read_memory_integer (cache->aregs[1],
+				       register_size (current_gdbarch,
+						      A1_REGNUM));
+	}
+      else
+	{
+	  /* Read caller's frame SP directly from the previous window.  */
+
+	  int regnum = AREG_NUMBER (A1_REGNUM, cache->wb);
+
+	  cache->prev_sp = read_register (regnum);
+	}
+    }
+
+  cache->base = frame_unwind_register_unsigned (next_frame,A1_REGNUM);
+
+  DEBUGINFO ("[xtensa_frame_cache] base 0x%08x, wb %d, "
+	     "ws 0x%08x, callsize %d, pc 0x%08x, ps 0x%08x, prev_sp 0x%08x\n",
+	     (unsigned int) cache->base, (unsigned int) cache->wb,
+	     cache->ws, cache->callsize, (unsigned int) cache->pc,
+	     (unsigned int) cache->ps, (unsigned int) cache->prev_sp);
+
+  return cache;
+}
+
+
+static void
+xtensa_frame_this_id (struct frame_info *next_frame,
+		      void **this_cache,
+		      struct frame_id *this_id)
+{
+  struct xtensa_frame_cache *cache =
+    xtensa_frame_cache (next_frame, this_cache);
+
+  DEBUGTRACE ("xtensa_frame_this_id (next 0x%08x, *this 0x%08x)\n",
+	      (unsigned int) next_frame, (unsigned int) *this_cache);
+
+  if (cache->prev_sp == 0)
+    return;
+
+  (*this_id) = frame_id_build (cache->prev_sp, cache->pc);
+}
+
+
+static void
+xtensa_frame_prev_register (struct frame_info *next_frame,
+			    void **this_cache,
+			    int regnum,
+			    int *optimizedp,
+			    enum lval_type *lvalp,
+			    CORE_ADDR *addrp,
+			    int *realnump,
+			    gdb_byte *valuep)
+{
+  struct xtensa_frame_cache *cache =
+    xtensa_frame_cache (next_frame, this_cache);
+  CORE_ADDR 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 (regnum == WS_REGNUM)
+    {
+      if (cache->ws != 0)
+	saved_reg = cache->ws;
+      else
+	saved_reg = 1 << cache->wb;
+    }
+  else if (regnum == WB_REGNUM)
+    saved_reg = cache->wb;
+  else if (regnum == PC_REGNUM)
+    saved_reg = cache->pc;
+  else if (regnum == PS_REGNUM)
+    saved_reg = cache->ps;
+  else
+    done = 0;
+
+  if (done)
+    {
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      if (valuep)
+	store_unsigned_integer (valuep, 4, saved_reg);
+
+      return;
+    }
+
+  /* Convert Ax register numbers to ARx register numbers.  */
+  if (regnum >= A0_REGNUM && regnum <= A15_REGNUM)
+    regnum = AREG_NUMBER (regnum, cache->wb);
+
+  /* Check if ARx register has been saved to stack.  */
+  if (regnum >= AR_BASE && regnum <= (AR_BASE + NUM_AREGS))
+    {
+      int areg = regnum - AR_BASE - (cache->wb * 4);
+
+      if (areg >= 0
+	  && areg < XTENSA_NUM_SAVED_AREGS
+	  && cache->aregs[areg] != -1)
+        {
+    	  *optimizedp = 0;
+	  *lvalp = lval_memory;
+	  *addrp = cache->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;
+	}
+    }
+
+  /* Note: All other registers have been either saved to the dummy stack
+     or are still alive in the processor.  */
+
+  frame_register_unwind (next_frame, regnum,
+			 optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+
+static const struct frame_unwind
+xtensa_frame_unwind =
+{
+  NORMAL_FRAME,
+  xtensa_frame_this_id,
+  xtensa_frame_prev_register
+};
+
+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)
+{
+  struct xtensa_frame_cache *cache =
+    xtensa_frame_cache (next_frame, this_cache);
+
+  return cache->base;
+}
+
+static const struct frame_base
+xtensa_frame_base =
+{
+  &xtensa_frame_unwind,
+  xtensa_frame_base_address,
+  xtensa_frame_base_address,
+  xtensa_frame_base_address
+};
+
+
+static void
+xtensa_extract_return_value (struct type *type,
+			     struct regcache *regcache,
+			     void *dst)
+{
+  bfd_byte *valbuf = dst;
+  int len = TYPE_LENGTH (type);
+  ULONGEST pc, wb;
+  int callsize, areg;
+  int offset = 0;
+
+  DEBUGTRACE ("xtensa_extract_return_value (...)\n");
+
+  gdb_assert(len > 0);
+
+  /* First, we have to find the caller window in the register file.  */
+  regcache_raw_read_unsigned (regcache, PC_REGNUM, &pc);
+  callsize = extract_call_winsize (pc);
+
+  /* On Xtensa, we can return up to 4 words (or 2 when called by call12).  */
+  if (len > (callsize > 8? 8 : 16))
+    internal_error (__FILE__, __LINE__,
+	            _("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);
+
+  DEBUGINFO ("[xtensa_extract_return_value] areg %d len %d\n", areg, len);
+
+  if (len < 4 && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    offset = 4 - len;
+
+  for (; len > 0; len -=4, areg++, valbuf+=4)
+    {
+      if (len < 4)
+	regcache_raw_read_part (regcache, areg, offset, len, valbuf);
+      else
+	regcache_raw_read (regcache, areg, valbuf);
+    }
+}
+
+
+static void
+xtensa_store_return_value (struct type *type,
+			   struct regcache *regcache,
+			   const void *dst)
+{
+  const bfd_byte *valbuf = dst;
+  unsigned int areg;
+  ULONGEST pc, wb;
+  int callsize;
+  int len = TYPE_LENGTH (type);
+  int offset = 0;
+
+  DEBUGTRACE ("xtensa_store_return_value (...)\n");
+
+  regcache_raw_read_unsigned (regcache, WB_REGNUM, &wb);
+  regcache_raw_read_unsigned (regcache, PC_REGNUM, &pc);
+  callsize = extract_call_winsize (pc);
+
+  if (len > (callsize > 8 ? 8 : 16))
+    internal_error (__FILE__, __LINE__,
+		    _("unimplemented for this length: %d"),
+		    TYPE_LENGTH (type));
+
+  DEBUGTRACE ("[xtensa_store_return_value] callsize %d wb %d\n",
+              callsize, (int) wb);
+
+  if (len < 4 && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+    offset = 4 - len;
+
+  areg = AREG_NUMBER (A2_REGNUM + callsize, wb);
+
+  for (; len > 0; len -= 4, areg++, valbuf += 4)
+    {
+      if (len < 4)
+	regcache_raw_write_part (regcache, areg, offset, len, valbuf);
+      else
+	regcache_raw_write (regcache, areg, valbuf);
+    }
+}
+
+
+enum return_value_convention
+xtensa_return_value (struct gdbarch *gdbarch,
+		     struct type *valtype,
+		     struct regcache *regcache,
+		     gdb_byte *readbuf,
+		     const gdb_byte *writebuf)
+{
+  /* Note: Structures up to 16 bytes are returned in registers.  */
+
+  int struct_return = ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+			|| TYPE_CODE (valtype) == TYPE_CODE_UNION
+			|| TYPE_CODE (valtype) == TYPE_CODE_ARRAY)
+		       && TYPE_LENGTH (valtype) > 16);
+
+  if (struct_return)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  DEBUGTRACE ("xtensa_return_value(...)\n");
+
+  if (writebuf != NULL)
+    {
+      xtensa_store_return_value (valtype, regcache, writebuf);
+    }
+
+  if (readbuf != NULL)
+    {
+      gdb_assert (!struct_return);
+      xtensa_extract_return_value (valtype, regcache, readbuf);
+    }
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
+/* DUMMY FRAME */
+
+static CORE_ADDR
+xtensa_push_dummy_call (struct gdbarch *gdbarch,
+			struct value *function,
+			struct regcache *regcache,
+			CORE_ADDR bp_addr,
+			int nargs,
+			struct value **args,
+			CORE_ADDR sp,
+			int struct_return,
+			CORE_ADDR struct_addr)
+{
+  int i;
+  int size, onstack_size;
+  char *buf = (char *) alloca (16);
+  CORE_ADDR ra, ps;
+  struct argument_info
+  {
+    const bfd_byte *contents;
+    int length;
+    int onstack;		/* onstack == 0 => in reg */
+    int align;			/* alignment */
+    union
+    {
+      int offset;		/* stack offset if on stack */
+      int regno;		/* regno if in register */
+    } u;
+  };
+
+  struct argument_info *arg_info =
+    (struct argument_info *) alloca (nargs * sizeof (struct argument_info));
+
+  CORE_ADDR osp = sp;
+
+  DEBUGTRACE ("xtensa_push_dummy_call (...)\n");
+
+  if (xtensa_debug_level > 3)
+    {
+      int i;
+      DEBUGINFO ("[xtensa_push_dummy_call] nargs = %d\n", nargs);
+      DEBUGINFO ("[xtensa_push_dummy_call] sp=0x%x, struct_return=%d, "
+		 "struct_addr=0x%x\n",
+		 (int) sp, (int) struct_return, (int) struct_addr);
+
+      for (i = 0; i < nargs; i++)
+        {
+	  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));
+	  switch (TYPE_CODE (arg_type))
+	    {
+	    case TYPE_CODE_INT:
+	      fprintf_unfiltered (gdb_stdlog, "int");
+	      break;
+	    case TYPE_CODE_STRUCT:
+	      fprintf_unfiltered (gdb_stdlog, "struct");
+	      break;
+	    default:
+	      fprintf_unfiltered (gdb_stdlog, "%3d", TYPE_CODE (arg_type));
+	      break;
+	    }
+	  fprintf_unfiltered (gdb_stdlog, " 0x%08x\n",
+			      (unsigned int) value_contents (arg));
+	}
+    }
+
+  /* First loop: collect information.
+     Cast into type_long.  (This shouldn't happen often for C because
+     GDB already does this earlier.)  It's possible that GDB could
+     do it all the time but it's harmless to leave this code here.  */
+
+  size = 0;
+  onstack_size = 0;
+  i = 0;
+
+  if (struct_return)
+    size = REGISTER_SIZE;
+
+  for (i = 0; i < nargs; i++)
+    {
+      struct argument_info *info = &arg_info[i];
+      struct value *arg = args[i];
+      struct type *arg_type = check_typedef (value_type (arg));
+
+      switch (TYPE_CODE (arg_type))
+	{
+	case TYPE_CODE_INT:
+	case TYPE_CODE_BOOL:
+	case TYPE_CODE_CHAR:
+	case TYPE_CODE_RANGE:
+	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))
+	    {
+	      arg_type = builtin_type_long;
+	      arg = value_cast (arg_type, arg);
+	    }
+	  info->align = TYPE_LENGTH (builtin_type_long);
+	  break;
+
+	case TYPE_CODE_FLT:
+
+	  /* Align doubles correctly.  */
+	  if (TYPE_LENGTH (arg_type) == TYPE_LENGTH (builtin_type_double))
+	    info->align = TYPE_LENGTH (builtin_type_double);
+	  else
+	    info->align = TYPE_LENGTH (builtin_type_long);
+	  break;
+
+	case TYPE_CODE_STRUCT:
+	default:
+	  info->align = TYPE_LENGTH (builtin_type_long);
+	  break;
+	}
+      info->length = TYPE_LENGTH (arg_type);
+      info->contents = value_contents (arg);
+
+      /* Align size and onstack_size.  */
+      size = (size + info->align - 1) & ~(info->align - 1);
+      onstack_size = (onstack_size + info->align - 1) & ~(info->align - 1);
+
+      if (size + info->length > REGISTER_SIZE * ARGS_NUM_REGS)
+	{
+	  info->onstack = 1;
+	  info->u.offset = onstack_size;
+	  onstack_size += info->length;
+	}
+      else
+	{
+	  info->onstack = 0;
+	  info->u.regno = ARGS_FIRST_REG + size / REGISTER_SIZE;
+	}
+      size += info->length;
+    }
+
+  /* Adjust the stack pointer and align it.  */
+  sp = align_down (sp - onstack_size, SP_ALIGNMENT);
+
+  /* Simulate MOVSP.  */
+  if (sp != osp)
+    {
+      read_memory (osp - 16, buf, 16);
+      write_memory (sp - 16, buf, 16);
+    }
+
+  /* Second Loop: Load arguments.  */
+
+  if (struct_return)
+    {
+      store_unsigned_integer (buf, REGISTER_SIZE, struct_addr);
+      regcache_cooked_write (regcache, ARGS_FIRST_REG, buf);
+    }
+
+  for (i = 0; i < nargs; i++)
+    {
+      struct argument_info *info = &arg_info[i];
+
+      if (info->onstack)
+	{
+	  int n = info->length;
+	  CORE_ADDR offset = sp + info->u.offset;
+
+	  /* Odd-sized structs are aligned to the lower side of a memory
+	     word in big-endian mode and require a shift.  This only
+	     applies for structures smaller than one word.  */
+
+	  if (n < REGISTER_SIZE && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+	    offset += (REGISTER_SIZE - n);
+
+	  write_memory (offset, info->contents, info->length);
+
+	}
+      else
+	{
+	  int n = info->length;
+	  const bfd_byte *cp = info->contents;
+	  int r = info->u.regno;
+
+	  /* Odd-sized structs are aligned to the lower side of registers in
+	     big-endian mode and require a shift.  The odd-sized leftover will
+	     be at the end.  Note that this is only true for structures smaller
+	     than REGISTER_SIZE; for larger odd-sized structures the excess
+	     will be left-aligned in the register on both endiannesses.  */
+
+	  if (n < REGISTER_SIZE && TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+	    {
+	      ULONGEST v = extract_unsigned_integer (cp, REGISTER_SIZE);
+	      v = v >> ((REGISTER_SIZE - n) * TARGET_CHAR_BIT);
+
+	      store_unsigned_integer (buf, REGISTER_SIZE, v);
+	      regcache_cooked_write (regcache, r, buf);
+
+	      cp += REGISTER_SIZE;
+	      n -= REGISTER_SIZE;
+	      r++;
+	    }
+	  else
+	    while (n > 0)
+	      {
+	        /* ULONGEST v = extract_unsigned_integer (cp, REGISTER_SIZE);*/
+		regcache_cooked_write (regcache, r, cp);
+
+		/* write_register (r, v); */
+		cp += REGISTER_SIZE;
+		n -= REGISTER_SIZE;
+		r++;
+	      }
+	}
+    }
+
+
+  /* Set the return address of dummy frame to the dummy address.
+     Note: The return address for the current function (in A0) is
+     saved in the dummy frame, so we can savely overwrite A0 here.  */
+
+  ra = (bp_addr & 0x3fffffff) | 0x40000000;
+  regcache_raw_read (regcache, PS_REGNUM, buf);
+  ps = extract_unsigned_integer (buf, 4) & ~0x00030000;
+  regcache_cooked_write_unsigned (regcache, A4_REGNUM, ra);
+  regcache_cooked_write_unsigned (regcache, PS_REGNUM, ps | 0x00010000);
+
+  /* Set new stack pointer and return it.  */
+  regcache_cooked_write_unsigned (regcache, A1_REGNUM, sp);
+  /* Make dummy frame ID unique by adding a constant.  */
+  return sp + SP_ALIGNMENT;
+}
+
+
+/* Return a breakpoint for the current location of PC.  We always use
+   the density version if we have density instructions (regardless of the
+   current instruction at PC), and use regular instructions otherwise.  */
+
+#define BIG_BREAKPOINT { 0x00, 0x04, 0x00 }
+#define LITTLE_BREAKPOINT { 0x00, 0x40, 0x00 }
+#define DENSITY_BIG_BREAKPOINT { 0xd2, 0x0f }
+#define DENSITY_LITTLE_BREAKPOINT { 0x2d, 0xf0 }
+
+const unsigned char *
+xtensa_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+{
+  static char big_breakpoint[] = BIG_BREAKPOINT;
+  static char little_breakpoint[] = LITTLE_BREAKPOINT;
+  static char density_big_breakpoint[] = DENSITY_BIG_BREAKPOINT;
+  static char density_little_breakpoint[] = DENSITY_LITTLE_BREAKPOINT;
+
+  DEBUGTRACE ("xtensa_breakpoint_from_pc (pc = 0x%08x)\n", (int) *pcptr);
+
+  if (ISA_USE_DENSITY_INSTRUCTIONS)
+    {
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+	{
+	  *lenptr = sizeof (density_big_breakpoint);
+	  return density_big_breakpoint;
+	}
+      else
+	{
+	  *lenptr = sizeof (density_little_breakpoint);
+	  return density_little_breakpoint;
+	}
+    }
+  else
+    {
+      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+	{
+	  *lenptr = sizeof (big_breakpoint);
+	  return big_breakpoint;
+	}
+      else
+	{
+	  *lenptr = sizeof (little_breakpoint);
+	  return little_breakpoint;
+	}
+    }
+}
+
+
+/* Return the pc of the first real instruction.  We assume that this
+   machine uses register windows.
+
+   If we have debug info ( line-number info, in particular ) we simply skip
+   the code associated with the first function line effectively skipping
+   the prologue code. It works even in cases like
+
+   int main()
+   {	int local_var = 1;
+   	....
+   }
+
+   because, for this source code, both Xtensa compilers will generate two
+   separate entries ( with the same line number ) in dwarf line-number
+   section to make sure there is a boundary between the prologue code and
+   the rest of the function.
+
+   If there is no debug info, we need to analyze the code. */
+
+CORE_ADDR
+xtensa_skip_prologue (CORE_ADDR start_pc)
+{
+  DEBUGTRACE ("xtensa_skip_prologue (start_pc = 0x%08x)\n", (int) start_pc);
+
+  if (ISA_USE_WINDOWED_REGISTERS)
+    {
+      unsigned char op1;
+      struct symtab_and_line prologue_sal;
+
+      op1 = read_memory_integer (start_pc, 1);
+      if (!XTENSA_IS_ENTRY (op1))
+	return start_pc;
+
+      prologue_sal = find_pc_line (start_pc, 0);
+      if (prologue_sal.line != 0)
+	return prologue_sal.end;
+      else
+	return start_pc + XTENSA_ENTRY_LENGTH;
+    }
+  else
+    {
+      internal_error (__FILE__, __LINE__,
+		      _("non-windowed configurations are not supported"));
+      return start_pc;
+    }
+}
+
+
+/* CONFIGURATION CHECK */
+
+/* Verify the current configuration.  */
+
+static void
+xtensa_verify_config (struct gdbarch *gdbarch)
+{
+  struct ui_file *log;
+  struct cleanup *cleanups;
+  struct gdbarch_tdep *tdep;
+  long dummy;
+  char *buf;
+
+  tdep = gdbarch_tdep (gdbarch);
+  log = mem_fileopen ();
+  cleanups = make_cleanup_ui_file_delete (log);
+
+  /* Verify that we got a reasonable number of AREGS.  */
+  if ((tdep->num_aregs & -tdep->num_aregs) != tdep->num_aregs)
+    fprintf_unfiltered (log, "\n\tnum_aregs: Number of AR registers (%d) "
+			"is not a power of two!", tdep->num_aregs);
+
+  /* Verify that certain registers exist.  */
+  if (tdep->pc_regnum == -1)
+    fprintf_unfiltered (log, "\n\tpc_regnum: No PC register");
+  if (tdep->ps_regnum == -1)
+    fprintf_unfiltered (log, "\n\tps_regnum: No PS register");
+  if (tdep->wb_regnum == -1)
+    fprintf_unfiltered (log, "\n\twb_regnum: No WB register");
+  if (tdep->ws_regnum == -1)
+    fprintf_unfiltered (log, "\n\tws_regnum: No WS register");
+  if (tdep->ar_base == -1)
+    fprintf_unfiltered (log, "\n\tar_base: No AR registers");
+  if (tdep->a0_base == -1)
+    fprintf_unfiltered (log, "\n\ta0_base: No Ax registers");
+
+  buf = ui_file_xstrdup (log, &dummy);
+  make_cleanup (xfree, buf);
+  if (strlen (buf) > 0)
+    internal_error (__FILE__, __LINE__,
+		    _("the following are invalid: %s"), buf);
+  do_cleanups (cleanups);
+}
+
+
+/* Module "constructor" function.  */
+
+static struct gdbarch *
+xtensa_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch_tdep *tdep;
+  struct gdbarch *gdbarch;
+  struct xtensa_abi_handler *abi_handler;
+
+  DEBUGTRACE ("gdbarch_init()\n");
+
+  /* We have to set the byte order before we call gdbarch_alloc.  */
+  info.byte_order = xtensa_config_byte_order (&info);
+
+  tdep = xtensa_config_tdep (&info);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* Verify our configuration.  */
+  xtensa_verify_config (gdbarch);
+
+  /* Pseudo-Register read/write  */
+  set_gdbarch_pseudo_register_read (gdbarch, xtensa_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, xtensa_pseudo_register_write);
+
+  /* Set target information.  */
+  set_gdbarch_num_regs (gdbarch, tdep->num_regs);
+  set_gdbarch_num_pseudo_regs (gdbarch, tdep->num_pseudo_regs);
+  set_gdbarch_sp_regnum (gdbarch, tdep->a0_base + 1);
+  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).  */
+  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 */
+  set_gdbarch_push_dummy_call (gdbarch, xtensa_push_dummy_call);
+
+  set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+  set_gdbarch_return_value (gdbarch, xtensa_return_value);
+
+  /* Advance PC across any prologue instructions to reach "real" code.  */
+  set_gdbarch_skip_prologue (gdbarch, xtensa_skip_prologue);
+
+  /* Stack grows downward.  */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  /* Set breakpoints.  */
+  set_gdbarch_breakpoint_from_pc (gdbarch, xtensa_breakpoint_from_pc);
+
+  /* After breakpoint instruction or illegal instruction, pc still
+     points at break instruction, so don't decrement.  */
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+  /* We don't skip args.  */
+  set_gdbarch_frame_args_skip (gdbarch, 0);
+
+  set_gdbarch_unwind_pc (gdbarch, xtensa_unwind_pc);
+
+  set_gdbarch_frame_align (gdbarch, xtensa_frame_align);
+
+  set_gdbarch_unwind_dummy_id (gdbarch, xtensa_unwind_dummy_id);
+
+  /* Frame handling.  */
+  frame_base_set_default (gdbarch, &xtensa_frame_base);
+  frame_unwind_append_sniffer (gdbarch, xtensa_frame_sniffer);
+
+  set_gdbarch_print_insn (gdbarch, print_insn_xtensa);
+
+  set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
+  xtensa_add_reggroups (gdbarch);
+  set_gdbarch_register_reggroup_p (gdbarch, xtensa_register_reggroup_p);
+
+  set_gdbarch_regset_from_core_section (gdbarch,
+					xtensa_regset_from_core_section);
+
+  return gdbarch;
+}
+
+
+/* Dump xtensa tdep structure.  */
+
+static void
+xtensa_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+{
+  error (_("xtensa_dump_tdep(): not implemented"));
+}
+
+
+void
+_initialize_xtensa_tdep (void)
+{
+  struct cmd_list_element *c;
+
+  gdbarch_register (bfd_arch_xtensa, xtensa_gdbarch_init, xtensa_dump_tdep);
+  xtensa_init_reggroups ();
+
+  add_setshow_zinteger_cmd ("xtensa",
+			    class_maintenance,
+			    &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,
+			    NULL,
+			    &setdebuglist, &showdebuglist);
+}
Index: gdb/config/xtensa/xtensa.mt
===================================================================
m@@ -0,0 +1,2 @@
+# Target: Tensilica Xtensa processors
+TDEPFILES= xtensa-tdep.o xtensa-config.o
Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.845
diff -u -r1.845 Makefile.in
--- gdb/Makefile.in	5 Oct 2006 19:42:31 -0000	1.845
+++ gdb/Makefile.in	5 Oct 2006 23:29:55 -0000
@@ -825,6 +825,8 @@
 wrapper_h = wrapper.h $(gdb_h)
 xcoffsolib_h = xcoffsolib.h
 xml_support_h = xml-support.h $(gdb_expat_h)
+xtensa_tdep_h = xtensa-tdep.h 
+
 
 #
 # gdb/cli/ headers
@@ -1330,7 +1332,6 @@
 	done
 
 Makefile: Makefile.in config.status @frags@
-	# Regenerate the Makefile and the tm.h / nm.h links.
 	CONFIG_FILES=Makefile \
 	  CONFIG_COMMANDS= \
 	  CONFIG_HEADERS= \
@@ -1500,7 +1501,10 @@
 	vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
 	win32-nat.c \
 	xcoffread.c xcoffsolib.c \
-	xstormy16-tdep.c
+	xstormy16-tdep.c \
+	xtensa-tdep.c xtensa-config.c
+
+
 
 # Some files need explicit build rules (due to -Werror problems) or due
 # to sub-directory fun 'n' games.
@@ -2862,6 +2866,16 @@
 	$(gdbcmd_h) $(gdbcore_h) $(value_h) $(dis_asm_h) $(inferior_h) \
 	$(gdb_string_h) $(gdb_assert_h) $(arch_utils_h) $(floatformat_h) \
 	$(regcache_h) $(doublest_h) $(osabi_h) $(objfiles_h)
+xtensa-linux-tdep.o: xtensa-linux-tdep.c $(defs_h) $(inferior_h) \
+	$(gdbcore_h) $(regcache_h) $(osabi_h) $(gdb_string_h) \
+	$(xtensa_tdep_h) $(xtensa_linux_tdep_h)
+xtensa-tdep.o: xtensa-tdep.c $(defs_h) $(doublest_h) $(frame_h) \
+	$(frame_unwind_h) $(frame_base_h) $(inferior_h) $(symtab_h) \
+	$(value_h) $(gdbcmd_h) $(gdbcore_h) $(dis_asm_h) $(symfile_h) \
+	$(objfiles_h) $(gdb_string_h) $(linespec_h) $(regcache_h) \
+	$(reggroups_h) $(arch_utils_h) $(osabi_h) $(block_h) $(gdb_assert_h) \
+	$(elf_bfd_h) $(xtensa_tdep_h) $(dwarf2_frame_h)
+xtensa-config.o: $(defs_h) $(xtensa_tdep_h)
 
 #
 # gdb/cli/ dependencies
Index: gdb/NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.197
diff -u -r1.197 NEWS
--- gdb/NEWS	16 Aug 2006 20:33:23 -0000	1.197
+++ gdb/NEWS	5 Oct 2006 23:30:00 -0000
@@ -3,6 +3,10 @@
 
 *** Changes since GDB 6.5
 
+* New targets
+
+Xtensa				xtensa-elf
+
 * GDB can now be configured as a cross-debugger targeting native Windows
 (mingw32) or Cygwin.  It can communicate with a remote debugging stub
 running on a Windows system over TCP/IP to debug Windows programs.
Index: gdb/configure.host
===================================================================
RCS file: /cvs/src/src/gdb/configure.host,v
retrieving revision 1.94
diff -u -r1.94 configure.host
--- gdb/configure.host	10 Feb 2006 21:53:51 -0000	1.94
+++ gdb/configure.host	5 Oct 2006 23:30:04 -0000
@@ -28,6 +28,7 @@
 x86_64*)		gdb_host_cpu=i386 ;;
 xscale*)		gdb_host_cpu=arm ;;
 m32r*)			gdb_host_cpu=m32r ;;
+xtensa*)		gdb_host_cpu=xtensa ;;
 *)			gdb_host_cpu=$host_cpu ;;
 
 esac
@@ -156,6 +157,8 @@
 
 m32r*-*-linux*)          gdb_host=linux ;;
 
+xtensa*-*-linux*)	gdb_host=linux ;;
+
 esac
 
 
Index: gdb/configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.177
diff -u -r1.177 configure.tgt
--- gdb/configure.tgt	8 Aug 2006 18:57:25 -0000	1.177
+++ gdb/configure.tgt	5 Oct 2006 23:30:07 -0000
@@ -28,6 +28,7 @@
 strongarm*)		gdb_target_cpu=arm ;;
 xscale*)		gdb_target_cpu=arm ;;
 x86_64*)		gdb_target_cpu=i386 ;;
+xtensa*)		gdb_target_cpu=xtensa ;;
 *)			gdb_target_cpu=$target_cpu ;;
 
 esac
@@ -224,6 +225,8 @@
 			gdb_target=nbsd64 ;;
 x86_64-*-openbsd*)	gdb_target=obsd64 ;;
 
+xtensa*)		gdb_target=xtensa ;;
+
 esac
 
 # map target onto default OS ABI
Index: gdb/doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.355
diff -u -r1.355 gdb.texinfo
--- gdb/doc/gdb.texinfo	21 Sep 2006 14:01:12 -0000	1.355
+++ gdb/doc/gdb.texinfo	5 Oct 2006 23:30:28 -0000
@@ -497,6 +497,11 @@
 Sakamoto, Yoshinori Sato, Michael Snyder, Corinna Vinschen, and Ulrich
 Weigand.
 
+Christian Zankel, Ross Morley, Bob Wilson, and Maxim Grigoriev from
+Tensilica, Inc.@: contributed support for Xtensa processors.  Others
+who have worked on the Xtensa port of @value{GDBN} in the past include
+Steve Tjiang, John Newlin, and Scott Foehner.
+
 @node Sample Session
 @chapter A Sample @value{GDBN} Session
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]