From: nobody <> Date: Sat, 15 Jun 2002 12:26:32 +0000 (+0000) Subject: This commit was manufactured by cvs2svn to create branch X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4c080fbef0aa817020f05918efae1e5d5b168d1b;p=thirdparty%2Fbinutils-gdb.git This commit was manufactured by cvs2svn to create branch 'cagney_regbuf-20020515-branch'. Cherrypick from master 2002-06-15 12:26:31 UTC Mark Kettenis '* 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 --- diff --git a/bfd/cpu-dlx.c b/bfd/cpu-dlx.c new file mode 100644 index 00000000000..2023ff53121 --- /dev/null +++ b/bfd/cpu-dlx.c @@ -0,0 +1,39 @@ +/* BFD support for the DLX Microprocessor architecture. + Copyright 2002 Free Software Foundation, Inc. + Hacked by Kuang Hwa Lin + + 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 index 00000000000..91d75f3360a --- /dev/null +++ b/bfd/elf32-dlx.c @@ -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 index 00000000000..5f2e1113f4c --- /dev/null +++ b/bfd/elf32-i386qnx.c @@ -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 index 00000000000..ae2cab4e690 --- /dev/null +++ b/bfd/elf32-sh64-com.c @@ -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 index 00000000000..2d3e3d99dbd --- /dev/null +++ b/bfd/elf32-sh64-nbsd.c @@ -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 index 00000000000..8901188b7c6 --- /dev/null +++ b/bfd/elf32-vax.c @@ -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 . + +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 + +/* 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 */ + 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 index 00000000000..43e4eaf42ed --- /dev/null +++ b/bfd/elf64-sh64-nbsd.c @@ -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 index 00000000000..e20cd171d86 --- /dev/null +++ b/bfd/vax1knetbsd.c @@ -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 index 00000000000..bb6d29bf276 --- /dev/null +++ b/gdb/ada-exp.tab.c @@ -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 +#include +#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 /* 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 /* 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 /* 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 + +#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 + +#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" + + + 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 index 00000000000..7d46dd2cf8b --- /dev/null +++ b/gdb/ada-exp.y @@ -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 ( and for example) just became + too messy, particularly when such includes can be inserted at random + times by the parser generator. */ + +%{ + +#include "defs.h" +#include +#include +#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 exp exp1 simple_exp start variable +%type type + +%token INT NULL_PTR CHARLIT +%token FLOAT +%token TYPENAME +%token 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 STRING +%token NAME DOT_ID OBJECT_RENAMING +%type block +%type arglist tick_arglist + +%type save_qualifier + +%token DOT_ALL + +/* Special type cases, put in to allow the parser to distinguish different + legal basetypes. */ +%token LAST REGNAME + +%token 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 + + +%% + +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 index 00000000000..2c4f1d94d41 --- /dev/null +++ b/gdb/ada-lang.c @@ -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 +#include +#include +#include +#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); + + + +/* 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); +} + + + /* 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; +} + + + /* 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)); +} + + + /* 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); +} + + + /* 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 + ? "" + : 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)); + + } +} + + /* 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; +} + + + /* 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); +} + + + /* 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, "")); +} + +/* 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); + } + } +} + + + /* 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; + } +} + + + /* 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 , 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; +} + + + /* 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 ? "" : 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; +} + + + + /* 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) = ""; + 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); +} + + + + + +/* 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)); +} + + + /* 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); +} + + + /* 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"); + } +} + + + /* 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")); +} + + + /* 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; +} + + + + /* 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} +}; + + /* 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 "". 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, "", 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 index 00000000000..e5353f8524b --- /dev/null +++ b/gdb/ada-lang.h @@ -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 index 00000000000..9538f76b0cb --- /dev/null +++ b/gdb/ada-lex.c @@ -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 + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* 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 +#include +#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 +#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 +#include + +/* 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 index 00000000000..2252d526a52 --- /dev/null +++ b/gdb/ada-lex.l @@ -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."); + } + +"'"({GRAPHIC}|\")"'" { + yylval.typed_val.type = builtin_type_ada_char; + yylval.typed_val.val = yytext[1]; + return CHARLIT; + } + +"'[\""{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); } + +\" { + tempbuf_len = 0; + BEGIN 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; + } + +{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; + } + +{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; } + +"'" { 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 +#include + +/* 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 index 00000000000..23dc105ea9d --- /dev/null +++ b/gdb/ada-tasks.c @@ -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 + + 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 +#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 +#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 ("\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; itask_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 (®s, 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 (" \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 index 00000000000..677356186b2 --- /dev/null +++ b/gdb/ada-typeprint.c @@ -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 +#include +#include + +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*); + + + +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, "", + 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, " ", 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, " 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, ""); + 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, " "); + 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 ? ()"); + 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 index 00000000000..6db18ebae1e --- /dev/null +++ b/gdb/ada-valprint.c @@ -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 +#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); + + +/* 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, " ", 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, " ", 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 ("", 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 index 00000000000..100e40b42bb --- /dev/null +++ b/gdb/config/arm/nbsdaout.mh @@ -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 index 00000000000..481d5cc92a5 --- /dev/null +++ b/gdb/config/arm/nbsdelf.mh @@ -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 index 00000000000..3f7fee9de1a --- /dev/null +++ b/gdb/config/arm/nm-nbsdaout.h @@ -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 index 00000000000..e52f38a5b21 --- /dev/null +++ b/gdb/config/i386/nbsdaout.mh @@ -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 index 00000000000..aa88957b9ea --- /dev/null +++ b/gdb/config/i386/nbsdaout.mt @@ -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 index 00000000000..dc8aac961c4 --- /dev/null +++ b/gdb/config/i386/nm-nbsdaout.h @@ -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 index 00000000000..8dde114cf82 --- /dev/null +++ b/gdb/config/i386/tm-nbsdaout.h @@ -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 index 00000000000..7ce279b332e --- /dev/null +++ b/gdb/config/m68k/nbsdaout.mh @@ -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 index 00000000000..b6ac5a000e1 --- /dev/null +++ b/gdb/config/m68k/nbsdaout.mt @@ -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 index 00000000000..cb755f0bed2 --- /dev/null +++ b/gdb/config/m68k/nm-nbsdaout.h @@ -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 index 00000000000..4556fc60b27 --- /dev/null +++ b/gdb/config/mips/nbsd.mh @@ -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 index 00000000000..de529166c56 --- /dev/null +++ b/gdb/config/mips/nbsd.mt @@ -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 index 00000000000..67628c2fa97 --- /dev/null +++ b/gdb/config/mips/nm-nbsd.h @@ -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 index 00000000000..fc7448665e1 --- /dev/null +++ b/gdb/config/mips/tm-nbsd.h @@ -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 index 00000000000..026f1ed8d50 --- /dev/null +++ b/gdb/config/nm-nbsdaout.h @@ -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 index 00000000000..8cf47816a1e --- /dev/null +++ b/gdb/config/ns32k/nbsdaout.mh @@ -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 index 00000000000..24418f4e8dc --- /dev/null +++ b/gdb/config/ns32k/nbsdaout.mt @@ -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 index 00000000000..aed3c7f3562 --- /dev/null +++ b/gdb/config/ns32k/nm-nbsdaout.h @@ -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 index 00000000000..cd1594294fc --- /dev/null +++ b/gdb/config/ns32k/tm-ns32k.h @@ -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 index 00000000000..eb54e489eb8 --- /dev/null +++ b/gdb/config/sparc/nbsd64.mh @@ -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 index 00000000000..93b8f7841d4 --- /dev/null +++ b/gdb/config/sparc/nbsd64.mt @@ -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 index 00000000000..45208998124 --- /dev/null +++ b/gdb/config/sparc/nbsdaout.mh @@ -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 index 00000000000..730759153e0 --- /dev/null +++ b/gdb/config/sparc/nm-nbsdaout.h @@ -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 index 00000000000..cc1d6b32297 --- /dev/null +++ b/gdb/config/sparc/tm-nbsd64.h @@ -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 index 00000000000..bbfa86f16c5 --- /dev/null +++ b/gdb/gdbserver/acinclude.m4 @@ -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 index 00000000000..becf565529b --- /dev/null +++ b/gdb/gdbserver/proc-service.c @@ -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 + via . */ +#ifdef HAVE_LINUX_ELF_H +#include +#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 index 00000000000..f3d57a54d62 --- /dev/null +++ b/gdb/gdbserver/thread-db.c @@ -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 +#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 + via . */ +#ifdef HAVE_LINUX_ELF_H +#include +#endif +#endif + +#include "../gdb_proc_service.h" + +/* Structure that identifies the child process for the + 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, ¬ify); + 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, ¬ify); + 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 index 00000000000..3c30130ede9 --- /dev/null +++ b/gdb/i386-linux-tdep.h @@ -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 index 00000000000..714f5db9b36 --- /dev/null +++ b/gdb/i386-sol2-tdep.c @@ -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; +} + + +/* 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 index 00000000000..40b31541f90 --- /dev/null +++ b/gdb/macrocmd.c @@ -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" + + +/* 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); +} + + + +/* 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); +} + + + +/* 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."); +} + + + +/* 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.", + ¯olist, "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.", + ¯olist); + add_alias_cmd ("exp", "expand", no_class, 1, ¯olist); + 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.", + ¯olist); + add_alias_cmd ("exp1", "expand-once", no_class, 1, ¯olist); + + 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))", + ¯olist); + + add_cmd + ("undef", no_class, macro_undef_command, + "Remove the definition of the C/C++ preprocessor macro with the" + " given name.", + ¯olist); + + add_cmd + ("list", no_class, macro_list_command, + "List all the macros defined using the `macro define' command.", + ¯olist); + + user_macros = new_macro_table (0, 0); +} diff --git a/gdb/macroscope.c b/gdb/macroscope.c new file mode 100644 index 00000000000..08ff6ebff58 --- /dev/null +++ b/gdb/macroscope.c @@ -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 index 00000000000..fc10b6dcd60 --- /dev/null +++ b/gdb/macroscope.h @@ -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 index 00000000000..16521f67617 --- /dev/null +++ b/gdb/mipsnbsd-nat.c @@ -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 +#include +#include + +/* 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) ®s, 0) == -1) + perror_with_name ("Couldn't get registers"); + + mipsnbsd_supply_reg ((char *) ®s, 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) ®s, 0) == -1) + perror_with_name ("Couldn't get registers"); + + mipsnbsd_fill_reg ((char *) ®s, regno); + + if (ptrace (PT_SETREGS, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) ®s, 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 index 00000000000..029ae6f28bc --- /dev/null +++ b/gdb/mipsnbsd-tdep.c @@ -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 index 00000000000..6e9f50ed7c2 --- /dev/null +++ b/gdb/mipsnbsd-tdep.h @@ -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 index 00000000000..c0463247f47 --- /dev/null +++ b/gdb/ns32k-tdep.h @@ -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 index 00000000000..1ca0b3b39ac --- /dev/null +++ b/gdb/ns32knbsd-tdep.c @@ -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 index 00000000000..1e122b8fb9f --- /dev/null +++ b/gdb/osabi.c @@ -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[] = +{ + "", + + "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", + + "" +}; + +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; +} + + +/* 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; +} + + +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)); +} + + +/* 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; +} + + +void +_initialize_gdb_osabi (void) +{ + if (strcmp (gdb_osabi_names[GDB_OSABI_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 index 00000000000..1654f9d6fa1 --- /dev/null +++ b/gdb/osabi.h @@ -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 index 00000000000..0d33683a4c4 --- /dev/null +++ b/gdb/ppc-sysv-tdep.c @@ -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 (®isters[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 (®isters[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 (®isters[REGISTER_BYTE (greg)], + VALUE_CONTENTS (arg), 4); + memcpy (®isters[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 (®isters[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 (®isters[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 index 00000000000..44d86825872 --- /dev/null +++ b/gdb/ppcnbsd-tdep.c @@ -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 index 00000000000..3eae72d819a --- /dev/null +++ b/gdb/ppcnbsd-tdep.h @@ -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 index 00000000000..cd7f35a8324 --- /dev/null +++ b/gdb/sh-tdep.h @@ -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 index 00000000000..5a7057b6b04 --- /dev/null +++ b/gdb/sim-regno.h @@ -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 index 00000000000..a991d0ef2a4 --- /dev/null +++ b/gdb/sparc64nbsd-nat.c @@ -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 +#include +#include + +/* 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) ®s, 0) == -1) + perror_with_name ("Couldn't get registers"); + + if (gdbarch_ptr_bit (current_gdbarch) == 32) + sparcnbsd_supply_reg32 ((char *) ®s.regs32, regno); + else + sparcnbsd_supply_reg64 ((char *) ®s.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) ®s, 0) == -1) + perror_with_name ("Couldn't get registers"); + + if (gdbarch_ptr_bit (current_gdbarch) == 32) + sparcnbsd_fill_reg32 ((char *) ®s.regs32, regno); + else + sparcnbsd_fill_reg64 ((char *) ®s.regs64, regno); + + if (ptrace (PT_SETREGS, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) ®s, 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 index 00000000000..ce5d44dc6b4 --- /dev/null +++ b/gdb/sparcnbsd-nat.c @@ -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 +#include +#include + +/* 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) ®s, 0) == -1) + perror_with_name ("Couldn't get registers"); + + sparcnbsd_supply_reg32 ((char *) ®s, 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) ®s, 0) == -1) + perror_with_name ("Couldn't get registers"); + + sparcnbsd_fill_reg32 ((char *) ®s, regno); + + if (ptrace (PT_SETREGS, PIDGET (inferior_ptid), + (PTRACE_ARG3_TYPE) ®s, 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 index 00000000000..ea70e517b6d --- /dev/null +++ b/gdb/sparcnbsd-tdep.c @@ -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 index 00000000000..bad2d653c8e --- /dev/null +++ b/gdb/sparcnbsd-tdep.h @@ -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 index 00000000000..5bcaeae25ab --- /dev/null +++ b/gdb/testsuite/gdb.asm/x86_64.inc @@ -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 index 00000000000..283fe844573 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp.exp @@ -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_ 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 index 00000000000..89a1b07d1e6 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp1.c @@ -0,0 +1,80 @@ +#include + +#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_ is #defined until just before the + definition of the function . + + A macro named BEFORE_ is not #defined until just before the + definition of . + + The macro WHERE is redefined before each function to the + token list ``before ''. + + 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 index 00000000000..ef0feaac5a5 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp2.h @@ -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 index 00000000000..ebfcc6e1930 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp3.h @@ -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 index 00000000000..5302d8d3c47 --- /dev/null +++ b/gdb/testsuite/gdb.base/macscp4.h @@ -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 index 00000000000..d9950274d7a --- /dev/null +++ b/gdb/testsuite/gdb.c++/m-data.cc @@ -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 + 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 + class gnu_obj_3 + { + protected: + typedef region antiquities; + gnu_obj_2 data; + + public: + gnu_obj_3(antiquities b): data(etruscan) { } + }; +} + +int main() +{ + using namespace __gnu_test; + gnu_obj_1 test1(egyptian, 4589); + gnu_obj_2 test2(roman); + gnu_obj_3 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 index 00000000000..ac6825870da --- /dev/null +++ b/gdb/testsuite/gdb.c++/m-data.exp @@ -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 + +# 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 index 00000000000..24338014365 --- /dev/null +++ b/gdb/testsuite/gdb.c++/m-static.cc @@ -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 + 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 gnu_obj_2::antiquities gnu_obj_2::value_derived = etruscan; + + // Test three. + template + class gnu_obj_3 + { + public: + typedef region antiquities; + static gnu_obj_2 data; + + public: + gnu_obj_3(antiquities b) { } + }; + + template + gnu_obj_2 gnu_obj_3::data(etruscan); +} + +// instantiate templates explicitly so their static members will exist +template class __gnu_test::gnu_obj_2; +template class __gnu_test::gnu_obj_2; +template class __gnu_test::gnu_obj_3; + +int main() +{ + using namespace __gnu_test; + + gnu_obj_1 test1(egyptian, 4589); + gnu_obj_2 test2(roman); + gnu_obj_3 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 index 00000000000..c05983b6538 --- /dev/null +++ b/gdb/testsuite/gdb.c++/m-static.exp @@ -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 + +# 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 index 00000000000..9a9c737b55d --- /dev/null +++ b/gdb/testsuite/gdb.c++/try_catch.cc @@ -0,0 +1,126 @@ +// 2002-05-27 + +#include +#include +#include + +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 + 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 + class gnu_obj_3 + { + public: + typedef region antiquities; + gnu_obj_2 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 test2(roman); + gnu_obj_3 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 index 00000000000..e024132b99e --- /dev/null +++ b/gdb/testsuite/gdb.c++/try_catch.exp @@ -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 + +# 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 index 00000000000..562f600f35d --- /dev/null +++ b/include/elf/dlx.h @@ -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 index 00000000000..aba5d9f08a0 --- /dev/null +++ b/include/elf/vax.h @@ -0,0 +1,51 @@ +/* VAX ELF support for BFD. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Matt Thomas . + + 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 index 00000000000..30752842ed9 --- /dev/null +++ b/include/gdb/callback.h @@ -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 +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif +#endif + +/* 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; + +/* 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 + +/* 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) + +/* 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 index 00000000000..726ec623fbd --- /dev/null +++ b/include/gdb/remote-sim.h @@ -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)); + + +/* 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 index 00000000000..1e49781e8c0 --- /dev/null +++ b/include/gdb/sim-arm.h @@ -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 index 00000000000..f153a419478 --- /dev/null +++ b/include/gdb/sim-d10v.h @@ -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 index 00000000000..e1b249f8523 --- /dev/null +++ b/include/opcode/dlx.h @@ -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 index 00000000000..8878b98aef0 --- /dev/null +++ b/opcodes/dlx-dis.c @@ -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 index 00000000000..7792373e789 --- /dev/null +++ b/sim/common/run-sim.h @@ -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 index 00000000000..24901d8b75a --- /dev/null +++ b/sim/mips/cp1.h @@ -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 index 00000000000..96abe1ddc12 --- /dev/null +++ b/sim/mips/mdmx.c @@ -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 + +#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 index 00000000000..f286e3b4ab4 --- /dev/null +++ b/sim/mips/mdmx.igen @@ -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 v, v, v" +*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 v, v" +*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 v, v" +*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 v, v, v, " +*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 v, v, v, r" +*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 v, v, v" +*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 v, v" +*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 v, v" +*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 v, v" +*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 v, v, v" +*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 v, v, v" +*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, v, v" +*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 v, v, v" +*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 v, v" +*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 v, v" +*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 v, v" +*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 v, v" +*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 v, v, v" +*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 v, v, v" +*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 v, v, v" +*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 v, v, v" +*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 v" +*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 v" +*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 v" +*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, v" +*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 v, v" +*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, v" +*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 v, v" +*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, v" +*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 v, v" +*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 v, v, v" +*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 v, v, v" +*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, v, v" +*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 v, v, v" +*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 v, v, v" +*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 v, v" +*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 v, v" +*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 v" +*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 v, v" +*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 v, v, v" +*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 index 00000000000..f7043efcac0 --- /dev/null +++ b/sim/mips/mips3d.igen @@ -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, f, f" +*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 , %#lx" +*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 , %#lx" +*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.%s , f, f" +*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, f" +*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, f" +*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, f, f" +*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 f, f" +*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 f, f, f" +*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 f, f" +*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 f, f, f" +*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 index 00000000000..6453670b1d6 --- /dev/null +++ b/sim/mips/sb1.igen @@ -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.?.%s v" +*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.?.%s v" +*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.?.%s v" +*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?.? v" +*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.?.%s v" +*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.?.%s v,v" +*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?.?.%s v,v" +*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 v,v,v" +*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.% v,v" +*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 v,v,v" +*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); +}