--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+# 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
--- /dev/null
+# Target: OpenBSD/arm
+TDEPFILES= arm-tdep.o armbsd-tdep.o armobsd-tdep.o obsd-tdep.o \
+ corelow.o solib.o solib-svr4.o
--- /dev/null
+# Target: SPARC embedded with simulator
+TDEPFILES= sparc-tdep.o
+
+SIM_OBS = remote-sim.o
+SIM = ../sim/erc32/libsim.a
--- /dev/null
+/* 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 (¤t_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 (¤t_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 (¤t_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 ();
+}
--- /dev/null
+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
--- /dev/null
+/* 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");
--- /dev/null
+# 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
+ }
+}
--- /dev/null
+# 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"
--- /dev/null
+/* 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;
+}
--- /dev/null
+# 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"
+
--- /dev/null
+# 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"
--- /dev/null
+/* 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. */
+}
--- /dev/null
+# 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"