]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Fri, 26 Mar 2004 23:15:42 +0000 (23:15 +0000)
committernobody <>
Fri, 26 Mar 2004 23:15:42 +0000 (23:15 +0000)
'drow_intercu-20040221-branch'.

Cherrypick from master 2004-03-26 23:15:40 UTC Joel Brobecker <brobecker@gnat.com> '        * amd64-tdep.c (amd64_classify): make RANGE_TYPE objects be part':
    gdb/amd64-linux-nat.c
    gdb/amd64-linux-tdep.c
    gdb/amd64-tdep.c
    gdb/amd64-tdep.h
    gdb/config/i386/linux64.mh
    gdb/config/i386/linux64.mt
    gdb/config/i386/nm-linux64.h
    gdb/config/i386/obsdaout.mh
    gdb/config/i386/tm-linux64.h
    gdb/config/nm-bsd.h
    gdb/frv-linux-tdep.c
    gdb/frv-tdep.h
    gdb/solib-frv.c
    gdb/testsuite/gdb.arch/gdb1431.s
    gdb/testsuite/gdb.base/auxv.c
    gdb/testsuite/gdb.base/auxv.exp
    gdb/testsuite/gdb.cp/classes.cc
    gdb/testsuite/gdb.cp/pr-1553.cc
    gdb/testsuite/gdb.cp/pr-1553.exp
    gdb/tramp-frame.c
    gdb/tramp-frame.h
    sim/frv/profile-fr450.c
    sim/testsuite/sim/frv/mqlclrhs.cgs
    sim/testsuite/sim/frv/mqlmths.cgs
    sim/testsuite/sim/frv/mqsllhi.cgs
    sim/testsuite/sim/frv/mqsrahi.cgs

26 files changed:
gdb/amd64-linux-nat.c [new file with mode: 0644]
gdb/amd64-linux-tdep.c [new file with mode: 0644]
gdb/amd64-tdep.c [new file with mode: 0644]
gdb/amd64-tdep.h [new file with mode: 0644]
gdb/config/i386/linux64.mh [new file with mode: 0644]
gdb/config/i386/linux64.mt [new file with mode: 0644]
gdb/config/i386/nm-linux64.h [new file with mode: 0644]
gdb/config/i386/obsdaout.mh [new file with mode: 0644]
gdb/config/i386/tm-linux64.h [new file with mode: 0644]
gdb/config/nm-bsd.h [new file with mode: 0644]
gdb/frv-linux-tdep.c [new file with mode: 0644]
gdb/frv-tdep.h [new file with mode: 0644]
gdb/solib-frv.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/gdb1431.s [new file with mode: 0644]
gdb/testsuite/gdb.base/auxv.c [new file with mode: 0644]
gdb/testsuite/gdb.base/auxv.exp [new file with mode: 0644]
gdb/testsuite/gdb.cp/classes.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/pr-1553.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/pr-1553.exp [new file with mode: 0644]
gdb/tramp-frame.c [new file with mode: 0644]
gdb/tramp-frame.h [new file with mode: 0644]
sim/frv/profile-fr450.c [new file with mode: 0644]
sim/testsuite/sim/frv/mqlclrhs.cgs [new file with mode: 0644]
sim/testsuite/sim/frv/mqlmths.cgs [new file with mode: 0644]
sim/testsuite/sim/frv/mqsllhi.cgs [new file with mode: 0644]
sim/testsuite/sim/frv/mqsrahi.cgs [new file with mode: 0644]

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
new file mode 100644 (file)
index 0000000..72aa73c
--- /dev/null
@@ -0,0 +1,385 @@
+/* Native-dependent code for GNU/Linux x86-64.
+
+   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Jiri Smid, SuSE Labs.
+
+   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 "gdbcore.h"
+#include "regcache.h"
+#include "linux-nat.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include <sys/ptrace.h>
+#include <sys/debugreg.h>
+#include <sys/syscall.h>
+#include <sys/procfs.h>
+#include <asm/prctl.h>
+/* FIXME ezannoni-2003-07-09: we need <sys/reg.h> to be included after
+   <asm/ptrace.h> because the latter redefines FS and GS for no apparent
+   reason, and those definitions don't match the ones that libpthread_db
+   uses, which come from <sys/reg.h>.  */
+/* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have
+   been removed from ptrace.h in the kernel.  However, better safe than
+   sorry.  */
+#include <asm/ptrace.h>
+#include <sys/reg.h>
+#include "gdb_proc_service.h"
+
+/* Prototypes for supply_gregset etc.  */
+#include "gregset.h"
+
+#include "amd64-tdep.h"
+#include "i386-linux-tdep.h"
+#include "amd64-nat.h"
+
+/* Mapping between the general-purpose registers in GNU/Linux x86-64
+   `struct user' format and GDB's register cache layout.  */
+
+static int amd64_linux_gregset64_reg_offset[] =
+{
+  RAX * 8, RBX * 8,            /* %rax, %rbx */
+  RCX * 8, RDX * 8,            /* %rcx, %rdx */
+  RSI * 8, RDI * 8,            /* %rsi, %rdi */
+  RBP * 8, RSP * 8,            /* %rbp, %rsp */
+  R8 * 8, R9 * 8,              /* %r8 ... */
+  R10 * 8, R11 * 8,
+  R12 * 8, R13 * 8,
+  R14 * 8, R15 * 8,            /* ... %r15 */
+  RIP * 8, EFLAGS * 8,         /* %rip, %eflags */
+  CS * 8, SS * 8,              /* %cs, %ss */
+  DS * 8, ES * 8,              /* %ds, %es */
+  FS * 8, GS * 8               /* %fs, %gs */
+};
+\f
+
+/* Mapping between the general-purpose registers in GNU/Linux x86-64
+   `struct user' format and GDB's register cache layout for GNU/Linux
+   i386.
+
+   Note that most GNU/Linux x86-64 registers are 64-bit, while the
+   GNU/Linux i386 registers are all 32-bit, but since we're
+   little-endian we get away with that.  */
+
+/* From <sys/reg.h> on GNU/Linux i386.  */
+static int amd64_linux_gregset32_reg_offset[] =
+{
+  RAX * 8, RCX * 8,            /* %eax, %ecx */
+  RDX * 8, RBX * 8,            /* %edx, %ebx */
+  RSP * 8, RBP * 8,            /* %esp, %ebp */
+  RSI * 8, RDI * 8,            /* %esi, %edi */
+  RIP * 8, EFLAGS * 8,         /* %eip, %eflags */
+  CS * 8, SS * 8,              /* %cs, %ss */
+  DS * 8, ES * 8,              /* %ds, %es */
+  FS * 8, GS * 8,              /* %fs, %gs */
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1, -1,
+  ORIG_RAX * 8                 /* "orig_eax" */
+};
+\f
+
+/* Transfering the general-purpose registers between GDB, inferiors
+   and core files.  */
+
+/* Fill GDB's register cache with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+supply_gregset (elf_gregset_t *gregsetp)
+{
+  amd64_supply_native_gregset (current_regcache, gregsetp, -1);
+}
+
+/* Fill register REGNUM (if it is a general-purpose register) in
+   *GREGSETP with the value in GDB's register cache.  If REGNUM is -1,
+   do this for all registers.  */
+
+void
+fill_gregset (elf_gregset_t *gregsetp, int regnum)
+{
+  amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
+}
+
+/* Transfering floating-point registers between GDB, inferiors and cores.  */
+
+/* Fill GDB's register cache with the floating-point and SSE register
+   values in *FPREGSETP.  */
+
+void
+supply_fpregset (elf_fpregset_t *fpregsetp)
+{
+  amd64_supply_fxsave (current_regcache, -1, fpregsetp);
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FPREGSETP with the value in GDB's register cache.  If REGNUM is
+   -1, do this for all registers.  */
+
+void
+fill_fpregset (elf_fpregset_t *fpregsetp, int regnum)
+{
+  amd64_collect_fxsave (current_regcache, regnum, fpregsetp);
+}
+\f
+
+/* Transferring arbitrary registers between GDB and inferior.  */
+
+/* Fetch register REGNUM from the child process.  If REGNUM is -1, do
+   this for all registers (including the floating point and SSE
+   registers).  */
+
+void
+fetch_inferior_registers (int regnum)
+{
+  int tid;
+
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
+
+  if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+    {
+      elf_gregset_t regs;
+
+      if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
+       perror_with_name ("Couldn't get registers");
+
+      amd64_supply_native_gregset (current_regcache, &regs, -1);
+      if (regnum != -1)
+       return;
+    }
+
+  if (regnum == -1 || regnum >= AMD64_ST0_REGNUM)
+    {
+      elf_fpregset_t fpregs;
+
+      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+       perror_with_name ("Couldn't get floating point status");
+
+      amd64_supply_fxsave (current_regcache, -1, &fpregs);
+    }
+}
+
+/* Store register REGNUM back into the child process.  If REGNUM is
+   -1, do this for all registers (including the floating-point and SSE
+   registers).  */
+
+void
+store_inferior_registers (int regnum)
+{
+  int tid;
+
+  /* GNU/Linux LWP ID's are process ID's.  */
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
+
+  if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
+    {
+      elf_gregset_t regs;
+
+      if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
+       perror_with_name ("Couldn't get registers");
+
+      amd64_collect_native_gregset (current_regcache, &regs, regnum);
+
+      if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
+       perror_with_name ("Couldn't write registers");
+
+      if (regnum != -1)
+       return;
+    }
+
+  if (regnum == -1 || regnum >= AMD64_ST0_REGNUM)
+    {
+      elf_fpregset_t fpregs;
+
+      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
+       perror_with_name ("Couldn't get floating point status");
+
+      amd64_collect_fxsave (current_regcache, regnum, &fpregs);
+
+      if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
+       perror_with_name ("Couldn't write floating point status");
+
+      return;
+    }
+}
+\f
+
+static unsigned long
+amd64_linux_dr_get (int regnum)
+{
+  int tid;
+  unsigned long value;
+
+  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
+     multi-threaded processes here.  For now, pretend there is just
+     one thread.  */
+  tid = PIDGET (inferior_ptid);
+
+  /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
+     ptrace call fails breaks debugging remote targets.  The correct
+     way to fix this is to add the hardware breakpoint and watchpoint
+     stuff to the target vectore.  For now, just return zero if the
+     ptrace call fails.  */
+  errno = 0;
+  value = ptrace (PT_READ_U, tid,
+                 offsetof (struct user, u_debugreg[regnum]), 0);
+  if (errno != 0)
+#if 0
+    perror_with_name ("Couldn't read debug register");
+#else
+    return 0;
+#endif
+
+  return value;
+}
+
+static void
+amd64_linux_dr_set (int regnum, unsigned long value)
+{
+  int tid;
+
+  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
+     multi-threaded processes here.  For now, pretend there is just
+     one thread.  */
+  tid = PIDGET (inferior_ptid);
+
+  errno = 0;
+  ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
+  if (errno != 0)
+    perror_with_name ("Couldn't write debug register");
+}
+
+void
+amd64_linux_dr_set_control (unsigned long control)
+{
+  amd64_linux_dr_set (DR_CONTROL, control);
+}
+
+void
+amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+{
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+}
+
+void
+amd64_linux_dr_reset_addr (int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
+}
+
+unsigned long
+amd64_linux_dr_get_status (void)
+{
+  return amd64_linux_dr_get (DR_STATUS);
+}
+\f
+
+/* This function is called by libthread_db as part of its handling of
+   a request for a thread's local storage address.  */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph,
+                    lwpid_t lwpid, int idx, void **base)
+{
+  if (gdbarch_ptr_bit (current_gdbarch) == 32)
+    {
+      /* The full structure is found in <asm-i386/ldt.h>.  The second
+        integer is the LDT's base_address and that is used to locate
+        the thread's local storage.  See i386-linux-nat.c more
+        info.  */
+      unsigned int desc[4];
+
+      /* This code assumes that "int" is 32 bits and that
+        GET_THREAD_AREA returns no more than 4 int values.  */
+      gdb_assert (sizeof (int) == 4);  
+#ifndef PTRACE_GET_THREAD_AREA
+#define PTRACE_GET_THREAD_AREA 25
+#endif
+      if  (ptrace (PTRACE_GET_THREAD_AREA, 
+                  lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
+       return PS_ERR;
+      
+      /* Extend the value to 64 bits.  Here it's assumed that a "long"
+        and a "void *" are the same.  */
+      (*base) = (void *) (long) desc[1];
+      return PS_OK;
+    }
+  else
+    {
+      /* This definition comes from prctl.h, but some kernels may not
+         have it.  */
+#ifndef PTRACE_ARCH_PRCTL
+#define PTRACE_ARCH_PRCTL      30
+#endif
+      /* FIXME: ezannoni-2003-07-09 see comment above about include
+        file order.  We could be getting bogus values for these two.  */
+      gdb_assert (FS < ELF_NGREG);
+      gdb_assert (GS < ELF_NGREG);
+      switch (idx)
+       {
+       case FS:
+         if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
+           return PS_OK;
+         break;
+       case GS:
+         if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
+           return PS_OK;
+         break;
+       default:                   /* Should not happen.  */
+         return PS_BADADDR;
+       }
+    }
+  return PS_ERR;               /* ptrace failed.  */
+}
+\f
+
+void
+child_post_startup_inferior (ptid_t ptid)
+{
+  i386_cleanup_dregs ();
+  linux_child_post_startup_inferior (ptid);
+}
+\f
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_amd64_linux_nat (void);
+
+void
+_initialize_amd64_linux_nat (void)
+{
+  amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
+  amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
+  amd64_native_gregset64_reg_offset = amd64_linux_gregset64_reg_offset;
+
+  gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
+             == amd64_native_gregset32_num_regs);
+  gdb_assert (ARRAY_SIZE (amd64_linux_gregset64_reg_offset)
+             == amd64_native_gregset64_num_regs);
+}
diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c
new file mode 100644 (file)
index 0000000..843a84e
--- /dev/null
@@ -0,0 +1,225 @@
+/* Target-dependent code for GNU/Linux x86-64.
+
+   Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Jiri Smid, SuSE Labs.
+
+   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 "frame.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "osabi.h"
+
+#include "gdb_string.h"
+
+#include "amd64-tdep.h"
+#include "solib-svr4.h"
+
+/* Mapping between the general-purpose registers in `struct user'
+   format and GDB's register cache layout.  */
+
+/* From <sys/reg.h>.  */
+static int amd64_linux_gregset_reg_offset[] =
+{
+  10 * 8,                      /* %rax */
+  5 * 8,                       /* %rbx */
+  11 * 8,                      /* %rcx */
+  12 * 8,                      /* %rdx */
+  13 * 8,                      /* %rsi */
+  14 * 8,                      /* %rdi */
+  4 * 8,                       /* %rbp */
+  19 * 8,                      /* %rsp */
+  9 * 8,                       /* %r8 ... */
+  8 * 8,
+  7 * 8,
+  6 * 8,
+  3 * 8,
+  2 * 8,
+  1 * 8,
+  0 * 8,                       /* ... %r15 */
+  16 * 8,                      /* %rip */
+  18 * 8,                      /* %eflags */
+  17 * 8,                      /* %cs */
+  20 * 8,                      /* %ss */
+  23 * 8,                      /* %ds */
+  24 * 8,                      /* %es */
+  25 * 8,                      /* %fs */
+  26 * 8                       /* %gs */
+};
+\f
+
+/* Support for signal handlers.  */
+
+#define LINUX_SIGTRAMP_INSN0   0x48    /* mov $NNNNNNNN, %rax */
+#define LINUX_SIGTRAMP_OFFSET0 0
+#define LINUX_SIGTRAMP_INSN1   0x0f    /* syscall */
+#define LINUX_SIGTRAMP_OFFSET1 7
+
+static const unsigned char linux_sigtramp_code[] =
+{
+  /* mov $__NR_rt_sigreturn, %rax */
+  LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
+  /* syscall */
+  LINUX_SIGTRAMP_INSN1, 0x05
+};
+
+#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
+
+/* If PC is in a sigtramp routine, return the address of the start of
+   the routine.  Otherwise, return 0.  */
+
+static CORE_ADDR
+amd64_linux_sigtramp_start (CORE_ADDR pc)
+{
+  unsigned char buf[LINUX_SIGTRAMP_LEN];
+
+  /* We only recognize a signal trampoline if PC is at the start of
+     one of the two instructions.  We optimize for finding the PC at
+     the start, as will be the case when the trampoline is not the
+     first frame on the stack.  We assume that in the case where the
+     PC is not at the start of the instruction sequence, there will be
+     a few trailing readable bytes on the stack.  */
+
+  if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  if (buf[0] != LINUX_SIGTRAMP_INSN0)
+    {
+      if (buf[0] != LINUX_SIGTRAMP_INSN1)
+       return 0;
+
+      pc -= LINUX_SIGTRAMP_OFFSET1;
+
+      if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+       return 0;
+    }
+
+  if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+    return 0;
+
+  return pc;
+}
+
+/* Return whether PC is in a GNU/Linux sigtramp routine.  */
+
+static int
+amd64_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  /* If we have NAME, we can optimize the search.  The trampoline is
+     named __restore_rt.  However, it isn't dynamically exported from
+     the shared C library, so the trampoline may appear to be part of
+     the preceding function.  This should always be sigaction,
+     __sigaction, or __libc_sigaction (all aliases to the same
+     function).  */
+  if (name == NULL || strstr (name, "sigaction") != NULL)
+    return (amd64_linux_sigtramp_start (pc) != 0);
+
+  return (strcmp ("__restore_rt", name) == 0);
+}
+
+/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
+#define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
+
+/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
+   routine, return the address of the associated sigcontext structure.  */
+
+static CORE_ADDR
+amd64_linux_sigcontext_addr (struct frame_info *next_frame)
+{
+  CORE_ADDR sp;
+  char buf[8];
+
+  frame_unwind_register (next_frame, SP_REGNUM, buf);
+  sp = extract_unsigned_integer (buf, 8);
+
+  /* The sigcontext structure is part of the user context.  A pointer
+     to the user context is passed as the third argument to the signal
+     handler, i.e. in %rdx.  Unfortunately %rdx isn't preserved across
+     function calls so we can't use it.  Fortunately the user context
+     is part of the signal frame and the unwound %rsp directly points
+     at it.  */
+  return sp + AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
+}
+\f
+
+/* From <asm/sigcontext.h>.  */
+static int amd64_linux_sc_reg_offset[] =
+{
+  13 * 8,                      /* %rax */
+  11 * 8,                      /* %rbx */
+  14 * 8,                      /* %rcx */
+  12 * 8,                      /* %rdx */
+  9 * 8,                       /* %rsi */
+  8 * 8,                       /* %rdi */
+  10 * 8,                      /* %rbp */
+  15 * 8,                      /* %rsp */
+  0 * 8,                       /* %r8 */
+  1 * 8,                       /* %r9 */
+  2 * 8,                       /* %r10 */
+  3 * 8,                       /* %r11 */
+  4 * 8,                       /* %r12 */
+  5 * 8,                       /* %r13 */
+  6 * 8,                       /* %r14 */
+  7 * 8,                       /* %r15 */
+  16 * 8,                      /* %rip */
+  17 * 8,                      /* %eflags */
+
+  /* FIXME: kettenis/2002030531: The registers %cs, %fs and %gs are
+     available in `struct sigcontext'.  However, they only occupy two
+     bytes instead of four, which makes using them here rather
+     difficult.  Leave them out for now.  */
+  -1,                          /* %cs */
+  -1,                          /* %ss */
+  -1,                          /* %ds */
+  -1,                          /* %es */
+  -1,                          /* %fs */
+  -1                           /* %gs */
+};
+
+static void
+amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
+  tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
+  tdep->sizeof_gregset = 27 * 8;
+
+  amd64_init_abi (info, gdbarch);
+
+  set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, amd64_linux_pc_in_sigtramp);
+  tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
+  tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
+  tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
+
+  /* GNU/Linux uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+}
+\f
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern void _initialize_amd64_linux_tdep (void);
+
+void
+_initialize_amd64_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
+                         GDB_OSABI_LINUX, amd64_linux_init_abi);
+}
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
new file mode 100644 (file)
index 0000000..1a66e45
--- /dev/null
@@ -0,0 +1,1191 @@
+/* Target-dependent code for AMD64.
+
+   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Jiri Smid, SuSE Labs.
+
+   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 "arch-utils.h"
+#include "block.h"
+#include "dummy-frame.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "objfiles.h"
+#include "regcache.h"
+#include "regset.h"
+#include "symfile.h"
+
+#include "gdb_assert.h"
+
+#include "amd64-tdep.h"
+#include "i387-tdep.h"
+
+/* Note that the AMD64 architecture was previously known as x86-64.
+   The latter is (forever) engraved into the canonical system name as
+   returned by config.guess, and used as the name for the AMD64 port
+   of GNU/Linux.  The BSD's have renamed their ports to amd64; they
+   don't like to shout.  For GDB we prefer the amd64_-prefix over the
+   x86_64_-prefix since it's so much easier to type.  */
+
+/* Register information.  */
+
+struct amd64_register_info
+{
+  char *name;
+  struct type **type;
+};
+
+static struct amd64_register_info amd64_register_info[] =
+{
+  { "rax", &builtin_type_int64 },
+  { "rbx", &builtin_type_int64 },
+  { "rcx", &builtin_type_int64 },
+  { "rdx", &builtin_type_int64 },
+  { "rsi", &builtin_type_int64 },
+  { "rdi", &builtin_type_int64 },
+  { "rbp", &builtin_type_void_data_ptr },
+  { "rsp", &builtin_type_void_data_ptr },
+
+  /* %r8 is indeed register number 8.  */
+  { "r8", &builtin_type_int64 },
+  { "r9", &builtin_type_int64 },
+  { "r10", &builtin_type_int64 },
+  { "r11", &builtin_type_int64 },
+  { "r12", &builtin_type_int64 },
+  { "r13", &builtin_type_int64 },
+  { "r14", &builtin_type_int64 },
+  { "r15", &builtin_type_int64 },
+  { "rip", &builtin_type_void_func_ptr },
+  { "eflags", &builtin_type_int32 },
+  { "cs", &builtin_type_int32 },
+  { "ss", &builtin_type_int32 },
+  { "ds", &builtin_type_int32 },
+  { "es", &builtin_type_int32 },
+  { "fs", &builtin_type_int32 },
+  { "gs", &builtin_type_int32 },
+
+  /* %st0 is register number 24.  */
+  { "st0", &builtin_type_i387_ext },
+  { "st1", &builtin_type_i387_ext },
+  { "st2", &builtin_type_i387_ext },
+  { "st3", &builtin_type_i387_ext },
+  { "st4", &builtin_type_i387_ext },
+  { "st5", &builtin_type_i387_ext },
+  { "st6", &builtin_type_i387_ext },
+  { "st7", &builtin_type_i387_ext },
+  { "fctrl", &builtin_type_int32 },
+  { "fstat", &builtin_type_int32 },
+  { "ftag", &builtin_type_int32 },
+  { "fiseg", &builtin_type_int32 },
+  { "fioff", &builtin_type_int32 },
+  { "foseg", &builtin_type_int32 },
+  { "fooff", &builtin_type_int32 },
+  { "fop", &builtin_type_int32 },
+
+  /* %xmm0 is register number 40.  */
+  { "xmm0", &builtin_type_v4sf },
+  { "xmm1", &builtin_type_v4sf },
+  { "xmm2", &builtin_type_v4sf },
+  { "xmm3", &builtin_type_v4sf },
+  { "xmm4", &builtin_type_v4sf },
+  { "xmm5", &builtin_type_v4sf },
+  { "xmm6", &builtin_type_v4sf },
+  { "xmm7", &builtin_type_v4sf },
+  { "xmm8", &builtin_type_v4sf },
+  { "xmm9", &builtin_type_v4sf },
+  { "xmm10", &builtin_type_v4sf },
+  { "xmm11", &builtin_type_v4sf },
+  { "xmm12", &builtin_type_v4sf },
+  { "xmm13", &builtin_type_v4sf },
+  { "xmm14", &builtin_type_v4sf },
+  { "xmm15", &builtin_type_v4sf },
+  { "mxcsr", &builtin_type_int32 }
+};
+
+/* Total number of registers.  */
+#define AMD64_NUM_REGS \
+  (sizeof (amd64_register_info) / sizeof (amd64_register_info[0]))
+
+/* Return the name of register REGNUM.  */
+
+static const char *
+amd64_register_name (int regnum)
+{
+  if (regnum >= 0 && regnum < AMD64_NUM_REGS)
+    return amd64_register_info[regnum].name;
+
+  return NULL;
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+   register REGNUM. */
+
+static struct type *
+amd64_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum < AMD64_NUM_REGS);
+
+  return *amd64_register_info[regnum].type;
+}
+
+/* DWARF Register Number Mapping as defined in the System V psABI,
+   section 3.6.  */
+
+static int amd64_dwarf_regmap[] =
+{
+  /* General Purpose Registers RAX, RDX, RCX, RBX, RSI, RDI.  */
+  AMD64_RAX_REGNUM, AMD64_RDX_REGNUM,
+  AMD64_RCX_REGNUM, AMD64_RBX_REGNUM,
+  AMD64_RSI_REGNUM, AMD64_RDI_REGNUM,
+
+  /* Frame Pointer Register RBP.  */
+  AMD64_RBP_REGNUM,
+
+  /* Stack Pointer Register RSP.  */
+  AMD64_RSP_REGNUM,
+
+  /* Extended Integer Registers 8 - 15.  */
+  8, 9, 10, 11, 12, 13, 14, 15,
+
+  /* Return Address RA.  Mapped to RIP.  */
+  AMD64_RIP_REGNUM,
+
+  /* SSE Registers 0 - 7.  */
+  AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM,
+  AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3,
+  AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5,
+  AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
+
+  /* Extended SSE Registers 8 - 15.  */
+  AMD64_XMM0_REGNUM + 8, AMD64_XMM0_REGNUM + 9,
+  AMD64_XMM0_REGNUM + 10, AMD64_XMM0_REGNUM + 11,
+  AMD64_XMM0_REGNUM + 12, AMD64_XMM0_REGNUM + 13,
+  AMD64_XMM0_REGNUM + 14, AMD64_XMM0_REGNUM + 15,
+
+  /* Floating Point Registers 0-7.  */
+  AMD64_ST0_REGNUM + 0, AMD64_ST0_REGNUM + 1,
+  AMD64_ST0_REGNUM + 2, AMD64_ST0_REGNUM + 3,
+  AMD64_ST0_REGNUM + 4, AMD64_ST0_REGNUM + 5,
+  AMD64_ST0_REGNUM + 6, AMD64_ST0_REGNUM + 7
+};
+
+static const int amd64_dwarf_regmap_len =
+  (sizeof (amd64_dwarf_regmap) / sizeof (amd64_dwarf_regmap[0]));
+
+/* Convert DWARF register number REG to the appropriate register
+   number used by GDB.  */
+
+static int
+amd64_dwarf_reg_to_regnum (int reg)
+{
+  int regnum = -1;
+
+  if (reg >= 0 || reg < amd64_dwarf_regmap_len)
+    regnum = amd64_dwarf_regmap[reg];
+
+  if (regnum == -1)
+    warning ("Unmapped DWARF Register #%d encountered\n", reg);
+
+  return regnum;
+}
+
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+   needs any special handling.  */
+
+static int
+amd64_convert_register_p (int regnum, struct type *type)
+{
+  return i386_fp_regnum_p (regnum);
+}
+\f
+
+/* Register classes as defined in the psABI.  */
+
+enum amd64_reg_class
+{
+  AMD64_INTEGER,
+  AMD64_SSE,
+  AMD64_SSEUP,
+  AMD64_X87,
+  AMD64_X87UP,
+  AMD64_COMPLEX_X87,
+  AMD64_NO_CLASS,
+  AMD64_MEMORY
+};
+
+/* Return the union class of CLASS1 and CLASS2.  See the psABI for
+   details.  */
+
+static enum amd64_reg_class
+amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
+{
+  /* Rule (a): If both classes are equal, this is the resulting class.  */
+  if (class1 == class2)
+    return class1;
+
+  /* Rule (b): If one of the classes is NO_CLASS, the resulting class
+     is the other class.  */
+  if (class1 == AMD64_NO_CLASS)
+    return class2;
+  if (class2 == AMD64_NO_CLASS)
+    return class1;
+
+  /* Rule (c): If one of the classes is MEMORY, the result is MEMORY.  */
+  if (class1 == AMD64_MEMORY || class2 == AMD64_MEMORY)
+    return AMD64_MEMORY;
+
+  /* Rule (d): If one of the classes is INTEGER, the result is INTEGER.  */
+  if (class1 == AMD64_INTEGER || class2 == AMD64_INTEGER)
+    return AMD64_INTEGER;
+
+  /* Rule (e): If one of the classes is X87, X87UP, COMPLEX_X87 class,
+     MEMORY is used as class.  */
+  if (class1 == AMD64_X87 || class1 == AMD64_X87UP
+      || class1 == AMD64_COMPLEX_X87 || class2 == AMD64_X87
+      || class2 == AMD64_X87UP || class2 == AMD64_COMPLEX_X87)
+    return AMD64_MEMORY;
+
+  /* Rule (f): Otherwise class SSE is used.  */
+  return AMD64_SSE;
+}
+
+static void amd64_classify (struct type *type, enum amd64_reg_class class[2]);
+
+/* Return non-zero if TYPE is a non-POD structure or union type.  */
+
+static int
+amd64_non_pod_p (struct type *type)
+{
+  /* ??? A class with a base class certainly isn't POD, but does this
+     catch all non-POD structure types?  */
+  if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_N_BASECLASSES (type) > 0)
+    return 1;
+
+  return 0;
+}
+
+/* Classify TYPE according to the rules for aggregate (structures and
+   arrays) and union types, and store the result in CLASS.  */
+
+static void
+amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
+{
+  int len = TYPE_LENGTH (type);
+
+  /* 1. If the size of an object is larger than two eightbytes, or in
+        C++, is a non-POD structure or union type, or contains
+        unaligned fields, it has class memory.  */
+  if (len > 16 || amd64_non_pod_p (type))
+    {
+      class[0] = class[1] = AMD64_MEMORY;
+      return;
+    }
+
+  /* 2. Both eightbytes get initialized to class NO_CLASS.  */
+  class[0] = class[1] = AMD64_NO_CLASS;
+
+  /* 3. Each field of an object is classified recursively so that
+        always two fields are considered. The resulting class is
+        calculated according to the classes of the fields in the
+        eightbyte: */
+
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+    {
+      struct type *subtype = check_typedef (TYPE_TARGET_TYPE (type));
+
+      /* All fields in an array have the same type.  */
+      amd64_classify (subtype, class);
+      if (len > 8 && class[1] == AMD64_NO_CLASS)
+       class[1] = class[0];
+    }
+  else
+    {
+      int i;
+
+      /* Structure or union.  */
+      gdb_assert (TYPE_CODE (type) == TYPE_CODE_STRUCT
+                 || TYPE_CODE (type) == TYPE_CODE_UNION);
+
+      for (i = 0; i < TYPE_NFIELDS (type); i++)
+       {
+         struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+         int pos = TYPE_FIELD_BITPOS (type, i) / 64;
+         enum amd64_reg_class subclass[2];
+
+         /* Ignore static fields.  */
+         if (TYPE_FIELD_STATIC (type, i))
+           continue;
+
+         gdb_assert (pos == 0 || pos == 1);
+
+         amd64_classify (subtype, subclass);
+         class[pos] = amd64_merge_classes (class[pos], subclass[0]);
+         if (pos == 0)
+           class[1] = amd64_merge_classes (class[1], subclass[1]);
+       }
+    }
+
+  /* 4. Then a post merger cleanup is done:  */
+
+  /* Rule (a): If one of the classes is MEMORY, the whole argument is
+     passed in memory.  */
+  if (class[0] == AMD64_MEMORY || class[1] == AMD64_MEMORY)
+    class[0] = class[1] = AMD64_MEMORY;
+
+  /* Rule (b): If SSEUP is not preceeded by SSE, it is converted to
+     SSE.  */
+  if (class[0] == AMD64_SSEUP)
+    class[0] = AMD64_SSE;
+  if (class[1] == AMD64_SSEUP && class[0] != AMD64_SSE)
+    class[1] = AMD64_SSE;
+}
+
+/* Classify TYPE, and store the result in CLASS.  */
+
+static void
+amd64_classify (struct type *type, enum amd64_reg_class class[2])
+{
+  enum type_code code = TYPE_CODE (type);
+  int len = TYPE_LENGTH (type);
+
+  class[0] = class[1] = AMD64_NO_CLASS;
+
+  /* Arguments of types (signed and unsigned) _Bool, char, short, int,
+     long, long long, and pointers are in the INTEGER class.  Similarly,
+     range types, used by languages such as Ada, are also in the INTEGER
+     class.  */
+  if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
+       || code == TYPE_CODE_RANGE
+       || code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
+      && (len == 1 || len == 2 || len == 4 || len == 8))
+    class[0] = AMD64_INTEGER;
+
+  /* Arguments of types float, double and __m64 are in class SSE.  */
+  else if (code == TYPE_CODE_FLT && (len == 4 || len == 8))
+    /* FIXME: __m64 .  */
+    class[0] = AMD64_SSE;
+
+  /* Arguments of types __float128 and __m128 are split into two
+     halves.  The least significant ones belong to class SSE, the most
+     significant one to class SSEUP.  */
+  /* FIXME: __float128, __m128.  */
+
+  /* The 64-bit mantissa of arguments of type long double belongs to
+     class X87, the 16-bit exponent plus 6 bytes of padding belongs to
+     class X87UP.  */
+  else if (code == TYPE_CODE_FLT && len == 16)
+    /* Class X87 and X87UP.  */
+    class[0] = AMD64_X87, class[1] = AMD64_X87UP;
+
+  /* Aggregates.  */
+  else if (code == TYPE_CODE_ARRAY || code == TYPE_CODE_STRUCT
+          || code == TYPE_CODE_UNION)
+    amd64_classify_aggregate (type, class);
+}
+
+static enum return_value_convention
+amd64_return_value (struct gdbarch *gdbarch, struct type *type,
+                   struct regcache *regcache,
+                   void *readbuf, const void *writebuf)
+{
+  enum amd64_reg_class class[2];
+  int len = TYPE_LENGTH (type);
+  static int integer_regnum[] = { AMD64_RAX_REGNUM, AMD64_RDX_REGNUM };
+  static int sse_regnum[] = { AMD64_XMM0_REGNUM, AMD64_XMM1_REGNUM };
+  int integer_reg = 0;
+  int sse_reg = 0;
+  int i;
+
+  gdb_assert (!(readbuf && writebuf));
+
+  /* 1. Classify the return type with the classification algorithm.  */
+  amd64_classify (type, class);
+
+  /* 2. If the type has class MEMORY, then the caller provides space
+        for the return value and passes the address of this storage in
+        %rdi as if it were the first argument to the function. In
+        effect, this address becomes a hidden first argument.  */
+  if (class[0] == AMD64_MEMORY)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  gdb_assert (class[1] != AMD64_MEMORY);
+  gdb_assert (len <= 16);
+
+  for (i = 0; len > 0; i++, len -= 8)
+    {
+      int regnum = -1;
+      int offset = 0;
+
+      switch (class[i])
+       {
+       case AMD64_INTEGER:
+         /* 3. If the class is INTEGER, the next available register
+            of the sequence %rax, %rdx is used.  */
+         regnum = integer_regnum[integer_reg++];
+         break;
+
+       case AMD64_SSE:
+         /* 4. If the class is SSE, the next available SSE register
+             of the sequence %xmm0, %xmm1 is used.  */
+         regnum = sse_regnum[sse_reg++];
+         break;
+
+       case AMD64_SSEUP:
+         /* 5. If the class is SSEUP, the eightbyte is passed in the
+            upper half of the last used SSE register.  */
+         gdb_assert (sse_reg > 0);
+         regnum = sse_regnum[sse_reg - 1];
+         offset = 8;
+         break;
+
+       case AMD64_X87:
+         /* 6. If the class is X87, the value is returned on the X87
+             stack in %st0 as 80-bit x87 number.  */
+         regnum = AMD64_ST0_REGNUM;
+         if (writebuf)
+           i387_return_value (gdbarch, regcache);
+         break;
+
+       case AMD64_X87UP:
+         /* 7. If the class is X87UP, the value is returned together
+             with the previous X87 value in %st0.  */
+         gdb_assert (i > 0 && class[0] == AMD64_X87);
+         regnum = AMD64_ST0_REGNUM;
+         offset = 8;
+         len = 2;
+         break;
+
+       case AMD64_NO_CLASS:
+         continue;
+
+       default:
+         gdb_assert (!"Unexpected register class.");
+       }
+
+      gdb_assert (regnum != -1);
+
+      if (readbuf)
+       regcache_raw_read_part (regcache, regnum, offset, min (len, 8),
+                               (char *) readbuf + i * 8);
+      if (writebuf)
+       regcache_raw_write_part (regcache, regnum, offset, min (len, 8),
+                                (const char *) writebuf + i * 8);
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+\f
+
+static CORE_ADDR
+amd64_push_arguments (struct regcache *regcache, int nargs,
+                     struct value **args, CORE_ADDR sp, int struct_return)
+{
+  static int integer_regnum[] =
+  {
+    AMD64_RDI_REGNUM,          /* %rdi */
+    AMD64_RSI_REGNUM,          /* %rsi */
+    AMD64_RDX_REGNUM,          /* %rdx */
+    AMD64_RCX_REGNUM,          /* %rcx */
+    8,                         /* %r8 */
+    9                          /* %r9 */
+  };
+  static int sse_regnum[] =
+  {
+    /* %xmm0 ... %xmm7 */
+    AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM,
+    AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3,
+    AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5,
+    AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
+  };
+  struct value **stack_args = alloca (nargs * sizeof (struct value *));
+  int num_stack_args = 0;
+  int num_elements = 0;
+  int element = 0;
+  int integer_reg = 0;
+  int sse_reg = 0;
+  int i;
+
+  /* Reserve a register for the "hidden" argument.  */
+  if (struct_return)
+    integer_reg++;
+
+  for (i = 0; i < nargs; i++)
+    {
+      struct type *type = VALUE_TYPE (args[i]);
+      int len = TYPE_LENGTH (type);
+      enum amd64_reg_class class[2];
+      int needed_integer_regs = 0;
+      int needed_sse_regs = 0;
+      int j;
+
+      /* Classify argument.  */
+      amd64_classify (type, class);
+
+      /* Calculate the number of integer and SSE registers needed for
+         this argument.  */
+      for (j = 0; j < 2; j++)
+       {
+         if (class[j] == AMD64_INTEGER)
+           needed_integer_regs++;
+         else if (class[j] == AMD64_SSE)
+           needed_sse_regs++;
+       }
+
+      /* Check whether enough registers are available, and if the
+         argument should be passed in registers at all.  */
+      if (integer_reg + needed_integer_regs > ARRAY_SIZE (integer_regnum)
+         || sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum)
+         || (needed_integer_regs == 0 && needed_sse_regs == 0))
+       {
+         /* The argument will be passed on the stack.  */
+         num_elements += ((len + 7) / 8);
+         stack_args[num_stack_args++] = args[i];
+       }
+      else
+       {
+         /* The argument will be passed in registers.  */
+         char *valbuf = VALUE_CONTENTS (args[i]);
+         char buf[8];
+
+         gdb_assert (len <= 16);
+
+         for (j = 0; len > 0; j++, len -= 8)
+           {
+             int regnum = -1;
+             int offset = 0;
+
+             switch (class[j])
+               {
+               case AMD64_INTEGER:
+                 regnum = integer_regnum[integer_reg++];
+                 break;
+
+               case AMD64_SSE:
+                 regnum = sse_regnum[sse_reg++];
+                 break;
+
+               case AMD64_SSEUP:
+                 gdb_assert (sse_reg > 0);
+                 regnum = sse_regnum[sse_reg - 1];
+                 offset = 8;
+                 break;
+
+               default:
+                 gdb_assert (!"Unexpected register class.");
+               }
+
+             gdb_assert (regnum != -1);
+             memset (buf, 0, sizeof buf);
+             memcpy (buf, valbuf + j * 8, min (len, 8));
+             regcache_raw_write_part (regcache, regnum, offset, 8, buf);
+           }
+       }
+    }
+
+  /* Allocate space for the arguments on the stack.  */
+  sp -= num_elements * 8;
+
+  /* The psABI says that "The end of the input argument area shall be
+     aligned on a 16 byte boundary."  */
+  sp &= ~0xf;
+
+  /* Write out the arguments to the stack.  */
+  for (i = 0; i < num_stack_args; i++)
+    {
+      struct type *type = VALUE_TYPE (stack_args[i]);
+      char *valbuf = VALUE_CONTENTS (stack_args[i]);
+      int len = TYPE_LENGTH (type);
+
+      write_memory (sp + element * 8, valbuf, len);
+      element += ((len + 7) / 8);
+    }
+
+  /* The psABI says that "For calls that may call functions that use
+     varargs or stdargs (prototype-less calls or calls to functions
+     containing ellipsis (...) in the declaration) %al is used as
+     hidden argument to specify the number of SSE registers used.  */
+  regcache_raw_write_unsigned (regcache, AMD64_RAX_REGNUM, sse_reg);
+  return sp; 
+}
+
+static CORE_ADDR
+amd64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+                      struct regcache *regcache, CORE_ADDR bp_addr,
+                      int nargs, struct value **args,  CORE_ADDR sp,
+                      int struct_return, CORE_ADDR struct_addr)
+{
+  char buf[8];
+
+  /* Pass arguments.  */
+  sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);
+
+  /* Pass "hidden" argument".  */
+  if (struct_return)
+    {
+      store_unsigned_integer (buf, 8, struct_addr);
+      regcache_cooked_write (regcache, AMD64_RDI_REGNUM, buf);
+    }
+
+  /* Store return address.  */
+  sp -= 8;
+  store_unsigned_integer (buf, 8, bp_addr);
+  write_memory (sp, buf, 8);
+
+  /* Finally, update the stack pointer...  */
+  store_unsigned_integer (buf, 8, sp);
+  regcache_cooked_write (regcache, AMD64_RSP_REGNUM, buf);
+
+  /* ...and fake a frame pointer.  */
+  regcache_cooked_write (regcache, AMD64_RBP_REGNUM, buf);
+
+  return sp + 16;
+}
+\f
+
+/* The maximum number of saved registers.  This should include %rip.  */
+#define AMD64_NUM_SAVED_REGS   AMD64_NUM_GREGS
+
+struct amd64_frame_cache
+{
+  /* Base address.  */
+  CORE_ADDR base;
+  CORE_ADDR sp_offset;
+  CORE_ADDR pc;
+
+  /* Saved registers.  */
+  CORE_ADDR saved_regs[AMD64_NUM_SAVED_REGS];
+  CORE_ADDR saved_sp;
+
+  /* Do we have a frame?  */
+  int frameless_p;
+};
+
+/* Allocate and initialize a frame cache.  */
+
+static struct amd64_frame_cache *
+amd64_alloc_frame_cache (void)
+{
+  struct amd64_frame_cache *cache;
+  int i;
+
+  cache = FRAME_OBSTACK_ZALLOC (struct amd64_frame_cache);
+
+  /* Base address.  */
+  cache->base = 0;
+  cache->sp_offset = -8;
+  cache->pc = 0;
+
+  /* Saved registers.  We initialize these to -1 since zero is a valid
+     offset (that's where %rbp is supposed to be stored).  */
+  for (i = 0; i < AMD64_NUM_SAVED_REGS; i++)
+    cache->saved_regs[i] = -1;
+  cache->saved_sp = 0;
+
+  /* Frameless until proven otherwise.  */
+  cache->frameless_p = 1;
+
+  return cache;
+}
+
+/* Do a limited analysis of the prologue at PC and update CACHE
+   accordingly.  Bail out early if CURRENT_PC is reached.  Return the
+   address where the analysis stopped.
+
+   We will handle only functions beginning with:
+
+      pushq %rbp        0x55
+      movq %rsp, %rbp   0x48 0x89 0xe5
+
+   Any function that doesn't start with this sequence will be assumed
+   to have no prologue and thus no valid frame pointer in %rbp.  */
+
+static CORE_ADDR
+amd64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+                       struct amd64_frame_cache *cache)
+{
+  static unsigned char proto[3] = { 0x48, 0x89, 0xe5 };
+  unsigned char buf[3];
+  unsigned char op;
+
+  if (current_pc <= pc)
+    return current_pc;
+
+  op = read_memory_unsigned_integer (pc, 1);
+
+  if (op == 0x55)              /* pushq %rbp */
+    {
+      /* Take into account that we've executed the `pushq %rbp' that
+         starts this instruction sequence.  */
+      cache->saved_regs[AMD64_RBP_REGNUM] = 0;
+      cache->sp_offset += 8;
+
+      /* If that's all, return now.  */
+      if (current_pc <= pc + 1)
+        return current_pc;
+
+      /* Check for `movq %rsp, %rbp'.  */
+      read_memory (pc + 1, buf, 3);
+      if (memcmp (buf, proto, 3) != 0)
+       return pc + 1;
+
+      /* OK, we actually have a frame.  */
+      cache->frameless_p = 0;
+      return pc + 4;
+    }
+
+  return pc;
+}
+
+/* Return PC of first real instruction.  */
+
+static CORE_ADDR
+amd64_skip_prologue (CORE_ADDR start_pc)
+{
+  struct amd64_frame_cache cache;
+  CORE_ADDR pc;
+
+  pc = amd64_analyze_prologue (start_pc, 0xffffffffffffffff, &cache);
+  if (cache.frameless_p)
+    return start_pc;
+
+  return pc;
+}
+\f
+
+/* Normal frames.  */
+
+static struct amd64_frame_cache *
+amd64_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  struct amd64_frame_cache *cache;
+  char buf[8];
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = amd64_alloc_frame_cache ();
+  *this_cache = cache;
+
+  cache->pc = frame_func_unwind (next_frame);
+  if (cache->pc != 0)
+    amd64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+
+  if (cache->frameless_p)
+    {
+      /* We didn't find a valid frame.  If we're at the start of a
+        function, or somewhere half-way its prologue, the function's
+        frame probably hasn't been fully setup yet.  Try to
+        reconstruct the base address for the stack frame by looking
+        at the stack pointer.  For truly "frameless" functions this
+        might work too.  */
+
+      frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset;
+    }
+  else
+    {
+      frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
+      cache->base = extract_unsigned_integer (buf, 8);
+    }
+
+  /* Now that we have the base address for the stack frame we can
+     calculate the value of %rsp in the calling frame.  */
+  cache->saved_sp = cache->base + 16;
+
+  /* For normal frames, %rip is stored at 8(%rbp).  If we don't have a
+     frame we find it at the same offset from the reconstructed base
+     address.  */
+  cache->saved_regs[AMD64_RIP_REGNUM] = 8;
+
+  /* Adjust all the saved registers such that they contain addresses
+     instead of offsets.  */
+  for (i = 0; i < AMD64_NUM_SAVED_REGS; i++)
+    if (cache->saved_regs[i] != -1)
+      cache->saved_regs[i] += cache->base;
+
+  return cache;
+}
+
+static void
+amd64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+                    struct frame_id *this_id)
+{
+  struct amd64_frame_cache *cache =
+    amd64_frame_cache (next_frame, this_cache);
+
+  /* This marks the outermost frame.  */
+  if (cache->base == 0)
+    return;
+
+  (*this_id) = frame_id_build (cache->base + 16, cache->pc);
+}
+
+static void
+amd64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
+                          int regnum, int *optimizedp,
+                          enum lval_type *lvalp, CORE_ADDR *addrp,
+                          int *realnump, void *valuep)
+{
+  struct amd64_frame_cache *cache =
+    amd64_frame_cache (next_frame, this_cache);
+
+  gdb_assert (regnum >= 0);
+
+  if (regnum == SP_REGNUM && cache->saved_sp)
+    {
+      *optimizedp = 0;
+      *lvalp = not_lval;
+      *addrp = 0;
+      *realnump = -1;
+      if (valuep)
+       {
+         /* Store the value.  */
+         store_unsigned_integer (valuep, 8, cache->saved_sp);
+       }
+      return;
+    }
+
+  if (regnum < AMD64_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
+    {
+      *optimizedp = 0;
+      *lvalp = lval_memory;
+      *addrp = cache->saved_regs[regnum];
+      *realnump = -1;
+      if (valuep)
+       {
+         /* Read the value in from memory.  */
+         read_memory (*addrp, valuep,
+                      register_size (current_gdbarch, regnum));
+       }
+      return;
+    }
+
+  frame_register_unwind (next_frame, regnum,
+                        optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind amd64_frame_unwind =
+{
+  NORMAL_FRAME,
+  amd64_frame_this_id,
+  amd64_frame_prev_register
+};
+
+static const struct frame_unwind *
+amd64_frame_sniffer (struct frame_info *next_frame)
+{
+  return &amd64_frame_unwind;
+}
+\f
+
+/* Signal trampolines.  */
+
+/* FIXME: kettenis/20030419: Perhaps, we can unify the 32-bit and
+   64-bit variants.  This would require using identical frame caches
+   on both platforms.  */
+
+static struct amd64_frame_cache *
+amd64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+{
+  struct amd64_frame_cache *cache;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  CORE_ADDR addr;
+  char buf[8];
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = amd64_alloc_frame_cache ();
+
+  frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
+  cache->base = extract_unsigned_integer (buf, 8) - 8;
+
+  addr = tdep->sigcontext_addr (next_frame);
+  gdb_assert (tdep->sc_reg_offset);
+  gdb_assert (tdep->sc_num_regs <= AMD64_NUM_SAVED_REGS);
+  for (i = 0; i < tdep->sc_num_regs; i++)
+    if (tdep->sc_reg_offset[i] != -1)
+      cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+
+  *this_cache = cache;
+  return cache;
+}
+
+static void
+amd64_sigtramp_frame_this_id (struct frame_info *next_frame,
+                             void **this_cache, struct frame_id *this_id)
+{
+  struct amd64_frame_cache *cache =
+    amd64_sigtramp_frame_cache (next_frame, this_cache);
+
+  (*this_id) = frame_id_build (cache->base + 16, frame_pc_unwind (next_frame));
+}
+
+static void
+amd64_sigtramp_frame_prev_register (struct frame_info *next_frame,
+                                   void **this_cache,
+                                   int regnum, int *optimizedp,
+                                   enum lval_type *lvalp, CORE_ADDR *addrp,
+                                   int *realnump, void *valuep)
+{
+  /* Make sure we've initialized the cache.  */
+  amd64_sigtramp_frame_cache (next_frame, this_cache);
+
+  amd64_frame_prev_register (next_frame, this_cache, regnum,
+                            optimizedp, lvalp, addrp, realnump, valuep);
+}
+
+static const struct frame_unwind amd64_sigtramp_frame_unwind =
+{
+  SIGTRAMP_FRAME,
+  amd64_sigtramp_frame_this_id,
+  amd64_sigtramp_frame_prev_register
+};
+
+static const struct frame_unwind *
+amd64_sigtramp_frame_sniffer (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (DEPRECATED_PC_IN_SIGTRAMP (pc, name))
+    {
+      gdb_assert (gdbarch_tdep (current_gdbarch)->sigcontext_addr);
+
+      return &amd64_sigtramp_frame_unwind;
+    }
+
+  return NULL;
+}
+\f
+
+static CORE_ADDR
+amd64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+{
+  struct amd64_frame_cache *cache =
+    amd64_frame_cache (next_frame, this_cache);
+
+  return cache->base;
+}
+
+static const struct frame_base amd64_frame_base =
+{
+  &amd64_frame_unwind,
+  amd64_frame_base_address,
+  amd64_frame_base_address,
+  amd64_frame_base_address
+};
+
+static struct frame_id
+amd64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  char buf[8];
+  CORE_ADDR fp;
+
+  frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
+  fp = extract_unsigned_integer (buf, 8);
+
+  return frame_id_build (fp + 16, frame_pc_unwind (next_frame));
+}
+
+/* 16 byte align the SP per frame requirements.  */
+
+static CORE_ADDR
+amd64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  return sp & -(CORE_ADDR)16;
+}
+\f
+
+/* Supply register REGNUM from the floating-point register set REGSET
+   to register cache REGCACHE.  If REGNUM is -1, do this for all
+   registers in REGSET.  */
+
+static void
+amd64_supply_fpregset (const struct regset *regset, struct regcache *regcache,
+                      int regnum, const void *fpregs, size_t len)
+{
+  const struct gdbarch_tdep *tdep = regset->descr;
+
+  gdb_assert (len == tdep->sizeof_fpregset);
+  amd64_supply_fxsave (regcache, regnum, fpregs);
+}
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+amd64_regset_from_core_section (struct gdbarch *gdbarch,
+                               const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
+    {
+      if (tdep->fpregset == NULL)
+       {
+         tdep->fpregset = XMALLOC (struct regset);
+         tdep->fpregset->descr = tdep;
+         tdep->fpregset->supply_regset = amd64_supply_fpregset;
+       }
+
+      return tdep->fpregset;
+    }
+
+  return i386_regset_from_core_section (gdbarch, sect_name, sect_size);
+}
+\f
+
+void
+amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* AMD64 generally uses `fxsave' instead of `fsave' for saving its
+     floating-point registers.  */
+  tdep->sizeof_fpregset = I387_SIZEOF_FXSAVE;
+
+  /* AMD64 has an FPU and 16 SSE registers.  */
+  tdep->st0_regnum = AMD64_ST0_REGNUM;
+  tdep->num_xmm_regs = 16;
+
+  /* This is what all the fuss is about.  */
+  set_gdbarch_long_bit (gdbarch, 64);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_ptr_bit (gdbarch, 64);
+
+  /* In contrast to the i386, on AMD64 a `long double' actually takes
+     up 128 bits, even though it's still based on the i387 extended
+     floating-point format which has only 80 significant bits.  */
+  set_gdbarch_long_double_bit (gdbarch, 128);
+
+  set_gdbarch_num_regs (gdbarch, AMD64_NUM_REGS);
+  set_gdbarch_register_name (gdbarch, amd64_register_name);
+  set_gdbarch_register_type (gdbarch, amd64_register_type);
+
+  /* Register numbers of various important registers.  */
+  set_gdbarch_sp_regnum (gdbarch, AMD64_RSP_REGNUM); /* %rsp */
+  set_gdbarch_pc_regnum (gdbarch, AMD64_RIP_REGNUM); /* %rip */
+  set_gdbarch_ps_regnum (gdbarch, AMD64_EFLAGS_REGNUM); /* %eflags */
+  set_gdbarch_fp0_regnum (gdbarch, AMD64_ST0_REGNUM); /* %st(0) */
+
+  /* The "default" register numbering scheme for AMD64 is referred to
+     as the "DWARF Register Number Mapping" in the System V psABI.
+     The preferred debugging format for all known AMD64 targets is
+     actually DWARF2, and GCC doesn't seem to support DWARF (that is
+     DWARF-1), but we provide the same mapping just in case.  This
+     mapping is also used for stabs, which GCC does support.  */
+  set_gdbarch_stab_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
+
+  /* We don't override SDB_REG_RO_REGNUM, since COFF doesn't seem to
+     be in use on any of the supported AMD64 targets.  */
+
+  /* Call dummy code.  */
+  set_gdbarch_push_dummy_call (gdbarch, amd64_push_dummy_call);
+  set_gdbarch_frame_align (gdbarch, amd64_frame_align);
+  set_gdbarch_frame_red_zone_size (gdbarch, 128);
+
+  set_gdbarch_convert_register_p (gdbarch, amd64_convert_register_p);
+  set_gdbarch_register_to_value (gdbarch, i387_register_to_value);
+  set_gdbarch_value_to_register (gdbarch, i387_value_to_register);
+
+  set_gdbarch_return_value (gdbarch, amd64_return_value);
+
+  set_gdbarch_skip_prologue (gdbarch, amd64_skip_prologue);
+
+  /* Avoid wiring in the MMX registers for now.  */
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  tdep->mm0_regnum = -1;
+
+  set_gdbarch_unwind_dummy_id (gdbarch, amd64_unwind_dummy_id);
+
+  /* FIXME: kettenis/20021026: This is ELF-specific.  Fine for now,
+     since all supported AMD64 targets are ELF, but that might change
+     in the future.  */
+  set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
+
+  frame_unwind_append_sniffer (gdbarch, amd64_sigtramp_frame_sniffer);
+  frame_unwind_append_sniffer (gdbarch, amd64_frame_sniffer);
+  frame_base_set_default (gdbarch, &amd64_frame_base);
+
+  /* If we have a register mapping, enable the generic core file support.  */
+  if (tdep->gregset_reg_offset)
+    set_gdbarch_regset_from_core_section (gdbarch,
+                                         amd64_regset_from_core_section);
+}
+\f
+
+#define I387_ST0_REGNUM AMD64_ST0_REGNUM
+
+/* The 64-bit FXSAVE format differs from the 32-bit format in the
+   sense that the instruction pointer and data pointer are simply
+   64-bit offsets into the code segment and the data segment instead
+   of a selector offset pair.  The functions below store the upper 32
+   bits of these pointers (instead of just the 16-bits of the segment
+   selector).  */
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+   floating-point or SSE register value from *FXSAVE.  If REGNUM is
+   -1, do this for all registers.  This function masks off any of the
+   reserved bits in *FXSAVE.  */
+
+void
+amd64_supply_fxsave (struct regcache *regcache, int regnum,
+                     const void *fxsave)
+{
+  i387_supply_fxsave (regcache, regnum, fxsave);
+
+  if (fxsave)
+    {
+      const char *regs = fxsave;
+
+      if (regnum == -1 || regnum == I387_FISEG_REGNUM)
+       regcache_raw_supply (regcache, I387_FISEG_REGNUM, regs + 12);
+      if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
+       regcache_raw_supply (regcache, I387_FOSEG_REGNUM, regs + 20);
+    }
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FXSAVE with the value from REGCACHE.  If REGNUM is -1, do this for
+   all registers.  This function doesn't touch any of the reserved
+   bits in *FXSAVE.  */
+
+void
+amd64_collect_fxsave (const struct regcache *regcache, int regnum,
+                     void *fxsave)
+{
+  char *regs = fxsave;
+
+  i387_collect_fxsave (regcache, regnum, fxsave);
+
+  if (regnum == -1 || regnum == I387_FISEG_REGNUM)
+    regcache_raw_collect (regcache, I387_FISEG_REGNUM, regs + 12);
+  if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
+    regcache_raw_collect (regcache, I387_FOSEG_REGNUM, regs + 20);
+}
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
new file mode 100644 (file)
index 0000000..bfc549b
--- /dev/null
@@ -0,0 +1,86 @@
+/* Target-dependent definitions for AMD64.
+
+   Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Jiri Smid, SuSE Labs.
+
+   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 AMD64_TDEP_H
+#define AMD64_TDEP_H
+
+struct gdbarch;
+struct frame_info;
+struct regcache;
+
+#include "i386-tdep.h"
+
+/* Register numbers of various important registers.  */
+
+enum amd64_regnum
+{
+  AMD64_RAX_REGNUM,            /* %rax */
+  AMD64_RBX_REGNUM,            /* %rbx */
+  AMD64_RCX_REGNUM,            /* %rcx */
+  AMD64_RDX_REGNUM,            /* %rdx */
+  AMD64_RSI_REGNUM,            /* %rsi */
+  AMD64_RDI_REGNUM,            /* %rdi */
+  AMD64_RBP_REGNUM,            /* %rbp */
+  AMD64_RSP_REGNUM,            /* %rsp */
+  AMD64_R8_REGNUM = 8,         /* %r8 */
+  AMD64_R15_REGNUM = 15,       /* %r15 */
+  AMD64_RIP_REGNUM,            /* %rip */
+  AMD64_EFLAGS_REGNUM,         /* %eflags */
+  AMD64_ST0_REGNUM = 24,       /* %st0 */
+  AMD64_XMM0_REGNUM = 40,      /* %xmm0 */
+  AMD64_XMM1_REGNUM            /* %xmm1 */
+};
+
+/* Number of general purpose registers.  */
+#define AMD64_NUM_GREGS                24
+
+extern void amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
+
+/* Fill register REGNUM in REGCACHE with the appropriate
+   floating-point or SSE register value from *FXSAVE.  If REGNUM is
+   -1, do this for all registers.  This function masks off any of the
+   reserved bits in *FXSAVE.  */
+
+extern void amd64_supply_fxsave (struct regcache *regcache, int regnum,
+                                const void *fxsave);
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FXSAVE with the value from REGCACHE.  If REGNUM is -1, do this for
+   all registers.  This function doesn't touch any of the reserved
+   bits in *FXSAVE.  */
+
+extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum,
+                                 void *fxsave);
+\f
+
+/* Variables exported from amd64nbsd-tdep.c.  */
+extern int amd64nbsd_r_reg_offset[];
+
+/* Variables exported from amd64obsd-tdep.c.  */
+extern int amd64obsd_r_reg_offset[];
+
+/* Variables exported from amd64fbsd-tdep.c.  */
+extern CORE_ADDR amd64fbsd_sigtramp_start_addr;
+extern CORE_ADDR amd64fbsd_sigtramp_end_addr;
+extern int amd64fbsd_sc_reg_offset[];
+
+#endif /* amd64-tdep.h */
diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh
new file mode 100644 (file)
index 0000000..c02e864
--- /dev/null
@@ -0,0 +1,10 @@
+# Host: GNU/Linux x86-64
+NATDEPFILES= infptrace.o inftarg.o fork-child.o \
+       i386-nat.o amd64-nat.o amd64-linux-nat.o linux-nat.o \
+       proc-service.o thread-db.o lin-lwp.o linux-proc.o gcore.o 
+NAT_FILE= nm-linux64.h
+XM_FILE= xm-i386.h
+
+# The dynamically loaded libthread_db needs access to symbols in the
+# gdb executable.
+LOADLIBES = -ldl -rdynamic
diff --git a/gdb/config/i386/linux64.mt b/gdb/config/i386/linux64.mt
new file mode 100644 (file)
index 0000000..f642e31
--- /dev/null
@@ -0,0 +1,5 @@
+# Target: GNU/Linux x86-64
+TDEPFILES= amd64-tdep.o amd64-linux-tdep.o \
+       i386-tdep.o i387-tdep.o i386-linux-tdep.o glibc-tdep.o \
+       solib.o solib-svr4.o solib-legacy.o corelow.o
+TM_FILE=tm-linux64.h
diff --git a/gdb/config/i386/nm-linux64.h b/gdb/config/i386/nm-linux64.h
new file mode 100644 (file)
index 0000000..1764758
--- /dev/null
@@ -0,0 +1,69 @@
+/* Native support for GNU/Linux x86-64.
+
+   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+   Contributed by Jiri Smid, SuSE Labs.
+
+   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_LINUX64_H
+#define NM_LINUX64_H
+
+/* GNU/Linux supports the i386 hardware debugging registers.  */
+#define I386_USE_GENERIC_WATCHPOINTS
+
+#include "i386/nm-i386.h"
+#include "config/nm-linux.h"
+
+/* Support for 8-byte wide hardware watchpoints.  */
+#define TARGET_HAS_DR_LEN_8 1
+
+/* Provide access to the i386 hardware debugging registers.  */
+
+extern void amd64_linux_dr_set_control (unsigned long control);
+#define I386_DR_LOW_SET_CONTROL(control) \
+  amd64_linux_dr_set_control (control)
+
+extern void amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr);
+#define I386_DR_LOW_SET_ADDR(regnum, addr) \
+  amd64_linux_dr_set_addr (regnum, addr)
+
+extern void amd64_linux_dr_reset_addr (int regnum);
+#define I386_DR_LOW_RESET_ADDR(regnum) \
+  amd64_linux_dr_reset_addr (regnum)
+
+extern unsigned long amd64_linux_dr_get_status (void);
+#define I386_DR_LOW_GET_STATUS() \
+  amd64_linux_dr_get_status ()
+\f
+
+/* Type of the third argument to the `ptrace' system call.  */
+#define PTRACE_ARG3_TYPE long
+
+/* Type of the fourth argument to the `ptrace' system call.  */
+#define PTRACE_XFER_TYPE long
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
+#define FETCH_INFERIOR_REGISTERS
+
+/* `linux-nat.c' and `i386-nat.c' have their own versions of
+   child_post_startup_inferior.  Define this to use the copy in
+   `x86-86-linux-nat.c' instead, which calls both.  */
+#define LINUX_CHILD_POST_STARTUP_INFERIOR
+
+#endif /* nm-linux64.h */
diff --git a/gdb/config/i386/obsdaout.mh b/gdb/config/i386/obsdaout.mh
new file mode 100644 (file)
index 0000000..3577178
--- /dev/null
@@ -0,0 +1,5 @@
+# Host: OpenBSD/i386 a.out
+NATDEPFILES= fork-child.o infptrace.o inftarg.o i386bsd-nat.o i386obsd-nat.o \
+       solib.o solib-sunos.o
+NAT_FILE= nm-obsd.h
+XM_FILE= xm-i386.h
diff --git a/gdb/config/i386/tm-linux64.h b/gdb/config/i386/tm-linux64.h
new file mode 100644 (file)
index 0000000..c3ff352
--- /dev/null
@@ -0,0 +1,36 @@
+/* Target-dependent definitions for GNU/Linux x86-64.
+
+   Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
+
+   Contributed by Michal Ludvig, SuSE Labs.
+
+   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_LINUX64_H
+#define TM_LINUX64_H
+
+/* We define SVR4_SHARED_LIBS unconditionally, on the assumption that
+   link.h is available on all linux platforms.  For I386 and SH3/4, we
+   hard-code the information rather than use link.h anyway (for the
+   benefit of cross-debugging).  We may move to doing that for other
+   architectures as well.  */
+
+#define SVR4_SHARED_LIBS
+#include "solib.h"              /* Support for shared libraries. */
+
+#endif /* tm-linux64.h */
diff --git a/gdb/config/nm-bsd.h b/gdb/config/nm-bsd.h
new file mode 100644 (file)
index 0000000..b44dd5e
--- /dev/null
@@ -0,0 +1,29 @@
+/* Native-dependent definitions for *BSD.
+
+   Copyright 2001, 2004 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.  */
+
+/* Type of the third argument to the `ptrace' system call.  */
+#define PTRACE_ARG3_TYPE caddr_t
+
+/* Override copies of {fetch,store}_inferior_registers in `infptrace.c'.  */
+#define FETCH_INFERIOR_REGISTERS
+
+/* We can attach and detach.  */
+#define ATTACH_DETACH
diff --git a/gdb/frv-linux-tdep.c b/gdb/frv-linux-tdep.c
new file mode 100644 (file)
index 0000000..e862625
--- /dev/null
@@ -0,0 +1,273 @@
+/* Target-dependent code for GNU/Linux running on the Fujitsu FR-V,
+   for GDB.
+   Copyright 2004 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 "target.h"
+#include "frame.h"
+#include "osabi.h"
+#include "elf-bfd.h"
+#include "elf/frv.h"
+#include "frv-tdep.h"
+
+/* Define the size (in bytes) of an FR-V instruction.  */
+static const int frv_instr_size = 4;
+
+enum {
+  NORMAL_SIGTRAMP = 1,
+  RT_SIGTRAMP = 2
+};
+
+static int
+frv_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  char buf[frv_instr_size];
+  LONGEST instr;
+  int retval = 0;
+
+  if (target_read_memory (pc, buf, sizeof buf) != 0)
+    return 0;
+
+  instr = extract_unsigned_integer (buf, sizeof buf);
+
+  if (instr == 0x8efc0077)     /* setlos #__NR_sigreturn, gr7 */
+    retval = NORMAL_SIGTRAMP;
+  else if (instr -= 0x8efc00ad)        /* setlos #__NR_rt_sigreturn, gr7 */
+    retval = RT_SIGTRAMP;
+  else
+    return 0;
+
+  if (target_read_memory (pc + frv_instr_size, buf, sizeof buf) != 0)
+    return 0;
+  instr = extract_unsigned_integer (buf, sizeof buf);
+  if (instr != 0xc0700000)     /* tira gr0, 0 */
+    return 0;
+
+  /* If we get this far, we'll return a non-zero value, either
+     NORMAL_SIGTRAMP (1) or RT_SIGTRAMP (2).  */
+  return retval;
+}
+
+/* Given NEXT_FRAME, "callee" frame of the sigtramp frame that we
+   wish to decode, and REGNO, one of the frv register numbers defined
+   in frv-tdep.h, return the address of the saved register (corresponding
+   to REGNO) in the sigtramp frame.  Return -1 if the register is not
+   found in the sigtramp frame.  The magic numbers in the code below
+   were computed by examining the following kernel structs:
+
+   From arch/frvnommu/signal.c:
+
+      struct sigframe
+      {
+             void (*pretcode)(void);
+             int sig;
+             struct sigcontext sc;
+             unsigned long extramask[_NSIG_WORDS-1];
+             uint32_t retcode[2];
+      };
+
+      struct rt_sigframe
+      {
+             void (*pretcode)(void);
+             int sig;
+             struct siginfo *pinfo;
+             void *puc;
+             struct siginfo info;
+             struct ucontext uc;
+             uint32_t retcode[2];
+      };
+
+   From include/asm-frvnommu/ucontext.h:
+
+      struct ucontext {
+             unsigned long             uc_flags;
+             struct ucontext           *uc_link;
+             stack_t                   uc_stack;
+             struct sigcontext uc_mcontext;
+             sigset_t          uc_sigmask;
+      };
+
+   From include/asm-frvnommu/sigcontext.h:
+
+      struct sigcontext {
+             struct user_context       sc_context;
+             unsigned long             sc_oldmask;
+      } __attribute__((aligned(8)));
+
+   From include/asm-frvnommu/registers.h:
+      struct user_int_regs
+      {
+             unsigned long             psr;
+             unsigned long             isr;
+             unsigned long             ccr;
+             unsigned long             cccr;
+             unsigned long             lr;
+             unsigned long             lcr;
+             unsigned long             pc;
+             unsigned long             __status;
+             unsigned long             syscallno;
+             unsigned long             orig_gr8;
+             unsigned long             gner[2];
+             unsigned long long        iacc[1];
+
+             union {
+                     unsigned long     tbr;
+                     unsigned long     gr[64];
+             };
+      };
+
+      struct user_fpmedia_regs
+      {
+             unsigned long     fr[64];
+             unsigned long     fner[2];
+             unsigned long     msr[2];
+             unsigned long     acc[8];
+             unsigned char     accg[8];
+             unsigned long     fsr[1];
+      };
+
+      struct user_context
+      {
+             struct user_int_regs              i;
+             struct user_fpmedia_regs  f;
+
+             void *extension;
+      } __attribute__((aligned(8)));  */
+
+static CORE_ADDR
+frv_linux_sigcontext_reg_addr (struct frame_info *next_frame, int regno,
+                               CORE_ADDR *sc_addr_cache_ptr)
+{
+  CORE_ADDR sc_addr;
+
+  if (sc_addr_cache_ptr && *sc_addr_cache_ptr)
+    {
+      sc_addr = *sc_addr_cache_ptr;
+    }
+  else
+    {
+      CORE_ADDR pc, sp;
+      char buf[4];
+      int tramp_type;
+
+      pc = frame_pc_unwind (next_frame);
+      tramp_type = frv_linux_pc_in_sigtramp (pc, 0);
+
+      frame_unwind_register (next_frame, sp_regnum, buf);
+      sp = extract_unsigned_integer (buf, sizeof buf);
+
+      if (tramp_type == NORMAL_SIGTRAMP)
+       {
+         /* For a normal sigtramp frame, the sigcontext struct starts
+            at SP + 8.  */
+         sc_addr = sp + 8;
+       }
+      else if (tramp_type == RT_SIGTRAMP)
+       {
+         /* For a realtime sigtramp frame, SP + 12 contains a pointer
+            to the a ucontext struct.  The ucontext struct contains
+            a sigcontext struct starting 12 bytes in.  */
+         if (target_read_memory (sp + 12, buf, sizeof buf) != 0)
+           {
+             warning ("Can't read realtime sigtramp frame.");
+             return 0;
+           }
+         sc_addr = extract_unsigned_integer (buf, sizeof buf);
+         sc_addr += 12;
+       }
+      else
+       internal_error (__FILE__, __LINE__, "not a signal trampoline");
+
+      if (sc_addr_cache_ptr)
+       *sc_addr_cache_ptr = sc_addr;
+    }
+
+  switch (regno)
+    {
+    case psr_regnum :
+      return sc_addr + 0;
+    /* sc_addr + 4 has "isr", the Integer Status Register.  */
+    case ccr_regnum :
+      return sc_addr + 8;
+    case cccr_regnum :
+      return sc_addr + 12;
+    case lr_regnum :
+      return sc_addr + 16;
+    case lcr_regnum :
+      return sc_addr + 20;
+    case pc_regnum :
+      return sc_addr + 24;
+    /* sc_addr + 28 is __status, the exception status.
+       sc_addr + 32 is syscallno, the syscall number or -1.
+       sc_addr + 36 is orig_gr8, the original syscall arg #1.
+       sc_addr + 40 is gner[0].
+       sc_addr + 44 is gner[1]. */
+    case iacc0h_regnum :
+      return sc_addr + 48;
+    case iacc0l_regnum :
+      return sc_addr + 52;
+    default : 
+      if (first_gpr_regnum <= regno && regno <= last_gpr_regnum)
+       return sc_addr + 56 + 4 * (regno - first_gpr_regnum);
+      else if (first_fpr_regnum <= regno && regno <= last_fpr_regnum)
+       return sc_addr + 312 + 4 * (regno - first_fpr_regnum);
+      else
+       return -1;  /* not saved. */
+    }
+}
+
+static void
+frv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  /* When the FR-V Linux kernel calls a signal handler, the return
+     address points to a bit of code on the stack.  This function is
+     used to identify this bit of code as a signal trampoline in order
+     to support backtracing through calls to signal handlers.  */
+  set_gdbarch_deprecated_pc_in_sigtramp (gdbarch, frv_linux_pc_in_sigtramp);
+  frv_set_sigcontext_reg_addr (gdbarch, frv_linux_sigcontext_reg_addr);
+}
+
+static enum gdb_osabi
+frv_linux_elf_osabi_sniffer (bfd *abfd)
+{
+  int elf_flags;
+
+  elf_flags = elf_elfheader (abfd)->e_flags;
+
+  /* Assume GNU/Linux if using the FDPIC ABI.  If/when another OS shows
+     up that uses this ABI, we'll need to start using .note sections
+     or some such.  */
+  if (elf_flags & EF_FRV_FDPIC)
+    return GDB_OSABI_LINUX;
+  else
+    return GDB_OSABI_UNKNOWN;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_frv_linux_tdep (void);
+
+void
+_initialize_frv_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_frv, 0, GDB_OSABI_LINUX, frv_linux_init_abi);
+  gdbarch_register_osabi_sniffer (bfd_arch_frv,
+                                 bfd_target_elf_flavour,
+                                 frv_linux_elf_osabi_sniffer);
+}
diff --git a/gdb/frv-tdep.h b/gdb/frv-tdep.h
new file mode 100644 (file)
index 0000000..5b9b88b
--- /dev/null
@@ -0,0 +1,105 @@
+/* Architecture-dependent code for the Fujitsu FR-V, for GDB, the GNU Debugger.
+   Copyright 2004 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.  */
+
+/* Enumerate the possible ABIs for FR-V.  */
+enum frv_abi
+  {
+    FRV_ABI_EABI,
+    FRV_ABI_FDPIC
+  };
+
+/* Register numbers.  The order in which these appear define the
+   remote protocol, so take care in changing them.  */
+enum {
+  /* Register numbers 0 -- 63 are always reserved for general-purpose
+     registers.  The chip at hand may have less.  */
+  first_gpr_regnum = 0,
+  sp_regnum = 1,
+  fp_regnum = 2,
+  struct_return_regnum = 3,
+  last_gpr_regnum = 63,
+
+  /* Register numbers 64 -- 127 are always reserved for floating-point
+     registers.  The chip at hand may have less.  */
+  first_fpr_regnum = 64,
+  last_fpr_regnum = 127,
+
+  /* The PC register.  */
+  pc_regnum = 128,
+
+  /* Register numbers 129 on up are always reserved for special-purpose
+     registers.  */
+  first_spr_regnum = 129,
+  psr_regnum = 129,
+  ccr_regnum = 130,
+  cccr_regnum = 131,
+  fdpic_loadmap_exec_regnum = 132,
+  fdpic_loadmap_interp_regnum = 133,
+  tbr_regnum = 135,
+  brr_regnum = 136,
+  dbar0_regnum = 137,
+  dbar1_regnum = 138,
+  dbar2_regnum = 139,
+  dbar3_regnum = 140,
+  scr0_regnum = 141,
+  scr1_regnum = 142,
+  scr2_regnum = 143,
+  scr3_regnum = 144,
+  lr_regnum = 145,
+  lcr_regnum = 146,
+  iacc0h_regnum = 147,
+  iacc0l_regnum = 148,
+  last_spr_regnum = 148,
+
+  /* The total number of registers we know exist.  */
+  frv_num_regs = last_spr_regnum + 1,
+
+  /* Pseudo registers */
+  first_pseudo_regnum = frv_num_regs,
+
+  /* iacc0 - the 64-bit concatenation of iacc0h and iacc0l.  */
+  iacc0_regnum = first_pseudo_regnum + 0,
+
+  last_pseudo_regnum = iacc0_regnum,
+  frv_num_pseudo_regs = last_pseudo_regnum - first_pseudo_regnum + 1,
+};
+
+/* Return the FR-V ABI associated with GDBARCH.  */
+enum frv_abi frv_abi (struct gdbarch *gdbarch);
+
+/* Associate a sigcontext address fetcher with GDBARCH.  */
+void frv_set_sigcontext_reg_addr (struct gdbarch *gdbarch,
+                                  CORE_ADDR (*sigcontext_reg_addr)
+                                   (struct frame_info *, int, CORE_ADDR *));
+
+/* Fetch the interpreter and executable loadmap addresses (for shared
+   library support) for the FDPIC ABI.  Return 0 if successful, -1 if
+   not.  (E.g, -1 will be returned if the ABI isn't the FDPIC ABI.)  */
+int frv_fdpic_loadmap_addresses (struct gdbarch *gdbarch,
+                                 CORE_ADDR *interp_addr, CORE_ADDR *exec_addr);
+
+/* Given a function entry point, find and return the GOT address for the
+   containing load module.  */
+CORE_ADDR frv_fdpic_find_global_pointer (CORE_ADDR addr);
+
+/* Given a function entry point, find and return the canonical descriptor
+   for that function, if one exists.  If no canonical descriptor could
+   be found, return 0.  */
+CORE_ADDR frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point);
diff --git a/gdb/solib-frv.c b/gdb/solib-frv.c
new file mode 100644 (file)
index 0000000..5995b80
--- /dev/null
@@ -0,0 +1,1230 @@
+/* Handle FR-V (FDPIC) shared libraries for GDB, the GNU Debugger.
+   Copyright 2004
+   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 "gdb_string.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "solist.h"
+#include "frv-tdep.h"
+#include "objfiles.h"
+#include "symtab.h"
+#include "language.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "elf/frv.h"
+
+/* Flag which indicates whether internal debug messages should be printed.  */
+static int solib_frv_debug;
+
+/* FR-V pointers are four bytes wide.  */
+enum { FRV_PTR_SIZE = 4 };
+
+/* Representation of loadmap and related structs for the FR-V FDPIC ABI.  */
+
+/* External versions; the size and alignment of the fields should be
+   the same as those on the target.  When loaded, the placement of
+   the bits in each field will be the same as on the target.  */
+typedef unsigned char ext_Elf32_Half[2];
+typedef unsigned char ext_Elf32_Addr[4];
+typedef unsigned char ext_Elf32_Word[4];
+
+struct ext_elf32_fdpic_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  ext_Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  ext_Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  ext_Elf32_Word p_memsz;
+};
+
+struct ext_elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  ext_Elf32_Half version;
+  /* Number of segments in this map.  */
+  ext_Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct ext_elf32_fdpic_loadseg segs[1 /* nsegs, actually */];
+};
+
+/* Internal versions; the types are GDB types and the data in each
+   of the fields is (or will be) decoded from the external struct
+   for ease of consumption.  */
+struct int_elf32_fdpic_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  CORE_ADDR addr;
+  /* VMA recorded in the program header.  */
+  CORE_ADDR p_vaddr;
+  /* Size of this segment in memory.  */
+  long p_memsz;
+};
+
+struct int_elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  int version;
+  /* Number of segments in this map.  */
+  int nsegs;
+  /* The actual memory map.  */
+  struct int_elf32_fdpic_loadseg segs[1 /* nsegs, actually */];
+};
+
+/* Given address LDMADDR, fetch and decode the loadmap at that address.
+   Return NULL if there is a problem reading the target memory or if
+   there doesn't appear to be a loadmap at the given address.  The
+   allocated space (representing the loadmap) returned by this
+   function may be freed via a single call to xfree().  */
+
+static struct int_elf32_fdpic_loadmap *
+fetch_loadmap (CORE_ADDR ldmaddr)
+{
+  struct ext_elf32_fdpic_loadmap ext_ldmbuf_partial;
+  struct ext_elf32_fdpic_loadmap *ext_ldmbuf;
+  struct int_elf32_fdpic_loadmap *int_ldmbuf;
+  int ext_ldmbuf_size, int_ldmbuf_size;
+  int version, seg, nsegs;
+
+  /* Fetch initial portion of the loadmap.  */
+  if (target_read_memory (ldmaddr, (char *) &ext_ldmbuf_partial,
+                          sizeof ext_ldmbuf_partial))
+    {
+      /* Problem reading the target's memory.  */
+      return NULL;
+    }
+
+  /* Extract the version.  */
+  version = extract_unsigned_integer (&ext_ldmbuf_partial.version,
+                                      sizeof ext_ldmbuf_partial.version);
+  if (version != 0)
+    {
+      /* We only handle version 0.  */
+      return NULL;
+    }
+
+  /* Extract the number of segments.  */
+  nsegs = extract_unsigned_integer (&ext_ldmbuf_partial.nsegs,
+                                    sizeof ext_ldmbuf_partial.nsegs);
+
+  /* Allocate space for the complete (external) loadmap.  */
+  ext_ldmbuf_size = sizeof (struct ext_elf32_fdpic_loadmap)
+               + (nsegs - 1) * sizeof (struct ext_elf32_fdpic_loadseg);
+  ext_ldmbuf = xmalloc (ext_ldmbuf_size);
+
+  /* Copy over the portion of the loadmap that's already been read.  */
+  memcpy (ext_ldmbuf, &ext_ldmbuf_partial, sizeof ext_ldmbuf_partial);
+
+  /* Read the rest of the loadmap from the target.  */
+  if (target_read_memory (ldmaddr + sizeof ext_ldmbuf_partial,
+                          (char *) ext_ldmbuf + sizeof ext_ldmbuf_partial,
+                          ext_ldmbuf_size - sizeof ext_ldmbuf_partial))
+    {
+      /* Couldn't read rest of the loadmap.  */
+      xfree (ext_ldmbuf);
+      return NULL;
+    }
+
+  /* Allocate space into which to put information extract from the
+     external loadsegs.  I.e, allocate the internal loadsegs.  */
+  int_ldmbuf_size = sizeof (struct int_elf32_fdpic_loadmap)
+               + (nsegs - 1) * sizeof (struct int_elf32_fdpic_loadseg);
+  int_ldmbuf = xmalloc (int_ldmbuf_size);
+
+  /* Place extracted information in internal structs.  */
+  int_ldmbuf->version = version;
+  int_ldmbuf->nsegs = nsegs;
+  for (seg = 0; seg < nsegs; seg++)
+    {
+      int_ldmbuf->segs[seg].addr
+       = extract_unsigned_integer (&ext_ldmbuf->segs[seg].addr,
+                                   sizeof (ext_ldmbuf->segs[seg].addr));
+      int_ldmbuf->segs[seg].p_vaddr
+       = extract_unsigned_integer (&ext_ldmbuf->segs[seg].p_vaddr,
+                                   sizeof (ext_ldmbuf->segs[seg].p_vaddr));
+      int_ldmbuf->segs[seg].p_memsz
+       = extract_unsigned_integer (&ext_ldmbuf->segs[seg].p_memsz,
+                                   sizeof (ext_ldmbuf->segs[seg].p_memsz));
+    }
+
+  free (ext_ldmbuf);
+  return int_ldmbuf;
+}
+
+/* External link_map and elf32_fdpic_loadaddr struct definitions.  */
+
+typedef unsigned char ext_ptr[4];
+
+struct ext_elf32_fdpic_loadaddr
+{
+  ext_ptr map;                 /* struct elf32_fdpic_loadmap *map; */
+  ext_ptr got_value;           /* void *got_value; */
+};
+
+struct ext_link_map
+{
+  struct ext_elf32_fdpic_loadaddr l_addr;
+
+  /* Absolute file name object was found in.  */
+  ext_ptr l_name;              /* char *l_name; */
+
+  /* Dynamic section of the shared object.  */
+  ext_ptr l_ld;                        /* ElfW(Dyn) *l_ld; */
+
+  /* Chain of loaded objects.  */
+  ext_ptr l_next, l_prev;      /* struct link_map *l_next, *l_prev; */
+};
+
+/* Link map info to include in an allocated so_list entry */
+
+struct lm_info
+  {
+    /* The loadmap, digested into an easier to use form.  */
+    struct int_elf32_fdpic_loadmap *map;
+    /* The GOT address for this link map entry.  */
+    CORE_ADDR got_value;
+
+    /* Cached dynamic symbol table and dynamic relocs initialized and
+       used only by find_canonical_descriptor_in_load_object().
+
+       Note: kevinb/2004-02-26: It appears that calls to
+       bfd_canonicalize_dynamic_reloc() will use the same symbols as
+       those supplied to the first call to this function.  Therefore,
+       it's important to NOT free the asymbol ** data structure
+       supplied to the first call.  Thus the caching of the dynamic
+       symbols (dyn_syms) is critical for correct operation.  The
+       caching of the dynamic relocations could be dispensed with.  */
+    asymbol **dyn_syms;
+    arelent **dyn_relocs;
+    int dyn_reloc_count;       /* number of dynamic relocs.  */
+
+  };
+
+/* The load map, got value, etc. are not available from the chain
+   of loaded shared objects.  ``main_executable_lm_info'' provides
+   a way to get at this information so that it doesn't need to be
+   frequently recomputed.  Initialized by frv_relocate_main_executable().  */
+static struct lm_info *main_executable_lm_info;
+
+static void frv_relocate_main_executable (void);
+static CORE_ADDR main_got (void);
+static int enable_break2 (void);
+
+/*
+
+   LOCAL FUNCTION
+
+   bfd_lookup_symbol -- lookup the value for a specific symbol
+
+   SYNOPSIS
+
+   CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname)
+
+   DESCRIPTION
+
+   An expensive way to lookup the value of a single symbol for
+   bfd's that are only temporary anyway.  This is used by the
+   shared library support to find the address of the debugger
+   interface structures in the shared library.
+
+   Note that 0 is specifically allowed as an error return (no
+   such symbol).
+ */
+
+static CORE_ADDR
+bfd_lookup_symbol (bfd *abfd, char *symname)
+{
+  long storage_needed;
+  asymbol *sym;
+  asymbol **symbol_table;
+  unsigned int number_of_symbols;
+  unsigned int i;
+  struct cleanup *back_to;
+  CORE_ADDR symaddr = 0;
+
+  storage_needed = bfd_get_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      back_to = make_cleanup (xfree, symbol_table);
+      number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
+
+      for (i = 0; i < number_of_symbols; i++)
+       {
+         sym = *symbol_table++;
+         if (strcmp (sym->name, symname) == 0)
+           {
+             /* Bfd symbols are section relative. */
+             symaddr = sym->value + sym->section->vma;
+             break;
+           }
+       }
+      do_cleanups (back_to);
+    }
+
+  if (symaddr)
+    return symaddr;
+
+  /* Look for the symbol in the dynamic string table too.  */
+
+  storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+  if (storage_needed > 0)
+    {
+      symbol_table = (asymbol **) xmalloc (storage_needed);
+      back_to = make_cleanup (xfree, symbol_table);
+      number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
+
+      for (i = 0; i < number_of_symbols; i++)
+       {
+         sym = *symbol_table++;
+         if (strcmp (sym->name, symname) == 0)
+           {
+             /* Bfd symbols are section relative. */
+             symaddr = sym->value + sym->section->vma;
+             break;
+           }
+       }
+      do_cleanups (back_to);
+    }
+
+  return symaddr;
+}
+
+
+/*
+
+  LOCAL FUNCTION
+
+  open_symbol_file_object
+
+  SYNOPSIS
+
+  void open_symbol_file_object (void *from_tty)
+
+  DESCRIPTION
+
+  If no open symbol file, attempt to locate and open the main symbol
+  file.
+
+  If FROM_TTYP dereferences to a non-zero integer, allow messages to
+  be printed.  This parameter is a pointer rather than an int because
+  open_symbol_file_object() is called via catch_errors() and
+  catch_errors() requires a pointer argument. */
+
+static int
+open_symbol_file_object (void *from_ttyp)
+{
+  /* Unimplemented.  */
+  return 0;
+}
+
+/* Cached value for lm_base(), below.  */
+static CORE_ADDR lm_base_cache = 0;
+
+/* Return the address from which the link map chain may be found.  On
+   the FR-V, this may be found in a number of ways.  Assuming that the
+   main executable has already been relocated, the easiest way to find
+   this value is to look up the address of _GLOBAL_OFFSET_TABLE_.  A
+   pointer to the start of the link map will be located at the word found
+   at _GLOBAL_OFFSET_TABLE_ + 8.  (This is part of the dynamic linker
+   reserve area mandated by the ABI.)  */
+
+static CORE_ADDR
+lm_base (void)
+{
+  struct minimal_symbol *got_sym;
+  CORE_ADDR addr;
+  char buf[FRV_PTR_SIZE];
+
+  /* If we already have a cached value, return it.  */
+  if (lm_base_cache)
+    return lm_base_cache;
+
+  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_", NULL,
+                                   symfile_objfile);
+  if (got_sym == 0)
+    {
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "lm_base: _GLOBAL_OFFSET_TABLE_ not found.\n");
+      return 0;
+    }
+
+  addr = SYMBOL_VALUE_ADDRESS (got_sym) + 8;
+
+  if (solib_frv_debug)
+    fprintf_unfiltered (gdb_stdlog,
+                       "lm_base: _GLOBAL_OFFSET_TABLE_ + 8 = %s\n",
+                       local_hex_string_custom (addr, "08l"));
+
+  if (target_read_memory (addr, buf, sizeof buf) != 0)
+    return 0;
+  lm_base_cache = extract_unsigned_integer (buf, sizeof buf);
+
+  if (solib_frv_debug)
+    fprintf_unfiltered (gdb_stdlog,
+                       "lm_base: lm_base_cache = %s\n",
+                       local_hex_string_custom (lm_base_cache, "08l"));
+
+  return lm_base_cache;
+}
+
+
+/* LOCAL FUNCTION
+
+   frv_current_sos -- build a list of currently loaded shared objects
+
+   SYNOPSIS
+
+   struct so_list *frv_current_sos ()
+
+   DESCRIPTION
+
+   Build a list of `struct so_list' objects describing the shared
+   objects currently loaded in the inferior.  This list does not
+   include an entry for the main executable file.
+
+   Note that we only gather information directly available from the
+   inferior --- we don't examine any of the shared library files
+   themselves.  The declaration of `struct so_list' says which fields
+   we provide values for.  */
+
+static struct so_list *
+frv_current_sos (void)
+{
+  CORE_ADDR lm_addr, mgot;
+  struct so_list *sos_head = NULL;
+  struct so_list **sos_next_ptr = &sos_head;
+
+  mgot = main_got ();
+
+  /* Locate the address of the first link map struct.  */
+  lm_addr = lm_base ();
+
+  /* We have at least one link map entry.  Fetch the the lot of them,
+     building the solist chain.  */
+  while (lm_addr)
+    {
+      struct ext_link_map lm_buf;
+      CORE_ADDR got_addr;
+
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "current_sos: reading link_map entry at %s\n",
+                           local_hex_string_custom (lm_addr, "08l"));
+
+      if (target_read_memory (lm_addr, (char *) &lm_buf, sizeof (lm_buf)) != 0)
+       {
+         warning ("frv_current_sos: Unable to read link map entry.  Shared object chain may be incomplete.");
+         break;
+       }
+
+      got_addr
+       = extract_unsigned_integer (&lm_buf.l_addr.got_value,
+                                   sizeof (lm_buf.l_addr.got_value));
+      /* If the got_addr is the same as mgotr, then we're looking at the
+        entry for the main executable.  By convention, we don't include
+        this in the list of shared objects.  */
+      if (got_addr != mgot)
+       {
+         int errcode;
+         char *name_buf;
+         struct int_elf32_fdpic_loadmap *loadmap;
+         struct so_list *sop;
+         CORE_ADDR addr;
+
+         /* Fetch the load map address.  */
+         addr = extract_unsigned_integer (&lm_buf.l_addr.map,
+                                          sizeof lm_buf.l_addr.map);
+         loadmap = fetch_loadmap (addr);
+         if (loadmap == NULL)
+           {
+             warning ("frv_current_sos: Unable to fetch load map.  Shared object chain may be incomplete.");
+             break;
+           }
+
+         sop = xcalloc (1, sizeof (struct so_list));
+         sop->lm_info = xcalloc (1, sizeof (struct lm_info));
+         sop->lm_info->map = loadmap;
+         sop->lm_info->got_value = got_addr;
+         /* Fetch the name.  */
+         addr = extract_unsigned_integer (&lm_buf.l_name,
+                                          sizeof (lm_buf.l_name));
+         target_read_string (addr, &name_buf, SO_NAME_MAX_PATH_SIZE - 1,
+                             &errcode);
+
+         if (solib_frv_debug)
+           fprintf_unfiltered (gdb_stdlog, "current_sos: name = %s\n",
+                               name_buf);
+         
+         if (errcode != 0)
+           {
+             warning ("frv_current_sos: Can't read pathname for link map entry: %s\n",
+                      safe_strerror (errcode));
+           }
+         else
+           {
+             strncpy (sop->so_name, name_buf, SO_NAME_MAX_PATH_SIZE - 1);
+             sop->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
+             xfree (name_buf);
+             strcpy (sop->so_original_name, sop->so_name);
+           }
+
+         *sos_next_ptr = sop;
+         sos_next_ptr = &sop->next;
+       }
+
+      lm_addr = extract_unsigned_integer (&lm_buf.l_next, sizeof (lm_buf.l_next));
+    }
+
+  enable_break2 ();
+
+  return sos_head;
+}
+
+
+/* Return 1 if PC lies in the dynamic symbol resolution code of the
+   run time loader.  */
+
+static CORE_ADDR interp_text_sect_low;
+static CORE_ADDR interp_text_sect_high;
+static CORE_ADDR interp_plt_sect_low;
+static CORE_ADDR interp_plt_sect_high;
+
+static int
+frv_in_dynsym_resolve_code (CORE_ADDR pc)
+{
+  return ((pc >= interp_text_sect_low && pc < interp_text_sect_high)
+         || (pc >= interp_plt_sect_low && pc < interp_plt_sect_high)
+         || in_plt_section (pc, NULL));
+}
+
+/* Given a loadmap and an address, return the displacement needed
+   to relocate the address.  */
+
+CORE_ADDR
+displacement_from_map (struct int_elf32_fdpic_loadmap *map,
+                       CORE_ADDR addr)
+{
+  int seg;
+
+  for (seg = 0; seg < map->nsegs; seg++)
+    {
+      if (map->segs[seg].p_vaddr <= addr
+          && addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
+       {
+         return map->segs[seg].addr - map->segs[seg].p_vaddr;
+       }
+    }
+
+  return 0;
+}
+
+/* Print a warning about being unable to set the dynamic linker
+   breakpoint.  */
+
+static void
+enable_break_failure_warning (void)
+{
+  warning ("Unable to find dynamic linker breakpoint function.\n"
+           "GDB will be unable to debug shared library initializers\n"
+          "and track explicitly loaded dynamic code.");
+}
+
+/*
+
+   LOCAL FUNCTION
+
+   enable_break -- arrange for dynamic linker to hit breakpoint
+
+   SYNOPSIS
+
+   int enable_break (void)
+
+   DESCRIPTION
+
+   The dynamic linkers has, as part of its debugger interface, support
+   for arranging for the inferior to hit a breakpoint after mapping in
+   the shared libraries.  This function enables that breakpoint.
+
+   On the FR-V, using the shared library (FDPIC) ABI, the symbol
+   _dl_debug_addr points to the r_debug struct which contains
+   a field called r_brk.  r_brk is the address of the function
+   descriptor upon which a breakpoint must be placed.  Being a
+   function descriptor, we must extract the entry point in order
+   to set the breakpoint.
+
+   Our strategy will be to get the .interp section from the
+   executable.  This section will provide us with the name of the
+   interpreter.  We'll open the interpreter and then look up
+   the address of _dl_debug_addr.  We then relocate this address
+   using the interpreter's loadmap.  Once the relocated address
+   is known, we fetch the value (address) corresponding to r_brk
+   and then use that value to fetch the entry point of the function
+   we're interested in.
+
+ */
+
+static int enable_break1_done = 0;
+static int enable_break2_done = 0;
+
+static int
+enable_break2 (void)
+{
+  int success = 0;
+  char **bkpt_namep;
+  asection *interp_sect;
+
+  if (!enable_break1_done || enable_break2_done)
+    return 1;
+
+  enable_break2_done = 1;
+
+  /* First, remove all the solib event breakpoints.  Their addresses
+     may have changed since the last time we ran the program.  */
+  remove_solib_event_breakpoints ();
+
+  interp_text_sect_low = interp_text_sect_high = 0;
+  interp_plt_sect_low = interp_plt_sect_high = 0;
+
+  /* Find the .interp section; if not found, warn the user and drop
+     into the old breakpoint at symbol code.  */
+  interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+  if (interp_sect)
+    {
+      unsigned int interp_sect_size;
+      char *buf;
+      bfd *tmp_bfd = NULL;
+      int tmp_fd = -1;
+      char *tmp_pathname = NULL;
+      int status;
+      CORE_ADDR addr, interp_loadmap_addr;
+      char addr_buf[FRV_PTR_SIZE];
+      struct int_elf32_fdpic_loadmap *ldm;
+
+      /* Read the contents of the .interp section into a local buffer;
+         the contents specify the dynamic linker this program uses.  */
+      interp_sect_size = bfd_section_size (exec_bfd, interp_sect);
+      buf = alloca (interp_sect_size);
+      bfd_get_section_contents (exec_bfd, interp_sect,
+                               buf, 0, interp_sect_size);
+
+      /* Now we need to figure out where the dynamic linker was
+         loaded so that we can load its symbols and place a breakpoint
+         in the dynamic linker itself.
+
+         This address is stored on the stack.  However, I've been unable
+         to find any magic formula to find it for Solaris (appears to
+         be trivial on GNU/Linux).  Therefore, we have to try an alternate
+         mechanism to find the dynamic linker's base address.  */
+
+      tmp_fd  = solib_open (buf, &tmp_pathname);
+      if (tmp_fd >= 0)
+       tmp_bfd = bfd_fdopenr (tmp_pathname, gnutarget, tmp_fd);
+
+      if (tmp_bfd == NULL)
+       {
+         enable_break_failure_warning ();
+         return 0;
+       }
+
+      /* Make sure the dynamic linker is really a useful object.  */
+      if (!bfd_check_format (tmp_bfd, bfd_object))
+       {
+         warning ("Unable to grok dynamic linker %s as an object file", buf);
+         enable_break_failure_warning ();
+         bfd_close (tmp_bfd);
+         return 0;
+       }
+
+      status = frv_fdpic_loadmap_addresses (current_gdbarch,
+                                            &interp_loadmap_addr, 0);
+      if (status < 0)
+       {
+         warning ("Unable to determine dynamic linker loadmap address\n");
+         enable_break_failure_warning ();
+         bfd_close (tmp_bfd);
+         return 0;
+       }
+
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: interp_loadmap_addr = %s\n",
+                           local_hex_string_custom (interp_loadmap_addr,
+                                                    "08l"));
+
+      ldm = fetch_loadmap (interp_loadmap_addr);
+      if (ldm == NULL)
+       {
+         warning ("Unable to load dynamic linker loadmap at address %s\n",
+                  local_hex_string_custom (interp_loadmap_addr, "08l"));
+         enable_break_failure_warning ();
+         bfd_close (tmp_bfd);
+         return 0;
+       }
+
+      /* Record the relocated start and end address of the dynamic linker
+         text and plt section for svr4_in_dynsym_resolve_code.  */
+      interp_sect = bfd_get_section_by_name (tmp_bfd, ".text");
+      if (interp_sect)
+       {
+         interp_text_sect_low
+           = bfd_section_vma (tmp_bfd, interp_sect);
+         interp_text_sect_low
+           += displacement_from_map (ldm, interp_text_sect_low);
+         interp_text_sect_high
+           = interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+       }
+      interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt");
+      if (interp_sect)
+       {
+         interp_plt_sect_low =
+           bfd_section_vma (tmp_bfd, interp_sect);
+         interp_plt_sect_low
+           += displacement_from_map (ldm, interp_plt_sect_low);
+         interp_plt_sect_high =
+           interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect);
+       }
+
+      addr = bfd_lookup_symbol (tmp_bfd, "_dl_debug_addr");
+      if (addr == 0)
+       {
+         warning ("Could not find symbol _dl_debug_addr in dynamic linker");
+         enable_break_failure_warning ();
+         bfd_close (tmp_bfd);
+         return 0;
+       }
+
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: _dl_debug_addr (prior to relocation) = %s\n",
+                           local_hex_string_custom (addr, "08l"));
+
+      addr += displacement_from_map (ldm, addr);
+
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: _dl_debug_addr (after relocation) = %s\n",
+                           local_hex_string_custom (addr, "08l"));
+
+      /* Fetch the address of the r_debug struct.  */
+      if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
+       {
+         warning ("Unable to fetch contents of _dl_debug_addr (at address %s) from dynamic linker",
+                  local_hex_string_custom (addr, "08l"));
+       }
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+
+      /* Fetch the r_brk field.  It's 8 bytes from the start of
+         _dl_debug_addr.  */
+      if (target_read_memory (addr + 8, addr_buf, sizeof addr_buf) != 0)
+       {
+         warning ("Unable to fetch _dl_debug_addr->r_brk (at address %s) from dynamic linker",
+                  local_hex_string_custom (addr + 8, "08l"));
+         enable_break_failure_warning ();
+         bfd_close (tmp_bfd);
+         return 0;
+       }
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+
+      /* Now fetch the function entry point.  */
+      if (target_read_memory (addr, addr_buf, sizeof addr_buf) != 0)
+       {
+         warning ("Unable to fetch _dl_debug_addr->.r_brk entry point (at address %s) from dynamic linker",
+                  local_hex_string_custom (addr, "08l"));
+         enable_break_failure_warning ();
+         bfd_close (tmp_bfd);
+         return 0;
+       }
+      addr = extract_unsigned_integer (addr_buf, sizeof addr_buf);
+
+      /* We're done with the temporary bfd.  */
+      bfd_close (tmp_bfd);
+
+      /* We're also done with the loadmap.  */
+      xfree (ldm);
+
+      /* Now (finally!) create the solib breakpoint.  */
+      create_solib_event_breakpoint (addr);
+
+      return 1;
+    }
+
+  /* Tell the user we couldn't set a dynamic linker breakpoint.  */
+  enable_break_failure_warning ();
+
+  /* Failure return.  */
+  return 0;
+}
+
+static int
+enable_break (void)
+{
+  asection *interp_sect;
+
+  /* Remove all the solib event breakpoints.  Their addresses
+     may have changed since the last time we ran the program.  */
+  remove_solib_event_breakpoints ();
+
+  /* Check for the presence of a .interp section.  If there is no
+     such section, the executable is statically linked.  */
+
+  interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
+
+  if (interp_sect)
+    {
+      enable_break1_done = 1;
+      create_solib_event_breakpoint (symfile_objfile->ei.entry_point);
+
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: solib event breakpoint placed at entry point: %s\n",
+                           local_hex_string_custom
+                             (symfile_objfile->ei.entry_point, "08l"));
+    }
+  else
+    {
+      if (solib_frv_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "enable_break: No .interp section found.\n");
+    }
+
+  return 1;
+}
+
+/*
+
+   LOCAL FUNCTION
+
+   special_symbol_handling -- additional shared library symbol handling
+
+   SYNOPSIS
+
+   void special_symbol_handling ()
+
+   DESCRIPTION
+
+   Once the symbols from a shared object have been loaded in the usual
+   way, we are called to do any system specific symbol handling that 
+   is needed.
+
+ */
+
+static void
+frv_special_symbol_handling (void)
+{
+  /* Nothing needed (yet) for FRV. */
+}
+
+static void
+frv_relocate_main_executable (void)
+{
+  int status;
+  CORE_ADDR exec_addr;
+  struct int_elf32_fdpic_loadmap *ldm;
+  struct cleanup *old_chain;
+  struct section_offsets *new_offsets;
+  int changed;
+  struct obj_section *osect;
+
+  status = frv_fdpic_loadmap_addresses (current_gdbarch, 0, &exec_addr);
+
+  if (status < 0)
+    {
+      /* Not using FDPIC ABI, so do nothing.  */
+      return;
+    }
+
+  /* Fetch the loadmap located at ``exec_addr''.  */
+  ldm = fetch_loadmap (exec_addr);
+  if (ldm == NULL)
+    error ("Unable to load the executable's loadmap.");
+
+  if (main_executable_lm_info)
+    xfree (main_executable_lm_info);
+  main_executable_lm_info = xcalloc (1, sizeof (struct lm_info));
+  main_executable_lm_info->map = ldm;
+
+  new_offsets = xcalloc (symfile_objfile->num_sections,
+                        sizeof (struct section_offsets));
+  old_chain = make_cleanup (xfree, new_offsets);
+  changed = 0;
+
+  ALL_OBJFILE_OSECTIONS (symfile_objfile, osect)
+    {
+      CORE_ADDR orig_addr, addr, offset;
+      int osect_idx;
+      int seg;
+      
+      osect_idx = osect->the_bfd_section->index;
+
+      /* Current address of section.  */
+      addr = osect->addr;
+      /* Offset from where this section started.  */
+      offset = ANOFFSET (symfile_objfile->section_offsets, osect_idx);
+      /* Original address prior to any past relocations.  */
+      orig_addr = addr - offset;
+
+      for (seg = 0; seg < ldm->nsegs; seg++)
+       {
+         if (ldm->segs[seg].p_vaddr <= orig_addr
+             && orig_addr < ldm->segs[seg].p_vaddr + ldm->segs[seg].p_memsz)
+           {
+             new_offsets->offsets[osect_idx]
+               = ldm->segs[seg].addr - ldm->segs[seg].p_vaddr;
+
+             if (new_offsets->offsets[osect_idx] != offset)
+               changed = 1;
+             break;
+           }
+       }
+    }
+
+  if (changed)
+    objfile_relocate (symfile_objfile, new_offsets);
+
+  do_cleanups (old_chain);
+
+  /* Now that symfile_objfile has been relocated, we can compute the
+     GOT value and stash it away.  */
+  main_executable_lm_info->got_value = main_got ();
+}
+
+/*
+
+   GLOBAL FUNCTION
+
+   frv_solib_create_inferior_hook -- shared library startup support
+
+   SYNOPSIS
+
+   void frv_solib_create_inferior_hook()
+
+   DESCRIPTION
+
+   When gdb starts up the inferior, it nurses it along (through the
+   shell) until it is ready to execute it's first instruction.  At this
+   point, this function gets called via expansion of the macro
+   SOLIB_CREATE_INFERIOR_HOOK.
+
+   For the FR-V shared library ABI (FDPIC), the main executable
+   needs to be relocated.  The shared library breakpoints also need
+   to be enabled.
+ */
+
+static void
+frv_solib_create_inferior_hook (void)
+{
+  /* Relocate main executable.  */
+  frv_relocate_main_executable ();
+
+  /* Enable shared library breakpoints.  */
+  if (!enable_break ())
+    {
+      warning ("shared library handler failed to enable breakpoint");
+      return;
+    }
+}
+
+static void
+frv_clear_solib (void)
+{
+  lm_base_cache = 0;
+  enable_break1_done = 0;
+  enable_break2_done = 0;
+}
+
+static void
+frv_free_so (struct so_list *so)
+{
+  xfree (so->lm_info->map);
+  xfree (so->lm_info->dyn_syms);
+  xfree (so->lm_info->dyn_relocs);
+  xfree (so->lm_info);
+}
+
+static void
+frv_relocate_section_addresses (struct so_list *so,
+                                 struct section_table *sec)
+{
+  int seg;
+  struct int_elf32_fdpic_loadmap *map;
+
+  map = so->lm_info->map;
+
+  for (seg = 0; seg < map->nsegs; seg++)
+    {
+      if (map->segs[seg].p_vaddr <= sec->addr
+          && sec->addr < map->segs[seg].p_vaddr + map->segs[seg].p_memsz)
+       {
+         CORE_ADDR displ = map->segs[seg].addr - map->segs[seg].p_vaddr;
+         sec->addr += displ;
+         sec->endaddr += displ;
+         break;
+       }
+    }
+}
+
+/* Return the GOT address associated with the main executable.  Return
+   0 if it can't be found.  */
+
+static CORE_ADDR
+main_got (void)
+{
+  struct minimal_symbol *got_sym;
+
+  got_sym = lookup_minimal_symbol ("_GLOBAL_OFFSET_TABLE_", NULL, symfile_objfile);
+  if (got_sym == 0)
+    return 0;
+
+  return SYMBOL_VALUE_ADDRESS (got_sym);
+}
+
+/* Find the global pointer for the given function address ADDR.  */
+
+CORE_ADDR
+frv_fdpic_find_global_pointer (CORE_ADDR addr)
+{
+  struct so_list *so;
+
+  so = master_so_list ();
+  while (so)
+    {
+      int seg;
+      struct int_elf32_fdpic_loadmap *map;
+
+      map = so->lm_info->map;
+
+      for (seg = 0; seg < map->nsegs; seg++)
+       {
+         if (map->segs[seg].addr <= addr
+             && addr < map->segs[seg].addr + map->segs[seg].p_memsz)
+           return so->lm_info->got_value;
+       }
+
+      so = so->next;
+    }
+
+  /* Didn't find it it any of the shared objects.  So assume it's in the
+     main executable.  */
+  return main_got ();
+}
+
+/* Forward declarations for frv_fdpic_find_canonical_descriptor().  */
+static CORE_ADDR find_canonical_descriptor_in_load_object
+  (CORE_ADDR, CORE_ADDR, char *, bfd *, struct lm_info *);
+
+/* Given a function entry point, attempt to find the canonical descriptor
+   associated with that entry point.  Return 0 if no canonical descriptor
+   could be found.  */
+
+CORE_ADDR
+frv_fdpic_find_canonical_descriptor (CORE_ADDR entry_point)
+{
+  char *name;
+  CORE_ADDR addr;
+  CORE_ADDR got_value;
+  struct int_elf32_fdpic_loadmap *ldm = 0;
+  struct symbol *sym;
+  int status;
+  CORE_ADDR exec_loadmap_addr;
+
+  /* Fetch the corresponding global pointer for the entry point.  */
+  got_value = frv_fdpic_find_global_pointer (entry_point);
+
+  /* Attempt to find the name of the function.  If the name is available,
+     it'll be used as an aid in finding matching functions in the dynamic
+     symbol table.  */
+  sym = find_pc_function (entry_point);
+  if (sym == 0)
+    name = 0;
+  else
+    name = SYMBOL_LINKAGE_NAME (sym);
+
+  /* Check the main executable.  */
+  addr = find_canonical_descriptor_in_load_object
+           (entry_point, got_value, name, symfile_objfile->obfd,
+           main_executable_lm_info);
+
+  /* If descriptor not found via main executable, check each load object
+     in list of shared objects.  */
+  if (addr == 0)
+    {
+      struct so_list *so;
+
+      so = master_so_list ();
+      while (so)
+       {
+         addr = find_canonical_descriptor_in_load_object
+                  (entry_point, got_value, name, so->abfd, so->lm_info);
+
+         if (addr != 0)
+           break;
+
+         so = so->next;
+       }
+    }
+
+  return addr;
+}
+
+static CORE_ADDR
+find_canonical_descriptor_in_load_object
+  (CORE_ADDR entry_point, CORE_ADDR got_value, char *name, bfd *abfd,
+   struct lm_info *lm)
+{
+  arelent *rel;
+  unsigned int i;
+  CORE_ADDR addr = 0;
+
+  /* Nothing to do if no bfd.  */
+  if (abfd == 0)
+    return 0;
+
+  /* We want to scan the dynamic relocs for R_FRV_FUNCDESC relocations.
+     (More about this later.)  But in order to fetch the relocs, we
+     need to first fetch the dynamic symbols.  These symbols need to
+     be cached due to the way that bfd_canonicalize_dynamic_reloc()
+     works.  (See the comments in the declaration of struct lm_info
+     for more information.)  */
+  if (lm->dyn_syms == NULL)
+    {
+      long storage_needed;
+      unsigned int number_of_symbols;
+
+      /* Determine amount of space needed to hold the dynamic symbol table.  */
+      storage_needed = bfd_get_dynamic_symtab_upper_bound (abfd);
+
+      /* If there are no dynamic symbols, there's nothing to do.  */
+      if (storage_needed <= 0)
+       return 0;
+
+      /* Allocate space for the dynamic symbol table.  */
+      lm->dyn_syms = (asymbol **) xmalloc (storage_needed);
+
+      /* Fetch the dynamic symbol table.  */
+      number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, lm->dyn_syms);
+
+      if (number_of_symbols == 0)
+       return 0;
+    }
+
+  /* Fetch the dynamic relocations if not already cached.  */
+  if (lm->dyn_relocs == NULL)
+    {
+      long storage_needed;
+
+      /* Determine amount of space needed to hold the dynamic relocs.  */
+      storage_needed = bfd_get_dynamic_reloc_upper_bound (abfd);
+
+      /* Bail out if there are no dynamic relocs.  */
+      if (storage_needed <= 0)
+       return 0;
+
+      /* Allocate space for the relocs.  */
+      lm->dyn_relocs = (arelent **) xmalloc (storage_needed);
+
+      /* Fetch the dynamic relocs.  */
+      lm->dyn_reloc_count 
+       = bfd_canonicalize_dynamic_reloc (abfd, lm->dyn_relocs, lm->dyn_syms);
+    }
+
+  /* Search the dynamic relocs.  */
+  for (i = 0; i < lm->dyn_reloc_count; i++)
+    {
+      rel = lm->dyn_relocs[i];
+
+      /* Relocs of interest are those which meet the following
+         criteria:
+
+          - the names match (assuming the caller could provide
+            a name which matches ``entry_point'').
+          - the relocation type must be R_FRV_FUNCDESC.  Relocs
+            of this type are used (by the dynamic linker) to
+            look up the address of a canonical descriptor (allocating
+            it if need be) and initializing the GOT entry referred
+            to by the offset to the address of the descriptor.
+
+        These relocs of interest may be used to obtain a
+        candidate descriptor by first adjusting the reloc's
+        address according to the link map and then dereferencing
+        this address (which is a GOT entry) to obtain a descriptor
+        address.  */
+      if ((name == 0 || strcmp (name, (*rel->sym_ptr_ptr)->name) == 0)
+          && rel->howto->type == R_FRV_FUNCDESC)
+       {
+         char buf[FRV_PTR_SIZE];
+
+         /* Compute address of address of candidate descriptor.  */
+         addr = rel->address + displacement_from_map (lm->map, rel->address);
+
+         /* Fetch address of candidate descriptor.  */
+         if (target_read_memory (addr, buf, sizeof buf) != 0)
+           continue;
+         addr = extract_unsigned_integer (buf, sizeof buf);
+
+         /* Check for matching entry point.  */
+         if (target_read_memory (addr, buf, sizeof buf) != 0)
+           continue;
+         if (extract_unsigned_integer (buf, sizeof buf) != entry_point)
+           continue;
+
+         /* Check for matching got value.  */
+         if (target_read_memory (addr + 4, buf, sizeof buf) != 0)
+           continue;
+         if (extract_unsigned_integer (buf, sizeof buf) != got_value)
+           continue;
+
+         /* Match was successful!  Exit loop.  */
+         break;
+       }
+    }
+
+  return addr;
+}
+
+static struct target_so_ops frv_so_ops;
+
+void
+_initialize_frv_solib (void)
+{
+  frv_so_ops.relocate_section_addresses = frv_relocate_section_addresses;
+  frv_so_ops.free_so = frv_free_so;
+  frv_so_ops.clear_solib = frv_clear_solib;
+  frv_so_ops.solib_create_inferior_hook = frv_solib_create_inferior_hook;
+  frv_so_ops.special_symbol_handling = frv_special_symbol_handling;
+  frv_so_ops.current_sos = frv_current_sos;
+  frv_so_ops.open_symbol_file_object = open_symbol_file_object;
+  frv_so_ops.in_dynsym_resolve_code = frv_in_dynsym_resolve_code;
+
+  /* FIXME: Don't do this here.  *_gdbarch_init() should set so_ops. */
+  current_target_so_ops = &frv_so_ops;
+
+  /* Debug this file's internals.  */
+  add_show_from_set (add_set_cmd ("solib-frv", class_maintenance, var_zinteger,
+                                 &solib_frv_debug,
+"Set internal debugging of shared library code for FR-V.\n"
+"When non-zero, FR-V solib specific internal debugging is enabled.",
+                                  &setdebuglist),
+                    &showdebuglist);
+}
diff --git a/gdb/testsuite/gdb.arch/gdb1431.s b/gdb/testsuite/gdb.arch/gdb1431.s
new file mode 100644 (file)
index 0000000..36b43d2
--- /dev/null
@@ -0,0 +1,129 @@
+! Copyright 2004 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@gnu.org
+!
+! This file is part of the gdb testsuite.
+!
+! It was generated using "sh-elf-gcc -S gdb1431.c", using the following
+! source file:
+!
+!      #include <stdio.h>
+!      
+!      main()
+!      {
+!        printf("hello world\n");
+!        sub1();
+!        sub2();
+!      }
+!      sub1()
+!      {
+!        int buf[64];
+!      
+!      }
+!      
+!      sub2()
+!      {
+!        int buf[65];
+!      
+!      }
+!
+! We use a pregenerated assembly file as the test input to avoid possible
+! problems with future versions of gcc generating different code.
+
+       .file   "gdb1431.c"
+       .text
+       .section        .rodata
+       .align 2
+.LC0:
+       .string "hello world\n"
+       .text
+       .align 1
+       .global _main
+       .type   _main, @function
+_main:
+       mov.l   r14,@-r15
+       sts.l   pr,@-r15
+       mov     r15,r14
+       mov.l   .L2,r1
+       mov     r1,r4
+       mov.l   .L3,r1
+       jsr     @r1
+       nop
+       mov.l   .L4,r1
+       jsr     @r1
+       nop
+       mov.l   .L5,r1
+       jsr     @r1
+       nop
+       mov     r14,r15
+       lds.l   @r15+,pr
+       mov.l   @r15+,r14
+       rts     
+       nop
+.L6:
+       .align 2
+.L2:
+       .long   .LC0
+.L3:
+       .long   _printf
+.L4:
+       .long   _sub1
+.L5:
+       .long   _sub2
+       .size   _main, .-_main
+       .align 1
+       .global _sub1
+       .type   _sub1, @function
+_sub1:
+       mov.l   r14,@-r15
+       sts.l   pr,@-r15
+       add     #-128,r15
+       add     #-128,r15
+       mov     r15,r14
+       mov.w   .L8,r7
+       add     r7,r14
+       mov     r14,r15
+       lds.l   @r15+,pr
+       mov.l   @r15+,r14
+       rts     
+       nop
+       .align 1
+.L8:
+       .short  256
+       .size   _sub1, .-_sub1
+       .align 1
+       .global _sub2
+       .type   _sub2, @function
+_sub2:
+       mov.l   r14,@-r15
+       sts.l   pr,@-r15
+       mov.w   .L11,r1
+       sub     r1,r15
+       mov     r15,r14
+       mov.w   .L11,r7
+       add     r7,r14
+       mov     r14,r15
+       lds.l   @r15+,pr
+       mov.l   @r15+,r14
+       rts     
+       nop
+       .align 1
+.L11:
+       .short  260
+       .size   _sub2, .-_sub2
+       .ident  "GCC: (GNU) 3.5.0 20040204 (experimental)"
diff --git a/gdb/testsuite/gdb.base/auxv.c b/gdb/testsuite/gdb.base/auxv.c
new file mode 100644 (file)
index 0000000..94f9d00
--- /dev/null
@@ -0,0 +1,58 @@
+/* Simple little program that just generates a core dump from inside some
+   nested function calls.  Keep this as self contained as possible, I.E.
+   use no environment resources other than possibly abort(). */
+
+#ifndef __STDC__
+#define        const   /**/
+#endif
+
+#ifndef HAVE_ABORT
+#define HAVE_ABORT 1
+#endif
+
+#if HAVE_ABORT
+#define ABORT abort()
+#else
+#define ABORT {char *invalid = 0; *invalid = 0xFF;}
+#endif
+
+/* Don't make these automatic vars or we will have to walk back up the
+   stack to access them. */
+
+char *buf1;
+char *buf2;
+
+int coremaker_data = 1;        /* In Data section */
+int coremaker_bss;     /* In BSS section */
+
+const int coremaker_ro = 201;  /* In Read-Only Data section */
+
+void
+func2 (int x)
+{
+  int coremaker_local[5];
+  int i;
+  static int y;
+
+  /* Make sure that coremaker_local doesn't get optimized away. */
+  for (i = 0; i < 5; i++)
+    coremaker_local[i] = i;
+  coremaker_bss = 0;
+  for (i = 0; i < 5; i++)
+    coremaker_bss += coremaker_local[i];
+  coremaker_data = coremaker_ro + 1;
+  y = 10 * x;
+  ABORT;
+}
+
+void
+func1 (int x)
+{
+  func2 (x * 2);
+}
+
+int main ()
+{
+  func1 (10);
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/auxv.exp b/gdb/testsuite/gdb.base/auxv.exp
new file mode 100644 (file)
index 0000000..3a509b9
--- /dev/null
@@ -0,0 +1,187 @@
+# Test `info auxv' and related functionality.
+
+# Copyright 1992,1993,1994,1995,1996,1997,1998,1999,2000,2004
+#      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
+
+# This file is based on corefile.exp which was written by Fred
+# Fish. (fnf@cygnus.com)
+
+if $tracelevel then {
+       strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile "auxv"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+set corefile ${objdir}/${subdir}/${testfile}.corefile
+set gcorefile ${objdir}/${subdir}/${testfile}.gcore
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+}
+
+# Use a fresh directory to confine the native core dumps.
+# Make it the working directory for gdb and its child.
+set coredir "${objdir}/${subdir}/coredir.[getpid]"
+file mkdir $coredir
+set core_works [isnative]
+
+# Run GDB on the test program up to where it will dump core.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+gdb_test "set print sevenbit-strings" "" \
+       "set print sevenbit-strings; ${testfile}"
+gdb_test "set width 0" "" \
+       "set width 0; ${testfile}"
+
+if {$core_works} {
+    if {[gdb_test "cd $coredir" ".*Working directory .*" \
+            "cd to temporary directory for core dumps"]} {
+       set core_works 0
+    }
+}
+
+if { ![runto_main] } then {
+    gdb_suppress_tests;
+}
+set print_core_line [gdb_get_line_number "ABORT;"]
+gdb_test "tbreak $print_core_line"
+gdb_test continue ".*ABORT;.*"
+
+proc fetch_auxv {test} {
+    global gdb_prompt
+
+    set auxv_lines {}
+    set bad -1
+    if {[gdb_test_multiple "info auxv" $test {
+       -re "info auxv\[\r\n\]+" {
+           exp_continue
+       }
+       -ex "The program has no auxiliary information now" {
+           set bad 1
+       }
+       -ex "Auxiliary vector is empty" {
+           set bad 1
+       }
+       -ex "No auxiliary vector found" {
+           set bad 1
+       }
+       -re "^\[0-9\]+\[ \t\]+(AT_\[^ \t\]+)\[^\r\n\]+\[\r\n\]+" {
+           lappend auxv_lines $expect_out(0,string)
+           exp_continue
+       }
+       -re "^\[0-9\]+\[ \t\]+\\?\\?\\?\[^\r\n\]+\[\r\n\]+" {
+           warning "Unrecognized tag value: $expect_out(0,string)"
+           set bad 1
+           lappend auxv_lines $expect_out(0,string)
+           exp_continue
+       }
+       -re ".*$gdb_prompt $" {
+           incr bad
+       }
+       -re "^\[^\r\n\]+\[\r\n\]+" {
+           warning "Unrecognized output: $expect_out(0,string)"
+           set bad 1
+       }
+    }] != 0} {
+       return {}
+    }
+
+    if {$bad} {
+       fail $test
+       return {}
+    }
+
+    pass $test
+    return $auxv_lines
+}
+
+set live_data [fetch_auxv "info auxv on live process"]
+
+# Now try gcore.
+set gcore_works 0
+set escapedfilename [string_to_regexp $gcorefile]
+gdb_test_multiple "gcore $gcorefile" "gcore" {
+    -re "Saved corefile ${escapedfilename}\[\r\n\]+$gdb_prompt $" {
+       pass "gcore"
+       set gcore_works 1
+    }
+    -re "Can't create a corefile\[\r\n\]+$gdb_prompt $" {
+       unsupported "gcore"
+    }
+}
+
+# Let the program continue and die.
+gdb_test continue ".*Program received signal.*"
+gdb_test continue ".*Program terminated with signal.*"
+
+# Now collect the core dump it left.
+set test "generate native core dump"
+if {$core_works} {
+    # Find the
+    set names [glob -nocomplain -directory $coredir *core*]
+    if {[llength $names] == 1} {
+       set file [file join $coredir [lindex $names 0]]
+       remote_exec build "mv $file $corefile"
+       pass $test
+    } else {
+       set core_works 0
+       warning "can't generate a core file - core tests suppressed - check ulimit -c"
+       fail $test
+    }
+} else {
+    unsupported $test
+}
+remote_exec build "rm -rf $coredir"
+
+# Now we can examine the core files and check that their data matches what
+# we saw in the process.  Note that the exact data can vary between runs,
+# so it's important that the native core dump file and the gcore-created dump
+# both be from the same run of the program as we examined live.
+
+proc do_core_test {works corefile test1 test2} {
+    if {! $works} {
+       unsupported $test1
+       unsupported $test2
+    } else {
+       gdb_test "core $corefile" "Core was generated by.*" \
+           "load core file for $test1" \
+           "A program is being debugged already.*" "y"
+       set core_data [fetch_auxv $test1]
+       global live_data
+       if {$core_data == $live_data} {
+           pass $test2
+       } else {
+           fail $test2
+       }
+    }
+}
+
+do_core_test $core_works $corefile \
+    "info auxv on native core dump" "matching auxv data from live and core"
+
+do_core_test $gcore_works $gcorefile \
+    "info auxv on gcore-created dump" "matching auxv data from live and gcore"
diff --git a/gdb/testsuite/gdb.cp/classes.cc b/gdb/testsuite/gdb.cp/classes.cc
new file mode 100644 (file)
index 0000000..d09f38f
--- /dev/null
@@ -0,0 +1,608 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2004
+   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.
+   */
+
+// Test various -*- C++ -*- things.
+
+// ====================== basic C++ types  =======================
+bool            v_bool;
+bool            v_bool_array[2];
+
+typedef struct fleep fleep;
+struct fleep { int a; } s;
+
+// ====================== simple class structures  =======================
+
+struct default_public_struct {
+ // defaults to public:
+  int a;
+  int b;
+};
+
+struct explicit_public_struct {
+ public:
+  int a;
+  int b;
+};
+
+struct protected_struct {
+ protected:
+  int a;
+  int b;
+};
+
+struct private_struct {
+ private:
+  int a;
+  int b;
+};
+
+struct mixed_protection_struct {
+ public:
+  int a;
+  int b;
+ private:
+  int c;
+  int d;
+ protected:
+  int e;
+  int f;
+ public:
+  int g;
+ private:
+  int h;
+ protected:
+  int i;
+};
+
+class public_class {
+ public:
+  int a;
+  int b;
+};
+
+class protected_class {
+ protected:
+  int a;
+  int b;
+};
+
+class default_private_class {
+ // defaults to private:
+  int a;
+  int b;
+};
+
+class explicit_private_class {
+ private:
+  int a;
+  int b;
+};
+
+class mixed_protection_class {
+ public:
+  int a;
+  int b;
+ private:
+  int c;
+  int d;
+ protected:
+  int e;
+  int f;
+ public:
+  int g;
+ private:
+  int h;
+ protected:
+  int i;
+};
+
+class const_vol_method_class {
+public:
+  int a;
+  int b;
+  int foo (int &) const;
+  int bar (int &) volatile;
+  int baz (int &) const volatile;
+};
+
+int const_vol_method_class::foo (int & ir) const
+{
+  return ir + 3;
+}
+int const_vol_method_class::bar (int & ir) volatile
+{
+  return ir + 4;
+}
+int const_vol_method_class::baz (int & ir) const volatile
+{
+  return ir + 5;
+}
+
+// ========================= simple inheritance ==========================
+
+class A {
+ public:
+  int a;
+  int x;
+};
+
+A g_A;
+
+class B : public A {
+ public:
+  int b;
+  int x;
+};
+
+B g_B;
+
+class C : public A {
+ public:
+  int c;
+  int x;
+};
+
+C g_C;
+
+class D : public B, public C {
+ public:
+  int d;
+  int x;
+};
+
+D g_D;
+
+class E : public D {
+ public:
+  int e;
+  int x;
+};
+
+E g_E;
+
+class class_with_anon_union
+{
+ public:
+  int one;
+  union
+  {
+    int a;
+    long b;
+  };
+};
+
+class_with_anon_union g_anon_union;
+
+void inheritance2 (void)
+{
+}
+
+void inheritance1 (void)
+{
+  int ival;
+  int *intp;
+
+  // {A::a, A::x}
+
+  g_A.A::a = 1;
+  g_A.A::x = 2;
+
+  // {{A::a,A::x},B::b,B::x}
+
+  g_B.A::a = 3;
+  g_B.A::x = 4;
+  g_B.B::b = 5;
+  g_B.B::x = 6;
+
+  // {{A::a,A::x},C::c,C::x}
+
+  g_C.A::a = 7;
+  g_C.A::x = 8;
+  g_C.C::c = 9;
+  g_C.C::x = 10;
+
+  // {{{A::a,A::x},B::b,B::x},{{A::a,A::x},C::c,C::x},D::d,D::x}
+
+  // The following initialization code is non-portable, but allows us
+  // to initialize all members of g_D until we can fill in the missing
+  // initialization code with legal C++ code.
+
+  for (intp = (int *) &g_D, ival = 11;
+       intp < ((int *) &g_D + sizeof (g_D) / sizeof (int));
+       intp++, ival++)
+    {
+      *intp = ival;
+    }
+
+  // Overlay the nonportable initialization with legal initialization.
+
+  // ????? = 11;  (g_D.A::a = 11; is ambiguous)
+  // ????? = 12;  (g_D.A::x = 12; is ambiguous)
+/* djb 6-3-2000
+
+       This should take care of it. Rather than try to initialize using an ambiguous
+       construct, use 2 unambiguous ones for each. Since the ambiguous a/x member is
+       coming from C, and B, initialize D's C::a, and B::a, and D's C::x and B::x.
+ */
+  g_D.C::a = 15;
+  g_D.C::x = 12;
+  g_D.B::a = 11;
+  g_D.B::x = 12;
+  g_D.B::b = 13;
+  g_D.B::x = 14;
+  // ????? = 15;
+  // ????? = 16;
+  g_D.C::c = 17;
+  g_D.C::x = 18;
+  g_D.D::d = 19;
+  g_D.D::x = 20;
+
+
+  // {{{{A::a,A::x},B::b,B::x},{{A::a,A::x},C::c,C::x},D::d,D::x}},E::e,E::x}
+
+  // The following initialization code is non-portable, but allows us
+  // to initialize all members of g_D until we can fill in the missing
+  // initialization code with legal C++ code.
+
+  for (intp = (int *) &g_E, ival = 21;
+       intp < ((int *) &g_E + sizeof (g_E) / sizeof (int));
+       intp++, ival++)
+  {
+    *intp = ival;
+  }
+
+  // Overlay the nonportable initialization with legal initialization.
+
+  // ????? = 21;  (g_E.A::a = 21; is ambiguous)
+  // ????? = 22;  (g_E.A::x = 22; is ambiguous)
+  g_E.B::b = 23;
+  g_E.B::x = 24;
+  // ????? = 25;
+  // ????? = 26;
+  g_E.C::c = 27;
+  g_E.C::x = 28;
+  g_E.D::d = 29;
+  g_E.D::x = 30;
+  g_E.E::e = 31;
+  g_E.E::x = 32;
+
+  g_anon_union.one = 1;
+  g_anon_union.a = 2;
+
+  inheritance2 ();     
+}
+
+// ======================== static member functions =====================
+
+class Static {
+public:
+  static void ii(int, int);
+};
+void Static::ii (int, int) { }
+
+// ======================== virtual base classes=========================
+
+class vA {
+ public:
+  int va;
+  int vx;
+};
+
+vA g_vA;
+
+class vB : public virtual vA {
+ public:
+  int vb;
+  int vx;
+};
+
+vB g_vB;
+
+class vC : public virtual vA {
+ public:
+  int vc;
+  int vx;
+};
+
+vC g_vC;
+
+class vD : public virtual vB, public virtual vC {
+ public:
+  int vd;
+  int vx;
+};
+
+vD g_vD;
+
+class vE : public virtual vD {
+ public:
+  int ve;
+  int vx;
+};
+
+vE g_vE;
+
+void inheritance4 (void)
+{
+}
+
+void inheritance3 (void)
+{
+  int ival;
+  int *intp;
+
+  // {vA::va, vA::vx}
+
+  g_vA.vA::va = 1;
+  g_vA.vA::vx = 2;
+
+  // {{vA::va, vA::vx}, vB::vb, vB::vx}
+
+  g_vB.vA::va = 3;
+  g_vB.vA::vx = 4;
+  g_vB.vB::vb = 5;
+  g_vB.vB::vx = 6;
+
+  // {{vA::va, vA::vx}, vC::vc, vC::vx}
+
+  g_vC.vA::va = 7;
+  g_vC.vA::vx = 8;
+  g_vC.vC::vc = 9;
+  g_vC.vC::vx = 10;
+
+  // {{{{vA::va, vA::vx}, vB::vb, vB::vx}, vC::vc, vC::vx}, vD::vd,vD::vx}
+
+  g_vD.vA::va = 11;
+  g_vD.vA::vx = 12;
+  g_vD.vB::vb = 13;
+  g_vD.vB::vx = 14;
+  g_vD.vC::vc = 15;
+  g_vD.vC::vx = 16;
+  g_vD.vD::vd = 17;
+  g_vD.vD::vx = 18;
+
+
+  // {{{{{vA::va,vA::vx},vB::vb,vB::vx},vC::vc,vC::vx},vD::vd,vD::vx},vE::ve,vE::vx}
+
+  g_vD.vA::va = 19;
+  g_vD.vA::vx = 20;
+  g_vD.vB::vb = 21;
+  g_vD.vB::vx = 22;
+  g_vD.vC::vc = 23;
+  g_vD.vC::vx = 24;
+  g_vD.vD::vd = 25;
+  g_vD.vD::vx = 26;
+  g_vE.vE::ve = 27;
+  g_vE.vE::vx = 28;
+
+  inheritance4 ();     
+}
+
+// ======================================================================
+
+class Base1 {
+ public:
+  int x;
+  Base1(int i) { x = i; }
+};
+
+class Foo
+{
+ public:
+  int x;
+  int y;
+  static int st;
+  Foo (int i, int j) { x = i; y = j; }
+  int operator! ();
+  operator int ();
+  int times (int y);
+};
+
+class Bar : public Base1, public Foo {
+ public:
+  int z;
+  Bar (int i, int j, int k) : Base1 (10*k), Foo (i, j) { z = k; }
+};
+
+int Foo::operator! () { return !x; }
+
+int Foo::times (int y) { return x * y; }
+
+int Foo::st = 100;
+
+Foo::operator int() { return x; }
+
+Foo foo(10, 11);
+Bar bar(20, 21, 22);
+
+class ClassWithEnum {
+public:
+  enum PrivEnum { red, green, blue, yellow = 42 };
+  PrivEnum priv_enum;
+  int x;
+};
+
+void enums2 (void)
+{
+}
+
+/* classes.exp relies on statement order in this function for testing
+   enumeration fields.  */
+
+void enums1 ()
+{
+  ClassWithEnum obj_with_enum;
+  obj_with_enum.priv_enum = ClassWithEnum::red;
+  obj_with_enum.x = 0;
+  enums2 ();
+  obj_with_enum.priv_enum = ClassWithEnum::green;
+  obj_with_enum.x = 1;
+}
+
+class ClassParam {
+public:
+  int Aptr_a (A *a) { return a->a; }
+  int Aptr_x (A *a) { return a->x; }
+  int Aref_a (A &a) { return a.a; }
+  int Aref_x (A &a) { return a.x; }
+  int Aval_a (A a) { return a.a; }
+  int Aval_x (A a) { return a.x; }
+};
+
+ClassParam class_param;
+
+class Contains_static_instance
+{
+ public:
+  int x;
+  int y;
+  Contains_static_instance (int i, int j) { x = i; y = j; }
+  static Contains_static_instance null;
+};
+
+Contains_static_instance Contains_static_instance::null(0,0);
+Contains_static_instance csi(10,20);
+
+class Contains_nested_static_instance
+{
+ public:
+  class Nested
+  {
+   public:
+    Nested(int i) : z(i) {}
+    int z;
+    static Contains_nested_static_instance xx;
+  };
+
+  Contains_nested_static_instance(int i, int j) : x(i), y(j) {}
+
+  int x;
+  int y;
+
+  static Contains_nested_static_instance null;
+  static Nested yy;
+};
+
+Contains_nested_static_instance Contains_nested_static_instance::null(0, 0);
+Contains_nested_static_instance::Nested Contains_nested_static_instance::yy(5);
+Contains_nested_static_instance
+  Contains_nested_static_instance::Nested::xx(1,2);
+Contains_nested_static_instance cnsi(30,40);
+
+typedef struct {
+  int one;
+  int two;
+} tagless_struct;
+tagless_struct v_tagless;
+
+/* Try to get the compiler to allocate a class in a register.  */
+class small {
+ public:
+  int x;
+  int method ();
+};
+
+int
+small::method ()
+{
+  return x + 5;
+}
+
+void marker_reg1 () {}
+
+int
+register_class ()
+{
+  /* We don't call any methods for v, so gcc version cygnus-2.3.3-930220
+     might put this variable in a register.  This is a lose, though, because
+     it means that GDB can't call any methods for that variable.  */
+  register small v;
+
+  int i;
+
+  /* Perform a computation sufficiently complicated that optimizing compilers
+     won't optimized out the variable.  If some compiler constant-folds this
+     whole loop, maybe using a parameter to this function here would help.  */
+  v.x = 0;
+  for (i = 0; i < 13; ++i)
+    v.x += i;
+  --v.x; /* v.x is now 77 */
+  marker_reg1 ();
+  return v.x + 5;
+}
+
+void dummy()
+{
+  v_bool = true;
+  v_bool_array[0] = false;
+  v_bool_array[1] = v_bool;
+}
+
+void use_methods ()
+{
+  /* Refer to methods so that they don't get optimized away. */
+  int i;
+  i = class_param.Aptr_a (&g_A);
+  i = class_param.Aptr_x (&g_A);
+  i = class_param.Aref_a (g_A);
+  i = class_param.Aref_x (g_A);
+  i = class_param.Aval_a (g_A);
+  i = class_param.Aval_x (g_A);
+}
+
+
+int
+main()
+{
+#ifdef usestubs
+  set_debug_traps();
+  breakpoint();
+#endif
+  dummy();
+  inheritance1 ();
+  inheritance3 ();
+  enums1 ();
+  register_class ();
+
+  /* FIXME: pmi gets optimized out.  Need to do some more computation with
+     it or something.  (No one notices, because the test is xfail'd anyway,
+     but that probably won't always be true...).  */
+  int Foo::* pmi = &Foo::y;
+
+  /* Make sure the AIX linker doesn't remove the variable.  */
+  v_tagless.one = 5;
+
+  use_methods ();
+
+  return foo.*pmi;
+}
+
+/* Create an instance for some classes, otherwise they get optimized away.  */
+
+default_public_struct default_public_s;
+explicit_public_struct explicit_public_s;
+protected_struct protected_s;
+private_struct private_s;
+mixed_protection_struct mixed_protection_s;
+public_class public_c;
+protected_class protected_c;
+default_private_class default_private_c;
+explicit_private_class explicit_private_c;
+mixed_protection_class mixed_protection_c;
diff --git a/gdb/testsuite/gdb.cp/pr-1553.cc b/gdb/testsuite/gdb.cp/pr-1553.cc
new file mode 100644 (file)
index 0000000..58441fd
--- /dev/null
@@ -0,0 +1,53 @@
+class A {
+public:
+  class B;
+  class C;
+};
+
+class A::B {
+  int a_b;
+
+public:
+  C* get_c(int i);
+};
+
+class A::C
+{
+  int a_c;
+};
+
+class E {
+public:
+  class F;
+};
+class E::F {
+public:
+  int e_f;
+  F& operator=(const F &other);
+};
+
+void refer_to (E::F *f) {
+  // Do nothing.
+}
+
+void refer_to (A::C **ref) {
+  // Do nothing.  But, while we're at it, force out debug info for
+  // A::B and E::F.
+
+  A::B b;
+  E::F f;
+
+  refer_to (&f);
+}
+
+int main () {
+  A::C* c_var;
+  A::B* b_var;
+  E *e_var;
+
+  // Keep around a reference so that GCC 3.4 doesn't optimize the variable
+  // away.
+  refer_to (&c_var);
+}
diff --git a/gdb/testsuite/gdb.cp/pr-1553.exp b/gdb/testsuite/gdb.cp/pr-1553.exp
new file mode 100644 (file)
index 0000000..fe9e2a2
--- /dev/null
@@ -0,0 +1,62 @@
+# Copyright 2004 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.  
+
+# Test for PR gdb/1553.
+
+# This file is part of the gdb testsuite.
+
+set ws "\[\r\n\t \]+"
+
+if $tracelevel then {
+       strace $tracelevel
+}
+
+if { [skip_cplus_tests] } { continue }
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+set testfile "pr-1553"
+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
+}
+
+gdb_test "ptype c_var" "type = class A::C \{${ws}private:${ws}int a_c;${ws}\} \\*"
+
+gdb_test "ptype E::F" "type = class E::F \{${ws}public:${ws}int e_f;${ws}E::F & operator=\\(E::F const ?&\\);${ws}\}"
+
+gdb_exit
+return 0
diff --git a/gdb/tramp-frame.c b/gdb/tramp-frame.c
new file mode 100644 (file)
index 0000000..ee3635f
--- /dev/null
@@ -0,0 +1,173 @@
+/* Signal trampoline unwinder, for GDB the GNU Debugger.
+
+   Copyright 2004 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 "tramp-frame.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "symtab.h"
+#include "objfiles.h"
+#include "target.h"
+#include "trad-frame.h"
+#include "frame-base.h"
+#include "gdb_assert.h"
+
+struct frame_data
+{
+  const struct tramp_frame *tramp_frame;
+};
+
+struct tramp_frame_cache
+{
+  CORE_ADDR func;
+  const struct tramp_frame *tramp_frame;
+  struct trad_frame_cache *trad_cache;
+};
+
+static struct trad_frame_cache *
+tramp_frame_cache (struct frame_info *next_frame,
+                  void **this_cache)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  struct tramp_frame_cache *tramp_cache = (*this_cache);
+  if (tramp_cache->trad_cache == NULL)
+    {
+      tramp_cache->trad_cache = trad_frame_cache_zalloc (next_frame);
+      tramp_cache->tramp_frame->init (tramp_cache->tramp_frame,
+                                     next_frame,
+                                     tramp_cache->trad_cache,
+                                     tramp_cache->func);
+    }
+  return tramp_cache->trad_cache;
+}
+
+static void
+tramp_frame_this_id (struct frame_info *next_frame,
+                    void **this_cache,
+                    struct frame_id *this_id)
+{
+  struct trad_frame_cache *trad_cache
+    = tramp_frame_cache (next_frame, this_cache);
+  trad_frame_get_id (trad_cache, this_id);
+}
+
+static void
+tramp_frame_prev_register (struct frame_info *next_frame,
+                          void **this_cache,
+                          int prev_regnum,
+                          int *optimizedp,
+                          enum lval_type * lvalp,
+                          CORE_ADDR *addrp,
+                          int *realnump, void *valuep)
+{
+  struct trad_frame_cache *trad_cache
+    = tramp_frame_cache (next_frame, this_cache);
+  trad_frame_get_register (trad_cache, next_frame, prev_regnum, optimizedp,
+                          lvalp, addrp, realnump, valuep);
+}
+
+static CORE_ADDR
+tramp_frame_start (CORE_ADDR pc, const struct tramp_frame *tramp)
+{
+  int ti;
+  /* Search through the trampoline for one that matches the
+     instruction sequence around PC.  */
+  for (ti = 0; tramp->insn[ti] != TRAMP_SENTINEL_INSN; ti++)
+    {
+      CORE_ADDR func = pc - tramp->insn_size * ti;
+      int i;
+      for (i = 0; 1; i++)
+       {
+         bfd_byte buf[sizeof (tramp->insn[0])];
+         ULONGEST insn;
+         if (tramp->insn[i] == TRAMP_SENTINEL_INSN)
+           return func;
+         if (target_read_memory (func + i * tramp->insn_size, buf,
+                                 tramp->insn_size) != 0)
+           break;
+         insn = extract_unsigned_integer (buf, tramp->insn_size);
+         if (tramp->insn[i] != insn)
+           break;
+       }
+    }
+  /* Trampoline doesn't match.  */
+  return 0;
+}
+
+static int
+tramp_frame_sniffer (const struct frame_unwind *self,
+                    struct frame_info *next_frame,
+                    void **this_cache)
+{
+  const struct tramp_frame *tramp = self->unwind_data->tramp_frame;
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+  CORE_ADDR func;
+  char *name;
+  struct tramp_frame_cache *tramp_cache;
+
+  /* If the function has a valid symbol name, it isn't a
+     trampoline.  */
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (name != NULL)
+    return 0;
+  /* If the function lives in a valid section (even without a starting
+     point) it isn't a trampoline.  */
+  if (find_pc_section (pc) != NULL)
+    return 0;
+  /* Finally, check that the trampoline matches at PC.  */
+  func = tramp_frame_start (pc, tramp);
+  if (func == 0)
+    return 0;
+  tramp_cache = FRAME_OBSTACK_ZALLOC (struct tramp_frame_cache);
+  tramp_cache->func = func;
+  tramp_cache->tramp_frame = tramp;
+  (*this_cache) = tramp_cache;
+  return 1;
+}
+
+void
+tramp_frame_append (struct gdbarch *gdbarch,
+                   const struct tramp_frame *tramp_frame)
+{
+  struct frame_data *data;
+  struct frame_unwind *unwinder;
+  int i;
+
+  /* Check that the instruction sequence contains a sentinel.  */
+  for (i = 0; i < ARRAY_SIZE (tramp_frame->insn); i++)
+    {
+      if (tramp_frame->insn[i] == TRAMP_SENTINEL_INSN)
+       break;
+    }
+  gdb_assert (i < ARRAY_SIZE (tramp_frame->insn));
+  gdb_assert (tramp_frame->insn_size <= sizeof (tramp_frame->insn[0]));
+
+  data = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_data);
+  unwinder = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind);
+
+  data->tramp_frame = tramp_frame;
+  unwinder->type = SIGTRAMP_FRAME;
+  unwinder->unwind_data = data;
+  unwinder->sniffer = tramp_frame_sniffer;
+  unwinder->this_id = tramp_frame_this_id;
+  unwinder->prev_register = tramp_frame_prev_register;
+  frame_unwind_register_unwinder (gdbarch, unwinder);
+}
diff --git a/gdb/tramp-frame.h b/gdb/tramp-frame.h
new file mode 100644 (file)
index 0000000..54f29bb
--- /dev/null
@@ -0,0 +1,69 @@
+/* Signal trampoline unwinder, for GDB the GNU Debugger.
+
+   Copyright 2004 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 TRAMP_FRAME_H
+#define TRAMP_FRAME_H
+
+struct trad_frame;
+struct frame_info;
+struct trad_frame_cache;
+
+/* A trampoline consists of a small sequence of instructions placed at
+   an unspecified location in the inferior's address space.  The only
+   identifying attribute of the trampoline's address is that it does
+   not fall inside an object file's section.
+
+   The only way to identify a trampoline is to perform a brute force
+   examination of the instructions at and around the PC.
+
+   This module provides a convent interface for performing that
+   operation.  */
+
+/* A trampoline descriptor.  */
+
+/* Magic instruction that to mark the end of the signal trampoline
+   instruction sequence.  */
+#define TRAMP_SENTINEL_INSN ((LONGEST) -1)
+
+struct tramp_frame
+{
+  /* The trampoline's entire instruction sequence.  Search for this in
+     the inferior at or around the frame's PC.  It is assumed that the
+     PC is INSN_SIZE aligned, and that each element of TRAMP contains
+     one INSN_SIZE instruction.  It is also assumed that TRAMP[0]
+     contains the first instruction of the trampoline and hence the
+     address of the instruction matching TRAMP[0] is the trampoline's
+     "func" address.  The instruction sequence shall be terminated by
+     TRAMP_SENTINEL_INSN.  */
+  int insn_size;
+  ULONGEST insn[8];
+  /* Initialize a trad-frame cache corresponding to the tramp-frame.
+     FUNC is the address of the instruction TRAMP[0] in memory.  */
+  void (*init) (const struct tramp_frame *self,
+               struct frame_info *next_frame,
+               struct trad_frame_cache *this_cache,
+               CORE_ADDR func);
+};
+
+void tramp_frame_append (struct gdbarch *gdbarch,
+                        const struct tramp_frame *tramp);
+
+#endif
diff --git a/sim/frv/profile-fr450.c b/sim/frv/profile-fr450.c
new file mode 100644 (file)
index 0000000..27b9755
--- /dev/null
@@ -0,0 +1,607 @@
+/* frv simulator fr450 dependent profiling code.
+
+   Copyright (C) 2001, 2004 Free Software Foundation, Inc.
+   Contributed by Red Hat
+
+This file is part of the GNU simulators.
+
+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.
+
+*/
+#define WANT_CPU
+#define WANT_CPU_FRVBF
+
+#include "sim-main.h"
+#include "bfd.h"
+
+#if WITH_PROFILE_MODEL_P
+
+#include "profile.h"
+#include "profile-fr400.h"
+
+int
+frvbf_model_fr450_u_exec (SIM_CPU *cpu, const IDESC *idesc,
+                           int unit_num, int referenced)
+{
+  return idesc->timing->units[unit_num].done;
+}
+
+int
+frvbf_model_fr450_u_integer (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_GRi, INT in_GRj, INT out_GRk,
+                            INT out_ICCi_1)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_integer (cpu, idesc, unit_num, referenced,
+                                     in_GRi, in_GRj, out_GRk, out_ICCi_1);
+}
+
+int
+frvbf_model_fr450_u_imul (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj, INT out_GRk, INT out_ICCi_1)
+{
+  int cycles;
+
+  if (model_insn == FRV_INSN_MODEL_PASS_1)
+    {
+      /* Pass 1 is the same as for fr500.  */
+      return frvbf_model_fr500_u_imul (cpu, idesc, unit_num, referenced,
+                                      in_GRi, in_GRj, out_GRk, out_ICCi_1);
+    }
+
+  /* icc0-icc4 are the upper 4 fields of the CCR.  */
+  if (out_ICCi_1 >= 0)
+    out_ICCi_1 += 4;
+
+  /* GRk and IACCi_1 have a latency of 1 cycle.  */
+  cycles = idesc->timing->units[unit_num].done;
+  update_GRdouble_latency (cpu, out_GRk, cycles + 1);
+  update_CCR_latency (cpu, out_ICCi_1, cycles + 1);
+
+  return cycles;
+}
+
+int
+frvbf_model_fr450_u_idiv (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj, INT out_GRk, INT out_ICCi_1)
+{
+  int cycles;
+
+  if (model_insn == FRV_INSN_MODEL_PASS_1)
+    {
+      /* Pass 1 is the same as for fr500.  */
+      return frvbf_model_fr500_u_idiv (cpu, idesc, unit_num, referenced,
+                                      in_GRi, in_GRj, out_GRk, out_ICCi_1);
+    }
+
+  /* icc0-icc4 are the upper 4 fields of the CCR.  */
+  if (out_ICCi_1 >= 0)
+    out_ICCi_1 += 4;
+
+  /* GRk, ICCi_1 and the divider have a latency of 18 cycles  */
+  cycles = idesc->timing->units[unit_num].done;
+  update_GR_latency (cpu, out_GRk, cycles + 18);
+  update_CCR_latency (cpu, out_ICCi_1, cycles + 18);
+  update_idiv_resource_latency (cpu, 0, cycles + 18);
+
+  return cycles;
+}
+
+int
+frvbf_model_fr450_u_branch (SIM_CPU *cpu, const IDESC *idesc,
+                           int unit_num, int referenced,
+                           INT in_GRi, INT in_GRj,
+                           INT in_ICCi_2, INT in_ICCi_3)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_branch (cpu, idesc, unit_num, referenced,
+                                    in_GRi, in_GRj, in_ICCi_2, in_ICCi_3);
+}
+
+int
+frvbf_model_fr450_u_trap (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj,
+                         INT in_ICCi_2, INT in_FCCi_2)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_trap (cpu, idesc, unit_num, referenced,
+                                  in_GRi, in_GRj, in_ICCi_2, in_FCCi_2);
+}
+
+int
+frvbf_model_fr450_u_check (SIM_CPU *cpu, const IDESC *idesc,
+                          int unit_num, int referenced,
+                          INT in_ICCi_3, INT in_FCCi_3)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_check (cpu, idesc, unit_num, referenced,
+                                   in_ICCi_3, in_FCCi_3);
+}
+
+int
+frvbf_model_fr450_u_set_hilo (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT out_GRkhi, INT out_GRklo)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_set_hilo (cpu, idesc, unit_num, referenced,
+                                      out_GRkhi, out_GRklo);
+}
+
+int
+frvbf_model_fr450_u_gr_load (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_GRi, INT in_GRj,
+                            INT out_GRk, INT out_GRdoublek)
+{
+  int cycles;
+
+  if (model_insn == FRV_INSN_MODEL_PASS_1)
+    {
+      /* Pass 1 is the same as for fr500.  */
+      return frvbf_model_fr500_u_fr_load (cpu, idesc, unit_num, referenced,
+                                         in_GRi, in_GRj, out_GRk,
+                                         out_GRdoublek);
+    }
+
+  cycles = idesc->timing->units[unit_num].done;
+
+  /* The latency of GRk for a load will depend on how long it takes to retrieve
+     the the data from the cache or memory.  */
+  update_GR_latency_for_load (cpu, out_GRk, cycles);
+  update_GRdouble_latency_for_load (cpu, out_GRdoublek, cycles);
+
+  if (CGEN_ATTR_VALUE(idesc, idesc->attrs, CGEN_INSN_NON_EXCEPTING))
+    {
+      /* GNER has a latency of 2 cycles.  */
+      update_SPR_latency (cpu, GNER_FOR_GR (out_GRk), cycles + 2);
+      update_SPR_latency (cpu, GNER_FOR_GR (out_GRdoublek), cycles + 2);
+    }
+
+  return cycles;
+}
+
+int
+frvbf_model_fr450_u_gr_store (SIM_CPU *cpu, const IDESC *idesc,
+                             int unit_num, int referenced,
+                             INT in_GRi, INT in_GRj,
+                             INT in_GRk, INT in_GRdoublek)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_gr_store (cpu, idesc, unit_num, referenced,
+                                      in_GRi, in_GRj, in_GRk, in_GRdoublek);
+}
+
+int
+frvbf_model_fr450_u_fr_load (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_GRi, INT in_GRj,
+                            INT out_FRk, INT out_FRdoublek)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_fr_load (cpu, idesc, unit_num, referenced,
+                                     in_GRi, in_GRj, out_FRk, out_FRdoublek);
+}
+
+int
+frvbf_model_fr450_u_fr_store (SIM_CPU *cpu, const IDESC *idesc,
+                             int unit_num, int referenced,
+                             INT in_GRi, INT in_GRj,
+                             INT in_FRk, INT in_FRdoublek)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_fr_load (cpu, idesc, unit_num, referenced,
+                                     in_GRi, in_GRj, in_FRk, in_FRdoublek);
+}
+
+int
+frvbf_model_fr450_u_swap (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj, INT out_GRk)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_swap (cpu, idesc, unit_num, referenced,
+                                  in_GRi, in_GRj, out_GRk);
+}
+
+int
+frvbf_model_fr450_u_fr2gr (SIM_CPU *cpu, const IDESC *idesc,
+                          int unit_num, int referenced,
+                          INT in_FRk, INT out_GRj)
+{
+  int cycles;
+
+  if (model_insn == FRV_INSN_MODEL_PASS_1)
+    {
+      /* Pass 1 is the same as for fr400.  */
+      return frvbf_model_fr500_u_fr2gr (cpu, idesc, unit_num, referenced,
+                                       in_FRk, out_GRj);
+    }
+
+  /* The latency of GRj is 1 cycle.  */
+  cycles = idesc->timing->units[unit_num].done;
+  update_GR_latency (cpu, out_GRj, cycles + 1);
+
+  return cycles;
+}
+
+int
+frvbf_model_fr450_u_spr2gr (SIM_CPU *cpu, const IDESC *idesc,
+                          int unit_num, int referenced,
+                          INT in_spr, INT out_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_spr2gr (cpu, idesc, unit_num, referenced,
+                                    in_spr, out_GRj);
+}
+
+int
+frvbf_model_fr450_u_gr2fr (SIM_CPU *cpu, const IDESC *idesc,
+                          int unit_num, int referenced,
+                          INT in_GRj, INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_gr2fr (cpu, idesc, unit_num, referenced,
+                                   in_GRj, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_gr2spr (SIM_CPU *cpu, const IDESC *idesc,
+                           int unit_num, int referenced,
+                           INT in_GRj, INT out_spr)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_gr2spr (cpu, idesc, unit_num, referenced,
+                                    in_GRj, out_spr);
+}
+
+int
+frvbf_model_fr450_u_media_1 (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_FRi, INT in_FRj,
+                            INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_1 (cpu, idesc, unit_num, referenced,
+                                     in_FRi, in_FRj, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_1_quad (SIM_CPU *cpu, const IDESC *idesc,
+                                 int unit_num, int referenced,
+                                 INT in_FRi, INT in_FRj,
+                                 INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_1_quad (cpu, idesc, unit_num, referenced,
+                                          in_FRi, in_FRj, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_hilo (SIM_CPU *cpu, const IDESC *idesc,
+                               int unit_num, int referenced,
+                               INT out_FRkhi, INT out_FRklo)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_hilo (cpu, idesc, unit_num, referenced,
+                                        out_FRkhi, out_FRklo);
+}
+
+int
+frvbf_model_fr450_u_media_2 (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_FRi, INT in_FRj,
+                            INT out_ACC40Sk, INT out_ACC40Uk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_2 (cpu, idesc, unit_num, referenced,
+                                     in_FRi, in_FRj, out_ACC40Sk,
+                                     out_ACC40Uk);
+}
+
+int
+frvbf_model_fr450_u_media_2_quad (SIM_CPU *cpu, const IDESC *idesc,
+                                 int unit_num, int referenced,
+                                 INT in_FRi, INT in_FRj,
+                                 INT out_ACC40Sk, INT out_ACC40Uk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_2_quad (cpu, idesc, unit_num, referenced,
+                                          in_FRi, in_FRj, out_ACC40Sk,
+                                          out_ACC40Uk);
+}
+
+int
+frvbf_model_fr450_u_media_2_acc (SIM_CPU *cpu, const IDESC *idesc,
+                                int unit_num, int referenced,
+                                INT in_ACC40Si, INT out_ACC40Sk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_2_acc (cpu, idesc, unit_num, referenced,
+                                         in_ACC40Si, out_ACC40Sk);
+}
+
+int
+frvbf_model_fr450_u_media_2_acc_dual (SIM_CPU *cpu, const IDESC *idesc,
+                                     int unit_num, int referenced,
+                                     INT in_ACC40Si, INT out_ACC40Sk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_2_acc_dual (cpu, idesc, unit_num,
+                                              referenced, in_ACC40Si,
+                                              out_ACC40Sk);
+}
+
+int
+frvbf_model_fr450_u_media_2_add_sub (SIM_CPU *cpu, const IDESC *idesc,
+                                    int unit_num, int referenced,
+                                    INT in_ACC40Si, INT out_ACC40Sk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_2_add_sub (cpu, idesc, unit_num,
+                                             referenced, in_ACC40Si,
+                                             out_ACC40Sk);
+}
+
+int
+frvbf_model_fr450_u_media_2_add_sub_dual (SIM_CPU *cpu, const IDESC *idesc,
+                                         int unit_num, int referenced,
+                                         INT in_ACC40Si, INT out_ACC40Sk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_2_add_sub_dual (cpu, idesc, unit_num,
+                                                  referenced, in_ACC40Si,
+                                                  out_ACC40Sk);
+}
+
+int
+frvbf_model_fr450_u_media_3 (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_FRi, INT in_FRj,
+                            INT out_FRk)
+{
+  /* Modelling is the same as media unit 1.  */
+  return frvbf_model_fr450_u_media_1 (cpu, idesc, unit_num, referenced,
+                                     in_FRi, in_FRj, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_3_dual (SIM_CPU *cpu, const IDESC *idesc,
+                                 int unit_num, int referenced,
+                                 INT in_FRi, INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_3_dual (cpu, idesc, unit_num, referenced,
+                                          in_FRi, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_3_quad (SIM_CPU *cpu, const IDESC *idesc,
+                                 int unit_num, int referenced,
+                                 INT in_FRi, INT in_FRj,
+                                 INT out_FRk)
+{
+  /* Modelling is the same as media unit 1.  */
+  return frvbf_model_fr450_u_media_1_quad (cpu, idesc, unit_num, referenced,
+                                          in_FRi, in_FRj, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_4 (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_ACC40Si, INT in_FRj,
+                            INT out_ACC40Sk, INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_4 (cpu, idesc, unit_num, referenced,
+                                     in_ACC40Si, in_FRj,
+                                     out_ACC40Sk, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_4_accg (SIM_CPU *cpu, const IDESC *idesc,
+                                 int unit_num, int referenced,
+                                 INT in_ACCGi, INT in_FRinti,
+                                 INT out_ACCGk, INT out_FRintk)
+{
+  /* Modelling is the same as media-4 unit except use accumulator guards
+     as input instead of accumulators.  */
+  return frvbf_model_fr450_u_media_4 (cpu, idesc, unit_num, referenced,
+                                     in_ACCGi, in_FRinti,
+                                     out_ACCGk, out_FRintk);
+}
+
+int
+frvbf_model_fr450_u_media_4_acc_dual (SIM_CPU *cpu, const IDESC *idesc,
+                                     int unit_num, int referenced,
+                                     INT in_ACC40Si, INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_4_acc_dual (cpu, idesc, unit_num,
+                                              referenced, in_ACC40Si,
+                                              out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_4_mclracca (SIM_CPU *cpu, const IDESC *idesc,
+                                     int unit_num, int referenced)
+{
+  int cycles;
+  int acc;
+  FRV_PROFILE_STATE *ps;
+
+  if (model_insn == FRV_INSN_MODEL_PASS_1)
+    return 0;
+
+  /* The preprocessing can execute right away.  */
+  cycles = idesc->timing->units[unit_num].done;
+
+  ps = CPU_PROFILE_STATE (cpu);
+
+  /* The post processing must wait for any pending ACC writes.  */
+  ps->post_wait = cycles;
+  for (acc = 0; acc < 4; acc++)
+    post_wait_for_ACC (cpu, acc);
+  for (acc = 8; acc < 12; acc++)
+    post_wait_for_ACC (cpu, acc);
+
+  for (acc = 0; acc < 4; acc++)
+    {
+      update_ACC_latency (cpu, acc, ps->post_wait);
+      update_ACC_ptime (cpu, acc, 2);
+    }
+  for (acc = 8; acc < 12; acc++)
+    {
+      update_ACC_latency (cpu, acc, ps->post_wait);
+      update_ACC_ptime (cpu, acc, 2);
+    }
+
+  return cycles;
+}
+
+int
+frvbf_model_fr450_u_media_6 (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_FRi, INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_6 (cpu, idesc, unit_num, referenced,
+                                     in_FRi, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_7 (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced,
+                            INT in_FRinti, INT in_FRintj,
+                            INT out_FCCk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_7 (cpu, idesc, unit_num, referenced,
+                                     in_FRinti, in_FRintj, out_FCCk);
+}
+
+int
+frvbf_model_fr450_u_media_dual_expand (SIM_CPU *cpu, const IDESC *idesc,
+                                      int unit_num, int referenced,
+                                      INT in_FRi,
+                                      INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_dual_expand (cpu, idesc, unit_num,
+                                               referenced, in_FRi, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_media_dual_htob (SIM_CPU *cpu, const IDESC *idesc,
+                                    int unit_num, int referenced,
+                                    INT in_FRj,
+                                    INT out_FRk)
+{
+  /* Modelling for this unit is the same as for fr400.  */
+  return frvbf_model_fr400_u_media_dual_htob (cpu, idesc, unit_num,
+                                             referenced, in_FRj, out_FRk);
+}
+
+int
+frvbf_model_fr450_u_ici (SIM_CPU *cpu, const IDESC *idesc,
+                        int unit_num, int referenced,
+                        INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_ici (cpu, idesc, unit_num, referenced,
+                                 in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_dci (SIM_CPU *cpu, const IDESC *idesc,
+                        int unit_num, int referenced,
+                        INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_dci (cpu, idesc, unit_num, referenced,
+                                 in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_dcf (SIM_CPU *cpu, const IDESC *idesc,
+                        int unit_num, int referenced,
+                        INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_dcf (cpu, idesc, unit_num, referenced,
+                                 in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_icpl (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_icpl (cpu, idesc, unit_num, referenced,
+                                  in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_dcpl (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_dcpl (cpu, idesc, unit_num, referenced,
+                                  in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_icul (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_icul (cpu, idesc, unit_num, referenced,
+                                  in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_dcul (SIM_CPU *cpu, const IDESC *idesc,
+                         int unit_num, int referenced,
+                         INT in_GRi, INT in_GRj)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_dcul (cpu, idesc, unit_num, referenced,
+                                  in_GRi, in_GRj);
+}
+
+int
+frvbf_model_fr450_u_barrier (SIM_CPU *cpu, const IDESC *idesc,
+                            int unit_num, int referenced)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_barrier (cpu, idesc, unit_num, referenced);
+}
+
+int
+frvbf_model_fr450_u_membar (SIM_CPU *cpu, const IDESC *idesc,
+                           int unit_num, int referenced)
+{
+  /* Modelling for this unit is the same as for fr500.  */
+  return frvbf_model_fr500_u_membar (cpu, idesc, unit_num, referenced);
+}
+
+#endif /* WITH_PROFILE_MODEL_P */
diff --git a/sim/testsuite/sim/frv/mqlclrhs.cgs b/sim/testsuite/sim/frv/mqlclrhs.cgs
new file mode 100644 (file)
index 0000000..5e090b0
--- /dev/null
@@ -0,0 +1,74 @@
+# frv testcase for mqlclrhs $FRi,$FRj,$FRj
+# mach: fr450
+
+       .include "testutils.inc"
+
+       start
+
+       .global mqlclrhs
+mqlclrhs:
+       set_fr_iimmed   0x1000,0x2000,fr4
+       set_fr_iimmed   0xe800,0xd800,fr5
+       set_fr_iimmed   0x0800,0x0800,fr6
+       set_fr_iimmed   0x0800,0x0800,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x1000,0x2000,fr8
+       test_fr_limmed  0xe800,0xd800,fr9
+
+       set_fr_iimmed   0x1000,0x2000,fr4
+       set_fr_iimmed   0xe800,0xd800,fr5
+       set_fr_iimmed   0xf800,0xf800,fr6
+       set_fr_iimmed   0xf800,0xf800,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0xf000,0xe000,fr8
+       test_fr_limmed  0x1800,0x2800,fr9
+
+       set_fr_iimmed   0x1000,0x1000,fr4
+       set_fr_iimmed   0x1000,0x1000,fr5
+       set_fr_iimmed   0xf000,0xf800,fr6
+       set_fr_iimmed   0x0800,0x1000,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x0000,0xf000,fr8
+       test_fr_limmed  0x1000,0x0000,fr9
+
+       set_fr_iimmed   0xf000,0xf000,fr4
+       set_fr_iimmed   0xf000,0xf000,fr5
+       set_fr_iimmed   0xf000,0xf800,fr6
+       set_fr_iimmed   0x0800,0x1000,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x0000,0x1000,fr8
+       test_fr_limmed  0xf000,0x0000,fr9
+
+       set_fr_iimmed   0x8000,0x8000,fr4
+       set_fr_iimmed   0x8000,0x8000,fr5
+       set_fr_iimmed   0x8000,0x7fff,fr6
+       set_fr_iimmed   0x8001,0x0000,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x0000,0x8000,fr8
+       test_fr_limmed  0x7fff,0x8000,fr9
+
+       set_fr_iimmed   0x7fff,0x7fff,fr4
+       set_fr_iimmed   0x7fff,0x7fff,fr5
+       set_fr_iimmed   0x8000,0x7fff,fr6
+       set_fr_iimmed   0x8001,0x0000,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x0000,0x0000,fr8
+       test_fr_limmed  0x0000,0x7fff,fr9
+
+       set_fr_iimmed   0x8001,0x8001,fr4
+       set_fr_iimmed   0x8001,0x8001,fr5
+       set_fr_iimmed   0x8000,0x7fff,fr6
+       set_fr_iimmed   0x8001,0x0000,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x0000,0x0000,fr8
+       test_fr_limmed  0x0000,0x8001,fr9
+
+       set_fr_iimmed   0x8000,0x8000,fr4
+       set_fr_iimmed   0x0001,0xffff,fr5
+       set_fr_iimmed   0x0001,0xffff,fr6
+       set_fr_iimmed   0x8000,0x8000,fr7
+       mqlclrhs        fr4,fr6,fr8
+       test_fr_limmed  0x8000,0x7fff,fr8
+       test_fr_limmed  0x0000,0x0000,fr9
+
+       pass
diff --git a/sim/testsuite/sim/frv/mqlmths.cgs b/sim/testsuite/sim/frv/mqlmths.cgs
new file mode 100644 (file)
index 0000000..d416d65
--- /dev/null
@@ -0,0 +1,74 @@
+# frv testcase for mqlmths $FRi,$FRj,$FRj
+# mach: fr450
+
+       .include "testutils.inc"
+
+       start
+
+       .global mqlmths
+mqlmths:
+       set_fr_iimmed   0x1000,0x2000,fr4
+       set_fr_iimmed   0xe800,0xd800,fr5
+       set_fr_iimmed   0x0800,0x0800,fr6
+       set_fr_iimmed   0x0800,0x0800,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0x0800,0x0800,fr8
+       test_fr_limmed  0xf800,0xf800,fr9
+
+       set_fr_iimmed   0x1000,0x2000,fr4
+       set_fr_iimmed   0xe800,0xd800,fr5
+       set_fr_iimmed   0xf800,0xf800,fr6
+       set_fr_iimmed   0xf800,0xf800,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0xf800,0xf800,fr8
+       test_fr_limmed  0x0800,0x0800,fr9
+
+       set_fr_iimmed   0x1000,0x1000,fr4
+       set_fr_iimmed   0x1000,0x1000,fr5
+       set_fr_iimmed   0xe800,0xf800,fr6
+       set_fr_iimmed   0x0800,0x1800,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0x1000,0xf800,fr8
+       test_fr_limmed  0x0800,0x1000,fr9
+
+       set_fr_iimmed   0xf000,0xf000,fr4
+       set_fr_iimmed   0xf000,0xf000,fr5
+       set_fr_iimmed   0xe800,0xf800,fr6
+       set_fr_iimmed   0x0800,0x1800,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0xf000,0x0800,fr8
+       test_fr_limmed  0xf800,0xf000,fr9
+
+       set_fr_iimmed   0x8000,0x8000,fr4
+       set_fr_iimmed   0x8000,0x8000,fr5
+       set_fr_iimmed   0x8000,0x7fff,fr6
+       set_fr_iimmed   0x8001,0x0000,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0x7fff,0x8001,fr8
+       test_fr_limmed  0x7fff,0x0000,fr9
+
+       set_fr_iimmed   0x7fff,0x7fff,fr4
+       set_fr_iimmed   0x7fff,0x7fff,fr5
+       set_fr_iimmed   0x8000,0x7fff,fr6
+       set_fr_iimmed   0x8001,0x0000,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0x7fff,0x7fff,fr8
+       test_fr_limmed  0x8001,0x0000,fr9
+
+       set_fr_iimmed   0x8001,0x8001,fr4
+       set_fr_iimmed   0x8001,0x8001,fr5
+       set_fr_iimmed   0x8000,0x7fff,fr6
+       set_fr_iimmed   0x8001,0x0000,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0x8001,0x8001,fr8
+       test_fr_limmed  0x7fff,0x0000,fr9
+
+       set_fr_iimmed   0x8000,0x8000,fr4
+       set_fr_iimmed   0x0001,0xffff,fr5
+       set_fr_iimmed   0x0001,0xffff,fr6
+       set_fr_iimmed   0x8000,0x8000,fr7
+       mqlmths         fr4,fr6,fr8
+       test_fr_limmed  0xffff,0x0001,fr8
+       test_fr_limmed  0x0001,0xffff,fr9
+
+       pass
diff --git a/sim/testsuite/sim/frv/mqsllhi.cgs b/sim/testsuite/sim/frv/mqsllhi.cgs
new file mode 100644 (file)
index 0000000..21379f2
--- /dev/null
@@ -0,0 +1,40 @@
+# frv testcase for mqsllhi $FRi,#u6,$FRj
+# mach: fr450
+
+       .include "testutils.inc"
+
+       start
+
+       .global mqsllhi
+mqsllhi:
+       set_fr_iimmed   0x0001,0x0002,fr4
+       set_fr_iimmed   0x0003,0x0004,fr5
+       mqsllhi         fr4,#1,fr6
+       test_fr_limmed  0x0002,0x0004,fr6
+       test_fr_limmed  0x0006,0x0008,fr7
+
+       set_fr_iimmed   0xffff,0xfffe,fr4
+       set_fr_iimmed   0xfffc,0xfff8,fr5
+       mqsllhi         fr4,#1,fr6
+       test_fr_limmed  0xfffe,0xfffc,fr6
+       test_fr_limmed  0xfff8,0xfff0,fr7
+
+       set_fr_iimmed   0xffff,0xfffe,fr4
+       set_fr_iimmed   0xfffc,0xfff8,fr5
+       mqsllhi         fr4,#12,fr6
+       test_fr_limmed  0xf000,0xe000,fr6
+       test_fr_limmed  0xc000,0x8000,fr7
+
+       set_fr_iimmed   0x1234,0x5678,fr4
+       set_fr_iimmed   0x9abc,0xdef0,fr5
+       mqsllhi         fr4,#12,fr6
+       test_fr_limmed  0x4000,0x8000,fr6
+       test_fr_limmed  0xc000,0x0000,fr7
+
+       set_fr_iimmed   0x1234,0x5678,fr4
+       set_fr_iimmed   0x9abc,0xdef0,fr5
+       mqsllhi         fr4,#16,fr6
+       test_fr_limmed  0x1234,0x5678,fr6
+       test_fr_limmed  0x9abc,0xdef0,fr7
+
+       pass
diff --git a/sim/testsuite/sim/frv/mqsrahi.cgs b/sim/testsuite/sim/frv/mqsrahi.cgs
new file mode 100644 (file)
index 0000000..1d30179
--- /dev/null
@@ -0,0 +1,40 @@
+# frv testcase for mqsrahi $FRi,#u6,$FRj
+# mach: fr450
+
+       .include "testutils.inc"
+
+       start
+
+       .global mqsrahi
+mqsrahi:
+       set_fr_iimmed   0x0001,0x0002,fr4
+       set_fr_iimmed   0x0003,0x0004,fr5
+       mqsrahi         fr4,#1,fr6
+       test_fr_limmed  0x0000,0x0001,fr6
+       test_fr_limmed  0x0001,0x0002,fr7
+
+       set_fr_iimmed   0xffff,0xfffe,fr4
+       set_fr_iimmed   0xfffc,0xfff8,fr5
+       mqsrahi         fr4,#1,fr6
+       test_fr_limmed  0xffff,0xffff,fr6
+       test_fr_limmed  0xfffe,0xfffc,fr7
+
+       set_fr_iimmed   0x8000,0xc000,fr4
+       set_fr_iimmed   0xe000,0xf000,fr5
+       mqsrahi         fr4,#12,fr6
+       test_fr_limmed  0xfff8,0xfffc,fr6
+       test_fr_limmed  0xfffe,0xffff,fr7
+
+       set_fr_iimmed   0x1234,0x5678,fr4
+       set_fr_iimmed   0x9abc,0xdef0,fr5
+       mqsrahi         fr4,#12,fr6
+       test_fr_limmed  0x0001,0x0005,fr6
+       test_fr_limmed  0xfff9,0xfffd,fr7
+
+       set_fr_iimmed   0x1234,0x5678,fr4
+       set_fr_iimmed   0x9abc,0xdef0,fr5
+       mqsrahi         fr4,#16,fr6
+       test_fr_limmed  0x1234,0x5678,fr6
+       test_fr_limmed  0x9abc,0xdef0,fr7
+
+       pass