]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch 'nickrob-
authornobody <>
Sat, 19 Aug 2006 15:15:19 +0000 (15:15 +0000)
committernobody <>
Sat, 19 Aug 2006 15:15:19 +0000 (15:15 +0000)
async-20060513-branch'.

Cherrypick from master 2006-08-19 15:15:18 UTC Daniel Jacobowitz <drow@false.org> 'gdb/':
    gdb/alphaobsd-tdep.c
    gdb/amd64-linux-tdep.h
    gdb/arm-linux-tdep.h
    gdb/armbsd-tdep.c
    gdb/armobsd-tdep.c
    gdb/config/alpha/obsd.mt
    gdb/config/arm/obsd.mt
    gdb/config/sparc/embed.mt
    gdb/gdbserver/win32-i386-low.c
    gdb/regformats/reg-x86-64-linux.dat
    gdb/testsuite/gdb.arch/i386-size.c
    gdb/testsuite/gdb.arch/i386-size.exp
    gdb/testsuite/gdb.base/ifelse.exp
    gdb/testsuite/gdb.base/step-bt.c
    gdb/testsuite/gdb.base/step-bt.exp
    gdb/testsuite/gdb.base/trace-commands.exp
    gdb/testsuite/gdb.cp/ref-params.cc
    gdb/testsuite/gdb.cp/ref-params.exp

18 files changed:
gdb/alphaobsd-tdep.c [new file with mode: 0644]
gdb/amd64-linux-tdep.h [new file with mode: 0644]
gdb/arm-linux-tdep.h [new file with mode: 0644]
gdb/armbsd-tdep.c [new file with mode: 0644]
gdb/armobsd-tdep.c [new file with mode: 0644]
gdb/config/alpha/obsd.mt [new file with mode: 0644]
gdb/config/arm/obsd.mt [new file with mode: 0644]
gdb/config/sparc/embed.mt [new file with mode: 0644]
gdb/gdbserver/win32-i386-low.c [new file with mode: 0644]
gdb/regformats/reg-x86-64-linux.dat [new file with mode: 0644]
gdb/testsuite/gdb.arch/i386-size.c [new file with mode: 0644]
gdb/testsuite/gdb.arch/i386-size.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/ifelse.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/step-bt.c [new file with mode: 0644]
gdb/testsuite/gdb.base/step-bt.exp [new file with mode: 0644]
gdb/testsuite/gdb.base/trace-commands.exp [new file with mode: 0644]
gdb/testsuite/gdb.cp/ref-params.cc [new file with mode: 0644]
gdb/testsuite/gdb.cp/ref-params.exp [new file with mode: 0644]

diff --git a/gdb/alphaobsd-tdep.c b/gdb/alphaobsd-tdep.c
new file mode 100644 (file)
index 0000000..58b4f8a
--- /dev/null
@@ -0,0 +1,137 @@
+/* Target-dependent code for OpenBSD/alpha.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "gdbcore.h"
+#include "osabi.h"
+
+#include "obsd-tdep.h"
+#include "alpha-tdep.h"
+#include "alphabsd-tdep.h"
+#include "solib-svr4.h"
+
+/* Signal trampolines.  */
+
+/* The OpenBSD kernel maps the signal trampoline at some random
+   location in user space, which means that the traditional BSD way of
+   detecting it won't work.
+
+   The signal trampoline will be mapped at an address that is page
+   aligned.  We recognize the signal trampoline by looking for the
+   sigreturn system call.  */
+
+static const int alphaobsd_page_size = 8192;
+
+static LONGEST
+alphaobsd_sigtramp_offset (CORE_ADDR pc)
+{
+  return (pc & (alphaobsd_page_size - 1));
+}
+
+static int
+alphaobsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
+{
+  CORE_ADDR start_pc = (pc & ~(alphaobsd_page_size - 1));
+  unsigned insn;
+
+  if (name)
+    return 0;
+
+  /* Check for "".  */
+  insn = alpha_read_insn (start_pc + 5 * ALPHA_INSN_SIZE);
+  if (insn != 0x201f0067)
+    return 0;
+
+  /* Check for "".  */
+  insn = alpha_read_insn (start_pc + 6 * ALPHA_INSN_SIZE);
+  if (insn != 0x00000083)
+    return 0;
+
+  return 1;
+}
+
+static CORE_ADDR
+alphaobsd_sigcontext_addr (struct frame_info *next_frame)
+{
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+  if (alphaobsd_sigtramp_offset (pc) < 3 * ALPHA_INSN_SIZE)
+    {
+      /* On entry, a pointer the `struct sigcontext' is passed in %a2.  */
+      return frame_unwind_register_unsigned (next_frame, ALPHA_A0_REGNUM + 2);
+    }
+  else if (alphaobsd_sigtramp_offset (pc) < 4 * ALPHA_INSN_SIZE)
+    {
+      /* It is stored on the stack Before calling the signal handler.  */
+      CORE_ADDR sp;
+      sp = frame_unwind_register_unsigned (next_frame, ALPHA_SP_REGNUM);
+      return get_frame_memory_unsigned (next_frame, sp, 8);
+    }
+  else
+    {
+      /* It is reloaded into %a0 for the sigreturn(2) call.  */
+      return frame_unwind_register_unsigned (next_frame, ALPHA_A0_REGNUM);
+    }
+}
+\f
+
+static void
+alphaobsd_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* Hook into the DWARF CFI frame unwinder.  */
+  alpha_dwarf2_init_abi (info, gdbarch);
+
+  /* Hook into the MDEBUG frame unwinder.  */
+  alpha_mdebug_init_abi (info, gdbarch);
+
+  /* OpenBSD/alpha 3.0 and earlier does not provide single step
+     support via ptrace(2); use software single-stepping for now.  */
+  set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
+
+  /* OpenBSD/alpha has SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_lp64_fetch_link_map_offsets);
+  set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
+
+  tdep->dynamic_sigtramp_offset = alphaobsd_sigtramp_offset;
+  tdep->pc_in_sigtramp = alphaobsd_pc_in_sigtramp;
+  tdep->sigcontext_addr = alphaobsd_sigcontext_addr;
+
+  tdep->jb_pc = 2;
+  tdep->jb_elt_size = 8;
+
+  set_gdbarch_regset_from_core_section
+    (gdbarch, alphanbsd_regset_from_core_section);
+}
+\f
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_alphaobsd_tdep (void);
+
+void
+_initialize_alphaobsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
+                          alphaobsd_init_abi);
+}
diff --git a/gdb/amd64-linux-tdep.h b/gdb/amd64-linux-tdep.h
new file mode 100644 (file)
index 0000000..4a5778d
--- /dev/null
@@ -0,0 +1,36 @@
+/* Target-dependent code for GNU/Linux AMD64.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#ifndef AMD64_LINUX_TDEP_H
+#define AMD64_LINUX_TDEP_H
+
+/* Like for i386 GNU/Linux, there is an extra "register"
+   used to control syscall restarting.  */
+
+/* Register number for the "orig_rax" register.  If this register
+   contains a value >= 0 it is interpreted as the system call number
+   that the kernel is supposed to restart.  */
+#define AMD64_LINUX_ORIG_RAX_REGNUM (AMD64_MXCSR_REGNUM + 1)
+
+/* Total number of registers for GNU/Linux.  */
+#define AMD64_LINUX_NUM_REGS (AMD64_LINUX_ORIG_RAX_REGNUM + 1)
+
+#endif /* amd64-linux-tdep.h */
diff --git a/gdb/arm-linux-tdep.h b/gdb/arm-linux-tdep.h
new file mode 100644 (file)
index 0000000..31d6ba0
--- /dev/null
@@ -0,0 +1,62 @@
+/* GNU/Linux on ARM target support, prototypes.
+
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+struct regset;
+struct regcache;
+
+#define                ARM_CPSR_REGNUM         16
+
+#define ARM_LINUX_SIZEOF_NWFPE (8 * FP_REGISTER_SIZE \
+                               + 2 * INT_REGISTER_SIZE \
+                               + 8 + INT_REGISTER_SIZE)
+
+/* Support for register format used by the NWFPE FPA emulator.  Each
+   register takes three words, where either the first one, two, or
+   three hold a single, double, or extended precision value (depending
+   on the corresponding tag).  The register set is eight registers,
+   followed by the fpsr and fpcr, followed by eight tag bytes, and a
+   final word flag which indicates whether NWFPE has been
+   initialized.  */
+
+#define NWFPE_FPSR_OFFSET (8 * FP_REGISTER_SIZE)
+#define NWFPE_FPCR_OFFSET (NWFPE_FPSR_OFFSET + INT_REGISTER_SIZE)
+#define NWFPE_TAGS_OFFSET (NWFPE_FPCR_OFFSET + INT_REGISTER_SIZE)
+#define NWFPE_INITFLAG_OFFSET (NWFPE_TAGS_OFFSET + 8)
+
+void arm_linux_supply_gregset (const struct regset *regset,
+                              struct regcache *regcache,
+                              int regnum, const void *gregs_buf, size_t len);
+void arm_linux_collect_gregset (const struct regset *regset,
+                               const struct regcache *regcache,
+                               int regnum, void *gregs_buf, size_t len);
+
+void supply_nwfpe_register (struct regcache *regcache, int regno,
+                           const gdb_byte *regs);
+void collect_nwfpe_register (const struct regcache *regcache, int regno,
+                            gdb_byte *regs);
+
+void arm_linux_supply_nwfpe (const struct regset *regset,
+                            struct regcache *regcache,
+                            int regnum, const void *regs_buf, size_t len);
+void arm_linux_collect_nwfpe (const struct regset *regset,
+                             const struct regcache *regcache,
+                             int regnum, void *regs_buf, size_t len);
diff --git a/gdb/armbsd-tdep.c b/gdb/armbsd-tdep.c
new file mode 100644 (file)
index 0000000..95ecd42
--- /dev/null
@@ -0,0 +1,129 @@
+/* Target-dependent code for ARM BSD's.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "regset.h"
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "arm-tdep.h"
+
+/* Core file support.  */
+
+/* Sizeof `struct reg' in <machine/reg.h>.  */
+#define ARMBSD_SIZEOF_GREGS    (17 * 4)
+
+/* Sizeof `struct fpreg' in <machine/reg.h.  */
+#define ARMBSD_SIZEOF_FPREGS   ((1 + (8 * 3)) * 4)
+
+int
+armbsd_fpreg_offset (int regnum)
+{
+  if (regnum == ARM_FPS_REGNUM)
+    return 0;
+
+  return 4 + (regnum - ARM_F0_REGNUM) * 12;
+}
+
+/* Supply register REGNUM from the buffer specified by FPREGS and LEN
+   in the floating-point register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+static void
+armbsd_supply_fpregset (const struct regset *regset,
+                       struct regcache *regcache,
+                       int regnum, const void *fpregs, size_t len)
+{
+  const gdb_byte *regs = fpregs;
+  int i;
+
+  gdb_assert (len >= ARMBSD_SIZEOF_FPREGS);
+
+  for (i = ARM_F0_REGNUM; i <= ARM_FPS_REGNUM; i++)
+    {
+      if (regnum == i || regnum == -1)
+       regcache_raw_supply (regcache, i, regs + armbsd_fpreg_offset (i));
+    }
+}
+
+/* Supply register REGNUM from the buffer specified by GREGS and LEN
+   in the general-purpose register set REGSET to register cache
+   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
+
+static void
+armbsd_supply_gregset (const struct regset *regset,
+                      struct regcache *regcache,
+                      int regnum, const void *gregs, size_t len)
+{
+  const gdb_byte *regs = gregs;
+  int i;
+
+  gdb_assert (len >= ARMBSD_SIZEOF_GREGS);
+
+  for (i = ARM_A1_REGNUM; i <= ARM_PC_REGNUM; i++)
+    {
+      if (regnum == i || regnum == -1)
+       regcache_raw_supply (regcache, i, regs + i * 4);
+    }
+
+  if (regnum == ARM_PS_REGNUM || regnum == -1)
+    regcache_raw_supply (regcache, i, regs + 16 * 4);
+
+  if (len >= ARMBSD_SIZEOF_GREGS + ARMBSD_SIZEOF_FPREGS)
+    {
+      regs += ARMBSD_SIZEOF_GREGS;
+      len -= ARMBSD_SIZEOF_GREGS;
+      armbsd_supply_fpregset (regset, regcache, regnum, regs, len);
+    }
+}
+
+/* ARM register sets.  */
+
+static struct regset armbsd_gregset =
+{
+  NULL,
+  armbsd_supply_gregset
+};
+
+static struct regset armbsd_fpregset =
+{
+  NULL,
+  armbsd_supply_fpregset
+};
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+const struct regset *
+armbsd_regset_from_core_section (struct gdbarch *gdbarch,
+                                const char *sect_name, size_t sect_size)
+{
+  if (strcmp (sect_name, ".reg") == 0 && sect_size >= ARMBSD_SIZEOF_GREGS)
+    return &armbsd_gregset;
+
+  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ARMBSD_SIZEOF_FPREGS)
+    return &armbsd_fpregset;
+
+  return NULL;
+}
diff --git a/gdb/armobsd-tdep.c b/gdb/armobsd-tdep.c
new file mode 100644 (file)
index 0000000..cc769b7
--- /dev/null
@@ -0,0 +1,120 @@
+/* Target-dependent code for OpenBSD/arm.
+
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "osabi.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+
+#include "gdb_string.h"
+
+#include "obsd-tdep.h"
+#include "arm-tdep.h"
+#include "solib-svr4.h"
+
+/* Signal trampolines.  */
+
+static void
+armobsd_sigframe_init (const struct tramp_frame *self,
+                      struct frame_info *next_frame,
+                      struct trad_frame_cache *cache,
+                      CORE_ADDR func)
+{
+  CORE_ADDR sp, sigcontext_addr, addr;
+  int regnum;
+
+  /* We find the appropriate instance of `struct sigcontext' at a
+     fixed offset in the signal frame.  */
+  sp = frame_unwind_register_signed (next_frame, ARM_SP_REGNUM);
+  sigcontext_addr = sp + 16;
+
+  /* PC.  */
+  trad_frame_set_reg_addr (cache, ARM_PC_REGNUM, sigcontext_addr + 76);
+
+  /* GPRs.  */
+  for (regnum = ARM_A1_REGNUM, addr = sigcontext_addr + 12;
+       regnum <= ARM_LR_REGNUM; regnum++, addr += 4)
+    trad_frame_set_reg_addr (cache, regnum, addr);
+
+  trad_frame_set_id (cache, frame_id_build (sp, func));
+}
+
+static const struct tramp_frame armobsd_sigframe =
+{
+  SIGTRAMP_FRAME,
+  4,
+  {
+    { 0xe28d0010, -1 },                /* add     r0, sp, #16 */
+    { 0xef000067, -1 },                /* swi     SYS_sigreturn */
+    { 0xef000001, -1 },                /* swi     SYS_exit */
+    { 0xeafffffc, -1 },                /* b       . - 8 */
+    { TRAMP_SENTINEL_INSN, -1 }
+  },
+  armobsd_sigframe_init
+};
+\f
+
+static void
+armobsd_init_abi (struct gdbarch_info info,
+                 struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (tdep->fp_model == ARM_FLOAT_AUTO)
+    tdep->fp_model = ARM_FLOAT_SOFT_VFP;
+
+  tramp_frame_prepend_unwinder (gdbarch, &armobsd_sigframe);
+
+  /* OpenBSD/arm uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+  set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
+
+  tdep->jb_pc = 24;
+  tdep->jb_elt_size = 4;
+
+  set_gdbarch_regset_from_core_section
+    (gdbarch, armbsd_regset_from_core_section);
+
+  /* OpenBSD/arm uses -fpcc-struct-return by default.  */
+  tdep->struct_return = pcc_struct_return;
+}
+\f
+
+static enum gdb_osabi
+armobsd_core_osabi_sniffer (bfd *abfd)
+{
+  if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
+    return GDB_OSABI_OPENBSD_ELF;
+
+  return GDB_OSABI_UNKNOWN;
+}
+
+void
+_initialize_armobsd_tdep (void)
+{
+  /* BFD doesn't set a flavour for NetBSD style a.out core files.  */
+  gdbarch_register_osabi_sniffer (bfd_arch_arm, bfd_target_unknown_flavour,
+                                  armobsd_core_osabi_sniffer);
+
+  gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_OPENBSD_ELF,
+                         armobsd_init_abi);
+}
diff --git a/gdb/config/alpha/obsd.mt b/gdb/config/alpha/obsd.mt
new file mode 100644 (file)
index 0000000..093d50c
--- /dev/null
@@ -0,0 +1,4 @@
+# Target: OpenBSD/alpha
+TDEPFILES= alpha-tdep.o alpha-mdebug-tdep.o alphabsd-tdep.o \
+       alphanbsd-tdep.o alphaobsd-tdep.o nbsd-tdep.o obsd-tdep.o \
+       corelow.o solib.o solib-svr4.o
diff --git a/gdb/config/arm/obsd.mt b/gdb/config/arm/obsd.mt
new file mode 100644 (file)
index 0000000..fcb1a76
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: OpenBSD/arm
+TDEPFILES= arm-tdep.o armbsd-tdep.o armobsd-tdep.o obsd-tdep.o \
+       corelow.o solib.o solib-svr4.o
diff --git a/gdb/config/sparc/embed.mt b/gdb/config/sparc/embed.mt
new file mode 100644 (file)
index 0000000..5d3039c
--- /dev/null
@@ -0,0 +1,5 @@
+# Target: SPARC embedded with simulator
+TDEPFILES= sparc-tdep.o
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/erc32/libsim.a
diff --git a/gdb/gdbserver/win32-i386-low.c b/gdb/gdbserver/win32-i386-low.c
new file mode 100644 (file)
index 0000000..de6ef0b
--- /dev/null
@@ -0,0 +1,1077 @@
+/* Low level interface to Windows debugging, for gdbserver.
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+
+   Contributed by Leo Zayas.  Based on "win32-nat.c" from GDB.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "server.h"
+#include "regcache.h"
+#include "gdb/signals.h"
+
+#include <windows.h>
+#include <imagehlp.h>
+#include <psapi.h>
+#include <sys/param.h>
+#include <malloc.h>
+#include <process.h>
+
+#ifndef USE_WIN32API
+#include <sys/cygwin.h>
+#endif
+
+#define LOG 0
+
+#define OUTMSG(X) do { printf X; fflush (stdout); } while (0)
+#if LOG
+#define OUTMSG2(X) do { printf X; fflush (stdout); } while (0)
+#else
+#define OUTMSG2(X)
+#endif
+
+int debug_threads;
+int using_threads = 1;
+
+/* Globals.  */
+static HANDLE current_process_handle = NULL;
+static DWORD current_process_id = 0;
+static enum target_signal last_sig = TARGET_SIGNAL_0;
+
+/* The current debug event from WaitForDebugEvent.  */
+static DEBUG_EVENT current_event;
+
+static int debug_registers_changed = 0;
+static int debug_registers_used = 0;
+static unsigned dr[8];
+
+typedef BOOL winapi_DebugActiveProcessStop (DWORD dwProcessId);
+typedef BOOL winapi_DebugSetProcessKillOnExit (BOOL KillOnExit);
+
+#define FLAG_TRACE_BIT 0x100
+#define CONTEXT_DEBUGGER (CONTEXT_FULL | CONTEXT_FLOATING_POINT)
+#define CONTEXT_DEBUGGER_DR CONTEXT_DEBUGGER | CONTEXT_DEBUG_REGISTERS \
+  | CONTEXT_EXTENDED_REGISTERS
+
+/* Thread information structure used to track extra information about
+   each thread.  */
+typedef struct thread_info_struct
+{
+  DWORD tid;
+  HANDLE h;
+  int suspend_count;
+  CONTEXT context;
+} thread_info;
+static DWORD main_thread_id = 0;
+
+/* Get the thread ID from the current selected inferior (the current
+   thread).  */
+static DWORD
+current_inferior_tid (void)
+{
+  thread_info *th = inferior_target_data (current_inferior);
+  return th->tid;
+}
+
+/* Find a thread record given a thread id.  If GET_CONTEXT is set then
+   also retrieve the context for this thread.  */
+static thread_info *
+thread_rec (DWORD id, int get_context)
+{
+  struct thread_info *thread;
+  thread_info *th;
+
+  thread = (struct thread_info *) find_inferior_id (&all_threads, id);
+  if (thread == NULL)
+    return NULL;
+
+  th = inferior_target_data (thread);
+  if (!th->suspend_count && get_context)
+    {
+      if (get_context > 0 && id != current_event.dwThreadId)
+       th->suspend_count = SuspendThread (th->h) + 1;
+      else if (get_context < 0)
+       th->suspend_count = -1;
+
+      th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
+
+      GetThreadContext (th->h, &th->context);
+
+      if (id == current_event.dwThreadId)
+       {
+         /* Copy dr values from that thread.  */
+         dr[0] = th->context.Dr0;
+         dr[1] = th->context.Dr1;
+         dr[2] = th->context.Dr2;
+         dr[3] = th->context.Dr3;
+         dr[6] = th->context.Dr6;
+         dr[7] = th->context.Dr7;
+       }
+    }
+
+  return th;
+}
+
+/* Add a thread to the thread list.  */
+static thread_info *
+child_add_thread (DWORD tid, HANDLE h)
+{
+  thread_info *th;
+
+  if ((th = thread_rec (tid, FALSE)))
+    return th;
+
+  th = (thread_info *) malloc (sizeof (*th));
+  memset (th, 0, sizeof (*th));
+  th->tid = tid;
+  th->h = h;
+
+  add_thread (tid, th, (unsigned int) tid);
+  set_inferior_regcache_data ((struct thread_info *)
+                             find_inferior_id (&all_threads, tid),
+                             new_register_cache ());
+
+  /* Set the debug registers for the new thread if they are used.  */
+  if (debug_registers_used)
+    {
+      /* Only change the value of the debug registers.  */
+      th->context.ContextFlags = CONTEXT_DEBUGGER_DR;
+
+      GetThreadContext (th->h, &th->context);
+
+      th->context.Dr0 = dr[0];
+      th->context.Dr1 = dr[1];
+      th->context.Dr2 = dr[2];
+      th->context.Dr3 = dr[3];
+      /* th->context.Dr6 = dr[6];
+         FIXME: should we set dr6 also ?? */
+      th->context.Dr7 = dr[7];
+      SetThreadContext (th->h, &th->context);
+      th->context.ContextFlags = 0;
+    }
+
+  return th;
+}
+
+/* Delete a thread from the list of threads.  */
+static void
+delete_thread_info (struct inferior_list_entry *thread)
+{
+  thread_info *th = inferior_target_data ((struct thread_info *) thread);
+
+  remove_thread ((struct thread_info *) thread);
+  CloseHandle (th->h);
+  free (th);
+}
+
+/* Delete a thread from the list of threads.  */
+static void
+child_delete_thread (DWORD id)
+{
+  struct inferior_list_entry *thread;
+
+  /* If the last thread is exiting, just return.  */
+  if (all_threads.head == all_threads.tail)
+    return;
+
+  thread = find_inferior_id (&all_threads, id);
+  if (thread == NULL)
+    return;
+
+  delete_thread_info (thread);
+}
+
+/* Transfer memory from/to the debugged process.  */
+static int
+child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
+                  int write, struct target_ops *target)
+{
+  SIZE_T done;
+  long addr = (long) memaddr;
+
+  if (write)
+    {
+      WriteProcessMemory (current_process_handle, (LPVOID) addr,
+                         (LPCVOID) our, len, &done);
+      FlushInstructionCache (current_process_handle, (LPCVOID) addr, len);
+    }
+  else
+    {
+      ReadProcessMemory (current_process_handle, (LPCVOID) addr, (LPVOID) our,
+                        len, &done);
+    }
+  return done;
+}
+
+/* Generally, what has the program done?  */
+enum target_waitkind
+{
+  /* The program has exited.  The exit status is in value.integer.  */
+  TARGET_WAITKIND_EXITED,
+
+  /* The program has stopped with a signal.  Which signal is in
+     value.sig.  */
+  TARGET_WAITKIND_STOPPED,
+
+  /* The program is letting us know that it dynamically loaded something
+     (e.g. it called load(2) on AIX).  */
+  TARGET_WAITKIND_LOADED,
+
+  /* The program has exec'ed a new executable file.  The new file's
+     pathname is pointed to by value.execd_pathname.  */
+
+  TARGET_WAITKIND_EXECD,
+
+  /* Nothing happened, but we stopped anyway.  This perhaps should be handled
+     within target_wait, but I'm not sure target_wait should be resuming the
+     inferior.  */
+  TARGET_WAITKIND_SPURIOUS,
+};
+
+struct target_waitstatus
+{
+  enum target_waitkind kind;
+
+  /* Forked child pid, execd pathname, exit status or signal number.  */
+  union
+  {
+    int integer;
+    enum target_signal sig;
+    int related_pid;
+    char *execd_pathname;
+    int syscall_id;
+  }
+  value;
+};
+
+#define NUM_REGS 41
+#define FCS_REGNUM 27
+#define FOP_REGNUM 31
+
+#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
+static const int mappings[] = {
+  context_offset (Eax),
+  context_offset (Ecx),
+  context_offset (Edx),
+  context_offset (Ebx),
+  context_offset (Esp),
+  context_offset (Ebp),
+  context_offset (Esi),
+  context_offset (Edi),
+  context_offset (Eip),
+  context_offset (EFlags),
+  context_offset (SegCs),
+  context_offset (SegSs),
+  context_offset (SegDs),
+  context_offset (SegEs),
+  context_offset (SegFs),
+  context_offset (SegGs),
+  context_offset (FloatSave.RegisterArea[0 * 10]),
+  context_offset (FloatSave.RegisterArea[1 * 10]),
+  context_offset (FloatSave.RegisterArea[2 * 10]),
+  context_offset (FloatSave.RegisterArea[3 * 10]),
+  context_offset (FloatSave.RegisterArea[4 * 10]),
+  context_offset (FloatSave.RegisterArea[5 * 10]),
+  context_offset (FloatSave.RegisterArea[6 * 10]),
+  context_offset (FloatSave.RegisterArea[7 * 10]),
+  context_offset (FloatSave.ControlWord),
+  context_offset (FloatSave.StatusWord),
+  context_offset (FloatSave.TagWord),
+  context_offset (FloatSave.ErrorSelector),
+  context_offset (FloatSave.ErrorOffset),
+  context_offset (FloatSave.DataSelector),
+  context_offset (FloatSave.DataOffset),
+  context_offset (FloatSave.ErrorSelector),
+  /* XMM0-7 */
+  context_offset (ExtendedRegisters[10 * 16]),
+  context_offset (ExtendedRegisters[11 * 16]),
+  context_offset (ExtendedRegisters[12 * 16]),
+  context_offset (ExtendedRegisters[13 * 16]),
+  context_offset (ExtendedRegisters[14 * 16]),
+  context_offset (ExtendedRegisters[15 * 16]),
+  context_offset (ExtendedRegisters[16 * 16]),
+  context_offset (ExtendedRegisters[17 * 16]),
+  /* MXCSR */
+  context_offset (ExtendedRegisters[24])
+};
+
+#undef context_offset
+
+/* Clear out any old thread list and reintialize it to a pristine
+   state. */
+static void
+child_init_thread_list (void)
+{
+  for_each_inferior (&all_threads, delete_thread_info);
+}
+
+static void
+do_initial_child_stuff (DWORD pid)
+{
+  int i;
+
+  last_sig = TARGET_SIGNAL_0;
+
+  debug_registers_changed = 0;
+  debug_registers_used = 0;
+  for (i = 0; i < sizeof (dr) / sizeof (dr[0]); i++)
+    dr[i] = 0;
+  memset (&current_event, 0, sizeof (current_event));
+
+  child_init_thread_list ();
+}
+
+/* Resume all artificially suspended threads if we are continuing
+   execution.  */
+static int
+continue_one_thread (struct inferior_list_entry *this_thread, void *id_ptr)
+{
+  struct thread_info *thread = (struct thread_info *) this_thread;
+  int thread_id = * (int *) id_ptr;
+  thread_info *th = inferior_target_data (thread);
+  int i;
+
+  if ((thread_id == -1 || thread_id == th->tid)
+      && th->suspend_count)
+    {
+      for (i = 0; i < th->suspend_count; i++)
+       (void) ResumeThread (th->h);
+      th->suspend_count = 0;
+      if (debug_registers_changed)
+       {
+         /* Only change the value of the debug registers.  */
+         th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
+         th->context.Dr0 = dr[0];
+         th->context.Dr1 = dr[1];
+         th->context.Dr2 = dr[2];
+         th->context.Dr3 = dr[3];
+         /* th->context.Dr6 = dr[6];
+            FIXME: should we set dr6 also ?? */
+         th->context.Dr7 = dr[7];
+         SetThreadContext (th->h, &th->context);
+         th->context.ContextFlags = 0;
+       }
+    }
+
+  return 0;
+}
+
+static BOOL
+child_continue (DWORD continue_status, int thread_id)
+{
+  BOOL res;
+
+  res = ContinueDebugEvent (current_event.dwProcessId,
+                           current_event.dwThreadId, continue_status);
+  continue_status = 0;
+  if (res)
+    find_inferior (&all_threads, continue_one_thread, &thread_id);
+
+  debug_registers_changed = 0;
+  return res;
+}
+
+/* Fetch register(s) from gdbserver regcache data.  */
+static void
+do_child_fetch_inferior_registers (thread_info *th, int r)
+{
+  char *context_offset = ((char *) &th->context) + mappings[r];
+  long l;
+  if (r == FCS_REGNUM)
+    {
+      l = *((long *) context_offset) & 0xffff;
+      supply_register (r, (char *) &l);
+    }
+  else if (r == FOP_REGNUM)
+    {
+      l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
+      supply_register (r, (char *) &l);
+    }
+  else
+    supply_register (r, context_offset);
+}
+
+/* Fetch register(s) from the current thread context.  */
+static void
+child_fetch_inferior_registers (int r)
+{
+  int regno;
+  thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  if (r == -1 || r == 0 || r > NUM_REGS)
+    child_fetch_inferior_registers (NUM_REGS);
+  else
+    for (regno = 0; regno < r; regno++)
+      do_child_fetch_inferior_registers (th, regno);
+}
+
+/* Get register from gdbserver regcache data.  */
+static void
+do_child_store_inferior_registers (thread_info *th, int r)
+{
+  collect_register (r, ((char *) &th->context) + mappings[r]);
+}
+
+/* Store a new register value into the current thread context.  We don't
+   change the program's context until later, when we resume it.  */
+static void
+child_store_inferior_registers (int r)
+{
+  int regno;
+  thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  if (r == -1 || r == 0 || r > NUM_REGS)
+    child_store_inferior_registers (NUM_REGS);
+  else
+    for (regno = 0; regno < r; regno++)
+      do_child_store_inferior_registers (th, regno);
+}
+
+/* Start a new process.
+   PROGRAM is a path to the program to execute.
+   ARGS is a standard NULL-terminated array of arguments,
+   to be passed to the inferior as ``argv''.
+   Returns the new PID on success, -1 on failure.  Registers the new
+   process with the process list.  */
+static int
+win32_create_inferior (char *program, char **program_args)
+{
+#ifndef USE_WIN32API
+  char real_path[MAXPATHLEN];
+  char *orig_path, *new_path, *path_ptr;
+#endif
+  char *winenv = NULL;
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+  BOOL ret;
+  DWORD flags;
+  char *args;
+  int argslen;
+  int argc;
+
+  if (!program)
+    error ("No executable specified, specify executable to debug.\n");
+
+  memset (&si, 0, sizeof (si));
+  si.cb = sizeof (si);
+
+  flags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
+
+#ifndef USE_WIN32API
+  orig_path = NULL;
+  path_ptr = getenv ("PATH");
+  if (path_ptr)
+    {
+      orig_path = alloca (strlen (path_ptr) + 1);
+      new_path = alloca (cygwin_posix_to_win32_path_list_buf_size (path_ptr));
+      strcpy (orig_path, path_ptr);
+      cygwin_posix_to_win32_path_list (path_ptr, new_path);
+      setenv ("PATH", new_path, 1);
+    }
+  cygwin_conv_to_win32_path (program, real_path);
+  program = real_path;
+#endif
+
+  argslen = strlen (program) + 1;
+  for (argc = 1; program_args[argc]; argc++)
+    argslen += strlen (program_args[argc]) + 1;
+  args = alloca (argslen);
+  strcpy (args, program);
+  for (argc = 1; program_args[argc]; argc++)
+    {
+      /* FIXME: Can we do better about quoting?  How does Cygwin
+         handle this?  */
+      strcat (args, " ");
+      strcat (args, program_args[argc]);
+    }
+  OUTMSG2 (("Command line is %s\n", args));
+
+  flags |= CREATE_NEW_PROCESS_GROUP;
+
+  ret = CreateProcess (0, args,        /* command line */
+                      NULL,    /* Security */
+                      NULL,    /* thread */
+                      TRUE,    /* inherit handles */
+                      flags,   /* start flags */
+                      winenv, NULL,    /* current directory */
+                      &si, &pi);
+
+#ifndef USE_WIN32API
+  if (orig_path)
+    setenv ("PATH", orig_path, 1);
+#endif
+
+  if (!ret)
+    {
+      error ("Error creating process %s, (error %d): %s\n", args,
+            (int) GetLastError (), strerror (GetLastError ()));
+    }
+  else
+    {
+      OUTMSG2 (("Process created: %s\n", (char *) args));
+    }
+
+  CloseHandle (pi.hThread);
+
+  current_process_handle = pi.hProcess;
+  current_process_id = pi.dwProcessId;
+
+  do_initial_child_stuff (current_process_id);
+
+  return current_process_id;
+}
+
+/* Attach to a running process.
+   PID is the process ID to attach to, specified by the user
+   or a higher layer.  */
+static int
+win32_attach (unsigned long pid)
+{
+  int res = 0;
+  HMODULE kernel32 = LoadLibrary ("KERNEL32.DLL");
+  winapi_DebugActiveProcessStop *DebugActiveProcessStop = NULL;
+  winapi_DebugSetProcessKillOnExit *DebugSetProcessKillOnExit = NULL;
+
+  DebugActiveProcessStop =
+    (winapi_DebugActiveProcessStop *) GetProcAddress (kernel32,
+                                                     "DebugActiveProcessStop");
+  DebugSetProcessKillOnExit =
+    (winapi_DebugSetProcessKillOnExit *) GetProcAddress (kernel32,
+                                                        "DebugSetProcessKillOnExit");
+
+  res = DebugActiveProcess (pid) ? 1 : 0;
+
+  if (!res)
+    error ("Attach to process failed.");
+
+  if (DebugSetProcessKillOnExit != NULL)
+    DebugSetProcessKillOnExit (FALSE);
+
+  current_process_id = pid;
+  current_process_handle = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
+
+  if (current_process_handle == NULL)
+    {
+      res = 0;
+      if (DebugActiveProcessStop != NULL)
+       DebugActiveProcessStop (current_process_id);
+    }
+
+  if (res)
+    do_initial_child_stuff (pid);
+
+  FreeLibrary (kernel32);
+
+  return res;
+}
+
+/* Kill all inferiors.  */
+static void
+win32_kill (void)
+{
+  TerminateProcess (current_process_handle, 0);
+  for (;;)
+    {
+      if (!child_continue (DBG_CONTINUE, -1))
+       break;
+      if (!WaitForDebugEvent (&current_event, INFINITE))
+       break;
+      if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
+       break;
+    }
+}
+
+/* Detach from all inferiors.  */
+static void
+win32_detach (void)
+{
+  HMODULE kernel32 = LoadLibrary ("KERNEL32.DLL");
+  winapi_DebugActiveProcessStop *DebugActiveProcessStop = NULL;
+  winapi_DebugSetProcessKillOnExit *DebugSetProcessKillOnExit = NULL;
+
+  DebugActiveProcessStop =
+    (winapi_DebugActiveProcessStop *) GetProcAddress (kernel32,
+                                                     "DebugActiveProcessStop");
+  DebugSetProcessKillOnExit =
+    (winapi_DebugSetProcessKillOnExit *) GetProcAddress (kernel32,
+                                                        "DebugSetProcessKillOnExit");
+
+  if (DebugSetProcessKillOnExit != NULL)
+    DebugSetProcessKillOnExit (FALSE);
+
+  if (DebugActiveProcessStop != NULL)
+    DebugActiveProcessStop (current_process_id);
+  else
+    win32_kill ();
+
+  FreeLibrary (kernel32);
+}
+
+/* Return 1 iff the thread with thread ID TID is alive.  */
+static int
+win32_thread_alive (unsigned long tid)
+{
+  int res;
+
+  /* Our thread list is reliable; don't bother to poll target
+     threads.  */
+  if (find_inferior_id (&all_threads, tid) != NULL)
+    res = 1;
+  else
+    res = 0;
+  return res;
+}
+
+/* Resume the inferior process.  RESUME_INFO describes how we want
+   to resume.  */
+static void
+win32_resume (struct thread_resume *resume_info)
+{
+  DWORD tid;
+  enum target_signal sig;
+  int step;
+  thread_info *th;
+  DWORD continue_status = DBG_CONTINUE;
+
+  /* This handles the very limited set of resume packets that GDB can
+     currently produce.  */
+
+  if (resume_info[0].thread == -1)
+    tid = -1;
+  else if (resume_info[1].thread == -1 && !resume_info[1].leave_stopped)
+    tid = -1;
+  else
+    /* Yes, we're ignoring resume_info[0].thread.  It'd be tricky to make
+       the Windows resume code do the right thing for thread switching.  */
+    tid = current_event.dwThreadId;
+
+  if (resume_info[0].thread != -1)
+    {
+      sig = resume_info[0].sig;
+      step = resume_info[0].step;
+    }
+  else
+    {
+      sig = 0;
+      step = 0;
+    }
+
+  if (sig != TARGET_SIGNAL_0)
+    {
+      if (current_event.dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
+       {
+         OUTMSG (("Cannot continue with signal %d here.\n", sig));
+       }
+      else if (sig == last_sig)
+       continue_status = DBG_EXCEPTION_NOT_HANDLED;
+      else
+       OUTMSG (("Can only continue with recieved signal %d.\n", last_sig));
+    }
+
+  last_sig = TARGET_SIGNAL_0;
+
+  /* Get context for the currently selected thread.  */
+  th = thread_rec (current_event.dwThreadId, FALSE);
+  if (th)
+    {
+      if (th->context.ContextFlags)
+       {
+         if (debug_registers_changed)
+           {
+             th->context.Dr0 = dr[0];
+             th->context.Dr1 = dr[1];
+             th->context.Dr2 = dr[2];
+             th->context.Dr3 = dr[3];
+             /* th->context.Dr6 = dr[6];
+                FIXME: should we set dr6 also ?? */
+             th->context.Dr7 = dr[7];
+           }
+
+         /* Move register values from the inferior into the thread
+            context structure.  */
+         regcache_invalidate ();
+
+         if (step)
+           th->context.EFlags |= FLAG_TRACE_BIT;
+
+         SetThreadContext (th->h, &th->context);
+         th->context.ContextFlags = 0;
+       }
+    }
+
+  /* Allow continuing with the same signal that interrupted us.
+     Otherwise complain.  */
+
+  child_continue (continue_status, tid);
+}
+
+static int
+handle_exception (struct target_waitstatus *ourstatus)
+{
+  thread_info *th;
+  DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode;
+
+  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+
+  /* Record the context of the current thread.  */
+  th = thread_rec (current_event.dwThreadId, -1);
+
+  switch (code)
+    {
+    case EXCEPTION_ACCESS_VIOLATION:
+      OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION"));
+      ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+      break;
+    case STATUS_STACK_OVERFLOW:
+      OUTMSG2 (("STATUS_STACK_OVERFLOW"));
+      ourstatus->value.sig = TARGET_SIGNAL_SEGV;
+      break;
+    case STATUS_FLOAT_DENORMAL_OPERAND:
+      OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+      OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_FLOAT_INEXACT_RESULT:
+      OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_FLOAT_INVALID_OPERATION:
+      OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_FLOAT_OVERFLOW:
+      OUTMSG2 (("STATUS_FLOAT_OVERFLOW"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_FLOAT_STACK_CHECK:
+      OUTMSG2 (("STATUS_FLOAT_STACK_CHECK"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_FLOAT_UNDERFLOW:
+      OUTMSG2 (("STATUS_FLOAT_UNDERFLOW"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_FLOAT_DIVIDE_BY_ZERO:
+      OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_INTEGER_DIVIDE_BY_ZERO:
+      OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case STATUS_INTEGER_OVERFLOW:
+      OUTMSG2 (("STATUS_INTEGER_OVERFLOW"));
+      ourstatus->value.sig = TARGET_SIGNAL_FPE;
+      break;
+    case EXCEPTION_BREAKPOINT:
+      OUTMSG2 (("EXCEPTION_BREAKPOINT"));
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+      break;
+    case DBG_CONTROL_C:
+      OUTMSG2 (("DBG_CONTROL_C"));
+      ourstatus->value.sig = TARGET_SIGNAL_INT;
+      break;
+    case DBG_CONTROL_BREAK:
+      OUTMSG2 (("DBG_CONTROL_BREAK"));
+      ourstatus->value.sig = TARGET_SIGNAL_INT;
+      break;
+    case EXCEPTION_SINGLE_STEP:
+      OUTMSG2 (("EXCEPTION_SINGLE_STEP"));
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+      break;
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+      OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION"));
+      ourstatus->value.sig = TARGET_SIGNAL_ILL;
+      break;
+    case EXCEPTION_PRIV_INSTRUCTION:
+      OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION"));
+      ourstatus->value.sig = TARGET_SIGNAL_ILL;
+      break;
+    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+      OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION"));
+      ourstatus->value.sig = TARGET_SIGNAL_ILL;
+      break;
+    default:
+      if (current_event.u.Exception.dwFirstChance)
+       return 0;
+      OUTMSG2 (("gdbserver: unknown target exception 0x%08lx at 0x%08lx",
+               current_event.u.Exception.ExceptionRecord.ExceptionCode,
+               (DWORD) current_event.u.Exception.ExceptionRecord.
+               ExceptionAddress));
+      ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+      break;
+    }
+  OUTMSG2 (("\n"));
+  last_sig = ourstatus->value.sig;
+  return 1;
+}
+
+/* Get the next event from the child.  Return 1 if the event requires
+   handling.  */
+static int
+get_child_debug_event (struct target_waitstatus *ourstatus)
+{
+  BOOL debug_event;
+  DWORD continue_status, event_code;
+  thread_info *th = NULL;
+  static thread_info dummy_thread_info;
+  int retval = 0;
+
+in:
+
+  last_sig = TARGET_SIGNAL_0;
+  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+
+  if (!(debug_event = WaitForDebugEvent (&current_event, 1000)))
+    goto out;
+
+  current_inferior =
+    (struct thread_info *) find_inferior_id (&all_threads,
+                                            current_event.dwThreadId);
+
+  continue_status = DBG_CONTINUE;
+  event_code = current_event.dwDebugEventCode;
+
+  switch (event_code)
+    {
+    case CREATE_THREAD_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event CREATE_THREAD_DEBUG_EVENT "
+               "for pid=%d tid=%x)\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+
+      /* Record the existence of this thread.  */
+      th = child_add_thread (current_event.dwThreadId,
+                            current_event.u.CreateThread.hThread);
+
+      retval = current_event.dwThreadId;
+      break;
+
+    case EXIT_THREAD_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event EXIT_THREAD_DEBUG_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      child_delete_thread (current_event.dwThreadId);
+      th = &dummy_thread_info;
+      break;
+
+    case CREATE_PROCESS_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event CREATE_PROCESS_DEBUG_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      CloseHandle (current_event.u.CreateProcessInfo.hFile);
+
+      current_process_handle = current_event.u.CreateProcessInfo.hProcess;
+      main_thread_id = current_event.dwThreadId;
+
+      ourstatus->kind = TARGET_WAITKIND_EXECD;
+      ourstatus->value.execd_pathname = "Main executable";
+
+      /* Add the main thread.  */
+      th =
+       child_add_thread (main_thread_id,
+                         current_event.u.CreateProcessInfo.hThread);
+
+      retval = ourstatus->value.related_pid = current_event.dwThreadId;
+      break;
+
+    case EXIT_PROCESS_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event EXIT_PROCESS_DEBUG_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      ourstatus->kind = TARGET_WAITKIND_EXITED;
+      ourstatus->value.integer = current_event.u.ExitProcess.dwExitCode;
+      CloseHandle (current_process_handle);
+      retval = main_thread_id;
+      break;
+
+    case LOAD_DLL_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event LOAD_DLL_DEBUG_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      CloseHandle (current_event.u.LoadDll.hFile);
+
+      ourstatus->kind = TARGET_WAITKIND_LOADED;
+      ourstatus->value.integer = 0;
+      retval = main_thread_id;
+      break;
+
+    case UNLOAD_DLL_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event UNLOAD_DLL_DEBUG_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      break;
+
+    case EXCEPTION_DEBUG_EVENT:
+      OUTMSG2 (("gdbserver: kernel event EXCEPTION_DEBUG_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      retval = handle_exception (ourstatus);
+      break;
+
+    case OUTPUT_DEBUG_STRING_EVENT:
+      /* A message from the kernel (or Cygwin).  */
+      OUTMSG2 (("gdbserver: kernel event OUTPUT_DEBUG_STRING_EVENT "
+               "for pid=%d tid=%x\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId));
+      break;
+
+    default:
+      OUTMSG2 (("gdbserver: kernel event unknown "
+               "for pid=%d tid=%x code=%ld\n",
+               (unsigned) current_event.dwProcessId,
+               (unsigned) current_event.dwThreadId,
+               current_event.dwDebugEventCode));
+      break;
+    }
+
+  current_inferior =
+    (struct thread_info *) find_inferior_id (&all_threads,
+                                            current_event.dwThreadId);
+
+  if (!retval || (event_code != EXCEPTION_DEBUG_EVENT && event_code != EXIT_PROCESS_DEBUG_EVENT))
+    {
+      child_continue (continue_status, -1);
+      goto in;
+    }
+
+  if (th == NULL)
+    thread_rec (current_event.dwThreadId, TRUE);
+
+out:
+  return retval;
+}
+
+/* Wait for the inferior process to change state.
+   STATUS will be filled in with a response code to send to GDB.
+   Returns the signal which caused the process to stop. */
+static unsigned char
+win32_wait (char *status)
+{
+  struct target_waitstatus our_status;
+
+  *status = 'T';
+
+  while (1)
+    {
+      get_child_debug_event (&our_status);
+
+      if (our_status.kind == TARGET_WAITKIND_EXITED)
+       {
+         OUTMSG2 (("Child exited with retcode = %x\n",
+                   our_status.value.integer));
+
+         *status = 'W';
+
+         child_fetch_inferior_registers (-1);
+
+         return our_status.value.integer;
+       }
+      else if (our_status.kind == TARGET_WAITKIND_STOPPED)
+       {
+         OUTMSG2 (("Child Stopped with signal = %x \n",
+                   WSTOPSIG (our_status.value.sig)));
+
+         *status = 'T';
+
+         child_fetch_inferior_registers (-1);
+
+         return our_status.value.sig;
+       }
+      else
+       OUTMSG (("Ignoring unknown internal event, %d\n", our_status.kind));
+
+      {
+       struct thread_resume resume;
+       resume.thread = -1;
+       resume.step = 0;
+       resume.sig = 0;
+       resume.leave_stopped = 0;
+       win32_resume (&resume);
+      }
+    }
+}
+
+/* Fetch registers from the inferior process.
+   If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO.  */
+static void
+win32_fetch_inferior_registers (int regno)
+{
+  child_fetch_inferior_registers (regno);
+}
+
+/* Store registers to the inferior process.
+   If REGNO is -1, store all registers; otherwise, store at least REGNO.  */
+static void
+win32_store_inferior_registers (int regno)
+{
+  child_store_inferior_registers (regno);
+}
+
+/* Read memory from the inferior process.  This should generally be
+   called through read_inferior_memory, which handles breakpoint shadowing.
+   Read LEN bytes at MEMADDR into a buffer at MYADDR.  */
+static int
+win32_read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+  return child_xfer_memory (memaddr, myaddr, len, 0, 0) != len;
+}
+
+/* Write memory to the inferior process.  This should generally be
+   called through write_inferior_memory, which handles breakpoint shadowing.
+   Write LEN bytes from the buffer at MYADDR to MEMADDR.
+   Returns 0 on success and errno on failure.  */
+static int
+win32_write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
+                            int len)
+{
+  return child_xfer_memory (memaddr, (char *) myaddr, len, 1, 0) != len;
+}
+
+static struct target_ops win32_target_ops = {
+  win32_create_inferior,
+  win32_attach,
+  win32_kill,
+  win32_detach,
+  win32_thread_alive,
+  win32_resume,
+  win32_wait,
+  win32_fetch_inferior_registers,
+  win32_store_inferior_registers,
+  win32_read_inferior_memory,
+  win32_write_inferior_memory,
+  0,
+  0
+};
+
+/* Initialize the Win32 backend.  */
+void
+initialize_low (void)
+{
+  set_target_ops (&win32_target_ops);
+
+  init_registers ();
+}
diff --git a/gdb/regformats/reg-x86-64-linux.dat b/gdb/regformats/reg-x86-64-linux.dat
new file mode 100644 (file)
index 0000000..47d324a
--- /dev/null
@@ -0,0 +1,60 @@
+name:x86_64_linux
+expedite:rbp,rsp,rip
+64:rax
+64:rbx
+64:rcx
+64:rdx
+64:rsi
+64:rdi
+64:rbp
+64:rsp
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:rip
+32:eflags
+32:cs
+32:ss
+32:ds
+32:es
+32:fs
+32:gs
+80:st0
+80:st1
+80:st2
+80:st3
+80:st4
+80:st5
+80:st6
+80:st7
+32:fctrl
+32:fstat
+32:ftag
+32:fiseg
+32:fioff
+32:foseg
+32:fooff
+32:fop
+128:xmm0
+128:xmm1
+128:xmm2
+128:xmm3
+128:xmm4
+128:xmm5
+128:xmm6
+128:xmm7
+128:xmm8
+128:xmm9
+128:xmm10
+128:xmm11
+128:xmm12
+128:xmm13
+128:xmm14
+128:xmm15
+32:mxcsr
+64:orig_rax
diff --git a/gdb/testsuite/gdb.arch/i386-size.c b/gdb/testsuite/gdb.arch/i386-size.c
new file mode 100644 (file)
index 0000000..80357dd
--- /dev/null
@@ -0,0 +1,50 @@
+/* Symbol size test program.
+
+   Copyright 2006 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifdef SYMBOL_PREFIX
+#define SYMBOL(str)    SYMBOL_PREFIX #str
+#else
+#define SYMBOL(str)    #str
+#endif
+
+void
+trap (void)
+{
+  asm ("int $0x03");
+}
+
+/* Jump from a function with its symbol size set, to a function
+   named by a local label.  If GDB does not look at the sizes of
+   symbols, we will still appear to be in the first function.  */
+
+asm(".text\n"
+    "    .align 8\n"
+    "    .globl " SYMBOL (main) "\n"
+    SYMBOL (main) ":\n"
+    "    pushl %ebp\n"
+    "    mov   %esp, %ebp\n"
+    "    call  .Lfunc\n"
+    "    ret\n"
+    "    .size " SYMBOL (main) ", .-" SYMBOL (main) "\n"
+    ".Lfunc:\n"
+    "    pushl %ebp\n"
+    "    mov   %esp, %ebp\n"
+    "    call  " SYMBOL (trap) "\n");
diff --git a/gdb/testsuite/gdb.arch/i386-size.exp b/gdb/testsuite/gdb.arch/i386-size.exp
new file mode 100644 (file)
index 0000000..dcf67e9
--- /dev/null
@@ -0,0 +1,89 @@
+# Copyright 2006 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.
+
+if $tracelevel {
+    strace $tracelevel
+}
+
+# Test that GDB can see the sizes of symbols.
+
+if ![istarget "i?86-*-*"] then {
+    verbose "Skipping i386 unwinder tests."
+    return
+}
+
+set testfile "i386-size"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# some targets have leading underscores on assembly symbols.
+# TODO: detect this automatically
+set additional_flags ""
+if [istarget "i?86-*-cygwin*"] then {
+  set additional_flags "additional_flags=-DSYMBOL_PREFIX=\"_\""
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+         executable [list debug $additional_flags]] != "" } {
+    untested "i386-size"
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# We use gdb_run_cmd so this stands a chance to work for remote
+# targets too.
+gdb_run_cmd
+
+gdb_expect {
+    -re "Program received signal SIGTRAP.*$gdb_prompt $" {
+       pass "run past main"
+    }
+    -re ".*$gdb_prompt $" {
+       fail "run past main"
+    }
+    timeout {
+       fail "run past main (timeout)"
+    }
+}
+
+set message "backtrace shows no function"
+gdb_test_multiple "backtrace 10" $message {
+    -re "#1\[ \t]*$hex in main.*$gdb_prompt $" {
+       fail $message
+    }
+    -re "#1\[ \t]*$hex in \\?\\? \\(\\).*$gdb_prompt $" {
+       pass $message
+    }
+}
+
+set message "disassemble stops at end of main"
+gdb_test_multiple "disassemble main" $message {
+    -re "call.*<trap>.*$gdb_prompt $" {
+       fail $message
+    }
+    -re "<main\\+8>:\[ \t\]+ret\[ \t\r\n\]+End of.*$gdb_prompt $" {
+       pass $message
+    }
+}
diff --git a/gdb/testsuite/gdb.base/ifelse.exp b/gdb/testsuite/gdb.base/ifelse.exp
new file mode 100644 (file)
index 0000000..1ad6520
--- /dev/null
@@ -0,0 +1,105 @@
+# Copyright 2006 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.
+
+# This test checks that the if .. else .. end construct works and may
+# contain empty bodies without crashing.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+gdb_exit
+gdb_start
+
+# First test that the if command works with an empty body
+# Test with different conditions because the body is ignored
+# if it is not executed.
+
+#    with true condition
+set message "if 1 with empty body"
+gdb_test_multiple "if 1\nend" $message {
+    -re "$gdb_prompt $" {pass $message}
+    eof {
+       fail "$message (crashed)"
+       gdb_exit
+       gdb_start
+    }
+}
+
+#    with false condition
+set message "if 0 with empty body"
+gdb_test_multiple "if 0\nend" $message {
+    -re "$gdb_prompt $" {pass $message}
+    eof {
+       fail "$message (crashed)"
+       gdb_exit
+       gdb_start
+    }
+}
+
+# Second, do the same tests with an empty else body.
+# This fails in GDB <=6.5
+
+# Unfortunately it was an uninitialised memory problem so
+# sometimes it just works. Preceed it with an if else end with
+# bodies and hopefully the memory with be dirty and the problem
+# will show itself (this works at time of writing).
+
+gdb_test "if 1\necho true\\n\nelse\necho false\\n\nend" "true" ""
+
+#    with true condition
+set message "if 1 .. else with empty body"
+gdb_test_multiple "if 1\nelse\nend" $message {
+    -re "$gdb_prompt $" {pass $message}
+    eof {
+       fail "$message (crashed)"
+       gdb_exit
+       gdb_start
+    }
+}
+
+# dirty memory
+gdb_test "if 1\necho true\\n\nelse\necho false\\n\nend" "true" ""
+
+#    with false condition
+set message "if 0 .. else with empty body"
+gdb_test_multiple "if 0\nelse\nend" $message {
+    -re "$gdb_prompt $" {pass $message}
+    eof {
+       fail "$message (crashed)"
+       gdb_exit
+       gdb_start
+    }
+}
+
+gdb_test "set confirm off" "" ""
+
+# Test that a define with an empty else can be replaced.
+# If there is memory corruption then free will fail.
+# dirty memory
+gdb_test "if 1\necho true\\n\nelse\necho false\\n\nend" "true" ""
+# create
+gdb_test "define abc\nif 1\nelse\nend\nend" "" "create define with empty else"
+# call (note that condition is 1 so should pass)
+gdb_test "abc" "" "call original define"
+# replace
+set message "replace define with if .. else with empty body"
+gdb_test_multiple "define abc\necho got here\\n\nend" $message {
+    -re "$gdb_prompt $" {pass $message}
+    eof {fail "$message (crashed)"}
+}
+# call
+gdb_test "abc" "got here" "call replacement define"
diff --git a/gdb/testsuite/gdb.base/step-bt.c b/gdb/testsuite/gdb.base/step-bt.c
new file mode 100644 (file)
index 0000000..95620e1
--- /dev/null
@@ -0,0 +1,36 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2006 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  */
+
+#include <stdio.h>
+
+void
+hello (void)
+{
+  printf ("Hello world.\n");
+}
+
+int
+main (void)
+{
+  hello ();
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/step-bt.exp b/gdb/testsuite/gdb.base/step-bt.exp
new file mode 100644 (file)
index 0000000..63e223d
--- /dev/null
@@ -0,0 +1,76 @@
+# Copyright 2006 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.  
+
+# The intent of this testcase it to verify that various aliases and
+# shortcuts of the "delete" command never stop working.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile step-bt
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    untested "Couldn't compile test program"
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+gdb_test "break *hello" \
+         "Breakpoint.*at.* file .*$srcfile, line .*" \
+         "breakpoint at first instruction of hello()"
+
+gdb_run_cmd
+gdb_expect {
+    -re ".*Breakpoint.* hello .* at .*$srcfile:.*$gdb_prompt $"  {
+       pass "run to hello()"
+    }
+    -re ".*$gdb_prompt $" {
+       fail "run to hello()"
+       return -1
+    }
+    timeout {
+        fail "run to hello() (timeout)"
+        return -1
+    }
+}
+
+gdb_test "stepi" \
+         "" \
+         "step first instruction"
+
+gdb_test "bt" \
+         "#0 +(0x\[0-9a-z\]+ in )?hello .*#1 +(0x\[0-9a-z\]* in )?main.*" \
+         "backtrace after first instruction step"
+
+gdb_test "stepi" \
+         "" \
+         "step second instruction"
+
+gdb_test "bt" \
+         "#0 +(0x\[0-9a-z\]+ in )?hello .*#1 +(0x\[0-9a-z\]* in )?main.*" \
+         "backtrace after second instruction step"
+
diff --git a/gdb/testsuite/gdb.base/trace-commands.exp b/gdb/testsuite/gdb.base/trace-commands.exp
new file mode 100644 (file)
index 0000000..78f35ad
--- /dev/null
@@ -0,0 +1,129 @@
+# Copyright 2006 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 that the source command's verbose mode works, the 'set trace-commands'
+# command works, and that the nest depth is correct in various circumstances.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+gdb_exit
+gdb_start
+
+# Create a file to source
+set fd [open "tracecommandsscript" w]
+puts $fd "\
+echo in tracecommandsscript\\n
+define func
+ echo in func \$arg0\\n
+end
+if 1
+ if 2
+  if 3
+   if 4
+    echo deep\\n
+    func 999
+   end
+  end
+ end
+end
+"
+close $fd
+
+# Make sure that the show trace-commands exists and the default is 'off'.
+gdb_test "show trace-commands" "State of GDB CLI command tracing is off\\." \
+        "show trace-commands says off"
+
+# Source the script with verbose mode.
+send_gdb "source -v tracecommandsscript\n"
+gdb_expect_list "source -v" ".*$gdb_prompt $" {
+  {[\r\n]\+echo in tracecommandsscript\\n}
+  {[\r\n]\+define func}
+  {[\r\n]\+if 1}
+  {[\r\n]\+\+if 2}
+  {[\r\n]\+\+\+if 3}
+  {[\r\n]\+\+\+\+if 4}
+  {[\r\n]\+\+\+\+\+echo deep\\n}
+  {[\r\n]\+\+\+\+\+func 999}
+  {[\r\n]\+\+\+\+\+\+echo in func 999\\n}
+}
+
+# Turn on command tracing.
+gdb_test "set trace-commands" "" "set trace-commands"
+
+# Make sure show trace-commands now gives 'on'.
+gdb_test "show trace-commands" \
+    {\+show trace-commands[\r\n]+State of GDB CLI command tracing is on\.} \
+        "show trace-commands says on"
+
+# Simple test
+gdb_test "echo hi\\n" {\+echo hi\\n[\r\n]+hi} "simple trace-commands test"
+
+# Nested test
+send_gdb "if 1\nset \$i = 0\nwhile \$i < 5\nfunc \$i\nset \$i += 1\nend\nend\n"
+gdb_expect_list        "nested trace-commands test" ".*$gdb_prompt $" {
+  {[\r\n]\+if 1}
+  {[\r\n]\+\+set \$i = 0}
+  {[\r\n]\+\+while \$i < 5}
+  {[\r\n]\+\+\+func \$i}
+  {[\r\n]\+\+\+\+echo in func \$i\\n}
+  {[\r\n]\+\+\+set \$i \+= 1}
+  {[\r\n]\+\+\+func \$i}
+  {[\r\n]\+\+\+\+echo in func \$i\\n}
+  {[\r\n]\+\+\+set \$i \+= 1}
+  {[\r\n]\+\+\+func \$i}
+  {[\r\n]\+\+\+\+echo in func \$i\\n}
+  {[\r\n]\+\+\+set \$i \+= 1}
+  {[\r\n]\+\+\+func \$i}
+  {[\r\n]\+\+\+\+echo in func \$i\\n}
+  {[\r\n]\+\+\+set \$i \+= 1}
+  {[\r\n]\+\+\+func \$i}
+  {[\r\n]\+\+\+\+echo in func \$i\\n}
+  {[\r\n]\+\+\+set \$i \+= 1}
+}
+
+# Function with source works
+send_gdb "define topfunc\nsource tracecommandsscript\nend\n"
+gdb_expect_list "define user command" ".*$gdb_prompt $" {
+  {[\r\n]\+define topfunc}
+}
+send_gdb "topfunc\n"
+gdb_expect_list "nested trace-commands test with source" ".*$gdb_prompt $" {
+  {[\r\n]\+topfunc}
+  {[\r\n]\+\+source tracecommandsscript}
+  {[\r\n]\+\+echo in tracecommandsscript\\n}
+  {[\r\n]\+\+define func}
+  {[\r\n]\+\+if 1}
+  {[\r\n]\+\+\+if 2}
+  {[\r\n]\+\+\+\+if 3}
+  {[\r\n]\+\+\+\+\+if 4}
+  {[\r\n]\+\+\+\+\+\+echo deep\\n}
+  {[\r\n]\+\+\+\+\+\+func 999}
+  {[\r\n]\+\+\+\+\+\+\+echo in func 999\\n}
+}
+
+# Test nest depth resets properly on error
+send_gdb "if 1\nif 2\nload\necho should not get here\\n\nend\nend\n"
+gdb_expect_list "depth resets on error part 1" ".*$gdb_prompt $" {
+  {[\r\n]\+if 1}
+  {[\r\n]\+\+if 2}
+  {[\r\n]\+\+\+load}
+  {[\r\n]No executable file specified\.}
+  {[\r\n]Use the "file" or "exec-file" command\.}
+}
+gdb_test "echo hi\\n" {[\r\n]\+echo hi\\n[\r\n]+hi} \
+        "depth resets on error part 2"
diff --git a/gdb/testsuite/gdb.cp/ref-params.cc b/gdb/testsuite/gdb.cp/ref-params.cc
new file mode 100644 (file)
index 0000000..9ccfe09
--- /dev/null
@@ -0,0 +1,80 @@
+/* This test script is part of GDB, the GNU debugger.
+
+   Copyright 2006
+   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.
+   */
+
+/* Author: Paul N. Hilfinger, AdaCore Inc. */
+
+struct Parent {
+  Parent (int id0) : id(id0) { }
+  int id;
+};
+
+struct Child : public Parent {
+  Child (int id0) : Parent(id0) { }
+};
+
+int f1(Parent& R)
+{
+  return R.id;                 /* Set breakpoint marker3 here.  */
+}
+
+int f2(Child& C)
+{
+  return f1(C);                        /* Set breakpoint marker2 here.  */
+}
+
+struct OtherParent {
+  OtherParent (int other_id0) : other_id(other_id0) { }
+  int other_id;
+};
+
+struct MultiChild : public Parent, OtherParent {
+  MultiChild (int id0) : Parent(id0), OtherParent(id0 * 2) { }
+};
+
+int mf1(OtherParent& R)
+{
+  return R.other_id;
+}
+
+int mf2(MultiChild& C)
+{
+  return mf1(C);
+}
+
+int main(void) 
+{
+  Child Q(42);
+  Child& QR = Q;
+
+  #ifdef usestubs
+     set_debug_traps();
+     breakpoint();
+  #endif
+
+  /* Set breakpoint marker1 here.  */
+
+  f2(Q);
+  f2(QR);
+
+  MultiChild MQ(53);
+  MultiChild& MQR = MQ;
+
+  mf2(MQ);                     /* Set breakpoint MQ here.  */
+}
diff --git a/gdb/testsuite/gdb.cp/ref-params.exp b/gdb/testsuite/gdb.cp/ref-params.exp
new file mode 100644 (file)
index 0000000..8a8eb90
--- /dev/null
@@ -0,0 +1,80 @@
+# Tests for reference parameters of types and their subtypes in GDB.
+# Copyright 2006 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.  
+
+# written by Paul N. Hilfinger (Hilfinger@adacore.com)
+
+if $tracelevel then {
+        strace $tracelevel
+        }
+
+#
+# test running programs
+#
+set prms_id 0
+set bug_id 0
+
+if { [skip_cplus_tests] } { continue }
+
+set testfile "ref-params"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+     untested ref-params.exp
+     return -1
+}
+
+gdb_exit
+
+proc gdb_start_again { text } {
+    global srcdir
+    global subdir
+    global binfile
+    global srcfile
+
+    gdb_start
+    gdb_reinitialize_dir $srcdir/$subdir
+    gdb_load ${binfile}
+
+    runto ${srcfile}:[gdb_get_line_number $text]
+}
+
+gdb_start_again "marker1 here"
+gdb_test "print Q" ".*id = 42.*" "print value of a Child in main"
+gdb_test "print f1(Q)" ".* = 42.*" "print value of f1 on Child in main"
+gdb_test "print f2(Q)" ".* = 42.*" "print value of f2 on Child in main"
+
+gdb_start_again "marker1 here"
+gdb_test "print f1(QR)" ".* = 42.*" "print value of f1 on (Child&) in main"
+
+gdb_start_again "marker1 here"
+gdb_test "print f2(QR)" ".* = 42.*" "print value of f2 on (Child&) in main"
+
+gdb_start_again "marker2 here"
+gdb_test "print C" ".*id = 42.*" "print value of Child& in f2"
+gdb_test "print f1(C)" ".* = 42.*" "print value of f1 on Child& in f2"
+
+gdb_start_again "marker3 here"
+gdb_test "print R" ".*id = 42.*" "print value of Parent& in f1"
+
+gdb_start_again "breakpoint MQ here"
+gdb_test "print f1(MQ)" ".* = 53"
+gdb_test "print mf1(MQ)" ".* = 106"
+gdb_test "print mf2(MQ)" ".* = 106"
+gdb_test "print f1(MQR)" ".* = 53"
+gdb_test "print mf1(MQR)" ".* = 106"
+gdb_test "print mf2(MQR)" ".* = 106"