]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Sat, 15 Jun 2002 12:26:32 +0000 (12:26 +0000)
committernobody <>
Sat, 15 Jun 2002 12:26:32 +0000 (12:26 +0000)
'cagney_regbuf-20020515-branch'.

Cherrypick from master 2002-06-15 12:26:31 UTC Mark Kettenis <kettenis@gnu.org> '* osabi.h (gdb_osabi): Add GDB_OSABI_LYNXOS.':
    bfd/cpu-dlx.c
    bfd/elf32-dlx.c
    bfd/elf32-i386qnx.c
    bfd/elf32-sh64-com.c
    bfd/elf32-sh64-nbsd.c
    bfd/elf32-vax.c
    bfd/elf64-sh64-nbsd.c
    bfd/vax1knetbsd.c
    gdb/ada-exp.tab.c
    gdb/ada-exp.y
    gdb/ada-lang.c
    gdb/ada-lang.h
    gdb/ada-lex.c
    gdb/ada-lex.l
    gdb/ada-tasks.c
    gdb/ada-typeprint.c
    gdb/ada-valprint.c
    gdb/config/arm/nbsdaout.mh
    gdb/config/arm/nbsdelf.mh
    gdb/config/arm/nm-nbsdaout.h
    gdb/config/i386/nbsdaout.mh
    gdb/config/i386/nbsdaout.mt
    gdb/config/i386/nm-nbsdaout.h
    gdb/config/i386/tm-nbsdaout.h
    gdb/config/m68k/nbsdaout.mh
    gdb/config/m68k/nbsdaout.mt
    gdb/config/m68k/nm-nbsdaout.h
    gdb/config/mips/nbsd.mh
    gdb/config/mips/nbsd.mt
    gdb/config/mips/nm-nbsd.h
    gdb/config/mips/tm-nbsd.h
    gdb/config/nm-nbsdaout.h
    gdb/config/ns32k/nbsdaout.mh
    gdb/config/ns32k/nbsdaout.mt
    gdb/config/ns32k/nm-nbsdaout.h
    gdb/config/ns32k/tm-ns32k.h
    gdb/config/sparc/nbsd64.mh
    gdb/config/sparc/nbsd64.mt
    gdb/config/sparc/nbsdaout.mh
    gdb/config/sparc/nm-nbsdaout.h
    gdb/config/sparc/tm-nbsd64.h
    gdb/gdbserver/acinclude.m4
    gdb/gdbserver/proc-service.c
    gdb/gdbserver/thread-db.c
    gdb/i386-linux-tdep.h
    gdb/i386-sol2-tdep.c
    gdb/macrocmd.c
    gdb/macroscope.c
    gdb/macroscope.h
    gdb/mipsnbsd-nat.c
    gdb/mipsnbsd-tdep.c
    gdb/mipsnbsd-tdep.h
    gdb/ns32k-tdep.h
    gdb/ns32knbsd-tdep.c
    gdb/osabi.c
    gdb/osabi.h
    gdb/ppc-sysv-tdep.c
    gdb/ppcnbsd-tdep.c
    gdb/ppcnbsd-tdep.h
    gdb/sh-tdep.h
    gdb/sim-regno.h
    gdb/sparc64nbsd-nat.c
    gdb/sparcnbsd-nat.c
    gdb/sparcnbsd-tdep.c
    gdb/sparcnbsd-tdep.h
    gdb/testsuite/gdb.asm/x86_64.inc
    gdb/testsuite/gdb.base/macscp.exp
    gdb/testsuite/gdb.base/macscp1.c
    gdb/testsuite/gdb.base/macscp2.h
    gdb/testsuite/gdb.base/macscp3.h
    gdb/testsuite/gdb.base/macscp4.h
    gdb/testsuite/gdb.c++/m-data.cc
    gdb/testsuite/gdb.c++/m-data.exp
    gdb/testsuite/gdb.c++/m-static.cc
    gdb/testsuite/gdb.c++/m-static.exp
    gdb/testsuite/gdb.c++/try_catch.cc
    gdb/testsuite/gdb.c++/try_catch.exp
    include/elf/dlx.h
    include/elf/vax.h
    include/gdb/callback.h
    include/gdb/remote-sim.h
    include/gdb/sim-arm.h
    include/gdb/sim-d10v.h
    include/opcode/dlx.h
    opcodes/dlx-dis.c
    sim/common/run-sim.h
    sim/mips/cp1.h
    sim/mips/mdmx.c
    sim/mips/mdmx.igen
    sim/mips/mips3d.igen
    sim/mips/sb1.igen

91 files changed:
bfd/cpu-dlx.c [new file with mode: 0644]
bfd/elf32-dlx.c [new file with mode: 0644]
bfd/elf32-i386qnx.c [new file with mode: 0644]
bfd/elf32-sh64-com.c [new file with mode: 0644]
bfd/elf32-sh64-nbsd.c [new file with mode: 0644]
bfd/elf32-vax.c [new file with mode: 0644]
bfd/elf64-sh64-nbsd.c [new file with mode: 0644]
bfd/vax1knetbsd.c [new file with mode: 0644]
gdb/ada-exp.tab.c [new file with mode: 0644]
gdb/ada-exp.y [new file with mode: 0644]
gdb/ada-lang.c [new file with mode: 0644]
gdb/ada-lang.h [new file with mode: 0644]
gdb/ada-lex.c [new file with mode: 0644]
gdb/ada-lex.l [new file with mode: 0644]
gdb/ada-tasks.c [new file with mode: 0644]
gdb/ada-typeprint.c [new file with mode: 0644]
gdb/ada-valprint.c [new file with mode: 0644]
gdb/config/arm/nbsdaout.mh [new file with mode: 0644]
gdb/config/arm/nbsdelf.mh [new file with mode: 0644]
gdb/config/arm/nm-nbsdaout.h [new file with mode: 0644]
gdb/config/i386/nbsdaout.mh [new file with mode: 0644]
gdb/config/i386/nbsdaout.mt [new file with mode: 0644]
gdb/config/i386/nm-nbsdaout.h [new file with mode: 0644]
gdb/config/i386/tm-nbsdaout.h [new file with mode: 0644]
gdb/config/m68k/nbsdaout.mh [new file with mode: 0644]
gdb/config/m68k/nbsdaout.mt [new file with mode: 0644]
gdb/config/m68k/nm-nbsdaout.h [new file with mode: 0644]
gdb/config/mips/nbsd.mh [new file with mode: 0644]
gdb/config/mips/nbsd.mt [new file with mode: 0644]
gdb/config/mips/nm-nbsd.h [new file with mode: 0644]
gdb/config/mips/tm-nbsd.h [new file with mode: 0644]
gdb/config/nm-nbsdaout.h [new file with mode: 0644]
gdb/config/ns32k/nbsdaout.mh [new file with mode: 0644]
gdb/config/ns32k/nbsdaout.mt [new file with mode: 0644]
gdb/config/ns32k/nm-nbsdaout.h [new file with mode: 0644]
gdb/config/ns32k/tm-ns32k.h [new file with mode: 0644]
gdb/config/sparc/nbsd64.mh [new file with mode: 0644]
gdb/config/sparc/nbsd64.mt [new file with mode: 0644]
gdb/config/sparc/nbsdaout.mh [new file with mode: 0644]
gdb/config/sparc/nm-nbsdaout.h [new file with mode: 0644]
gdb/config/sparc/tm-nbsd64.h [new file with mode: 0644]
gdb/gdbserver/acinclude.m4 [new file with mode: 0644]
gdb/gdbserver/proc-service.c [new file with mode: 0644]
gdb/gdbserver/thread-db.c [new file with mode: 0644]
gdb/i386-linux-tdep.h [new file with mode: 0644]
gdb/i386-sol2-tdep.c [new file with mode: 0644]
gdb/macrocmd.c [new file with mode: 0644]
gdb/macroscope.c [new file with mode: 0644]
gdb/macroscope.h [new file with mode: 0644]
gdb/mipsnbsd-nat.c [new file with mode: 0644]
gdb/mipsnbsd-tdep.c [new file with mode: 0644]
gdb/mipsnbsd-tdep.h [new file with mode: 0644]
gdb/ns32k-tdep.h [new file with mode: 0644]
gdb/ns32knbsd-tdep.c [new file with mode: 0644]
gdb/osabi.c [new file with mode: 0644]
gdb/osabi.h [new file with mode: 0644]
gdb/ppc-sysv-tdep.c [new file with mode: 0644]
gdb/ppcnbsd-tdep.c [new file with mode: 0644]
gdb/ppcnbsd-tdep.h [new file with mode: 0644]
gdb/sh-tdep.h [new file with mode: 0644]
gdb/sim-regno.h [new file with mode: 0644]
gdb/sparc64nbsd-nat.c [new file with mode: 0644]
gdb/sparcnbsd-nat.c [new file with mode: 0644]
gdb/sparcnbsd-tdep.c [new file with mode: 0644]
gdb/sparcnbsd-tdep.h [new file with mode: 0644]
gdb/testsuite/gdb.asm/x86_64.inc [new file with mode: 0644]
gdb/testsuite/gdb.base/macscp.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/macscp1.c [new file with mode: 0644]
gdb/testsuite/gdb.base/macscp2.h [new file with mode: 0644]
gdb/testsuite/gdb.base/macscp3.h [new file with mode: 0644]
gdb/testsuite/gdb.base/macscp4.h [new file with mode: 0644]
gdb/testsuite/gdb.c++/m-data.cc [new file with mode: 0644]
gdb/testsuite/gdb.c++/m-data.exp [new file with mode: 0644]
gdb/testsuite/gdb.c++/m-static.cc [new file with mode: 0644]
gdb/testsuite/gdb.c++/m-static.exp [new file with mode: 0644]
gdb/testsuite/gdb.c++/try_catch.cc [new file with mode: 0644]
gdb/testsuite/gdb.c++/try_catch.exp [new file with mode: 0644]
include/elf/dlx.h [new file with mode: 0644]
include/elf/vax.h [new file with mode: 0644]
include/gdb/callback.h [new file with mode: 0644]
include/gdb/remote-sim.h [new file with mode: 0644]
include/gdb/sim-arm.h [new file with mode: 0644]
include/gdb/sim-d10v.h [new file with mode: 0644]
include/opcode/dlx.h [new file with mode: 0644]
opcodes/dlx-dis.c [new file with mode: 0644]
sim/common/run-sim.h [new file with mode: 0644]
sim/mips/cp1.h [new file with mode: 0644]
sim/mips/mdmx.c [new file with mode: 0644]
sim/mips/mdmx.igen [new file with mode: 0644]
sim/mips/mips3d.igen [new file with mode: 0644]
sim/mips/sb1.igen [new file with mode: 0644]

diff --git a/bfd/cpu-dlx.c b/bfd/cpu-dlx.c
new file mode 100644 (file)
index 0000000..2023ff5
--- /dev/null
@@ -0,0 +1,39 @@
+/* BFD support for the DLX Microprocessor architecture.
+   Copyright 2002 Free Software Foundation, Inc.
+   Hacked by Kuang Hwa Lin <kuang@sbcglobal.net>
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+
+const bfd_arch_info_type bfd_dlx_arch =
+  {
+    32,        /* 32 bits in a word.  */
+    32,        /* 32 bits in an address.  */
+    8, /* 8 bits in a byte.  */
+    bfd_arch_dlx,
+    0, /* Only 1 machine.  */
+    "dlx",
+    "dlx",
+    4,
+    true, /* The one and only.  */
+    bfd_default_compatible,
+    bfd_default_scan ,
+    0,
+};
diff --git a/bfd/elf32-dlx.c b/bfd/elf32-dlx.c
new file mode 100644 (file)
index 0000000..91d75f3
--- /dev/null
@@ -0,0 +1,659 @@
+/* DLX specific support for 32-bit ELF
+   Copyright 2002 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/dlx.h"
+
+int    set_dlx_skip_hi16_flag PARAMS ((int));
+
+static boolean elf32_dlx_check_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *));
+static void elf32_dlx_info_to_howto
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+static void elf32_dlx_info_to_howto_rel
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *));
+static bfd_reloc_status_type elf32_dlx_relocate16
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static bfd_reloc_status_type elf32_dlx_relocate26
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static reloc_howto_type *elf32_dlx_reloc_type_lookup
+  PARAMS ((bfd *, bfd_reloc_code_real_type));
+static bfd_reloc_status_type _bfd_dlx_elf_hi16_reloc
+  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+static reloc_howto_type * dlx_rtype_to_howto
+  PARAMS ((unsigned int));
+
+
+#define USE_REL 1
+
+#define bfd_elf32_bfd_reloc_type_lookup elf32_dlx_reloc_type_lookup
+#define elf_info_to_howto               elf32_dlx_info_to_howto
+#define elf_info_to_howto_rel           elf32_dlx_info_to_howto_rel
+#define elf_backend_check_relocs        elf32_dlx_check_relocs
+
+static reloc_howto_type dlx_elf_howto_table[]=
+  {
+    /* No relocation.  */
+    HOWTO (R_DLX_NONE,            /* type */
+          0,                     /* rightshift */
+          0,                     /* size (0 = byte, 1 = short, 2 = long) */
+          0,                     /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          bfd_elf_generic_reloc, /* special_function */
+          "R_DLX_NONE",          /* name */
+          false,                 /* partial_inplace */
+          0,                     /* src_mask */
+          0,                     /* dst_mask */
+          false),                /* pcrel_offset */
+
+    /* 8 bit relocation.  */
+    HOWTO (R_DLX_RELOC_8,         /* type */
+          0,                     /* rightshift */
+          0,                     /* size (0 = byte, 1 = short, 2 = long) */
+          8,                     /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          bfd_elf_generic_reloc, /* special_function */
+          "R_DLX_RELOC_8",       /* name */
+          true,                  /* partial_inplace */
+          0xff,                  /* src_mask */
+          0xff,                  /* dst_mask */
+          false),                /* pcrel_offset */
+
+    /* 16 bit relocation.  */
+    HOWTO (R_DLX_RELOC_16,        /* type */
+          0,                     /* rightshift */
+          1,                     /* size (0 = byte, 1 = short, 2 = long) */
+          16,                    /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          bfd_elf_generic_reloc, /* special_function */
+          "R_DLX_RELOC_16",      /* name */
+          true,                  /* partial_inplace */
+          0xffff,                /* src_mask */
+          0xffff,                /* dst_mask */
+          false),                /* pcrel_offset */
+
+#if 0
+    /* 26 bit jump address.  */
+    HOWTO (R_DLX_RELOC_26,        /* type */
+          0,                     /* rightshift */
+          2,                     /* size (0 = byte, 1 = short, 2 = long) */
+          26,                    /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          /* This needs complex overflow detection, because the upper four
+             bits must match the PC + 4.  */
+          bfd_elf_generic_reloc, /* special_function */
+          "R_DLX_RELOC_26",      /* name */
+          true,                  /* partial_inplace */
+          0x3ffffff,             /* src_mask */
+          0x3ffffff,             /* dst_mask */
+          false),                /* pcrel_offset */
+#endif
+
+    /* 32 bit relocation.  */
+    HOWTO (R_DLX_RELOC_32,        /* type */
+          0,                     /* rightshift */
+          2,                     /* size (0 = byte, 1 = short, 2 = long) */
+          32,                    /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          bfd_elf_generic_reloc, /* special_function */
+          "R_DLX_RELOC_32",      /* name */
+          true,                  /* partial_inplace */
+          0xffffffff,            /* src_mask */
+          0xffffffff,            /* dst_mask */
+          false),                /* pcrel_offset */
+
+    /* GNU extension to record C++ vtable hierarchy */
+    HOWTO (R_DLX_GNU_VTINHERIT,   /* type */
+          0,                     /* rightshift */
+          2,                     /* size (0 = byte, 1 = short, 2 = long) */
+          0,                     /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          NULL,                  /* special_function */
+          "R_DLX_GNU_VTINHERIT", /* name */
+          false,                 /* partial_inplace */
+          0,                     /* src_mask */
+          0,                     /* dst_mask */
+          false),                /* pcrel_offset */
+
+    /* GNU extension to record C++ vtable member usage */
+    HOWTO (R_DLX_GNU_VTENTRY,     /* type */
+          0,                     /* rightshift */
+          2,                     /* size (0 = byte, 1 = short, 2 = long) */
+          0,                     /* bitsize */
+          false,                 /* pc_relative */
+          0,                     /* bitpos */
+          complain_overflow_dont,/* complain_on_overflow */
+          _bfd_elf_rel_vtable_reloc_fn,/* special_function */
+          "R_DLX_GNU_VTENTRY",   /* name */
+          false,                 /* partial_inplace */
+          0,                     /* src_mask */
+          0,                     /* dst_mask */
+          false)                 /* pcrel_offset */
+  };
+
+/* 16 bit offset for pc-relative branches.  */
+static reloc_howto_type elf_dlx_gnu_rel16_s2 =
+HOWTO (R_DLX_RELOC_16_PCREL,  /* type */
+       0,                     /* rightshift */
+       1,                     /* size (0 = byte, 1 = short, 2 = long) */
+       16,                    /* bitsize */
+       true,                  /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_signed, /* complain_on_overflow */
+       elf32_dlx_relocate16,  /* special_function */
+       "R_DLX_RELOC_16_PCREL",/* name */
+       true,                  /* partial_inplace */
+       0xffff,                /* src_mask */
+       0xffff,                /* dst_mask */
+       true);                 /* pcrel_offset */
+
+/* 26 bit offset for pc-relative branches.  */
+static reloc_howto_type elf_dlx_gnu_rel26_s2 =
+HOWTO (R_DLX_RELOC_26_PCREL,  /* type */
+       0,                     /* rightshift */
+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
+       26,                    /* bitsize */
+       true,                  /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_dont,/* complain_on_overflow */
+       elf32_dlx_relocate26,  /* special_function */
+       "R_DLX_RELOC_26_PCREL",/* name */
+       true,                  /* partial_inplace */
+       0xffff,                /* src_mask */
+       0xffff,                /* dst_mask */
+       true);                 /* pcrel_offset */
+
+/* High 16 bits of symbol value.  */
+static reloc_howto_type elf_dlx_reloc_16_hi =
+HOWTO (R_DLX_RELOC_16_HI,     /* type */
+       16,                    /* rightshift */
+       2,                     /* size (0 = byte, 1 = short, 2 = long) */
+       32,                    /* bitsize */
+       false,                 /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_dont, /* complain_on_overflow */
+       _bfd_dlx_elf_hi16_reloc,/* special_function */
+       "R_DLX_RELOC_16_HI",   /* name */
+       true,                  /* partial_inplace */
+       0xFFFF,                /* src_mask */
+       0xffff,                /* dst_mask */
+       false);                /* pcrel_offset */
+
+  /* Low 16 bits of symbol value.  */
+static reloc_howto_type elf_dlx_reloc_16_lo =
+HOWTO (R_DLX_RELOC_16_LO,     /* type */
+       0,                     /* rightshift */
+       1,                     /* size (0 = byte, 1 = short, 2 = long) */
+       16,                    /* bitsize */
+       false,                 /* pc_relative */
+       0,                     /* bitpos */
+       complain_overflow_dont,/* complain_on_overflow */
+       bfd_elf_generic_reloc, /* special_function */
+       "R_DLX_RELOC_16_LO",   /* name */
+       true,                  /* partial_inplace */
+       0xffff,                /* src_mask */
+       0xffff,                /* dst_mask */
+       false);                /* pcrel_offset */
+
+
+/* The gas default beheaver is not to preform the %hi modifier so that the
+   GNU assembler can have the lower 16 bits offset placed in the insn, BUT
+   we do like the gas to indicate it is %hi reloc type so when we in the link
+   loader phase we can have the corrected hi16 vale replace the buggous lo16
+   value that was placed there by gas.  */
+
+static int skip_dlx_elf_hi16_reloc = 0;
+
+int
+set_dlx_skip_hi16_flag (flag)
+     int flag;
+{
+  skip_dlx_elf_hi16_reloc = flag;
+  return flag;
+}
+
+static bfd_reloc_status_type
+_bfd_dlx_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
+                        input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message;
+{
+  bfd_reloc_status_type ret;
+  bfd_vma relocation;
+
+  /* If the skip flag is set then we simply do the generic relocating, this
+     is more of a hack for dlx gas/gld, so we do not need to do the %hi/%lo
+     fixup like mips gld did.   */
+#if 0
+  printf ("DEBUG: skip_dlx_elf_hi16_reloc = 0x%08x\n", skip_dlx_elf_hi16_reloc);
+#endif
+  if (skip_dlx_elf_hi16_reloc)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                          input_section, output_bfd, error_message);
+
+  /* If we're relocating, and this an external symbol, we don't want
+     to change anything.  */
+  if (output_bfd != (bfd *) NULL
+      && (symbol->flags & BSF_SECTION_SYM) == 0
+      && reloc_entry->addend == 0)
+    {
+      reloc_entry->address += input_section->output_offset;
+      return bfd_reloc_ok;
+    }
+
+  ret = bfd_reloc_ok;
+
+  if (bfd_is_und_section (symbol->section)
+      && output_bfd == (bfd *) NULL)
+    ret = bfd_reloc_undefined;
+
+#if 0
+  {
+    unsigned long vallo, val;
+
+    vallo = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
+    printf ("DEBUG: The relocation address = 0x%08x\n", reloc_entry->address);
+    printf ("DEBUG: The symbol        = 0x%08x\n", vallo);
+    printf ("DEBUG: The symbol name   = %s\n", bfd_asymbol_name (symbol));
+    printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
+    printf ("DEBUG: The vma           = 0x%08x\n", symbol->section->output_section->vma);
+    printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
+    printf ("DEBUG: The input_offset  = 0x%08x\n", input_section->output_offset);
+    printf ("DEBUG: The input_vma     = 0x%08x\n", input_section->vma);
+    printf ("DEBUG: The addend        = 0x%08x\n", reloc_entry->addend);
+  }
+#endif
+
+  relocation = (bfd_is_com_section (symbol->section)) ? 0 : symbol->value;
+  relocation += symbol->section->output_section->vma;
+  relocation += symbol->section->output_offset;
+  relocation += reloc_entry->addend;
+  relocation += bfd_get_16 (abfd, (bfd_byte *)data + reloc_entry->address);
+
+  if (reloc_entry->address > input_section->_cooked_size)
+    return bfd_reloc_outofrange;
+
+#if 0
+  printf ("DEBUG: The finial relocation value = 0x%08x\n", relocation);
+#endif
+
+  bfd_put_16 (abfd, (short)((relocation >> 16) & 0xFFFF),
+              (bfd_byte *)data + reloc_entry->address);
+
+  return ret;
+}
+
+/* ELF relocs are against symbols.  If we are producing relocateable
+   output, and the reloc is against an external symbol, and nothing
+   has given us any additional addend, the resulting reloc will also
+   be against the same symbol.  In such a case, we don't want to
+   change anything about the way the reloc is handled, since it will
+   all be done at final link time.  Rather than put special case code
+   into bfd_perform_relocation, all the reloc types use this howto
+   function.  It just short circuits the reloc if producing
+   relocateable output against an external symbol.  */
+
+static bfd_reloc_status_type
+elf32_dlx_relocate16  (abfd, reloc_entry, symbol, data,
+                       input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  unsigned long insn, vallo, allignment;
+  int           val;
+
+  /* HACK: I think this first condition is necessary when producing
+     relocatable output.  After the end of HACK, the code is identical
+     to bfd_elf_generic_reloc().  I would _guess_ the first change
+     belongs there rather than here.  martindo 1998-10-23.  */
+
+  if (skip_dlx_elf_hi16_reloc)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  /* Check undefined section and undefined symbols  */
+  if (bfd_is_und_section (symbol->section)
+      && output_bfd == (bfd *) NULL)
+    return bfd_reloc_undefined;
+
+  /* Can not support a long jump to sections other then .text   */
+  if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
+    {
+      fprintf (stderr,
+              "BFD Link Error: branch (PC rel16) to section (%s) not supported\n",
+              symbol->section->output_section->name);
+      return bfd_reloc_undefined;
+    }
+
+  insn  = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
+  allignment = 1 << (input_section->output_section->alignment_power - 1);
+  vallo = insn & 0x0000FFFF;
+
+  if (vallo & 0x8000)
+    vallo = ~(vallo | 0xFFFF0000) + 1;
+
+  /* vallo points to the vma of next instruction.  */
+  vallo += (((unsigned long)(input_section->output_section->vma +
+                           input_section->output_offset) +
+            allignment) & ~allignment);
+
+  /* val is the displacement (PC relative to next instruction).  */
+  val =  (symbol->section->output_offset +
+         symbol->section->output_section->vma +
+         symbol->value) - vallo;
+#if 0
+  printf ("DEBUG elf32_dlx_relocate: We are here\n");
+  printf ("DEBUG: The insn            = 0x%08x\n", insn);
+  printf ("DEBUG: The vallo           = 0x%08x\n", vallo);
+  printf ("DEBUG: The val             = 0x%08x\n", val);
+  printf ("DEBUG: The symbol name     = %s\n", bfd_asymbol_name (symbol));
+  printf ("DEBUG: The symbol->value   = 0x%08x\n", symbol->value);
+  printf ("DEBUG: The vma             = 0x%08x\n", symbol->section->output_section->vma);
+  printf ("DEBUG: The lma             = 0x%08x\n", symbol->section->output_section->lma);
+  printf ("DEBUG: The alignment_power = 0x%08x\n", symbol->section->output_section->alignment_power);
+  printf ("DEBUG: The output_offset   = 0x%08x\n", symbol->section->output_offset);
+  printf ("DEBUG: The addend          = 0x%08x\n", reloc_entry->addend);
+#endif
+
+  if (abs ((int) val) > 0x00007FFF)
+    return bfd_reloc_outofrange;
+
+  insn  = (insn & 0xFFFF0000) | (val & 0x0000FFFF);
+
+  bfd_put_32 (abfd, insn,
+              (bfd_byte *) data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+static bfd_reloc_status_type
+elf32_dlx_relocate26  (abfd, reloc_entry, symbol, data,
+                       input_section, output_bfd, error_message)
+     bfd *abfd;
+     arelent *reloc_entry;
+     asymbol *symbol;
+     PTR data;
+     asection *input_section;
+     bfd *output_bfd;
+     char **error_message ATTRIBUTE_UNUSED;
+{
+  unsigned long insn, vallo, allignment;
+  int           val;
+
+  /* HACK: I think this first condition is necessary when producing
+     relocatable output.  After the end of HACK, the code is identical
+     to bfd_elf_generic_reloc().  I would _guess_ the first change
+     belongs there rather than here.  martindo 1998-10-23.  */
+
+  if (skip_dlx_elf_hi16_reloc)
+    return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+                                 input_section, output_bfd, error_message);
+
+  /* Check undefined section and undefined symbols.  */
+  if (bfd_is_und_section (symbol->section)
+      && output_bfd == (bfd *) NULL)
+    return bfd_reloc_undefined;
+
+  /* Can not support a long jump to sections other then .text   */
+  if (strcmp (input_section->name, symbol->section->output_section->name) != 0)
+    {
+      fprintf (stderr,
+              "BFD Link Error: jump (PC rel26) to section (%s) not supported\n",
+              symbol->section->output_section->name);
+      return bfd_reloc_undefined;
+    }
+
+  insn  = bfd_get_32 (abfd, (bfd_byte *)data + reloc_entry->address);
+  allignment = 1 << (input_section->output_section->alignment_power - 1);
+  vallo = insn & 0x03FFFFFF;
+
+  if (vallo & 0x03000000)
+    vallo = ~(vallo | 0xFC000000) + 1;
+
+  /* vallo is the vma for the next instruction.  */
+  vallo += (((unsigned long) (input_section->output_section->vma +
+                             input_section->output_offset) +
+            allignment) & ~allignment);
+
+  /* val is the displacement (PC relative to next instruction).  */
+  val = (symbol->section->output_offset +
+        symbol->section->output_section->vma + symbol->value)
+    - vallo;
+#if 0
+  printf ("DEBUG elf32_dlx_relocate26: We are here\n");
+  printf ("DEBUG: The insn          = 0x%08x\n", insn);
+  printf ("DEBUG: The vallo         = 0x%08x\n", vallo);
+  printf ("DEBUG: The val           = 0x%08x\n", val);
+  printf ("DEBUG: The abs(val)      = 0x%08x\n", abs (val));
+  printf ("DEBUG: The symbol name   = %s\n", bfd_asymbol_name (symbol));
+  printf ("DEBUG: The symbol->value = 0x%08x\n", symbol->value);
+  printf ("DEBUG: The vma           = 0x%08x\n", symbol->section->output_section->vma);
+  printf ("DEBUG: The output_offset = 0x%08x\n", symbol->section->output_offset);
+  printf ("DEBUG: The input_vma     = 0x%08x\n", input_section->output_section->vma);
+  printf ("DEBUG: The input_offset  = 0x%08x\n", input_section->output_offset);
+  printf ("DEBUG: The input_name    = %s\n", input_section->name);
+  printf ("DEBUG: The addend        = 0x%08x\n", reloc_entry->addend);
+#endif
+
+  if (abs ((int) val) > 0x01FFFFFF)
+    return bfd_reloc_outofrange;
+
+  insn  = (insn & 0xFC000000) | (val & 0x03FFFFFF);
+  bfd_put_32 (abfd, insn,
+              (bfd_byte *) data + reloc_entry->address);
+
+  return bfd_reloc_ok;
+}
+
+/* A mapping from BFD reloc types to DLX ELF reloc types.
+   Stolen from elf32-mips.c.
+
+   More about this table - for dlx elf relocation we do not really
+   need this table, if we have a rtype defined in this table will
+   caused tc_gen_relocate confused and die on us, but if we remove
+   this table it will caused more problem, so for now simple soulation
+   is to remove those entries which may cause problem.  */
+struct elf_reloc_map
+{
+  bfd_reloc_code_real_type bfd_reloc_val;
+  enum elf_dlx_reloc_type elf_reloc_val;
+};
+
+static const struct elf_reloc_map dlx_reloc_map[] =
+  {
+    { BFD_RELOC_NONE,           R_DLX_NONE },
+    { BFD_RELOC_16,             R_DLX_RELOC_16 },
+#if 0
+    { BFD_RELOC_DLX_JMP26,      R_DLX_RELOC_26_PCREL },
+#endif
+    { BFD_RELOC_32,             R_DLX_RELOC_32 },
+    { BFD_RELOC_DLX_HI16_S,     R_DLX_RELOC_16_HI },
+    { BFD_RELOC_DLX_LO16,       R_DLX_RELOC_16_LO },
+    { BFD_RELOC_VTABLE_INHERIT,        R_DLX_GNU_VTINHERIT },
+    { BFD_RELOC_VTABLE_ENTRY,  R_DLX_GNU_VTENTRY }
+  };
+
+
+/* Look through the relocs for a section during the first phase.
+   Since we don't do .gots or .plts, we just need to consider the
+   virtual table relocs for gc.  */
+
+static boolean
+elf32_dlx_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+
+  if (info->relocateable)
+    return true;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  sym_hashes_end = sym_hashes + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+  if (!elf_bad_symtab (abfd))
+    sym_hashes_end -= symtab_hdr->sh_info;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      struct elf_link_hash_entry *h;
+      unsigned long r_symndx;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+      if (r_symndx < symtab_hdr->sh_info)
+        h = NULL;
+      else
+        h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+      switch (ELF32_R_TYPE (rel->r_info))
+        {
+        /* This relocation describes the C++ object vtable hierarchy.
+           Reconstruct it for later use during GC.  */
+        case R_DLX_GNU_VTINHERIT:
+          if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+            return false;
+          break;
+
+        /* This relocation describes which C++ vtable entries are actually
+           used.  Record for later use during GC.  */
+        case R_DLX_GNU_VTENTRY:
+          if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+            return false;
+          break;
+        }
+    }
+
+  return true;
+}
+
+/* Given a BFD reloc type, return a howto structure.  */
+
+static reloc_howto_type *
+elf32_dlx_reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     bfd_reloc_code_real_type code;
+{
+  unsigned int i;
+
+  for (i = 0; i < sizeof (dlx_reloc_map) / sizeof (struct elf_reloc_map); i++)
+    if (dlx_reloc_map[i].bfd_reloc_val == code)
+      return &dlx_elf_howto_table[(int) dlx_reloc_map[i].elf_reloc_val];
+
+  switch (code)
+    {
+    default:
+      bfd_set_error (bfd_error_bad_value);
+      return NULL;
+    case BFD_RELOC_16_PCREL_S2:
+      return &elf_dlx_gnu_rel16_s2;
+    case BFD_RELOC_DLX_JMP26:
+      return &elf_dlx_gnu_rel26_s2;
+    case BFD_RELOC_HI16_S:
+      return &elf_dlx_reloc_16_hi;
+    case BFD_RELOC_LO16:
+      return &elf_dlx_reloc_16_lo;
+    }
+}
+
+static reloc_howto_type *
+dlx_rtype_to_howto (r_type)
+     unsigned int r_type;
+{
+  switch (r_type)
+    {
+    case R_DLX_RELOC_16_PCREL:
+      return & elf_dlx_gnu_rel16_s2;
+      break;
+    case R_DLX_RELOC_26_PCREL:
+      return & elf_dlx_gnu_rel26_s2;
+      break;
+    case R_DLX_RELOC_16_HI:
+      return & elf_dlx_reloc_16_hi;
+      break;
+    case R_DLX_RELOC_16_LO:
+      return & elf_dlx_reloc_16_lo;
+      break;
+
+    default:
+      BFD_ASSERT (r_type < (unsigned int) R_DLX_max);
+      return & dlx_elf_howto_table[r_type];
+      break;
+    }
+}
+
+static void
+elf32_dlx_info_to_howto (abfd, cache_ptr, dst)
+     bfd * abfd ATTRIBUTE_UNUSED;
+     arelent * cache_ptr ATTRIBUTE_UNUSED;
+     Elf32_Internal_Rela * dst ATTRIBUTE_UNUSED;
+{
+  abort ();
+}
+
+static void
+elf32_dlx_info_to_howto_rel (abfd, cache_ptr, dst)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *cache_ptr;
+     Elf32_Internal_Rel *dst;
+{
+  unsigned int r_type;
+
+  r_type = ELF32_R_TYPE (dst->r_info);
+  cache_ptr->howto = dlx_rtype_to_howto (r_type);
+  return;
+}
+
+#define TARGET_BIG_SYM          bfd_elf32_dlx_big_vec
+#define TARGET_BIG_NAME         "elf32-dlx"
+#define ELF_ARCH                bfd_arch_dlx
+#define ELF_MACHINE_CODE        EM_DLX
+#define ELF_MAXPAGESIZE         1 /* FIXME: This number is wrong,  It should be the page size in bytes.  */
+
+#include "elf32-target.h"
diff --git a/bfd/elf32-i386qnx.c b/bfd/elf32-i386qnx.c
new file mode 100644 (file)
index 0000000..5f2e111
--- /dev/null
@@ -0,0 +1,111 @@
+/* Intel 80386/80486 QNX specific support for 32-bit ELF
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define ELF32_I386_C_INCLUDED
+#include "elf32-i386.c"
+
+  /* Returns the end address of the segment + 1.  */
+#define SEGMENT_END(segment, start)                     \
+  (start + (segment->p_memsz > segment->p_filesz        \
+   ? segment->p_memsz : segment->p_filesz))
+
+static boolean elf_i386qnx_copy_private_bfd_data_p
+  PARAMS ((bfd *, asection *, bfd *, asection *));
+static boolean elf_i386qnx_is_contained_by_filepos
+  PARAMS ((asection *, Elf_Internal_Phdr *));
+static void elf_i386qnx_set_nonloadable_filepos
+  PARAMS ((bfd *, Elf_Internal_Phdr *));
+
+static boolean
+elf_i386qnx_copy_private_bfd_data_p (ibfd, isec, obfd, osec)
+     bfd *ibfd;
+     asection *isec;
+     bfd *obfd;
+     asection *osec;
+{
+  /* We don't use these parameters, but another target might.  */
+  ibfd = ibfd;
+  obfd = obfd;
+  osec = osec;
+  return isec->next == NULL;
+}
+
+static boolean
+elf_i386qnx_is_contained_by_filepos (section, segment)
+     asection *section;
+     Elf_Internal_Phdr *segment;
+{
+  return ((bfd_vma) section->filepos >= segment->p_offset
+          && ((bfd_vma) section->filepos + section->_raw_size
+             <= SEGMENT_END (segment, segment->p_offset)));
+}
+
+static void
+elf_i386qnx_set_nonloadable_filepos (abfd, phdrs)
+     bfd *abfd;
+     Elf_Internal_Phdr *phdrs;
+{
+  struct elf_segment_map *m;
+  Elf_Internal_Phdr *p;
+  file_ptr off = 0;
+
+  for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+       m != NULL;
+       m = m->next, p++)
+    {
+      unsigned int i;
+      asection **secpp;
+
+      for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+        {
+          asection *sec;
+
+          sec = *secpp;
+
+          if (p->p_type == PT_LOAD)
+           off = sec->filepos;
+          else
+            {
+              if (i == 0)
+                {
+                  if (sec->filepos)
+                    p->p_offset = sec->filepos;
+                  else
+                    p->p_offset = off;
+                }
+              if (!sec->filepos)
+                {
+                  off += sec->_raw_size;
+                  p->p_filesz += sec->_raw_size;
+                }
+            }
+        }
+    }
+  return;
+}
+
+#undef  TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM                  bfd_elf32_i386qnx_vec
+
+#define elf_backend_set_nonloadable_filepos elf_i386qnx_set_nonloadable_filepos
+#define elf_backend_is_contained_by_filepos elf_i386qnx_is_contained_by_filepos
+#define elf_backend_copy_private_bfd_data_p elf_i386qnx_copy_private_bfd_data_p
+
+#include "elf32-target.h"
diff --git a/bfd/elf32-sh64-com.c b/bfd/elf32-sh64-com.c
new file mode 100644 (file)
index 0000000..ae2cab4
--- /dev/null
@@ -0,0 +1,264 @@
+/* Hitachi SH64-specific support for 32-bit ELF
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. 
+      
+   This file is part of BFD, the Binary File Descriptor library.
+  
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define SH64_ELF
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/sh.h"
+#include "../opcodes/sh64-opc.h"
+
+static boolean sh64_address_in_cranges
+  PARAMS ((asection *cranges, bfd_vma, sh64_elf_crange *));
+
+/* Ordering functions of a crange, for the qsort and bsearch calls and for
+   different endianness.  */
+
+int
+_bfd_sh64_crange_qsort_cmpb (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  bfd_vma a1 = bfd_getb32 (p1);
+  bfd_vma a2 = bfd_getb32 (p2);
+
+  /* Preserve order if there's ambiguous contents.  */
+  if (a1 == a2)
+    return (char *) p1 - (char *) p2;
+
+  return a1 - a2;
+}
+
+int
+_bfd_sh64_crange_qsort_cmpl (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  bfd_vma a1 = (bfd_vma) bfd_getl32 (p1);
+  bfd_vma a2 = (bfd_vma) bfd_getl32 (p2);
+
+  /* Preserve order if there's ambiguous contents.  */
+  if (a1 == a2)
+    return (char *) p1 - (char *) p2;
+
+  return a1 - a2;
+}
+
+int
+_bfd_sh64_crange_bsearch_cmpb (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  bfd_vma a1 = *(bfd_vma *) p1;
+  bfd_vma a2 = (bfd_vma) bfd_getb32 (p2);
+  bfd_size_type size
+    = (bfd_size_type) bfd_getb32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2);
+
+  if (a1 >= a2 + size)
+    return 1;
+  if (a1 < a2)
+    return -1;
+  return 0;
+}
+
+int
+_bfd_sh64_crange_bsearch_cmpl (p1, p2)
+     const PTR p1;
+     const PTR p2;
+{
+  bfd_vma a1 = *(bfd_vma *) p1;
+  bfd_vma a2 = (bfd_vma) bfd_getl32 (p2);
+  bfd_size_type size
+    = (bfd_size_type) bfd_getl32 (SH64_CRANGE_CR_SIZE_OFFSET + (char *) p2);
+
+  if (a1 >= a2 + size)
+    return 1;
+  if (a1 < a2)
+    return -1;
+  return 0;
+}
+
+/* Check whether a specific address is specified within a .cranges
+   section.  Return FALSE if not found, and TRUE if found, and the region
+   filled into RANGEP if non-NULL.  */
+
+static boolean
+sh64_address_in_cranges (cranges, addr, rangep)
+     asection *cranges;
+     bfd_vma addr;
+     sh64_elf_crange *rangep;
+{
+  bfd_byte *cranges_contents;
+  bfd_byte *found_rangep;
+  bfd_size_type cranges_size = bfd_section_size (cranges->owner, cranges);
+
+  /* If the size is not a multiple of the cranges entry size, then
+     something is badly wrong.  */
+  if ((cranges_size % SH64_CRANGE_SIZE) != 0)
+    return false;
+
+  /* If this section has relocations, then we can't do anything sane.  */
+  if (bfd_get_section_flags (cranges->owner, cranges) & SEC_RELOC)
+    return false;
+
+  /* Has some kind soul (or previous call) left processed, sorted contents
+     for us?  */
+  if ((bfd_get_section_flags (cranges->owner, cranges) & SEC_IN_MEMORY)
+      && elf_section_data (cranges)->this_hdr.sh_type == SHT_SH5_CR_SORTED)
+    cranges_contents = cranges->contents;
+  else
+    {
+      cranges_contents
+       = bfd_malloc (cranges->_cooked_size == 0
+                     ? cranges->_cooked_size : cranges->_raw_size);
+      if (cranges_contents == NULL)
+       return false;
+
+      if (! bfd_get_section_contents (cranges->owner, cranges,
+                                     cranges_contents, (file_ptr) 0,
+                                     cranges_size))
+       goto error_return;
+
+      /* Is it sorted?  */
+      if (elf_section_data (cranges)->this_hdr.sh_type
+         != SHT_SH5_CR_SORTED)
+       /* Nope.  Lets sort it.  */
+       qsort (cranges_contents, cranges_size / SH64_CRANGE_SIZE,
+              SH64_CRANGE_SIZE,
+              bfd_big_endian (cranges->owner)
+              ? _bfd_sh64_crange_qsort_cmpb : _bfd_sh64_crange_qsort_cmpl);
+
+      /* Let's keep it around.  */
+      cranges->contents = cranges_contents;
+      bfd_set_section_flags (cranges->owner, cranges,
+                            bfd_get_section_flags (cranges->owner, cranges)
+                            | SEC_IN_MEMORY);
+
+      /* It's sorted now.  */
+      elf_section_data (cranges)->this_hdr.sh_type = SHT_SH5_CR_SORTED;
+    }
+
+  /* Try and find a matching range.  */
+  found_rangep
+    = bsearch (&addr, cranges_contents, cranges_size / SH64_CRANGE_SIZE,
+              SH64_CRANGE_SIZE,
+              bfd_big_endian (cranges->owner)
+              ? _bfd_sh64_crange_bsearch_cmpb
+              : _bfd_sh64_crange_bsearch_cmpl);
+
+  /* Fill in a few return values if we found a matching range.  */
+  if (found_rangep)
+    {
+      enum sh64_elf_cr_type cr_type
+       = bfd_get_16 (cranges->owner,
+                     SH64_CRANGE_CR_TYPE_OFFSET + found_rangep);
+      bfd_vma cr_addr
+       = bfd_get_32 (cranges->owner,
+                     SH64_CRANGE_CR_ADDR_OFFSET
+                     + (char *) found_rangep);
+      bfd_size_type cr_size
+       = bfd_get_32 (cranges->owner,
+                     SH64_CRANGE_CR_SIZE_OFFSET
+                     + (char *) found_rangep);
+
+      rangep->cr_addr = cr_addr;
+      rangep->cr_size = cr_size;
+      rangep->cr_type = cr_type;
+
+      return true;
+    }
+
+  /* There is a .cranges section, but it does not have a descriptor
+     matching this address.  */
+  return false;
+
+error_return:
+  free (cranges_contents);
+  return false;
+}
+
+/* Determine what ADDR points to in SEC, and fill in a range descriptor in
+   *RANGEP if it's non-NULL.  */
+
+enum sh64_elf_cr_type
+sh64_get_contents_type (sec, addr, rangep)
+     asection *sec;
+     bfd_vma addr;
+     sh64_elf_crange *rangep;
+{
+  asection *cranges;
+
+  /* Fill in the range with the boundaries of the section as a default.  */
+  if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour
+      && elf_elfheader (sec->owner)->e_type == ET_EXEC)
+    {
+      rangep->cr_addr = bfd_get_section_vma (sec->owner, sec);
+      rangep->cr_size = bfd_section_size (sec->owner, sec);
+      rangep->cr_type = CRT_NONE;
+    }
+  else
+    return false;
+
+  /* If none of the pertinent bits are set, then it's a SHcompact (or at
+     least not SHmedia).  */
+  if ((elf_section_data (sec)->this_hdr.sh_flags
+       & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == 0)
+    {
+      enum sh64_elf_cr_type cr_type
+       = ((bfd_get_section_flags (sec->owner, sec) & SEC_CODE) != 0
+          ? CRT_SH5_ISA16 : CRT_DATA);
+      rangep->cr_type = cr_type;
+      return cr_type;
+    }
+
+  /* If only the SHF_SH5_ISA32 bit is set, then we have SHmedia.  */
+  if ((elf_section_data (sec)->this_hdr.sh_flags
+       & (SHF_SH5_ISA32 | SHF_SH5_ISA32_MIXED)) == SHF_SH5_ISA32)
+    {
+      rangep->cr_type = CRT_SH5_ISA32;
+      return CRT_SH5_ISA32;
+    }
+
+  /* Otherwise, we have to look up the .cranges section.  */
+  cranges = bfd_get_section_by_name (sec->owner, SH64_CRANGES_SECTION_NAME);
+
+  if (cranges == NULL)
+    /* A mixed section but there's no .cranges section.  This is probably
+       bad input; it does not comply to specs.  */
+    return CRT_NONE;
+
+  /* If this call fails, we will still have CRT_NONE in rangep->cr_type
+     and that will be suitable to return.  */
+  sh64_address_in_cranges (cranges, addr, rangep);
+
+  return rangep->cr_type;
+}
+
+/* This is a simpler exported interface for the benefit of gdb et al.  */
+
+boolean
+sh64_address_is_shmedia (sec, addr)
+     asection *sec;
+     bfd_vma addr;
+{
+  sh64_elf_crange dummy;
+  return sh64_get_contents_type (sec, addr, &dummy) == CRT_SH5_ISA32;
+}
diff --git a/bfd/elf32-sh64-nbsd.c b/bfd/elf32-sh64-nbsd.c
new file mode 100644 (file)
index 0000000..2d3e3d9
--- /dev/null
@@ -0,0 +1,29 @@
+/* SuperH SH64 specific support for 32-bit NetBSD
+   Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define TARGET_BIG_SYM         bfd_elf32_sh64nbsd_vec
+#define TARGET_BIG_NAME                "elf32-sh64-nbsd"
+#define TARGET_LITTLE_SYM      bfd_elf32_sh64lnbsd_vec
+#define TARGET_LITTLE_NAME     "elf32-sh64l-nbsd"
+#define ELF_ARCH               bfd_arch_sh
+#define ELF_MACHINE_CODE       EM_SH
+#define ELF_MAXPAGESIZE                0x10000
+#define elf_symbol_leading_char        0
+
+#include "elf32-sh64.c"
diff --git a/bfd/elf32-vax.c b/bfd/elf32-vax.c
new file mode 100644 (file)
index 0000000..8901188
--- /dev/null
@@ -0,0 +1,2214 @@
+/* VAX series support for 32-bit ELF
+   Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Free Software Foundation, Inc.
+   Contributed by Matt Thomas <matt@3am-software.com>.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "bfdlink.h"
+#include "libbfd.h"
+#include "elf-bfd.h"
+#include "elf/vax.h"
+
+static reloc_howto_type *reloc_type_lookup
+  PARAMS ((bfd *, bfd_reloc_code_real_type));
+static void rtype_to_howto
+  PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
+static struct bfd_hash_entry *elf_vax_link_hash_newfunc
+  PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
+static struct bfd_link_hash_table *elf_vax_link_hash_table_create
+  PARAMS ((bfd *));
+static boolean elf_vax_check_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
+static asection *elf_vax_gc_mark_hook
+  PARAMS ((bfd *, struct bfd_link_info *, Elf_Internal_Rela *,
+          struct elf_link_hash_entry *, Elf_Internal_Sym *));
+static boolean elf_vax_gc_sweep_hook
+  PARAMS ((bfd *, struct bfd_link_info *, asection *,
+          const Elf_Internal_Rela *));
+static boolean elf_vax_adjust_dynamic_symbol
+  PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean elf_vax_size_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+static boolean elf_vax_relocate_section
+  PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
+          Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static boolean elf_vax_finish_dynamic_symbol
+  PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *,
+          Elf_Internal_Sym *));
+static boolean elf_vax_finish_dynamic_sections
+  PARAMS ((bfd *, struct bfd_link_info *));
+
+static boolean elf32_vax_set_private_flags
+  PARAMS ((bfd *, flagword));
+static boolean elf32_vax_merge_private_bfd_data
+  PARAMS ((bfd *, bfd *));
+static boolean elf32_vax_print_private_bfd_data
+  PARAMS ((bfd *, PTR));
+
+static reloc_howto_type howto_table[] = {
+  HOWTO (R_VAX_NONE,           /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_NONE",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x00000000,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_32,             /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_32",            /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_16,             /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_16",            /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_8,              /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_8",             /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x000000ff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_PC32,           /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_PC32",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  HOWTO (R_VAX_PC16,           /* type */
+        0,                     /* rightshift */
+        1,                     /* size (0 = byte, 1 = short, 2 = long) */
+        16,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_PC16",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x0000ffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  HOWTO (R_VAX_PC8,            /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        8,                     /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_signed, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_PC8",           /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0x000000ff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  HOWTO (R_VAX_GOT32,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_GOT32",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+
+  HOWTO (R_VAX_PLT32,          /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        true,                  /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_bitfield, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_PLT32",         /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        true),                 /* pcrel_offset */
+
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+  EMPTY_HOWTO (-1),
+
+  HOWTO (R_VAX_COPY,           /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_COPY",          /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_GLOB_DAT,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_GLOB_DAT",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_JMP_SLOT,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_JMP_SLOT",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  HOWTO (R_VAX_RELATIVE,       /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        32,                    /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_VAX_RELATIVE",      /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0xffffffff,            /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable hierarchy */
+  HOWTO (R_VAX_GNU_VTINHERIT,  /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        NULL,                  /* special_function */
+        "R_VAX_GNU_VTINHERIT", /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false),                /* pcrel_offset */
+
+  /* GNU extension to record C++ vtable member usage */
+  HOWTO (R_VAX_GNU_VTENTRY,    /* type */
+        0,                     /* rightshift */
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */
+        0,                     /* bitsize */
+        false,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont, /* complain_on_overflow */
+        _bfd_elf_rel_vtable_reloc_fn, /* special_function */
+        "R_VAX_GNU_VTENTRY",   /* name */
+        false,                 /* partial_inplace */
+        0,                     /* src_mask */
+        0,                     /* dst_mask */
+        false),                /* pcrel_offset */
+};
+
+static void
+rtype_to_howto (abfd, cache_ptr, dst)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     arelent *cache_ptr;
+     Elf_Internal_Rela *dst;
+{
+  BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_VAX_max);
+  cache_ptr->howto = &howto_table[ELF32_R_TYPE(dst->r_info)];
+}
+
+#define elf_info_to_howto rtype_to_howto
+
+static const struct
+{
+  bfd_reloc_code_real_type bfd_val;
+  int elf_val;
+} reloc_map[] = {
+  { BFD_RELOC_NONE, R_VAX_NONE },
+  { BFD_RELOC_32, R_VAX_32 },
+  { BFD_RELOC_16, R_VAX_16 },
+  { BFD_RELOC_8, R_VAX_8 },
+  { BFD_RELOC_32_PCREL, R_VAX_PC32 },
+  { BFD_RELOC_16_PCREL, R_VAX_PC16 },
+  { BFD_RELOC_8_PCREL, R_VAX_PC8 },
+  { BFD_RELOC_32_GOT_PCREL, R_VAX_GOT32 },
+  { BFD_RELOC_32_PLT_PCREL, R_VAX_PLT32 },
+  { BFD_RELOC_NONE, R_VAX_COPY },
+  { BFD_RELOC_VAX_GLOB_DAT, R_VAX_GLOB_DAT },
+  { BFD_RELOC_VAX_JMP_SLOT, R_VAX_JMP_SLOT },
+  { BFD_RELOC_VAX_RELATIVE, R_VAX_RELATIVE },
+  { BFD_RELOC_CTOR, R_VAX_32 },
+  { BFD_RELOC_VTABLE_INHERIT, R_VAX_GNU_VTINHERIT },
+  { BFD_RELOC_VTABLE_ENTRY, R_VAX_GNU_VTENTRY },
+};
+
+static reloc_howto_type *
+reloc_type_lookup (abfd, code)
+     bfd *abfd ATTRIBUTE_UNUSED;
+     bfd_reloc_code_real_type code;
+{
+  unsigned int i;
+  for (i = 0; i < sizeof (reloc_map) / sizeof (reloc_map[0]); i++)
+    {
+      if (reloc_map[i].bfd_val == code)
+       return &howto_table[reloc_map[i].elf_val];
+    }
+  return 0;
+}
+
+#define bfd_elf32_bfd_reloc_type_lookup reloc_type_lookup
+#define ELF_ARCH bfd_arch_vax
+/* end code generated by elf.el */
+
+#define USE_RELA
+\f
+/* Functions for the VAX ELF linker.  */
+
+/* The name of the dynamic interpreter.  This is put in the .interp
+   section.  */
+
+#define ELF_DYNAMIC_INTERPRETER "/usr/libexec/ld.elf_so"
+
+/* The size in bytes of an entry in the procedure linkage table.  */
+
+#define PLT_ENTRY_SIZE 12
+
+/* The first entry in a procedure linkage table looks like this.  See
+   the SVR4 ABI VAX supplement to see how this works.  */
+
+static const bfd_byte elf_vax_plt0_entry[PLT_ENTRY_SIZE] =
+{
+  0xdd, 0xef,          /* pushl l^ */
+  0, 0, 0, 0,          /* offset to .plt.got + 4 */
+  0x17, 0xff,          /* jmp @L^(pc) */
+  0, 0, 0, 0,          /* offset to .plt.got + 8 */
+};
+
+/* Subsequent entries in a procedure linkage table look like this.  */
+
+static const bfd_byte elf_vax_plt_entry[PLT_ENTRY_SIZE] =
+{
+  0x40, 0x00,          /* .word ^M<r6> */
+  0x16,        0xef,           /* jsb L^(pc) */
+  0, 0, 0, 0,          /* replaced with offset to start of .plt  */
+  0, 0, 0, 0,          /* index into .rela.plt */
+};
+
+/* The VAX linker needs to keep track of the number of relocs that it
+   decides to copy in check_relocs for each symbol.  This is so that it
+   can discard PC relative relocs if it doesn't need them when linking
+   with -Bsymbolic.  We store the information in a field extending the
+   regular ELF linker hash table.  */
+
+/* This structure keeps track of the number of PC relative relocs we have
+   copied for a given symbol.  */
+
+struct elf_vax_pcrel_relocs_copied
+{
+  /* Next section.  */
+  struct elf_vax_pcrel_relocs_copied *next;
+  /* A section in dynobj.  */
+  asection *section;
+  /* Number of relocs copied in this section.  */
+  bfd_size_type count;
+};
+
+/* VAX ELF linker hash entry.  */
+
+struct elf_vax_link_hash_entry
+{
+  struct elf_link_hash_entry root;
+
+  /* Number of PC relative relocs copied for this symbol.  */
+  struct elf_vax_pcrel_relocs_copied *pcrel_relocs_copied;
+
+  bfd_vma got_addend;
+};
+
+/* VAX ELF linker hash table.  */
+
+struct elf_vax_link_hash_table
+{
+  struct elf_link_hash_table root;
+};
+
+/* Declare this now that the above structures are defined.  */
+
+static boolean elf_vax_discard_copies
+  PARAMS ((struct elf_vax_link_hash_entry *, PTR));
+
+/* Traverse an VAX ELF linker hash table.  */
+
+#define elf_vax_link_hash_traverse(table, func, info)                  \
+  (elf_link_hash_traverse                                              \
+   (&(table)->root,                                                    \
+    (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \
+    (info)))
+
+/* Get the VAX ELF linker hash table from a link_info structure.  */
+
+#define elf_vax_hash_table(p) \
+  ((struct elf_vax_link_hash_table *) (p)->hash)
+
+/* Create an entry in an VAX ELF linker hash table.  */
+
+static struct bfd_hash_entry *
+elf_vax_link_hash_newfunc (entry, table, string)
+     struct bfd_hash_entry *entry;
+     struct bfd_hash_table *table;
+     const char *string;
+{
+  struct elf_vax_link_hash_entry *ret =
+    (struct elf_vax_link_hash_entry *) entry;
+
+  /* Allocate the structure if it has not already been allocated by a
+     subclass.  */
+  if (ret == (struct elf_vax_link_hash_entry *) NULL)
+    ret = ((struct elf_vax_link_hash_entry *)
+          bfd_hash_allocate (table,
+                             sizeof (struct elf_vax_link_hash_entry)));
+  if (ret == (struct elf_vax_link_hash_entry *) NULL)
+    return (struct bfd_hash_entry *) ret;
+
+  /* Call the allocation method of the superclass.  */
+  ret = ((struct elf_vax_link_hash_entry *)
+        _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
+                                    table, string));
+  if (ret != (struct elf_vax_link_hash_entry *) NULL)
+    {
+      ret->pcrel_relocs_copied = NULL;
+    }
+
+  return (struct bfd_hash_entry *) ret;
+}
+
+/* Create an VAX ELF linker hash table.  */
+
+static struct bfd_link_hash_table *
+elf_vax_link_hash_table_create (abfd)
+     bfd *abfd;
+{
+  struct elf_vax_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct elf_vax_link_hash_table);
+
+  ret = (struct elf_vax_link_hash_table *) bfd_malloc (amt);
+  if (ret == (struct elf_vax_link_hash_table *) NULL)
+    return NULL;
+
+  if (! _bfd_elf_link_hash_table_init (&ret->root, abfd,
+                                      elf_vax_link_hash_newfunc))
+    {
+      free (ret);
+      return NULL;
+    }
+
+  return &ret->root.root;
+}
+
+/* Keep vax-specific flags in the ELF header */
+static boolean
+elf32_vax_set_private_flags (abfd, flags)
+     bfd *abfd;
+     flagword flags;
+{
+  elf_elfheader (abfd)->e_flags = flags;
+  elf_flags_init (abfd) = true;
+  return true;
+}
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+static boolean
+elf32_vax_merge_private_bfd_data (ibfd, obfd)
+     bfd *ibfd;
+     bfd *obfd;
+{
+  flagword out_flags;
+  flagword in_flags;
+
+  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return true;
+
+  in_flags  = elf_elfheader (ibfd)->e_flags;
+  out_flags = elf_elfheader (obfd)->e_flags;
+
+  if (!elf_flags_init (obfd))
+    {
+      elf_flags_init (obfd) = true;
+      elf_elfheader (obfd)->e_flags = in_flags;
+    }
+
+  return true;
+}
+
+/* Display the flags field */
+static boolean
+elf32_vax_print_private_bfd_data (abfd, ptr)
+     bfd *abfd;
+     PTR ptr;
+{
+  FILE *file = (FILE *) ptr;
+
+  BFD_ASSERT (abfd != NULL && ptr != NULL);
+
+  /* Print normal ELF private data.  */
+  _bfd_elf_print_private_bfd_data (abfd, ptr);
+
+  /* Ignore init flag - it may not be set, despite the flags field containing valid data.  */
+
+  /* xgettext:c-format */
+  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
+
+  if (elf_elfheader (abfd)->e_flags & EF_NONPIC)
+    fprintf (file, _(" [nonpic]"));
+
+  if (elf_elfheader (abfd)->e_flags & EF_DFLOAT)
+    fprintf (file, _(" [d-float]"));
+
+  if (elf_elfheader (abfd)->e_flags & EF_GFLOAT)
+    fprintf (file, _(" [g-float]"));
+
+  fputc ('\n', file);
+
+  return true;
+}
+/* Look through the relocs for a section during the first phase, and
+   allocate space in the global offset table or procedure linkage
+   table.  */
+
+static boolean
+elf_vax_check_relocs (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel;
+  const Elf_Internal_Rela *rel_end;
+  asection *sgot;
+  asection *srelgot;
+  asection *sreloc;
+
+  if (info->relocateable)
+    return true;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  sgot = NULL;
+  srelgot = NULL;
+  sreloc = NULL;
+
+  rel_end = relocs + sec->reloc_count;
+  for (rel = relocs; rel < rel_end; rel++)
+    {
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      if (r_symndx < symtab_hdr->sh_info)
+       h = NULL;
+      else
+       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       case R_VAX_GOT32:
+         if (h != NULL
+             && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+           break;
+
+         /* This symbol requires a global offset table entry.  */
+
+         if (dynobj == NULL)
+           {
+             /* Create the .got section.  */
+             elf_hash_table (info)->dynobj = dynobj = abfd;
+             if (!_bfd_elf_create_got_section (dynobj, info))
+               return false;
+           }
+
+         if (sgot == NULL)
+           {
+             sgot = bfd_get_section_by_name (dynobj, ".got");
+             BFD_ASSERT (sgot != NULL);
+           }
+
+         if (srelgot == NULL
+             && (h != NULL || info->shared))
+           {
+             srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+             if (srelgot == NULL)
+               {
+                 srelgot = bfd_make_section (dynobj, ".rela.got");
+                 if (srelgot == NULL
+                     || !bfd_set_section_flags (dynobj, srelgot,
+                                                (SEC_ALLOC
+                                                 | SEC_LOAD
+                                                 | SEC_HAS_CONTENTS
+                                                 | SEC_IN_MEMORY
+                                                 | SEC_LINKER_CREATED
+                                                 | SEC_READONLY))
+                     || !bfd_set_section_alignment (dynobj, srelgot, 2))
+                   return false;
+               }
+           }
+
+         if (h != NULL)
+           {
+             struct elf_vax_link_hash_entry *eh;
+
+             eh = (struct elf_vax_link_hash_entry *) h;
+             if (h->got.refcount == -1)
+               {
+                 h->got.refcount = 1;
+                 eh->got_addend = rel->r_addend;
+
+                 /* Make sure this symbol is output as a dynamic symbol.  */
+                 if (h->dynindx == -1)
+                   {
+                     if (!bfd_elf32_link_record_dynamic_symbol (info, h))
+                       return false;
+                   }
+
+                 /* Allocate space in the .got section.  */
+                 sgot->_raw_size += 4;
+                 /* Allocate relocation space.  */
+                 srelgot->_raw_size += sizeof (Elf32_External_Rela);
+               }
+             else
+               {
+                 h->got.refcount++;
+                 if (eh->got_addend != (bfd_vma) rel->r_addend)
+                   (*_bfd_error_handler)
+                     (_("%s: warning: GOT addend of %ld to `%s' does not match previous GOT addend of %ld"),
+                             bfd_get_filename (abfd), rel->r_addend,
+                             h->root.root.string,
+                             eh->got_addend);
+
+               }
+           }
+         break;
+
+       case R_VAX_PLT32:
+         /* This symbol requires a procedure linkage table entry.  We
+            actually build the entry in adjust_dynamic_symbol,
+             because this might be a case of linking PIC code which is
+             never referenced by a dynamic object, in which case we
+             don't need to generate a procedure linkage table entry
+             after all.  */
+
+         /* If this is a local symbol, we resolve it directly without
+            creating a procedure linkage table entry.  */
+         if (h == NULL)
+           continue;
+
+         h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+         if (h->plt.refcount == -1)
+           h->plt.refcount = 1;
+         else
+           h->plt.refcount++;
+         break;
+
+       case R_VAX_PC8:
+       case R_VAX_PC16:
+       case R_VAX_PC32:
+         /* If we are creating a shared library and this is not a local
+            symbol, we need to copy the reloc into the shared library.
+            However when linking with -Bsymbolic and this is a global
+            symbol which is defined in an object we are including in the
+            link (i.e., DEF_REGULAR is set), then we can resolve the
+            reloc directly.  At this point we have not seen all the input
+            files, so it is possible that DEF_REGULAR is not set now but
+            will be set later (it is never cleared).  We account for that
+            possibility below by storing information in the
+            pcrel_relocs_copied field of the hash table entry.  */
+         if (!(info->shared
+               && (sec->flags & SEC_ALLOC) != 0
+               && h != NULL
+               && (!info->symbolic
+                   || (h->elf_link_hash_flags
+                       & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+           {
+             if (h != NULL)
+               {
+                 /* Make sure a plt entry is created for this symbol if
+                    it turns out to be a function defined by a dynamic
+                    object.  */
+                 if (h->plt.refcount == -1)
+                   h->plt.refcount = 1;
+                 else
+                   h->plt.refcount++;
+               }
+             break;
+           }
+         /* Fall through.  */
+       case R_VAX_8:
+       case R_VAX_16:
+       case R_VAX_32:
+         if (h != NULL)
+           {
+             /* Make sure a plt entry is created for this symbol if it
+                turns out to be a function defined by a dynamic object.  */
+             if (h->plt.refcount == -1)
+               h->plt.refcount = 1;
+             else
+               h->plt.refcount++;
+           }
+
+         /* If we are creating a shared library, we need to copy the
+            reloc into the shared library.  */
+         if (info->shared
+             && (sec->flags & SEC_ALLOC) != 0)
+           {
+             /* When creating a shared object, we must copy these
+                reloc types into the output file.  We create a reloc
+                section in dynobj and make room for this reloc.  */
+             if (sreloc == NULL)
+               {
+                 const char *name;
+
+                 name = (bfd_elf_string_from_elf_section
+                         (abfd,
+                          elf_elfheader (abfd)->e_shstrndx,
+                          elf_section_data (sec)->rel_hdr.sh_name));
+                 if (name == NULL)
+                   return false;
+
+                 BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+                             && strcmp (bfd_get_section_name (abfd, sec),
+                                        name + 5) == 0);
+
+                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 if (sreloc == NULL)
+                   {
+                     sreloc = bfd_make_section (dynobj, name);
+                     if (sreloc == NULL
+                         || !bfd_set_section_flags (dynobj, sreloc,
+                                                    (SEC_ALLOC
+                                                     | SEC_LOAD
+                                                     | SEC_HAS_CONTENTS
+                                                     | SEC_IN_MEMORY
+                                                     | SEC_LINKER_CREATED
+                                                     | SEC_READONLY))
+                         || !bfd_set_section_alignment (dynobj, sreloc, 2))
+                       return false;
+                   }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
+               }
+
+             sreloc->_raw_size += sizeof (Elf32_External_Rela);
+
+             /* If we are linking with -Bsymbolic, we count the number of
+                PC relative relocations we have entered for this symbol,
+                so that we can discard them again if the symbol is later
+                defined by a regular object.  Note that this function is
+                only called if we are using an vaxelf linker hash table,
+                which means that h is really a pointer to an
+                elf_vax_link_hash_entry.  */
+             if ((ELF32_R_TYPE (rel->r_info) == R_VAX_PC8
+                  || ELF32_R_TYPE (rel->r_info) == R_VAX_PC16
+                  || ELF32_R_TYPE (rel->r_info) == R_VAX_PC32)
+                 && info->symbolic)
+               {
+                 struct elf_vax_link_hash_entry *eh;
+                 struct elf_vax_pcrel_relocs_copied *p;
+
+                 eh = (struct elf_vax_link_hash_entry *) h;
+
+                 for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next)
+                   if (p->section == sreloc)
+                     break;
+
+                 if (p == NULL)
+                   {
+                     p = ((struct elf_vax_pcrel_relocs_copied *)
+                          bfd_alloc (dynobj, (bfd_size_type) sizeof *p));
+                     if (p == NULL)
+                       return false;
+                     p->next = eh->pcrel_relocs_copied;
+                     eh->pcrel_relocs_copied = p;
+                     p->section = sreloc;
+                     p->count = 0;
+                   }
+
+                 ++p->count;
+               }
+           }
+
+         break;
+
+         /* This relocation describes the C++ object vtable hierarchy.
+            Reconstruct it for later use during GC.  */
+       case R_VAX_GNU_VTINHERIT:
+         if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+           return false;
+         break;
+
+         /* This relocation describes which C++ vtable entries are actually
+            used.  Record for later use during GC.  */
+       case R_VAX_GNU_VTENTRY:
+         if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+           return false;
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  return true;
+}
+
+/* Return the section that should be marked against GC for a given
+   relocation.  */
+
+static asection *
+elf_vax_gc_mark_hook (abfd, info, rel, h, sym)
+     bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     Elf_Internal_Rela *rel;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  if (h != NULL)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       case R_VAX_GNU_VTINHERIT:
+       case R_VAX_GNU_VTENTRY:
+         break;
+
+       default:
+         switch (h->root.type)
+           {
+           default:
+             break;
+
+           case bfd_link_hash_defined:
+           case bfd_link_hash_defweak:
+             return h->root.u.def.section;
+
+           case bfd_link_hash_common:
+             return h->root.u.c.p->section;
+           }
+       }
+    }
+  else
+    {
+      return bfd_section_from_elf_index (abfd, sym->st_shndx);
+    }
+
+  return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed.  */
+
+static boolean
+elf_vax_gc_sweep_hook (abfd, info, sec, relocs)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection *sec;
+     const Elf_Internal_Rela *relocs;
+{
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_signed_vma *local_got_refcounts;
+  const Elf_Internal_Rela *rel, *relend;
+  unsigned long r_symndx;
+  struct elf_link_hash_entry *h;
+  bfd *dynobj;
+  asection *sgot;
+  asection *srelgot;
+
+  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (abfd);
+  local_got_refcounts = elf_local_got_refcounts (abfd);
+
+  dynobj = elf_hash_table (info)->dynobj;
+  if (dynobj == NULL)
+    return true;
+
+  sgot = bfd_get_section_by_name (dynobj, ".got");
+  srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+
+  relend = relocs + sec->reloc_count;
+  for (rel = relocs; rel < relend; rel++)
+    {
+      switch (ELF32_R_TYPE (rel->r_info))
+       {
+       case R_VAX_GOT32:
+         r_symndx = ELF32_R_SYM (rel->r_info);
+         if (r_symndx >= symtab_hdr->sh_info)
+           {
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             if (h->got.refcount > 0)
+               {
+                 --h->got.refcount;
+                 if (h->got.refcount == 0)
+                   {
+                     /* We don't need the .got entry any more.  */
+                     sgot->_raw_size -= 4;
+                     srelgot->_raw_size -= sizeof (Elf32_External_Rela);
+                   }
+               }
+           }
+         else if (local_got_refcounts != NULL)
+           {
+             if (local_got_refcounts[r_symndx] > 0)
+               {
+                 --local_got_refcounts[r_symndx];
+                 if (local_got_refcounts[r_symndx] == 0)
+                   {
+                     /* We don't need the .got entry any more.  */
+                     sgot->_raw_size -= 4;
+                     if (info->shared)
+                       srelgot->_raw_size -= sizeof (Elf32_External_Rela);
+                   }
+               }
+           }
+         break;
+
+       case R_VAX_PLT32:
+       case R_VAX_PC8:
+       case R_VAX_PC16:
+       case R_VAX_PC32:
+       case R_VAX_8:
+       case R_VAX_16:
+       case R_VAX_32:
+         r_symndx = ELF32_R_SYM (rel->r_info);
+         if (r_symndx >= symtab_hdr->sh_info)
+           {
+             h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+             if (h->plt.refcount > 0)
+               --h->plt.refcount;
+           }
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  return true;
+}
+
+/* Adjust a symbol defined by a dynamic object and referenced by a
+   regular object.  The current definition is in some section of the
+   dynamic object, but we're not including those sections.  We have to
+   change the definition to something the rest of the link can
+   understand.  */
+
+static boolean
+elf_vax_adjust_dynamic_symbol (info, h)
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+{
+  bfd *dynobj;
+  asection *s;
+  unsigned int power_of_two;
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  /* Make sure we know what is going on here.  */
+  BFD_ASSERT (dynobj != NULL
+             && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT)
+                 || h->weakdef != NULL
+                 || ((h->elf_link_hash_flags
+                      & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+                     && (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_REF_REGULAR) != 0
+                     && (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0)));
+
+  /* If this is a function, put it in the procedure linkage table.  We
+     will fill in the contents of the procedure linkage table later,
+     when we know the address of the .got section.  */
+  if (h->type == STT_FUNC
+      || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+    {
+      if (! info->shared
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0
+         /* We must always create the plt entry if it was referenced
+            by a PLTxxO relocation.  In this case we already recorded
+            it as a dynamic symbol.  */
+         && h->dynindx == -1)
+       {
+         /* This case can occur if we saw a PLTxx reloc in an input
+            file, but the symbol was never referred to by a dynamic
+            object.  In such a case, we don't actually need to build
+            a procedure linkage table, and we can just do a PCxx
+            reloc instead.  */
+         BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0);
+         h->plt.offset = (bfd_vma) -1;
+         return true;
+       }
+
+      /* GC may have rendered this entry unused.  */
+      if (h->plt.refcount <= 0)
+       {
+         h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
+         h->plt.offset = (bfd_vma) -1;
+         return true;
+       }
+
+      /* Make sure this symbol is output as a dynamic symbol.  */
+      if (h->dynindx == -1)
+       {
+         if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+           return false;
+       }
+
+      s = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (s != NULL);
+
+      /* If this is the first .plt entry, make room for the special
+        first entry.  */
+      if (s->_raw_size == 0)
+       {
+         s->_raw_size += PLT_ENTRY_SIZE;
+       }
+
+      /* If this symbol is not defined in a regular file, and we are
+        not generating a shared library, then set the symbol to this
+        location in the .plt.  This is required to make function
+        pointers compare as equal between the normal executable and
+        the shared library.  */
+      if (!info->shared
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+       {
+         h->root.u.def.section = s;
+         h->root.u.def.value = s->_raw_size;
+       }
+
+      h->plt.offset = s->_raw_size;
+
+      /* Make room for this entry.  */
+      s->_raw_size += PLT_ENTRY_SIZE;
+
+      /* We also need to make an entry in the .got.plt section, which
+        will be placed in the .got section by the linker script.  */
+
+      s = bfd_get_section_by_name (dynobj, ".got.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += 4;
+
+      /* We also need to make an entry in the .rela.plt section.  */
+
+      s = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (s != NULL);
+      s->_raw_size += sizeof (Elf32_External_Rela);
+
+      return true;
+    }
+
+  /* Reinitialize the plt offset now that it is not used as a reference
+     count any more.  */
+  h->plt.offset = (bfd_vma) -1;
+
+  /* If this is a weak symbol, and there is a real definition, the
+     processor independent code will have arranged for us to see the
+     real definition first, and we can just use the same value.  */
+  if (h->weakdef != NULL)
+    {
+      BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined
+                 || h->weakdef->root.type == bfd_link_hash_defweak);
+      h->root.u.def.section = h->weakdef->root.u.def.section;
+      h->root.u.def.value = h->weakdef->root.u.def.value;
+      return true;
+    }
+
+  /* This is a reference to a symbol defined by a dynamic object which
+     is not a function.  */
+
+  /* If we are creating a shared library, we must presume that the
+     only references to the symbol are via the global offset table.
+     For such cases we need not do anything here; the relocations will
+     be handled correctly by relocate_section.  */
+  if (info->shared)
+    return true;
+
+  /* We must allocate the symbol in our .dynbss section, which will
+     become part of the .bss section of the executable.  There will be
+     an entry for this symbol in the .dynsym section.  The dynamic
+     object will contain position independent code, so all references
+     from the dynamic object to this symbol will go through the global
+     offset table.  The dynamic linker will use the .dynsym entry to
+     determine the address it must put in the global offset table, so
+     both the dynamic object and the regular object will refer to the
+     same memory location for the variable.  */
+
+  s = bfd_get_section_by_name (dynobj, ".dynbss");
+  BFD_ASSERT (s != NULL);
+
+  /* We must generate a R_VAX_COPY reloc to tell the dynamic linker to
+     copy the initial value out of the dynamic object and into the
+     runtime process image.  We need to remember the offset into the
+     .rela.bss section we are going to use.  */
+  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
+    {
+      asection *srel;
+
+      srel = bfd_get_section_by_name (dynobj, ".rela.bss");
+      BFD_ASSERT (srel != NULL);
+      srel->_raw_size += sizeof (Elf32_External_Rela);
+      h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY;
+    }
+
+  /* We need to figure out the alignment required for this symbol.  I
+     have no idea how ELF linkers handle this.  */
+  power_of_two = bfd_log2 (h->size);
+  if (power_of_two > 3)
+    power_of_two = 3;
+
+  /* Apply the required alignment.  */
+  s->_raw_size = BFD_ALIGN (s->_raw_size,
+                           (bfd_size_type) (1 << power_of_two));
+  if (power_of_two > bfd_get_section_alignment (dynobj, s))
+    {
+      if (!bfd_set_section_alignment (dynobj, s, power_of_two))
+       return false;
+    }
+
+  /* Define the symbol as being at this point in the section.  */
+  h->root.u.def.section = s;
+  h->root.u.def.value = s->_raw_size;
+
+  /* Increment the section size to make room for the symbol.  */
+  s->_raw_size += h->size;
+
+  return true;
+}
+
+/* Set the sizes of the dynamic sections.  */
+
+static boolean
+elf_vax_size_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  bfd *dynobj;
+  asection *s;
+  boolean plt;
+  boolean relocs;
+  boolean reltext;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  BFD_ASSERT (dynobj != NULL);
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Set the contents of the .interp section to the interpreter.  */
+      if (!info->shared)
+       {
+         s = bfd_get_section_by_name (dynobj, ".interp");
+         BFD_ASSERT (s != NULL);
+         s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER;
+         s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
+       }
+    }
+  else
+    {
+      /* We may have created entries in the .rela.got and .got sections.
+        However, if we are not creating the dynamic sections, we will
+        not actually use these entries.  Reset the size of .rela.got
+        and .got, which will cause it to get stripped from the output
+        file below.  */
+      s = bfd_get_section_by_name (dynobj, ".rela.got");
+      if (s != NULL)
+       s->_raw_size = 0;
+      s = bfd_get_section_by_name (dynobj, ".got.plt");
+      if (s != NULL)
+       s->_raw_size = 0;
+      s = bfd_get_section_by_name (dynobj, ".got");
+      if (s != NULL)
+       s->_raw_size = 0;
+    }
+
+  /* If this is a -Bsymbolic shared link, then we need to discard all PC
+     relative relocs against symbols defined in a regular object.  We
+     allocated space for them in the check_relocs routine, but we will not
+     fill them in in the relocate_section routine.  */
+  if (info->shared && info->symbolic)
+    elf_vax_link_hash_traverse (elf_vax_hash_table (info),
+                                elf_vax_discard_copies,
+                                (PTR) NULL);
+
+  /* The check_relocs and adjust_dynamic_symbol entry points have
+     determined the sizes of the various dynamic sections.  Allocate
+     memory for them.  */
+  plt = false;
+  relocs = false;
+  reltext = false;
+  for (s = dynobj->sections; s != NULL; s = s->next)
+    {
+      const char *name;
+      boolean strip;
+
+      if ((s->flags & SEC_LINKER_CREATED) == 0)
+       continue;
+
+      /* It's OK to base decisions on the section name, because none
+        of the dynobj section names depend upon the input files.  */
+      name = bfd_get_section_name (dynobj, s);
+
+      strip = false;
+
+      if (strcmp (name, ".plt") == 0)
+       {
+         if (s->_raw_size == 0)
+           {
+             /* Strip this section if we don't need it; see the
+                 comment below.  */
+             strip = true;
+           }
+         else
+           {
+             /* Remember whether there is a PLT.  */
+             plt = true;
+           }
+       }
+      else if (strncmp (name, ".rela", 5) == 0)
+       {
+         if (s->_raw_size == 0)
+           {
+             /* If we don't need this section, strip it from the
+                output file.  This is mostly to handle .rela.bss and
+                .rela.plt.  We must create both sections in
+                create_dynamic_sections, because they must be created
+                before the linker maps input sections to output
+                sections.  The linker does that before
+                adjust_dynamic_symbol is called, and it is that
+                function which decides whether anything needs to go
+                into these sections.  */
+             strip = true;
+           }
+         else
+           {
+             asection *target;
+
+             /* Remember whether there are any reloc sections other
+                 than .rela.plt.  */
+             if (strcmp (name, ".rela.plt") != 0)
+               {
+                 const char *outname;
+
+                 relocs = true;
+
+                 /* If this relocation section applies to a read only
+                    section, then we probably need a DT_TEXTREL
+                    entry.  .rela.plt is actually associated with
+                    .got.plt, which is never readonly.  */
+                 outname = bfd_get_section_name (output_bfd,
+                                                 s->output_section);
+                 target = bfd_get_section_by_name (output_bfd, outname + 5);
+                 if (target != NULL
+                     && (target->flags & SEC_READONLY) != 0
+                     && (target->flags & SEC_ALLOC) != 0)
+                   reltext = true;
+               }
+
+             /* We use the reloc_count field as a counter if we need
+                to copy relocs into the output file.  */
+             s->reloc_count = 0;
+           }
+       }
+      else if (strncmp (name, ".got", 4) != 0)
+       {
+         /* It's not one of our sections, so don't allocate space.  */
+         continue;
+       }
+
+      if (strip)
+       {
+         _bfd_strip_section_from_output (info, s);
+         continue;
+       }
+
+      /* Allocate memory for the section contents.  */
+      s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
+      if (s->contents == NULL && s->_raw_size != 0)
+       return false;
+    }
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      /* Add some entries to the .dynamic section.  We fill in the
+        values later, in elf_vax_finish_dynamic_sections, but we
+        must add the entries now so that we get the correct size for
+        the .dynamic section.  The DT_DEBUG entry is filled in by the
+        dynamic linker and used by the debugger.  */
+#define add_dynamic_entry(TAG, VAL) \
+  bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL))
+
+      if (!info->shared)
+       {
+         if (!add_dynamic_entry (DT_DEBUG, 0))
+           return false;
+       }
+
+      if (plt)
+       {
+         if (!add_dynamic_entry (DT_PLTGOT, 0)
+             || !add_dynamic_entry (DT_PLTRELSZ, 0)
+             || !add_dynamic_entry (DT_PLTREL, DT_RELA)
+             || !add_dynamic_entry (DT_JMPREL, 0))
+           return false;
+       }
+
+      if (relocs)
+       {
+         if (!add_dynamic_entry (DT_RELA, 0)
+             || !add_dynamic_entry (DT_RELASZ, 0)
+             || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela)))
+           return false;
+       }
+
+      if (reltext || (info->flags & DF_TEXTREL) != 0)
+       {
+         if (!add_dynamic_entry (DT_TEXTREL, 0))
+           return false;
+       }
+    }
+#undef add_dynamic_entry
+
+  return true;
+}
+
+/* This function is called via elf_vax_link_hash_traverse if we are
+   creating a shared object with -Bsymbolic.  It discards the space
+   allocated to copy PC relative relocs against symbols which are defined
+   in regular objects.  We allocated space for them in the check_relocs
+   routine, but we won't fill them in in the relocate_section routine.  */
+
+/*ARGSUSED*/
+static boolean
+elf_vax_discard_copies (h, ignore)
+     struct elf_vax_link_hash_entry *h;
+     PTR ignore ATTRIBUTE_UNUSED;
+{
+  struct elf_vax_pcrel_relocs_copied *s;
+
+  if (h->root.root.type == bfd_link_hash_warning)
+    h = (struct elf_vax_link_hash_entry *) h->root.root.u.i.link;
+
+  /* We only discard relocs for symbols defined in a regular object.  */
+  if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+    return true;
+
+  for (s = h->pcrel_relocs_copied; s != NULL; s = s->next)
+    s->section->_raw_size -= s->count * sizeof (Elf32_External_Rela);
+
+  return true;
+}
+
+/* Relocate an VAX ELF section.  */
+
+static boolean
+elf_vax_relocate_section (output_bfd, info, input_bfd, input_section,
+                          contents, relocs, local_syms, local_sections)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     bfd *input_bfd;
+     asection *input_section;
+     bfd_byte *contents;
+     Elf_Internal_Rela *relocs;
+     Elf_Internal_Sym *local_syms;
+     asection **local_sections;
+{
+  bfd *dynobj;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  bfd_vma *local_got_offsets;
+  bfd_vma plt_index;
+  bfd_vma got_offset;
+  asection *sgot;
+  asection *splt;
+  asection *sgotplt;
+  asection *sreloc;
+  Elf_Internal_Rela *rel;
+  Elf_Internal_Rela *relend;
+
+  dynobj = elf_hash_table (info)->dynobj;
+  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
+  sym_hashes = elf_sym_hashes (input_bfd);
+  local_got_offsets = elf_local_got_offsets (input_bfd);
+
+  sgot = NULL;
+  splt = NULL;
+  sgotplt = NULL;
+  sreloc = NULL;
+
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      int r_type;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      struct elf_link_hash_entry *h;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      bfd_vma relocation;
+      bfd_reloc_status_type r;
+
+      r_type = ELF32_R_TYPE (rel->r_info);
+      if (r_type < 0 || r_type >= (int) R_VAX_max)
+       {
+         bfd_set_error (bfd_error_bad_value);
+         return false;
+       }
+      howto = howto_table + r_type;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
+
+      if (info->relocateable)
+       {
+         /* This is a relocateable link.  We don't have to change
+            anything, unless the reloc is against a section symbol,
+            in which case we have to adjust according to where the
+            section symbol winds up in the output section.  */
+         if (r_symndx < symtab_hdr->sh_info)
+           {
+             sym = local_syms + r_symndx;
+             if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+               {
+                 sec = local_sections[r_symndx];
+                 rel->r_addend += sec->output_offset + sym->st_value;
+               }
+           }
+
+         continue;
+       }
+
+      /* This is a final link.  */
+      h = NULL;
+      sym = NULL;
+      sec = NULL;
+      if (r_symndx < symtab_hdr->sh_info)
+       {
+         sym = local_syms + r_symndx;
+         sec = local_sections[r_symndx];
+         relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+       }
+      else
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+         if (h->root.type == bfd_link_hash_defined
+             || h->root.type == bfd_link_hash_defweak)
+           {
+             sec = h->root.u.def.section;
+             if ((r_type == R_VAX_PLT32
+                  && h->plt.offset != (bfd_vma) -1
+                  && elf_hash_table (info)->dynamic_sections_created)
+                 || (r_type == R_VAX_GOT32
+                     && strcmp (h->root.root.string,
+                                "_GLOBAL_OFFSET_TABLE_") != 0
+                     && elf_hash_table (info)->dynamic_sections_created
+                     && (! info->shared
+                         || (! info->symbolic && h->dynindx != -1)
+                         || (h->elf_link_hash_flags
+                             & ELF_LINK_HASH_DEF_REGULAR) == 0))
+                 || (info->shared
+                     && ((! info->symbolic && h->dynindx != -1)
+                         || (h->elf_link_hash_flags
+                             & ELF_LINK_HASH_DEF_REGULAR) == 0)
+                     && ((input_section->flags & SEC_ALLOC) != 0
+                         /* DWARF will emit R_VAX_32 relocations in its
+                            sections against symbols defined externally
+                            in shared libraries.  We can't do anything
+                            with them here.  */
+
+                         || ((input_section->flags & SEC_DEBUGGING) != 0
+                             && (h->elf_link_hash_flags
+                                 & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
+                     && (r_type == R_VAX_8
+                         || r_type == R_VAX_16
+                         || r_type == R_VAX_32
+                         || r_type == R_VAX_PC8
+                         || r_type == R_VAX_PC16
+                         || r_type == R_VAX_PC32)))
+               {
+                 /* In these cases, we don't need the relocation
+                    value.  We check specially because in some
+                    obscure cases sec->output_section will be NULL.  */
+                 relocation = 0;
+               }
+             else
+               relocation = (h->root.u.def.value
+                             + sec->output_section->vma
+                             + sec->output_offset);
+           }
+         else if (h->root.type == bfd_link_hash_undefweak)
+           relocation = 0;
+         else if (info->shared
+                  && (!info->symbolic || info->allow_shlib_undefined)
+                  && !info->no_undefined
+                  && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
+           relocation = 0;
+         else
+           {
+             if (!(info->callbacks->undefined_symbol
+                   (info, h->root.root.string, input_bfd,
+                    input_section, rel->r_offset,
+                    (!info->shared || info->no_undefined
+                     || ELF_ST_VISIBILITY (h->other)))))
+               return false;
+             relocation = 0;
+           }
+       }
+
+      switch (r_type)
+       {
+       case R_VAX_GOT32:
+         /* Relocation is to the address of the entry for this symbol
+            in the global offset table.  */
+         if (h != NULL
+             && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+           break;
+
+         /* Relocation is the offset of the entry for this symbol in
+            the global offset table.  */
+
+         {
+           bfd_vma off;
+
+           if (!elf_hash_table (info)->dynamic_sections_created
+               || (h == NULL)
+               || (info->shared
+                && info->symbolic
+                && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+             {
+               /* This is actually a static link, or it is a -Bsymbolic link
+                  and the symbol is defined locally or there is no symbol.
+                  Change the GOT32 entry to a PC32 entry.  */
+               break;
+             }
+
+           if (sgot == NULL)
+             {
+               sgot = bfd_get_section_by_name (dynobj, ".got");
+               BFD_ASSERT (sgot != NULL);
+             }
+
+           BFD_ASSERT (h != NULL);
+           off = h->got.offset;
+           BFD_ASSERT (off != (bfd_vma) -1);
+
+           if (info->shared
+               && h->dynindx == -1
+               && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+             {
+               /* The symbol was forced to be local
+                  because of a version file..  We must initialize
+                  this entry in the global offset table.  Since
+                  the offset must always be a multiple of 4, we
+                  use the least significant bit to record whether
+                  we have initialized it already.
+
+                  When doing a dynamic link, we create a .rela.got
+                  relocation entry to initialize the value.  This
+                  is done in the finish_dynamic_symbol routine.  */
+               if ((off & 1) != 0)
+                 off &= ~1;
+               else
+                 {
+                   bfd_put_32 (output_bfd, relocation + rel->r_addend,
+                               sgot->contents + off);
+                   h->got.offset |= 1;
+                 }
+             } else {
+               bfd_put_32 (output_bfd, rel->r_addend, sgot->contents + off);
+             }
+
+           relocation = sgot->output_offset + off;
+           /* Neither GOT relocation uses the addend.  */
+           rel->r_addend = 0;
+
+           if (r_type == R_VAX_GOT32)
+             {
+               /* Change the reference to be indirect */
+               contents[rel->r_offset - 1] |= 0x10;
+               relocation += sgot->output_section->vma;
+             }
+         }
+         break;
+
+       case R_VAX_PLT32:
+         /* Relocation is to the entry for this symbol in the
+            procedure linkage table.  */
+
+         /* Resolve a PLTxx reloc against a local symbol directly,
+            without using the procedure linkage table.  */
+         if (h == NULL)
+           break;
+
+         if (h->plt.offset == (bfd_vma) -1
+             || !elf_hash_table (info)->dynamic_sections_created)
+           {
+             /* We didn't make a PLT entry for this symbol.  This
+                happens when statically linking PIC code, or when
+                using -Bsymbolic.  */
+             break;
+           }
+
+         if (splt == NULL)
+           {
+             splt = bfd_get_section_by_name (dynobj, ".plt");
+             BFD_ASSERT (splt != NULL);
+           }
+
+         if (sgotplt == NULL)
+           {
+             sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
+             BFD_ASSERT (splt != NULL);
+           }
+
+         plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+
+         /* Get the offset into the .got table of the entry that
+            corresponds to this function.  Each .got entry is 4 bytes.
+            The first two are reserved.  */
+         got_offset = (plt_index + 3) * 4;
+
+         /* We want the relocate to point into the .got.plt instead
+            of the plt itself.  */
+         relocation = (sgotplt->output_section->vma
+                       + sgotplt->output_offset
+                       + got_offset);
+         contents[rel->r_offset-1] |= 0x10; /* make indirect */
+         if (rel->r_addend == 2)
+           {
+             h->plt.offset |= 1;
+           }
+         else if (rel->r_addend != 0)
+           (*_bfd_error_handler)
+             (_("%s: warning: PLT addend of %d to `%s' from %s section ignored"),
+                     bfd_get_filename (input_bfd), rel->r_addend,
+                     h->root.root.string,
+                     bfd_get_section_name (input_bfd, input_section));
+         rel->r_addend = 0;
+
+         break;
+
+       case R_VAX_PC8:
+       case R_VAX_PC16:
+       case R_VAX_PC32:
+         if (h == NULL)
+           break;
+         /* Fall through.  */
+       case R_VAX_8:
+       case R_VAX_16:
+       case R_VAX_32:
+         if (info->shared
+             && r_symndx != 0
+             && (input_section->flags & SEC_ALLOC) != 0
+             && ((r_type != R_VAX_PC8
+                  && r_type != R_VAX_PC16
+                  && r_type != R_VAX_PC32)
+                 || (!info->symbolic
+                     || (h->elf_link_hash_flags
+                         & ELF_LINK_HASH_DEF_REGULAR) == 0)))
+           {
+             Elf_Internal_Rela outrel;
+             boolean skip, relocate;
+
+             /* When generating a shared object, these relocations
+                are copied into the output file to be resolved at run
+                time.  */
+
+             if (sreloc == NULL)
+               {
+                 const char *name;
+
+                 name = (bfd_elf_string_from_elf_section
+                         (input_bfd,
+                          elf_elfheader (input_bfd)->e_shstrndx,
+                          elf_section_data (input_section)->rel_hdr.sh_name));
+                 if (name == NULL)
+                   return false;
+
+                 BFD_ASSERT (strncmp (name, ".rela", 5) == 0
+                             && strcmp (bfd_get_section_name (input_bfd,
+                                                              input_section),
+                                        name + 5) == 0);
+
+                 sreloc = bfd_get_section_by_name (dynobj, name);
+                 BFD_ASSERT (sreloc != NULL);
+               }
+
+             skip = false;
+             relocate = false;
+
+             outrel.r_offset =
+               _bfd_elf_section_offset (output_bfd, info, input_section,
+                                        rel->r_offset);
+             if (outrel.r_offset == (bfd_vma) -1)
+               skip = true;
+             if (outrel.r_offset == (bfd_vma) -2)
+               skip = true, relocate = true;
+             outrel.r_offset += (input_section->output_section->vma
+                                 + input_section->output_offset);
+
+             if (skip)
+                 memset (&outrel, 0, sizeof outrel);
+             /* h->dynindx may be -1 if the symbol was marked to
+                 become local.  */
+             else if (h != NULL
+                      && ((! info->symbolic && h->dynindx != -1)
+                          || (h->elf_link_hash_flags
+                              & ELF_LINK_HASH_DEF_REGULAR) == 0))
+               {
+                 BFD_ASSERT (h->dynindx != -1);
+                 outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
+                 outrel.r_addend = relocation + rel->r_addend;
+               }
+             else
+               {
+                 if (r_type == R_VAX_32)
+                   {
+                     relocate = true;
+                     outrel.r_info = ELF32_R_INFO (0, R_VAX_RELATIVE);
+                     BFD_ASSERT (bfd_get_signed_32 (input_bfd,
+                                                    &contents[rel->r_offset]) == 0);
+                     outrel.r_addend = relocation + rel->r_addend;
+                   }
+                 else
+                   {
+                     long indx;
+
+                     if (h == NULL)
+                       sec = local_sections[r_symndx];
+                     else
+                       {
+                         BFD_ASSERT (h->root.type == bfd_link_hash_defined
+                                     || (h->root.type
+                                         == bfd_link_hash_defweak));
+                         sec = h->root.u.def.section;
+                       }
+                     if (sec != NULL && bfd_is_abs_section (sec))
+                       indx = 0;
+                     else if (sec == NULL || sec->owner == NULL)
+                       {
+                         bfd_set_error (bfd_error_bad_value);
+                         return false;
+                       }
+                     else
+                       {
+                         asection *osec;
+
+                         osec = sec->output_section;
+                         indx = elf_section_data (osec)->dynindx;
+                         BFD_ASSERT (indx > 0);
+                       }
+
+                     outrel.r_info = ELF32_R_INFO (indx, r_type);
+                     outrel.r_addend = relocation + rel->r_addend;
+                   }
+               }
+
+             if (!strcmp (bfd_get_section_name (input_bfd, input_section),
+                          ".text") != 0 ||
+                 (info->shared
+                  && ELF32_R_TYPE(outrel.r_info) != R_VAX_32
+                  && ELF32_R_TYPE(outrel.r_info) != R_VAX_RELATIVE
+                  && ELF32_R_TYPE(outrel.r_info) != R_VAX_COPY
+                  && ELF32_R_TYPE(outrel.r_info) != R_VAX_JMP_SLOT
+                  && ELF32_R_TYPE(outrel.r_info) != R_VAX_GLOB_DAT))
+               {
+                 if (h != NULL)
+                   (*_bfd_error_handler)
+                     (_("%s: warning: %s relocation against symbol `%s' from %s section"),
+                     bfd_get_filename (input_bfd), howto->name,
+                     h->root.root.string,
+                     bfd_get_section_name (input_bfd, input_section));
+                 else
+                   (*_bfd_error_handler)
+                     (_("%s: warning: %s relocation to 0x%x from %s section"),
+                     bfd_get_filename (input_bfd), howto->name,
+                     outrel.r_addend,
+                     bfd_get_section_name (input_bfd, input_section));
+               }
+             bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+                                        (((Elf32_External_Rela *)
+                                          sreloc->contents)
+                                         + sreloc->reloc_count));
+             ++sreloc->reloc_count;
+
+             /* This reloc will be computed at runtime, so there's no
+                 need to do anything now, except for R_VAX_32
+                 relocations that have been turned into
+                 R_VAX_RELATIVE.  */
+             if (!relocate)
+               continue;
+           }
+
+         break;
+
+       case R_VAX_GNU_VTINHERIT:
+       case R_VAX_GNU_VTENTRY:
+         /* These are no-ops in the end.  */
+         continue;
+
+       default:
+         break;
+       }
+
+      /* VAX PCREL relocations are from the end of relocation, not the start */
+      if (howto->pc_relative && howto->pcrel_offset)
+       {
+         relocation -= bfd_get_reloc_size(howto);
+       }
+
+      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+                                   contents, rel->r_offset,
+                                   relocation, rel->r_addend);
+
+      if (r != bfd_reloc_ok)
+       {
+         switch (r)
+           {
+           default:
+           case bfd_reloc_outofrange:
+             abort ();
+           case bfd_reloc_overflow:
+             {
+               const char *name;
+
+               if (h != NULL)
+                 name = h->root.root.string;
+               else
+                 {
+                   name = bfd_elf_string_from_elf_section (input_bfd,
+                                                           symtab_hdr->sh_link,
+                                                           sym->st_name);
+                   if (name == NULL)
+                     return false;
+                   if (*name == '\0')
+                     name = bfd_section_name (input_bfd, sec);
+                 }
+               if (!(info->callbacks->reloc_overflow
+                     (info, name, howto->name, (bfd_vma) 0,
+                      input_bfd, input_section, rel->r_offset)))
+                 return false;
+             }
+             break;
+           }
+       }
+    }
+
+  return true;
+}
+
+/* Finish up dynamic symbol handling.  We set the contents of various
+   dynamic sections here.  */
+
+static boolean
+elf_vax_finish_dynamic_symbol (output_bfd, info, h, sym)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+     struct elf_link_hash_entry *h;
+     Elf_Internal_Sym *sym;
+{
+  bfd *dynobj;
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  if (h->plt.offset != (bfd_vma) -1)
+    {
+      asection *splt;
+      asection *sgot;
+      asection *srela;
+      bfd_vma plt_index;
+      bfd_vma got_offset;
+      bfd_vma addend;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the procedure linkage table.  Set
+        it up.  */
+
+      BFD_ASSERT (h->dynindx != -1);
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+      srela = bfd_get_section_by_name (dynobj, ".rela.plt");
+      BFD_ASSERT (splt != NULL && sgot != NULL && srela != NULL);
+
+      addend = 2 * (h->plt.offset & 1);
+      h->plt.offset &= ~1;
+
+      /* Get the index in the procedure linkage table which
+        corresponds to this symbol.  This is the index of this symbol
+        in all the symbols for which we are making plt entries.  The
+        first entry in the procedure linkage table is reserved.  */
+      plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+
+      /* Get the offset into the .got table of the entry that
+        corresponds to this function.  Each .got entry is 4 bytes.
+        The first two are reserved.  */
+      got_offset = (plt_index + 3) * 4;
+
+      /* Fill in the entry in the procedure linkage table.  */
+      memcpy (splt->contents + h->plt.offset, elf_vax_plt_entry,
+                 PLT_ENTRY_SIZE);
+
+      /* The offset is relative to the first extension word.  */
+      bfd_put_32 (output_bfd,
+                 -(h->plt.offset + 8),
+                 splt->contents + h->plt.offset + 4);
+
+      bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rela),
+                 splt->contents + h->plt.offset + 8);
+
+      /* Fill in the entry in the global offset table.  */
+      bfd_put_32 (output_bfd,
+                 (splt->output_section->vma
+                  + splt->output_offset
+                  + h->plt.offset) + addend,
+                 sgot->contents + got_offset);
+
+      /* Fill in the entry in the .rela.plt section.  */
+      rela.r_offset = (sgot->output_section->vma
+                      + sgot->output_offset
+                      + got_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_VAX_JMP_SLOT);
+      rela.r_addend = addend;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+                                ((Elf32_External_Rela *) srela->contents
+                                 + plt_index));
+
+      if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
+       {
+         /* Mark the symbol as undefined, rather than as defined in
+            the .plt section.  Leave the value alone.  */
+         sym->st_shndx = SHN_UNDEF;
+       }
+    }
+
+  if (h->got.offset != (bfd_vma) -1)
+    {
+      asection *sgot;
+      asection *srela;
+      Elf_Internal_Rela rela;
+
+      /* This symbol has an entry in the global offset table.  Set it
+        up.  */
+
+      sgot = bfd_get_section_by_name (dynobj, ".got");
+      srela = bfd_get_section_by_name (dynobj, ".rela.got");
+      BFD_ASSERT (sgot != NULL && srela != NULL);
+
+      rela.r_offset = (sgot->output_section->vma
+                      + sgot->output_offset
+                      + (h->got.offset &~ 1));
+
+      /* If the symbol was forced to be local because of a version file
+        locally we just want to emit a RELATIVE reloc.  The entry in
+        the global offset table will already have been initialized in
+        the relocate_section function.  */
+      if (info->shared
+         && h->dynindx == -1
+         && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))
+       {
+         rela.r_info = ELF32_R_INFO (0, R_VAX_RELATIVE);
+       }
+      else
+       {
+         rela.r_info = ELF32_R_INFO (h->dynindx, R_VAX_GLOB_DAT);
+       }
+      rela.r_addend = bfd_get_signed_32 (output_bfd,
+                                        (sgot->contents
+                                         + (h->got.offset & ~1)));
+
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+                                ((Elf32_External_Rela *) srela->contents
+                                 + srela->reloc_count));
+      ++srela->reloc_count;
+    }
+
+  if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0)
+    {
+      asection *s;
+      Elf_Internal_Rela rela;
+
+      /* This symbol needs a copy reloc.  Set it up.  */
+
+      BFD_ASSERT (h->dynindx != -1
+                 && (h->root.type == bfd_link_hash_defined
+                     || h->root.type == bfd_link_hash_defweak));
+
+      s = bfd_get_section_by_name (h->root.u.def.section->owner,
+                                  ".rela.bss");
+      BFD_ASSERT (s != NULL);
+
+      rela.r_offset = (h->root.u.def.value
+                      + h->root.u.def.section->output_section->vma
+                      + h->root.u.def.section->output_offset);
+      rela.r_info = ELF32_R_INFO (h->dynindx, R_VAX_COPY);
+      rela.r_addend = 0;
+      bfd_elf32_swap_reloca_out (output_bfd, &rela,
+                                ((Elf32_External_Rela *) s->contents
+                                 + s->reloc_count));
+      ++s->reloc_count;
+    }
+
+  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */
+  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+    sym->st_shndx = SHN_ABS;
+
+  return true;
+}
+
+/* Finish up the dynamic sections.  */
+
+static boolean
+elf_vax_finish_dynamic_sections (output_bfd, info)
+     bfd *output_bfd;
+     struct bfd_link_info *info;
+{
+  bfd *dynobj;
+  asection *sgot;
+  asection *sdyn;
+
+  dynobj = elf_hash_table (info)->dynobj;
+
+  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+  BFD_ASSERT (sgot != NULL);
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+
+  if (elf_hash_table (info)->dynamic_sections_created)
+    {
+      asection *splt;
+      Elf32_External_Dyn *dyncon, *dynconend;
+
+      splt = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (splt != NULL && sdyn != NULL);
+
+      dyncon = (Elf32_External_Dyn *) sdyn->contents;
+      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
+      for (; dyncon < dynconend; dyncon++)
+       {
+         Elf_Internal_Dyn dyn;
+         const char *name;
+         asection *s;
+
+         bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
+
+         switch (dyn.d_tag)
+           {
+           default:
+             break;
+
+           case DT_PLTGOT:
+             name = ".got";
+             goto get_vma;
+           case DT_JMPREL:
+             name = ".rela.plt";
+           get_vma:
+             s = bfd_get_section_by_name (output_bfd, name);
+             BFD_ASSERT (s != NULL);
+             dyn.d_un.d_ptr = s->vma;
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+
+           case DT_PLTRELSZ:
+             s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+             BFD_ASSERT (s != NULL);
+             if (s->_cooked_size != 0)
+               dyn.d_un.d_val = s->_cooked_size;
+             else
+               dyn.d_un.d_val = s->_raw_size;
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+
+           case DT_RELASZ:
+             /* The procedure linkage table relocs (DT_JMPREL) should
+                not be included in the overall relocs (DT_RELA).
+                Therefore, we override the DT_RELASZ entry here to
+                make it not include the JMPREL relocs.  Since the
+                linker script arranges for .rela.plt to follow all
+                other relocation sections, we don't have to worry
+                about changing the DT_RELA entry.  */
+             s = bfd_get_section_by_name (output_bfd, ".rela.plt");
+             if (s != NULL)
+               {
+                 if (s->_cooked_size != 0)
+                   dyn.d_un.d_val -= s->_cooked_size;
+                 else
+                   dyn.d_un.d_val -= s->_raw_size;
+               }
+             bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+             break;
+           }
+       }
+
+      /* Fill in the first entry in the procedure linkage table.  */
+      if (splt->_raw_size > 0)
+       {
+         memcpy (splt->contents, elf_vax_plt0_entry, PLT_ENTRY_SIZE);
+         bfd_put_32 (output_bfd,
+                         (sgot->output_section->vma
+                          + sgot->output_offset + 4
+                          - (splt->output_section->vma + 6)),
+                         splt->contents + 2);
+         bfd_put_32 (output_bfd,
+                         (sgot->output_section->vma
+                          + sgot->output_offset + 8
+                          - (splt->output_section->vma + 12)),
+                         splt->contents + 8);
+          elf_section_data (splt->output_section)->this_hdr.sh_entsize
+           = PLT_ENTRY_SIZE;
+       }
+    }
+
+  /* Fill in the first three entries in the global offset table.  */
+  if (sgot->_raw_size > 0)
+    {
+      if (sdyn == NULL)
+       bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+      else
+       bfd_put_32 (output_bfd,
+                   sdyn->output_section->vma + sdyn->output_offset,
+                   sgot->contents);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
+      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+    }
+
+  elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+
+  return true;
+}
+
+#define TARGET_LITTLE_SYM              bfd_elf32_vax_vec
+#define TARGET_LITTLE_NAME             "elf32-vax"
+#define ELF_MACHINE_CODE               EM_VAX
+#define ELF_MAXPAGESIZE                        0x1000
+
+#define elf_backend_create_dynamic_sections \
+                                       _bfd_elf_create_dynamic_sections
+#define bfd_elf32_bfd_link_hash_table_create \
+                                       elf_vax_link_hash_table_create
+#define bfd_elf32_bfd_final_link       _bfd_elf32_gc_common_final_link
+
+#define elf_backend_check_relocs       elf_vax_check_relocs
+#define elf_backend_adjust_dynamic_symbol \
+                                       elf_vax_adjust_dynamic_symbol
+#define elf_backend_size_dynamic_sections \
+                                       elf_vax_size_dynamic_sections
+#define elf_backend_relocate_section   elf_vax_relocate_section
+#define elf_backend_finish_dynamic_symbol \
+                                       elf_vax_finish_dynamic_symbol
+#define elf_backend_finish_dynamic_sections \
+                                       elf_vax_finish_dynamic_sections
+#define elf_backend_gc_mark_hook       elf_vax_gc_mark_hook
+#define elf_backend_gc_sweep_hook      elf_vax_gc_sweep_hook
+#define bfd_elf32_bfd_merge_private_bfd_data \
+                                        elf32_vax_merge_private_bfd_data
+#define bfd_elf32_bfd_set_private_flags \
+                                        elf32_vax_set_private_flags
+#define bfd_elf32_bfd_print_private_bfd_data \
+                                        elf32_vax_print_private_bfd_data
+
+#define elf_backend_can_gc_sections    1
+#define elf_backend_want_got_plt       1
+#define elf_backend_plt_readonly       1
+#define elf_backend_want_plt_sym       0
+#define elf_backend_got_header_size    16
+
+#include "elf32-target.h"
diff --git a/bfd/elf64-sh64-nbsd.c b/bfd/elf64-sh64-nbsd.c
new file mode 100644 (file)
index 0000000..43e4eaf
--- /dev/null
@@ -0,0 +1,29 @@
+/* SuperH SH64 specific support for 64-bit NetBSD
+   Copyright 2002 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define TARGET_BIG_SYM         bfd_elf64_sh64nbsd_vec
+#define TARGET_BIG_NAME                "elf64-sh64-nbsd"
+#define TARGET_LITTLE_SYM      bfd_elf64_sh64lnbsd_vec
+#define TARGET_LITTLE_NAME     "elf64-sh64l-nbsd"
+#define ELF_ARCH               bfd_arch_sh
+#define ELF_MACHINE_CODE       EM_SH
+#define ELF_MAXPAGESIZE                0x10000
+#define elf_symbol_leading_char        0
+
+#include "elf64-sh64.c"
diff --git a/bfd/vax1knetbsd.c b/bfd/vax1knetbsd.c
new file mode 100644 (file)
index 0000000..e20cd17
--- /dev/null
@@ -0,0 +1,37 @@
+/* BFD back-end for NetBSD/VAX (1K page size) a.out-ish binaries.
+   Copyright 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of BFD, the Binary File Descriptor library.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#define        BYTES_IN_WORD   4
+#undef TARGET_IS_BIG_ENDIAN_P
+
+#define        TARGET_PAGE_SIZE        1024
+#define        SEGMENT_SIZE    TARGET_PAGE_SIZE
+
+#define        DEFAULT_ARCH    bfd_arch_vax
+#define        DEFAULT_MID     M_VAX_NETBSD
+
+/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
+   remove whitespace added here, and thus will fail to concatenate
+   the tokens.  */
+#define MY(OP) CONCAT2 (vax1knetbsd_,OP)
+
+/* This needs to start with a.out so GDB knows it is an a.out variant.  */
+#define TARGETNAME "a.out-vax1k-netbsd"
+
+#include "netbsd.h"
diff --git a/gdb/ada-exp.tab.c b/gdb/ada-exp.tab.c
new file mode 100644 (file)
index 0000000..bb6d29b
--- /dev/null
@@ -0,0 +1,2389 @@
+/* A Bison parser, made from ./ada-exp.y
+   by GNU bison 1.35.  */
+
+#define YYBISON 1  /* Identify Bison output.  */
+
+# define       INT     257
+# define       NULL_PTR        258
+# define       CHARLIT 259
+# define       FLOAT   260
+# define       TYPENAME        261
+# define       BLOCKNAME       262
+# define       STRING  263
+# define       NAME    264
+# define       DOT_ID  265
+# define       OBJECT_RENAMING 266
+# define       DOT_ALL 267
+# define       LAST    268
+# define       REGNAME 269
+# define       INTERNAL_VARIABLE       270
+# define       ASSIGN  271
+# define       _AND_   272
+# define       OR      273
+# define       XOR     274
+# define       THEN    275
+# define       ELSE    276
+# define       NOTEQUAL        277
+# define       LEQ     278
+# define       GEQ     279
+# define       IN      280
+# define       DOTDOT  281
+# define       UNARY   282
+# define       MOD     283
+# define       REM     284
+# define       STARSTAR        285
+# define       ABS     286
+# define       NOT     287
+# define       TICK_ACCESS     288
+# define       TICK_ADDRESS    289
+# define       TICK_FIRST      290
+# define       TICK_LAST       291
+# define       TICK_LENGTH     292
+# define       TICK_MAX        293
+# define       TICK_MIN        294
+# define       TICK_MODULUS    295
+# define       TICK_POS        296
+# define       TICK_RANGE      297
+# define       TICK_SIZE       298
+# define       TICK_TAG        299
+# define       TICK_VAL        300
+# define       ARROW   301
+# define       NEW     302
+
+#line 38 "./ada-exp.y"
+
+
+#include "defs.h"
+#include <string.h>
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "ada-lang.h"
+#include "bfd.h" /* Required by objfiles.h.  */
+#include "symfile.h" /* Required by objfiles.h.  */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "frame.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in gdb.  These are only the variables
+   produced by yacc.  If other parser generators (bison, byacc, etc) produce
+   additional global names that conflict at link time, then those parser
+   generators need to be fixed instead of adding those names to this list. */
+
+/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix  
+   options.  I presume we are maintaining it to accommodate systems
+   without BISON?  (PNH) */
+
+#define        yymaxdepth ada_maxdepth
+#define        yyparse _ada_parse      /* ada_parse calls this after  initialization */
+#define        yylex   ada_lex
+#define        yyerror ada_error
+#define        yylval  ada_lval
+#define        yychar  ada_char
+#define        yydebug ada_debug
+#define        yypact  ada_pact        
+#define        yyr1    ada_r1                  
+#define        yyr2    ada_r2                  
+#define        yydef   ada_def         
+#define        yychk   ada_chk         
+#define        yypgo   ada_pgo         
+#define        yyact   ada_act         
+#define        yyexca  ada_exca
+#define yyerrflag ada_errflag
+#define yynerrs        ada_nerrs
+#define        yyps    ada_ps
+#define        yypv    ada_pv
+#define        yys     ada_s
+#define        yy_yys  ada_yys
+#define        yystate ada_state
+#define        yytmp   ada_tmp
+#define        yyv     ada_v
+#define        yy_yyv  ada_yyv
+#define        yyval   ada_val
+#define        yylloc  ada_lloc
+#define yyreds ada_reds                /* With YYDEBUG defined */
+#define yytoks ada_toks                /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define        YYDEBUG 0               /* Default to no yydebug support */
+#endif
+
+struct name_info {
+  struct symbol* sym;
+  struct minimal_symbol* msym;
+  struct block* block;
+  struct stoken stoken;
+};
+
+/* If expression is in the context of TYPE'(...), then TYPE, else
+ * NULL. */
+static struct type* type_qualifier;
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static struct stoken string_to_operator (struct stoken);
+
+static void write_attribute_call0 (enum ada_attribute);
+
+static void write_attribute_call1 (enum ada_attribute, LONGEST);
+
+static void write_attribute_calln (enum ada_attribute, int);
+
+static void write_object_renaming (struct block*, struct symbol*);
+
+static void write_var_from_name (struct block*, struct name_info);
+
+static LONGEST
+convert_char_literal (struct type*, LONGEST);
+
+#line 131 "./ada-exp.y"
+#ifndef YYSTYPE
+typedef union
+  {
+    LONGEST lval;
+    struct {
+      LONGEST val;
+      struct type *type;
+    } typed_val;
+    struct {
+      DOUBLEST dval;
+      struct type *type;
+    } typed_val_float;
+    struct type *tval;
+    struct stoken sval;
+    struct name_info ssym;
+    int voidval;
+    struct block *bval;
+    struct internalvar *ivar;
+
+  } yystype;
+# define YYSTYPE yystype
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+
+
+#define        YYFINAL         184
+#define        YYFLAG          -32768
+#define        YYNTBASE        68
+
+/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
+#define YYTRANSLATE(x) ((unsigned)(x) <= 302 ? yytranslate[x] : 82)
+
+/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
+static const char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    34,    63,
+      57,    62,    36,    32,    64,    33,    56,    37,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,    61,
+      25,    23,    26,     2,    31,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    58,     2,    67,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    65,     2,    66,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    17,    18,    19,    20,    21,    22,    24,    27,    28,
+      29,    30,    35,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    59,    60
+};
+
+#if YYDEBUG
+static const short yyprhs[] =
+{
+       0,     0,     2,     4,     6,    10,    13,    16,    21,    26,
+      27,    35,    36,    43,    47,    49,    51,    53,    55,    57,
+      61,    64,    67,    70,    73,    74,    76,    80,    84,    90,
+      95,    99,   103,   107,   111,   115,   119,   123,   127,   131,
+     135,   139,   143,   149,   155,   159,   166,   173,   178,   182,
+     186,   190,   194,   199,   203,   208,   212,   215,   218,   222,
+     226,   230,   233,   236,   244,   252,   258,   262,   266,   270,
+     276,   279,   280,   284,   286,   288,   289,   291,   293,   295,
+     297,   299,   302,   304,   307,   309,   312,   314,   316,   318,
+     320,   323,   325,   328,   331,   335,   338,   341
+};
+static const short yyrhs[] =
+{
+      69,     0,    81,     0,    73,     0,    69,    61,    73,     0,
+      70,    13,     0,    70,    11,     0,    70,    57,    74,    62,
+       0,    81,    57,    73,    62,     0,     0,    81,    63,    72,
+      71,    57,    73,    62,     0,     0,    70,    57,    73,    30,
+      73,    62,     0,    57,    69,    62,     0,    78,     0,    15,
+       0,    16,     0,    70,     0,    14,     0,    73,    17,    73,
+       0,    33,    73,     0,    32,    73,     0,    42,    73,     0,
+      41,    73,     0,     0,    73,     0,    79,    59,    73,     0,
+      74,    64,    73,     0,    74,    64,    79,    59,    73,     0,
+      65,    81,    66,    73,     0,    73,    40,    73,     0,    73,
+      36,    73,     0,    73,    37,    73,     0,    73,    39,    73,
+       0,    73,    38,    73,     0,    73,    31,    73,     0,    73,
+      32,    73,     0,    73,    34,    73,     0,    73,    33,    73,
+       0,    73,    23,    73,     0,    73,    24,    73,     0,    73,
+      27,    73,     0,    73,    29,    73,    30,    73,     0,    73,
+      29,    73,    52,    75,     0,    73,    29,     7,     0,    73,
+      42,    29,    73,    30,    73,     0,    73,    42,    29,    73,
+      52,    75,     0,    73,    42,    29,     7,     0,    73,    28,
+      73,     0,    73,    25,    73,     0,    73,    26,    73,     0,
+      73,    18,    73,     0,    73,    18,    21,    73,     0,    73,
+      19,    73,     0,    73,    19,    22,    73,     0,    73,    20,
+      73,     0,    70,    43,     0,    70,    44,     0,    70,    45,
+      75,     0,    70,    46,    75,     0,    70,    47,    75,     0,
+      70,    53,     0,    70,    54,     0,    77,    49,    57,    73,
+      64,    73,    62,     0,    77,    48,    57,    73,    64,    73,
+      62,     0,    77,    51,    57,    73,    62,     0,    76,    45,
+      75,     0,    76,    46,    75,     0,    76,    47,    75,     0,
+      76,    55,    57,    73,    62,     0,    76,    50,     0,     0,
+      57,     3,    62,     0,     7,     0,    76,     0,     0,     3,
+       0,     5,     0,     6,     0,     4,     0,     9,     0,    60,
+       7,     0,    10,     0,    80,    10,     0,    12,     0,    80,
+      12,     0,    10,     0,     7,     0,    12,     0,     8,     0,
+      80,     8,     0,     7,     0,    80,     7,     0,     7,    43,
+       0,    80,     7,    43,     0,    36,    73,     0,    34,    73,
+       0,    73,    58,    73,    67,     0
+};
+
+#endif
+
+#if YYDEBUG
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const short yyrline[] =
+{
+       0,   203,   204,   210,   211,   216,   220,   227,   235,   243,
+     243,   254,   256,   261,   264,   267,   274,   282,   285,   292,
+     296,   300,   304,   308,   312,   315,   317,   319,   321,   325,
+     335,   339,   343,   347,   351,   355,   359,   363,   367,   371,
+     375,   379,   383,   387,   393,   400,   405,   413,   423,   427,
+     431,   435,   439,   443,   447,   451,   455,   457,   463,   465,
+     467,   469,   471,   473,   475,   477,   479,   481,   483,   485,
+     487,   491,   493,   497,   504,   506,   513,   521,   533,   541,
+     548,   575,   579,   580,   582,   583,   587,   588,   589,   592,
+     594,   599,   600,   601,   603,   610,   612,   614
+};
+#endif
+
+
+#if (YYDEBUG) || defined YYERROR_VERBOSE
+
+/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
+static const char *const yytname[] =
+{
+  "$", "error", "$undefined.", "INT", "NULL_PTR", "CHARLIT", "FLOAT", 
+  "TYPENAME", "BLOCKNAME", "STRING", "NAME", "DOT_ID", "OBJECT_RENAMING", 
+  "DOT_ALL", "LAST", "REGNAME", "INTERNAL_VARIABLE", "ASSIGN", "_AND_", 
+  "OR", "XOR", "THEN", "ELSE", "'='", "NOTEQUAL", "'<'", "'>'", "LEQ", 
+  "GEQ", "IN", "DOTDOT", "'@'", "'+'", "'-'", "'&'", "UNARY", "'*'", 
+  "'/'", "MOD", "REM", "STARSTAR", "ABS", "NOT", "TICK_ACCESS", 
+  "TICK_ADDRESS", "TICK_FIRST", "TICK_LAST", "TICK_LENGTH", "TICK_MAX", 
+  "TICK_MIN", "TICK_MODULUS", "TICK_POS", "TICK_RANGE", "TICK_SIZE", 
+  "TICK_TAG", "TICK_VAL", "'.'", "'('", "'['", "ARROW", "NEW", "';'", 
+  "')'", "'\\''", "','", "'{'", "'}'", "']'", "start", "exp1", 
+  "simple_exp", "@1", "save_qualifier", "exp", "arglist", "tick_arglist", 
+  "type_prefix", "opt_type_prefix", "variable", "any_name", "block", 
+  "type", 0
+};
+#endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const short yyr1[] =
+{
+       0,    68,    68,    69,    69,    70,    70,    70,    70,    71,
+      70,    72,    70,    70,    70,    70,    70,    73,    70,    73,
+      73,    73,    73,    73,    74,    74,    74,    74,    74,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    73,    73,    73,    73,
+      73,    73,    73,    73,    73,    73,    70,    70,    70,    70,
+      70,    70,    70,    70,    70,    70,    70,    70,    70,    70,
+      70,    75,    75,    76,    77,    77,    73,    73,    73,    73,
+      73,    73,    78,    78,    78,    78,    79,    79,    79,    80,
+      80,    81,    81,    81,    81,    73,    73,    73
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const short yyr2[] =
+{
+       0,     1,     1,     1,     3,     2,     2,     4,     4,     0,
+       7,     0,     6,     3,     1,     1,     1,     1,     1,     3,
+       2,     2,     2,     2,     0,     1,     3,     3,     5,     4,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     5,     5,     3,     6,     6,     4,     3,     3,
+       3,     3,     4,     3,     4,     3,     2,     2,     3,     3,
+       3,     2,     2,     7,     7,     5,     3,     3,     3,     5,
+       2,     0,     3,     1,     1,     0,     1,     1,     1,     1,
+       1,     2,     1,     2,     1,     2,     1,     1,     1,     1,
+       2,     1,     2,     2,     3,     2,     2,     4
+};
+
+/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
+   doesn't specify something else to do.  Zero means the default is an
+   error. */
+static const short yydefact[] =
+{
+      75,    76,    79,    77,    78,    73,    89,    80,    82,    84,
+      18,    15,    16,    75,    75,    75,    75,    75,    75,    75,
+       0,     0,     1,    17,     3,    74,     0,    14,     0,     2,
+      93,    21,     0,    20,    96,    95,    23,    22,     0,    81,
+      91,     0,     0,    75,     6,     5,    56,    57,    71,    71,
+      71,    61,    62,    75,    75,    75,    75,    75,    75,    75,
+      75,    75,    75,    75,    75,    75,    75,    75,    75,    75,
+      75,    75,    75,    75,     0,    75,    71,    71,    71,    70,
+       0,     0,     0,     0,    92,    90,    83,    85,    75,    11,
+      13,    75,     4,     0,    58,    59,    60,    73,    82,    84,
+      25,     0,     0,    19,    75,    51,    75,    53,    55,    39,
+      40,    49,    50,    41,    48,    44,     0,    35,    36,    38,
+      37,    31,    32,    34,    33,    30,    75,     0,    66,    67,
+      68,    75,    75,    75,    75,    94,     0,     9,    29,     0,
+      75,     7,    75,    75,    52,    54,    75,    71,    47,     0,
+      97,     0,     0,     0,     0,     8,     0,    72,     0,    27,
+       0,    26,    42,    43,    75,    71,    69,    75,    75,    65,
+      75,    12,    75,    45,    46,     0,     0,     0,    28,    64,
+      63,    10,     0,     0,     0
+};
+
+static const short yydefgoto[] =
+{
+     182,    22,    23,   156,   137,    24,   101,    94,    25,    26,
+      27,   102,    28,    32
+};
+
+static const short yypact[] =
+{
+     251,-32768,-32768,-32768,-32768,    20,-32768,-32768,-32768,-32768,
+  -32768,-32768,-32768,   251,   251,   251,   251,   251,   251,   251,
+       2,    79,   -47,    53,   958,   -23,    54,-32768,   104,   -32,
+  -32768,    31,   -32,    31,   -22,   -22,    31,    31,    33,-32768,
+      -5,   101,   -27,   251,-32768,-32768,-32768,-32768,     4,     4,
+       4,-32768,-32768,   131,   251,   171,   211,   251,   251,   251,
+     251,   251,   251,   251,   291,   251,   251,   251,   251,   251,
+     251,   251,   251,   251,    47,   251,     4,     4,     4,-32768,
+      23,    25,    27,    35,    45,-32768,-32768,-32768,   251,-32768,
+  -32768,   251,   958,    98,-32768,-32768,-32768,    22,    56,    58,
+     930,   -36,    64,   986,   251,  1009,   251,  1009,  1009,   -21,
+     -21,   -21,   -21,   -21,   -21,   534,   858,   387,    31,    31,
+      31,    32,    32,    32,    32,    32,   331,   415,-32768,-32768,
+  -32768,   251,   251,   251,   251,-32768,   536,-32768,   -22,    62,
+     251,-32768,   371,   251,  1009,  1009,   251,     4,   534,   894,
+  -32768,   582,   452,   494,   628,-32768,    68,-32768,   674,   958,
+      67,   958,   -21,-32768,   251,     4,-32768,   251,   251,-32768,
+     251,-32768,   251,   -21,-32768,   720,   766,   812,   958,-32768,
+  -32768,-32768,   128,   132,-32768
+};
+
+static const short yypgoto[] =
+{
+  -32768,   112,-32768,-32768,-32768,   -13,-32768,   -43,-32768,-32768,
+  -32768,     0,   123,     8
+};
+
+
+#define        YYLAST          1067
+
+
+static const short yytable[] =
+{
+      31,    33,    34,    35,    36,    37,    95,    96,    29,    39,
+      65,    66,    67,    68,    43,    69,    70,    71,    72,    73,
+     -91,    74,    76,    77,    78,    88,   141,    79,   142,    42,
+      92,    89,    80,   128,   129,   130,    75,    75,    30,    91,
+     100,   103,   105,   107,   108,   109,   110,   111,   112,   113,
+     114,   116,   117,   118,   119,   120,   121,   122,   123,   124,
+     125,    93,   127,    30,    44,    30,    45,    69,    70,    71,
+      72,    73,    73,    74,    74,   136,   126,   -91,   138,   -91,
+     131,   -87,   132,   -91,   133,   -91,    40,     6,   135,    75,
+      75,   144,   134,   145,    43,    90,    46,    47,    48,    49,
+      50,   139,    81,    82,   163,    83,    51,    52,    84,    85,
+      53,    84,    85,   149,    86,   -86,    87,   -88,   151,   152,
+     153,   154,   174,   143,   157,   170,   172,   158,   183,   159,
+     161,    38,   184,   162,     1,     2,     3,     4,    97,     6,
+       7,    98,   160,    99,    41,    10,    11,    12,     0,     0,
+       0,   173,     0,     0,   175,   176,     0,   177,     0,   178,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     1,     2,     3,     4,     5,     6,
+       7,     8,     0,     9,     0,    10,    11,    12,    19,     0,
+       0,    20,   104,   -24,     0,   -24,    21,     0,     0,     0,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     1,     2,     3,     4,     5,     6,
+       7,     8,     0,     9,     0,    10,    11,    12,    19,     0,
+       0,    20,     0,   106,     0,     0,    21,     0,     0,     0,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     1,     2,     3,     4,     5,     6,
+       7,     8,     0,     9,     0,    10,    11,    12,    19,     0,
+       0,    20,     0,     0,     0,     0,    21,     0,     0,     0,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     1,     2,     3,     4,   115,     6,
+       7,     8,     0,     9,     0,    10,    11,    12,    19,     0,
+       0,    20,     0,     0,     0,     0,    21,     0,     0,     0,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     1,     2,     3,     4,   148,     6,
+       7,     8,     0,     9,     0,    10,    11,    12,    19,     0,
+       0,    20,     0,     0,     0,     0,    21,     0,     0,     0,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     1,     2,     3,     4,    97,     6,
+       7,    98,     0,    99,     0,    10,    11,    12,    19,     0,
+       0,    20,     0,     0,     0,     0,    21,     0,     0,     0,
+       0,     0,     0,    13,    14,    15,     0,    16,     0,     0,
+       0,     0,    17,    18,     0,     0,     0,     0,     0,    66,
+      67,    68,     0,    69,    70,    71,    72,    73,    19,    74,
+       0,    20,    54,    55,    56,    57,    21,     0,    58,    59,
+      60,    61,    62,    63,    64,    75,    65,    66,    67,    68,
+       0,    69,    70,    71,    72,    73,     0,    74,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    54,
+      55,    56,    57,    75,     0,    58,    59,    60,    61,    62,
+      63,    64,   150,    65,    66,    67,    68,     0,    69,    70,
+      71,    72,    73,     0,    74,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      75,    54,    55,    56,    57,     0,   167,    58,    59,    60,
+      61,    62,    63,    64,     0,    65,    66,    67,    68,     0,
+      69,    70,    71,    72,    73,     0,    74,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    75,    54,    55,    56,    57,     0,   168,    58,
+      59,    60,    61,    62,    63,    64,     0,    65,    66,    67,
+      68,     0,    69,    70,    71,    72,    73,    30,    74,   -73,
+     -73,   -73,   -73,   -73,   -73,   -73,     0,     0,     0,   -73,
+       0,   -91,     0,     0,    75,     0,     0,   -91,   155,    54,
+      55,    56,    57,     0,     0,    58,    59,    60,    61,    62,
+      63,    64,     0,    65,    66,    67,    68,     0,    69,    70,
+      71,    72,    73,     0,    74,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      75,     0,     0,     0,   166,    54,    55,    56,    57,     0,
+       0,    58,    59,    60,    61,    62,    63,    64,     0,    65,
+      66,    67,    68,     0,    69,    70,    71,    72,    73,     0,
+      74,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    75,     0,     0,     0,
+     169,    54,    55,    56,    57,     0,     0,    58,    59,    60,
+      61,    62,    63,    64,     0,    65,    66,    67,    68,     0,
+      69,    70,    71,    72,    73,     0,    74,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    75,     0,     0,     0,   171,    54,    55,    56,
+      57,     0,     0,    58,    59,    60,    61,    62,    63,    64,
+       0,    65,    66,    67,    68,     0,    69,    70,    71,    72,
+      73,     0,    74,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,    75,     0,
+       0,     0,   179,    54,    55,    56,    57,     0,     0,    58,
+      59,    60,    61,    62,    63,    64,     0,    65,    66,    67,
+      68,     0,    69,    70,    71,    72,    73,     0,    74,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    75,     0,     0,     0,   180,    54,
+      55,    56,    57,     0,     0,    58,    59,    60,    61,    62,
+      63,    64,     0,    65,    66,    67,    68,     0,    69,    70,
+      71,    72,    73,     0,    74,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      75,     0,     0,     0,   181,    54,    55,    56,    57,     0,
+       0,    58,    59,    60,    61,    62,    63,    64,   146,    65,
+      66,    67,    68,     0,    69,    70,    71,    72,    73,     0,
+      74,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+     147,    54,    55,    56,    57,     0,    75,    58,    59,    60,
+      61,    62,    63,    64,   164,    65,    66,    67,    68,     0,
+      69,    70,    71,    72,    73,     0,    74,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,   165,    54,    55,    56,
+      57,     0,    75,    58,    59,    60,    61,    62,    63,    64,
+     140,    65,    66,    67,    68,     0,    69,    70,    71,    72,
+      73,     0,    74,     0,     0,    54,    55,    56,    57,     0,
+       0,    58,    59,    60,    61,    62,    63,    64,    75,    65,
+      66,    67,    68,     0,    69,    70,    71,    72,    73,     0,
+      74,     0,     0,-32768,    55,    56,    57,     0,     0,    58,
+      59,    60,    61,    62,    63,    64,    75,    65,    66,    67,
+      68,     0,    69,    70,    71,    72,    73,     0,    74,     0,
+       0,     0,    58,    59,    60,    61,    62,    63,    64,     0,
+      65,    66,    67,    68,    75,    69,    70,    71,    72,    73,
+       0,    74,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,    75
+};
+
+static const short yycheck[] =
+{
+      13,    14,    15,    16,    17,    18,    49,    50,     0,     7,
+      31,    32,    33,    34,    61,    36,    37,    38,    39,    40,
+       0,    42,    45,    46,    47,    57,    62,    50,    64,    21,
+      43,    63,    55,    76,    77,    78,    58,    58,    43,    66,
+      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,    57,    75,    43,    11,    43,    13,    36,    37,    38,
+      39,    40,    40,    42,    42,    88,    29,    57,    91,    57,
+      57,    59,    57,    63,    57,    63,     7,     8,    43,    58,
+      58,   104,    57,   106,    61,    62,    43,    44,    45,    46,
+      47,     3,    48,    49,   147,    51,    53,    54,     7,     8,
+      57,     7,     8,   126,    10,    59,    12,    59,   131,   132,
+     133,   134,   165,    59,    62,    57,    59,   140,     0,   142,
+     143,    19,     0,   146,     3,     4,     5,     6,     7,     8,
+       9,    10,   142,    12,    21,    14,    15,    16,    -1,    -1,
+      -1,   164,    -1,    -1,   167,   168,    -1,   170,    -1,   172,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,     3,     4,     5,     6,     7,     8,
+       9,    10,    -1,    12,    -1,    14,    15,    16,    57,    -1,
+      -1,    60,    21,    62,    -1,    64,    65,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,     3,     4,     5,     6,     7,     8,
+       9,    10,    -1,    12,    -1,    14,    15,    16,    57,    -1,
+      -1,    60,    -1,    22,    -1,    -1,    65,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,     3,     4,     5,     6,     7,     8,
+       9,    10,    -1,    12,    -1,    14,    15,    16,    57,    -1,
+      -1,    60,    -1,    -1,    -1,    -1,    65,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,     3,     4,     5,     6,     7,     8,
+       9,    10,    -1,    12,    -1,    14,    15,    16,    57,    -1,
+      -1,    60,    -1,    -1,    -1,    -1,    65,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,     3,     4,     5,     6,     7,     8,
+       9,    10,    -1,    12,    -1,    14,    15,    16,    57,    -1,
+      -1,    60,    -1,    -1,    -1,    -1,    65,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,     3,     4,     5,     6,     7,     8,
+       9,    10,    -1,    12,    -1,    14,    15,    16,    57,    -1,
+      -1,    60,    -1,    -1,    -1,    -1,    65,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    33,    34,    -1,    36,    -1,    -1,
+      -1,    -1,    41,    42,    -1,    -1,    -1,    -1,    -1,    32,
+      33,    34,    -1,    36,    37,    38,    39,    40,    57,    42,
+      -1,    60,    17,    18,    19,    20,    65,    -1,    23,    24,
+      25,    26,    27,    28,    29,    58,    31,    32,    33,    34,
+      -1,    36,    37,    38,    39,    40,    -1,    42,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    17,
+      18,    19,    20,    58,    -1,    23,    24,    25,    26,    27,
+      28,    29,    67,    31,    32,    33,    34,    -1,    36,    37,
+      38,    39,    40,    -1,    42,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      58,    17,    18,    19,    20,    -1,    64,    23,    24,    25,
+      26,    27,    28,    29,    -1,    31,    32,    33,    34,    -1,
+      36,    37,    38,    39,    40,    -1,    42,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    58,    17,    18,    19,    20,    -1,    64,    23,
+      24,    25,    26,    27,    28,    29,    -1,    31,    32,    33,
+      34,    -1,    36,    37,    38,    39,    40,    43,    42,    45,
+      46,    47,    48,    49,    50,    51,    -1,    -1,    -1,    55,
+      -1,    57,    -1,    -1,    58,    -1,    -1,    63,    62,    17,
+      18,    19,    20,    -1,    -1,    23,    24,    25,    26,    27,
+      28,    29,    -1,    31,    32,    33,    34,    -1,    36,    37,
+      38,    39,    40,    -1,    42,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      58,    -1,    -1,    -1,    62,    17,    18,    19,    20,    -1,
+      -1,    23,    24,    25,    26,    27,    28,    29,    -1,    31,
+      32,    33,    34,    -1,    36,    37,    38,    39,    40,    -1,
+      42,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,
+      62,    17,    18,    19,    20,    -1,    -1,    23,    24,    25,
+      26,    27,    28,    29,    -1,    31,    32,    33,    34,    -1,
+      36,    37,    38,    39,    40,    -1,    42,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    58,    -1,    -1,    -1,    62,    17,    18,    19,
+      20,    -1,    -1,    23,    24,    25,    26,    27,    28,    29,
+      -1,    31,    32,    33,    34,    -1,    36,    37,    38,    39,
+      40,    -1,    42,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    58,    -1,
+      -1,    -1,    62,    17,    18,    19,    20,    -1,    -1,    23,
+      24,    25,    26,    27,    28,    29,    -1,    31,    32,    33,
+      34,    -1,    36,    37,    38,    39,    40,    -1,    42,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    58,    -1,    -1,    -1,    62,    17,
+      18,    19,    20,    -1,    -1,    23,    24,    25,    26,    27,
+      28,    29,    -1,    31,    32,    33,    34,    -1,    36,    37,
+      38,    39,    40,    -1,    42,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      58,    -1,    -1,    -1,    62,    17,    18,    19,    20,    -1,
+      -1,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+      32,    33,    34,    -1,    36,    37,    38,    39,    40,    -1,
+      42,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      52,    17,    18,    19,    20,    -1,    58,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    -1,
+      36,    37,    38,    39,    40,    -1,    42,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    52,    17,    18,    19,
+      20,    -1,    58,    23,    24,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    -1,    36,    37,    38,    39,
+      40,    -1,    42,    -1,    -1,    17,    18,    19,    20,    -1,
+      -1,    23,    24,    25,    26,    27,    28,    29,    58,    31,
+      32,    33,    34,    -1,    36,    37,    38,    39,    40,    -1,
+      42,    -1,    -1,    17,    18,    19,    20,    -1,    -1,    23,
+      24,    25,    26,    27,    28,    29,    58,    31,    32,    33,
+      34,    -1,    36,    37,    38,    39,    40,    -1,    42,    -1,
+      -1,    -1,    23,    24,    25,    26,    27,    28,    29,    -1,
+      31,    32,    33,    34,    58,    36,    37,    38,    39,    40,
+      -1,    42,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    58
+};
+/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
+#line 3 "/usr/local/share/bison/bison.simple"
+
+/* Skeleton output parser for bison,
+
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software
+   Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* This is the parser code that is written into each bison parser when
+   the %semantic_parser declaration is not specified in the grammar.
+   It was written by Richard Stallman by simplifying the hairy parser
+   used when %semantic_parser is specified.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)
+
+/* The parser invokes alloca or xmalloc; define the necessary symbols.  */
+
+# if YYSTACK_USE_ALLOCA
+#  define YYSTACK_ALLOC alloca
+# else
+#  ifndef YYSTACK_USE_ALLOCA
+#   if defined (alloca) || defined (_ALLOCA_H)
+#    define YYSTACK_ALLOC alloca
+#   else
+#    ifdef __GNUC__
+#     define YYSTACK_ALLOC __builtin_alloca
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+#  if defined (__STDC__) || defined (__cplusplus)
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   define YYSIZE_T size_t
+#  endif
+#  define YYSTACK_ALLOC xmalloc
+#  define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+        || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short yyss;
+  YYSTYPE yyvs;
+# if YYLSP_NEEDED
+  YYLTYPE yyls;
+# endif
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# if YYLSP_NEEDED
+#  define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE))     \
+      + 2 * YYSTACK_GAP_MAX)
+# else
+#  define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short) + sizeof (YYSTYPE))                                \
+      + YYSTACK_GAP_MAX)
+# endif
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         register YYSIZE_T yyi;                \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)                                       \
+    do                                                                 \
+      {                                                                        \
+       YYSIZE_T yynewbytes;                                            \
+       YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+       Stack = &yyptr->Stack;                                          \
+       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX;   \
+       yyptr += yynewbytes / sizeof (*yyptr);                          \
+      }                                                                        \
+    while (0)
+
+#endif
+
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok                (yyerrstatus = 0)
+#define yyclearin      (yychar = YYEMPTY)
+#define YYEMPTY                -2
+#define YYEOF          0
+#define YYACCEPT       goto yyacceptlab
+#define YYABORT        goto yyabortlab
+#define YYERROR                goto yyerrlab1
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+#define YYFAIL         goto yyerrlab
+#define YYRECOVERING()  (!!yyerrstatus)
+#define YYBACKUP(Token, Value)                                 \
+do                                                             \
+  if (yychar == YYEMPTY && yylen == 1)                         \
+    {                                                          \
+      yychar = (Token);                                                \
+      yylval = (Value);                                                \
+      yychar1 = YYTRANSLATE (yychar);                          \
+      YYPOPSTACK;                                              \
+      goto yybackup;                                           \
+    }                                                          \
+  else                                                         \
+    {                                                          \
+      yyerror ("syntax error: cannot back up");                        \
+      YYERROR;                                                 \
+    }                                                          \
+while (0)
+
+#define YYTERROR       1
+#define YYERRCODE      256
+
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+   are run).
+
+   When YYLLOC_DEFAULT is run, CURRENT is set the location of the
+   first token.  By default, to implement support for ranges, extend
+   its range to the last symbol.  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)               \
+   Current.last_line   = Rhs[N].last_line;     \
+   Current.last_column = Rhs[N].last_column;
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#if YYPURE
+# if YYLSP_NEEDED
+#  ifdef YYLEX_PARAM
+#   define YYLEX               yylex (&yylval, &yylloc, YYLEX_PARAM)
+#  else
+#   define YYLEX               yylex (&yylval, &yylloc)
+#  endif
+# else /* !YYLSP_NEEDED */
+#  ifdef YYLEX_PARAM
+#   define YYLEX               yylex (&yylval, YYLEX_PARAM)
+#  else
+#   define YYLEX               yylex (&yylval)
+#  endif
+# endif /* !YYLSP_NEEDED */
+#else /* !YYPURE */
+# define YYLEX                 yylex ()
+#endif /* !YYPURE */
+
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                       \
+do {                                           \
+  if (yydebug)                                 \
+    YYFPRINTF Args;                            \
+} while (0)
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+#endif /* !YYDEBUG */
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef        YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+\f
+#ifdef YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+#endif
+\f
+#line 315 "/usr/local/share/bison/bison.simple"
+
+
+/* The user can define YYPARSE_PARAM as the name of an argument to be passed
+   into yyparse.  The argument should have type void *.
+   It should actually point to an object.
+   Grammar actions can access the variable by casting it
+   to the proper pointer type.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+#  define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
+#  define YYPARSE_PARAM_DECL
+# else
+#  define YYPARSE_PARAM_ARG YYPARSE_PARAM
+#  define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
+# endif
+#else /* !YYPARSE_PARAM */
+# define YYPARSE_PARAM_ARG
+# define YYPARSE_PARAM_DECL
+#endif /* !YYPARSE_PARAM */
+
+/* Prevent warning if -Wstrict-prototypes.  */
+#ifdef __GNUC__
+# ifdef YYPARSE_PARAM
+int yyparse (void *);
+# else
+int yyparse (void);
+# endif
+#endif
+
+/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
+   variables are global, or local to YYPARSE.  */
+
+#define YY_DECL_NON_LSP_VARIABLES                      \
+/* The lookahead symbol.  */                           \
+int yychar;                                            \
+                                                       \
+/* The semantic value of the lookahead symbol. */      \
+YYSTYPE yylval;                                                \
+                                                       \
+/* Number of parse errors so far.  */                  \
+int yynerrs;
+
+#if YYLSP_NEEDED
+# define YY_DECL_VARIABLES                     \
+YY_DECL_NON_LSP_VARIABLES                      \
+                                               \
+/* Location data for the lookahead symbol.  */ \
+YYLTYPE yylloc;
+#else
+# define YY_DECL_VARIABLES                     \
+YY_DECL_NON_LSP_VARIABLES
+#endif
+
+
+/* If nonreentrant, generate the variables here. */
+
+#if !YYPURE
+YY_DECL_VARIABLES
+#endif  /* !YYPURE */
+
+int
+yyparse (YYPARSE_PARAM_ARG)
+     YYPARSE_PARAM_DECL
+{
+  /* If reentrant, generate the variables here. */
+#if YYPURE
+  YY_DECL_VARIABLES
+#endif  /* !YYPURE */
+
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yychar1 = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to xreallocate them elsewhere.  */
+
+  /* The state stack. */
+  short        yyssa[YYINITDEPTH];
+  short *yyss = yyssa;
+  register short *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+#if YYLSP_NEEDED
+  /* The location stack.  */
+  YYLTYPE yylsa[YYINITDEPTH];
+  YYLTYPE *yyls = yylsa;
+  YYLTYPE *yylsp;
+#endif
+
+#if YYLSP_NEEDED
+# define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
+#else
+# define YYPOPSTACK   (yyvsp--, yyssp--)
+#endif
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+#if YYLSP_NEEDED
+  YYLTYPE yyloc;
+#endif
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule. */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;            /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+#if YYLSP_NEEDED
+  yylsp = yyls;
+#endif
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyssp >= yyss + yystacksize - 1)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+       /* Give user a chance to xreallocate the stack. Use copies of
+          these so that the &'s don't force the real ones into
+          memory.  */
+       YYSTYPE *yyvs1 = yyvs;
+       short *yyss1 = yyss;
+
+       /* Each stack pointer address is followed by the size of the
+          data in use in that stack, in bytes.  */
+# if YYLSP_NEEDED
+       YYLTYPE *yyls1 = yyls;
+       /* This used to be a conditional around just the two extra args,
+          but that might be undefined if yyoverflow is a macro.  */
+       yyoverflow ("parser stack overflow",
+                   &yyss1, yysize * sizeof (*yyssp),
+                   &yyvs1, yysize * sizeof (*yyvsp),
+                   &yyls1, yysize * sizeof (*yylsp),
+                   &yystacksize);
+       yyls = yyls1;
+# else
+       yyoverflow ("parser stack overflow",
+                   &yyss1, yysize * sizeof (*yyssp),
+                   &yyvs1, yysize * sizeof (*yyvsp),
+                   &yystacksize);
+# endif
+       yyss = yyss1;
+       yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (yystacksize >= YYMAXDEPTH)
+       goto yyoverflowlab;
+      yystacksize *= 2;
+      if (yystacksize > YYMAXDEPTH)
+       yystacksize = YYMAXDEPTH;
+
+      {
+       short *yyss1 = yyss;
+       union yyalloc *yyptr =
+         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+       if (! yyptr)
+         goto yyoverflowlab;
+       YYSTACK_RELOCATE (yyss);
+       YYSTACK_RELOCATE (yyvs);
+# if YYLSP_NEEDED
+       YYSTACK_RELOCATE (yyls);
+# endif
+# undef YYSTACK_RELOCATE
+       if (yyss1 != yyssa)
+         YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+#if YYLSP_NEEDED
+      yylsp = yyls + yysize - 1;
+#endif
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                 (unsigned long int) yystacksize));
+
+      if (yyssp >= yyss + yystacksize - 1)
+       YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* yychar is either YYEMPTY or YYEOF
+     or a valid token in external form.  */
+
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  /* Convert token to internal form (in yychar1) for indexing tables with */
+
+  if (yychar <= 0)             /* This means end of input. */
+    {
+      yychar1 = 0;
+      yychar = YYEOF;          /* Don't call YYLEX any more */
+
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yychar1 = YYTRANSLATE (yychar);
+
+#if YYDEBUG
+     /* We have to keep this `#if YYDEBUG', since we use variables
+       which are defined only if `YYDEBUG' is set.  */
+      if (yydebug)
+       {
+         YYFPRINTF (stderr, "Next token is %d (%s",
+                    yychar, yytname[yychar1]);
+         /* Give the individual parser a way to print the precise
+            meaning of a token, for further debugging info.  */
+# ifdef YYPRINT
+         YYPRINT (stderr, yychar, yylval);
+# endif
+         YYFPRINTF (stderr, ")\n");
+       }
+#endif
+    }
+
+  yyn += yychar1;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+    goto yydefault;
+
+  yyn = yytable[yyn];
+
+  /* yyn is what to do for this token type in this state.
+     Negative => reduce, -yyn is rule number.
+     Positive => shift, yyn is new state.
+       New state is final state => don't bother to shift,
+       just return success.
+     0, or most negative number => error.  */
+
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+       goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrlab;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+  YYDPRINTF ((stderr, "Shifting token %d (%s), ",
+             yychar, yytname[yychar1]));
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+#if YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to the semantic value of
+     the lookahead token.  This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+#if YYLSP_NEEDED
+  /* Similarly for the default location.  Let the user run additional
+     commands if for instance locations are ranges.  */
+  yyloc = yylsp[1-yylen];
+  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
+#endif
+
+#if YYDEBUG
+  /* We have to keep this `#if YYDEBUG', since we use variables which
+     are defined only if `YYDEBUG' is set.  */
+  if (yydebug)
+    {
+      int yyi;
+
+      YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",
+                yyn, yyrline[yyn]);
+
+      /* Print the symbols being reduced, and their result.  */
+      for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
+       YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
+      YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);
+    }
+#endif
+
+  switch (yyn) {
+
+case 2:
+#line 204 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type (yyvsp[0].tval);
+                         write_exp_elt_opcode (OP_TYPE); }
+    break;
+case 4:
+#line 212 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_COMMA); }
+    break;
+case 5:
+#line 217 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_IND); }
+    break;
+case 6:
+#line 221 "./ada-exp.y"
+{ write_exp_elt_opcode (STRUCTOP_STRUCT);
+                         write_exp_string (yyvsp[0].ssym.stoken);
+                         write_exp_elt_opcode (STRUCTOP_STRUCT); 
+                         }
+    break;
+case 7:
+#line 228 "./ada-exp.y"
+{
+                         write_exp_elt_opcode (OP_FUNCALL);
+                         write_exp_elt_longcst (yyvsp[-1].lval);
+                         write_exp_elt_opcode (OP_FUNCALL);
+                       }
+    break;
+case 8:
+#line 236 "./ada-exp.y"
+{
+                         write_exp_elt_opcode (UNOP_CAST);
+                         write_exp_elt_type (yyvsp[-3].tval);
+                         write_exp_elt_opcode (UNOP_CAST); 
+                       }
+    break;
+case 9:
+#line 243 "./ada-exp.y"
+{ type_qualifier = yyvsp[-2].tval; }
+    break;
+case 10:
+#line 244 "./ada-exp.y"
+{
+                         /*                      write_exp_elt_opcode (UNOP_QUAL); */
+                         /* FIXME: UNOP_QUAL should be defined in expression.h */
+                         write_exp_elt_type (yyvsp[-6].tval);
+                         /* write_exp_elt_opcode (UNOP_QUAL); */
+                         /* FIXME: UNOP_QUAL should be defined in expression.h */
+                         type_qualifier = yyvsp[-4].tval;
+                       }
+    break;
+case 11:
+#line 254 "./ada-exp.y"
+{ yyval.tval = type_qualifier; }
+    break;
+case 12:
+#line 258 "./ada-exp.y"
+{ write_exp_elt_opcode (TERNOP_SLICE); }
+    break;
+case 13:
+#line 261 "./ada-exp.y"
+{ }
+    break;
+case 15:
+#line 268 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_REGISTER);
+                         write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+                         write_exp_elt_opcode (OP_REGISTER); 
+                       }
+    break;
+case 16:
+#line 275 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_INTERNALVAR);
+                         write_exp_elt_intern (yyvsp[0].ivar);
+                         write_exp_elt_opcode (OP_INTERNALVAR); 
+                       }
+    break;
+case 18:
+#line 286 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_LAST);
+                         write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+                         write_exp_elt_opcode (OP_LAST); 
+                        }
+    break;
+case 19:
+#line 293 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_ASSIGN); }
+    break;
+case 20:
+#line 297 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_NEG); }
+    break;
+case 21:
+#line 301 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_PLUS); }
+    break;
+case 22:
+#line 305 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+    break;
+case 23:
+#line 309 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_ABS); }
+    break;
+case 24:
+#line 312 "./ada-exp.y"
+{ yyval.lval = 0; }
+    break;
+case 25:
+#line 316 "./ada-exp.y"
+{ yyval.lval = 1; }
+    break;
+case 26:
+#line 318 "./ada-exp.y"
+{ yyval.lval = 1; }
+    break;
+case 27:
+#line 320 "./ada-exp.y"
+{ yyval.lval = yyvsp[-2].lval + 1; }
+    break;
+case 28:
+#line 322 "./ada-exp.y"
+{ yyval.lval = yyvsp[-4].lval + 1; }
+    break;
+case 29:
+#line 327 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_MEMVAL);
+                         write_exp_elt_type (yyvsp[-2].tval);
+                         write_exp_elt_opcode (UNOP_MEMVAL); 
+                       }
+    break;
+case 30:
+#line 336 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_EXP); }
+    break;
+case 31:
+#line 340 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_MUL); }
+    break;
+case 32:
+#line 344 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_DIV); }
+    break;
+case 33:
+#line 348 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_REM); }
+    break;
+case 34:
+#line 352 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_MOD); }
+    break;
+case 35:
+#line 356 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_REPEAT); }
+    break;
+case 36:
+#line 360 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_ADD); }
+    break;
+case 37:
+#line 364 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_CONCAT); }
+    break;
+case 38:
+#line 368 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_SUB); }
+    break;
+case 39:
+#line 372 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_EQUAL); }
+    break;
+case 40:
+#line 376 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
+    break;
+case 41:
+#line 380 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_LEQ); }
+    break;
+case 42:
+#line 384 "./ada-exp.y"
+{ /*write_exp_elt_opcode (TERNOP_MBR); */ }
+    break;
+case 43:
+#line 388 "./ada-exp.y"
+{ /*write_exp_elt_opcode (BINOP_MBR); */
+                         /* FIXME: BINOP_MBR should be defined in expression.h */
+                         write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+                         /*write_exp_elt_opcode (BINOP_MBR); */
+                       }
+    break;
+case 44:
+#line 394 "./ada-exp.y"
+{ /*write_exp_elt_opcode (UNOP_MBR); */
+                         /* FIXME: UNOP_QUAL should be defined in expression.h */                        
+                         write_exp_elt_type (yyvsp[0].tval);
+                         /*                      write_exp_elt_opcode (UNOP_MBR); */
+                         /* FIXME: UNOP_MBR should be defined in expression.h */                         
+                       }
+    break;
+case 45:
+#line 401 "./ada-exp.y"
+{ /*write_exp_elt_opcode (TERNOP_MBR); */
+                         /* FIXME: TERNOP_MBR should be defined in expression.h */                                               
+                         write_exp_elt_opcode (UNOP_LOGICAL_NOT); 
+                       }
+    break;
+case 46:
+#line 406 "./ada-exp.y"
+{ /* write_exp_elt_opcode (BINOP_MBR); */
+                         /* FIXME: BINOP_MBR should be defined in expression.h */
+                         write_exp_elt_longcst ((LONGEST) yyvsp[0].lval);
+                         /*write_exp_elt_opcode (BINOP_MBR);*/
+                         /* FIXME: BINOP_MBR should be defined in expression.h */                        
+                         write_exp_elt_opcode (UNOP_LOGICAL_NOT); 
+                       }
+    break;
+case 47:
+#line 414 "./ada-exp.y"
+{ /*write_exp_elt_opcode (UNOP_MBR);*/
+                         /* FIXME: UNOP_MBR should be defined in expression.h */                         
+                         write_exp_elt_type (yyvsp[0].tval);
+                         /*                      write_exp_elt_opcode (UNOP_MBR);*/
+                         /* FIXME: UNOP_MBR should be defined in expression.h */                                                 
+                         write_exp_elt_opcode (UNOP_LOGICAL_NOT); 
+                       }
+    break;
+case 48:
+#line 424 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_GEQ); }
+    break;
+case 49:
+#line 428 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_LESS); }
+    break;
+case 50:
+#line 432 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_GTR); }
+    break;
+case 51:
+#line 436 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_BITWISE_AND); }
+    break;
+case 52:
+#line 440 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+    break;
+case 53:
+#line 444 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+    break;
+case 54:
+#line 448 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+    break;
+case 55:
+#line 452 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+    break;
+case 56:
+#line 456 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_ADDR); }
+    break;
+case 57:
+#line 458 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_ADDR);
+                         write_exp_elt_opcode (UNOP_CAST);
+                         write_exp_elt_type (builtin_type_ada_system_address);
+                         write_exp_elt_opcode (UNOP_CAST);
+                       }
+    break;
+case 58:
+#line 464 "./ada-exp.y"
+{ write_attribute_call1 (ATR_FIRST, yyvsp[0].lval); }
+    break;
+case 59:
+#line 466 "./ada-exp.y"
+{ write_attribute_call1 (ATR_LAST, yyvsp[0].lval); }
+    break;
+case 60:
+#line 468 "./ada-exp.y"
+{ write_attribute_call1 (ATR_LENGTH, yyvsp[0].lval); }
+    break;
+case 61:
+#line 470 "./ada-exp.y"
+{ write_attribute_call0 (ATR_SIZE); }
+    break;
+case 62:
+#line 472 "./ada-exp.y"
+{ write_attribute_call0 (ATR_TAG); }
+    break;
+case 63:
+#line 474 "./ada-exp.y"
+{ write_attribute_calln (ATR_MIN, 2); }
+    break;
+case 64:
+#line 476 "./ada-exp.y"
+{ write_attribute_calln (ATR_MAX, 2); }
+    break;
+case 65:
+#line 478 "./ada-exp.y"
+{ write_attribute_calln (ATR_POS, 1); }
+    break;
+case 66:
+#line 480 "./ada-exp.y"
+{ write_attribute_call1 (ATR_FIRST, yyvsp[0].lval); }
+    break;
+case 67:
+#line 482 "./ada-exp.y"
+{ write_attribute_call1 (ATR_LAST, yyvsp[0].lval); }
+    break;
+case 68:
+#line 484 "./ada-exp.y"
+{ write_attribute_call1 (ATR_LENGTH, yyvsp[0].lval); }
+    break;
+case 69:
+#line 486 "./ada-exp.y"
+{ write_attribute_calln (ATR_VAL, 1); }
+    break;
+case 70:
+#line 488 "./ada-exp.y"
+{ write_attribute_call0 (ATR_MODULUS); }
+    break;
+case 71:
+#line 492 "./ada-exp.y"
+{ yyval.lval = 1; }
+    break;
+case 72:
+#line 494 "./ada-exp.y"
+{ yyval.lval = yyvsp[-1].typed_val.val; }
+    break;
+case 73:
+#line 499 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type (yyvsp[0].tval);
+                         write_exp_elt_opcode (OP_TYPE); }
+    break;
+case 75:
+#line 507 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type (builtin_type_void);
+                         write_exp_elt_opcode (OP_TYPE); }
+    break;
+case 76:
+#line 514 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+                         write_exp_elt_type (yyvsp[0].typed_val.type);
+                         write_exp_elt_longcst ((LONGEST)(yyvsp[0].typed_val.val));
+                         write_exp_elt_opcode (OP_LONG); 
+                       }
+    break;
+case 77:
+#line 522 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+                         if (type_qualifier == NULL) 
+                           write_exp_elt_type (yyvsp[0].typed_val.type);
+                         else
+                           write_exp_elt_type (type_qualifier);
+                         write_exp_elt_longcst 
+                           (convert_char_literal (type_qualifier, yyvsp[0].typed_val.val));
+                         write_exp_elt_opcode (OP_LONG); 
+                       }
+    break;
+case 78:
+#line 534 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_DOUBLE);
+                         write_exp_elt_type (yyvsp[0].typed_val_float.type);
+                         write_exp_elt_dblcst (yyvsp[0].typed_val_float.dval);
+                         write_exp_elt_opcode (OP_DOUBLE); 
+                       }
+    break;
+case 79:
+#line 542 "./ada-exp.y"
+{ write_exp_elt_opcode (OP_LONG);
+                         write_exp_elt_type (builtin_type_int);
+                         write_exp_elt_longcst ((LONGEST)(0));
+                         write_exp_elt_opcode (OP_LONG); 
+                        }
+    break;
+case 80:
+#line 549 "./ada-exp.y"
+{ /* Ada strings are converted into array constants 
+                            a lower bound of 1.  Thus, the array upper bound 
+                            is the string length. */
+                         char *sp = yyvsp[0].sval.ptr; int count;
+                         if (yyvsp[0].sval.length == 0) 
+                           { /* One dummy character for the type */
+                             write_exp_elt_opcode (OP_LONG);
+                             write_exp_elt_type (builtin_type_ada_char);
+                             write_exp_elt_longcst ((LONGEST)(0));
+                             write_exp_elt_opcode (OP_LONG);
+                           }
+                         for (count = yyvsp[0].sval.length; count > 0; count -= 1)
+                           {
+                             write_exp_elt_opcode (OP_LONG);
+                             write_exp_elt_type (builtin_type_ada_char);
+                             write_exp_elt_longcst ((LONGEST)(*sp));
+                             sp += 1;
+                             write_exp_elt_opcode (OP_LONG);
+                           }
+                         write_exp_elt_opcode (OP_ARRAY);
+                         write_exp_elt_longcst ((LONGEST) 1);
+                         write_exp_elt_longcst ((LONGEST) (yyvsp[0].sval.length));
+                         write_exp_elt_opcode (OP_ARRAY); 
+                        }
+    break;
+case 81:
+#line 576 "./ada-exp.y"
+{ error ("NEW not implemented."); }
+    break;
+case 82:
+#line 579 "./ada-exp.y"
+{ write_var_from_name (NULL, yyvsp[0].ssym); }
+    break;
+case 83:
+#line 581 "./ada-exp.y"
+{ write_var_from_name (yyvsp[-1].bval, yyvsp[0].ssym); }
+    break;
+case 84:
+#line 582 "./ada-exp.y"
+{ write_object_renaming (NULL, yyvsp[0].ssym.sym); }
+    break;
+case 85:
+#line 584 "./ada-exp.y"
+{ write_object_renaming (yyvsp[-1].bval, yyvsp[0].ssym.sym); }
+    break;
+case 86:
+#line 587 "./ada-exp.y"
+{ }
+    break;
+case 87:
+#line 588 "./ada-exp.y"
+{ }
+    break;
+case 88:
+#line 589 "./ada-exp.y"
+{ }
+    break;
+case 89:
+#line 593 "./ada-exp.y"
+{ yyval.bval = yyvsp[0].bval; }
+    break;
+case 90:
+#line 595 "./ada-exp.y"
+{ yyval.bval = yyvsp[0].bval; }
+    break;
+case 91:
+#line 599 "./ada-exp.y"
+{ yyval.tval = yyvsp[0].tval; }
+    break;
+case 92:
+#line 600 "./ada-exp.y"
+{ yyval.tval = yyvsp[0].tval; }
+    break;
+case 93:
+#line 602 "./ada-exp.y"
+{ yyval.tval = lookup_pointer_type (yyvsp[-1].tval); }
+    break;
+case 94:
+#line 604 "./ada-exp.y"
+{ yyval.tval = lookup_pointer_type (yyvsp[-1].tval); }
+    break;
+case 95:
+#line 611 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_IND); }
+    break;
+case 96:
+#line 613 "./ada-exp.y"
+{ write_exp_elt_opcode (UNOP_ADDR); }
+    break;
+case 97:
+#line 615 "./ada-exp.y"
+{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+    break;
+}
+
+#line 705 "/usr/local/share/bison/bison.simple"
+
+\f
+  yyvsp -= yylen;
+  yyssp -= yylen;
+#if YYLSP_NEEDED
+  yylsp -= yylen;
+#endif
+
+#if YYDEBUG
+  if (yydebug)
+    {
+      short *yyssp1 = yyss - 1;
+      YYFPRINTF (stderr, "state stack now");
+      while (yyssp1 != yyssp)
+       YYFPRINTF (stderr, " %d", *++yyssp1);
+      YYFPRINTF (stderr, "\n");
+    }
+#endif
+
+  *++yyvsp = yyval;
+#if YYLSP_NEEDED
+  *++yylsp = yyloc;
+#endif
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
+  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTBASE];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+
+#ifdef YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (yyn > YYFLAG && yyn < YYLAST)
+       {
+         YYSIZE_T yysize = 0;
+         char *yymsg;
+         int yyx, yycount;
+
+         yycount = 0;
+         /* Start YYX at -YYN if negative to avoid negative indexes in
+            YYCHECK.  */
+         for (yyx = yyn < 0 ? -yyn : 0;
+              yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+           if (yycheck[yyx + yyn] == yyx)
+             yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+         yysize += yystrlen ("parse error, unexpected ") + 1;
+         yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);
+         yymsg = (char *) YYSTACK_ALLOC (yysize);
+         if (yymsg != 0)
+           {
+             char *yyp = yystpcpy (yymsg, "parse error, unexpected ");
+             yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);
+
+             if (yycount < 5)
+               {
+                 yycount = 0;
+                 for (yyx = yyn < 0 ? -yyn : 0;
+                      yyx < (int) (sizeof (yytname) / sizeof (char *));
+                      yyx++)
+                   if (yycheck[yyx + yyn] == yyx)
+                     {
+                       const char *yyq = ! yycount ? ", expecting " : " or ";
+                       yyp = yystpcpy (yyp, yyq);
+                       yyp = yystpcpy (yyp, yytname[yyx]);
+                       yycount++;
+                     }
+               }
+             yyerror (yymsg);
+             YYSTACK_FREE (yymsg);
+           }
+         else
+           yyerror ("parse error; also virtual memory exhausted");
+       }
+      else
+#endif /* defined (YYERROR_VERBOSE) */
+       yyerror ("parse error");
+    }
+  goto yyerrlab1;
+
+
+/*--------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action |
+`--------------------------------------------------*/
+yyerrlab1:
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+        error, discard it.  */
+
+      /* return failure if at end of input */
+      if (yychar == YYEOF)
+       YYABORT;
+      YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
+                 yychar, yytname[yychar1]));
+      yychar = YYEMPTY;
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+
+  yyerrstatus = 3;             /* Each real token shifted decrements this */
+
+  goto yyerrhandle;
+
+
+/*-------------------------------------------------------------------.
+| yyerrdefault -- current state does not do anything special for the |
+| error token.                                                       |
+`-------------------------------------------------------------------*/
+yyerrdefault:
+#if 0
+  /* This is wrong; only states that explicitly want error tokens
+     should shift them.  */
+
+  /* If its default is to accept any token, ok.  Otherwise pop it.  */
+  yyn = yydefact[yystate];
+  if (yyn)
+    goto yydefault;
+#endif
+
+
+/*---------------------------------------------------------------.
+| yyerrpop -- pop the current state because it cannot handle the |
+| error token                                                    |
+`---------------------------------------------------------------*/
+yyerrpop:
+  if (yyssp == yyss)
+    YYABORT;
+  yyvsp--;
+  yystate = *--yyssp;
+#if YYLSP_NEEDED
+  yylsp--;
+#endif
+
+#if YYDEBUG
+  if (yydebug)
+    {
+      short *yyssp1 = yyss - 1;
+      YYFPRINTF (stderr, "Error: state stack now");
+      while (yyssp1 != yyssp)
+       YYFPRINTF (stderr, " %d", *++yyssp1);
+      YYFPRINTF (stderr, "\n");
+    }
+#endif
+
+/*--------------.
+| yyerrhandle.  |
+`--------------*/
+yyerrhandle:
+  yyn = yypact[yystate];
+  if (yyn == YYFLAG)
+    goto yyerrdefault;
+
+  yyn += YYTERROR;
+  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
+    goto yyerrdefault;
+
+  yyn = yytable[yyn];
+  if (yyn < 0)
+    {
+      if (yyn == YYFLAG)
+       goto yyerrpop;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+  else if (yyn == 0)
+    goto yyerrpop;
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  YYDPRINTF ((stderr, "Shifting error token, "));
+
+  *++yyvsp = yylval;
+#if YYLSP_NEEDED
+  *++yylsp = yylloc;
+#endif
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+/*---------------------------------------------.
+| yyoverflowab -- parser overflow comes here.  |
+`---------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+#line 618 "./ada-exp.y"
+
+
+/* yylex defined in ada-lex.c: Reads one token, getting characters */
+/* through lexptr.  */
+
+/* Remap normal flex interface names (yylex) as well as gratuitiously */
+/* global symbol names, so we can have multiple flex-generated parsers */
+/* in gdb.  */
+
+/* (See note above on previous definitions for YACC.) */
+
+#define yy_create_buffer ada_yy_create_buffer
+#define yy_delete_buffer ada_yy_delete_buffer
+#define yy_init_buffer ada_yy_init_buffer
+#define yy_load_buffer_state ada_yy_load_buffer_state
+#define yy_switch_to_buffer ada_yy_switch_to_buffer
+#define yyrestart ada_yyrestart
+#define yytext ada_yytext
+#define yywrap ada_yywrap
+
+/* The following kludge was found necessary to prevent conflicts between */
+/* defs.h and non-standard stdlib.h files.  */
+#define qsort __qsort__dummy
+#include "ada-lex.c"
+
+int
+ada_parse ()
+{
+  lexer_init (yyin);           /* (Re-)initialize lexer. */
+  left_block_context = NULL;
+  type_qualifier = NULL;
+  
+  return _ada_parse ();
+}
+
+void
+yyerror (msg)
+     char *msg;
+{
+  error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
+
+/* The operator name corresponding to operator symbol STRING (adds 
+   quotes and maps to lower-case).  Destroys the previous contents of
+   the array pointed to by STRING.ptr.  Error if STRING does not match
+   a valid Ada operator.  Assumes that STRING.ptr points to a
+   null-terminated string and that, if STRING is a valid operator
+   symbol, the array pointed to by STRING.ptr contains at least
+   STRING.length+3 characters. */ 
+
+static struct stoken
+string_to_operator (string)
+     struct stoken string;
+{
+  int i;
+
+  for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+    {
+      if (string.length == strlen (ada_opname_table[i].demangled)-2
+         && strncasecmp (string.ptr, ada_opname_table[i].demangled+1,
+                         string.length) == 0)
+       {
+         strncpy (string.ptr, ada_opname_table[i].demangled,
+                  string.length+2);
+         string.length += 2;
+         return string;
+       }
+    }
+  error ("Invalid operator symbol `%s'", string.ptr);
+}
+
+/* Emit expression to access an instance of SYM, in block BLOCK (if
+ * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */
+static void
+write_var_from_sym (orig_left_context, block, sym)
+     struct block* orig_left_context;
+     struct block* block;
+     struct symbol* sym;
+{
+  if (orig_left_context == NULL && symbol_read_needs_frame (sym))
+    {
+      if (innermost_block == 0 ||
+         contained_in (block, innermost_block))
+       innermost_block = block;
+    }
+
+  write_exp_elt_opcode (OP_VAR_VALUE);
+  /* We want to use the selected frame, not another more inner frame
+     which happens to be in the same block */
+  write_exp_elt_block (NULL);
+  write_exp_elt_sym (sym);
+  write_exp_elt_opcode (OP_VAR_VALUE);
+}
+
+/* Emit expression to access an instance of NAME. */
+static void
+write_var_from_name (orig_left_context, name)
+     struct block* orig_left_context;
+     struct name_info name;
+{
+  if (name.msym != NULL)
+    {
+      write_exp_msymbol (name.msym, 
+                        lookup_function_type (builtin_type_int),
+                        builtin_type_int);
+    }
+  else if (name.sym == NULL) 
+    {
+      /* Multiple matches: record name and starting block for later 
+         resolution by ada_resolve. */
+      /*      write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+      /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */      
+      write_exp_elt_block (name.block);
+      /*      write_exp_elt_name (name.stoken.ptr); */
+      /* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */      
+      /*      write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+      /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */      
+    }
+  else
+    write_var_from_sym (orig_left_context, name.block, name.sym);
+}
+
+/* Write a call on parameterless attribute ATR.  */
+
+static void
+write_attribute_call0 (atr)
+     enum ada_attribute atr;
+{
+  /*  write_exp_elt_opcode (OP_ATTRIBUTE); */
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */      
+  write_exp_elt_longcst ((LONGEST) 0);
+  write_exp_elt_longcst ((LONGEST) atr);
+  /*  write_exp_elt_opcode (OP_ATTRIBUTE); */
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */      
+}
+
+/* Write a call on an attribute ATR with one constant integer
+ * parameter. */
+
+static void
+write_attribute_call1 (atr, arg)
+     enum ada_attribute atr;
+     LONGEST arg;
+{
+  write_exp_elt_opcode (OP_LONG);
+  write_exp_elt_type (builtin_type_int);
+  write_exp_elt_longcst (arg);
+  write_exp_elt_opcode (OP_LONG);
+  /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+  write_exp_elt_longcst ((LONGEST) 1);
+  write_exp_elt_longcst ((LONGEST) atr);
+  /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */        
+}  
+
+/* Write a call on an attribute ATR with N parameters, whose code must have
+ * been generated previously. */
+
+static void
+write_attribute_calln (atr, n)
+     enum ada_attribute atr;
+     int n;
+{
+  /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */      
+  write_exp_elt_longcst ((LONGEST) n);
+  write_exp_elt_longcst ((LONGEST) atr);
+  /*  write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */        
+}  
+
+/* Emit expression corresponding to the renamed object designated by 
+ * the type RENAMING, which must be the referent of an object renaming
+ * type, in the context of ORIG_LEFT_CONTEXT (?). */
+static void
+write_object_renaming (orig_left_context, renaming)
+     struct block* orig_left_context;
+     struct symbol* renaming;
+{
+  const char* qualification = SYMBOL_NAME (renaming);
+  const char* simple_tail;
+  const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0);
+  const char* suffix;
+  char* name;
+  struct symbol* sym;
+  enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
+
+  /* if orig_left_context is null, then use the currently selected
+     block, otherwise we might fail our symbol lookup below */
+  if (orig_left_context == NULL)
+    orig_left_context = get_selected_block (NULL);
+
+  for (simple_tail = qualification + strlen (qualification); 
+       simple_tail != qualification; simple_tail -= 1)
+    {
+      if (*simple_tail == '.')
+       {
+         simple_tail += 1;
+         break;
+       } 
+      else if (STREQN (simple_tail, "__", 2))
+       {
+         simple_tail += 2;
+         break;
+       }
+    }
+
+  suffix = strstr (expr, "___XE");
+  if (suffix == NULL)
+    goto BadEncoding;
+
+  name = (char*) xmalloc (suffix - expr + 1);
+  /*  add_name_string_cleanup (name); */
+  /* FIXME: add_name_string_cleanup should be defined in
+     parser-defs.h, implemented in parse.c */    
+  strncpy (name, expr, suffix-expr);
+  name[suffix-expr] = '\000';
+  sym = lookup_symbol (name, orig_left_context, VAR_NAMESPACE, 0, NULL);
+  /*  if (sym == NULL) 
+    error ("Could not find renamed variable: %s", ada_demangle (name));
+  */
+  /* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */  
+  write_var_from_sym (orig_left_context, block_found, sym);
+
+  suffix += 5;
+  slice_state = SIMPLE_INDEX;
+  while (*suffix == 'X') 
+    {
+      suffix += 1;
+
+      switch (*suffix) {
+      case 'L':
+       slice_state = LOWER_BOUND;
+      case 'S':
+       suffix += 1;
+       if (isdigit (*suffix)) 
+         {
+           char* next;
+           long val = strtol (suffix, &next, 10);
+           if (next == suffix) 
+             goto BadEncoding;
+           suffix = next;
+           write_exp_elt_opcode (OP_LONG);
+           write_exp_elt_type (builtin_type_ada_int);
+           write_exp_elt_longcst ((LONGEST) val);
+           write_exp_elt_opcode (OP_LONG);
+         } 
+       else
+         {
+           const char* end;
+           char* index_name;
+           int index_len;
+           struct symbol* index_sym;
+
+           end = strchr (suffix, 'X');
+           if (end == NULL) 
+             end = suffix + strlen (suffix);
+           
+           index_len = simple_tail - qualification + 2 + (suffix - end) + 1;
+           index_name = (char*) xmalloc (index_len);
+           memset (index_name, '\000', index_len);
+           /*      add_name_string_cleanup (index_name);*/
+           /* FIXME: add_name_string_cleanup should be defined in
+              parser-defs.h, implemented in parse.c */             
+           strncpy (index_name, qualification, simple_tail - qualification);
+           index_name[simple_tail - qualification] = '\000';
+           strncat (index_name, suffix, suffix-end);
+           suffix = end;
+
+           index_sym = 
+             lookup_symbol (index_name, NULL, VAR_NAMESPACE, 0, NULL);
+           if (index_sym == NULL)
+             error ("Could not find %s", index_name);
+           write_var_from_sym (NULL, block_found, sym);
+         }
+       if (slice_state == SIMPLE_INDEX)
+         { 
+           write_exp_elt_opcode (OP_FUNCALL);
+           write_exp_elt_longcst ((LONGEST) 1);
+           write_exp_elt_opcode (OP_FUNCALL);
+         }
+       else if (slice_state == LOWER_BOUND)
+         slice_state = UPPER_BOUND;
+       else if (slice_state == UPPER_BOUND)
+         {
+           write_exp_elt_opcode (TERNOP_SLICE);
+           slice_state = SIMPLE_INDEX;
+         }
+       break;
+
+      case 'R':
+       {
+         struct stoken field_name;
+         const char* end;
+         suffix += 1;
+         
+         if (slice_state != SIMPLE_INDEX)
+           goto BadEncoding;
+         end = strchr (suffix, 'X');
+         if (end == NULL) 
+           end = suffix + strlen (suffix);
+         field_name.length = end - suffix;
+         field_name.ptr = (char*) xmalloc (end - suffix + 1);
+         strncpy (field_name.ptr, suffix, end - suffix);
+         field_name.ptr[end - suffix] = '\000';
+         suffix = end;
+         write_exp_elt_opcode (STRUCTOP_STRUCT);
+         write_exp_string (field_name);
+         write_exp_elt_opcode (STRUCTOP_STRUCT);         
+         break;
+       }
+         
+      default:
+       goto BadEncoding;
+      }
+    }
+  if (slice_state == SIMPLE_INDEX)
+    return;
+
+ BadEncoding:
+  error ("Internal error in encoding of renaming declaration: %s",
+        SYMBOL_NAME (renaming));
+}
+
+/* Convert the character literal whose ASCII value would be VAL to the
+   appropriate value of type TYPE, if there is a translation.
+   Otherwise return VAL.  Hence, in an enumeration type ('A', 'B'), 
+   the literal 'A' (VAL == 65), returns 0. */
+static LONGEST
+convert_char_literal (struct type* type, LONGEST val)
+{
+  char name[7];
+  int f;
+
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM)
+    return val;
+  sprintf (name, "QU%02x", (int) val);
+  for (f = 0; f < TYPE_NFIELDS (type); f += 1) 
+    {
+      if (STREQ (name, TYPE_FIELD_NAME (type, f)))
+       return TYPE_FIELD_BITPOS (type, f);
+    }
+  return val;
+}
diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
new file mode 100644 (file)
index 0000000..7d46dd2
--- /dev/null
@@ -0,0 +1,962 @@
+/* YACC parser for Ada expressions, for GDB.
+   Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994, 1997, 2000
+   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* Parse an Ada expression from text in a string,
+   and return the result as a  struct expression  pointer.
+   That structure contains arithmetic operations in reverse polish,
+   with constants represented by operations that are followed by special data.
+   See expression.h for the details of the format.
+   What is important here is that it can be built up sequentially
+   during the process of parsing; the lower levels of the tree always
+   come first in the result.
+
+   malloc's and realloc's in this file are transformed to
+   xmalloc and xrealloc respectively by the same sed command in the
+   makefile that remaps any other malloc/realloc inserted by the parser
+   generator.  Doing this with #defines and trying to control the interaction
+   with include files (<malloc.h> and <stdlib.h> for example) just became
+   too messy, particularly when such includes can be inserted at random
+   times by the parser generator.  */
+   
+%{
+
+#include "defs.h"
+#include <string.h>
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "ada-lang.h"
+#include "bfd.h" /* Required by objfiles.h.  */
+#include "symfile.h" /* Required by objfiles.h.  */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "frame.h"
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in gdb.  These are only the variables
+   produced by yacc.  If other parser generators (bison, byacc, etc) produce
+   additional global names that conflict at link time, then those parser
+   generators need to be fixed instead of adding those names to this list. */
+
+/* NOTE: This is clumsy, especially since BISON and FLEX provide --prefix  
+   options.  I presume we are maintaining it to accommodate systems
+   without BISON?  (PNH) */
+
+#define        yymaxdepth ada_maxdepth
+#define        yyparse _ada_parse      /* ada_parse calls this after  initialization */
+#define        yylex   ada_lex
+#define        yyerror ada_error
+#define        yylval  ada_lval
+#define        yychar  ada_char
+#define        yydebug ada_debug
+#define        yypact  ada_pact        
+#define        yyr1    ada_r1                  
+#define        yyr2    ada_r2                  
+#define        yydef   ada_def         
+#define        yychk   ada_chk         
+#define        yypgo   ada_pgo         
+#define        yyact   ada_act         
+#define        yyexca  ada_exca
+#define yyerrflag ada_errflag
+#define yynerrs        ada_nerrs
+#define        yyps    ada_ps
+#define        yypv    ada_pv
+#define        yys     ada_s
+#define        yy_yys  ada_yys
+#define        yystate ada_state
+#define        yytmp   ada_tmp
+#define        yyv     ada_v
+#define        yy_yyv  ada_yyv
+#define        yyval   ada_val
+#define        yylloc  ada_lloc
+#define yyreds ada_reds                /* With YYDEBUG defined */
+#define yytoks ada_toks                /* With YYDEBUG defined */
+
+#ifndef YYDEBUG
+#define        YYDEBUG 0               /* Default to no yydebug support */
+#endif
+
+struct name_info {
+  struct symbol* sym;
+  struct minimal_symbol* msym;
+  struct block* block;
+  struct stoken stoken;
+};
+
+/* If expression is in the context of TYPE'(...), then TYPE, else
+ * NULL. */
+static struct type* type_qualifier;
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+static struct stoken string_to_operator (struct stoken);
+
+static void write_attribute_call0 (enum ada_attribute);
+
+static void write_attribute_call1 (enum ada_attribute, LONGEST);
+
+static void write_attribute_calln (enum ada_attribute, int);
+
+static void write_object_renaming (struct block*, struct symbol*);
+
+static void write_var_from_name (struct block*, struct name_info);
+
+static LONGEST
+convert_char_literal (struct type*, LONGEST);
+%} 
+
+%union
+  {
+    LONGEST lval;
+    struct {
+      LONGEST val;
+      struct type *type;
+    } typed_val;
+    struct {
+      DOUBLEST dval;
+      struct type *type;
+    } typed_val_float;
+    struct type *tval;
+    struct stoken sval;
+    struct name_info ssym;
+    int voidval;
+    struct block *bval;
+    struct internalvar *ivar;
+
+  }
+
+%type <voidval> exp exp1 simple_exp start variable
+%type <tval> type
+
+%token <typed_val> INT NULL_PTR CHARLIT
+%token <typed_val_float> FLOAT
+%token <tval> TYPENAME
+%token <bval> BLOCKNAME
+
+/* Both NAME and TYPENAME tokens represent symbols in the input,
+   and both convey their data as strings.
+   But a TYPENAME is a string that happens to be defined as a typedef
+   or builtin type name (such as int or char)
+   and a NAME is any other symbol.
+   Contexts where this distinction is not important can use the
+   nonterminal "name", which matches either NAME or TYPENAME.  */
+
+%token <sval> STRING 
+%token <ssym> NAME DOT_ID OBJECT_RENAMING
+%type <bval> block 
+%type <lval> arglist tick_arglist
+
+%type <tval> save_qualifier
+
+%token DOT_ALL
+
+/* Special type cases, put in to allow the parser to distinguish different
+   legal basetypes.  */
+%token <lval> LAST REGNAME
+
+%token <ivar> INTERNAL_VARIABLE
+
+%nonassoc ASSIGN
+%left _AND_ OR XOR THEN ELSE
+%left '=' NOTEQUAL '<' '>' LEQ GEQ IN DOTDOT
+%left '@'
+%left '+' '-' '&'
+%left UNARY
+%left '*' '/' MOD REM
+%right STARSTAR ABS NOT
+ /* The following are right-associative only so that reductions at this 
+    precedence have lower precedence than '.' and '('. The syntax still 
+    forces a.b.c, e.g., to be LEFT-associated. */
+%right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH
+%right TICK_MAX TICK_MIN TICK_MODULUS
+%right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL
+%right '.' '(' '[' DOT_ID DOT_ALL
+
+%token ARROW NEW
+
+\f
+%%
+
+start   :      exp1
+       |       type    { write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type ($1);
+                         write_exp_elt_opcode (OP_TYPE); }
+       ;
+
+/* Expressions, including the sequencing operator.  */
+exp1   :       exp
+       |       exp1 ';' exp
+                       { write_exp_elt_opcode (BINOP_COMMA); }
+       ;
+
+/* Expressions, not including the sequencing operator.  */
+simple_exp :   simple_exp DOT_ALL
+                       { write_exp_elt_opcode (UNOP_IND); }
+       ;
+
+simple_exp :   simple_exp DOT_ID
+                       { write_exp_elt_opcode (STRUCTOP_STRUCT);
+                         write_exp_string ($2.stoken);
+                         write_exp_elt_opcode (STRUCTOP_STRUCT); 
+                         }
+       ;
+
+simple_exp :   simple_exp '(' arglist ')'
+                       {
+                         write_exp_elt_opcode (OP_FUNCALL);
+                         write_exp_elt_longcst ($3);
+                         write_exp_elt_opcode (OP_FUNCALL);
+                       }
+       ;
+
+simple_exp :   type '(' exp ')'
+                       {
+                         write_exp_elt_opcode (UNOP_CAST);
+                         write_exp_elt_type ($1);
+                         write_exp_elt_opcode (UNOP_CAST); 
+                       }
+       ;
+
+simple_exp :   type '\'' save_qualifier { type_qualifier = $1; } '(' exp ')'
+                       {
+                         /*                      write_exp_elt_opcode (UNOP_QUAL); */
+                         /* FIXME: UNOP_QUAL should be defined in expression.h */
+                         write_exp_elt_type ($1);
+                         /* write_exp_elt_opcode (UNOP_QUAL); */
+                         /* FIXME: UNOP_QUAL should be defined in expression.h */
+                         type_qualifier = $3;
+                       }
+       ;
+
+save_qualifier :       { $$ = type_qualifier; }
+
+simple_exp :
+               simple_exp '(' exp DOTDOT exp ')'
+                       { write_exp_elt_opcode (TERNOP_SLICE); }
+       ;
+
+simple_exp :   '(' exp1 ')'    { }
+       ;
+
+simple_exp :   variable        
+       ;
+
+simple_exp:    REGNAME /* GDB extension */
+                       { write_exp_elt_opcode (OP_REGISTER);
+                         write_exp_elt_longcst ((LONGEST) $1);
+                         write_exp_elt_opcode (OP_REGISTER); 
+                       }
+       ;
+
+simple_exp:    INTERNAL_VARIABLE /* GDB extension */
+                       { write_exp_elt_opcode (OP_INTERNALVAR);
+                         write_exp_elt_intern ($1);
+                         write_exp_elt_opcode (OP_INTERNALVAR); 
+                       }
+       ;
+
+
+exp    :       simple_exp
+       ;
+
+simple_exp:    LAST
+                       { write_exp_elt_opcode (OP_LAST);
+                         write_exp_elt_longcst ((LONGEST) $1);
+                         write_exp_elt_opcode (OP_LAST); 
+                        }
+       ;
+
+exp    :       exp ASSIGN exp   /* Extension for convenience */
+                       { write_exp_elt_opcode (BINOP_ASSIGN); }
+       ;
+
+exp    :       '-' exp    %prec UNARY
+                       { write_exp_elt_opcode (UNOP_NEG); }
+       ;
+
+exp    :       '+' exp    %prec UNARY
+                       { write_exp_elt_opcode (UNOP_PLUS); }
+       ;
+
+exp     :      NOT exp    %prec UNARY
+                       { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+       ;
+
+exp    :       ABS exp    %prec UNARY
+                       { write_exp_elt_opcode (UNOP_ABS); }
+       ;
+
+arglist        :               { $$ = 0; }
+       ;
+
+arglist        :       exp
+                       { $$ = 1; }
+       |       any_name ARROW exp
+                       { $$ = 1; }
+       |       arglist ',' exp
+                       { $$ = $1 + 1; }
+       |       arglist ',' any_name ARROW exp
+                       { $$ = $1 + 1; }
+       ;
+
+exp    :       '{' type '}' exp  %prec '.'
+               /* GDB extension */
+                       { write_exp_elt_opcode (UNOP_MEMVAL);
+                         write_exp_elt_type ($2);
+                         write_exp_elt_opcode (UNOP_MEMVAL); 
+                       }
+       ;
+
+/* Binary operators in order of decreasing precedence.  */
+
+exp    :       exp STARSTAR exp
+                       { write_exp_elt_opcode (BINOP_EXP); }
+       ;
+
+exp    :       exp '*' exp
+                       { write_exp_elt_opcode (BINOP_MUL); }
+       ;
+
+exp    :       exp '/' exp
+                       { write_exp_elt_opcode (BINOP_DIV); }
+       ;
+
+exp    :       exp REM exp /* May need to be fixed to give correct Ada REM */
+                       { write_exp_elt_opcode (BINOP_REM); }
+       ;
+
+exp    :       exp MOD exp
+                       { write_exp_elt_opcode (BINOP_MOD); }
+       ;
+
+exp    :       exp '@' exp     /* GDB extension */
+                       { write_exp_elt_opcode (BINOP_REPEAT); }
+       ;
+
+exp    :       exp '+' exp
+                       { write_exp_elt_opcode (BINOP_ADD); }
+       ;
+
+exp    :       exp '&' exp
+                       { write_exp_elt_opcode (BINOP_CONCAT); }
+       ;
+
+exp    :       exp '-' exp
+                       { write_exp_elt_opcode (BINOP_SUB); }
+       ;
+
+exp    :       exp '=' exp
+                       { write_exp_elt_opcode (BINOP_EQUAL); }
+       ;
+
+exp    :       exp NOTEQUAL exp
+                       { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+       ;
+
+exp    :       exp LEQ exp
+                       { write_exp_elt_opcode (BINOP_LEQ); }
+       ;
+
+exp    :       exp IN exp DOTDOT exp
+                        { /*write_exp_elt_opcode (TERNOP_MBR); */ }
+                          /* FIXME: TERNOP_MBR should be defined in
+                            expression.h */
+        |       exp IN exp TICK_RANGE tick_arglist
+                        { /*write_exp_elt_opcode (BINOP_MBR); */
+                         /* FIXME: BINOP_MBR should be defined in expression.h */
+                         write_exp_elt_longcst ((LONGEST) $5);
+                         /*write_exp_elt_opcode (BINOP_MBR); */
+                       }
+       |       exp IN TYPENAME         %prec TICK_ACCESS
+                        { /*write_exp_elt_opcode (UNOP_MBR); */
+                         /* FIXME: UNOP_QUAL should be defined in expression.h */                        
+                         write_exp_elt_type ($3);
+                         /*                      write_exp_elt_opcode (UNOP_MBR); */
+                         /* FIXME: UNOP_MBR should be defined in expression.h */                         
+                       }
+       |       exp NOT IN exp DOTDOT exp
+                        { /*write_exp_elt_opcode (TERNOP_MBR); */
+                         /* FIXME: TERNOP_MBR should be defined in expression.h */                                               
+                         write_exp_elt_opcode (UNOP_LOGICAL_NOT); 
+                       }
+        |       exp NOT IN exp TICK_RANGE tick_arglist
+                        { /* write_exp_elt_opcode (BINOP_MBR); */
+                         /* FIXME: BINOP_MBR should be defined in expression.h */
+                         write_exp_elt_longcst ((LONGEST) $6);
+                         /*write_exp_elt_opcode (BINOP_MBR);*/
+                         /* FIXME: BINOP_MBR should be defined in expression.h */                        
+                         write_exp_elt_opcode (UNOP_LOGICAL_NOT); 
+                       }
+       |       exp NOT IN TYPENAME     %prec TICK_ACCESS
+                        { /*write_exp_elt_opcode (UNOP_MBR);*/
+                         /* FIXME: UNOP_MBR should be defined in expression.h */                         
+                         write_exp_elt_type ($4);
+                         /*                      write_exp_elt_opcode (UNOP_MBR);*/
+                         /* FIXME: UNOP_MBR should be defined in expression.h */                                                 
+                         write_exp_elt_opcode (UNOP_LOGICAL_NOT); 
+                       }
+       ;
+
+exp    :       exp GEQ exp
+                       { write_exp_elt_opcode (BINOP_GEQ); }
+       ;
+
+exp    :       exp '<' exp
+                       { write_exp_elt_opcode (BINOP_LESS); }
+       ;
+
+exp    :       exp '>' exp
+                       { write_exp_elt_opcode (BINOP_GTR); }
+       ;
+
+exp     :      exp _AND_ exp  /* Fix for Ada elementwise AND. */
+                       { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+        ;
+
+exp     :       exp _AND_ THEN exp     %prec _AND_
+                       { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+        ;
+
+exp     :      exp OR exp     /* Fix for Ada elementwise OR */
+                       { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+        ;
+
+exp     :       exp OR ELSE exp        
+                       { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+        ;
+
+exp     :       exp XOR exp    /* Fix for Ada elementwise XOR */
+                       { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+        ;
+
+simple_exp :   simple_exp TICK_ACCESS
+                       { write_exp_elt_opcode (UNOP_ADDR); }
+       |       simple_exp TICK_ADDRESS
+                       { write_exp_elt_opcode (UNOP_ADDR);
+                         write_exp_elt_opcode (UNOP_CAST);
+                         write_exp_elt_type (builtin_type_ada_system_address);
+                         write_exp_elt_opcode (UNOP_CAST);
+                       }
+       |       simple_exp TICK_FIRST tick_arglist
+                       { write_attribute_call1 (ATR_FIRST, $3); }
+       |       simple_exp TICK_LAST tick_arglist
+                       { write_attribute_call1 (ATR_LAST, $3); }
+       |       simple_exp TICK_LENGTH tick_arglist
+                       { write_attribute_call1 (ATR_LENGTH, $3); }
+        |       simple_exp TICK_SIZE 
+                       { write_attribute_call0 (ATR_SIZE); }
+       |       simple_exp TICK_TAG
+                       { write_attribute_call0 (ATR_TAG); }
+        |       opt_type_prefix TICK_MIN '(' exp ',' exp ')'
+                       { write_attribute_calln (ATR_MIN, 2); }
+        |       opt_type_prefix TICK_MAX '(' exp ',' exp ')'
+                       { write_attribute_calln (ATR_MAX, 2); }
+       |       opt_type_prefix TICK_POS '(' exp ')'
+                       { write_attribute_calln (ATR_POS, 1); }
+       |       type_prefix TICK_FIRST tick_arglist
+                       { write_attribute_call1 (ATR_FIRST, $3); }
+       |       type_prefix TICK_LAST tick_arglist
+                       { write_attribute_call1 (ATR_LAST, $3); }
+       |       type_prefix TICK_LENGTH tick_arglist
+                       { write_attribute_call1 (ATR_LENGTH, $3); }
+       |       type_prefix TICK_VAL '(' exp ')'
+                       { write_attribute_calln (ATR_VAL, 1); }
+       |       type_prefix TICK_MODULUS 
+                       { write_attribute_call0 (ATR_MODULUS); }
+       ;
+
+tick_arglist :                 %prec '('
+                       { $$ = 1; }
+       |       '(' INT ')'
+                       { $$ = $2.val; }
+       ;
+
+type_prefix :
+               TYPENAME
+                       { write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type ($1);
+                         write_exp_elt_opcode (OP_TYPE); }
+       ;
+
+opt_type_prefix :
+               type_prefix
+       |       /* EMPTY */     
+                       { write_exp_elt_opcode (OP_TYPE);
+                         write_exp_elt_type (builtin_type_void);
+                         write_exp_elt_opcode (OP_TYPE); }
+       ;
+               
+
+exp    :       INT
+                       { write_exp_elt_opcode (OP_LONG);
+                         write_exp_elt_type ($1.type);
+                         write_exp_elt_longcst ((LONGEST)($1.val));
+                         write_exp_elt_opcode (OP_LONG); 
+                       }
+       ;
+
+exp    :       CHARLIT
+                       { write_exp_elt_opcode (OP_LONG);
+                         if (type_qualifier == NULL) 
+                           write_exp_elt_type ($1.type);
+                         else
+                           write_exp_elt_type (type_qualifier);
+                         write_exp_elt_longcst 
+                           (convert_char_literal (type_qualifier, $1.val));
+                         write_exp_elt_opcode (OP_LONG); 
+                       }
+
+                             
+exp    :       FLOAT
+                       { write_exp_elt_opcode (OP_DOUBLE);
+                         write_exp_elt_type ($1.type);
+                         write_exp_elt_dblcst ($1.dval);
+                         write_exp_elt_opcode (OP_DOUBLE); 
+                       }
+       ;
+
+exp    :       NULL_PTR
+                       { write_exp_elt_opcode (OP_LONG);
+                         write_exp_elt_type (builtin_type_int);
+                         write_exp_elt_longcst ((LONGEST)(0));
+                         write_exp_elt_opcode (OP_LONG); 
+                        }
+
+exp    :       STRING
+                       { /* Ada strings are converted into array constants 
+                            a lower bound of 1.  Thus, the array upper bound 
+                            is the string length. */
+                         char *sp = $1.ptr; int count;
+                         if ($1.length == 0) 
+                           { /* One dummy character for the type */
+                             write_exp_elt_opcode (OP_LONG);
+                             write_exp_elt_type (builtin_type_ada_char);
+                             write_exp_elt_longcst ((LONGEST)(0));
+                             write_exp_elt_opcode (OP_LONG);
+                           }
+                         for (count = $1.length; count > 0; count -= 1)
+                           {
+                             write_exp_elt_opcode (OP_LONG);
+                             write_exp_elt_type (builtin_type_ada_char);
+                             write_exp_elt_longcst ((LONGEST)(*sp));
+                             sp += 1;
+                             write_exp_elt_opcode (OP_LONG);
+                           }
+                         write_exp_elt_opcode (OP_ARRAY);
+                         write_exp_elt_longcst ((LONGEST) 1);
+                         write_exp_elt_longcst ((LONGEST) ($1.length));
+                         write_exp_elt_opcode (OP_ARRAY); 
+                        }
+       ;
+
+exp    :       NEW TYPENAME
+                       { error ("NEW not implemented."); }
+       ;
+
+variable:      NAME            { write_var_from_name (NULL, $1); }
+       |       block NAME      /* GDB extension */
+                                { write_var_from_name ($1, $2); }
+       |       OBJECT_RENAMING { write_object_renaming (NULL, $1.sym); }
+       |       block OBJECT_RENAMING 
+                               { write_object_renaming ($1, $2.sym); }
+       ;
+
+any_name :     NAME            { }
+        |       TYPENAME       { }
+        |       OBJECT_RENAMING        { }
+        ;
+
+block  :       BLOCKNAME  /* GDB extension */
+                       { $$ = $1; }
+       |       block BLOCKNAME /* GDB extension */
+                       { $$ = $2; }
+       ;
+
+
+type   :       TYPENAME        { $$ = $1; }
+       |       block TYPENAME  { $$ = $2; }
+       |       TYPENAME TICK_ACCESS 
+                               { $$ = lookup_pointer_type ($1); }
+       |       block TYPENAME TICK_ACCESS
+                               { $$ = lookup_pointer_type ($2); }
+        ;
+
+/* Some extensions borrowed from C, for the benefit of those who find they
+   can't get used to Ada notation in GDB. */
+
+exp    :       '*' exp         %prec '.'
+                       { write_exp_elt_opcode (UNOP_IND); }
+       |       '&' exp         %prec '.'
+                       { write_exp_elt_opcode (UNOP_ADDR); }
+       |       exp '[' exp ']'
+                       { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+       ;
+
+%%
+
+/* yylex defined in ada-lex.c: Reads one token, getting characters */
+/* through lexptr.  */
+
+/* Remap normal flex interface names (yylex) as well as gratuitiously */
+/* global symbol names, so we can have multiple flex-generated parsers */
+/* in gdb.  */
+
+/* (See note above on previous definitions for YACC.) */
+
+#define yy_create_buffer ada_yy_create_buffer
+#define yy_delete_buffer ada_yy_delete_buffer
+#define yy_init_buffer ada_yy_init_buffer
+#define yy_load_buffer_state ada_yy_load_buffer_state
+#define yy_switch_to_buffer ada_yy_switch_to_buffer
+#define yyrestart ada_yyrestart
+#define yytext ada_yytext
+#define yywrap ada_yywrap
+
+/* The following kludge was found necessary to prevent conflicts between */
+/* defs.h and non-standard stdlib.h files.  */
+#define qsort __qsort__dummy
+#include "ada-lex.c"
+
+int
+ada_parse ()
+{
+  lexer_init (yyin);           /* (Re-)initialize lexer. */
+  left_block_context = NULL;
+  type_qualifier = NULL;
+  
+  return _ada_parse ();
+}
+
+void
+yyerror (msg)
+     char *msg;
+{
+  error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
+
+/* The operator name corresponding to operator symbol STRING (adds 
+   quotes and maps to lower-case).  Destroys the previous contents of
+   the array pointed to by STRING.ptr.  Error if STRING does not match
+   a valid Ada operator.  Assumes that STRING.ptr points to a
+   null-terminated string and that, if STRING is a valid operator
+   symbol, the array pointed to by STRING.ptr contains at least
+   STRING.length+3 characters. */ 
+
+static struct stoken
+string_to_operator (string)
+     struct stoken string;
+{
+  int i;
+
+  for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+    {
+      if (string.length == strlen (ada_opname_table[i].demangled)-2
+         && strncasecmp (string.ptr, ada_opname_table[i].demangled+1,
+                         string.length) == 0)
+       {
+         strncpy (string.ptr, ada_opname_table[i].demangled,
+                  string.length+2);
+         string.length += 2;
+         return string;
+       }
+    }
+  error ("Invalid operator symbol `%s'", string.ptr);
+}
+
+/* Emit expression to access an instance of SYM, in block BLOCK (if
+ * non-NULL), and with :: qualification ORIG_LEFT_CONTEXT. */
+static void
+write_var_from_sym (orig_left_context, block, sym)
+     struct block* orig_left_context;
+     struct block* block;
+     struct symbol* sym;
+{
+  if (orig_left_context == NULL && symbol_read_needs_frame (sym))
+    {
+      if (innermost_block == 0 ||
+         contained_in (block, innermost_block))
+       innermost_block = block;
+    }
+
+  write_exp_elt_opcode (OP_VAR_VALUE);
+  /* We want to use the selected frame, not another more inner frame
+     which happens to be in the same block */
+  write_exp_elt_block (NULL);
+  write_exp_elt_sym (sym);
+  write_exp_elt_opcode (OP_VAR_VALUE);
+}
+
+/* Emit expression to access an instance of NAME. */
+static void
+write_var_from_name (orig_left_context, name)
+     struct block* orig_left_context;
+     struct name_info name;
+{
+  if (name.msym != NULL)
+    {
+      write_exp_msymbol (name.msym, 
+                        lookup_function_type (builtin_type_int),
+                        builtin_type_int);
+    }
+  else if (name.sym == NULL) 
+    {
+      /* Multiple matches: record name and starting block for later 
+         resolution by ada_resolve. */
+      /*      write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+      /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */      
+      write_exp_elt_block (name.block);
+      /*      write_exp_elt_name (name.stoken.ptr); */
+      /* FIXME: write_exp_elt_name should be defined in defs.h, located in parse.c */      
+      /*      write_exp_elt_opcode (OP_UNRESOLVED_VALUE); */
+      /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */      
+    }
+  else
+    write_var_from_sym (orig_left_context, name.block, name.sym);
+}
+
+/* Write a call on parameterless attribute ATR.  */
+
+static void
+write_attribute_call0 (atr)
+     enum ada_attribute atr;
+{
+  /*  write_exp_elt_opcode (OP_ATTRIBUTE); */
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */      
+  write_exp_elt_longcst ((LONGEST) 0);
+  write_exp_elt_longcst ((LONGEST) atr);
+  /*  write_exp_elt_opcode (OP_ATTRIBUTE); */
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */      
+}
+
+/* Write a call on an attribute ATR with one constant integer
+ * parameter. */
+
+static void
+write_attribute_call1 (atr, arg)
+     enum ada_attribute atr;
+     LONGEST arg;
+{
+  write_exp_elt_opcode (OP_LONG);
+  write_exp_elt_type (builtin_type_int);
+  write_exp_elt_longcst (arg);
+  write_exp_elt_opcode (OP_LONG);
+  /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+  write_exp_elt_longcst ((LONGEST) 1);
+  write_exp_elt_longcst ((LONGEST) atr);
+  /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */        
+}  
+
+/* Write a call on an attribute ATR with N parameters, whose code must have
+ * been generated previously. */
+
+static void
+write_attribute_calln (atr, n)
+     enum ada_attribute atr;
+     int n;
+{
+  /*write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */      
+  write_exp_elt_longcst ((LONGEST) n);
+  write_exp_elt_longcst ((LONGEST) atr);
+  /*  write_exp_elt_opcode (OP_ATTRIBUTE);*/
+  /* FIXME: OP_ATTRIBUTE should be defined in expression.h */        
+}  
+
+/* Emit expression corresponding to the renamed object designated by 
+ * the type RENAMING, which must be the referent of an object renaming
+ * type, in the context of ORIG_LEFT_CONTEXT (?). */
+static void
+write_object_renaming (orig_left_context, renaming)
+     struct block* orig_left_context;
+     struct symbol* renaming;
+{
+  const char* qualification = SYMBOL_NAME (renaming);
+  const char* simple_tail;
+  const char* expr = TYPE_FIELD_NAME (SYMBOL_TYPE (renaming), 0);
+  const char* suffix;
+  char* name;
+  struct symbol* sym;
+  enum { SIMPLE_INDEX, LOWER_BOUND, UPPER_BOUND } slice_state;
+
+  /* if orig_left_context is null, then use the currently selected
+     block, otherwise we might fail our symbol lookup below */
+  if (orig_left_context == NULL)
+    orig_left_context = get_selected_block (NULL);
+
+  for (simple_tail = qualification + strlen (qualification); 
+       simple_tail != qualification; simple_tail -= 1)
+    {
+      if (*simple_tail == '.')
+       {
+         simple_tail += 1;
+         break;
+       } 
+      else if (STREQN (simple_tail, "__", 2))
+       {
+         simple_tail += 2;
+         break;
+       }
+    }
+
+  suffix = strstr (expr, "___XE");
+  if (suffix == NULL)
+    goto BadEncoding;
+
+  name = (char*) malloc (suffix - expr + 1);
+  /*  add_name_string_cleanup (name); */
+  /* FIXME: add_name_string_cleanup should be defined in
+     parser-defs.h, implemented in parse.c */    
+  strncpy (name, expr, suffix-expr);
+  name[suffix-expr] = '\000';
+  sym = lookup_symbol (name, orig_left_context, VAR_NAMESPACE, 0, NULL);
+  /*  if (sym == NULL) 
+    error ("Could not find renamed variable: %s", ada_demangle (name));
+  */
+  /* FIXME: ada_demangle should be defined in defs.h, implemented in ada-lang.c */  
+  write_var_from_sym (orig_left_context, block_found, sym);
+
+  suffix += 5;
+  slice_state = SIMPLE_INDEX;
+  while (*suffix == 'X') 
+    {
+      suffix += 1;
+
+      switch (*suffix) {
+      case 'L':
+       slice_state = LOWER_BOUND;
+      case 'S':
+       suffix += 1;
+       if (isdigit (*suffix)) 
+         {
+           char* next;
+           long val = strtol (suffix, &next, 10);
+           if (next == suffix) 
+             goto BadEncoding;
+           suffix = next;
+           write_exp_elt_opcode (OP_LONG);
+           write_exp_elt_type (builtin_type_ada_int);
+           write_exp_elt_longcst ((LONGEST) val);
+           write_exp_elt_opcode (OP_LONG);
+         } 
+       else
+         {
+           const char* end;
+           char* index_name;
+           int index_len;
+           struct symbol* index_sym;
+
+           end = strchr (suffix, 'X');
+           if (end == NULL) 
+             end = suffix + strlen (suffix);
+           
+           index_len = simple_tail - qualification + 2 + (suffix - end) + 1;
+           index_name = (char*) malloc (index_len);
+           memset (index_name, '\000', index_len);
+           /*      add_name_string_cleanup (index_name);*/
+           /* FIXME: add_name_string_cleanup should be defined in
+              parser-defs.h, implemented in parse.c */             
+           strncpy (index_name, qualification, simple_tail - qualification);
+           index_name[simple_tail - qualification] = '\000';
+           strncat (index_name, suffix, suffix-end);
+           suffix = end;
+
+           index_sym = 
+             lookup_symbol (index_name, NULL, VAR_NAMESPACE, 0, NULL);
+           if (index_sym == NULL)
+             error ("Could not find %s", index_name);
+           write_var_from_sym (NULL, block_found, sym);
+         }
+       if (slice_state == SIMPLE_INDEX)
+         { 
+           write_exp_elt_opcode (OP_FUNCALL);
+           write_exp_elt_longcst ((LONGEST) 1);
+           write_exp_elt_opcode (OP_FUNCALL);
+         }
+       else if (slice_state == LOWER_BOUND)
+         slice_state = UPPER_BOUND;
+       else if (slice_state == UPPER_BOUND)
+         {
+           write_exp_elt_opcode (TERNOP_SLICE);
+           slice_state = SIMPLE_INDEX;
+         }
+       break;
+
+      case 'R':
+       {
+         struct stoken field_name;
+         const char* end;
+         suffix += 1;
+         
+         if (slice_state != SIMPLE_INDEX)
+           goto BadEncoding;
+         end = strchr (suffix, 'X');
+         if (end == NULL) 
+           end = suffix + strlen (suffix);
+         field_name.length = end - suffix;
+         field_name.ptr = (char*) malloc (end - suffix + 1);
+         strncpy (field_name.ptr, suffix, end - suffix);
+         field_name.ptr[end - suffix] = '\000';
+         suffix = end;
+         write_exp_elt_opcode (STRUCTOP_STRUCT);
+         write_exp_string (field_name);
+         write_exp_elt_opcode (STRUCTOP_STRUCT);         
+         break;
+       }
+         
+      default:
+       goto BadEncoding;
+      }
+    }
+  if (slice_state == SIMPLE_INDEX)
+    return;
+
+ BadEncoding:
+  error ("Internal error in encoding of renaming declaration: %s",
+        SYMBOL_NAME (renaming));
+}
+
+/* Convert the character literal whose ASCII value would be VAL to the
+   appropriate value of type TYPE, if there is a translation.
+   Otherwise return VAL.  Hence, in an enumeration type ('A', 'B'), 
+   the literal 'A' (VAL == 65), returns 0. */
+static LONGEST
+convert_char_literal (struct type* type, LONGEST val)
+{
+  char name[7];
+  int f;
+
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM)
+    return val;
+  sprintf (name, "QU%02x", (int) val);
+  for (f = 0; f < TYPE_NFIELDS (type); f += 1) 
+    {
+      if (STREQ (name, TYPE_FIELD_NAME (type, f)))
+       return TYPE_FIELD_BITPOS (type, f);
+    }
+  return val;
+}
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
new file mode 100644 (file)
index 0000000..2c4f1d9
--- /dev/null
@@ -0,0 +1,8626 @@
+/* Ada language support routines for GDB, the GNU debugger.  Copyright
+   1992, 1993, 1994, 1997, 1998, 1999, 2000 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include "demangle.h"
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "breakpoint.h"
+#include "gdbcore.h"
+#include "ada-lang.h"
+#ifdef UI_OUT
+#include "ui-out.h"
+#endif
+
+struct cleanup* unresolved_names;
+
+void extract_string (CORE_ADDR addr, char *buf);
+
+static struct type * ada_create_fundamental_type (struct objfile *, int);
+
+static void modify_general_field (char *, LONGEST, int, int);
+
+static struct type* desc_base_type (struct type*);
+
+static struct type* desc_bounds_type (struct type*);
+
+static struct value* desc_bounds (struct value*);
+
+static int fat_pntr_bounds_bitpos (struct type*);
+
+static int fat_pntr_bounds_bitsize (struct type*);
+
+static struct type* desc_data_type (struct type*);
+
+static struct value* desc_data (struct value*);
+
+static int fat_pntr_data_bitpos (struct type*);
+
+static int fat_pntr_data_bitsize (struct type*);
+
+static struct value* desc_one_bound (struct value*, int, int);
+
+static int desc_bound_bitpos (struct type*, int, int);
+
+static int desc_bound_bitsize (struct type*, int, int);
+
+static struct type*  desc_index_type (struct type*, int);
+
+static int desc_arity (struct type*);
+
+static int ada_type_match (struct type*, struct type*, int);
+
+static int ada_args_match (struct symbol*, struct value**, int);
+
+static struct value* place_on_stack (struct value*, CORE_ADDR*);
+
+static struct value* convert_actual (struct value*, struct type*, CORE_ADDR*);
+
+static struct value* make_array_descriptor (struct type*, struct value*, CORE_ADDR*);
+
+static void ada_add_block_symbols (struct block*, const char*,
+                                  namespace_enum, struct objfile*, int);
+
+static void fill_in_ada_prototype (struct symbol*);
+
+static int is_nonfunction (struct symbol**, int);
+
+static void add_defn_to_vec (struct symbol*, struct block*);
+
+static struct partial_symbol* 
+ada_lookup_partial_symbol (struct partial_symtab*, const char*, 
+                          int, namespace_enum, int);
+
+static struct symtab* symtab_for_sym (struct symbol*);
+
+static struct value* ada_resolve_subexp (struct expression**, int*, int, struct type*);
+
+static void replace_operator_with_call (struct expression**, int, int, int,
+                                       struct symbol*, struct block*);
+
+static int possible_user_operator_p (enum exp_opcode, struct value**);
+
+static const char* ada_op_name (enum exp_opcode);
+
+static int numeric_type_p (struct type*);
+
+static int integer_type_p (struct type*);
+
+static int scalar_type_p (struct type*);
+
+static int discrete_type_p (struct type*);
+
+static char* extended_canonical_line_spec (struct symtab_and_line, const char*);
+
+static struct value* evaluate_subexp (struct type*, struct expression*, int*, enum noside);
+
+static struct value* evaluate_subexp_type (struct expression*, int*);
+
+static struct type * ada_create_fundamental_type (struct objfile*, int);
+
+static int  is_dynamic_field (struct type *, int);
+
+static struct type*
+to_fixed_variant_branch_type (struct type*, char*, CORE_ADDR, struct value*);
+
+static struct type* to_fixed_range_type (char*, struct value*, struct objfile*);
+
+static struct type* to_static_fixed_type (struct type*);
+
+static struct value* unwrap_value (struct value*);
+
+static struct type* packed_array_type (struct type*, long*);
+
+static struct type* decode_packed_array_type (struct type*);
+
+static struct value* decode_packed_array (struct value*);
+
+static struct value* value_subscript_packed (struct value*, int, struct value**);
+
+static struct value* coerce_unspec_val_to_type (struct value*, long, struct type*);
+
+static struct value* get_var_value (char*, char*);
+
+static int lesseq_defined_than (struct symbol*, struct symbol*);
+
+static int equiv_types (struct type*, struct type*);
+
+static int is_name_suffix (const char*);
+
+static int wild_match (const char*, int, const char*);
+
+static struct symtabs_and_lines find_sal_from_funcs_and_line (const char*, int, struct symbol**, int);
+
+static int
+find_line_in_linetable (struct linetable*, int, struct symbol**, int, int*);
+
+static int find_next_line_in_linetable (struct linetable*, int, int, int);
+
+static struct symtabs_and_lines all_sals_for_line (const char*, int, char***);
+
+static void read_all_symtabs (const char*);
+
+static int is_plausible_func_for_line (struct symbol*, int);
+
+static struct value*  ada_coerce_ref (struct value*);
+
+static struct value* value_pos_atr (struct value*);
+
+static struct value* value_val_atr (struct type*, struct value*);
+
+static struct symbol* standard_lookup (const char*, namespace_enum);
+
+extern void markTimeStart (int index);
+extern void markTimeStop (int index);
+
+\f
+
+/* Maximum-sized dynamic type. */
+static unsigned int varsize_limit;
+
+static const char* ada_completer_word_break_characters =
+  " \t\n!@#$%^&*()+=|~`}{[]\";:?/,-";
+
+/* The name of the symbol to use to get the name of the main subprogram */
+#define ADA_MAIN_PROGRAM_SYMBOL_NAME "__gnat_ada_main_program_name"
+
+                               /* Utilities */
+
+/* extract_string
+ *
+ * read the string located at ADDR from the inferior and store the
+ * result into BUF
+ */
+void
+extract_string (CORE_ADDR addr, char *buf)
+{
+   int char_index = 0;
+
+   /* Loop, reading one byte at a time, until we reach the '\000' 
+      end-of-string marker */
+   do
+   {
+     target_read_memory (addr + char_index * sizeof (char), 
+                         buf + char_index * sizeof (char), 
+                         sizeof (char));
+     char_index++;
+   }
+   while (buf[char_index - 1] != '\000');
+}
+
+/* Assuming *OLD_VECT points to an array of *SIZE objects of size
+   ELEMENT_SIZE, grow it to contain at least MIN_SIZE objects,
+   updating *OLD_VECT and *SIZE as necessary. */
+
+void
+grow_vect (old_vect, size, min_size, element_size)
+     void** old_vect;
+     size_t* size;
+     size_t min_size;
+     int element_size;
+{
+  if (*size < min_size) {
+    *size *= 2;
+    if (*size < min_size)
+      *size = min_size;
+    *old_vect = xrealloc (*old_vect, *size * element_size);
+  }
+}
+
+/* True (non-zero) iff TARGET matches FIELD_NAME up to any trailing
+   suffix of FIELD_NAME beginning "___" */
+
+static int
+field_name_match (field_name, target)
+     const char *field_name;
+     const char *target;
+{
+  int len = strlen (target);
+  return 
+    STREQN (field_name, target, len) 
+    && (field_name[len] == '\0' 
+       || (STREQN (field_name + len, "___", 3)
+          && ! STREQ (field_name + strlen (field_name) - 6, "___XVN")));
+}
+
+
+/* The length of the prefix of NAME prior to any "___" suffix. */
+
+int
+ada_name_prefix_len (name)
+     const char* name;
+{
+  if (name == NULL)
+    return 0;
+  else 
+    {
+      const char* p = strstr (name, "___");
+      if (p == NULL)
+       return strlen (name);
+      else
+       return p - name;
+    }
+}
+
+/* SUFFIX is a suffix of STR. False if STR is null. */
+static int
+is_suffix (const char* str, const char* suffix)
+{
+  int len1, len2;
+  if (str == NULL)
+    return 0;
+  len1 = strlen (str);
+  len2 = strlen (suffix);
+  return (len1 >= len2 && STREQ (str + len1 - len2, suffix));
+}
+
+/* Create a value of type TYPE whose contents come from VALADDR, if it
+ * is non-null, and whose memory address (in the inferior) is
+ * ADDRESS. */
+struct value*
+value_from_contents_and_address (type, valaddr, address)
+     struct type* type;
+     char* valaddr;
+     CORE_ADDR address;
+{
+  struct value* v = allocate_value (type);
+  if (valaddr == NULL) 
+    VALUE_LAZY (v) = 1;
+  else
+    memcpy (VALUE_CONTENTS_RAW (v), valaddr, TYPE_LENGTH (type));
+  VALUE_ADDRESS (v) = address;
+  if (address != 0)
+    VALUE_LVAL (v) = lval_memory;
+  return v;
+}
+
+/* The contents of value VAL, beginning at offset OFFSET, treated as a
+   value of type TYPE.  The result is an lval in memory if VAL is. */
+
+static struct value*
+coerce_unspec_val_to_type (val, offset, type)
+     struct value* val;
+     long offset;
+     struct type *type;
+{
+  CHECK_TYPEDEF (type);
+  if (VALUE_LVAL (val) == lval_memory)
+    return value_at_lazy (type,
+      VALUE_ADDRESS (val) + VALUE_OFFSET (val) + offset, NULL);
+  else 
+    {
+      struct value* result = allocate_value (type);
+      VALUE_LVAL (result) = not_lval;
+      if (VALUE_ADDRESS (val) == 0) 
+       memcpy (VALUE_CONTENTS_RAW (result), VALUE_CONTENTS (val) + offset,
+               TYPE_LENGTH (type) > TYPE_LENGTH (VALUE_TYPE (val)) 
+               ? TYPE_LENGTH (VALUE_TYPE (val)) : TYPE_LENGTH (type));
+      else 
+       {
+         VALUE_ADDRESS (result) = 
+           VALUE_ADDRESS (val) + VALUE_OFFSET (val) + offset;
+         VALUE_LAZY (result) = 1;
+       }
+      return result;
+    }
+}
+
+static char*
+cond_offset_host (valaddr, offset)
+     char* valaddr;
+     long offset;
+{
+  if (valaddr == NULL)
+    return NULL;
+  else
+    return valaddr + offset;
+}
+
+static CORE_ADDR
+cond_offset_target (address, offset)
+     CORE_ADDR address;
+     long offset;
+{
+  if (address == 0)
+    return 0;
+  else 
+    return address + offset;
+}
+
+/* Perform execute_command on the result of concatenating all
+   arguments up to NULL. */
+static void
+do_command (const char* arg, ...)
+{
+  int len;
+  char* cmd;
+  const char* s;
+  va_list ap;
+
+  va_start (ap, arg);
+  len = 0;
+  s = arg;
+  cmd = "";
+  for (; s != NULL; s = va_arg (ap, const char*)) 
+    {
+      char* cmd1;
+      len += strlen (s);
+      cmd1 = alloca (len+1);
+      strcpy (cmd1, cmd);
+      strcat (cmd1, s);
+      cmd = cmd1;
+    }
+  va_end (ap);
+  execute_command (cmd, 0);
+}
+
+\f
+                               /* Language Selection */
+
+/* If the main program is in Ada, return language_ada, otherwise return LANG
+   (the main program is in Ada iif the adainit symbol is found).
+
+   MAIN_PST is not used. */
+   
+enum language
+ada_update_initial_language (lang, main_pst)
+     enum language lang;
+     struct partial_symtab* main_pst;
+{
+  if (lookup_minimal_symbol ("adainit", (const char*) NULL,
+                            (struct objfile*) NULL) != NULL)
+    /*    return language_ada; */
+    /* FIXME: language_ada should be defined in defs.h */
+    return language_unknown;
+
+  return lang;
+}
+      
+\f
+                               /* Symbols */
+
+/* Table of Ada operators and their GNAT-mangled names.  Last entry is pair 
+   of NULLs. */
+
+const struct ada_opname_map ada_opname_table[] =
+{
+  { "Oadd", "\"+\"", BINOP_ADD },
+  { "Osubtract", "\"-\"", BINOP_SUB },
+  { "Omultiply", "\"*\"", BINOP_MUL },
+  { "Odivide", "\"/\"", BINOP_DIV },
+  { "Omod", "\"mod\"", BINOP_MOD },
+  { "Orem", "\"rem\"", BINOP_REM },
+  { "Oexpon", "\"**\"", BINOP_EXP },
+  { "Olt", "\"<\"", BINOP_LESS },
+  { "Ole", "\"<=\"", BINOP_LEQ },
+  { "Ogt", "\">\"", BINOP_GTR },
+  { "Oge", "\">=\"", BINOP_GEQ },
+  { "Oeq", "\"=\"", BINOP_EQUAL },
+  { "One", "\"/=\"", BINOP_NOTEQUAL },
+  { "Oand", "\"and\"", BINOP_BITWISE_AND },
+  { "Oor", "\"or\"", BINOP_BITWISE_IOR },
+  { "Oxor", "\"xor\"", BINOP_BITWISE_XOR },
+  { "Oconcat", "\"&\"", BINOP_CONCAT },
+  { "Oabs", "\"abs\"", UNOP_ABS },
+  { "Onot", "\"not\"", UNOP_LOGICAL_NOT },
+  { "Oadd", "\"+\"", UNOP_PLUS },
+  { "Osubtract", "\"-\"", UNOP_NEG },
+  { NULL, NULL }
+};
+
+/* True if STR should be suppressed in info listings. */
+static int
+is_suppressed_name (str) 
+     const char* str;
+{
+  if (STREQN (str, "_ada_", 5))
+    str += 5;
+  if (str[0] == '_' || str[0] == '\000')
+    return 1;
+  else
+    {
+      const char* p;
+      const char* suffix = strstr (str, "___");
+      if (suffix != NULL && suffix[3] != 'X')
+       return 1;
+      if (suffix == NULL)
+       suffix = str + strlen (str);
+      for (p = suffix-1; p != str; p -= 1)
+       if (isupper (*p))
+         {
+           int i;
+           if (p[0] == 'X' && p[-1] != '_')
+             goto OK;
+           if (*p != 'O')
+             return 1;
+           for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+             if (STREQN (ada_opname_table[i].mangled, p, 
+                         strlen (ada_opname_table[i].mangled)))
+               goto OK;
+           return 1;
+         OK: ;
+         }
+      return 0;
+    }
+}
+
+/* The "mangled" form of DEMANGLED, according to GNAT conventions.
+ * The result is valid until the next call to ada_mangle. */
+char *
+ada_mangle (demangled)
+     const char* demangled;
+{
+  static char* mangling_buffer = NULL;
+  static size_t mangling_buffer_size = 0;
+  const char* p;
+  int k;
+  
+  if (demangled == NULL)
+    return NULL;
+
+  GROW_VECT (mangling_buffer, mangling_buffer_size, 2*strlen (demangled) + 10);
+
+  k = 0;
+  for (p = demangled; *p != '\0'; p += 1)
+    {
+      if (*p == '.') 
+       {
+         mangling_buffer[k] = mangling_buffer[k+1] = '_';
+         k += 2;
+       }
+      else if (*p == '"')
+       {
+         const struct ada_opname_map* mapping;
+
+         for (mapping = ada_opname_table;
+              mapping->mangled != NULL && 
+              ! STREQN (mapping->demangled, p, strlen (mapping->demangled));
+              p += 1)
+           ;
+         if (mapping->mangled == NULL)
+           error ("invalid Ada operator name: %s", p);
+         strcpy (mangling_buffer+k, mapping->mangled);
+         k += strlen (mapping->mangled);
+         break;
+       }
+      else 
+       {
+         mangling_buffer[k] = *p;
+         k += 1;
+       }
+    }
+
+  mangling_buffer[k] = '\0';
+  return mangling_buffer;
+}
+
+/* Return NAME folded to lower case, or, if surrounded by single
+ * quotes, unfolded, but with the quotes stripped away.  Result good
+ * to next call. */
+char*
+ada_fold_name (const char* name)
+{
+  static char* fold_buffer = NULL;
+  static size_t fold_buffer_size = 0;
+
+  int len = strlen (name);
+  GROW_VECT (fold_buffer, fold_buffer_size, len+1);
+
+  if (name[0] == '\'')
+    {
+      strncpy (fold_buffer, name+1, len-2);
+      fold_buffer[len-2] = '\000';
+    }
+  else
+    {
+      int i;
+      for (i = 0; i <= len; i += 1)
+       fold_buffer[i] = tolower (name[i]);
+    }
+
+  return fold_buffer;
+}
+
+/* Demangle: 
+     1. Discard final __{DIGIT}+ or ${DIGIT}+
+     2. Convert other instances of embedded "__" to `.'.
+     3. Discard leading _ada_.
+     4. Convert operator names to the appropriate quoted symbols.
+     5. Remove everything after first ___ if it is followed by 
+        'X'.
+     6. Replace TK__ with __, and a trailing B or TKB with nothing.
+     7. Put symbols that should be suppressed in <...> brackets.
+     8. Remove trailing X[bn]* suffix (indicating names in package bodies).
+   The resulting string is valid until the next call of ada_demangle.
+  */
+
+char *
+ada_demangle (mangled)
+     const char* mangled;
+{
+  int i, j;
+  int len0;
+  const char* p;
+  char* demangled;
+  int at_start_name;
+  static char* demangling_buffer = NULL;
+  static size_t demangling_buffer_size = 0;
+  
+  if (STREQN (mangled, "_ada_", 5))
+    mangled += 5;
+
+  if (mangled[0] == '_' || mangled[0] == '<')
+    goto Suppress;
+
+  p = strstr (mangled, "___");
+  if (p == NULL)
+    len0 = strlen (mangled);
+  else 
+    {
+      if (p[3] == 'X')
+       len0 = p - mangled;
+      else
+       goto Suppress;
+    }
+  if (len0 > 3 && STREQ (mangled + len0 - 3, "TKB"))
+    len0 -= 3;
+  if (len0 > 1 && STREQ (mangled + len0 - 1, "B"))
+    len0 -= 1;
+
+  /* Make demangled big enough for possible expansion by operator name. */
+  GROW_VECT (demangling_buffer, demangling_buffer_size, 2*len0+1);
+  demangled = demangling_buffer;
+
+  if (isdigit (mangled[len0 - 1])) {
+    for (i = len0-2; i >= 0 && isdigit (mangled[i]); i -= 1)
+      ;
+    if (i > 1 && mangled[i] == '_' && mangled[i-1] == '_')
+      len0 = i - 1;
+    else if (mangled[i] == '$')
+      len0 = i;
+  }
+
+  for (i = 0, j = 0; i < len0 && ! isalpha (mangled[i]); i += 1, j += 1)
+    demangled[j] = mangled[i];
+
+  at_start_name = 1;
+  while (i < len0)
+    {
+      if (at_start_name && mangled[i] == 'O')
+       {
+         int k;
+         for (k = 0; ada_opname_table[k].mangled != NULL; k += 1)
+           {
+             int op_len = strlen (ada_opname_table[k].mangled); 
+             if (STREQN (ada_opname_table[k].mangled+1, mangled+i+1, op_len-1)
+                 && ! isalnum (mangled[i + op_len]))
+               {
+                 strcpy (demangled + j, ada_opname_table[k].demangled);
+                 at_start_name = 0;
+                 i += op_len;
+                 j += strlen (ada_opname_table[k].demangled);
+                 break;
+               }
+           }
+         if (ada_opname_table[k].mangled != NULL)
+           continue;
+       }
+      at_start_name = 0;
+
+      if (i < len0-4 && STREQN (mangled+i, "TK__", 4))
+       i += 2;
+      if (mangled[i] == 'X' && i != 0 && isalnum (mangled[i-1]))
+       {
+         do
+           i += 1;
+         while (i < len0 && (mangled[i] == 'b' || mangled[i] == 'n'));
+         if (i < len0)
+           goto Suppress;
+       }
+      else if (i < len0-2 && mangled[i] == '_' && mangled[i+1] == '_') 
+       {
+         demangled[j] = '.';
+         at_start_name = 1;
+         i += 2; j += 1;
+       }
+      else
+       {
+         demangled[j] = mangled[i];
+         i += 1;  j += 1;
+       }
+    }
+  demangled[j] = '\000';
+
+  for (i = 0; demangled[i] != '\0'; i += 1)
+    if (isupper (demangled[i]) || demangled[i] == ' ')
+      goto Suppress;
+
+  return demangled;
+
+Suppress:
+  GROW_VECT (demangling_buffer, demangling_buffer_size, 
+            strlen (mangled) + 3);  
+  demangled = demangling_buffer;
+  if (mangled[0] == '<')
+    strcpy (demangled, mangled);
+  else
+    sprintf (demangled, "<%s>", mangled);
+  return demangled;
+
+}
+
+/* Returns non-zero iff SYM_NAME matches NAME, ignoring any trailing
+ * suffixes that encode debugging information or leading _ada_ on
+ * SYM_NAME (see is_name_suffix commentary for the debugging
+ * information that is ignored).  If WILD, then NAME need only match a
+ * suffix of SYM_NAME minus the same suffixes. Also returns 0 if
+ * either argument is NULL. */
+
+int
+ada_match_name (sym_name, name, wild)
+     const char* sym_name;
+     const char* name;
+     int wild;
+{
+  if (sym_name == NULL || name == NULL)
+    return 0;
+  else if (wild)
+    return wild_match (name, strlen (name), sym_name);
+  else {
+    int len_name = strlen (name);
+    return (STREQN (sym_name, name, len_name) 
+           && is_name_suffix (sym_name+len_name))
+      ||   (STREQN (sym_name, "_ada_", 5) 
+           && STREQN (sym_name+5, name, len_name)
+           && is_name_suffix (sym_name+len_name+5));
+  }
+}
+
+/* True (non-zero) iff in Ada mode, the symbol SYM should be
+   suppressed in info listings. */
+
+int
+ada_suppress_symbol_printing (sym)
+     struct symbol *sym;
+{
+  if (SYMBOL_NAMESPACE (sym) == STRUCT_NAMESPACE)
+    return 1;
+  else 
+    return is_suppressed_name (SYMBOL_NAME (sym));
+}
+
+\f
+                               /* Arrays */
+
+/* Names of MAX_ADA_DIMENS bounds in P_BOUNDS fields of 
+   array descriptors.  */
+
+static char* bound_name[] = {
+  "LB0", "UB0", "LB1", "UB1", "LB2", "UB2", "LB3", "UB3", 
+  "LB4", "UB4", "LB5", "UB5", "LB6", "UB6", "LB7", "UB7"
+};
+
+/* Maximum number of array dimensions we are prepared to handle.  */
+
+#define MAX_ADA_DIMENS (sizeof(bound_name) / (2*sizeof(char*)))
+
+/* Like modify_field, but allows bitpos > wordlength. */
+
+static void
+modify_general_field (addr, fieldval, bitpos, bitsize)
+     char *addr;
+     LONGEST fieldval;
+     int bitpos, bitsize;
+{
+  modify_field (addr + sizeof (LONGEST) * bitpos / (8 * sizeof (LONGEST)), 
+               fieldval, bitpos % (8 * sizeof (LONGEST)), 
+               bitsize);
+}
+
+
+/* The desc_* routines return primitive portions of array descriptors 
+   (fat pointers). */
+
+/* The descriptor or array type, if any, indicated by TYPE; removes
+   level of indirection, if needed. */
+static struct type*
+desc_base_type (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return NULL;
+  CHECK_TYPEDEF (type);
+  if (type != NULL && TYPE_CODE (type) == TYPE_CODE_PTR)
+    return check_typedef (TYPE_TARGET_TYPE (type));
+  else
+    return type;
+}
+
+/* True iff TYPE indicates a "thin" array pointer type. */
+static int
+is_thin_pntr (struct type* type)
+{
+  return 
+    is_suffix (ada_type_name (desc_base_type (type)), "___XUT")
+    || is_suffix (ada_type_name (desc_base_type (type)), "___XUT___XVE");
+}
+
+/* The descriptor type for thin pointer type TYPE. */
+static struct type*
+thin_descriptor_type (struct type* type)
+{
+  struct type* base_type = desc_base_type (type);
+  if (base_type == NULL)
+    return NULL;
+  if (is_suffix (ada_type_name (base_type), "___XVE"))
+    return base_type;
+  else 
+    {
+      struct type* alt_type = 
+       ada_find_parallel_type (base_type, "___XVE");
+      if (alt_type == NULL)
+       return base_type;
+      else
+       return alt_type;
+    }
+}
+
+/* A pointer to the array data for thin-pointer value VAL. */
+static struct value*
+thin_data_pntr (struct value* val)
+{
+  struct type* type = VALUE_TYPE (val);
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    return value_cast (desc_data_type (thin_descriptor_type (type)), 
+                      value_copy (val));
+  else 
+    return value_from_longest (desc_data_type (thin_descriptor_type (type)),
+                              VALUE_ADDRESS (val) + VALUE_OFFSET (val));
+}
+
+/* True iff TYPE indicates a "thick" array pointer type. */
+static int
+is_thick_pntr (struct type* type) 
+{
+  type = desc_base_type (type);
+  return (type != NULL && TYPE_CODE (type) == TYPE_CODE_STRUCT
+         && lookup_struct_elt_type (type, "P_BOUNDS", 1) != NULL);
+}
+
+/* If TYPE is the type of an array descriptor (fat or thin pointer) or a 
+   pointer to one, the type of its bounds data; otherwise, NULL. */
+static struct type*
+desc_bounds_type (type)
+     struct type* type;
+{
+  struct type* r;
+
+  type = desc_base_type (type);
+
+  if (type == NULL)
+    return NULL;
+  else if (is_thin_pntr (type))
+    {
+      type = thin_descriptor_type (type);
+      if (type == NULL)
+       return NULL;
+      r = lookup_struct_elt_type (type, "BOUNDS", 1);
+      if (r != NULL)
+       return check_typedef (r);
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    {
+      r = lookup_struct_elt_type (type, "P_BOUNDS", 1);
+      if (r != NULL)
+       return check_typedef (TYPE_TARGET_TYPE (check_typedef (r)));
+    }
+  return NULL;
+}
+
+/* If ARR is an array descriptor (fat or thin pointer), or pointer to
+   one, a pointer to its bounds data.   Otherwise NULL. */
+static struct value*
+desc_bounds (arr)
+     struct value* arr;
+{
+  struct type* type = check_typedef (VALUE_TYPE (arr));
+  if (is_thin_pntr (type)) 
+    {
+      struct type* bounds_type = desc_bounds_type (thin_descriptor_type (type));
+      LONGEST addr;
+
+      if (desc_bounds_type == NULL)
+       error ("Bad GNAT array descriptor");
+
+      /* NOTE: The following calculation is not really kosher, but
+        since desc_type is an XVE-encoded type (and shouldn't be),
+        the correct calculation is a real pain. FIXME (and fix GCC). */
+      if (TYPE_CODE (type) == TYPE_CODE_PTR)
+       addr = value_as_long (arr);
+      else 
+       addr = VALUE_ADDRESS (arr) + VALUE_OFFSET (arr);
+
+      return 
+         value_from_longest (lookup_pointer_type (bounds_type), 
+                             addr - TYPE_LENGTH (bounds_type));
+    }
+
+  else if (is_thick_pntr (type))
+    return value_struct_elt (&arr, NULL, "P_BOUNDS", NULL, 
+                            "Bad GNAT array descriptor");
+  else
+    return NULL;
+}
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+   position of the field containing the address of the bounds data. */
+static int
+fat_pntr_bounds_bitpos (type)
+     struct type* type;
+{
+  return TYPE_FIELD_BITPOS (desc_base_type (type), 1);
+}
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+   size of the field containing the address of the bounds data. */
+static int
+fat_pntr_bounds_bitsize (type)
+     struct type* type;
+{
+  type = desc_base_type (type);
+
+  if (TYPE_FIELD_BITSIZE (type, 1) > 0) 
+    return TYPE_FIELD_BITSIZE (type, 1);
+  else
+    return 8 * TYPE_LENGTH (check_typedef (TYPE_FIELD_TYPE (type, 1)));
+}
+
+/* If TYPE is the type of an array descriptor (fat or thin pointer) or a 
+   pointer to one, the type of its array data (a
+   pointer-to-array-with-no-bounds type); otherwise,  NULL.  Use
+   ada_type_of_array to get an array type with bounds data. */
+static struct type*
+desc_data_type (type)
+     struct type* type;
+{
+  type = desc_base_type (type);
+
+  /* NOTE: The following is bogus; see comment in desc_bounds. */
+  if (is_thin_pntr (type))
+    return lookup_pointer_type 
+      (desc_base_type (TYPE_FIELD_TYPE (thin_descriptor_type (type),1)));
+  else if (is_thick_pntr (type))
+    return lookup_struct_elt_type (type, "P_ARRAY", 1);
+  else
+    return NULL;
+}
+
+/* If ARR is an array descriptor (fat or thin pointer), a pointer to
+   its array data.  */
+static struct value*
+desc_data (arr)
+     struct value* arr;
+{
+  struct type* type = VALUE_TYPE (arr);
+  if (is_thin_pntr (type))
+    return thin_data_pntr (arr);
+  else if (is_thick_pntr (type))
+    return value_struct_elt (&arr, NULL, "P_ARRAY", NULL, 
+                            "Bad GNAT array descriptor");
+  else
+    return NULL;
+}
+
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+   position of the field containing the address of the data. */
+static int
+fat_pntr_data_bitpos (type)
+     struct type* type;
+{
+  return TYPE_FIELD_BITPOS (desc_base_type (type), 0);
+}
+
+/* If TYPE is the type of an array-descriptor (fat pointer), the bit
+   size of the field containing the address of the data. */
+static int
+fat_pntr_data_bitsize (type)
+     struct type* type;
+{
+  type = desc_base_type (type);
+
+  if (TYPE_FIELD_BITSIZE (type, 0) > 0)
+    return TYPE_FIELD_BITSIZE (type, 0);
+  else 
+    return TARGET_CHAR_BIT * TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0));
+}
+
+/* If BOUNDS is an array-bounds structure (or pointer to one), return 
+   the Ith lower bound stored in it, if WHICH is 0, and the Ith upper
+   bound, if WHICH is 1.  The first bound is I=1. */
+static struct value*
+desc_one_bound (bounds, i, which)
+     struct value* bounds;
+     int i;
+     int which;
+{
+  return value_struct_elt (&bounds, NULL, bound_name[2*i+which-2], NULL,
+                          "Bad GNAT array descriptor bounds");
+}
+
+/* If BOUNDS is an array-bounds structure type, return the bit position
+   of the Ith lower bound stored in it, if WHICH is 0, and the Ith upper
+   bound, if WHICH is 1.  The first bound is I=1. */
+static int
+desc_bound_bitpos (type, i, which)
+     struct type* type;
+     int i;
+     int which;
+{
+  return TYPE_FIELD_BITPOS (desc_base_type (type), 2*i+which-2);
+}
+
+/* If BOUNDS is an array-bounds structure type, return the bit field size
+   of the Ith lower bound stored in it, if WHICH is 0, and the Ith upper
+   bound, if WHICH is 1.  The first bound is I=1. */
+static int
+desc_bound_bitsize (type, i, which)
+     struct type* type;
+     int i;
+     int which;
+{
+  type = desc_base_type (type);
+
+  if (TYPE_FIELD_BITSIZE (type, 2*i+which-2) > 0)
+    return TYPE_FIELD_BITSIZE (type, 2*i+which-2);
+  else 
+    return 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, 2*i+which-2));
+}
+
+/* If TYPE is the type of an array-bounds structure, the type of its
+   Ith bound (numbering from 1). Otherwise, NULL. */ 
+static struct type* 
+desc_index_type (type, i)
+     struct type* type;
+     int i;
+{
+  type = desc_base_type (type);
+
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
+    return lookup_struct_elt_type (type, bound_name[2*i-2], 1);
+  else 
+    return NULL;
+}
+
+/* The number of index positions in the array-bounds type TYPE.  0
+   if TYPE is NULL. */
+static int
+desc_arity (type)
+     struct type* type;
+{
+  type = desc_base_type (type);
+
+  if (type != NULL)
+    return TYPE_NFIELDS (type) / 2;
+  return 0;
+}
+
+
+/* Non-zero iff type is a simple array type (or pointer to one). */
+int
+ada_is_simple_array (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return 0;
+  CHECK_TYPEDEF (type);
+  return (TYPE_CODE (type) == TYPE_CODE_ARRAY
+         || (TYPE_CODE (type) == TYPE_CODE_PTR
+             && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_ARRAY));
+}
+
+/* Non-zero iff type belongs to a GNAT array descriptor. */
+int
+ada_is_array_descriptor (type)
+     struct type* type;
+{
+  struct type* data_type = desc_data_type (type);
+
+  if (type == NULL)
+    return 0;
+  CHECK_TYPEDEF (type);
+  return 
+    data_type != NULL
+    && ((TYPE_CODE (data_type) == TYPE_CODE_PTR
+        && TYPE_TARGET_TYPE (data_type) != NULL
+        && TYPE_CODE (TYPE_TARGET_TYPE (data_type)) == TYPE_CODE_ARRAY)
+       || 
+       TYPE_CODE (data_type) == TYPE_CODE_ARRAY)
+    && desc_arity (desc_bounds_type (type)) > 0;
+}
+
+/* Non-zero iff type is a partially mal-formed GNAT array
+   descriptor.  (FIXME: This is to compensate for some problems with 
+   debugging output from GNAT.  Re-examine periodically to see if it
+   is still needed. */
+int
+ada_is_bogus_array_descriptor (type)
+     struct type *type;
+{
+  return 
+    type != NULL
+    && TYPE_CODE (type) == TYPE_CODE_STRUCT
+    && (lookup_struct_elt_type (type, "P_BOUNDS", 1) != NULL
+       || lookup_struct_elt_type (type, "P_ARRAY", 1) != NULL)
+    && ! ada_is_array_descriptor (type);
+}
+
+
+/* If ARR has a record type in the form of a standard GNAT array descriptor, 
+   (fat pointer) returns the type of the array data described---specifically,
+   a pointer-to-array type.  If BOUNDS is non-zero, the bounds data are filled 
+   in from the descriptor; otherwise, they are left unspecified.  If
+   the ARR denotes a null array descriptor and BOUNDS is non-zero, 
+   returns NULL.  The result is simply the type of ARR if ARR is not 
+   a descriptor.  */
+struct type*
+ada_type_of_array (arr, bounds)
+     struct value* arr;
+     int bounds;
+{
+  if (ada_is_packed_array_type (VALUE_TYPE (arr)))
+    return decode_packed_array_type (VALUE_TYPE (arr));
+
+  if (! ada_is_array_descriptor (VALUE_TYPE (arr)))
+    return VALUE_TYPE (arr);
+  
+  if (! bounds)
+    return check_typedef (TYPE_TARGET_TYPE (desc_data_type (VALUE_TYPE (arr))));
+  else
+    {
+      struct type* elt_type;
+      int arity;
+      struct value* descriptor;
+      struct objfile *objf = TYPE_OBJFILE (VALUE_TYPE (arr));
+
+      elt_type = ada_array_element_type (VALUE_TYPE (arr), -1);
+      arity = ada_array_arity (VALUE_TYPE (arr));
+
+      if (elt_type == NULL || arity == 0) 
+       return check_typedef (VALUE_TYPE (arr));
+
+      descriptor = desc_bounds (arr);
+      if (value_as_long (descriptor) == 0) 
+       return NULL;
+      while (arity > 0) {
+       struct type* range_type = alloc_type (objf);
+       struct type* array_type = alloc_type (objf);
+       struct value* low = desc_one_bound (descriptor, arity, 0);
+       struct value* high = desc_one_bound (descriptor, arity, 1);
+       arity -= 1;
+
+       create_range_type (range_type, VALUE_TYPE (low), 
+                          (int) value_as_long (low), 
+                          (int) value_as_long (high));
+       elt_type = create_array_type (array_type, elt_type, range_type);
+      }
+
+      return lookup_pointer_type (elt_type);
+    }
+}
+
+/* If ARR does not represent an array, returns ARR unchanged.
+   Otherwise, returns either a standard GDB array with bounds set 
+   appropriately or, if ARR is a non-null fat pointer, a pointer to a standard 
+   GDB array.  Returns NULL if ARR is a null fat pointer. */
+struct value*
+ada_coerce_to_simple_array_ptr (arr)
+     struct value* arr;
+{
+  if (ada_is_array_descriptor (VALUE_TYPE (arr)))
+    {
+      struct type* arrType = ada_type_of_array (arr, 1);
+      if (arrType == NULL)
+       return NULL;
+      return value_cast (arrType, value_copy (desc_data (arr)));
+    }
+  else if (ada_is_packed_array_type (VALUE_TYPE (arr)))
+    return decode_packed_array (arr);
+  else
+    return arr;
+}
+
+/* If ARR does not represent an array, returns ARR unchanged.
+   Otherwise, returns a standard GDB array describing ARR (which may
+   be ARR itself if it already is in the proper form). */
+struct value*
+ada_coerce_to_simple_array (arr)
+     struct value* arr;
+{
+  if (ada_is_array_descriptor (VALUE_TYPE (arr)))
+    {
+      struct value* arrVal = ada_coerce_to_simple_array_ptr (arr);
+      if (arrVal == NULL)
+       error ("Bounds unavailable for null array pointer.");
+      return value_ind (arrVal);
+    }
+  else if (ada_is_packed_array_type (VALUE_TYPE (arr)))
+    return decode_packed_array (arr);
+  else 
+    return arr;
+}
+
+/* If TYPE represents a GNAT array type, return it translated to an
+   ordinary GDB array type (possibly with BITSIZE fields indicating
+   packing). For other types, is the identity. */
+struct type*
+ada_coerce_to_simple_array_type (type)
+     struct type* type;
+{
+  struct value* mark = value_mark ();
+  struct value* dummy = value_from_longest (builtin_type_long, 0);
+  struct type* result;
+  VALUE_TYPE (dummy) = type;
+  result = ada_type_of_array (dummy, 0);
+  value_free_to_mark (dummy);
+  return result;
+}
+
+/* Non-zero iff TYPE represents a standard GNAT packed-array type. */
+int
+ada_is_packed_array_type (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return 0;
+  CHECK_TYPEDEF (type);
+  return 
+    ada_type_name (type) != NULL
+    && strstr (ada_type_name (type), "___XP") != NULL;
+}
+
+/* Given that TYPE is a standard GDB array type with all bounds filled
+   in, and that the element size of its ultimate scalar constituents
+   (that is, either its elements, or, if it is an array of arrays, its
+   elements' elements, etc.) is *ELT_BITS, return an identical type,
+   but with the bit sizes of its elements (and those of any
+   constituent arrays) recorded in the BITSIZE components of its
+   TYPE_FIELD_BITSIZE values, and with *ELT_BITS set to its total size 
+   in bits. */
+static struct type*
+packed_array_type (type, elt_bits)
+     struct type* type;
+     long* elt_bits;
+{
+  struct type* new_elt_type;
+  struct type* new_type;
+  LONGEST low_bound, high_bound;
+
+  CHECK_TYPEDEF (type);
+  if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
+    return type;
+
+  new_type = alloc_type (TYPE_OBJFILE (type));
+  new_elt_type = packed_array_type (check_typedef (TYPE_TARGET_TYPE (type)),
+                                   elt_bits);
+  create_array_type (new_type, new_elt_type, TYPE_FIELD_TYPE (type, 0));
+  TYPE_FIELD_BITSIZE (new_type, 0) = *elt_bits;
+  TYPE_NAME (new_type) = ada_type_name (type);
+
+  if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), 
+                          &low_bound, &high_bound) < 0)
+    low_bound = high_bound = 0;
+  if (high_bound < low_bound)
+    *elt_bits = TYPE_LENGTH (new_type) = 0;
+  else 
+    {
+      *elt_bits *= (high_bound - low_bound + 1);
+      TYPE_LENGTH (new_type) = 
+       (*elt_bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+    }
+
+  /*  TYPE_FLAGS (new_type) |= TYPE_FLAG_FIXED_INSTANCE; */
+  /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+  return new_type;
+}
+
+/* The array type encoded by TYPE, where ada_is_packed_array_type (TYPE).
+ */
+static struct type*
+decode_packed_array_type (type)
+     struct type* type;
+{
+  struct symbol** syms;
+  struct block** blocks;
+  const char* raw_name = ada_type_name (check_typedef (type));
+  char* name = (char*) alloca (strlen (raw_name) + 1);
+  char* tail = strstr (raw_name, "___XP");
+  struct type* shadow_type;
+  long bits;
+  int i, n;
+
+  memcpy (name, raw_name, tail - raw_name);
+  name[tail - raw_name] = '\000';
+
+  /* NOTE: Use ada_lookup_symbol_list because of bug in some versions
+   * of gcc (Solaris, e.g.). FIXME when compiler is fixed. */
+  n = ada_lookup_symbol_list (name, get_selected_block (NULL), 
+                             VAR_NAMESPACE, &syms, &blocks);
+  for (i = 0; i < n; i += 1)
+    if (syms[i] != NULL && SYMBOL_CLASS (syms[i]) == LOC_TYPEDEF
+       && STREQ (name, ada_type_name (SYMBOL_TYPE (syms[i]))))
+      break;
+  if (i >= n)
+    {
+      warning ("could not find bounds information on packed array");
+      return NULL;
+    }
+  shadow_type = SYMBOL_TYPE (syms[i]);
+
+  if (TYPE_CODE (shadow_type) != TYPE_CODE_ARRAY)
+    {
+      warning ("could not understand bounds information on packed array");
+      return NULL;
+    }
+                                                                
+  if (sscanf (tail + sizeof ("___XP") - 1, "%ld", &bits) != 1)
+    {
+      warning ("could not understand bit size information on packed array");
+      return NULL;
+    }
+    
+  return packed_array_type (shadow_type, &bits);
+}
+
+/* Given that ARR is a struct value* indicating a GNAT packed array,
+   returns a simple array that denotes that array.  Its type is a
+   standard GDB array type except that the BITSIZEs of the array
+   target types are set to the number of bits in each element, and the
+   type length is set appropriately. */
+
+static struct value*
+decode_packed_array (arr)
+     struct value* arr;
+{
+  struct type* type = decode_packed_array_type (VALUE_TYPE (arr));
+
+  if (type == NULL)
+    {
+      error ("can't unpack array");
+      return NULL;
+    }
+  else
+    return coerce_unspec_val_to_type (arr, 0, type);
+}
+
+
+/* The value of the element of packed array ARR at the ARITY indices
+   given in IND.   ARR must be a simple array. */
+
+static struct value*
+value_subscript_packed (arr, arity, ind)
+     struct value* arr;
+     int arity;
+     struct value** ind;
+{
+  int i;
+  int bits, elt_off, bit_off;
+  long elt_total_bit_offset;
+  struct type* elt_type;
+  struct value* v;
+
+  bits = 0;
+  elt_total_bit_offset = 0;
+  elt_type = check_typedef (VALUE_TYPE (arr));
+  for (i = 0; i < arity; i += 1) 
+    {
+      if (TYPE_CODE (elt_type) != TYPE_CODE_ARRAY 
+         || TYPE_FIELD_BITSIZE (elt_type, 0) == 0)
+       error ("attempt to do packed indexing of something other than a packed array");
+      else
+       {
+         struct type *range_type = TYPE_INDEX_TYPE (elt_type);
+         LONGEST lowerbound, upperbound;
+         LONGEST idx;
+
+         if (get_discrete_bounds (range_type, &lowerbound,
+                                  &upperbound) < 0)
+           {
+             warning ("don't know bounds of array");
+             lowerbound = upperbound = 0;
+           }
+      
+         idx = value_as_long (value_pos_atr (ind[i]));
+         if (idx < lowerbound || idx > upperbound)
+           warning ("packed array index %ld out of bounds", (long) idx);
+         bits = TYPE_FIELD_BITSIZE (elt_type, 0);
+         elt_total_bit_offset += (idx - lowerbound) * bits;
+         elt_type = check_typedef (TYPE_TARGET_TYPE (elt_type));
+       }
+    }
+  elt_off = elt_total_bit_offset / HOST_CHAR_BIT;
+  bit_off = elt_total_bit_offset % HOST_CHAR_BIT;
+  
+  v = ada_value_primitive_packed_val (arr, NULL, elt_off, bit_off, 
+                                     bits, elt_type);
+  if (VALUE_LVAL (arr) == lval_internalvar)
+    VALUE_LVAL (v) = lval_internalvar_component;
+  else
+    VALUE_LVAL (v) = VALUE_LVAL (arr);
+  return v;
+}
+
+/* Non-zero iff TYPE includes negative integer values. */
+
+static int
+has_negatives (type)
+     struct type* type;
+{
+  switch (TYPE_CODE (type)) {
+  default:
+    return 0;
+  case TYPE_CODE_INT:
+    return ! TYPE_UNSIGNED (type);
+  case TYPE_CODE_RANGE:
+    return TYPE_LOW_BOUND (type) < 0;
+  }
+}
+      
+
+/* Create a new value of type TYPE from the contents of OBJ starting
+   at byte OFFSET, and bit offset BIT_OFFSET within that byte,
+   proceeding for BIT_SIZE bits.  If OBJ is an lval in memory, then
+   assigning through the result will set the field fetched from. OBJ
+   may also be NULL, in which case, VALADDR+OFFSET must address the
+   start of storage containing the packed value.  The value returned 
+   in this case is never an lval.   
+   Assumes 0 <= BIT_OFFSET < HOST_CHAR_BIT. */
+
+struct value*
+ada_value_primitive_packed_val (obj, valaddr, offset, bit_offset, 
+                               bit_size, type)
+     struct value* obj;
+     char* valaddr;
+     long offset;
+     int bit_offset;
+     int bit_size;
+     struct type* type;
+{
+  struct value* v;
+  int src,                     /* Index into the source area. */
+    targ,                      /* Index into the target area. */
+    i, 
+    srcBitsLeft,               /* Number of source bits left to move. */
+    nsrc, ntarg,               /* Number of source and target bytes. */
+    unusedLS,                  /* Number of bits in next significant
+                                * byte of source that are unused. */
+    accumSize;                 /* Number of meaningful bits in accum */
+  unsigned char* bytes;   /* First byte containing data to unpack. */
+  unsigned char* unpacked;
+  unsigned long accum;         /* Staging area for bits being transferred */
+  unsigned char sign;
+  int len = (bit_size + bit_offset + HOST_CHAR_BIT - 1) / 8;
+  /* Transmit bytes from least to most significant; delta is the
+   * direction the indices move. */     
+  int delta = BITS_BIG_ENDIAN ? -1 : 1;
+
+  CHECK_TYPEDEF (type);
+
+  if (obj == NULL)
+    {
+      v = allocate_value (type);
+      bytes = (unsigned char*) (valaddr + offset);
+    }
+  else if (VALUE_LAZY (obj))
+    {
+      v = value_at (type,
+                   VALUE_ADDRESS (obj) + VALUE_OFFSET (obj) + offset, NULL);
+      bytes = (unsigned char*) alloca (len);
+      read_memory (VALUE_ADDRESS (v), bytes, len);
+    }
+  else 
+    {
+      v = allocate_value (type);
+      bytes = (unsigned char*) VALUE_CONTENTS (obj) + offset;
+    }
+      
+  if (obj != NULL) 
+    {
+      VALUE_LVAL (v) = VALUE_LVAL (obj);
+      if (VALUE_LVAL (obj) == lval_internalvar)
+       VALUE_LVAL (v) = lval_internalvar_component;
+      VALUE_ADDRESS (v) = VALUE_ADDRESS (obj) + VALUE_OFFSET (obj) + offset;
+      VALUE_BITPOS (v) = bit_offset + VALUE_BITPOS (obj);
+      VALUE_BITSIZE (v) = bit_size;
+      if (VALUE_BITPOS (v) >= HOST_CHAR_BIT)
+        {
+          VALUE_ADDRESS (v) += 1;
+          VALUE_BITPOS (v) -= HOST_CHAR_BIT;
+        }
+    }
+  else
+    VALUE_BITSIZE (v) = bit_size;
+  unpacked = (unsigned char*) VALUE_CONTENTS (v);
+
+  srcBitsLeft = bit_size;
+  nsrc = len;
+  ntarg = TYPE_LENGTH (type);
+  sign = 0;
+  if (bit_size == 0)
+    {
+      memset (unpacked, 0, TYPE_LENGTH (type));
+      return v;
+    }
+  else if (BITS_BIG_ENDIAN)
+    {
+      src = len-1;
+      if (has_negatives (type) && 
+         ((bytes[0] << bit_offset) & (1 << (HOST_CHAR_BIT-1))))
+       sign = ~0;
+      
+      unusedLS = 
+       (HOST_CHAR_BIT - (bit_size + bit_offset) % HOST_CHAR_BIT)
+       % HOST_CHAR_BIT;
+
+      switch (TYPE_CODE (type))
+        {
+        case TYPE_CODE_ARRAY:
+        case TYPE_CODE_UNION:
+        case TYPE_CODE_STRUCT:
+          /* Non-scalar values must be aligned at a byte boundary. */
+          accumSize =
+            (HOST_CHAR_BIT - bit_size % HOST_CHAR_BIT) % HOST_CHAR_BIT;
+         /* And are placed at the beginning (most-significant) bytes
+          * of the target. */
+         targ = src;
+          break;
+        default:
+         accumSize = 0;
+         targ = TYPE_LENGTH (type) - 1;
+          break;
+        }
+    }
+  else 
+    {
+      int sign_bit_offset = (bit_size + bit_offset - 1) % 8;
+
+      src = targ = 0;
+      unusedLS = bit_offset;
+      accumSize = 0;
+
+      if (has_negatives (type) && (bytes[len-1] & (1 << sign_bit_offset)))
+       sign = ~0;
+    }
+      
+  accum = 0;
+  while (nsrc > 0)
+    {
+      /* Mask for removing bits of the next source byte that are not
+       * part of the value. */
+      unsigned int unusedMSMask = 
+       (1 << (srcBitsLeft >= HOST_CHAR_BIT ? HOST_CHAR_BIT : srcBitsLeft))-1;
+      /* Sign-extend bits for this byte. */
+      unsigned int signMask = sign & ~unusedMSMask;
+      accum |= 
+       (((bytes[src] >> unusedLS) & unusedMSMask) | signMask) << accumSize;
+      accumSize += HOST_CHAR_BIT - unusedLS;
+      if (accumSize >= HOST_CHAR_BIT) 
+       {
+         unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
+         accumSize -= HOST_CHAR_BIT;
+         accum >>= HOST_CHAR_BIT;
+         ntarg -= 1;
+         targ += delta;
+       }
+      srcBitsLeft -= HOST_CHAR_BIT - unusedLS;
+      unusedLS = 0;
+      nsrc -= 1;
+      src += delta;
+    }
+  while (ntarg > 0)
+    {
+      accum |= sign << accumSize;
+      unpacked[targ] = accum & ~(~0L << HOST_CHAR_BIT);
+      accumSize -= HOST_CHAR_BIT;
+      accum >>= HOST_CHAR_BIT;
+      ntarg -= 1;
+      targ += delta;
+    }
+
+  return v;
+}
+      
+/* Move N bits from SOURCE, starting at bit offset SRC_OFFSET to
+   TARGET, starting at bit offset TARG_OFFSET.  SOURCE and TARGET must
+   not overlap. */
+static void
+move_bits (char* target, int targ_offset, char* source, int src_offset, int n)
+{
+  unsigned int accum, mask;
+  int accum_bits, chunk_size;
+
+  target += targ_offset / HOST_CHAR_BIT;
+  targ_offset %= HOST_CHAR_BIT;
+  source += src_offset / HOST_CHAR_BIT;
+  src_offset %= HOST_CHAR_BIT;
+  if (BITS_BIG_ENDIAN) 
+    {
+      accum = (unsigned char) *source;
+      source += 1;
+      accum_bits = HOST_CHAR_BIT - src_offset;
+
+      while (n > 0) 
+       {
+         int unused_right;
+         accum = (accum << HOST_CHAR_BIT) + (unsigned char) *source;
+         accum_bits += HOST_CHAR_BIT;
+         source += 1;
+         chunk_size = HOST_CHAR_BIT - targ_offset;
+         if (chunk_size > n)
+           chunk_size = n;
+         unused_right = HOST_CHAR_BIT - (chunk_size + targ_offset);
+         mask = ((1 << chunk_size) - 1) << unused_right;
+         *target = 
+           (*target & ~mask) 
+           | ((accum >> (accum_bits - chunk_size - unused_right)) & mask);
+         n -= chunk_size;
+         accum_bits -= chunk_size;
+         target += 1;
+         targ_offset = 0;
+       }
+    }
+  else
+    {
+      accum = (unsigned char) *source >> src_offset;
+      source += 1;
+      accum_bits = HOST_CHAR_BIT - src_offset;
+
+      while (n > 0) 
+       {
+         accum = accum + ((unsigned char) *source << accum_bits);
+         accum_bits += HOST_CHAR_BIT;
+         source += 1;
+         chunk_size = HOST_CHAR_BIT - targ_offset;
+         if (chunk_size > n)
+           chunk_size = n;
+         mask = ((1 << chunk_size) - 1) << targ_offset;
+         *target = 
+           (*target & ~mask) | ((accum << targ_offset) & mask);
+         n -= chunk_size;
+         accum_bits -= chunk_size;
+         accum >>= chunk_size;
+         target += 1;
+         targ_offset = 0;
+       }
+    }
+}
+
+
+/* Store the contents of FROMVAL into the location of TOVAL.
+   Return a new value with the location of TOVAL and contents of
+   FROMVAL.   Handles assignment into packed fields that have
+   floating-point or non-scalar types. */
+
+static struct value*
+ada_value_assign (struct value* toval, struct value* fromval)
+{
+  struct type* type = VALUE_TYPE (toval);
+  int bits = VALUE_BITSIZE (toval);
+
+  if (!toval->modifiable)
+    error ("Left operand of assignment is not a modifiable lvalue.");
+
+  COERCE_REF (toval);
+
+  if (VALUE_LVAL (toval) == lval_memory 
+      && bits > 0
+      && (TYPE_CODE (type) == TYPE_CODE_FLT 
+         || TYPE_CODE (type) == TYPE_CODE_STRUCT))
+    {
+      int len = 
+       (VALUE_BITPOS (toval) + bits + HOST_CHAR_BIT - 1)
+       / HOST_CHAR_BIT;
+      char* buffer = (char*) alloca (len);
+      struct value* val;
+
+      if (TYPE_CODE (type) == TYPE_CODE_FLT)
+       fromval = value_cast (type, fromval);
+
+      read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), buffer, len);
+      if (BITS_BIG_ENDIAN)
+       move_bits (buffer, VALUE_BITPOS (toval), 
+                  VALUE_CONTENTS (fromval), 
+                  TYPE_LENGTH (VALUE_TYPE (fromval)) * TARGET_CHAR_BIT - bits,
+                  bits);
+      else
+       move_bits (buffer, VALUE_BITPOS (toval), VALUE_CONTENTS (fromval), 
+                  0, bits);
+      write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), buffer, len);
+
+      val = value_copy (toval);
+      memcpy (VALUE_CONTENTS_RAW (val), VALUE_CONTENTS (fromval),
+             TYPE_LENGTH (type));
+      VALUE_TYPE (val) = type;
+  
+      return val;
+    }
+
+  return value_assign (toval, fromval);
+}
+
+
+/* The value of the element of array ARR at the ARITY indices given in IND. 
+   ARR may be either a simple array, GNAT array descriptor, or pointer 
+   thereto.  */
+
+struct value*
+ada_value_subscript (arr, arity, ind)
+     struct value* arr;
+     int arity;
+     struct value** ind;
+{
+  int k;
+  struct value* elt;
+  struct type* elt_type;
+
+  elt = ada_coerce_to_simple_array (arr);
+
+  elt_type = check_typedef (VALUE_TYPE (elt));
+  if (TYPE_CODE (elt_type) == TYPE_CODE_ARRAY 
+      && TYPE_FIELD_BITSIZE (elt_type, 0) > 0)
+    return value_subscript_packed (elt, arity, ind);
+
+  for (k = 0; k < arity; k += 1)
+    {
+      if (TYPE_CODE (elt_type) != TYPE_CODE_ARRAY)
+       error("too many subscripts (%d expected)", k);
+      elt = value_subscript (elt, value_pos_atr (ind[k]));
+    }
+  return elt;
+}
+
+/* Assuming ARR is a pointer to a standard GDB array of type TYPE, the
+   value of the element of *ARR at the ARITY indices given in
+   IND. Does not read the entire array into memory. */
+
+struct value*
+ada_value_ptr_subscript (arr, type, arity, ind)
+     struct value* arr;
+     struct type* type;
+     int arity;
+     struct value** ind;
+{
+  int k;
+
+  for (k = 0; k < arity; k += 1)
+    {
+      LONGEST lwb, upb;
+      struct value* idx;
+
+      if (TYPE_CODE (type) != TYPE_CODE_ARRAY)
+       error("too many subscripts (%d expected)", k);
+      arr = value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (type)), 
+                       value_copy (arr));
+      get_discrete_bounds (TYPE_INDEX_TYPE (type), &lwb, &upb);
+      if (lwb == 0) 
+       idx = ind[k];
+      else
+       idx = value_sub (ind[k], value_from_longest (builtin_type_int, lwb));
+      arr = value_add (arr, idx);
+      type = TYPE_TARGET_TYPE (type);
+    }
+
+  return value_ind (arr);
+}
+
+/* If type is a record type in the form of a standard GNAT array
+   descriptor, returns the number of dimensions for type.  If arr is a
+   simple array, returns the number of "array of"s that prefix its
+   type designation. Otherwise, returns 0. */
+
+int
+ada_array_arity (type)
+     struct type* type;
+{
+  int arity;
+
+  if (type == NULL)
+    return 0;
+
+  type = desc_base_type (type);
+
+  arity = 0;
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT) 
+    return desc_arity (desc_bounds_type (type));
+  else 
+    while (TYPE_CODE (type) == TYPE_CODE_ARRAY) 
+      {
+       arity += 1;
+       type = check_typedef (TYPE_TARGET_TYPE (type));
+      }
+           
+  return arity;
+}
+
+/* If TYPE is a record type in the form of a standard GNAT array
+   descriptor or a simple array type, returns the element type for
+   TYPE after indexing by NINDICES indices, or by all indices if
+   NINDICES is -1. Otherwise, returns NULL. */
+
+struct type*
+ada_array_element_type (type, nindices)
+     struct type* type;
+     int nindices;
+{
+  type = desc_base_type (type);
+
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT) 
+    {
+      int k;
+      struct type* p_array_type;
+
+      p_array_type = desc_data_type (type);
+
+      k = ada_array_arity (type);
+      if (k == 0)
+       return NULL;
+      
+      /* Initially p_array_type = elt_type(*)[]...(k times)...[] */
+      if (nindices >= 0 && k > nindices)
+       k = nindices;
+      p_array_type = TYPE_TARGET_TYPE (p_array_type);
+      while (k > 0 && p_array_type != NULL) 
+       {
+         p_array_type = check_typedef (TYPE_TARGET_TYPE (p_array_type));
+         k -= 1;
+       }
+      return p_array_type;
+    }
+  else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    {
+      while (nindices != 0 && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+       {
+         type = TYPE_TARGET_TYPE (type);
+         nindices -= 1;
+       }
+      return type;
+    }
+
+  return NULL;
+}
+
+/* The type of nth index in arrays of given type (n numbering from 1).  Does 
+   not examine memory. */
+
+struct type*
+ada_index_type (type, n)
+     struct type* type;
+     int n;
+{
+  type = desc_base_type (type);
+
+  if (n > ada_array_arity (type))
+    return NULL;
+
+  if (ada_is_simple_array (type))
+    {
+      int i;
+
+      for (i = 1; i < n; i += 1)
+       type = TYPE_TARGET_TYPE (type);
+
+      return TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, 0));
+    }
+  else 
+    return desc_index_type (desc_bounds_type (type), n);
+}
+
+/* Given that arr is an array type, returns the lower bound of the
+   Nth index (numbering from 1) if WHICH is 0, and the upper bound if
+   WHICH is 1. This returns bounds 0 .. -1 if ARR_TYPE is an
+   array-descriptor type.  If TYPEP is non-null, *TYPEP is set to the 
+   bounds type.  It works for other arrays with bounds supplied by 
+   run-time quantities other than discriminants. */
+
+LONGEST
+ada_array_bound_from_type (arr_type, n, which, typep)
+     struct type* arr_type;
+     int n; 
+     int which;
+     struct type** typep;
+{
+  struct type* type;
+  struct type* index_type_desc;
+
+  if (ada_is_packed_array_type (arr_type))
+    arr_type = decode_packed_array_type (arr_type);
+
+  if (arr_type == NULL || ! ada_is_simple_array (arr_type)) 
+    {
+      if (typep != NULL)
+       *typep = builtin_type_int;
+      return (LONGEST) -which;
+    }
+
+  if (TYPE_CODE (arr_type) == TYPE_CODE_PTR)
+    type = TYPE_TARGET_TYPE (arr_type);
+  else
+    type = arr_type;
+
+  index_type_desc = ada_find_parallel_type (type, "___XA");
+  if (index_type_desc == NULL) 
+    {
+      struct type* range_type;
+      struct type* index_type;
+
+      while (n > 1) 
+       {
+         type = TYPE_TARGET_TYPE (type);
+         n -= 1;
+       }
+
+      range_type = TYPE_INDEX_TYPE (type);
+      index_type = TYPE_TARGET_TYPE (range_type);
+      if (TYPE_CODE (index_type) == TYPE_CODE_UNDEF)
+         index_type = builtin_type_long;
+      if (typep != NULL)
+       *typep = index_type;
+      return 
+       (LONGEST) (which == 0 
+                  ? TYPE_LOW_BOUND (range_type)
+                  : TYPE_HIGH_BOUND (range_type));
+    }
+  else 
+    {
+      struct type* index_type =
+       to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, n-1),
+                            NULL, TYPE_OBJFILE (arr_type));
+      if (typep != NULL)
+       *typep = TYPE_TARGET_TYPE (index_type);
+      return 
+       (LONGEST) (which == 0 
+                  ? TYPE_LOW_BOUND (index_type)
+                  : TYPE_HIGH_BOUND (index_type));
+    }
+}
+
+/* Given that arr is an array value, returns the lower bound of the
+   nth index (numbering from 1) if which is 0, and the upper bound if
+   which is 1. This routine will also work for arrays with bounds
+   supplied by run-time quantities other than discriminants. */
+
+struct value*
+ada_array_bound (arr, n, which)
+     struct value* arr;
+     int n; 
+     int which;
+{
+  struct type* arr_type = VALUE_TYPE (arr);
+
+  if (ada_is_packed_array_type (arr_type))
+    return ada_array_bound (decode_packed_array (arr), n, which);
+  else if (ada_is_simple_array (arr_type)) 
+    {
+      struct type* type;
+      LONGEST v = ada_array_bound_from_type (arr_type, n, which, &type);
+      return value_from_longest (type, v);
+    }
+  else
+    return desc_one_bound (desc_bounds (arr), n, which);
+}
+
+/* Given that arr is an array value, returns the length of the
+   nth index.  This routine will also work for arrays with bounds
+   supplied by run-time quantities other than discriminants. Does not
+   work for arrays indexed by enumeration types with representation
+   clauses at the moment. */ 
+
+struct value*
+ada_array_length (arr, n)
+     struct value* arr;
+     int n; 
+{
+  struct type* arr_type = check_typedef (VALUE_TYPE (arr));
+  struct type* index_type_desc;
+
+  if (ada_is_packed_array_type (arr_type))
+    return ada_array_length (decode_packed_array (arr), n);
+
+  if (ada_is_simple_array (arr_type))
+    {
+      struct type* type;
+      LONGEST v =
+       ada_array_bound_from_type (arr_type, n, 1, &type) -
+       ada_array_bound_from_type (arr_type, n, 0, NULL) + 1;
+      return value_from_longest (type, v);
+    }
+  else
+    return 
+      value_from_longest (builtin_type_ada_int,
+                         value_as_long (desc_one_bound (desc_bounds (arr),
+                                                        n, 1))
+                         - value_as_long (desc_one_bound (desc_bounds (arr),
+                                                          n, 0))
+                         + 1);
+}
+
+\f
+                               /* Name resolution */
+
+/* The "demangled" name for the user-definable Ada operator corresponding
+   to op. */
+
+static const char*
+ada_op_name (op)
+     enum exp_opcode op;
+{
+  int i;
+
+  for (i = 0; ada_opname_table[i].mangled != NULL; i += 1)
+    {
+      if (ada_opname_table[i].op == op)
+       return ada_opname_table[i].demangled;
+    }
+  error ("Could not find operator name for opcode");
+}
+
+
+/* Same as evaluate_type (*EXP), but resolves ambiguous symbol 
+   references (OP_UNRESOLVED_VALUES) and converts operators that are 
+   user-defined into appropriate function calls.  If CONTEXT_TYPE is 
+   non-null, it provides a preferred result type [at the moment, only
+   type void has any effect---causing procedures to be preferred over
+   functions in calls].  A null CONTEXT_TYPE indicates that a non-void
+   return type is preferred.  The variable unresolved_names contains a list
+   of character strings referenced by expout that should be freed.  
+   May change (expand) *EXP.  */
+
+void
+ada_resolve (expp, context_type)
+     struct expression** expp;
+     struct type* context_type;
+{
+  int pc;
+  pc = 0;
+  ada_resolve_subexp (expp, &pc, 1, context_type);
+}
+
+/* Resolve the operator of the subexpression beginning at 
+   position *POS of *EXPP. "Resolving" consists of replacing
+   OP_UNRESOLVED_VALUE with an appropriate OP_VAR_VALUE, replacing
+   built-in operators with function calls to user-defined operators,
+   where appropriate, and (when DEPROCEDURE_P is non-zero), converting
+   function-valued variables into parameterless calls.  May expand
+   EXP. The CONTEXT_TYPE functions as in ada_resolve, above. */
+
+static struct value*
+ada_resolve_subexp (expp, pos, deprocedure_p, context_type) 
+     struct expression** expp;
+     int *pos;
+     int deprocedure_p;
+     struct type* context_type;
+{
+  int pc = *pos;
+  int i;
+  struct expression* exp;      /* Convenience: == *expp */
+  enum exp_opcode op = (*expp)->elts[pc].opcode;
+  struct value** argvec;               /* Vector of operand types (alloca'ed). */
+  int nargs;                   /* Number of operands */
+
+  argvec = NULL;
+  nargs = 0;
+  exp = *expp;
+
+  /* Pass one: resolve operands, saving their types and updating *pos. */
+  switch (op)
+    {
+    case OP_VAR_VALUE:
+      /*    case OP_UNRESOLVED_VALUE:*/
+      /* FIXME:  OP_UNRESOLVED_VALUE should be defined in expression.h */
+      *pos += 4;
+      break;
+
+    case OP_FUNCALL:
+      nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+      /* FIXME:  OP_UNRESOLVED_VALUE should be defined in expression.h */
+      /*      if (exp->elts[pc+3].opcode == OP_UNRESOLVED_VALUE)       
+       {
+         *pos += 7;
+
+         argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1));
+         for (i = 0; i < nargs-1; i += 1)
+           argvec[i] = ada_resolve_subexp (expp, pos, 1, NULL);
+         argvec[i] = NULL;
+       }
+      else
+       {
+         *pos += 3;
+         ada_resolve_subexp (expp, pos, 0, NULL);
+         for (i = 1; i < nargs; i += 1)
+           ada_resolve_subexp (expp, pos, 1, NULL);
+       }
+      */
+      exp = *expp;
+      break;
+
+      /* FIXME:  UNOP_QUAL should be defined in expression.h */
+      /*    case UNOP_QUAL:
+      nargs = 1;
+      *pos += 3;
+      ada_resolve_subexp (expp, pos, 1, exp->elts[pc + 1].type);
+      exp = *expp;
+      break;
+      */
+      /* FIXME:  OP_ATTRIBUTE should be defined in expression.h */      
+      /*    case OP_ATTRIBUTE:
+      nargs = longest_to_int (exp->elts[pc + 1].longconst) + 1;
+      *pos += 4;
+      for (i = 0; i < nargs; i += 1)
+       ada_resolve_subexp (expp, pos, 1, NULL);
+      exp = *expp;
+      break;
+      */
+    case UNOP_ADDR:
+      nargs = 1;
+      *pos += 1;
+      ada_resolve_subexp (expp, pos, 0, NULL);
+      exp = *expp;
+      break;
+
+    case BINOP_ASSIGN:
+      {
+       struct value* arg1;
+       nargs = 2;
+       *pos += 1;
+       arg1 = ada_resolve_subexp (expp, pos, 0, NULL);
+       if (arg1 == NULL)
+         ada_resolve_subexp (expp, pos, 1, NULL);
+       else
+         ada_resolve_subexp (expp, pos, 1, VALUE_TYPE (arg1));
+       break;
+      }
+
+    default:
+      switch (op) 
+       {
+       default:
+         error ("Unexpected operator during name resolution");
+       case UNOP_CAST:
+         /*    case UNOP_MBR:
+         nargs = 1;
+         *pos += 3;
+         break;
+         */
+       case BINOP_ADD:
+       case BINOP_SUB:
+       case BINOP_MUL:
+       case BINOP_DIV:
+       case BINOP_REM:
+       case BINOP_MOD:
+       case BINOP_EXP:
+       case BINOP_CONCAT:
+       case BINOP_LOGICAL_AND:
+       case BINOP_LOGICAL_OR:
+       case BINOP_BITWISE_AND:
+       case BINOP_BITWISE_IOR:
+       case BINOP_BITWISE_XOR:
+
+       case BINOP_EQUAL:
+       case BINOP_NOTEQUAL:
+       case BINOP_LESS:
+       case BINOP_GTR:
+       case BINOP_LEQ:
+       case BINOP_GEQ:
+
+       case BINOP_REPEAT:
+       case BINOP_SUBSCRIPT:
+       case BINOP_COMMA:
+         nargs = 2;
+         *pos += 1;
+         break;
+
+       case UNOP_NEG:
+       case UNOP_PLUS:
+       case UNOP_LOGICAL_NOT:
+       case UNOP_ABS:
+       case UNOP_IND:
+         nargs = 1;
+         *pos += 1;
+         break;
+
+       case OP_LONG:
+       case OP_DOUBLE:
+       case OP_VAR_VALUE:
+         *pos += 4;
+         break;
+
+       case OP_TYPE:
+       case OP_BOOL:
+       case OP_LAST:
+       case OP_REGISTER:
+       case OP_INTERNALVAR:
+         *pos += 3;
+         break;
+
+       case UNOP_MEMVAL:
+         *pos += 3;
+         nargs = 1;
+         break;
+
+       case STRUCTOP_STRUCT:
+       case STRUCTOP_PTR:
+         nargs = 1;
+         *pos += 4 + BYTES_TO_EXP_ELEM (exp->elts[pc + 1].longconst + 1);
+         break;
+
+       case OP_ARRAY:
+         *pos += 4;  
+         nargs = longest_to_int (exp->elts[pc + 2].longconst) + 1;
+         nargs -= longest_to_int (exp->elts[pc + 1].longconst);
+         /* A null array contains one dummy element to give the type. */
+         /*      if (nargs == 0)
+           nargs = 1;
+           break;*/
+
+       case TERNOP_SLICE:
+         /* FIXME: TERNOP_MBR should be defined in expression.h */
+         /*    case TERNOP_MBR:
+         *pos += 1;
+         nargs = 3;
+         break;
+         */
+         /* FIXME: BINOP_MBR should be defined in expression.h */
+         /*    case BINOP_MBR:
+         *pos += 3;
+         nargs = 2;
+         break;*/
+       }
+
+      argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1));
+      for (i = 0; i < nargs; i += 1)
+       argvec[i] = ada_resolve_subexp (expp, pos, 1, NULL);
+      argvec[i] = NULL;
+      exp = *expp;
+      break;
+    }
+
+  /* Pass two: perform any resolution on principal operator. */
+  switch (op)
+    {
+    default:
+      break;
+
+      /* FIXME:  OP_UNRESOLVED_VALUE should be defined in expression.h */
+      /*    case OP_UNRESOLVED_VALUE:
+      {
+       struct symbol** candidate_syms;
+       struct block** candidate_blocks;
+       int n_candidates;
+
+       n_candidates = ada_lookup_symbol_list (exp->elts[pc + 2].name,
+                                              exp->elts[pc + 1].block,
+                                              VAR_NAMESPACE,
+                                              &candidate_syms,
+                                              &candidate_blocks);
+       
+       if (n_candidates > 1) 
+       {*/
+           /* Types tend to get re-introduced locally, so if there
+              are any local symbols that are not types, first filter
+              out all types.*/        /*
+           int j;
+           for (j = 0; j < n_candidates; j += 1) 
+             switch (SYMBOL_CLASS (candidate_syms[j])) 
+               {
+               case LOC_REGISTER:
+               case LOC_ARG:
+               case LOC_REF_ARG:
+               case LOC_REGPARM:
+               case LOC_REGPARM_ADDR:
+               case LOC_LOCAL:
+               case LOC_LOCAL_ARG:
+               case LOC_BASEREG:
+               case LOC_BASEREG_ARG:
+                 goto FoundNonType;
+               default:
+                 break;
+               }
+         FoundNonType:
+           if (j < n_candidates) 
+             {
+               j = 0;
+               while (j < n_candidates) 
+                 {
+                   if (SYMBOL_CLASS (candidate_syms[j]) == LOC_TYPEDEF)
+                     {
+                       candidate_syms[j] = candidate_syms[n_candidates-1];
+                       candidate_blocks[j] = candidate_blocks[n_candidates-1];
+                       n_candidates -= 1;
+                     }
+                   else
+                     j += 1;
+                 }
+             }
+         }
+
+       if (n_candidates == 0)
+         error ("No definition found for %s", 
+                ada_demangle (exp->elts[pc + 2].name));
+       else if (n_candidates == 1)
+         i = 0;
+       else if (deprocedure_p 
+                && ! is_nonfunction (candidate_syms, n_candidates))
+         {
+           i = ada_resolve_function (candidate_syms, candidate_blocks,
+                                     n_candidates, NULL, 0,
+                                     exp->elts[pc + 2].name, context_type);
+           if (i < 0) 
+             error ("Could not find a match for %s", 
+                    ada_demangle (exp->elts[pc + 2].name));
+         }
+       else 
+         {
+           printf_filtered ("Multiple matches for %s\n", 
+                            ada_demangle (exp->elts[pc+2].name));
+           user_select_syms (candidate_syms, candidate_blocks, 
+                             n_candidates, 1);
+           i = 0;
+         }
+
+       exp->elts[pc].opcode = exp->elts[pc + 3].opcode = OP_VAR_VALUE;
+       exp->elts[pc + 1].block = candidate_blocks[i];
+       exp->elts[pc + 2].symbol = candidate_syms[i];
+       if (innermost_block == NULL ||
+           contained_in (candidate_blocks[i], innermost_block))
+         innermost_block = candidate_blocks[i];
+      }*/
+      /* FALL THROUGH */
+
+    case OP_VAR_VALUE:
+      if (deprocedure_p && 
+         TYPE_CODE (SYMBOL_TYPE (exp->elts[pc+2].symbol)) == TYPE_CODE_FUNC)
+       {
+         replace_operator_with_call (expp, pc, 0, 0, 
+                                     exp->elts[pc+2].symbol,
+                                     exp->elts[pc+1].block);
+         exp = *expp;
+       }
+      break;
+
+    case OP_FUNCALL:
+      {
+       /* FIXME:  OP_UNRESOLVED_VALUE should be defined in expression.h */
+       /*      if (exp->elts[pc+3].opcode == OP_UNRESOLVED_VALUE)      
+         {
+           struct symbol** candidate_syms;
+           struct block** candidate_blocks;
+           int n_candidates;
+
+           n_candidates = ada_lookup_symbol_list (exp->elts[pc + 5].name,
+                                                  exp->elts[pc + 4].block,
+                                                  VAR_NAMESPACE,
+                                                  &candidate_syms,
+                                                  &candidate_blocks);
+           if (n_candidates == 1)
+             i = 0;
+           else
+             {
+               i = ada_resolve_function (candidate_syms, candidate_blocks,
+                                         n_candidates, argvec, nargs-1,
+                                         exp->elts[pc + 5].name, context_type);
+               if (i < 0) 
+                 error ("Could not find a match for %s", 
+                        ada_demangle (exp->elts[pc + 5].name));
+             }
+
+           exp->elts[pc + 3].opcode = exp->elts[pc + 6].opcode = OP_VAR_VALUE;
+           exp->elts[pc + 4].block = candidate_blocks[i];
+           exp->elts[pc + 5].symbol = candidate_syms[i];
+           if (innermost_block == NULL ||
+               contained_in (candidate_blocks[i], innermost_block))
+             innermost_block = candidate_blocks[i];
+             }*/
+       
+      }
+      break;
+    case BINOP_ADD:
+    case BINOP_SUB:
+    case BINOP_MUL:
+    case BINOP_DIV:
+    case BINOP_REM:
+    case BINOP_MOD:
+    case BINOP_CONCAT:
+    case BINOP_BITWISE_AND:
+    case BINOP_BITWISE_IOR:
+    case BINOP_BITWISE_XOR:
+    case BINOP_EQUAL:
+    case BINOP_NOTEQUAL:
+    case BINOP_LESS:
+    case BINOP_GTR:
+    case BINOP_LEQ:
+    case BINOP_GEQ:
+    case BINOP_EXP:
+    case UNOP_NEG:
+    case UNOP_PLUS:
+    case UNOP_LOGICAL_NOT:
+    case UNOP_ABS:
+      if (possible_user_operator_p (op, argvec))
+       {
+         struct symbol** candidate_syms;
+         struct block** candidate_blocks;
+         int n_candidates;
+
+         n_candidates = ada_lookup_symbol_list (ada_mangle (ada_op_name (op)),
+                                                (struct block*) NULL,
+                                                VAR_NAMESPACE,
+                                                &candidate_syms,
+                                                &candidate_blocks);
+         i = ada_resolve_function (candidate_syms, candidate_blocks,
+                                   n_candidates, argvec, nargs,
+                                   ada_op_name (op), NULL);
+         if (i < 0)
+           break;
+
+         replace_operator_with_call (expp, pc, nargs, 1,
+                                     candidate_syms[i], candidate_blocks[i]);
+         exp = *expp;
+       }
+      break;
+    }
+
+  *pos = pc;
+  return evaluate_subexp_type (exp, pos);
+}
+
+/* Return non-zero if formal type FTYPE matches actual type ATYPE.  If
+   MAY_DEREF is non-zero, the formal may be a pointer and the actual 
+   a non-pointer. */ 
+/* The term "match" here is rather loose.  The match is heuristic and
+   liberal.  FIXME: TOO liberal, in fact. */
+
+static int
+ada_type_match (ftype, atype, may_deref)
+     struct type* ftype;
+     struct type* atype;
+     int may_deref;
+{
+  CHECK_TYPEDEF (ftype);
+  CHECK_TYPEDEF (atype);
+
+  if (TYPE_CODE (ftype) == TYPE_CODE_REF)
+    ftype = TYPE_TARGET_TYPE (ftype);
+  if (TYPE_CODE (atype) == TYPE_CODE_REF)
+    atype = TYPE_TARGET_TYPE (atype);
+
+  if (TYPE_CODE (ftype) == TYPE_CODE_VOID 
+      || TYPE_CODE (atype) == TYPE_CODE_VOID)
+    return 1;
+
+  switch (TYPE_CODE (ftype)) 
+    {
+    default:
+      return 1;
+    case TYPE_CODE_PTR:
+      if (TYPE_CODE (atype) == TYPE_CODE_PTR)
+       return ada_type_match (TYPE_TARGET_TYPE (ftype),
+                              TYPE_TARGET_TYPE (atype), 0);
+      else return (may_deref && 
+                  ada_type_match (TYPE_TARGET_TYPE (ftype), atype, 0));
+    case TYPE_CODE_INT:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_RANGE:
+      switch (TYPE_CODE (atype))
+       {
+       case TYPE_CODE_INT:
+       case TYPE_CODE_ENUM:
+       case TYPE_CODE_RANGE:
+         return 1;
+       default:
+         return 0;
+       }
+
+    case TYPE_CODE_ARRAY:
+      return (TYPE_CODE (atype) == TYPE_CODE_ARRAY 
+             || ada_is_array_descriptor (atype));
+
+    case TYPE_CODE_STRUCT:
+      if (ada_is_array_descriptor (ftype))
+       return (TYPE_CODE (atype) == TYPE_CODE_ARRAY 
+               || ada_is_array_descriptor (atype));
+      else
+       return (TYPE_CODE (atype) == TYPE_CODE_STRUCT
+               && ! ada_is_array_descriptor (atype));
+
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_FLT:
+      return (TYPE_CODE (atype) == TYPE_CODE (ftype));
+    }
+}
+
+/* Return non-zero if the formals of FUNC "sufficiently match" the
+   vector of actual argument types ACTUALS of size N_ACTUALS.  FUNC
+   may also be an enumeral, in which case it is treated as a 0-
+   argument function. */
+
+static int
+ada_args_match (func, actuals, n_actuals)
+     struct symbol* func;
+     struct value** actuals;
+     int n_actuals;
+{
+  int i;
+  struct type* func_type = SYMBOL_TYPE (func);
+
+  if (SYMBOL_CLASS (func) == LOC_CONST && 
+      TYPE_CODE (func_type) == TYPE_CODE_ENUM)
+    return (n_actuals == 0);
+  else if (func_type == NULL || TYPE_CODE (func_type) != TYPE_CODE_FUNC)
+    return 0;
+
+  if (TYPE_NFIELDS (func_type) != n_actuals)
+    return 0;
+
+  for (i = 0; i < n_actuals; i += 1)
+    {
+      struct type* ftype = check_typedef (TYPE_FIELD_TYPE (func_type, i));
+      struct type* atype = check_typedef (VALUE_TYPE (actuals[i]));
+
+      if (! ada_type_match (TYPE_FIELD_TYPE (func_type, i), 
+                           VALUE_TYPE (actuals[i]), 1))
+       return 0;
+    }
+  return 1;
+}
+
+/* False iff function type FUNC_TYPE definitely does not produce a value
+   compatible with type CONTEXT_TYPE.  Conservatively returns 1 if
+   FUNC_TYPE is not a valid function type with a non-null return type
+   or an enumerated type.  A null CONTEXT_TYPE indicates any non-void type.  */
+
+static int
+return_match (func_type, context_type)
+     struct type* func_type;
+     struct type* context_type;
+{
+  struct type* return_type;
+
+  if (func_type == NULL)
+    return 1;
+
+  /* FIXME: base_type should be declared in gdbtypes.h, implemented in valarith.c */
+  /*  if (TYPE_CODE (func_type) == TYPE_CODE_FUNC)
+        return_type = base_type (TYPE_TARGET_TYPE (func_type));
+      else 
+       return_type = base_type (func_type);*/
+  if (return_type == NULL)
+    return 1;
+
+  /* FIXME: base_type should be declared in gdbtypes.h, implemented in valarith.c */
+  /*  context_type = base_type (context_type);*/
+
+  if (TYPE_CODE (return_type) == TYPE_CODE_ENUM)
+    return context_type == NULL || return_type == context_type;
+  else if (context_type == NULL)
+    return TYPE_CODE (return_type) != TYPE_CODE_VOID;
+  else
+    return TYPE_CODE (return_type) == TYPE_CODE (context_type);
+}
+
+
+/* Return the index in SYMS[0..NSYMS-1] of symbol for the 
+   function (if any) that matches the types of the NARGS arguments in
+   ARGS.  If CONTEXT_TYPE is non-null, and there is at least one match
+   that returns type CONTEXT_TYPE, then eliminate other matches.  If
+   CONTEXT_TYPE is null, prefer a non-void-returning function.
+   Asks the user if there is more than one match remaining.  Returns -1
+   if there is no such symbol or none is selected.  NAME is used
+   solely for messages.   May re-arrange and modify SYMS in
+   the process; the index returned is for the modified vector.  BLOCKS
+   is modified in parallel to SYMS. */
+
+int
+ada_resolve_function (syms, blocks, nsyms, args, nargs, name, context_type)
+     struct symbol* syms[];
+     struct block* blocks[];
+     struct value** args;
+     int nsyms, nargs;
+     const char* name;
+     struct type* context_type;
+{
+  int k;
+  int m;                       /* Number of hits */
+  struct type* fallback;
+  struct type* return_type;
+
+  return_type = context_type;
+  if (context_type == NULL)
+    fallback = builtin_type_void;
+  else
+    fallback = NULL;
+
+  m = 0; 
+  while (1)
+    {
+      for (k = 0; k < nsyms; k += 1)
+       {
+         struct type* type = check_typedef (SYMBOL_TYPE (syms[k]));
+
+         if (ada_args_match (syms[k], args, nargs)
+             && return_match (SYMBOL_TYPE (syms[k]), return_type))
+           {
+             syms[m] = syms[k];
+             if (blocks != NULL)
+               blocks[m] = blocks[k];
+             m += 1;
+           }
+       }
+      if (m > 0 || return_type == fallback)
+       break;
+      else
+       return_type = fallback;
+    }
+
+  if (m == 0)
+    return -1;
+  else if (m > 1)
+    {
+      printf_filtered ("Multiple matches for %s\n", name);
+      user_select_syms (syms, blocks, m, 1);
+      return 0;
+    }
+  return 0;
+}
+
+/* Returns true (non-zero) iff demangled name N0 should appear before N1 */
+/* in a listing of choices during disambiguation (see sort_choices, below). */
+/* The idea is that overloadings of a subprogram name from the */
+/* same package should sort in their source order.  We settle for ordering */
+/* such symbols by their trailing number (__N  or $N). */
+static int
+mangled_ordered_before (char* N0, char* N1)
+{
+  if (N1 == NULL)
+    return 0;
+  else if (N0 == NULL)
+    return 1;
+  else
+    {
+      int k0, k1;
+      for (k0 = strlen (N0)-1; k0 > 0 && isdigit (N0[k0]); k0 -= 1)
+       ;
+      for (k1 = strlen (N1)-1; k1 > 0 && isdigit (N1[k1]); k1 -= 1)
+       ;
+      if ((N0[k0] == '_' || N0[k0] == '$') && N0[k0+1] != '\000'
+         && (N1[k1] == '_' || N1[k1] == '$') && N1[k1+1] != '\000')
+       {
+         int n0, n1;
+         n0 = k0;
+         while (N0[n0] == '_' && n0 > 0 && N0[n0-1] == '_')
+           n0 -= 1;
+         n1 = k1;
+         while (N1[n1] == '_' && n1 > 0 && N1[n1-1] == '_')
+           n1 -= 1;
+         if (n0 == n1 && STREQN (N0, N1, n0))
+           return (atoi (N0+k0+1) < atoi (N1+k1+1));
+       }
+      return (strcmp (N0, N1) < 0);
+    }
+}
+         
+/* Sort SYMS[0..NSYMS-1] to put the choices in a canonical order by their */
+/* mangled names, rearranging BLOCKS[0..NSYMS-1] according to the same */
+/* permutation. */
+static void 
+sort_choices (syms, blocks, nsyms)
+     struct symbol* syms[];
+     struct block* blocks[];
+     int nsyms;
+{
+  int i, j;
+  for (i = 1; i < nsyms; i += 1) 
+    {
+      struct symbol* sym = syms[i];
+      struct block* block = blocks[i];
+      int j;
+
+      for (j = i-1; j >= 0; j -= 1) 
+       {
+         if (mangled_ordered_before (SYMBOL_NAME (syms[j]),
+                                     SYMBOL_NAME (sym)))
+           break;
+         syms[j+1] = syms[j];
+         blocks[j+1] = blocks[j];
+       }
+      syms[j+1] = sym;
+      blocks[j+1] = block;
+    }
+}
+
+/* Given a list of NSYMS symbols in SYMS and corresponding blocks in */
+/* BLOCKS, select up to MAX_RESULTS>0 by asking the user (if */
+/* necessary), returning the number selected, and setting the first */
+/* elements of SYMS and BLOCKS to the selected symbols and */
+/* corresponding blocks.  Error if no symbols selected.   BLOCKS may */
+/* be NULL, in which case it is ignored. */
+
+/* NOTE: Adapted from decode_line_2 in symtab.c, with which it ought
+   to be re-integrated one of these days. */
+
+int
+user_select_syms (syms, blocks, nsyms, max_results)
+     struct symbol* syms[];
+     struct block* blocks[];
+     int nsyms;
+     int max_results;
+{
+  int i;
+  int* chosen = (int*) alloca (sizeof(int) * nsyms);
+  int n_chosen;
+  int first_choice = (max_results == 1) ? 1 : 2;
+
+  if (max_results < 1)
+    error ("Request to select 0 symbols!");
+  if (nsyms <= 1)
+    return nsyms;
+
+  printf_unfiltered("[0] cancel\n");
+  if (max_results > 1)
+      printf_unfiltered("[1] all\n");
+
+  sort_choices (syms, blocks, nsyms);
+
+  for (i = 0; i < nsyms; i += 1)
+    {
+      if (syms[i] == NULL)
+       continue;
+
+      if (SYMBOL_CLASS (syms[i]) == LOC_BLOCK)
+       {
+         struct symtab_and_line sal = find_function_start_sal (syms[i], 1);
+         printf_unfiltered ("[%d] %s at %s:%d\n",
+                            i + first_choice, 
+                            SYMBOL_SOURCE_NAME (syms[i]),
+                            sal.symtab == NULL 
+                              ? "<no source file available>"
+                              : sal.symtab->filename, 
+                            sal.line);
+         continue;
+       }
+      else 
+       {
+         int is_enumeral = 
+           (SYMBOL_CLASS (syms[i]) == LOC_CONST
+            && SYMBOL_TYPE (syms[i]) != NULL
+            && TYPE_CODE (SYMBOL_TYPE (syms[i]))
+               == TYPE_CODE_ENUM);
+         struct symtab* symtab = symtab_for_sym (syms[i]);
+
+         if (SYMBOL_LINE (syms[i]) != 0 && symtab != NULL)
+           printf_unfiltered ("[%d] %s at %s:%d\n",
+                              i + first_choice,
+                              SYMBOL_SOURCE_NAME (syms[i]),
+                              symtab->filename, SYMBOL_LINE (syms[i]));
+         else if (is_enumeral && 
+                  TYPE_NAME (SYMBOL_TYPE (syms[i])) != NULL)
+           {
+             printf_unfiltered ("[%d] ", i + first_choice);
+             ada_print_type (SYMBOL_TYPE (syms[i]), NULL, gdb_stdout, -1, 0);
+             printf_unfiltered ("'(%s) (enumeral)\n",
+                                SYMBOL_SOURCE_NAME (syms[i]));
+           }
+         else if (symtab != NULL)
+           printf_unfiltered (is_enumeral 
+                              ? "[%d] %s in %s (enumeral)\n"
+                              : "[%d] %s at %s:?\n",
+                              i + first_choice,
+                              SYMBOL_SOURCE_NAME (syms[i]),
+                              symtab->filename);
+         else
+           printf_unfiltered (is_enumeral
+                              ? "[%d] %s (enumeral)\n"
+                              : "[%d] %s at ?\n",
+                              i + first_choice, SYMBOL_SOURCE_NAME (syms[i]));
+       }
+    }
+  
+  n_chosen = get_selections (chosen, nsyms, max_results, max_results > 1,
+                            "overload-choice");
+
+  for (i = 0; i < n_chosen; i += 1)
+    {
+      syms[i] = syms[chosen[i]];
+      if (blocks != NULL) 
+       blocks[i] = blocks[chosen[i]];
+    }
+
+  return n_chosen;
+}
+
+/* Read and validate a set of numeric choices from the user in the
+   range 0 .. N_CHOICES-1. Place the results in increasing
+   order in CHOICES[0 .. N-1], and return N.
+
+   The user types choices as a sequence of numbers on one line
+   separated by blanks, encoding them as follows:
+
+     + A choice of 0 means to cancel the selection, throwing an error.  
+     + If IS_ALL_CHOICE, a choice of 1 selects the entire set 0 .. N_CHOICES-1.
+     + The user chooses k by typing k+IS_ALL_CHOICE+1.
+
+   The user is not allowed to choose more than MAX_RESULTS values. 
+
+   ANNOTATION_SUFFIX, if present, is used to annotate the input
+   prompts (for use with the -f switch). */
+
+int
+get_selections (choices, n_choices, max_results, is_all_choice, 
+               annotation_suffix)
+     int* choices;
+     int n_choices;
+     int max_results;
+     int is_all_choice;
+     char* annotation_suffix;
+{
+  int i;
+  char* args;
+  const char* prompt;
+  int n_chosen;
+  int first_choice = is_all_choice ? 2 : 1;
+  
+  prompt = getenv ("PS2");
+  if (prompt == NULL)
+    prompt = ">";
+
+  printf_unfiltered ("%s ", prompt);
+  gdb_flush (gdb_stdout);
+
+  args = command_line_input ((char *) NULL, 0, annotation_suffix);
+  
+  if (args == NULL)
+    error_no_arg ("one or more choice numbers");
+
+  n_chosen = 0;
+
+  /* Set choices[0 .. n_chosen-1] to the users' choices in ascending 
+     order, as given in args.   Choices are validated. */
+  while (1)
+    {
+      char* args2;
+      int choice, j;
+
+      while (isspace (*args))
+       args += 1;
+      if (*args == '\0' && n_chosen == 0)
+       error_no_arg ("one or more choice numbers");
+      else if (*args == '\0')
+       break;
+
+      choice = strtol (args, &args2, 10);
+      if (args == args2 || choice < 0 || choice > n_choices + first_choice - 1)
+       error ("Argument must be choice number");
+      args = args2;
+
+      if (choice == 0) 
+       error ("cancelled");
+
+      if (choice < first_choice)
+       {
+         n_chosen = n_choices;
+         for (j = 0; j < n_choices; j += 1)
+           choices[j] = j;
+         break;
+       }
+      choice -= first_choice;
+
+      for (j = n_chosen-1; j >= 0 && choice < choices[j]; j -= 1)
+       {}
+
+      if (j < 0 || choice != choices[j])
+       {
+         int k;
+         for (k = n_chosen-1; k > j; k -= 1)
+           choices[k+1] = choices[k];
+         choices[j+1] = choice;
+         n_chosen += 1;
+       }
+    }
+
+  if (n_chosen > max_results)
+    error ("Select no more than %d of the above", max_results);
+  
+  return n_chosen;
+}
+
+/* Replace the operator of length OPLEN at position PC in *EXPP with a call */
+/* on the function identified by SYM and BLOCK, and taking NARGS */
+/* arguments.  Update *EXPP as needed to hold more space. */
+
+static void
+replace_operator_with_call (expp, pc, nargs, oplen, sym, block)
+     struct expression** expp;
+     int pc, nargs, oplen;
+     struct symbol* sym;
+     struct block* block; 
+{
+  /* A new expression, with 6 more elements (3 for funcall, 4 for function
+     symbol, -oplen for operator being replaced). */
+  struct expression* newexp = (struct expression*)
+    xmalloc (sizeof (struct expression)
+            + EXP_ELEM_TO_BYTES ((*expp)->nelts + 7 - oplen));
+  struct expression* exp = *expp;
+
+  newexp->nelts = exp->nelts + 7 - oplen;
+  newexp->language_defn = exp->language_defn;
+  memcpy (newexp->elts, exp->elts, EXP_ELEM_TO_BYTES (pc));
+  memcpy (newexp->elts + pc + 7, exp->elts + pc + oplen, 
+         EXP_ELEM_TO_BYTES (exp->nelts - pc - oplen));
+
+  newexp->elts[pc].opcode = newexp->elts[pc + 2].opcode = OP_FUNCALL;
+  newexp->elts[pc + 1].longconst = (LONGEST) nargs;
+
+  newexp->elts[pc + 3].opcode = newexp->elts[pc + 6].opcode = OP_VAR_VALUE;
+  newexp->elts[pc + 4].block = block;
+  newexp->elts[pc + 5].symbol = sym;
+
+  *expp = newexp;
+  free (exp);
+}  
+
+/* Type-class predicates */
+
+/* True iff TYPE is numeric (i.e., an INT, RANGE (of numeric type), or */
+/* FLOAT.) */
+
+static int
+numeric_type_p (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return 0;
+  else {
+    switch (TYPE_CODE (type))
+      {
+      case TYPE_CODE_INT:
+      case TYPE_CODE_FLT:
+       return 1;
+      case TYPE_CODE_RANGE:
+       return (type == TYPE_TARGET_TYPE (type)
+               || numeric_type_p (TYPE_TARGET_TYPE (type)));
+      default:
+       return 0;
+      }
+  }
+}
+
+/* True iff TYPE is integral (an INT or RANGE of INTs). */
+
+static int
+integer_type_p (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return 0;
+  else {
+    switch (TYPE_CODE (type))
+      {
+      case TYPE_CODE_INT:
+       return 1;
+      case TYPE_CODE_RANGE:
+       return (type == TYPE_TARGET_TYPE (type) 
+               || integer_type_p (TYPE_TARGET_TYPE (type)));
+      default:
+       return 0;
+      }
+  }
+}
+
+/* True iff TYPE is scalar (INT, RANGE, FLOAT, ENUM). */
+
+static int
+scalar_type_p (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return 0;
+  else {
+    switch (TYPE_CODE (type))
+      {
+      case TYPE_CODE_INT:
+      case TYPE_CODE_RANGE:
+      case TYPE_CODE_ENUM:
+      case TYPE_CODE_FLT:
+       return 1;
+      default:
+       return 0;
+      }
+  }
+}
+
+/* True iff TYPE is discrete (INT, RANGE, ENUM). */
+
+static int
+discrete_type_p (type)
+     struct type* type;
+{
+  if (type == NULL)
+    return 0;
+  else {
+    switch (TYPE_CODE (type))
+      {
+      case TYPE_CODE_INT:
+      case TYPE_CODE_RANGE:
+      case TYPE_CODE_ENUM:
+       return 1;
+      default:
+       return 0;
+      }
+  }
+}
+
+/* Returns non-zero if OP with operatands in the vector ARGS could be
+   a user-defined function. Errs on the side of pre-defined operators
+   (i.e., result 0). */
+
+static int
+possible_user_operator_p (op, args)
+     enum exp_opcode op;
+     struct value* args[];
+{
+  struct type* type0 = check_typedef (VALUE_TYPE (args[0]));
+  struct type* type1 = 
+    (args[1] == NULL) ? NULL : check_typedef (VALUE_TYPE (args[1]));
+  
+  switch (op)
+    {
+    default:
+      return 0;
+
+    case BINOP_ADD:
+    case BINOP_SUB:
+    case BINOP_MUL:
+    case BINOP_DIV:
+      return (! (numeric_type_p (type0) && numeric_type_p (type1)));
+
+    case BINOP_REM:
+    case BINOP_MOD:
+    case BINOP_BITWISE_AND:
+    case BINOP_BITWISE_IOR:
+    case BINOP_BITWISE_XOR:
+      return (! (integer_type_p (type0) && integer_type_p (type1)));
+
+    case BINOP_EQUAL:
+    case BINOP_NOTEQUAL:
+    case BINOP_LESS:
+    case BINOP_GTR:
+    case BINOP_LEQ:
+    case BINOP_GEQ:
+      return (! (scalar_type_p (type0) && scalar_type_p (type1)));
+
+    case BINOP_CONCAT:
+      return ((TYPE_CODE (type0) != TYPE_CODE_ARRAY && 
+              (TYPE_CODE (type0) != TYPE_CODE_PTR || 
+               TYPE_CODE (TYPE_TARGET_TYPE (type0)) 
+                   != TYPE_CODE_ARRAY))
+             || (TYPE_CODE (type1) != TYPE_CODE_ARRAY && 
+                 (TYPE_CODE (type1) != TYPE_CODE_PTR || 
+                  TYPE_CODE (TYPE_TARGET_TYPE (type1)) 
+                    != TYPE_CODE_ARRAY)));
+
+    case BINOP_EXP:
+      return (! (numeric_type_p (type0) && integer_type_p (type1)));
+
+    case UNOP_NEG:
+    case UNOP_PLUS:
+    case UNOP_LOGICAL_NOT:
+    case UNOP_ABS:      
+      return (! numeric_type_p (type0));
+
+    }
+}
+\f
+                               /* Renaming */
+
+/** NOTE: In the following, we assume that a renaming type's name may
+ *  have an ___XD suffix.  It would be nice if this went away at some
+ *  point. */
+
+/* If TYPE encodes a renaming, returns the renaming suffix, which
+ * is XR for an object renaming, XRP for a procedure renaming, XRE for
+ * an exception renaming, and XRS for a subprogram renaming.  Returns
+ * NULL if NAME encodes none of these. */
+const char*
+ada_renaming_type (type)
+     struct type* type;
+{
+  if (type != NULL && TYPE_CODE (type) == TYPE_CODE_ENUM)
+    {
+      const char* name = type_name_no_tag (type);
+      const char* suffix = (name == NULL) ? NULL : strstr (name, "___XR");
+      if (suffix == NULL 
+      || (suffix[5] != '\000' && strchr ("PES_", suffix[5]) == NULL))
+       return NULL;
+      else
+       return suffix + 3;
+    }
+  else
+    return NULL;
+}
+
+/* Return non-zero iff SYM encodes an object renaming. */
+int
+ada_is_object_renaming (sym)
+     struct symbol* sym;
+{
+  const char* renaming_type = ada_renaming_type (SYMBOL_TYPE (sym));
+  return renaming_type != NULL 
+    && (renaming_type[2] == '\0' || renaming_type[2] == '_');
+}
+
+/* Assuming that SYM encodes a non-object renaming, returns the original
+ * name of the renamed entity.   The name is good until the end of
+ * parsing. */
+const char*
+ada_simple_renamed_entity (sym)
+     struct symbol* sym;
+{
+  struct type* type;
+  const char* raw_name;
+  int len;
+  char* result;
+
+  type = SYMBOL_TYPE (sym);
+  if (type == NULL || TYPE_NFIELDS (type) < 1)
+    error ("Improperly encoded renaming.");
+
+  raw_name = TYPE_FIELD_NAME (type, 0);
+  len = (raw_name == NULL ? 0 : strlen (raw_name)) - 5;
+  if (len <= 0)
+    error ("Improperly encoded renaming.");
+
+  result = xmalloc (len + 1);
+  /* FIXME: add_name_string_cleanup should be defined in parse.c */  
+  /*  add_name_string_cleanup (result);*/
+  strncpy (result, raw_name, len);
+  result[len] = '\000';
+  return result;
+}
+
+\f
+                               /* Evaluation: Function Calls */
+
+/* Copy VAL onto the stack, using and updating *SP as the stack 
+   pointer. Return VAL as an lvalue. */
+
+static struct value*
+place_on_stack (val, sp)
+    struct value* val;
+     CORE_ADDR* sp;
+{
+  CORE_ADDR old_sp = *sp;
+
+#ifdef STACK_ALIGN
+  *sp = push_bytes (*sp, VALUE_CONTENTS_RAW (val), 
+                   STACK_ALIGN (TYPE_LENGTH (check_typedef (VALUE_TYPE (val)))));
+#else
+  *sp = push_bytes (*sp, VALUE_CONTENTS_RAW (val), 
+                   TYPE_LENGTH (check_typedef (VALUE_TYPE (val))));
+#endif
+
+  VALUE_LVAL (val) = lval_memory;
+  if (INNER_THAN (1, 2))
+    VALUE_ADDRESS (val) = *sp;
+  else
+    VALUE_ADDRESS (val) = old_sp;
+
+  return val;
+}
+
+/* Return the value ACTUAL, converted to be an appropriate value for a
+   formal of type FORMAL_TYPE.  Use *SP as a stack pointer for
+   allocating any necessary descriptors (fat pointers), or copies of
+   values not residing in memory, updating it as needed. */ 
+
+static struct value*
+convert_actual (actual, formal_type0, sp)
+     struct value* actual;
+     struct type* formal_type0;
+     CORE_ADDR* sp;
+{
+  struct type* actual_type = check_typedef (VALUE_TYPE (actual));
+  struct type* formal_type = check_typedef (formal_type0);
+  struct type* formal_target =
+    TYPE_CODE (formal_type) == TYPE_CODE_PTR 
+      ? check_typedef (TYPE_TARGET_TYPE (formal_type)) : formal_type;
+  struct type* actual_target = 
+    TYPE_CODE (actual_type) == TYPE_CODE_PTR 
+      ? check_typedef (TYPE_TARGET_TYPE (actual_type)) : actual_type;
+
+  if (ada_is_array_descriptor (formal_target)
+      && TYPE_CODE (actual_target) == TYPE_CODE_ARRAY)
+    return make_array_descriptor (formal_type, actual, sp);
+  else if (TYPE_CODE (formal_type) == TYPE_CODE_PTR)
+    {
+      if (TYPE_CODE (formal_target) == TYPE_CODE_ARRAY
+         && ada_is_array_descriptor (actual_target)) 
+       return desc_data (actual);
+      else if (TYPE_CODE (actual_type) != TYPE_CODE_PTR)
+       {
+         if (VALUE_LVAL (actual) != lval_memory)
+           {
+             struct value* val;
+             actual_type = check_typedef (VALUE_TYPE (actual));
+             val = allocate_value (actual_type);
+             memcpy ((char*) VALUE_CONTENTS_RAW (val), 
+                     (char*) VALUE_CONTENTS (actual),
+                     TYPE_LENGTH (actual_type));
+             actual = place_on_stack (val, sp);
+           }
+         return value_addr (actual);
+       }
+    }
+  else if (TYPE_CODE (actual_type) == TYPE_CODE_PTR)
+    return ada_value_ind (actual);
+
+  return actual;
+}
+
+
+/* Push a descriptor of type TYPE for array value ARR on the stack at 
+   *SP, updating *SP to reflect the new descriptor.  Return either 
+   an lvalue representing the new descriptor, or (if TYPE is a pointer-
+   to-descriptor type rather than a descriptor type), a struct value*
+   representing a pointer to this descriptor. */
+
+static struct value*
+make_array_descriptor (type, arr, sp)
+     struct type* type;
+     struct value* arr;
+     CORE_ADDR* sp;
+{
+  struct type* bounds_type = desc_bounds_type (type);
+  struct type* desc_type = desc_base_type (type);
+  struct value* descriptor = allocate_value (desc_type);
+  struct value* bounds = allocate_value (bounds_type);
+  CORE_ADDR bounds_addr;
+  int i;
+  
+  for (i = ada_array_arity (check_typedef (VALUE_TYPE (arr))); i > 0; i -= 1)
+    {
+      modify_general_field (VALUE_CONTENTS (bounds),
+                           value_as_long (ada_array_bound (arr, i, 0)), 
+                           desc_bound_bitpos (bounds_type, i, 0),
+                           desc_bound_bitsize (bounds_type, i, 0));
+      modify_general_field (VALUE_CONTENTS (bounds),
+                           value_as_long (ada_array_bound (arr, i, 1)), 
+                           desc_bound_bitpos (bounds_type, i, 1),
+                           desc_bound_bitsize (bounds_type, i, 1));
+    }
+  
+  bounds = place_on_stack (bounds, sp);
+  
+  modify_general_field (VALUE_CONTENTS (descriptor),
+                       arr,
+                       fat_pntr_data_bitpos (desc_type),
+                       fat_pntr_data_bitsize (desc_type));
+  modify_general_field (VALUE_CONTENTS (descriptor),
+                       VALUE_ADDRESS (bounds),
+                       fat_pntr_bounds_bitpos (desc_type),
+                       fat_pntr_bounds_bitsize (desc_type));
+
+  descriptor = place_on_stack (descriptor, sp);
+
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    return value_addr (descriptor);
+  else
+    return descriptor;
+}
+
+
+/* Assuming a dummy frame has been established on the target, perform any 
+   conversions needed for calling function FUNC on the NARGS actual
+   parameters in ARGS, other than standard C conversions.   Does
+   nothing if FUNC does not have Ada-style prototype data, or if NARGS
+   does not match the number of arguments expected.   Use *SP as a
+   stack pointer for additional data that must be pushed, updating its
+   value as needed. */
+
+void
+ada_convert_actuals (func, nargs, args, sp)
+     struct value* func;
+     int nargs;
+     struct value* args[];
+     CORE_ADDR* sp;
+{
+  int i;
+
+  if (TYPE_NFIELDS (VALUE_TYPE (func)) == 0 
+      || nargs != TYPE_NFIELDS (VALUE_TYPE (func)))
+    return;
+
+  for (i = 0; i < nargs; i += 1)
+    args[i] = 
+      convert_actual (args[i], 
+                     TYPE_FIELD_TYPE (VALUE_TYPE (func), i), 
+                     sp);
+}
+
+\f
+                               /* Symbol Lookup */
+
+
+/* The vectors of symbols and blocks ultimately returned from */
+/* ada_lookup_symbol_list. */
+
+/* Current size of defn_symbols and defn_blocks */
+static size_t defn_vector_size = 0; 
+
+/* Current number of symbols found. */
+static int ndefns = 0;
+
+static struct symbol** defn_symbols = NULL;
+static struct block** defn_blocks = NULL;
+
+/* Return the result of a standard (literal, C-like) lookup of NAME in 
+ * given NAMESPACE. */
+
+static struct symbol*
+standard_lookup (name, namespace)
+     const char* name;
+     namespace_enum namespace;
+{
+  struct symbol* sym;
+  struct symtab* symtab;
+  sym = lookup_symbol (name, (struct block*) NULL, namespace, 0, &symtab);
+  return sym;
+}
+  
+
+/* Non-zero iff there is at least one non-function/non-enumeral symbol */
+/* in SYMS[0..N-1].  We treat enumerals as functions, since they */
+/* contend in overloading in the same way. */ 
+static int
+is_nonfunction (syms, n)
+     struct symbol* syms[];
+     int n;
+{
+  int i;
+
+  for (i = 0; i < n; i += 1)
+    if (TYPE_CODE (SYMBOL_TYPE (syms[i])) != TYPE_CODE_FUNC
+       && TYPE_CODE (SYMBOL_TYPE (syms[i])) != TYPE_CODE_ENUM)
+      return 1;
+
+  return 0;
+}
+
+/* If true (non-zero), then TYPE0 and TYPE1 represent equivalent
+   struct types.  Otherwise, they may not. */
+
+static int
+equiv_types (type0, type1)
+     struct type* type0;
+     struct type* type1;
+{
+  if (type0 == type1) 
+    return 1;
+  if (type0 == NULL || type1 == NULL 
+      || TYPE_CODE (type0) != TYPE_CODE (type1))
+    return 0;
+  if ((TYPE_CODE (type0) == TYPE_CODE_STRUCT 
+       || TYPE_CODE (type0) == TYPE_CODE_ENUM)
+      && ada_type_name (type0) != NULL && ada_type_name (type1) != NULL
+      && STREQ (ada_type_name (type0), ada_type_name (type1)))
+    return 1;
+  
+  return 0;
+}
+
+/* True iff SYM0 represents the same entity as SYM1, or one that is
+   no more defined than that of SYM1. */
+
+static int
+lesseq_defined_than (sym0, sym1)
+     struct symbol* sym0;
+     struct symbol* sym1;
+{
+  if (sym0 == sym1)
+    return 1;
+  if (SYMBOL_NAMESPACE (sym0) != SYMBOL_NAMESPACE (sym1)
+      || SYMBOL_CLASS (sym0) != SYMBOL_CLASS (sym1))
+    return 0;
+
+  switch (SYMBOL_CLASS (sym0)) 
+    {
+    case LOC_UNDEF:
+      return 1;
+    case LOC_TYPEDEF:
+      {
+       struct type* type0 = SYMBOL_TYPE (sym0);
+       struct type* type1 = SYMBOL_TYPE (sym1);
+       char* name0 = SYMBOL_NAME (sym0);
+       char* name1 = SYMBOL_NAME (sym1);
+       int len0 = strlen (name0);
+       return 
+         TYPE_CODE (type0) == TYPE_CODE (type1)
+         && (equiv_types (type0, type1)
+             || (len0 < strlen (name1) && STREQN (name0, name1, len0)
+                 && STREQN (name1 + len0, "___XV", 5)));
+      }
+    case LOC_CONST:
+      return SYMBOL_VALUE (sym0) == SYMBOL_VALUE (sym1)
+       && equiv_types (SYMBOL_TYPE (sym0), SYMBOL_TYPE (sym1));
+    default: 
+      return 0;      
+    }
+}
+
+/* Append SYM to the end of defn_symbols, and BLOCK to the end of
+   defn_blocks, updating ndefns, and expanding defn_symbols and
+   defn_blocks as needed.   Do not include SYM if it is a duplicate.  */
+
+static void
+add_defn_to_vec (sym, block)
+     struct symbol* sym;
+     struct block* block;
+{
+  int i;
+  size_t tmp;
+
+  if (SYMBOL_TYPE (sym) != NULL) 
+    CHECK_TYPEDEF (SYMBOL_TYPE (sym));
+  for (i = 0; i < ndefns; i += 1)
+    {
+      if (lesseq_defined_than (sym, defn_symbols[i]))
+       return;
+      else if (lesseq_defined_than (defn_symbols[i], sym))
+       {
+         defn_symbols[i] = sym;
+         defn_blocks[i] = block;
+         return;
+       }
+    }
+
+  tmp = defn_vector_size;
+  GROW_VECT (defn_symbols, tmp, ndefns+2);
+  GROW_VECT (defn_blocks, defn_vector_size, ndefns+2);
+
+  defn_symbols[ndefns] = sym;
+  defn_blocks[ndefns] = block;
+  ndefns += 1;
+}
+
+/* Look, in partial_symtab PST, for symbol NAME in given namespace.
+   Check the global symbols if GLOBAL, the static symbols if not.  Do
+   wild-card match if WILD. */
+
+static struct partial_symbol *
+ada_lookup_partial_symbol (pst, name, global, namespace, wild)
+     struct partial_symtab *pst;
+     const char *name;
+     int global;
+     namespace_enum namespace;
+     int wild;
+{
+  struct partial_symbol **start;
+  int name_len = strlen (name);
+  int length = (global ? pst->n_global_syms : pst->n_static_syms);
+  int i;
+
+  if (length == 0)
+    {
+      return (NULL);
+    }
+  
+  start = (global ?
+          pst->objfile->global_psymbols.list + pst->globals_offset :
+          pst->objfile->static_psymbols.list + pst->statics_offset  );
+
+  if (wild)
+    {
+      for (i = 0; i < length; i += 1)
+       {
+         struct partial_symbol* psym = start[i];
+
+         if (SYMBOL_NAMESPACE (psym) == namespace &&
+             wild_match (name, name_len, SYMBOL_NAME (psym)))
+           return psym;
+       }
+      return NULL;
+    }
+  else 
+    {
+      if (global)
+       {
+         int U;
+         i = 0; U = length-1;
+         while (U - i > 4) 
+           {
+             int M = (U+i) >> 1;
+             struct partial_symbol* psym = start[M];
+             if (SYMBOL_NAME (psym)[0] < name[0])
+               i = M+1;
+             else if (SYMBOL_NAME (psym)[0] > name[0])
+               U = M-1;
+             else if (strcmp (SYMBOL_NAME (psym), name) < 0)
+               i = M+1;
+             else
+               U = M;
+           }
+       }
+      else
+       i = 0;
+
+      while (i < length)
+       {
+         struct partial_symbol *psym = start[i];
+
+         if (SYMBOL_NAMESPACE (psym) == namespace)
+           {
+             int cmp = strncmp (name, SYMBOL_NAME (psym), name_len);
+       
+             if (cmp < 0) 
+               {
+                 if (global)
+                   break;
+               }
+             else if (cmp == 0 
+                      && is_name_suffix (SYMBOL_NAME (psym) + name_len)) 
+               return psym;
+           }
+         i += 1;
+       }
+
+      if (global)
+       {
+         int U;
+         i = 0; U = length-1;
+         while (U - i > 4) 
+           {
+             int M = (U+i) >> 1;
+             struct partial_symbol *psym = start[M];
+             if (SYMBOL_NAME (psym)[0] < '_')
+               i = M+1;
+             else if (SYMBOL_NAME (psym)[0] > '_')
+               U = M-1;
+             else if (strcmp (SYMBOL_NAME (psym), "_ada_") < 0)
+               i = M+1;
+             else
+               U = M;
+           }
+       }
+      else
+       i = 0;
+
+      while (i < length)
+       {
+         struct partial_symbol* psym = start[i];
+
+         if (SYMBOL_NAMESPACE (psym) == namespace)
+           {
+             int cmp;
+
+             cmp = (int) '_' - (int) SYMBOL_NAME (psym)[0];
+             if (cmp == 0) 
+               {
+                 cmp = strncmp ("_ada_", SYMBOL_NAME (psym), 5);
+                 if (cmp == 0)
+                   cmp = strncmp (name, SYMBOL_NAME (psym) + 5, name_len);
+               }
+       
+             if (cmp < 0) 
+               {
+                 if (global)
+                   break;
+               }
+             else if (cmp == 0 
+                      && is_name_suffix (SYMBOL_NAME (psym) + name_len + 5)) 
+               return psym;
+           }
+         i += 1;
+       }
+      
+    }
+  return NULL;
+}
+
+
+/* Find a symbol table containing symbol SYM or NULL if none.  */
+static struct symtab*
+symtab_for_sym (sym)
+     struct symbol* sym;
+{
+  struct symtab* s;
+  struct objfile *objfile;
+  struct block *b;
+  int i, j;
+
+  ALL_SYMTABS (objfile, s)
+    {
+      switch (SYMBOL_CLASS (sym))
+       {
+       case LOC_CONST:
+       case LOC_STATIC:
+       case LOC_TYPEDEF:
+       case LOC_REGISTER:
+       case LOC_LABEL:
+       case LOC_BLOCK:
+       case LOC_CONST_BYTES:
+         b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+         for (i = 0; i < BLOCK_NSYMS (b); i += 1)
+           if (sym == BLOCK_SYM (b, i))
+             return s;
+         b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+         for (i = 0; i < BLOCK_NSYMS (b); i += 1)
+           if (sym == BLOCK_SYM (b, i))
+             return s;
+         break;
+       default:
+         break;
+       }
+      switch (SYMBOL_CLASS (sym))
+       {
+       case LOC_REGISTER:
+       case LOC_ARG:
+       case LOC_REF_ARG:
+       case LOC_REGPARM:
+       case LOC_REGPARM_ADDR:
+       case LOC_LOCAL:
+       case LOC_TYPEDEF:
+       case LOC_LOCAL_ARG:
+       case LOC_BASEREG:
+       case LOC_BASEREG_ARG:
+         for (j = FIRST_LOCAL_BLOCK; 
+              j < BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)); j += 1)
+           {
+             b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), j);
+             for (i = 0; i < BLOCK_NSYMS (b); i += 1)
+               if (sym == BLOCK_SYM (b, i))
+                 return s;
+           }
+         break;
+       default:
+         break;
+       }
+    }
+  return NULL;
+}
+
+/* Return a minimal symbol matching NAME according to Ada demangling 
+   rules. Returns NULL if there is no such minimal symbol. */
+
+struct minimal_symbol*
+ada_lookup_minimal_symbol (name)
+     const char* name;
+{
+  struct objfile* objfile;
+  struct minimal_symbol* msymbol;
+  int wild_match = (strstr (name, "__") == NULL);
+
+  ALL_MSYMBOLS (objfile, msymbol)
+    {
+      if (ada_match_name (SYMBOL_NAME (msymbol), name, wild_match)
+         && MSYMBOL_TYPE (msymbol) != mst_solib_trampoline)
+       return msymbol;
+    }
+
+  return NULL;
+}
+
+/* For all subprograms that statically enclose the subprogram of the
+ * selected frame, add symbols matching identifier NAME in NAMESPACE
+ * and their blocks to vectors *defn_symbols and *defn_blocks, as for
+ * ada_add_block_symbols (q.v.).   If WILD, treat as NAME with a
+ * wildcard prefix.  At the moment, this function uses a heuristic to
+ * find the frames of enclosing subprograms: it treats the
+ * pointer-sized value at location 0 from the local-variable base of a
+ * frame as a static link, and then searches up the call stack for a
+ * frame with that same local-variable base. */
+static void
+add_symbols_from_enclosing_procs (name, namespace, wild_match)
+     const char* name;
+     namespace_enum namespace;
+     int wild_match;
+{
+#ifdef i386
+  static struct symbol static_link_sym;
+  static struct symbol *static_link;
+
+  struct cleanup* old_chain = make_cleanup (null_cleanup, NULL);
+  struct frame_info* frame;
+  struct frame_info* target_frame;
+
+  if (static_link == NULL)
+    {
+      /* Initialize the local variable symbol that stands for the
+       * static link (when it exists). */
+      static_link = &static_link_sym;
+      SYMBOL_NAME (static_link) = "";
+      SYMBOL_LANGUAGE (static_link) = language_unknown;
+      SYMBOL_CLASS (static_link) = LOC_LOCAL;
+      SYMBOL_NAMESPACE (static_link) = VAR_NAMESPACE;
+      SYMBOL_TYPE (static_link) = lookup_pointer_type (builtin_type_void);
+      SYMBOL_VALUE (static_link) = 
+       - (long) TYPE_LENGTH (SYMBOL_TYPE (static_link));
+    }
+
+  frame = selected_frame;
+  while (frame != NULL && ndefns == 0)
+    {
+      struct block* block;
+      struct value* target_link_val = read_var_value (static_link, frame);
+      CORE_ADDR target_link;
+
+      if (target_link_val == NULL)
+       break;
+      QUIT;
+
+      target_link = target_link_val;
+      do {
+         QUIT;
+         frame = get_prev_frame (frame);
+      } while (frame != NULL && FRAME_LOCALS_ADDRESS (frame) != target_link);
+
+      if (frame == NULL)
+       break;
+
+      block = get_frame_block (frame, 0);
+      while (block != NULL && block_function (block) != NULL && ndefns == 0)
+       {
+         ada_add_block_symbols (block, name, namespace, NULL, wild_match);
+      
+         block = BLOCK_SUPERBLOCK (block);
+       }
+    }
+
+  do_cleanups (old_chain);
+#endif
+}
+
+/* True if TYPE is definitely an artificial type supplied to a symbol
+ * for which no debugging information was given in the symbol file. */
+static int
+is_nondebugging_type (type)
+     struct type* type;
+{
+  char* name = ada_type_name (type);
+  return (name != NULL && STREQ (name, "<variable, no debug info>"));
+}
+
+/* Remove any non-debugging symbols in SYMS[0 .. NSYMS-1] that definitely 
+ * duplicate other symbols in the list.  (The only case I know of where
+ * this happens is when object files containing stabs-in-ecoff are
+ * linked with files containing ordinary ecoff debugging symbols (or no
+ * debugging symbols)). Modifies SYMS to squeeze out deleted symbols,
+ * and applies the same modification to BLOCKS to maintain the
+ * correspondence between SYMS[i] and BLOCKS[i].  Returns the number
+ * of symbols in the modified list. */
+static int
+remove_extra_symbols (syms, blocks, nsyms)
+     struct symbol** syms;
+     struct block** blocks;
+     int nsyms;
+{
+  int i, j;
+
+  i = 0;
+  while (i < nsyms)
+    {
+      if (SYMBOL_NAME (syms[i]) != NULL && SYMBOL_CLASS (syms[i]) == LOC_STATIC
+         && is_nondebugging_type (SYMBOL_TYPE (syms[i])))
+       {
+         for (j = 0; j < nsyms; j += 1)
+           {
+             if (i != j 
+                 && SYMBOL_NAME (syms[j]) != NULL
+                 && STREQ (SYMBOL_NAME (syms[i]), SYMBOL_NAME (syms[j]))
+                 && SYMBOL_CLASS (syms[i]) == SYMBOL_CLASS (syms[j])
+                 && SYMBOL_VALUE_ADDRESS (syms[i]) 
+                 == SYMBOL_VALUE_ADDRESS (syms[j]))
+               {
+                 int k;
+                 for (k = i+1; k < nsyms; k += 1) 
+                   {
+                     syms[k-1] = syms[k];
+                     blocks[k-1] = blocks[k];
+                   }
+                 nsyms -= 1;
+                 goto NextSymbol;
+               }
+           }
+       }
+      i += 1;
+    NextSymbol:
+      ;
+    }
+  return nsyms;
+}
+
+/* Find symbols in NAMESPACE matching NAME, in BLOCK0 and enclosing 
+   scope and in global scopes, returning the number of matches.  Sets 
+   *SYMS to point to a vector of matching symbols, with *BLOCKS
+   pointing to the vector of corresponding blocks in which those
+   symbols reside.  These two vectors are transient---good only to the
+   next call of ada_lookup_symbol_list.  Any non-function/non-enumeral symbol
+   match within the nest of blocks whose innermost member is BLOCK0,
+   is the outermost match returned (no other matches in that or
+   enclosing blocks is returned).  If there are any matches in or
+   surrounding BLOCK0, then these alone are returned. */
+
+int
+ada_lookup_symbol_list (name, block0, namespace, syms, blocks)
+     const char *name;
+     struct block *block0;
+     namespace_enum namespace;
+     struct symbol*** syms;
+     struct block*** blocks;
+{
+  struct symbol *sym;
+  struct symtab *s;
+  struct partial_symtab *ps;
+  struct blockvector *bv;
+  struct objfile *objfile;
+  struct block *b;
+  struct block *block;
+  struct minimal_symbol *msymbol;
+  int wild_match = (strstr (name, "__") == NULL);
+  int cacheIfUnique;
+
+#ifdef TIMING
+  markTimeStart (0);
+#endif
+
+  ndefns = 0;
+  cacheIfUnique = 0;
+
+  /* Search specified block and its superiors.  */
+
+  block = block0;
+  while (block != NULL)
+    {
+      ada_add_block_symbols (block, name, namespace, NULL, wild_match);
+
+      /* If we found a non-function match, assume that's the one. */
+      if (is_nonfunction (defn_symbols, ndefns))
+       goto done;
+
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  /* If we found ANY matches in the specified BLOCK, we're done. */
+
+  if (ndefns > 0)
+    goto done;
+  
+  cacheIfUnique = 1;
+
+  /* Now add symbols from all global blocks: symbol tables, minimal symbol
+     tables, and psymtab's */
+
+  ALL_SYMTABS (objfile, s)
+    {
+      QUIT;
+      if (! s->primary)
+       continue;
+      bv = BLOCKVECTOR (s);
+      block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+      ada_add_block_symbols (block, name, namespace, objfile, wild_match);
+    }
+
+  if (namespace == VAR_NAMESPACE)
+    {
+      ALL_MSYMBOLS (objfile, msymbol)
+       {
+         if (ada_match_name (SYMBOL_NAME (msymbol), name, wild_match))
+           {
+             switch (MSYMBOL_TYPE (msymbol))
+               {
+               case mst_solib_trampoline:
+                 break;
+               default:
+                 s = find_pc_symtab (SYMBOL_VALUE_ADDRESS (msymbol));
+                 if (s != NULL)
+                   {
+                     int old_ndefns = ndefns;
+                     QUIT;
+                     bv = BLOCKVECTOR (s);
+                     block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+                     ada_add_block_symbols (block, 
+                                            SYMBOL_NAME (msymbol), 
+                                            namespace, objfile, wild_match);
+                     if (ndefns == old_ndefns) 
+                       {
+                         block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+                         ada_add_block_symbols (block, 
+                                                SYMBOL_NAME (msymbol), 
+                                                namespace, objfile,
+                                                wild_match);
+                       }
+                   }
+               }
+           }
+       }
+    }
+      
+  ALL_PSYMTABS (objfile, ps)
+    {
+      QUIT;
+      if (!ps->readin 
+         && ada_lookup_partial_symbol (ps, name, 1, namespace, wild_match))
+       {
+         s = PSYMTAB_TO_SYMTAB (ps);
+         if (! s->primary)
+           continue;
+         bv = BLOCKVECTOR (s);
+         block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+         ada_add_block_symbols (block, name, namespace, objfile, wild_match);
+       }
+    }
+  
+  /* Now add symbols from all per-file blocks if we've gotten no hits.  
+     (Not strictly correct, but perhaps better than an error).
+     Do the symtabs first, then check the psymtabs */
+  
+  if (ndefns == 0)
+    {
+
+      ALL_SYMTABS (objfile, s)
+       {
+         QUIT;
+         if (! s->primary)
+           continue;
+         bv = BLOCKVECTOR (s);
+         block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+         ada_add_block_symbols (block, name, namespace, objfile, wild_match);
+       }
+      
+      ALL_PSYMTABS (objfile, ps)
+       {
+         QUIT;
+         if (!ps->readin 
+             && ada_lookup_partial_symbol (ps, name, 0, namespace, wild_match))
+           {
+             s = PSYMTAB_TO_SYMTAB(ps);
+             bv = BLOCKVECTOR (s);
+             if (! s->primary)
+               continue;
+             block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+             ada_add_block_symbols (block, name, namespace, 
+                                    objfile, wild_match);
+           }
+       }
+    }  
+
+  /* Finally, we try to find NAME as a local symbol in some lexically
+     enclosing block.  We do this last, expecting this case to be
+     rare. */
+  if (ndefns == 0) 
+    {
+      add_symbols_from_enclosing_procs (name, namespace, wild_match);
+      if (ndefns > 0)
+       goto done;
+    }
+
+ done:
+  ndefns = remove_extra_symbols (defn_symbols, defn_blocks, ndefns);
+
+
+  *syms = defn_symbols;
+  *blocks = defn_blocks;
+#ifdef TIMING
+  markTimeStop (0);
+#endif
+  return ndefns;
+}
+
+/* Return a symbol in NAMESPACE matching NAME, in BLOCK0 and enclosing 
+ * scope and in global scopes, or NULL if none.  NAME is folded to
+ * lower case first, unless it is surrounded in single quotes. 
+ * Otherwise, the result is as for ada_lookup_symbol_list, but is 
+ * disambiguated by user query if needed. */
+
+struct symbol*
+ada_lookup_symbol (name, block0, namespace)
+     const char *name;
+     struct block *block0;
+     namespace_enum namespace;
+{
+  struct symbol** candidate_syms;
+  struct block** candidate_blocks;
+  int n_candidates;
+
+  n_candidates = ada_lookup_symbol_list (name,
+                                        block0, namespace,
+                                        &candidate_syms, &candidate_blocks);
+
+  if (n_candidates == 0)
+    return NULL;
+  else if (n_candidates != 1)
+    user_select_syms (candidate_syms, candidate_blocks, n_candidates, 1);
+
+  return candidate_syms[0];
+}
+
+
+/* True iff STR is a possible encoded suffix of a normal Ada name 
+ * that is to be ignored for matching purposes.  Suffixes of parallel
+ * names (e.g., XVE) are not included here.  Currently, the possible suffixes 
+ * are given by the regular expression:
+ *        (X[nb]*)?(__[0-9]+|\$[0-9]+|___(LJM|X([FDBUP].*|R[^T]?)))?$
+ * 
+ */
+static int
+is_name_suffix (str)
+     const char* str;
+{
+  int k;
+  if (str[0] == 'X')
+    {
+      str += 1;
+      while (str[0] != '_' && str[0] != '\0') 
+       {
+         if (str[0] != 'n' && str[0] != 'b')
+           return 0;
+         str += 1;
+       } 
+    }
+  if (str[0] == '\000')
+    return 1;
+  if (str[0] == '_') 
+    {
+      if (str[1] != '_' || str[2] == '\000')
+       return 0;
+      if (str[2] == '_') 
+       {
+         if (STREQ (str+3, "LJM"))
+           return 1;
+         if (str[3] != 'X')
+           return 0;
+         if (str[4] == 'F' || str[4] == 'D' || str[4] == 'B' ||
+             str[4] == 'U' || str[4] == 'P')
+           return 1;
+         if (str[4] == 'R' && str[5] != 'T')
+           return 1;
+         return 0;
+       }
+      for (k = 2; str[k] != '\0'; k += 1)
+       if (!isdigit (str[k]))
+         return 0;
+      return 1;
+    }
+  if (str[0] == '$' && str[1] != '\000')
+    {
+      for (k = 1; str[k] != '\0'; k += 1)
+       if (!isdigit (str[k]))
+         return 0;
+      return 1;
+    }
+  return 0;
+}
+      
+/* True if NAME represents a name of the form A1.A2....An, n>=1 and 
+ * PATN[0..PATN_LEN-1] = Ak.Ak+1.....An for some k >= 1.  Ignores
+ * informational suffixes of NAME (i.e., for which is_name_suffix is
+ * true). */ 
+static int
+wild_match (patn, patn_len, name)
+     const char* patn;
+     int patn_len;
+     const char* name;
+{
+  int name_len;
+  int s, e;
+
+  name_len = strlen (name);
+  if (name_len >= patn_len+5 && STREQN (name, "_ada_", 5)
+      && STREQN (patn, name+5, patn_len)
+      && is_name_suffix (name+patn_len+5))
+    return 1;
+
+  while (name_len >= patn_len) 
+    {
+      if (STREQN (patn, name, patn_len)
+         && is_name_suffix (name+patn_len))
+       return 1;
+      do {
+       name += 1; name_len -= 1;
+      } while (name_len > 0
+              && name[0] != '.' && (name[0] != '_' || name[1] != '_'));
+      if (name_len <= 0)
+       return 0;
+      if (name[0] == '_')
+       {
+         if (! islower (name[2]))
+           return 0;
+         name += 2; name_len -= 2;
+       }
+      else
+       {
+         if (! islower (name[1]))
+           return 0;
+         name += 1; name_len -= 1;
+       }
+    }
+
+  return 0;
+}
+
+
+/* Add symbols from BLOCK matching identifier NAME in NAMESPACE to 
+   vector *defn_symbols, updating *defn_symbols (if necessary), *SZ (the size of
+   the vector *defn_symbols), and *ndefns (the number of symbols
+   currently stored in *defn_symbols).  If WILD, treat as NAME with a
+   wildcard prefix. OBJFILE is the section containing BLOCK. */
+
+static void 
+ada_add_block_symbols (block, name, namespace, objfile, wild)
+     struct block* block;
+     const char* name;
+     namespace_enum namespace;
+     struct objfile* objfile;
+     int wild;
+{
+  int i;
+  int name_len = strlen (name);
+  /* A matching argument symbol, if any. */
+  struct symbol *arg_sym;
+  /* Set true when we find a matching non-argument symbol */
+  int found_sym;
+  int is_sorted = BLOCK_SHOULD_SORT (block);
+
+  arg_sym = NULL; found_sym = 0;
+  if (wild)
+    {
+      for (i = 0; i < BLOCK_NSYMS (block); i += 1)
+       {
+         struct symbol *sym = BLOCK_SYM (block, i);
+
+         if (SYMBOL_NAMESPACE (sym) == namespace &&
+             wild_match (name, name_len, SYMBOL_NAME (sym)))
+           {
+             switch (SYMBOL_CLASS (sym))
+               {
+               case LOC_ARG:
+               case LOC_LOCAL_ARG:
+               case LOC_REF_ARG:
+               case LOC_REGPARM:
+               case LOC_REGPARM_ADDR:
+               case LOC_BASEREG_ARG:
+                 arg_sym = sym;
+                 break;
+               case LOC_UNRESOLVED:
+                 continue;
+               default:
+                 found_sym = 1;
+                 fill_in_ada_prototype (sym);
+                 add_defn_to_vec (fixup_symbol_section (sym, objfile), block);
+                 break;
+               }
+           }
+       }
+    }
+  else 
+    {
+      if (is_sorted)
+       {
+         int U;
+         i = 0; U = BLOCK_NSYMS (block)-1;
+         while (U - i > 4) 
+           {
+             int M = (U+i) >> 1;
+             struct symbol *sym = BLOCK_SYM (block, M);
+             if (SYMBOL_NAME (sym)[0] < name[0])
+               i = M+1;
+             else if (SYMBOL_NAME (sym)[0] > name[0])
+               U = M-1;
+             else if (strcmp (SYMBOL_NAME (sym), name) < 0)
+               i = M+1;
+             else
+               U = M;
+           }
+       }
+      else
+       i = 0;
+
+      for (; i < BLOCK_NSYMS (block); i += 1)
+       {
+         struct symbol *sym = BLOCK_SYM (block, i);
+
+         if (SYMBOL_NAMESPACE (sym) == namespace)
+           {
+             int cmp = strncmp (name, SYMBOL_NAME (sym), name_len);
+       
+             if (cmp < 0) 
+               {
+                 if (is_sorted)
+                   break;
+               }
+             else if (cmp == 0 
+                      && is_name_suffix (SYMBOL_NAME (sym) + name_len)) 
+               {
+                 switch (SYMBOL_CLASS (sym))
+                   {
+                   case LOC_ARG:
+                   case LOC_LOCAL_ARG:
+                   case LOC_REF_ARG:
+                   case LOC_REGPARM:
+                   case LOC_REGPARM_ADDR:
+                   case LOC_BASEREG_ARG:
+                     arg_sym = sym;
+                     break;
+                   case LOC_UNRESOLVED:
+                     break;
+                   default:
+                     found_sym = 1;
+                     fill_in_ada_prototype (sym);
+                     add_defn_to_vec (fixup_symbol_section (sym, objfile),
+                                      block);
+                     break;
+                   }
+               }
+           }
+       }
+    }
+
+  if (! found_sym && arg_sym != NULL)
+    {
+      fill_in_ada_prototype (arg_sym);
+      add_defn_to_vec (fixup_symbol_section (arg_sym, objfile), block);
+    }
+
+  if (! wild)
+    {
+      arg_sym = NULL; found_sym = 0;
+      if (is_sorted)
+       {
+         int U;
+         i = 0; U = BLOCK_NSYMS (block)-1;
+         while (U - i > 4) 
+           {
+             int M = (U+i) >> 1;
+             struct symbol *sym = BLOCK_SYM (block, M);
+             if (SYMBOL_NAME (sym)[0] < '_')
+               i = M+1;
+             else if (SYMBOL_NAME (sym)[0] > '_')
+               U = M-1;
+             else if (strcmp (SYMBOL_NAME (sym), "_ada_") < 0)
+               i = M+1;
+             else
+               U = M;
+           }
+       }
+      else
+       i = 0;
+
+      for (; i < BLOCK_NSYMS (block); i += 1)
+       {
+         struct symbol *sym = BLOCK_SYM (block, i);
+
+         if (SYMBOL_NAMESPACE (sym) == namespace)
+           {
+             int cmp;
+
+             cmp = (int) '_' - (int) SYMBOL_NAME (sym)[0];
+             if (cmp == 0) 
+               {
+                 cmp = strncmp ("_ada_", SYMBOL_NAME (sym), 5);
+                 if (cmp == 0)
+                   cmp = strncmp (name, SYMBOL_NAME (sym) + 5, name_len);
+               }
+       
+             if (cmp < 0) 
+               {
+                 if (is_sorted)
+                   break;
+               }
+             else if (cmp == 0 
+                      && is_name_suffix (SYMBOL_NAME (sym) + name_len + 5)) 
+               {
+                 switch (SYMBOL_CLASS (sym))
+                   {
+                   case LOC_ARG:
+                   case LOC_LOCAL_ARG:
+                   case LOC_REF_ARG:
+                   case LOC_REGPARM:
+                   case LOC_REGPARM_ADDR:
+                   case LOC_BASEREG_ARG:
+                     arg_sym = sym;
+                     break;
+                   case LOC_UNRESOLVED:
+                     break;
+                   default:
+                     found_sym = 1;
+                     fill_in_ada_prototype (sym);
+                     add_defn_to_vec (fixup_symbol_section (sym, objfile),
+                                      block);
+                     break;
+                   }
+               }
+           }
+       }
+      
+      /* NOTE: This really shouldn't be needed for _ada_ symbols.
+        They aren't parameters, right? */
+      if (! found_sym && arg_sym != NULL)
+       {
+         fill_in_ada_prototype (arg_sym);
+         add_defn_to_vec (fixup_symbol_section (arg_sym, objfile), block);
+       }
+    }
+}
+
+\f
+                               /* Function Types */
+
+/* Assuming that SYM is the symbol for a function, fill in its type 
+   with prototype information, if it is not already there.  
+   
+   Why is there provision in struct type for BOTH an array of argument
+   types (TYPE_ARG_TYPES) and for an array of typed fields, whose
+   comment suggests it may also represent argument types?  I presume
+   this is some attempt to save space.  The problem is that argument
+   names in Ada are significant.  Therefore, for Ada we use the
+   (apparently older) TYPE_FIELD_* stuff to store argument types. */
+
+
+static void
+fill_in_ada_prototype (func)
+     struct symbol* func;
+{
+  struct block* b;
+  int nargs, nsyms;
+  int i;
+  struct type* ftype;
+  struct type* rtype;
+  size_t max_fields;
+
+  if (func == NULL
+      || TYPE_CODE (SYMBOL_TYPE (func)) != TYPE_CODE_FUNC
+      || TYPE_FIELDS (SYMBOL_TYPE (func)) != NULL)
+    return;
+
+  /* We make each function type unique, so that each may have its own */
+  /* parameter types.  This particular way of doing so wastes space: */
+  /* it would be nicer to build the argument types while the original */
+  /* function type is being built (FIXME). */
+  rtype = check_typedef (TYPE_TARGET_TYPE (SYMBOL_TYPE (func)));
+  ftype = alloc_type (TYPE_OBJFILE (SYMBOL_TYPE (func)));
+  make_function_type (rtype, &ftype);
+  SYMBOL_TYPE (func) = ftype;
+
+  b = SYMBOL_BLOCK_VALUE (func);
+  nsyms = BLOCK_NSYMS (b);
+
+  nargs = 0;
+  max_fields = 8; 
+  TYPE_FIELDS (ftype) = 
+    (struct field*) xmalloc (sizeof (struct field) * max_fields);
+  for (i = 0; i < nsyms; i += 1)
+    {
+      struct symbol *sym = BLOCK_SYM (b, i);
+
+      GROW_VECT (TYPE_FIELDS (ftype), max_fields, nargs+1);
+       
+      switch (SYMBOL_CLASS (sym)) 
+       {
+       case LOC_REF_ARG:
+       case LOC_REGPARM_ADDR:
+         TYPE_FIELD_BITPOS (ftype, nargs) = nargs;
+         TYPE_FIELD_BITSIZE (ftype, nargs) = 0;
+         TYPE_FIELD_TYPE (ftype, nargs) = 
+           lookup_pointer_type (check_typedef (SYMBOL_TYPE (sym)));
+         TYPE_FIELD_NAME (ftype, nargs) = SYMBOL_NAME (sym);
+         nargs += 1;
+       
+         break;
+
+       case LOC_ARG:
+       case LOC_REGPARM:
+       case LOC_LOCAL_ARG:
+       case LOC_BASEREG_ARG:
+         TYPE_FIELD_BITPOS (ftype, nargs) = nargs;
+         TYPE_FIELD_BITSIZE (ftype, nargs) = 0;
+         TYPE_FIELD_TYPE (ftype, nargs) = check_typedef (SYMBOL_TYPE (sym));
+         TYPE_FIELD_NAME (ftype, nargs) = SYMBOL_NAME (sym);
+         nargs += 1;
+       
+         break;
+
+       default:
+         break;
+       }
+    }
+
+  /* Re-allocate fields vector; if there are no fields, make the */
+  /* fields pointer non-null anyway, to mark that this function type */
+  /* has been filled in. */
+
+  TYPE_NFIELDS (ftype) = nargs;
+  if (nargs == 0)
+    {
+      static struct field dummy_field = {0, 0, 0, 0};
+      free (TYPE_FIELDS (ftype));
+      TYPE_FIELDS (ftype) = &dummy_field;
+    }
+  else
+    {
+      struct field* fields = 
+       (struct field*) TYPE_ALLOC (ftype, nargs * sizeof (struct field));
+      memcpy ((char*) fields, 
+             (char*) TYPE_FIELDS (ftype), 
+             nargs * sizeof (struct field));
+      free (TYPE_FIELDS (ftype));
+      TYPE_FIELDS (ftype) = fields;
+    }
+}
+
+\f
+                               /* Breakpoint-related */
+
+char no_symtab_msg[] = "No symbol table is loaded.  Use the \"file\" command.";
+
+/* Assuming that LINE is pointing at the beginning of an argument to
+   'break', return a pointer to the delimiter for the initial segment
+   of that name.  This is the first ':', ' ', or end of LINE. 
+*/
+char*
+ada_start_decode_line_1 (line)
+     char* line;
+{
+  /* [NOTE: strpbrk would be more elegant, but I am reluctant to be
+     the first to use such a library function in GDB code.] */
+  char* p;
+  for (p = line; *p != '\000' && *p != ' ' && *p != ':'; p += 1)
+    ;
+  return p;
+}
+
+/* *SPEC points to a function and line number spec (as in a break
+   command), following any initial file name specification.
+
+   Return all symbol table/line specfications (sals) consistent with the
+   information in *SPEC and FILE_TABLE in the
+   following sense: 
+     + FILE_TABLE is null, or the sal refers to a line in the file
+       named by FILE_TABLE.
+     + If *SPEC points to an argument with a trailing ':LINENUM',
+       then the sal refers to that line (or one following it as closely as 
+       possible).
+     + If *SPEC does not start with '*', the sal is in a function with 
+       that name.
+
+   Returns with 0 elements if no matching non-minimal symbols found.
+
+   If *SPEC begins with a function name of the form <NAME>, then NAME
+   is taken as a literal name; otherwise the function name is subject
+   to the usual mangling.
+
+   *SPEC is updated to point after the function/line number specification.
+
+   FUNFIRSTLINE is non-zero if we desire the first line of real code
+   in each function (this is ignored in the presence of a LINENUM spec.).
+
+   If CANONICAL is non-NULL, and if any of the sals require a
+   'canonical line spec', then *CANONICAL is set to point to an array
+   of strings, corresponding to and equal in length to the returned
+   list of sals, such that (*CANONICAL)[i] is non-null and contains a 
+   canonical line spec for the ith returned sal, if needed.  If no 
+   canonical line specs are required and CANONICAL is non-null, 
+   *CANONICAL is set to NULL.
+
+   A 'canonical line spec' is simply a name (in the format of the
+   breakpoint command) that uniquely identifies a breakpoint position,
+   with no further contextual information or user selection.  It is
+   needed whenever the file name, function name, and line number
+   information supplied is insufficient for this unique
+   identification.  Currently overloaded functions, the name '*', 
+   or static functions without a filename yield a canonical line spec.
+   The array and the line spec strings are allocated on the heap; it
+   is the caller's responsibility to free them.   */
+
+struct symtabs_and_lines
+ada_finish_decode_line_1 (spec, file_table, funfirstline, canonical)
+     char** spec;
+     struct symtab* file_table;
+     int funfirstline;
+     char*** canonical;
+{
+  struct symbol** symbols;
+  struct block** blocks;
+  struct block* block;
+  int n_matches, i, line_num;
+  struct symtabs_and_lines selected;
+  struct cleanup* old_chain = make_cleanup (null_cleanup, NULL);
+  char* name;
+
+  int len;
+  char* lower_name;
+  char* unquoted_name;
+
+  if (file_table == NULL)
+    block = get_selected_block (NULL);
+  else
+    block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (file_table), STATIC_BLOCK);
+
+  if (canonical != NULL)
+    *canonical = (char**) NULL;
+
+  name = *spec;
+  if (**spec == '*') 
+    *spec += 1;
+  else
+    {
+      while (**spec != '\000' && 
+            ! strchr (ada_completer_word_break_characters, **spec))
+       *spec += 1;
+    }
+  len = *spec - name;
+
+  line_num = -1;
+  if (file_table != NULL && (*spec)[0] == ':' && isdigit ((*spec)[1]))
+    {
+      line_num = strtol (*spec + 1, spec, 10);
+      while (**spec == ' ' || **spec == '\t') 
+       *spec += 1;
+    }
+
+  if (name[0] == '*') 
+    {
+      if (line_num == -1)
+       error ("Wild-card function with no line number or file name.");
+
+      return all_sals_for_line (file_table->filename, line_num, canonical);
+    }
+
+  if (name[0] == '\'')
+    {
+      name += 1;
+      len -= 2;
+    }
+
+  if (name[0] == '<')
+    {
+      unquoted_name = (char*) alloca (len-1);
+      memcpy (unquoted_name, name+1, len-2);
+      unquoted_name[len-2] = '\000';
+      lower_name = NULL;
+    }
+  else
+    {
+      unquoted_name = (char*) alloca (len+1);
+      memcpy (unquoted_name, name, len);
+      unquoted_name[len] = '\000';
+      lower_name = (char*) alloca (len + 1);
+      for (i = 0; i < len; i += 1)
+       lower_name[i] = tolower (name[i]);
+      lower_name[len] = '\000';
+    }
+
+  n_matches = 0;
+  if (lower_name != NULL) 
+    n_matches = ada_lookup_symbol_list (ada_mangle (lower_name), block, 
+                                       VAR_NAMESPACE, &symbols, &blocks);
+  if (n_matches == 0)
+    n_matches = ada_lookup_symbol_list (unquoted_name, block, 
+                                       VAR_NAMESPACE, &symbols, &blocks);
+  if (n_matches == 0 && line_num >= 0)
+    error ("No line number information found for %s.", unquoted_name);
+  else if (n_matches == 0)
+    {
+#ifdef HPPA_COMPILER_BUG
+      /* FIXME: See comment in symtab.c::decode_line_1 */
+#undef volatile
+      volatile struct symtab_and_line val;
+#define volatile /*nothing*/
+#else
+      struct symtab_and_line val;
+#endif
+      struct minimal_symbol* msymbol;
+
+      INIT_SAL (&val);
+
+      msymbol = NULL;
+      if (lower_name != NULL) 
+       msymbol = ada_lookup_minimal_symbol (ada_mangle (lower_name));
+      if (msymbol == NULL)
+       msymbol = ada_lookup_minimal_symbol (unquoted_name);
+      if (msymbol != NULL)
+       {
+         val.pc      = SYMBOL_VALUE_ADDRESS (msymbol);
+         val.section = SYMBOL_BFD_SECTION (msymbol);
+         if (funfirstline)
+           {
+             val.pc += FUNCTION_START_OFFSET;
+             SKIP_PROLOGUE (val.pc);
+           }
+         selected.sals = (struct symtab_and_line *)
+           xmalloc (sizeof (struct symtab_and_line));
+         selected.sals[0] = val;
+         selected.nelts = 1;
+         return selected;
+       }       
+      
+      if (!have_full_symbols () &&
+         !have_partial_symbols () && !have_minimal_symbols ())
+       error (no_symtab_msg);
+
+      error ("Function \"%s\" not defined.", unquoted_name);
+      return selected; /* for lint */
+    }
+
+  if (line_num >= 0)
+    {
+      return 
+       find_sal_from_funcs_and_line (file_table->filename, line_num, 
+                                     symbols, n_matches);
+    }
+  else
+    {
+      selected.nelts = user_select_syms (symbols, blocks, n_matches, n_matches);
+    }
+
+  selected.sals = (struct symtab_and_line*) 
+    xmalloc (sizeof (struct symtab_and_line) * selected.nelts);
+  memset (selected.sals, 0, selected.nelts * sizeof (selected.sals[i]));
+  make_cleanup (free, selected.sals);
+
+  i = 0;
+  while (i < selected.nelts)
+    {
+      if (SYMBOL_CLASS (symbols[i]) == LOC_BLOCK) 
+       selected.sals[i] = find_function_start_sal (symbols[i], funfirstline);
+      else if (SYMBOL_LINE (symbols[i]) != 0) 
+       {
+         selected.sals[i].symtab = symtab_for_sym (symbols[i]);
+         selected.sals[i].line = SYMBOL_LINE (symbols[i]);
+       }
+      else if (line_num >= 0)
+       {
+         /* Ignore this choice */
+         symbols[i] = symbols[selected.nelts-1];
+         blocks[i] = blocks[selected.nelts-1];
+         selected.nelts -= 1;
+         continue;
+       }
+      else 
+       error ("Line number not known for symbol \"%s\"", unquoted_name);
+      i += 1;
+    }
+
+  if (canonical != NULL && (line_num >= 0 || n_matches > 1))
+    {
+      *canonical = (char**) xmalloc (sizeof(char*) * selected.nelts);
+      for (i = 0; i < selected.nelts; i += 1)
+       (*canonical)[i] = 
+         extended_canonical_line_spec (selected.sals[i], 
+                                       SYMBOL_SOURCE_NAME (symbols[i]));
+    }
+   
+  discard_cleanups (old_chain);
+  return selected;
+}  
+      
+/* The (single) sal corresponding to line LINE_NUM in a symbol table
+   with file name FILENAME that occurs in one of the functions listed 
+   in SYMBOLS[0 .. NSYMS-1]. */   
+static struct symtabs_and_lines
+find_sal_from_funcs_and_line (filename, line_num, symbols, nsyms)
+     const char* filename;
+     int line_num;
+     struct symbol** symbols;
+     int nsyms;
+{
+  struct symtabs_and_lines sals;
+  int best_index, best;
+  struct linetable* best_linetable;
+  struct objfile* objfile;
+  struct symtab* s;
+  struct symtab* best_symtab;
+
+  read_all_symtabs (filename);
+
+  best_index = 0; best_linetable = NULL; best_symtab = NULL;
+  best = 0;
+  ALL_SYMTABS (objfile, s)
+    {
+      struct linetable *l;
+      int ind, exact;
+
+      QUIT;    
+
+      if (!STREQ (filename, s->filename))
+       continue;
+      l = LINETABLE (s);
+      ind = find_line_in_linetable (l, line_num, symbols, nsyms, &exact);
+      if (ind >= 0)
+       {
+         if (exact)
+           {
+             best_index = ind;
+             best_linetable = l;
+             best_symtab = s;
+             goto done;
+           }
+         if (best == 0 || l->item[ind].line < best)
+           {
+             best = l->item[ind].line;
+             best_index = ind;
+             best_linetable = l;
+             best_symtab = s;
+           }
+       }
+    }
+
+  if (best == 0)
+    error ("Line number not found in designated function.");
+
+ done:
+  
+  sals.nelts = 1;
+  sals.sals = (struct symtab_and_line*) xmalloc (sizeof (sals.sals[0]));
+
+  INIT_SAL (&sals.sals[0]);
+  
+  sals.sals[0].line = best_linetable->item[best_index].line;
+  sals.sals[0].pc = best_linetable->item[best_index].pc;
+  sals.sals[0].symtab = best_symtab;
+
+  return sals;
+}
+
+/* Return the index in LINETABLE of the best match for LINE_NUM whose
+   pc falls within one of the functions denoted by SYMBOLS[0..NSYMS-1].  
+   Set *EXACTP to the 1 if the match is exact, and 0 otherwise. */
+static int
+find_line_in_linetable (linetable, line_num, symbols, nsyms, exactp)
+     struct linetable* linetable;
+     int line_num;
+     struct symbol** symbols;
+     int nsyms;
+     int* exactp;
+{
+  int i, len, best_index, best;
+
+  if (line_num <= 0 || linetable == NULL)
+    return -1;
+
+  len = linetable->nitems;
+  for (i = 0, best_index = -1, best = 0; i < len; i += 1)
+    {
+      int k;
+      struct linetable_entry* item = &(linetable->item[i]);
+
+      for (k = 0; k < nsyms; k += 1)
+       {
+         if (symbols[k] != NULL && SYMBOL_CLASS (symbols[k]) == LOC_BLOCK
+             && item->pc >= BLOCK_START (SYMBOL_BLOCK_VALUE (symbols[k]))
+             && item->pc < BLOCK_END (SYMBOL_BLOCK_VALUE (symbols[k])))
+           goto candidate;
+       }
+      continue;
+
+    candidate:
+
+      if (item->line == line_num)
+       {
+         *exactp = 1;
+         return i;
+       }
+
+      if (item->line > line_num && (best == 0 || item->line < best))
+       {
+         best = item->line;
+         best_index = i;
+       }
+    }
+
+  *exactp = 0;
+  return best_index;
+}
+
+/* Find the smallest k >= LINE_NUM such that k is a line number in
+   LINETABLE, and k falls strictly within a named function that begins at
+   or before LINE_NUM.  Return -1 if there is no such k. */
+static int
+nearest_line_number_in_linetable (linetable, line_num)
+     struct linetable* linetable;
+     int line_num;
+{
+  int i, len, best;
+
+  if (line_num <= 0 || linetable == NULL || linetable->nitems == 0)
+    return -1;
+  len = linetable->nitems;
+
+  i = 0; best = INT_MAX;
+  while (i < len)
+    {
+      int k;
+      struct linetable_entry* item = &(linetable->item[i]);
+
+      if (item->line >= line_num && item->line < best)
+       {
+         char* func_name;
+         CORE_ADDR start, end;
+
+         func_name = NULL;
+         find_pc_partial_function (item->pc, &func_name, &start, &end);
+
+         if (func_name != NULL && item->pc < end)
+           {
+             if (item->line == line_num)
+               return line_num;
+             else 
+               {
+                 struct symbol* sym = 
+                   standard_lookup (func_name, VAR_NAMESPACE);
+                 if (is_plausible_func_for_line (sym, line_num))
+                   best = item->line;
+                 else
+                   {
+                     do
+                       i += 1;
+                     while (i < len && linetable->item[i].pc < end);
+                     continue;
+                   }
+               }
+           }
+       }
+
+      i += 1;
+    }
+
+  return (best == INT_MAX) ? -1 : best;
+}
+
+
+/* Return the next higher index, k, into LINETABLE such that k > IND, 
+   entry k in LINETABLE has a line number equal to LINE_NUM, k
+   corresponds to a PC that is in a function different from that 
+   corresponding to IND, and falls strictly within a named function
+   that begins at a line at or preceding STARTING_LINE.  
+   Return -1 if there is no such k.  
+   IND == -1 corresponds to no function. */
+
+static int
+find_next_line_in_linetable (linetable, line_num, starting_line, ind)
+     struct linetable* linetable;
+     int line_num;
+     int starting_line;
+     int ind;
+{
+  int i, len;
+
+  if (line_num <= 0 || linetable == NULL || ind >= linetable->nitems)
+    return -1;
+  len = linetable->nitems;
+
+  if (ind >= 0) 
+    {
+      CORE_ADDR start, end;
+
+      if (find_pc_partial_function (linetable->item[ind].pc,
+                                   (char**) NULL, &start, &end)) 
+       {
+         while (ind < len && linetable->item[ind].pc < end)
+           ind += 1;
+       }
+      else
+       ind += 1;
+    }
+  else
+    ind = 0;
+
+  i = ind;
+  while (i < len)
+    {
+      int k;
+      struct linetable_entry* item = &(linetable->item[i]);
+
+      if (item->line >= line_num)
+       {
+         char* func_name;
+         CORE_ADDR start, end;
+
+         func_name = NULL;
+         find_pc_partial_function (item->pc, &func_name, &start, &end);
+
+         if (func_name != NULL && item->pc < end)
+           {
+             if (item->line == line_num)
+               {
+                 struct symbol* sym = 
+                   standard_lookup (func_name, VAR_NAMESPACE);
+                 if (is_plausible_func_for_line (sym, starting_line))
+                   return i;
+                 else
+                   {
+                     while ((i+1) < len && linetable->item[i+1].pc < end)
+                       i += 1;
+                   }
+               }
+           }
+       }
+      i += 1;
+    }
+
+  return -1;
+}
+
+/* True iff function symbol SYM starts somewhere at or before line #
+   LINE_NUM. */
+static int
+is_plausible_func_for_line (sym, line_num)
+     struct symbol* sym;
+     int line_num;
+{
+  struct symtab_and_line start_sal;
+
+  if (sym == NULL)
+    return 0;
+
+  start_sal = find_function_start_sal (sym, 0);
+
+  return (start_sal.line != 0 && line_num >= start_sal.line);
+}
+
+static void
+debug_print_lines (lt)
+     struct linetable* lt;
+{
+  int i;
+
+  if (lt == NULL) 
+    return;
+
+  fprintf (stderr, "\t");
+  for (i = 0; i < lt->nitems; i += 1)
+    fprintf (stderr, "(%d->%p) ", lt->item[i].line, (void *) lt->item[i].pc);
+  fprintf (stderr, "\n");
+}
+
+static void
+debug_print_block (b)
+     struct block* b;
+{
+  int i;
+  fprintf (stderr, "Block: %p; [0x%lx, 0x%lx]", 
+          b, BLOCK_START(b), BLOCK_END(b));
+  if (BLOCK_FUNCTION(b) != NULL)
+    fprintf (stderr, " Function: %s", SYMBOL_NAME (BLOCK_FUNCTION(b)));
+  fprintf (stderr, "\n");
+  fprintf (stderr, "\t    Superblock: %p\n", BLOCK_SUPERBLOCK(b));
+  fprintf (stderr, "\t    Symbols:");
+  for (i = 0; i < BLOCK_NSYMS (b); i += 1)
+    {
+      if (i > 0 && i % 4 == 0)
+       fprintf (stderr, "\n\t\t    ");
+      fprintf (stderr, " %s", SYMBOL_NAME (BLOCK_SYM (b, i)));
+    }
+  fprintf (stderr, "\n");
+}
+
+static void
+debug_print_blocks (bv)
+     struct blockvector* bv;
+{
+  int i;
+
+  if (bv == NULL)
+    return;
+  for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); i += 1) {
+    fprintf (stderr, "%6d. ", i);
+    debug_print_block (BLOCKVECTOR_BLOCK (bv, i));
+  }
+}
+
+static void
+debug_print_symtab (s)
+     struct symtab* s;
+{
+  fprintf (stderr, "Symtab %p\n    File: %s; Dir: %s\n", s,
+          s->filename, s->dirname);
+  fprintf (stderr, "    Blockvector: %p, Primary: %d\n",
+          BLOCKVECTOR(s), s->primary);
+  debug_print_blocks (BLOCKVECTOR(s));
+  fprintf (stderr, "    Line table: %p\n", LINETABLE (s));
+  debug_print_lines (LINETABLE(s));
+}
+
+/* Read in all symbol tables corresponding to partial symbol tables
+   with file name FILENAME. */
+static void
+read_all_symtabs (filename)
+     const char* filename;
+{
+  struct partial_symtab* ps;
+  struct objfile* objfile;
+
+  ALL_PSYMTABS (objfile, ps)
+    {
+      QUIT;
+
+      if (STREQ (filename, ps->filename))
+       PSYMTAB_TO_SYMTAB (ps);
+    }
+}
+
+/* All sals corresponding to line LINE_NUM in a symbol table from file
+   FILENAME, as filtered by the user.  If CANONICAL is not null, set
+   it to a corresponding array of canonical line specs. */
+static struct symtabs_and_lines
+all_sals_for_line (filename, line_num, canonical)
+     const char* filename;
+     int line_num;
+     char*** canonical;
+{
+  struct symtabs_and_lines result;
+  struct objfile* objfile;
+  struct symtab* s;
+  struct cleanup* old_chain = make_cleanup (null_cleanup, NULL);
+  size_t len;
+
+  read_all_symtabs (filename);
+
+  result.sals = (struct symtab_and_line*) xmalloc (4 * sizeof (result.sals[0]));
+  result.nelts = 0;
+  len = 4;
+  make_cleanup (free_current_contents, &result.sals);
+
+  ALL_SYMTABS (objfile, s) 
+    {
+      int ind, target_line_num;
+
+      QUIT;
+
+      if (!STREQ (s->filename, filename))
+       continue;
+
+      target_line_num = 
+       nearest_line_number_in_linetable (LINETABLE (s), line_num);
+      if (target_line_num == -1)
+       continue;
+
+      ind = -1;
+      while (1) 
+       {
+         ind = 
+           find_next_line_in_linetable (LINETABLE (s),
+                                        target_line_num, line_num, ind);
+         
+         if (ind < 0)
+           break;
+
+         GROW_VECT (result.sals, len, result.nelts+1);
+         INIT_SAL (&result.sals[result.nelts]);
+         result.sals[result.nelts].line = LINETABLE(s)->item[ind].line;
+         result.sals[result.nelts].pc = LINETABLE(s)->item[ind].pc;
+         result.sals[result.nelts].symtab = s;
+         result.nelts += 1;
+       }
+    }
+
+  if (canonical != NULL || result.nelts > 1)
+    {
+      int k;
+      char** func_names = (char**) alloca (result.nelts * sizeof (char*));
+      int first_choice = (result.nelts > 1) ? 2 : 1;
+      int n;
+      int* choices = (int*) alloca (result.nelts * sizeof (int));
+      
+      for (k = 0; k < result.nelts; k += 1) 
+       {
+         find_pc_partial_function (result.sals[k].pc, &func_names[k], 
+                                   (CORE_ADDR*) NULL, (CORE_ADDR*) NULL);
+         if (func_names[k] == NULL)
+           error ("Could not find function for one or more breakpoints.");
+       }
+      
+      if (result.nelts > 1) 
+       {
+         printf_unfiltered("[0] cancel\n");
+         if (result.nelts > 1) 
+           printf_unfiltered("[1] all\n");
+         for (k = 0; k < result.nelts; k += 1)
+           printf_unfiltered ("[%d] %s\n", k + first_choice, 
+                              ada_demangle (func_names[k]));
+         
+         n = get_selections (choices, result.nelts, result.nelts,
+                             result.nelts > 1, "instance-choice");
+      
+         for (k = 0; k < n; k += 1) 
+           {
+             result.sals[k] = result.sals[choices[k]];
+             func_names[k] = func_names[choices[k]];
+           }
+         result.nelts = n;
+       }
+
+      if (canonical != NULL) 
+       {
+         *canonical = (char**) xmalloc (result.nelts * sizeof (char**));
+         make_cleanup (free, *canonical);
+         for (k = 0; k < result.nelts; k += 1) 
+           {
+             (*canonical)[k] = 
+               extended_canonical_line_spec (result.sals[k], func_names[k]);
+             if ((*canonical)[k] == NULL)
+               error ("Could not locate one or more breakpoints.");
+             make_cleanup (free, (*canonical)[k]);
+           }
+       }
+    }
+
+  discard_cleanups (old_chain);
+  return result;
+}
+
+
+/* A canonical line specification of the form FILE:NAME:LINENUM for
+   symbol table and line data SAL.  NULL if insufficient
+   information. The caller is responsible for releasing any space
+   allocated. */
+
+static char*
+extended_canonical_line_spec (sal, name)
+     struct symtab_and_line sal;
+     const char* name;
+{
+  char* r;
+
+  if (sal.symtab == NULL || sal.symtab->filename == NULL || 
+      sal.line <= 0)
+    return NULL;
+
+  r = (char*) xmalloc (strlen (name) + strlen (sal.symtab->filename)  
+                      + sizeof(sal.line)*3 + 3);
+  sprintf (r, "%s:'%s':%d", sal.symtab->filename, name, sal.line);
+  return r;
+}
+
+#if 0
+int begin_bnum = -1;
+#endif
+int begin_annotate_level = 0;
+
+static void 
+begin_cleanup (void* dummy) 
+{
+  begin_annotate_level = 0;
+}
+
+static void
+begin_command (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  struct minimal_symbol *msym;
+  CORE_ADDR main_program_name_addr;
+  char main_program_name[1024];
+  struct cleanup* old_chain = make_cleanup (begin_cleanup, NULL);
+  begin_annotate_level = 2;
+
+  /* Check that there is a program to debug */
+  if (!have_full_symbols () && !have_partial_symbols ())
+    error ("No symbol table is loaded.  Use the \"file\" command.");
+  
+  /* Check that we are debugging an Ada program */
+  /*  if (ada_update_initial_language (language_unknown, NULL) != language_ada)
+    error ("Cannot find the Ada initialization procedure.  Is this an Ada main program?");
+  */
+  /* FIXME: language_ada should be defined in defs.h */
+
+  /* Get the address of the name of the main procedure */
+  msym = lookup_minimal_symbol (ADA_MAIN_PROGRAM_SYMBOL_NAME, NULL, NULL);
+
+  if (msym != NULL)
+  {
+    main_program_name_addr = SYMBOL_VALUE_ADDRESS (msym);
+    if (main_program_name_addr == 0)
+      error ("Invalid address for Ada main program name.");
+
+    /* Read the name of the main procedure */
+    extract_string (main_program_name_addr, main_program_name);
+
+    /* Put a temporary breakpoint in the Ada main program and run */
+    do_command ("tbreak ", main_program_name, 0);
+    do_command ("run ", args, 0);
+  }
+  else
+  {
+    /* If we could not find the symbol containing the name of the
+       main program, that means that the compiler that was used to build
+       was not recent enough. In that case, we fallback to the previous
+       mechanism, which is a little bit less reliable, but has proved to work
+       in most cases. The only cases where it will fail is when the user
+       has set some breakpoints which will be hit before the end of the
+       begin command processing (eg in the initialization code).
+
+       The begining of the main Ada subprogram is located by breaking
+       on the adainit procedure. Since we know that the binder generates
+       the call to this procedure exactly 2 calls before the call to the
+       Ada main subprogram, it is then easy to put a breakpoint on this
+       Ada main subprogram once we hit adainit.
+     */
+     do_command ("tbreak adainit", 0);
+     do_command ("run ", args, 0);
+     do_command ("up", 0);
+     do_command ("tbreak +2", 0);
+     do_command ("continue", 0);
+     do_command ("step", 0);
+  }
+
+  do_cleanups (old_chain);
+}
+
+int
+is_ada_runtime_file (filename)
+     char *filename;
+{
+  return (STREQN (filename, "s-", 2) ||
+         STREQN (filename, "a-", 2) ||
+         STREQN (filename, "g-", 2) ||
+         STREQN (filename, "i-", 2));
+}
+
+/* find the first frame that contains debugging information and that is not
+   part of the Ada run-time, starting from fi and moving upward. */
+
+int
+find_printable_frame (fi, level)
+     struct frame_info *fi;
+     int level;
+{
+  struct symtab_and_line sal;
+  
+  for (; fi != NULL; level += 1, fi = get_prev_frame (fi))
+    {
+      /* If fi is not the innermost frame, that normally means that fi->pc
+        points to *after* the call instruction, and we want to get the line
+        containing the call, never the next line.  But if the next frame is
+        a signal_handler_caller or a dummy frame, then the next frame was
+        not entered as the result of a call, and we want to get the line
+        containing fi->pc.  */
+      sal =
+        find_pc_line (fi->pc,
+                     fi->next != NULL
+                     && !fi->next->signal_handler_caller
+                     && !frame_in_dummy (fi->next));
+      if (sal.symtab && !is_ada_runtime_file (sal.symtab->filename))
+       {
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+       /* libpthread.so contains some debugging information that prevents us
+          from finding the right frame */
+
+         if (sal.symtab->objfile &&
+             STREQ (sal.symtab->objfile->name, "/usr/shlib/libpthread.so"))
+             continue;
+#endif
+         selected_frame = fi;
+         break;
+       }
+    }
+
+  return level;
+}
+
+void
+ada_report_exception_break (b)
+     struct breakpoint *b;
+{
+#ifdef UI_OUT
+  /* FIXME: break_on_exception should be defined in breakpoint.h */
+  /*  if (b->break_on_exception == 1)
+    {
+      /* Assume that cond has 16 elements, the 15th
+        being the exception */ /*
+      if (b->cond && b->cond->nelts == 16)
+       {
+         ui_out_text (uiout, "on ");
+         ui_out_field_string (uiout, "exception",
+                              SYMBOL_NAME (b->cond->elts[14].symbol));
+       }
+      else
+       ui_out_text (uiout, "on all exceptions");
+    }
+  else if (b->break_on_exception == 2)
+    ui_out_text (uiout, "on unhandled exception");
+  else if (b->break_on_exception == 3)
+    ui_out_text (uiout, "on assert failure");
+#else
+  if (b->break_on_exception == 1)
+  {*/
+      /* Assume that cond has 16 elements, the 15th
+        being the exception */ /*
+      if (b->cond && b->cond->nelts == 16)
+       {
+         fputs_filtered ("on ", gdb_stdout);
+         fputs_filtered (SYMBOL_NAME
+                         (b->cond->elts[14].symbol), gdb_stdout);
+       }
+      else
+       fputs_filtered ("on all exceptions", gdb_stdout);
+    }
+  else if (b->break_on_exception == 2)
+    fputs_filtered ("on unhandled exception", gdb_stdout);
+  else if (b->break_on_exception == 3)
+    fputs_filtered ("on assert failure", gdb_stdout);
+*/    
+#endif
+}
+
+int
+ada_is_exception_sym (struct symbol* sym)
+{
+  char *type_name = type_name_no_tag (SYMBOL_TYPE (sym));
+  
+  return (SYMBOL_CLASS (sym) != LOC_TYPEDEF
+         && SYMBOL_CLASS (sym) != LOC_BLOCK
+         && SYMBOL_CLASS (sym) != LOC_CONST
+         && type_name != NULL
+         && STREQ (type_name, "exception"));
+}
+
+int
+ada_maybe_exception_partial_symbol (struct partial_symbol* sym)
+{
+  return (SYMBOL_CLASS (sym) != LOC_TYPEDEF
+         && SYMBOL_CLASS (sym) != LOC_BLOCK
+         && SYMBOL_CLASS (sym) != LOC_CONST);
+}
+
+/* If ARG points to an Ada exception or assert breakpoint, rewrite
+   into equivalent form.  Return resulting argument string. Set
+   *BREAK_ON_EXCEPTIONP to 1 for ordinary break on exception, 2 for
+   break on unhandled, 3 for assert, 0 otherwise. */
+char* ada_breakpoint_rewrite (char* arg, int* break_on_exceptionp)
+{
+  if (arg == NULL)
+    return arg;
+  *break_on_exceptionp = 0;
+  /* FIXME: language_ada should be defined in defs.h */  
+  /*  if (current_language->la_language == language_ada
+      && STREQN (arg, "exception", 9) &&
+      (arg[9] == ' ' || arg[9] == '\t' || arg[9] == '\0'))
+    {
+      char *tok, *end_tok;
+      int toklen;
+
+      *break_on_exceptionp = 1;
+
+      tok = arg+9;
+      while (*tok == ' ' || *tok == '\t')
+       tok += 1;
+
+      end_tok = tok;
+
+      while (*end_tok != ' ' && *end_tok != '\t' && *end_tok != '\000')
+       end_tok += 1;
+
+      toklen = end_tok - tok;
+
+      arg = (char*) xmalloc (sizeof ("__gnat_raise_nodefer_with_msg if "
+                                    "long_integer(e) = long_integer(&)")
+                            + toklen + 1);
+      make_cleanup (free, arg);
+      if (toklen == 0)
+       strcpy (arg, "__gnat_raise_nodefer_with_msg");
+      else if (STREQN (tok, "unhandled", toklen))
+       {
+         *break_on_exceptionp = 2;
+         strcpy (arg, "__gnat_unhandled_exception");
+       }
+      else
+       {
+         sprintf (arg, "__gnat_raise_nodefer_with_msg if "
+                  "long_integer(e) = long_integer(&%.*s)", 
+                  toklen, tok);
+       }
+    }
+  else if (current_language->la_language == language_ada
+          && STREQN (arg, "assert", 6) &&
+          (arg[6] == ' ' || arg[6] == '\t' || arg[6] == '\0'))
+    {
+      char *tok = arg + 6;
+
+      *break_on_exceptionp = 3;
+
+      arg = (char*) 
+       xmalloc (sizeof ("system__assertions__raise_assert_failure")
+                + strlen (tok) + 1);
+      make_cleanup (free, arg);
+      sprintf (arg, "system__assertions__raise_assert_failure%s", tok);
+    }
+  */
+  return arg;
+}
+
+\f
+                               /* Field Access */
+
+/* True if field number FIELD_NUM in struct or union type TYPE is supposed
+   to be invisible to users. */
+
+int
+ada_is_ignored_field (type, field_num)
+     struct type *type;
+     int field_num;
+{
+  if (field_num < 0 || field_num > TYPE_NFIELDS (type))
+    return 1;
+  else 
+    {
+      const char* name = TYPE_FIELD_NAME (type, field_num);
+      return (name == NULL
+             || (name[0] == '_' && ! STREQN (name, "_parent", 7)));
+    }
+}
+
+/* True iff structure type TYPE has a tag field. */
+
+int
+ada_is_tagged_type (type)
+     struct type *type;
+{
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT)
+    return 0;
+
+  return (ada_lookup_struct_elt_type (type, "_tag", 1, NULL) != NULL);
+}
+
+/* The type of the tag on VAL. */
+
+struct type*
+ada_tag_type (val)
+     struct value* val;
+{
+  return ada_lookup_struct_elt_type (VALUE_TYPE (val), "_tag", 0, NULL);
+}
+
+/* The value of the tag on VAL. */
+
+struct value*
+ada_value_tag (val)
+     struct value* val;
+{
+  return ada_value_struct_elt (val, "_tag", "record");
+}
+
+/* The parent type of TYPE, or NULL if none. */
+
+struct type*
+ada_parent_type (type)
+     struct type *type;
+{
+  int i;
+
+  CHECK_TYPEDEF (type);
+
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT)
+    return NULL;
+
+  for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+    if (ada_is_parent_field (type, i))
+      return check_typedef (TYPE_FIELD_TYPE (type, i));
+
+  return NULL;
+}
+
+/* True iff field number FIELD_NUM of structure type TYPE contains the 
+   parent-type (inherited) fields of a derived type.  Assumes TYPE is 
+   a structure type with at least FIELD_NUM+1 fields. */
+
+int
+ada_is_parent_field (type, field_num)
+     struct type *type;
+     int field_num;
+{
+  const char* name = TYPE_FIELD_NAME (check_typedef (type), field_num);
+  return (name != NULL && 
+         (STREQN (name, "PARENT", 6) || STREQN (name, "_parent", 7)));
+}
+
+/* True iff field number FIELD_NUM of structure type TYPE is a 
+   transparent wrapper field (which should be silently traversed when doing
+   field selection and flattened when printing).  Assumes TYPE is a 
+   structure type with at least FIELD_NUM+1 fields.  Such fields are always
+   structures. */
+
+int
+ada_is_wrapper_field (type, field_num)
+     struct type *type;
+     int field_num;
+{
+  const char* name = TYPE_FIELD_NAME (type, field_num);
+  return (name != NULL 
+         && (STREQN (name, "PARENT", 6) || STREQ (name, "REP") 
+             || STREQN (name, "_parent", 7)
+             || name[0] == 'S' || name[0] == 'R' || name[0] == 'O'));
+}
+
+/* True iff field number FIELD_NUM of structure or union type TYPE 
+   is a variant wrapper.  Assumes TYPE is a structure type with at least 
+   FIELD_NUM+1 fields. */ 
+
+int
+ada_is_variant_part (type, field_num)
+     struct type *type;
+     int field_num;
+{
+  struct type* field_type = TYPE_FIELD_TYPE (type, field_num);
+  return (TYPE_CODE (field_type) == TYPE_CODE_UNION
+         || (is_dynamic_field (type, field_num)
+             && TYPE_CODE (TYPE_TARGET_TYPE (field_type)) == TYPE_CODE_UNION));
+}
+
+/* Assuming that VAR_TYPE is a variant wrapper (type of the variant part)
+   whose discriminants are contained in the record type OUTER_TYPE, 
+   returns the type of the controlling discriminant for the variant.  */
+
+struct type*
+ada_variant_discrim_type (var_type, outer_type)
+     struct type *var_type;
+     struct type *outer_type;
+{
+  char* name = ada_variant_discrim_name (var_type);
+  struct type *type = 
+    ada_lookup_struct_elt_type (outer_type, name, 1, NULL);
+  if (type == NULL)
+    return builtin_type_int;
+  else
+    return type;
+}
+
+/* Assuming that TYPE is the type of a variant wrapper, and FIELD_NUM is a 
+   valid field number within it, returns 1 iff field FIELD_NUM of TYPE
+   represents a 'when others' clause; otherwise 0. */
+
+int
+ada_is_others_clause (type, field_num)
+     struct type *type;
+     int field_num;
+{
+  const char* name = TYPE_FIELD_NAME (type, field_num);
+  return (name != NULL && name[0] == 'O');
+}
+
+/* Assuming that TYPE0 is the type of the variant part of a record,
+   returns the name of the discriminant controlling the variant.  The
+   value is valid until the next call to ada_variant_discrim_name. */
+
+char * 
+ada_variant_discrim_name (type0)
+     struct type *type0;
+{
+  static char* result = NULL;
+  static size_t result_len = 0;
+  struct type* type;
+  const char* name;
+  const char* discrim_end; 
+  const char* discrim_start;
+
+  if (TYPE_CODE (type0) == TYPE_CODE_PTR)
+    type = TYPE_TARGET_TYPE (type0);
+  else
+    type = type0;
+
+  name = ada_type_name (type);
+
+  if (name == NULL || name[0] == '\000')
+    return "";
+
+  for (discrim_end = name + strlen (name) - 6; discrim_end != name;
+       discrim_end -= 1)
+    {
+      if (STREQN (discrim_end, "___XVN", 6))
+       break;
+    }
+  if (discrim_end == name)
+    return "";
+
+  for (discrim_start = discrim_end; discrim_start != name+3;
+       discrim_start -= 1)
+    {
+      if (discrim_start == name+1)
+       return "";
+      if ((discrim_start > name+3 && STREQN (discrim_start-3, "___", 3))
+         || discrim_start[-1] == '.')
+       break;
+    }
+
+  GROW_VECT (result, result_len, discrim_end - discrim_start + 1);
+  strncpy (result, discrim_start, discrim_end - discrim_start);
+  result[discrim_end-discrim_start] = '\0';
+  return result;
+}
+
+/* Scan STR for a subtype-encoded number, beginning at position K. Put the 
+   position of the character just past the number scanned in *NEW_K, 
+   if NEW_K!=NULL. Put the scanned number in *R, if R!=NULL.  Return 1 
+   if there was a valid number at the given position, and 0 otherwise.  A 
+   "subtype-encoded" number consists of the absolute value in decimal, 
+   followed by the letter 'm' to indicate a negative number.  Assumes 0m 
+   does not occur. */
+
+int
+ada_scan_number (str, k, R, new_k)
+     const char str[];
+     int k;
+     LONGEST *R;
+     int *new_k;
+{
+  ULONGEST RU;
+
+  if (! isdigit (str[k]))
+    return 0;
+
+  /* Do it the hard way so as not to make any assumption about 
+     the relationship of unsigned long (%lu scan format code) and
+     LONGEST. */
+  RU = 0;
+  while (isdigit (str[k]))
+    {
+      RU = RU*10 + (str[k] - '0');
+      k += 1;
+    }
+
+  if (str[k] == 'm') 
+    {
+      if (R != NULL)
+       *R = (- (LONGEST) (RU-1)) - 1;
+      k += 1;
+    }
+  else if (R != NULL)
+    *R = (LONGEST) RU;
+
+  /* NOTE on the above: Technically, C does not say what the results of 
+     - (LONGEST) RU or (LONGEST) -RU are for RU == largest positive
+     number representable as a LONGEST (although either would probably work
+     in most implementations).  When RU>0, the locution in the then branch
+     above is always equivalent to the negative of RU. */
+
+  if (new_k != NULL)
+    *new_k = k;
+  return 1;
+}
+
+/* Assuming that TYPE is a variant part wrapper type (a VARIANTS field), 
+   and FIELD_NUM is a valid field number within it, returns 1 iff VAL is 
+   in the range encoded by field FIELD_NUM of TYPE; otherwise 0. */
+
+int 
+ada_in_variant (val, type, field_num)
+     LONGEST val;
+     struct type *type;
+     int field_num;
+{
+  const char* name = TYPE_FIELD_NAME (type, field_num);
+  int p;
+
+  p = 0;
+  while (1)
+    {
+      switch (name[p]) 
+       {
+       case '\0':
+         return 0;
+       case 'S':
+         {
+           LONGEST W;
+           if (! ada_scan_number (name, p + 1, &W, &p))
+             return 0;
+           if (val == W)
+             return 1;
+           break;
+         }
+       case 'R':
+         {
+           LONGEST L, U;
+           if (! ada_scan_number (name, p + 1, &L, &p)
+               || name[p] != 'T'
+               || ! ada_scan_number (name, p + 1, &U, &p))
+             return 0;
+           if (val >= L && val <= U)
+             return 1;
+           break;
+         }
+       case 'O':
+         return 1;
+       default:
+         return 0;
+       }
+    }
+}
+
+/* Given a value ARG1 (offset by OFFSET bytes)
+   of a struct or union type ARG_TYPE,
+   extract and return the value of one of its (non-static) fields.
+   FIELDNO says which field.   Differs from value_primitive_field only
+   in that it can handle packed values of arbitrary type. */
+
+struct value*
+ada_value_primitive_field (arg1, offset, fieldno, arg_type)
+     struct value* arg1;
+     int offset;
+     int fieldno;
+     struct type *arg_type;
+{
+  struct value* v;
+  struct type *type;
+
+  CHECK_TYPEDEF (arg_type);
+  type = TYPE_FIELD_TYPE (arg_type, fieldno);
+
+  /* Handle packed fields */
+
+  if (TYPE_FIELD_BITSIZE (arg_type, fieldno) != 0)
+    {
+      int bit_pos = TYPE_FIELD_BITPOS (arg_type, fieldno);
+      int bit_size = TYPE_FIELD_BITSIZE (arg_type, fieldno);
+      
+      return ada_value_primitive_packed_val (arg1, VALUE_CONTENTS (arg1),
+                                            offset + bit_pos/8, bit_pos % 8,
+                                            bit_size, type);
+    }
+  else
+    return value_primitive_field (arg1, offset, fieldno, arg_type);
+}
+
+
+/* Look for a field NAME in ARG. Adjust the address of ARG by OFFSET bytes,
+   and search in it assuming it has (class) type TYPE.
+   If found, return value, else return NULL.
+
+   Searches recursively through wrapper fields (e.g., '_parent'). */
+
+struct value*
+ada_search_struct_field (name, arg, offset, type)
+     char *name;
+     struct value* arg;
+     int offset;
+     struct type *type;
+{
+  int i;
+  CHECK_TYPEDEF (type);
+
+  for (i = TYPE_NFIELDS (type)-1; i >= 0; i -= 1)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+
+      if (t_field_name == NULL)
+       continue;
+
+      else if (field_name_match (t_field_name, name))
+         return ada_value_primitive_field (arg, offset, i, type);
+
+      else if (ada_is_wrapper_field (type, i))
+       {
+         struct value* v = 
+           ada_search_struct_field (name, arg, 
+                                    offset + TYPE_FIELD_BITPOS (type, i) / 8, 
+                                    TYPE_FIELD_TYPE (type, i));
+         if (v != NULL)
+           return v;
+       }
+
+      else if (ada_is_variant_part (type, i))
+       {
+         int j;
+         struct type *field_type = check_typedef (TYPE_FIELD_TYPE (type, i));
+         int var_offset = offset + TYPE_FIELD_BITPOS (type, i) / 8;
+
+         for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1)
+           {
+             struct value* v = 
+               ada_search_struct_field (name, arg, 
+                                        var_offset 
+                                        + TYPE_FIELD_BITPOS (field_type, j)/8,
+                                        TYPE_FIELD_TYPE (field_type, j));
+             if (v != NULL)
+               return v;
+           }
+       }
+    }
+  return NULL;
+}
+  
+/* Given ARG, a value of type (pointer to a)* structure/union,
+   extract the component named NAME from the ultimate target structure/union
+   and return it as a value with its appropriate type.
+
+   The routine searches for NAME among all members of the structure itself 
+   and (recursively) among all members of any wrapper members 
+   (e.g., '_parent').
+
+   ERR is a name (for use in error messages) that identifies the class 
+   of entity that ARG is supposed to be. */
+
+struct value*
+ada_value_struct_elt (arg, name, err)
+     struct value* arg;
+     char *name;
+     char *err;
+{
+  struct type *t;
+  struct value* v;
+
+  arg = ada_coerce_ref (arg);
+  t = check_typedef (VALUE_TYPE (arg));
+
+  /* Follow pointers until we get to a non-pointer.  */
+
+  while (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_CODE (t) == TYPE_CODE_REF)
+    {
+      arg = ada_value_ind (arg);
+      t = check_typedef (VALUE_TYPE (arg));
+    }
+
+  if (   TYPE_CODE (t) != TYPE_CODE_STRUCT
+      && TYPE_CODE (t) != TYPE_CODE_UNION)
+    error ("Attempt to extract a component of a value that is not a %s.", err);
+
+  v = ada_search_struct_field (name, arg, 0, t);
+  if (v == NULL)
+    error ("There is no member named %s.", name);
+
+  return v;
+}
+
+/* Given a type TYPE, look up the type of the component of type named NAME.
+   If DISPP is non-null, add its byte displacement from the beginning of a 
+   structure (pointed to by a value) of type TYPE to *DISPP (does not 
+   work for packed fields).
+
+   Matches any field whose name has NAME as a prefix, possibly
+   followed by "___". 
+
+   TYPE can be either a struct or union, or a pointer or reference to 
+   a struct or union.  If it is a pointer or reference, its target 
+   type is automatically used.
+
+   Looks recursively into variant clauses and parent types.
+
+   If NOERR is nonzero, return NULL if NAME is not suitably defined. */
+
+struct type *
+ada_lookup_struct_elt_type (type, name, noerr, dispp)
+     struct type *type;
+     char *name;
+     int noerr;
+     int *dispp;
+{
+  int i;
+
+  if (name == NULL)
+    goto BadName;
+
+  while (1)
+    {
+      CHECK_TYPEDEF (type);
+      if (TYPE_CODE (type) != TYPE_CODE_PTR
+         && TYPE_CODE (type) != TYPE_CODE_REF)
+       break;
+      type = TYPE_TARGET_TYPE (type);
+    }
+
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT &&
+      TYPE_CODE (type) != TYPE_CODE_UNION)
+    {
+      target_terminal_ours ();
+      gdb_flush (gdb_stdout);
+      fprintf_unfiltered (gdb_stderr, "Type ");
+      type_print (type, "", gdb_stderr, -1);
+      error (" is not a structure or union type");
+    }
+
+  type = to_static_fixed_type (type);
+
+  for (i = 0; i < TYPE_NFIELDS (type); i += 1)
+    {
+      char *t_field_name = TYPE_FIELD_NAME (type, i);
+      struct type *t;
+      int disp;
+  
+      if (t_field_name == NULL)
+       continue;
+
+      else if (field_name_match (t_field_name, name))
+       {
+         if (dispp != NULL) 
+           *dispp += TYPE_FIELD_BITPOS (type, i) / 8;
+         return check_typedef (TYPE_FIELD_TYPE (type, i));
+       }
+
+      else if (ada_is_wrapper_field (type, i))
+       {
+         disp = 0;
+         t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (type, i), name, 
+                                         1, &disp);
+         if (t != NULL)
+           {
+             if (dispp != NULL)
+               *dispp += disp + TYPE_FIELD_BITPOS (type, i) / 8;
+             return t;
+           }
+       }
+
+      else if (ada_is_variant_part (type, i))
+       {
+         int j;
+         struct type *field_type = check_typedef (TYPE_FIELD_TYPE (type, i));
+
+         for (j = TYPE_NFIELDS (field_type) - 1; j >= 0; j -= 1)
+           {
+             disp = 0;
+             t = ada_lookup_struct_elt_type (TYPE_FIELD_TYPE (field_type, j),
+                                             name, 1, &disp);
+             if (t != NULL)
+               {
+                 if (dispp != NULL) 
+                   *dispp += disp + TYPE_FIELD_BITPOS (type, i) / 8;
+                 return t;
+               }
+           }
+       }
+
+    }
+
+BadName:
+  if (! noerr)
+    {
+      target_terminal_ours ();
+      gdb_flush (gdb_stdout);
+      fprintf_unfiltered (gdb_stderr, "Type ");
+      type_print (type, "", gdb_stderr, -1);
+      fprintf_unfiltered (gdb_stderr, " has no component named ");
+      error ("%s", name == NULL ? "<null>" : name);
+    }
+
+  return NULL;
+}
+
+/* Assuming that VAR_TYPE is the type of a variant part of a record (a union),
+   within a value of type OUTER_TYPE that is stored in GDB at
+   OUTER_VALADDR, determine which variant clause (field number in VAR_TYPE, 
+   numbering from 0) is applicable.  Returns -1 if none are. */
+
+int 
+ada_which_variant_applies (var_type, outer_type, outer_valaddr)
+     struct type *var_type;
+     struct type *outer_type;
+     char* outer_valaddr;
+{
+  int others_clause;
+  int i;
+  int disp;
+  struct type* discrim_type;
+  char* discrim_name = ada_variant_discrim_name (var_type);
+  LONGEST discrim_val;
+
+  disp = 0;
+  discrim_type = 
+    ada_lookup_struct_elt_type (outer_type, discrim_name, 1, &disp);
+  if (discrim_type == NULL)
+    return -1;
+  discrim_val = unpack_long (discrim_type, outer_valaddr + disp);
+
+  others_clause = -1;
+  for (i = 0; i < TYPE_NFIELDS (var_type); i += 1)
+    {
+      if (ada_is_others_clause (var_type, i))
+       others_clause = i;
+      else if (ada_in_variant (discrim_val, var_type, i))
+       return i;
+    }
+
+  return others_clause;
+}
+
+
+\f
+                               /* Dynamic-Sized Records */
+
+/* Strategy: The type ostensibly attached to a value with dynamic size
+   (i.e., a size that is not statically recorded in the debugging
+   data) does not accurately reflect the size or layout of the value.
+   Our strategy is to convert these values to values with accurate,
+   conventional types that are constructed on the fly. */
+
+/* There is a subtle and tricky problem here.  In general, we cannot
+   determine the size of dynamic records without its data.  However,
+   the 'struct value' data structure, which GDB uses to represent
+   quantities in the inferior process (the target), requires the size
+   of the type at the time of its allocation in order to reserve space
+   for GDB's internal copy of the data.  That's why the
+   'to_fixed_xxx_type' routines take (target) addresses as parameters,
+   rather than struct value*s.  
+
+   However, GDB's internal history variables ($1, $2, etc.) are
+   struct value*s containing internal copies of the data that are not, in
+   general, the same as the data at their corresponding addresses in
+   the target.  Fortunately, the types we give to these values are all
+   conventional, fixed-size types (as per the strategy described
+   above), so that we don't usually have to perform the
+   'to_fixed_xxx_type' conversions to look at their values.
+   Unfortunately, there is one exception: if one of the internal
+   history variables is an array whose elements are unconstrained
+   records, then we will need to create distinct fixed types for each
+   element selected.  */
+
+/* The upshot of all of this is that many routines take a (type, host
+   address, target address) triple as arguments to represent a value.
+   The host address, if non-null, is supposed to contain an internal
+   copy of the relevant data; otherwise, the program is to consult the
+   target at the target address. */
+
+/* Assuming that VAL0 represents a pointer value, the result of
+   dereferencing it.  Differs from value_ind in its treatment of
+   dynamic-sized types. */
+
+struct value*
+ada_value_ind (val0)
+     struct value* val0;
+{
+  struct value* val = unwrap_value (value_ind (val0));
+  return ada_to_fixed_value (VALUE_TYPE (val), 0,
+                            VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+                            val);
+}
+
+/* The value resulting from dereferencing any "reference to"
+ * qualifiers on VAL0. */
+static struct value* 
+ada_coerce_ref (val0)
+     struct value* val0;
+{
+  if (TYPE_CODE (VALUE_TYPE (val0)) == TYPE_CODE_REF) {
+    struct value* val = val0;
+    COERCE_REF (val);
+    val = unwrap_value (val);
+    return ada_to_fixed_value (VALUE_TYPE (val), 0, 
+                              VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+                              val);
+  } else
+    return val0;
+}
+
+/* Return OFF rounded upward if necessary to a multiple of
+   ALIGNMENT (a power of 2). */
+
+static unsigned int
+align_value (off, alignment)
+     unsigned int off;
+     unsigned int alignment;
+{
+  return (off + alignment - 1) & ~(alignment - 1);
+}
+
+/* Return the additional bit offset required by field F of template
+   type TYPE. */
+
+static unsigned int
+field_offset (type, f)
+     struct type *type;
+     int f;
+{
+  int n = TYPE_FIELD_BITPOS (type, f);
+  /* Kludge (temporary?) to fix problem with dwarf output. */
+  if (n < 0)
+    return (unsigned int) n & 0xffff;
+  else
+    return n;
+}
+
+
+/* Return the bit alignment required for field #F of template type TYPE. */
+
+static unsigned int
+field_alignment (type, f)
+     struct type *type;
+     int f;
+{
+  const char* name = TYPE_FIELD_NAME (type, f);
+  int len = (name == NULL) ? 0 : strlen (name);
+  int align_offset;
+
+  if (len < 8 || ! isdigit (name[len-1]))
+    return TARGET_CHAR_BIT;
+
+  if (isdigit (name[len-2]))
+    align_offset = len - 2;
+  else
+    align_offset = len - 1;
+
+  if (align_offset < 7 || ! STREQN ("___XV", name+align_offset-6, 5))
+    return TARGET_CHAR_BIT;
+
+  return atoi (name+align_offset) * TARGET_CHAR_BIT;
+}
+
+/* Find a type named NAME.  Ignores ambiguity.  */
+struct type*
+ada_find_any_type (name)
+     const char *name;
+{
+  struct symbol* sym;
+
+  sym = standard_lookup (name, VAR_NAMESPACE);
+  if (sym != NULL && SYMBOL_CLASS (sym) == LOC_TYPEDEF)
+    return SYMBOL_TYPE (sym);
+
+  sym = standard_lookup (name, STRUCT_NAMESPACE);
+  if (sym != NULL)
+    return SYMBOL_TYPE (sym);
+
+  return NULL;
+}
+
+/* Because of GNAT encoding conventions, several GDB symbols may match a
+   given type name. If the type denoted by TYPE0 is to be preferred to
+   that of TYPE1 for purposes of type printing, return non-zero;
+   otherwise return 0. */
+int
+ada_prefer_type (type0, type1)
+     struct type* type0;
+     struct type* type1;
+{
+  if (type1 == NULL)
+    return 1;
+  else if (type0 == NULL)
+    return 0;
+  else if (TYPE_CODE (type1) == TYPE_CODE_VOID)
+    return 1;
+  else if (TYPE_CODE (type0) == TYPE_CODE_VOID)
+    return 0;
+  else if (ada_is_packed_array_type (type0))
+    return 1;
+  else if (ada_is_array_descriptor (type0) && ! ada_is_array_descriptor (type1))
+    return 1;
+  else if (ada_renaming_type (type0) != NULL 
+          && ada_renaming_type (type1) == NULL)
+    return 1;
+  return 0;
+}
+
+/* The name of TYPE, which is either its TYPE_NAME, or, if that is
+   null, its TYPE_TAG_NAME.  Null if TYPE is null. */
+char*
+ada_type_name (type)
+     struct type* type;
+{
+  if (type == NULL) 
+    return NULL;
+  else if (TYPE_NAME (type) != NULL)
+    return TYPE_NAME (type);
+  else
+    return TYPE_TAG_NAME (type);
+}
+
+/* Find a parallel type to TYPE whose name is formed by appending
+   SUFFIX to the name of TYPE. */
+
+struct type*
+ada_find_parallel_type (type, suffix)
+     struct type *type;
+     const char *suffix;
+{
+  static char* name;
+  static size_t name_len = 0;
+  struct symbol** syms;
+  struct block** blocks;
+  int nsyms;
+  int len;
+  char* typename = ada_type_name (type);
+  
+  if (typename == NULL)
+    return NULL;
+
+  len = strlen (typename);
+
+  GROW_VECT (name, name_len, len+strlen (suffix)+1);
+
+  strcpy (name, typename);
+  strcpy (name + len, suffix);
+
+  return ada_find_any_type (name);
+}
+
+
+/* If TYPE is a variable-size record type, return the corresponding template
+   type describing its fields.  Otherwise, return NULL. */
+
+static struct type*
+dynamic_template_type (type)
+     struct type* type;
+{
+  CHECK_TYPEDEF (type);
+
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT
+      || ada_type_name (type) == NULL) 
+    return NULL;
+  else 
+    {
+      int len = strlen (ada_type_name (type));
+      if (len > 6 && STREQ (ada_type_name (type) + len - 6, "___XVE"))
+       return type;
+      else
+       return ada_find_parallel_type (type, "___XVE");
+    }
+}
+
+/* Assuming that TEMPL_TYPE is a union or struct type, returns
+   non-zero iff field FIELD_NUM of TEMPL_TYPE has dynamic size. */
+
+static int 
+is_dynamic_field (templ_type, field_num)
+     struct type* templ_type;
+     int field_num;
+{
+  const char *name = TYPE_FIELD_NAME (templ_type, field_num);
+  return name != NULL 
+    && TYPE_CODE (TYPE_FIELD_TYPE (templ_type, field_num)) == TYPE_CODE_PTR
+    && strstr (name, "___XVL") != NULL;
+}
+
+/* Assuming that TYPE is a struct type, returns non-zero iff TYPE
+   contains a variant part. */
+
+static int 
+contains_variant_part (type)
+     struct type* type;
+{
+  int f;
+
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_STRUCT
+      || TYPE_NFIELDS (type) <= 0)
+    return 0;
+  return ada_is_variant_part (type, TYPE_NFIELDS (type) - 1);
+}
+
+/* A record type with no fields, . */
+static struct type*
+empty_record (objfile) 
+     struct objfile* objfile;
+{
+  struct type* type = alloc_type (objfile);
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+  TYPE_NFIELDS (type) = 0;
+  TYPE_FIELDS (type) = NULL;
+  TYPE_NAME (type) = "<empty>";
+  TYPE_TAG_NAME (type) = NULL;
+  TYPE_FLAGS (type) = 0;
+  TYPE_LENGTH (type) = 0;
+  return type;
+}
+
+/* An ordinary record type (with fixed-length fields) that describes
+   the value of type TYPE at VALADDR or ADDRESS (see comments at 
+   the beginning of this section) VAL according to GNAT conventions.  
+   DVAL0 should describe the (portion of a) record that contains any 
+   necessary discriminants.  It should be NULL if VALUE_TYPE (VAL) is
+   an outer-level type (i.e., as opposed to a branch of a variant.)  A
+   variant field (unless unchecked) is replaced by a particular branch
+   of the variant. */
+/* NOTE: Limitations: For now, we assume that dynamic fields and
+ * variants occupy whole numbers of bytes.  However, they need not be
+ * byte-aligned.  */
+
+static struct type*
+template_to_fixed_record_type (type, valaddr, address, dval0)
+     struct type* type;
+     char* valaddr;
+     CORE_ADDR address;
+     struct value* dval0;
+
+{
+  struct value* mark = value_mark();
+  struct value* dval;
+  struct type* rtype;
+  int nfields, bit_len;
+  long off;
+  int f;
+
+  nfields = TYPE_NFIELDS (type);
+  rtype = alloc_type (TYPE_OBJFILE (type));
+  TYPE_CODE (rtype) = TYPE_CODE_STRUCT;
+  INIT_CPLUS_SPECIFIC (rtype);
+  TYPE_NFIELDS (rtype) = nfields;
+  TYPE_FIELDS (rtype) = (struct field*) 
+    TYPE_ALLOC (rtype, nfields * sizeof (struct field));
+  memset (TYPE_FIELDS (rtype), 0, sizeof (struct field) * nfields);
+  TYPE_NAME (rtype) = ada_type_name (type);
+  TYPE_TAG_NAME (rtype) = NULL;
+  /* FIXME: TYPE_FLAG_FIXED_INSTANCE should be defined in
+     gdbtypes.h */  
+  /*  TYPE_FLAGS (rtype) |= TYPE_FLAG_FIXED_INSTANCE;*/
+
+  off = 0; bit_len = 0;
+  for (f = 0; f < nfields; f += 1)
+    {
+      int fld_bit_len, bit_incr;
+      off = 
+       align_value (off, field_alignment (type, f))+TYPE_FIELD_BITPOS (type,f);
+      /* NOTE: used to use field_offset above, but that causes
+       * problems with really negative bit positions.  So, let's
+       * rediscover why we needed field_offset and fix it properly. */
+      TYPE_FIELD_BITPOS (rtype, f) = off;
+      TYPE_FIELD_BITSIZE (rtype, f) = 0;  
+
+      if (ada_is_variant_part (type, f)) 
+       {
+         struct type *branch_type;
+
+         if (dval0 == NULL)
+           dval = 
+             value_from_contents_and_address (rtype, valaddr, address);
+         else
+           dval = dval0;
+
+         branch_type = 
+           to_fixed_variant_branch_type 
+             (TYPE_FIELD_TYPE (type, f),
+              cond_offset_host (valaddr, off / TARGET_CHAR_BIT),
+              cond_offset_target (address, off / TARGET_CHAR_BIT),
+              dval);
+         if (branch_type == NULL) 
+           TYPE_NFIELDS (rtype) -= 1;
+         else
+           {
+             TYPE_FIELD_TYPE (rtype, f) = branch_type;
+             TYPE_FIELD_NAME (rtype, f) = "S";
+           }
+         bit_incr = 0;
+         fld_bit_len =
+           TYPE_LENGTH (TYPE_FIELD_TYPE (rtype, f)) * TARGET_CHAR_BIT;
+       }
+      else if (is_dynamic_field (type, f))
+       {
+         if (dval0 == NULL)
+           dval = 
+             value_from_contents_and_address (rtype, valaddr, address);
+         else
+           dval = dval0;
+
+         TYPE_FIELD_TYPE (rtype, f) = 
+           ada_to_fixed_type 
+             (ada_get_base_type 
+              (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (type, f))),
+              cond_offset_host (valaddr, off / TARGET_CHAR_BIT),
+              cond_offset_target (address, off / TARGET_CHAR_BIT),
+              dval);
+         TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f);
+         bit_incr = fld_bit_len =
+           TYPE_LENGTH (TYPE_FIELD_TYPE (rtype, f)) * TARGET_CHAR_BIT;
+       }
+      else
+       {
+         TYPE_FIELD_TYPE (rtype, f) = TYPE_FIELD_TYPE (type, f);
+         TYPE_FIELD_NAME (rtype, f) = TYPE_FIELD_NAME (type, f);
+         if (TYPE_FIELD_BITSIZE (type, f) > 0)
+           bit_incr = fld_bit_len = 
+             TYPE_FIELD_BITSIZE (rtype, f) = TYPE_FIELD_BITSIZE (type, f);
+         else
+           bit_incr = fld_bit_len =
+             TYPE_LENGTH (TYPE_FIELD_TYPE (type, f)) * TARGET_CHAR_BIT;
+       }
+      if (off + fld_bit_len > bit_len)
+       bit_len = off + fld_bit_len;
+      off += bit_incr;
+      TYPE_LENGTH (rtype) = bit_len / TARGET_CHAR_BIT;
+    }
+  TYPE_LENGTH (rtype) = align_value (TYPE_LENGTH (rtype), TYPE_LENGTH (type));
+
+  value_free_to_mark (mark);
+  if (TYPE_LENGTH (rtype) > varsize_limit) 
+    error ("record type with dynamic size is larger than varsize-limit");
+  return rtype;
+}
+
+/* As for template_to_fixed_record_type, but uses no run-time values.
+   As a result, this type can only be approximate, but that's OK,
+   since it is used only for type determinations.   Works on both
+   structs and unions.
+   Representation note: to save space, we memoize the result of this
+   function in the TYPE_TARGET_TYPE of the template type. */
+
+static struct type*
+template_to_static_fixed_type (templ_type)
+     struct type* templ_type;
+{
+  struct type *type;
+  int nfields;
+  int f;
+
+  if (TYPE_TARGET_TYPE (templ_type) != NULL)
+    return TYPE_TARGET_TYPE (templ_type);
+
+  nfields = TYPE_NFIELDS (templ_type);
+  TYPE_TARGET_TYPE (templ_type) = type = alloc_type (TYPE_OBJFILE (templ_type));
+  TYPE_CODE (type) = TYPE_CODE (templ_type);
+  INIT_CPLUS_SPECIFIC (type);
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field*) 
+    TYPE_ALLOC (type, nfields * sizeof (struct field));
+  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+  TYPE_NAME (type) = ada_type_name (templ_type);
+  TYPE_TAG_NAME (type) = NULL;
+  /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */  
+  /*  TYPE_FLAGS (type) |= TYPE_FLAG_FIXED_INSTANCE; */
+  TYPE_LENGTH (type) = 0;
+
+  for (f = 0; f < nfields; f += 1)
+    {
+      TYPE_FIELD_BITPOS (type, f) = 0;
+      TYPE_FIELD_BITSIZE (type, f) = 0;  
+
+      if (is_dynamic_field (templ_type, f))
+       {
+         TYPE_FIELD_TYPE (type, f) = 
+           to_static_fixed_type (TYPE_TARGET_TYPE 
+                                 (TYPE_FIELD_TYPE (templ_type, f)));
+         TYPE_FIELD_NAME (type, f) = TYPE_FIELD_NAME (templ_type, f);
+       }
+      else
+       {
+         TYPE_FIELD_TYPE (type, f) = 
+           check_typedef (TYPE_FIELD_TYPE (templ_type, f));
+         TYPE_FIELD_NAME (type, f) = TYPE_FIELD_NAME (templ_type, f);
+       }
+    }
+
+  return type;
+}
+
+/* A revision of TYPE0 -- a non-dynamic-sized record with a variant
+   part -- in which the variant part is replaced with the appropriate
+   branch. */
+static struct type*
+to_record_with_fixed_variant_part (type, valaddr, address, dval)
+     struct type* type;
+     char* valaddr;
+     CORE_ADDR address;
+     struct value* dval;
+{
+  struct value* mark = value_mark();
+  struct type* rtype;
+  struct type *branch_type;
+  int nfields = TYPE_NFIELDS (type);
+
+  if (dval == NULL)
+    return type;
+
+  rtype = alloc_type (TYPE_OBJFILE (type));
+  TYPE_CODE (rtype) = TYPE_CODE_STRUCT;
+  INIT_CPLUS_SPECIFIC (type);
+  TYPE_NFIELDS (rtype) = TYPE_NFIELDS (type);
+  TYPE_FIELDS (rtype) = 
+    (struct field*) TYPE_ALLOC (rtype, nfields * sizeof (struct field));
+  memcpy (TYPE_FIELDS (rtype), TYPE_FIELDS (type), 
+         sizeof (struct field) * nfields);
+  TYPE_NAME (rtype) = ada_type_name (type);
+  TYPE_TAG_NAME (rtype) = NULL;
+  /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */  
+  /*  TYPE_FLAGS (rtype) |= TYPE_FLAG_FIXED_INSTANCE; */
+  TYPE_LENGTH (rtype) = TYPE_LENGTH (type);
+
+  branch_type = 
+    to_fixed_variant_branch_type 
+      (TYPE_FIELD_TYPE (type, nfields - 1),
+       cond_offset_host (valaddr, 
+                        TYPE_FIELD_BITPOS (type, nfields-1) / TARGET_CHAR_BIT),
+       cond_offset_target (address, 
+                        TYPE_FIELD_BITPOS (type, nfields-1) / TARGET_CHAR_BIT),
+       dval);
+  if (branch_type == NULL) 
+    {
+      TYPE_NFIELDS (rtype) -= 1;
+      TYPE_LENGTH (rtype) -= TYPE_LENGTH (TYPE_FIELD_TYPE (type, nfields - 1));
+    }
+  else
+    {
+      TYPE_FIELD_TYPE (rtype, nfields-1) = branch_type;
+      TYPE_FIELD_NAME (rtype, nfields-1) = "S";
+      TYPE_FIELD_BITSIZE (rtype, nfields-1) = 0;
+      TYPE_LENGTH (rtype) += TYPE_LENGTH (branch_type);
+       - TYPE_LENGTH (TYPE_FIELD_TYPE (type, nfields - 1));
+    }
+  
+  return rtype;
+}
+
+/* An ordinary record type (with fixed-length fields) that describes
+   the value at (TYPE0, VALADDR, ADDRESS) [see explanation at
+   beginning of this section].   Any necessary discriminants' values
+   should be in DVAL, a record value; it should be NULL if the object
+   at ADDR itself contains any necessary  discriminant values.  A
+   variant field (unless unchecked) is replaced by a particular branch
+   of the variant. */ 
+
+static struct type*
+to_fixed_record_type (type0, valaddr, address, dval)
+     struct type* type0;
+     char* valaddr;
+     CORE_ADDR address;
+     struct value* dval;
+{
+  struct type* templ_type;
+
+  /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+  /*  if (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE)
+    return type0;
+  */
+  templ_type = dynamic_template_type (type0);  
+
+  if (templ_type != NULL)
+    return template_to_fixed_record_type (templ_type, valaddr, address, dval);
+  else if (contains_variant_part (type0))
+    return to_record_with_fixed_variant_part (type0, valaddr, address, dval);
+  else
+    {
+      /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */      
+      /*      TYPE_FLAGS (type0) |= TYPE_FLAG_FIXED_INSTANCE; */
+      return type0;
+    }
+
+}
+
+/* An ordinary record type (with fixed-length fields) that describes
+   the value at (VAR_TYPE0, VALADDR, ADDRESS), where VAR_TYPE0 is a
+   union type.  Any necessary discriminants' values should be in DVAL,
+   a record value.  That is, this routine selects the appropriate
+   branch of the union at ADDR according to the discriminant value
+   indicated in the union's type name. */
+
+static struct type*
+to_fixed_variant_branch_type (var_type0, valaddr, address, dval)
+     struct type* var_type0;
+     char* valaddr;
+     CORE_ADDR address;
+     struct value* dval;
+{
+  int which;
+  struct type* templ_type;
+  struct type* var_type;
+
+  if (TYPE_CODE (var_type0) == TYPE_CODE_PTR)
+    var_type = TYPE_TARGET_TYPE (var_type0);
+  else 
+    var_type = var_type0;
+
+  templ_type = ada_find_parallel_type (var_type, "___XVU");
+
+  if (templ_type != NULL)
+    var_type = templ_type;
+
+  which = 
+    ada_which_variant_applies (var_type, 
+                              VALUE_TYPE (dval), VALUE_CONTENTS (dval));
+
+  if (which < 0)
+    return empty_record (TYPE_OBJFILE (var_type));
+  else if (is_dynamic_field (var_type, which))
+    return 
+      to_fixed_record_type 
+         (TYPE_TARGET_TYPE (TYPE_FIELD_TYPE (var_type, which)),
+         valaddr, address, dval);
+  else if (contains_variant_part (TYPE_FIELD_TYPE (var_type, which)))
+    return 
+      to_fixed_record_type 
+         (TYPE_FIELD_TYPE (var_type, which), valaddr, address, dval);
+  else
+    return TYPE_FIELD_TYPE (var_type, which);
+}
+
+/* Assuming that TYPE0 is an array type describing the type of a value
+   at ADDR, and that DVAL describes a record containing any
+   discriminants used in TYPE0, returns a type for the value that
+   contains no dynamic components (that is, no components whose sizes
+   are determined by run-time quantities).  Unless IGNORE_TOO_BIG is
+   true, gives an error message if the resulting type's size is over
+   varsize_limit.
+*/
+
+static struct type*
+to_fixed_array_type (type0, dval, ignore_too_big)
+     struct type* type0;
+     struct value* dval;
+     int ignore_too_big;
+{
+  struct type* index_type_desc;
+  struct type* result;
+
+  /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+  /*  if (ada_is_packed_array_type (type0)  /* revisit? */ /*
+      || (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE))
+    return type0;*/
+
+  index_type_desc = ada_find_parallel_type (type0, "___XA");
+  if (index_type_desc == NULL)
+    {
+      struct type *elt_type0 = check_typedef (TYPE_TARGET_TYPE (type0));
+      /* NOTE: elt_type---the fixed version of elt_type0---should never
+       * depend on the contents of the array in properly constructed
+       * debugging data. */       
+      struct type *elt_type = 
+       ada_to_fixed_type (elt_type0, 0, 0, dval);
+
+      if (elt_type0 == elt_type)
+       result = type0;
+      else
+       result = create_array_type (alloc_type (TYPE_OBJFILE (type0)), 
+                                   elt_type, TYPE_INDEX_TYPE (type0));
+    }
+  else
+    {
+      int i;
+      struct type *elt_type0;
+
+      elt_type0 = type0;
+      for (i = TYPE_NFIELDS (index_type_desc); i > 0; i -= 1)
+       elt_type0 = TYPE_TARGET_TYPE (elt_type0);
+
+      /* NOTE: result---the fixed version of elt_type0---should never
+       * depend on the contents of the array in properly constructed
+       * debugging data. */       
+      result = 
+       ada_to_fixed_type (check_typedef (elt_type0), 0, 0, dval);
+      for (i = TYPE_NFIELDS (index_type_desc) - 1; i >= 0; i -= 1)
+       {
+         struct type *range_type = 
+           to_fixed_range_type (TYPE_FIELD_NAME (index_type_desc, i),
+                                dval, TYPE_OBJFILE (type0));
+         result = create_array_type (alloc_type (TYPE_OBJFILE (type0)),
+                                     result, range_type);
+       }
+      if (! ignore_too_big && TYPE_LENGTH (result) > varsize_limit) 
+       error ("array type with dynamic size is larger than varsize-limit");
+    }
+
+/* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+/*  TYPE_FLAGS (result) |= TYPE_FLAG_FIXED_INSTANCE; */
+  return result;
+}  
+
+
+/* A standard type (containing no dynamically sized components)
+   corresponding to TYPE for the value (TYPE, VALADDR, ADDRESS)
+   DVAL describes a record containing any discriminants used in TYPE0,
+   and may be NULL if there are none. */
+
+struct type*
+ada_to_fixed_type (type, valaddr, address, dval)
+     struct type* type;
+     char* valaddr;
+     CORE_ADDR address;
+     struct value* dval;
+{
+  CHECK_TYPEDEF (type);
+  switch (TYPE_CODE (type)) {
+  default:
+    return type;
+  case TYPE_CODE_STRUCT:
+    return to_fixed_record_type (type, valaddr, address, NULL);
+  case TYPE_CODE_ARRAY:
+    return to_fixed_array_type (type, dval, 0);
+  case TYPE_CODE_UNION:
+    if (dval == NULL) 
+      return type;
+    else
+      return to_fixed_variant_branch_type (type, valaddr, address, dval);
+  }
+}
+
+/* A standard (static-sized) type corresponding as well as possible to
+   TYPE0, but based on no runtime data. */
+
+static struct type*
+to_static_fixed_type (type0)
+     struct type* type0;
+{
+  struct type* type;
+
+  if (type0 == NULL)
+    return NULL;
+
+  /* FIXME:  TYPE_FLAG_FIXED_INSTANCE should be defined in gdbtypes.h */
+  /*  if (TYPE_FLAGS (type0) & TYPE_FLAG_FIXED_INSTANCE)
+    return type0;
+  */
+  CHECK_TYPEDEF (type0);
+  
+  switch (TYPE_CODE (type0))
+    {
+    default:
+      return type0;
+    case TYPE_CODE_STRUCT:
+      type = dynamic_template_type (type0);
+      if (type != NULL) 
+       return template_to_static_fixed_type (type);
+      return type0;
+    case TYPE_CODE_UNION:
+      type = ada_find_parallel_type (type0, "___XVU");
+      if (type != NULL)
+       return template_to_static_fixed_type (type);
+      return type0;
+    }
+}
+
+/* A static approximation of TYPE with all type wrappers removed. */
+static struct type*
+static_unwrap_type (type)
+     struct type* type;
+{
+  if (ada_is_aligner_type (type))
+    {
+      struct type* type1 = TYPE_FIELD_TYPE (check_typedef (type), 0);
+      if (ada_type_name (type1) == NULL)
+       TYPE_NAME (type1) = ada_type_name (type);
+
+      return static_unwrap_type (type1);
+    }
+  else 
+    {
+      struct type* raw_real_type = ada_get_base_type (type);
+      if (raw_real_type == type) 
+       return type;
+      else
+       return to_static_fixed_type (raw_real_type);
+    }
+}
+
+/* In some cases, incomplete and private types require
+   cross-references that are not resolved as records (for example, 
+      type Foo;
+      type FooP is access Foo;
+      V: FooP;
+      type Foo is array ...;
+   ). In these cases, since there is no mechanism for producing 
+   cross-references to such types, we instead substitute for FooP a
+   stub enumeration type that is nowhere resolved, and whose tag is
+   the name of the actual type.  Call these types "non-record stubs". */
+
+/* A type equivalent to TYPE that is not a non-record stub, if one
+   exists, otherwise TYPE. */
+struct type*
+ada_completed_type (type)
+     struct type* type;
+{
+  CHECK_TYPEDEF (type);
+  if (type == NULL || TYPE_CODE (type) != TYPE_CODE_ENUM
+      || (TYPE_FLAGS (type) & TYPE_FLAG_STUB) == 0
+      || TYPE_TAG_NAME (type) == NULL)
+    return type;
+  else 
+    {
+      char* name = TYPE_TAG_NAME (type);
+      struct type* type1 = ada_find_any_type (name);
+      return (type1 == NULL) ? type : type1;
+    }
+}
+
+/* A value representing the data at VALADDR/ADDRESS as described by
+   type TYPE0, but with a standard (static-sized) type that correctly
+   describes it.  If VAL0 is not NULL and TYPE0 already is a standard
+   type, then return VAL0 [this feature is simply to avoid redundant
+   creation of struct values]. */ 
+
+struct value*
+ada_to_fixed_value (type0, valaddr, address, val0)
+     struct type* type0;
+     char* valaddr;
+     CORE_ADDR address;
+     struct value* val0;
+{
+  struct type* type = ada_to_fixed_type (type0, valaddr, address, NULL);
+  if (type == type0 && val0 != NULL)
+    return val0;
+  else return value_from_contents_and_address (type, valaddr, address);
+}
+
+/* A value representing VAL, but with a standard (static-sized) type 
+   chosen to approximate the real type of VAL as well as possible, but
+   without consulting any runtime values.  For Ada dynamic-sized
+   types, therefore, the type of the result is likely to be inaccurate. */
+
+struct value*
+ada_to_static_fixed_value (val)
+     struct value* val;
+{
+  struct type *type = 
+    to_static_fixed_type (static_unwrap_type (VALUE_TYPE (val)));
+  if (type == VALUE_TYPE (val))
+    return val;
+  else
+    return coerce_unspec_val_to_type (val, 0, type);
+}
+
+
+\f
+
+
+/* Attributes */
+
+/* Table mapping attribute numbers to names */
+/* NOTE: Keep up to date with enum ada_attribute definition in ada-lang.h */
+
+static const char* attribute_names[] = {
+  "<?>",
+
+  "first", 
+  "last",
+  "length",
+  "image",
+  "img",
+  "max",
+  "min",
+  "pos"
+  "tag",
+  "val",
+
+  0
+};
+
+const char*
+ada_attribute_name (n)
+     int n;
+{
+  if (n > 0 && n < (int) ATR_END)
+    return attribute_names[n];
+  else
+    return attribute_names[0];
+}
+
+/* Evaluate the 'POS attribute applied to ARG. */
+
+static struct value*
+value_pos_atr (arg)
+     struct value* arg;
+{
+  struct type *type = VALUE_TYPE (arg);
+
+  if (! discrete_type_p (type))
+    error ("'POS only defined on discrete types");
+
+  if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+    {
+      int i;
+      LONGEST v = value_as_long (arg);
+
+      for (i = 0; i < TYPE_NFIELDS (type); i += 1) 
+       {
+         if (v == TYPE_FIELD_BITPOS (type, i))
+           return value_from_longest (builtin_type_ada_int, i);
+       }
+      error ("enumeration value is invalid: can't find 'POS");
+    }
+  else
+    return value_from_longest (builtin_type_ada_int, value_as_long (arg));
+}
+
+/* Evaluate the TYPE'VAL attribute applied to ARG. */
+
+static struct value*
+value_val_atr (type, arg)
+     struct type *type;
+     struct value* arg;
+{
+  if (! discrete_type_p (type))
+    error ("'VAL only defined on discrete types");
+  if (! integer_type_p (VALUE_TYPE (arg)))
+    error ("'VAL requires integral argument");
+
+  if (TYPE_CODE (type) == TYPE_CODE_ENUM)
+    {
+      long pos = value_as_long (arg);
+      if (pos < 0 || pos >= TYPE_NFIELDS (type))
+       error ("argument to 'VAL out of range");
+      return 
+       value_from_longest (type, TYPE_FIELD_BITPOS (type, pos));
+    }
+  else
+    return value_from_longest (type, value_as_long (arg));
+}
+
+\f
+                               /* Evaluation */
+
+/* True if TYPE appears to be an Ada character type.  
+ * [At the moment, this is true only for Character and Wide_Character;
+ * It is a heuristic test that could stand improvement]. */
+
+int 
+ada_is_character_type (type)
+     struct type* type;
+{
+  const char* name = ada_type_name (type);
+  return 
+    name != NULL
+    && (TYPE_CODE (type) == TYPE_CODE_CHAR 
+       || TYPE_CODE (type) == TYPE_CODE_INT
+       || TYPE_CODE (type) == TYPE_CODE_RANGE)
+    && (STREQ (name, "character") || STREQ (name, "wide_character")
+       || STREQ (name, "unsigned char"));
+}
+
+/* True if TYPE appears to be an Ada string type. */
+
+int
+ada_is_string_type (type)
+     struct type *type;
+{
+  CHECK_TYPEDEF (type);
+  if (type != NULL 
+      && TYPE_CODE (type) != TYPE_CODE_PTR
+      && (ada_is_simple_array (type) || ada_is_array_descriptor (type))
+      && ada_array_arity (type) == 1)
+    {
+      struct type *elttype = ada_array_element_type (type, 1);
+
+      return ada_is_character_type (elttype);
+    }
+  else 
+    return 0;
+}
+
+
+/* True if TYPE is a struct type introduced by the compiler to force the
+   alignment of a value.  Such types have a single field with a
+   distinctive name. */
+
+int
+ada_is_aligner_type (type)
+     struct type *type;
+{
+  CHECK_TYPEDEF (type);
+  return (TYPE_CODE (type) == TYPE_CODE_STRUCT
+         && TYPE_NFIELDS (type) == 1
+         && STREQ (TYPE_FIELD_NAME (type, 0), "F"));
+}
+
+/* If there is an ___XVS-convention type parallel to SUBTYPE, return
+   the parallel type. */
+
+struct type*
+ada_get_base_type (raw_type)
+     struct type* raw_type;
+{
+  struct type* real_type_namer;
+  struct type* raw_real_type;
+  struct type* real_type;
+
+  if (raw_type == NULL || TYPE_CODE (raw_type) != TYPE_CODE_STRUCT)
+    return raw_type;
+
+  real_type_namer = ada_find_parallel_type (raw_type, "___XVS");
+  if (real_type_namer == NULL 
+      || TYPE_CODE (real_type_namer) != TYPE_CODE_STRUCT
+      || TYPE_NFIELDS (real_type_namer) != 1)
+    return raw_type;
+
+  raw_real_type = ada_find_any_type (TYPE_FIELD_NAME (real_type_namer, 0));
+  if (raw_real_type == NULL) 
+    return raw_type;
+  else
+    return raw_real_type;
+}  
+
+/* The type of value designated by TYPE, with all aligners removed. */
+
+struct type*
+ada_aligned_type (type)
+     struct type* type;
+{
+  if (ada_is_aligner_type (type))
+    return ada_aligned_type (TYPE_FIELD_TYPE (type, 0));
+  else
+    return ada_get_base_type (type);
+}
+
+
+/* The address of the aligned value in an object at address VALADDR
+   having type TYPE.  Assumes ada_is_aligner_type (TYPE). */
+
+char*
+ada_aligned_value_addr (type, valaddr)
+     struct type *type;
+     char *valaddr;
+{
+  if (ada_is_aligner_type (type)) 
+    return ada_aligned_value_addr (TYPE_FIELD_TYPE (type, 0),
+                                  valaddr + 
+                                  TYPE_FIELD_BITPOS (type, 0)/TARGET_CHAR_BIT);
+  else
+    return valaddr;
+}
+
+/* The printed representation of an enumeration literal with encoded
+   name NAME. The value is good to the next call of ada_enum_name. */
+const char*
+ada_enum_name (name)
+     const char* name;
+{
+  char* tmp;
+
+  while (1) 
+    {
+      if ((tmp = strstr (name, "__")) != NULL)
+       name = tmp+2;
+      else if ((tmp = strchr (name, '.')) != NULL)
+       name = tmp+1;
+      else
+       break;
+    }
+
+  if (name[0] == 'Q')
+    {
+      static char result[16];
+      int v;
+      if (name[1] == 'U' || name[1] == 'W')
+       {
+         if (sscanf (name+2, "%x", &v) != 1) 
+           return name;
+       }
+      else
+       return name;
+
+      if (isascii (v) && isprint (v))
+       sprintf (result, "'%c'", v);
+      else if (name[1] == 'U')
+       sprintf (result, "[\"%02x\"]", v);
+      else
+       sprintf (result, "[\"%04x\"]", v);
+
+      return result;
+    }
+  else 
+    return name;
+}
+
+static struct value*
+evaluate_subexp (expect_type, exp, pos, noside)
+     struct type *expect_type;
+     struct expression *exp;
+     int *pos;
+     enum noside noside;
+{
+  return (*exp->language_defn->evaluate_exp) (expect_type, exp, pos, noside);
+}
+
+/* Evaluate the subexpression of EXP starting at *POS as for
+   evaluate_type, updating *POS to point just past the evaluated
+   expression. */
+
+static struct value*
+evaluate_subexp_type (exp, pos)
+     struct expression* exp;
+     int* pos;
+{
+  return (*exp->language_defn->evaluate_exp) 
+    (NULL_TYPE, exp, pos, EVAL_AVOID_SIDE_EFFECTS);
+}
+
+/* If VAL is wrapped in an aligner or subtype wrapper, return the
+   value it wraps. */ 
+
+static struct value*
+unwrap_value (val)
+     struct value* val;
+{
+  struct type* type = check_typedef (VALUE_TYPE (val));
+  if (ada_is_aligner_type (type))
+    {
+      struct value* v = value_struct_elt (&val, NULL, "F", 
+                                     NULL, "internal structure");
+      struct type* val_type = check_typedef (VALUE_TYPE (v));
+      if (ada_type_name (val_type) == NULL)
+       TYPE_NAME (val_type) = ada_type_name (type);
+
+      return unwrap_value (v);
+    }
+  else 
+    {
+      struct type* raw_real_type = 
+       ada_completed_type (ada_get_base_type (type));
+      
+      if (type == raw_real_type)
+       return val;
+
+      return 
+       coerce_unspec_val_to_type 
+       (val, 0, ada_to_fixed_type (raw_real_type, 0,
+                                   VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+                                   NULL));
+    }
+}
+    
+static struct value*
+cast_to_fixed (type, arg)
+     struct type *type;
+     struct value* arg;
+{
+  LONGEST val;
+
+  if (type == VALUE_TYPE (arg))
+    return arg;
+  else if (ada_is_fixed_point_type (VALUE_TYPE (arg)))
+    val = ada_float_to_fixed (type, 
+                             ada_fixed_to_float (VALUE_TYPE (arg),
+                                                 value_as_long (arg)));
+  else 
+    {
+      DOUBLEST argd = 
+       value_as_double (value_cast (builtin_type_double, value_copy (arg)));
+      val = ada_float_to_fixed (type, argd);
+    }
+
+  return value_from_longest (type, val);
+}
+
+static struct value*
+cast_from_fixed_to_double (arg)
+     struct value* arg;
+{
+  DOUBLEST val = ada_fixed_to_float (VALUE_TYPE (arg),
+                                    value_as_long (arg));
+  return value_from_double (builtin_type_double, val);
+}
+
+/* Coerce VAL as necessary for assignment to an lval of type TYPE, and 
+ * return the converted value. */
+static struct value*
+coerce_for_assign (type, val)
+     struct type* type;
+     struct value* val;
+{
+  struct type* type2 = VALUE_TYPE (val);
+  if (type == type2)
+    return val;
+
+  CHECK_TYPEDEF (type2);
+  CHECK_TYPEDEF (type);
+
+  if (TYPE_CODE (type2) == TYPE_CODE_PTR && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    {
+      val = ada_value_ind (val);
+      type2 = VALUE_TYPE (val);
+    }
+
+  if (TYPE_CODE (type2) == TYPE_CODE_ARRAY 
+      && TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    {
+      if (TYPE_LENGTH (type2) != TYPE_LENGTH (type)
+         || TYPE_LENGTH (TYPE_TARGET_TYPE (type2))
+            != TYPE_LENGTH (TYPE_TARGET_TYPE (type2)))
+       error ("Incompatible types in assignment");
+      VALUE_TYPE (val) = type;
+    }
+  return val;  
+}
+
+struct value*
+ada_evaluate_subexp (expect_type, exp, pos, noside)
+     struct type *expect_type;
+     struct expression *exp;
+     int *pos;
+     enum noside noside;
+{
+  enum exp_opcode op;
+  enum ada_attribute atr;
+  int tem, tem2, tem3;
+  int pc;
+  struct value *arg1 = NULL, *arg2 = NULL, *arg3;
+  struct type *type;
+  int nargs;
+  struct value* *argvec;
+
+  pc = *pos; *pos += 1;
+  op = exp->elts[pc].opcode;
+
+  switch (op) 
+    {
+    default:
+      *pos -= 1;
+      return unwrap_value (evaluate_subexp_standard (expect_type, exp, pos, noside));
+
+    case UNOP_CAST:
+      (*pos) += 2;
+      type = exp->elts[pc + 1].type;
+      arg1 = evaluate_subexp (type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (type != check_typedef (VALUE_TYPE (arg1)))
+       {
+         if (ada_is_fixed_point_type (type))
+           arg1 = cast_to_fixed (type, arg1);
+         else if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+           arg1 = value_cast (type, cast_from_fixed_to_double (arg1));
+         else if (VALUE_LVAL (arg1) == lval_memory) 
+           {
+             /* This is in case of the really obscure (and undocumented,
+                but apparently expected) case of (Foo) Bar.all, where Bar 
+                is an integer constant and Foo is a dynamic-sized type.
+                If we don't do this, ARG1 will simply be relabeled with
+                TYPE. */
+             if (noside == EVAL_AVOID_SIDE_EFFECTS) 
+               return value_zero (to_static_fixed_type (type), not_lval);
+             arg1 = 
+               ada_to_fixed_value 
+                 (type, 0, VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), 0);
+           }
+         else           
+           arg1 = value_cast (type, arg1);     
+       }
+      return arg1;
+
+      /* FIXME:  UNOP_QUAL should be defined in expression.h */
+      /*    case UNOP_QUAL:
+      (*pos) += 2;
+      type = exp->elts[pc + 1].type;
+      return ada_evaluate_subexp (type, exp, pos, noside);
+      */
+    case BINOP_ASSIGN:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (VALUE_TYPE (arg1), exp, pos, noside);
+      if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS)
+       return arg1;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL);
+      else 
+       {
+         if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+           arg2 = cast_to_fixed (VALUE_TYPE (arg1), arg2);
+         else if (ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+           error ("Fixed-point values must be assigned to fixed-point variables");
+         else 
+           arg2 = coerce_for_assign (VALUE_TYPE (arg1), arg2);
+         return ada_value_assign (arg1, arg2);
+       }
+
+    case BINOP_ADD:
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL);
+      else
+       {
+         if ((ada_is_fixed_point_type (VALUE_TYPE (arg1))
+              || ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+             && VALUE_TYPE (arg1) != VALUE_TYPE (arg2))
+           error ("Operands of fixed-point addition must have the same type");
+         return value_cast (VALUE_TYPE (arg1), value_add (arg1, arg2));
+       }
+
+    case BINOP_SUB:
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL);
+      else
+       {
+         if ((ada_is_fixed_point_type (VALUE_TYPE (arg1))
+              || ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+             && VALUE_TYPE (arg1) != VALUE_TYPE (arg2))
+           error ("Operands of fixed-point subtraction must have the same type");              
+         return value_cast (VALUE_TYPE (arg1), value_sub (arg1, arg2));
+       }
+
+    case BINOP_MUL:
+    case BINOP_DIV:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return value_x_binop (arg1, arg2, op, OP_NULL, EVAL_NORMAL);
+      else
+       if (noside == EVAL_AVOID_SIDE_EFFECTS
+           && (op == BINOP_DIV || op == BINOP_REM || op == BINOP_MOD))
+         return value_zero (VALUE_TYPE (arg1), not_lval);
+      else
+       {
+         if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+           arg1 = cast_from_fixed_to_double (arg1);
+         if (ada_is_fixed_point_type (VALUE_TYPE (arg2)))
+           arg2 = cast_from_fixed_to_double (arg2);
+         return value_binop (arg1, arg2, op);
+       }
+
+    case UNOP_NEG:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (unop_user_defined_p (op, arg1))
+       return value_x_unop (arg1, op, EVAL_NORMAL);
+      else if (ada_is_fixed_point_type (VALUE_TYPE (arg1)))
+       return value_cast (VALUE_TYPE (arg1), value_neg (arg1));
+      else
+       return value_neg (arg1);
+
+      /* FIXME:  OP_UNRESOLVED_VALUE should be defined in expression.h */
+      /*    case OP_UNRESOLVED_VALUE:
+      /* Only encountered when an unresolved symbol occurs in a
+         context other than a function call, in which case, it is
+        illegal. *//*
+      (*pos) += 3;
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      else 
+       error ("Unexpected unresolved symbol, %s, during evaluation",
+              ada_demangle (exp->elts[pc + 2].name));
+      */
+    case OP_VAR_VALUE:
+      *pos -= 1;
+      if (noside == EVAL_SKIP)
+       {
+         *pos += 4;
+         goto nosideret;
+       } 
+      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         *pos += 4;
+         return value_zero 
+           (to_static_fixed_type 
+            (static_unwrap_type (SYMBOL_TYPE (exp->elts[pc+2].symbol))),
+            not_lval);
+       }
+      else 
+       {
+         arg1 = unwrap_value (evaluate_subexp_standard (expect_type, exp, pos, 
+                                                        noside));
+         return ada_to_fixed_value (VALUE_TYPE (arg1), 0,
+                                    VALUE_ADDRESS (arg1) + VALUE_OFFSET(arg1),
+                                    arg1);
+       }
+
+    case OP_ARRAY:
+      (*pos) += 3;
+      tem2 = longest_to_int (exp->elts[pc + 1].longconst);
+      tem3 = longest_to_int (exp->elts[pc + 2].longconst);
+      nargs = tem3 - tem2 + 1;
+      type = expect_type ? check_typedef (expect_type) : NULL_TYPE;
+
+      argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 1));
+      for (tem = 0; tem == 0 || tem < nargs; tem += 1)
+       /* At least one element gets inserted for the type */
+       {
+         /* Ensure that array expressions are coerced into pointer objects. */
+         argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside);
+       }
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return value_array (tem2, tem3, argvec);
+
+    case OP_FUNCALL:
+      (*pos) += 2;
+
+      /* Allocate arg vector, including space for the function to be
+        called in argvec[0] and a terminating NULL */
+      nargs = longest_to_int (exp->elts[pc + 1].longconst);
+      argvec = (struct value* *) alloca (sizeof (struct value*) * (nargs + 2));
+
+      /* FIXME: OP_UNRESOLVED_VALUE should be defined in expression.h */
+      /* FIXME: name should be defined in expresion.h */
+      /*      if (exp->elts[*pos].opcode == OP_UNRESOLVED_VALUE)
+       error ("Unexpected unresolved symbol, %s, during evaluation",
+              ada_demangle (exp->elts[pc + 5].name));
+      */
+      if (0) 
+       {
+         error ("unexpected code path, FIXME");
+       }
+      else
+       {
+         for (tem = 0; tem <= nargs; tem += 1)
+           argvec[tem] = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         argvec[tem] = 0;
+
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+       }
+
+      if (TYPE_CODE (VALUE_TYPE (argvec[0])) == TYPE_CODE_REF)
+       argvec[0] = value_addr (argvec[0]);
+
+      if (ada_is_packed_array_type (VALUE_TYPE (argvec[0])))
+       argvec[0] = ada_coerce_to_simple_array (argvec[0]);
+
+      type = check_typedef (VALUE_TYPE (argvec[0]));
+      if (TYPE_CODE (type) == TYPE_CODE_PTR)
+       {       
+         switch (TYPE_CODE (check_typedef (TYPE_TARGET_TYPE (type))))
+           {
+           case TYPE_CODE_FUNC:
+             type = check_typedef (TYPE_TARGET_TYPE (type));
+             break;
+           case TYPE_CODE_ARRAY:
+             break;
+           case TYPE_CODE_STRUCT:
+             if (noside != EVAL_AVOID_SIDE_EFFECTS)
+               argvec[0] = ada_value_ind (argvec[0]);
+             type = check_typedef (TYPE_TARGET_TYPE (type));
+             break;
+           default:
+             error ("cannot subscript or call something of type `%s'",
+                    ada_type_name (VALUE_TYPE (argvec[0])));
+             break;
+         }
+       }
+         
+      switch (TYPE_CODE (type))
+       {
+       case TYPE_CODE_FUNC:
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return allocate_value (TYPE_TARGET_TYPE (type));
+         return call_function_by_hand (argvec[0], nargs, argvec + 1);
+       case TYPE_CODE_STRUCT: 
+         {
+           int arity = ada_array_arity (type);
+           type = ada_array_element_type (type, nargs);
+           if (type == NULL) 
+             error ("cannot subscript or call a record");
+           if (arity != nargs) 
+             error ("wrong number of subscripts; expecting %d", arity);
+           if (noside == EVAL_AVOID_SIDE_EFFECTS) 
+             return allocate_value (ada_aligned_type (type));
+           return unwrap_value (ada_value_subscript (argvec[0], nargs, argvec+1));
+         }
+       case TYPE_CODE_ARRAY:
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           {   
+             type = ada_array_element_type (type, nargs);
+             if (type == NULL)
+               error ("element type of array unknown");
+             else
+               return allocate_value (ada_aligned_type (type));
+           }
+         return 
+           unwrap_value (ada_value_subscript
+                         (ada_coerce_to_simple_array (argvec[0]),
+                          nargs, argvec+1));
+       case TYPE_CODE_PTR: /* Pointer to array */
+         type = to_fixed_array_type (TYPE_TARGET_TYPE (type), NULL, 1);
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           {   
+             type = ada_array_element_type (type, nargs);
+             if (type == NULL)
+               error ("element type of array unknown");
+             else
+               return allocate_value (ada_aligned_type (type));
+           }
+         return 
+           unwrap_value (ada_value_ptr_subscript (argvec[0], type, 
+                                                  nargs, argvec+1));
+
+       default:
+         error ("Internal error in evaluate_subexp");
+       }
+
+    case TERNOP_SLICE:
+      {
+       struct value* array = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+       int lowbound
+         = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+       int upper
+         = value_as_long (evaluate_subexp (NULL_TYPE, exp, pos, noside));
+       if (noside == EVAL_SKIP)
+         goto nosideret;
+        
+        /* If this is a reference to an array, then dereference it */
+        if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_REF
+            && TYPE_TARGET_TYPE (VALUE_TYPE (array)) != NULL
+            && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (array))) ==
+                 TYPE_CODE_ARRAY
+            && !ada_is_array_descriptor (check_typedef (VALUE_TYPE
+               (array))))
+          {
+            array = ada_coerce_ref (array);
+          }
+
+       if (noside == EVAL_AVOID_SIDE_EFFECTS &&
+           ada_is_array_descriptor (check_typedef (VALUE_TYPE (array))))
+         {
+           /* Try to dereference the array, in case it is an access to array */
+           struct type * arrType = ada_type_of_array (array, 0);
+           if (arrType != NULL)
+             array = value_at_lazy (arrType, 0, NULL); 
+         }
+       if (ada_is_array_descriptor (VALUE_TYPE (array)))
+         array = ada_coerce_to_simple_array (array);
+
+        /* If at this point we have a pointer to an array, it means that
+           it is a pointer to a simple (non-ada) array. We just then
+           dereference it */
+        if (TYPE_CODE (VALUE_TYPE (array)) == TYPE_CODE_PTR
+            && TYPE_TARGET_TYPE (VALUE_TYPE (array)) != NULL
+            && TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (array))) ==
+                 TYPE_CODE_ARRAY)
+          {
+              array = ada_value_ind (array);
+          }
+        
+       if (noside == EVAL_AVOID_SIDE_EFFECTS)
+         /* The following will get the bounds wrong, but only in contexts
+            where the value is not being requested (FIXME?). */
+         return array;
+       else
+         return value_slice (array, lowbound, upper - lowbound + 1);
+      }
+
+      /* FIXME: UNOP_MBR should be defined in expression.h */
+      /*    case UNOP_MBR:
+      (*pos) += 2;
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      type = exp->elts[pc + 1].type;
+
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+
+      switch (TYPE_CODE (type)) 
+       {
+       default:
+         warning ("Membership test incompletely implemented; always returns true");
+         return value_from_longest (builtin_type_int, (LONGEST) 1);
+         
+       case TYPE_CODE_RANGE:
+         arg2 = value_from_longest (builtin_type_int, 
+                                    (LONGEST) TYPE_LOW_BOUND (type));
+         arg3 = value_from_longest (builtin_type_int, 
+                                    (LONGEST) TYPE_HIGH_BOUND (type));
+         return 
+           value_from_longest (builtin_type_int,
+                               (value_less (arg1,arg3) 
+                                || value_equal (arg1,arg3))
+                               && (value_less (arg2,arg1)
+                                   || value_equal (arg2,arg1)));
+       }
+      */
+      /* FIXME: BINOP_MBR should be defined in expression.h */      
+      /*    case BINOP_MBR:
+      (*pos) += 2;
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (builtin_type_int, not_lval);
+
+      tem = longest_to_int (exp->elts[pc + 1].longconst);
+
+      if (tem < 1 || tem > ada_array_arity (VALUE_TYPE (arg2)))
+       error ("invalid dimension number to '%s", "range");
+
+      arg3 = ada_array_bound (arg2, tem, 1);
+      arg2 = ada_array_bound (arg2, tem, 0);
+
+      return 
+       value_from_longest (builtin_type_int,
+                           (value_less (arg1,arg3) 
+                            || value_equal (arg1,arg3))
+                           && (value_less (arg2,arg1)
+                               || value_equal (arg2,arg1)));
+      */
+      /* FIXME: TERNOP_MBR should be defined in expression.h */
+      /*    case TERNOP_MBR:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg3 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+
+      return 
+       value_from_longest (builtin_type_int,
+                           (value_less (arg1,arg3) 
+                            || value_equal (arg1,arg3))
+                           && (value_less (arg2,arg1)
+                               || value_equal (arg2,arg1)));
+      */
+      /* FIXME: OP_ATTRIBUTE should be defined in expression.h */
+      /*    case OP_ATTRIBUTE:
+      *pos += 3;
+      atr = (enum ada_attribute) longest_to_int (exp->elts[pc + 2].longconst);
+      switch (atr) 
+       {
+       default:
+         error ("unexpected attribute encountered");
+
+       case ATR_FIRST:
+       case ATR_LAST:
+       case ATR_LENGTH:
+         {
+           struct type* type_arg;
+           if (exp->elts[*pos].opcode == OP_TYPE)
+             {
+               evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+               arg1 = NULL;
+               type_arg = exp->elts[pc + 5].type;
+             }
+           else
+             {
+               arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+               type_arg = NULL;
+             }
+
+           if (exp->elts[*pos].opcode != OP_LONG) 
+             error ("illegal operand to '%s", ada_attribute_name (atr));
+           tem = longest_to_int (exp->elts[*pos+2].longconst);
+           *pos += 4;
+
+           if (noside == EVAL_SKIP)
+             goto nosideret;
+
+           if (type_arg == NULL)
+             {
+               arg1 = ada_coerce_ref (arg1);
+
+               if (ada_is_packed_array_type (VALUE_TYPE (arg1)))
+                 arg1 = ada_coerce_to_simple_array (arg1);
+
+               if (tem < 1 || tem > ada_array_arity (VALUE_TYPE (arg1)))
+                 error ("invalid dimension number to '%s", 
+                        ada_attribute_name (atr));
+
+               if (noside == EVAL_AVOID_SIDE_EFFECTS)
+                 {
+                   type = ada_index_type (VALUE_TYPE (arg1), tem);
+                   if (type == NULL) 
+                     error ("attempt to take bound of something that is not an array");
+                   return allocate_value (type);
+                 }
+
+               switch (atr) 
+                 {
+                 default: 
+                   error ("unexpected attribute encountered");
+                 case ATR_FIRST:
+                   return ada_array_bound (arg1, tem, 0);
+                 case ATR_LAST:
+                   return ada_array_bound (arg1, tem, 1);
+                 case ATR_LENGTH:
+                   return ada_array_length (arg1, tem);
+                 }
+             }
+           else if (TYPE_CODE (type_arg) == TYPE_CODE_RANGE
+                    || TYPE_CODE (type_arg) == TYPE_CODE_INT) 
+             {
+               struct type* range_type;
+               char* name = ada_type_name (type_arg);
+               if (name == NULL)
+                 {
+                   if (TYPE_CODE (type_arg) == TYPE_CODE_RANGE) 
+                     range_type = type_arg;
+                   else
+                     error ("unimplemented type attribute");
+                 }
+               else 
+                 range_type = 
+                   to_fixed_range_type (name, NULL, TYPE_OBJFILE (type_arg));
+               switch (atr) 
+                 {
+                 default: 
+                   error ("unexpected attribute encountered");
+                 case ATR_FIRST:
+                   return value_from_longest (TYPE_TARGET_TYPE (range_type),
+                                              TYPE_LOW_BOUND (range_type));
+                 case ATR_LAST:
+                   return value_from_longest (TYPE_TARGET_TYPE (range_type),
+                                              TYPE_HIGH_BOUND (range_type));
+                 }
+             }         
+           else if (TYPE_CODE (type_arg) == TYPE_CODE_ENUM)
+             {
+               switch (atr) 
+                 {
+                 default: 
+                   error ("unexpected attribute encountered");
+                 case ATR_FIRST:
+                   return value_from_longest 
+                     (type_arg, TYPE_FIELD_BITPOS (type_arg, 0));
+                 case ATR_LAST:
+                   return value_from_longest 
+                     (type_arg, 
+                      TYPE_FIELD_BITPOS (type_arg,
+                                         TYPE_NFIELDS (type_arg) - 1));
+                 }
+             }
+           else if (TYPE_CODE (type_arg) == TYPE_CODE_FLT)
+             error ("unimplemented type attribute");
+           else 
+             {
+               LONGEST low, high;
+
+               if (ada_is_packed_array_type (type_arg))
+                 type_arg = decode_packed_array_type (type_arg);
+
+               if (tem < 1 || tem > ada_array_arity (type_arg))
+                 error ("invalid dimension number to '%s", 
+                        ada_attribute_name (atr));
+
+               if (noside == EVAL_AVOID_SIDE_EFFECTS)
+                 {
+                   type = ada_index_type (type_arg, tem);
+                   if (type == NULL) 
+                     error ("attempt to take bound of something that is not an array");
+                   return allocate_value (type);
+                 }
+
+               switch (atr) 
+                 {
+                 default: 
+                   error ("unexpected attribute encountered");
+                 case ATR_FIRST:
+                   low = ada_array_bound_from_type (type_arg, tem, 0, &type);
+                   return value_from_longest (type, low);
+                 case ATR_LAST:
+                   high = ada_array_bound_from_type (type_arg, tem, 1, &type);
+                   return value_from_longest (type, high);
+                 case ATR_LENGTH:
+                   low = ada_array_bound_from_type (type_arg, tem, 0, &type);
+                   high = ada_array_bound_from_type (type_arg, tem, 1, NULL);
+                   return value_from_longest (type, high-low+1);
+                 }
+             }
+         }
+
+       case ATR_TAG:
+         arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return      
+             value_zero (ada_tag_type (arg1), not_lval);
+         
+         return ada_value_tag (arg1);
+         
+       case ATR_MIN:
+       case ATR_MAX:
+         evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+         arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+         else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (VALUE_TYPE (arg1), not_lval);
+         else
+           return value_binop (arg1, arg2, 
+                               atr == ATR_MIN ? BINOP_MIN : BINOP_MAX);
+
+       case ATR_MODULUS:
+         {
+           struct type* type_arg = exp->elts[pc + 5].type;
+           evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+           *pos += 4;
+
+           if (noside == EVAL_SKIP)
+             goto nosideret;
+
+           if (! ada_is_modular_type (type_arg))
+             error ("'modulus must be applied to modular type");
+
+           return value_from_longest (TYPE_TARGET_TYPE (type_arg),
+                                      ada_modulus (type_arg));
+         }
+         
+
+       case ATR_POS:
+         evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+         arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+         else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (builtin_type_ada_int, not_lval);
+         else 
+           return value_pos_atr (arg1);
+
+       case ATR_SIZE:
+         arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+         else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (builtin_type_ada_int, not_lval);
+         else
+           return value_from_longest (builtin_type_ada_int,
+                                      TARGET_CHAR_BIT 
+                                      * TYPE_LENGTH (VALUE_TYPE (arg1)));
+
+       case ATR_VAL:
+         evaluate_subexp (NULL_TYPE, exp, pos, EVAL_SKIP);
+         arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+         type = exp->elts[pc + 5].type;
+         if (noside == EVAL_SKIP)
+           goto nosideret;
+         else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (type, not_lval);
+         else 
+           return value_val_atr (type, arg1);
+           }*/
+    case BINOP_EXP:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      arg2 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (binop_user_defined_p (op, arg1, arg2))
+       return unwrap_value (value_x_binop (arg1, arg2, op, OP_NULL,
+         EVAL_NORMAL));
+      else
+       if (noside == EVAL_AVOID_SIDE_EFFECTS)
+         return value_zero (VALUE_TYPE (arg1), not_lval);
+      else
+       return value_binop (arg1, arg2, op);
+
+    case UNOP_PLUS:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (unop_user_defined_p (op, arg1))
+       return unwrap_value (value_x_unop (arg1, op, EVAL_NORMAL));
+      else
+       return arg1;
+
+    case UNOP_ABS:
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (value_less (arg1, value_zero (VALUE_TYPE (arg1), not_lval)))
+       return value_neg (arg1);
+      else
+       return arg1;
+
+    case UNOP_IND:
+      if (expect_type && TYPE_CODE (expect_type) == TYPE_CODE_PTR)
+        expect_type = TYPE_TARGET_TYPE (check_typedef (expect_type));
+      arg1 = evaluate_subexp (expect_type, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      type = check_typedef (VALUE_TYPE (arg1));
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       {
+         if (ada_is_array_descriptor (type))
+           /* GDB allows dereferencing GNAT array descriptors. */
+           {
+             struct type* arrType = ada_type_of_array (arg1, 0); 
+             if (arrType == NULL)
+               error ("Attempt to dereference null array pointer.");
+             return value_at_lazy (arrType, 0, NULL);
+           }
+         else if (TYPE_CODE (type) == TYPE_CODE_PTR
+             || TYPE_CODE (type) == TYPE_CODE_REF
+             /* In C you can dereference an array to get the 1st elt.  */
+             || TYPE_CODE (type) == TYPE_CODE_ARRAY
+             )
+           return 
+             value_zero 
+               (to_static_fixed_type 
+                 (ada_aligned_type (check_typedef (TYPE_TARGET_TYPE (type)))),
+                lval_memory);
+         else if (TYPE_CODE (type) == TYPE_CODE_INT)
+           /* GDB allows dereferencing an int.  */
+           return value_zero (builtin_type_int, lval_memory);
+         else
+           error ("Attempt to take contents of a non-pointer value.");
+       }
+      arg1 = ada_coerce_ref (arg1);
+      type = check_typedef (VALUE_TYPE (arg1));
+         
+      if (ada_is_array_descriptor (type))
+       /* GDB allows dereferencing GNAT array descriptors. */
+       return ada_coerce_to_simple_array (arg1);
+      else
+       return ada_value_ind (arg1);
+
+    case STRUCTOP_STRUCT:
+      tem = longest_to_int (exp->elts[pc + 1].longconst);
+      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (ada_aligned_type 
+                          (ada_lookup_struct_elt_type (VALUE_TYPE (arg1),
+                                                       &exp->elts[pc + 2].string,
+                                                       0, NULL)),
+                          lval_memory);
+      else
+       return unwrap_value (ada_value_struct_elt (arg1,
+                                                  &exp->elts[pc + 2].string,
+                                                  "record"));
+    case OP_TYPE:
+      /* The value is not supposed to be used. This is here to make it
+         easier to accommodate expressions that contain types. */
+      (*pos) += 2;
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      else if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return allocate_value (builtin_type_void);
+      else 
+       error ("Attempt to use a type name as an expression");
+      
+    case STRUCTOP_PTR:
+      tem = longest_to_int (exp->elts[pc + 1].longconst);
+      (*pos) += 3 + BYTES_TO_EXP_ELEM (tem + 1);
+      arg1 = evaluate_subexp (NULL_TYPE, exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      if (noside == EVAL_AVOID_SIDE_EFFECTS)
+       return value_zero (ada_aligned_type 
+                          (ada_lookup_struct_elt_type (VALUE_TYPE (arg1),
+                                                       &exp->elts[pc + 2].string,
+                                                       0, NULL)),
+                          lval_memory);
+      else
+       return unwrap_value (ada_value_struct_elt (arg1,
+                                                  &exp->elts[pc + 2].string,
+                                                  "record access"));
+    }
+
+nosideret:
+  return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+\f
+                               /* Fixed point */
+
+/* If TYPE encodes an Ada fixed-point type, return the suffix of the
+   type name that encodes the 'small and 'delta information.
+   Otherwise, return NULL. */
+
+static const char*
+fixed_type_info (type)
+     struct type *type;
+{
+  const char* name = ada_type_name (type);
+  enum type_code code = (type == NULL) ? TYPE_CODE_UNDEF : TYPE_CODE (type);
+
+  if ((code == TYPE_CODE_INT || code == TYPE_CODE_RANGE)
+      && name != NULL)
+    {  
+      const char *tail = strstr (name, "___XF_");
+      if (tail == NULL)
+       return NULL;
+      else 
+       return tail + 5;
+    }
+  else if (code == TYPE_CODE_RANGE && TYPE_TARGET_TYPE (type) != type)
+    return fixed_type_info (TYPE_TARGET_TYPE (type));
+  else
+    return NULL;
+}
+
+/* Returns non-zero iff TYPE represents an Ada fixed-point type. */
+
+int
+ada_is_fixed_point_type (type)
+     struct type *type;
+{
+  return fixed_type_info (type) != NULL;
+}
+
+/* Assuming that TYPE is the representation of an Ada fixed-point
+   type, return its delta, or -1 if the type is malformed and the
+   delta cannot be determined. */
+
+DOUBLEST
+ada_delta (type)
+     struct type *type;
+{
+  const char *encoding = fixed_type_info (type);
+  long num, den;
+
+  if (sscanf (encoding, "_%ld_%ld", &num, &den) < 2)
+    return -1.0;
+  else 
+    return (DOUBLEST) num / (DOUBLEST) den;
+}
+
+/* Assuming that ada_is_fixed_point_type (TYPE), return the scaling
+   factor ('SMALL value) associated with the type. */
+
+static DOUBLEST
+scaling_factor (type)
+     struct type *type;
+{
+  const char *encoding = fixed_type_info (type);
+  unsigned long num0, den0, num1, den1;
+  int n;
+  
+  n = sscanf (encoding, "_%lu_%lu_%lu_%lu", &num0, &den0, &num1, &den1);
+
+  if (n < 2)
+    return 1.0;
+  else if (n == 4)
+    return (DOUBLEST) num1 / (DOUBLEST) den1;
+  else 
+    return (DOUBLEST) num0 / (DOUBLEST) den0;
+}
+
+
+/* Assuming that X is the representation of a value of fixed-point
+   type TYPE, return its floating-point equivalent. */
+
+DOUBLEST
+ada_fixed_to_float (type, x)
+     struct type *type;
+     LONGEST x;
+{
+  return (DOUBLEST) x * scaling_factor (type);
+}
+
+/* The representation of a fixed-point value of type TYPE 
+   corresponding to the value X. */
+
+LONGEST
+ada_float_to_fixed (type, x)
+     struct type *type;
+     DOUBLEST x;
+{
+  return (LONGEST) (x / scaling_factor (type) + 0.5);
+}
+
+
+                               /* VAX floating formats */
+
+/* Non-zero iff TYPE represents one of the special VAX floating-point
+   types. */
+int
+ada_is_vax_floating_type (type)
+     struct type* type;
+{
+  int name_len = 
+    (ada_type_name (type) == NULL) ? 0 : strlen (ada_type_name (type));
+  return 
+    name_len > 6
+    && (TYPE_CODE (type) == TYPE_CODE_INT 
+       || TYPE_CODE (type) == TYPE_CODE_RANGE)
+    && STREQN (ada_type_name (type) + name_len - 6, "___XF", 5);
+}
+
+/* The type of special VAX floating-point type this is, assuming
+   ada_is_vax_floating_point */
+int
+ada_vax_float_type_suffix (type)
+     struct type* type;
+{
+  return ada_type_name (type)[strlen (ada_type_name (type))-1];
+}
+
+/* A value representing the special debugging function that outputs 
+   VAX floating-point values of the type represented by TYPE.  Assumes
+   ada_is_vax_floating_type (TYPE). */
+struct value*
+ada_vax_float_print_function (type)
+
+     struct type* type;
+{
+  switch (ada_vax_float_type_suffix (type)) {
+  case 'F':
+    return 
+      get_var_value ("DEBUG_STRING_F", 0);
+  case 'D':
+    return 
+      get_var_value ("DEBUG_STRING_D", 0);
+  case 'G':
+    return 
+      get_var_value ("DEBUG_STRING_G", 0);
+  default:
+    error ("invalid VAX floating-point type");
+  }
+}
+
+\f
+                               /* Range types */
+
+/* Scan STR beginning at position K for a discriminant name, and
+   return the value of that discriminant field of DVAL in *PX.  If
+   PNEW_K is not null, put the position of the character beyond the
+   name scanned in *PNEW_K.  Return 1 if successful; return 0 and do
+   not alter *PX and *PNEW_K if unsuccessful. */
+
+static int
+scan_discrim_bound (str, k, dval, px, pnew_k)
+     char *str;
+     int k;
+     struct value* dval;
+     LONGEST *px;
+     int *pnew_k;
+{
+  static char *bound_buffer = NULL;
+  static size_t bound_buffer_len = 0;
+  char *bound;
+  char *pend;
+  struct value* bound_val;
+
+  if (dval == NULL || str == NULL || str[k] == '\0')
+    return 0;
+
+  pend = strstr (str+k, "__");
+  if (pend == NULL)
+    {
+      bound = str+k;
+      k += strlen (bound);
+    }
+  else 
+    {
+      GROW_VECT (bound_buffer, bound_buffer_len, pend - (str+k) + 1);
+      bound = bound_buffer;
+      strncpy (bound_buffer, str+k, pend-(str+k));
+      bound[pend-(str+k)] = '\0';
+      k = pend-str;
+    }
+  
+  bound_val = 
+    ada_search_struct_field (bound, dval, 0, VALUE_TYPE (dval));
+  if (bound_val == NULL)
+    return 0;
+
+  *px = value_as_long (bound_val);
+  if (pnew_k != NULL)
+    *pnew_k = k;
+  return 1;
+}
+
+/* Value of variable named NAME in the current environment.  If
+   no such variable found, then if ERR_MSG is null, returns 0, and
+   otherwise causes an error with message ERR_MSG. */
+static struct value*
+get_var_value (name, err_msg)
+     char* name;
+     char* err_msg;
+{
+  struct symbol** syms;
+  struct block** blocks;
+  int nsyms;
+
+  nsyms = ada_lookup_symbol_list (name, get_selected_block (NULL), VAR_NAMESPACE,
+                                 &syms, &blocks);
+
+  if (nsyms != 1)
+    {
+      if (err_msg == NULL)
+       return 0;
+      else
+       error ("%s", err_msg);
+    }
+
+  return value_of_variable (syms[0], blocks[0]);
+}
+/* Value of integer variable named NAME in the current environment.  If
+   no such variable found, then if ERR_MSG is null, returns 0, and sets
+   *FLAG to 0.  If successful, sets *FLAG to 1. */
+LONGEST
+get_int_var_value (name, err_msg, flag)
+     char* name;
+     char* err_msg;
+     int* flag;
+{
+  struct value* var_val = get_var_value (name, err_msg);
+  
+  if (var_val == 0)
+    {
+      if (flag != NULL)
+       *flag = 0;
+      return 0;
+    }
+  else
+    {
+      if (flag != NULL)
+       *flag = 1;
+      return value_as_long (var_val);
+    }
+}
+
+/* Return a range type whose base type is that of the range type named
+   NAME in the current environment, and whose bounds are calculated
+   from NAME according to the GNAT range encoding conventions. 
+   Extract discriminant values, if needed, from DVAL.  If a new type
+   must be created, allocate in OBJFILE's space.  The bounds
+   information, in general, is encoded in NAME, the base type given in
+   the named range type. */
+
+static struct type*
+to_fixed_range_type (name, dval, objfile)
+     char *name;
+     struct value *dval;
+     struct objfile *objfile;
+{
+  struct type *raw_type = ada_find_any_type (name);
+  struct type *base_type;
+  LONGEST low, high;
+  char* subtype_info;
+
+  if (raw_type == NULL)
+    base_type = builtin_type_int;
+  else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE)
+    base_type = TYPE_TARGET_TYPE (raw_type);
+  else
+    base_type = raw_type;
+
+  subtype_info = strstr (name, "___XD");
+  if (subtype_info == NULL)
+    return raw_type;
+  else
+    {
+      static char *name_buf = NULL;
+      static size_t name_len = 0;
+      int prefix_len = subtype_info - name;
+      LONGEST L, U;
+      struct type *type;
+      char *bounds_str;
+      int n;
+
+      GROW_VECT (name_buf, name_len, prefix_len + 5);
+      strncpy (name_buf, name, prefix_len);
+      name_buf[prefix_len] = '\0';
+
+      subtype_info += 5;
+      bounds_str = strchr (subtype_info, '_');
+      n = 1;
+
+      if (*subtype_info == 'L') 
+       {
+         if (! ada_scan_number (bounds_str, n, &L, &n)
+             && ! scan_discrim_bound (bounds_str, n, dval, &L, &n))
+           return raw_type;
+         if (bounds_str[n] == '_')
+           n += 2;
+         else if (bounds_str[n] == '.') /* FIXME? SGI Workshop kludge. */
+           n += 1;
+         subtype_info += 1;
+       }
+      else 
+       {
+         strcpy (name_buf+prefix_len, "___L");
+         L = get_int_var_value (name_buf, "Index bound unknown.", NULL);
+       }
+
+      if (*subtype_info == 'U') 
+       {
+         if (! ada_scan_number (bounds_str, n, &U, &n)
+             && !scan_discrim_bound (bounds_str, n, dval, &U, &n))
+           return raw_type;
+       }
+      else 
+       {
+         strcpy (name_buf+prefix_len, "___U");
+         U = get_int_var_value (name_buf, "Index bound unknown.", NULL);
+       }
+
+      if (objfile == NULL) 
+       objfile = TYPE_OBJFILE (base_type);
+      type = create_range_type (alloc_type (objfile), base_type, L, U);
+      TYPE_NAME (type) = name; 
+      return type;
+    }
+}
+
+/* True iff NAME is the name of a range type. */
+int
+ada_is_range_type_name (name)
+     const char* name;
+{
+  return (name != NULL && strstr (name, "___XD"));
+}        
+
+\f
+                               /* Modular types */
+
+/* True iff TYPE is an Ada modular type. */
+int
+ada_is_modular_type (type)
+     struct type* type;
+{
+  /* FIXME: base_type should be declared in gdbtypes.h, implemented in
+     valarith.c */  
+  struct type* subranged_type; /* = base_type (type);*/
+
+  return (subranged_type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE
+         && TYPE_CODE (subranged_type) != TYPE_CODE_ENUM
+         && TYPE_UNSIGNED (subranged_type));
+}
+
+/* Assuming ada_is_modular_type (TYPE), the modulus of TYPE. */
+LONGEST
+ada_modulus (type)
+     struct type* type;
+{
+    return TYPE_HIGH_BOUND (type) + 1;
+}
+
+
+\f
+                               /* Operators */
+
+/* Table mapping opcodes into strings for printing operators
+   and precedences of the operators.  */
+
+static const struct op_print ada_op_print_tab[] =
+  {
+    {":=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
+    {"or else", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+    {"and then", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+    {"or",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+    {"xor",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+    {"and",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
+    {"=", BINOP_EQUAL, PREC_EQUAL, 0},
+    {"/=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+    {"<=", BINOP_LEQ, PREC_ORDER, 0},
+    {">=", BINOP_GEQ, PREC_ORDER, 0},
+    {">",  BINOP_GTR, PREC_ORDER, 0},
+    {"<",  BINOP_LESS, PREC_ORDER, 0},
+    {">>", BINOP_RSH, PREC_SHIFT, 0},
+    {"<<", BINOP_LSH, PREC_SHIFT, 0},
+    {"+",  BINOP_ADD, PREC_ADD, 0},
+    {"-",  BINOP_SUB, PREC_ADD, 0},
+    {"&",  BINOP_CONCAT, PREC_ADD, 0},
+    {"*",  BINOP_MUL, PREC_MUL, 0},
+    {"/",  BINOP_DIV, PREC_MUL, 0},
+    {"rem",  BINOP_REM, PREC_MUL, 0},
+    {"mod",  BINOP_MOD, PREC_MUL, 0},
+    {"**", BINOP_EXP, PREC_REPEAT, 0 },
+    {"@",  BINOP_REPEAT, PREC_REPEAT, 0},
+    {"-",  UNOP_NEG, PREC_PREFIX, 0},
+    {"+",  UNOP_PLUS, PREC_PREFIX, 0},
+    {"not ",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+    {"not ",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
+    {"abs ",  UNOP_ABS, PREC_PREFIX, 0},
+    {".all",  UNOP_IND, PREC_SUFFIX, 1},  /* FIXME: postfix .ALL */
+    {"'access",  UNOP_ADDR, PREC_SUFFIX, 1}, /* FIXME: postfix 'ACCESS */
+    {NULL, 0, 0, 0}
+};
+\f
+                       /* Assorted Types and Interfaces */
+
+struct type* builtin_type_ada_int;
+struct type* builtin_type_ada_short;
+struct type* builtin_type_ada_long;
+struct type* builtin_type_ada_long_long;
+struct type* builtin_type_ada_char;
+struct type* builtin_type_ada_float;
+struct type* builtin_type_ada_double;
+struct type* builtin_type_ada_long_double;
+struct type* builtin_type_ada_natural;
+struct type* builtin_type_ada_positive;
+struct type* builtin_type_ada_system_address;
+
+struct type ** const (ada_builtin_types[]) = 
+{
+  
+  &builtin_type_ada_int,
+  &builtin_type_ada_long,
+  &builtin_type_ada_short,
+  &builtin_type_ada_char,
+  &builtin_type_ada_float,
+  &builtin_type_ada_double,
+  &builtin_type_ada_long_long,
+  &builtin_type_ada_long_double,
+  &builtin_type_ada_natural,
+  &builtin_type_ada_positive,
+
+  /* The following types are carried over from C for convenience. */
+  &builtin_type_int,
+  &builtin_type_long,
+  &builtin_type_short,
+  &builtin_type_char,
+  &builtin_type_float,
+  &builtin_type_double,
+  &builtin_type_long_long,
+  &builtin_type_void,
+  &builtin_type_signed_char,
+  &builtin_type_unsigned_char,
+  &builtin_type_unsigned_short,
+  &builtin_type_unsigned_int,
+  &builtin_type_unsigned_long,
+  &builtin_type_unsigned_long_long,
+  &builtin_type_long_double,
+  &builtin_type_complex,
+  &builtin_type_double_complex,
+  0
+};
+
+/* Not really used, but needed in the ada_language_defn. */
+static void emit_char (int c, struct ui_file* stream, int quoter) 
+{
+  ada_emit_char (c, stream, quoter, 1);
+}
+
+const struct language_defn ada_language_defn = {
+  "ada",                       /* Language name */
+  /*  language_ada, */
+  language_unknown,
+  /* FIXME: language_ada should be defined in defs.h */
+  ada_builtin_types,
+  range_check_off,
+  type_check_off,
+  case_sensitive_on,           /* Yes, Ada is case-insensitive, but
+                                * that's not quite what this means. */
+  ada_parse,
+  ada_error,
+  ada_evaluate_subexp,
+  ada_printchar,               /* Print a character constant */
+  ada_printstr,                        /* Function to print string constant */
+  emit_char,                   /* Function to print single char (not used) */
+  ada_create_fundamental_type, /* Create fundamental type in this language */
+  ada_print_type,              /* Print a type using appropriate syntax */
+  ada_val_print,               /* Print a value using appropriate syntax */
+  ada_value_print,             /* Print a top-level value */
+  {"",     "",    "",  ""},    /* Binary format info */
+#if 0
+  {"8#%lo#",  "8#",   "o", "#"},       /* Octal format info */
+  {"%ld",   "",    "d", ""},   /* Decimal format info */
+  {"16#%lx#", "16#",  "x", "#"},       /* Hex format info */
+#else
+  /* Copied from c-lang.c. */
+  {"0%lo",  "0",   "o", ""},   /* Octal format info */
+  {"%ld",   "",    "d", ""},   /* Decimal format info */
+  {"0x%lx", "0x",  "x", ""},   /* Hex format info */
+#endif
+  ada_op_print_tab,            /* expression operators for printing */
+  1,                           /* c-style arrays (FIXME?) */
+  0,                           /* String lower bound (FIXME?) */
+  &builtin_type_ada_char,
+  LANG_MAGIC
+};
+
+void
+_initialize_ada_language ()
+{
+  builtin_type_ada_int =
+    init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+              0,
+              "integer", (struct objfile *) NULL);
+  builtin_type_ada_long =
+    init_type (TYPE_CODE_INT, TARGET_LONG_BIT / TARGET_CHAR_BIT,
+              0,
+              "long_integer", (struct objfile *) NULL);
+  builtin_type_ada_short =
+    init_type (TYPE_CODE_INT, TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+              0,
+              "short_integer", (struct objfile *) NULL);
+  builtin_type_ada_char =
+    init_type (TYPE_CODE_INT, TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+              0,
+              "character", (struct objfile *) NULL);
+  builtin_type_ada_float =
+    init_type (TYPE_CODE_FLT, TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+              0,
+              "float", (struct objfile *) NULL);
+  builtin_type_ada_double =
+    init_type (TYPE_CODE_FLT, TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+              0,
+              "long_float", (struct objfile *) NULL);
+  builtin_type_ada_long_long =
+    init_type (TYPE_CODE_INT, TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+              0,
+              "long_long_integer", (struct objfile *) NULL);
+  builtin_type_ada_long_double =
+    init_type (TYPE_CODE_FLT, TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+              0,
+              "long_long_float", (struct objfile *) NULL);
+  builtin_type_ada_natural =
+    init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+              0,
+              "natural", (struct objfile *) NULL);
+  builtin_type_ada_positive =
+    init_type (TYPE_CODE_INT, TARGET_INT_BIT / TARGET_CHAR_BIT,
+              0,
+              "positive", (struct objfile *) NULL);
+
+
+  builtin_type_ada_system_address = 
+    lookup_pointer_type (init_type (TYPE_CODE_VOID, 1, 0, "void", 
+                                   (struct objfile *) NULL));
+  TYPE_NAME (builtin_type_ada_system_address) = "system__address";
+
+  add_language (&ada_language_defn);
+
+  add_show_from_set 
+    (add_set_cmd ("varsize-limit", class_support, var_uinteger,
+                 (char*) &varsize_limit,
+                 "Set maximum bytes in dynamic-sized object.",
+                 &setlist),
+     &showlist);
+  varsize_limit = 65536;
+
+  add_com ("begin", class_breakpoint, begin_command,
+          "Start the debugged program, stopping at the beginning of the\n\
+main program.  You may specify command-line arguments to give it, as for\n\
+the \"run\" command (q.v.).");
+}
+
+
+/* Create a fundamental Ada type using default reasonable for the current
+   target machine.
+
+   Some object/debugging file formats (DWARF version 1, COFF, etc) do not
+   define fundamental types such as "int" or "double".  Others (stabs or
+   DWARF version 2, etc) do define fundamental types.  For the formats which
+   don't provide fundamental types, gdb can create such types using this
+   function.
+
+   FIXME:  Some compilers distinguish explicitly signed integral types
+   (signed short, signed int, signed long) from "regular" integral types
+   (short, int, long) in the debugging information.  There is some dis-
+   agreement as to how useful this feature is.  In particular, gcc does
+   not support this.  Also, only some debugging formats allow the
+   distinction to be passed on to a debugger.  For now, we always just
+   use "short", "int", or "long" as the type name, for both the implicit
+   and explicitly signed types.  This also makes life easier for the
+   gdb test suite since we don't have to account for the differences
+   in output depending upon what the compiler and debugging format
+   support.  We will probably have to re-examine the issue when gdb
+   starts taking it's fundamental type information directly from the
+   debugging information supplied by the compiler.  fnf@cygnus.com */
+
+static struct type *
+ada_create_fundamental_type (objfile, typeid)
+     struct objfile *objfile;
+     int typeid;
+{
+  struct type *type = NULL;
+
+  switch (typeid)
+    {
+      default:
+       /* FIXME:  For now, if we are asked to produce a type not in this
+          language, create the equivalent of a C integer type with the
+          name "<?type?>".  When all the dust settles from the type
+          reconstruction work, this should probably become an error. */
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_INT_BIT / TARGET_CHAR_BIT,
+                         0, "<?type?>", objfile);
+        warning ("internal error: no Ada fundamental type %d", typeid);
+       break;
+      case FT_VOID:
+       type = init_type (TYPE_CODE_VOID,
+                         TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+                         0, "void", objfile);
+       break;
+      case FT_CHAR:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+                         0, "character", objfile);
+       break;
+      case FT_SIGNED_CHAR:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+                         0, "signed char", objfile);
+       break;
+      case FT_UNSIGNED_CHAR:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_CHAR_BIT / TARGET_CHAR_BIT,
+                         TYPE_FLAG_UNSIGNED, "unsigned char", objfile);
+       break;
+      case FT_SHORT:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+                         0, "short_integer", objfile);
+       break;
+      case FT_SIGNED_SHORT:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+                         0, "short_integer", objfile); 
+       break;
+      case FT_UNSIGNED_SHORT:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_SHORT_BIT / TARGET_CHAR_BIT,
+                         TYPE_FLAG_UNSIGNED, "unsigned short", objfile);
+       break;
+      case FT_INTEGER:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_INT_BIT / TARGET_CHAR_BIT,
+                         0, "integer", objfile);
+       break;
+      case FT_SIGNED_INTEGER:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_INT_BIT / TARGET_CHAR_BIT,
+                         0, "integer", objfile); /* FIXME -fnf */
+       break;
+      case FT_UNSIGNED_INTEGER:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_INT_BIT / TARGET_CHAR_BIT,
+                         TYPE_FLAG_UNSIGNED, "unsigned int", objfile);
+       break;
+      case FT_LONG:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_LONG_BIT / TARGET_CHAR_BIT,
+                         0, "long_integer", objfile);
+       break;
+      case FT_SIGNED_LONG:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_LONG_BIT / TARGET_CHAR_BIT,
+                         0, "long_integer", objfile);
+       break;
+      case FT_UNSIGNED_LONG:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_LONG_BIT / TARGET_CHAR_BIT,
+                         TYPE_FLAG_UNSIGNED, "unsigned long", objfile);
+       break;
+      case FT_LONG_LONG:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+                         0, "long_long_integer", objfile);
+       break;
+      case FT_SIGNED_LONG_LONG:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+                         0, "long_long_integer", objfile);
+       break;
+      case FT_UNSIGNED_LONG_LONG:
+       type = init_type (TYPE_CODE_INT,
+                         TARGET_LONG_LONG_BIT / TARGET_CHAR_BIT,
+                         TYPE_FLAG_UNSIGNED, "unsigned long long", objfile);
+       break;
+      case FT_FLOAT:
+       type = init_type (TYPE_CODE_FLT,
+                         TARGET_FLOAT_BIT / TARGET_CHAR_BIT,
+                         0, "float", objfile);
+       break;
+      case FT_DBL_PREC_FLOAT:
+       type = init_type (TYPE_CODE_FLT,
+                         TARGET_DOUBLE_BIT / TARGET_CHAR_BIT,
+                         0, "long_float", objfile);
+       break;
+      case FT_EXT_PREC_FLOAT:
+       type = init_type (TYPE_CODE_FLT,
+                         TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT,
+                         0, "long_long_float", objfile);
+       break;
+      }
+  return (type);
+}
+
+void ada_dump_symtab (struct symtab* s)
+{
+  int i;
+  fprintf (stderr, "New symtab: [\n");
+  fprintf (stderr, "  Name: %s/%s;\n", 
+          s->dirname ? s->dirname : "?", 
+          s->filename ? s->filename : "?");
+  fprintf (stderr, "  Format: %s;\n", s->debugformat);
+  if (s->linetable != NULL)
+    {
+      fprintf (stderr, "  Line table (section %d):\n", s->block_line_section);
+      for (i = 0; i < s->linetable->nitems; i += 1)
+       {
+         struct linetable_entry* e = s->linetable->item + i;
+         fprintf (stderr, "    %4ld: %8lx\n", (long) e->line, (long) e->pc);
+       }
+    }
+  fprintf (stderr, "]\n");
+}
+
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
new file mode 100644 (file)
index 0000000..e5353f8
--- /dev/null
@@ -0,0 +1,365 @@
+/* Ada language support definitions for GDB, the GNU debugger.
+   Copyright 1992, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#if !defined (ADA_LANG_H)
+#define ADA_LANG_H 1
+
+#include "value.h"
+#include "gdbtypes.h"
+
+/* A macro to reorder the bytes of an address depending on the endiannes
+   of the target */
+#define EXTRACT_ADDRESS(x) ((void *) extract_address (&(x), sizeof (x)))
+/* A macro to reorder the bytes of an int depending on the endiannes
+   of the target */
+#define EXTRACT_INT(x) ((int) extract_signed_integer (&(x), sizeof (x)))
+
+/* Chain of cleanups for arguments of OP_UNRESOLVED_VALUE names.  Created in
+   yyparse and freed in ada_resolve. */
+extern struct cleanup* unresolved_names;
+
+/* Corresponding mangled/demangled names and opcodes for Ada user-definable 
+   operators. */
+struct ada_opname_map {
+  const char* mangled;
+  const char* demangled;
+  enum exp_opcode op;
+};
+
+/* Table of Ada operators in mangled and demangled forms. */
+/* Defined in ada-lang.c */
+extern const struct ada_opname_map ada_opname_table[];
+
+/* The maximum number of tasks known to the Ada runtime */
+extern const int MAX_NUMBER_OF_KNOWN_TASKS;
+
+/* Identifiers for Ada attributes that need special processing.  Be sure 
+   to update the table attribute_names in ada-lang.c whenever you change this.
+   */
+
+enum ada_attribute {
+  /* Invalid attribute for error checking. */
+  ATR_INVALID,
+
+  ATR_FIRST,
+  ATR_LAST,
+  ATR_LENGTH,
+  ATR_IMAGE,
+  ATR_IMG,
+  ATR_MAX,
+  ATR_MIN,
+  ATR_MODULUS,
+  ATR_POS,
+  ATR_SIZE,
+  ATR_TAG,
+  ATR_VAL,
+
+  /* Dummy last attribute. */
+  ATR_END
+};
+
+enum task_states {
+  Unactivated,
+  Runnable,
+  Terminated,
+  Activator_Sleep,
+  Acceptor_Sleep,
+  Entry_Caller_Sleep,
+  Async_Select_Sleep,
+  Delay_Sleep,
+  Master_Completion_Sleep,
+  Master_Phase_2_Sleep
+};
+
+extern char *ada_task_states[];
+
+typedef struct {
+  char *P_ARRAY;
+  int *P_BOUNDS;
+} fat_string;
+
+typedef struct entry_call {
+  void *self;
+} *entry_call_link;
+
+struct task_fields
+{
+  int entry_num;
+#if (defined (VXWORKS_TARGET) || !defined (i386)) \
+    && !(defined (VXWORKS_TARGET) && defined (M68K_TARGET))
+  int pad1;
+#endif
+  char state;
+#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET))
+  char pad_8bits;
+#endif
+  void *parent;
+  int priority;
+  int current_priority;
+  fat_string image;
+  entry_call_link call;
+#if (defined (sun) && defined (__SVR4)) && !defined (VXWORKS_TARGET)
+  int pad2;
+  unsigned thread;
+  unsigned lwp;
+#else
+  void *thread;
+  void *lwp;
+#endif
+}
+#if (defined (VXWORKS_TARGET) && defined (M68K_TARGET))
+__attribute__ ((packed))
+#endif
+;
+
+struct task_entry
+{
+  void *task_id;
+  int task_num;
+  int known_tasks_index;
+  struct task_entry *next_task;
+  void *thread;
+  void *lwp;
+  int stack_per;
+};
+
+extern struct type* builtin_type_ada_int;
+extern struct type* builtin_type_ada_short;
+extern struct type* builtin_type_ada_long;
+extern struct type* builtin_type_ada_long_long;
+extern struct type* builtin_type_ada_char;
+extern struct type* builtin_type_ada_float;
+extern struct type* builtin_type_ada_double;
+extern struct type* builtin_type_ada_long_double;
+extern struct type* builtin_type_ada_natural;
+extern struct type* builtin_type_ada_positive;
+extern struct type* builtin_type_ada_system_address;
+
+/* Assuming V points to an array of S objects,  make sure that it contains at 
+   least M objects, updating V and S as necessary. */
+
+#define GROW_VECT(v, s, m)                                             \
+   if ((s) < (m)) grow_vect ((void**) &(v), &(s), (m), sizeof(*(v)));
+
+extern void grow_vect (void**, size_t*, size_t, int);
+
+extern int ada_parse (void);   /* Defined in ada-exp.y */
+
+extern void ada_error (char *);        /* Defined in ada-exp.y */
+
+                       /* Defined in ada-typeprint.c */ 
+extern void ada_print_type (struct type*, char*, struct ui_file*, int, int);
+
+extern int ada_val_print (struct type*, char*, int, CORE_ADDR, 
+                         struct ui_file*, int, int, int, enum val_prettyprint);
+
+extern int ada_value_print (struct value*, struct ui_file*, int, 
+                           enum val_prettyprint);
+
+                               /* Defined in ada-lang.c */
+
+extern struct value* value_from_contents_and_address (struct type*, char*, CORE_ADDR);
+
+extern void ada_emit_char (int, struct ui_file *, int, int);
+
+extern void ada_printchar (int, struct ui_file*);
+
+extern void ada_printstr (struct ui_file*, char *, unsigned int, int, int);
+
+extern void ada_convert_actuals (struct value*, int, struct value**, CORE_ADDR*);
+
+extern struct value* ada_value_subscript (struct value*, int, struct value**);
+
+extern struct type* ada_array_element_type (struct type*, int);
+
+extern int ada_array_arity (struct type*);
+
+struct type* ada_type_of_array (struct value*, int);
+
+extern struct value* ada_coerce_to_simple_array (struct value*);
+
+extern struct value* ada_coerce_to_simple_array_ptr (struct value*);
+
+extern int ada_is_simple_array (struct type*);
+
+extern int ada_is_array_descriptor (struct type*);
+
+extern int ada_is_bogus_array_descriptor (struct type*);
+
+extern struct type* ada_index_type (struct type*, int);
+
+extern struct value* ada_array_bound (struct value*, int, int);
+
+extern int ada_lookup_symbol_list (const char*, struct block*, namespace_enum,
+                                  struct symbol***, struct block***);
+
+extern char*  ada_fold_name (const char*);
+
+extern struct symbol* ada_lookup_symbol (const char*, struct block*, namespace_enum);
+
+extern struct minimal_symbol* ada_lookup_minimal_symbol (const char*);
+
+extern void ada_resolve (struct expression**, struct type*);
+
+extern int ada_resolve_function (struct symbol**, struct block**, int, 
+                                struct value**, int, const char*, struct type*);
+
+extern void ada_fill_in_ada_prototype (struct symbol*);
+
+extern int user_select_syms (struct symbol**, struct block**, int, int);
+
+extern int get_selections (int*, int, int, int, char*);
+
+extern char* ada_start_decode_line_1 (char*);
+
+extern struct symtabs_and_lines ada_finish_decode_line_1 (char**, struct symtab*, int, char***);
+
+extern int ada_scan_number (const char*, int, LONGEST*, int*);
+
+extern struct type* ada_parent_type (struct type*);
+
+extern int ada_is_ignored_field (struct type*, int);
+
+extern int ada_is_packed_array_type (struct type*);
+
+extern struct value* ada_value_primitive_packed_val (struct value*, char*, long, int,
+                                                int, struct type*);
+
+extern struct type* ada_coerce_to_simple_array_type (struct type*);
+
+extern int ada_is_character_type (struct type*);
+
+extern int ada_is_string_type (struct type*);
+
+extern int  ada_is_tagged_type (struct type*);
+
+extern struct type* ada_tag_type (struct value*);
+
+extern struct value* ada_value_tag (struct value*);
+
+extern int ada_is_parent_field (struct type*, int);
+
+extern int ada_is_wrapper_field (struct type*, int);
+
+extern int ada_is_variant_part (struct type*, int);
+
+extern struct type* ada_variant_discrim_type (struct type*, struct type*);
+
+extern int ada_is_others_clause (struct type*, int);
+
+extern int ada_in_variant (LONGEST, struct type*, int);
+
+extern char* ada_variant_discrim_name (struct type*);
+
+extern struct type* ada_lookup_struct_elt_type (struct type*, char*, int, int*);
+
+extern struct value* ada_value_struct_elt (struct value*, char*, char*);
+
+extern struct value* ada_search_struct_field (char*, struct value*, int, struct type*);
+
+extern int ada_is_aligner_type (struct type*);
+
+extern struct type* ada_aligned_type (struct type*);
+
+extern char* ada_aligned_value_addr (struct type*, char*);
+
+extern const char* ada_attribute_name (int);
+
+extern int ada_is_fixed_point_type (struct type*);
+
+extern DOUBLEST ada_delta (struct type*);
+
+extern DOUBLEST ada_fixed_to_float (struct type *, LONGEST);
+
+extern LONGEST ada_float_to_fixed (struct type*, DOUBLEST);
+
+extern int ada_is_vax_floating_type (struct type*);
+
+extern int ada_vax_float_type_suffix (struct type*);
+
+extern struct value* ada_vax_float_print_function (struct type*);
+
+extern struct type* ada_system_address_type (void);
+
+extern int  ada_which_variant_applies (struct type*, struct type*, char*);
+
+extern struct value* ada_to_fixed_value (struct type*, char*, CORE_ADDR, struct value*);
+
+extern struct type* ada_to_fixed_type (struct type*, char*, CORE_ADDR, struct value*);
+
+extern int ada_name_prefix_len (const char*);
+
+extern char* ada_type_name (struct type*);
+
+extern struct type* ada_find_parallel_type (struct type*, const char *suffix);
+
+extern LONGEST get_int_var_value (char*, char*, int* );
+
+extern struct type* ada_find_any_type (const char *name);
+
+extern int ada_prefer_type (struct type*, struct type*);
+
+extern struct type* ada_get_base_type (struct type*);
+
+extern struct type* ada_completed_type (struct type*);
+
+extern char*  ada_mangle (const char*);
+
+extern const char* ada_enum_name (const char*);
+
+extern int ada_is_modular_type (struct type*);
+
+extern LONGEST ada_modulus (struct type*);
+
+extern struct value* ada_value_ind (struct value*);
+
+extern void ada_print_scalar (struct type*, LONGEST, struct ui_file*);
+
+extern int ada_is_range_type_name (const char*);
+
+extern const char* ada_renaming_type (struct type*);
+
+extern int ada_is_object_renaming (struct symbol*);
+
+extern const char* ada_simple_renamed_entity (struct symbol*);
+
+extern char* ada_breakpoint_rewrite (char*, int*);
+
+/* Tasking-related: ada-tasks.c */
+
+extern int valid_task_id (int);
+
+extern int get_current_task (void); 
+
+extern void init_task_list (void);
+
+extern void* get_self_id (void);
+
+extern int get_current_task (void);
+
+extern int get_entry_number (void*);
+
+extern void ada_report_exception_break (struct breakpoint *);
+
+extern int ada_maybe_exception_partial_symbol (struct partial_symbol* sym);
+
+extern int ada_is_exception_sym (struct symbol* sym);
+
+
+#endif
diff --git a/gdb/ada-lex.c b/gdb/ada-lex.c
new file mode 100644 (file)
index 0000000..9538f76
--- /dev/null
@@ -0,0 +1,3174 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ * $FreeBSD: src/usr.bin/lex/flex.skl,v 1.4 1999/10/27 07:56:44 obrien Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ *     if ( condition_holds )
+ *             yyless( 5 );
+ *     else
+ *             do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               *yy_cp = yy_hold_char; \
+               YY_RESTORE_YY_MORE_OFFSET \
+               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+       {
+       FILE *yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;         /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;                /* whether we need to initialize */
+static int yy_start = 0;       /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define YY_USES_REJECT
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yytext_ptr = yy_bp; \
+       yyleng = (int) (yy_cp - yy_bp); \
+       yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 57
+#define YY_END_OF_BUFFER 58
+static yyconst short int yy_acclist[386] =
+    {   0,
+       58,   56,   57,    1,   56,   57,    1,   57,   15,   56,
+       57,   53,   56,   57,   41,   56,   57,   56,   57,   43,
+       56,   57,   44,   56,   57,   41,   56,   57,   42,   56,
+       57,   41,   56,   57,   41,   56,   57,   41,   56,   57,
+        4,   56,   57,    4,   56,   57,   41,   56,   57,   41,
+       56,   57,   41,   56,   57,   41,   56,   57,   50,   56,
+       57,   47,   56,   57,   47,   56,   57,   47,   56,   57,
+       47,   56,   57,   47,   56,   57,   47,   56,   57,   47,
+       56,   57,   47,   56,   57,   47,   56,   57,   47,   56,
+       57,    1,   56,   57,   56,   57,   16,   56,   57,   53,
+
+       56,   57,   41,   56,   57,   56,   57,   43,   56,   57,
+       44,   56,   57,   41,   56,   57,   42,   56,   57,   41,
+       56,   57,   41,   56,   57,   41,   56,   57,    4,   56,
+       57,    4,   56,   57,   41,   56,   57,   41,   56,   57,
+       41,   56,   57,   41,   56,   57,   50,   56,   57,   41,
+       56,   57,   47,   56,   57,   47,   56,   57,   47,   56,
+       57,   47,   56,   57,   47,   56,   57,   47,   56,   57,
+       47,   56,   57,   47,   56,   57,   47,   56,   57,   47,
+       56,   57,   56,   57,   40,   56,   57,   51,   55,   54,
+       55,   55,   35,    2,   34,   46,   46,   37,    4,   36,
+
+       38,   33,   39,   47,   47,   47,   47,   47,   19,   47,
+       23,   47,   47,   47,   47,   47,   28,   47,   47,   47,
+       47,   16,   51,   55,   54,   55,   55,   16,   35,    2,
+       34,   46,   46,   37,    4,   36,   38,   33,   39,   16,
+       47,   47,   47,   47,   47,   19,   47,   23,   47,   47,
+       47,   47,   47,   28,   47,   47,   47,   47,16398,   52,
+       55,   12,   12,   32,    2,   46,   46,    9,    3,    7,
+       47,   47,   49,   20,   47,   21,   47,   47,   24,   47,
+       25,   47,   26,   47,   47,   29,   47,   47,   31,   47,
+       52,   55,   16,   32,    2,    2,   16,    2,   46,   46,
+
+        9,    3,    7,   47,   16,   47,   49,   20,   47,   21,
+       47,   47,   24,   47,   25,   47,   26,   47,   47,   29,
+       47,   47,   31,   47, 8206,   46,   45,   46,    6,    9,
+        3,   47,   22,   47,   27,   47,   30,   47,    2,   16,
+       46,   45,   46,    6,    9,    3,   47,   22,   47,   27,
+       47,   30,   47,   48,   47,   48,    2,    2,   18,   47,
+        5,   11,    8,   18,    2,    2,    5,   11,    8,   17,
+        5,    8,   17,    2,   18,    2,    5,    8,   13,    2,
+       17,   10,   10,   10,   10
+    } ;
+
+static yyconst short int yy_accept[364] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    2,    4,    7,
+        9,   12,   15,   18,   20,   23,   26,   29,   32,   35,
+       38,   41,   44,   47,   50,   53,   56,   59,   62,   65,
+       68,   71,   74,   77,   80,   83,   86,   89,   92,   95,
+       97,  100,  103,  106,  108,  111,  114,  117,  120,  123,
+      126,  129,  132,  135,  138,  141,  144,  147,  150,  153,
+      156,  159,  162,  165,  168,  171,  174,  177,  180,  183,
+      185,  188,  188,  188,  188,  188,  188,  188,  188,  188,
+      188,  188,  188,  190,  192,  193,  193,  193,  193,  193,
+      193,  193,  193,  194,  195,  195,  196,  196,  197,  198,
+
+      199,  199,  199,  200,  200,  200,  201,  202,  202,  203,
+      204,  204,  204,  205,  205,  206,  206,  207,  208,  209,
+      211,  213,  214,  215,  216,  217,  219,  220,  221,  222,
+      222,  223,  223,  225,  227,  228,  228,  228,  229,  229,
+      229,  230,  231,  231,  232,  232,  233,  234,  235,  235,
+      235,  236,  236,  236,  237,  238,  238,  239,  240,  241,
+      241,  242,  242,  243,  243,  244,  245,  246,  248,  250,
+      251,  252,  253,  254,  256,  257,  258,  259,  259,  260,
+      260,  260,  260,  260,  260,  260,  262,  262,  263,  264,
+      264,  265,  266,  266,  267,  268,  268,  269,  269,  270,
+
+      271,  271,  272,  272,  272,  272,  273,  274,  276,  278,
+      279,  281,  283,  285,  286,  288,  289,  291,  293,  293,
+      294,  295,  296,  298,  299,  299,  300,  301,  301,  302,
+      302,  303,  304,  304,  305,  305,  305,  305,  306,  306,
+      307,  308,  310,  312,  313,  315,  317,  319,  320,  322,
+      323,  325,  325,  326,  326,  326,  326,  326,  327,  329,
+      330,  330,  330,  331,  331,  332,  332,  332,  332,  332,
+      332,  332,  332,  332,  332,  332,  332,  332,  333,  335,
+      337,  339,  339,  339,  339,  339,  341,  341,  342,  344,
+      345,  345,  345,  346,  346,  347,  347,  347,  347,  348,
+
+      350,  352,  354,  355,  355,  355,  355,  355,  356,  356,
+      356,  356,  356,  356,  356,  356,  357,  357,  357,  358,
+      359,  359,  359,  359,  360,  360,  360,  361,  361,  361,
+      362,  363,  363,  364,  365,  365,  366,  367,  367,  368,
+      369,  369,  370,  371,  371,  372,  372,  373,  374,  376,
+      377,  378,  378,  379,  380,  380,  382,  382,  383,  384,
+      385,  386,  386
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    4,    5,    6,    7,    8,    5,    9,   10,   11,
+       12,   13,   14,   15,   16,   17,   18,   19,   20,   20,
+       20,   20,   20,   20,   20,   20,   20,   21,   22,   23,
+       24,   25,    5,   26,   30,   31,   32,   33,   34,   35,
+       36,   37,   38,   36,   36,   39,   40,   41,   42,   36,
+       36,   43,   44,   45,   46,   36,   47,   48,   36,   36,
+       27,    5,   28,    5,   29,    5,   30,   31,   32,   33,
+
+       34,   35,   36,   37,   38,   36,   36,   39,   40,   41,
+       42,   36,   36,   43,   44,   45,   46,   36,   47,   48,
+       36,   36,   26,   22,   26,    5,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[49] =
+    {   0,
+        1,    2,    3,    4,    5,    6,    7,    8,    5,    9,
+        5,    5,    5,    5,    5,    5,   10,    5,   11,   11,
+        9,    5,   12,   13,   14,    5,    5,    5,   15,   16,
+       16,   16,   16,   16,   16,   17,   17,   17,   17,   17,
+       17,   17,   17,   17,   17,   17,   17,   17
+    } ;
+
+static yyconst short int yy_base[385] =
+    {   0,
+        0,    0,   48,    0,   91,   92, 1405, 1771, 1771, 1771,
+       94,   96, 1771,  142, 1771, 1771, 1391, 1771, 1387,  189,
+     1378,  188,  194, 1377, 1376, 1374, 1361, 1771,  222,  242,
+       82,   91,   89,  196,   68,  163,  179,   97,  100,  194,
+        0,  280,  223,  328,  227,  228,  234,  229,  235,  375,
+      242,  418, 1335,  243,  463,  247,  251,  252,  254,  510,
+      168, 1343,  161, 1333,  234, 1331, 1336, 1323, 1316,    0,
+      558, 1340,  127,  258,  420,  422,  398, 1299, 1285, 1258,
+     1266, 1257,  411,  413,    0,  605, 1288, 1287, 1286, 1285,
+      119,  644, 1771,    0,  691, 1771,    0,    0, 1255, 1771,
+
+        0,  421,  690,  429,    0, 1771, 1771, 1244, 1771, 1771,
+      608,  696, 1771,  699,  419, 1247,  420,  422,  582,  583,
+      586,  587,  624,  625,  591,  590,  627,  628,  684,  430,
+     1771,  705,  653, 1256,  710, 1252,  731,    0, 1254,  750,
+      710,  798, 1222,  717,  802,  832, 1199,  720,  875,  730,
+     1189,  732,  892,  733,  795,  924,  796,  797, 1230,  971,
+      800,  997,    0,  876, 1183, 1191, 1176,    0,    0, 1174,
+     1151, 1150, 1097,    0, 1095, 1100, 1089, 1096,  805, 1043,
+     1047, 1043, 1023, 1016, 1010,  439,  808,  883, 1771, 1027,
+     1041,    0,  971,    0,  952,  736,  864,  614,  799,    0,
+
+      965,  976, 1046, 1061,    0, 1061, 1771,  714,  717,  858,
+      774,  789,  859, 1042,  860,  953,  954, 1047, 1086, 1108,
+        0, 1092,    0, 1094, 1140,    0,  950, 1182, 1091, 1110,
+     1199, 1210,    0, 1244,  981,    0,    0,    0, 1243, 1273,
+      890,    0,    0,  949,    0,    0,    0,  943,    0,  935,
+        0, 1120, 1771, 1188,  900, 1303,  895, 1771,    0,  882,
+        0, 1098, 1174,  440, 1177,  909,  421, 1048, 1093, 1102,
+     1169,  846,  818,  814,  822,  779,  792, 1249, 1190, 1191,
+     1192, 1322, 1228,  750, 1331, 1361,    0, 1106,    0, 1229,
+     1378,    0, 1325, 1326, 1349,  726,  725, 1410,    0,    0,
+
+        0,    0, 1771,  722,  839,  713,  644, 1369,  668,  671,
+      663,  615,  617,  576,  591, 1198,  540,  459,  456, 1440,
+     1462, 1483, 1458, 1771,  414,    0, 1517,  249,  794, 1238,
+      237,  258, 1310,    0,  203,  190,  209, 1460, 1477, 1350,
+        0, 1480, 1771,  131, 1328,  726, 1472,    0,    0,   86,
+     1516, 1523, 1522, 1385,  835,    0, 1505, 1511, 1527, 1533,
+     1549, 1771, 1571, 1587, 1592, 1608, 1622, 1639, 1642, 1649,
+       89,  187, 1656, 1672, 1689, 1701, 1707, 1718, 1720, 1736,
+      902,  903, 1743, 1754
+    } ;
+
+static yyconst short int yy_def[385] =
+    {   0,
+      362,    1,  362,    3,    1,    1,  362,  362,  362,  362,
+      362,  363,  362,  362,  362,  362,  362,  362,  362,  364,
+      362,  362,  362,  362,  365,  362,  362,  362,  366,  366,
+       30,   30,   30,   30,   30,   30,   30,   30,  367,  367,
+       11,  362,  367,  362,  367,  367,  367,  367,  367,  362,
+      367,  367,   52,  367,  362,  367,  367,  367,  367,  362,
+       60,   60,   60,   60,   60,   60,   60,   60,   60,   11,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  363,  363,  363,   71,   71,   71,   86,  362,
+       86,   86,  362,  368,  364,  362,  369,  370,  370,  362,
+
+      371,  362,  362,  362,  372,  362,  362,  373,  362,  362,
+      362,  362,  362,  374,   30,  362,   30,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   30,   30,  367,
+      362,  367,   42,   42,   42,   44,   44,   86,  137,  137,
+      367,  375,   50,  367,   55,  145,  146,  367,  367,  367,
+       52,  367,  149,  367,  367,  362,  367,  367,  376,  367,
+      367,  362,   60,  367,   60,   60,   60,   60,   60,   60,
+       60,   60,   60,   60,   60,   60,   60,   92,  362,  362,
+      362,  362,  362,  362,  362,  363,  362,  362,  362,   86,
+       92,  368,  377,  370,  370,  378,  362,  362,  362,  372,
+
+      373,  362,  374,  362,  379,  380,  362,   30,   30,   30,
+       30,   30,   30,   30,   30,   30,   30,   42,  367,   86,
+      140,  375,  368,  375,  362,  146,  146,  149,  367,  367,
+      367,  149,  156,  367,  362,  381,  162,  204,  145,   60,
+      367,   60,   60,   60,   60,   60,   60,   60,   60,   60,
+       60,  362,  362,  362,  362,   86,  377,  362,  370,  362,
+      382,  378,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  383,  380,   30,   30,
+       30,  367,  367,   86,   86,  368,  225,  367,  146,  367,
+      149,  228,  367,  367,  367,  362,  362,  362,  240,   60,
+
+       60,   60,  362,   86,  362,  384,  362,  362,  362,  362,
+      362,  362,  362,  362,  383,  367,   86,   86,  368,  368,
+      367,  149,  367,  362,  362,  298,  367,   86,  362,  362,
+      362,  384,  362,   86,   86,  368,  368,  367,  367,  367,
+      322,  367,  362,   86,  362,  362,  362,   86,  368,  368,
+      367,  367,  367,  362,  362,  368,  367,  362,  367,  362,
+      367,    0,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362
+    } ;
+
+static yyconst short int yy_nxt[1820] =
+    {   0,
+        8,    9,   10,    9,    8,   11,    8,   12,   13,   14,
+       15,   16,   17,   13,   18,   19,   20,   21,   22,   23,
+       24,   13,   25,   26,   27,   28,   13,   13,   29,   30,
+       29,   29,   29,   31,   29,   29,   29,   32,   29,   33,
+       34,   35,   36,   29,   37,   29,   29,   38,    8,    9,
+       10,   39,   40,   41,   40,   42,   43,   44,   45,   46,
+       47,   43,   48,   49,   50,   51,   52,   53,   54,   43,
+       55,   56,   57,   58,   59,   43,   60,   61,   60,   60,
+       60,   62,   60,   60,   60,   63,   60,   64,   65,   66,
+       67,   60,   68,   60,   60,   69,   70,   70,  115,  196,
+
+       71,   71,   72,   83,  196,  131,   73,   72,  115,   72,
+      126,   74,  115,  356,   84,   84,   75,   72,   76,  115,
+      119,  115,  115,   77,  190,  120,  132,  115,  188,  115,
+      122,  121,  179,   78,   79,   80,   81,  115,  129,   72,
+      354,   82,   86,   87,   87,   88,   89,   89,   89,   89,
+       89,   90,   89,   89,   89,   89,   89,   89,   89,   89,
+       89,   89,   89,   89,   89,   89,   89,   89,   91,   89,
+       89,   92,   92,   92,   92,   92,   92,   92,   92,   92,
+       92,   92,   92,   92,   92,   92,   92,   92,   92,   92,
+       95,   95,   95,  115,  101,  168,  127,  200,  165,  131,
+
+      101,  169,  200,  115,  102,   96,  103,  103,  166,  115,
+      102,   97,  103,  103,  350,  128,  103,  349,   99,  115,
+      132,  104,  103,  111,  111,  112,  115,  104,  131,  123,
+      348,  113,  131,  131,  131,  105,  115,  124,  114,  131,
+      131,  125,  116,  111,  111,  112,  141,  131,  131,  132,
+      142,  113,  131,  132,  132,  132,  131,  131,  114,  159,
+      132,  132,  116,  179,  331,  148,  154,  171,  132,  132,
+      346,  157,  117,  132,  158,  172,  344,  132,  132,  173,
+      132,   72,  118,  130,  130,  131,  130,  133,  130,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  134,  134,
+
+      130,  130,  130,  130,  130,  130,  132,  130,  135,  135,
+      135,  135,  135,  135,  135,  135,  135,  135,  135,  135,
+      135,  135,  135,  135,  135,  135,  135,  135,   86,   87,
+       87,  136,  137,  138,  137,  137,  137,  130,  137,  137,
+      137,  137,  137,  137,  137,  137,  137,  137,  137,  137,
+      137,  137,  137,  137,  139,  137,  137,  140,  140,  140,
+      140,  140,  140,  140,  140,  140,  140,  140,  140,  140,
+      140,  140,  140,  140,  140,  140,   95,   95,  143,  130,
+      131,  130,  130,  130,  130,  130,  130,  130,  130,  130,
+      130,  144,  130,  130,  130,  130,  130,  145,  130,  130,
+
+      130,  132,  130,  146,  147,  146,  146,  146,  146,  146,
+      146,  146,  146,  146,  146,  146,  146,  146,  146,  146,
+      146,  146,  146,  131,  149,  179,  308,  179,  180,  186,
+      186,   84,   84,  266,  150,  131,  151,  151,  181,  197,
+      197,  343,  198,   72,  132,   72,  151,  199,  199,  115,
+      115,  152,  115,  307,  209,  307,  132,  186,  186,  115,
+      115,  336,  115,  208,  335,  153,  130,  130,  131,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,
+      130,  130,  130,  130,  130,  130,  155,  130,  130,  132,
+      130,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  111,  111,  160,  130,  131,  130,  130,  130,  161,
+      130,  130,  130,  130,  130,  130,  162,  130,  163,  163,
+      164,  130,  130,  130,  130,  130,  132,  130,  163,  163,
+      163,  163,  163,  163,  163,  163,  163,  163,  163,  163,
+      163,  163,  163,  163,  163,  163,  163,  163,   86,   87,
+       87,   87,   86,   86,   86,   86,   86,  334,   86,   86,
+       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
+       86,   86,   86,   86,   86,   86,   86,  178,  178,  178,
+      178,  178,  178,  178,  178,  178,  178,  178,  178,  178,
+
+      178,  178,  178,  178,  178,  178,   86,   86,   86,  111,
+      111,  111,  115,  115,  187,  308,  115,  115,  266,  211,
+      115,  115,  115,  115,  114,  210,  115,  115,  116,  214,
+      115,  115,  199,  199,   86,   86,   86,   86,   86,   86,
+       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
+       86,   86,   86,  188,  115,  115,  266,  115,  115,  266,
+      135,  216,  333,  333,  115,  115,  215,  115,  115,  213,
+      212,  218,  218,  191,  191,  191,  191,  191,  191,  191,
+      191,  191,  191,  191,  191,  191,  191,  191,  191,  191,
+      191,  191,   95,   95,   95,  266,  101,  111,  111,  112,
+
+      203,  203,  203,  266,  204,  113,  102,  362,  103,  103,
+      159,  266,  114,   97,  115,  131,  116,  135,  103,  331,
+       99,  205,  131,  104,  115,  131,  217,  328,  135,  135,
+      325,  132,   86,   86,  137,  131,  132,  131,  131,  355,
+      219,  355,  260,  132,  115,  230,  132,  115,  229,  229,
+      231,  231,  261,  324,  115,  317,  132,  115,  132,  132,
+      137,  137,  137,  137,  137,  137,  137,  137,  137,  137,
+      137,  137,  137,  137,  137,  137,  137,  137,  137,  221,
+      221,  221,  221,  221,  221,  221,  221,  221,  221,  221,
+      221,  221,  221,  221,  221,  221,  221,  221,  192,  192,
+
+      131,  131,  131,  223,  115,  131,  252,  252,  252,  254,
+      254,  254,  330,  330,  115,  253,  308,  265,  265,  115,
+      314,  132,  132,  132,  224,  130,  132,  265,  255,  115,
+      225,  225,  225,  225,  225,  225,  225,  225,  225,  225,
+      225,  225,  225,  225,  225,  225,  225,  225,  225,  225,
+      226,  226,  329,  358,  358,  313,  266,  330,  330,  312,
+      226,  226,  226,  226,  226,  226,  226,  226,  226,  226,
+      226,  226,  226,  226,  226,  226,  226,  226,  226,  226,
+      131,  131,  263,  263,  254,  254,  254,  311,  115,  115,
+      115,  279,  263,  228,  228,  131,  241,  264,  115,  115,
+
+      115,  132,  132,  255,  228,  228,  228,  228,  228,  228,
+      232,  232,  297,  306,  308,  305,  132,  297,  306,  258,
+      303,  232,  232,  232,  232,  232,  232,  130,  130,  131,
+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,
+      130,  130,  233,  233,  130,  130,  130,  130,  234,  130,
+      132,  130,  233,  233,  233,  233,  233,  233,  233,  233,
+      233,  233,  233,  233,  233,  233,  233,  233,  233,  233,
+      233,  233,  111,  111,  160,  302,  131,  111,  111,  112,
+      161,  301,  300,  115,  115,  113,  296,  162,  289,  202,
+      259,  164,  114,  281,  115,  258,  116,  132,  203,  203,
+
+      237,  130,  238,  130,  130,  130,  130,  130,  130,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  130,  239,
+      130,  130,  130,  132,  130,  240,  240,  240,  240,  240,
+      240,  240,  240,  240,  240,  240,  240,  240,  240,  240,
+      240,  240,  240,  240,  240,  256,  256,  203,  203,  203,
+      187,  204,   72,  308,  135,   72,  256,  256,  256,  256,
+      256,  256,  111,  111,  112,  218,  218,   72,  205,  266,
+      113,  266,  115,  267,  266,   72,  266,  114,  268,   72,
+      280,  116,  115,  269,  266,  270,   72,  254,  254,  282,
+      271,  131,  192,  192,  192,  192,  131,  223,  308,  286,
+
+      272,  273,  274,  275,  260,  187,  283,  308,  276,  293,
+      293,  131,  132,  284,  261,  131,  266,  132,  224,  293,
+      224,  252,  252,  252,  294,  266,  285,  285,  231,  231,
+      253,  251,  132,  250,  249,  248,  132,  285,  285,  285,
+      285,  285,  285,  130,  130,  131,  130,  130,  130,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  287,  287,
+      130,  130,  130,  130,  288,  130,  132,  130,  287,  287,
+      287,  287,  287,  287,  287,  287,  287,  287,  287,  287,
+      287,  287,  287,  287,  287,  287,  287,  287,  290,  254,
+      254,  254,  263,  263,  247,  265,  265,  246,  291,  309,
+
+      292,  292,  263,  131,  131,  265,  245,  264,  255,  310,
+      292,  292,  292,  292,  292,  292,  292,  295,  295,  244,
+      115,  115,  115,  243,  132,  132,  242,  295,  232,  232,
+      115,  115,  115,  131,  131,  235,  130,  227,  130,  232,
+      232,  232,  232,  232,  232,  111,  111,  160,  316,  131,
+      111,  111,  112,  161,  132,  132,  345,  345,  113,  220,
+      162,  219,  321,  135,  164,  114,  345,  207,  202,  116,
+      132,  298,  298,  298,  298,  298,  298,  298,  298,  298,
+      298,  298,  298,  298,  298,  298,  298,  298,  298,  298,
+      298,  299,  299,  195,  189,  188,  188,  187,  185,  184,
+
+       72,  299,  299,  299,  299,  299,  299,  299,  299,  299,
+      299,  299,  299,  299,  299,  299,  299,  299,  299,  299,
+      299,  304,  304,  254,  254,  282,  183,  131,  347,  347,
+      131,  131,  304,  304,  304,  304,  304,  304,  347,  323,
+      182,  323,  283,  293,  293,  179,  345,  345,  132,  318,
+      318,  132,  132,  293,  131,  131,  345,  177,  294,  176,
+      318,  318,  318,  318,  318,  318,  319,  295,  295,  175,
+      111,  111,  112,  174,  170,  132,  132,  295,  113,  320,
+      320,  167,  130,  352,  110,  114,  254,  254,  254,  116,
+      320,  320,  320,  320,  320,  320,  322,  322,  109,  107,
+
+      106,  100,   94,   93,  362,  255,  362,  322,  322,  322,
+      322,  322,  322,  130,  130,  131,  130,  130,  130,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  326,  326,
+      130,  130,  130,  130,  327,  130,  132,  130,  326,  326,
+      326,  326,  326,  326,  326,  326,  326,  326,  326,  326,
+      326,  326,  326,  326,  326,  326,  326,  326,  337,  337,
+      362,  362,  362,  131,  362,  131,  362,  131,  362,  337,
+      337,  337,  337,  337,  337,  338,  342,  342,  339,  339,
+      339,  339,  131,  362,  132,  131,  132,  362,  132,  340,
+      347,  347,  362,  362,  362,  351,  351,  362,  353,  353,
+
+      347,  341,  341,  132,  362,  351,  132,  362,  353,  362,
+      131,  341,  341,  341,  341,  341,  341,  341,  111,  111,
+      160,  131,  131,  359,  359,  362,  161,  131,  131,  360,
+      360,  132,  131,  162,  351,  351,  357,  164,  357,  360,
+      353,  353,  132,  132,  351,  361,  361,  362,  132,  132,
+      353,  360,  360,  132,  131,  361,  362,  362,  362,  362,
+      362,  360,  362,  362,  362,  362,  362,  361,  361,  362,
+      362,  362,  362,  362,  362,  132,  362,  361,   85,  362,
+      362,   85,  362,  362,  362,   85,   85,   85,   98,   98,
+       98,  362,  362,  362,  362,  362,   98,  362,   98,  362,
+
+      362,   98,   98,   98,  108,  362,  108,  108,  108,  115,
+      115,  115,  362,  362,  362,  362,  115,  115,  115,  362,
+      362,  362,  115,  115,  115,  130,  130,  130,  130,  130,
+      130,  130,  130,  130,  130,  130,  130,  130,  130,  192,
+      192,  362,  192,  192,  192,  192,  192,  192,  192,  192,
+      192,  192,  192,  192,  192,  192,  193,  193,  193,  194,
+      362,  362,  362,  194,  194,  194,  201,  362,  362,  201,
+      201,  201,  201,  206,  206,  206,  362,  206,  362,  362,
+      362,  362,  362,  206,  362,  362,  206,  206,  206,  222,
+      222,  362,  222,  222,  222,  222,  222,  222,  222,  222,
+
+      222,  222,  222,  222,  222,  222,  236,  362,  362,  362,
+      362,  236,  362,  362,  362,  362,  236,  257,  362,  362,
+      257,  257,  257,  257,  262,  362,  362,  262,  262,  362,
+      362,  362,  262,  262,  277,  277,  277,  278,  278,  278,
+      362,  362,  362,  362,  278,  278,  278,  362,  362,  362,
+      278,  278,  278,  315,  362,  362,  315,  315,  315,  315,
+      332,  362,  362,  362,  332,  362,  362,  362,  332,  332,
+        7,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362
+    } ;
+
+static yyconst short int yy_chk[1820] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    5,    6,   35,  371,
+
+        5,    6,   11,   12,  371,   39,   11,   11,   35,   11,
+       35,   11,   31,  350,   12,   12,   11,   11,   11,   33,
+       31,   32,   31,   11,   91,   32,   39,   38,   91,   33,
+       33,   32,   73,   11,   11,   11,   11,   38,   38,   73,
+      344,   11,   14,   14,   14,   14,   14,   14,   14,   14,
+       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
+       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
+       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
+       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
+       20,   20,   20,   36,   22,   63,   36,  372,   61,   40,
+
+       23,   63,  372,   36,   22,   20,   22,   22,   61,   37,
+       23,   20,   23,   23,  337,   37,   22,  336,   20,   37,
+       40,   22,   23,   29,   29,   29,   34,   23,   43,   34,
+      335,   29,   45,   46,   48,   22,   34,   34,   29,   47,
+       49,   34,   29,   30,   30,   30,   47,   51,   54,   43,
+       49,   30,   56,   45,   46,   48,   57,   58,   30,   59,
+       47,   49,   30,   74,  332,   51,   54,   65,   51,   54,
+      331,   56,   30,   56,   57,   65,  328,   57,   58,   65,
+       59,   74,   30,   42,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
+
+       42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
+       42,   42,   42,   42,   42,   42,   42,   42,   44,   44,
+       44,   44,   44,   44,   44,   44,   44,   44,   44,   44,
+       44,   44,   44,   44,   44,   44,   44,   44,   44,   44,
+       44,   44,   44,   44,   44,   44,   44,   44,   44,   44,
+       44,   44,   44,   44,   44,   44,   44,   44,   44,   44,
+       44,   44,   44,   44,   44,   44,   50,   50,   50,   50,
+       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
+       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
+
+       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
+       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
+       50,   50,   50,   52,   52,   75,  267,   76,   77,   83,
+       83,   84,   84,  267,   52,  130,   52,   52,   77,  102,
+      102,  325,  104,   75,   52,   76,   52,  104,  104,  115,
+      117,   52,  118,  264,  118,  264,  130,  186,  186,  115,
+      117,  319,  118,  117,  318,   52,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+
+       55,   55,   55,   55,   55,   55,   55,   55,   55,   55,
+       55,   60,   60,   60,   60,   60,   60,   60,   60,   60,
+       60,   60,   60,   60,   60,   60,   60,   60,   60,   60,
+       60,   60,   60,   60,   60,   60,   60,   60,   60,   60,
+       60,   60,   60,   60,   60,   60,   60,   60,   60,   60,
+       60,   60,   60,   60,   60,   60,   60,   60,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,  317,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+       71,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+
+       71,   71,   71,   71,   71,   71,   86,   86,   86,  111,
+      111,  111,  119,  120,   86,  315,  121,  122,  314,  122,
+      126,  125,  119,  120,  111,  119,  121,  122,  111,  125,
+      126,  125,  198,  198,   86,   86,   86,   86,   86,   86,
+       86,   86,   86,   86,   86,   86,   86,   86,   86,   86,
+       86,   86,   86,   92,  123,  124,  313,  127,  128,  312,
+      133,  128,  307,  307,  123,  124,  127,  127,  128,  124,
+      123,  133,  133,   92,   92,   92,   92,   92,   92,   92,
+       92,   92,   92,   92,   92,   92,   92,   92,   92,   92,
+       92,   92,   95,   95,   95,  311,  103,  112,  112,  112,
+
+      114,  114,  114,  310,  114,  112,  103,   95,  103,  103,
+      132,  309,  112,   95,  129,  141,  112,  135,  103,  306,
+       95,  114,  144,  103,  129,  148,  129,  304,  135,  135,
+      297,  132,  137,  137,  137,  150,  141,  152,  154,  346,
+      137,  346,  196,  144,  208,  152,  148,  209,  150,  150,
+      152,  152,  196,  296,  208,  284,  150,  209,  152,  154,
+      137,  137,  137,  137,  137,  137,  137,  137,  137,  137,
+      137,  137,  137,  137,  137,  137,  137,  137,  137,  140,
+      140,  140,  140,  140,  140,  140,  140,  140,  140,  140,
+      140,  140,  140,  140,  140,  140,  140,  140,  142,  142,
+
+      155,  157,  158,  142,  211,  161,  179,  179,  179,  187,
+      187,  187,  329,  329,  211,  179,  277,  199,  199,  212,
+      276,  155,  157,  158,  142,  145,  161,  199,  187,  212,
+      145,  145,  145,  145,  145,  145,  145,  145,  145,  145,
+      145,  145,  145,  145,  145,  145,  145,  145,  145,  145,
+      146,  146,  305,  355,  355,  275,  274,  305,  305,  273,
+      146,  146,  146,  146,  146,  146,  146,  146,  146,  146,
+      146,  146,  146,  146,  146,  146,  146,  146,  146,  146,
+      149,  164,  197,  197,  188,  188,  188,  272,  210,  213,
+      215,  210,  197,  149,  149,  241,  164,  197,  210,  213,
+
+      215,  149,  164,  188,  149,  149,  149,  149,  149,  149,
+      153,  153,  381,  382,  266,  260,  241,  381,  382,  257,
+      255,  153,  153,  153,  153,  153,  153,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  156,  156,  156,  156,  156,  156,  156,  156,
+      156,  156,  160,  160,  160,  250,  160,  202,  202,  202,
+      160,  248,  244,  216,  217,  202,  235,  160,  227,  201,
+      195,  160,  202,  216,  217,  193,  202,  160,  162,  162,
+
+      162,  162,  162,  162,  162,  162,  162,  162,  162,  162,
+      162,  162,  162,  162,  162,  162,  162,  162,  162,  162,
+      162,  162,  162,  162,  162,  162,  162,  162,  162,  162,
+      162,  162,  162,  162,  162,  162,  162,  162,  162,  162,
+      162,  162,  162,  162,  162,  190,  190,  203,  203,  203,
+      191,  203,  185,  268,  218,  184,  190,  190,  190,  190,
+      190,  190,  206,  206,  206,  218,  218,  183,  203,  204,
+      206,  268,  214,  204,  204,  182,  204,  206,  204,  181,
+      214,  206,  214,  204,  204,  204,  180,  219,  219,  219,
+      204,  219,  222,  222,  224,  224,  229,  222,  269,  224,
+
+      204,  204,  204,  204,  262,  178,  219,  270,  204,  229,
+      229,  288,  219,  220,  262,  230,  269,  229,  222,  229,
+      224,  252,  252,  252,  229,  270,  220,  220,  230,  230,
+      252,  177,  288,  176,  175,  173,  230,  220,  220,  220,
+      220,  220,  220,  225,  225,  225,  225,  225,  225,  225,
+      225,  225,  225,  225,  225,  225,  225,  225,  225,  225,
+      225,  225,  225,  225,  225,  225,  225,  225,  225,  225,
+      225,  225,  225,  225,  225,  225,  225,  225,  225,  225,
+      225,  225,  225,  225,  225,  225,  225,  225,  228,  254,
+      254,  254,  263,  263,  172,  265,  265,  171,  228,  271,
+
+      228,  228,  263,  316,  231,  265,  170,  263,  254,  271,
+      228,  228,  228,  228,  228,  228,  228,  231,  231,  167,
+      279,  280,  281,  166,  316,  231,  165,  231,  232,  232,
+      279,  280,  281,  283,  290,  159,  151,  147,  143,  232,
+      232,  232,  232,  232,  232,  234,  234,  234,  283,  234,
+      278,  278,  278,  234,  283,  290,  330,  330,  278,  139,
+      234,  136,  290,  134,  234,  278,  330,  116,  108,  278,
+      234,  239,  239,  239,  239,  239,  239,  239,  239,  239,
+      239,  239,  239,  239,  239,  239,  239,  239,  239,  239,
+      239,  240,  240,   99,   90,   89,   88,   87,   82,   81,
+
+       80,  240,  240,  240,  240,  240,  240,  240,  240,  240,
+      240,  240,  240,  240,  240,  240,  240,  240,  240,  240,
+      240,  256,  256,  282,  282,  282,   79,  282,  333,  333,
+      293,  294,  256,  256,  256,  256,  256,  256,  333,  294,
+       78,  294,  282,  293,  293,   72,  345,  345,  282,  285,
+      285,  293,  294,  293,  295,  340,  345,   69,  293,   68,
+      285,  285,  285,  285,  285,  285,  286,  295,  295,   67,
+      308,  308,  308,   66,   64,  295,  340,  295,  308,  286,
+      286,   62,   53,  340,   27,  308,  354,  354,  354,  308,
+      286,  286,  286,  286,  286,  286,  291,  291,   26,   25,
+
+       24,   21,   19,   17,    7,  354,    0,  291,  291,  291,
+      291,  291,  291,  298,  298,  298,  298,  298,  298,  298,
+      298,  298,  298,  298,  298,  298,  298,  298,  298,  298,
+      298,  298,  298,  298,  298,  298,  298,  298,  298,  298,
+      298,  298,  298,  298,  298,  298,  298,  298,  298,  298,
+      298,  298,  298,  298,  298,  298,  298,  298,  320,  320,
+        0,    0,    0,  323,    0,  338,    0,  321,    0,  320,
+      320,  320,  320,  320,  320,  321,  323,  323,  338,  338,
+      321,  321,  339,    0,  323,  342,  338,    0,  321,  322,
+      347,  347,    0,    0,    0,  339,  339,    0,  342,  342,
+
+      347,  322,  322,  339,    0,  339,  342,    0,  342,    0,
+      357,  322,  322,  322,  322,  322,  322,  322,  327,  327,
+      327,  351,  327,  357,  357,    0,  327,  353,  352,  358,
+      358,  357,  359,  327,  351,  351,  352,  327,  352,  358,
+      353,  353,  351,  327,  351,  359,  359,    0,  353,  352,
+      353,  360,  360,  359,  361,  359,    0,    0,    0,    0,
+        0,  360,    0,    0,    0,    0,    0,  361,  361,    0,
+        0,    0,    0,    0,    0,  361,    0,  361,  363,    0,
+        0,  363,    0,    0,    0,  363,  363,  363,  364,  364,
+      364,    0,    0,    0,    0,    0,  364,    0,  364,    0,
+
+        0,  364,  364,  364,  365,    0,  365,  365,  365,  366,
+      366,  366,    0,    0,    0,    0,  366,  366,  366,    0,
+        0,    0,  366,  366,  366,  367,  367,  367,  367,  367,
+      367,  367,  367,  367,  367,  367,  367,  367,  367,  368,
+      368,    0,  368,  368,  368,  368,  368,  368,  368,  368,
+      368,  368,  368,  368,  368,  368,  369,  369,  369,  370,
+        0,    0,    0,  370,  370,  370,  373,    0,    0,  373,
+      373,  373,  373,  374,  374,  374,    0,  374,    0,    0,
+        0,    0,    0,  374,    0,    0,  374,  374,  374,  375,
+      375,    0,  375,  375,  375,  375,  375,  375,  375,  375,
+
+      375,  375,  375,  375,  375,  375,  376,    0,    0,    0,
+        0,  376,    0,    0,    0,    0,  376,  377,    0,    0,
+      377,  377,  377,  377,  378,    0,    0,  378,  378,    0,
+        0,    0,  378,  378,  379,  379,  379,  380,  380,  380,
+        0,    0,    0,    0,  380,  380,  380,    0,    0,    0,
+      380,  380,  380,  383,    0,    0,  383,  383,  383,  383,
+      384,    0,    0,    0,  384,    0,    0,    0,  384,  384,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+
+      362,  362,  362,  362,  362,  362,  362,  362,  362,  362,
+      362,  362,  362,  362,  362,  362,  362,  362,  362
+    } ;
+
+static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr;
+static char *yy_full_match;
+static int yy_lp;
+static int yy_looking_for_trail_begin = 0;
+static int yy_full_lp;
+static int *yy_full_state;
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#define REJECT \
+{ \
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \
+yy_cp = yy_full_match; /* restore poss. backed-over text */ \
+yy_lp = yy_full_lp; /* restore orig. accepting pos. */ \
+yy_state_ptr = yy_full_state; /* restore orig. state */ \
+yy_current_state = *yy_state_ptr; /* restore curr. state */ \
+++yy_lp; \
+goto find_rule; \
+}
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "./ada-lex.l"
+#define INITIAL 0
+/* FLEX lexer for Ada expressions, for GDB.
+   Copyright (C) 1994, 1997, 2000
+   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+/*----------------------------------------------------------------------*/
+/* The converted version of this file is to be included in ada-exp.y, */
+/* the Ada parser for gdb.  The function yylex obtains characters from */
+/* the global pointer lexptr.  It returns a syntactic category for */
+/* each successive token and places a semantic value into yylval */
+/* (ada-lval), defined by the parser.   */
+/* Run flex with (at least) the -i option (case-insensitive), and the -I */
+/* option (interactive---no unnecessary lookahead).  */
+#line 48 "./ada-lex.l"
+#define NUMERAL_WIDTH 256
+#define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
+
+/* Temporary staging for numeric literals. */
+static char numbuf[NUMERAL_WIDTH]; 
+ static void canonicalizeNumeral (char* s1, const char*);
+static int processInt (const char*, const char*, const char*);
+static int processReal (const char*);
+static int processId (const char*, int);
+static int processAttribute (const char*);
+static int find_dot_all (const char*);
+
+#undef YY_DECL
+#define YY_DECL static int yylex ( void ) 
+
+#undef YY_INPUT
+#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
+    if ( *lexptr == '\000' ) \
+      (RESULT) = YY_NULL; \
+    else \
+      { \
+        *(BUF) = *lexptr; \
+        (RESULT) = 1; \
+       lexptr += 1; \
+      }
+
+static char *tempbuf = NULL;
+static int tempbufsize = 0;
+static int tempbuf_len;
+static struct block* left_block_context;
+
+static void resize_tempbuf (unsigned int);
+
+static void block_lookup (char*, char*);
+
+static int name_lookup (char*, char*, int*);
+
+static int find_dot_all (const char*);
+
+#define IN_STRING 1
+#define BEFORE_QUAL_QUOTE 2
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( yy_current_buffer->yy_is_interactive ) \
+               { \
+               int c = '*', n; \
+               for ( n = 0; n < max_size && \
+                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+                       buf[n] = (char) c; \
+               if ( c == '\n' ) \
+                       buf[n++] = (char) c; \
+               if ( c == EOF && ferror( yyin ) ) \
+                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
+               result = n; \
+               } \
+       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+                 && ferror( yyin ) ) \
+               YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+YY_DECL
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+
+#line 91 "./ada-lex.l"
+
+
+
+       if ( yy_init )
+               {
+               yy_init = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yy_start )
+                       yy_start = 1;   /* first start state */
+
+               if ( ! yyin )
+                       yyin = stdin;
+
+               if ( ! yyout )
+                       yyout = stdout;
+
+               if ( ! yy_current_buffer )
+                       yy_current_buffer =
+                               yy_create_buffer( yyin, YY_BUF_SIZE );
+
+               yy_load_buffer_state();
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yy_start;
+               yy_state_ptr = yy_state_buf;
+               *yy_state_ptr++ = yy_current_state;
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 363 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       *yy_state_ptr++ = yy_current_state;
+                       ++yy_cp;
+                       }
+               while ( yy_base[yy_current_state] != 1771 );
+
+yy_find_action:
+               yy_current_state = *--yy_state_ptr;
+               yy_lp = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+               for ( ; ; ) /* until we find what rule we matched */
+                       {
+                       if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )
+                               {
+                               yy_act = yy_acclist[yy_lp];
+                               if ( yy_act & YY_TRAILING_HEAD_MASK ||
+                                    yy_looking_for_trail_begin )
+                                       {
+                                       if ( yy_act == yy_looking_for_trail_begin )
+                                               {
+                                               yy_looking_for_trail_begin = 0;
+                                               yy_act &= ~YY_TRAILING_HEAD_MASK;
+                                               break;
+                                               }
+                                       }
+                               else if ( yy_act & YY_TRAILING_MASK )
+                                       {
+                                       yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK;
+                                       yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK;
+                                       }
+                               else
+                                       {
+                                       yy_full_match = yy_cp;
+                                       yy_full_state = yy_state_ptr;
+                                       yy_full_lp = yy_lp;
+                                       break;
+                                       }
+                               ++yy_lp;
+                               goto find_rule;
+                               }
+                       --yy_cp;
+                       yy_current_state = *--yy_state_ptr;
+                       yy_lp = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+
+do_action:     /* This label is used only to access EOF actions. */
+
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 93 "./ada-lex.l"
+{ }
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 95 "./ada-lex.l"
+{ yyterminate(); }
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 97 "./ada-lex.l"
+{ 
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1);
+                }
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 102 "./ada-lex.l"
+{ 
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processInt (NULL, numbuf, NULL);
+                }
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 107 "./ada-lex.l"
+{
+                  canonicalizeNumeral (numbuf, yytext);
+                  return processInt (numbuf,
+                                     strchr (numbuf, '#') + 1, 
+                                     strrchr(numbuf, '#') + 1);
+                }
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 114 "./ada-lex.l"
+{
+                  canonicalizeNumeral (numbuf, yytext);
+                  return processInt (numbuf, strchr (numbuf, '#') + 1, NULL);
+                }
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 119 "./ada-lex.l"
+{
+                 canonicalizeNumeral (numbuf, yytext+2);
+                 return processInt ("16#", numbuf, NULL);
+               }
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 125 "./ada-lex.l"
+{
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processReal (numbuf);
+               }
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 130 "./ada-lex.l"
+{
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processReal (numbuf);
+               }
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 135 "./ada-lex.l"
+{
+                   error ("Based real literals not implemented yet.");
+               }
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 139 "./ada-lex.l"
+{
+                   error ("Based real literals not implemented yet.");
+               }
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 143 "./ada-lex.l"
+{
+                  yylval.typed_val.type = builtin_type_ada_char;
+                  yylval.typed_val.val = yytext[1];
+                  return CHARLIT;
+               }
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 149 "./ada-lex.l"
+{
+                   int v;
+                   yylval.typed_val.type = builtin_type_ada_char;
+                  sscanf (yytext+3, "%2x", &v);
+                  yylval.typed_val.val = v;
+                  return CHARLIT;
+               }
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 157 "./ada-lex.l"
+{ return processId (yytext, yyleng); }
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 159 "./ada-lex.l"
+{ 
+                  tempbuf_len = 0;
+                  BEGIN IN_STRING;
+               }
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 164 "./ada-lex.l"
+{
+                  resize_tempbuf (yyleng+tempbuf_len);
+                  strncpy (tempbuf+tempbuf_len, yytext, yyleng-1);
+                  tempbuf_len += yyleng-1;
+                  yylval.sval.ptr = tempbuf;
+                  yylval.sval.length = tempbuf_len;
+                  BEGIN INITIAL;
+                  return STRING;
+               }
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 174 "./ada-lex.l"
+{
+                  int n;
+                  resize_tempbuf (yyleng-5+tempbuf_len+1);
+                  strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
+                  sscanf(yytext+yyleng-4, "%2x", &n);
+                  tempbuf[yyleng-6+tempbuf_len] = (char) n;
+                  tempbuf_len += yyleng-5;
+               }
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 183 "./ada-lex.l"
+{
+                  int n;
+                  resize_tempbuf (yyleng-4+tempbuf_len+1);
+                  strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
+                  tempbuf[yyleng-5+tempbuf_len] = '"';
+                  tempbuf_len += yyleng-4;
+               }
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 191 "./ada-lex.l"
+{ 
+                 while (*lexptr != 'i' && *lexptr != 'I') 
+                   lexptr -= 1; 
+                 yyrestart(NULL); 
+                 return 0;
+               }
+       YY_BREAK
+/* ADA KEYWORDS */
+case 20:
+YY_RULE_SETUP
+#line 200 "./ada-lex.l"
+{ return ABS; }
+       YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 201 "./ada-lex.l"
+{ return _AND_; }
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 202 "./ada-lex.l"
+{ return ELSE; }
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 203 "./ada-lex.l"
+{ return IN; }
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 204 "./ada-lex.l"
+{ return MOD; }
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 205 "./ada-lex.l"
+{ return NEW; }
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 206 "./ada-lex.l"
+{ return NOT; }
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 207 "./ada-lex.l"
+{ return NULL_PTR; }
+       YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 208 "./ada-lex.l"
+{ return OR; }
+       YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 209 "./ada-lex.l"
+{ return REM; }
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 210 "./ada-lex.l"
+{ return THEN; }
+       YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 211 "./ada-lex.l"
+{ return XOR; }
+       YY_BREAK
+/* ATTRIBUTES */
+case 32:
+YY_RULE_SETUP
+#line 215 "./ada-lex.l"
+{ return processAttribute (yytext+1); }
+       YY_BREAK
+/* PUNCTUATION */
+case 33:
+YY_RULE_SETUP
+#line 219 "./ada-lex.l"
+{ return ARROW; }
+       YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 220 "./ada-lex.l"
+{ return DOTDOT; }
+       YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 221 "./ada-lex.l"
+{ return STARSTAR; }
+       YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 222 "./ada-lex.l"
+{ return ASSIGN; }
+       YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 223 "./ada-lex.l"
+{ return NOTEQUAL; }
+       YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 224 "./ada-lex.l"
+{ return LEQ; }
+       YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 225 "./ada-lex.l"
+{ return GEQ; }
+       YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 227 "./ada-lex.l"
+{ BEGIN INITIAL; return '\''; }
+       YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 229 "./ada-lex.l"
+{ return yytext[0]; }
+       YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 231 "./ada-lex.l"
+{ if (paren_depth == 0 && comma_terminates)
+                   {
+                     lexptr -= 1;
+                     yyrestart(NULL);
+                     return 0;
+                   }
+                 else 
+                   return ',';
+               }
+       YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 241 "./ada-lex.l"
+{ paren_depth += 1; return '('; }
+       YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 242 "./ada-lex.l"
+{ if (paren_depth == 0) 
+                   {
+                     lexptr -= 1;
+                     yyrestart(NULL);
+                     return 0;
+                   }
+                 else 
+                   {
+                     paren_depth -= 1; 
+                     return ')';
+                   }
+               }
+       YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 255 "./ada-lex.l"
+{ return DOT_ALL; }
+       YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 257 "./ada-lex.l"
+{ 
+                 processId (yytext+1, yyleng-1);
+                 return DOT_ID; 
+               }
+       YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 262 "./ada-lex.l"
+{ 
+                  int all_posn = find_dot_all (yytext);
+                 int token_type, segments, k;
+                 int quote_follows;
+
+                  if (all_posn == -1 && yytext[yyleng-1] == '\'') 
+                   {
+                     quote_follows = 1;
+                     do { 
+                       yyless (yyleng-1); 
+                     } while (yytext[yyleng-1] == ' ');
+                   }
+                 else
+                   quote_follows = 0;                  
+                   
+                  if (all_posn >= 0)
+                   yyless (all_posn);
+                  processId(yytext, yyleng);
+                  segments = name_lookup (ada_mangle (yylval.ssym.stoken.ptr),
+                                         yylval.ssym.stoken.ptr, &token_type);
+                 left_block_context = NULL;
+                 for (k = yyleng; segments > 0 && k > 0; k -= 1)
+                    {
+                     if (yytext[k-1] == '.')
+                       segments -= 1;
+                     quote_follows = 0;
+                   }
+                 if (k <= 0)
+                   error ("confused by name %s", yytext);
+                 yyless (k);
+                 if (quote_follows) 
+                   BEGIN BEFORE_QUAL_QUOTE;
+                 return token_type;
+                }
+       YY_BREAK
+/* GDB EXPRESSION CONSTRUCTS  */
+case 48:
+YY_RULE_SETUP
+#line 300 "./ada-lex.l"
+{
+                  processId(yytext, yyleng-2);
+                  block_lookup (yylval.ssym.stoken.ptr, yylval.ssym.stoken.ptr);
+                  return BLOCKNAME;
+               }
+       YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 306 "./ada-lex.l"
+{ 
+                  processId(yytext, yyleng-2);
+                  block_lookup (ada_mangle (yylval.ssym.stoken.ptr),
+                                yylval.ssym.stoken.ptr);
+                  return BLOCKNAME;
+               }
+       YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 313 "./ada-lex.l"
+{ return yytext[0]; }
+       YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 315 "./ada-lex.l"
+{ yylval.lval = -1; return LAST; }
+       YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 316 "./ada-lex.l"
+{ yylval.lval = -atoi(yytext+2); return LAST; }
+       YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 317 "./ada-lex.l"
+{ yylval.lval = 0; return LAST; }
+       YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 318 "./ada-lex.l"
+{ yylval.lval = atoi(yytext+1); return LAST; }
+       YY_BREAK
+/* REGISTERS AND GDB CONVENIENCE VARIABLES */
+case 55:
+YY_RULE_SETUP
+#line 323 "./ada-lex.l"
+{
+                 int c;
+                 for (c = 0; c < NUM_REGS; c++)
+                   if (REGISTER_NAME (c) &&
+                        strcmp (yytext + 1, REGISTER_NAME (c)) == 0)
+                     {
+                       yylval.lval = c;
+                       return REGNAME;
+                     }
+                 yylval.sval.ptr = yytext;
+                 yylval.sval.length = yyleng;
+                 yylval.ivar = 
+                   lookup_internalvar (copy_name (yylval.sval) + 1);
+                 return INTERNAL_VARIABLE;
+               }
+       YY_BREAK
+/* CATCH-ALL ERROR CASE */
+case 56:
+YY_RULE_SETUP
+#line 341 "./ada-lex.l"
+{ error ("Invalid character '%s' in expression.", yytext); }
+       YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 342 "./ada-lex.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+       YY_BREAK
+                       case YY_STATE_EOF(INITIAL):
+                       case YY_STATE_EOF(IN_STRING):
+                       case YY_STATE_EOF(BEFORE_QUAL_QUOTE):
+                               yyterminate();
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yy_hold_char;
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between yy_current_buffer and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yy_n_chars = yy_current_buffer->yy_n_chars;
+                       yy_current_buffer->yy_input_file = yyin;
+                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state();
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yy_c_buf_p;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer() )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yy_did_buffer_switch_on_eof = 0;
+
+                               if ( yywrap() )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yy_c_buf_p =
+                                       yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yy_c_buf_p =
+                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+       } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+       {
+       register char *dest = yy_current_buffer->yy_ch_buf;
+       register char *source = yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( yy_current_buffer->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+       else
+               {
+               int num_to_read =
+                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = yy_current_buffer;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yy_flex_realloc( (void *) b->yy_ch_buf,
+                                                        b->yy_buf_size + 2 );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = yy_current_buffer->yy_buf_size -
+                                               number_to_move - 1;
+#endif
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+                       yy_n_chars, num_to_read );
+
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       if ( yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart( yyin );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       yy_current_buffer->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       yy_n_chars += number_to_move;
+       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+       return ret_val;
+       }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+
+       yy_current_state = yy_start;
+       yy_state_ptr = yy_state_buf;
+       *yy_state_ptr++ = yy_current_state;
+
+       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 363 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               *yy_state_ptr++ = yy_current_state;
+               }
+
+       return yy_current_state;
+       }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+       {
+       register int yy_is_jam;
+
+       register YY_CHAR yy_c = 1;
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 363 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 362);
+       if ( ! yy_is_jam )
+               *yy_state_ptr++ = yy_current_state;
+
+       return yy_is_jam ? 0 : yy_current_state;
+       }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+       {
+       register char *yy_cp = yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yy_hold_char;
+
+       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yy_n_chars + 2;
+               register char *dest = &yy_current_buffer->yy_ch_buf[
+                                       yy_current_buffer->yy_buf_size + 2];
+               register char *source =
+                               &yy_current_buffer->yy_ch_buf[number_to_move];
+
+               while ( source > yy_current_buffer->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               yy_current_buffer->yy_n_chars =
+                       yy_n_chars = yy_current_buffer->yy_buf_size;
+
+               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+
+       yytext_ptr = yy_bp;
+       yy_hold_char = *yy_cp;
+       yy_c_buf_p = yy_cp;
+       }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+       {
+       int c;
+
+       *yy_c_buf_p = yy_hold_char;
+
+       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = yy_c_buf_p - yytext_ptr;
+                       ++yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer() )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       yyrestart( yyin );
+
+                                       /* fall through */
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap() )
+                                               return EOF;
+
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yy_c_buf_p = yytext_ptr + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
+       *yy_c_buf_p = '\0';     /* preserve yytext */
+       yy_hold_char = *++yy_c_buf_p;
+
+
+       return c;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+       {
+       if ( ! yy_current_buffer )
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+       yy_init_buffer( yy_current_buffer, input_file );
+       yy_load_buffer_state();
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+       {
+       if ( yy_current_buffer == new_buffer )
+               return;
+
+       if ( yy_current_buffer )
+               {
+               /* Flush out information for old buffer. */
+               *yy_c_buf_p = yy_hold_char;
+               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       yy_current_buffer = new_buffer;
+       yy_load_buffer_state();
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yy_did_buffer_switch_on_eof = 1;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+       {
+       yy_n_chars = yy_current_buffer->yy_n_chars;
+       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+       yyin = yy_current_buffer->yy_input_file;
+       yy_hold_char = *yy_c_buf_p;
+       }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+       {
+       YY_BUFFER_STATE b;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer( b, file );
+
+       return b;
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+       {
+       if ( ! b )
+               return;
+
+       if ( b == yy_current_buffer )
+               yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yy_flex_free( (void *) b->yy_ch_buf );
+
+       yy_flex_free( (void *) b );
+       }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+       {
+       yy_flush_buffer( b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+       b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+       b->yy_is_interactive = 0;
+#else
+       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+       }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+       {
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == yy_current_buffer )
+               yy_load_buffer_state();
+       }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+       {
+       YY_BUFFER_STATE b;
+
+       if ( size < 2 ||
+            base[size-2] != YY_END_OF_BUFFER_CHAR ||
+            base[size-1] != YY_END_OF_BUFFER_CHAR )
+               /* They forgot to leave room for the EOB's. */
+               return 0;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
+       b->yy_buf_pos = b->yy_ch_buf = base;
+       b->yy_is_our_buffer = 0;
+       b->yy_input_file = 0;
+       b->yy_n_chars = b->yy_buf_size;
+       b->yy_is_interactive = 0;
+       b->yy_at_bol = 1;
+       b->yy_fill_buffer = 0;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       yy_switch_to_buffer( b );
+
+       return b;
+       }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+       {
+       int len;
+       for ( len = 0; yy_str[len]; ++len )
+               ;
+
+       return yy_scan_bytes( yy_str, len );
+       }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+       {
+       YY_BUFFER_STATE b;
+       char *buf;
+       yy_size_t n;
+       int i;
+
+       /* Get memory for full buffer, including space for trailing EOB's. */
+       n = len + 2;
+       buf = (char *) yy_flex_alloc( n );
+       if ( ! buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+       for ( i = 0; i < len; ++i )
+               buf[i] = bytes[i];
+
+       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+       b = yy_scan_buffer( buf, n );
+       if ( ! b )
+               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+       /* It's okay to grow etc. this buffer, and we should throw it
+        * away when we're done.
+        */
+       b->yy_is_our_buffer = 1;
+
+       return b;
+       }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+       {
+       if ( yy_start_stack_ptr >= yy_start_stack_depth )
+               {
+               yy_size_t new_size;
+
+               yy_start_stack_depth += YY_START_STACK_INCR;
+               new_size = yy_start_stack_depth * sizeof( int );
+
+               if ( ! yy_start_stack )
+                       yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+               else
+                       yy_start_stack = (int *) yy_flex_realloc(
+                                       (void *) yy_start_stack, new_size );
+
+               if ( ! yy_start_stack )
+                       YY_FATAL_ERROR(
+                       "out of memory expanding start-condition stack" );
+               }
+
+       yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+       BEGIN(new_state);
+       }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+       {
+       if ( --yy_start_stack_ptr < 0 )
+               YY_FATAL_ERROR( "start-condition stack underflow" );
+
+       BEGIN(yy_start_stack[yy_start_stack_ptr]);
+       }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+       {
+       return yy_start_stack[yy_start_stack_ptr - 1];
+       }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+       {
+       (void) fprintf( stderr, "%s\n", msg );
+       exit( YY_EXIT_FAILURE );
+       }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               yytext[yyleng] = yy_hold_char; \
+               yy_c_buf_p = yytext + n; \
+               yy_hold_char = *yy_c_buf_p; \
+               *yy_c_buf_p = '\0'; \
+               yyleng = n; \
+               } \
+       while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+       {
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+       }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+       {
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+       }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+       {
+       return (void *) malloc( size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+       {
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+       {
+       free( ptr );
+       }
+
+#if YY_MAIN
+int main()
+       {
+       yylex();
+       return 0;
+       }
+#endif
+#line 342 "./ada-lex.l"
+
+
+#include <ctype.h>
+#include <string.h>
+
+/* Initialize the lexer for processing new expression */
+void
+lexer_init (FILE* inp)
+{
+  BEGIN INITIAL;
+  yyrestart (inp);
+}
+
+
+/* Make sure that tempbuf points at an array at least N characters long. */
+
+static void
+resize_tempbuf (n)
+     unsigned int n;
+{
+  if (tempbufsize < n)
+    {
+      tempbufsize = (n+63) & ~63;
+      tempbuf = (char*) xrealloc (tempbuf, tempbufsize);
+    }
+}
+/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
+
+static void
+canonicalizeNumeral (s1,s2)
+     char* s1;
+     const char* s2;
+{
+  for (; *s2 != '\000'; s2 += 1) 
+    {
+      if (*s2 != '_')
+       {
+         *s1 = tolower(*s2);
+         s1 += 1;
+       }
+    }
+  s1[0] = '\000';
+}
+
+#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
+
+/* True (non-zero) iff DIGIT is a valid digit in radix BASE, 
+   where 2 <= BASE <= 16.  */
+
+static int
+is_digit_in_base (digit, base)
+     unsigned char digit;
+     int base;
+{
+  if (!isxdigit (digit))
+    return 0;
+  if (base <= 10)
+    return (isdigit (digit) && digit < base + '0');
+  else 
+    return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
+}
+
+static int
+digit_to_int (c)
+     unsigned char c;
+{
+  if (isdigit (c))
+    return c - '0';
+  else
+    return tolower (c) - 'a' + 10;
+}
+
+/* As for strtoul, but for ULONGEST results. */
+ULONGEST
+strtoulst (num, trailer, base)
+     const char *num;
+     const char **trailer;
+     int base;
+{
+  unsigned int high_part;
+  ULONGEST result;
+  int i;
+  unsigned char lim;
+
+  if (base < 2 || base > 16)
+    {
+      errno = EINVAL;
+      return 0;
+    }
+  lim = base - 1 + '0';
+
+  result = high_part = 0;
+  for (i = 0; is_digit_in_base (num[i], base); i += 1)
+    {
+      result = result*base + digit_to_int (num[i]);
+      high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN);
+      result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
+      if (high_part > 0xff) 
+       {
+         errno = ERANGE;
+         result = high_part = 0;
+         break;
+       }
+    }
+
+  if (trailer != NULL)
+    *trailer = &num[i];
+
+  return result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
+}
+
+
+
+/* Interprets the prefix of NUM that consists of digits of the given BASE
+   as an integer of that BASE, with the string EXP as an exponent.
+   Puts value in yylval, and returns INT, if the string is valid.  Causes
+   an error if the number is improperly formated.   BASE, if NULL, defaults 
+   to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'. */
+
+static int
+processInt (base0, num0, exp0)
+     const char* num0;
+     const char* base0;
+     const char* exp0;
+{
+  ULONGEST result;
+  long exp;
+  int base;
+
+  char* trailer;
+
+  if (base0 == NULL)
+    base = 10;
+  else
+    {  
+      base = strtol (base0, (char**) NULL, 10);
+      if (base < 2 || base > 16)
+       error ("Invalid base: %d.", base);
+    }
+
+  if (exp0 == NULL)
+    exp = 0;
+  else
+    exp = strtol(exp0, (char**) NULL, 10);
+
+  errno = 0;
+  result = strtoulst (num0, &trailer, base);
+  if (errno == ERANGE)
+    error ("Integer literal out of range");
+  if (isxdigit(*trailer))
+    error ("Invalid digit `%c' in based literal", *trailer);
+
+  while (exp > 0) 
+    {
+      if (result > (ULONG_MAX / base))
+       error ("Integer literal out of range");
+      result *= base;
+      exp -= 1;
+    }
+    
+  if ((result >> (TARGET_INT_BIT-1)) == 0)
+    yylval.typed_val.type = builtin_type_ada_int;
+  else if ((result >> (TARGET_LONG_BIT-1)) == 0)
+    yylval.typed_val.type = builtin_type_ada_long;
+  else if (((result >> (TARGET_LONG_BIT-1)) >> 1) == 0)
+    {
+      /* We have a number representable as an unsigned integer quantity.
+         For consistency with the C treatment, we will treat it as an 
+        anonymous modular (unsigned) quantity.  Alas, the types are such
+        that we need to store .val as a signed quantity.  Sorry 
+         for the mess, but C doesn't officially guarantee that a simple
+         assignment does the trick (no, it doesn't; read the reference manual).
+       */
+      yylval.typed_val.type = builtin_type_unsigned_long;
+      if (result & LONGEST_SIGN)
+       yylval.typed_val.val = 
+         (LONGEST) (result & ~LONGEST_SIGN) 
+         - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
+      else
+       yylval.typed_val.val = (LONGEST) result;
+      return INT;
+    }
+  else 
+    yylval.typed_val.type = builtin_type_ada_long_long;
+
+  yylval.typed_val.val = (LONGEST) result;
+  return INT;
+}
+
+static int
+processReal (num0)
+     const char* num0;
+{
+  if (sizeof (DOUBLEST) <= sizeof (float))
+    sscanf (num0, "%g", &yylval.typed_val_float.dval);
+  else if (sizeof (DOUBLEST) <= sizeof (double))
+    sscanf (num0, "%lg", &yylval.typed_val_float.dval);
+  else
+    {
+#ifdef PRINTF_HAS_LONG_DOUBLE
+      sscanf (num0, "%Lg", &yylval.typed_val_float.dval);
+#else
+      /* Scan it into a double, then convert and assign it to the 
+        long double.  This at least wins with values representable 
+        in the range of doubles. */
+      double temp;
+      sscanf (num0, "%lg", &temp);
+      yylval.typed_val_float.dval = temp;
+#endif
+    }
+
+  yylval.typed_val_float.type = builtin_type_ada_float;
+  if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT)
+    yylval.typed_val_float.type = builtin_type_ada_double;
+  if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT)
+    yylval.typed_val_float.type = builtin_type_ada_long_double;
+
+  return FLOAT;
+}
+
+static int
+processId (name0, len)
+     const char *name0;
+     int len;
+{
+  char* name = xmalloc (len + 11);
+  int i0, i;
+  
+/*  add_name_string_cleanup (name); */
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+  while (len > 0 && isspace (name0[len-1]))
+    len -= 1;
+  i = i0 = 0;
+  while (i0 < len) 
+    {
+      if (isalnum (name0[i0]))
+       {
+         name[i] = tolower (name0[i0]);
+         i += 1; i0 += 1;
+       }
+      else switch (name0[i0]) 
+       {
+       default:
+         name[i] = name0[i0];
+         i += 1; i0 += 1;
+         break;
+       case ' ': case '\t':
+         i0 += 1;
+         break;
+       case '\'':
+         i0 += 1;
+         while (i0 < len && name0[i0] != '\'')
+           {
+             name[i] = name0[i0];
+             i += 1; i0 += 1;
+           }
+         i0 += 1;
+         break;
+       case '<':
+         i0 += 1;
+         while (i0 < len && name0[i0] != '>')
+           {
+             name[i] = name0[i0];
+             i += 1; i0 += 1;
+           }
+         i0 += 1;
+         break;
+       }
+    }
+  name[i] = '\000';
+
+  yylval.ssym.sym = NULL;
+  yylval.ssym.stoken.ptr = name;
+  yylval.ssym.stoken.length = i;
+  return NAME;
+}
+
+static void 
+block_lookup (name, err_name)
+     char* name;
+     char* err_name;
+{
+  struct symbol** syms;
+  struct block** blocks;
+  int nsyms;
+  struct symtab *symtab;
+  nsyms = ada_lookup_symbol_list (name, left_block_context,
+                                 VAR_NAMESPACE, &syms, &blocks);
+  if (left_block_context == NULL &&
+      (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK))
+    symtab = lookup_symtab (name);
+  else
+    symtab = NULL;
+
+  if (symtab != NULL)
+    left_block_context = yylval.bval =
+      BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+  else if (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK)
+    {
+      if (left_block_context == NULL)
+       error ("No file or function \"%s\".", err_name);
+      else
+       error ("No function \"%s\" in specified context.", err_name);
+    }
+  else 
+    {
+      left_block_context = yylval.bval = SYMBOL_BLOCK_VALUE (syms[0]); 
+      if (nsyms > 1)
+       warning ("Function name \"%s\" ambiguous here", err_name);
+    }
+}
+
+/* Look up NAME0 (assumed to be mangled) as a name in VAR_NAMESPACE,
+   setting *TOKEN_TYPE to NAME or TYPENAME, depending on what is
+   found.  Try first the entire name, then the name without the last 
+   segment (i.e., after the last .id), etc., and return the number of
+   segments that had to be removed to get a match.  Calls error if no
+   matches are found, using ERR_NAME in any error message.  When
+   exactly one symbol match is found, it is placed in yylval. */
+static int
+name_lookup (name0, err_name, token_type)
+     char* name0;
+     char* err_name;
+     int* token_type;
+{
+  struct symbol** syms;
+  struct block** blocks;
+  struct type* type;
+  int len0 = strlen (name0);
+  char* name = savestring (name0, len0);
+  int nsyms;
+  int segments;
+/*  add_name_string_cleanup (name);*/
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+  yylval.ssym.stoken.ptr = name;
+  yylval.ssym.stoken.length = strlen (name);
+  for (segments = 0; ; segments += 1)
+    {
+      struct type* preferred_type;
+      int i, preferred_index;
+
+      if (left_block_context == NULL) 
+       nsyms = ada_lookup_symbol_list (name, expression_context_block, 
+                                       VAR_NAMESPACE, &syms, &blocks);
+      else
+       nsyms = ada_lookup_symbol_list (name, left_block_context, 
+                                       VAR_NAMESPACE, &syms, &blocks);
+
+      /* Check for a type definition. */
+
+      /* Look for a symbol that doesn't denote void.  This is (I think) a */
+      /* temporary kludge to get around problems in GNAT output. */
+      preferred_index = -1; preferred_type = NULL;
+      for (i = 0; i < nsyms; i += 1)
+       switch (SYMBOL_CLASS (syms[i])) 
+         {
+         case LOC_TYPEDEF:
+           if (ada_prefer_type (SYMBOL_TYPE (syms[i]), preferred_type))
+             {
+               preferred_index = i;
+               preferred_type = SYMBOL_TYPE (syms[i]);
+             }
+           break;
+         case LOC_REGISTER:
+         case LOC_ARG:
+         case LOC_REF_ARG:
+         case LOC_REGPARM:
+         case LOC_REGPARM_ADDR:
+         case LOC_LOCAL:
+         case LOC_LOCAL_ARG:
+         case LOC_BASEREG:
+         case LOC_BASEREG_ARG:
+           goto NotType;
+         default:
+           break;
+         }
+      if (preferred_type != NULL)
+       {
+/*       if (TYPE_CODE (preferred_type) == TYPE_CODE_VOID)
+           error ("`%s' matches only void type name(s)", 
+                  ada_demangle (name));
+*/
+/* FIXME: ada_demangle should be defined in defs.h, and is located in ada-lang.c */
+/*       else*/ if (ada_is_object_renaming (syms[preferred_index]))
+           {
+             yylval.ssym.sym = syms[preferred_index];
+             *token_type = OBJECT_RENAMING;
+             return segments;
+           } 
+         else if (ada_renaming_type (SYMBOL_TYPE (syms[preferred_index])) 
+                   != NULL)
+           {
+             int result;
+             const char* renaming = 
+               ada_simple_renamed_entity (syms[preferred_index]);
+             char* new_name = xmalloc (strlen (renaming) + len0 
+                                       - yylval.ssym.stoken.length + 1);
+/*           add_name_string_cleanup (new_name);*/
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+             strcpy (new_name, renaming);
+             strcat (new_name, name0 + yylval.ssym.stoken.length);
+             result = name_lookup (new_name, err_name, token_type);
+             if (result > segments) 
+               error ("Confused by renamed symbol.");
+             return result;
+           }
+         else if (segments == 0)
+           {
+             yylval.tval = preferred_type;
+             *token_type = TYPENAME;
+             return 0;
+           } 
+       }
+
+      if (segments == 0)
+       {
+         type = lookup_primitive_typename (name);
+         if (type == NULL && STREQ ("system__address", name))
+           type = builtin_type_ada_system_address;
+         if (type != NULL)
+           {
+             yylval.tval = type;
+             *token_type = TYPENAME;
+             return 0;
+           }
+       }
+
+    NotType:
+      if (nsyms == 1) 
+       {
+         *token_type = NAME;
+         yylval.ssym.sym = syms[0];
+         yylval.ssym.msym = NULL;
+         yylval.ssym.block = blocks[0];
+         return segments;
+       }
+      else if (nsyms == 0) {
+       int i;
+       yylval.ssym.msym = ada_lookup_minimal_symbol (name);
+       if (yylval.ssym.msym != NULL)
+         {
+           yylval.ssym.sym = NULL;
+           yylval.ssym.block = NULL;
+            *token_type = NAME;
+           return segments;
+         }
+
+       for (i = yylval.ssym.stoken.length - 1; i > 0; i -= 1)
+         {
+            if (name[i] == '.')
+             { 
+               name[i] = '\0';
+               yylval.ssym.stoken.length = i;
+               break;
+             }
+           else if (name[i] == '_' && name[i-1] == '_')
+             {
+               i -= 1;
+               name[i] = '\0';
+               yylval.ssym.stoken.length = i;
+               break;
+             }
+         }
+       if (i <= 0) 
+         {
+           if (!have_full_symbols () && !have_partial_symbols ()
+               && left_block_context == NULL)
+             error ("No symbol table is loaded.  Use the \"file\" command.");
+           if (left_block_context == NULL)
+             error ("No definition of \"%s\" in current context.", 
+                    err_name);
+           else
+             error ("No definition of \"%s\" in specified context.", 
+                    err_name);
+         }
+      }
+      else 
+       {
+         *token_type = NAME;
+         yylval.ssym.sym = NULL;
+         yylval.ssym.msym = NULL;
+         if (left_block_context == NULL)
+           yylval.ssym.block = expression_context_block;
+         else
+           yylval.ssym.block = left_block_context;
+         return segments;
+       }
+    }
+}
+
+/* Returns the position within STR of the '.' in a
+   '.{WHITE}*all' component of a dotted name, or -1 if there is none. */
+static int
+find_dot_all (str)
+     const char* str;
+{
+  int i;
+  for (i = 0; str[i] != '\000'; i += 1)
+    {
+      if (str[i] == '.')
+       {
+         int i0 = i;
+         do 
+           i += 1;
+         while (isspace (str[i]));
+         if (strcmp (str+i, "all") == 0
+             && ! isalnum (str[i+3]) && str[i+3] != '_')
+           return i0;
+       }
+    }
+  return -1;
+}    
+
+/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
+   case. */
+
+static int
+subseqMatch (subseq, str)
+     const char* subseq;
+     const char* str;
+{
+  if (subseq[0] == '\0')
+    return 1;
+  else if (str[0] == '\0')
+    return 0;
+  else if (tolower (subseq[0]) == tolower (str[0]))
+    return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
+  else
+    return subseqMatch (subseq, str+1);
+}
+  
+
+static struct { const char* name; int code; } 
+attributes[] = {
+  { "address", TICK_ADDRESS },
+  { "unchecked_access", TICK_ACCESS },
+  { "unrestricted_access", TICK_ACCESS },
+  { "access", TICK_ACCESS },
+  { "first", TICK_FIRST },
+  { "last", TICK_LAST },
+  { "length", TICK_LENGTH },
+  { "max", TICK_MAX },
+  { "min", TICK_MIN },
+  { "modulus", TICK_MODULUS },
+  { "pos", TICK_POS },
+  { "range", TICK_RANGE },
+  { "size", TICK_SIZE },
+  { "tag", TICK_TAG },
+  { "val", TICK_VAL },
+  { NULL, -1 }
+};
+
+/* Return the syntactic code corresponding to the attribute name or
+   abbreviation STR.  */
+
+static int
+processAttribute (str)
+     const char* str;
+{
+  int i, k;
+
+  for (i = 0; attributes[i].code != -1; i += 1)
+    if (strcasecmp (str, attributes[i].name) == 0)
+      return attributes[i].code;
+
+  for (i = 0, k = -1; attributes[i].code != -1; i += 1)
+    if (subseqMatch (str, attributes[i].name)) 
+      {
+       if (k == -1)
+         k = i;
+       else 
+         error ("ambiguous attribute name: `%s'", str);
+      }
+  if (k == -1)
+    error ("unrecognized attribute: `%s'", str);
+
+  return attributes[k].code;
+}
+
+int
+yywrap()
+{
+  return 1;
+}
diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l
new file mode 100644 (file)
index 0000000..2252d52
--- /dev/null
@@ -0,0 +1,928 @@
+/* FLEX lexer for Ada expressions, for GDB.
+   Copyright (C) 1994, 1997, 2000
+   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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*----------------------------------------------------------------------*/
+
+/* The converted version of this file is to be included in ada-exp.y, */
+/* the Ada parser for gdb.  The function yylex obtains characters from */
+/* the global pointer lexptr.  It returns a syntactic category for */
+/* each successive token and places a semantic value into yylval */
+/* (ada-lval), defined by the parser.   */
+
+/* Run flex with (at least) the -i option (case-insensitive), and the -I */
+/* option (interactive---no unnecessary lookahead).  */
+
+DIG    [0-9]
+NUM10  ({DIG}({DIG}|_)*)
+HEXDIG [0-9a-f]
+NUM16  ({HEXDIG}({HEXDIG}|_)*)
+OCTDIG [0-7]
+LETTER [a-z_]
+ID     ({LETTER}({LETTER}|{DIG})*|"<"{LETTER}({LETTER}|{DIG})*">")
+WHITE  [ \t\n]
+TICK   ("'"{WHITE}*)
+GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
+OPER    ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs")
+
+EXP    (e[+-]{NUM10})
+POSEXP  (e"+"?{NUM10})
+
+%{
+#define NUMERAL_WIDTH 256
+#define LONGEST_SIGN ((ULONGEST) 1 << (sizeof(LONGEST) * HOST_CHAR_BIT - 1))
+
+/* Temporary staging for numeric literals. */
+static char numbuf[NUMERAL_WIDTH]; 
+ static void canonicalizeNumeral (char* s1, const char*);
+static int processInt (const char*, const char*, const char*);
+static int processReal (const char*);
+static int processId (const char*, int);
+static int processAttribute (const char*);
+static int find_dot_all (const char*);
+
+#undef YY_DECL
+#define YY_DECL static int yylex ( void ) 
+
+#undef YY_INPUT
+#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
+    if ( *lexptr == '\000' ) \
+      (RESULT) = YY_NULL; \
+    else \
+      { \
+        *(BUF) = *lexptr; \
+        (RESULT) = 1; \
+       lexptr += 1; \
+      }
+
+static char *tempbuf = NULL;
+static int tempbufsize = 0;
+static int tempbuf_len;
+static struct block* left_block_context;
+
+static void resize_tempbuf (unsigned int);
+
+static void block_lookup (char*, char*);
+
+static int name_lookup (char*, char*, int*);
+
+static int find_dot_all (const char*);
+
+%}
+
+%s IN_STRING BEFORE_QUAL_QUOTE
+
+%%
+
+{WHITE}                 { }
+
+"--".*          { yyterminate(); }
+
+{NUM10}{POSEXP}  { 
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processInt (NULL, numbuf, strrchr(numbuf, 'e')+1);
+                }
+
+{NUM10}          { 
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processInt (NULL, numbuf, NULL);
+                }
+
+{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
+                  canonicalizeNumeral (numbuf, yytext);
+                  return processInt (numbuf,
+                                     strchr (numbuf, '#') + 1, 
+                                     strrchr(numbuf, '#') + 1);
+                }
+
+{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#" {
+                  canonicalizeNumeral (numbuf, yytext);
+                  return processInt (numbuf, strchr (numbuf, '#') + 1, NULL);
+                }
+
+"0x"{HEXDIG}+  {
+                 canonicalizeNumeral (numbuf, yytext+2);
+                 return processInt ("16#", numbuf, NULL);
+               }
+
+
+{NUM10}"."{NUM10}{EXP} {
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processReal (numbuf);
+               }
+
+{NUM10}"."{NUM10} {
+                  canonicalizeNumeral (numbuf, yytext); 
+                  return processReal (numbuf);
+               }
+
+{NUM10}"#"{NUM16}"."{NUM16}"#"{EXP} {
+                   error ("Based real literals not implemented yet.");
+               }
+
+{NUM10}"#"{NUM16}"."{NUM16}"#" {
+                   error ("Based real literals not implemented yet.");
+               }
+
+<INITIAL>"'"({GRAPHIC}|\")"'" {
+                  yylval.typed_val.type = builtin_type_ada_char;
+                  yylval.typed_val.val = yytext[1];
+                  return CHARLIT;
+               }
+
+<INITIAL>"'[\""{HEXDIG}{2}"\"]'"   {
+                   int v;
+                   yylval.typed_val.type = builtin_type_ada_char;
+                  sscanf (yytext+3, "%2x", &v);
+                  yylval.typed_val.val = v;
+                  return CHARLIT;
+               }
+
+\"{OPER}\"/{WHITE}*"(" { return processId (yytext, yyleng); }
+
+<INITIAL>\"    { 
+                  tempbuf_len = 0;
+                  BEGIN IN_STRING;
+               }
+
+<IN_STRING>{GRAPHIC}*\"  {
+                  resize_tempbuf (yyleng+tempbuf_len);
+                  strncpy (tempbuf+tempbuf_len, yytext, yyleng-1);
+                  tempbuf_len += yyleng-1;
+                  yylval.sval.ptr = tempbuf;
+                  yylval.sval.length = tempbuf_len;
+                  BEGIN INITIAL;
+                  return STRING;
+               }
+
+<IN_STRING>{GRAPHIC}*"[\""{HEXDIG}{2}"\"]" {
+                  int n;
+                  resize_tempbuf (yyleng-5+tempbuf_len+1);
+                  strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
+                  sscanf(yytext+yyleng-4, "%2x", &n);
+                  tempbuf[yyleng-6+tempbuf_len] = (char) n;
+                  tempbuf_len += yyleng-5;
+               }
+
+<IN_STRING>{GRAPHIC}*"[\"\"\"]" {
+                  int n;
+                  resize_tempbuf (yyleng-4+tempbuf_len+1);
+                  strncpy (tempbuf+tempbuf_len, yytext, yyleng-6);
+                  tempbuf[yyleng-5+tempbuf_len] = '"';
+                  tempbuf_len += yyleng-4;
+               }
+
+if             { 
+                 while (*lexptr != 'i' && *lexptr != 'I') 
+                   lexptr -= 1; 
+                 yyrestart(NULL); 
+                 return 0;
+               }
+
+       /* ADA KEYWORDS */
+
+abs            { return ABS; }
+and            { return _AND_; }
+else           { return ELSE; }
+in             { return IN; }
+mod            { return MOD; }
+new            { return NEW; }
+not            { return NOT; }
+null           { return NULL_PTR; }
+or             { return OR; }
+rem            { return REM; }
+then           { return THEN; }
+xor            { return XOR; }
+
+        /* ATTRIBUTES */
+
+{TICK}[a-zA-Z][a-zA-Z]+ { return processAttribute (yytext+1); }
+
+       /* PUNCTUATION */
+
+"=>"           { return ARROW; }
+".."           { return DOTDOT; }
+"**"           { return STARSTAR; }
+":="           { return ASSIGN; }
+"/="           { return NOTEQUAL; }
+"<="           { return LEQ; }
+">="           { return GEQ; }
+
+<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; }
+
+[-&*+./:<>=|;\[\]] { return yytext[0]; }
+
+","            { if (paren_depth == 0 && comma_terminates)
+                   {
+                     lexptr -= 1;
+                     yyrestart(NULL);
+                     return 0;
+                   }
+                 else 
+                   return ',';
+               }
+
+"("            { paren_depth += 1; return '('; }
+")"            { if (paren_depth == 0) 
+                   {
+                     lexptr -= 1;
+                     yyrestart(NULL);
+                     return 0;
+                   }
+                 else 
+                   {
+                     paren_depth -= 1; 
+                     return ')';
+                   }
+               }
+
+"."{WHITE}*all  { return DOT_ALL; }
+
+"."{WHITE}*{ID} { 
+                 processId (yytext+1, yyleng-1);
+                 return DOT_ID; 
+               }
+
+{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'")?  { 
+                  int all_posn = find_dot_all (yytext);
+                 int token_type, segments, k;
+                 int quote_follows;
+
+                  if (all_posn == -1 && yytext[yyleng-1] == '\'') 
+                   {
+                     quote_follows = 1;
+                     do { 
+                       yyless (yyleng-1); 
+                     } while (yytext[yyleng-1] == ' ');
+                   }
+                 else
+                   quote_follows = 0;                  
+                   
+                  if (all_posn >= 0)
+                   yyless (all_posn);
+                  processId(yytext, yyleng);
+                  segments = name_lookup (ada_mangle (yylval.ssym.stoken.ptr),
+                                         yylval.ssym.stoken.ptr, &token_type);
+                 left_block_context = NULL;
+                 for (k = yyleng; segments > 0 && k > 0; k -= 1)
+                    {
+                     if (yytext[k-1] == '.')
+                       segments -= 1;
+                     quote_follows = 0;
+                   }
+                 if (k <= 0)
+                   error ("confused by name %s", yytext);
+                 yyless (k);
+                 if (quote_follows) 
+                   BEGIN BEFORE_QUAL_QUOTE;
+                 return token_type;
+                }
+
+       /* GDB EXPRESSION CONSTRUCTS  */
+
+
+"'"[^']+"'"{WHITE}*:: {
+                  processId(yytext, yyleng-2);
+                  block_lookup (yylval.ssym.stoken.ptr, yylval.ssym.stoken.ptr);
+                  return BLOCKNAME;
+               }
+
+{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*{WHITE}*::  { 
+                  processId(yytext, yyleng-2);
+                  block_lookup (ada_mangle (yylval.ssym.stoken.ptr),
+                                yylval.ssym.stoken.ptr);
+                  return BLOCKNAME;
+               }
+
+[{}@]          { return yytext[0]; }
+
+"$$"           { yylval.lval = -1; return LAST; }
+"$$"{DIG}+     { yylval.lval = -atoi(yytext+2); return LAST; }
+"$"            { yylval.lval = 0; return LAST; }
+"$"{DIG}+      { yylval.lval = atoi(yytext+1); return LAST; }
+
+
+       /* REGISTERS AND GDB CONVENIENCE VARIABLES */
+
+"$"({LETTER}|{DIG}|"$")+  {
+                 int c;
+                 for (c = 0; c < NUM_REGS; c++)
+                   if (REGISTER_NAME (c) &&
+                        strcmp (yytext + 1, REGISTER_NAME (c)) == 0)
+                     {
+                       yylval.lval = c;
+                       return REGNAME;
+                     }
+                 yylval.sval.ptr = yytext;
+                 yylval.sval.length = yyleng;
+                 yylval.ivar = 
+                   lookup_internalvar (copy_name (yylval.sval) + 1);
+                 return INTERNAL_VARIABLE;
+               }
+
+       /* CATCH-ALL ERROR CASE */
+
+.              { error ("Invalid character '%s' in expression.", yytext); }
+%%
+
+#include <ctype.h>
+#include <string.h>
+
+/* Initialize the lexer for processing new expression */
+void
+lexer_init (FILE* inp)
+{
+  BEGIN INITIAL;
+  yyrestart (inp);
+}
+
+
+/* Make sure that tempbuf points at an array at least N characters long. */
+
+static void
+resize_tempbuf (n)
+     unsigned int n;
+{
+  if (tempbufsize < n)
+    {
+      tempbufsize = (n+63) & ~63;
+      tempbuf = (char*) xrealloc (tempbuf, tempbufsize);
+    }
+}
+/* Copy S2 to S1, removing all underscores, and downcasing all letters. */
+
+static void
+canonicalizeNumeral (s1,s2)
+     char* s1;
+     const char* s2;
+{
+  for (; *s2 != '\000'; s2 += 1) 
+    {
+      if (*s2 != '_')
+       {
+         *s1 = tolower(*s2);
+         s1 += 1;
+       }
+    }
+  s1[0] = '\000';
+}
+
+#define HIGH_BYTE_POSN ((sizeof (ULONGEST) - 1) * HOST_CHAR_BIT)
+
+/* True (non-zero) iff DIGIT is a valid digit in radix BASE, 
+   where 2 <= BASE <= 16.  */
+
+static int
+is_digit_in_base (digit, base)
+     unsigned char digit;
+     int base;
+{
+  if (!isxdigit (digit))
+    return 0;
+  if (base <= 10)
+    return (isdigit (digit) && digit < base + '0');
+  else 
+    return (isdigit (digit) || tolower (digit) < base - 10 + 'a');
+}
+
+static int
+digit_to_int (c)
+     unsigned char c;
+{
+  if (isdigit (c))
+    return c - '0';
+  else
+    return tolower (c) - 'a' + 10;
+}
+
+/* As for strtoul, but for ULONGEST results. */
+ULONGEST
+strtoulst (num, trailer, base)
+     const char *num;
+     const char **trailer;
+     int base;
+{
+  unsigned int high_part;
+  ULONGEST result;
+  int i;
+  unsigned char lim;
+
+  if (base < 2 || base > 16)
+    {
+      errno = EINVAL;
+      return 0;
+    }
+  lim = base - 1 + '0';
+
+  result = high_part = 0;
+  for (i = 0; is_digit_in_base (num[i], base); i += 1)
+    {
+      result = result*base + digit_to_int (num[i]);
+      high_part = high_part*base + (unsigned int) (result >> HIGH_BYTE_POSN);
+      result &= ((ULONGEST) 1 << HIGH_BYTE_POSN) - 1;
+      if (high_part > 0xff) 
+       {
+         errno = ERANGE;
+         result = high_part = 0;
+         break;
+       }
+    }
+
+  if (trailer != NULL)
+    *trailer = &num[i];
+
+  return result + ((ULONGEST) high_part << HIGH_BYTE_POSN);
+}
+
+
+
+/* Interprets the prefix of NUM that consists of digits of the given BASE
+   as an integer of that BASE, with the string EXP as an exponent.
+   Puts value in yylval, and returns INT, if the string is valid.  Causes
+   an error if the number is improperly formated.   BASE, if NULL, defaults 
+   to "10", and EXP to "1". The EXP does not contain a leading 'e' or 'E'. */
+
+static int
+processInt (base0, num0, exp0)
+     const char* num0;
+     const char* base0;
+     const char* exp0;
+{
+  ULONGEST result;
+  long exp;
+  int base;
+
+  char* trailer;
+
+  if (base0 == NULL)
+    base = 10;
+  else
+    {  
+      base = strtol (base0, (char**) NULL, 10);
+      if (base < 2 || base > 16)
+       error ("Invalid base: %d.", base);
+    }
+
+  if (exp0 == NULL)
+    exp = 0;
+  else
+    exp = strtol(exp0, (char**) NULL, 10);
+
+  errno = 0;
+  result = strtoulst (num0, &trailer, base);
+  if (errno == ERANGE)
+    error ("Integer literal out of range");
+  if (isxdigit(*trailer))
+    error ("Invalid digit `%c' in based literal", *trailer);
+
+  while (exp > 0) 
+    {
+      if (result > (ULONG_MAX / base))
+       error ("Integer literal out of range");
+      result *= base;
+      exp -= 1;
+    }
+    
+  if ((result >> (TARGET_INT_BIT-1)) == 0)
+    yylval.typed_val.type = builtin_type_ada_int;
+  else if ((result >> (TARGET_LONG_BIT-1)) == 0)
+    yylval.typed_val.type = builtin_type_ada_long;
+  else if (((result >> (TARGET_LONG_BIT-1)) >> 1) == 0)
+    {
+      /* We have a number representable as an unsigned integer quantity.
+         For consistency with the C treatment, we will treat it as an 
+        anonymous modular (unsigned) quantity.  Alas, the types are such
+        that we need to store .val as a signed quantity.  Sorry 
+         for the mess, but C doesn't officially guarantee that a simple
+         assignment does the trick (no, it doesn't; read the reference manual).
+       */
+      yylval.typed_val.type = builtin_type_unsigned_long;
+      if (result & LONGEST_SIGN)
+       yylval.typed_val.val = 
+         (LONGEST) (result & ~LONGEST_SIGN) 
+         - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
+      else
+       yylval.typed_val.val = (LONGEST) result;
+      return INT;
+    }
+  else 
+    yylval.typed_val.type = builtin_type_ada_long_long;
+
+  yylval.typed_val.val = (LONGEST) result;
+  return INT;
+}
+
+static int
+processReal (num0)
+     const char* num0;
+{
+  if (sizeof (DOUBLEST) <= sizeof (float))
+    sscanf (num0, "%g", &yylval.typed_val_float.dval);
+  else if (sizeof (DOUBLEST) <= sizeof (double))
+    sscanf (num0, "%lg", &yylval.typed_val_float.dval);
+  else
+    {
+#ifdef PRINTF_HAS_LONG_DOUBLE
+      sscanf (num0, "%Lg", &yylval.typed_val_float.dval);
+#else
+      /* Scan it into a double, then convert and assign it to the 
+        long double.  This at least wins with values representable 
+        in the range of doubles. */
+      double temp;
+      sscanf (num0, "%lg", &temp);
+      yylval.typed_val_float.dval = temp;
+#endif
+    }
+
+  yylval.typed_val_float.type = builtin_type_ada_float;
+  if (sizeof(DOUBLEST) >= TARGET_DOUBLE_BIT / TARGET_CHAR_BIT)
+    yylval.typed_val_float.type = builtin_type_ada_double;
+  if (sizeof(DOUBLEST) >= TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT)
+    yylval.typed_val_float.type = builtin_type_ada_long_double;
+
+  return FLOAT;
+}
+
+static int
+processId (name0, len)
+     const char *name0;
+     int len;
+{
+  char* name = xmalloc (len + 11);
+  int i0, i;
+  
+/*  add_name_string_cleanup (name); */
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+  while (len > 0 && isspace (name0[len-1]))
+    len -= 1;
+  i = i0 = 0;
+  while (i0 < len) 
+    {
+      if (isalnum (name0[i0]))
+       {
+         name[i] = tolower (name0[i0]);
+         i += 1; i0 += 1;
+       }
+      else switch (name0[i0]) 
+       {
+       default:
+         name[i] = name0[i0];
+         i += 1; i0 += 1;
+         break;
+       case ' ': case '\t':
+         i0 += 1;
+         break;
+       case '\'':
+         i0 += 1;
+         while (i0 < len && name0[i0] != '\'')
+           {
+             name[i] = name0[i0];
+             i += 1; i0 += 1;
+           }
+         i0 += 1;
+         break;
+       case '<':
+         i0 += 1;
+         while (i0 < len && name0[i0] != '>')
+           {
+             name[i] = name0[i0];
+             i += 1; i0 += 1;
+           }
+         i0 += 1;
+         break;
+       }
+    }
+  name[i] = '\000';
+
+  yylval.ssym.sym = NULL;
+  yylval.ssym.stoken.ptr = name;
+  yylval.ssym.stoken.length = i;
+  return NAME;
+}
+
+static void 
+block_lookup (name, err_name)
+     char* name;
+     char* err_name;
+{
+  struct symbol** syms;
+  struct block** blocks;
+  int nsyms;
+  struct symtab *symtab;
+  nsyms = ada_lookup_symbol_list (name, left_block_context,
+                                 VAR_NAMESPACE, &syms, &blocks);
+  if (left_block_context == NULL &&
+      (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK))
+    symtab = lookup_symtab (name);
+  else
+    symtab = NULL;
+
+  if (symtab != NULL)
+    left_block_context = yylval.bval =
+      BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), STATIC_BLOCK);
+  else if (nsyms == 0 || SYMBOL_CLASS (syms[0]) != LOC_BLOCK)
+    {
+      if (left_block_context == NULL)
+       error ("No file or function \"%s\".", err_name);
+      else
+       error ("No function \"%s\" in specified context.", err_name);
+    }
+  else 
+    {
+      left_block_context = yylval.bval = SYMBOL_BLOCK_VALUE (syms[0]); 
+      if (nsyms > 1)
+       warning ("Function name \"%s\" ambiguous here", err_name);
+    }
+}
+
+/* Look up NAME0 (assumed to be mangled) as a name in VAR_NAMESPACE,
+   setting *TOKEN_TYPE to NAME or TYPENAME, depending on what is
+   found.  Try first the entire name, then the name without the last 
+   segment (i.e., after the last .id), etc., and return the number of
+   segments that had to be removed to get a match.  Calls error if no
+   matches are found, using ERR_NAME in any error message.  When
+   exactly one symbol match is found, it is placed in yylval. */
+static int
+name_lookup (name0, err_name, token_type)
+     char* name0;
+     char* err_name;
+     int* token_type;
+{
+  struct symbol** syms;
+  struct block** blocks;
+  struct type* type;
+  int len0 = strlen (name0);
+  char* name = savestring (name0, len0);
+  int nsyms;
+  int segments;
+/*  add_name_string_cleanup (name);*/
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+  yylval.ssym.stoken.ptr = name;
+  yylval.ssym.stoken.length = strlen (name);
+  for (segments = 0; ; segments += 1)
+    {
+      struct type* preferred_type;
+      int i, preferred_index;
+
+      if (left_block_context == NULL) 
+       nsyms = ada_lookup_symbol_list (name, expression_context_block, 
+                                       VAR_NAMESPACE, &syms, &blocks);
+      else
+       nsyms = ada_lookup_symbol_list (name, left_block_context, 
+                                       VAR_NAMESPACE, &syms, &blocks);
+
+      /* Check for a type definition. */
+
+      /* Look for a symbol that doesn't denote void.  This is (I think) a */
+      /* temporary kludge to get around problems in GNAT output. */
+      preferred_index = -1; preferred_type = NULL;
+      for (i = 0; i < nsyms; i += 1)
+       switch (SYMBOL_CLASS (syms[i])) 
+         {
+         case LOC_TYPEDEF:
+           if (ada_prefer_type (SYMBOL_TYPE (syms[i]), preferred_type))
+             {
+               preferred_index = i;
+               preferred_type = SYMBOL_TYPE (syms[i]);
+             }
+           break;
+         case LOC_REGISTER:
+         case LOC_ARG:
+         case LOC_REF_ARG:
+         case LOC_REGPARM:
+         case LOC_REGPARM_ADDR:
+         case LOC_LOCAL:
+         case LOC_LOCAL_ARG:
+         case LOC_BASEREG:
+         case LOC_BASEREG_ARG:
+           goto NotType;
+         default:
+           break;
+         }
+      if (preferred_type != NULL)
+       {
+/*       if (TYPE_CODE (preferred_type) == TYPE_CODE_VOID)
+           error ("`%s' matches only void type name(s)", 
+                  ada_demangle (name));
+*/
+/* FIXME: ada_demangle should be defined in defs.h, and is located in ada-lang.c */
+/*       else*/ if (ada_is_object_renaming (syms[preferred_index]))
+           {
+             yylval.ssym.sym = syms[preferred_index];
+             *token_type = OBJECT_RENAMING;
+             return segments;
+           } 
+         else if (ada_renaming_type (SYMBOL_TYPE (syms[preferred_index])) 
+                   != NULL)
+           {
+             int result;
+             const char* renaming = 
+               ada_simple_renamed_entity (syms[preferred_index]);
+             char* new_name = xmalloc (strlen (renaming) + len0 
+                                       - yylval.ssym.stoken.length + 1);
+/*           add_name_string_cleanup (new_name);*/
+/* FIXME: add_name_string_cleanup should be defined in parse.c */
+             strcpy (new_name, renaming);
+             strcat (new_name, name0 + yylval.ssym.stoken.length);
+             result = name_lookup (new_name, err_name, token_type);
+             if (result > segments) 
+               error ("Confused by renamed symbol.");
+             return result;
+           }
+         else if (segments == 0)
+           {
+             yylval.tval = preferred_type;
+             *token_type = TYPENAME;
+             return 0;
+           } 
+       }
+
+      if (segments == 0)
+       {
+         type = lookup_primitive_typename (name);
+         if (type == NULL && STREQ ("system__address", name))
+           type = builtin_type_ada_system_address;
+         if (type != NULL)
+           {
+             yylval.tval = type;
+             *token_type = TYPENAME;
+             return 0;
+           }
+       }
+
+    NotType:
+      if (nsyms == 1) 
+       {
+         *token_type = NAME;
+         yylval.ssym.sym = syms[0];
+         yylval.ssym.msym = NULL;
+         yylval.ssym.block = blocks[0];
+         return segments;
+       }
+      else if (nsyms == 0) {
+       int i;
+       yylval.ssym.msym = ada_lookup_minimal_symbol (name);
+       if (yylval.ssym.msym != NULL)
+         {
+           yylval.ssym.sym = NULL;
+           yylval.ssym.block = NULL;
+            *token_type = NAME;
+           return segments;
+         }
+
+       for (i = yylval.ssym.stoken.length - 1; i > 0; i -= 1)
+         {
+            if (name[i] == '.')
+             { 
+               name[i] = '\0';
+               yylval.ssym.stoken.length = i;
+               break;
+             }
+           else if (name[i] == '_' && name[i-1] == '_')
+             {
+               i -= 1;
+               name[i] = '\0';
+               yylval.ssym.stoken.length = i;
+               break;
+             }
+         }
+       if (i <= 0) 
+         {
+           if (!have_full_symbols () && !have_partial_symbols ()
+               && left_block_context == NULL)
+             error ("No symbol table is loaded.  Use the \"file\" command.");
+           if (left_block_context == NULL)
+             error ("No definition of \"%s\" in current context.", 
+                    err_name);
+           else
+             error ("No definition of \"%s\" in specified context.", 
+                    err_name);
+         }
+      }
+      else 
+       {
+         *token_type = NAME;
+         yylval.ssym.sym = NULL;
+         yylval.ssym.msym = NULL;
+         if (left_block_context == NULL)
+           yylval.ssym.block = expression_context_block;
+         else
+           yylval.ssym.block = left_block_context;
+         return segments;
+       }
+    }
+}
+
+/* Returns the position within STR of the '.' in a
+   '.{WHITE}*all' component of a dotted name, or -1 if there is none. */
+static int
+find_dot_all (str)
+     const char* str;
+{
+  int i;
+  for (i = 0; str[i] != '\000'; i += 1)
+    {
+      if (str[i] == '.')
+       {
+         int i0 = i;
+         do 
+           i += 1;
+         while (isspace (str[i]));
+         if (strcmp (str+i, "all") == 0
+             && ! isalnum (str[i+3]) && str[i+3] != '_')
+           return i0;
+       }
+    }
+  return -1;
+}    
+
+/* Returns non-zero iff string SUBSEQ matches a subsequence of STR, ignoring
+   case. */
+
+static int
+subseqMatch (subseq, str)
+     const char* subseq;
+     const char* str;
+{
+  if (subseq[0] == '\0')
+    return 1;
+  else if (str[0] == '\0')
+    return 0;
+  else if (tolower (subseq[0]) == tolower (str[0]))
+    return subseqMatch (subseq+1, str+1) || subseqMatch (subseq, str+1);
+  else
+    return subseqMatch (subseq, str+1);
+}
+  
+
+static struct { const char* name; int code; } 
+attributes[] = {
+  { "address", TICK_ADDRESS },
+  { "unchecked_access", TICK_ACCESS },
+  { "unrestricted_access", TICK_ACCESS },
+  { "access", TICK_ACCESS },
+  { "first", TICK_FIRST },
+  { "last", TICK_LAST },
+  { "length", TICK_LENGTH },
+  { "max", TICK_MAX },
+  { "min", TICK_MIN },
+  { "modulus", TICK_MODULUS },
+  { "pos", TICK_POS },
+  { "range", TICK_RANGE },
+  { "size", TICK_SIZE },
+  { "tag", TICK_TAG },
+  { "val", TICK_VAL },
+  { NULL, -1 }
+};
+
+/* Return the syntactic code corresponding to the attribute name or
+   abbreviation STR.  */
+
+static int
+processAttribute (str)
+     const char* str;
+{
+  int i, k;
+
+  for (i = 0; attributes[i].code != -1; i += 1)
+    if (strcasecmp (str, attributes[i].name) == 0)
+      return attributes[i].code;
+
+  for (i = 0, k = -1; attributes[i].code != -1; i += 1)
+    if (subseqMatch (str, attributes[i].name)) 
+      {
+       if (k == -1)
+         k = i;
+       else 
+         error ("ambiguous attribute name: `%s'", str);
+      }
+  if (k == -1)
+    error ("unrecognized attribute: `%s'", str);
+
+  return attributes[k].code;
+}
+
+int
+yywrap()
+{
+  return 1;
+}
diff --git a/gdb/ada-tasks.c b/gdb/ada-tasks.c
new file mode 100644 (file)
index 0000000..23dc105
--- /dev/null
@@ -0,0 +1,806 @@
+/* file ada-tasks.c: Ada tasking control for GDB
+   Copyright 1997 Free Software Foundation, Inc.
+   Contributed by Ada Core Technologies, Inc
+.
+   This file is part of GDB.
+
+   [$Id$]
+   Authors: Roch-Alexandre Nomine Beguin, Arnaud Charlet <charlet@gnat.com>
+
+   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.
+
+*/
+
+#include <ctype.h> 
+#include "defs.h" 
+#include "command.h" 
+#include "value.h"
+#include "language.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "target.h"
+#include "gdbcore.h"
+
+#if (defined(__alpha__) && defined(__osf__) && !defined(__alpha_vxworks))
+#include <sys/procfs.h>
+#endif
+
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+#include "gregset.h"
+#endif 
+
+#include "ada-lang.h"
+
+/* FIXME: move all this conditional compilation in description
+   files or in configure.in */
+
+#if defined (VXWORKS_TARGET)
+#define THREAD_TO_PID(tid,lwpid) (tid)
+
+#elif defined (linux)
+#define THREAD_TO_PID(tid,lwpid) (0)
+
+#elif (defined (sun) && defined (__SVR4))
+#define THREAD_TO_PID thread_to_pid
+
+#elif defined (sgi) || defined (__WIN32__) || defined (hpux)
+#define THREAD_TO_PID(tid,lwpid) ((int)lwpid)
+
+#else
+#define THREAD_TO_PID(tid,lwpid) (0)
+#endif
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+#define THREAD_FETCH_REGISTERS dec_thread_fetch_registers
+#define GET_CURRENT_THREAD dec_thread_get_current_thread
+extern int dec_thread_get_registers (gdb_gregset_t *, gdb_fpregset_t *);
+#endif
+
+#if defined (_AIX)
+#define THREAD_FETCH_REGISTERS aix_thread_fetch_registers
+#define GET_CURRENT_THREAD aix_thread_get_current_thread
+#endif
+
+#if defined(VXWORKS_TARGET)
+#define GET_CURRENT_THREAD() ((void*)inferior_pid)
+#define THREAD_FETCH_REGISTERS() (-1)
+
+#elif defined (sun) && defined (__SVR4)
+#define GET_CURRENT_THREAD solaris_thread_get_current_thread
+#define THREAD_FETCH_REGISTERS() (-1)
+extern void *GET_CURRENT_THREAD();
+
+#elif defined (_AIX) || (defined(__alpha__) && defined(__osf__))
+extern void *GET_CURRENT_THREAD();
+
+#elif defined (__WIN32__) || defined (hpux)
+#define GET_CURRENT_THREAD() (inferior_pid)
+#define THREAD_FETCH_REGISTERS() (-1)
+
+#else
+#define GET_CURRENT_THREAD() (NULL)
+#define THREAD_FETCH_REGISTERS() (-1)
+#endif
+
+#define KNOWN_TASKS_NAME "system__tasking__debug__known_tasks"
+
+#define READ_MEMORY(addr, var) read_memory (addr, (char*) &var, sizeof (var))
+/* external declarations */
+
+extern struct value* find_function_in_inferior (char *);
+
+/* Global visible variables */
+
+struct task_entry *task_list = NULL;
+int ada__tasks_check_symbol_table = 1;
+void *pthread_kern_addr = NULL;
+
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+gdb_gregset_t gregset_saved;
+gdb_fpregset_t fpregset_saved;
+#endif
+
+/* The maximum number of tasks known to the Ada runtime */
+const int MAX_NUMBER_OF_KNOWN_TASKS = 1000;
+
+/* the current task */
+int current_task = -1, current_task_id = -1, current_task_index;
+void *current_thread, *current_lwp;
+
+char *ada_task_states[] =
+{
+  "Unactivated",
+  "Runnable",
+  "Terminated",
+  "Child Activation Wait",
+  "Accept Statement",
+  "Waiting on entry call",
+  "Async Select Wait",
+  "Delay Sleep",
+  "Child Termination Wait",
+  "Wait Child in Term Alt",
+  "",
+  "",
+  "",
+  "",
+  "Asynchronous Hold"
+};
+
+/* Global internal types */
+
+static char *ada_long_task_states[] =
+{
+  "Unactivated",
+  "Runnable",
+  "Terminated",
+  "Waiting for child activation",
+  "Blocked in accept statement",
+  "Waiting on entry call",
+  "Asynchronous Selective Wait",
+  "Delay Sleep",
+  "Waiting for children termination",
+  "Waiting for children in terminate alternative",
+  "",
+  "",
+  "",
+  "",
+  "Asynchronous Hold"
+};
+
+/* Global internal variables */
+
+static int highest_task_num = 0;
+int thread_support = 0; /* 1 if the thread library in use is supported */
+static int gdbtk_task_initialization = 0;
+
+static int add_task_entry (p_task_id, index)
+     void *p_task_id;
+     int index;
+{
+  struct task_entry *new_task_entry = NULL;
+  struct task_entry *pt;
+
+  highest_task_num++;
+  new_task_entry = malloc (sizeof (struct task_entry));
+  new_task_entry->task_num = highest_task_num;
+  new_task_entry->task_id = p_task_id;
+  new_task_entry->known_tasks_index = index;
+  new_task_entry->next_task = NULL;
+  pt = task_list;
+  if (pt)
+    {
+      while (pt->next_task)
+       pt = pt->next_task;
+      pt->next_task = new_task_entry;
+      pt->stack_per = 0;
+    }
+  else task_list = new_task_entry;
+  return new_task_entry->task_num;
+}
+
+int 
+get_entry_number (p_task_id)
+     void *p_task_id;
+{
+  struct task_entry *pt;
+
+  pt = task_list;
+  while (pt != NULL)
+    {
+      if (pt->task_id == p_task_id)
+       return pt->task_num;
+      pt = pt->next_task;
+    }
+  return 0;
+}
+
+static struct task_entry *get_thread_entry_vptr (thread)
+     void *thread;
+{
+  struct task_entry *pt;
+
+  pt = task_list;
+  while (pt != NULL)
+    {
+      if (pt->thread == thread)
+      return pt;
+      pt = pt->next_task;
+    }
+  return 0;
+}
+
+static struct task_entry *get_entry_vptr (p_task_num)
+     int p_task_num;
+{
+  struct task_entry *pt;
+
+  pt = task_list;
+  while (pt)
+    {
+      if (pt->task_num == p_task_num)
+       return pt;
+      pt = pt->next_task;
+    }
+  return NULL;
+}
+
+void init_task_list ()
+{
+  struct task_entry *pt, *old_pt;
+
+  pt = task_list;
+  while (pt)
+    {
+      old_pt = pt;
+      pt = pt->next_task;
+      free (old_pt);
+    };
+  task_list = NULL;
+  highest_task_num = 0;
+}
+
+int valid_task_id (task)
+     int task;
+{
+  return get_entry_vptr (task) != NULL;
+}
+
+void *get_self_id ()
+{
+  struct value* val;
+  void *self_id;
+  int result;
+  struct task_entry *ent;
+  extern int do_not_insert_breakpoints;
+
+#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__))
+  if (thread_support)
+#endif
+    {
+      ent = get_thread_entry_vptr (GET_CURRENT_THREAD ());
+      return ent ? ent->task_id : 0;
+    }
+
+  /* FIXME: calling a function in the inferior with a multithreaded application
+     is not reliable, so return NULL if there is no safe way to get the current
+     task */
+  return NULL;
+}
+
+int get_current_task ()
+{
+  int result;
+  
+  /* FIXME: language_ada should be defined in defs.h */
+  /*  if (current_language->la_language != language_ada) return -1; */
+
+  result = get_entry_number (get_self_id ());
+
+  /* return -1 if not found */
+  return result == 0 ? -1 : result;
+}
+
+/* Print detailed information about specified task */
+
+static void
+info_task (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  void *temp_task;
+  struct task_entry *pt, *pt2;
+  void *self_id, *caller;
+  struct task_fields atcb, atcb2;
+  struct entry_call call;
+  int bounds [2];
+  char image [256];
+  int num;
+
+  /* FIXME: language_ada should be defined in defs.h */
+  /*  if (current_language->la_language != language_ada) 
+    { 
+      printf_filtered ("The current language does not support tasks.\n"); 
+      return; 
+    } 
+  */
+  pt = get_entry_vptr (atoi (arg));
+  if (pt == NULL)
+    {
+      printf_filtered ("Task %s not found.\n", arg); 
+      return; 
+    }
+
+  temp_task = pt->task_id;
+
+  /* read the atcb in the inferior */
+  READ_MEMORY ((CORE_ADDR) temp_task, atcb);
+
+  /* print the Ada task id */
+  printf_filtered ("Ada Task: %p\n", temp_task);
+
+  /* print the name of the task */
+  if (atcb.image.P_ARRAY != NULL) {
+    READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
+    bounds [1] = EXTRACT_INT (bounds [1]);
+    read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
+                 (char*) &image, bounds [1]);
+    printf_filtered ("Name: %.*s\n", bounds [1], image);
+  }
+  else printf_filtered ("<no name>\n");
+
+  /* print the thread id */
+
+  if ((long) pt->thread < 65536)
+    printf_filtered ("Thread: %ld\n", (long int) pt->thread);
+  else
+    printf_filtered ("Thread: %p\n", pt->thread);
+
+  if ((long) pt->lwp != 0)
+    {
+      if ((long) pt->lwp < 65536)
+        printf_filtered ("LWP: %ld\n", (long int) pt->lwp);
+      else
+        printf_filtered ("LWP: %p\n", pt->lwp);
+    }
+
+  /* print the parent gdb task id */
+  num = get_entry_number (EXTRACT_ADDRESS (atcb.parent));
+  if (num != 0)
+    {
+      printf_filtered ("Parent: %d", num);
+      pt2 = get_entry_vptr (num);
+      READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
+
+      /* print the name of the task */
+      if (atcb2.image.P_ARRAY != NULL) {
+        READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
+                     bounds);
+        bounds [1] = EXTRACT_INT (bounds [1]);
+        read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
+                     (char*) &image, bounds [1]);
+        printf_filtered (" (%.*s)\n", bounds [1], image);
+      }
+      else
+        printf_filtered ("\n");
+    }
+  else
+    printf_filtered ("No parent\n");
+
+  /* print the base priority of the task */
+  printf_filtered ("Base Priority: %d\n", EXTRACT_INT (atcb.priority));
+
+  /* print the current state of the task */
+
+  /* check if this task is accepting a rendezvous */
+  if (atcb.call == NULL)
+    caller = NULL;
+  else {
+    READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
+    caller = EXTRACT_ADDRESS (call.self);
+  }
+  if (caller != NULL)
+    {
+      num = get_entry_number (caller);
+      printf_filtered ("Accepting rendezvous with %d", num);
+
+      if (num != 0)
+       {
+         pt2 = get_entry_vptr (num);
+         READ_MEMORY ((CORE_ADDR) pt2->task_id, atcb2);
+
+         /* print the name of the task */
+         if (atcb2.image.P_ARRAY != NULL) {
+           READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_BOUNDS),
+                         bounds);
+            bounds [1] = EXTRACT_INT (bounds [1]);
+           read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb2.image.P_ARRAY),
+                         (char*) &image, bounds [1]);
+           printf_filtered (" (%.*s)\n", bounds [1], image);
+         }
+         else
+           printf_filtered ("\n");
+       }
+      else
+       printf_filtered ("\n");
+    }
+  else
+    printf_filtered ("State: %s\n", ada_long_task_states [atcb.state]);
+}
+
+#if 0
+
+/* A useful function that shows the alignment of all the fields in the
+   tasks_fields structure
+ */
+
+print_align ()
+{
+  struct task_fields tf;
+  void *tf_base             = &(tf);
+  void *tf_state            = &(tf.state);
+  void *tf_entry_num        = &(tf.entry_num);
+  void *tf_parent           = &(tf.parent);
+  void *tf_priority         = &(tf.priority);
+  void *tf_current_priority = &(tf.current_priority);
+  void *tf_image            = &(tf.image);
+  void *tf_call             = &(tf.call);
+  void *tf_thread           = &(tf.thread);
+  void *tf_lwp              = &(tf.lwp);
+  printf_filtered ("\n");
+  printf_filtered ("(tf_base = 0x%x)\n", tf_base);
+  printf_filtered ("task_fields.entry_num        at %3d (0x%x)\n", tf_entry_num - tf_base, tf_entry_num);
+  printf_filtered ("task_fields.state            at %3d (0x%x)\n", tf_state - tf_base, tf_state);
+  printf_filtered ("task_fields.parent           at %3d (0x%x)\n", tf_parent - tf_base, tf_parent);
+  printf_filtered ("task_fields.priority         at %3d (0x%x)\n", tf_priority - tf_base, tf_priority);
+  printf_filtered ("task_fields.current_priority at %3d (0x%x)\n", tf_current_priority - tf_base, tf_current_priority);
+  printf_filtered ("task_fields.image            at %3d (0x%x)\n", tf_image - tf_base, tf_image);
+  printf_filtered ("task_fields.call             at %3d (0x%x)\n", tf_call - tf_base, tf_call);
+  printf_filtered ("task_fields.thread           at %3d (0x%x)\n", tf_thread - tf_base, tf_thread);
+  printf_filtered ("task_fields.lwp              at %3d (0x%x)\n", tf_lwp - tf_base, tf_lwp);
+  printf_filtered ("\n"); 
+}
+#endif
+
+/* Print information about currently known tasks */
+
+static void
+info_tasks (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+  struct value* val;
+  int i, task_number, state;
+  void *temp_task, *temp_tasks [MAX_NUMBER_OF_KNOWN_TASKS];
+  struct task_entry *pt;
+  void *self_id, *caller, *thread_id=NULL;
+  struct task_fields atcb;
+  struct entry_call call;
+  int bounds [2];
+  char image [256];
+  int size;
+  char car;
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+  pthreadTeb_t thr;
+  gdb_gregset_t regs;
+#endif
+
+  static struct symbol *sym;
+  static struct minimal_symbol *msym;
+  static void *known_tasks_addr = NULL;
+
+  int init_only = gdbtk_task_initialization;
+  gdbtk_task_initialization = 0;
+
+  task_number = 0;
+
+  if (PIDGET(inferior_ptid) == 0)
+    {
+      printf_filtered ("The program is not being run under gdb. ");
+      printf_filtered ("Use 'run' or 'attach' first.\n");
+      return;
+    }
+
+  if (ada__tasks_check_symbol_table)
+    {
+      thread_support = 0;
+#if (defined(__alpha__) && defined(__osf__) & !defined(VXWORKS_TARGET)) || \
+    defined (_AIX)
+      thread_support = 1;
+#endif
+
+      msym = lookup_minimal_symbol (KNOWN_TASKS_NAME, NULL, NULL);
+      if (msym != NULL)
+       known_tasks_addr = (void *) SYMBOL_VALUE_ADDRESS (msym);
+      else
+#ifndef VXWORKS_TARGET
+       return; 
+#else
+       {
+         if (target_lookup_symbol (KNOWN_TASKS_NAME, &known_tasks_addr) != 0)
+           return;
+       }
+#endif
+
+      ada__tasks_check_symbol_table = 0;
+    }
+
+  if (known_tasks_addr == NULL)
+    return;
+
+#if !((defined(sun) && defined(__SVR4)) || defined(VXWORKS_TARGET) || defined(__WIN32__) || defined (hpux))
+  if (thread_support)
+#endif
+    thread_id = GET_CURRENT_THREAD ();
+
+  /* then we get a list of tasks created */
+
+  init_task_list ();
+
+  READ_MEMORY ((CORE_ADDR) known_tasks_addr, temp_tasks);
+
+  for (i=0; i<MAX_NUMBER_OF_KNOWN_TASKS; i++)
+    {
+      temp_task = EXTRACT_ADDRESS (temp_tasks[i]);
+
+      if (temp_task != NULL)
+        {
+          task_number = get_entry_number (temp_task);
+          if (task_number == 0)
+           task_number = add_task_entry (temp_task, i);
+        }
+    }      
+
+  /* Return without printing anything if this function was called in
+     order to init GDBTK tasking. */
+
+  if (init_only) return;
+
+  /* print the header */
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+  printf_filtered
+   ("  ID       TID P-ID Pri Stack  %% State                  Name\n");
+#else
+  printf_filtered ("  ID       TID P-ID Pri State                  Name\n");
+#endif
+
+  /* Now that we have a list of task id's, we can print them */
+  pt = task_list;
+  while (pt)
+    {
+      temp_task = pt->task_id;
+
+      /* read the atcb in the inferior */
+      READ_MEMORY ((CORE_ADDR) temp_task, atcb);
+
+      /* store the thread id for future use */
+      pt->thread = EXTRACT_ADDRESS (atcb.thread);
+
+#if defined (linux)
+      pt->lwp = (void *) THREAD_TO_PID (atcb.thread, 0);
+#else
+      pt->lwp = EXTRACT_ADDRESS (atcb.lwp);
+#endif
+
+      /* print a star if this task is the current one */
+      if (thread_id)
+#if defined (__WIN32__) || defined (SGI) || defined (hpux)
+       printf_filtered (pt->lwp == thread_id ? "*" : " ");
+#else
+       printf_filtered (pt->thread == thread_id ? "*" : " ");
+#endif
+
+      /* print the gdb task id */
+      printf_filtered ("%3d", pt->task_num);
+
+      /* print the Ada task id */
+#ifndef VXWORKS_TARGET
+      printf_filtered (" %9lx", (long) temp_task);
+#else
+#ifdef TARGET_64
+      printf_filtered (" %#9lx", (unsigned long)pt->thread & 0x3ffffffffff);
+#else
+      printf_filtered (" %#9lx", (long)pt->thread);
+#endif
+#endif
+
+      /* print the parent gdb task id */
+      printf_filtered
+        (" %4d", get_entry_number (EXTRACT_ADDRESS (atcb.parent)));
+
+      /* print the base priority of the task */
+      printf_filtered (" %3d", EXTRACT_INT (atcb.priority));
+
+#if defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET)
+      if (pt->task_num == 1 || atcb.state == Terminated)
+       {
+          printf_filtered ("  Unknown");
+         goto next;
+       }
+
+      read_memory ((CORE_ADDR)atcb.thread, &thr, sizeof (thr));
+      current_thread = atcb.thread;
+      regs.regs [SP_REGNUM] = 0;
+      if (dec_thread_get_registers (&regs, NULL) == 0) {
+       pt->stack_per = (100 * ((long)thr.__stack_base -
+       regs.regs [SP_REGNUM])) / thr.__stack_size;
+       /* if the thread is terminated but still there, the
+       stack_base/size values are erroneous. Try to patch it */
+       if (pt->stack_per < 0 || pt->stack_per > 100) pt->stack_per = 0;
+      }
+
+      /* print information about stack space used in the thread */
+      if (thr.__stack_size < 1024*1024)
+       {
+         size = thr.__stack_size / 1024;
+         car = 'K';
+       }
+      else if (thr.__stack_size < 1024*1024*1024)
+       {
+         size = thr.__stack_size / 1024 / 1024;
+         car = 'M';
+       }
+      else /* Who knows... */
+       {
+         size = thr.__stack_size / 1024 / 1024 / 1024;
+         car = 'G';
+       }
+      printf_filtered (" %4d%c %2d", size, car, pt->stack_per);
+next:
+#endif
+
+      /* print the current state of the task */
+
+      /* check if this task is accepting a rendezvous */
+      if (atcb.call == NULL)
+       caller = NULL;
+      else {
+       READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.call), call);
+       caller = EXTRACT_ADDRESS (call.self);
+      }
+      if (caller != NULL)
+       printf_filtered (" Accepting RV with %-4d", get_entry_number (caller));
+      else
+       {
+         state = atcb.state;
+#if defined (__WIN32__) || defined (SGI) || defined (hpux)
+         if (state == Runnable && (thread_id && pt->lwp == thread_id))
+#else
+         if (state == Runnable && (thread_id && pt->thread == thread_id))
+#endif
+           /* Replace "Runnable" by "Running" if this is the current task */
+           printf_filtered (" %-22s", "Running");
+         else
+           printf_filtered (" %-22s", ada_task_states [state]);
+       }
+
+      /* finally, print the name of the task */
+      if (atcb.image.P_ARRAY != NULL) {
+        READ_MEMORY ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_BOUNDS), bounds);
+        bounds [1] = EXTRACT_INT (bounds [1]);
+        read_memory ((CORE_ADDR) EXTRACT_ADDRESS (atcb.image.P_ARRAY),
+                     (char*)&image, bounds [1]);
+        printf_filtered (" %.*s\n", bounds [1], image);
+      }
+      else printf_filtered (" <no name>\n");
+
+      pt = pt->next_task;
+    }
+}
+
+/* Task list initialization for GDB-Tk.  We basically use info_tasks()
+   to initialize our variables, but abort that function before we
+   actually print anything. */
+
+int
+gdbtk_tcl_tasks_initialize ()
+{
+  gdbtk_task_initialization = 1;
+  info_tasks ("", gdb_stdout);
+
+  return (task_list != NULL);
+}
+
+static void
+info_tasks_command (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+   if (arg == NULL || *arg == '\000')
+      info_tasks (arg, from_tty);
+   else
+      info_task (arg, from_tty);
+}
+
+/* Switch from one thread to another. */
+
+static void
+switch_to_thread (ptid_t ptid)
+
+{
+  if (ptid_equal (ptid, inferior_ptid))
+    return;
+
+  inferior_ptid = ptid;
+  flush_cached_frames ();
+  registers_changed ();
+  stop_pc = read_pc ();
+  select_frame (get_current_frame ());
+}
+
+/* Switch to a specified task. */
+
+static int task_switch (tid, lwpid)
+     void *tid, *lwpid;
+{
+  int res = 0, pid;
+
+  if (thread_support)
+    {
+      flush_cached_frames ();
+
+      if (current_task != current_task_id)
+       {
+         res = THREAD_FETCH_REGISTERS ();
+       }
+      else
+       {
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+         supply_gregset (&gregset_saved);
+         supply_fpregset (&fpregset_saved);
+#endif
+       }
+
+      if (res == 0) stop_pc = read_pc();
+      select_frame (get_current_frame ());
+      return res;
+    }
+
+  return -1;
+}
+
+static void task_command (tidstr, from_tty)
+     char *tidstr;
+     int from_tty;
+{
+  int num;
+  struct task_entry *e;
+
+  if (!tidstr)
+    error ("Please specify a task ID.  Use the \"info tasks\" command to\n"
+           "see the IDs of currently known tasks.");
+
+  num = atoi (tidstr);
+  e = get_entry_vptr (num);
+
+  if (e == NULL)
+    error ("Task ID %d not known.  Use the \"info tasks\" command to\n"
+           "see the IDs of currently known tasks.", num);
+
+  if (current_task_id == -1)
+    {
+#if (defined(__alpha__) && defined(__osf__) && !defined(VXWORKS_TARGET))
+      fill_gregset (&gregset_saved, -1);
+      fill_fpregset (&fpregset_saved, -1);
+#endif
+      current_task_id = get_current_task ();
+    }
+
+  current_task = num;
+  current_task_index = e->known_tasks_index;
+  current_thread = e->thread;
+  current_lwp = e->lwp;
+  if (task_switch (e->thread, e->lwp) == 0)
+    {
+      /* FIXME: find_printable_frame should be defined in frame.h, and
+        implemented in ada-lang.c */
+      /*      find_printable_frame (selected_frame, frame_relative_level (selected_frame));*/
+      printf_filtered ("[Switching to task %d]\n", num);
+      print_stack_frame (selected_frame, frame_relative_level (selected_frame), 1);
+    }
+  else
+    printf_filtered ("Unable to switch to task %d\n", num);
+}
+
+void
+_initialize_tasks ()
+{
+  static struct cmd_list_element *task_cmd_list = NULL;
+  extern struct cmd_list_element *cmdlist;
+
+  add_info (
+        "tasks", info_tasks_command,
+       "Without argument: list all known Ada tasks, with status information.\n"
+       "info tasks n: print detailed information of task n.\n");
+
+  add_prefix_cmd ("task", class_run, task_command,
+                  "Use this command to switch between tasks.\n\
+ The new task ID must be currently known.", &task_cmd_list, "task ", 1,
+                  &cmdlist);
+}
diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c
new file mode 100644 (file)
index 0000000..6773561
--- /dev/null
@@ -0,0 +1,896 @@
+/* Support for printing Ada types for GDB, the GNU debugger.
+   Copyright 1986, 1988, 1989, 1991, 1997 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include "defs.h"
+#include "obstack.h"
+#include "bfd.h"               /* Binary File Description */
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "demangle.h"
+#include "c-lang.h"
+#include "typeprint.h"
+#include "ada-lang.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+static int print_record_field_types (struct type *, struct type *, 
+                                    struct ui_file *, int, int);
+
+static void print_array_type (struct type*, struct ui_file*, int, int);
+
+static void print_choices (struct type*, int, struct ui_file*, struct type*);
+
+static void print_range (struct type*, struct ui_file*);
+
+static void print_range_bound (struct type*, char*, int*, struct ui_file*);
+
+static void 
+print_dynamic_range_bound (struct type*, const char*, int, 
+                          const char*, struct ui_file*);
+
+static void print_range_type_named (char*, struct ui_file*);
+
+\f
+
+static char* name_buffer;
+static int name_buffer_len;
+
+/* The (demangled) Ada name of TYPE. This value persists until the
+   next call. */
+
+static char*
+demangled_type_name (type)
+     struct type *type;
+{
+  if (ada_type_name (type) == NULL)
+    return NULL;
+  else 
+    {
+      char* raw_name = ada_type_name (type);
+      char *s, *q; 
+
+      if (name_buffer == NULL || name_buffer_len <= strlen (raw_name))
+       {
+         name_buffer_len = 16 + 2 * strlen (raw_name);
+         name_buffer = xrealloc (name_buffer, name_buffer_len);
+       }
+      strcpy (name_buffer, raw_name);
+
+      s = (char*) strstr (name_buffer, "___");
+      if (s != NULL)
+       *s = '\0';
+
+      s = name_buffer + strlen (name_buffer) - 1;
+      while (s > name_buffer && (s[0] != '_' || s[-1] != '_'))
+       s -= 1;
+
+      if (s == name_buffer)
+       return name_buffer;
+
+      if (! islower (s[1]))
+       return NULL;
+
+      for (s = q = name_buffer; *s != '\0'; q += 1)
+       {
+         if (s[0] == '_' && s[1] == '_')
+           {
+             *q = '.'; s += 2;
+           }
+         else
+           {
+             *q = *s; s += 1;
+           }
+       }
+      *q = '\0';
+      return name_buffer;
+    }
+}
+
+
+/* Print a description of a type in the format of a 
+   typedef for the current language.
+   NEW is the new name for a type TYPE. */
+
+void
+ada_typedef_print (type, new, stream)
+   struct type *type;
+   struct symbol *new;
+   struct ui_file *stream;
+{
+  fprintf_filtered (stream, "type %.*s is ", 
+                   ada_name_prefix_len (SYMBOL_SOURCE_NAME(new)), 
+                   SYMBOL_SOURCE_NAME(new));
+  type_print (type, "", stream, 1);
+}
+
+/* Print range type TYPE on STREAM. */
+
+static void
+print_range (type, stream)
+     struct type* type;
+     struct ui_file* stream;
+{
+  struct type* target_type;
+  target_type = TYPE_TARGET_TYPE (type);
+  if (target_type == NULL)
+    target_type = type;
+
+  switch (TYPE_CODE (target_type)) 
+    {
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_INT:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_ENUM:
+      break;
+    default:
+      target_type = builtin_type_ada_int;
+      break;
+    }
+
+  if (TYPE_NFIELDS (type) < 2)
+    {
+      /* A range needs at least 2 bounds to be printed. If there are less
+         than 2, just print the type name instead of the range itself.
+         This check handles cases such as characters, for example. 
+
+         Note that if the name is not defined, then we don't print anything.
+       */
+      fprintf_filtered (stream, "%.*s",
+                        ada_name_prefix_len (TYPE_NAME (type)),
+                        TYPE_NAME (type));
+    }
+  else
+    {
+      /* We extract the range type bounds respectively from the first element
+         and the last element of the type->fields array */
+      const LONGEST lower_bound = (LONGEST) TYPE_LOW_BOUND (type);
+      const LONGEST upper_bound =
+        (LONGEST) TYPE_FIELD_BITPOS (type, TYPE_NFIELDS (type) -1);
+
+      ada_print_scalar (target_type, lower_bound, stream);
+      fprintf_filtered (stream, " .. ");
+      ada_print_scalar (target_type, upper_bound, stream);
+    }
+}
+
+/* Print the number or discriminant bound at BOUNDS+*N on STREAM, and
+   set *N past the bound and its delimiter, if any. */
+
+static void
+print_range_bound (type, bounds, n, stream)
+     struct type* type;
+     char* bounds;
+     int* n;
+     struct ui_file* stream;
+{
+  LONGEST B;
+  if (ada_scan_number (bounds, *n, &B, n))
+    {
+      ada_print_scalar (type, B, stream);
+      if (bounds[*n] == '_')
+       *n += 2;
+    }
+  else
+    {
+      int bound_len;
+      char* bound = bounds + *n;
+      char* pend;
+
+      pend = strstr (bound, "__");
+      if (pend == NULL)
+       *n += bound_len = strlen (bound);
+      else 
+       {
+         bound_len = pend - bound;
+         *n += bound_len + 2;
+       }
+      fprintf_filtered (stream, "%.*s", bound_len, bound);
+    }
+}
+
+/* Assuming NAME[0 .. NAME_LEN-1] is the name of a range type, print
+   the value (if found) of the bound indicated by SUFFIX ("___L" or
+   "___U") according to the ___XD conventions. */
+
+static void
+print_dynamic_range_bound (type, name, name_len, suffix, stream)
+     struct type* type;
+     const char* name;
+     int name_len;
+     const char* suffix;
+     struct ui_file* stream;
+{
+  static char *name_buf = NULL;
+  static size_t name_buf_len = 0;
+  LONGEST B;
+  int OK;
+
+  GROW_VECT (name_buf, name_buf_len, name_len + strlen (suffix) + 1);
+  strncpy (name_buf, name, name_len);
+  strcpy (name_buf + name_len, suffix);
+
+  B = get_int_var_value (name_buf, 0, &OK);
+  if (OK)
+    ada_print_scalar (type, B, stream);
+  else
+    fprintf_filtered (stream, "?");
+}
+
+/* Print the range type named NAME. */
+
+static void
+print_range_type_named (name, stream)
+     char* name;
+     struct ui_file* stream;
+{
+  struct type *raw_type = ada_find_any_type (name);
+  struct type *base_type;
+  LONGEST low, high;
+  char* subtype_info;
+
+  if (raw_type == NULL)
+    base_type = builtin_type_int;
+  else if (TYPE_CODE (raw_type) == TYPE_CODE_RANGE)
+    base_type = TYPE_TARGET_TYPE (raw_type);
+  else
+    base_type = raw_type;
+
+  subtype_info = strstr (name, "___XD");
+  if (subtype_info == NULL && raw_type == NULL)
+    fprintf_filtered (stream, "? .. ?");
+  else if (subtype_info == NULL)
+    print_range (raw_type, stream);
+  else
+    {
+      int prefix_len = subtype_info - name;
+      char *bounds_str;
+      int n;
+
+      subtype_info += 5;
+      bounds_str = strchr (subtype_info, '_');
+      n = 1;
+
+      if (*subtype_info == 'L') 
+       {
+         print_range_bound (raw_type, bounds_str, &n, stream);
+         subtype_info += 1;
+       }
+      else
+       print_dynamic_range_bound (raw_type, name, prefix_len, "___L", stream);
+
+      fprintf_filtered (stream, " .. ");
+
+      if (*subtype_info == 'U') 
+       print_range_bound (raw_type, bounds_str, &n, stream);
+      else
+       print_dynamic_range_bound (raw_type, name, prefix_len, "___U", stream);
+    }
+}  
+
+/* Print enumerated type TYPE on STREAM. */
+
+static void
+print_enum_type (type, stream)
+     struct type *type;
+     struct ui_file *stream;
+{
+  int len = TYPE_NFIELDS (type);
+  int i, lastval;
+
+  fprintf_filtered (stream, "(");
+  wrap_here (" ");
+
+  lastval = 0;
+  for (i = 0; i < len; i++)
+    {
+      QUIT;
+      if (i) fprintf_filtered (stream, ", ");
+      wrap_here ("    ");
+      fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream);
+      if (lastval != TYPE_FIELD_BITPOS (type, i))
+       {
+         fprintf_filtered (stream, " => %d", TYPE_FIELD_BITPOS (type, i));
+         lastval = TYPE_FIELD_BITPOS (type, i);
+       }
+      lastval += 1;
+    }
+  fprintf_filtered (stream, ")");
+}
+
+/* Print representation of Ada fixed-point type TYPE on STREAM. */
+
+static void
+print_fixed_point_type (type, stream)
+     struct type *type;
+     struct ui_file *stream;
+{
+  DOUBLEST delta = ada_delta (type);
+  DOUBLEST small = ada_fixed_to_float (type, 1.0);
+
+  if (delta < 0.0)
+    fprintf_filtered (stream, "delta ??");
+  else
+    {
+      fprintf_filtered (stream, "delta %g", (double) delta);
+      if (delta != small) 
+       fprintf_filtered (stream, " <'small = %g>", (double) small);
+    }
+}
+
+/* Print representation of special VAX floating-point type TYPE on STREAM. */
+
+static void
+print_vax_floating_point_type (type, stream)
+     struct type *type;
+     struct ui_file *stream;
+{
+  fprintf_filtered (stream, "<float format %c>",
+                   ada_vax_float_type_suffix (type));
+}
+
+/* Print simple (constrained) array type TYPE on STREAM.  LEVEL is the 
+   recursion (indentation) level, in case the element type itself has 
+   nested structure, and SHOW is the number of levels of internal
+   structure to show (see ada_print_type). */
+
+static void
+print_array_type (type, stream, show, level)
+     struct type *type;
+     struct ui_file *stream;
+     int show;
+     int level;
+{
+  int bitsize;
+  int n_indices;
+
+  bitsize = 0;
+  fprintf_filtered (stream, "array (");
+
+  n_indices = -1;
+  if (show < 0) 
+    fprintf_filtered (stream, "...");
+  else
+    {
+      if (ada_is_packed_array_type (type))
+       type = ada_coerce_to_simple_array_type (type);
+      if (ada_is_simple_array (type)) 
+       {
+         struct type* range_desc_type = 
+           ada_find_parallel_type (type, "___XA");
+         struct type* arr_type;
+
+         bitsize = 0;
+         if (range_desc_type == NULL)
+           {
+             for (arr_type = type; TYPE_CODE (arr_type) == TYPE_CODE_ARRAY;
+                  arr_type = TYPE_TARGET_TYPE (arr_type))
+               {
+                 if (arr_type != type)
+                   fprintf_filtered (stream, ", ");
+                 print_range (TYPE_INDEX_TYPE (arr_type), stream);
+                 if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
+                   bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
+               }
+           }
+         else 
+           {
+             int k;
+             n_indices = TYPE_NFIELDS (range_desc_type); 
+             for (k = 0, arr_type = type; 
+                  k < n_indices;
+                  k += 1, arr_type = TYPE_TARGET_TYPE (arr_type))
+               {
+                 if (k > 0)
+                   fprintf_filtered (stream, ", ");
+                 print_range_type_named (TYPE_FIELD_NAME (range_desc_type, k),
+                                         stream);
+                 if (TYPE_FIELD_BITSIZE (arr_type, 0) > 0)
+                   bitsize = TYPE_FIELD_BITSIZE (arr_type, 0);
+               }                 
+           }
+       }
+      else 
+       {
+         int i, i0;
+         for (i = i0 = ada_array_arity (type); i > 0; i -= 1)
+           fprintf_filtered (stream, "%s<>", i == i0 ? "" : ", ");
+       }
+    }
+
+  fprintf_filtered (stream, ") of ");
+  wrap_here ("");
+  ada_print_type (ada_array_element_type (type, n_indices), "", stream, 
+                 show == 0 ? 0 : show-1, level+1);
+  if (bitsize > 0)
+    fprintf_filtered (stream, " <packed: %d-bit elements>", bitsize);
+}
+
+/* Print the choices encoded by field FIELD_NUM of variant-part TYPE on
+   STREAM, assuming the VAL_TYPE is the type of the values. */
+
+static void
+print_choices (type, field_num, stream, val_type)
+     struct type *type;
+     int field_num;
+     struct ui_file *stream;
+     struct type *val_type;
+{
+  int have_output;
+  int p;
+  const char* name = TYPE_FIELD_NAME (type, field_num);
+
+  have_output = 0;
+
+  /* Skip over leading 'V': NOTE soon to be obsolete. */
+  if (name[0] == 'V')
+    {
+      if (! ada_scan_number (name, 1, NULL, &p))
+       goto Huh;
+    }
+  else
+    p = 0;
+
+  while (1)
+    {
+      switch (name[p]) 
+       {
+       default:
+         return;
+       case 'S':
+       case 'R':
+       case 'O':
+         if (have_output) 
+           fprintf_filtered (stream, " | ");
+         have_output = 1;
+         break;
+       }
+
+      switch (name[p]) 
+       {
+       case 'S':
+         {
+           LONGEST W;
+           if (! ada_scan_number (name, p + 1, &W, &p))
+             goto Huh;
+           ada_print_scalar (val_type, W, stream);
+           break;
+         }
+       case 'R':
+         {
+           LONGEST L, U;
+           if (! ada_scan_number (name, p + 1, &L, &p)
+               || name[p] != 'T'
+               || ! ada_scan_number (name, p + 1, &U, &p))
+             goto Huh;
+           ada_print_scalar (val_type, L, stream);
+           fprintf_filtered (stream, " .. ");
+           ada_print_scalar (val_type, U, stream);
+           break;
+         }
+       case 'O':
+         fprintf_filtered (stream, "others");
+         p += 1;
+         break;
+       }
+    }
+
+Huh:
+  fprintf_filtered (stream, "??");
+
+}
+
+/* Assuming that field FIELD_NUM of TYPE is a VARIANTS field whose 
+   discriminant is contained in OUTER_TYPE, print its variants on STREAM.  
+   LEVEL is the recursion
+   (indentation) level, in case any of the fields themselves have
+   nested structure, and SHOW is the number of levels of internal structure
+   to show (see ada_print_type). For this purpose, fields nested in a
+   variant part are taken to be at the same level as the fields
+   immediately outside the variant part. */
+
+static void
+print_variant_clauses (type, field_num, outer_type, stream, show, level)
+     struct type *type;
+     int field_num;
+     struct type *outer_type;
+     struct ui_file *stream;
+     int show;
+     int level;
+{
+  int i;
+  struct type *var_type;
+  struct type *discr_type;
+
+  var_type = TYPE_FIELD_TYPE (type, field_num);
+  discr_type = ada_variant_discrim_type (var_type, outer_type);
+
+  if (TYPE_CODE (var_type) == TYPE_CODE_PTR)
+    {
+      var_type = TYPE_TARGET_TYPE (var_type);
+      if (TYPE_FLAGS (var_type) & TYPE_FLAG_STUB) 
+       {
+         var_type = ada_find_parallel_type (var_type, "___XVU");
+         if (var_type == NULL)
+           return;
+       }
+    }
+
+  for (i = 0; i < TYPE_NFIELDS (var_type); i += 1) 
+    {
+      fprintf_filtered (stream, "\n%*swhen ", level + 4, "");
+      print_choices (var_type, i, stream, discr_type);
+      fprintf_filtered (stream, " =>");
+      if (print_record_field_types (TYPE_FIELD_TYPE (var_type, i), 
+                                   outer_type, stream, show, level+4) <= 0)
+       fprintf_filtered (stream, " null;");
+    }
+}
+
+/* Assuming that field FIELD_NUM of TYPE is a variant part whose 
+   discriminants are contained in OUTER_TYPE, print a description of it
+   on STREAM.  LEVEL is the recursion (indentation) level, in case any of 
+   the fields themselves have nested structure, and SHOW is the number of 
+   levels of internal structure to show (see ada_print_type). For this 
+   purpose, fields nested in a variant part are taken to be at the same 
+   level as the fields immediately outside the variant part. */
+
+static void
+print_variant_part (type, field_num, outer_type, stream, show, level)
+     struct type *type;
+     int field_num;
+     struct type *outer_type;
+     struct ui_file *stream;
+     int show;
+     int level;
+{
+  fprintf_filtered (stream, "\n%*scase %s is", level + 4, "",
+                   ada_variant_discrim_name 
+                     (TYPE_FIELD_TYPE (type, field_num)));
+  print_variant_clauses (type, field_num, outer_type, stream, show, level + 4);
+  fprintf_filtered (stream, "\n%*send case;", level + 4, "");
+}
+
+/* Print a description on STREAM of the fields in record type TYPE, whose 
+   discriminants are in OUTER_TYPE.  LEVEL is the recursion (indentation) 
+   level, in case any of the fields themselves have nested structure, 
+   and SHOW is the number of levels of internal structure to show 
+   (see ada_print_type).  Does not print parent type information of TYPE. 
+   Returns 0 if no fields printed, -1 for an incomplete type, else > 0. 
+   Prints each field beginning on a new line, but does not put a new line at
+   end. */
+
+static int
+print_record_field_types (type, outer_type, stream, show, level)
+     struct type *type;
+     struct type *outer_type;
+     struct ui_file *stream;
+     int show;
+     int level;
+{
+  int len, i, flds;
+
+  flds = 0;
+  len = TYPE_NFIELDS (type);
+
+  if (len == 0 && (TYPE_FLAGS (type) & TYPE_FLAG_STUB) != 0)
+    return -1;
+
+  for (i = 0; i < len; i += 1)
+    {
+      QUIT;
+
+      if (ada_is_parent_field (type, i) 
+         || ada_is_ignored_field (type, i))
+       ;
+      else if (ada_is_wrapper_field (type, i))
+       flds += print_record_field_types (TYPE_FIELD_TYPE (type, i), type,
+                                         stream, show, level);
+      else if (ada_is_variant_part (type, i)) 
+       {
+         print_variant_part (type, i, outer_type, stream, show, level);
+         flds = 1;
+       }
+      else
+       {
+         flds += 1;
+         fprintf_filtered (stream, "\n%*s", level + 4, "");
+         ada_print_type (TYPE_FIELD_TYPE (type, i),
+                         TYPE_FIELD_NAME (type, i),
+                         stream, show - 1, level + 4);
+         fprintf_filtered (stream, ";");
+       }
+    }
+
+  return flds;
+}
+
+/* Print record type TYPE on STREAM.  LEVEL is the recursion (indentation) 
+   level, in case the element type itself has nested structure, and SHOW is 
+   the number of levels of internal structure to show (see ada_print_type). */
+
+static void
+print_record_type (type0, stream, show, level)
+     struct type* type0;
+     struct ui_file* stream;
+     int show;
+     int level;
+{
+  struct type* parent_type;
+  struct type* type;
+  
+  type = type0;
+  if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
+    {
+      struct type* type1 = ada_find_parallel_type (type, "___XVE");
+      if (type1 != NULL)
+       type = type1;
+    }
+
+  parent_type = ada_parent_type (type);
+  if (ada_type_name (parent_type) != NULL) 
+    fprintf_filtered (stream, "new %s with ", 
+                     demangled_type_name (parent_type));
+  else if (parent_type == NULL && ada_is_tagged_type (type))
+    fprintf_filtered (stream, "tagged ");
+
+  fprintf_filtered (stream, "record");
+
+  if (show < 0)
+    fprintf_filtered (stream, " ... end record");
+  else
+    {
+      int flds;
+
+      flds = 0;
+      if (parent_type != NULL && ada_type_name (parent_type) == NULL)
+       flds += print_record_field_types (parent_type, parent_type, 
+                                         stream, show, level);
+      flds += print_record_field_types (type, type, stream, show, level);
+      
+      if (flds > 0)
+       fprintf_filtered (stream, "\n%*send record", level, "");
+      else if (flds < 0) 
+       fprintf_filtered (stream, " <incomplete type> end record");
+      else 
+       fprintf_filtered (stream, " null; end record");
+    }
+}
+
+/* Print the unchecked union type TYPE in something resembling Ada
+   format on STREAM. LEVEL is the recursion (indentation) level
+   in case the element type itself has nested structure, and SHOW is the
+   number of levels of internal structure to show (see ada_print_type). */
+static void
+print_unchecked_union_type (struct type* type, struct ui_file* stream, 
+                           int show, int level)
+{
+  fprintf_filtered (stream, "record (?) is");
+
+  if (show < 0)
+    fprintf_filtered (stream, " ... end record");
+  else if (TYPE_NFIELDS (type) == 0) 
+    fprintf_filtered (stream, " null; end record");
+  else
+    {
+      int i;
+
+      fprintf_filtered (stream, "\n%*scase ? is", 
+                       level+4, "");
+
+      for (i = 0; i < TYPE_NFIELDS (type); i += 1) 
+       {
+         fprintf_filtered (stream, "\n%*swhen ? =>\n%*s", level+8, "",
+                           level+12, "");
+         ada_print_type (TYPE_FIELD_TYPE (type, i),
+                         TYPE_FIELD_NAME (type, i),
+                         stream, show - 1, level + 12);
+         fprintf_filtered (stream, ";");
+       }
+
+      fprintf_filtered (stream, "\n%*send case;\n%*send record", 
+                       level+4, "", level, "");
+    }
+}
+  
+
+
+/* Print function or procedure type TYPE on STREAM.  Make it a header
+   for function or procedure NAME if NAME is not null. */
+
+static void
+print_func_type (type, stream, name)
+     struct type *type;
+     struct ui_file *stream;
+     char* name;
+{
+  int i, len = TYPE_NFIELDS (type);
+
+  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_VOID)
+    fprintf_filtered (stream, "procedure");
+  else
+    fprintf_filtered (stream, "function");
+
+  if (name != NULL && name[0] != '\0') 
+    fprintf_filtered (stream, " %s", name);
+
+  if (len > 0) 
+    {
+      fprintf_filtered (stream, " (");
+      for (i = 0; i < len; i += 1)
+       {
+         if (i > 0)
+           {
+             fputs_filtered ("; ", stream);
+             wrap_here ("    ");
+           }
+         fprintf_filtered (stream, "a%d: ", i+1);
+         ada_print_type (TYPE_FIELD_TYPE (type, i), "", stream, -1, 0);
+       }
+      fprintf_filtered (stream, ")");
+    }      
+
+  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_VOID)
+    {
+      fprintf_filtered (stream, " return ");
+      ada_print_type (TYPE_TARGET_TYPE (type), "", stream, 0, 0);
+    }
+}
+
+
+/* Print a description of a type TYPE0.
+   Output goes to STREAM (via stdio).
+   If VARSTRING is a non-empty string, print as an Ada variable/field
+       declaration.
+   SHOW+1 is the maximum number of levels of internal type structure 
+      to show (this applies to record types, enumerated types, and
+      array types).
+   SHOW is the number of levels of internal type structure to show
+      when there is a type name for the SHOWth deepest level (0th is 
+      outer level).
+   When SHOW<0, no inner structure is shown.
+   LEVEL indicates level of recursion (for nested definitions). */
+
+void
+ada_print_type (type0, varstring, stream, show, level)
+     struct type* type0;
+     char* varstring;
+     struct ui_file* stream;
+     int show;
+     int level;
+{
+  enum type_code code;
+  int demangled_args;
+  struct type* type = ada_completed_type (ada_get_base_type (type0));
+  char* type_name = demangled_type_name (type);
+  int is_var_decl = (varstring != NULL && varstring[0] != '\0');
+
+  if (type == NULL)
+    {
+      if (is_var_decl)
+       fprintf_filtered (stream, "%.*s: ",
+                         ada_name_prefix_len(varstring),
+                         varstring);
+      fprintf_filtered (stream, "<null type?>");
+      return;
+    }
+
+  if (show > 0)
+      CHECK_TYPEDEF (type);
+
+  if (is_var_decl && TYPE_CODE (type) != TYPE_CODE_FUNC)
+      fprintf_filtered (stream, "%.*s: ", 
+                       ada_name_prefix_len (varstring), varstring);
+
+  if (type_name != NULL && show <= 0)
+    {
+      fprintf_filtered (stream, "%.*s", 
+                       ada_name_prefix_len (type_name), type_name);
+      return;
+    }
+
+  if (ada_is_aligner_type (type))
+    ada_print_type (ada_aligned_type (type), "", stream, show, level);
+  else if (ada_is_packed_array_type (type))
+    print_array_type (type, stream, show, level);
+  else
+  switch (TYPE_CODE (type))
+    {
+    default:
+      fprintf_filtered (stream, "<");
+      c_print_type (type, "", stream, show, level);
+      fprintf_filtered (stream, ">");
+      break;
+    case TYPE_CODE_PTR:
+      fprintf_filtered (stream, "access ");
+      ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show,
+                     level);
+      break;
+    case TYPE_CODE_REF:
+      fprintf_filtered (stream, "<ref> ");
+      ada_print_type (TYPE_TARGET_TYPE (type), "", stream, show,
+                     level);
+      break;
+    case TYPE_CODE_ARRAY:
+      print_array_type (type, stream, show, level);
+      break;
+    case TYPE_CODE_INT:
+      if (ada_is_fixed_point_type (type))
+       print_fixed_point_type (type, stream);
+      else if (ada_is_vax_floating_type (type))
+       print_vax_floating_point_type (type, stream);
+      else
+       {
+         char* name = ada_type_name (type);
+         if (! ada_is_range_type_name (name))
+           fprintf_filtered (stream, "<%d-byte integer>", TYPE_LENGTH (type));
+         else
+           {
+             fprintf_filtered (stream, "range ");
+             print_range_type_named (name, stream);
+           }
+       }
+      break;
+    case TYPE_CODE_RANGE:
+      if (ada_is_fixed_point_type (type))
+       print_fixed_point_type (type, stream);
+      else if (ada_is_vax_floating_type (type))
+       print_vax_floating_point_type (type, stream);
+      else if (ada_is_modular_type (type))
+       fprintf_filtered (stream, "mod %ld", (long) ada_modulus (type));
+      else
+       {
+         fprintf_filtered (stream, "range ");
+         print_range (type, stream);
+       }
+      break;
+    case TYPE_CODE_FLT:
+      fprintf_filtered (stream, "<%d-byte float>", TYPE_LENGTH (type));
+      break;
+    case TYPE_CODE_ENUM:
+      if (show < 0)
+       fprintf_filtered (stream, "(...)");
+      else
+       print_enum_type (type, stream);
+      break;
+    case TYPE_CODE_STRUCT:
+      if (ada_is_array_descriptor (type))
+       print_array_type (type, stream, show, level);
+      else if (ada_is_bogus_array_descriptor (type))
+       fprintf_filtered (stream, "array (?) of ? (<mal-formed descriptor>)");
+      else
+       print_record_type (type, stream, show, level);
+      break;
+    case TYPE_CODE_UNION:
+      print_unchecked_union_type (type, stream, show, level);
+      break;
+    case TYPE_CODE_FUNC:
+      print_func_type (type, stream, varstring);
+      break;
+    }
+}
diff --git a/gdb/ada-valprint.c b/gdb/ada-valprint.c
new file mode 100644 (file)
index 0000000..6db18eb
--- /dev/null
@@ -0,0 +1,1058 @@
+/* Support for printing Ada values for GDB, the GNU debugger.  
+   Copyright 1986, 1988, 1989, 1991, 1992, 1993, 1994, 1997, 2001
+             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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#include <ctype.h>
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "language.h"
+#include "annotate.h"
+#include "ada-lang.h"
+#include "c-lang.h"
+
+/* Encapsulates arguments to ada_val_print. */
+struct ada_val_print_args {
+  struct type* type;
+  char* valaddr0;
+  int embedded_offset;
+  CORE_ADDR address;
+  struct ui_file *stream;
+  int format;
+  int deref_ref;
+  int recurse;
+  enum val_prettyprint pretty;
+};
+
+extern int inspect_it;
+extern unsigned int repeat_count_threshold;
+
+static void print_record (struct type*, char*, struct ui_file*, int,
+                         int, enum val_prettyprint);
+
+static int print_field_values (struct type*, char*, struct ui_file*, 
+                              int, int, enum val_prettyprint,
+                              int, struct type*, char*);
+
+static int print_variant_part (struct type*, int, char*, 
+                              struct ui_file*, int, int, enum val_prettyprint,
+                              int, struct type*, char*);
+
+static void
+val_print_packed_array_elements (struct type*, char *valaddr, int,
+                                struct ui_file*, int, int, 
+                                enum val_prettyprint);
+
+static void adjust_type_signedness (struct type*);
+
+static int ada_val_print_stub (PTR args0);
+
+static int
+ada_val_print_1 (struct type*, char*, int, CORE_ADDR, struct ui_file*,
+                int, int, int, enum val_prettyprint);
+\f
+
+/* Make TYPE unsigned if its range of values includes no negatives. */
+static void 
+adjust_type_signedness (type)
+     struct type* type;
+{
+  if (type != NULL && TYPE_CODE (type) == TYPE_CODE_RANGE 
+      && TYPE_LOW_BOUND (type) >= 0)
+    TYPE_FLAGS (type) |= TYPE_FLAG_UNSIGNED;
+}      
+
+/* Assuming TYPE is a simple array type, prints its lower bound on STREAM,
+   if non-standard (i.e., other than 1 for numbers, other than lower bound
+   of index type for enumerated type). Returns 1 if something printed, 
+   otherwise 0. */
+
+static int 
+print_optional_low_bound (stream, type)
+     struct ui_file *stream;
+     struct type *type;
+{
+  struct type *index_type;
+  long low_bound;
+
+  index_type = TYPE_INDEX_TYPE (type);
+  low_bound = 0;
+
+  if (index_type == NULL)
+    return 0;
+  if (TYPE_CODE (index_type) == TYPE_CODE_RANGE) 
+    {
+      low_bound = TYPE_LOW_BOUND (index_type);
+      index_type = TYPE_TARGET_TYPE (index_type);
+    }
+  else
+    return 0;
+      
+  switch (TYPE_CODE (index_type)) {
+  case TYPE_CODE_ENUM:
+    if (low_bound == TYPE_FIELD_BITPOS (index_type, 0))
+      return 0;
+    break;
+  case TYPE_CODE_UNDEF:
+    index_type = builtin_type_long;
+    /* FALL THROUGH */
+  default:
+    if (low_bound == 1)
+      return 0;
+    break;
+  }
+
+  ada_print_scalar (index_type, (LONGEST) low_bound, stream);
+  fprintf_filtered (stream, " => ");
+  return 1;
+}
+
+/*  Version of val_print_array_elements for GNAT-style packed arrays.
+    Prints elements of packed array of type TYPE at bit offset
+    BITOFFSET from VALADDR on STREAM.  Formats according to FORMAT and
+    separates with commas. RECURSE is the recursion (nesting) level.
+    If PRETTY, uses "prettier" format. TYPE must have been decoded (as
+    by ada_coerce_to_simple_array).  */ 
+
+static void
+val_print_packed_array_elements (type, valaddr, bitoffset, stream, format, 
+                                recurse, pretty)
+     struct type *type;
+     char *valaddr;
+     int bitoffset;
+     struct ui_file *stream;
+     int format;
+     int recurse;
+     enum val_prettyprint pretty;
+{
+  unsigned int i;
+  unsigned int things_printed = 0;
+  unsigned len;
+  struct type *elttype;
+  unsigned eltlen;
+  /* Position of the array element we are examining to see
+     whether it is repeated.  */
+  unsigned int rep1;
+  /* Number of repetitions we have detected so far.  */
+  unsigned int reps;
+  unsigned long bitsize = TYPE_FIELD_BITSIZE (type, 0);
+  struct value* mark = value_mark ();
+      
+  elttype = TYPE_TARGET_TYPE (type);
+  eltlen = TYPE_LENGTH (check_typedef (elttype));
+
+  {
+    LONGEST low, high;
+    if (get_discrete_bounds (TYPE_FIELD_TYPE (type, 0), &low, &high) < 0)
+      len = 1;
+    else
+      len = high - low + 1;
+  }
+
+  i = 0;
+  annotate_array_section_begin (i, elttype);
+
+  while (i < len && things_printed < print_max)
+    {
+      struct value *v0, *v1;
+      int i0;
+
+      if (i != 0)
+       {
+         if (prettyprint_arrays)
+           {
+             fprintf_filtered (stream, ",\n");
+             print_spaces_filtered (2 + 2 * recurse, stream);
+           }
+         else
+           {
+             fprintf_filtered (stream, ", ");
+           }
+       }
+      wrap_here (n_spaces (2 + 2 * recurse));
+
+      i0 = i;
+      v0 = ada_value_primitive_packed_val (NULL, valaddr, 
+                                          (i0 * bitsize) / HOST_CHAR_BIT,
+                                          (i0 * bitsize) % HOST_CHAR_BIT,
+                                          bitsize, elttype);
+      while (1)
+       {
+         i += 1;
+         if (i >= len)
+           break;
+         v1 = ada_value_primitive_packed_val (NULL, valaddr, 
+                                              (i * bitsize) / HOST_CHAR_BIT,
+                                              (i * bitsize) % HOST_CHAR_BIT,
+                                              bitsize, elttype);
+         if (memcmp (VALUE_CONTENTS (v0), VALUE_CONTENTS (v1), eltlen) 
+             != 0)
+           break;
+       }
+
+      if (i - i0 > repeat_count_threshold)
+       {
+         val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format,
+                    0, recurse + 1, pretty);
+         annotate_elt_rep (i - i0);
+         fprintf_filtered (stream, " <repeats %u times>", i - i0);
+         annotate_elt_rep_end ();
+
+       }
+      else
+       {
+         int j;
+         for (j = i0; j < i; j += 1)
+           {
+             if (j > i0) 
+               {
+                 if (prettyprint_arrays)
+                   {
+                     fprintf_filtered (stream, ",\n");
+                     print_spaces_filtered (2 + 2 * recurse, stream);
+                   }
+                 else
+                   {
+                     fprintf_filtered (stream, ", ");
+                   }
+                 wrap_here (n_spaces (2 + 2 * recurse));
+               }
+             val_print (elttype, VALUE_CONTENTS (v0), 0, 0, stream, format,
+                        0, recurse + 1, pretty);
+             annotate_elt ();
+           }
+       }
+      things_printed += i - i0;
+    }
+  annotate_array_section_end ();
+  if (i < len)
+    {
+      fprintf_filtered (stream, "...");
+    }
+
+  value_free_to_mark (mark);
+}
+
+static struct type*
+printable_val_type (type, valaddr)
+     struct type* type;
+     char* valaddr;
+{
+  return ada_to_fixed_type (ada_aligned_type (type), valaddr, 0, NULL);
+}
+
+/* Print the character C on STREAM as part of the contents of a literal
+   string whose delimiter is QUOTER.  TYPE_LEN is the length in bytes
+   (1 or 2) of the character. */
+
+void
+ada_emit_char (c, stream, quoter, type_len)
+     int c;
+     struct ui_file *stream;
+     int quoter;
+     int type_len;
+{
+  if (type_len != 2)
+    type_len = 1;
+
+  c &= (1 << (type_len * TARGET_CHAR_BIT)) - 1;
+
+  if (isascii (c) && isprint (c))
+    {
+      if (c == quoter && c == '"')
+       fprintf_filtered (stream, "[\"%c\"]", quoter);
+      else
+       fprintf_filtered (stream, "%c", c);
+    }
+  else
+    fprintf_filtered (stream, "[\"%0*x\"]", type_len*2, c);
+}
+
+/* Character #I of STRING, given that TYPE_LEN is the size in bytes (1
+   or 2) of a character. */
+
+static int
+char_at (string, i, type_len)
+     char* string;
+     int i;
+     int type_len;
+{
+  if (type_len == 1)
+    return string[i];
+  else 
+    return (int) extract_unsigned_integer (string + 2*i, 2);
+}
+
+void
+ada_printchar (c, stream)
+     int c;
+     struct ui_file *stream;
+{
+  fputs_filtered ("'", stream);
+  ada_emit_char (c, stream, '\'', 1);
+  fputs_filtered ("'", stream);
+}
+
+/* [From print_type_scalar in typeprint.c].   Print VAL on STREAM in a
+   form appropriate for TYPE. */
+
+void
+ada_print_scalar (type, val, stream)
+     struct type *type;
+     LONGEST val;
+     struct ui_file *stream;
+{
+  unsigned int i;
+  unsigned len;
+
+  CHECK_TYPEDEF (type);
+
+  switch (TYPE_CODE (type))
+    {
+
+    case TYPE_CODE_ENUM:
+      len = TYPE_NFIELDS (type);
+      for (i = 0; i < len; i++)
+       {
+         if (TYPE_FIELD_BITPOS (type, i) == val)
+           {
+             break;
+           }
+       }
+      if (i < len)
+       {
+         fputs_filtered (ada_enum_name (TYPE_FIELD_NAME (type, i)), stream);
+       }
+      else
+       {
+         print_longest (stream, 'd', 0, val);
+       }
+      break;
+
+    case TYPE_CODE_INT:
+      print_longest (stream, TYPE_UNSIGNED (type) ? 'u' : 'd', 0, val);
+      break;
+
+    case TYPE_CODE_CHAR:
+      LA_PRINT_CHAR ((unsigned char) val, stream);
+      break;
+
+    case TYPE_CODE_BOOL:
+      fprintf_filtered (stream, val ? "true" : "false");
+      break;
+
+    case TYPE_CODE_RANGE:
+      ada_print_scalar (TYPE_TARGET_TYPE (type), val, stream);
+      return;
+
+    case TYPE_CODE_UNDEF:
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_ARRAY:
+    case TYPE_CODE_STRUCT:
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_VOID:
+    case TYPE_CODE_SET:
+    case TYPE_CODE_STRING:
+    case TYPE_CODE_ERROR:
+    case TYPE_CODE_MEMBER:
+    case TYPE_CODE_METHOD:
+    case TYPE_CODE_REF:
+      warning ("internal error: unhandled type in ada_print_scalar");
+      break;
+
+    default:
+      error ("Invalid type code in symbol table.");
+    }
+  gdb_flush (stream);
+}
+
+/* Print the character string STRING, printing at most LENGTH characters.
+   Printing stops early if the number hits print_max; repeat counts
+   are printed as appropriate.  Print ellipses at the end if we
+   had to stop before printing LENGTH characters, or if
+   FORCE_ELLIPSES.   TYPE_LEN is the length (1 or 2) of the character type.
+ */
+
+static void
+printstr (stream, string, length, force_ellipses, type_len)
+     struct ui_file *stream;
+     char *string;
+     unsigned int length;
+     int force_ellipses;
+     int type_len;
+{
+  unsigned int i;
+  unsigned int things_printed = 0;
+  int in_quotes = 0;
+  int need_comma = 0;
+
+  if (length == 0)
+    {
+      fputs_filtered ("\"\"", stream);
+      return;
+    }
+
+  for (i = 0; i < length && things_printed < print_max; i += 1)
+    {
+      /* Position of the character we are examining
+        to see whether it is repeated.  */
+      unsigned int rep1;
+      /* Number of repetitions we have detected so far.  */
+      unsigned int reps;
+
+      QUIT;
+
+      if (need_comma)
+       {
+         fputs_filtered (", ", stream);
+         need_comma = 0;
+       }
+
+      rep1 = i + 1;
+      reps = 1;
+      while (rep1 < length && 
+            char_at(string, rep1, type_len) == char_at (string, i, type_len))
+       {
+         rep1 += 1;
+         reps += 1;
+       }
+
+      if (reps > repeat_count_threshold)
+       {
+         if (in_quotes)
+           {
+             if (inspect_it)
+               fputs_filtered ("\\\", ", stream);
+             else
+               fputs_filtered ("\", ", stream);
+             in_quotes = 0;
+           }
+         fputs_filtered ("'", stream);
+         ada_emit_char (char_at (string, i, type_len), stream, '\'', type_len);
+         fputs_filtered ("'", stream);
+         fprintf_filtered (stream, " <repeats %u times>", reps);
+         i = rep1 - 1;
+         things_printed += repeat_count_threshold;
+         need_comma = 1;
+       }
+      else
+       {
+         if (!in_quotes)
+           {
+             if (inspect_it)
+               fputs_filtered ("\\\"", stream);
+             else
+               fputs_filtered ("\"", stream);
+             in_quotes = 1;
+           }
+         ada_emit_char (char_at (string, i, type_len), stream, '"',
+                        type_len);
+         things_printed += 1;
+       }
+    }
+
+  /* Terminate the quotes if necessary.  */
+  if (in_quotes)
+    {
+      if (inspect_it)
+       fputs_filtered ("\\\"", stream);
+      else
+       fputs_filtered ("\"", stream);
+    }
+
+  if (force_ellipses || i < length)
+    fputs_filtered ("...", stream);
+}
+
+void
+ada_printstr (stream, string, length, force_ellipses, width)
+     struct ui_file *stream;
+     char *string;
+     unsigned int length;
+     int force_ellipses;
+     int width;
+{
+  printstr (stream, string, length, force_ellipses, width);
+}
+
+
+/* Print data of type TYPE located at VALADDR (within GDB), which came from
+   the inferior at address ADDRESS, onto stdio stream STREAM according to
+   FORMAT (a letter as for the printf % codes or 0 for natural format).  
+   The data at VALADDR is in target byte order.
+
+   If the data is printed as a string, returns the number of string characters
+   printed.
+
+   If DEREF_REF is nonzero, then dereference references, otherwise just print
+   them like pointers.
+
+   RECURSE indicates the amount of indentation to supply before
+   continuation lines; this amount is roughly twice the value of RECURSE.
+
+   When PRETTY is non-zero, prints record fields on separate lines.
+   (For some reason, the current version of gdb instead uses a global
+   variable---prettyprint_arrays--- to causes a similar effect on
+   arrays.)  */
+
+int
+ada_val_print (type, valaddr0, embedded_offset, address, stream,
+              format, deref_ref, recurse, pretty)
+     struct type* type;
+     char* valaddr0;
+     int embedded_offset;
+     CORE_ADDR address;
+     struct ui_file *stream;
+     int format;
+     int deref_ref;
+     int recurse;
+     enum val_prettyprint pretty;
+{
+  struct ada_val_print_args args;
+  args.type = type; args.valaddr0 = valaddr0; 
+  args.embedded_offset = embedded_offset;
+  args.address = address;
+  args.stream = stream;
+  args.format = format;
+  args.deref_ref = deref_ref;
+  args.recurse = recurse;
+  args.pretty = pretty;
+
+  return catch_errors (ada_val_print_stub, &args, NULL, RETURN_MASK_ALL);
+}
+
+/* Helper for ada_val_print; used as argument to catch_errors to
+   unmarshal the arguments to ada_val_print_1, which does the work. */
+static int
+ada_val_print_stub (PTR args0)
+{
+  struct ada_val_print_args* argsp = (struct ada_val_print_args*) args0;
+  return ada_val_print_1 (argsp->type, argsp->valaddr0, argsp->embedded_offset,
+                         argsp->address, argsp->stream, argsp->format,
+                         argsp->deref_ref, argsp->recurse,
+                         argsp->pretty);
+}
+
+/* See the comment on ada_val_print.  This function differs in that it
+ * does not catch evaluation errors (leaving that to ada_val_print). */
+
+static int
+ada_val_print_1 (type, valaddr0, embedded_offset, address, stream,
+                format, deref_ref, recurse, pretty)
+     struct type* type;
+     char* valaddr0;
+     int embedded_offset;
+     CORE_ADDR address;
+     struct ui_file *stream;
+     int format;
+     int deref_ref;
+     int recurse;
+     enum val_prettyprint pretty;
+{
+  unsigned int len;
+  int i;
+  struct type *elttype;
+  unsigned int eltlen;
+  LONGEST val;
+  CORE_ADDR addr;
+  char* valaddr = valaddr0 + embedded_offset;
+
+  CHECK_TYPEDEF (type);
+
+  if (ada_is_array_descriptor (type) || ada_is_packed_array_type (type))
+    {
+      int retn;
+      struct value* mark = value_mark ();
+      struct value* val;
+      val = value_from_contents_and_address (type, valaddr, address);
+      val = ada_coerce_to_simple_array_ptr (val);
+      if (val == NULL)
+       {
+         fprintf_filtered (stream, "(null)");
+         retn = 0;
+       }
+      else
+       retn = ada_val_print_1 (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
+                               VALUE_ADDRESS (val), stream, format, 
+                               deref_ref, recurse, pretty);
+      value_free_to_mark (mark);
+      return retn;
+    }
+
+  valaddr = ada_aligned_value_addr (type, valaddr);
+  embedded_offset -= valaddr - valaddr0 - embedded_offset;
+  type = printable_val_type (type, valaddr);
+
+  switch (TYPE_CODE (type))
+    {
+    default:
+      return c_val_print (type, valaddr0, embedded_offset, address, stream, 
+                         format, deref_ref, recurse, pretty);
+
+    case TYPE_CODE_INT:
+    case TYPE_CODE_RANGE:
+      if (ada_is_fixed_point_type (type))
+       {
+         LONGEST v = unpack_long (type, valaddr);
+         int len = TYPE_LENGTH (type);
+
+         fprintf_filtered (stream, len < 4 ? "%.11g" : "%.17g",
+                           (double) ada_fixed_to_float (type, v));
+         return 0;
+       }
+      else if (ada_is_vax_floating_type (type))
+       {
+         struct value* val = 
+           value_from_contents_and_address (type, valaddr, address);
+         struct value* func = ada_vax_float_print_function (type);
+         if (func != 0)
+           {
+             static struct type* parray_of_char = NULL;
+             struct value* printable_val;
+
+             if (parray_of_char == NULL) 
+               parray_of_char = 
+                 make_pointer_type 
+                   (create_array_type 
+                     (NULL, builtin_type_char,
+                      create_range_type (NULL, builtin_type_int, 0, 32)),
+                    NULL);
+
+             printable_val = 
+               value_ind (value_cast (parray_of_char,
+                                      call_function_by_hand (func, 1, &val)));
+             
+             fprintf_filtered (stream, "%s", VALUE_CONTENTS (printable_val));
+             return 0;
+           }
+         /* No special printing function.  Do as best we can. */
+       }
+      else if (TYPE_CODE (type) == TYPE_CODE_RANGE)
+       {
+         struct type* target_type = TYPE_TARGET_TYPE (type);
+         if (TYPE_LENGTH (type) != TYPE_LENGTH (target_type))
+           {
+             /* Obscure case of range type that has different length from
+                its base type.  Perform a conversion, or we will get a
+                nonsense value.  Actually, we could use the same
+                code regardless of lengths; I'm just avoiding a cast. */
+             struct value* v = 
+               value_cast (target_type, 
+                           value_from_contents_and_address (type, valaddr, 0));
+             return ada_val_print_1 (target_type, VALUE_CONTENTS (v), 0, 0,
+                                     stream, format, 0, recurse + 1, pretty);
+           }
+         else
+           return ada_val_print_1 (TYPE_TARGET_TYPE (type), 
+                                   valaddr0, embedded_offset,
+                                   address,  stream, format, deref_ref, 
+                                   recurse, pretty);
+       }
+      else 
+       {
+         format = format ? format : output_format;
+         if (format)
+           {
+             print_scalar_formatted (valaddr, type, format, 0, stream);
+           }
+         else
+           {
+             val_print_type_code_int (type, valaddr, stream);
+             if (ada_is_character_type (type))
+               {
+                 fputs_filtered (" ", stream);
+                 ada_printchar ((unsigned char) unpack_long (type, valaddr),
+                                stream);
+               }
+           }
+         return 0;
+       }
+
+    case TYPE_CODE_ENUM:
+      if (format)
+       {
+         print_scalar_formatted (valaddr, type, format, 0, stream);
+         break;
+       }
+      len = TYPE_NFIELDS (type);
+      val = unpack_long (type, valaddr);
+      for (i = 0; i < len; i++)
+       {
+         QUIT;
+         if (val == TYPE_FIELD_BITPOS (type, i))
+           {
+             break;
+           }
+       }
+      if (i < len)
+       {
+         const char* name = ada_enum_name (TYPE_FIELD_NAME (type, i));
+         if (name[0] == '\'') 
+           fprintf_filtered (stream, "%ld %s", (long) val, name);
+         else
+           fputs_filtered (name, stream);
+       }
+      else
+       {
+         print_longest (stream, 'd', 0, val);
+       }
+      break;
+      
+    case TYPE_CODE_UNION:
+    case TYPE_CODE_STRUCT:
+      if (ada_is_bogus_array_descriptor (type))
+       {
+         fprintf_filtered (stream, "(...?)");
+         return 0;
+       }                             
+      else
+       {
+         print_record (type, valaddr, stream, format,
+                       recurse, pretty);
+         return 0;
+       }
+
+    case TYPE_CODE_ARRAY:
+      if (TYPE_LENGTH (type) > 0 && TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
+       {
+         elttype = TYPE_TARGET_TYPE (type);
+         eltlen = TYPE_LENGTH (elttype);
+         len = TYPE_LENGTH (type) / eltlen;
+             
+         /* For an array of chars, print with string syntax.  */
+         if (ada_is_string_type (type) 
+             && (format == 0 || format == 's'))
+           {
+             if (prettyprint_arrays)
+               {
+                 print_spaces_filtered (2 + 2 * recurse, stream);
+               }
+             /* If requested, look for the first null char and only print
+                elements up to it.  */
+             if (stop_print_at_null)
+               {
+                 int temp_len;
+                 
+                 /* Look for a NULL char. */
+                 for (temp_len = 0;
+                      temp_len < len && temp_len < print_max
+                      && char_at (valaddr, temp_len, eltlen) != 0;
+                      temp_len += 1);
+                 len = temp_len;
+               }
+             
+             printstr (stream, valaddr, len, 0, eltlen);
+           }
+         else
+           {
+             len = 0;
+             fprintf_filtered (stream, "(");
+             print_optional_low_bound (stream, type);
+             if (TYPE_FIELD_BITSIZE (type, 0) > 0) 
+               val_print_packed_array_elements (type, valaddr, 0, stream,
+                                                format, recurse,
+                                                pretty);
+             else
+               val_print_array_elements (type, valaddr, address, stream,
+                                         format, deref_ref, recurse,
+                                         pretty, 0);
+             fprintf_filtered (stream, ")");
+           }
+         gdb_flush (stream);
+         return len;
+       }
+
+    case TYPE_CODE_REF:
+      elttype = check_typedef (TYPE_TARGET_TYPE (type));
+      if (addressprint)
+        {
+         fprintf_filtered (stream, "@");
+         print_address_numeric
+           (extract_address (valaddr,
+                             TARGET_PTR_BIT / HOST_CHAR_BIT), 1, stream);
+         if (deref_ref)
+           fputs_filtered (": ", stream);
+        }
+      /* De-reference the reference */
+      if (deref_ref)
+       {
+         if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF)
+           {
+             LONGEST deref_val_int = (LONGEST) 
+               unpack_pointer (lookup_pointer_type (builtin_type_void), 
+                               valaddr);
+             if (deref_val_int != 0) 
+               {
+                 struct value* deref_val =
+                   ada_value_ind (value_from_longest 
+                                  (lookup_pointer_type (elttype), 
+                                   deref_val_int));
+                 val_print (VALUE_TYPE (deref_val),
+                            VALUE_CONTENTS (deref_val), 0,
+                            VALUE_ADDRESS (deref_val), stream, format,
+                            deref_ref, recurse + 1, pretty);
+               }
+             else
+               fputs_filtered ("(null)", stream);
+           }
+         else
+           fputs_filtered ("???", stream);
+       }
+      break;
+    }
+  return 0;
+}
+
+static int
+print_variant_part (type, field_num, valaddr, 
+                   stream, format, recurse, pretty, comma_needed,
+                   outer_type, outer_valaddr)
+     struct type *type;
+     int field_num;
+     char *valaddr;
+     struct ui_file *stream;
+     int format;
+     int recurse;
+     enum val_prettyprint pretty;
+     int comma_needed;
+     struct type *outer_type;
+     char *outer_valaddr;
+{
+  struct type *var_type = TYPE_FIELD_TYPE (type, field_num);
+  int which = 
+    ada_which_variant_applies (var_type, outer_type, outer_valaddr);
+
+  if (which < 0)
+    return 0;
+  else
+    return print_field_values 
+      (TYPE_FIELD_TYPE (var_type, which),
+       valaddr + TYPE_FIELD_BITPOS (type, field_num) / HOST_CHAR_BIT
+       + TYPE_FIELD_BITPOS (var_type, which) / HOST_CHAR_BIT,
+       stream, format, recurse, pretty,
+       comma_needed, outer_type, outer_valaddr);
+}
+
+int
+ada_value_print (val0, stream, format, pretty)
+     struct value* val0;
+     struct ui_file *stream;
+     int format;
+     enum val_prettyprint pretty;
+{
+  char* valaddr = VALUE_CONTENTS (val0);
+  CORE_ADDR address = VALUE_ADDRESS (val0) + VALUE_OFFSET (val0);
+  struct type* type = 
+    ada_to_fixed_type (VALUE_TYPE (val0), valaddr, address, NULL);
+  struct value* val = value_from_contents_and_address (type, valaddr, address);
+
+  /* If it is a pointer, indicate what it points to. */
+  if (TYPE_CODE (type) == TYPE_CODE_PTR ||
+      TYPE_CODE (type) == TYPE_CODE_REF)
+    {
+      /* Hack:  remove (char *) for char strings.  Their
+        type is indicated by the quoted string anyway. */
+      if (TYPE_CODE (type) == TYPE_CODE_PTR &&
+         TYPE_LENGTH (TYPE_TARGET_TYPE (type)) == sizeof(char) &&
+         TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_INT &&
+         !TYPE_UNSIGNED (TYPE_TARGET_TYPE (type)))
+       {
+         /* Print nothing */
+       }
+      else
+       {
+         fprintf_filtered (stream, "(");
+         type_print (type, "", stream, -1);
+         fprintf_filtered (stream, ") ");
+       }
+    }
+  else if (ada_is_array_descriptor (type)) 
+    {
+      fprintf_filtered (stream, "(");
+      type_print (type, "", stream, -1);
+      fprintf_filtered (stream, ") ");
+    }
+  else if (ada_is_bogus_array_descriptor (type))
+    {
+      fprintf_filtered (stream, "(");
+      type_print (type, "", stream, -1);
+      fprintf_filtered (stream, ") (...?)");
+      return 0;
+    }
+  return (val_print (type, VALUE_CONTENTS (val), 0, address, 
+                    stream, format, 1, 0, pretty));
+}
+static void
+print_record (type, valaddr, stream, format, recurse, pretty)
+     struct type *type;
+     char *valaddr;
+     struct ui_file *stream;
+     int format;
+     int recurse;
+     enum val_prettyprint pretty;
+{
+  CHECK_TYPEDEF (type);
+
+  fprintf_filtered (stream, "(");
+
+  if (print_field_values (type, valaddr, stream, format, recurse, pretty,
+                         0, type, valaddr) != 0
+      && pretty)
+    {
+      fprintf_filtered (stream, "\n");
+      print_spaces_filtered (2 * recurse, stream);
+    }
+
+  fprintf_filtered (stream, ")");
+}
+
+/* Print out fields of value at VALADDR having structure type TYPE.
+  
+   TYPE, VALADDR, STREAM, FORMAT, RECURSE, and PRETTY have the
+   same meanings as in ada_print_value and ada_val_print.   
+
+   OUTER_TYPE and OUTER_VALADDR give type and address of enclosing record
+   (used to get discriminant values when printing variant parts).
+
+   COMMA_NEEDED is 1 if fields have been printed at the current recursion 
+   level, so that a comma is needed before any field printed by this
+   call. 
+
+   Returns 1 if COMMA_NEEDED or any fields were printed. */
+
+static int
+print_field_values (type, valaddr, stream, format, recurse, pretty, 
+                   comma_needed, outer_type, outer_valaddr)
+     struct type *type;
+     char *valaddr;
+     struct ui_file *stream;
+     int format;
+     int recurse;
+     enum val_prettyprint pretty;
+     int comma_needed;
+     struct type *outer_type;
+     char *outer_valaddr;
+{
+  int i, len;
+
+  len = TYPE_NFIELDS (type);
+
+  for (i = 0; i < len; i += 1)
+    {
+      if (ada_is_ignored_field (type, i))
+         continue;
+
+      if (ada_is_wrapper_field (type, i))
+       {
+         comma_needed = 
+           print_field_values (TYPE_FIELD_TYPE (type, i),
+                               valaddr 
+                               + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT,
+                               stream, format, recurse, pretty,
+                               comma_needed, type, valaddr);
+         continue;
+       }
+      else if (ada_is_variant_part (type, i))
+       {
+         comma_needed =
+           print_variant_part (type, i, valaddr,
+                               stream, format, recurse, pretty, comma_needed,
+                               outer_type, outer_valaddr);
+         continue;
+       }
+
+      if (comma_needed)
+       fprintf_filtered (stream, ", ");
+      comma_needed = 1;
+
+      if (pretty)
+       {
+         fprintf_filtered (stream, "\n");
+         print_spaces_filtered (2 + 2 * recurse, stream);
+       }
+      else 
+       {
+         wrap_here (n_spaces (2 + 2 * recurse));
+       }
+      if (inspect_it)
+       {
+         if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR)
+           fputs_filtered ("\"( ptr \"", stream);
+         else
+           fputs_filtered ("\"( nodef \"", stream);
+         fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+                                  language_cplus, DMGL_NO_OPTS);
+         fputs_filtered ("\" \"", stream);
+         fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
+                                  language_cplus, DMGL_NO_OPTS);
+         fputs_filtered ("\") \"", stream);
+       }
+      else
+       {
+         annotate_field_begin (TYPE_FIELD_TYPE (type, i));
+         fprintf_filtered (stream, "%.*s", 
+                           ada_name_prefix_len (TYPE_FIELD_NAME (type, i)),
+                           TYPE_FIELD_NAME (type, i));
+         annotate_field_name_end ();
+         fputs_filtered (" => ", stream);
+         annotate_field_value ();
+       }
+
+      if (TYPE_FIELD_PACKED (type, i))
+       {
+         struct value* v;
+
+         /* Bitfields require special handling, especially due to byte
+            order problems.  */
+         if (TYPE_CPLUS_SPECIFIC (type) != NULL
+             && TYPE_FIELD_IGNORE (type, i))
+           {
+             fputs_filtered ("<optimized out or zero length>", stream);
+           }
+         else
+           {
+             int bit_pos = TYPE_FIELD_BITPOS (type, i);
+             int bit_size = TYPE_FIELD_BITSIZE (type, i);
+      
+             adjust_type_signedness (TYPE_FIELD_TYPE (type, i));
+             v = ada_value_primitive_packed_val (NULL, valaddr,
+                                                 bit_pos / HOST_CHAR_BIT,
+                                                 bit_pos % HOST_CHAR_BIT,
+                                                 bit_size, 
+                                                 TYPE_FIELD_TYPE (type, i));
+             val_print (TYPE_FIELD_TYPE(type, i), VALUE_CONTENTS (v), 0, 0,
+                        stream, format, 0, recurse + 1, pretty);
+           }
+       }
+      else
+         ada_val_print (TYPE_FIELD_TYPE (type, i), 
+                        valaddr + TYPE_FIELD_BITPOS (type, i) / HOST_CHAR_BIT,
+                        0, 0, stream, format, 0, recurse + 1, pretty);
+      annotate_field_end ();
+    }
+
+  return comma_needed;
+}
diff --git a/gdb/config/arm/nbsdaout.mh b/gdb/config/arm/nbsdaout.mh
new file mode 100644 (file)
index 0000000..100e40b
--- /dev/null
@@ -0,0 +1,5 @@
+# Host ARM running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o armnbsd-nat.o \
+       solib-sunos.o
+XM_FILE=xm-nbsd.h
+NAT_FILE=nm-nbsdaout.h
diff --git a/gdb/config/arm/nbsdelf.mh b/gdb/config/arm/nbsdelf.mh
new file mode 100644 (file)
index 0000000..481d5cc
--- /dev/null
@@ -0,0 +1,4 @@
+# Host ARM running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o armnbsd-nat.o
+XM_FILE=xm-nbsd.h
+NAT_FILE=nm-nbsd.h
diff --git a/gdb/config/arm/nm-nbsdaout.h b/gdb/config/arm/nm-nbsdaout.h
new file mode 100644 (file)
index 0000000..3f7fee9
--- /dev/null
@@ -0,0 +1,29 @@
+/* Native-dependent definitions for ARM running NetBSD, for GDB.
+   Copyright 1986, 1987, 1989, 1992, 1994, 1999 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "arm/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* NM_NBSDAOUT_H */
diff --git a/gdb/config/i386/nbsdaout.mh b/gdb/config/i386/nbsdaout.mh
new file mode 100644 (file)
index 0000000..e52f38a
--- /dev/null
@@ -0,0 +1,6 @@
+# Host: Intel 386 running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o i386bsd-nat.o \
+       solib.o solib-sunos.o
+
+XM_FILE= xm-nbsd.h
+NAT_FILE= nm-nbsdaout.h
diff --git a/gdb/config/i386/nbsdaout.mt b/gdb/config/i386/nbsdaout.mt
new file mode 100644 (file)
index 0000000..aa88957
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: Intel 386 running NetBSD
+TDEPFILES= i386-tdep.o i387-tdep.o i386bsd-tdep.o i386nbsd-tdep.o corelow.o
+TM_FILE= tm-nbsdaout.h
diff --git a/gdb/config/i386/nm-nbsdaout.h b/gdb/config/i386/nm-nbsdaout.h
new file mode 100644 (file)
index 0000000..dc8aac9
--- /dev/null
@@ -0,0 +1,30 @@
+/* Native-dependent definitions for Intel 386 running NetBSD, for GDB.
+   Copyright 1986, 1987, 1989, 1992, 1994, 1996, 2000
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "i386/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* NM_NBSDAOUT_H */
diff --git a/gdb/config/i386/tm-nbsdaout.h b/gdb/config/i386/tm-nbsdaout.h
new file mode 100644 (file)
index 0000000..8dde114
--- /dev/null
@@ -0,0 +1,30 @@
+/* Macro definitions for i386 running under NetBSD.
+   Copyright 2000, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef TM_NBSDAOUT_H
+#define TM_NBSDAOUT_H
+
+#include "i386/tm-nbsd.h"
+
+/* Return non-zero if we are in a shared library trampoline code stub. */
+#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) \
+  (name && !strcmp(name, "_DYNAMIC"))
+
+#endif /* TM_NBSDAOUT_H */
diff --git a/gdb/config/m68k/nbsdaout.mh b/gdb/config/m68k/nbsdaout.mh
new file mode 100644 (file)
index 0000000..7ce279b
--- /dev/null
@@ -0,0 +1,5 @@
+# Host: Motorola m68k running NetBSD
+NATDEPFILES= infptrace.o inftarg.o fork-child.o corelow.o m68knbsd-nat.o \
+       solib.o solib-sunos.o
+XM_FILE= xm-nbsd.h
+NAT_FILE= nm-nbsdaout.h
diff --git a/gdb/config/m68k/nbsdaout.mt b/gdb/config/m68k/nbsdaout.mt
new file mode 100644 (file)
index 0000000..b6ac5a0
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: Motorola m68k running NetBSD
+TDEPFILES= m68k-tdep.o m68knbsd-tdep.o
+TM_FILE= tm-nbsd.h
diff --git a/gdb/config/m68k/nm-nbsdaout.h b/gdb/config/m68k/nm-nbsdaout.h
new file mode 100644 (file)
index 0000000..cb755f0
--- /dev/null
@@ -0,0 +1,29 @@
+/* Native-dependent definitions for Motorola m68k running NetBSD, for GDB.
+   Copyright 1996, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "m68k/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* NM_NBSDAOUT_H */
diff --git a/gdb/config/mips/nbsd.mh b/gdb/config/mips/nbsd.mh
new file mode 100644 (file)
index 0000000..4556fc6
--- /dev/null
@@ -0,0 +1,4 @@
+# Host: MIPS running NetBSD
+NAT_CLIBS=
+NATDEPFILES= infptrace.o inftarg.o fork-child.o mipsnbsd-nat.o
+NAT_FILE= nm-nbsd.h
diff --git a/gdb/config/mips/nbsd.mt b/gdb/config/mips/nbsd.mt
new file mode 100644 (file)
index 0000000..de52916
--- /dev/null
@@ -0,0 +1,6 @@
+# Target: MIPS running NetBSD
+TDEPFILES= mips-tdep.o mipsnbsd-tdep.o corelow.o solib.o solib-svr4.o
+TM_FILE= tm-nbsd.h
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/mips/libsim.a
diff --git a/gdb/config/mips/nm-nbsd.h b/gdb/config/mips/nm-nbsd.h
new file mode 100644 (file)
index 0000000..67628c2
--- /dev/null
@@ -0,0 +1,28 @@
+/* Native-dependent definitions for NetBSD/mips.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_NBSD_H
+#define NM_NBSD_H
+
+/* Get generic NetBSD native definitions.  */
+#include "config/nm-nbsd.h"
+
+#endif /* NM_NBSD_H */
diff --git a/gdb/config/mips/tm-nbsd.h b/gdb/config/mips/tm-nbsd.h
new file mode 100644 (file)
index 0000000..fc74486
--- /dev/null
@@ -0,0 +1,45 @@
+/* Target-dependent definitions for NetBSD/mips.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef TM_NBSD_H
+#define TM_NBSD_H
+
+/* Saved Pc.  Get it from sigcontext if within sigtramp.  */
+#define SIGCONTEXT_PC_OFFSET 8
+
+#include "mips/tm-mips.h"
+#include "solib.h"
+
+/* There's an E_MIPS_ABI_O32 flag in e_flags, but we don't use it - in
+   fact, using it may violate the o32 ABI.  */
+
+#define MIPS_DEFAULT_ABI MIPS_ABI_O32
+
+/* We don't want to inherit tm-mips.h's shared library trampoline code.  */
+#undef IN_SOLIB_CALL_TRAMPOLINE
+#undef IN_SOLIB_RETURN_TRAMPOLINE
+#undef SKIP_TRAMPOLINE_CODE
+#undef IGNORE_HELPER_CALL
+
+/* XXX undef a bunch of stuff we want to use multi-arch */
+#undef IN_SIGTRAMP
+
+#endif /* TM_NBSD_H */
diff --git a/gdb/config/nm-nbsdaout.h b/gdb/config/nm-nbsdaout.h
new file mode 100644 (file)
index 0000000..026f1ed
--- /dev/null
@@ -0,0 +1,72 @@
+/* Native-dependent definitions for NetBSD a.out.
+   Copyright 1994, 1996, 1999 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* make structure definitions match up with those expected in solib.c */
+#define link_object    sod
+#define lo_name                sod_name
+#define lo_library     sod_library
+#define lo_unused      sod_reserved
+#define lo_major       sod_major
+#define lo_minor       sod_minor
+#define lo_next                sod_next
+
+#define link_map       so_map
+#define lm_addr                som_addr
+#define lm_name                som_path
+#define lm_next                som_next
+#define lm_lop         som_sod
+#define lm_lob         som_sodbase
+#define lm_rwt         som_write
+#define lm_ld          som_dynamic
+#define lm_lpd         som_spd
+
+#define link_dynamic_2 section_dispatch_table
+#define ld_loaded      sdt_loaded
+#define ld_need                sdt_sods
+#define ld_rules       sdt_filler1
+#define ld_got         sdt_got
+#define ld_plt         sdt_plt
+#define ld_rel         sdt_rel
+#define ld_hash                sdt_hash
+#define ld_stab                sdt_nzlist
+#define ld_stab_hash   sdt_filler2
+#define ld_buckets     sdt_buckets
+#define ld_symbols     sdt_strings
+#define ld_symb_size   sdt_str_sz
+#define ld_text                sdt_text_sz
+#define ld_plt_sz      sdt_plt_sz
+
+#define rtc_symb       rt_symbol
+#define rtc_sp         rt_sp
+#define rtc_next       rt_next
+
+#define ld_debug       so_debug
+#define ldd_version    dd_version
+#define ldd_in_debugger        dd_in_debugger
+#define ldd_sym_loaded dd_sym_loaded
+#define ldd_bp_addr    dd_bpt_addr
+#define ldd_bp_inst    dd_bpt_shadow
+#define ldd_cp         dd_cc
+
+#define link_dynamic   _dynamic
+#define ld_version     d_version
+#define ldd            d_debug
+#define ld_un          d_un
+#define ld_2           d_sdt
diff --git a/gdb/config/ns32k/nbsdaout.mh b/gdb/config/ns32k/nbsdaout.mh
new file mode 100644 (file)
index 0000000..8cf4781
--- /dev/null
@@ -0,0 +1,5 @@
+# Host: PC532 running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o corelow.o ns32knbsd-nat.o \
+       solib.o solib-sunos.o
+XM_FILE= xm-nbsd.h
+NAT_FILE= nm-nbsdaout.h
diff --git a/gdb/config/ns32k/nbsdaout.mt b/gdb/config/ns32k/nbsdaout.mt
new file mode 100644 (file)
index 0000000..24418f4
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: PC532 running NetBSD
+TDEPFILES= ns32k-tdep.o ns32knbsd-tdep.o
+TM_FILE= tm-nbsd.h
diff --git a/gdb/config/ns32k/nm-nbsdaout.h b/gdb/config/ns32k/nm-nbsdaout.h
new file mode 100644 (file)
index 0000000..aed3c7f
--- /dev/null
@@ -0,0 +1,30 @@
+/* Native-dependent definitions for ns32k running NetBSD, for GDB.
+   Copyright 1986, 1987, 1989, 1992, 1994, 2000, 2002
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "ns32k/nm-nbsd.h"
+
+/* Get generic NetBSD native definitions. */
+#include "config/nm-nbsdaout.h"
+
+#endif /* NM_NBSDAOUT_H */
diff --git a/gdb/config/ns32k/tm-ns32k.h b/gdb/config/ns32k/tm-ns32k.h
new file mode 100644 (file)
index 0000000..cd15942
--- /dev/null
@@ -0,0 +1,39 @@
+/* Definitions to make GDB run on an encore under umax 4.2
+   Copyright 1987, 1989, 1991, 1993, 1994, 1998, 1999, 2000, 2001, 2002
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef TM_NS32K_H
+#define TM_NS32K_H
+
+#define GDB_MULTI_ARCH GDB_MULTI_ARCH_PARTIAL
+
+/* Need to get function ends by adding this to epilogue address from .bf
+   record, not using x_fsize field.  */
+#define FUNCTION_EPILOGUE_SIZE 4
+
+/* Address of end of stack space.  */
+
+#ifndef STACK_END_ADDR
+#define STACK_END_ADDR (0xfffff000)
+#endif
+
+#define NUM_GENERAL_REGS       8
+
+#endif /* TM_NS32K_H */
diff --git a/gdb/config/sparc/nbsd64.mh b/gdb/config/sparc/nbsd64.mh
new file mode 100644 (file)
index 0000000..eb54e48
--- /dev/null
@@ -0,0 +1,3 @@
+# Host: UltraSPARC running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o sparc64nbsd-nat.o
+NAT_FILE= nm-nbsd.h
diff --git a/gdb/config/sparc/nbsd64.mt b/gdb/config/sparc/nbsd64.mt
new file mode 100644 (file)
index 0000000..93b8f78
--- /dev/null
@@ -0,0 +1,4 @@
+# Target: UltraSPARC running NetBSD
+TDEPFILES= sparc-tdep.o sparcnbsd-tdep.o nbsd-tdep.o corelow.o solib.o \
+       solib-svr4.o
+TM_FILE= tm-nbsd64.h
diff --git a/gdb/config/sparc/nbsdaout.mh b/gdb/config/sparc/nbsdaout.mh
new file mode 100644 (file)
index 0000000..4520899
--- /dev/null
@@ -0,0 +1,4 @@
+# Host: Sun 4 or Sparcstation, running NetBSD
+NATDEPFILES= fork-child.o infptrace.o inftarg.o sparcnbsd-nat.o solib-sunos.o
+XM_FILE= xm-nbsd.h
+NAT_FILE= nm-nbsdaout.h
diff --git a/gdb/config/sparc/nm-nbsdaout.h b/gdb/config/sparc/nm-nbsdaout.h
new file mode 100644 (file)
index 0000000..7307591
--- /dev/null
@@ -0,0 +1,30 @@
+/* Native-dependent definitions for Sparc running NetBSD a.out, for GDB.
+   Copyright 1999 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NM_NBSDAOUT_H
+#define NM_NBSDAOUT_H
+
+#include "sparc/nm-nbsd.h"
+
+/* Get generic NetBSD a.out native definitions. */
+
+#include "config/nm-nbsdaout.h"
+
+#endif /* NM_NBSDAOUT_H */
diff --git a/gdb/config/sparc/tm-nbsd64.h b/gdb/config/sparc/tm-nbsd64.h
new file mode 100644 (file)
index 0000000..cc1d6b3
--- /dev/null
@@ -0,0 +1,27 @@
+/* Macro definitions for UltraSPARC running under NetBSD.
+   Copyright 1994, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef TM_NBSD64_H
+#define TM_NBSD64_H
+
+#include "sparc/tm-sp64.h" /* sets GDB_MULTI_ARCH */
+#include "solib.h"
+
+#endif /* TM_NBSD64_H */
diff --git a/gdb/gdbserver/acinclude.m4 b/gdb/gdbserver/acinclude.m4
new file mode 100644 (file)
index 0000000..bbfa86f
--- /dev/null
@@ -0,0 +1,41 @@
+dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
+sinclude(../../bfd/acinclude.m4)
+
+AC_DEFUN([SRV_CHECK_THREAD_DB],
+[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
+ [old_LIBS="$LIBS"
+  LIBS="$LIBS -lthread_db"
+  AC_TRY_LINK(
+  [void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}],
+  [td_ta_new();],
+  [srv_cv_thread_db="-lthread_db"],
+  [srv_cv_thread_db=no
+
+ if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
+  thread_db="/lib/libthread_db.so.1"
+ else
+  thread_db='$prefix/lib/libthread_db.so.1'
+ fi
+ LIBS="$old_LIBS `eval echo "$thread_db"`"
+ AC_TRY_LINK(
+  [void ps_pglobal_lookup() {}
+   void ps_pdread() {}
+   void ps_pdwrite() {}
+   void ps_lgetregs() {}
+   void ps_lsetregs() {}
+   void ps_lgetfpregs() {}
+   void ps_lsetfpregs() {}
+   void ps_getpid() {}],
+  [td_ta_new();],
+  [srv_cv_thread_db="$thread_db"],
+  [srv_cv_thread_db=no])
+ LIBS="$old_LIBS"
+ ]])
+)])
diff --git a/gdb/gdbserver/proc-service.c b/gdb/gdbserver/proc-service.c
new file mode 100644 (file)
index 0000000..becf565
--- /dev/null
@@ -0,0 +1,256 @@
+/* libthread_db helper functions for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "server.h"
+
+/* This file is currently tied to GNU/Linux.  It should scale well to
+   another libthread_db implementation, with the approriate gdbserver
+   hooks, but for now this means we can use GNU/Linux's target data.  */
+
+#include "linux-low.h"
+
+/* Correct for all GNU/Linux targets (for quite some time).  */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
+   via <sys/procfs.h>.  */
+#ifdef HAVE_LINUX_ELF_H   
+#include <linux/elf.h>    
+#endif
+#endif
+
+#include "../gdb_proc_service.h"
+
+typedef struct ps_prochandle *gdb_ps_prochandle_t;
+typedef void *gdb_ps_read_buf_t;
+typedef const void *gdb_ps_write_buf_t;
+typedef size_t gdb_ps_size_t;
+
+/* FIXME redo this right */
+#if 0
+#ifndef HAVE_LINUX_REGSETS
+#error HAVE_LINUX_REGSETS required!
+#else
+static struct regset_info *
+gregset_info(void)
+{
+  int i = 0;
+
+  while (target_regsets[i].size != -1)
+    {
+      if (target_regsets[i].type == GENERAL_REGS)
+       break;
+      i++;
+    }
+
+  return &target_regsets[i];
+}
+
+static struct regset_info *
+fpregset_info(void)
+{
+  int i = 0;
+
+  while (target_regsets[i].size != -1)
+    {
+      if (target_regsets[i].type == FP_REGS)
+       break;
+      i++;
+    }
+
+  return &target_regsets[i];
+}
+#endif
+#endif
+
+/* Search for the symbol named NAME within the object named OBJ within
+   the target process PH.  If the symbol is found the address of the
+   symbol is stored in SYM_ADDR.  */
+
+ps_err_e
+ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
+                  const char *name, paddr_t *sym_addr)
+{
+  CORE_ADDR addr;
+
+  if (look_up_one_symbol (name, &addr) == 0)
+    return PS_NOSYM;
+
+  *sym_addr = (paddr_t) (unsigned long) addr;
+  return PS_OK;
+}
+
+/* Read SIZE bytes from the target process PH at address ADDR and copy
+   them into BUF.  */
+
+ps_err_e
+ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr,
+          gdb_ps_read_buf_t buf, gdb_ps_size_t size)
+{
+  read_inferior_memory (addr, buf, size);
+  return PS_OK;
+}
+
+/* Write SIZE bytes from BUF into the target process PH at address ADDR.  */
+
+ps_err_e
+ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
+           gdb_ps_write_buf_t buf, gdb_ps_size_t size)
+{
+  return write_inferior_memory (addr, buf, size);
+}
+
+/* Get the general registers of LWP LWPID within the target process PH
+   and store them in GREGSET.  */
+
+ps_err_e
+ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads,
+                                                         lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  the_target->fetch_registers (0, regcache);
+  gregset_info()->fill_function (gregset, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Set the general registers of LWP LWPID within the target process PH
+   from GREGSET.  */
+
+ps_err_e
+ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  gregset_info()->store_function (gregset, regcache);
+  the_target->store_registers (0, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Get the floating-point registers of LWP LWPID within the target
+   process PH and store them in FPREGSET.  */
+
+ps_err_e
+ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+              gdb_prfpregset_t *fpregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  the_target->fetch_registers (0, regcache);
+  fpregset_info()->fill_function (fpregset, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Set the floating-point registers of LWP LWPID within the target
+   process PH from FPREGSET.  */
+
+ps_err_e
+ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
+              const gdb_prfpregset_t *fpregset)
+{
+#if 0
+  struct thread_info *reg_inferior, *save_inferior;
+  void *regcache;
+
+  reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  if (reg_inferior == NULL)
+    return PS_ERR;
+
+  save_inferior = current_inferior;
+  current_inferior = reg_inferior;
+
+  regcache = new_register_cache ();
+  fpregset_info()->store_function (fpregset, regcache);
+  the_target->store_registers (0, regcache);
+  free_register_cache (regcache);
+
+  current_inferior = save_inferior;
+
+  return PS_OK;
+#endif
+  /* FIXME */
+  return PS_ERR;
+}
+
+/* Return overall process id of the target PH.  Special for GNU/Linux
+   -- not used on Solaris.  */
+
+pid_t
+ps_getpid (gdb_ps_prochandle_t ph)
+{
+  return ph->pid;
+}
+
+
diff --git a/gdb/gdbserver/thread-db.c b/gdb/gdbserver/thread-db.c
new file mode 100644 (file)
index 0000000..f3d57a5
--- /dev/null
@@ -0,0 +1,342 @@
+/* Thread management interface, for the remote server for GDB.
+   Copyright 2002
+   Free Software Foundation, Inc.
+
+   Contributed by MontaVista Software.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "server.h"
+
+#include "linux-low.h"
+
+extern int debug_threads;
+
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#endif
+
+/* Correct for all GNU/Linux targets (for quite some time).  */
+#define GDB_GREGSET_T elf_gregset_t
+#define GDB_FPREGSET_T elf_fpregset_t
+
+#ifndef HAVE_ELF_FPREGSET_T
+/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
+   via <sys/procfs.h>.  */
+#ifdef HAVE_LINUX_ELF_H
+#include <linux/elf.h>
+#endif
+#endif
+
+#include "../gdb_proc_service.h"
+
+/* Structure that identifies the child process for the
+   <proc_service.h> interface.  */
+static struct ps_prochandle proc_handle;
+
+/* Connection to the libthread_db library.  */
+static td_thragent_t *thread_agent;
+
+static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
+
+static char *
+thread_db_err_str (td_err_e err)
+{
+  static char buf[64];
+
+  switch (err)
+    {
+    case TD_OK:
+      return "generic 'call succeeded'";
+    case TD_ERR:
+      return "generic error";
+    case TD_NOTHR:
+      return "no thread to satisfy query";
+    case TD_NOSV:
+      return "no sync handle to satisfy query";
+    case TD_NOLWP:
+      return "no LWP to satisfy query";
+    case TD_BADPH:
+      return "invalid process handle";
+    case TD_BADTH:
+      return "invalid thread handle";
+    case TD_BADSH:
+      return "invalid synchronization handle";
+    case TD_BADTA:
+      return "invalid thread agent";
+    case TD_BADKEY:
+      return "invalid key";
+    case TD_NOMSG:
+      return "no event message for getmsg";
+    case TD_NOFPREGS:
+      return "FPU register set not available";
+    case TD_NOLIBTHREAD:
+      return "application not linked with libthread";
+    case TD_NOEVENT:
+      return "requested event is not supported";
+    case TD_NOCAPAB:
+      return "capability not available";
+    case TD_DBERR:
+      return "debugger service failed";
+    case TD_NOAPLIC:
+      return "operation not applicable to";
+    case TD_NOTSD:
+      return "no thread-specific data for this thread";
+    case TD_MALLOC:
+      return "malloc failed";
+    case TD_PARTIALREG:
+      return "only part of register set was written/read";
+    case TD_NOXREGS:
+      return "X register set not available for this thread";
+    default:
+      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
+      return buf;
+    }
+}
+
+#if 0
+static char *
+thread_db_state_str (td_thr_state_e state)
+{
+  static char buf[64];
+
+  switch (state)
+    {
+    case TD_THR_STOPPED:
+      return "stopped by debugger";
+    case TD_THR_RUN:
+      return "runnable";
+    case TD_THR_ACTIVE:
+      return "active";
+    case TD_THR_ZOMBIE:
+      return "zombie";
+    case TD_THR_SLEEP:
+      return "sleeping";
+    case TD_THR_STOPPED_ASLEEP:
+      return "stopped by debugger AND blocked";
+    default:
+      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
+      return buf;
+    }
+}
+#endif
+
+static void
+thread_db_create_event (CORE_ADDR where)
+{
+  td_event_msg_t msg;
+  td_err_e err;
+  struct inferior_linux_data *tdata;
+
+  if (debug_threads)
+    fprintf (stderr, "Thread creation event.\n");
+
+  tdata = inferior_target_data (current_inferior);
+
+  /* FIXME: This assumes we don't get another event.
+     In the LinuxThreads implementation, this is safe,
+     because all events come from the manager thread
+     (except for its own creation, of course).  */
+  err = td_ta_event_getmsg (thread_agent, &msg);
+  if (err != TD_OK)
+    fprintf (stderr, "thread getmsg err: %s\n",
+            thread_db_err_str (err));
+
+  /* msg.event == TD_EVENT_CREATE */
+
+  find_new_threads_callback (msg.th_p, NULL);
+}
+
+#if 0
+static void
+thread_db_death_event (CORE_ADDR where)
+{
+  if (debug_threads)
+    fprintf (stderr, "Thread death event.\n");
+}
+#endif
+
+static int
+thread_db_enable_reporting ()
+{
+  td_thr_events_t events;
+  td_notify_t notify;
+  td_err_e err;
+
+  /* Set the process wide mask saying which events we're interested in.  */
+  td_event_emptyset (&events);
+  td_event_addset (&events, TD_CREATE);
+
+#if 0
+  /* This is reported to be broken in glibc 2.1.3.  A different approach
+     will be necessary to support that.  */
+  td_event_addset (&events, TD_DEATH);
+#endif
+
+  err = td_ta_set_event (thread_agent, &events);
+  if (err != TD_OK)
+    {
+      warning ("Unable to set global thread event mask: %s",
+               thread_db_err_str (err));
+      return 0;
+    }
+
+  /* Get address for thread creation breakpoint.  */
+  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
+  if (err != TD_OK)
+    {
+      warning ("Unable to get location for thread creation breakpoint: %s",
+              thread_db_err_str (err));
+      return 0;
+    }
+  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+                    thread_db_create_event);
+
+#if 0
+  /* Don't concern ourselves with reported thread deaths, only
+     with actual thread deaths (via wait).  */
+
+  /* Get address for thread death breakpoint.  */
+  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
+  if (err != TD_OK)
+    {
+      warning ("Unable to get location for thread death breakpoint: %s",
+              thread_db_err_str (err));
+      return;
+    }
+  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
+                    thread_db_death_event);
+#endif
+
+  return 1;
+}
+
+static void
+maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
+{
+  td_err_e err;
+  struct thread_info *inferior;
+  struct process_info *process;
+
+  /* If we are attaching to our first thread, things are a little
+     different.  */
+  if (all_threads.head == all_threads.tail)
+    {
+      inferior = (struct thread_info *) all_threads.head;
+      process = get_thread_process (inferior);
+      if (process->thread_known == 0)
+       {
+         /* Switch to indexing the threads list by TID.  */
+         change_inferior_id (&all_threads, ti_p->ti_tid);
+         goto found;
+       }
+    }
+  
+  inferior = (struct thread_info *) find_inferior_id (&all_threads,
+                                                     ti_p->ti_tid);
+  if (inferior != NULL)
+    return;
+
+  if (debug_threads)
+    fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
+            ti_p->ti_tid, ti_p->ti_lid);
+  linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
+  inferior = (struct thread_info *) find_inferior_id (&all_threads,
+                                                     ti_p->ti_tid);
+  if (inferior == NULL)
+    {
+      warning ("Could not attach to thread %ld (LWP %d)\n",
+              ti_p->ti_tid, ti_p->ti_lid);
+      return;
+    }
+
+  process = inferior_target_data (inferior);
+
+found:
+  new_thread_notify (ti_p->ti_tid);
+
+  process->tid = ti_p->ti_tid;
+  process->lwpid = ti_p->ti_lid;
+
+  process->thread_known = 1;
+  err = td_thr_event_enable (th_p, 1);
+  if (err != TD_OK)
+    error ("Cannot enable thread event reporting for %d: %s",
+           ti_p->ti_lid, thread_db_err_str (err));
+}
+
+static int
+find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
+{
+  td_thrinfo_t ti;
+  td_err_e err;
+
+  err = td_thr_get_info (th_p, &ti);
+  if (err != TD_OK)
+    error ("Cannot get thread info: %s", thread_db_err_str (err));
+
+  /* Check for zombies.  */
+  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
+    return 0;
+
+  maybe_attach_thread (th_p, &ti);
+
+  return 0;
+}
+
+static void
+thread_db_find_new_threads (void)
+{
+  td_err_e err;
+
+  /* Iterate over all user-space threads to discover new threads.  */
+  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
+                       TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+                       TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+  if (err != TD_OK)
+    error ("Cannot find new threads: %s", thread_db_err_str (err));
+}
+
+int
+thread_db_init ()
+{
+  int err;
+
+  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
+
+  err = td_ta_new (&proc_handle, &thread_agent);
+  switch (err)
+    {
+    case TD_NOLIBTHREAD:
+      /* No thread library was detected.  */
+      return 0;
+
+    case TD_OK:
+      /* The thread library was detected.  */
+
+      if (thread_db_enable_reporting () == 0)
+       return 0;
+      thread_db_find_new_threads ();
+      return 1;
+
+    default:
+      warning ("error initializing thread_db library.");
+    }
+
+  return 0;
+}
diff --git a/gdb/i386-linux-tdep.h b/gdb/i386-linux-tdep.h
new file mode 100644 (file)
index 0000000..3c30130
--- /dev/null
@@ -0,0 +1,36 @@
+/* Target-dependent code for Linux/x86.
+   Copyright 2002
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef I386_LINUX_TDEP_H
+#define I386_LINUX_TDEP_H
+
+/* The Linux kernel pretends there is an additional "orig_eax"
+   register.  Since GDB needs access to that register to be able to
+   properly restart system calls when necessary (see
+   i386-linux-tdep.c) we need our own versions of a number of
+   functions that deal with GDB's register cache.  */
+
+/* Register number for the "orig_eax" pseudo-register.  If this
+   pseudo-register contains a value >= 0 it is interpreted as the
+   system call number that the kernel is supposed to restart.  */
+#define I386_LINUX_ORIG_EAX_REGNUM I386_SSE_NUM_REGS
+
+#endif /* i386-linux-tdep.h */
diff --git a/gdb/i386-sol2-tdep.c b/gdb/i386-sol2-tdep.c
new file mode 100644 (file)
index 0000000..714f5db
--- /dev/null
@@ -0,0 +1,59 @@
+/* Target-dependent code for Solaris x86.
+   Copyright 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+
+#include "i386-tdep.h"
+
+static int
+i386_sol2_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  /* Signal handler frames under Solaris 2 are recognized by a return
+     address of 0xffffffff.  */
+  return (pc == 0xffffffff);
+}
+
+/* Solaris 2.  */
+
+static void
+i386_sol2_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* Solaris is SVR4-based.  */
+  i386_svr4_init_abi (info, gdbarch);
+
+  /* Signal trampolines are different from SVR4, in fact they're
+     rather similar to BSD.  */
+  set_gdbarch_pc_in_sigtramp (gdbarch, i386_sol2_pc_in_sigtramp);
+  tdep->sigtramp_saved_pc = i386bsd_sigtramp_saved_pc;
+  tdep->sc_pc_offset = 36 + 14 * 4;
+}
+\f
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_i386_sol2_tdep (void);
+
+void
+_initialize_i386_sol2_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_i386, GDB_OSABI_SOLARIS,
+                         i386_sol2_init_abi);
+}
diff --git a/gdb/macrocmd.c b/gdb/macrocmd.c
new file mode 100644 (file)
index 0000000..40b3154
--- /dev/null
@@ -0,0 +1,287 @@
+/* C preprocessor macro expansion commands for GDB.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Red Hat, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+
+#include "defs.h"
+#include "macrotab.h"
+#include "macroexp.h"
+#include "macroscope.h"
+#include "command.h"
+#include "gdbcmd.h"
+
+\f
+/* The `macro' prefix command.  */
+
+static struct cmd_list_element *macrolist;
+
+static void
+macro_command (char *arg, int from_tty)
+{
+  printf_unfiltered
+    ("\"macro\" must be followed by the name of a macro command.\n");
+  help_list (macrolist, "macro ", -1, gdb_stdout);
+}
+
+
+\f
+/* Macro expansion commands.  */
+
+
+static void
+macro_expand_command (char *exp, int from_tty)
+{
+  struct macro_scope *ms = NULL;
+  char *expanded = NULL;
+  struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+  make_cleanup (free_current_contents, &expanded);
+
+  /* You know, when the user doesn't specify any expression, it would be
+     really cool if this defaulted to the last expression evaluated.
+     Then it would be easy to ask, "Hey, what did I just evaluate?"  But
+     at the moment, the `print' commands don't save the last expression
+     evaluated, just its value.  */
+  if (! exp || ! *exp)
+    error ("You must follow the `macro expand' command with the"
+           " expression you\n"
+           "want to expand.");
+
+  ms = default_macro_scope ();
+  if (ms)
+    {
+      expanded = macro_expand (exp, standard_macro_lookup, ms);
+      fputs_filtered ("expands to: ", gdb_stdout);
+      fputs_filtered (expanded, gdb_stdout);
+      fputs_filtered ("\n", gdb_stdout);
+    }
+  else
+    fputs_filtered ("GDB has no preprocessor macro information for "
+                    "that code.\n",
+                    gdb_stdout);
+
+  do_cleanups (cleanup_chain);
+  return;
+}
+
+
+static void
+macro_expand_once_command (char *exp, int from_tty)
+{
+  struct macro_scope *ms = NULL;
+  char *expanded = NULL;
+  struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+  make_cleanup (free_current_contents, &expanded);
+
+  /* You know, when the user doesn't specify any expression, it would be
+     really cool if this defaulted to the last expression evaluated.
+     And it should set the once-expanded text as the new `last
+     expression'.  That way, you could just hit return over and over and
+     see the expression expanded one level at a time.  */
+  if (! exp || ! *exp)
+    error ("You must follow the `macro expand-once' command with"
+           " the expression\n"
+           "you want to expand.");
+
+  ms = default_macro_scope ();
+  if (ms)
+    {
+      expanded = macro_expand_once (exp, standard_macro_lookup, ms);
+      fputs_filtered ("expands to: ", gdb_stdout);
+      fputs_filtered (expanded, gdb_stdout);
+      fputs_filtered ("\n", gdb_stdout);
+    }
+  else
+    fputs_filtered ("GDB has no preprocessor macro information for "
+                    "that code.\n",
+                    gdb_stdout);
+
+  do_cleanups (cleanup_chain);
+  return;
+}
+
+
+static void
+show_pp_source_pos (struct ui_file *stream,
+                    struct macro_source_file *file,
+                    int line)
+{
+  fprintf_filtered (stream, "%s:%d\n", file->filename, line);
+
+  while (file->included_by)
+    {
+      fprintf_filtered (gdb_stdout, "  included at %s:%d\n",
+                        file->included_by->filename,
+                        file->included_at_line);
+      file = file->included_by;
+    }
+}
+
+
+static void
+info_macro_command (char *name, int from_tty)
+{
+  struct macro_scope *ms = NULL;
+  struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &ms);
+  struct macro_definition *d;
+  
+  if (! name || ! *name)
+    error ("You must follow the `info macro' command with the name"
+           " of the macro\n"
+           "whose definition you want to see.");
+
+  ms = default_macro_scope ();
+  if (! ms)
+    error ("GDB has no preprocessor macro information for that code.\n");
+
+  d = macro_lookup_definition (ms->file, ms->line, name);
+  if (d)
+    {
+      int line;
+      struct macro_source_file *file
+        = macro_definition_location (ms->file, ms->line, name, &line);
+
+      fprintf_filtered (gdb_stdout, "Defined at ");
+      show_pp_source_pos (gdb_stdout, file, line);
+      fprintf_filtered (gdb_stdout, "#define %s", name);
+      if (d->kind == macro_function_like)
+        {
+          int i;
+
+          fputs_filtered ("(", gdb_stdout);
+          for (i = 0; i < d->argc; i++)
+            {
+              fputs_filtered (d->argv[i], gdb_stdout);
+              if (i + 1 < d->argc)
+                fputs_filtered (", ", gdb_stdout);
+            }
+          fputs_filtered (")", gdb_stdout);
+        }
+      fprintf_filtered (gdb_stdout, " %s\n", d->replacement);
+    }
+  else
+    {
+      fprintf_filtered (gdb_stdout,
+                        "The symbol `%s' has no definition as a C/C++"
+                        " preprocessor macro\n"
+                        "at ", name);
+      show_pp_source_pos (gdb_stdout, ms->file, ms->line);
+    }
+
+  do_cleanups (cleanup_chain);
+}
+
+
+\f
+/* User-defined macros.  */
+
+/* A table of user-defined macros.  Unlike the macro tables used for
+   symtabs, this one uses xmalloc for all its allocation, not an
+   obstack, and it doesn't bcache anything; it just xmallocs things.  So
+   it's perfectly possible to remove things from this, or redefine
+   things.  */
+static struct macro_table *user_macros;
+
+static void
+macro_define_command (char *exp, int from_tty)
+{
+  error ("Command not implemented yet.");
+}
+
+
+static void
+macro_undef_command (char *exp, int from_tty)
+{
+  error ("Command not implemented yet.");
+}
+
+
+static void
+macro_list_command (char *exp, int from_tty)
+{
+  error ("Command not implemented yet.");
+}
+
+
+\f
+/* Initializing the `macrocmd' module.  */
+
+void
+_initialize_macrocmd (void)
+{
+  struct cmd_list_element *c;
+
+  /* We introduce a new command prefix, `macro', under which we'll put
+     the various commands for working with preprocessor macros.  */
+  add_prefix_cmd
+    ("macro", class_info, macro_command,
+     "Prefix for commands dealing with C preprocessor macros.",
+     &macrolist, "macro ", 0, &cmdlist);
+
+  add_cmd
+    ("expand", no_class, macro_expand_command,
+     "Fully expand any C/C++ preprocessor macro invocations in EXPRESSION.\n"
+     "Show the expanded expression.",
+     &macrolist);
+  add_alias_cmd ("exp", "expand", no_class, 1, &macrolist);
+  add_cmd
+    ("expand-once", no_class, macro_expand_once_command,
+     "Expand C/C++ preprocessor macro invocations appearing directly in"
+     " EXPRESSION.\n"
+     "Show the expanded expression.\n"
+     "\n"
+     "This command differs from `macro expand' in that it only expands macro\n"
+     "invocations that appear directly in EXPRESSION; if expanding a macro\n"
+     "introduces further macro invocations, those are left unexpanded.\n"
+     "\n"
+     "`macro expand-once' helps you see how a particular macro expands,\n"
+     "whereas `macro expand' shows you how all the macros involved in an\n"
+     "expression work together to yield a pre-processed expression.",
+     &macrolist);
+  add_alias_cmd ("exp1", "expand-once", no_class, 1, &macrolist);
+
+  add_cmd
+    ("macro", no_class, info_macro_command,
+     "Show the definition of MACRO, and its source location.",
+     &infolist);
+
+  add_cmd
+    ("define", no_class, macro_define_command,
+     "Define a new C/C++ preprocessor macro.\n"
+     "The GDB command `macro define DEFINITION' is equivalent to placing a\n"
+     "preprocessor directive of the form `#define DEFINITION' such that the\n"
+     "definition is visible in all the inferior's source files.\n"
+     "For example:\n"
+     "  (gdb) macro define PI (3.1415926)\n"
+     "  (gdb) macro define MIN(x,y) ((x) < (y) ? (x) : (y))",
+     &macrolist);
+
+  add_cmd
+    ("undef", no_class, macro_undef_command,
+     "Remove the definition of the C/C++ preprocessor macro with the"
+     " given name.",
+     &macrolist);
+
+  add_cmd
+    ("list", no_class, macro_list_command,
+     "List all the macros defined using the `macro define' command.",
+     &macrolist);
+
+  user_macros = new_macro_table (0, 0);
+}
diff --git a/gdb/macroscope.c b/gdb/macroscope.c
new file mode 100644 (file)
index 0000000..08ff6eb
--- /dev/null
@@ -0,0 +1,107 @@
+/* Functions for deciding which macros are currently in scope.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Red Hat, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+
+#include "macroscope.h"
+#include "symtab.h"
+#include "target.h"
+#include "frame.h"
+#include "inferior.h"
+
+
+struct macro_scope *
+sal_macro_scope (struct symtab_and_line sal)
+{
+  struct macro_source_file *main;
+  struct macro_scope *ms;
+
+  if (! sal.symtab
+      || ! sal.symtab->macro_table)
+    return 0;
+
+  ms = (struct macro_scope *) xmalloc (sizeof (*ms));
+
+  main = macro_main (sal.symtab->macro_table);
+  ms->file = macro_lookup_inclusion (main, sal.symtab->filename);
+
+  if (! ms->file)
+    internal_error
+      (__FILE__, __LINE__,
+       "\n"
+       "the symtab `%s' refers to a preprocessor macro table which doesn't\n"
+       "have any record of processing a file by that name.\n",
+       sal.symtab->filename);
+
+  ms->line = sal.line;
+
+  return ms;
+}
+
+
+struct macro_scope *
+default_macro_scope (void)
+{
+  struct symtab_and_line sal;
+  struct macro_source_file *main;
+  struct macro_scope *ms;
+
+  /* If there's a selected frame, use its PC.  */ 
+  if (selected_frame)
+    sal = find_pc_line (selected_frame->pc, 0);
+  
+  /* If the target has any registers at all, then use its PC.  Why we
+     would have registers but no stack, I'm not sure.  */
+  else if (target_has_registers)
+    sal = find_pc_line (read_pc (), 0);
+
+  /* If all else fails, fall back to the current listing position.  */
+  else
+    {
+      /* Don't call select_source_symtab here.  That can raise an
+         error if symbols aren't loaded, but GDB calls the expression
+         evaluator in all sorts of contexts.
+
+         For example, commands like `set width' call the expression
+         evaluator to evaluate their numeric arguments.  If the
+         current language is C, then that may call this function to
+         choose a scope for macro expansion.  If you don't have any
+         symbol files loaded, then select_source_symtab will raise an
+         error.  But `set width' shouldn't raise an error just because
+         it can't decide which scope to macro-expand its argument in.  */
+      sal.symtab = current_source_symtab;
+      sal.line = current_source_line;
+    }
+
+  return sal_macro_scope (sal);
+}
+
+
+/* Look up the definition of the macro named NAME in scope at the source
+   location given by BATON, which must be a pointer to a `struct
+   macro_scope' structure.  */
+struct macro_definition *
+standard_macro_lookup (const char *name, void *baton)
+{
+  struct macro_scope *ms = (struct macro_scope *) baton;
+
+  return macro_lookup_definition (ms->file, ms->line, name);
+}
diff --git a/gdb/macroscope.h b/gdb/macroscope.h
new file mode 100644 (file)
index 0000000..fc10b6d
--- /dev/null
@@ -0,0 +1,63 @@
+/* Interface to functions for deciding which macros are currently in scope.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Red Hat, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef MACROSCOPE_H
+#define MACROSCOPE_H
+
+#include "macrotab.h"
+#include "symtab.h"
+
+
+/* All the information we need to decide which macro definitions are
+   in scope: a source file (either a main source file or an
+   #inclusion), and a line number in that file.  */
+struct macro_scope {
+  struct macro_source_file *file;
+  int line;
+};
+
+
+/* Return a `struct macro_scope' object corresponding to the symtab
+   and line given in SAL.  If we have no macro information for that
+   location, or if SAL's pc is zero, return zero.  */
+struct macro_scope *sal_macro_scope (struct symtab_and_line sal);
+
+
+/* Return a `struct macro_scope' object describing the scope the `macro
+   expand' and `macro expand-once' commands should use for looking up
+   macros.  If we have a selected frame, this is the source location of
+   its PC; otherwise, this is the last listing position.
+
+   If we have no macro information for the current location, return zero.
+
+   The object returned is allocated using xmalloc; the caller is
+   responsible for freeing it.  */
+struct macro_scope *default_macro_scope (void);
+
+
+/* Look up the definition of the macro named NAME in scope at the source
+   location given by BATON, which must be a pointer to a `struct
+   macro_scope' structure.  This function is suitable for use as
+   a macro_lookup_ftype function.  */
+struct macro_definition *standard_macro_lookup (const char *name, void *baton);
+
+
+#endif /* MACROSCOPE_H */
diff --git a/gdb/mipsnbsd-nat.c b/gdb/mipsnbsd-nat.c
new file mode 100644 (file)
index 0000000..16521f6
--- /dev/null
@@ -0,0 +1,101 @@
+/* Native-dependent code for MIPS systems running NetBSD.
+   Copyright 2000, 2001, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include "mipsnbsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* Determine if PT_GETREGS fetches this register.  */
+static int
+getregs_supplies (int regno)
+{
+  return ((regno) >= ZERO_REGNUM && (regno) <= PC_REGNUM);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+  if (regno == -1 || getregs_supplies (regno))
+    {
+      struct reg regs;
+
+      if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't get registers");
+      
+      mipsnbsd_supply_reg ((char *) &regs, regno);
+      if (regno != -1)
+       return;
+    }
+
+  if (regno == -1 || regno >= FP0_REGNUM)
+    {
+      struct fpreg fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't get floating point status");
+
+      mipsnbsd_supply_fpreg ((char *) &fpregs, regno);
+    }
+}
+
+void
+store_inferior_registers (int regno)
+{
+  if (regno == -1 || getregs_supplies (regno))
+    {
+      struct reg regs;
+
+      if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't get registers");
+
+      mipsnbsd_fill_reg ((char *) &regs, regno);
+
+      if (ptrace (PT_SETREGS, PIDGET (inferior_ptid), 
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't write registers");
+
+      if (regno != -1)
+       return;
+    }
+
+  if (regno == -1 || regno >= FP0_REGNUM)
+    {
+      struct fpreg fpregs; 
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't get floating point status");
+
+      mipsnbsd_fill_fpreg ((char *) &fpregs, regno);
+
+      if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't write floating point status");
+    }
+}
diff --git a/gdb/mipsnbsd-tdep.c b/gdb/mipsnbsd-tdep.c
new file mode 100644 (file)
index 0000000..029ae6f
--- /dev/null
@@ -0,0 +1,367 @@
+/* Target-dependent code for MIPS systems running NetBSD.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "target.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "mipsnbsd-tdep.h"
+
+#include "solib-svr4.h"
+
+/* Conveniently, GDB uses the same register numbering as the
+   ptrace register structure used by NetBSD/mips.  */
+
+void
+mipsnbsd_supply_reg (char *regs, int regno)
+{
+  int i;
+
+  for (i = 0; i <= PC_REGNUM; i++)
+    {
+      if (regno == i || regno == -1)
+       {
+         if (CANNOT_FETCH_REGISTER (i))
+           supply_register (i, NULL);
+         else
+            supply_register (i, regs + (i * MIPS_REGSIZE));
+        }
+    }
+}
+
+void
+mipsnbsd_fill_reg (char *regs, int regno)
+{
+  int i;
+
+  for (i = 0; i <= PC_REGNUM; i++)
+    if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+      regcache_collect (i, regs + (i * MIPS_REGSIZE));
+}
+
+void
+mipsnbsd_supply_fpreg (char *fpregs, int regno)
+{
+  int i;
+
+  for (i = FP0_REGNUM; i <= FCRIR_REGNUM; i++)
+    {
+      if (regno == i || regno == -1)
+       {
+         if (CANNOT_FETCH_REGISTER (i))
+           supply_register (i, NULL);
+         else
+            supply_register (i, fpregs + ((i - FP0_REGNUM) * MIPS_REGSIZE));
+       }
+    }
+}
+
+void
+mipsnbsd_fill_fpreg (char *fpregs, int regno)
+{
+  int i;
+
+  for (i = FP0_REGNUM; i <= FCRCS_REGNUM; i++)
+    if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
+      regcache_collect (i, fpregs + ((i - FP0_REGNUM) * MIPS_REGSIZE));
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+                      CORE_ADDR ignore)
+{
+  char *regs, *fpregs;
+
+  /* We get everything from one section.  */
+  if (which != 0)
+    return;
+
+  regs = core_reg_sect;
+  fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+  /* Integer registers.  */
+  mipsnbsd_supply_reg (regs, -1);
+
+  /* Floating point registers.  */
+  mipsnbsd_supply_fpreg (regs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+                         CORE_ADDR ignore)
+{
+  switch (which)
+    {
+    case 0:  /* Integer registers.  */
+      if (core_reg_size != SIZEOF_STRUCT_REG)
+       warning ("Wrong size register set in core file.");
+      else
+       mipsnbsd_supply_reg (core_reg_sect, -1);
+      break;
+
+    case 2:  /* Floating point registers.  */
+      if (core_reg_size != SIZEOF_STRUCT_FPREG)
+       warning ("Wrong size register set in core file.");
+      else
+       mipsnbsd_supply_fpreg (core_reg_sect, -1);
+      break;
+
+    default:
+      /* Don't know what kind of register request this is; just ignore it.  */
+      break;
+    }
+}
+
+static struct core_fns mipsnbsd_core_fns =
+{
+  bfd_target_unknown_flavour,          /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  fetch_core_registers,                        /* core_read_registers */
+  NULL                                 /* next */
+};
+
+static struct core_fns mipsnbsd_elfcore_fns =
+{
+  bfd_target_elf_flavour,              /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  fetch_elfcore_registers,             /* core_read_registers */
+  NULL                                 /* next */
+};
+
+/* Under NetBSD/mips, signal handler invocations can be identified by the
+   designated code sequence that is used to return from a signal handler.
+   In particular, the return address of a signal handler points to the
+   following code sequence:
+
+       addu    a0, sp, 16
+       li      v0, 295                 # __sigreturn14
+       syscall
+   
+   Each instruction has a unique encoding, so we simply attempt to match
+   the instruction the PC is pointing to with any of the above instructions.
+   If there is a hit, we know the offset to the start of the designated
+   sequence and can then check whether we really are executing in the
+   signal trampoline.  If not, -1 is returned, otherwise the offset from the
+   start of the return sequence is returned.  */
+
+#define RETCODE_NWORDS 3
+#define RETCODE_SIZE   (RETCODE_NWORDS * 4)
+
+static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
+{
+  0x10, 0x00, 0xa4, 0x27,      /* addu a0, sp, 16 */
+  0x27, 0x01, 0x02, 0x24,      /* li v0, 295 */
+  0x0c, 0x00, 0x00, 0x00,      /* syscall */
+};
+
+static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
+{
+  0x27, 0xa4, 0x00, 0x10,      /* addu a0, sp, 16 */
+  0x24, 0x02, 0x01, 0x27,      /* li v0, 295 */
+  0x00, 0x00, 0x00, 0x0c,      /* syscall */
+};
+
+static LONGEST
+mipsnbsd_sigtramp_offset (CORE_ADDR pc)
+{
+  const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+       ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel;
+  unsigned char ret[RETCODE_SIZE], w[4];
+  LONGEST off;
+  int i;
+
+  if (read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0)
+    return -1;
+
+  for (i = 0; i < RETCODE_NWORDS; i++)
+    {
+      if (memcmp (w, retcode + (i * 4), 4) == 0)
+       break;
+    }
+  if (i == RETCODE_NWORDS)
+    return -1;
+
+  off = i * 4;
+  pc -= off;
+
+  if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
+    return -1;
+
+  if (memcmp (ret, retcode, RETCODE_SIZE) == 0)
+    return off;
+
+  return -1;
+}
+
+static int
+mipsnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
+{
+  return (mipsnbsd_sigtramp_offset (pc) >= 0);
+}
+
+/* Figure out where the longjmp will land.  We expect that we have
+   just entered longjmp and haven't yet setup the stack frame, so
+   the args are still in the argument regs.  A0_REGNUM points at the
+   jmp_buf structure from which we extract the PC that we will land
+   at.  The PC is copied into *pc.  This routine returns true on
+   success.  */
+
+#define NBSD_MIPS_JB_PC                        (2 * 4)
+#define NBSD_MIPS_JB_ELEMENT_SIZE      MIPS_REGSIZE
+#define NBSD_MIPS_JB_OFFSET            (NBSD_MIPS_JB_PC * \
+                                        NBSD_MIPS_JB_ELEMENT_SIZE)
+
+static int
+mipsnbsd_get_longjmp_target (CORE_ADDR *pc)
+{
+  CORE_ADDR jb_addr;
+  char *buf;
+
+  buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE);
+
+  jb_addr = read_register (A0_REGNUM);
+
+  if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf,
+                         NBSD_MIPS_JB_ELEMENT_SIZE))
+    return 0;
+
+  *pc = extract_address (buf, NBSD_MIPS_JB_ELEMENT_SIZE);
+
+  return 1;
+}
+
+static int
+mipsnbsd_cannot_fetch_register (int regno)
+{
+  return (regno >= FP_REGNUM
+         || regno == ZERO_REGNUM
+         || regno == FCRIR_REGNUM);
+}
+
+static int
+mipsnbsd_cannot_store_register (int regno)
+{
+  return (regno >= FP_REGNUM
+         || regno == ZERO_REGNUM
+         || regno == FCRIR_REGNUM);
+}
+
+/* NetBSD/mips uses a slightly different link_map structure from the
+   other NetBSD platforms.  */
+static struct link_map_offsets *
+mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
+{
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL) 
+    {
+      lmp = &lmo;
+
+      lmo.r_debug_size = 16;
+
+      lmo.r_map_offset = 4;
+      lmo.r_map_size   = 4;
+
+      lmo.link_map_size = 24;
+
+      lmo.l_addr_offset = 0;
+      lmo.l_addr_size   = 4;
+
+      lmo.l_name_offset = 8;
+      lmo.l_name_size   = 4;
+
+      lmo.l_next_offset = 16;
+      lmo.l_next_size   = 4;
+
+      lmo.l_prev_offset = 20;
+      lmo.l_prev_size   = 4;
+    }
+
+  return lmp;
+}
+
+static struct link_map_offsets *
+mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void)
+{
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    {
+      lmp = &lmo;
+
+      lmo.r_debug_size = 32;
+
+      lmo.r_map_offset = 8;  
+      lmo.r_map_size   = 8;
+
+      lmo.link_map_size = 48;
+
+      lmo.l_addr_offset = 0;
+      lmo.l_addr_size   = 8;
+
+      lmo.l_name_offset = 16; 
+      lmo.l_name_size   = 8;
+
+      lmo.l_next_offset = 32;
+      lmo.l_next_size   = 8;
+
+      lmo.l_prev_offset = 40;
+      lmo.l_prev_size   = 8;
+    }
+
+  return lmp;
+}
+
+static void
+mipsnbsd_init_abi (struct gdbarch_info info,
+                   struct gdbarch *gdbarch)
+{
+  set_gdbarch_pc_in_sigtramp (gdbarch, mipsnbsd_pc_in_sigtramp);
+
+  set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
+
+  set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
+  set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
+
+  set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
+
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+                                        gdbarch_ptr_bit (gdbarch) == 32 ?
+                            mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets :
+                           mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets);
+}
+
+void
+_initialize_mipsnbsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_mips, GDB_OSABI_NETBSD_ELF,
+                         mipsnbsd_init_abi);
+
+  add_core_fns (&mipsnbsd_core_fns);
+  add_core_fns (&mipsnbsd_elfcore_fns);
+}
diff --git a/gdb/mipsnbsd-tdep.h b/gdb/mipsnbsd-tdep.h
new file mode 100644 (file)
index 0000000..6e9f50e
--- /dev/null
@@ -0,0 +1,33 @@
+/* Common target dependent code for GDB on MIPS systems running NetBSD.
+   Copyright 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef MIPSNBSD_TDEP_H
+#define MIPSNBSD_TDEP_H
+
+void mipsnbsd_supply_reg (char *, int);
+void mipsnbsd_fill_reg (char *, int);
+
+void mipsnbsd_supply_fpreg (char *, int);
+void mipsnbsd_fill_fpreg (char *, int);
+
+#define SIZEOF_STRUCT_REG      (38 * MIPS_REGSIZE)
+#define SIZEOF_STRUCT_FPREG    (33 * MIPS_REGSIZE)
+
+#endif /* MIPSNBSD_TDEP_H */
diff --git a/gdb/ns32k-tdep.h b/gdb/ns32k-tdep.h
new file mode 100644 (file)
index 0000000..c046324
--- /dev/null
@@ -0,0 +1,66 @@
+/* Target-dependent definitions for GDB on NS32000 systems.
+   Copyright 1987, 1989, 1991, 1993, 1994, 1998, 1999, 2000, 2001, 2002
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef NS32K_TDEP_H
+#define NS32K_TDEP_H
+
+#include "osabi.h"
+
+/* Register numbers of various important registers.
+   Note that some of these values are "real" register numbers,
+   and correspond to the general registers of the machine,
+   and some are "phony" register numbers which are too large
+   to be actual register numbers as far as the user is concerned
+   but do serve to get the desired values when passed to read_register.  */
+
+#define NS32K_R0_REGNUM   0    /* General register 0 */
+#define NS32K_FP0_REGNUM  8    /* Floating point register 0 */
+#define NS32K_SP_REGNUM          16    /* Contains address of top of stack */
+#define NS32K_AP_REGNUM   NS32K_FP_REGNUM
+#define NS32K_FP_REGNUM   17   /* Contains address of executing stack frame */
+#define NS32K_PC_REGNUM   18   /* Contains program counter */
+#define NS32K_PS_REGNUM   19   /* Contains processor status */
+#define NS32K_FPS_REGNUM  20   /* Floating point status register */
+#define NS32K_LP0_REGNUM  21   /* Double register 0 (same as FP0) */
+
+#define NS32K_NUM_REGS_32082 25
+#define NS32K_REGISTER_BYTES_32082 \
+  ((NS32K_NUM_REGS_32082 - 4) * 4 /* size of general purpose regs */ \
+   + 4                        * 8 /* size of floating point regs */)
+
+#define NS32K_NUM_REGS_32382 29
+#define NS32K_REGISTER_BYTES_32382 \
+  ((NS32K_NUM_REGS_32382 - 4) * 4 /* size of general purpose regs */ \
+   + 8                        * 8 /* size of floating point regs */)
+
+#define NS32K_REGISTER_SIZE             4
+#define NS32K_MAX_REGISTER_RAW_SIZE     8
+#define NS32K_MAX_REGISTER_VIRTUAL_SIZE 8
+
+struct gdbarch_tdep
+{
+  enum gdb_osabi osabi;
+};
+
+void ns32k_gdbarch_init_32082 (struct gdbarch *);
+void ns32k_gdbarch_init_32382 (struct gdbarch *);
+
+#endif /* NS32K_TDEP_H */
diff --git a/gdb/ns32knbsd-tdep.c b/gdb/ns32knbsd-tdep.c
new file mode 100644 (file)
index 0000000..1ca0b3b
--- /dev/null
@@ -0,0 +1,70 @@
+/* Target-dependent code for NS32000 systems running NetBSD.
+   Copyright 2002 Free Software Foundation, Inc. 
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+
+#include "ns32k-tdep.h"
+
+static int
+ns32knbsd_aout_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+  if (strcmp (name, "_DYNAMIC") == 0)
+    return 1;
+
+  return 0;
+}
+
+static void
+ns32knbsd_init_abi_common (struct gdbarch_info info,
+                           struct gdbarch *gdbarch)
+{
+  /* We only support machines with the 32382 FPU.  */
+  ns32k_gdbarch_init_32382 (gdbarch);
+}
+
+static void
+ns32knbsd_init_abi_aout (struct gdbarch_info info,
+                         struct gdbarch *gdbarch)
+{
+  ns32knbsd_init_abi_common (info, gdbarch);
+
+  set_gdbarch_in_solib_call_trampoline (gdbarch,
+                                     ns32knbsd_aout_in_solib_call_trampoline);
+}
+
+static enum gdb_osabi
+ns32knbsd_aout_osabi_sniffer (bfd *abfd)
+{
+  if (strcmp (bfd_get_target (abfd), "a.out-ns32k-netbsd") == 0)
+    return GDB_OSABI_NETBSD_AOUT;
+
+  return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_ns32knbsd_tdep (void)
+{
+  gdbarch_register_osabi_sniffer (bfd_arch_ns32k, bfd_target_aout_flavour,
+                                 ns32knbsd_aout_osabi_sniffer);
+
+  gdbarch_register_osabi (bfd_arch_ns32k, GDB_OSABI_NETBSD_AOUT,
+                         ns32knbsd_init_abi_aout);
+}
diff --git a/gdb/osabi.c b/gdb/osabi.c
new file mode 100644 (file)
index 0000000..1e122b8
--- /dev/null
@@ -0,0 +1,427 @@
+/* OS ABI variant handling for GDB.
+   Copyright 2001, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "osabi.h"
+
+#include "elf-bfd.h"
+
+
+/* This table matches the indices assigned to enum gdb_osabi.  Keep
+   them in sync.  */
+static const char * const gdb_osabi_names[] =
+{
+  "<unknown>",
+
+  "SVR4",
+  "GNU/Hurd",
+  "Solaris",
+  "OSF/1",
+  "GNU/Linux",
+  "FreeBSD a.out",
+  "FreeBSD ELF",
+  "NetBSD a.out",
+  "NetBSD ELF",
+  "Windows CE",
+  "DJGPP",
+  "NetWare",
+  "LynxOS",
+
+  "ARM EABI v1",
+  "ARM EABI v2",
+  "ARM APCS",
+
+  "<invalid>"
+};
+
+const char *
+gdbarch_osabi_name (enum gdb_osabi osabi)
+{
+  if (osabi >= GDB_OSABI_UNKNOWN && osabi < GDB_OSABI_INVALID)
+    return gdb_osabi_names[osabi];
+
+  return gdb_osabi_names[GDB_OSABI_INVALID];
+}
+
+/* Handler for a given architecture/OS ABI pair.  There should be only
+   one handler for a given OS ABI each architecture family.  */
+struct gdb_osabi_handler  
+{
+  struct gdb_osabi_handler *next;
+  enum bfd_architecture arch;
+  enum gdb_osabi osabi;
+  void (*init_osabi)(struct gdbarch_info, struct gdbarch *);
+};
+
+static struct gdb_osabi_handler *gdb_osabi_handler_list;
+
+void
+gdbarch_register_osabi (enum bfd_architecture arch, enum gdb_osabi osabi,
+                        void (*init_osabi)(struct gdbarch_info,
+                                          struct gdbarch *))
+{
+  struct gdb_osabi_handler **handler_p;
+
+  /* Registering an OS ABI handler for "unknown" is not allowed.  */
+  if (osabi == GDB_OSABI_UNKNOWN)
+    {
+      internal_error
+       (__FILE__, __LINE__,
+        "gdbarch_register_osabi: An attempt to register a handler for "
+         "OS ABI \"%s\" for architecture %s was made.  The handler will "
+        "not be registered",
+        gdbarch_osabi_name (osabi),
+        bfd_printable_arch_mach (arch, 0));
+      return;
+    }
+
+  for (handler_p = &gdb_osabi_handler_list; *handler_p != NULL;
+       handler_p = &(*handler_p)->next)
+    {
+      if ((*handler_p)->arch == arch
+         && (*handler_p)->osabi == osabi)
+       {
+         internal_error
+           (__FILE__, __LINE__,
+            "gdbarch_register_osabi: A handler for OS ABI \"%s\" "
+            "has already been registered for architecture %s",
+            gdbarch_osabi_name (osabi),
+            bfd_printable_arch_mach (arch, 0));
+         /* If user wants to continue, override previous definition.  */
+         (*handler_p)->init_osabi = init_osabi;
+         return;
+       }
+    }
+
+  (*handler_p)
+    = (struct gdb_osabi_handler *) xmalloc (sizeof (struct gdb_osabi_handler));
+  (*handler_p)->next = NULL;
+  (*handler_p)->arch = arch;
+  (*handler_p)->osabi = osabi;
+  (*handler_p)->init_osabi = init_osabi;
+}
+\f
+
+/* Sniffer to find the OS ABI for a given file's architecture and flavour. 
+   It is legal to have multiple sniffers for each arch/flavour pair, to
+   disambiguate one OS's a.out from another, for example.  The first sniffer
+   to return something other than GDB_OSABI_UNKNOWN wins, so a sniffer should
+   be careful to claim a file only if it knows for sure what it is.  */
+struct gdb_osabi_sniffer
+{
+  struct gdb_osabi_sniffer *next;
+  enum bfd_architecture arch;   /* bfd_arch_unknown == wildcard */
+  enum bfd_flavour flavour;
+  enum gdb_osabi (*sniffer)(bfd *);
+};
+
+static struct gdb_osabi_sniffer *gdb_osabi_sniffer_list;
+
+void
+gdbarch_register_osabi_sniffer (enum bfd_architecture arch,
+                                enum bfd_flavour flavour,
+                               enum gdb_osabi (*sniffer_fn)(bfd *))
+{
+  struct gdb_osabi_sniffer *sniffer;
+
+  sniffer =
+    (struct gdb_osabi_sniffer *) xmalloc (sizeof (struct gdb_osabi_sniffer));
+  sniffer->arch = arch;
+  sniffer->flavour = flavour;
+  sniffer->sniffer = sniffer_fn;
+
+  sniffer->next = gdb_osabi_sniffer_list;
+  gdb_osabi_sniffer_list = sniffer;
+}
+\f
+
+enum gdb_osabi
+gdbarch_lookup_osabi (bfd *abfd)
+{
+  struct gdb_osabi_sniffer *sniffer;
+  enum gdb_osabi osabi, match;
+  int match_specific;
+
+  match = GDB_OSABI_UNKNOWN;
+  match_specific = 0;
+
+  for (sniffer = gdb_osabi_sniffer_list; sniffer != NULL;
+       sniffer = sniffer->next)
+    {
+      if ((sniffer->arch == bfd_arch_unknown /* wildcard */
+          || sniffer->arch == bfd_get_arch (abfd))
+         && sniffer->flavour == bfd_get_flavour (abfd))
+       {
+         osabi = (*sniffer->sniffer) (abfd);
+         if (osabi < GDB_OSABI_UNKNOWN || osabi >= GDB_OSABI_INVALID)
+           {
+             internal_error
+               (__FILE__, __LINE__,
+                "gdbarch_lookup_osabi: invalid OS ABI (%d) from sniffer "
+                "for architecture %s flavour %d",
+                (int) osabi,
+                bfd_printable_arch_mach (bfd_get_arch (abfd), 0),
+                (int) bfd_get_flavour (abfd));
+           }
+         else if (osabi != GDB_OSABI_UNKNOWN)
+           {
+             /* A specific sniffer always overrides a generic sniffer.
+                Croak on multiple match if the two matches are of the
+                same class.  If the user wishes to continue, we'll use
+                the first match.  */
+             if (match != GDB_OSABI_UNKNOWN)
+               {
+                 if ((match_specific && sniffer->arch != bfd_arch_unknown)
+                  || (!match_specific && sniffer->arch == bfd_arch_unknown))
+                   {
+                     internal_error
+                       (__FILE__, __LINE__,
+                        "gdbarch_lookup_osabi: multiple %sspecific OS ABI "
+                        "match for architecture %s flavour %d: first "
+                        "match \"%s\", second match \"%s\"",
+                        match_specific ? "" : "non-",
+                        bfd_printable_arch_mach (bfd_get_arch (abfd), 0),
+                        (int) bfd_get_flavour (abfd),
+                        gdbarch_osabi_name (match),
+                        gdbarch_osabi_name (osabi));
+                   }
+                 else if (sniffer->arch != bfd_arch_unknown)
+                   {
+                     match = osabi;
+                     match_specific = 1;
+                   }
+               }
+             else
+               {
+                 match = osabi;
+                 if (sniffer->arch != bfd_arch_unknown)
+                   match_specific = 1;
+               }
+           }
+       }
+    }
+
+  return match;
+}
+
+void
+gdbarch_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch,
+                    enum gdb_osabi osabi)
+{
+  struct gdb_osabi_handler *handler;
+  bfd *abfd = info.abfd;
+  const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch);
+
+  if (osabi == GDB_OSABI_UNKNOWN)
+    {
+      /* Don't complain about not knowing the OS ABI if we don't
+        have an inferior.  */
+      if (info.abfd)
+       fprintf_filtered
+         (gdb_stderr, "GDB doesn't recognize the OS ABI of the inferior.  "
+          "Attempting to continue with the default %s settings",
+          bfd_printable_arch_mach (arch_info->arch, arch_info->mach));
+      return;
+    }
+
+  for (handler = gdb_osabi_handler_list; handler != NULL;
+       handler = handler->next)
+    {
+      if (handler->arch == bfd_get_arch (abfd)
+         && handler->osabi == osabi)
+       {
+         (*handler->init_osabi) (info, gdbarch);
+         return;
+       }
+    }
+
+  /* We assume that if GDB_MULTI_ARCH is less than GDB_MULTI_ARCH_TM
+     that an ABI variant can be supported by overriding definitions in
+     the tm-file.  */
+  if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL)
+    fprintf_filtered
+      (gdb_stderr,
+       "A handler for the OS ABI \"%s\" is not built into this "
+       "configuration of GDB.  "
+       "Attempting to continue with the default %s settings",
+       gdbarch_osabi_name (osabi),
+       bfd_printable_arch_mach (arch_info->arch, arch_info->mach));
+}
+\f
+
+/* Generic sniffer for ELF flavoured files.  */
+
+void
+generic_elf_osabi_sniff_abi_tag_sections (bfd *abfd, asection *sect, void *obj)
+{
+  enum gdb_osabi *os_ident_ptr = obj;
+  const char *name;
+  unsigned int sectsize;
+
+  name = bfd_get_section_name (abfd, sect);
+  sectsize = bfd_section_size (abfd, sect);
+
+  /* .note.ABI-tag notes, used by GNU/Linux and FreeBSD.  */
+  if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0)
+    {
+      unsigned int name_length, data_length, note_type;
+      char *note;
+
+      /* If the section is larger than this, it's probably not what we are
+        looking for.  */
+      if (sectsize > 128)
+       sectsize = 128;
+
+      note = alloca (sectsize);
+
+      bfd_get_section_contents (abfd, sect, note,
+                               (file_ptr) 0, (bfd_size_type) sectsize);
+
+      name_length = bfd_h_get_32 (abfd, note);
+      data_length = bfd_h_get_32 (abfd, note + 4);
+      note_type   = bfd_h_get_32 (abfd, note + 8);
+
+      if (name_length == 4 && data_length == 16 && note_type == NT_GNU_ABI_TAG
+         && strcmp (note + 12, "GNU") == 0)
+       {
+         int os_number = bfd_h_get_32 (abfd, note + 16);
+
+         switch (os_number)
+           {
+           case GNU_ABI_TAG_LINUX:
+             *os_ident_ptr = GDB_OSABI_LINUX;
+             break;
+
+           case GNU_ABI_TAG_HURD:
+             *os_ident_ptr = GDB_OSABI_HURD;
+             break;
+
+           case GNU_ABI_TAG_SOLARIS:
+             *os_ident_ptr = GDB_OSABI_SOLARIS;
+             break;
+
+           default:
+             internal_error
+               (__FILE__, __LINE__,
+                "generic_elf_osabi_sniff_abi_tag_sections: unknown OS number %d",
+                os_number);
+           }
+         return;
+       }
+      else if (name_length == 8 && data_length == 4
+              && note_type == NT_FREEBSD_ABI_TAG
+              && strcmp (note + 12, "FreeBSD") == 0)
+       {
+         /* XXX Should we check the version here?  Probably not
+            necessary yet.  */
+         *os_ident_ptr = GDB_OSABI_FREEBSD_ELF;
+       }
+      return;
+    }
+
+  /* .note.netbsd.ident notes, used by NetBSD.  */
+  if (strcmp (name, ".note.netbsd.ident") == 0 && sectsize > 0)
+    {
+      unsigned int name_length, data_length, note_type;
+      char *note;
+
+      /* If the section is larger than this, it's probably not what we are
+        looking for.  */
+      if (sectsize > 128) 
+       sectsize = 128;
+
+      note = alloca (sectsize);
+
+      bfd_get_section_contents (abfd, sect, note,
+                               (file_ptr) 0, (bfd_size_type) sectsize);
+      
+      name_length = bfd_h_get_32 (abfd, note);
+      data_length = bfd_h_get_32 (abfd, note + 4);
+      note_type   = bfd_h_get_32 (abfd, note + 8);
+
+      if (name_length == 7 && data_length == 4 && note_type == NT_NETBSD_IDENT
+         && strcmp (note + 12, "NetBSD") == 0)
+       {
+         /* XXX Should we check the version here?  Probably not
+            necessary yet.  */
+         *os_ident_ptr = GDB_OSABI_NETBSD_ELF;
+       }
+      return;
+    }
+}
+
+static enum gdb_osabi
+generic_elf_osabi_sniffer (bfd *abfd)
+{
+  unsigned int elfosabi;
+  enum gdb_osabi osabi = GDB_OSABI_UNKNOWN;
+
+  elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI];
+
+  switch (elfosabi)
+    {
+    case ELFOSABI_NONE:
+      /* When elfosabi is ELFOSABI_NONE (0), then the ELF structures in the
+         file are conforming to the base specification for that machine
+        (there are no OS-specific extensions).  In order to determine the
+        real OS in use we must look for OS notes that have been added.  */
+      bfd_map_over_sections (abfd,
+                            generic_elf_osabi_sniff_abi_tag_sections,
+                            &osabi);
+      break;
+
+    case ELFOSABI_FREEBSD:
+      osabi = GDB_OSABI_FREEBSD_ELF;
+      break;
+
+    case ELFOSABI_NETBSD:
+      osabi = GDB_OSABI_NETBSD_ELF;
+      break;
+
+    case ELFOSABI_LINUX:
+      osabi = GDB_OSABI_LINUX;
+      break;
+
+    case ELFOSABI_HURD:
+      osabi = GDB_OSABI_HURD;
+      break;
+
+    case ELFOSABI_SOLARIS:
+      osabi = GDB_OSABI_SOLARIS;
+      break;
+    }
+
+  return osabi;
+}
+\f
+
+void
+_initialize_gdb_osabi (void)
+{
+  if (strcmp (gdb_osabi_names[GDB_OSABI_INVALID], "<invalid>") != 0)
+    internal_error
+      (__FILE__, __LINE__,
+       "_initialize_gdb_osabi: gdb_osabi_names[] is inconsistent");
+
+  /* Register a generic sniffer for ELF flavoured files.  */
+  gdbarch_register_osabi_sniffer (bfd_arch_unknown,
+                                 bfd_target_elf_flavour,
+                                 generic_elf_osabi_sniffer);
+}
diff --git a/gdb/osabi.h b/gdb/osabi.h
new file mode 100644 (file)
index 0000000..1654f9d
--- /dev/null
@@ -0,0 +1,81 @@
+/* OS ABI variant handling for GDB.
+   Copyright 2001, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef OSABI_H
+#define OSABI_H
+
+/* List of known OS ABIs.  If you change this, make sure to update the
+   table in osabi.c.  */
+enum gdb_osabi
+{
+  GDB_OSABI_UNKNOWN = 0,       /* keep this first */
+
+  GDB_OSABI_SVR4,
+  GDB_OSABI_HURD,
+  GDB_OSABI_SOLARIS,
+  GDB_OSABI_OSF1,
+  GDB_OSABI_LINUX,
+  GDB_OSABI_FREEBSD_AOUT,
+  GDB_OSABI_FREEBSD_ELF,
+  GDB_OSABI_NETBSD_AOUT,
+  GDB_OSABI_NETBSD_ELF,
+  GDB_OSABI_WINCE,
+  GDB_OSABI_GO32,
+  GDB_OSABI_NETWARE,
+  GDB_OSABI_LYNXOS,
+
+  GDB_OSABI_ARM_EABI_V1,
+  GDB_OSABI_ARM_EABI_V2,
+  GDB_OSABI_ARM_APCS,
+
+  GDB_OSABI_INVALID            /* keep this last */
+};
+
+/* Register an OS ABI sniffer.  Each arch/flavour may have more than
+   one sniffer.  This is used to e.g. differentiate one OS's a.out from
+   another.  The first sniffer to return something other than
+   GDB_OSABI_UNKNOWN wins, so a sniffer should be careful to claim a file
+   only if it knows for sure what it is.  */
+void gdbarch_register_osabi_sniffer (enum bfd_architecture,
+                                    enum bfd_flavour,
+                                    enum gdb_osabi (*)(bfd *));
+
+/* Register a handler for an OS ABI variant for a given architecture.  There
+   should be only one handler for a given OS ABI each architecture family.  */
+void gdbarch_register_osabi (enum bfd_architecture, enum gdb_osabi,
+                             void (*)(struct gdbarch_info,
+                                     struct gdbarch *));
+
+/* Lookup the OS ABI corresponding to the specified BFD.  */
+enum gdb_osabi gdbarch_lookup_osabi (bfd *);
+
+/* Initialize the gdbarch for the specified OS ABI variant.  */
+void gdbarch_init_osabi (struct gdbarch_info, struct gdbarch *,
+                         enum gdb_osabi);
+
+/* Return the name of the specified OS ABI.  */
+const char *gdbarch_osabi_name (enum gdb_osabi);
+
+/* Helper routine for ELF file sniffers.  This looks at ABI tag note
+   sections to determine the OS ABI from the note.  It should be called
+   via bfd_map_over_sections.  */
+void generic_elf_osabi_sniff_abi_tag_sections (bfd *, asection *, void *);
+
+#endif /* OSABI_H */
diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c
new file mode 100644 (file)
index 0000000..0d33683
--- /dev/null
@@ -0,0 +1,312 @@
+/* Target-dependent code for PowerPC systems using the SVR4 ABI
+   for GDB, the GNU debugger.
+
+   Copyright 2000, 2001, 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "value.h"
+
+#include "ppc-tdep.h"
+
+/* round2 rounds x up to the nearest multiple of s assuming that s is a
+   power of 2 */
+
+#undef round2
+#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
+
+/* Pass the arguments in either registers, or in the stack. Using the
+   ppc sysv ABI, the first eight words of the argument list (that might
+   be less than eight parameters if some parameters occupy more than one
+   word) are passed in r3..r10 registers.  float and double parameters are
+   passed in fpr's, in addition to that. Rest of the parameters if any
+   are passed in user stack. 
+
+   If the function is returning a structure, then the return address is passed
+   in r3, then the first 7 words of the parametes can be passed in registers,
+   starting from r4. */
+
+CORE_ADDR
+ppc_sysv_abi_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
+                            int struct_return, CORE_ADDR struct_addr)
+{
+  int argno;
+  /* Next available general register for non-float, non-vector arguments. */
+  int greg;
+  /* Next available floating point register for float arguments. */
+  int freg;
+  /* Next available vector register for vector arguments. */
+  int vreg;
+  int argstkspace;
+  int structstkspace;
+  int argoffset;
+  int structoffset;
+  struct value *arg;
+  struct type *type;
+  int len;
+  char old_sp_buf[4];
+  CORE_ADDR saved_sp;
+
+  greg = struct_return ? 4 : 3;
+  freg = 1;
+  vreg = 2;
+  argstkspace = 0;
+  structstkspace = 0;
+
+  /* Figure out how much new stack space is required for arguments
+     which don't fit in registers.  Unlike the PowerOpen ABI, the
+     SysV ABI doesn't reserve any extra space for parameters which
+     are put in registers. */
+  for (argno = 0; argno < nargs; argno++)
+    {
+      arg = args[argno];
+      type = check_typedef (VALUE_TYPE (arg));
+      len = TYPE_LENGTH (type);
+
+      if (TYPE_CODE (type) == TYPE_CODE_FLT)
+       {
+         if (freg <= 8)
+           freg++;
+         else
+           {
+             /* SysV ABI converts floats to doubles when placed in
+                memory and requires 8 byte alignment */
+             if (argstkspace & 0x4)
+               argstkspace += 4;
+             argstkspace += 8;
+           }
+       }
+      else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8)  /* long long */
+       {
+         if (greg > 9)
+           {
+             greg = 11;
+             if (argstkspace & 0x4)
+               argstkspace += 4;
+             argstkspace += 8;
+           }
+         else
+           {
+             if ((greg & 1) == 0)
+               greg++;
+             greg += 2;
+           }
+       }
+      else if (!TYPE_VECTOR (type))
+        {
+         if (len > 4
+             || TYPE_CODE (type) == TYPE_CODE_STRUCT
+             || TYPE_CODE (type) == TYPE_CODE_UNION)
+           {
+             /* Rounding to the nearest multiple of 8 may not be necessary,
+                but it is safe.  Particularly since we don't know the
+                field types of the structure */
+             structstkspace += round2 (len, 8);
+           }
+         if (greg <= 10)
+           greg++;
+         else
+           argstkspace += 4;
+       }
+      else
+        {
+          if (len == 16
+             && TYPE_CODE (type) == TYPE_CODE_ARRAY
+             && TYPE_VECTOR (type))
+           {
+             if (vreg <= 13)
+               vreg++;
+             else
+               {
+                 /* Vector arguments must be aligned to 16 bytes on
+                     the stack. */
+                 argstkspace += round2 (argstkspace, 16);
+                 argstkspace += 16;
+               }
+           }
+       }
+    }
+
+  /* Get current SP location */
+  saved_sp = read_sp ();
+
+  sp -= argstkspace + structstkspace;
+
+  /* Allocate space for backchain and callee's saved lr */
+  sp -= 8;
+
+  /* Make sure that we maintain 16 byte alignment */
+  sp &= ~0x0f;
+
+  /* Update %sp before proceeding any further */
+  write_register (SP_REGNUM, sp);
+
+  /* write the backchain */
+  store_address (old_sp_buf, 4, saved_sp);
+  write_memory (sp, old_sp_buf, 4);
+
+  argoffset = 8;
+  structoffset = argoffset + argstkspace;
+  freg = 1;
+  greg = 3;
+  vreg = 2;
+  /* Fill in r3 with the return structure, if any */
+  if (struct_return)
+    {
+      char val_buf[4];
+      store_address (val_buf, 4, struct_addr);
+      memcpy (&registers[REGISTER_BYTE (greg)], val_buf, 4);
+      greg++;
+    }
+  /* Now fill in the registers and stack... */
+  for (argno = 0; argno < nargs; argno++)
+    {
+      arg = args[argno];
+      type = check_typedef (VALUE_TYPE (arg));
+      len = TYPE_LENGTH (type);
+
+      if (TYPE_CODE (type) == TYPE_CODE_FLT)
+       {
+         if (freg <= 8)
+           {
+             if (len > 8)
+               printf_unfiltered (
+                                  "Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
+             memcpy (&registers[REGISTER_BYTE (FP0_REGNUM + freg)],
+                     VALUE_CONTENTS (arg), len);
+             freg++;
+           }
+         else
+           {
+             /* SysV ABI converts floats to doubles when placed in
+                memory and requires 8 byte alignment */
+             /* FIXME: Convert floats to doubles */
+             if (argoffset & 0x4)
+               argoffset += 4;
+             write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
+             argoffset += 8;
+           }
+       }
+      else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8)  /* long long */
+       {
+         if (greg > 9)
+           {
+             greg = 11;
+             if (argoffset & 0x4)
+               argoffset += 4;
+             write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
+             argoffset += 8;
+           }
+         else
+           {
+             if ((greg & 1) == 0)
+               greg++;
+
+             memcpy (&registers[REGISTER_BYTE (greg)],
+                     VALUE_CONTENTS (arg), 4);
+             memcpy (&registers[REGISTER_BYTE (greg + 1)],
+                     VALUE_CONTENTS (arg) + 4, 4);
+             greg += 2;
+           }
+       }
+      else if (!TYPE_VECTOR (type))
+       {
+         char val_buf[4];
+         if (len > 4
+             || TYPE_CODE (type) == TYPE_CODE_STRUCT
+             || TYPE_CODE (type) == TYPE_CODE_UNION)
+           {
+             write_memory (sp + structoffset, VALUE_CONTENTS (arg), len);
+             store_address (val_buf, 4, sp + structoffset);
+             structoffset += round2 (len, 8);
+           }
+         else
+           {
+             memset (val_buf, 0, 4);
+             memcpy (val_buf, VALUE_CONTENTS (arg), len);
+           }
+         if (greg <= 10)
+           {
+             memcpy (&registers[REGISTER_BYTE (greg)], val_buf, 4);
+             greg++;
+           }
+         else
+           {
+             write_memory (sp + argoffset, val_buf, 4);
+             argoffset += 4;
+           }
+       }
+      else
+       {
+         if (len == 16
+             && TYPE_CODE (type) == TYPE_CODE_ARRAY
+             && TYPE_VECTOR (type))
+           {
+             struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+             char *v_val_buf = alloca (16);
+             memset (v_val_buf, 0, 16);
+             memcpy (v_val_buf, VALUE_CONTENTS (arg), len);
+             if (vreg <= 13)
+               {
+                 memcpy (&registers[REGISTER_BYTE (tdep->ppc_vr0_regnum
+                                                   + vreg)],
+                         v_val_buf, 16);
+                 vreg++;
+               }
+             else
+               {
+                 write_memory (sp + argoffset, v_val_buf, 16);
+                 argoffset += 16;
+               }
+           }
+        }
+    }
+
+  target_store_registers (-1);
+  return sp;
+}
+
+/* Until November 2001, gcc was not complying to the SYSV ABI for 
+   returning structures less than or equal to 8 bytes in size.  It was
+   returning everything in memory.  When this was corrected, it wasn't
+   fixed for native platforms.  */
+int     
+ppc_sysv_abi_broken_use_struct_convention (int gcc_p, struct type *value_type)
+{  
+  if (TYPE_LENGTH (value_type) == 16 
+      && TYPE_VECTOR (value_type))
+    return 0;                            
+
+  return generic_use_struct_convention (gcc_p, value_type);
+}
+
+/* Structures 8 bytes or less long are returned in the r3 & r4
+   registers, according to the SYSV ABI. */
+int
+ppc_sysv_abi_use_struct_convention (int gcc_p, struct type *value_type)
+{
+  if (TYPE_LENGTH (value_type) == 16
+      && TYPE_VECTOR (value_type))
+    return 0;
+
+  return (TYPE_LENGTH (value_type) > 8);
+}   
diff --git a/gdb/ppcnbsd-tdep.c b/gdb/ppcnbsd-tdep.c
new file mode 100644 (file)
index 0000000..44d8682
--- /dev/null
@@ -0,0 +1,216 @@
+/* Target-dependent code for PowerPC systems running NetBSD.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "target.h"
+#include "breakpoint.h"
+#include "value.h"
+
+#include "ppc-tdep.h"
+#include "ppcnbsd-tdep.h"
+#include "nbsd-tdep.h"
+
+#include "solib-svr4.h"
+
+#define REG_FIXREG_OFFSET(x)   ((x) * 4)
+#define REG_LR_OFFSET          (32 * 4)
+#define REG_CR_OFFSET          (33 * 4)
+#define REG_XER_OFFSET         (34 * 4)
+#define REG_CTR_OFFSET         (35 * 4)
+#define REG_PC_OFFSET          (36 * 4)
+#define SIZEOF_STRUCT_REG      (37 * 4)
+
+#define FPREG_FPR_OFFSET(x)    ((x) * 8)
+#define FPREG_FPSCR_OFFSET     (32 * 8)
+#define SIZEOF_STRUCT_FPREG    (33 * 8)
+
+void
+ppcnbsd_supply_reg (char *regs, int regno)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  int i;
+
+  for (i = 0; i <= 31; i++)
+    {
+      if (regno == i || regno == -1)
+       supply_register (i, regs + REG_FIXREG_OFFSET (i));
+    }
+
+  if (regno == tdep->ppc_lr_regnum || regno == -1)
+    supply_register (tdep->ppc_lr_regnum, regs + REG_LR_OFFSET);
+
+  if (regno == tdep->ppc_cr_regnum || regno == -1)
+    supply_register (tdep->ppc_cr_regnum, regs + REG_CR_OFFSET);
+
+  if (regno == tdep->ppc_xer_regnum || regno == -1)
+    supply_register (tdep->ppc_xer_regnum, regs + REG_XER_OFFSET);
+
+  if (regno == tdep->ppc_ctr_regnum || regno == -1)
+    supply_register (tdep->ppc_ctr_regnum, regs + REG_CTR_OFFSET);
+
+  if (regno == PC_REGNUM || regno == -1)
+    supply_register (PC_REGNUM, regs + REG_PC_OFFSET);
+}
+
+void
+ppcnbsd_fill_reg (char *regs, int regno)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  int i;
+
+  for (i = 0; i <= 31; i++)
+    {
+      if (regno == i || regno == -1)
+       regcache_collect (i, regs + REG_FIXREG_OFFSET (i));
+    }
+
+  if (regno == tdep->ppc_lr_regnum || regno == -1)
+    regcache_collect (tdep->ppc_lr_regnum, regs + REG_LR_OFFSET);
+
+  if (regno == tdep->ppc_cr_regnum || regno == -1)
+    regcache_collect (tdep->ppc_cr_regnum, regs + REG_CR_OFFSET);
+
+  if (regno == tdep->ppc_xer_regnum || regno == -1)
+    regcache_collect (tdep->ppc_xer_regnum, regs + REG_XER_OFFSET);
+
+  if (regno == tdep->ppc_ctr_regnum || regno == -1)
+    regcache_collect (tdep->ppc_ctr_regnum, regs + REG_CTR_OFFSET);
+
+  if (regno == PC_REGNUM || regno == -1)
+    regcache_collect (PC_REGNUM, regs + REG_PC_OFFSET);
+}
+
+void
+ppcnbsd_supply_fpreg (char *fpregs, int regno)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  int i;
+
+  for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+    {
+      if (regno == i || regno == -1)
+       supply_register (i, fpregs + FPREG_FPR_OFFSET (i - FP0_REGNUM));
+    }
+
+  if (regno == tdep->ppc_fpscr_regnum || regno == -1)
+    supply_register (tdep->ppc_fpscr_regnum, fpregs + FPREG_FPSCR_OFFSET);
+}
+
+void
+ppcnbsd_fill_fpreg (char *fpregs, int regno)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  int i;
+
+  for (i = FP0_REGNUM; i <= FP0_REGNUM + 31; i++)
+    {
+      if (regno == i || regno == -1)
+       regcache_collect (i, fpregs + FPREG_FPR_OFFSET (i - FP0_REGNUM));
+    }
+
+  if (regno == tdep->ppc_fpscr_regnum || regno == -1)
+    regcache_collect (tdep->ppc_fpscr_regnum, fpregs + FPREG_FPSCR_OFFSET);
+}
+
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+                      CORE_ADDR ignore)
+{
+  char *regs, *fpregs;
+
+  /* We get everything from one section.  */
+  if (which != 0)
+    return;
+
+  regs = core_reg_sect;
+  fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
+
+  /* Integer registers.  */
+  ppcnbsd_supply_reg (regs, -1);
+
+  /* Floating point registers.  */
+  ppcnbsd_supply_fpreg (fpregs, -1);
+}
+
+static void
+fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+                         CORE_ADDR ignore)
+{
+  switch (which)
+    {
+    case 0:  /* Integer registers.  */
+      if (core_reg_size != SIZEOF_STRUCT_REG)
+       warning ("Wrong size register set in core file.");
+      else
+       ppcnbsd_supply_reg (core_reg_sect, -1);
+      break;
+
+    case 2:  /* Floating point registers.  */
+      if (core_reg_size != SIZEOF_STRUCT_FPREG)
+       warning ("Wrong size FP register set in core file.");
+      else
+       ppcnbsd_supply_fpreg (core_reg_sect, -1);
+      break;
+
+    default:
+      /* Don't know what kind of register request this is; just ignore it.  */
+      break;
+    }
+}
+
+static struct core_fns ppcnbsd_core_fns =
+{
+  bfd_target_unknown_flavour,          /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  fetch_core_registers,                        /* core_read_registers */
+  NULL                                 /* next */
+};
+
+static struct core_fns ppcnbsd_elfcore_fns =
+{
+  bfd_target_elf_flavour,              /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  fetch_elfcore_registers,             /* core_read_registers */
+  NULL                                 /* next */
+};
+
+static void
+ppcnbsd_init_abi (struct gdbarch_info info,
+                  struct gdbarch *gdbarch)
+{
+
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+                                nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
+}
+
+void
+_initialize_ppcnbsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_powerpc, GDB_OSABI_NETBSD_ELF,
+                         ppcnbsd_init_abi);
+
+  add_core_fns (&ppcnbsd_core_fns);
+  add_core_fns (&ppcnbsd_elfcore_fns);
+}
diff --git a/gdb/ppcnbsd-tdep.h b/gdb/ppcnbsd-tdep.h
new file mode 100644 (file)
index 0000000..3eae72d
--- /dev/null
@@ -0,0 +1,30 @@
+/* Common target dependent code for GDB on PowerPC systems running NetBSD.
+   Copyright 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef PPCNBSD_TDEP_H
+#define PPCNBSD_TDEP_H
+
+void ppcnbsd_supply_reg (char *, int);
+void ppcnbsd_fill_reg (char *, int);
+
+void ppcnbsd_supply_fpreg (char *, int);
+void ppcnbsd_fill_fpreg (char *, int);
+
+#endif /* PPCNBSD_TDEP_H */
diff --git a/gdb/sh-tdep.h b/gdb/sh-tdep.h
new file mode 100644 (file)
index 0000000..cd7f35a
--- /dev/null
@@ -0,0 +1,111 @@
+/* Target-specific definition for a Hitachi Super-H.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef SH_TDEP_H
+#define SH_TDEP_H
+
+#include "osabi.h"
+
+/* Contributed by Steve Chamberlain sac@cygnus.com */
+
+/* Information that is dependent on the processor variant. */
+
+enum sh_abi
+  {
+    SH_ABI_UNKNOWN,
+    SH_ABI_32,
+    SH_ABI_64
+  };
+
+struct gdbarch_tdep
+  {
+    int PR_REGNUM;
+    int FPUL_REGNUM;  /*                       sh3e, sh4 */
+    int FPSCR_REGNUM; /*                       sh3e, sh4 */
+    int SR_REGNUM;    /* sh-dsp, sh3, sh3-dsp, sh3e, sh4 */
+    int DSR_REGNUM;   /* sh-dsp,      sh3-dsp            */
+    int FP_LAST_REGNUM; /*                     sh3e, sh4 */
+    int A0G_REGNUM;   /* sh-dsp,      sh3-dsp            */
+    int A0_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int A1G_REGNUM;   /* sh-dsp,      sh3-dsp            */
+    int A1_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int M0_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int M1_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int X0_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int X1_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int Y0_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int Y1_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int MOD_REGNUM;   /* sh-dsp,      sh3-dsp            */
+    int SSR_REGNUM;   /*         sh3, sh3-dsp, sh3e, sh4 */
+    int SPC_REGNUM;   /*         sh3, sh3-dsp, sh3e, sh4 */
+    int RS_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int RE_REGNUM;    /* sh-dsp,      sh3-dsp            */
+    int DR0_REGNUM;   /*                             sh4 */
+    int DR_LAST_REGNUM; /*                           sh4 */
+    int FV0_REGNUM;   /*                             sh4 */
+    int FV_LAST_REGNUM; /*                           sh4 */
+    /* FPP stands for Floating Point Pair, to avoid confusion with
+       GDB's FP0_REGNUM, which is the number of the first Floating
+       point register. Unfortunately on the sh5, the floating point
+       registers are called FR, and the floating point pairs are called FP. */
+    int TR7_REGNUM;       /*                            sh5-media*/
+    int FPP0_REGNUM;      /*                            sh5-media*/
+    int FPP_LAST_REGNUM;  /*                            sh5-media*/
+    int R0_C_REGNUM;      /*                            sh5-compact*/
+    int R_LAST_C_REGNUM;  /*                            sh5-compact*/
+    int PC_C_REGNUM;      /*                            sh5-compact*/
+    int GBR_C_REGNUM;     /*                            sh5-compact*/
+    int MACH_C_REGNUM;    /*                            sh5-compact*/
+    int MACL_C_REGNUM;    /*                            sh5-compact*/
+    int PR_C_REGNUM;      /*                            sh5-compact*/
+    int T_C_REGNUM;       /*                            sh5-compact*/
+    int FPSCR_C_REGNUM;   /*                            sh5-compact*/
+    int FPUL_C_REGNUM;    /*                            sh5-compact*/
+    int FP0_C_REGNUM;     /*                            sh5-compact*/
+    int FP_LAST_C_REGNUM; /*                            sh5-compact*/
+    int DR0_C_REGNUM;     /*                            sh5-compact*/
+    int DR_LAST_C_REGNUM; /*                            sh5-compact*/
+    int FV0_C_REGNUM;     /*                            sh5-compact*/
+    int FV_LAST_C_REGNUM; /*                            sh5-compact*/
+    int ARG0_REGNUM;
+    int ARGLAST_REGNUM;
+    int FLOAT_ARGLAST_REGNUM;
+    int RETURN_REGNUM;
+    enum gdb_osabi osabi;      /* OS/ABI of the inferior */
+    enum sh_abi sh_abi;
+  };
+
+/* Registers common to all the SH variants. */
+enum
+  {
+    R0_REGNUM = 0,
+    STRUCT_RETURN_REGNUM = 2,
+    ARG0_REGNUM = 4, /* Used in h8300-tdep.c */
+    ARGLAST_REGNUM = 7, /* Used in h8300-tdep.c */
+    PR_REGNUM = 17, /* used in sh3-rom.c */
+    GBR_REGNUM = 18,
+    VBR_REGNUM = 19,
+    MACH_REGNUM = 20,
+    MACL_REGNUM = 21,
+    SR_REGNUM = 22
+  };
+
+#endif /* SH_TDEP_H */
diff --git a/gdb/sim-regno.h b/gdb/sim-regno.h
new file mode 100644 (file)
index 0000000..5a7057b
--- /dev/null
@@ -0,0 +1,45 @@
+/* Generic remote debugging interface for simulators.
+
+   Copyright 2002 Free Software Foundation, Inc.
+
+   Contributed by Red Hat, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef SIM_REGNO_H
+#define SIM_REGNO_H
+
+/* The REGISTER_SIM_REGNO(REGNUM) method, when there is a
+   corresponding simulator register, returns that register number as a
+   cardinal.  When there is no corresponding register, it returns a
+   negative value.  */
+
+enum sim_regno {
+  /* Normal sane architecture.  The simulator is known to not model
+     this register.  */
+  SIM_REGNO_DOES_NOT_EXIST = -1,
+  /* For possible backward compatibility.  The register cache doesn't
+     have a corresponding name.  Skip the register entirely.  */
+  LEGACY_SIM_REGNO_IGNORE = -2
+};
+
+/* Treat all raw registers as valid.  */
+
+extern int one2one_register_sim_regno (int regnum);
+
+#endif
diff --git a/gdb/sparc64nbsd-nat.c b/gdb/sparc64nbsd-nat.c
new file mode 100644 (file)
index 0000000..a991d0e
--- /dev/null
@@ -0,0 +1,207 @@
+/* Native-dependent code for UltraSPARC systems running NetBSD.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include "sparcnbsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* NOTE: We don't bother with any of the deferred_store nonsense; it
+   makes things a lot more complicated than they need to be.  */
+
+/* Determine if PT_GETREGS fetches this register.  */
+static int
+getregs_supplies (int regno)
+{
+  /* FIXME: PS_REGNUM for 32-bit code.  */
+  return (regno == TSTATE_REGNUM
+         || regno == PC_REGNUM
+         || regno == NPC_REGNUM
+         || regno == Y_REGNUM
+         || (regno >= G0_REGNUM && regno <= G7_REGNUM)
+         || (regno >= O0_REGNUM && regno <= O7_REGNUM)
+         /* stack regs (handled by sparcnbsd_supply_reg)  */
+         || (regno >= L0_REGNUM && regno <= I7_REGNUM));
+}
+
+/* Determine if PT_GETFPREGS fetches this register.  */
+static int
+getfpregs_supplies (int regno)
+{
+  return ((regno >= FP0_REGNUM && regno <= (FP0_REGNUM + 47))
+         || regno == FPS_REGNUM);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+  /* We don't use deferred stores.  */
+  if (deferred_stores)
+    internal_error (__FILE__, __LINE__,
+                   "fetch_inferior_registers: deferred stores pending");
+
+  if (regno == -1 || getregs_supplies (regno))
+    {
+      union {
+       struct reg32 regs32;
+       struct reg64 regs64;
+      } regs;
+
+      if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+        perror_with_name ("Couldn't get registers");
+
+      if (gdbarch_ptr_bit (current_gdbarch) == 32)
+        sparcnbsd_supply_reg32 ((char *) &regs.regs32, regno);
+      else
+       sparcnbsd_supply_reg64 ((char *) &regs.regs64, regno);
+      if (regno != -1)
+       return;
+    }
+
+  if (regno == -1 || getfpregs_supplies (regno))
+    {
+      union {
+        struct fpreg32 fpregs32;
+       struct fpreg64 fpregs64;
+      } fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+        perror_with_name ("Couldn't get floating point registers");
+
+      if (gdbarch_ptr_bit (current_gdbarch) == 32)
+        sparcnbsd_supply_fpreg32 ((char *) &fpregs.fpregs32, regno);
+      else
+        sparcnbsd_supply_fpreg64 ((char *) &fpregs.fpregs64, regno);
+      if (regno != -1)
+       return;
+    }
+}
+
+void
+store_inferior_registers (int regno)
+{
+  /* We don't use deferred stores.  */
+  if (deferred_stores)
+    internal_error (__FILE__, __LINE__,
+                   "store_inferior_registers: deferred stores pending");
+
+  if (regno == -1 || getregs_supplies (regno))
+    {
+      union {
+       struct reg32 regs32;
+       struct reg64 regs64;
+      } regs;
+
+      if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't get registers");
+
+      if (gdbarch_ptr_bit (current_gdbarch) == 32)
+        sparcnbsd_fill_reg32 ((char *) &regs.regs32, regno);
+      else
+       sparcnbsd_fill_reg64 ((char *) &regs.regs64, regno);
+
+      if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't write registers");
+
+      /* Deal with the stack regs.  */
+      if (regno == -1 || regno == SP_REGNUM
+         || (regno >= L0_REGNUM && regno <= I7_REGNUM))
+       {
+         CORE_ADDR sp = read_register (SP_REGNUM);
+         int i;
+         char buf[8];
+
+         if (sp & 1)
+           {
+             /* Registers are 64-bit.  */
+             sp += 2047;
+
+             for (i = L0_REGNUM; i <= I7_REGNUM; i++)
+               {
+                 if (regno == -1 || regno == SP_REGNUM || regno == i)
+                   {
+                     regcache_collect (i, buf);
+                     target_write_memory (sp + ((i - L0_REGNUM) * 8),
+                                          buf, sizeof (buf));
+                   }
+               }
+            }
+         else
+           {
+             /* Registers are 32-bit.  Toss any sign-extension of the stack
+                pointer.
+
+                FIXME: We don't currently handle 32-bit code in a binary
+                that indicated LP64.  Do we have to care about that?  */
+              if (gdbarch_ptr_bit (current_gdbarch) != 32)
+               internal_error
+                   (__FILE__, __LINE__,
+                   "store_inferior_registers: 32-bit code in 64-bit inferior");
+
+             sp &= 0xffffffffUL;
+             for (i = L0_REGNUM; i <= I7_REGNUM; i++)
+               {
+                 if (regno == -1 || regno == SP_REGNUM || regno == i)
+                   {
+                     regcache_collect (i, buf);
+                     target_write_memory (sp + ((i - L0_REGNUM) * 4), buf, 4);
+                   }
+               }
+           }
+       }
+
+      if (regno != -1)
+       return;
+    }
+
+  if (regno == -1 || getfpregs_supplies (regno))
+    {
+      union {
+       struct fpreg32 fpregs32;
+       struct fpreg64 fpregs64;
+      } fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't get floating point registers");
+
+      if (gdbarch_ptr_bit (current_gdbarch) == 32)
+        sparcnbsd_fill_fpreg32 ((char *) &fpregs.fpregs32, regno);
+      else
+       sparcnbsd_fill_fpreg64 ((char *) &fpregs.fpregs64, regno);
+      
+      if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't write floating point registers");
+
+      if (regno != -1)
+       return;
+    }
+}
diff --git a/gdb/sparcnbsd-nat.c b/gdb/sparcnbsd-nat.c
new file mode 100644 (file)
index 0000000..ce5d44d
--- /dev/null
@@ -0,0 +1,154 @@
+/* Native-dependent code for SPARC systems running NetBSD.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include "sparcnbsd-tdep.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <machine/reg.h>
+
+/* NOTE: We don't bother with any of the deferred_store nonsense; it
+   makes things a lot more complicated than they need to be.  */
+
+/* Determine if PT_GETREGS fetches this register.  */
+static int
+getregs_supplies (int regno)
+{
+  return (regno == PS_REGNUM
+         || regno == PC_REGNUM
+         || regno == NPC_REGNUM
+         || regno == Y_REGNUM
+         || (regno >= G0_REGNUM && regno <= G7_REGNUM)
+         || (regno >= O0_REGNUM && regno <= O7_REGNUM)
+         /* stack regs (handled by sparcnbsd_supply_reg)  */
+         || (regno >= L0_REGNUM && regno <= I7_REGNUM));
+}
+
+/* Determine if PT_GETFPREGS fetches this register.  */
+static int
+getfpregs_supplies (int regno)
+{
+  return ((regno >= FP0_REGNUM && regno <= (FP0_REGNUM + 31))
+         || regno == FPS_REGNUM);
+}
+
+void
+fetch_inferior_registers (int regno)
+{
+  /* We don't use deferred stores.  */
+  if (deferred_stores)
+    internal_error (__FILE__, __LINE__,
+                   "fetch_inferior_registers: deferred stores pending");
+
+  if (regno == -1 || getregs_supplies (regno))
+    {
+      struct reg regs;
+
+      if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+        perror_with_name ("Couldn't get registers");
+
+      sparcnbsd_supply_reg32 ((char *) &regs, regno);
+      if (regno != -1)
+       return;
+    }
+
+  if (regno == -1 || getfpregs_supplies (regno))
+    {
+      struct fpreg fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+        perror_with_name ("Couldn't get floating point registers");
+
+      sparcnbsd_supply_fpreg32 ((char *) &fpregs, regno);
+      if (regno != -1)
+       return;
+    }
+}
+
+void
+store_inferior_registers (int regno)
+{
+  /* We don't use deferred stores.  */
+  if (deferred_stores)
+    internal_error (__FILE__, __LINE__,
+                   "store_inferior_registers: deferred stores pending");
+
+  if (regno == -1 || getregs_supplies (regno))
+    {
+      struct reg regs;
+
+      if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't get registers");
+
+      sparcnbsd_fill_reg32 ((char *) &regs, regno);
+
+      if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &regs, 0) == -1)
+       perror_with_name ("Couldn't write registers");
+
+      /* Deal with the stack regs.  */
+      if (regno == -1 || regno == SP_REGNUM
+         || (regno >= L0_REGNUM && regno <= I7_REGNUM))
+       {
+         CORE_ADDR sp = read_register (SP_REGNUM);
+         int i;
+         char buf[4];
+
+         for (i = L0_REGNUM; i <= I7_REGNUM; i++)
+           {
+             if (regno == -1 || regno == SP_REGNUM || regno == i)
+               {
+                 regcache_collect (i, buf);
+                 target_write_memory (sp + ((i - L0_REGNUM) * 4),
+                                      buf, sizeof (buf));
+               }
+           }
+       }
+
+      if (regno != -1)
+       return;
+    }
+
+  if (regno == -1 || getfpregs_supplies (regno))
+    {
+      struct fpreg fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't get floating point registers");
+
+      sparcnbsd_fill_fpreg32 ((char *) &fpregs, regno);
+      
+      if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+                 (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
+       perror_with_name ("Couldn't write floating point registers");
+
+      if (regno != -1)
+       return;
+    }
+}
diff --git a/gdb/sparcnbsd-tdep.c b/gdb/sparcnbsd-tdep.c
new file mode 100644 (file)
index 0000000..ea70e51
--- /dev/null
@@ -0,0 +1,531 @@
+/* Target-dependent code for SPARC systems running NetBSD.
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Wasabi Systems, 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "target.h"
+#include "value.h"
+#include "osabi.h"
+
+#include "sparcnbsd-tdep.h"
+#include "nbsd-tdep.h"
+
+#include "solib-svr4.h"
+
+#define REG32_OFFSET_PSR       (0 * 4)
+#define REG32_OFFSET_PC                (1 * 4)
+#define REG32_OFFSET_NPC       (2 * 4)
+#define REG32_OFFSET_Y         (3 * 4)
+#define REG32_OFFSET_GLOBAL    (4 * 4)
+#define REG32_OFFSET_OUT       (12 * 4)
+
+#define REG64_OFFSET_TSTATE    (0 * 8)
+#define REG64_OFFSET_PC                (1 * 8)
+#define REG64_OFFSET_NPC       (2 * 8)
+#define REG64_OFFSET_Y         (3 * 8)
+#define REG64_OFFSET_GLOBAL    (4 * 8)
+#define REG64_OFFSET_OUT       (12 * 8)
+
+void
+sparcnbsd_supply_reg32 (char *regs, int regno)
+{
+  int i;
+
+  if (regno == PS_REGNUM || regno == -1)
+    supply_register (PS_REGNUM, regs + REG32_OFFSET_PSR);
+
+  if (regno == PC_REGNUM || regno == -1)
+    supply_register (PC_REGNUM, regs + REG32_OFFSET_PC);
+
+  if (regno == NPC_REGNUM || regno == -1)
+    supply_register (NPC_REGNUM, regs + REG32_OFFSET_NPC);
+
+  if (regno == Y_REGNUM || regno == -1)
+    supply_register (Y_REGNUM, regs + REG32_OFFSET_Y);
+
+  if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1)
+    {
+      if (regno == G0_REGNUM || regno == -1)
+       supply_register (G0_REGNUM, NULL);      /* %g0 is always zero */
+      for (i = G1_REGNUM; i <= G7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           supply_register (i, regs + REG32_OFFSET_GLOBAL +
+                            ((i - G0_REGNUM) * 4));
+       }
+    }
+
+  if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1)
+    {
+      for (i = O0_REGNUM; i <= O7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           supply_register (i, regs + REG32_OFFSET_OUT +
+                            ((i - O0_REGNUM) * 4));
+        }
+    }
+
+  /* Inputs and Locals are stored onto the stack by by the kernel.  */
+  if ((regno >= L0_REGNUM && regno <= I7_REGNUM) || regno == -1)
+    {
+      CORE_ADDR sp = read_register (SP_REGNUM);
+      char buf[4];
+
+      for (i = L0_REGNUM; i <= I7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           {
+              target_read_memory (sp + ((i - L0_REGNUM) * 4),
+                                  buf, sizeof (buf));
+             supply_register (i, buf);
+           }
+       }
+    }
+
+  /* FIXME: If we don't set these valid, read_register_bytes() rereads
+     all the regs every time it is called!  */
+  if (regno == WIM_REGNUM || regno == -1)
+    supply_register (WIM_REGNUM, NULL);
+  if (regno == TBR_REGNUM || regno == -1)
+    supply_register (TBR_REGNUM, NULL);
+  if (regno == CPS_REGNUM || regno == -1)
+    supply_register (CPS_REGNUM, NULL);
+}
+
+void
+sparcnbsd_supply_reg64 (char *regs, int regno)
+{
+  int i;
+  char buf[8];
+
+  if (regno == TSTATE_REGNUM || regno == -1)
+    supply_register (PS_REGNUM, regs + REG64_OFFSET_TSTATE);
+
+  if (regno == PC_REGNUM || regno == -1)
+    supply_register (PC_REGNUM, regs + REG64_OFFSET_PC);
+
+  if (regno == NPC_REGNUM || regno == -1)
+    supply_register (NPC_REGNUM, regs + REG64_OFFSET_NPC);
+
+  if (regno == Y_REGNUM || regno == -1)
+    {
+      memset (buf, 0, sizeof (buf));
+      memcpy (&buf[4], regs + REG64_OFFSET_Y, 4);
+      supply_register (Y_REGNUM, buf);
+    }
+
+  if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1)
+    {
+      if (regno == G0_REGNUM || regno == -1)
+       supply_register (G0_REGNUM, NULL);      /* %g0 is always zero */
+      for (i = G1_REGNUM; i <= G7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           supply_register (i, regs + REG64_OFFSET_GLOBAL +
+                            ((i - G0_REGNUM) * 8));
+       }
+    }
+
+  if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1)
+    {
+      for (i = O0_REGNUM; i <= O7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           supply_register (i, regs + REG64_OFFSET_OUT +
+                            ((i - O0_REGNUM) * 8));
+        }
+    }
+
+  /* Inputs and Locals are stored onto the stack by by the kernel.  */
+  if ((regno >= L0_REGNUM && regno <= I7_REGNUM) || regno == -1)
+    {
+      CORE_ADDR sp = read_register (SP_REGNUM);
+      char buf[8];
+
+      if (sp & 1)
+       {
+         /* Registers are 64-bit.  */
+         sp += 2047;
+
+         for (i = L0_REGNUM; i <= I7_REGNUM; i++)
+           {
+             if (regno == i || regno == -1)
+               {
+                  target_read_memory (sp + ((i - L0_REGNUM) * 8),
+                                      buf, sizeof (buf));
+                 supply_register (i, buf);
+               }
+           }
+       }
+      else
+       {
+         /* Registers are 32-bit.  Toss any sign-extension of the stack
+            pointer, clear out the top half of the temporary buffer, and
+            put the register value in the bottom half.  */
+
+         sp &= 0xffffffffUL;
+         memset (buf, 0, sizeof (buf));
+         for (i = L0_REGNUM; i <= I7_REGNUM; i++)
+           {
+             if (regno == i || regno == -1)
+               {
+                 target_read_memory (sp + ((i - L0_REGNUM) * 4),
+                                     &buf[4], sizeof (buf));
+                  supply_register (i, buf);
+               }
+           }
+       }
+    }
+
+  /* FIXME: If we don't set these valid, read_register_bytes() rereads
+     all the regs every time it is called!  */
+  if (regno == WIM_REGNUM || regno == -1)
+    supply_register (WIM_REGNUM, NULL);
+  if (regno == TBR_REGNUM || regno == -1)
+    supply_register (TBR_REGNUM, NULL);
+  if (regno == CPS_REGNUM || regno == -1)
+    supply_register (CPS_REGNUM, NULL);
+}
+
+void
+sparcnbsd_fill_reg32 (char *regs, int regno)
+{
+  int i;
+
+  if (regno == PS_REGNUM || regno == -1)
+    regcache_collect (PS_REGNUM, regs + REG32_OFFSET_PSR);
+
+  if (regno == PC_REGNUM || regno == -1)
+    regcache_collect (PC_REGNUM, regs + REG32_OFFSET_PC);
+
+  if (regno == NPC_REGNUM || regno == -1)
+    regcache_collect (NPC_REGNUM, regs + REG32_OFFSET_NPC);
+
+  if (regno == Y_REGNUM || regno == -1)
+    regcache_collect (Y_REGNUM, regs + REG32_OFFSET_Y);
+
+  if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1)
+    {
+      /* %g0 is always zero */
+      for (i = G1_REGNUM; i <= G7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           regcache_collect (i, regs + REG32_OFFSET_GLOBAL +
+                             ((i - G0_REGNUM) * 4));
+       }
+    }
+
+  if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1)
+    {
+      for (i = O0_REGNUM; i <= O7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           regcache_collect (i, regs + REG32_OFFSET_OUT +
+                             ((i - O0_REGNUM) * 4));
+        }
+    }
+
+  /* Responsibility for the stack regs is pushed off onto the caller.  */
+}
+
+void
+sparcnbsd_fill_reg64 (char *regs, int regno)
+{
+  int i;
+
+  if (regno == TSTATE_REGNUM || regno == -1)
+    regcache_collect (TSTATE_REGNUM, regs + REG64_OFFSET_TSTATE);
+
+  if (regno == PC_REGNUM || regno == -1)
+    regcache_collect (PC_REGNUM, regs + REG64_OFFSET_PC);
+
+  if (regno == NPC_REGNUM || regno == -1)
+    regcache_collect (NPC_REGNUM, regs + REG64_OFFSET_NPC);
+
+  if (regno == Y_REGNUM || regno == -1)
+    regcache_collect (Y_REGNUM, regs + REG64_OFFSET_Y);
+
+  if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1)
+    {
+      /* %g0 is always zero */
+      for (i = G1_REGNUM; i <= G7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           regcache_collect (i, regs + REG64_OFFSET_GLOBAL +
+                             ((i - G0_REGNUM) * 4));
+       }
+    }
+
+  if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1)
+    {
+      for (i = O0_REGNUM; i <= O7_REGNUM; i++)
+       {
+         if (regno == i || regno == -1)
+           regcache_collect (i, regs + REG64_OFFSET_OUT +
+                             ((i - O0_REGNUM) * 4));
+        }
+    }
+
+  /* Responsibility for the stack regs is pushed off onto the caller.  */
+}
+
+void
+sparcnbsd_supply_fpreg32 (char *fpregs, int regno)
+{
+  int i;
+
+  for (i = 0; i <= 31; i++)
+    {
+      if (regno == (FP0_REGNUM + i) || regno == -1)
+       supply_register (FP0_REGNUM + i, fpregs + (i * 4));
+    }
+
+  if (regno == FPS_REGNUM || regno == -1)
+    supply_register (FPS_REGNUM, fpregs + (32 * 4));
+}
+
+void
+sparcnbsd_supply_fpreg64 (char *fpregs, int regno)
+{
+  int i;
+
+  for (i = 0; i <= 31; i++)
+    {
+      if (regno == (FP0_REGNUM + i) || regno == -1)
+       supply_register (FP0_REGNUM + i, fpregs + (i * 4));
+    }
+
+  for (; i <= 47; i++)
+    {
+      if (regno == (FP0_REGNUM + i) || regno == -1)
+       supply_register (FP0_REGNUM + i, fpregs + (32 * 4) + (i * 8));
+    }
+
+  if (regno == FPS_REGNUM || regno == -1)
+    supply_register (FPS_REGNUM, fpregs + (32 * 4) + (16 * 8));
+
+  /* XXX %gsr */
+}
+
+void
+sparcnbsd_fill_fpreg32 (char *fpregs, int regno)
+{
+  int i;
+
+  for (i = 0; i <= 31; i++)
+    {
+      if (regno == (FP0_REGNUM + i) || regno == -1)
+       regcache_collect (FP0_REGNUM + i, fpregs + (i * 4));
+    }
+
+  if (regno == FPS_REGNUM || regno == -1)
+    regcache_collect (FPS_REGNUM, fpregs + (32 * 4));
+}
+
+void
+sparcnbsd_fill_fpreg64 (char *fpregs, int regno)
+{
+  int i;
+
+  for (i = 0; i <= 31; i++)
+    {
+      if (regno == (FP0_REGNUM + i) || regno == -1)
+       regcache_collect (FP0_REGNUM + i, fpregs + (i * 4));
+    }
+
+  for (; i <= 47; i++)
+    {
+      if (regno == (FP0_REGNUM + i) || regno == -1)
+       regcache_collect (FP0_REGNUM + i, fpregs + (32 * 4) + (i * 8));
+    }
+
+  if (regno == FPS_REGNUM || regno == -1)
+    regcache_collect (FPS_REGNUM, fpregs + (32 * 4) + (16 * 8));
+
+  /* XXX %gsr */
+}
+
+/* Unlike other NetBSD implementations, the SPARC port historically used
+   .reg and .reg2 (see bfd/netbsd-core.c), and as such, we can share one
+   routine for a.out and ELF core files.  */
+static void
+fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
+                      CORE_ADDR ignore)
+{
+  int reg_size, fpreg_size;
+
+  if (gdbarch_ptr_bit (current_gdbarch) == 32)
+    {
+      reg_size = (20 * 4);
+      fpreg_size = (33 * 4);
+    }
+  else
+    {
+      reg_size = (20 * 8);
+      fpreg_size = (64 * 4)
+        + 8  /* fsr */
+        + 4  /* gsr */
+        + 4; /* pad */
+    }
+
+  switch (which)
+    {
+    case 0:  /* Integer registers */
+      if (core_reg_size != reg_size)
+       warning ("Wrong size register set in core file.");
+      else if (gdbarch_ptr_bit (current_gdbarch) == 32)
+       sparcnbsd_supply_reg32 (core_reg_sect, -1);
+      else
+       sparcnbsd_supply_reg64 (core_reg_sect, -1);
+      break;
+
+    case 2:  /* Floating pointer registers */
+      if (core_reg_size != fpreg_size)
+       warning ("Wrong size FP register set in core file.");
+      else if (gdbarch_ptr_bit (current_gdbarch) == 32)
+       sparcnbsd_supply_fpreg32 (core_reg_sect, -1);
+      else
+       sparcnbsd_supply_fpreg64 (core_reg_sect, -1);
+      break;
+
+    default:
+      /* Don't know what kind of register request this is; just ignore it.  */
+      break;
+    }
+}
+
+static struct core_fns sparcnbsd_core_fns =
+{
+  bfd_target_unknown_flavour,          /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  fetch_core_registers,                        /* core_read_registers */
+  NULL
+};
+
+static struct core_fns sparcnbsd_elfcore_fns =
+{
+  bfd_target_elf_flavour,              /* core_flavour */
+  default_check_format,                        /* check_format */
+  default_core_sniffer,                        /* core_sniffer */
+  fetch_core_registers,                        /* core_read_registers */
+  NULL
+};
+
+/* FIXME: Need PC_IN_SIGTRAMP() support, but NetBSD/sparc signal trampolines
+   aren't easily identified.  */
+
+static int
+sparcnbsd_get_longjmp_target_32 (CORE_ADDR *pc)
+{
+  CORE_ADDR jb_addr;
+  char buf[4];
+
+  jb_addr = read_register (O0_REGNUM);
+
+  if (target_read_memory (jb_addr + 12, buf, sizeof (buf)))
+    return 0;
+
+  *pc = extract_address (buf, sizeof (buf));
+
+  return 1;
+}
+
+static int
+sparcnbsd_get_longjmp_target_64 (CORE_ADDR *pc)
+{
+  CORE_ADDR jb_addr;
+  char buf[8];
+
+  jb_addr = read_register (O0_REGNUM);
+
+  if (target_read_memory (jb_addr + 16, buf, sizeof (buf)))
+    return 0;
+
+  *pc = extract_address (buf, sizeof (buf));
+
+  return 1;
+}
+
+static int
+sparcnbsd_aout_in_solib_call_trampoline (CORE_ADDR pc, char *name)
+{
+  if (strcmp (name, "_DYNAMIC") == 0)
+    return 1;
+
+  return 0;
+}
+
+static void
+sparcnbsd_init_abi_common (struct gdbarch_info info,
+                           struct gdbarch *gdbarch)
+{
+  set_gdbarch_get_longjmp_target (gdbarch, gdbarch_ptr_bit (gdbarch) == 32 ?
+                                          sparcnbsd_get_longjmp_target_32 :
+                                          sparcnbsd_get_longjmp_target_64);
+}
+
+static void
+sparcnbsd_init_abi_aout (struct gdbarch_info info,
+                         struct gdbarch *gdbarch)
+{
+  sparcnbsd_init_abi_common (info, gdbarch);
+
+  set_gdbarch_in_solib_call_trampoline (gdbarch,
+                                     sparcnbsd_aout_in_solib_call_trampoline);
+}
+
+static void
+sparcnbsd_init_abi_elf (struct gdbarch_info info,
+                        struct gdbarch *gdbarch)
+{
+  sparcnbsd_init_abi_common (info, gdbarch);
+
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+                                        gdbarch_ptr_bit (gdbarch) == 32 ?
+                                nbsd_ilp32_solib_svr4_fetch_link_map_offsets :
+                               nbsd_lp64_solib_svr4_fetch_link_map_offsets);
+}
+
+static enum gdb_osabi
+sparcnbsd_aout_osabi_sniffer (bfd *abfd)
+{
+  if (strcmp (bfd_get_target (abfd), "a.out-sparc-netbsd") == 0)
+    return GDB_OSABI_NETBSD_AOUT;
+
+  return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_sparnbsd_tdep (void)
+{
+  gdbarch_register_osabi_sniffer (bfd_arch_sparc, bfd_target_aout_flavour,
+                                 sparcnbsd_aout_osabi_sniffer);
+
+  gdbarch_register_osabi (bfd_arch_sparc, GDB_OSABI_NETBSD_AOUT,
+                         sparcnbsd_init_abi_aout);
+  gdbarch_register_osabi (bfd_arch_sparc, GDB_OSABI_NETBSD_ELF,
+                         sparcnbsd_init_abi_elf);
+
+  add_core_fns (&sparcnbsd_core_fns);
+  add_core_fns (&sparcnbsd_elfcore_fns);
+}
diff --git a/gdb/sparcnbsd-tdep.h b/gdb/sparcnbsd-tdep.h
new file mode 100644 (file)
index 0000000..bad2d65
--- /dev/null
@@ -0,0 +1,34 @@
+/* Common target dependent code for GDB on SPARC systems running NetBSD.
+   Copyright 2002 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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef SPARCNBSD_TDEP_H
+#define SPARCNBSD_TDEP_H
+
+void sparcnbsd_supply_reg32 (char *, int);
+void sparcnbsd_supply_reg64 (char *, int);
+void sparcnbsd_fill_reg32 (char *, int);
+void sparcnbsd_fill_reg64 (char *, int);
+
+void sparcnbsd_supply_fpreg32 (char *, int);
+void sparcnbsd_supply_fpreg64 (char *, int);
+void sparcnbsd_fill_fpreg32 (char *, int);
+void sparcnbsd_fill_fpreg64 (char *, int);
+
+#endif /* SPARCNBSD_TDEP_H */
diff --git a/gdb/testsuite/gdb.asm/x86_64.inc b/gdb/testsuite/gdb.asm/x86_64.inc
new file mode 100644 (file)
index 0000000..5bcaeae
--- /dev/null
@@ -0,0 +1,39 @@
+       comment "subroutine prologue"
+       .macro gdbasm_enter
+       push    %rbp
+       mov     %rsp,%rbp
+       .endm
+
+       comment "subroutine epilogue"
+       .macro gdbasm_leave
+       pop     %rbp
+       ret
+       .endm
+
+       .macro gdbasm_call subr
+       call    \subr
+       .endm
+
+       .macro gdbasm_several_nops
+       nop
+       nop
+       nop
+       nop
+       .endm
+
+       comment "exit (0)"
+       .macro gdbasm_exit0
+       hlt
+       .endm
+
+       comment "crt0 startup"
+       .macro gdbasm_startup
+       xor     %rbp, %rbp
+       .endm
+
+       comment "Declare a data variable"
+       .macro gdbasm_datavar name value
+       .data
+\name:
+       .long   \value
+       .endm
diff --git a/gdb/testsuite/gdb.base/macscp.exp b/gdb/testsuite/gdb.base/macscp.exp
new file mode 100644 (file)
index 0000000..283fe84
--- /dev/null
@@ -0,0 +1,403 @@
+# Test macro scoping.
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@prep.ai.mit.edu
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile "macscp"
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  {[gdb_compile "${srcdir}/${subdir}/macscp1.c" "${binfile}" executable {debug}] != "" } {
+    gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+
+# Ask GDB to show the current definition of MACRO, and return a list
+# describing the result.
+#
+# The return value has the form {FILE1 FILE2 ... DEF}, which means
+# that MACRO has the definition `DEF', and was defined in `FILE1',
+# which was included from `FILE2', included from ... .
+#
+# If GDB says that MACRO has no definition, return the string `undefined'.
+#
+# If GDB complains that it doesn't have any information about
+# preprocessor macro definitions, return the string `no-macro-info'.
+# 
+# If expect times out waiting for GDB, we return the string `timeout'.
+#
+# If GDB's output doesn't otherwise match what we're expecting, we
+# return the empty string.
+
+proc info_macro {macro} {
+    global gdb_prompt
+    global decimal
+
+    set filepat {macscp[0-9]+\.[ch]}
+    set definition {}
+    set location {}
+
+    send_gdb "info macro ${macro}\n"
+
+    set debug_me 0
+
+    if {$debug_me} {exp_internal 1}
+    gdb_expect {
+        -re "Defined at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" {
+            # `location' and `definition' should be empty when we see
+            # this message.
+            if {[llength $location] == 0 && [llength $definition] == 0} {
+                set location $expect_out(1,string)
+                exp_continue
+            } else {
+                # Exit this expect loop, with a result indicating failure.
+                set definition {}
+            }
+        }
+        -re "The symbol `${macro}' has no definition as a C/C\\+\\+ preprocessor macro\[^\r\n\]*\[\r\n\]" {
+            # `location' and `definition' should be empty when we see
+            # this message.
+            if {[llength $location] == 0 && [llength $definition] == 0} {
+                set definition undefined
+                exp_continue
+            } else {
+                # Exit this expect loop, with a result indicating failure.
+                set definition {}
+            }
+        }
+        -re "^\[\r\n\]*  included at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" {
+            # `location' should *not* be empty when we see this
+            # message.  It should have recorded at least the initial
+            # `Defined at ' message (for definitions) or ` at' message
+            # (for undefined symbols).
+            if {[llength $location] != 0} {
+                lappend location $expect_out(1,string)
+                exp_continue
+            } else {
+                # Exit this expect loop, with a result indicating failure.
+                set definition {}
+            }
+        }
+        -re "^\[\r\n\]*at \[^\r\n\]*(${filepat}):${decimal}\[\r\n\]" {
+            # This appears after a `has no definition' message.
+            # `location' should be empty when we see it.
+            if {[string compare $definition undefined] == 0 \
+                    && [llength $location] == 0} {
+                set location $expect_out(1,string)
+                exp_continue
+            } else {
+                # Exit this expect loop, with a result indicating failure.
+                set definition {}
+            }
+        }
+        -re "#define ${macro} (\[^\r\n\]*)\[\r\n\]" {
+            # `definition' should be empty when we see this message.
+            if {[string compare $definition ""] == 0} {
+                set definition $expect_out(1,string)
+                exp_continue
+            } else {
+                # Exit this expect loop, with a result indicating failure.
+                set definition {}
+            }
+        }
+        -re "has no preprocessor macro information.*$gdb_prompt $" {
+            set definition no-macro-info
+        }
+        -re "$gdb_prompt $" {
+            # Exit the expect loop; let the existing value of `definition'
+            # indicate failure or success.
+        }
+        timeout {
+            set definition timeout
+        }
+    }
+    if {$debug_me} {exp_internal 0}
+
+    switch -exact -- $definition {
+        no-macro-info { return no-macro-info }
+        timeout { return timeout }
+        undefined -
+        default {
+            if {[llength $location] >= 1} {
+                return [concat $location [list $definition]]
+            } else {
+                return {}
+            }
+        }
+    }
+}
+
+
+# Call info_macro to show the definition of MACRO.  Expect a result of
+# EXPECTED.  Use WHERE in pass/fail messages to identify the context.
+# Return non-zero if we should abort the entire test file, or zero if
+# we can continue.
+proc check_macro {macro expected where} {
+    set func_def [info_macro $macro]
+    if {[string compare $func_def $expected] == 0} {
+        pass "info macro $macro $where"
+    } else {
+        switch -exact -- $func_def {
+            no-macro-info {
+                xfail "executable includes no macro debugging information"
+                return 1
+            }
+            timeout {
+                fail "info macro $macro $where (timeout)"
+            }
+            default {
+                fail "info macro $macro $where"
+            }
+        }
+    }
+    return 0
+}
+    
+
+# List the function FUNC, and then show the definition of MACRO,
+# expecting the result EXPECTED.
+proc list_and_check_macro {func macro expected} {
+    gdb_test "list $func" ".*${func}.*"
+    return [check_macro $macro $expected "after `list $func'"]
+}
+
+
+if {[list_and_check_macro main WHERE {macscp1.c {before macscp1_3}}]} {
+    return 0
+}
+list_and_check_macro macscp2_2 WHERE {macscp2.h macscp1.c {before macscp2_2}}
+list_and_check_macro macscp3_2 WHERE {macscp3.h macscp1.c {before macscp3_2}}
+
+
+# Although GDB's macro table structures distinguish between multiple
+# #inclusions of the same file, GDB's other structures don't.  So the
+# `list' command here doesn't reliably select one #inclusion or the
+# other, even though it could.  It would be nice to eventually change
+# GDB's structures to handle this correctly.
+gdb_test "list macscp4_2_from_macscp2" ".*macscp4_2_, MACSCP4_INCLUSION.*"
+switch -exact -- [info_macro WHERE] {
+    {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}} {
+        pass "info macro WHERE after `list macscp_4_2_from_macscp2'"
+    }
+    {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}} {
+        # setup_kfail "gdb/555"
+        fail "info macro WHERE after `list macscp_4_2_from_macscp2' (gdb/555)"
+    }
+    timeout { 
+        fail "info macro WHERE after `list macscp_4_2_from_macscp2' (timeout)"
+    }
+    default { fail "info macro WHERE after `list macscp_4_2_from_macscp2'" }
+}
+
+gdb_test "list macscp4_2_from_macscp3" ".*macscp4_2_, MACSCP4_INCLUSION.*"
+switch -exact -- [info_macro WHERE] {
+    {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}} {
+        pass "info macro WHERE after `list macscp_4_2_from_macscp3'"
+    }
+    {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}} {
+        # setup_kfail "gdb/555"
+        fail "info macro WHERE after `list macscp_4_2_from_macscp3' (gdb/555)"
+    }
+    timeout {
+        fail "info macro WHERE after `list macscp_4_2_from_macscp3' (timeout)"
+    }
+    default { fail "info macro WHERE after `list macscp_4_2_from_macscp3'" }
+}
+
+
+#### Test the selection of the macro scope by the current frame.
+
+### A table of functions, in the order they will be reached, which is
+### also the order they appear in the preprocessed output.  Each entry
+### has the form {FUNCNAME WHERE KFAILWHERE}, where:
+### - FUNCNAME is the name of the function,
+### - WHERE is the definition we expect to see for the macro `WHERE', as
+###   returned by `info_macro', and
+### - KFAILWHERE is an alternate definition which should be reported
+###   as a `known failure', due to GDB's inability to distinguish multiple
+###   #inclusions of the same file.
+### KFAILWHERE may be omitted.
+
+set funcs {
+    {
+        macscp1_1
+        {macscp1.c {before macscp1_1}}
+    }
+    {
+        macscp2_1
+        {macscp2.h macscp1.c {before macscp2_1}}
+    }
+    {
+        macscp4_1_from_macscp2
+        {macscp4.h macscp2.h macscp1.c {before macscp4_1_..., from macscp2.h}}
+        {macscp4.h macscp3.h macscp1.c {before macscp4_1_..., from macscp3.h}}
+    }
+    {
+        macscp4_2_from_macscp2
+        {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}}
+        {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}}
+    }
+    {
+        macscp2_2
+        {macscp2.h macscp1.c {before macscp2_2}}
+    }
+    {
+        macscp1_2
+        {macscp1.c {before macscp1_2}}
+    }
+    {
+        macscp3_1
+        {macscp3.h macscp1.c {before macscp3_1}}
+    }
+    {
+        macscp4_1_from_macscp3
+        {macscp4.h macscp3.h macscp1.c {before macscp4_1_..., from macscp3.h}}
+        {macscp4.h macscp2.h macscp1.c {before macscp4_1_..., from macscp2.h}}
+    }
+    {
+        macscp4_2_from_macscp3
+        {macscp4.h macscp3.h macscp1.c {before macscp4_2_..., from macscp3.h}}
+        {macscp4.h macscp2.h macscp1.c {before macscp4_2_..., from macscp2.h}}
+    }
+    {
+        macscp3_2
+        {macscp3.h macscp1.c {before macscp3_2}}
+    }
+    {
+        macscp1_3
+        {macscp1.c {before macscp1_3}}
+    }
+}
+
+
+# Start the program running.
+if {! [runto_main]} {
+    fail "macro tests suppressed: couldn't run to main"
+    return 0
+}
+
+# Set a breakpoint on each of the functions.
+foreach func_entry $funcs {
+    set func [lindex $func_entry 0]
+    gdb_test "break $func" "Breakpoint.*"
+}
+
+# Run to each of the breakpoints and check the definition (or lack
+# thereof) of each macro.
+for {set i 0} {$i < [llength $funcs]} {incr i} {
+    set func_entry [lindex $funcs $i]
+    set func [lindex $func_entry 0]
+    set expected [lindex $func_entry 1]
+    set kfail_expected [lindex $func_entry 2]
+
+    # Run to the breakpoint for $func.
+    gdb_test "continue" "Breakpoint $decimal, $func .*" "continue to $func"
+
+    # Check the macro WHERE.
+    set result [info_macro WHERE]
+    if {[string compare $result $expected] == 0} {
+        pass "info macro WHERE stopped in $func"
+    } elseif {[string compare $result $kfail_expected] == 0} {
+        # setup_kfail "gdb/555"
+        fail "info macro WHERE stopped in $func (gdb/555)"
+    } elseif {[string compare $result timeout] == 0} {
+        fail "info macro WHERE stopped in $func (timeout)"
+    } else {
+        fail "info macro WHERE stopped in $func"
+    }
+
+    # Check that the BEFORE_<func> macros for all prior functions are
+    # #defined, and that those for all subsequent functions are not.
+    for {set j 0} {$j < [llength $funcs]} {incr j} {
+        if {$j != $i} {
+            set func_j_entry [lindex $funcs $j]
+            set func_j [lindex $func_j_entry 0]
+
+            set before_macro "BEFORE_[string toupper $func_j]"
+            set test_name \
+                    "$before_macro defined/undefined when stopped at $func"
+            set result [info_macro $before_macro]
+
+            # We can't get the right scope info when we're stopped in
+            # the macro4_ functions.
+            if {[string match macscp4_* $func]} {
+                # setup_kfail "gdb/555"
+                set test_name "$test_name (gdb/555)"
+            }
+            if {$j < $i} {
+                if {[llength $result] >= 2 && \
+                        [string compare [lindex $result end] {}] == 0} {
+                    pass $test_name
+                } elseif {[string compare $result timeout] == 0} {
+                    fail "$test_name (timeout)"
+                } else {
+                    fail "$test_name"
+                }
+            } elseif {$j > $i} {
+                switch -- [lindex $result end] {
+                    undefined { pass $test_name }
+                    timeout { fail "$test_name (timeout)" }
+                    default { 
+                        fail "$test_name"
+                    }
+                }
+            }
+
+            set until_macro "UNTIL_[string toupper $func_j]"
+            set test_name \
+                    "$until_macro defined/undefined when stopped at $func"
+            set result [info_macro $until_macro]
+
+            # We can't get the right scope info when we're stopped in
+            # the macro4_ functions.
+            if {[string match macscp4_* $func]} {
+                # setup_kfail "gdb/555"
+                set test_name "$test_name (gdb/555)"
+            }
+            if {$j <= $i} {
+                switch -- [lindex $result end] {
+                    undefined { pass $test_name }
+                    timeout { fail "$test_name (timeout)" }
+                    default { 
+                        fail "$test_name"
+                    }
+                }
+            } elseif {$j > $i} {
+                if {[llength $result] >= 2 && \
+                        [string compare [lindex $result end] {}] == 0} {
+                    pass $test_name
+                } elseif {[string compare $result timeout] == 0} {
+                    fail "$test_name (timeout)"
+                } else {
+                    fail "$test_name"
+                }
+            }
+        }
+    }
+}
diff --git a/gdb/testsuite/gdb.base/macscp1.c b/gdb/testsuite/gdb.base/macscp1.c
new file mode 100644 (file)
index 0000000..89a1b07
--- /dev/null
@@ -0,0 +1,80 @@
+#include <stdio.h>
+
+#define SPLICE(a, b) INNER_SPLICE(a, b)
+#define INNER_SPLICE(a, b) a ## b
+#define STRINGIFY(a) INNER_STRINGIFY(a)
+#define INNER_STRINGIFY(a) #a
+
+/* A macro named UNTIL_<func> is #defined until just before the
+   definition of the function <func>.
+
+   A macro named BEFORE_<func> is not #defined until just before the
+   definition of <func>.
+
+   The macro WHERE is redefined before each function <func> to the
+   token list ``before <func>''.
+
+   The macscp IN_MACSCP2_H and IN_MACSCP3_H are defined while
+   processing those header files; macscp4.h uses them to choose
+   appropriate function names, output strings, and macro definitions.  */
+
+#define UNTIL_MACSCP1_1
+#define UNTIL_MACSCP2_1
+#define UNTIL_MACSCP4_1_FROM_MACSCP2
+#define UNTIL_MACSCP4_2_FROM_MACSCP2
+#define UNTIL_MACSCP2_2
+#define UNTIL_MACSCP1_2
+#define UNTIL_MACSCP3_1
+#define UNTIL_MACSCP4_1_FROM_MACSCP3
+#define UNTIL_MACSCP4_2_FROM_MACSCP3
+#define UNTIL_MACSCP3_2
+#define UNTIL_MACSCP1_3
+
+#define WHERE before macscp1_1
+#define BEFORE_MACSCP1_1
+#undef UNTIL_MACSCP1_1
+void
+macscp1_1 ()
+{
+  puts ("macscp1_1");
+}
+
+#include "macscp2.h"
+
+#undef WHERE
+#define WHERE before macscp1_2
+#define BEFORE_MACSCP1_2
+#undef UNTIL_MACSCP1_2
+void
+macscp1_2 ()
+{
+  puts ("macscp1_2");
+}
+
+#include "macscp3.h"
+
+#undef WHERE
+#define WHERE before macscp1_3
+#define BEFORE_MACSCP1_3
+#undef UNTIL_MACSCP1_3
+void
+macscp1_3 ()
+{
+  puts ("macscp1_3");
+}
+
+int
+main (int argc, char **argv)
+{
+  macscp1_1 ();
+  macscp2_1 ();
+  macscp4_1_from_macscp2 ();
+  macscp4_2_from_macscp2 ();
+  macscp2_2 ();
+  macscp1_2 ();
+  macscp3_1 ();
+  macscp4_1_from_macscp3 ();
+  macscp4_2_from_macscp3 ();
+  macscp3_2 ();
+  macscp1_3 ();
+}
diff --git a/gdb/testsuite/gdb.base/macscp2.h b/gdb/testsuite/gdb.base/macscp2.h
new file mode 100644 (file)
index 0000000..ef0feaa
--- /dev/null
@@ -0,0 +1,25 @@
+#define IN_MACSCP2_H
+
+#undef WHERE
+#define WHERE before macscp2_1
+#define BEFORE_MACSCP2_1
+#undef UNTIL_MACSCP2_1
+void
+macscp2_1 ()
+{
+  puts ("macscp2_1");
+}
+
+#include "macscp4.h"
+
+#undef WHERE
+#define WHERE before macscp2_2
+#define BEFORE_MACSCP2_2
+#undef UNTIL_MACSCP2_2
+void
+macscp2_2 ()
+{
+  puts ("macscp2_2");
+}
+
+#undef IN_MACSCP2_H
diff --git a/gdb/testsuite/gdb.base/macscp3.h b/gdb/testsuite/gdb.base/macscp3.h
new file mode 100644 (file)
index 0000000..ebfcc6e
--- /dev/null
@@ -0,0 +1,25 @@
+#define IN_MACSCP3_H
+
+#undef WHERE
+#define WHERE before macscp3_1
+#define BEFORE_MACSCP3_1
+#undef UNTIL_MACSCP3_1
+void
+macscp3_1 ()
+{
+  puts ("macscp3_1");
+}
+
+#include "macscp4.h"
+
+#undef WHERE
+#define WHERE before macscp3_2
+#define BEFORE_MACSCP3_2
+#undef UNTIL_MACSCP3_2
+void
+macscp3_2 ()
+{
+  puts ("macscp3_2");
+}
+
+#undef IN_MACSCP3_H
diff --git a/gdb/testsuite/gdb.base/macscp4.h b/gdb/testsuite/gdb.base/macscp4.h
new file mode 100644 (file)
index 0000000..5302d8d
--- /dev/null
@@ -0,0 +1,44 @@
+/* Put together a macro we can use as part of function names.  */
+#undef MACSCP4_INCLUSION
+#ifdef IN_MACSCP2_H
+#define MACSCP4_INCLUSION from_macscp2
+#endif
+#ifdef IN_MACSCP3_H
+#define MACSCP4_INCLUSION from_macscp3
+#endif
+
+#undef WHERE
+#ifdef IN_MACSCP2_H
+#define WHERE before macscp4_1_..., from macscp2.h
+#define BEFORE_MACSCP4_1_FROM_MACSCP2
+#undef UNTIL_MACSCP4_1_FROM_MACSCP2
+#endif
+#ifdef IN_MACSCP3_H
+#define WHERE before macscp4_1_..., from macscp3.h
+#define BEFORE_MACSCP4_1_FROM_MACSCP3
+#undef UNTIL_MACSCP4_1_FROM_MACSCP3
+#endif
+void
+SPLICE (macscp4_1_, MACSCP4_INCLUSION) ()
+{
+  puts ("macscp4_1_" STRINGIFY(MACSCP4_INCLUSION));
+}
+
+#undef WHERE
+#ifdef IN_MACSCP2_H
+#define WHERE before macscp4_2_..., from macscp2.h
+#define BEFORE_MACSCP4_2_FROM_MACSCP2
+#undef UNTIL_MACSCP4_2_FROM_MACSCP2
+#endif
+#ifdef IN_MACSCP3_H
+#define WHERE before macscp4_2_..., from macscp3.h
+#define BEFORE_MACSCP4_2_FROM_MACSCP3
+#undef UNTIL_MACSCP4_2_FROM_MACSCP3
+#endif
+void
+SPLICE (macscp4_2_, MACSCP4_INCLUSION) ()
+{
+  puts ("macscp4_2_" STRINGIFY(MACSCP4_INCLUSION));
+}
+
+#define DEFINED_IN_MACSCP4 this was defined in macscp4.h.
diff --git a/gdb/testsuite/gdb.c++/m-data.cc b/gdb/testsuite/gdb.c++/m-data.cc
new file mode 100644 (file)
index 0000000..d995027
--- /dev/null
@@ -0,0 +1,53 @@
+// 2002-05-13
+
+namespace __gnu_test
+{
+  enum         region { oriental, egyptian, greek, etruscan, roman };
+
+  // Test one.
+  class gnu_obj_1
+  {
+  protected:
+    typedef region antiquities;
+    const bool                 test;
+    const int          key1;
+    long                       key2;
+
+    antiquities        value;
+
+  public:
+    gnu_obj_1(antiquities a, long l): test(true), key1(5), key2(l), value(a) {}
+  };
+
+  // Test two.
+  template<typename T>
+    class gnu_obj_2: public virtual gnu_obj_1
+    {
+    protected:
+      antiquities      value_derived;
+      
+    public:
+      gnu_obj_2(antiquities b): gnu_obj_1(oriental, 7), value_derived(b) { }
+    }; 
+
+  // Test three.
+  template<typename T>
+    class gnu_obj_3
+    {
+    protected:
+      typedef region antiquities;
+      gnu_obj_2<int>           data;
+      
+    public:
+      gnu_obj_3(antiquities b): data(etruscan) { }
+    }; 
+} 
+
+int main()
+{
+  using namespace __gnu_test;
+  gnu_obj_1            test1(egyptian, 4589);
+  gnu_obj_2<long>      test2(roman);
+  gnu_obj_3<long>      test3(greek);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.c++/m-data.exp b/gdb/testsuite/gdb.c++/m-data.exp
new file mode 100644 (file)
index 0000000..ac68258
--- /dev/null
@@ -0,0 +1,112 @@
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Tests for member data
+# 2002-05-13  Benjamin Kosnik  <bkoz@redhat.com>
+
+# This file is part of the gdb testsuite
+
+if $tracelevel then {
+        strace $tracelevel
+        }
+
+if { [skip_cplus_tests] } { continue }
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "m-data"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+     gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+# One.
+gdb_test "break 50" "Breakpoint \[0-9\]*.*line 50\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*m-data\\.cc:50\r\n.*" "continue to 50"
+
+# simple object, const bool
+gdb_test "print test1.test" "\\$\[0-9\]* = true" "simple object, const bool"
+
+# simple object, const int
+gdb_test "print test1.key1" "\\$\[0-9\]* = 5" "simple object, const int"
+
+# simple object, long
+gdb_test "print test1.key2" "\\$\[0-9\]* = 4589" "simple object, long"
+
+# simple object, enum
+gdb_test "print test1.value" "\\$\[0-9\]* = egyptian" "simple object, enum"
+
+# Two.
+gdb_test "break 51" "Breakpoint \[0-9\]*.*line 51\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*m-data\\.cc:51\r\n.*" "continue to 51"
+
+# derived template object, base const bool
+gdb_test "print test2.test" "\\$\[0-9\]* = true" "derived template object, base const bool"
+
+# derived template object, base const int
+gdb_test "print test2.key1" "\\$\[0-9\]* = 5" "derived template object, base const int"
+
+# derived template object, base long
+gdb_test "print test2.key2" "\\$\[0-9\]* = 7" "derived template object, base long"
+
+# derived template object, base enum
+gdb_test "print test2.value" "\\$\[0-9\]* = oriental" "derived template object, base enum"
+
+# derived template object, enum
+gdb_test "print test2.value_derived" "\\$\[0-9\]* = roman" "derived template object, derived enum"
+
+# Three.
+gdb_test "break 52" "Breakpoint \[0-9\]*.*line 52\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*m-data\\.cc:52\r\n.*" "continue to 52"
+
+# template object, derived template data member's base const bool
+gdb_test "print test3.data.test" "\\$\[0-9\]* = true" "template object, const bool"
+
+# template object, derived template data member's base const int
+gdb_test "print test3.data.key1" "\\$\[0-9\]* = 5" "template object, const int"
+
+# template object, derived template data member's base long
+gdb_test "print test3.data.key2" "\\$\[0-9\]* = 7" "template object, long"
+
+# template object, derived template data member's base enum
+gdb_test "print test3.data.value" "\\$\[0-9\]* = oriental" "template object, base enum"
+
+# template object, derived template data member's enum
+gdb_test "print test3.data.value_derived" "\\$\[0-9]\* = etruscan" "template object, derived enum"
+
+gdb_exit
+return 0
diff --git a/gdb/testsuite/gdb.c++/m-static.cc b/gdb/testsuite/gdb.c++/m-static.cc
new file mode 100644 (file)
index 0000000..2433801
--- /dev/null
@@ -0,0 +1,72 @@
+// 2002-05-13
+
+namespace __gnu_test
+{
+  enum         region { oriental, egyptian, greek, etruscan, roman };
+
+  // Test one.
+  class gnu_obj_1
+  {
+  protected:
+    typedef region antiquities;
+    static const bool  test = true;
+    static const int   key1 = 5;
+    static long        key2;
+
+    static antiquities         value;
+
+  public:
+    gnu_obj_1(antiquities a, long l) {}
+  };
+
+  const bool gnu_obj_1::test;
+  const int gnu_obj_1::key1;
+  long gnu_obj_1::key2 = 77;
+  gnu_obj_1::antiquities gnu_obj_1::value = oriental;
+
+
+  // Test two.
+  template<typename T>
+    class gnu_obj_2: public virtual gnu_obj_1
+    {
+    public:
+      static antiquities       value_derived;
+      
+    public:
+      gnu_obj_2(antiquities b): gnu_obj_1(oriental, 7) { }
+    }; 
+
+  template<typename T>
+    typename gnu_obj_2<T>::antiquities gnu_obj_2<T>::value_derived = etruscan;
+
+  // Test three.
+  template<typename T>
+    class gnu_obj_3
+    {
+    public:
+      typedef region antiquities;
+      static gnu_obj_2<int>    data;
+      
+    public:
+      gnu_obj_3(antiquities b) { }
+    }; 
+
+  template<typename T>
+    gnu_obj_2<int> gnu_obj_3<T>::data(etruscan);
+} 
+
+// instantiate templates explicitly so their static members will exist
+template class __gnu_test::gnu_obj_2<int>;
+template class __gnu_test::gnu_obj_2<long>;
+template class __gnu_test::gnu_obj_3<long>;
+
+int main()
+{
+  using namespace __gnu_test;
+
+  gnu_obj_1            test1(egyptian, 4589);
+  gnu_obj_2<long>      test2(roman);
+  gnu_obj_3<long>      test3(greek);
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.c++/m-static.exp b/gdb/testsuite/gdb.c++/m-static.exp
new file mode 100644 (file)
index 0000000..c05983b
--- /dev/null
@@ -0,0 +1,112 @@
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Tests for member static data
+# 2002-05-13  Benjamin Kosnik  <bkoz@redhat.com>
+
+# This file is part of the gdb testsuite
+
+if $tracelevel then {
+        strace $tracelevel
+        }
+
+if { [skip_cplus_tests] } { continue }
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "m-static"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+     gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+# One.
+gdb_test "break 68" "Breakpoint \[0-9\]*.*line 68\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*m-static\\.cc:68\r\n.*" "continue to 68"
+
+# simple object, static const bool
+gdb_test "print test1.test" "\\$\[0-9\]* = true" "simple object, static const bool"
+
+# simple object, static const int
+gdb_test "print test1.key1" "\\$\[0-9\]* = 5" "simple object, static const int"
+
+# simple object, static long
+gdb_test "print test1.key2" "\\$\[0-9\]* = 77" "simple object, static long"
+
+# simple object, static enum
+gdb_test "print test1.value" "\\$\[0-9\]* = oriental" "simple object, static enum"
+
+# Two.
+gdb_test "break 69" "Breakpoint \[0-9\]*.*line 69\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*m-static\\.cc:69\r\n.*" "continue to 69"
+
+# derived template object, base static const bool
+gdb_test "print test2.test" "\\$\[0-9\]* = true" "derived template object, base static const bool"
+
+# derived template object, base static const int
+gdb_test "print test2.key1" "\\$\[0-9\]* = 5" "derived template object, base static const int"
+
+# derived template object, base static long
+gdb_test "print test2.key2" "\\$\[0-9\]* = 77" "derived template object, base static long"
+
+# derived template object, base static enum
+gdb_test "print test2.value" "\\$\[0-9\].* = oriental" "derived template object, base static enum"
+
+# derived template object, static enum
+gdb_test "print test2.value_derived" "\\$\[0-9\].* = etruscan" "derived template object, static enum"
+
+# Three.
+gdb_test "break 71" "Breakpoint \[0-9\]*.*line 71\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*m-static\\.cc:71\r\n.*" "continue to 71"
+
+# template object, static derived template data member's base static const bool
+gdb_test "print test3.data.test" "\\$\[0-9\].* = true" "template object, static const bool"
+
+# template object, static derived template data member's base static const int
+gdb_test "print test3.data.key1" "\\$\[0-9\].* = 5" "template object, static const int"
+
+# template object, static derived template data member's base static long
+gdb_test "print test3.data.key2" "\\$\[0-9\].* = 77" "template object, static long"
+
+# template object, static derived template data member's base static enum
+gdb_test "print test3.data.value" "\\$\[0-9\].* = oriental" "template object, static enum"
+
+#  template object, static derived template data member's static enum
+gdb_test "print test3.data.value_derived" "\\$\[0-9\].* = etruscan" "template object, static derived enum"
+
+gdb_exit
+return 0
diff --git a/gdb/testsuite/gdb.c++/try_catch.cc b/gdb/testsuite/gdb.c++/try_catch.cc
new file mode 100644 (file)
index 0000000..9a9c737
--- /dev/null
@@ -0,0 +1,126 @@
+// 2002-05-27
+
+#include <exception>
+#include <stdexcept>
+#include <string>
+
+namespace __gnu_test
+{
+  enum         region { oriental, egyptian, greek, etruscan, roman };
+
+  // Test one.
+  class gnu_obj_1
+  {
+  public:
+    typedef region antiquities;
+    const bool                 test;
+    const int          key1;
+    long                       key2;
+
+    antiquities        value;
+
+    gnu_obj_1(antiquities a, long l): test(true), key1(5), key2(l), value(a) {}
+  };
+
+  // Test two.
+  template<typename T>
+    class gnu_obj_2: public virtual gnu_obj_1
+    {
+    public:
+      antiquities      value_derived;
+      
+      gnu_obj_2(antiquities b): gnu_obj_1(oriental, 7), value_derived(b) { }
+    }; 
+
+  // Test three.
+  template<typename T>
+    class gnu_obj_3
+    {
+    public:
+      typedef region antiquities;
+      gnu_obj_2<int>           data;
+      
+      gnu_obj_3(antiquities b): data(etruscan) { }
+    }; 
+} 
+
+int main()
+{
+  using namespace __gnu_test;
+
+  bool test = true;
+  const int i = 5;
+  int j = i;
+  gnu_obj_2<long> test2(roman);
+  gnu_obj_3<long> test3(greek);
+
+  // 1
+  try
+    {
+      ++j;
+      throw gnu_obj_1(egyptian, 4589);      
+    }
+  catch (gnu_obj_1& obj)
+    {
+      ++j;
+      if (obj.value != egyptian)
+       test &= false;
+      if (obj.key2 != 4589)
+       test &= false;     
+    }
+  catch (...)
+    {
+      j = 0;
+      test &= false;
+    }
+
+  // 2
+  try
+    {
+      ++j;
+      try
+       {
+         ++j;
+         try
+           {
+             ++j;
+             throw gnu_obj_1(egyptian, 4589); 
+           }
+         catch (gnu_obj_1& obj)
+           {
+             ++j;
+             if (obj.value != egyptian)
+               test &= false;
+             if (obj.key2 != 4589)
+               test &= false;     
+           }
+       }
+      catch (gnu_obj_1& obj)
+       {
+         ++j;
+         if (obj.value != egyptian)
+           test &= false;
+         if (obj.key2 != 4589)
+           test &= false;     
+       }
+    }
+  catch (...)
+    {
+      j = 0;
+      test &= false;
+    }
+
+  // 3 use standard library
+  using namespace std;
+  try
+    {
+      if (j < 100)
+       throw invalid_argument("gdb.1");
+    }
+  catch (exception& obj)
+    {
+      if (obj.what() != "gdb.1")
+       test &= false;
+    }
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.c++/try_catch.exp b/gdb/testsuite/gdb.c++/try_catch.exp
new file mode 100644 (file)
index 0000000..e024132
--- /dev/null
@@ -0,0 +1,84 @@
+# Copyright 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# Tests for member data
+# 2002-05-27  Benjamin Kosnik  <bkoz@redhat.com>
+
+# This file is part of the gdb testsuite
+
+if $tracelevel then {
+        strace $tracelevel
+        }
+
+if { [skip_cplus_tests] } { continue }
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "try_catch"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+     gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+if [get_compiler_info ${binfile} "c++"] {
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+# One.
+
+gdb_test "break 61" "Breakpoint \[0-9\]*.*line 61\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:61\r\n.*" "continue to 61"
+
+gdb_test "break 66" "Breakpoint \[0-9\]*.*line 66\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:66\r\n.*" "continue to 66"
+
+gdb_test "break 80" "Breakpoint \[0-9\]*.*line 80\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:80\r\n.*" "continue to 80"
+
+gdb_test "break 83" "Breakpoint \[0-9\]*.*line 83\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:83\r\n.*" "continue to 83"
+
+gdb_test "break 87" "Breakpoint \[0-9\]*.*line 87\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:87\r\n.*" "continue to 87"
+
+gdb_test "break 92" "Breakpoint \[0-9\]*.*line 92\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:92\r\n.*" "continue to 92"
+
+gdb_test "break 118" "Breakpoint \[0-9\]*.*line 118\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:118\r\n.*" "continue to 118"
+
+gdb_test "break 122" "Breakpoint \[0-9\]*.*line 122\\."
+gdb_test "continue" "Continuing\\.\r\n\r\nBreakpoint.*at.*try_catch\\.cc:122\r\n.*" "continue to 122"
+
+gdb_exit
+return 0
diff --git a/include/elf/dlx.h b/include/elf/dlx.h
new file mode 100644 (file)
index 0000000..562f600
--- /dev/null
@@ -0,0 +1,53 @@
+/* DLX support for BFD.
+   Copyright 2002 Free Software Foundation, Inc.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _ELF_DLX_H
+#define _ELF_DLX_H
+
+#include "elf/reloc-macros.h"
+
+#if 0
+START_RELOC_NUMBERS (elf_dlx_reloc_type)
+     RELOC_NUMBER (R_DLX_NONE,            0)
+     RELOC_NUMBER (R_DLX_RELOC_16,        1)
+     RELOC_NUMBER (R_DLX_RELOC_26,        2)
+     RELOC_NUMBER (R_DLX_RELOC_32,        3)
+     RELOC_NUMBER (R_DLX_GNU_VTINHERIT,   4)
+     RELOC_NUMBER (R_DLX_GNU_VTENTRY,     5)
+     RELOC_NUMBER (R_DLX_RELOC_16_HI,     6)
+     RELOC_NUMBER (R_DLX_RELOC_16_LO,     7)
+     RELOC_NUMBER (R_DLX_RELOC_16_PCREL,  8)
+     RELOC_NUMBER (R_DLX_RELOC_26_PCREL,  9)
+END_RELOC_NUMBERS (R_DLX_max)
+#else
+START_RELOC_NUMBERS (elf_dlx_reloc_type)
+     RELOC_NUMBER (R_DLX_NONE,            0)
+     RELOC_NUMBER (R_DLX_RELOC_8,         1)
+     RELOC_NUMBER (R_DLX_RELOC_16,        2)
+     RELOC_NUMBER (R_DLX_RELOC_32,        3)
+     RELOC_NUMBER (R_DLX_GNU_VTINHERIT,   4)
+     RELOC_NUMBER (R_DLX_GNU_VTENTRY,     5)
+     RELOC_NUMBER (R_DLX_RELOC_16_HI,     6)
+     RELOC_NUMBER (R_DLX_RELOC_16_LO,     7)
+     RELOC_NUMBER (R_DLX_RELOC_16_PCREL,  8)
+     RELOC_NUMBER (R_DLX_RELOC_26_PCREL,  9)
+END_RELOC_NUMBERS (R_DLX_max)
+#endif /* 0 */
+
+#endif /* _ELF_DLX_H */
diff --git a/include/elf/vax.h b/include/elf/vax.h
new file mode 100644 (file)
index 0000000..aba5d9f
--- /dev/null
@@ -0,0 +1,51 @@
+/* VAX ELF support for BFD.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   Contributed by Matt Thomas <matt@3am-software.com>.
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef _ELF_VAX_H
+#define _ELF_VAX_H
+
+#include "elf/reloc-macros.h"
+
+/* Relocation types.  */
+START_RELOC_NUMBERS (elf_vax_reloc_type)
+  RELOC_NUMBER (R_VAX_NONE, 0)         /* No reloc */
+  RELOC_NUMBER (R_VAX_32, 1)           /* Direct 32 bit  */
+  RELOC_NUMBER (R_VAX_16, 2)           /* Direct 16 bit  */
+  RELOC_NUMBER (R_VAX_8, 3)            /* Direct 8 bit  */
+  RELOC_NUMBER (R_VAX_PC32, 4)         /* PC relative 32 bit */
+  RELOC_NUMBER (R_VAX_PC16, 5)         /* PC relative 16 bit */
+  RELOC_NUMBER (R_VAX_PC8, 6)          /* PC relative 8 bit */
+  RELOC_NUMBER (R_VAX_GOT32, 7)                /* 32 bit PC relative GOT entry */
+  RELOC_NUMBER (R_VAX_PLT32, 13)       /* 32 bit PC relative PLT address */
+  RELOC_NUMBER (R_VAX_COPY, 19)                /* Copy symbol at runtime */
+  RELOC_NUMBER (R_VAX_GLOB_DAT, 20)    /* Create GOT entry */
+  RELOC_NUMBER (R_VAX_JMP_SLOT, 21)    /* Create PLT entry */
+  RELOC_NUMBER (R_VAX_RELATIVE, 22)    /* Adjust by program base */
+  /* These are GNU extensions to enable C++ vtable garbage collection.  */
+  RELOC_NUMBER (R_VAX_GNU_VTINHERIT, 23)
+  RELOC_NUMBER (R_VAX_GNU_VTENTRY, 24)
+END_RELOC_NUMBERS (R_VAX_max)   
+
+/* Processor specific flags for the ELF header e_flags field.  */
+#define EF_NONPIC              0x0001  /* Object contains non-PIC code */
+#define EF_DFLOAT              0x0100  /* Object contains D-Float insn.  */
+#define EF_GFLOAT              0x0200  /* Object contains G-Float insn.  */
+
+#endif
diff --git a/include/gdb/callback.h b/include/gdb/callback.h
new file mode 100644 (file)
index 0000000..3075284
--- /dev/null
@@ -0,0 +1,270 @@
+/* Remote target system call callback support.
+   Copyright 1997 Free Software Foundation, Inc.
+   Contributed by Cygnus Solutions.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* This interface isn't intended to be specific to any particular kind
+   of remote (hardware, simulator, whatever).  As such, support for it
+   (e.g. sim/common/callback.c) should *not* live in the simulator source
+   tree, nor should it live in the gdb source tree.  */
+
+/* There are various ways to handle system calls:
+
+   1) Have a simulator intercept the appropriate trap instruction and
+   directly perform the system call on behalf of the target program.
+   This is the typical way of handling system calls for embedded targets.
+   [Handling system calls for embedded targets isn't that much of an
+   oxymoron as running compiler testsuites make use of the capability.]
+
+   This method of system call handling is done when STATE_ENVIRONMENT
+   is ENVIRONMENT_USER.
+
+   2) Have a simulator emulate the hardware as much as possible.
+   If the program running on the real hardware communicates with some sort
+   of target manager, one would want to be able to run this program on the
+   simulator as well.
+
+   This method of system call handling is done when STATE_ENVIRONMENT
+   is ENVIRONMENT_OPERATING.
+*/
+
+#ifndef CALLBACK_H
+#define CALLBACK_H
+
+/* ??? The reason why we check for va_start here should be documented.  */
+
+#ifndef va_start
+#include <ansidecl.h>
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#endif
+\f
+/* Mapping of host/target values.  */
+/* ??? For debugging purposes, one might want to add a string of the
+   name of the symbol.  */
+
+typedef struct {
+  int host_val;
+  int target_val;
+} CB_TARGET_DEFS_MAP;
+
+#define MAX_CALLBACK_FDS 10
+
+/* Forward decl for stat/fstat.  */
+struct stat;
+
+typedef struct host_callback_struct host_callback;
+
+struct host_callback_struct 
+{
+  int (*close) PARAMS ((host_callback *,int));
+  int (*get_errno) PARAMS ((host_callback *));
+  int (*isatty) PARAMS ((host_callback *, int));
+  int (*lseek) PARAMS ((host_callback *, int, long , int));
+  int (*open) PARAMS ((host_callback *, const char*, int mode));
+  int (*read) PARAMS ((host_callback *,int,  char *, int));
+  int (*read_stdin) PARAMS (( host_callback *, char *, int));
+  int (*rename) PARAMS ((host_callback *, const char *, const char *));
+  int (*system) PARAMS ((host_callback *, const char *));
+  long (*time) PARAMS ((host_callback *, long *));
+  int (*unlink) PARAMS ((host_callback *, const char *));
+  int (*write) PARAMS ((host_callback *,int, const char *, int));
+  int (*write_stdout) PARAMS ((host_callback *, const char *, int));
+  void (*flush_stdout) PARAMS ((host_callback *));
+  int (*write_stderr) PARAMS ((host_callback *, const char *, int));
+  void (*flush_stderr) PARAMS ((host_callback *));
+  int (*stat) PARAMS ((host_callback *, const char *, struct stat *));
+  int (*fstat) PARAMS ((host_callback *, int, struct stat *));
+
+  /* When present, call to the client to give it the oportunity to
+     poll any io devices for a request to quit (indicated by a nonzero
+     return value). */
+  int (*poll_quit) PARAMS ((host_callback *));
+
+  /* Used when the target has gone away, so we can close open
+     handles and free memory etc etc.  */
+  int (*shutdown) PARAMS ((host_callback *));
+  int (*init)     PARAMS ((host_callback *));
+
+  /* depreciated, use vprintf_filtered - Talk to the user on a console.  */
+  void (*printf_filtered) PARAMS ((host_callback *, const char *, ...));
+
+  /* Talk to the user on a console.  */
+  void (*vprintf_filtered) PARAMS ((host_callback *, const char *, va_list));
+
+  /* Same as vprintf_filtered but to stderr.  */
+  void (*evprintf_filtered) PARAMS ((host_callback *, const char *, va_list));
+
+  /* Print an error message and "exit".
+     In the case of gdb "exiting" means doing a longjmp back to the main
+     command loop.  */
+  void (*error) PARAMS ((host_callback *, const char *, ...));
+
+  int last_errno;              /* host format */
+
+  int fdmap[MAX_CALLBACK_FDS];
+  char fdopen[MAX_CALLBACK_FDS];
+  char alwaysopen[MAX_CALLBACK_FDS];
+
+  /* System call numbers.  */
+  CB_TARGET_DEFS_MAP *syscall_map;
+  /* Errno values.  */
+  CB_TARGET_DEFS_MAP *errno_map;
+  /* Flags to the open system call.  */
+  CB_TARGET_DEFS_MAP *open_map;
+  /* Signal numbers.  */
+  CB_TARGET_DEFS_MAP *signal_map;
+  /* Layout of `stat' struct.
+     The format is a series of "name,length" pairs separated by colons.
+     Empty space is indicated with a `name' of "space".
+     All padding must be explicitly mentioned.
+     Lengths are in bytes.  If this needs to be extended to bits,
+     use "name.bits".
+     Example: "st_dev,4:st_ino,4:st_mode,4:..."  */
+  const char *stat_map;
+
+  /* Marker for those wanting to do sanity checks.
+     This should remain the last member of this struct to help catch
+     miscompilation errors. */
+#define HOST_CALLBACK_MAGIC 4705 /* teds constant */
+  int magic;
+};
+
+extern host_callback default_callback;
+\f
+/* Canonical versions of system call numbers.
+   It's not intended to willy-nilly throw every system call ever heard
+   of in here.  Only include those that have an important use.
+   ??? One can certainly start a discussion over the ones that are currently
+   here, but that will always be true.  */
+
+/* These are used by the ANSI C support of libc.  */
+#define        CB_SYS_exit     1
+#define        CB_SYS_open     2
+#define        CB_SYS_close    3
+#define        CB_SYS_read     4
+#define        CB_SYS_write    5
+#define        CB_SYS_lseek    6
+#define        CB_SYS_unlink   7
+#define        CB_SYS_getpid   8
+#define        CB_SYS_kill     9
+#define CB_SYS_fstat    10
+/*#define CB_SYS_sbrk  11 - not currently a system call, but reserved.  */
+
+/* ARGV support.  */
+#define CB_SYS_argvlen 12
+#define CB_SYS_argv    13
+
+/* These are extras added for one reason or another.  */
+#define CB_SYS_chdir   14
+#define CB_SYS_stat    15
+#define CB_SYS_chmod   16
+#define CB_SYS_utime   17
+#define CB_SYS_time    18
+\f
+/* Struct use to pass and return information necessary to perform a
+   system call.  */
+/* FIXME: Need to consider target word size.  */
+
+typedef struct cb_syscall {
+  /* The target's value of what system call to perform.  */
+  int func;
+  /* The arguments to the syscall.  */
+  long arg1, arg2, arg3, arg4;
+
+  /* The result.  */
+  long result;
+  /* Some system calls have two results.  */
+  long result2;
+  /* The target's errno value, or 0 if success.
+     This is converted to the target's value with host_to_target_errno.  */
+  int errcode;
+
+  /* Working space to be used by memory read/write callbacks.  */
+  PTR p1;
+  PTR p2;
+  long x1,x2;
+
+  /* Callbacks for reading/writing memory (e.g. for read/write syscalls).
+     ??? long or unsigned long might be better to use for the `count'
+     argument here.  We mimic sim_{read,write} for now.  Be careful to
+     test any changes with -Wall -Werror, mixed signed comparisons
+     will get you.  */
+  int (*read_mem) PARAMS ((host_callback * /*cb*/, struct cb_syscall * /*sc*/,
+                          unsigned long /*taddr*/, char * /*buf*/,
+                          int /*bytes*/));
+  int (*write_mem) PARAMS ((host_callback * /*cb*/, struct cb_syscall * /*sc*/,
+                           unsigned long /*taddr*/, const char * /*buf*/,
+                           int /*bytes*/));
+
+  /* For sanity checking, should be last entry.  */
+  int magic;
+} CB_SYSCALL;
+
+/* Magic number sanity checker.  */
+#define CB_SYSCALL_MAGIC 0x12344321
+
+/* Macro to initialize CB_SYSCALL.  Called first, before filling in
+   any fields.  */
+#define CB_SYSCALL_INIT(sc) \
+do { \
+  memset ((sc), 0, sizeof (*(sc))); \
+  (sc)->magic = CB_SYSCALL_MAGIC; \
+} while (0)
+\f
+/* Return codes for various interface routines.  */
+
+typedef enum {
+  CB_RC_OK = 0,
+  /* generic error */
+  CB_RC_ERR,
+  /* either file not found or no read access */
+  CB_RC_ACCESS,
+  CB_RC_NO_MEM
+} CB_RC;
+
+/* Read in target values for system call numbers, errno values, signals.  */
+CB_RC cb_read_target_syscall_maps PARAMS ((host_callback *, const char *));
+
+/* Translate target to host syscall function numbers.  */
+int cb_target_to_host_syscall PARAMS ((host_callback *, int));
+
+/* Translate host to target errno value.  */
+int cb_host_to_target_errno PARAMS ((host_callback *, int));
+
+/* Translate target to host open flags.  */
+int cb_target_to_host_open PARAMS ((host_callback *, int));
+
+/* Translate target signal number to host.  */
+int cb_target_to_host_signal PARAMS ((host_callback *, int));
+
+/* Translate host signal number to target.  */
+int cb_host_to_target_signal PARAMS ((host_callback *, int));
+
+/* Translate host stat struct to target.
+   If stat struct ptr is NULL, just compute target stat struct size.
+   Result is size of target stat struct or 0 if error.  */
+int cb_host_to_target_stat PARAMS ((host_callback *, const struct stat *, PTR));
+
+/* Perform a system call.  */
+CB_RC cb_syscall PARAMS ((host_callback *, CB_SYSCALL *));
+
+#endif
diff --git a/include/gdb/remote-sim.h b/include/gdb/remote-sim.h
new file mode 100644 (file)
index 0000000..726ec62
--- /dev/null
@@ -0,0 +1,354 @@
+/* This file defines the interface between the simulator and gdb.
+   Copyright 1993, 1994, 1996, 1997, 1998, 2000
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if !defined (REMOTE_SIM_H)
+#define REMOTE_SIM_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This file is used when building stand-alone simulators, so isolate this
+   file from gdb.  */
+
+/* Pick up CORE_ADDR_TYPE if defined (from gdb), otherwise use same value as
+   gdb does (unsigned int - from defs.h).  */
+
+#ifndef CORE_ADDR_TYPE
+typedef unsigned int SIM_ADDR;
+#else
+typedef CORE_ADDR_TYPE SIM_ADDR;
+#endif
+
+
+/* Semi-opaque type used as result of sim_open and passed back to all
+   other routines.  "desc" is short for "descriptor".
+   It is up to each simulator to define `sim_state'.  */
+
+typedef struct sim_state *SIM_DESC;
+
+
+/* Values for `kind' arg to sim_open.  */
+
+typedef enum {
+  SIM_OPEN_STANDALONE, /* simulator used standalone (run.c) */
+  SIM_OPEN_DEBUG       /* simulator used by debugger (gdb) */
+} SIM_OPEN_KIND;
+
+
+/* Return codes from various functions.  */
+
+typedef enum {
+  SIM_RC_FAIL = 0,
+  SIM_RC_OK = 1,
+  SIM_RC_UNKNOWN_BREAKPOINT = 2,
+  SIM_RC_INSUFFICIENT_RESOURCES = 3,
+  SIM_RC_DUPLICATE_BREAKPOINT = 4
+} SIM_RC;
+
+
+/* The bfd struct, as an opaque type.  */
+
+struct _bfd;
+
+
+/* Main simulator entry points.  */
+
+
+/* Create a fully initialized simulator instance.
+
+   (This function is called when the simulator is selected from the
+   gdb command line.)
+
+   KIND specifies how the simulator shall be used.  Currently there
+   are only two kinds: stand-alone and debug.
+
+   CALLBACK specifies a standard host callback (defined in callback.h).
+
+   ABFD, when non NULL, designates a target program.  The program is
+   not loaded.
+
+   ARGV is a standard ARGV pointer such as that passed from the
+   command line.  The syntax of the argument list is is assumed to be
+   ``SIM-PROG { SIM-OPTION } [ TARGET-PROGRAM { TARGET-OPTION } ]''.
+   The trailing TARGET-PROGRAM and args are only valid for a
+   stand-alone simulator.
+
+   On success, the result is a non NULL descriptor that shall be
+   passed to the other sim_foo functions.  While the simulator
+   configuration can be parameterized by (in decreasing precedence)
+   ARGV's SIM-OPTION, ARGV's TARGET-PROGRAM and the ABFD argument, the
+   successful creation of the simulator shall not dependent on the
+   presence of any of these arguments/options.
+
+   Hardware simulator: The created simulator shall be sufficiently
+   initialized to handle, with out restrictions any client requests
+   (including memory reads/writes, register fetch/stores and a
+   resume).
+
+   Process simulator: that process is not created until a call to
+   sim_create_inferior.  FIXME: What should the state of the simulator
+   be? */
+
+SIM_DESC sim_open PARAMS ((SIM_OPEN_KIND kind, struct host_callback_struct *callback, struct _bfd *abfd, char **argv));
+
+
+/* Destory a simulator instance.
+
+   QUITTING is non-zero if we cannot hang on errors.
+
+   This may involve freeing target memory and closing any open files
+   and mmap'd areas.  You cannot assume sim_kill has already been
+   called. */
+
+void sim_close PARAMS ((SIM_DESC sd, int quitting));
+
+
+/* Load program PROG into the simulators memory.
+
+   If ABFD is non-NULL, the bfd for the file has already been opened.
+   The result is a return code indicating success.
+
+   Hardware simulator: Normally, each program section is written into
+   memory according to that sections LMA using physical (direct)
+   addressing.  The exception being systems, such as PPC/CHRP, which
+   support more complicated program loaders.  A call to this function
+   should not effect the state of the processor registers.  Multiple
+   calls to this function are permitted and have an accumulative
+   effect.
+
+   Process simulator: Calls to this function may be ignored.
+
+   FIXME: Most hardware simulators load the image at the VMA using
+   virtual addressing.
+
+   FIXME: For some hardware targets, before a loaded program can be
+   executed, it requires the manipulation of VM registers and tables.
+   Such manipulation should probably (?) occure in
+   sim_create_inferior. */
+
+SIM_RC sim_load PARAMS ((SIM_DESC sd, char *prog, struct _bfd *abfd, int from_tty));
+
+
+/* Prepare to run the simulated program.
+
+   ABFD, if not NULL, provides initial processor state information.
+   ARGV and ENV, if non NULL, are NULL terminated lists of pointers.
+
+   Hardware simulator: This function shall initialize the processor
+   registers to a known value.  The program counter and possibly stack
+   pointer shall be set using information obtained from ABFD (or
+   hardware reset defaults).  ARGV and ENV, dependant on the target
+   ABI, may be written to memory.
+
+   Process simulator: After a call to this function, a new process
+   instance shall exist. The TEXT, DATA, BSS and stack regions shall
+   all be initialized, ARGV and ENV shall be written to process
+   address space (according to the applicable ABI) and the program
+   counter and stack pointer set accordingly. */
+
+SIM_RC sim_create_inferior PARAMS ((SIM_DESC sd, struct _bfd *abfd, char **argv, char **env));
+
+
+/* Fetch LENGTH bytes of the simulated program's memory.  Start fetch
+   at virtual address MEM and store in BUF.  Result is number of bytes
+   read, or zero if error.  */
+
+int sim_read PARAMS ((SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length));
+
+
+/* Store LENGTH bytes from BUF into the simulated program's
+   memory. Store bytes starting at virtual address MEM. Result is
+   number of bytes write, or zero if error.  */
+
+int sim_write PARAMS ((SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length));
+
+
+/* Fetch register REGNO storing its raw (target endian) value in the
+   LENGTH byte buffer BUF.  Return the actual size of the register or
+   zero if REGNO is not applicable.
+
+   Legacy implementations ignore LENGTH and always return -1.
+
+   If LENGTH does not match the size of REGNO no data is transfered
+   (the actual register size is still returned). */
+
+int sim_fetch_register PARAMS ((SIM_DESC sd, int regno, unsigned char *buf, int length));
+
+
+/* Store register REGNO from the raw (target endian) value in BUF.
+   Return the actual size of the register or zero if REGNO is not
+   applicable.
+
+   Legacy implementations ignore LENGTH and always return -1.
+
+   If LENGTH does not match the size of REGNO no data is transfered
+   (the actual register size is still returned). */
+
+int sim_store_register PARAMS ((SIM_DESC sd, int regno, unsigned char *buf, int length));
+
+
+/* Print whatever statistics the simulator has collected.
+
+   VERBOSE is currently unused and must always be zero.  */
+
+void sim_info PARAMS ((SIM_DESC sd, int verbose));
+
+
+/* Run (or resume) the simulated program.
+
+   STEP, when non-zero indicates that only a single simulator cycle
+   should be emulated.
+
+   SIGGNAL, if non-zero is a (HOST) SIGRC value indicating the type of
+   event (hardware interrupt, signal) to be delivered to the simulated
+   program.
+
+   Hardware simulator: If the SIGRC value returned by
+   sim_stop_reason() is passed back to the simulator via SIGGNAL then
+   the hardware simulator shall correctly deliver the hardware event
+   indicated by that signal.  If a value of zero is passed in then the
+   simulation will continue as if there were no outstanding signal.
+   The effect of any other SIGGNAL value is is implementation
+   dependant.
+
+   Process simulator: If SIGRC is non-zero then the corresponding
+   signal is delivered to the simulated program and execution is then
+   continued.  A zero SIGRC value indicates that the program should
+   continue as normal. */
+
+void sim_resume PARAMS ((SIM_DESC sd, int step, int siggnal));
+
+
+/* Asynchronous request to stop the simulation.
+   A nonzero return indicates that the simulator is able to handle
+   the request */
+
+int sim_stop PARAMS ((SIM_DESC sd));
+
+
+/* Fetch the REASON why the program stopped.
+
+   SIM_EXITED: The program has terminated. SIGRC indicates the target
+   dependant exit status.
+
+   SIM_STOPPED: The program has stopped.  SIGRC uses the host's signal
+   numbering as a way of identifying the reaon: program interrupted by
+   user via a sim_stop request (SIGINT); a breakpoint instruction
+   (SIGTRAP); a completed single step (SIGTRAP); an internal error
+   condition (SIGABRT); an illegal instruction (SIGILL); Access to an
+   undefined memory region (SIGSEGV); Mis-aligned memory access
+   (SIGBUS).  For some signals information in addition to the signal
+   number may be retained by the simulator (e.g. offending address),
+   that information is not directly accessable via this interface.
+
+   SIM_SIGNALLED: The program has been terminated by a signal. The
+   simulator has encountered target code that causes the the program
+   to exit with signal SIGRC.
+
+   SIM_RUNNING, SIM_POLLING: The return of one of these values
+   indicates a problem internal to the simulator. */
+
+enum sim_stop { sim_running, sim_polling, sim_exited, sim_stopped, sim_signalled };
+
+void sim_stop_reason PARAMS ((SIM_DESC sd, enum sim_stop *reason, int *sigrc));
+
+
+/* Passthru for other commands that the simulator might support.
+   Simulators should be prepared to deal with any combination of NULL
+   or empty CMD. */
+
+void sim_do_command PARAMS ((SIM_DESC sd, char *cmd));
+
+/* Call these functions to set and clear breakpoints at ADDR. */
+
+SIM_RC sim_set_breakpoint PARAMS ((SIM_DESC sd, SIM_ADDR addr));
+SIM_RC sim_clear_breakpoint PARAMS ((SIM_DESC sd, SIM_ADDR addr));
+SIM_RC sim_clear_all_breakpoints PARAMS ((SIM_DESC sd));
+
+/* These functions are used to enable and disable breakpoints. */
+
+SIM_RC sim_enable_breakpoint PARAMS ((SIM_DESC sd, SIM_ADDR addr));
+SIM_RC sim_disable_breakpoint PARAMS ((SIM_DESC sd, SIM_ADDR addr));
+SIM_RC sim_enable_all_breakpoints PARAMS ((SIM_DESC sd));
+SIM_RC sim_disable_all_breakpoints PARAMS ((SIM_DESC sd));
+\f
+
+/* Provide simulator with a default (global) host_callback_struct.
+   THIS PROCEDURE IS DEPRECIATED.
+   GDB and NRUN do not use this interface.
+   This procedure does not take a SIM_DESC argument as it is
+   used before sim_open. */
+
+void sim_set_callbacks PARAMS ((struct host_callback_struct *));
+
+
+/* Set the size of the simulator memory array.
+   THIS PROCEDURE IS DEPRECIATED.
+   GDB and NRUN do not use this interface.
+   This procedure does not take a SIM_DESC argument as it is
+   used before sim_open. */
+
+void sim_size PARAMS ((int i));
+
+
+/* Single-step simulator with tracing enabled.
+   THIS PROCEDURE IS DEPRECIATED.
+   THIS PROCEDURE IS EVEN MORE DEPRECATED THAN SIM_SET_TRACE
+   GDB and NRUN do not use this interface.
+   This procedure returns: ``0'' indicating that the simulator should
+   be continued using sim_trace() calls; ``1'' indicating that the
+   simulation has finished. */
+
+int sim_trace PARAMS ((SIM_DESC sd));
+
+
+/* Enable tracing.
+   THIS PROCEDURE IS DEPRECIATED.
+   GDB and NRUN do not use this interface.
+   This procedure returns: ``0'' indicating that the simulator should
+   be continued using sim_trace() calls; ``1'' indicating that the
+   simulation has finished. */
+
+void sim_set_trace PARAMS ((void));
+
+
+/* Configure the size of the profile buffer.
+   THIS PROCEDURE IS DEPRECIATED.
+   GDB and NRUN do not use this interface.
+   This procedure does not take a SIM_DESC argument as it is
+   used before sim_open. */
+
+void sim_set_profile_size PARAMS ((int n));
+
+
+/* Kill the running program.
+   THIS PROCEDURE IS DEPRECIATED.
+   GDB and NRUN do not use this interface.
+   This procedure will be replaced as part of the introduction of
+   multi-cpu simulators. */
+
+void sim_kill PARAMS ((SIM_DESC sd));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !defined (REMOTE_SIM_H) */
diff --git a/include/gdb/sim-arm.h b/include/gdb/sim-arm.h
new file mode 100644 (file)
index 0000000..1e49781
--- /dev/null
@@ -0,0 +1,65 @@
+/* This file defines the interface between the Arm simulator and GDB.
+
+   Copyright 2002 Free Software Foundation, Inc.
+
+   Contributed by Red Hat.
+
+   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., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#if !defined (SIM_ARM_H)
+#define SIM_ARM_H
+
+#ifdef __cplusplus
+extern "C" { // }
+#endif
+
+enum sim_arm_regnum
+{
+  SIM_ARM_R0_REGNUM,
+  SIM_ARM_R1_REGNUM,
+  SIM_ARM_R2_REGNUM,
+  SIM_ARM_R3_REGNUM,
+  SIM_ARM_R4_REGNUM,
+  SIM_ARM_R5_REGNUM,
+  SIM_ARM_R6_REGNUM,
+  SIM_ARM_R7_REGNUM,
+  SIM_ARM_R8_REGNUM,
+  SIM_ARM_R9_REGNUM,
+  SIM_ARM_R10_REGNUM,
+  SIM_ARM_R11_REGNUM,
+  SIM_ARM_R12_REGNUM,
+  SIM_ARM_R13_REGNUM,
+  SIM_ARM_R14_REGNUM,
+  SIM_ARM_R15_REGNUM, /* PC */
+  SIM_ARM_FP0_REGNUM,
+  SIM_ARM_FP1_REGNUM,
+  SIM_ARM_FP2_REGNUM,
+  SIM_ARM_FP3_REGNUM,
+  SIM_ARM_FP4_REGNUM,
+  SIM_ARM_FP5_REGNUM,
+  SIM_ARM_FP6_REGNUM,
+  SIM_ARM_FP7_REGNUM,
+  SIM_ARM_FPS_REGNUM,
+  SIM_ARM_PS_REGNUM
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/gdb/sim-d10v.h b/include/gdb/sim-d10v.h
new file mode 100644 (file)
index 0000000..f153a41
--- /dev/null
@@ -0,0 +1,139 @@
+/* This file defines the interface between the d10v simulator and gdb.
+
+   Copyright 1999, 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#if !defined (SIM_D10V_H)
+#define SIM_D10V_H
+
+#ifdef __cplusplus
+extern "C" { // }
+#endif
+
+/* GDB interprets addresses as:
+
+   0x00xxxxxx: Physical unified memory segment     (Unified memory)
+   0x01xxxxxx: Physical instruction memory segment (On-chip insn memory)
+   0x02xxxxxx: Physical data memory segment        (On-chip data memory)
+   0x10xxxxxx: Logical data address segment        (DMAP translated memory)
+   0x11xxxxxx: Logical instruction address segment (IMAP translated memory)
+
+   The remote d10v board interprets addresses as:
+
+   0x00xxxxxx: Physical unified memory segment     (Unified memory)
+   0x01xxxxxx: Physical instruction memory segment (On-chip insn memory)
+   0x02xxxxxx: Physical data memory segment        (On-chip data memory)
+
+   The following translate a virtual DMAP/IMAP offset into a physical
+   memory segment assigning the translated address to PHYS.  Since a
+   memory access may cross a page boundrary the number of bytes for
+   which the translation is applicable (or 0 for an invalid virtual
+   offset) is returned. */
+
+enum
+  {
+    SIM_D10V_MEMORY_UNIFIED = 0x00000000,
+    SIM_D10V_MEMORY_INSN = 0x01000000,
+    SIM_D10V_MEMORY_DATA = 0x02000000,
+    SIM_D10V_MEMORY_DMAP = 0x10000000,
+    SIM_D10V_MEMORY_IMAP = 0x11000000
+  };
+
+extern unsigned long sim_d10v_translate_dmap_addr
+  (unsigned long offset,
+   int nr_bytes,
+   unsigned long *phys,
+   unsigned long (*dmap_register) (int reg_nr));
+
+extern unsigned long sim_d10v_translate_imap_addr
+  (unsigned long offset,
+   int nr_bytes,
+   unsigned long *phys,
+   unsigned long (*imap_register) (int reg_nr));
+
+extern unsigned long sim_d10v_translate_addr
+  (unsigned long vaddr,
+   int nr_bytes,
+   unsigned long *phys,
+   unsigned long (*dmap_register) (int reg_nr),
+   unsigned long (*imap_register) (int reg_nr));
+
+
+/* The simulator makes use of the following register information. */
+
+enum sim_d10v_regs
+{
+  SIM_D10V_R0_REGNUM,
+  SIM_D10V_R1_REGNUM,
+  SIM_D10V_R2_REGNUM,
+  SIM_D10V_R3_REGNUM,
+  SIM_D10V_R4_REGNUM,
+  SIM_D10V_R5_REGNUM,
+  SIM_D10V_R6_REGNUM,
+  SIM_D10V_R7_REGNUM,
+  SIM_D10V_R8_REGNUM,
+  SIM_D10V_R9_REGNUM,
+  SIM_D10V_R10_REGNUM,
+  SIM_D10V_R11_REGNUM,
+  SIM_D10V_R12_REGNUM,
+  SIM_D10V_R13_REGNUM,
+  SIM_D10V_R14_REGNUM,
+  SIM_D10V_R15_REGNUM,
+  SIM_D10V_CR0_REGNUM,
+  SIM_D10V_CR1_REGNUM,
+  SIM_D10V_CR2_REGNUM,
+  SIM_D10V_CR3_REGNUM,
+  SIM_D10V_CR4_REGNUM,
+  SIM_D10V_CR5_REGNUM,
+  SIM_D10V_CR6_REGNUM,
+  SIM_D10V_CR7_REGNUM,
+  SIM_D10V_CR8_REGNUM,
+  SIM_D10V_CR9_REGNUM,
+  SIM_D10V_CR10_REGNUM,
+  SIM_D10V_CR11_REGNUM,
+  SIM_D10V_CR12_REGNUM,
+  SIM_D10V_CR13_REGNUM,
+  SIM_D10V_CR14_REGNUM,
+  SIM_D10V_CR15_REGNUM,
+  SIM_D10V_A0_REGNUM,
+  SIM_D10V_A1_REGNUM,
+  SIM_D10V_SPI_REGNUM,
+  SIM_D10V_SPU_REGNUM,
+  SIM_D10V_IMAP0_REGNUM,
+  SIM_D10V_IMAP1_REGNUM,
+  SIM_D10V_DMAP0_REGNUM,
+  SIM_D10V_DMAP1_REGNUM,
+  SIM_D10V_DMAP2_REGNUM,
+  SIM_D10V_DMAP3_REGNUM,
+  SIM_D10V_TS2_DMAP_REGNUM
+};
+  
+enum
+{
+  SIM_D10V_NR_R_REGS = 16,
+  SIM_D10V_NR_A_REGS = 2,
+  SIM_D10V_NR_IMAP_REGS = 2,
+  SIM_D10V_NR_DMAP_REGS = 4,
+  SIM_D10V_NR_CR_REGS = 16
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/opcode/dlx.h b/include/opcode/dlx.h
new file mode 100644 (file)
index 0000000..e1b249f
--- /dev/null
@@ -0,0 +1,282 @@
+/* Table of opcodes for the DLX microprocess.
+   Copyright 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB and GAS.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   Initially created by Kuang Hwa Lin, 2002.   */
+
+/* Following are the function codes for the Special OP (ALU).  */
+#define  ALUOP       0x00000000
+#define  SPECIALOP   0x00000000
+
+#define  NOPF        0x00000000
+#define  SLLF        0x00000004
+#define  SRLF        0x00000006
+#define  SRAF        0x00000007
+
+#define  SEQUF       0x00000010
+#define  SNEUF       0x00000011
+#define  SLTUF       0x00000012
+#define  SGTUF       0x00000013
+#define  SLEUF       0x00000014
+#define  SGEUF       0x00000015
+
+#define  ADDF        0x00000020
+#define  ADDUF       0x00000021
+#define  SUBF        0x00000022
+#define  SUBUF       0x00000023
+#define  ANDF        0x00000024
+#define  ORF         0x00000025
+#define  XORF        0x00000026
+
+#define  SEQF        0x00000028
+#define  SNEF        0x00000029
+#define  SLTF        0x0000002A
+#define  SGTF        0x0000002B
+#define  SLEF        0x0000002C
+#define  SGEF        0x0000002D
+  /* Following special functions was not mentioned in the
+     Hennessy's book but was implemented in the RTL.  */
+#define  MVTSF              0x00000030
+#define  MVFSF       0x00000031
+#define  BSWAPF      0x00000032
+#define  LUTF        0x00000033
+/* Following special functions was mentioned in the
+   Hennessy's book but was not implemented in the RTL.  */
+#define  MULTF       0x00000005
+#define  MULTUF      0x00000006
+#define  DIVF        0x00000007
+#define  DIVUF       0x00000008
+
+
+/* Following are the rest of the OPcodes:
+   JOP    = (0x002 << 26), JALOP  = (0x003 << 26), BEQOP = (0x004 << 26),   BNEOP  = (0x005 << 26)
+   ADDIOP = (0x008 << 26), ADDUIOP= (0x009 << 26), SUBIOP      = (0x00A << 26), SUBUIOP= (0x00B << 26)
+   ANDIOP = (0x00C << 26), ORIOP  = (0x00D << 26), XORIOP = (0x00E << 26),  LHIOP  = (0x00F << 26)
+   RFEOP  = (0x010 << 26), TRAPOP = (0x011 << 26), JROP        = (0x012 << 26), JALROP = (0x013 << 26)
+   BREAKOP= (0x014 << 26)
+   SEQIOP = (0x018 << 26), SNEIOP = (0x019 << 26), SLTIOP = (0x01A << 26),  SGTIOP = (0x01B << 26)
+   SLEIOP = (0x01C << 26), SGEIOP = (0x01D << 26)
+   LBOP   = (0x020 << 26), LHOP   = (0x021 << 26), LWOP   = (0x023 << 26),  LBUOP  = (0x024 << 26)
+   LHUOP  = (0x025 << 26), SBOP   = (0x028 << 26), SHOP   = (0x029 << 26),  SWOP   = (0x02B << 26)
+   LSBUOP = (0x026 << 26), LSHU   = (0x027 << 26), LSW    = (0x02C << 26),
+   SEQUIOP= (0x030 << 26), SNEUIOP= (0x031 << 26), SLTUIOP= (0x032 << 26),  SGTUIOP= (0x033 << 26)
+   SLEUIOP= (0x034 << 26), SGEUIOP= (0x035 << 26)
+   SLLIOP = (0x036 << 26), SRLIOP = (0x037 << 26), SRAIOP = (0x038 << 26).  */
+#define  JOP        0x08000000
+#define  JALOP      0x0c000000
+#define  BEQOP      0x10000000
+#define  BNEOP      0x14000000
+
+#define  ADDIOP             0x20000000
+#define  ADDUIOP     0x24000000
+#define  SUBIOP             0x28000000
+#define  SUBUIOP     0x2c000000
+#define  ANDIOP      0x30000000
+#define  ORIOP       0x34000000
+#define  XORIOP      0x38000000
+#define  LHIOP       0x3c000000
+#define  RFEOP      0x40000000
+#define  TRAPOP      0x44000000
+#define  JROP       0x48000000
+#define  JALROP      0x4c000000
+#define  BREAKOP     0x50000000
+
+#define  SEQIOP      0x60000000
+#define  SNEIOP      0x64000000
+#define  SLTIOP      0x68000000
+#define  SGTIOP      0x6c000000
+#define  SLEIOP      0x70000000
+#define  SGEIOP      0x74000000
+
+#define  LBOP        0x80000000
+#define  LHOP        0x84000000
+#define  LWOP        0x8c000000
+#define  LBUOP       0x90000000
+#define  LHUOP      0x94000000
+#define  LDSTBU
+#define  LDSTHU
+#define  SBOP       0xa0000000
+#define  SHOP        0xa4000000
+#define  SWOP        0xac000000
+#define  LDST
+
+#define  SEQUIOP     0xc0000000
+#define  SNEUIOP     0xc4000000
+#define  SLTUIOP     0xc8000000
+#define  SGTUIOP     0xcc000000
+#define  SLEUIOP     0xd0000000
+#define  SGEUIOP     0xd4000000
+
+#define  SLLIOP      0xd8000000
+#define  SRLIOP      0xdc000000
+#define  SRAIOP      0xe0000000
+
+/* Following 3 ops was added to provide the MP atonmic operation.  */
+#define  LSBUOP      0x98000000
+#define  LSHUOP      0x9c000000
+#define  LSWOP       0xb0000000
+
+/* Following opcode was defined in the Hennessy's book as
+   "normal" opcode but was implemented in the RTL as special
+   functions.  */
+#if 0
+#define  MVTSOP             0x50000000
+#define  MVFSOP      0x54000000
+#endif
+
+struct dlx_opcode
+{
+  /* Name of the instruction.  */
+  char *name;
+
+  /* Opcode word.  */
+  unsigned long opcode;
+
+  /* A string of characters which describe the operands.
+     Valid characters are:
+     ,        Itself.  The character appears in the assembly code.
+     a        rs1      The register number is in bits 21-25 of the instruction.
+     b        rs2/rd   The register number is in bits 16-20 of the instruction.
+     c        rd.      The register number is in bits 11-15 of the instruction.
+     f        FUNC bits 0-10 of the instruction.
+     i        An immediate operand is in bits 0-16 of the instruction. 0 extended
+     I        An immediate operand is in bits 0-16 of the instruction. sign extended
+     d       An 16 bit PC relative displacement.
+     D       An immediate operand is in bits 0-25 of the instruction.
+     N       No opperands needed, for nops.
+     P       it can be a register or a 16 bit operand.  */
+  char *args;
+};
+
+static const struct dlx_opcode dlx_opcodes[] =
+  {
+  /* Arithmetic and Logic R-TYPE instructions.  */
+    { "nop",      (ALUOP|NOPF),   "N"     },  /* NOP                          */
+    { "add",      (ALUOP|ADDF),   "c,a,b" },  /* Add                          */
+    { "addu",     (ALUOP|ADDUF),  "c,a,b" },  /* Add Unsigned                 */
+    { "sub",      (ALUOP|SUBF),   "c,a,b" },  /* SUB                          */
+    { "subu",     (ALUOP|SUBUF),  "c,a,b" },  /* Sub Unsigned                 */
+    { "mult",     (ALUOP|MULTF),  "c,a,b" },  /* MULTIPLY                     */
+    { "multu",    (ALUOP|MULTUF), "c,a,b" },  /* MULTIPLY Unsigned            */
+    { "div",      (ALUOP|DIVF),   "c,a,b" },  /* DIVIDE                       */
+    { "divu",     (ALUOP|DIVUF),  "c,a,b" },  /* DIVIDE Unsigned              */
+    { "and",      (ALUOP|ANDF),   "c,a,b" },  /* AND                          */
+    { "or",       (ALUOP|ORF),    "c,a,b" },  /* OR                           */
+    { "xor",      (ALUOP|XORF),   "c,a,b" },  /* Exclusive OR                 */
+    { "sll",      (ALUOP|SLLF),   "c,a,b" },  /* SHIFT LEFT LOGICAL           */
+    { "sra",      (ALUOP|SRAF),   "c,a,b" },  /* SHIFT RIGHT ARITHMETIC       */
+    { "srl",      (ALUOP|SRLF),   "c,a,b" },  /* SHIFT RIGHT LOGICAL          */
+    { "seq",      (ALUOP|SEQF),   "c,a,b" },  /* Set if equal                 */
+    { "sne",      (ALUOP|SNEF),   "c,a,b" },  /* Set if not equal             */
+    { "slt",      (ALUOP|SLTF),   "c,a,b" },  /* Set if less                  */
+    { "sgt",      (ALUOP|SGTF),   "c,a,b" },  /* Set if greater               */
+    { "sle",      (ALUOP|SLEF),   "c,a,b" },  /* Set if less or equal         */
+    { "sge",      (ALUOP|SGEF),   "c,a,b" },  /* Set if greater or equal      */
+    { "sequ",     (ALUOP|SEQUF),  "c,a,b" },  /* Set if equal unsigned        */
+    { "sneu",     (ALUOP|SNEUF),  "c,a,b" },  /* Set if not equal unsigned    */
+    { "sltu",     (ALUOP|SLTUF),  "c,a,b" },  /* Set if less unsigned         */
+    { "sgtu",     (ALUOP|SGTUF),  "c,a,b" },  /* Set if greater unsigned      */
+    { "sleu",     (ALUOP|SLEUF),  "c,a,b" },  /* Set if less or equal unsigned*/
+    { "sgeu",     (ALUOP|SGEUF),  "c,a,b" },  /* Set if greater or equal      */
+    { "mvts",     (ALUOP|MVTSF),  "c,a"   },  /* Move to special register     */
+    { "mvfs",     (ALUOP|MVFSF),  "c,a"   },  /* Move from special register   */
+    { "bswap",    (ALUOP|BSWAPF), "c,a,b" },  /* ??? Was not documented       */
+    { "lut",      (ALUOP|LUTF),   "c,a,b" },  /* ????? same as above          */
+
+    /* Arithmetic and Logical Immediate I-TYPE instructions.  */
+    { "addi",     ADDIOP,         "b,a,I" },  /* Add Immediate                */
+    { "addui",    ADDUIOP,        "b,a,i" },  /* Add Usigned Immediate        */
+    { "subi",     SUBIOP,         "b,a,I" },  /* Sub Immediate                */
+    { "subui",    SUBUIOP,        "b,a,i" },  /* Sub Unsigned Immedated       */
+    { "andi",     ANDIOP,         "b,a,i" },  /* AND Immediate                */
+    { "ori",      ORIOP,          "b,a,i" },  /* OR  Immediate                */
+    { "xori",     XORIOP,         "b,a,i" },  /* Exclusive OR  Immediate      */
+    { "slli",     SLLIOP,         "b,a,i" },  /* SHIFT LEFT LOCICAL Immediate */
+    { "srai",     SRAIOP,         "b,a,i" },  /* SHIFT RIGHT ARITH. Immediate */
+    { "srli",     SRLIOP,         "b,a,i" },  /* SHIFT RIGHT LOGICAL Immediate*/
+    { "seqi",     SEQIOP,         "b,a,i" },  /* Set if equal                 */
+    { "snei",     SNEIOP,         "b,a,i" },  /* Set if not equal             */
+    { "slti",     SLTIOP,         "b,a,i" },  /* Set if less                  */
+    { "sgti",     SGTIOP,         "b,a,i" },  /* Set if greater               */
+    { "slei",     SLEIOP,         "b,a,i" },  /* Set if less or equal         */
+    { "sgei",     SGEIOP,         "b,a,i" },  /* Set if greater or equal      */
+    { "sequi",    SEQUIOP,        "b,a,i" },  /* Set if equal                 */
+    { "sneui",    SNEUIOP,        "b,a,i" },  /* Set if not equal             */
+    { "sltui",    SLTUIOP,        "b,a,i" },  /* Set if less                  */
+    { "sgtui",    SGTUIOP,        "b,a,i" },  /* Set if greater               */
+    { "sleui",    SLEUIOP,        "b,a,i" },  /* Set if less or equal         */
+    { "sgeui",    SGEUIOP,        "b,a,i" },  /* Set if greater or equal      */
+    /* Macros for I type instructions.  */
+    { "mov",      ADDIOP,         "b,P"   },  /* a move macro                 */
+    { "movu",     ADDUIOP,        "b,P"   },  /* a move macro, unsigned       */
+
+#if 0
+    /* Move special.  */
+    { "mvts",     MVTSOP,         "b,a"   },  /* Move From Integer to Special */
+    { "mvfs",     MVFSOP,         "b,a"   },  /* Move From Special to Integer */
+#endif
+
+    /* Load high Immediate I-TYPE instruction.  */
+    { "lhi",      LHIOP,          "b,i"   },  /* Load High Immediate          */
+    { "lui",      LHIOP,          "b,i"   },  /* Load High Immediate          */
+    { "sethi",    LHIOP,          "b,i"   },  /* Load High Immediate          */
+
+  /* LOAD/STORE BYTE 8 bits I-TYPE.  */
+    { "lb",       LBOP,           "b,a,I" },  /* Load Byte                    */
+    { "lbu",      LBUOP,          "b,a,I" },  /* Load Byte Unsigned           */
+    { "ldstbu",   LSBUOP,         "b,a,I" },  /* Load store Byte Unsigned     */
+    { "sb",       SBOP,           "b,a,I" },  /* Store Byte                   */
+
+    /* LOAD/STORE HALFWORD 16 bits.  */
+    { "lh",       LHOP,           "b,a,I" },  /* Load Halfword                */
+    { "lhu",      LHUOP,          "b,a,I" },  /* Load Halfword Unsigned       */
+    { "ldsthu",   LSHUOP,         "b,a,I" },  /* Load Store Halfword Unsigned */
+    { "sh",       SHOP,           "b,a,I" },  /* Store Halfword               */
+
+  /* LOAD/STORE WORD 32 bits.  */
+    { "lw",       LWOP,           "b,a,I" },  /* Load Word                    */
+    { "sw",       SWOP,           "b,a,I" },  /* Store Word                   */
+    { "ldstw",    LSWOP,          "b,a,I" },  /* Load Store Word              */
+
+  /* Branch PC-relative, 16 bits offset.  */
+    { "beqz",     BEQOP,          "a,d" },    /* Branch if a == 0             */
+    { "bnez",     BNEOP,          "a,d" },    /* Branch if a != 0             */
+    { "beq",      BEQOP,          "a,d" },    /* Branch if a == 0             */
+    { "bne",      BNEOP,          "a,d" },    /* Branch if a != 0             */
+
+    /* Jumps Trap and RFE J-TYPE.  */
+    { "j",        JOP,            "D" },      /* Jump, PC-relative 26 bits    */
+    { "jal",      JALOP,          "D" },      /* JAL, PC-relative 26 bits     */
+    { "break",    BREAKOP,        "D" },      /* break to OS                  */
+    { "trap" ,    TRAPOP,         "D" },      /* TRAP to OS                   */
+    { "rfe",      RFEOP,          "N" },      /* Return From Exception        */
+    /* Macros.  */
+    { "call",     JOP,            "D" },      /* Jump, PC-relative 26 bits    */
+
+    /* Jumps Trap and RFE I-TYPE.  */
+    { "jr",       JROP,           "a" },      /* Jump Register, Abs (32 bits) */
+    { "jalr",     JALROP,         "a" },      /* JALR, Abs (32 bits)          */
+    /* Macros.  */
+    { "retr",     JROP,           "a" },      /* Jump Register, Abs (32 bits) */
+
+    { "", 0x0, "" }            /* Dummy entry, not included in NUM_OPCODES.
+                                  This lets code examine entry i + 1 without
+                                  checking if we've run off the end of the table.  */
+  };
+
+const unsigned int num_dlx_opcodes = (((sizeof dlx_opcodes) / (sizeof dlx_opcodes[0])) - 1);
diff --git a/opcodes/dlx-dis.c b/opcodes/dlx-dis.c
new file mode 100644 (file)
index 0000000..8878b98
--- /dev/null
@@ -0,0 +1,544 @@
+/* Instruction printing code for the DLX Microprocessor
+   Copyright 2002 Free Software Foundation, Inc.
+   Contributed by Kuang Hwa Lin.  Written by Kuang Hwa Lin, 03/2002.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "sysdep.h"
+#include "dis-asm.h"
+#include "opcode/dlx.h"
+
+#define R_ERROR     0x1
+#define R_TYPE      0x2
+#define ILD_TYPE    0x3
+#define IST_TYPE    0x4
+#define IAL_TYPE    0x5
+#define IBR_TYPE    0x6
+#define IJ_TYPE     0x7
+#define IJR_TYPE    0x8
+#define NIL         0x9
+
+#define OPC(x)      ((x >> 26) & 0x3F)
+#define FUNC(x)     (x & 0x7FF)
+
+unsigned char opc, rs1, rs2, rd;
+unsigned long imm26, imm16, func, current_insn_addr;
+
+static unsigned char dlx_get_opcode PARAMS ((unsigned long));
+static unsigned char dlx_get_rs1    PARAMS ((unsigned long));
+static unsigned char dlx_get_rs2    PARAMS ((unsigned long));
+static unsigned char dlx_get_rdR    PARAMS ((unsigned long));
+static unsigned long dlx_get_func   PARAMS ((unsigned long)); 
+static unsigned long dlx_get_imm16  PARAMS ((unsigned long));
+static unsigned long dlx_get_imm26  PARAMS ((unsigned long));
+static void     operand_deliminator PARAMS ((struct disassemble_info *, char *));
+static unsigned char dlx_r_type     PARAMS ((struct disassemble_info *));
+static unsigned char dlx_load_type  PARAMS ((struct disassemble_info *));
+static unsigned char dlx_store_type PARAMS ((struct disassemble_info *));
+static unsigned char dlx_aluI_type  PARAMS ((struct disassemble_info *));
+static unsigned char dlx_br_type    PARAMS ((struct disassemble_info *));
+static unsigned char dlx_jmp_type   PARAMS ((struct disassemble_info *));
+static unsigned char dlx_jr_type    PARAMS ((struct disassemble_info *));
+
+/* Print one instruction from MEMADDR on INFO->STREAM.
+   Return the size of the instruction (always 4 on dlx).  */
+
+static unsigned char
+dlx_get_opcode (opcode)
+     unsigned long opcode;
+{
+  return (unsigned char) ((opcode >> 26) & 0x3F);
+}
+
+static unsigned char
+dlx_get_rs1 (opcode)
+     unsigned long opcode;
+{
+  return (unsigned char) ((opcode >> 21) & 0x1F);
+}
+
+static unsigned char
+dlx_get_rs2 (opcode)
+     unsigned long opcode;
+{
+  return (unsigned char) ((opcode >> 16) & 0x1F);
+}
+
+static unsigned char
+dlx_get_rdR (opcode)
+     unsigned long opcode;
+{
+  return (unsigned char) ((opcode >> 11) & 0x1F);
+}
+
+static unsigned long
+dlx_get_func (opcode)
+     unsigned long opcode;
+{
+  return (unsigned char) (opcode & 0x7FF);
+}
+
+static unsigned long
+dlx_get_imm16 (opcode)
+     unsigned long opcode;
+{
+  return (unsigned long) (opcode & 0xFFFF);
+}
+
+static unsigned long
+dlx_get_imm26 (opcode)
+     unsigned long opcode;
+{
+  return (unsigned long) (opcode & 0x03FFFFFF);
+}
+
+/* Fill the opcode to the max length.  */
+static void
+operand_deliminator (info, ptr)
+     struct disassemble_info *info;
+     char *ptr;
+{
+  int difft = 8 - (int) strlen (ptr);
+
+  while (difft > 0)
+    {
+      (*info->fprintf_func) (info->stream, "%c", ' ');
+      difft -= 1;
+    }
+}
+
+/* Process the R-type opcode.  */
+static unsigned char
+dlx_r_type (info)
+     struct disassemble_info *info;
+{
+  unsigned char r_opc[] = { OPC(ALUOP) }; /* Fix ME */
+  int r_opc_num = (sizeof r_opc) / (sizeof (char));
+  struct _r_opcode
+  {
+    unsigned long func;
+    char *name;
+  }
+  dlx_r_opcode[] =
+    {
+    { NOPF,     "nop"    },  /* NOP                          */
+    { ADDF,     "add"    },  /* Add                          */
+    { ADDUF,    "addu"   },  /* Add Unsigned                 */
+    { SUBF,     "sub"    },  /* SUB                          */
+    { SUBUF,    "subu"   },  /* Sub Unsigned                 */
+    { MULTF,    "mult"   },  /* MULTIPLY                     */
+    { MULTUF,   "multu"  },  /* MULTIPLY Unsigned            */
+    { DIVF,     "div"    },  /* DIVIDE                       */
+    { DIVUF,    "divu"   },  /* DIVIDE Unsigned              */
+    { ANDF,     "and"    },  /* AND                          */
+    { ORF,      "or"     },  /* OR                           */
+    { XORF,     "xor"    },  /* Exclusive OR                 */
+    { SLLF,     "sll"    },  /* SHIFT LEFT LOGICAL           */
+    { SRAF,     "sra"    },  /* SHIFT RIGHT ARITHMETIC       */
+    { SRLF,     "srl"    },  /* SHIFT RIGHT LOGICAL          */
+    { SEQF,     "seq"    },  /* Set if equal                 */
+    { SNEF,     "sne"    },  /* Set if not equal             */
+    { SLTF,     "slt"    },  /* Set if less                  */
+    { SGTF,     "sgt"    },  /* Set if greater               */
+    { SLEF,     "sle"    },  /* Set if less or equal         */
+    { SGEF,     "sge"    },  /* Set if greater or equal      */
+    { SEQUF,    "sequ"   },  /* Set if equal                 */
+    { SNEUF,    "sneu"   },  /* Set if not equal             */
+    { SLTUF,    "sltu"   },  /* Set if less                  */
+    { SGTUF,    "sgtu"   },  /* Set if greater               */
+    { SLEUF,    "sleu"   },  /* Set if less or equal         */
+    { SGEUF,    "sgeu"   },  /* Set if greater or equal      */
+    { MVTSF,    "mvts"   },  /* Move to special register     */
+    { MVFSF,    "mvfs"   },  /* Move from special register   */
+    { BSWAPF,   "bswap"  },  /* Byte swap ??                 */
+    { LUTF,     "lut"    }   /* ????????? ??                 */
+  };
+  int dlx_r_opcode_num = (sizeof dlx_r_opcode) / (sizeof dlx_r_opcode[0]);
+  int idx;
+
+  for (idx = 0; idx < r_opc_num; idx++)
+    {
+      if (r_opc[idx] != opc)
+       continue;
+      else
+       break;
+  }
+
+  if (idx == r_opc_num)
+    return NIL;
+
+  for (idx = 0 ; idx < dlx_r_opcode_num; idx++)
+    if (dlx_r_opcode[idx].func == func)
+      {
+       (*info->fprintf_func) (info->stream, "%s", dlx_r_opcode[idx].name);
+
+       if (func != NOPF)
+         {
+           /* This is not a nop.  */
+           operand_deliminator (info, dlx_r_opcode[idx].name);
+           (*info->fprintf_func) (info->stream, "r%d,", (int)rd);
+           (*info->fprintf_func) (info->stream, "r%d", (int)rs1);
+           if (func != MVTSF && func != MVFSF)
+             (*info->fprintf_func) (info->stream, ",r%d", (int)rs2);
+         }
+       return (unsigned char) R_TYPE;
+      }
+
+  return (unsigned char) R_ERROR;
+}
+
+/* Process the memory read opcode.  */
+
+static unsigned char
+dlx_load_type (info)
+     struct disassemble_info* info;
+{
+  struct _load_opcode
+  {
+    unsigned long opcode;
+    char *name;
+  }
+  dlx_load_opcode[] =
+    {
+      { OPC(LHIOP),   "lhi" },  /* Load HI to register.           */
+      { OPC(LBOP),     "lb" },  /* load byte sign extended.       */
+      { OPC(LBUOP),   "lbu" },  /* load byte unsigned.            */
+      { OPC(LSBUOP),"ldstbu"},  /* load store byte unsigned.      */
+      { OPC(LHOP),     "lh" },  /* load halfword sign extended.   */
+      { OPC(LHUOP),   "lhu" },  /* load halfword unsigned.        */
+      { OPC(LSHUOP),"ldsthu"},  /* load store halfword unsigned.  */
+      { OPC(LWOP),     "lw" },  /* load word.                     */
+      { OPC(LSWOP), "ldstw" }   /* load store word.               */
+    };
+  int dlx_load_opcode_num =
+    (sizeof dlx_load_opcode) / (sizeof dlx_load_opcode[0]);
+  int idx;
+
+  for (idx = 0 ; idx < dlx_load_opcode_num; idx++)
+    if (dlx_load_opcode[idx].opcode == opc)
+      {
+       if (opc == OPC (LHIOP))
+         {
+           (*info->fprintf_func) (info->stream, "%s", dlx_load_opcode[idx].name);
+           operand_deliminator (info, dlx_load_opcode[idx].name);
+           (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
+           (*info->fprintf_func) (info->stream, "0x%04x", (int)imm16);
+         }
+       else
+         {
+           (*info->fprintf_func) (info->stream, "%s", dlx_load_opcode[idx].name);
+           operand_deliminator (info, dlx_load_opcode[idx].name);
+           (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
+           (*info->fprintf_func) (info->stream, "0x%04x[r%d]", (int)imm16, (int)rs1);
+         }
+
+       return (unsigned char) ILD_TYPE;
+    }
+
+  return (unsigned char) NIL;
+}
+
+/* Process the memory store opcode.  */
+
+static unsigned char
+dlx_store_type (info)
+     struct disassemble_info* info;
+{
+  struct _store_opcode
+  {
+    unsigned long opcode;
+    char *name;
+  }
+  dlx_store_opcode[] =
+    {
+      { OPC(SBOP),     "sb" },  /* Store byte.      */
+      { OPC(SHOP),     "sh" },  /* Store halfword.  */
+      { OPC(SWOP),     "sw" },  /* Store word.      */
+    };
+  int dlx_store_opcode_num =
+    (sizeof dlx_store_opcode) / (sizeof dlx_store_opcode[0]);
+  int idx;
+
+  for (idx = 0 ; idx < dlx_store_opcode_num; idx++)
+    if (dlx_store_opcode[idx].opcode == opc)
+      {
+       (*info->fprintf_func) (info->stream, "%s", dlx_store_opcode[idx].name);
+       operand_deliminator (info, dlx_store_opcode[idx].name);
+       (*info->fprintf_func) (info->stream, "0x%04x[r%d],", (int)imm16, (int)rs1);
+       (*info->fprintf_func) (info->stream, "r%d", (int)rs2);
+       return (unsigned char) IST_TYPE;
+      }
+
+  return (unsigned char) NIL;
+}
+
+/* Process the Arithmetic and Logical I-TYPE opcode.  */
+
+static unsigned char
+dlx_aluI_type (info)
+     struct disassemble_info* info;
+{
+  struct _aluI_opcode
+  {
+    unsigned long opcode;
+    char *name;
+  }
+  dlx_aluI_opcode[] =
+    {
+      { OPC(ADDIOP),   "addi"  },  /* Store byte.      */
+      { OPC(ADDUIOP),  "addui" },  /* Store halfword.  */
+      { OPC(SUBIOP),   "subi"  },  /* Store word.      */
+      { OPC(SUBUIOP),  "subui" },  /* Store word.      */
+      { OPC(ANDIOP),   "andi"  },  /* Store word.      */
+      { OPC(ORIOP),    "ori"   },  /* Store word.      */
+      { OPC(XORIOP),   "xori"  },  /* Store word.      */
+      { OPC(SLLIOP),   "slli"  },  /* Store word.      */
+      { OPC(SRAIOP),   "srai"  },  /* Store word.      */
+      { OPC(SRLIOP),   "srli"  },  /* Store word.      */
+      { OPC(SEQIOP),   "seqi"  },  /* Store word.      */
+      { OPC(SNEIOP),   "snei"  },  /* Store word.      */
+      { OPC(SLTIOP),   "slti"  },  /* Store word.      */
+      { OPC(SGTIOP),   "sgti"  },  /* Store word.      */
+      { OPC(SLEIOP),   "slei"  },  /* Store word.      */
+      { OPC(SGEIOP),   "sgei"  },  /* Store word.      */
+      { OPC(SEQUIOP),  "sequi" },  /* Store word.      */
+      { OPC(SNEUIOP),  "sneui" },  /* Store word.      */
+      { OPC(SLTUIOP),  "sltui" },  /* Store word.      */
+      { OPC(SGTUIOP),  "sgtui" },  /* Store word.      */
+      { OPC(SLEUIOP),  "sleui" },  /* Store word.      */
+      { OPC(SGEUIOP),  "sgeui" },  /* Store word.      */
+#if 0                                                 
+      { OPC(MVTSOP),   "mvts"  },  /* Store word.      */
+      { OPC(MVFSOP),   "mvfs"  },  /* Store word.      */
+#endif
+    };
+  int dlx_aluI_opcode_num =
+    (sizeof dlx_aluI_opcode) / (sizeof dlx_aluI_opcode[0]);
+  int idx;
+
+  for (idx = 0 ; idx < dlx_aluI_opcode_num; idx++)
+    if (dlx_aluI_opcode[idx].opcode == opc)
+      {
+       (*info->fprintf_func) (info->stream, "%s", dlx_aluI_opcode[idx].name);
+       operand_deliminator (info, dlx_aluI_opcode[idx].name);
+       (*info->fprintf_func) (info->stream, "r%d,", (int)rs2);
+       (*info->fprintf_func) (info->stream, "r%d,", (int)rs1);
+       (*info->fprintf_func) (info->stream, "0x%04x", (int)imm16);
+
+       return (unsigned char) IAL_TYPE;
+      }
+
+  return (unsigned char) NIL;
+}
+
+/* Process the branch instruction.  */
+
+static unsigned char
+dlx_br_type (info)
+     struct disassemble_info* info;
+{
+  struct _br_opcode
+  {
+    unsigned long opcode;
+    char *name;
+  }
+  dlx_br_opcode[] =
+    {
+      { OPC(BEQOP), "beqz" }, /* Store byte.  */
+      { OPC(BNEOP), "bnez" }  /* Store halfword.  */
+    };
+  int dlx_br_opcode_num =
+    (sizeof dlx_br_opcode) / (sizeof dlx_br_opcode[0]);
+  int idx;
+
+  for (idx = 0 ; idx < dlx_br_opcode_num; idx++)
+    if (dlx_br_opcode[idx].opcode == opc)
+      {
+       if (imm16 & 0x00008000)
+         imm16 |= 0xFFFF0000;
+
+       imm16 += (current_insn_addr + 4);
+       (*info->fprintf_func) (info->stream, "%s", dlx_br_opcode[idx].name);
+       operand_deliminator (info, dlx_br_opcode[idx].name);
+       (*info->fprintf_func) (info->stream, "r%d,", (int)rs1);
+       (*info->fprintf_func) (info->stream, "0x%08x", (int)imm16);
+
+       return (unsigned char) IBR_TYPE;
+      }
+
+  return (unsigned char) NIL;
+}
+
+/* Process the jump instruction.  */
+
+static unsigned char
+dlx_jmp_type (info)
+     struct disassemble_info* info;
+{
+  struct _jmp_opcode
+  {
+    unsigned long opcode;
+    char *name;
+  }
+  dlx_jmp_opcode[] =
+    {
+      { OPC(JOP),         "j" },  /* Store byte.      */
+      { OPC(JALOP),     "jal" },  /* Store halfword.  */
+      { OPC(BREAKOP), "break" },  /* Store halfword.  */
+      { OPC(TRAPOP),   "trap" },  /* Store halfword.  */
+      { OPC(RFEOP),     "rfe" }   /* Store halfword.  */
+    };
+  int dlx_jmp_opcode_num =
+    (sizeof dlx_jmp_opcode) / (sizeof dlx_jmp_opcode[0]);
+  int idx;
+
+  for (idx = 0 ; idx < dlx_jmp_opcode_num; idx++)
+    if (dlx_jmp_opcode[idx].opcode == opc)
+      {
+       if (imm26 & 0x02000000)
+         imm26 |= 0xFC000000;
+
+       imm26 += (current_insn_addr + 4);
+
+       (*info->fprintf_func) (info->stream, "%s", dlx_jmp_opcode[idx].name);
+       operand_deliminator (info, dlx_jmp_opcode[idx].name);
+       (*info->fprintf_func) (info->stream, "0x%08x", (int)imm26);
+
+       return (unsigned char) IJ_TYPE;
+      }
+
+  return (unsigned char) NIL;
+}
+
+/* Process the jump register instruction.  */
+
+static unsigned char
+dlx_jr_type (info)
+     struct disassemble_info* info;
+{
+  struct _jr_opcode
+  {
+    unsigned long opcode;
+    char *name;
+  }
+  dlx_jr_opcode[] = {
+    { OPC(JROP),   "jr"    },  /* Store byte.  */
+    { OPC(JALROP), "jalr"  }   /* Store halfword.  */
+  };
+  int dlx_jr_opcode_num =
+    (sizeof dlx_jr_opcode) / (sizeof dlx_jr_opcode[0]);
+  int idx;
+
+  for (idx = 0 ; idx < dlx_jr_opcode_num; idx++)
+    if (dlx_jr_opcode[idx].opcode == opc)
+      {
+       (*info->fprintf_func) (info->stream, "%s", dlx_jr_opcode[idx].name);
+       operand_deliminator (info, dlx_jr_opcode[idx].name);
+       (*info->fprintf_func) (info->stream, "r%d", (int)rs1);
+       return (unsigned char) IJR_TYPE;
+      }
+
+  return (unsigned char) NIL;
+}
+
+typedef unsigned char (* dlx_insn) PARAMS ((struct disassemble_info *));
+
+/* This is the main DLX insn handling routine.  */
+
+int
+print_insn_dlx (memaddr, info)
+     bfd_vma memaddr;
+     struct disassemble_info* info;
+{
+  bfd_byte buffer[4];
+  int insn_idx;
+  unsigned long insn_word;
+  unsigned char rtn_code;
+  unsigned long dlx_insn_type[] =
+    {
+      (unsigned long) dlx_r_type,
+      (unsigned long) dlx_load_type,
+      (unsigned long) dlx_store_type,
+      (unsigned long) dlx_aluI_type,
+      (unsigned long) dlx_br_type,
+      (unsigned long) dlx_jmp_type,
+      (unsigned long) dlx_jr_type,
+      (unsigned long) NULL
+  };
+  int dlx_insn_type_num = ((sizeof dlx_insn_type) / (sizeof (unsigned long))) - 1;
+  int status =
+    (*info->read_memory_func) (memaddr, (bfd_byte *) &buffer[0], 4, info);
+
+  if (status != 0)
+    {
+      (*info->memory_error_func) (status, memaddr, info);
+      return -1;
+    }
+
+  /* Now decode the insn    */
+  insn_word = bfd_getb32 (buffer);
+  opc  = dlx_get_opcode (insn_word);
+  rs1  = dlx_get_rs1 (insn_word);
+  rs2  = dlx_get_rs2 (insn_word);
+  rd   = dlx_get_rdR (insn_word);
+  func = dlx_get_func (insn_word);
+  imm16= dlx_get_imm16 (insn_word);
+  imm26= dlx_get_imm26 (insn_word);
+
+#if 0
+  printf ("print_insn_big_dlx: opc = 0x%02x\n"
+         "                    rs1 = 0x%02x\n"
+         "                    rs2 = 0x%02x\n"
+         "                    rd  = 0x%02x\n"
+         "                  func  = 0x%08x\n"
+         "                 imm16  = 0x%08x\n"
+         "                 imm26  = 0x%08x\n",
+         opc, rs1, rs2, rd, func, imm16, imm26);
+#endif
+
+  /* Scan through all the insn type and print the insn out.  */
+  rtn_code = 0;
+  current_insn_addr = (unsigned long) memaddr;
+
+  for (insn_idx = 0; dlx_insn_type[insn_idx] != 0x0; insn_idx++)
+    switch (((dlx_insn) (dlx_insn_type[insn_idx])) (info))
+      {
+       /* Found the correct opcode   */
+      case R_TYPE:
+      case ILD_TYPE:
+      case IST_TYPE:
+      case IAL_TYPE:
+      case IBR_TYPE:
+      case IJ_TYPE:
+      case IJR_TYPE:
+       return 4;
+
+       /* Wrong insn type check next one. */
+      default:
+      case NIL:
+       continue;
+
+       /* All rest of the return code are not recongnized, treat it as error */
+       /* we should never get here,  I hope! */
+      case R_ERROR:
+       return -1;
+      }
+
+  if (insn_idx ==  dlx_insn_type_num)
+    /* Well, does not recoganize this opcode.  */
+    (*info->fprintf_func) (info->stream, "<%s>", "Unrecognized Opcode");
+
+  return 4;
+}
diff --git a/sim/common/run-sim.h b/sim/common/run-sim.h
new file mode 100644 (file)
index 0000000..7792373
--- /dev/null
@@ -0,0 +1,32 @@
+/* This file defines the part of the interface between the standalone
+   simaulator program - run - and simulator library - libsim.a - that
+   is not used by GDB.  The GDB part is described in include/remote-sim.h.
+   
+   Copyright 2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifdef SIM_TARGET_SWITCHES
+  /* Parse the command line, extracting any target specific switches
+     before the generic simulator code gets a chance to complain
+     about them.  Returns the adjusted value of argc.  */
+int sim_target_parse_command_line PARAMS ((int, char **));
+
+  /* Display a list of target specific switches supported by this
+     target.  */
+void sim_target_display_usage PARAMS ((void));
+#endif
diff --git a/sim/mips/cp1.h b/sim/mips/cp1.h
new file mode 100644 (file)
index 0000000..24901d8
--- /dev/null
@@ -0,0 +1,82 @@
+/*> cp1.h <*/
+/* MIPS Simulator FPU (CoProcessor 1) definitions.
+   Copyright (C) 1997, 1998, 2002 Free Software Foundation, Inc.
+   Derived from sim-main.h contributed by Cygnus Solutions,
+   modified substially by Broadcom Corporation (SiByte).
+
+This file is part of GDB, the GNU debugger.
+
+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, 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.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#ifndef CP1_H
+#define CP1_H
+
+/* See sim-main.h for allocation of registers FCR0 and FCR31 (FCSR) 
+   in CPU state (struct sim_cpu), and for FPU functions.  */
+
+#define fcsr_FCC_mask      (0xFE800000)
+#define fcsr_FCC_shift     (23)
+#define        fcsr_FCC_bit(cc)   ((cc) == 0 ? 23 : (24 + (cc)))
+#define fcsr_FS            (1 << 24) /* MIPS III onwards : Flush to Zero */
+#define fcsr_ZERO_mask     (0x007C0000)
+#define fcsr_CAUSE_mask    (0x0003F000)
+#define fcsr_CAUSE_shift   (12)
+#define fcsr_ENABLES_mask  (0x00000F80)
+#define fcsr_ENABLES_shift (7)
+#define fcsr_FLAGS_mask    (0x0000007C)
+#define fcsr_FLAGS_shift   (2)
+#define fcsr_RM_mask       (0x00000003)
+#define fcsr_RM_shift      (0)
+
+#define fenr_FS            (0x00000004)
+
+/* Macros to update and retrieve the FCSR condition-code bits.  This
+   is complicated by the fact that there is a hole in the index range
+   of the bits within the FCSR register.  (Note that the number of bits
+   visible depends on the ISA in use, but that is handled elsewhere.)  */
+#define SETFCC(cc,v) \
+  do { \
+    (FCSR = ((FCSR & ~(1 << fcsr_FCC_bit(cc))) | ((v) << fcsr_FCC_bit(cc)))); \
+  } while (0)
+#define GETFCC(cc) ((FCSR & (1 << fcsr_FCC_bit(cc))) != 0 ? 1 : 0)
+
+
+/* Read flush-to-zero bit (not right-justified).  */
+#define GETFS()            ((int)(FCSR & fcsr_FS))
+
+
+/* FCSR flag bits definitions and access macros.  */
+#define IR            0   /* I: Inexact Result */
+#define UF            1   /* U: UnderFlow */
+#define OF            2   /* O: OverFlow */
+#define DZ            3   /* Z: Division by Zero */
+#define IO            4   /* V: Invalid Operation */
+#define UO            5   /* E: Unimplemented Operation (CAUSE field only) */
+
+#define FP_FLAGS(b)   (1 << ((b) + fcsr_FLAGS_shift))
+#define FP_ENABLE(b)  (1 << ((b) + fcsr_ENABLES_shift))
+#define FP_CAUSE(b)   (1 << ((b) + fcsr_CAUSE_shift))
+
+
+/* Rounding mode bit definitions and access macros.  */
+#define FP_RM_NEAREST 0   /* Round to nearest (Round).  */
+#define FP_RM_TOZERO  1   /* Round to zero (Trunc).  */
+#define FP_RM_TOPINF  2   /* Round to Plus infinity (Ceil).  */
+#define FP_RM_TOMINF  3   /* Round to Minus infinity (Floor).  */
+
+#define GETRM()       ((FCSR >> fcsr_RM_shift) & fcsr_RM_mask)
+
+
+#endif /* CP1_H */
diff --git a/sim/mips/mdmx.c b/sim/mips/mdmx.c
new file mode 100644 (file)
index 0000000..96abe1d
--- /dev/null
@@ -0,0 +1,1472 @@
+/* Simulation code for the MIPS MDMX ASE.
+   Copyright (C) 2002 Free Software Foundation, Inc.
+   Contributed by Broadcom Corporation (SiByte).
+
+This file is part of GDB, the GNU debugger.
+
+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, 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.,
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include <stdio.h>
+
+#include "sim-main.h"
+
+/* Within mdmx.c we refer to the sim_cpu directly. */
+#define CPU cpu
+#define SD  (CPU_STATE(CPU))
+#define        SD_ cpu, cia, -1
+
+/* MDMX Representations
+
+   An 8-bit packed byte element (OB) is always unsigned.
+   The 24-bit accumulators are signed and are represented as 32-bit
+   signed values, which are reduced to 24-bit signed values prior to
+   Round and Clamp operations.
+  
+   A 16-bit packed halfword element (QH) is always signed.
+   The 48-bit accumulators are signed and are represented as 64-bit
+   signed values, which are reduced to 48-bit signed values prior to
+   Round and Clamp operations.
+  
+   The code below assumes a 2's-complement representation of signed
+   quantities.  Care is required to clear extended sign bits when
+   repacking fields.
+  
+   The code (and the code for arithmetic shifts in mips.igen) also makes
+   the (not guaranteed portable) assumption that right shifts of signed
+   quantities in C do sign extension.  */
+
+typedef unsigned64 unsigned48;
+#define MASK48 (UNSIGNED64 (0xffffffffffff))
+
+typedef unsigned32 unsigned24;
+#define MASK24 (UNSIGNED32 (0xffffff))
+
+typedef enum {
+  mdmx_ob,          /* OB (octal byte) */
+  mdmx_qh           /* QH (quad half-word) */
+} MX_fmt;
+
+typedef enum {
+  sel_elem,         /* element select */
+  sel_vect,         /* vector select */
+  sel_imm           /* immediate select */
+} VT_select;
+
+#define OB_MAX  ((unsigned8)0xFF)
+#define QH_MIN  ((signed16)0x8000)
+#define QH_MAX  ((signed16)0x7FFF)
+
+#define OB_CLAMP(x)  ((unsigned8)((x) > OB_MAX ? OB_MAX : (x)))
+#define QH_CLAMP(x)  ((signed16)((x) < QH_MIN ? QH_MIN : \
+                                ((x) > QH_MAX ? QH_MAX : (x))))
+
+#define MX_FMT(fmtsel) (((fmtsel) & 0x1) == 0 ? mdmx_ob : mdmx_qh)
+#define MX_VT(fmtsel)  (((fmtsel) & 0x10) == 0 ?    sel_elem : \
+                       (((fmtsel) & 0x18) == 0x10 ? sel_vect : sel_imm))
+
+#define QH_ELEM(v,fmtsel) \
+        ((signed16)(((v) >> (((fmtsel) & 0xC) << 2)) & 0xFFFF))
+#define OB_ELEM(v,fmtsel) \
+        ((unsigned8)(((v) >> (((fmtsel) & 0xE) << 2)) & 0xFF))
+
+
+typedef signed16 (*QH_FUNC)(signed16, signed16);
+typedef unsigned8 (*OB_FUNC)(unsigned8, unsigned8);
+
+/* vectorized logical operators */
+
+static signed16
+AndQH(signed16 ts, signed16 tt)
+{
+  return (signed16)((unsigned16)ts & (unsigned16)tt);
+}
+
+static unsigned8
+AndOB(unsigned8 ts, unsigned8 tt)
+{
+  return ts & tt;
+}
+
+static signed16
+NorQH(signed16 ts, signed16 tt)
+{
+  return (signed16)(((unsigned16)ts | (unsigned16)tt) ^ 0xFFFF);
+}
+
+static unsigned8
+NorOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts | tt) ^ 0xFF;
+}
+
+static signed16
+OrQH(signed16 ts, signed16 tt)
+{
+  return (signed16)((unsigned16)ts | (unsigned16)tt);
+}
+
+static unsigned8
+OrOB(unsigned8 ts, unsigned8 tt)
+{
+  return ts | tt;
+}
+
+static signed16
+XorQH(signed16 ts, signed16 tt)
+{
+  return (signed16)((unsigned16)ts ^ (unsigned16)tt);
+}
+
+static unsigned8
+XorOB(unsigned8 ts, unsigned8 tt)
+{
+  return ts ^ tt;
+}
+
+static signed16
+SLLQH(signed16 ts, signed16 tt)
+{
+  unsigned32 s = (unsigned32)tt & 0xF;
+  return (signed16)(((unsigned32)ts << s) & 0xFFFF);
+}
+
+static unsigned8
+SLLOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 s = tt & 0x7;
+  return (ts << s) & 0xFF;
+}
+
+static signed16
+SRLQH(signed16 ts, signed16 tt)
+{
+  unsigned32 s = (unsigned32)tt & 0xF;
+  return (signed16)((unsigned16)ts >> s);
+}
+
+static unsigned8
+SRLOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 s = tt & 0x7;
+  return ts >> s;
+}
+
+
+/* Vectorized arithmetic operators.  */
+
+static signed16
+AddQH(signed16 ts, signed16 tt)
+{
+  signed32 t = (signed32)ts + (signed32)tt;
+  return QH_CLAMP(t);
+}
+
+static unsigned8
+AddOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 t = (unsigned32)ts + (unsigned32)tt;
+  return OB_CLAMP(t);
+}
+
+static signed16
+SubQH(signed16 ts, signed16 tt)
+{
+  signed32 t = (signed32)ts - (signed32)tt;
+  return QH_CLAMP(t);
+}
+
+static unsigned8
+SubOB(unsigned8 ts, unsigned8 tt)
+{
+  signed32 t;
+  t = (signed32)ts - (signed32)tt;
+  if (t < 0)
+    t = 0;
+  return (unsigned8)t;
+}
+
+static signed16
+MinQH(signed16 ts, signed16 tt)
+{
+  return (ts < tt ? ts : tt);
+}
+
+static unsigned8
+MinOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts < tt ? ts : tt);
+}
+
+static signed16
+MaxQH(signed16 ts, signed16 tt)
+{
+  return (ts > tt ? ts : tt);
+}
+
+static unsigned8
+MaxOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts > tt ? ts : tt);
+}
+
+static signed16
+MulQH(signed16 ts, signed16 tt)
+{
+  signed32 t = (signed32)ts * (signed32)tt;
+  return QH_CLAMP(t);
+}
+
+static unsigned8
+MulOB(unsigned8 ts, unsigned8 tt)
+{
+  unsigned32 t = (unsigned32)ts * (unsigned32)tt;
+  return OB_CLAMP(t);
+}
+
+/* "msgn" and "sra" are defined only for QH format.  */
+
+static signed16
+MsgnQH(signed16 ts, signed16 tt)
+{
+  signed16 t;
+  if (ts < 0)
+    t = (tt == QH_MIN ? QH_MAX : -tt);
+  else if (ts == 0)
+    t = 0;
+  else
+    t = tt;
+  return t;
+}
+
+static signed16
+SRAQH(signed16 ts, signed16 tt)
+{
+  unsigned32 s = (unsigned32)tt & 0xF;
+  return (signed16)((signed32)ts >> s);
+}
+
+
+/* "pabsdiff" and "pavg" are defined only for OB format.  */
+
+static unsigned8
+AbsDiffOB(unsigned8 ts, unsigned8 tt)
+{
+  return (ts >= tt ? ts - tt : tt - ts);
+}
+
+static unsigned8
+AvgOB(unsigned8 ts, unsigned8 tt)
+{
+  return ((unsigned32)ts + (unsigned32)tt + 1) >> 1;
+}
+
+
+/* Dispatch tables for operations that update a CPR.  */
+
+static const QH_FUNC qh_func[] = {
+  AndQH,  NorQH,  OrQH,   XorQH, SLLQH, SRLQH,
+  AddQH,  SubQH,  MinQH,  MaxQH,
+  MulQH,  MsgnQH, SRAQH,  NULL,  NULL
+};
+
+static const OB_FUNC ob_func[] = {
+  AndOB,  NorOB,  OrOB,   XorOB, SLLOB, SRLOB,
+  AddOB,  SubOB,  MinOB,  MaxOB,
+  MulOB,  NULL,   NULL,   AbsDiffOB, AvgOB
+};
+
+/* Auxiliary functions for CPR updates.  */
+
+/* Vector mapping for QH format.  */
+static unsigned64
+qh_vector_op(unsigned64 v1, unsigned64 v2, QH_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  signed16 h, h1, h2;
+
+  for (i = 0; i < 64; i += 16)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h2 = (signed16)(v2 & 0xFFFF);  v2 >>= 16;
+      h = (*func)(h1, h2);
+      result |= ((unsigned64)((unsigned16)h) << i);
+    }
+  return result;
+}
+
+static unsigned64
+qh_map_op(unsigned64 v1, signed16 h2, QH_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  signed16 h, h1;
+
+  for (i = 0; i < 64; i += 16)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h = (*func)(h1, h2);
+      result |= ((unsigned64)((unsigned16)h) << i);
+    }
+  return result;
+}
+
+
+/* Vector operations for OB format.  */
+
+static unsigned64
+ob_vector_op(unsigned64 v1, unsigned64 v2, OB_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  unsigned8 b, b1, b2;
+
+  for (i = 0; i < 64; i += 8)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      b = (*func)(b1, b2);
+      result |= ((unsigned64)b << i);
+    }
+  return result;
+}
+
+static unsigned64
+ob_map_op(unsigned64 v1, unsigned8 b2, OB_FUNC func)
+{
+  unsigned64 result = 0;
+  int  i;
+  unsigned8 b, b1;
+
+  for (i = 0; i < 64; i += 8)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b = (*func)(b1, b2);
+      result |= ((unsigned64)b << i);
+    }
+  return result;
+}
+
+
+/* Primary entry for operations that update CPRs.  */
+unsigned64
+mdmx_cpr_op(sim_cpu *cpu,
+           address_word cia,
+           int op,
+           unsigned64 op1,
+           int vt,
+           MX_fmtsel fmtsel) 
+{
+  unsigned64 op2;
+  unsigned64 result = 0;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_map_op(op1, QH_ELEM(op2, fmtsel), qh_func[op]);
+         break;
+       case sel_vect:
+         result = qh_vector_op(op1, ValueFPR(vt, fmt_mdmx), qh_func[op]);
+         break;
+       case sel_imm:
+         result = qh_map_op(op1, vt, qh_func[op]);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_map_op(op1, OB_ELEM(op2, fmtsel), ob_func[op]);
+         break;
+       case sel_vect:
+         result = ob_vector_op(op1, ValueFPR(vt, fmt_mdmx), ob_func[op]);
+         break;
+       case sel_imm:
+         result = ob_map_op(op1, vt, ob_func[op]);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+
+  return result;
+}
+
+
+/* Operations that update CCs */
+
+static void
+qh_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond)
+{
+  int  i;
+  signed16 h1, h2;
+  int  boolean;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h2 = (signed16)(v2 & 0xFFFF);  v2 >>= 16;
+      boolean = ((cond & MX_C_EQ) && (h1 == h2)) ||
+       ((cond & MX_C_LT) && (h1 < h2));
+      SETFCC(i, boolean);
+    }
+}
+
+static void
+qh_map_test(sim_cpu *cpu, unsigned64 v1, signed16 h2, int cond)
+{
+  int  i;
+  signed16 h1;
+  int  boolean;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      boolean = ((cond & MX_C_EQ) && (h1 == h2)) ||
+       ((cond & MX_C_LT) && (h1 < h2));
+      SETFCC(i, boolean);
+    }
+}
+
+static void
+ob_vector_test(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int cond)
+{
+  int  i;
+  unsigned8 b1, b2;
+  int  boolean;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      boolean = ((cond & MX_C_EQ) && (b1 == b2)) ||
+       ((cond & MX_C_LT) && (b1 < b2));
+      SETFCC(i, boolean);
+    }
+}
+
+static void
+ob_map_test(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int cond)
+{
+  int  i;
+  unsigned8 b1;
+  int  boolean;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = (unsigned8)(v1 & 0xFF);  v1 >>= 8;
+      boolean = ((cond & MX_C_EQ) && (b1 == b2)) ||
+       ((cond & MX_C_LT) && (b1 < b2));
+      SETFCC(i, boolean);
+    }
+}
+
+
+void
+mdmx_cc_op(sim_cpu *cpu,
+          address_word cia,
+          int cond,
+          unsigned64 v1,
+          int vt,
+          MX_fmtsel fmtsel)
+{
+  unsigned64 op2;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         qh_map_test(cpu, v1, QH_ELEM(op2, fmtsel), cond);
+         break;
+       case sel_vect:
+         qh_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond);
+         break;
+       case sel_imm:
+         qh_map_test(cpu, v1, vt, cond);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         ob_map_test(cpu, v1, OB_ELEM(op2, fmtsel), cond);
+         break;
+       case sel_vect:
+         ob_vector_test(cpu, v1, ValueFPR(vt, fmt_mdmx), cond);
+         break;
+       case sel_imm:
+         ob_map_test(cpu, v1, vt, cond);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+
+/* Pick operations.  */
+
+static unsigned64
+qh_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned16 h;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      h = ((GETFCC(i) == tf) ? (v1 & 0xFFFF) : (v2 & 0xFFFF));
+      v1 >>= 16;  v2 >>= 16;
+      result |= ((unsigned64)h << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+qh_map_pick(sim_cpu *cpu, unsigned64 v1, signed16 h2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned16 h;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      h = (GETFCC(i) == tf) ? (v1 & 0xFFFF) : (unsigned16)h2;
+      v1 >>= 16;
+      result |= ((unsigned64)h << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+ob_vector_pick(sim_cpu *cpu, unsigned64 v1, unsigned64 v2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b = (GETFCC(i) == tf) ? (v1 & 0xFF) : (v2 & 0xFF);
+      v1 >>= 8;  v2 >>= 8;
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+static unsigned64
+ob_map_pick(sim_cpu *cpu, unsigned64 v1, unsigned8 b2, int tf)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b = (GETFCC(i) == tf) ? (v1 & 0xFF) : b2;
+      v1 >>= 8;
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+
+unsigned64
+mdmx_pick_op(sim_cpu *cpu,
+            address_word cia,
+            int tf,
+            unsigned64 v1,
+            int vt,
+            MX_fmtsel fmtsel)
+{
+  unsigned64 result = 0;
+  unsigned64 op2;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_map_pick(cpu, v1, QH_ELEM(op2, fmtsel), tf);
+         break;
+       case sel_vect:
+         result = qh_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf);
+         break;
+       case sel_imm:
+         result = qh_map_pick(cpu, v1, vt, tf);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_map_pick(cpu, v1, OB_ELEM(op2, fmtsel), tf);
+         break;
+       case sel_vect:
+         result = ob_vector_pick(cpu, v1, ValueFPR(vt, fmt_mdmx), tf);
+         break;
+       case sel_imm:
+         result = ob_map_pick(cpu, v1, vt, tf);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+  return result;
+}
+
+
+/* Accumulators.  */
+
+typedef void (*QH_ACC)(signed48 *a, signed16 ts, signed16 tt);
+
+static void
+AccAddAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a += (signed48)ts + (signed48)tt;
+}
+
+static void
+AccAddLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a = (signed48)ts + (signed48)tt;
+}
+
+static void
+AccMulAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a += (signed48)ts * (signed48)tt;
+}
+
+static void
+AccMulLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a = (signed48)ts * (signed48)tt;
+}
+
+static void
+SubMulAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a -= (signed48)ts * (signed48)tt;
+}
+
+static void
+SubMulLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a = -((signed48)ts * (signed48)tt);
+}
+
+static void
+AccSubAQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a += (signed48)ts - (signed48)tt;
+}
+
+static void
+AccSubLQH(signed48 *a, signed16 ts, signed16 tt)
+{
+  *a =  (signed48)ts - (signed48)tt;
+}
+
+
+typedef void (*OB_ACC)(signed24 *acc, unsigned8 ts, unsigned8 tt);
+
+static void
+AccAddAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a += (signed24)ts + (signed24)tt;
+}
+
+static void
+AccAddLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = (signed24)ts + (signed24)tt;
+}
+
+static void
+AccMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a += (signed24)ts * (signed24)tt;
+}
+
+static void
+AccMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = (signed24)ts * (signed24)tt;
+}
+
+static void
+SubMulAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a -= (signed24)ts * (signed24)tt;
+}
+
+static void
+SubMulLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = -((signed24)ts * (signed24)tt);
+}
+
+static void
+AccSubAOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a += (signed24)ts - (signed24)tt;
+}
+
+static void
+AccSubLOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  *a = (signed24)ts - (signed24)tt;
+}
+
+static void
+AccAbsDiffOB(signed24 *a, unsigned8 ts, unsigned8 tt)
+{
+  unsigned8 t = (ts >= tt ? ts - tt : tt - ts);
+  *a += (signed24)t;
+}
+
+
+/* Dispatch tables for operations that update a CPR.  */
+
+static const QH_ACC qh_acc[] = {
+  AccAddAQH, AccAddAQH, AccMulAQH, AccMulLQH,
+  SubMulAQH, SubMulLQH, AccSubAQH, AccSubLQH,
+  NULL
+};
+
+static const OB_ACC ob_acc[] = {
+  AccAddAOB, AccAddLOB, AccMulAOB, AccMulLOB,
+  SubMulAOB, SubMulLOB, AccSubAOB, AccSubLOB,
+  AccAbsDiffOB
+};
+
+
+static void
+qh_vector_acc(signed48 a[], unsigned64 v1, unsigned64 v2, QH_ACC acc)
+{
+  int  i;
+  signed16 h1, h2;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      h2 = (signed16)(v2 & 0xFFFF);  v2 >>= 16;
+      (*acc)(&a[i], h1, h2);
+    }
+}
+
+static void
+qh_map_acc(signed48 a[], unsigned64 v1, signed16 h2, QH_ACC acc)
+{
+  int  i;
+  signed16 h1;
+
+  for (i = 0; i < 4; i++)
+    {
+      h1 = (signed16)(v1 & 0xFFFF);  v1 >>= 16;
+      (*acc)(&a[i], h1, h2);
+    }
+}
+
+static void
+ob_vector_acc(signed24 a[], unsigned64 v1, unsigned64 v2, OB_ACC acc)
+{
+  int  i;
+  unsigned8  b1, b2;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      (*acc)(&a[i], b1, b2);
+    }
+}
+
+static void
+ob_map_acc(signed24 a[], unsigned64 v1, unsigned8 b2, OB_ACC acc)
+{
+  int  i;
+  unsigned8 b1;
+
+  for (i = 0; i < 8; i++)
+    {
+      b1 = v1 & 0xFF;  v1 >>= 8;
+      (*acc)(&a[i], b1, b2);
+    }
+}
+
+
+/* Primary entry for operations that accumulate */
+void
+mdmx_acc_op(sim_cpu *cpu,
+           address_word cia,
+           int op,
+           unsigned64 op1,
+           int vt,
+           MX_fmtsel fmtsel) 
+{
+  unsigned64 op2;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         qh_map_acc(ACC.qh, op1, QH_ELEM(op2, fmtsel), qh_acc[op]);
+         break;
+       case sel_vect:
+         qh_vector_acc(ACC.qh, op1, ValueFPR(vt, fmt_mdmx), qh_acc[op]);
+         break;
+       case sel_imm:
+         qh_map_acc(ACC.qh, op1, vt, qh_acc[op]);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         ob_map_acc(ACC.ob, op1, OB_ELEM(op2, fmtsel), ob_acc[op]);
+         break;
+       case sel_vect:
+         ob_vector_acc(ACC.ob, op1, ValueFPR(vt, fmt_mdmx), ob_acc[op]);
+         break;
+       case sel_imm:
+         ob_map_acc(ACC.ob, op1, op2, ob_acc[op]);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+
+/* Reading and writing accumulator (no conversion).  */
+
+unsigned64
+mdmx_rac_op(sim_cpu *cpu,
+           address_word cia,
+           int op,
+           int fmt) 
+{
+  unsigned64    result;
+  unsigned int  shift;
+  int           i;
+
+  shift = op;          /* L = 00, M = 01, H = 10.  */
+  result = 0;
+
+  switch (fmt)
+    {
+    case MX_FMT_QH:
+      shift <<= 4;              /* 16 bits per element.  */
+      for (i = 3; i >= 0; --i)
+       {
+         result <<= 16;
+         result |= ((ACC.qh[i] >> shift) & 0xFFFF);
+       }
+      break;
+    case MX_FMT_OB:
+      shift <<= 3;              /*  8 bits per element.  */
+      for (i = 7; i >= 0; --i)
+       {
+         result <<= 8;
+         result |= ((ACC.ob[i] >> shift) & 0xFF);
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+  return result;
+}
+
+void
+mdmx_wacl(sim_cpu *cpu,
+         address_word cia,
+         int fmt,
+         unsigned64 vs,
+         unsigned64 vt) 
+{
+  int           i;
+
+  switch (fmt)
+    {
+    case MX_FMT_QH:
+      for (i = 0; i < 4; i++)
+       {
+         signed32  s = (signed16)(vs & 0xFFFF);
+         ACC.qh[i] = ((signed48)s << 16) | (vt & 0xFFFF);
+         vs >>= 16;  vt >>= 16;
+       }
+      break;
+    case MX_FMT_OB:
+      for (i = 0; i < 8; i++)
+       {
+         signed16  s = (signed8)(vs & 0xFF);
+         ACC.ob[i] = ((signed24)s << 8) | (vt & 0xFF);
+         vs >>= 8;   vt >>= 8;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+void
+mdmx_wach(sim_cpu *cpu,
+         address_word cia,
+         int fmt,
+         unsigned64 vs)
+{
+  int           i;
+
+  switch (fmt)
+    {
+    case MX_FMT_QH:
+      for (i = 0; i < 4; i++)
+       {
+         signed32  s = (signed16)(vs & 0xFFFF);
+         ACC.qh[i] &= ~((signed48)0xFFFF << 32);
+         ACC.qh[i] |=  ((signed48)s << 32);
+         vs >>= 16;
+       }
+      break;
+    case MX_FMT_OB:
+      for (i = 0; i < 8; i++)
+       {
+         ACC.ob[i] &= ~((signed24)0xFF << 16);
+         ACC.ob[i] |=  ((signed24)(vs & 0xFF) << 16);
+         vs >>= 8;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+}
+
+
+/* Reading and writing accumulator (rounding conversions).
+   Enumerating function guarantees s >= 0 for QH ops.  */
+
+typedef signed16 (*QH_ROUND)(signed48 a, signed16 s);
+
+#define QH_BIT(n)  ((unsigned48)1 << (n))
+#define QH_ONES(n) (((unsigned48)1 << (n))-1)
+
+static signed16
+RNASQH(signed48 a, signed16 s)
+{
+  signed48 t;
+  signed16 result = 0;
+
+  if (s > 48)
+    result = 0;
+  else
+    {
+      t = (a >> s);
+      if ((a & QH_BIT(47)) == 0)
+       {
+         if (s > 0 && ((a >> (s-1)) & 1) == 1)
+           t++;
+         if (t > QH_MAX)
+           t = QH_MAX;
+       }
+      else
+       {
+         if (s > 0 && ((a >> (s-1)) & 1) == 1)
+           {
+             if (s > 1 && ((unsigned48)a & QH_ONES(s-1)) != 0)
+               t++;
+           }
+         if (t < QH_MIN)
+           t = QH_MIN;
+       }
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RNAUQH(signed48 a, signed16 s)
+{
+  unsigned48 t;
+  signed16 result;
+
+  if (s > 48)
+    result = 0;
+  else if (s == 48)
+    result = ((unsigned48)a & MASK48) >> 47;
+  else
+    {
+      t = ((unsigned48)a & MASK48) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       t++;
+      if (t > 0xFFFF)
+       t = 0xFFFF;
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RNESQH(signed48 a, signed16 s)
+{
+  signed48 t;
+  signed16 result = 0;
+
+  if (s > 47)
+    result = 0;
+  else
+    {
+      t = (a >> s);
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       {
+         if (s == 1 || (a & QH_ONES(s-1)) == 0)
+           t += t & 1;
+         else
+           t += 1;
+       }
+      if ((a & QH_BIT(47)) == 0)
+       {
+         if (t > QH_MAX)
+           t = QH_MAX;
+       }
+      else
+       {
+         if (t < QH_MIN)
+           t = QH_MIN;
+       }
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RNEUQH(signed48 a, signed16 s)
+{
+  unsigned48 t;
+  signed16 result;
+
+  if (s > 48)
+    result = 0;
+  else if (s == 48)
+    result = ((unsigned48)a > QH_BIT(47) ? 1 : 0);
+  else
+    {
+      t = ((unsigned48)a & MASK48) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       {
+         if (s > 1 && (a & QH_ONES(s-1)) != 0)
+           t++;
+         else
+           t += t & 1;
+       }
+      if (t > 0xFFFF)
+       t = 0xFFFF;
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RZSQH(signed48 a, signed16 s)
+{
+  signed48 t;
+  signed16 result = 0;
+
+  if (s > 47)
+    result = 0;
+  else
+    {
+      t = (a >> s);
+      if ((a & QH_BIT(47)) == 0)
+       {
+         if (t > QH_MAX)
+           t = QH_MAX;
+       }
+      else
+       {
+         if (t < QH_MIN)
+           t = QH_MIN;
+       }
+      result = (signed16)t;
+    }
+  return result;
+}
+
+static signed16
+RZUQH(signed48 a, signed16 s)
+{
+  unsigned48 t;
+  signed16 result = 0;
+
+  if (s > 48)
+    result = 0;
+  else if (s == 48)
+    result = ((unsigned48)a > QH_BIT(47) ? 1 : 0);
+  else
+    {
+      t = ((unsigned48)a & MASK48) >> s;
+      if (t > 0xFFFF)
+       t = 0xFFFF;
+      result = (signed16)t;
+    }
+  return result;
+}
+
+
+typedef unsigned8 (*OB_ROUND)(signed24 a, unsigned8 s);
+
+#define OB_BIT(n)  ((unsigned24)1 << (n))
+#define OB_ONES(n) (((unsigned24)1 << (n))-1)
+
+static unsigned8
+RNAUOB(signed24 a, unsigned8 s)
+{
+  unsigned8 result;
+  unsigned24 t;
+
+  if (s > 24)
+    result = 0;
+  else if (s == 24)
+    result = ((unsigned24)a & MASK24) >> 23;
+  else
+    {
+      t = ((unsigned24)a & MASK24) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       t ++;
+      result = OB_CLAMP(t);
+    }
+  return result;
+}
+
+static unsigned8
+RNEUOB(signed24 a, unsigned8 s)
+{
+  unsigned8 result;
+  unsigned24 t;
+
+  if (s > 24)
+    result = 0;
+  else if (s == 24)
+    result = (((unsigned24)a & MASK24) > OB_BIT(23) ? 1 : 0);
+  else
+    {
+      t = ((unsigned24)a & MASK24) >> s;
+      if (s > 0 && ((a >> (s-1)) & 1) == 1)
+       {
+         if (s > 1 && (a & OB_ONES(s-1)) != 0)
+           t++;
+         else
+           t += t & 1;
+       }
+      result = OB_CLAMP(t);
+    }
+  return result;
+}
+
+static unsigned8
+RZUOB(signed24 a, unsigned8 s)
+{
+  unsigned8 result;
+  unsigned24 t;
+
+  if (s >= 24)
+    result = 0;
+  else
+    {
+      t = ((unsigned24)a & MASK24) >> s;
+      result = OB_CLAMP(t);
+    }
+  return result;
+}
+
+
+static const QH_ROUND qh_round[] = {
+  RNASQH, RNAUQH, RNESQH, RNEUQH, RZSQH,  RZUQH
+};
+
+static const OB_ROUND ob_round[] = {
+  NULL,   RNAUOB, NULL,   RNEUOB, NULL,   RZUOB
+};
+
+
+static unsigned64
+qh_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, QH_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  signed16 h, h2;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      h2 = (signed16)(v2 & 0xFFFF);
+      if (h2 >= 0)
+       h = (*round)(ACC.qh[i], h2);
+      else
+       {
+         UnpredictableResult ();
+         h = 0xdead;
+       }
+      v2 >>= 16;
+      result |= ((unsigned64)((unsigned16)h) << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+qh_map_round(sim_cpu *cpu, address_word cia, signed16 h2, QH_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  signed16  h;
+
+  s = 0;
+  for (i = 0; i < 4; i++)
+    {
+      if (h2 >= 0)
+       h = (*round)(ACC.qh[i], h2);
+      else
+       {
+         UnpredictableResult ();
+         h = 0xdead;
+       }
+      result |= ((unsigned64)((unsigned16)h) << s);
+      s += 16;
+    }
+  return result;
+}
+
+static unsigned64
+ob_vector_round(sim_cpu *cpu, address_word cia, unsigned64 v2, OB_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b, b2;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b2 = v2 & 0xFF;  v2 >>= 8;
+      b = (*round)(ACC.ob[i], b2);
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+static unsigned64
+ob_map_round(sim_cpu *cpu, address_word cia, unsigned8 b2, OB_ROUND round)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  unsigned8 b;
+
+  s = 0;
+  for (i = 0; i < 8; i++)
+    {
+      b = (*round)(ACC.ob[i], b2);
+      result |= ((unsigned64)b << s);
+      s += 8;
+    }
+  return result;
+}
+
+
+unsigned64
+mdmx_round_op(sim_cpu *cpu,
+             address_word cia,
+             int rm,
+             int vt,
+             MX_fmtsel fmtsel) 
+{
+  unsigned64 op2;
+  unsigned64 result = 0;
+
+  switch (MX_FMT (fmtsel))
+    {
+    case mdmx_qh:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_map_round(cpu, cia, QH_ELEM(op2, fmtsel), qh_round[rm]);
+         break;
+       case sel_vect:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = qh_vector_round(cpu, cia, op2, qh_round[rm]);
+         break;
+       case sel_imm:
+         result = qh_map_round(cpu, cia, vt, qh_round[rm]);
+         break;
+       }
+      break;
+    case mdmx_ob:
+      switch (MX_VT (fmtsel))
+       {
+       case sel_elem:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_map_round(cpu, cia, OB_ELEM(op2, fmtsel), ob_round[rm]);
+         break;
+       case sel_vect:
+         op2 = ValueFPR(vt, fmt_mdmx);
+         result = ob_vector_round(cpu, cia, op2, ob_round[rm]);
+         break;
+       case sel_imm:
+         result = ob_map_round(cpu, cia, vt, ob_round[rm]);
+         break;
+       }
+      break;
+    default:
+      Unpredictable ();
+    }
+
+  return result;
+}
+
+
+/* Shuffle operation.  */
+
+typedef struct {
+  enum {vs, ss, vt} source;
+  unsigned int      index;
+} sh_map;
+
+static const sh_map ob_shuffle[][8] = {
+  /* MDMX 2.0 encodings (3-4, 6-7).  */
+  /* vr5400   encoding  (5), otherwise.  */
+  {                                                              }, /* RSVD */
+  {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* RSVD */
+  {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}, /* RSVD */
+  {{vs,0}, {ss,0}, {vs,1}, {ss,1}, {vs,2}, {ss,2}, {vs,3}, {ss,3}}, /* upsl */
+  {{vt,1}, {vt,3}, {vt,5}, {vt,7}, {vs,1}, {vs,3}, {vs,5}, {vs,7}}, /* pach */
+  {{vt,0}, {vt,2}, {vt,4}, {vt,6}, {vs,0}, {vs,2}, {vs,4}, {vs,6}}, /* pacl */
+  {{vt,4}, {vs,4}, {vt,5}, {vs,5}, {vt,6}, {vs,6}, {vt,7}, {vs,7}}, /* mixh */
+  {{vt,0}, {vs,0}, {vt,1}, {vs,1}, {vt,2}, {vs,2}, {vt,3}, {vs,3}}  /* mixl */
+};
+
+static const sh_map qh_shuffle[][4] = {
+  {{vt,2}, {vs,2}, {vt,3}, {vs,3}},  /* mixh */
+  {{vt,0}, {vs,0}, {vt,1}, {vs,1}},  /* mixl */
+  {{vt,1}, {vt,3}, {vs,1}, {vs,3}},  /* pach */
+  {                              },  /* RSVD */
+  {{vt,1}, {vs,0}, {vt,3}, {vs,2}},  /* bfla */
+  {                              },  /* RSVD */
+  {{vt,2}, {vt,3}, {vs,2}, {vs,3}},  /* repa */
+  {{vt,0}, {vt,1}, {vs,0}, {vs,1}}   /* repb */
+};
+
+
+unsigned64
+mdmx_shuffle(sim_cpu *cpu,
+            address_word cia,
+            int shop,
+            unsigned64 op1,
+            unsigned64 op2)
+{
+  unsigned64 result = 0;
+  int  i, s;
+  int  op;
+
+  if ((shop & 0x3) == 0x1)       /* QH format.  */
+    {
+      op = shop >> 2;
+      s = 0;
+      for (i = 0; i < 4; i++)
+       {
+         unsigned64 v;
+
+         switch (qh_shuffle[op][i].source)
+           {
+           case vs:
+             v = op1;
+             break;
+           case vt:
+             v = op2;
+             break;
+           default:
+             Unpredictable ();
+             v = 0;
+           }
+         result |= (((v >> 16*qh_shuffle[op][i].index) & 0xFFFF) << s);
+         s += 16;
+       }
+    }
+  else if ((shop & 0x1) == 0x0)  /* OB format.  */
+    {
+      op = shop >> 1;
+      s = 0;
+      for (i = 0; i < 8; i++)
+       {
+         unsigned8 b;
+         unsigned int ishift = 8*ob_shuffle[op][i].index;
+
+         switch (ob_shuffle[op][i].source)
+           {
+           case vs:
+             b = (op1 >> ishift) & 0xFF;
+             break;
+           case ss:
+             b = ((op1 >> ishift) & 0x80) ? 0xFF : 0;
+             break;
+           case vt:
+             b = (op2 >> ishift) & 0xFF;
+             break;
+           default:
+             Unpredictable ();
+             b = 0;
+           }
+         result |= ((unsigned64)b << s);
+         s += 8;
+       }
+    }
+  else
+    Unpredictable ();
+
+  return result;
+}
diff --git a/sim/mips/mdmx.igen b/sim/mips/mdmx.igen
new file mode 100644 (file)
index 0000000..f286e3b
--- /dev/null
@@ -0,0 +1,592 @@
+// -*- C -*-
+
+// Simulator definition for the MIPS MDMX ASE.
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Broadcom Corporation (SiByte).
+//
+// This file is part of GDB, the GNU debugger.
+// 
+// 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, 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.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+//  Reference: MIPS64 Architecture Volume IV-b:
+//             The MDMX Application-Specific Extension
+
+//  Notes on "format selectors" (FMTSEL):
+//
+//   A selector with final bit 0 indicates OB format.
+//   A selector with final bits 01 indicates QH format.
+//   A selector with final bits 11 has UNPREDICTABLE result per the spec.
+//
+//  Similarly, for the single-bit fields which differentiate between
+//  formats (FMTOP), 0 is OB format and 1 is QH format.
+
+//  If you change this file to add instructions, please make sure that model
+//  "sb1" configurations still build, and that you've added no new
+//  instructions to the "sb1" model.
+
+
+// Helper:
+//
+// Check whether MDMX is usable, and if not signal an appropriate exception.
+//
+
+:function:::void:check_mdmx:instruction_word insn
+*mdmx:
+{
+  if (! COP_Usable (1))
+    SignalExceptionCoProcessorUnusable (1);
+  if ((SR & (status_MX|status_FR)) != (status_MX|status_FR))
+    SignalExceptionMDMX ();
+  check_u64 (SD_, insn);
+}
+
+
+// Helper:
+//
+// Check whether a given MDMX format selector indicates a valid and usable
+// format, and if not signal an appropriate exception.
+//
+
+:function:::int:check_mdmx_fmtsel:instruction_word insn, int fmtsel
+*mdmx:
+{
+  switch (fmtsel & 0x03)
+    {
+    case 0x00:     /* ob */
+    case 0x02:
+    case 0x01:     /* qh */
+      return 1;
+    case 0x03:     /* UNPREDICTABLE */
+      SignalException (ReservedInstruction, insn);
+      return 0;
+    }
+  return 0;
+}
+
+
+// Helper:
+//
+// Check whether a given MDMX format bit indicates a valid and usable
+// format, and if not signal an appropriate exception.
+//
+
+:function:::int:check_mdmx_fmtop:instruction_word insn, int fmtop
+*mdmx:
+{
+  switch (fmtop & 0x01)
+    {
+    case 0x00:     /* ob */
+    case 0x01:     /* qh */
+      return 1;
+    }
+  return 0;
+}
+
+
+:%s::::FMTSEL:int fmtsel
+*mdmx:
+*sb1:
+{
+  if ((fmtsel & 0x1) == 0)
+    return "ob";
+  else if ((fmtsel & 0x3) == 1)
+    return "qh";
+  else
+    return "?";
+}
+
+
+:%s::::FMTOP:int fmtop
+*mdmx:
+*sb1:
+{
+  switch (fmtop)
+    {
+    case 0: return "ob";
+    case 1: return "qh";
+    default: return "?";
+    }
+}
+
+
+:%s::::SHOP:int shop
+*mdmx:
+*sb1:
+{
+  if ((shop & 0x11) == 0x00)
+    switch ((shop >> 1) & 0x07)
+      {
+      case 3:  return "upsl.ob";
+      case 4:  return "pach.ob";
+      case 6:  return "mixh.ob";
+      case 7:  return "mixl.ob";
+      default: return "?";
+      }
+  else if ((shop & 0x03) == 0x01)
+    switch ((shop >> 2) & 0x07)
+      {
+      case 0:  return "mixh.qh";
+      case 1:  return "mixl.qh";
+      case 2:  return "pach.qh";
+      case 4:  return "bfla.qh";
+      case 6:  return "repa.qh";
+      case 7:  return "repb.qh";
+      default: return "?";
+      }
+  else
+    return "?";
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001011:MDMX:64::ADD.fmt
+"add.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Add(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110111:MDMX:64::ADDA.fmt
+"adda.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_AddA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110111:MDMX:64::ADDL.fmt
+"addl.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_AddL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,00,3.IMM,5.VT,5.VS,5.VD,0110,1.FMTOP,0:MDMX:64::ALNI.fmt
+"alni.%s<FMTOP> v<VD>, v<VS>, v<VT>, <IMM>"
+*mdmx:
+*sb1:
+{
+  unsigned64 result;
+  int s;
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  s = (IMM << 3);
+  result = ValueFPR(VS,fmt_mdmx) << s;
+  if (s != 0)  // x86 gcc treats >> 64 as >> 0
+    result |= ValueFPR(VT,fmt_mdmx) >> (64 - s);
+  StoreFPR(VD,fmt_mdmx,result);
+}
+
+
+011110,5.RS,5.VT,5.VS,5.VD,0110,1.FMTOP,1:MDMX:64::ALNV.fmt
+"alnv.%s<FMTOP> v<VD>, v<VS>, v<VT>, r<RS>"
+*mdmx:
+*sb1:
+{
+  unsigned64 result;
+  int s;
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  s = ((GPR[RS] & 0x7) << 3);
+  result = ValueFPR(VS,fmt_mdmx) << s;
+  if (s != 0)  // x86 gcc treats >> 64 as >> 0
+    result |= ValueFPR(VT,fmt_mdmx) >> (64 - s);
+  StoreFPR(VD,fmt_mdmx,result);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001100:MDMX:64::AND.fmt
+"and.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_And(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,000001:MDMX:64::C.EQ.fmt
+"c.eq.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_EQ,VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,000101:MDMX:64::C.LE.fmt
+"c.le.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_LT|MX_C_EQ,VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,000100:MDMX:64::C.LT.fmt
+"c.lt.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_Comp(ValueFPR(VS,fmt_mdmx),MX_C_LT,VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000111:MDMX:64::MAX.fmt
+"max.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Max(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000110:MDMX:64::MIN.fmt
+"min.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Min(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,5.VS,5.VD,000000:MDMX:64::MSGN.QH
+"msgn.qh v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_Msgn(ValueFPR(VS,fmt_mdmx),VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,110000:MDMX:64::MUL.fmt
+"mul.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Mul(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110011:MDMX:64::MULA.fmt
+"mula.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110011:MDMX:64::MULL.fmt
+"mull.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110010:MDMX:64::MULS.fmt
+"muls.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulS(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110010:MDMX:64::MULSL.fmt
+"mulsl.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_MulSL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001111:MDMX:64::NOR.fmt
+"nor.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Nor(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001110:MDMX:64::OR.fmt
+"or.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Or(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000010:MDMX:64::PICKF.fmt
+"pickf.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Pick(0,ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,000011:MDMX:64::PICKT.fmt
+"pickt.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Pick(1,ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,1000,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACH.fmt
+"rach.%s<FMTOP> v<VD>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_H,FMTOP));
+}
+
+
+011110,0000,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACL.fmt
+"racl.%s<FMTOP> v<VD>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_L,FMTOP));
+}
+
+
+011110,0100,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACM.fmt
+"racm.%s<FMTOP> v<VD>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  StoreFPR(VD,fmt_mdmx,MX_RAC(MX_RAC_M,FMTOP));
+}
+
+
+011110,3.SEL,01,5.VT,00000,5.VD,100101:MDMX:64::RNAS.QH
+"rnas.qh v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_RNAS(VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,00000,5.VD,100001:MDMX:64::RNAU.fmt
+"rnau.%s<FMTSEL> v<VD>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_RNAU(VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,00000,5.VD,100110:MDMX:64::RNES.QH
+"rnes.qh v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_RNES(VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,00000,5.VD,100010:MDMX:64::RNEU.fmt
+"rneu.%s<FMTSEL> v<VD>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_RNEU(VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,00000,5.VD,100100:MDMX:64::RZS.QH
+"rzs.qh v<VD>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_RZS(VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,00000,5.VD,100000:MDMX:64::RZU.fmt
+"rzu.%s<FMTSEL> v<VD>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_RZU(VT,FMTSEL));
+}
+
+
+011110,5.SHOP,5.VT,5.VS,5.VD,011111:MDMX:64::SHFL.op.fmt
+"shfl.%s<SHOP> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, SHOP))
+    StoreFPR(VD,fmt_mdmx,MX_SHFL(SHOP,ValueFPR(VS,fmt_mdmx),ValueFPR(VT,fmt_mdmx)));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,010000:MDMX:64::SLL.fmt
+"sll.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_ShiftLeftLogical(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,3.SEL,01,5.VT,5.VS,5.VD,010011:MDMX:64::SRA.QH
+"sra.qh v<VD>, v<VS>, v<VT>"
+*mdmx:
+{
+  check_mdmx (SD_, instruction_0);
+  StoreFPR(VD,fmt_mdmx,MX_ShiftRightArith(ValueFPR(VS,fmt_mdmx),VT,qh_fmtsel(SEL)));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,010010:MDMX:64::SRL.fmt
+"srl.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_ShiftRightLogical(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001010:MDMX:64::SUB.fmt
+"sub.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Sub(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,0,0000,110110:MDMX:64::SUBA.fmt
+"suba.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_SubA(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,1,0000,110110:MDMX:64::SUBL.fmt
+"subl.%s<FMTSEL> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    MX_SubL(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+}
+
+
+011110,1000,1.FMTOP,00000,5.VS,00000,111110:MDMX:64::WACH.fmt
+"wach.%s<FMTOP> v<VS>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  MX_WACH(FMTOP,ValueFPR(VS,fmt_mdmx));
+}
+
+
+011110,0000,1.FMTOP,5.VT,5.VS,00000,111110:MDMX:64::WACL.fmt
+"wacl.%s<FMTOP> v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  MX_WACL(FMTOP,ValueFPR(VS,fmt_mdmx),ValueFPR(VT,fmt_mdmx));
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001101:MDMX:64::XOR.fmt
+"xor.%s<FMTSEL> v<VD>, v<VS>, v<VT>"
+*mdmx:
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (check_mdmx_fmtsel (SD_, instruction_0, FMTSEL))
+    StoreFPR(VD,fmt_mdmx,MX_Xor(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+}
diff --git a/sim/mips/mips3d.igen b/sim/mips/mips3d.igen
new file mode 100644 (file)
index 0000000..f7043ef
--- /dev/null
@@ -0,0 +1,176 @@
+// -*- C -*-
+
+// Simulator definition for the MIPS MIPS-3D ASE.
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Broadcom Corporation (SiByte).
+//
+// This file is part of GDB, the GNU debugger.
+// 
+// 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, 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.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+//  Reference: MIPS64 Architecture for Programmers Volume IV-c:
+//             The MIPS-3D Application-Specific Extension to the
+//             MIPS64 Architecture.  (MIPS Document MD00099)
+
+
+010001,10,110,5.FT,5.FS,5.FD,011000:COP1:64,f::ADDR.PS
+"addr.ps f<FD>, f<FS>, f<FT>"
+*mips3d:
+{
+  /* fd.PL = ft.PU + ft.PL;  fd.PU = fs.PU + fs.PL;  */
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, AddR (ValueFPR (FS, fmt_ps),
+                             ValueFPR (FT, fmt_ps), fmt_ps));
+}
+
+
+010001,01001,3.CC,0,1.TF,16.OFFSET:COP1:64,f::BC1ANY2tf
+"bc1any2%s<TF> <CC>, %#lx<OFFSET>"
+*mips3d:
+{
+  address_word offset;
+  int cc = CC;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  if ((cc & 0x1) != 0)
+    Unpredictable ();
+  if ((GETFCC (cc) == TF) || (GETFCC (cc + 1) == TF))
+    {
+      offset = (EXTEND16 (OFFSET) << 2);
+      DELAY_SLOT (NIA + offset);
+    }
+}
+
+
+010001,01010,3.CC,0,1.TF,16.OFFSET:COP1:64,f::BC1ANY4tf
+"bc1any4%s<TF> <CC>, %#lx<OFFSET>"
+*mips3d:
+{
+  address_word offset;
+  int cc = CC;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  if ((cc & 0x3) != 0)
+    Unpredictable ();
+  if ((GETFCC (cc) == TF)
+      || (GETFCC (cc + 1) == TF)
+      || (GETFCC (cc + 2) == TF)
+      || (GETFCC (cc + 3) == TF))
+    {
+      offset = (EXTEND16 (OFFSET) << 2);
+      DELAY_SLOT (NIA + offset);
+    }
+}
+
+
+010001,10,3.FMT,5.FT,5.FS,3.CC,01,11,4.COND:COP1:64,f::CABS.cond.fmt
+"cabs.%s<COND>.%s<FMT> <CC>, f<FS>, f<FT>"
+*mips3d:
+{
+  int fmt = FMT;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  CompareAbs (ValueFPR (FS, fmt), ValueFPR (FT, fmt), fmt, COND, CC);
+  TRACE_ALU_RESULT (ValueFCR (31));
+}
+
+
+010001,10,110,00000,5.FS,5.FD,100100:COP1:64,f::CVT.PW.PS
+"cvt.pw.ps f<FD>, f<FS>"
+*mips3d:
+{
+  /* fd.pu = cvt_rnd (fs.pu); fd.pl = cvt_rnd (fs.pl);  */
+  /* fmt_pw is fmt_long for 64 bit transfers, but cvt encoding is fmt_word.  */
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_pw, ConvertPS (GETRM (), ValueFPR (FS, fmt_ps),
+                                  fmt_ps, fmt_word));
+}
+
+
+010001,10,100,00000,5.FS,5.FD,100110:COP1:64,f::CVT.PS.PW
+"cvt.ps.pw f<FD>, f<FS>"
+*mips3d:
+{
+  /* fd.pl = cvt_rnd (fs.pl); fd.pu = cvt_rnd (fs.pu);  */
+  /* fmt_pw is fmt_long for 64 bit transfers, but cvt encoding is fmt_word.  */
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, ConvertPS (GETRM (), ValueFPR (FS, fmt_pw),
+                                  fmt_word, fmt_ps));
+}
+
+
+010001,10,110,5.FT,5.FS,5.FD,011010:COP1:64,f::MULR.PS
+"mulr.ps f<FD>, f<FS>, f<FT>"
+*mips3d:
+{
+  /* fd.PL = ft.PU * ft.PL;  fd.PU = fs.PU * fs.PL;  */
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  StoreFPR (FD, fmt_ps, MultiplyR (ValueFPR (FS, fmt_ps),
+                                  ValueFPR (FT, fmt_ps), fmt_ps));
+}
+
+
+010001,10,3.FMT,00000,5.FS,5.FD,011101:COP1:64,f::RECIP1.fmt
+"recip1.%s<FMT> f<FD>, f<FS>"
+*mips3d:
+{
+  int fmt = FMT;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, Recip1 (ValueFPR (FS, fmt), fmt));
+}
+
+
+010001,10,3.FMT,5.FT,5.FS,5.FD,011100:COP1:64,f::RECIP2.fmt
+"recip2.%s<FMT> f<FD>, f<FS>, f<FT>"
+*mips3d:
+{
+  int fmt = FMT;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, Recip2 (ValueFPR (FS, fmt), ValueFPR (FT, fmt), fmt));
+}
+
+
+010001,10,3.FMT,00000,5.FS,5.FD,011110:COP1:64,f::RSQRT1.fmt
+"rsqrt1.%s<FMT> f<FD>, f<FS>"
+*mips3d:
+{
+  int fmt = FMT;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, RSquareRoot1 (ValueFPR (FS, fmt), fmt));
+}
+
+
+010001,10,3.FMT,5.FT,5.FS,5.FD,011111:COP1:64,f::RSQRT2.fmt
+"rsqrt2.%s<FMT> f<FD>, f<FS>, f<FT>"
+*mips3d:
+{
+  int fmt = FMT;
+  check_fpu (SD_);
+  check_u64 (SD_, instruction_0);
+  check_fmt_p (SD_, fmt, instruction_0);
+  StoreFPR (FD, fmt, RSquareRoot2 (ValueFPR (FS, fmt),
+                                  ValueFPR (FT, fmt), fmt));
+}
diff --git a/sim/mips/sb1.igen b/sim/mips/sb1.igen
new file mode 100644 (file)
index 0000000..6453670
--- /dev/null
@@ -0,0 +1,191 @@
+// -*- C -*-
+
+// Simulator definition for the Broadcom SiByte SB-1 CPU extensions.
+// Copyright (C) 2002 Free Software Foundation, Inc.
+// Contributed by Broadcom Corporation (SiByte).
+//
+// This file is part of GDB, the GNU debugger.
+// 
+// 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, 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.,
+// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+//  MDMX ASE Instructions
+//  ---------------------
+//
+//  The SB-1 implements the format OB subset of MDMX
+//  and has three additions (pavg, pabsdiff, pabsdifc).
+//  In addition, there are a couple of partial-decoding
+//  issues for the read/write accumulator instructions.
+//
+//  This code is structured so that mdmx.igen can be used by
+//  selecting the allowed instructions either via model, or by
+//  using check_mdmx_fmtsel and check_mdmx_fmtop to cause an
+//  exception if the instruction is not allowed.
+
+
+:function:::void:check_mdmx:instruction_word insn
+*sb1:
+{
+  if (!COP_Usable(1))
+    SignalExceptionCoProcessorUnusable(1);
+  if ((SR & status_MX) == 0)
+    SignalExceptionMDMX();
+  check_u64 (SD_, insn);
+}
+
+:function:::int:check_mdmx_fmtsel:instruction_word insn, int fmtsel
+*sb1:
+{
+  switch (fmtsel & 0x03)
+    {
+    case 0x00:     /* ob */
+    case 0x02:
+      return 1;
+    case 0x01:     /* qh */
+    case 0x03:     /* UNPREDICTABLE */
+      SignalException (ReservedInstruction, insn);
+      return 0;
+    }
+  return 0;
+}
+
+:function:::int:check_mdmx_fmtop:instruction_word insn, int fmtop
+*sb1:
+{
+  switch (fmtop & 0x01)
+    {
+    case 0x00:     /* ob */
+      return 1;
+    case 0x01:     /* qh */
+      SignalException (ReservedInstruction, insn);
+      return 0;
+    }
+  return 0;
+}
+
+
+011110,10,2.X!0,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACH.sb1.fmt
+"rach.?<X>.%s<FMTOP> v<VD>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,00,2.X!0,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACL.sb1.fmt
+"racl.?<X>.%s<FMTOP> v<VD>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,01,2.X!0,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RACM.sb1.fmt
+"racm.?<X>.%s<FMTOP> v<VD>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,2.X1!0!1!2,2.X2,1.FMTOP,00000,00000,5.VD,111111:MDMX:64::RAC.sb1.fmt
+"rac?<X1>.?<X2> v<VD>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,10,2.X!0,1.FMTOP,00000,5.VS,00000,111110:MDMX:64::WACH.sb1.fmt
+"wach.?<X>.%s<FMTOP> v<VS>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,00,2.X!0,1.FMTOP,5.VT,5.VS,00000,111110:MDMX:64::WACL.sb1.fmt
+"wacl.?<X>.%s<FMTOP> v<VS>,v<VT>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,2.X1!0!2,2.X2,1.FMTOP,5.VT,5.VS,00000,111110:MDMX:64::WAC.sb1.fmt
+"wacl?<X1>.?<X2>.%s<FMTOP> v<VS>,v<VT>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  check_mdmx_fmtop (SD_, instruction_0, FMTOP);
+  /* No op.  */
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001001:MDMX:64::PABSDIFF.fmt
+"pabsdiff.%s<FMTSEL> v<VD>,v<VS>,v<VT>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (SR & status_SBX)
+    {
+      check_mdmx_fmtsel (SD_, instruction_0, FMTSEL);
+      StoreFPR(VD,fmt_mdmx,MX_AbsDiff(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+    }
+  else
+    SignalException(ReservedInstruction, instruction_0);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,00000,110101:MDMX:64::PABSDIFC.fmt
+"pabsdifc.%<FMTSEL> v<VS>,v<VT>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (SR & status_SBX)
+    {
+      check_mdmx_fmtsel (SD_, instruction_0, FMTSEL);
+      MX_AbsDiffC(ValueFPR(VS,fmt_mdmx),VT,FMTSEL);
+    }
+  else
+    SignalException(ReservedInstruction, instruction_0);
+}
+
+
+011110,5.FMTSEL,5.VT,5.VS,5.VD,001000:MDMX:64::PAVG.fmt
+"pavg.%s<FMTSEL> v<VD>,v<VS>,v<VT>"
+*sb1:
+{
+  check_mdmx (SD_, instruction_0);
+  if (SR & status_SBX)
+    {
+      check_mdmx_fmtsel (SD_, instruction_0, FMTSEL);
+      StoreFPR(VD,fmt_mdmx,MX_Avg(ValueFPR(VS,fmt_mdmx),VT,FMTSEL));
+    }
+  else
+    SignalException(ReservedInstruction, instruction_0);
+}