Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 2/2] Port gdbserver to GNU/Hurd
@ 2013-09-03  8:03 ` Yue Lu
  2013-09-03  9:38   ` [PATCH 1/2] " Thomas Schwinge
  0 siblings, 1 reply; 25+ messages in thread
From: Yue Lu @ 2013-09-03  8:03 UTC (permalink / raw)
  To: gdb-patches, bug-hurd; +Cc: Thomas Schwinge, Luis Machado

Hi all,

2013-09-03  Yue Lu  <hacklu.newborn@gmail.com>

        * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load
        i386gnu.mh.
        * configure.srv (srv_tgtobj): Add gnu-low.o gnu-i386-low.o for
        GNU/Hurd.
        (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd.
        (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd.
        * configure: Regenerate.
        * Makefile.in (OBS): Add $(NATDEPFILES).
        (generated_files): Add $(NAT_GENERATED_FILES).
        (@host_makefile_frag@): New rule.
        (MIG): New tools.
        (AWK): New tools.
        * exc_request.defs: New file. copy from [gdb]/gdb/exc_request.defs.
        * gnu-i386-low.c: New file. Modified from [gdb]/gdb/i386gnu-nat.c.
        * gnu-low.c: New file. The main part for gdbserver on GNU/Hurd. Most
        of code are borrowed from [gdb]/gdb/gnu-nat.c.
        * gnu-low.h: New file. Most of code are borrowed from
        [gdb]/gdb/gnu-nat.h.
        * hostio.c: Add macro define PATH_MAX 512.
        * i386gnu.mh: New file. copy from
[gdb]/gdb/config/i386/i386gnu.mh and delete
        unused part.
        * msg.defs: New file. copy from [gdb]/gdb/msg.defs.
        * msg_reply.defs: New file. copy from [gdb]/gdb/msg_reply.defs.
        * notify.defs: New file. copy from [gdb]/gdb/notify.defs.
        * process_reply.defs: New file. copy from [gdb]/gdb/process_reply.defs.
        * reply_mid_hack.awk: New file. copy from [gdb]/gdb/reply_mid_hack.awk.
        * server.h: Add typedef long CORE_ADDR;
        * utils.c (host_address_to_string): New functions, copy from
[gdb]/gdb/utils.c.

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index e8470a8..3250b5a 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@
 RANLIB = @RANLIB@

 CC = @CC@
+MIG = @MIG@
+AWK = @AWK@

 # Dependency tracking information.
 DEPMODE = @CCDEPMODE@
@@ -172,7 +174,7 @@ OBS = agent.o ax.o inferiors.o regcache.o
remote-utils.o server.o signals.o targ
  xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \
  dll.o notif.o tdesc.o \
  $(XML_BUILTIN) \
- $(DEPFILES) $(LIBOBJS)
+ $(DEPFILES) $(LIBOBJS) $(NATDEPFILES)
 GDBREPLAY_OBS = gdbreplay.o version.o
 GDBSERVER_LIBS = @GDBSERVER_LIBS@
 XM_CLIBS = @LIBS@
@@ -195,6 +197,10 @@ CLEANDIRS = $(SUBDIRS)
 # The format here is for the `case' shell command.
 REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR)

+# Host-dependent makefile fragment comes in here.
+@host_makefile_frag@
+# End of host-dependent makefile fragment
+
 FLAGS_TO_PASS = \
  "prefix=$(prefix)" \
  "exec_prefix=$(exec_prefix)" \
@@ -228,7 +234,7 @@ FLAGS_TO_PASS = \
  "RUNTESTFLAGS=$(RUNTESTFLAGS)"

 # All generated files which can be included by another file.
-generated_files = config.h $(GNULIB_H)
+generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES)

 .c.o:
  $(COMPILE) $<
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index b9928d7..6c0ed20 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -456,6 +456,31 @@ if $want_ipa ; then
    fi
 fi

+frags=
+case $host_os in
+  gnu*)
+    #Needed for GNU Hurd hosts.
+    AC_PROG_AWK
+    AC_CHECK_TOOL(MIG, mig)
+    if test x"$MIG" = x; then
+      AC_MSG_ERROR([MIG not found but required for $host hosts])
+    fi
+    host_makefile_frag=${srcdir}/i386gnu.mh
+    if test ! -f ${host_makefile_frag}; then
+       AC_MSG_ERROR("*** Gdb does not support native target ${host}")
+    fi
+    frags="$frags $host_makefile_frag"
+    ;;
+  *)
+    host_makefile_frag=/dev/null
+    ;;
+esac
+
+echo "host_makefile_frag=$host_makefile_frag"
+    echo "frags=$frags"
+AC_SUBST_FILE(host_makefile_frag)
+AC_SUBST(frags)
+
 AC_SUBST(GDBSERVER_DEPFILES)
 AC_SUBST(GDBSERVER_LIBS)
 AC_SUBST(srv_xmlbuiltin)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 879d0de..e2a6a08 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -118,6 +118,11 @@ case "${target}" in
  srv_linux_btrace=yes
  ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
  ;;
+  i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj"
+ srv_tgtobj="gnu-low.o gnu-i386-low.o"
+ srv_xmlfiles="$srv_i386_xmlfiles"
+ ;;
+
   i[34567]86-*-lynxos*) srv_regobj="i386.o"
  srv_tgtobj="lynx-low.o lynx-i386-low.o"
  srv_xmlfiles="i386/i386.xml"
diff --git a/gdb/gdbserver/exc_request.defs b/gdb/gdbserver/exc_request.defs
new file mode 100644
index 0000000..9b5ed2e
--- /dev/null
+++ b/gdb/gdbserver/exc_request.defs
@@ -0,0 +1,51 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/*
+ * Abstract:
+ * MiG definitions file for Mach exception interface (request half).
+ */
+
+subsystem exc 2400;
+
+#include <mach/std_types.defs>
+
+#ifdef USERPREFIX
+userprefix USERPREFIX;
+#endif
+
+#ifdef SERVERPREFIX
+serverprefix SERVERPREFIX;
+#endif
+
+simpleroutine exception_raise_request (
+ exception_port : mach_port_t;
+ replyport reply : mach_port_send_once_t;
+ thread : mach_port_t;
+ task : mach_port_t;
+ exception : integer_t;
+ code : integer_t;
+ subcode : integer_t);
diff --git a/gdb/gdbserver/gnu-i386-low.c b/gdb/gdbserver/gnu-i386-low.c
new file mode 100644
index 0000000..643b0e9
--- /dev/null
+++ b/gdb/gdbserver/gnu-i386-low.c
@@ -0,0 +1,296 @@
+/* Low level interface to i386 running the GNU Hurd.
+
+   Copyright (C) 1992-2013 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 3 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, see <http://www.gnu.org/licenses/>.  */
+#include "server.h"
+#include "target.h"
+
+#include "gnu-low.h"
+
+#include <limits.h>
+#include <sys/ptrace.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include "gdb_wait.h"
+#include <signal.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/message.h>
+#include <mach/exception.h>
+
+#define I386_NUM_GREGS 16
+
+/* Offset to the thread_state_t location where REG is stored.  */
+#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
+
+/* At REG_OFFSET[N] is the offset to the thread_state_t location where
+   the GDB register N is stored.  */
+static int reg_offset[] = {
+  REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx),
+  REG_OFFSET (uesp), REG_OFFSET (ebp), REG_OFFSET (esi), REG_OFFSET (edi),
+  REG_OFFSET (eip), REG_OFFSET (efl), REG_OFFSET (cs), REG_OFFSET (ss),
+  REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs)
+};
+
+/* Offset to the greg_t location where REG is stored.  */
+#define CREG_OFFSET(reg) (REG_##reg * 4)
+
+/* At CREG_OFFSET[N] is the offset to the greg_t location where
+   the GDB register N is stored.  */
+static int creg_offset[] = {
+  CREG_OFFSET (EAX), CREG_OFFSET (ECX), CREG_OFFSET (EDX), CREG_OFFSET (EBX),
+  CREG_OFFSET (UESP), CREG_OFFSET (EBP), CREG_OFFSET (ESI), CREG_OFFSET (EDI),
+  CREG_OFFSET (EIP), CREG_OFFSET (EFL), CREG_OFFSET (CS), CREG_OFFSET (SS),
+  CREG_OFFSET (DS), CREG_OFFSET (ES), CREG_OFFSET (FS), CREG_OFFSET (GS)
+};
+
+#define REG_ADDR(state, regnum) ((char *)(state) + reg_offset[regnum])
+#define CREG_ADDR(state, regnum) ((const char *)(state) + creg_offset[regnum])
+
+
+/* Get the whole floating-point state of THREAD and record the values
+   of the corresponding (pseudo) registers.  */
+
+static void
+fetch_fpregs (struct regcache *regcache, struct proc *thread)
+{
+  gnu_debug ("fetch_fpregs() not support now\n");
+#if 0
+  mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+  struct i386_float_state state;
+  error_t err;
+
+  err = thread_get_state (thread->port, i386_FLOAT_STATE,
+  (thread_state_t) & state, &count);
+  if (err)
+    {
+      warning (_("Couldn't fetch floating-point state from %s"),
+       proc_string (thread));
+      return;
+    }
+
+  if (!state.initialized)
+    {
+      /* The floating-point state isn't initialized.  */
+      i387_supply_fsave (regcache, -1, NULL);
+    }
+  else
+    {
+      /* Supply the floating-point registers.  */
+      i387_supply_fsave (regcache, -1, state.hw_state);
+    }
+#endif
+}
+
+extern struct inf *gnu_current_inf;
+extern ptid_t inferior_ptid;
+/* Fetch register REGNO, or all regs if REGNO is -1.  */
+void
+gnu_fetch_registers_1 (struct target_ops *ops,
+       struct regcache *regcache, int regno)
+{
+  struct proc *thread;
+
+  /* Make sure we know about new threads.  */
+  inf_update_procs (gnu_current_inf);
+
+  thread = inf_tid_to_thread (gnu_current_inf, TIDGET (inferior_ptid));
+  if (!thread)
+    error (_
+   ("[gnu_fetch_registers_1]Can't fetch registers from thread %s: No
such thread"),
+   target_pid_to_str (inferior_ptid));
+
+  if (regno < I386_NUM_GREGS || regno == -1)
+    {
+      thread_state_t state;
+
+      /* This does the dirty work for us.  */
+      state = proc_get_state (thread, 0);
+      if (!state)
+ {
+  warning (_("Couldn't fetch registers from %s"),
+   proc_string (thread));
+
+  return;
+ }
+
+      if (regno == -1)
+ {
+  int i;
+
+  proc_debug (thread, "fetching all register");
+
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    /*regcache_raw_supply (regcache, i, REG_ADDR (state, i)); */
+    supply_register (regcache, i, REG_ADDR (state, i));
+  thread->fetched_regs = ~0;
+ }
+      else
+ {
+  /*proc_debug (thread, "fetching register %s", */
+  /*gdbarch_register_name (get_regcache_arch (regcache), */
+  /*regno)); */
+
+  /*regcache_raw_supply (regcache, regno,REG_ADDR (state, regno)); */
+  supply_register (regcache, regno, REG_ADDR (state, regno));
+  thread->fetched_regs |= (1 << regno);
+ }
+    }
+
+  if (regno >= I386_NUM_GREGS || regno == -1)
+    {
+      proc_debug (thread, "fetching floating-point registers");
+
+      fetch_fpregs (regcache, thread);
+    }
+}
+
+
+/* Store the whole floating-point state into THREAD using information
+   from the corresponding (pseudo) registers.  */
+void
+store_fpregs (const struct regcache *regcache, struct proc *thread, int regno)
+{
+  gnu_debug ("store_fpregs() not support now\n");
+#if 0
+  mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+  struct i386_float_state state;
+  error_t err;
+
+  err = thread_get_state (thread->port, i386_FLOAT_STATE,
+  (thread_state_t) & state, &count);
+  if (err)
+    {
+      warning (_("Couldn't fetch floating-point state from %s"),
+       proc_string (thread));
+      return;
+    }
+
+  /* FIXME: kettenis/2001-07-15: Is this right?  Should we somehow
+     take into account DEPRECATED_REGISTER_VALID like the old code did?  */
+  i387_collect_fsave (regcache, regno, state.hw_state);
+
+  err = thread_set_state (thread->port, i386_FLOAT_STATE,
+  (thread_state_t) & state, i386_FLOAT_STATE_COUNT);
+  if (err)
+    {
+      warning (_("Couldn't store floating-point state into %s"),
+       proc_string (thread));
+      return;
+    }
+#endif
+}
+
+/* Store at least register REGNO, or all regs if REGNO == -1.  */
+void
+gnu_store_registers_1 (struct target_ops *ops,
+       struct regcache *regcache, int regno)
+{
+  struct proc *thread;
+  /*struct gdbarch *gdbarch = get_regcache_arch (regcache); */
+  const struct target_desc *gdbarch = regcache->tdesc;
+
+  /* Make sure we know about new threads.  */
+  inf_update_procs (gnu_current_inf);
+
+  thread = inf_tid_to_thread (gnu_current_inf, TIDGET (inferior_ptid));
+  if (!thread)
+    error (_("Couldn't store registers into thread %s: No such thread"),
+   target_pid_to_str (inferior_ptid));
+
+  if (regno < I386_NUM_GREGS || regno == -1)
+    {
+      thread_state_t state;
+      thread_state_data_t old_state;
+      int was_aborted = thread->aborted;
+      int was_valid = thread->state_valid;
+      int trace;
+
+      if (!was_aborted && was_valid)
+ memcpy (&old_state, &thread->state, sizeof (old_state));
+
+      state = proc_get_state (thread, 1);
+      if (!state)
+ {
+  warning (_("Couldn't store registers into %s"),
+   proc_string (thread));
+  return;
+ }
+
+      /* Save the T bit.  We might try to restore the %eflags register
+         below, but changing the T bit would seriously confuse GDB.  */
+      trace = ((struct i386_thread_state *) state)->efl & 0x100;
+
+      if (!was_aborted && was_valid)
+ /* See which registers have changed after aborting the thread.  */
+ {
+  int check_regno;
+
+  for (check_regno = 0; check_regno < I386_NUM_GREGS; check_regno++)
+    if ((thread->fetched_regs & (1 << check_regno))
+ && memcpy (REG_ADDR (&old_state, check_regno),
+   REG_ADDR (state, check_regno),
+   register_size (gdbarch, check_regno)))
+      /* Register CHECK_REGNO has changed!  Ack!  */
+      {
+ /*warning (_("Register %s changed after the thread was aborted"), */
+ /*gdbarch_register_name (gdbarch, check_regno)); */
+ if (regno >= 0 && regno != check_regno)
+  /* Update GDB's copy of the register.  */
+  /*regcache_raw_supply (regcache, check_regno,REG_ADDR (state,
check_regno)); */
+  supply_register (regcache, check_regno,
+   REG_ADDR (state, check_regno));
+ else
+  warning (_("... also writing this register!  "
+     "Suspicious..."));
+      }
+ }
+
+      if (regno == -1)
+ {
+  int i;
+
+  proc_debug (thread, "storing all registers");
+
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    /*if (REG_VALID == regcache_register_status (regcache, i)) */
+    /*regcache_raw_collect (regcache, i, REG_ADDR (state, i)); */
+    collect_register (regcache, i, REG_ADDR (state, i));
+ }
+      else
+ {
+  /*proc_debug (thread, "storing register %s",gdbarch_register_name
(gdbarch, regno)); */
+
+  /*gdb_assert (REG_VALID == regcache_register_status (regcache, regno)); */
+  /*regcache_raw_collect (regcache, regno, REG_ADDR (state, regno)); */
+  collect_register (regcache, regno, REG_ADDR (state, regno));
+ }
+
+      /* Restore the T bit.  */
+      ((struct i386_thread_state *) state)->efl &= ~0x100;
+      ((struct i386_thread_state *) state)->efl |= trace;
+    }
+
+  if (regno >= I386_NUM_GREGS || regno == -1)
+    {
+      proc_debug (thread, "storing floating-point registers");
+
+      store_fpregs (regcache, thread, regno);
+    }
+}
diff --git a/gdb/gdbserver/gnu-low.c b/gdb/gdbserver/gnu-low.c
new file mode 100644
index 0000000..3fd1f04
--- /dev/null
+++ b/gdb/gdbserver/gnu-low.c
@@ -0,0 +1,2327 @@
+/* Copyright (C) 2009-2013 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include "target.h"
+
+#include "gnu-low.h"
+
+#include <limits.h>
+#include <sys/ptrace.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include "gdb_wait.h"
+#include <signal.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/message.h>
+#include <mach/exception.h>
+
+#include "msg_reply_S.h"
+#include "exc_request_S.h"
+#include "process_reply_S.h"
+#include "notify_S.h"
+
+/* this should move into gnu-i386-low.c ?*/
+/* Defined in auto-generated file i386.c.  */
+extern void init_registers_i386 (void);
+extern const struct target_desc *tdesc_i386;
+
+const struct target_desc *gnu_tdesc;
+/* If we've sent a proc_wait_request to the proc server, the pid of the
+   process we asked about.  We can only ever have one outstanding.  */
+int proc_wait_pid = 0;
+
+/* The number of wait requests we've sent, and expect replies from.  */
+int proc_waits_pending = 0;
+
+int using_threads = 1;
+
+struct inf *gnu_current_inf = NULL;
+struct inf *waiting_inf = NULL;
+static process_t proc_server = MACH_PORT_NULL;
+static int next_thread_id = 1;
+ptid_t inferior_ptid;
+
+/* Evaluate RPC_EXPR in a scope with the variables MSGPORT and REFPORT bound
+   to INF's msg port and task port respectively.  If it has no msg port,
+   EIEIO is returned.  INF must refer to a running process!  */
+#define INF_MSGPORT_RPC(inf, rpc_expr) \
+ HURD_MSGPORT_RPC (proc_getmsgport (proc_server, inf->pid, &msgport), \
+ (refport = inf->task->port, 0), 0, \
+ msgport ? (rpc_expr) : EIEIO)
+
+/* Like INF_MSGPORT_RPC, but will also resume the signal thread to ensure
+   there's someone around to deal with the RPC (and resuspend things
+   afterwards).  This effects INF's threads' resume_sc count.  */
+#define INF_RESUME_MSGPORT_RPC(inf, rpc_expr) \
+ (inf_set_threads_resume_sc_for_signal_thread (inf) \
+ ? ({ error_t __e; \
+ inf_resume (inf); \
+ __e = INF_MSGPORT_RPC (inf, rpc_expr); \
+ inf_suspend (inf); \
+ __e; }) \
+ : EIEIO)
+static struct target_ops gnu_target_ops;
+
+struct process_info_private
+{
+  struct inf *inf;
+};
+
+int debug_flags = 0;
+
+void
+gnu_debug (char *string, ...)
+{
+  va_list args;
+
+  if (!debug_flags)
+    return;
+  va_start (args, string);
+  fprintf (stderr, "DEBUG(gnu): ");
+  vfprintf (stderr, string, args);
+  fprintf (stderr, "\n");
+  va_end (args);
+}
+
+/* Set up the thread resume_sc's so that only the signal thread is running
+   (plus whatever other thread are set to always run).  Returns true if we
+   did so, or false if we can't find a signal thread.  */
+int
+inf_set_threads_resume_sc_for_signal_thread (struct inf *inf)
+{
+  if (inf->signal_thread)
+    {
+      inf_set_threads_resume_sc (inf, inf->signal_thread, 0);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+/* Sets the resume_sc of each thread in inf.  That of RUN_THREAD is set to 0,
+   and others are set to their run_sc if RUN_OTHERS is true, and otherwise
+   their pause_sc.  */
+void
+inf_set_threads_resume_sc (struct inf *inf,
+   struct proc *run_thread, int run_others)
+{
+  struct proc *thread;
+
+  inf_update_procs (inf);
+  for (thread = inf->threads; thread; thread = thread->next)
+    if (thread == run_thread)
+      thread->resume_sc = 0;
+    else if (run_others)
+      thread->resume_sc = thread->run_sc;
+    else
+      thread->resume_sc = thread->pause_sc;
+}
+
+void
+inf_clear_wait (struct inf *inf)
+{
+  inf_debug (inf, "clearing wait");
+  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
+  inf->wait.thread = 0;
+  inf->wait.suppress = 0;
+  if (inf->wait.exc.handler != MACH_PORT_NULL)
+    {
+      mach_port_deallocate (mach_task_self (), inf->wait.exc.handler);
+      inf->wait.exc.handler = MACH_PORT_NULL;
+    }
+  if (inf->wait.exc.reply != MACH_PORT_NULL)
+    {
+      mach_port_deallocate (mach_task_self (), inf->wait.exc.reply);
+      inf->wait.exc.reply = MACH_PORT_NULL;
+    }
+}
+
+int
+__proc_pid (struct proc *proc)
+{
+  return proc->inf->pid;
+}
+
+static ptid_t
+gnu_ptid_build (int pid, long lwp, long tid)
+{
+  return ptid_build (pid, tid, 0);
+}
+
+static long
+gnu_get_tid (ptid_t ptid)
+{
+  return ptid_get_lwp (ptid);
+}
+
+int
+proc_update_sc (struct proc *proc)
+{
+  int running;
+  int err = 0;
+  int delta = proc->sc - proc->cur_sc;
+
+  if (delta)
+    gnu_debug ("sc: %d --> %d", proc->cur_sc, proc->sc);
+
+  if (proc->sc == 0 && proc->state_changed)
+    /* Since PROC may start running, we must write back any state changes.  */
+    {
+      gdb_assert (proc_is_thread (proc));
+      err = thread_set_state (proc->port, THREAD_STATE_FLAVOR,
+      (thread_state_t) & proc->state,
+      THREAD_STATE_SIZE);
+      if (!err)
+ proc->state_changed = 0;
+    }
+
+  if (delta > 0)
+    {
+      while (delta-- > 0 && !err)
+ {
+  if (proc_is_task (proc))
+    err = task_suspend (proc->port);
+  else
+    err = thread_suspend (proc->port);
+ }
+    }
+  else
+    {
+      while (delta++ < 0 && !err)
+ {
+  if (proc_is_task (proc))
+    err = task_resume (proc->port);
+  else
+    err = thread_resume (proc->port);
+ }
+    }
+  if (!err)
+    proc->cur_sc = proc->sc;
+
+  /* If we got an error, then the task/thread has disappeared.  */
+  running = !err && proc->sc == 0;
+
+  proc_debug (proc, "is %s",
+      err ? "dead" : running ? "running" : "suspended");
+  if (err)
+    proc_debug (proc, "err = %s", safe_strerror (err));
+
+  if (running)
+    {
+      proc->aborted = 0;
+      proc->state_valid = proc->state_changed = 0;
+      proc->fetched_regs = 0;
+    }
+
+  return running;
+}
+
+error_t
+proc_get_exception_port (struct proc * proc, mach_port_t * port)
+{
+  if (proc_is_task (proc))
+    return task_get_exception_port (proc->port, port);
+  else
+    return thread_get_exception_port (proc->port, port);
+}
+
+static mach_port_t
+_proc_get_exc_port (struct proc *proc)
+{
+  mach_port_t exc_port;
+  error_t err = proc_get_exception_port (proc, &exc_port);
+
+  if (err)
+    /* PROC must be dead.  */
+    {
+      if (proc->exc_port)
+ mach_port_deallocate (mach_task_self (), proc->exc_port);
+      proc->exc_port = MACH_PORT_NULL;
+      if (proc->saved_exc_port)
+ mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+      proc->saved_exc_port = MACH_PORT_NULL;
+    }
+
+  return exc_port;
+}
+
+void
+inf_set_traced (struct inf *inf, int on)
+{
+  if (on == inf->traced)
+    return;
+
+  if (inf->task && !inf->task->dead)
+    /* Make it take effect immediately.  */
+    {
+      sigset_t mask = on ? ~(sigset_t) 0 : 0;
+      error_t err =
+ INF_RESUME_MSGPORT_RPC (inf, msg_set_init_int (msgport, refport,
+       INIT_TRACEMASK, mask));
+
+      if (err == EIEIO)
+ {
+  /*if (on) */
+  /*warning (_("Can't modify tracing state for pid %d: %s"), */
+  /*inf->pid, "No signal thread"); */
+  inf->traced = on;
+ }
+      else if (err)
+ ;
+      /*warning (_("Can't modify tracing state for pid %d: %s"), */
+      /*inf->pid, safe_strerror (err)); */
+      else
+ inf->traced = on;
+    }
+  else
+    inf->traced = on;
+}
+
+/* Makes all the real suspend count deltas of all the procs in INF
+   match the desired values.  Careful to always do thread/task suspend
+   counts in the safe order.  Returns true if at least one thread is
+   thought to be running.  */
+int
+inf_update_suspends (struct inf *inf)
+{
+  struct proc *task = inf->task;
+
+  /* We don't have to update INF->threads even though we're iterating over it
+     because we'll change a thread only if it already has an existing proc
+     entry.  */
+  inf_debug (inf, "updating suspend counts");
+
+  if (task)
+    {
+      struct proc *thread;
+      int task_running = (task->sc == 0), thread_running = 0;
+
+      if (task->sc > task->cur_sc)
+ /* The task is becoming _more_ suspended; do before any threads.  */
+ task_running = proc_update_sc (task);
+
+      if (inf->pending_execs)
+ /* When we're waiting for an exec, things may be happening behind our
+   back, so be conservative.  */
+ thread_running = 1;
+
+      /* Do all the thread suspend counts.  */
+      for (thread = inf->threads; thread; thread = thread->next)
+ thread_running |= proc_update_sc (thread);
+
+      if (task->sc != task->cur_sc)
+ /* We didn't do the task first, because we wanted to wait for the
+   threads; do it now.  */
+ task_running = proc_update_sc (task);
+
+      inf_debug (inf, "%srunning...",
+ (thread_running && task_running) ? "" : "not ");
+
+      inf->running = thread_running && task_running;
+
+      /* Once any thread has executed some code, we can't depend on the
+         threads list any more.  */
+      if (inf->running)
+ inf->threads_up_to_date = 0;
+
+      return inf->running;
+    }
+
+  return 0;
+}
+
+void
+proc_abort (struct proc *proc, int force)
+{
+  gdb_assert (proc_is_thread (proc));
+
+  if (!proc->aborted)
+    {
+      struct inf *inf = proc->inf;
+      int running = (proc->cur_sc == 0 && inf->task->cur_sc == 0);
+
+      if (running && force)
+ {
+  proc->sc = 1;
+  inf_update_suspends (proc->inf);
+  running = 0;
+  /*warning (_("Stopped %s."), proc_string (proc)); */
+ }
+      else if (proc == inf->wait.thread && inf->wait.exc.reply && !force)
+ /* An exception is pending on PROC, which don't mess with.  */
+ running = 1;
+
+      if (!running)
+ /* We only abort the thread if it's not actually running.  */
+ {
+  thread_abort (proc->port);
+  proc_debug (proc, "aborted");
+  proc->aborted = 1;
+ }
+      else
+ proc_debug (proc, "not aborting");
+    }
+}
+
+thread_state_t
+proc_get_state (struct proc *proc, int will_modify)
+{
+  int was_aborted = proc->aborted;
+
+  proc_debug (proc, "updating state info%s",
+      will_modify ? " (with intention to modify)" : "");
+
+  proc_abort (proc, will_modify);
+
+  if (!was_aborted && proc->aborted)
+    /* PROC's state may have changed since we last fetched it.  */
+    proc->state_valid = 0;
+
+  if (!proc->state_valid)
+    {
+      mach_msg_type_number_t state_size = THREAD_STATE_SIZE;
+      error_t err = thread_get_state (proc->port, THREAD_STATE_FLAVOR,
+      (thread_state_t) & proc->state,
+      &state_size);
+
+      proc_debug (proc, "getting thread state");
+      proc->state_valid = !err;
+    }
+
+  if (proc->state_valid)
+    {
+      if (will_modify)
+ proc->state_changed = 1;
+      return (thread_state_t) & proc->state;
+    }
+  else
+    return 0;
+}
+
+void
+proc_steal_exc_port (struct proc *proc, mach_port_t exc_port)
+{
+  mach_port_t cur_exc_port = _proc_get_exc_port (proc);
+
+  if (cur_exc_port)
+    {
+      error_t err = 0;
+
+      proc_debug (proc, "inserting exception port: %d", exc_port);
+
+      if (cur_exc_port != exc_port)
+ /* Put in our exception port.  */
+ err = proc_set_exception_port (proc, exc_port);
+
+      if (err || cur_exc_port == proc->exc_port)
+ /* We previously set the exception port, and it's still set.  So we
+   just keep the old saved port which is what the proc set.  */
+ {
+  if (cur_exc_port)
+    mach_port_deallocate (mach_task_self (), cur_exc_port);
+ }
+      else
+ /* Keep a copy of PROC's old exception port so it can be restored.  */
+ {
+  if (proc->saved_exc_port)
+    mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+  proc->saved_exc_port = cur_exc_port;
+ }
+
+      proc_debug (proc, "saved exception port: %d", proc->saved_exc_port);
+
+      if (!err)
+ proc->exc_port = exc_port;
+      /*else */
+      /*warning (_("Error setting exception port for %s: %s"), */
+      /*proc_string (proc), safe_strerror (err)); */
+    }
+}
+
+int
+proc_trace (struct proc *proc, int set)
+{
+  thread_state_t state = proc_get_state (proc, 1);
+
+  if (!state)
+    return 0; /* The thread must be dead.  */
+
+  proc_debug (proc, "tracing %s", set ? "on" : "off");
+
+  if (set)
+    {
+      /* XXX We don't get the exception unless the thread has its own
+         exception port????  */
+      if (proc->exc_port == MACH_PORT_NULL)
+ proc_steal_exc_port (proc, proc->inf->event_port);
+      THREAD_STATE_SET_TRACED (state);
+    }
+  else
+    THREAD_STATE_CLEAR_TRACED (state);
+
+  return 1;
+}
+
+error_t
+proc_set_exception_port (struct proc * proc, mach_port_t port)
+{
+  proc_debug (proc, "setting exception port: %d", port);
+  if (proc_is_task (proc))
+    return task_set_exception_port (proc->port, port);
+  else
+    return thread_set_exception_port (proc->port, port);
+}
+
+void
+proc_restore_exc_port (struct proc *proc)
+{
+  mach_port_t cur_exc_port = _proc_get_exc_port (proc);
+
+  if (cur_exc_port)
+    {
+      error_t err = 0;
+
+      proc_debug (proc, "restoring real exception port");
+
+      if (proc->exc_port == cur_exc_port)
+ /* Our's is still there.  */
+ err = proc_set_exception_port (proc, proc->saved_exc_port);
+
+      if (proc->saved_exc_port)
+ mach_port_deallocate (mach_task_self (), proc->saved_exc_port);
+      proc->saved_exc_port = MACH_PORT_NULL;
+
+      if (!err)
+ proc->exc_port = MACH_PORT_NULL;
+      else
+ gnu_debug ("Error setting exception port\n");
+    }
+}
+
+void
+inf_set_step_thread (struct inf *inf, struct proc *thread)
+{
+  gdb_assert (!thread || proc_is_thread (thread));
+
+  /*if (thread) */
+  /*inf_debug (inf, "setting step thread: %d/%d", inf->pid, thread->tid); */
+  /*else */
+  /*inf_debug (inf, "clearing step thread"); */
+
+  if (inf->step_thread != thread)
+    {
+      if (inf->step_thread && inf->step_thread->port != MACH_PORT_NULL)
+ if (!proc_trace (inf->step_thread, 0))
+  return;
+      if (thread && proc_trace (thread, 1))
+ inf->step_thread = thread;
+      else
+ inf->step_thread = 0;
+    }
+}
+
+struct proc *
+_proc_free (struct proc *proc)
+{
+  struct inf *inf = proc->inf;
+  struct proc *next = proc->next;
+
+  if (proc == inf->step_thread)
+    /* Turn off single stepping.  */
+    inf_set_step_thread (inf, 0);
+  if (proc == inf->wait.thread)
+    inf_clear_wait (inf);
+  if (proc == inf->signal_thread)
+    inf->signal_thread = 0;
+
+  if (proc->port != MACH_PORT_NULL)
+    {
+      if (proc->exc_port != MACH_PORT_NULL)
+ /* Restore the original exception port.  */
+ proc_restore_exc_port (proc);
+      if (proc->cur_sc != 0)
+ /* Resume the thread/task.  */
+ {
+  proc->sc = 0;
+  proc_update_sc (proc);
+ }
+      mach_port_deallocate (mach_task_self (), proc->port);
+    }
+
+  xfree (proc);
+  return next;
+}
+
+struct proc *
+make_proc (struct inf *inf, mach_port_t port, int tid)
+{
+  error_t err;
+  mach_port_t prev_port = MACH_PORT_NULL;
+  struct proc *proc = xmalloc (sizeof (struct proc));
+
+  proc->port = port;
+  proc->tid = tid;
+  proc->inf = inf;
+  proc->next = 0;
+  proc->saved_exc_port = MACH_PORT_NULL;
+  proc->exc_port = MACH_PORT_NULL;
+
+  proc->sc = 0;
+  proc->cur_sc = 0;
+
+  /* Note that these are all the values for threads; the task simply uses the
+     corresponding field in INF directly.  */
+  proc->run_sc = inf->default_thread_run_sc;
+  proc->pause_sc = inf->default_thread_pause_sc;
+  proc->detach_sc = inf->default_thread_detach_sc;
+  proc->resume_sc = proc->run_sc;
+
+  proc->aborted = 0;
+  proc->dead = 0;
+  proc->state_valid = 0;
+  proc->state_changed = 0;
+
+  proc_debug (proc, "is new");
+
+  /* Get notified when things die.  */
+  err =
+    mach_port_request_notification (mach_task_self (), port,
+    MACH_NOTIFY_DEAD_NAME, 1,
+    inf->event_port,
+    MACH_MSG_TYPE_MAKE_SEND_ONCE, &prev_port);
+  if (err)
+    warning (_("Couldn't request notification for port %d: %s"),
+     port, safe_strerror (err));
+  else
+    {
+      proc_debug (proc, "notifications to: %d", inf->event_port);
+      if (prev_port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), prev_port);
+    }
+
+  if (inf->want_exceptions)
+    {
+      if (proc_is_task (proc))
+ /* Make the task exception port point to us.  */
+ proc_steal_exc_port (proc, inf->event_port);
+      else
+ /* Just clear thread exception ports -- they default to the
+   task one.  */
+ proc_steal_exc_port (proc, MACH_PORT_NULL);
+    }
+
+  return proc;
+}
+
+void
+inf_validate_procs (struct inf *inf)
+{
+  thread_array_t threads;
+  mach_msg_type_number_t num_threads, i;
+  struct proc *task = inf->task;
+
+  /* If no threads are currently running, this function will guarantee that
+     things are up to date.  The exception is if there are zero threads --
+     then it is almost certainly in an odd state, and probably some outside
+     agent will create threads.  */
+  inf->threads_up_to_date = inf->threads ? !inf->running : 0;
+
+  if (task)
+    {
+      error_t err = task_threads (task->port, &threads, &num_threads);
+
+      inf_debug (inf, "fetching threads");
+      if (err)
+ /* TASK must be dead.  */
+ {
+  task->dead = 1;
+  task = 0;
+ }
+    }
+
+  if (!task)
+    {
+      num_threads = 0;
+      inf_debug (inf, "no task");
+    }
+
+  {
+    /* Make things normally linear.  */
+    mach_msg_type_number_t search_start = 0;
+    /* Which thread in PROCS corresponds to each task thread, & the task.  */
+    struct proc *matched[num_threads + 1];
+    /* The last thread in INF->threads, so we can add to the end.  */
+    struct proc *last = 0;
+    /* The current thread we're considering.  */
+    struct proc *thread = inf->threads;
+
+    memset (matched, 0, sizeof (matched));
+
+    while (thread)
+      {
+ mach_msg_type_number_t left;
+
+ for (i = search_start, left = num_threads; left; i++, left--)
+  {
+    if (i >= num_threads)
+      i -= num_threads; /* I wrapped around.  */
+    if (thread->port == threads[i])
+      /* We already know about this thread.  */
+      {
+ matched[i] = thread;
+ last = thread;
+ thread = thread->next;
+ search_start++;
+ break;
+      }
+  }
+
+ if (!left)
+  {
+    proc_debug (thread, "died!");
+
+    ptid_t ptid;
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+    if (find_thread_ptid (ptid))
+      remove_thread (find_thread_ptid (ptid));
+
+    thread->port = MACH_PORT_NULL;
+    thread = _proc_free (thread); /* THREAD is dead.  */
+    if (last)
+      last->next = thread;
+    else
+      inf->threads = thread;
+  }
+      }
+
+    for (i = 0; i < num_threads; i++)
+      {
+ if (matched[i])
+  /* Throw away the duplicate send right.  */
+  mach_port_deallocate (mach_task_self (), threads[i]);
+ else
+  /* THREADS[I] is a thread we don't know about yet!  */
+  {
+    ptid_t ptid;
+
+    thread = make_proc (inf, threads[i], next_thread_id++);
+    if (last)
+      last->next = thread;
+    else
+      inf->threads = thread;
+    last = thread;
+    proc_debug (thread, "new thread: %d", threads[i]);
+
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+
+    /* Tell GDB's generic thread code.  */
+
+#if 0
+    if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid)))
+      /* This is the first time we're hearing about thread
+         ids, after a fork-child.  */
+      thread_change_ptid (inferior_ptid, ptid);
+    else if (inf->pending_execs != 0)
+      /* This is a shell thread.  */
+      add_thread_silent (ptid);
+    else
+      add_thread (ptid);
+#endif
+    if (!find_thread_ptid (ptid))
+      {
+ gnu_debug ("New thread, pid=%d, tid=%d\n", inf->pid,
+   thread->tid);
+ add_thread (ptid, thread);
+ inferior_ptid = ptid; // need fix!!!!!!!!!!!!!
+      }
+  }
+      }
+
+    vm_deallocate (mach_task_self (),
+   (vm_address_t) threads, (num_threads * sizeof (thread_t)));
+  }
+}
+
+int
+inf_update_procs (struct inf *inf)
+{
+  if (!inf->task)
+    return 0;
+  if (!inf->threads_up_to_date)
+    inf_validate_procs (inf);
+  return !!inf->task;
+}
+
+void
+inf_set_pid (struct inf *inf, pid_t pid)
+{
+  task_t task_port;
+  struct proc *task = inf->task;
+
+  inf_debug (inf, "setting pid: %d", pid);
+
+  if (pid < 0)
+    task_port = MACH_PORT_NULL;
+  else
+    {
+      error_t err = proc_pid2task (proc_server, pid, &task_port);
+
+      if (err)
+ {
+  error (_("Error getting task for pid %d: %s"), pid, "XXXX");
+  /*pid, safe_strerror (err)); */
+ }
+    }
+
+  inf_debug (inf, "setting task: %d", task_port);
+
+  if (inf->pause_sc)
+    task_suspend (task_port);
+
+  if (task && task->port != task_port)
+    {
+      inf->task = 0;
+      inf_validate_procs (inf); /* Trash all the threads.  */
+      _proc_free (task); /* And the task.  */
+    }
+
+  if (task_port != MACH_PORT_NULL)
+    {
+      inf->task = make_proc (inf, task_port, PROC_TID_TASK);
+      inf->threads_up_to_date = 0;
+    }
+
+  if (inf->task)
+    {
+      inf->pid = pid;
+      if (inf->pause_sc)
+ /* Reflect task_suspend above.  */
+ inf->task->sc = inf->task->cur_sc = 1;
+    }
+  else
+    inf->pid = -1;
+}
+
+void
+inf_cleanup (struct inf *inf)
+{
+  inf_debug (inf, "cleanup");
+
+  inf_clear_wait (inf);
+
+  inf_set_pid (inf, -1);
+  inf->pid = 0;
+  inf->running = 0;
+  inf->stopped = 0;
+  inf->nomsg = 1;
+  inf->traced = 0;
+  inf->no_wait = 0;
+  inf->pending_execs = 0;
+
+  if (inf->event_port)
+    {
+      mach_port_destroy (mach_task_self (), inf->event_port);
+      inf->event_port = MACH_PORT_NULL;
+    }
+}
+
+void
+inf_startup (struct inf *inf, int pid)
+{
+  error_t err;
+
+  inf_debug (inf, "startup: pid = %d", pid);
+
+  inf_cleanup (inf);
+
+  /* Make the port on which we receive all events.  */
+  err = mach_port_allocate (mach_task_self (),
+    MACH_PORT_RIGHT_RECEIVE, &inf->event_port);
+  /*if (err) */
+  /*error (_("Error allocating event port: %s"), safe_strerror (err)); */
+
+  /* Make a send right for it, so we can easily copy it for other people.  */
+  mach_port_insert_right (mach_task_self (), inf->event_port,
+  inf->event_port, MACH_MSG_TYPE_MAKE_SEND);
+  inf_set_pid (inf, pid);
+}
+
+/* Detachs from INF's inferior task, letting it run once again...  */
+void
+inf_detach (struct inf *inf)
+{
+  struct proc *task = inf->task;
+
+  inf_debug (inf, "detaching...");
+
+  inf_clear_wait (inf);
+  inf_set_step_thread (inf, 0);
+
+  if (task)
+    {
+      struct proc *thread;
+
+      inf_validate_procinfo (inf);
+
+      inf_set_traced (inf, 0);
+      if (inf->stopped)
+ {
+  if (inf->nomsg)
+    inf_continue (inf);
+  else
+    inf_signal (inf, GDB_SIGNAL_0);
+ }
+
+      proc_restore_exc_port (task);
+      task->sc = inf->detach_sc;
+
+      for (thread = inf->threads; thread; thread = thread->next)
+ {
+  proc_restore_exc_port (thread);
+  thread->sc = thread->detach_sc;
+ }
+
+      inf_update_suspends (inf);
+    }
+
+  inf_cleanup (inf);
+}
+
+void
+inf_attach (struct inf *inf, int pid)
+{
+  inf_debug (inf, "attaching: %d", pid);
+
+  if (inf->pid)
+    {
+      inf_detach (inf);
+    }
+
+  inf_startup (inf, pid);
+}
+
+struct inf *
+make_inf (void)
+{
+  struct inf *inf = xmalloc (sizeof (struct inf));
+
+  inf->task = 0;
+  inf->threads = 0;
+  inf->threads_up_to_date = 0;
+  inf->pid = 0;
+  inf->wait.status.kind = TARGET_WAITKIND_SPURIOUS;
+  inf->wait.thread = 0;
+  inf->wait.exc.handler = MACH_PORT_NULL;
+  inf->wait.exc.reply = MACH_PORT_NULL;
+  inf->step_thread = 0;
+  inf->signal_thread = 0;
+  inf->event_port = MACH_PORT_NULL;
+  inf->running = 0;
+  inf->stopped = 0;
+  inf->nomsg = 1;
+  inf->traced = 0;
+  inf->no_wait = 0;
+  inf->pending_execs = 0;
+  inf->pause_sc = 1;
+  inf->detach_sc = 0;
+  inf->default_thread_run_sc = 0;
+  inf->default_thread_pause_sc = 0;
+  inf->default_thread_detach_sc = 0;
+  inf->want_signals = 1; /* By default */
+  inf->want_exceptions = 1; /* By default */
+
+  return inf;
+}
+
+static struct inf *
+cur_inf (void)
+{
+  if (!gnu_current_inf)
+    gnu_current_inf = make_inf ();
+  return gnu_current_inf;
+}
+
+
+static struct process_info *
+gnu_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  proc = add_process (pid, attached);
+  proc->tdesc = gnu_tdesc;
+  proc->private = xcalloc (1, sizeof (*proc->private));
+  proc->private->inf = cur_inf ();
+  struct inf *inf = gnu_current_inf;
+
+  inf_attach (inf, pid);
+  inf->pending_execs = 2;
+  inf->nomsg = 1;
+  inf->traced = 1;
+
+  inf_resume (inf);
+
+  return proc;
+}
+
+static int
+gnu_create_inferior (char *program, char **allargs)
+{
+  int pid;
+  pid = fork ();
+  if (pid < 0)
+    perror_with_name ("fork");
+
+  if (pid == 0)
+    {
+      ptrace (PTRACE_TRACEME);
+      setpgid (0, 0);
+      execv (program, allargs);
+
+      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  gnu_add_process (pid, 0);
+  return pid;
+}
+
+/* Fork an inferior process, and start debugging it.  */
+
+/* Set INFERIOR_PID to the first thread available in the child, if any.  */
+static int
+inf_pick_first_thread (void)
+{
+  if (gnu_current_inf->task && gnu_current_inf->threads)
+    /* The first thread.  */
+    return gnu_current_inf->threads->tid;
+  else
+    /* What may be the next thread.  */
+    return next_thread_id;
+}
+
+static int
+gnu_attach (unsigned long pid)
+{
+  return -1; //not support now
+  struct inf *inf = cur_inf ();
+  /*struct inferior *inferior; */
+
+  if (pid == getpid ()) /* Trying to masturbate?  */
+    error (_("I refuse to debug myself!"));
+
+  inf_debug (inf, "attaching to pid: %d", pid);
+
+  inf_attach (inf, pid);
+
+  inf_update_procs (inf);
+
+  inferior_ptid = gnu_ptid_build (pid, 0, inf_pick_first_thread ());
+
+  inf_validate_procinfo (inf);
+  inf->signal_thread = inf->threads ? inf->threads->next : 0;
+  inf_set_traced (inf, inf->want_signals);
+
+  gnu_add_process (pid, 1);
+  add_thread (inferior_ptid, NULL);
+  return 0;
+}
+
+static int
+gnu_kill (int pid)
+{
+  struct proc *task = gnu_current_inf->task;
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+
+  if (task)
+    {
+      proc_debug (task, "terminating...");
+      task_terminate (task->port);
+      inf_set_pid (gnu_current_inf, -1);
+    }
+  the_target->mourn (process);
+  return 0;
+}
+
+static int
+gnu_detach (int pid)
+{
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
+
+  inf_detach (gnu_current_inf);
+
+  inferior_ptid = null_ptid;
+  the_target->mourn (process);
+  return 0;
+}
+
+
+static void
+gnu_mourn (struct process_info *process)
+{
+  /* Free our private data.  */
+  free (process->private);
+  process->private = NULL;
+
+  clear_inferiors ();
+}
+
+static void
+gnu_join (int pid)
+{
+  /* doesn't need */
+}
+
+static int
+gnu_thread_alive (ptid_t ptid)
+{
+  /* this function is copyed from lynx-low.c */
+  return (find_thread_ptid (ptid) != NULL);
+}
+
+
+/* Fill in INF's wait field after a task has died without giving us more
+   detailed information.  */
+void
+inf_task_died_status (struct inf *inf)
+{
+  printf ("Pid %d died with unknown exit status, using SIGKILL.", inf->pid);
+  inf->wait.status.kind = TARGET_WAITKIND_SIGNALLED;
+  inf->wait.status.value.sig = GDB_SIGNAL_KILL;
+}
+
+struct proc *
+inf_tid_to_thread (struct inf *inf, int tid)
+{
+  struct proc *thread = inf->threads;
+
+  gnu_debug ("[inf_tid_to_thread]:search thread which tid=%d\n", tid);
+
+  while (thread)
+    if (thread->tid == tid)
+      return thread;
+    else
+      thread = thread->next;
+  return 0;
+}
+
+/* Validates INF's stopped, nomsg and traced field from the actual
+   proc server state.  Note that the traced field is only updated from
+   the proc server state if we do not have a message port.  If we do
+   have a message port we'd better look at the tracemask itself.  */
+static void
+inf_validate_procinfo (struct inf *inf)
+{
+  char *noise;
+  mach_msg_type_number_t noise_len = 0;
+  struct procinfo *pi;
+  mach_msg_type_number_t pi_len = 0;
+  int info_flags = 0;
+  error_t err = proc_getprocinfo (proc_server, inf->pid, &info_flags,
+  (procinfo_t *) & pi, &pi_len, &noise,
+  &noise_len);
+
+  if (!err)
+    {
+      inf->stopped = !!(pi->state & PI_STOPPED);
+      inf->nomsg = !!(pi->state & PI_NOMSG);
+      if (inf->nomsg)
+ inf->traced = !!(pi->state & PI_TRACED);
+      vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+      if (noise_len > 0)
+ vm_deallocate (mach_task_self (), (vm_address_t) noise, noise_len);
+    }
+}
+
+/* Deliver signal SIG to INF.  If INF is stopped, delivering a signal, even
+   signal 0, will continue it.  INF is assumed to be in a paused state, and
+   the resume_sc's of INF's threads may be affected.  */
+void
+inf_signal (struct inf *inf, enum gdb_signal sig)
+{
+  error_t err = 0;
+  int host_sig = gdb_signal_to_host (sig);
+
+#define NAME gdb_signal_to_name (sig)
+
+  if (host_sig >= _NSIG)
+    /* A mach exception.  Exceptions are encoded in the signal space by
+       putting them after _NSIG; this assumes they're positive (and not
+       extremely large)!  */
+    {
+      struct inf_wait *w = &inf->wait;
+
+      if (w->status.kind == TARGET_WAITKIND_STOPPED
+  && w->status.value.sig == sig && w->thread && !w->thread->aborted)
+ /* We're passing through the last exception we received.  This is
+   kind of bogus, because exceptions are per-thread whereas gdb
+   treats signals as per-process.  We just forward the exception to
+   the correct handler, even it's not for the same thread as TID --
+   i.e., we pretend it's global.  */
+ {
+  struct exc_state *e = &w->exc;
+
+  inf_debug (inf, "passing through exception:"
+     " task = %d, thread = %d, exc = %d"
+     ", code = %d, subcode = %d",
+     w->thread->port, inf->task->port,
+     e->exception, e->code, e->subcode);
+  err =
+    exception_raise_request (e->handler,
+     e->reply, MACH_MSG_TYPE_MOVE_SEND_ONCE,
+     w->thread->port, inf->task->port,
+     e->exception, e->code, e->subcode);
+ }
+      else
+ error (_("Can't forward spontaneous exception (%s)."), NAME);
+    }
+  else
+    /* A Unix signal.  */
+  if (inf->stopped)
+    /* The process is stopped and expecting a signal.  Just send off a
+       request and let it get handled when we resume everything.  */
+    {
+      inf_debug (inf, "sending %s to stopped process", NAME);
+      err =
+ INF_MSGPORT_RPC (inf,
+ msg_sig_post_untraced_request (msgport,
+ inf->event_port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ host_sig, 0,
+ refport));
+      if (!err)
+ /* Posting an untraced signal automatically continues it.
+   We clear this here rather than when we get the reply
+   because we'd rather assume it's not stopped when it
+   actually is, than the reverse.  */
+ inf->stopped = 0;
+    }
+  else
+    /* It's not expecting it.  We have to let just the signal thread
+       run, and wait for it to get into a reasonable state before we
+       can continue the rest of the process.  When we finally resume the
+       process the signal we request will be the very first thing that
+       happens.  */
+    {
+      inf_debug (inf, "sending %s to unstopped process"
+ " (so resuming signal thread)", NAME);
+      err =
+ INF_RESUME_MSGPORT_RPC (inf,
+ msg_sig_post_untraced (msgport, host_sig,
+       0, refport));
+    }
+
+  if (err == EIEIO)
+    /* Can't do too much...  */
+    warning (_("Can't deliver signal %s: No signal thread."), NAME);
+  else if (err)
+    warning (_("Delivering signal %s: %s"), NAME, safe_strerror (err));
+
+#undef NAME
+}
+
+/* Continue INF without delivering a signal.  This is meant to be used
+   when INF does not have a message port.  */
+void
+inf_continue (struct inf *inf)
+{
+  process_t proc;
+  error_t err = proc_pid2proc (proc_server, inf->pid, &proc);
+
+  if (!err)
+    {
+      inf_debug (inf, "continuing process");
+
+      err = proc_mark_cont (proc);
+      if (!err)
+ {
+  struct proc *thread;
+
+  for (thread = inf->threads; thread; thread = thread->next)
+    thread_resume (thread->port);
+
+  inf->stopped = 0;
+ }
+    }
+
+  if (err)
+    warning (_("Can't continue process: %s"), safe_strerror (err));
+}
+
+/* Returns the number of messages queued for the receive right PORT.  */
+static mach_port_msgcount_t
+port_msgs_queued (mach_port_t port)
+{
+  struct mach_port_status status;
+  error_t err =
+    mach_port_get_receive_status (mach_task_self (), port, &status);
+
+  if (err)
+    return 0;
+  else
+    return status.mps_msgcount;
+}
+
+static void
+gnu_resume_1 (struct target_ops *ops,
+      ptid_t ptid, int step, enum gdb_signal sig)
+{
+  struct proc *step_thread = 0;
+  int resume_all;
+  struct inf *inf = gnu_current_inf;
+
+  inf_debug (inf, "ptid = %s, step = %d, sig = %d",
+     target_pid_to_str (ptid), step, sig);
+
+  inf_validate_procinfo (inf);
+
+  if (sig != GDB_SIGNAL_0 || inf->stopped)
+    {
+      if (sig == GDB_SIGNAL_0 && inf->nomsg)
+ inf_continue (inf);
+      else
+ inf_signal (inf, sig);
+    }
+  else if (inf->wait.exc.reply != MACH_PORT_NULL)
+    /* We received an exception to which we have chosen not to forward, so
+       abort the faulting thread, which will perhaps retake it.  */
+    {
+      proc_abort (inf->wait.thread, 1);
+      /*warning (_("Aborting %s with unforwarded exception %s."), */
+      /*proc_string (inf->wait.thread), */
+      /*gdb_signal_to_name (inf->wait.status.value.sig)); */
+    }
+
+  if (port_msgs_queued (inf->event_port))
+    /* If there are still messages in our event queue, don't bother resuming
+       the process, as we're just going to stop it right away anyway.  */
+    return;
+
+  inf_update_procs (inf);
+
+  /* A specific PTID means `step only this process id'.  */
+  resume_all = ptid_equal (ptid, minus_one_ptid);
+
+  if (resume_all)
+    /* Allow all threads to run, except perhaps single-stepping one.  */
+    {
+      inf_debug (inf, "running all threads; tid = %d",
+ PIDGET (inferior_ptid));
+      ptid = inferior_ptid; /* What to step.  */
+      inf_set_threads_resume_sc (inf, 0, 1);
+    }
+  else
+    /* Just allow a single thread to run.  */
+    {
+      struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
+
+      if (!thread)
+ error (_("Can't run single thread id %s: no such thread!"),
+       target_pid_to_str (ptid));
+      inf_debug (inf, "running one thread: %s", target_pid_to_str (ptid));
+      inf_set_threads_resume_sc (inf, thread, 0);
+    }
+
+  if (step)
+    {
+      step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
+      if (!step_thread)
+ warning (_("Can't step thread id %s: no such thread."),
+ target_pid_to_str (ptid));
+      else
+ inf_debug (inf, "stepping thread: %s", target_pid_to_str (ptid));
+    }
+  if (step_thread != inf->step_thread)
+    inf_set_step_thread (inf, step_thread);
+
+  inf_debug (inf, "here we go...");
+  inf_resume (inf);
+}
+
+static void
+gnu_resume (struct thread_resume *resume_info, size_t n)
+{
+  /* FIXME: Assume for now that n == 1.  */
+  ptid_t ptid = resume_info[0].thread;
+  const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1
means step, 0 means contiune
+  const int signal = resume_info[0].sig;
+  if (ptid_equal (ptid, minus_one_ptid))
+    ptid = thread_to_gdb_id (current_inferior);
+
+  regcache_invalidate ();
+
+  gnu_debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step,
+     signal);
+
+  /*my_resume(); */
+  /*static void gnu_resume_1 (struct target_ops *ops,ptid_t ptid, int
step, enum gdb_signal sig) */
+  gnu_resume_1 (NULL, ptid, step, signal);
+
+}
+
+void
+inf_suspend (struct inf *inf)
+{
+  struct proc *thread;
+
+  inf_update_procs (inf);
+
+  for (thread = inf->threads; thread; thread = thread->next)
+    thread->sc = thread->pause_sc;
+
+  if (inf->task)
+    inf->task->sc = inf->pause_sc;
+
+  inf_update_suspends (inf);
+}
+
+static ptid_t
+gnu_wait_1 (ptid_t ptid, struct target_waitstatus *status, int target_options)
+{
+  struct msg
+  {
+    mach_msg_header_t hdr;
+    mach_msg_type_t type;
+    int data[8000];
+  } msg;
+  error_t err;
+  struct proc *thread;
+  struct inf *inf = gnu_current_inf;
+
+  extern int exc_server (mach_msg_header_t *, mach_msg_header_t *);
+  extern int msg_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+  extern int notify_server (mach_msg_header_t *, mach_msg_header_t *);
+  extern int process_reply_server (mach_msg_header_t *, mach_msg_header_t *);
+
+  gdb_assert (inf->task);
+
+  if (!inf->threads && !inf->pending_execs)
+    /* No threads!  Assume that maybe some outside agency is frobbing our
+       task, and really look for new threads.  If we can't find any, just tell
+       the user to try again later.  */
+    {
+      inf_validate_procs (inf);
+      if (!inf->threads && !inf->task->dead)
+ error (_("There are no threads; try again later."));
+    }
+
+  waiting_inf = inf;
+
+  inf_debug (inf, "waiting for: %s", target_pid_to_str (ptid));
+
+rewait:
+  if (proc_wait_pid != inf->pid && !inf->no_wait)
+    /* Always get information on events from the proc server.  */
+    {
+      inf_debug (inf, "requesting wait on pid %d", inf->pid);
+
+      if (proc_wait_pid)
+ /* The proc server is single-threaded, and only allows a single
+   outstanding wait request, so we have to cancel the previous one.  */
+ {
+  inf_debug (inf, "cancelling previous wait on pid %d",
+     proc_wait_pid);
+  interrupt_operation (proc_server, 0);
+ }
+
+      err =
+ proc_wait_request (proc_server, inf->event_port, inf->pid, WUNTRACED);
+      if (err)
+ warning (_("wait request failed: %s"), safe_strerror (err));
+      else
+ {
+  inf_debug (inf, "waits pending: %d", proc_waits_pending);
+  proc_wait_pid = inf->pid;
+  /* Even if proc_waits_pending was > 0 before, we still won't
+     get any other replies, because it was either from a
+     different INF, or a different process attached to INF --
+     and the event port, which is the wait reply port, changes
+     when you switch processes.  */
+  proc_waits_pending = 1;
+ }
+    }
+
+  inf_clear_wait (inf);
+
+  /* What can happen? (1) Dead name notification; (2) Exceptions arrive;
+     (3) wait reply from the proc server.  */
+
+  inf_debug (inf, "waiting for an event...");
+  err = mach_msg (&msg.hdr, MACH_RCV_MSG | MACH_RCV_INTERRUPT,
+  0, sizeof (struct msg), inf->event_port,
+  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+
+  /* Re-suspend the task.  */
+  inf_suspend (inf);
+
+  if (!inf->task && inf->pending_execs)
+    /* When doing an exec, it's possible that the old task wasn't reused
+       (e.g., setuid execs).  So if the task seems to have disappeared,
+       attempt to refetch it, as the pid should still be the same.  */
+    inf_set_pid (inf, inf->pid);
+
+  if (err == EMACH_RCV_INTERRUPTED)
+    printf ("interrupted\n");
+  /*inf_debug (inf, "interrupted"); */
+  else if (err)
+    printf ("Couldn't wait for an event:\n");
+  /*error (_("Couldn't wait for an event: %s"), safe_strerror (err)); */
+  else
+    {
+      struct
+      {
+ mach_msg_header_t hdr;
+ mach_msg_type_t err_type;
+ kern_return_t err;
+ char noise[200];
+      }
+      reply;
+
+      inf_debug (inf, "event: msgid = %d", msg.hdr.msgh_id);
+
+      /* Handle what we got.  */
+      if (!notify_server (&msg.hdr, &reply.hdr)
+  && !exc_server (&msg.hdr, &reply.hdr)
+  && !process_reply_server (&msg.hdr, &reply.hdr)
+  && !msg_reply_server (&msg.hdr, &reply.hdr))
+ /* Whatever it is, it's something strange.  */
+ error (_("Got a strange event, msg id = %d."), msg.hdr.msgh_id);
+
+      if (reply.err)
+ error (_("Handling event, msgid = %d: %s"),
+       msg.hdr.msgh_id, safe_strerror (reply.err));
+    }
+
+  if (inf->pending_execs)
+    /* We're waiting for the inferior to finish execing.  */
+    {
+      struct inf_wait *w = &inf->wait;
+      enum target_waitkind kind = w->status.kind;
+
+      if (kind == TARGET_WAITKIND_SPURIOUS)
+ /* Since gdb is actually counting the number of times the inferior
+   stops, expecting one stop per exec, we only return major events
+   while execing.  */
+ {
+  w->suppress = 1;
+  inf_debug (inf, "pending_execs = %d, ignoring minor event",
+     inf->pending_execs);
+ }
+      else if (kind == TARGET_WAITKIND_STOPPED
+       && w->status.value.sig == GDB_SIGNAL_TRAP)
+ /* Ah hah!  A SIGTRAP from the inferior while starting up probably
+   means we've succesfully completed an exec!  */
+ {
+  if (--inf->pending_execs == 0)
+    /* We're done!  */
+    {
+#if 0 /* do we need this?  */
+      prune_threads (1); /* Get rid of the old shell
+   threads.  */
+      renumber_threads (0); /* Give our threads reasonable
+   names.  */
+#endif
+    }
+  inf_debug (inf, "pending exec completed, pending_execs => %d",
+     inf->pending_execs);
+ }
+      else if (kind == TARGET_WAITKIND_STOPPED)
+ /* It's possible that this signal is because of a crashed process
+   being handled by the hurd crash server; in this case, the process
+   will have an extra task suspend, which we need to know about.
+   Since the code in inf_resume that normally checks for this is
+   disabled while INF->pending_execs, we do the check here instead.  */
+ inf_validate_task_sc (inf);
+    }
+
+  if (inf->wait.suppress)
+    /* Some totally spurious event happened that we don't consider
+       worth returning to gdb.  Just keep waiting.  */
+    {
+      inf_debug (inf, "suppressing return, rewaiting...");
+      inf_resume (inf);
+      goto rewait;
+    }
+
+  /* Pass back out our results.  */
+  memcpy (status, &inf->wait.status, sizeof (*status));
+
+  thread = inf->wait.thread;
+  if (thread)
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+  else if (ptid_equal (ptid, minus_one_ptid))
+    thread = inf_tid_to_thread (inf, -1);
+  else
+    thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
+
+  if (!thread || thread->port == MACH_PORT_NULL)
+    {
+      /* TID is dead; try and find a new thread.  */
+      if (inf_update_procs (inf) && inf->threads)
+ ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid);
+      /* The first
+         available
+         thread.  */
+      else
+ ptid = inferior_ptid; /* let wait_for_inferior handle exit case */
+    }
+
+  if (thread
+      && !ptid_equal (ptid, minus_one_ptid)
+      && status->kind != TARGET_WAITKIND_SPURIOUS
+      && inf->pause_sc == 0 && thread->pause_sc == 0)
+    /* If something actually happened to THREAD, make sure we
+       suspend it.  */
+    {
+      thread->sc = 1;
+      inf_update_suspends (inf);
+    }
+
+  inf_debug (inf, "returning ptid = %s, status = %s (%d)",
+     target_pid_to_str (ptid),
+     status->kind == TARGET_WAITKIND_EXITED ? "EXITED"
+     : status->kind == TARGET_WAITKIND_STOPPED ? "STOPPED"
+     : status->kind == TARGET_WAITKIND_SIGNALLED ? "SIGNALLED"
+     : status->kind == TARGET_WAITKIND_LOADED ? "LOADED"
+     : status->kind == TARGET_WAITKIND_SPURIOUS ? "SPURIOUS"
+     : "?", status->value.integer);
+
+  inferior_ptid = ptid;
+  return ptid;
+}
+
+static ptid_t
+gnu_wait (ptid_t ptid, struct target_waitstatus *status, int target_options)
+{
+  ptid_t event_ptid;
+  gnu_debug ("gnu_wait: [%s]", target_pid_to_str (ptid));
+  event_ptid = gnu_wait_1 (ptid, status, target_options);
+  gnu_debug ("          -> (status->kind = %d)\n", status->kind);
+  return event_ptid;
+}
+
+/* Return printable description of proc.  */
+char *
+proc_string (struct proc *proc)
+{
+  static char tid_str[80];
+
+  if (proc_is_task (proc))
+    xsnprintf (tid_str, sizeof (tid_str), "process %d", proc->inf->pid);
+  else
+    xsnprintf (tid_str, sizeof (tid_str), "Thread %d.%d",
+       proc->inf->pid, proc->tid);
+  return tid_str;
+}
+
+void
+gnu_fetch_registers (struct regcache *regcache, int regno)
+{
+  gnu_debug ("gnu_fetch_registers() regno=%d\n", regno);
+  return gnu_fetch_registers_1 (NULL, regcache, regno);
+}
+
+void
+gnu_store_registers (struct regcache *regcache, int regno)
+{
+  gnu_debug ("gnu_store_registers() regno=%d\n", regno);
+  return gnu_store_registers_1 (NULL, regcache, regno);
+}
+
+/* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in
+   gdb's address space.  Return 0 on failure; number of bytes read
+   otherwise.  */
+int
+gnu_read_inferior (task_t task, CORE_ADDR addr, unsigned char *myaddr,
+   int length)
+{
+  error_t err;
+  vm_address_t low_address = (vm_address_t) trunc_page (addr);
+  vm_size_t aligned_length =
+    (vm_size_t) round_page (addr + length) - low_address;
+  pointer_t copied;
+  int copy_count;
+
+  /* Get memory from inferior with page aligned addresses.  */
+  err = vm_read (task, low_address, aligned_length, &copied, &copy_count);
+  if (err)
+    return 0;
+
+  err = hurd_safe_copyin (myaddr, (void *) (addr - low_address + copied),
+  length);
+  if (err)
+    {
+      warning (_("Read from inferior faulted: %s"), safe_strerror (err));
+      length = 0;
+    }
+
+  err = vm_deallocate (mach_task_self (), copied, copy_count);
+  if (err)
+    warning (_("gnu_read_inferior vm_deallocate failed: %s"),
+     safe_strerror (err));
+
+  return length;
+}
+
+#define CHK_GOTO_OUT(str,ret) \
+ do if (ret != KERN_SUCCESS) { errstr = #str; goto out; } while(0)
+
+struct vm_region_list
+{
+  struct vm_region_list *next;
+  vm_prot_t protection;
+  vm_address_t start;
+  vm_size_t length;
+};
+/*struct obstack region_obstack;*/
+
+/* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
+   task's address space.  */
+int
+gnu_write_inferior (task_t task, CORE_ADDR addr, const char *myaddr,
+    int length)
+{
+  error_t err = 0;
+  vm_address_t low_address = (vm_address_t) trunc_page (addr);
+  vm_size_t aligned_length =
+    (vm_size_t) round_page (addr + length) - low_address;
+  pointer_t copied;
+  int copy_count;
+  int deallocate = 0;
+
+  char *errstr = "Bug in gnu_write_inferior";
+
+  struct vm_region_list *region_element;
+  struct vm_region_list *region_head = (struct vm_region_list *) NULL;
+
+  /* Get memory from inferior with page aligned addresses.  */
+  err = vm_read (task, low_address, aligned_length, &copied, &copy_count);
+  CHK_GOTO_OUT ("gnu_write_inferior vm_read failed", err);
+
+  deallocate++;
+
+  err = hurd_safe_copyout ((void *) (addr - low_address + copied),
+   myaddr, length);
+  CHK_GOTO_OUT ("Write to inferior faulted", err);
+
+  /*obstack_init (&region_obstack); */
+
+  /* Do writes atomically.
+     First check for holes and unwritable memory.  */
+  {
+    vm_size_t remaining_length = aligned_length;
+    vm_address_t region_address = low_address;
+
+    struct vm_region_list *scan;
+
+    while (region_address < low_address + aligned_length)
+      {
+ vm_prot_t protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ boolean_t shared;
+ mach_port_t object_name;
+ vm_offset_t offset;
+ vm_size_t region_length = remaining_length;
+ vm_address_t old_address = region_address;
+
+ err = vm_region (task,
+ &region_address,
+ &region_length,
+ &protection,
+ &max_protection,
+ &inheritance, &shared, &object_name, &offset);
+ CHK_GOTO_OUT ("vm_region failed", err);
+
+ /* Check for holes in memory.  */
+ if (old_address != region_address)
+  {
+    warning (_("No memory at 0x%x. Nothing written"), old_address);
+    err = KERN_SUCCESS;
+    length = 0;
+    goto out;
+  }
+
+ if (!(max_protection & VM_PROT_WRITE))
+  {
+    warning (_("Memory at address 0x%x is unwritable. "
+       "Nothing written"), old_address);
+    err = KERN_SUCCESS;
+    length = 0;
+    goto out;
+  }
+
+ /* Chain the regions for later use.  */
+ /*region_element = */
+ /*(struct vm_region_list *) */
+ /*obstack_alloc (&region_obstack, sizeof (struct vm_region_list)); */
+ region_element =
+  (struct vm_region_list *) malloc (sizeof (struct vm_region_list));
+
+ region_element->protection = protection;
+ region_element->start = region_address;
+ region_element->length = region_length;
+
+ /* Chain the regions along with protections.  */
+ region_element->next = region_head;
+ region_head = region_element;
+
+ region_address += region_length;
+ remaining_length = remaining_length - region_length;
+      }
+
+    /* If things fail after this, we give up.
+       Somebody is messing up inferior_task's mappings.  */
+
+    /* Enable writes to the chained vm regions.  */
+    for (scan = region_head; scan; scan = scan->next)
+      {
+ if (!(scan->protection & VM_PROT_WRITE))
+  {
+    err = vm_protect (task,
+      scan->start,
+      scan->length,
+      FALSE, scan->protection | VM_PROT_WRITE);
+    CHK_GOTO_OUT ("vm_protect: enable write failed", err);
+  }
+      }
+
+    err = vm_write (task, low_address, copied, aligned_length);
+    CHK_GOTO_OUT ("vm_write failed", err);
+
+    /* Set up the original region protections, if they were changed.  */
+    for (scan = region_head; scan; scan = scan->next)
+      {
+ if (!(scan->protection & VM_PROT_WRITE))
+  {
+    err = vm_protect (task,
+      scan->start,
+      scan->length, FALSE, scan->protection);
+    CHK_GOTO_OUT ("vm_protect: enable write failed", err);
+  }
+      }
+  }
+
+out:
+  if (deallocate)
+    {
+      /*obstack_free (&region_obstack, 0); */
+
+      (void) vm_deallocate (mach_task_self (), copied, copy_count);
+    }
+
+  if (err != KERN_SUCCESS)
+    {
+      warning (_("%s: %s"), errstr, mach_error_string (err));
+      return 0;
+    }
+
+  return length;
+}
+
+static int
+gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_read_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret);
+      return -1;
+    }
+  return 0;
+}
+
+static int
+gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_write_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length,
+ ret);
+      return -1;
+    }
+  return 0;
+}
+
+static void
+gnu_request_interrupt (void)
+{
+  printf ("gnu_request_interrupt not support!\n");
+  exit (-1);
+}
+
+/* Helper function for child_wait and the derivatives of child_wait.
+   HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
+   translation of that in OURSTATUS.  */
+void
+store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
+{
+  if (WIFEXITED (hoststatus))
+    {
+      ourstatus->kind = TARGET_WAITKIND_EXITED;
+      ourstatus->value.integer = WEXITSTATUS (hoststatus);
+    }
+  else if (!WIFSTOPPED (hoststatus))
+    {
+      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+      ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus));
+    }
+  else
+    {
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus));
+    }
+}
+
+/* Validates INF's task suspend count.  If it's higher than we expect,
+   verify with the user before `stealing' the extra count.  */
+static void
+inf_validate_task_sc (struct inf *inf)
+{
+  char *noise;
+  mach_msg_type_number_t noise_len = 0;
+  struct procinfo *pi;
+  mach_msg_type_number_t pi_len = 0;
+  int info_flags = PI_FETCH_TASKINFO;
+  int suspend_count = -1;
+  error_t err;
+
+retry:
+  err = proc_getprocinfo (proc_server, inf->pid, &info_flags,
+  (procinfo_t *) & pi, &pi_len, &noise, &noise_len);
+  if (err)
+    {
+      inf->task->dead = 1; /* oh well */
+      return;
+    }
+
+  if (inf->task->cur_sc < pi->taskinfo.suspend_count && suspend_count == -1)
+    {
+      /* The proc server might have suspended the task while stopping
+         it.  This happens when the task is handling a traced signal.
+         Refetch the suspend count.  The proc server should be
+         finished stopping the task by now.  */
+      suspend_count = pi->taskinfo.suspend_count;
+      goto retry;
+    }
+
+  suspend_count = pi->taskinfo.suspend_count;
+
+  vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+  if (noise_len > 0)
+    vm_deallocate (mach_task_self (), (vm_address_t) pi, pi_len);
+
+  if (inf->task->cur_sc < suspend_count)
+    {
+#if 0
+      int abort;
+
+      target_terminal_ours (); /* Allow I/O.  */
+      abort = !query (_("Pid %d has an additional task suspend count of %d;"
+ " clear it? "), inf->pid,
+      suspend_count - inf->task->cur_sc);
+      target_terminal_inferior (); /* Give it back to the child.  */
+
+      if (abort)
+ error (_("Additional task suspend count left untouched."));
+#endif
+
+      //need fix!
+      inf->task->cur_sc = suspend_count;
+    }
+}
+
+void
+inf_resume (struct inf *inf)
+{
+  struct proc *thread;
+
+  inf_update_procs (inf);
+
+  for (thread = inf->threads; thread; thread = thread->next)
+    thread->sc = thread->resume_sc;
+
+  if (inf->task)
+    {
+      if (!inf->pending_execs)
+ /* Try to make sure our task count is correct -- in the case where
+   we're waiting for an exec though, things are too volatile, so just
+   assume things will be reasonable (which they usually will be).  */
+ inf_validate_task_sc (inf);
+      inf->task->sc = 0;
+    }
+
+  inf_update_suspends (inf);
+}
+
+/* Converts a thread port to a struct proc.  */
+struct proc *
+inf_port_to_thread (struct inf *inf, mach_port_t port)
+{
+  struct proc *thread = inf->threads;
+
+  while (thread)
+    if (thread->port == port)
+      return thread;
+    else
+      thread = thread->next;
+  return 0;
+}
+
+error_t
+S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
+   thread_t thread_port, task_t task_port,
+   int exception, int code, int subcode)
+{
+  struct inf *inf = waiting_inf;
+  struct proc *thread = inf_port_to_thread (inf, thread_port);
+
+  inf_debug (waiting_inf,
+     "S_exception_raise_request thread = %d, task = %d, exc = %d,
code = %d, subcode = %d",
+     thread_port, task_port, exception, code, subcode);
+
+  if (!thread)
+    /* We don't know about thread?  */
+    {
+      inf_update_procs (inf);
+      thread = inf_port_to_thread (inf, thread_port);
+      if (!thread)
+ /* Give up, the generating thread is gone.  */
+ return 0;
+    }
+
+  mach_port_deallocate (mach_task_self (), thread_port);
+  mach_port_deallocate (mach_task_self (), task_port);
+
+  if (!thread->aborted)
+    /* THREAD hasn't been aborted since this exception happened (abortion
+       clears any exception state), so it must be real.  */
+    {
+      /* Store away the details; this will destroy any previous info.  */
+      inf->wait.thread = thread;
+
+      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
+
+      if (exception == EXC_BREAKPOINT)
+ /* GDB likes to get SIGTRAP for breakpoints.  */
+ {
+  inf->wait.status.value.sig = GDB_SIGNAL_TRAP;
+  mach_port_deallocate (mach_task_self (), reply_port);
+ }
+      else
+ /* Record the exception so that we can forward it later.  */
+ {
+  if (thread->exc_port == port)
+    {
+      inf_debug (waiting_inf, "Handler is thread exception port <%d>",
+ thread->saved_exc_port);
+      inf->wait.exc.handler = thread->saved_exc_port;
+    }
+  else
+    {
+      inf_debug (waiting_inf, "Handler is task exception port <%d>",
+ inf->task->saved_exc_port);
+      inf->wait.exc.handler = inf->task->saved_exc_port;
+      gdb_assert (inf->task->exc_port == port);
+    }
+  if (inf->wait.exc.handler != MACH_PORT_NULL)
+    /* Add a reference to the exception handler.  */
+    mach_port_mod_refs (mach_task_self (),
+ inf->wait.exc.handler, MACH_PORT_RIGHT_SEND,
+ 1);
+
+  inf->wait.exc.exception = exception;
+  inf->wait.exc.code = code;
+  inf->wait.exc.subcode = subcode;
+  inf->wait.exc.reply = reply_port;
+
+  /* Exceptions are encoded in the signal space by putting
+     them after _NSIG; this assumes they're positive (and not
+     extremely large)!  */
+  inf->wait.status.value.sig =
+    gdb_signal_from_host (_NSIG + exception);
+ }
+    }
+  else
+    /* A supppressed exception, which ignore.  */
+    {
+      inf->wait.suppress = 1;
+      mach_port_deallocate (mach_task_self (), reply_port);
+    }
+  return 0;
+}
+
+error_t
+S_proc_wait_reply (mach_port_t reply, error_t err,
+   int status, int sigcode, rusage_t rusage, pid_t pid)
+{
+  struct inf *inf = waiting_inf;
+
+  inf_debug (inf,
+     "S_proc_wait_reply  err = %s, pid = %d, status = 0x%x, sigcode = %d",
+     err ? safe_strerror (err) : "0", pid, status, sigcode);
+
+  if (err && proc_wait_pid && (!inf->task || !inf->task->port))
+    /* Ack.  The task has died, but the task-died notification code didn't
+       tell anyone because it thought a more detailed reply from the
+       procserver was forthcoming.  However, we now learn that won't
+       happen...  So we have to act like the task just died, and this time,
+       tell the world.  */
+    inf_task_died_status (inf);
+
+  if (--proc_waits_pending == 0)
+    /* PROC_WAIT_PID represents the most recent wait.  We will always get
+       replies in order because the proc server is single threaded.  */
+    proc_wait_pid = 0;
+
+  inf_debug (inf, "waits pending now: %d", proc_waits_pending);
+
+  if (err)
+    {
+      if (err != EINTR)
+ {
+  /*warning (_("Can't wait for pid %d: %s"), */
+  /*inf->pid, safe_strerror (err)); */
+  inf->no_wait = 1;
+
+  /* Since we can't see the inferior's signals, don't trap them.  */
+  inf_set_traced (inf, 0);
+ }
+    }
+  else if (pid == inf->pid)
+    {
+      store_waitstatus (&inf->wait.status, status);
+      if (inf->wait.status.kind == TARGET_WAITKIND_STOPPED)
+ /* The process has sent us a signal, and stopped itself in a sane
+   state pending our actions.  */
+ {
+  inf_debug (inf, "process has stopped itself");
+  inf->stopped = 1;
+ }
+    }
+  else
+    inf->wait.suppress = 1; /* Something odd happened.  Ignore.  */
+
+  return 0;
+}
+
+error_t
+S_msg_sig_post_untraced_reply (mach_port_t reply, error_t err)
+{
+  struct inf *inf = waiting_inf;
+
+  if (err == EBUSY)
+    /* EBUSY is what we get when the crash server has grabbed control of the
+       process and doesn't like what signal we tried to send it.  Just act
+       like the process stopped (using a signal of 0 should mean that the
+       *next* time the user continues, it will pass signal 0, which the crash
+       server should like).  */
+    {
+      inf->wait.status.kind = TARGET_WAITKIND_STOPPED;
+      inf->wait.status.value.sig = GDB_SIGNAL_0;
+    }
+  else if (err)
+    warning (_("Signal delivery failed: %s"), safe_strerror (err));
+
+  if (err)
+    /* We only get this reply when we've posted a signal to a process which we
+       thought was stopped, and which we expected to continue after the signal.
+       Given that the signal has failed for some reason, it's reasonable to
+       assume it's still stopped.  */
+    inf->stopped = 1;
+  else
+    inf->wait.suppress = 1;
+  return 0;
+}
+
+error_t
+S_msg_sig_post_reply (mach_port_t reply, error_t err)
+{
+  printf ("bug in S_msg_sig_post_reply!!\n");
+  exit (-238);
+}
+
+error_t
+do_mach_notify_dead_name (mach_port_t notify, mach_port_t dead_port)
+{
+  struct inf *inf = waiting_inf;
+
+  inf_debug (waiting_inf, "port = %d", dead_port);
+
+  if (inf->task && inf->task->port == dead_port)
+    {
+      proc_debug (inf->task, "is dead");
+      inf->task->port = MACH_PORT_NULL;
+      if (proc_wait_pid == inf->pid)
+ /* We have a wait outstanding on the process, which will return more
+   detailed information, so delay until we get that.  */
+ inf->wait.suppress = 1;
+      else
+ /* We never waited for the process (maybe it wasn't a child), so just
+   pretend it got a SIGKILL.  */
+ inf_task_died_status (inf);
+    }
+  else
+    {
+      struct proc *thread = inf_port_to_thread (inf, dead_port);
+
+      if (thread)
+ {
+  proc_debug (thread, "is dead");
+  thread->port = MACH_PORT_NULL;
+ }
+
+      if (inf->task->dead)
+ /* Since the task is dead, its threads are dying with it.  */
+ inf->wait.suppress = 1;
+    }
+
+  mach_port_deallocate (mach_task_self (), dead_port);
+  inf->threads_up_to_date = 0; /* Just in case.  */
+
+  return 0;
+}
+
+static error_t
+ill_rpc (char *fun)
+{
+  warning (_("illegal rpc: %s"), fun);
+  return 0;
+}
+
+error_t
+do_mach_notify_no_senders (mach_port_t notify, mach_port_mscount_t count)
+{
+  return ill_rpc ("do_mach_notify_no_senders");
+}
+
+error_t
+do_mach_notify_port_deleted (mach_port_t notify, mach_port_t name)
+{
+  return ill_rpc ("do_mach_notify_port_deleted");
+}
+
+error_t
+do_mach_notify_msg_accepted (mach_port_t notify, mach_port_t name)
+{
+  return ill_rpc ("do_mach_notify_msg_accepted");
+}
+
+error_t
+do_mach_notify_port_destroyed (mach_port_t notify, mach_port_t name)
+{
+  return ill_rpc ("do_mach_notify_port_destroyed");
+}
+
+error_t
+do_mach_notify_send_once (mach_port_t notify)
+{
+  return ill_rpc ("do_mach_notify_send_once");
+}
+
+error_t
+S_proc_setmsgport_reply (mach_port_t reply, error_t err,
+ mach_port_t old_msg_port)
+{
+  return ill_rpc ("S_proc_setmsgport_reply");
+}
+
+error_t
+S_proc_getmsgport_reply (mach_port_t reply, error_t err, mach_port_t msg_port)
+{
+  return ill_rpc ("S_proc_getmsgport_reply");
+}
+
+static struct target_ops gnu_target_ops = {
+  gnu_create_inferior,
+  gnu_attach,
+  gnu_kill,
+  gnu_detach,
+  gnu_mourn,
+  gnu_join,
+  gnu_thread_alive,
+  gnu_resume,
+  gnu_wait,
+  gnu_fetch_registers,
+  gnu_store_registers,
+  NULL, /* prepare_to_access_memory */
+  NULL, /* done_accessing_memory */
+  gnu_read_memory,
+  gnu_write_memory,
+  NULL, /* look_up_symbols */
+  gnu_request_interrupt,
+  NULL, /* read_auxv */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* read_offsets */
+  NULL, /* get_tls_address */
+  NULL, /* qxfer_spu */
+  NULL, /* hostio_last_error */
+  NULL, /* qxfer_osdata */
+  NULL, /* qxfer_siginfo */
+  NULL, /* supports_non_stop */
+  NULL, /* async */
+  NULL, /* start_non_stop */
+  NULL, /* supports_multi_process */
+  NULL, /* handle_monitor_command */
+};
+
+void
+_initialize_gnu_nat (void)
+{
+  proc_server = getproc ();
+}
+
+static void
+initialize_low_arch ()
+{
+  init_registers_i386 ();
+  gnu_tdesc = tdesc_i386;
+}
+
+void
+initialize_low (void)
+{
+  set_target_ops (&gnu_target_ops);
+  initialize_low_arch ();
+  _initialize_gnu_nat ();
+}
diff --git a/gdb/gdbserver/gnu-low.h b/gdb/gdbserver/gnu-low.h
new file mode 100644
index 0000000..fa211d2
--- /dev/null
+++ b/gdb/gdbserver/gnu-low.h
@@ -0,0 +1,270 @@
+/* Copyright (C) 2010-2013 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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/exception.h>
+#include <mach/message.h>
+#include <mach/notify.h>
+#include <mach/vm_attributes.h>
+
+#include <hurd.h>
+#include <hurd/interrupt.h>
+#include <hurd/msg.h>
+#include <hurd/msg_request.h>
+#include <hurd/process.h>
+/* All info needed to access an architecture/mode's registers.  */
+
+struct regs_info
+{
+  /* Regset support bitmap: 1 for registers that are transferred as a part
+     of a regset, 0 for ones that need to be handled individually.  This
+     can be NULL if all registers are transferred with regsets or regsets
+     are not supported.  */
+  unsigned char *regset_bitmap;
+
+  /* Info used when accessing registers with PTRACE_PEEKUSER /
+     PTRACE_POKEUSER.  This can be NULL if all registers are
+     transferred with regsets  .*/
+  struct usrregs_info *usrregs;
+
+#ifdef HAVE_gnu_REGSETS
+  /* Info used when accessing registers with regsets.  */
+  struct regsets_info *regsets_info;
+#endif
+};
+
+#define ptid_of(proc) ((proc)->head.id)
+#define pid_of(proc) ptid_get_pid ((proc)->head.id)
+#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
+
+#define get_lwp(inf) ((struct lwp_info *)(inf))
+#define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr)))
+#define get_lwp_thread(proc) ((struct thread_info *) \
+      find_inferior_id (&all_threads, \
+ get_lwp (proc)->head.id))
+
+#define PROC_TID_TASK (-1)
+#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE
+#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT
+#define THREAD_STATE_SET_TRACED(state) \
+   ((struct i386_thread_state *) (state))->efl |= 0x100
+#define THREAD_STATE_CLEAR_TRACED(state) \
+   ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1)
+
+#define proc_is_task(proc) ((proc)->tid == PROC_TID_TASK)
+#define proc_is_thread(proc) ((proc)->tid != PROC_TID_TASK)
+
+#ifndef PIDGET
+#define PIDGET(PTID) (ptid_get_pid (PTID))
+#define TIDGET(PTID) (ptid_get_lwp (PTID))
+#define MERGEPID(PID, TID) ptid_build (PID, TID, 0)
+#endif
+
+struct exc_state
+  {
+    int exception; /* The exception code.  */
+    int code, subcode;
+    mach_port_t handler; /* The real exception port to handle this.  */
+    mach_port_t reply; /* The reply port from the exception call.  */
+  };
+
+/* The results of the last wait an inf did.  */
+struct inf_wait
+  {
+    struct target_waitstatus status; /* The status returned to gdb.  */
+    struct exc_state exc; /* The exception that caused us to return.  */
+    struct proc *thread; /* The thread in question.  */
+    int suppress; /* Something trivial happened.  */
+  };
+
+struct proc
+{
+ thread_t port; /* The task or thread port.  */
+ int tid; /* The GDB pid (actually a thread id).  */
+ int num; /* An id number for threads, to print.  */
+
+ mach_port_t saved_exc_port; /* The task/thread's real exception port.  */
+ mach_port_t exc_port; /* Our replacement, which for.  */
+
+ int sc; /* Desired suspend count.   */
+ int cur_sc; /* Implemented suspend count.  */
+ int run_sc; /* Default sc when the program is running.  */
+ int pause_sc; /* Default sc when gdb has control.  */
+ int resume_sc; /* Sc resulting from the last resume.  */
+ int detach_sc; /* SC to leave around when detaching
+   from program.  */
+
+ thread_state_data_t state; /* Registers, &c.  */
+ int state_valid:1; /* True if STATE is up to date.  */
+ int state_changed:1;
+
+ int aborted:1; /* True if thread_abort has been called.  */
+ int dead:1; /* We happen to know it's actually dead.  */
+
+ /* Bit mask of registers fetched by gdb.  This is used when we re-fetch
+   STATE after aborting the thread, to detect that gdb may have out-of-date
+   information.  */
+ unsigned long fetched_regs;
+
+ struct inf *inf; /* Where we come from.  */
+
+ struct proc *next;
+};
+
+struct inf
+{
+ /* Fields describing the current inferior.  */
+
+ struct proc *task; /* The mach task.   */
+ struct proc *threads; /* A linked list of all threads in TASK.  */
+
+ /* True if THREADS needn't be validated by querying the task.  We
+   assume that we and the task in question are the only ones
+   frobbing the thread list, so as long as we don't let any code
+   run, we don't have to worry about THREADS changing.  */
+ int threads_up_to_date;
+
+ pid_t pid; /* The real system PID.  */
+
+ struct inf_wait wait; /* What to return from target_wait.  */
+
+ /* One thread proc in INF may be in `single-stepping mode'.  This
+   is it.  */
+ struct proc *step_thread;
+
+ /* The thread we think is the signal thread.  */
+ struct proc *signal_thread;
+
+ mach_port_t event_port; /* Where we receive various msgs.  */
+
+ /* True if we think at least one thread in the inferior could currently be
+   running.  */
+ unsigned int running:1;
+
+ /* True if the process has stopped (in the proc server sense).  Note that
+   since a proc server `stop' leaves the signal thread running, the inf can
+   be RUNNING && STOPPED...  */
+ unsigned int stopped:1;
+
+ /* True if the inferior has no message port.  */
+ unsigned int nomsg:1;
+
+ /* True if the inferior is traced.  */
+ unsigned int traced:1;
+
+ /* True if we shouldn't try waiting for the inferior, usually because we
+   can't for some reason.  */
+ unsigned int no_wait:1;
+
+ /* When starting a new inferior, we don't try to validate threads until all
+   the proper execs have been done.  This is a count of how many execs we
+   expect to happen.  */
+ unsigned pending_execs;
+
+ /* Fields describing global state.  */
+
+ /* The task suspend count used when gdb has control.  This is normally 1 to
+   make things easier for us, but sometimes (like when attaching to vital
+   system servers) it may be desirable to let the task continue to run
+   (pausing individual threads as necessary).  */
+ int pause_sc;
+
+ /* The task suspend count left when detaching from a task.  */
+ int detach_sc;
+
+ /* The initial values used for the run_sc and pause_sc of newly discovered
+   threads -- see the definition of those fields in struct proc.  */
+ int default_thread_run_sc;
+ int default_thread_pause_sc;
+ int default_thread_detach_sc;
+
+ /* True if the process should be traced when started/attached.  Newly
+   started processes *must* be traced at first to exec them properly, but
+   if this is false, tracing is turned off as soon it has done so.  */
+ int want_signals;
+
+ /* True if exceptions from the inferior process should be trapped.  This
+   must be on to use breakpoints.  */
+ int want_exceptions;
+};
+
+/* Forward decls */
+struct inf *make_inf ();
+void inf_clear_wait (struct inf *inf);
+void inf_cleanup (struct inf *inf);
+void inf_startup (struct inf *inf, int pid);
+int inf_update_suspends (struct inf *inf);
+void inf_set_pid (struct inf *inf, pid_t pid);
+void inf_validate_procs (struct inf *inf);
+void inf_steal_exc_ports (struct inf *inf);
+void inf_restore_exc_ports (struct inf *inf);
+struct proc *inf_tid_to_proc (struct inf *inf, int tid);
+void inf_set_threads_resume_sc (struct inf *inf,
+ struct proc *run_thread,
+ int run_others);
+int inf_set_threads_resume_sc_for_signal_thread (struct inf *inf);
+void inf_suspend (struct inf *inf);
+void inf_resume (struct inf *inf);
+void inf_set_step_thread (struct inf *inf, struct proc *proc);
+void inf_detach (struct inf *inf);
+void inf_attach (struct inf *inf, int pid);
+void inf_signal (struct inf *inf, enum gdb_signal sig);
+void inf_continue (struct inf *inf);
+int inf_update_procs (struct inf *inf);
+
+void proc_abort (struct proc *proc, int force);
+struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
+struct proc *_proc_free (struct proc *proc);
+int proc_update_sc (struct proc *proc);
+error_t proc_get_exception_port (struct proc *proc, mach_port_t * port);
+error_t proc_set_exception_port (struct proc *proc, mach_port_t port);
+static mach_port_t _proc_get_exc_port (struct proc *proc);
+void proc_steal_exc_port (struct proc *proc, mach_port_t exc_port);
+void proc_restore_exc_port (struct proc *proc);
+int proc_trace (struct proc *proc, int set);
+static void inf_validate_task_sc (struct inf *inf);
+static void inf_validate_procinfo (struct inf *inf);
+
+//gdbserver use ptid_t not the same as gdb does!
+static ptid_t gnu_ptid_build(int pid,long lwp,long tid);
+
+//add for erase warning
+extern const char * host_address_to_string (const void *addr);
+
+extern int debug_flags;
+#define inf_debug(_inf, msg, args...) \
+  do { struct inf *__inf = (_inf); \
+       debug ("{inf %d %s}: " msg, __inf->pid, \
+       host_address_to_string (__inf) , ##args); } while (0)
+
+#define proc_debug(_proc, msg, args...) \
+  do { struct proc *__proc = (_proc); \
+       debug ("{proc %d/%d %s}: " msg, \
+      __proc_pid (__proc), __proc->tid, \
+      host_address_to_string (__proc) , ##args); } while (0)
+
+#define debug(msg, args...) \
+ do { if (debug_flags) \
+        printf ("%s:%d: " msg "\r\n", \
+    __FILE__ , __LINE__ , ##args); } while (0)
+#ifndef safe_strerror
+#define safe_strerror(err) \
+ "XXXX"
+#endif
diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c
index df94d31..f3af499 100644
--- a/gdb/gdbserver/hostio.c
+++ b/gdb/gdbserver/hostio.c
@@ -25,6 +25,10 @@
 #include <limits.h>
 #include <unistd.h>

+#ifndef PATH_MAX
+#define PATH_MAX 512
+#endif
+
 extern int remote_debug;

 struct fd_list
diff --git a/gdb/gdbserver/i386gnu.mh b/gdb/gdbserver/i386gnu.mh
new file mode 100644
index 0000000..3bdffe7
--- /dev/null
+++ b/gdb/gdbserver/i386gnu.mh
@@ -0,0 +1,30 @@
+# Host: Intel 386 running the GNU Hurd
+NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \
+      exc_request_U.o exc_request_S.o
+
+# Use our own user stubs for the msg rpcs, so we can make them time out, in
+# case the program is fucked, or we guess the wrong signal thread.
+msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;'
+
+# ick
+MIGCOM = $(MIG) -cc cat - /dev/null
+
+# Reply servers need special massaging of the code mig generates, to make
+# them work correctly for error returns in some cases.
+%_reply_S.h %_reply_S.c: %_reply.defs
+ $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \
+ | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user
/dev/null -header /dev/null \
+ && $(AWK) -f $(srcdir)/reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c
+# Normal servers
+%_S.h %_S.c: %.defs
+ $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \
+ | $(MIGCOM) -sheader $*_S.h -server $*_S.c -user /dev/null -header /dev/null
+# User rpc stubs
+%_U.h %_U.c: %.defs
+ $(CPP) $(CPPFLAGS) $($*-MIGUFLAGS) -x c $< \
+ | $(MIGCOM) -sheader /dev/null -server /dev/null -user $*_U.c -header $*_U.h
+
+NAT_GENERATED_FILES = notify_S.h notify_S.c \
+ process_reply_S.h process_reply_S.c \
+ msg_reply_S.h msg_reply_S.c \
+ exc_request_U.h exc_request_U.c exc_request_S.h exc_request_S.c
diff --git a/gdb/gdbserver/msg.defs b/gdb/gdbserver/msg.defs
new file mode 100644
index 0000000..7c9fcd1
--- /dev/null
+++ b/gdb/gdbserver/msg.defs
@@ -0,0 +1 @@
+#include <hurd/msg.defs>
diff --git a/gdb/gdbserver/msg_reply.defs b/gdb/gdbserver/msg_reply.defs
new file mode 100644
index 0000000..049bfa8
--- /dev/null
+++ b/gdb/gdbserver/msg_reply.defs
@@ -0,0 +1 @@
+#include <hurd/msg_reply.defs>
diff --git a/gdb/gdbserver/notify.defs b/gdb/gdbserver/notify.defs
new file mode 100644
index 0000000..2014be5
--- /dev/null
+++ b/gdb/gdbserver/notify.defs
@@ -0,0 +1 @@
+#include <mach/notify.defs>
diff --git a/gdb/gdbserver/process_reply.defs b/gdb/gdbserver/process_reply.defs
new file mode 100644
index 0000000..824b5c6
--- /dev/null
+++ b/gdb/gdbserver/process_reply.defs
@@ -0,0 +1 @@
+#include <hurd/process_reply.defs>
diff --git a/gdb/gdbserver/reply_mig_hack.awk b/gdb/gdbserver/reply_mig_hack.awk
new file mode 100644
index 0000000..97e080f
--- /dev/null
+++ b/gdb/gdbserver/reply_mig_hack.awk
@@ -0,0 +1,122 @@
+# Reply server mig-output massager
+#
+#   Copyright (C) 1995-2013 Free Software Foundation, Inc.
+#
+#   Written by Miles Bader <miles@gnu.ai.mit.edu>
+#
+#   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 3, 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, see <http://www.gnu.org/licenses/>.
+#
+# This awk script hacks the output of mig-generated reply server code
+# so that it allows replies with just the error-code in them (as this is
+# how mig returns errors).
+#
+# It is highly, highly, dependent on the exact format of mig output.  Ick.
+#
+
+BEGIN { parse_phase = 0; }
+
+/^}/ { parse_phase = 0; }
+
+parse_phase == 0 && /^mig_internal void _X[a-zA-Z0-9_]*_reply/ {
+  # The start of a mig server routine.  Reset everything.  Note that we only
+  # mess with rpcs that have the suffix `_reply'.
+  num_args = 0;
+  num_checks = 0;
+  parse_phase = 1;
+  print; next;
+}
+
+parse_phase == 1 && /^[\t ]*typedef struct/ {
+  # The first structure in the server routine should describe the arguments
+  parse_phase = 2;
+  print; next;
+}
+
+parse_phase == 2 {
+  # The message header field in the args structure, which skip.
+  parse_phase = 3;
+  print; next;
+}
+
+parse_phase == 3 && /}/ {
+  # The args structure is over.
+  if (num_args > 1)
+    parse_phase = 5;
+  else
+    # There's no extra args that could screw up the normal mechanism for
+    # error returns, so we don't have to insert any new code.
+    parse_phase = 0;
+  print; next;
+}
+
+parse_phase == 3 {
+  # The type field for an argument.
+  arg_type_code_name[num_args] = $2;
+  sub (/;$/, "", arg_type_code_name[num_args]) # Get rid of the semi-colon
+  parse_phase = 4;
+  print; next;
+}
+
+parse_phase == 4 {
+  # The value field for an argument.
+  arg_name[num_args] = $2;
+  sub (/;$/, "", arg_name[num_args]) # Get rid of the semi-colon
+  arg_type[num_args] = $1;
+  num_args++;
+  parse_phase = 3;
+  print; next;
+}
+
+parse_phase == 5 && /^[ \t]*(auto|static) const mach_msg_type_t/ {
+  # The type check structure for an argument.
+  arg_check_name[num_checks] = $4;
+  num_checks++;
+  print; next;
+}
+
+parse_phase == 5 && /^[ \t]*mig_external kern_return_t/ {
+  # The declaration of the user server function for this rpc.
+  user_function_name = $3;
+  print; next;
+}
+
+parse_phase == 5 && /^#if[ \t]TypeCheck/ {
+  # The first args type checking statement; we need to insert our chunk of
+  # code that bypasses all the type checks if this is an error return, after
+  # which we're done until we get to the next function.  Handily, the size
+  # of mig's Reply structure is also the size of the alternate Request
+  # structure that we want to check for.
+  print "\tif (In0P->Head.msgh_size == sizeof (Reply)";
+  print "\t    && ! (In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)";
+  print "\t    && ! BAD_TYPECHECK(&In0P->" arg_type_code_name[0] ",
&" arg_check_name[0] ")";
+  print "\t    && In0P->" arg_name[0] " != 0)";
+  print "\t  /* Error return, only the error code argument is passed.  */";
+  print "\t  {";
+  # Force the function into a type that only takes the first two args, via
+  # the temp variable SFUN (is there another way to correctly do this cast?).
+  # This is possibly bogus, but easier than supplying bogus values for all
+  # the other args (we can't just pass 0 for them, as they might not
be scalar).
+  printf ("\t    kern_return_t (*sfun)(mach_port_t");
+  for (i = 0; i < num_args; i++)
+    printf (", %s", arg_type[i]);
+  printf (") = %s;\n", user_function_name);
+  print "\t    OutP->RetCode = (*(kern_return_t (*)(mach_port_t,
kern_return_t))sfun) (In0P->Head.msgh_request_port, In0P->"
arg_name[0] ");";
+  print "\t    return;";
+  print "\t  }";
+  print "";
+  parse_phase = 0;
+  print; next;
+}
+
+{ print; }
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 18d060c..20e88bf 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -91,7 +91,8 @@ typedef unsigned char gdb_byte;

 /* FIXME: This should probably be autoconf'd for.  It's an integer type at
    least the size of a (void *).  */
-typedef long long CORE_ADDR;
+//typedef long long CORE_ADDR;
+typedef long CORE_ADDR;

 typedef long long LONGEST;
 typedef unsigned long long ULONGEST;
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 9706d74..d6dd4f9 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -170,7 +170,6 @@ internal_error (const char *file, int line, const
char *fmt, ...)
 #define CELLSIZE 50

 /* Return the next entry in the circular buffer.  */
-
 static char *
 get_cell (void)
 {
@@ -181,6 +180,15 @@ get_cell (void)
   return buf[cell];
 }

+const char *
+host_address_to_string (const void *addr)
+{
+  char *str = get_cell ();
+
+  xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long)
addr, sizeof (addr)));
+  return str;
+}
+
 static char *
 decimal2str (char *sign, ULONGEST addr)
 {


-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-03  8:03 ` [PATCH 2/2] Port gdbserver to GNU/Hurd Yue Lu
@ 2013-09-03  9:38   ` Thomas Schwinge
  2013-09-03 11:11     ` Pedro Alves
  0 siblings, 1 reply; 25+ messages in thread
From: Thomas Schwinge @ 2013-09-03  9:38 UTC (permalink / raw)
  To: gdb-patches; +Cc: Luis Machado, bug-hurd, Yue Lu

[-- Attachment #1: Type: text/plain, Size: 2310 bytes --]

Hi!

For context, Yue Lu is a student participating in this year's Google
Summer of Code program, to port gdbserver to GNU Hurd, and is both a GDB
as well as a GNU Hurd newbie.  (So, be gentle.)  ;-)

On Tue, 3 Sep 2013 16:00:32 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
> This is my patch to port gdbserver to GNU/Hurd. Most of code are
> copied  from [gdb]/gdb/gnu-nat.c.

... and elsewhere.  Our strategy was to first get this into a basic
functional state:

> Now the gdbserver on GNU/Hurd can set breakpoint and check memory or
> register(but without float-register support).

So, this initial port just posted is a great milestone!  Especially so
given your previous lack of experience with both GDB and the Hurd -- both
of which are not always easy to grasp.

There are lots of things to be polished (Yue, don't worry -- this
entirely was to be expected), such as GDB coding standard, and changes
that are unrelated to your port, which all has to be cleared out before I
can commit this initial port to GDB upstream.

There is missing functionality, but we decided this can be enhanced piece
by piece once the initial port is accepted.

There is the issue of code sharing between GDB proper and gdbserver, a
strategy for which has been briefly discussed in
<http://news.gmane.org/find-root.php?message_id=%3CCAB8fV%3Djzv_rPHP3-HQVBA-pCNZNat6PNbh%2BOJEU7tZgQdKX3%2Bw%40mail.gmail.com%3E>.
Likewise for code sharing between the new Hurd gdbserver port and the
existing x86 Linux kernel port.  Again I suggest this to be done *after*
the initial port is accepted: this will turn into a nice (and easily
reviewable) series of cleanup patches à la: remove from GDB proper
gdb/gnu-nat.c:[function] and from gdbserver
gdb/gdbserver/gnu-low.c:[function], and add
gdb/common/gnu-low.c:[function], and so on.  Likewise for build
infrastructure that can be shared.

Does this strategy generally make sense to you GDB maintainers?


For the curious, in
<http://news.gmane.org/find-root.php?message_id=%3C87ppwqlgot.fsf%40kepler.schwinge.homeip.net%3E>
I describe the MIG usage in GDB.  (This message also states that ptrace
is a system call which it is not; it's a glibc library function using RPC
calls to implement its functionality.)


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-03  9:38   ` [PATCH 1/2] " Thomas Schwinge
@ 2013-09-03 11:11     ` Pedro Alves
  2013-09-03 13:09       ` Thomas Schwinge
                         ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: Pedro Alves @ 2013-09-03 11:11 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: gdb-patches, Luis Machado, bug-hurd, Yue Lu

On 09/03/2013 10:38 AM, Thomas Schwinge wrote:
> Hi!
> 
> For context, Yue Lu is a student participating in this year's Google
> Summer of Code program, to port gdbserver to GNU Hurd, and is both a GDB
> as well as a GNU Hurd newbie.  (So, be gentle.)  ;-)
> 
> On Tue, 3 Sep 2013 16:00:32 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
>> This is my patch to port gdbserver to GNU/Hurd. Most of code are
>> copied  from [gdb]/gdb/gnu-nat.c.
> 
> ... and elsewhere.  Our strategy was to first get this into a basic
> functional state:
> 
>> Now the gdbserver on GNU/Hurd can set breakpoint and check memory or
>> register(but without float-register support).
> 
> So, this initial port just posted is a great milestone!  Especially so
> given your previous lack of experience with both GDB and the Hurd -- both
> of which are not always easy to grasp.

Indeed!

> 
> There are lots of things to be polished (Yue, don't worry -- this
> entirely was to be expected), such as GDB coding standard, and changes
> that are unrelated to your port, which all has to be cleared out before I
> can commit this initial port to GDB upstream.
> 
> There is missing functionality, but we decided this can be enhanced piece
> by piece once the initial port is accepted.
> 
> There is the issue of code sharing between GDB proper and gdbserver, a
> strategy for which has been briefly discussed in
> <http://news.gmane.org/find-root.php?message_id=%3CCAB8fV%3Djzv_rPHP3-HQVBA-pCNZNat6PNbh%2BOJEU7tZgQdKX3%2Bw%40mail.gmail.com%3E>.

That has been further discussed recently:

 https://sourceware.org/ml/gdb-patches/2013-07/msg00788.html

and we ended up with putting native target files under the
new gdb/nat/ directory, rather than in gdb/common/:

 https://sourceware.org/ml/gdb-patches/2013-08/msg00618.html

> Likewise for code sharing between the new Hurd gdbserver port and the
> existing x86 Linux kernel port.  Again I suggest this to be done *after*
> the initial port is accepted: this will turn into a nice (and easily
> reviewable) series of cleanup patches à la: remove from GDB proper
> gdb/gnu-nat.c:[function] and from gdbserver
> gdb/gdbserver/gnu-low.c:[function], and add
> gdb/common/gnu-low.c:[function], and so on.  Likewise for build
> infrastructure that can be shared.
> 
> Does this strategy generally make sense to you GDB maintainers?

I've been thinking about this this morning, after seeing these
patches.

For new gdbserver ports, this path just seems to swim further away from
a full sharing approach, by adding lots duplication as first step, and
actually making it hard to see what exactly needed to be changed/adapted
for gdbserver use, and puts the tree in a state where any further changes
for the GNU/Hurd target will need to be considered twice going further,
exactly what we're fighting against with the existing ports.  I think
that strategy ultimately is slower to get at where we want to, and
is actually more work than an alternative that does things the other
way around.

I checked out Yue's git branch, and diffed gdb/gnu-nat.c vs
gdbserver/gnu-low.c, and gdb/i386gnu-nat.c vs gdbserver/gnu-i386-low.c.
I didn't diff the rest of the files, as I assume they'll probably have
even less divergence.  There are several spurious formatting differences,
and some reordering of functions, but for the most port, the code is
mostly identical.  There's some expected necessary adjustment to GDBserver's
interfaces, but it turns out it's not that much.  We've been converging
gdb's and gdbserver's interfaces throughout the years, and it now shows.

So my idea would be, instead of adding the new files under gdbserver,
to remove the spurious differences (formatting, reordering, etc.) that
were introduced in the gdbserver copies of the files, eliminating the
unnecessary divergence, and then fold back the resulting differences into
the original gdb/gnu-nat.c etc. files, guarded by #ifdef GDBSERVER.  Some
cleanups might have been identified and done in the gdbserver files, and
it might make sense to do those as preparatory work, in the original files.
This should result in smaller patches, and will actually avoid
the need for most of the polishing Thomas mentioned, and as consequence
review burden -- reviewing the new gnu-low.c etc., for GNU conventions,
formatting, or even appropriate use of the Hurd's debug APIs etc., is
just unnecessary that way, by design, and we'll be able to focus on the
bits that are the real new code -- the glue between the target and gdb, and
the target and gdbserver.

The current state of the work isn't wasted at all!  And I don't
think following this direction is that much work.  I'd do this my
literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and
use git diff to guide me through, in identifying what would need to
be restored, and guarded with #if[n]def GDBSERVER.  #ifdef GDBSERVER
is how we've adapting shared code under gdb/common/ and gdb/nat/
to work on both programs.  Medium/long term, core gdb and core
gdbserver target interface differences should converge further, and
the #ifdefs disappear, but for now that's a necessary evil.

It's fine to leave bits of functionality disabled on gdbserver,
wrapped in #ifndef GDBSERVER.  After that initial work is committed,
we can then easily progress the gdbserver port by just looking for
those #ifdefs.

It's fine with me to leave the existing native files under gdb/ while
doing this; it's probably easier that way.  Moving them under gdb/nat/
can be left for a cleanup step further down the road.

Could we try that approach?

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-03 11:11     ` Pedro Alves
@ 2013-09-03 13:09       ` Thomas Schwinge
  2013-09-04  1:47         ` Yue Lu
  2013-09-04  1:38       ` Yue Lu
  2013-09-05 10:54       ` Yue Lu
  2 siblings, 1 reply; 25+ messages in thread
From: Thomas Schwinge @ 2013-09-03 13:09 UTC (permalink / raw)
  To: Pedro Alves, Yue Lu; +Cc: gdb-patches, Luis Machado, bug-hurd

[-- Attachment #1: Type: text/plain, Size: 1096 bytes --]

Hi!

On Tue, 03 Sep 2013 12:11:02 +0100, Pedro Alves <palves@redhat.com> wrote:
> On 09/03/2013 10:38 AM, Thomas Schwinge wrote:
> > [strategy]
> 
> I've been thinking about this this morning, after seeing these
> patches.
> 
> For new gdbserver ports, this path just seems to swim further away from
> a full sharing approach, by adding lots duplication as first step, [...]

> So my idea would be, [...]

Understood, and yes, your argumentation is reasonable.

> I'd do this [by]
> literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and
> use git diff to guide me through, in identifying what would need to
> be restored, and guarded with #if[n]def GDBSERVER.  [...]

Yes, that's a nice technique for displaying and integrating the
differences between the existing Hurd native port's files and the new
gdbserver port's.  Yue, does the approach of diffing the files as Pedro
described make sense to you?  Please tell if you need help with how to
use Git to do that, etc.

> Could we try that approach?

Thanks for the input!


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-03 11:11     ` Pedro Alves
  2013-09-03 13:09       ` Thomas Schwinge
@ 2013-09-04  1:38       ` Yue Lu
  2013-09-05 10:54       ` Yue Lu
  2 siblings, 0 replies; 25+ messages in thread
From: Yue Lu @ 2013-09-04  1:38 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

Thanks for your review!

On Tue, Sep 3, 2013 at 7:11 PM, Pedro Alves <palves@redhat.com> wrote:
>
> For new gdbserver ports, this path just seems to swim further away from
> a full sharing approach, by adding lots duplication as first step, and
> actually making it hard to see what exactly needed to be changed/adapted
> for gdbserver use, and puts the tree in a state where any further changes
> for the GNU/Hurd target will need to be considered twice going further,
> exactly what we're fighting against with the existing ports.  I think
> that strategy ultimately is slower to get at where we want to, and
> is actually more work than an alternative that does things the other
> way around.
>
> I checked out Yue's git branch, and diffed gdb/gnu-nat.c vs
> gdbserver/gnu-low.c, and gdb/i386gnu-nat.c vs gdbserver/gnu-i386-low.c.
> I didn't diff the rest of the files, as I assume they'll probably have
> even less divergence.  There are several spurious formatting differences,
> and some reordering of functions, but for the most port, the code is

The reason is, at first, I plan to write the new file, and then I
found one function can be re-use, so I copy it, it call another one,
so I copy the another one. One by one, so there are some reordering of
functions. The formatting differences comes with "indent program", I
found this from GNU_CODIND_STYLE
(http://www.gnu.org/prep/standards/standards.html ).

> mostly identical.  There's some expected necessary adjustment to GDBserver's
> interfaces, but it turns out it's not that much.  We've been converging
> gdb's and gdbserver's interfaces throughout the years, and it now shows.

I have found some interfaces which must be adjustment. Like use the
lwp as tid in structure ptid_t.

> So my idea would be, instead of adding the new files under gdbserver,
> to remove the spurious differences (formatting, reordering, etc.) that
> were introduced in the gdbserver copies of the files, eliminating the
> unnecessary divergence, and then fold back the resulting differences into
> the original gdb/gnu-nat.c etc. files, guarded by #ifdef GDBSERVER.  Some
> cleanups might have been identified and done in the gdbserver files, and
> it might make sense to do those as preparatory work, in the original files.
> This should result in smaller patches, and will actually avoid
> the need for most of the polishing Thomas mentioned, and as consequence
> review burden -- reviewing the new gnu-low.c etc., for GNU conventions,
> formatting, or even appropriate use of the Hurd's debug APIs etc., is
> just unnecessary that way, by design, and we'll be able to focus on the
> bits that are the real new code -- the glue between the target and gdb, and
> the target and gdbserver.
>
> The current state of the work isn't wasted at all!  And I don't
> think following this direction is that much work.  I'd do this my
> literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and
> use git diff to guide me through, in identifying what would need to
> be restored, and guarded with #if[n]def GDBSERVER.  #ifdef GDBSERVER
> is how we've adapting shared code under gdb/common/ and gdb/nat/
> to work on both programs.  Medium/long term, core gdb and core
> gdbserver target interface differences should converge further, and
> the #ifdefs disappear, but for now that's a necessary evil.
>
> It's fine to leave bits of functionality disabled on gdbserver,
> wrapped in #ifndef GDBSERVER.  After that initial work is committed,
> we can then easily progress the gdbserver port by just looking for
> those #ifdefs.
>
> It's fine with me to leave the existing native files under gdb/ while
> doing this; it's probably easier that way.  Moving them under gdb/nat/
> can be left for a cleanup step further down the road.
>
> Could we try that approach?

Ok, I will try to move the gdbserver/gnu-low.c back into gdb/gnu-nat.c.

> --
> Pedro Alves
>



-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-03 13:09       ` Thomas Schwinge
@ 2013-09-04  1:47         ` Yue Lu
  0 siblings, 0 replies; 25+ messages in thread
From: Yue Lu @ 2013-09-04  1:47 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Pedro Alves, gdb-patches, Luis Machado, bug-hurd

Hi,

On Tue, Sep 3, 2013 at 9:09 PM, Thomas Schwinge <thomas@codesourcery.com> wrote:
> Hi!
>
> On Tue, 03 Sep 2013 12:11:02 +0100, Pedro Alves <palves@redhat.com> wrote:
>> On 09/03/2013 10:38 AM, Thomas Schwinge wrote:
>> > [strategy]
>>
>> I've been thinking about this this morning, after seeing these
>> patches.
>>
>> For new gdbserver ports, this path just seems to swim further away from
>> a full sharing approach, by adding lots duplication as first step, [...]
>
>> So my idea would be, [...]
>
> Understood, and yes, your argumentation is reasonable.
>
>> I'd do this [by]
>> literally moving gdbserver/gnu-low.c on top of gdb/gnu-nat.c (etc.), and
>> use git diff to guide me through, in identifying what would need to
>> be restored, and guarded with #if[n]def GDBSERVER.  [...]
>
> Yes, that's a nice technique for displaying and integrating the
> differences between the existing Hurd native port's files and the new
> gdbserver port's.  Yue, does the approach of diffing the files as Pedro
> described make sense to you?  Please tell if you need help with how to
> use Git to do that, etc.

Yeah, I will do that. But in my understand, I will use diff gnu-low.c
../gnu-nat.c and something like this. But I don't know how to use git
do this.  Like git diff a.c b.c?

BTW, I got these patches by  git diff <early_commit>  > gdb.patch.
Then I edit the patch to two file. When I use git format-patch
<early_commit> I will get a patche for each commit after the
early_commit. What is the better way you generate patches?

-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-03 11:11     ` Pedro Alves
  2013-09-03 13:09       ` Thomas Schwinge
  2013-09-04  1:38       ` Yue Lu
@ 2013-09-05 10:54       ` Yue Lu
  2013-09-05 19:29         ` Pedro Alves
  2 siblings, 1 reply; 25+ messages in thread
From: Yue Lu @ 2013-09-05 10:54 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

Hi,

This is the my new patch.

On Tue, Sep 3, 2013 at 7:11 PM, Pedro Alves <palves@redhat.com> wrote:
> So my idea would be, instead of adding the new files under gdbserver,
> to remove the spurious differences (formatting, reordering, etc.) that
> were introduced in the gdbserver copies of the files, eliminating the
> unnecessary divergence, and then fold back the resulting differences into
> the original gdb/gnu-nat.c etc. files, guarded by #ifdef GDBSERVER.  Some
> cleanups might have been identified and done in the gdbserver files, and
> it might make sense to do those as preparatory work, in the original files.
> This should result in smaller patches, and will actually avoid
> the need for most of the polishing Thomas mentioned, and as consequence
> review burden -- reviewing the new gnu-low.c etc., for GNU conventions,
> formatting, or even appropriate use of the Hurd's debug APIs etc., is
> just unnecessary that way, by design, and we'll be able to focus on the
> bits that are the real new code -- the glue between the target and gdb, and
> the target and gdbserver.

I have put some soft link in directory gdbserver like *.defs which
point to [gdb]/gdb/*.defs.
2013-09-03  Yue Lu  <hacklu.newborn@gmail.com>
gdb
        * configure.tgt: Set build_gdbserver=yes for GNU/Hurd hosts.
        * configure: Regenerate.
        * config/i386/i386gnu.mh: Add #ifdef to determine which rule
to use in gdbserver.
        * i386gnu-nat.c: Add macor GDBSERVER to support build gdbserver.
        * gnu-nat.h: Add macor GDBSERVER to support build gdbserver.
        * gnu-nat.c: Add macor GDBSERVER to support build gdbserver.
        (gnu_debug): New function, use for debug printf.
        (gnu_wait_1): wait for inferior used in gdbserver.
        (gnu_resume_1): resume inferior used in gdbserver.
        (gnu_kill): New function, used in gdbserver.
        (gnu_mourn): New function, clean up after inferior dies, used
in gdbserver.
        (gnu_create_inferior): New function, use for create inferior
in gdbserver.
        (gnu_attach): New function, a placeholder.
        (gnu_detach): New function, used in gdbserver detach from inferior.
        (gnu_thread_alive): New function, call find_thread_ptid().
        (gnu_ptid_build): New function, build structure ptid_t from
pid, and tid.
        (gnu_get_tid): New function, return lwp from structure ptid_t,
this is different with gdb's behavior.
        (gnu_add_process): New function, add a new process to process list.
        (gnu_join): New function, a placeholder.
        (gnu_resume): New function, a wrap function, just call gnu_resume_1().
        (gnu_wait): New function, a wrap function, just call gnu_wait_1().
        (gnu_fetch_registers_wrap): New function, a wrap function,
just call gnu_fetch_registers().
        (gnu_store_registers_wrap): New function, a wrap function,
just call gnu_store_registers().
        (gnu_read_memory): New function, a wrap function, just call
gnu_read_inferior().
        (gnu_write_memory): New function, a wrap function, just call
gnu_write_inferior().
        (gnu_request_interrupt): New function, a placeholder.
        (store_waitstatus): New function, helper function, copy from
[gdb]/gdb/inf-child.c.
        (initialize_low): New function, use for initialize gdbserver's
target_ops.
        (initialize_low_arch): New function, used by initialize_low().
        (_initialize_gnu_nat): New function, used by initialize_low().

diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh
index a3ea122..224cf0f 100644
--- a/gdb/config/i386/i386gnu.mh
+++ b/gdb/config/i386/i386gnu.mh
@@ -1,4 +1,5 @@
 # Host: Intel 386 running the GNU Hurd
+ifndef GDBSERVER
 NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \
      notify_S.o process_reply_S.o msg_reply_S.o \
      msg_U.o exc_request_U.o exc_request_S.o
@@ -12,6 +13,10 @@ XM_CLIBS = -lshouldbeinlibc
 # Use our own user stubs for the msg rpcs, so we can make them time out, in
 # case the program is fucked, or we guess the wrong signal thread.
 msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;'
+else
+NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \
+      exc_request_U.o exc_request_S.o
+endif

 # ick
 MIGCOM = $(MIG) -cc cat - /dev/null
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index b0bee47..3eb2ff7 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -231,6 +231,7 @@ i[34567]86-*-linux*)
 i[34567]86-*-gnu*)
  # Target: Intel 386 running the GNU Hurd
  gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o"
+ build_gdbserver=yes
  ;;
 i[34567]86-*-cygwin*)
  # Target: Intel 386 running win32
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 59d2f23..1cdcd1d 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1,6 +1,7 @@
 /* Interface GDB to the GNU Hurd.
    Copyright (C) 1992-2013 Free Software Foundation, Inc.

+
    This file is part of GDB.

    Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -20,6 +21,7 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

+#ifndef GDBSERVER
 #include "defs.h"

 #include <ctype.h>
@@ -31,18 +33,6 @@
 #include "gdb_string.h"
 #include <sys/ptrace.h>

-#include <mach.h>
-#include <mach_error.h>
-#include <mach/exception.h>
-#include <mach/message.h>
-#include <mach/notify.h>
-#include <mach/vm_attributes.h>
-
-#include <hurd.h>
-#include <hurd/interrupt.h>
-#include <hurd/msg.h>
-#include <hurd/msg_request.h>
-#include <hurd/process.h>
 /* Defined in <hurd/process.h>, but we need forward declarations from
    <hurd/process_request.h> as well.  */
 #undef _process_user_
@@ -64,17 +54,55 @@
 #include "gdb_assert.h"
 #include "gdb_obstack.h"

-#include "gnu-nat.h"
 #include "inf-child.h"

+#include "exc_request_U.h"
+#include "msg_U.h"
+
+#else /* GDBSERVER */
+#include "server.h"
+#include "target.h"
+
+#include <limits.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include "gdb_wait.h"
+#include <signal.h>
+#include <sys/ptrace.h>
+#endif /* GDBSERVER */
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/exception.h>
+#include <mach/message.h>
+
+#include <mach/notify.h>
+#include <mach/vm_attributes.h>
+
+#include <hurd.h>
+#include <hurd/interrupt.h>
+#include <hurd/msg.h>
+#include <hurd/msg_request.h>
+#include <hurd/process.h>
+
+#include "gnu-nat.h"
 #include "exc_request_S.h"
 #include "notify_S.h"
 #include "process_reply_S.h"
 #include "msg_reply_S.h"
-#include "exc_request_U.h"
-#include "msg_U.h"

 static process_t proc_server = MACH_PORT_NULL;
+#ifdef GDBSERVER
+/* this should move into gnu-i386-low.c ?*/
+/* Defined in auto-generated file i386.c.  */
+extern void init_registers_i386 (void);
+extern const struct target_desc *tdesc_i386;
+const struct target_desc *gnu_tdesc;
+int using_threads = 1;
+ptid_t inferior_ptid;
+static struct target_ops gnu_target_ops;
+#endif

 /* If we've sent a proc_wait_request to the proc server, the pid of the
    process we asked about.  We can only ever have one outstanding.  */
@@ -114,6 +142,12 @@ void inf_continue (struct inf *inf);
        debug ("{inf %d %s}: " msg, __inf->pid, \
        host_address_to_string (__inf) , ##args); } while (0)

+#ifdef GDBSERVER
+static ptid_t gnu_ptid_build (int pid, long lwp, long tid);
+static long gnu_get_tid (ptid_t ptid);
+static struct process_info * gnu_add_process (int pid, int attached);
+#endif
+
 void proc_abort (struct proc *proc, int force);
 struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
 struct proc *_proc_free (struct proc *proc);
@@ -145,7 +179,27 @@ int proc_trace (struct proc *proc, int set);
  __e; }) \
    : EIEIO)

-
+#ifdef GDBSERVER
+struct process_info_private
+{
+  struct inf *inf;
+};
+
+void
+gnu_debug (char *string, ...)
+{
+  va_list args;
+
+  if (!gnu_debug_flag)
+    return;
+  va_start (args, string);
+  fprintf (stderr, "DEBUG(gnu): ");
+  vfprintf (stderr, string, args);
+  fprintf (stderr, "\n");
+  va_end (args);
+}
+#endif
+
 /* The state passed by an exception message.  */
 struct exc_state
   {
@@ -242,14 +296,12 @@ struct inf
     int want_exceptions;
   };

-
 int
 __proc_pid (struct proc *proc)
 {
   return proc->inf->pid;
 }

-
 /* Update PROC's real suspend count to match it's desired one.  Returns true
    if we think PROC is now in a runnable state.  */
 int
@@ -313,7 +365,6 @@ proc_update_sc (struct proc *proc)
   return running;
 }

-
 /* Thread_abort is called on PROC if needed.  PROC must be a thread proc.
    If PROC is deemed `precious', then nothing is done unless FORCE is true.
    In particular, a thread is precious if it's running (in which case forcing
@@ -390,7 +441,6 @@ proc_get_state (struct proc *proc, int will_modify)
     return 0;
 }

-
 /* Set PORT to PROC's exception port.  */
 error_t
 proc_get_exception_port (struct proc * proc, mach_port_t * port)
@@ -506,7 +556,6 @@ proc_restore_exc_port (struct proc *proc)
     }
 }

-
 /* Turns hardware tracing in PROC on or off when SET is true or false,
    respectively.  Returns true on success.  */
 int
@@ -533,7 +582,6 @@ proc_trace (struct proc *proc, int set)
   return 1;
 }

-
 /* A variable from which to assign new TIDs.  */
 static int next_thread_id = 1;

@@ -610,7 +658,6 @@ _proc_free (struct proc *proc)
   struct proc *next = proc->next;

   proc_debug (proc, "freeing...");
-
   if (proc == inf->step_thread)
     /* Turn off single stepping.  */
     inf_set_step_thread (inf, 0);
@@ -637,7 +684,6 @@ _proc_free (struct proc *proc)
   return next;
 }

-
 struct inf *
 make_inf (void)
 {
@@ -691,7 +737,6 @@ inf_clear_wait (struct inf *inf)
     }
 }

-
 void
 inf_cleanup (struct inf *inf)
 {
@@ -736,7 +781,6 @@ inf_startup (struct inf *inf, int pid)
   inf_set_pid (inf, pid);
 }

-
 /* Close current process, if any, and attach INF to process PORT.  */
 void
 inf_set_pid (struct inf *inf, pid_t pid)
@@ -786,7 +830,6 @@ inf_set_pid (struct inf *inf, pid_t pid)
     inf->pid = -1;
 }

-
 /* Validates INF's stopped, nomsg and traced field from the actual
    proc server state.  Note that the traced field is only updated from
    the proc server state if we do not have a message port.  If we do
@@ -855,6 +898,7 @@ inf_validate_task_sc (struct inf *inf)

   if (inf->task->cur_sc < suspend_count)
     {
+#ifndef GDBSERVER
       int abort;

       target_terminal_ours (); /* Allow I/O.  */
@@ -865,7 +909,9 @@ inf_validate_task_sc (struct inf *inf)

       if (abort)
  error (_("Additional task suspend count left untouched."));
+#endif

+      //need fix!
       inf->task->cur_sc = suspend_count;
     }
 }
@@ -905,7 +951,6 @@ inf_set_traced (struct inf *inf, int on)
     inf->traced = on;
 }

-
 /* Makes all the real suspend count deltas of all the procs in INF
    match the desired values.  Careful to always do thread/task suspend
    counts in the safe order.  Returns true if at least one thread is
@@ -959,7 +1004,6 @@ inf_update_suspends (struct inf *inf)
   return 0;
 }

-
 /* Converts a GDB pid to a struct proc.  */
 struct proc *
 inf_tid_to_thread (struct inf *inf, int tid)
@@ -988,7 +1032,6 @@ inf_port_to_thread (struct inf *inf, mach_port_t port)
   return 0;
 }

-
 /* Make INF's list of threads be consistent with reality of TASK.  */
 void
 inf_validate_procs (struct inf *inf)
@@ -1056,6 +1099,12 @@ inf_validate_procs (struct inf *inf)
  if (!left)
   {
     proc_debug (thread, "died!");
+#ifdef GDBSERVER
+    ptid_t ptid;
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+    if (find_thread_ptid (ptid))
+      remove_thread (find_thread_ptid (ptid));
+#endif
     thread->port = MACH_PORT_NULL;
     thread = _proc_free (thread); /* THREAD is dead.  */
     if (last)
@@ -1083,10 +1132,15 @@ inf_validate_procs (struct inf *inf)
     last = thread;
     proc_debug (thread, "new thread: %d", threads[i]);

+#ifndef GDBSERVER
     ptid = ptid_build (inf->pid, 0, thread->tid);
+#else
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+#endif

     /* Tell GDB's generic thread code.  */

+#ifndef GDBSERVER
     if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid)))
       /* This is the first time we're hearing about thread
  ids, after a fork-child.  */
@@ -1096,6 +1150,15 @@ inf_validate_procs (struct inf *inf)
       add_thread_silent (ptid);
     else
       add_thread (ptid);
+#else
+    if (!find_thread_ptid (ptid))
+      {
+ gnu_debug ("New thread, pid=%d, tid=%d\n", inf->pid,
+   thread->tid);
+ add_thread (ptid, thread);
+ inferior_ptid = ptid; // need fix!!!!!!!!!!!!!
+      }
+#endif
   }
       }

@@ -1104,7 +1167,6 @@ inf_validate_procs (struct inf *inf)
   }
 }

-
 /* Makes sure that INF's thread list is synced with the actual process.  */
 int
 inf_update_procs (struct inf *inf)
@@ -1135,7 +1197,6 @@ inf_set_threads_resume_sc (struct inf *inf,
       thread->resume_sc = thread->pause_sc;
 }

-
 /* Cause INF to continue execution immediately; individual threads may still
    be suspended (but their suspend counts will be updated).  */
 void
@@ -1179,7 +1240,6 @@ inf_suspend (struct inf *inf)
   inf_update_suspends (inf);
 }

-
 /* INF has one thread PROC that is in single-stepping mode.  This
    function changes it to be PROC, changing any old step_thread to be
    a normal one.  A PROC of 0 clears any existing value.  */
@@ -1205,7 +1265,6 @@ inf_set_step_thread (struct inf *inf, struct proc *thread)
     }
 }

-
 /* Set up the thread resume_sc's so that only the signal thread is running
    (plus whatever other thread are set to always run).  Returns true if we
    did so, or false if we can't find a signal thread.  */
@@ -1221,6 +1280,7 @@ inf_set_threads_resume_sc_for_signal_thread
(struct inf *inf)
     return 0;
 }

+#ifndef GDBSERVER
 static void
 inf_update_signal_thread (struct inf *inf)
 {
@@ -1229,7 +1289,7 @@ inf_update_signal_thread (struct inf *inf)
   inf->signal_thread = inf->threads ? inf->threads->next : 0;
 }

-
+#endif
 /* Detachs from INF's inferior task, letting it run once again...  */
 void
 inf_detach (struct inf *inf)
@@ -1284,7 +1344,7 @@ inf_attach (struct inf *inf, int pid)
   inf_startup (inf, pid);
 }

-
+#ifndef GDBSERVER
 /* Makes sure that we've got our exception ports entrenched in the process.  */
 void
 inf_steal_exc_ports (struct inf *inf)
@@ -1314,8 +1374,8 @@ inf_restore_exc_ports (struct inf *inf)
   for (thread = inf->threads; thread; thread = thread->next)
     proc_restore_exc_port (thread);
 }
+#endif

-
 /* Deliver signal SIG to INF.  If INF is stopped, delivering a signal, even
    signal 0, will continue it.  INF is assumed to be in a paused state, and
    the resume_sc's of INF's threads may be affected.  */
@@ -1404,7 +1464,6 @@ inf_signal (struct inf *inf, enum gdb_signal sig)
 #undef NAME
 }

-
 /* Continue INF without delivering a signal.  This is meant to be used
    when INF does not have a message port.  */
 void
@@ -1433,7 +1492,6 @@ inf_continue (struct inf *inf)
     warning (_("Can't continue process: %s"), safe_strerror (err));
 }

-
 /* The inferior used for all gdb target ops.  */
 struct inf *gnu_current_inf = 0;

@@ -1443,8 +1501,13 @@ struct inf *waiting_inf;

 /* Wait for something to happen in the inferior, returning what in STATUS.  */
 static ptid_t
+#ifdef GDBSERVER
+gnu_wait_1 (ptid_t ptid, struct target_waitstatus *status,
+    int target_options)
+#else
 gnu_wait (struct target_ops *ops,
   ptid_t ptid, struct target_waitstatus *status, int options)
+#endif
 {
   struct msg
     {
@@ -1613,19 +1676,29 @@ rewait:

   thread = inf->wait.thread;
   if (thread)
+#ifndef GDBSERVER
     ptid = ptid_build (inf->pid, 0, thread->tid);
+#else
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+#endif
   else if (ptid_equal (ptid, minus_one_ptid))
     thread = inf_tid_to_thread (inf, -1);
   else
+#ifndef GDBSERVER
     thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+#else
+    thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
+#endif

   if (!thread || thread->port == MACH_PORT_NULL)
     {
       /* TID is dead; try and find a new thread.  */
       if (inf_update_procs (inf) && inf->threads)
- ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first
-       available
-       thread.  */
+#ifndef GDBSERVER
+ ptid = ptid_build (inf->pid, 0, inf->threads->tid);
+#else
+ ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid);
+#endif /* The first available thread*/
       else
  ptid = inferior_ptid; /* let wait_for_inferior handle exit case */
     }
@@ -1651,10 +1724,12 @@ rewait:
      : "?",
      status->value.integer);

+#ifdef GDBSERVER
+  inferior_ptid = ptid;
+#endif
   return ptid;
 }

-
 /* The rpc handler called by exc_server.  */
 error_t
 S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
@@ -1736,11 +1811,9 @@ S_exception_raise_request (mach_port_t port,
mach_port_t reply_port,
       inf->wait.suppress = 1;
       mach_port_deallocate (mach_task_self (), reply_port);
     }
-
   return 0;
 }

-
 /* Fill in INF's wait field after a task has died without giving us more
    detailed information.  */
 void
@@ -1794,7 +1867,6 @@ do_mach_notify_dead_name (mach_port_t notify,
mach_port_t dead_port)
   return 0;
 }

-
 static error_t
 ill_rpc (char *fun)
 {
@@ -1832,7 +1904,6 @@ do_mach_notify_send_once (mach_port_t notify)
   return ill_rpc ("do_mach_notify_send_once");
 }

-
 /* Process_reply server routines.  We only use process_wait_reply.  */

 error_t
@@ -1901,7 +1972,6 @@ S_proc_getmsgport_reply (mach_port_t reply,
error_t err, mach_port_t msg_port)
   return ill_rpc ("S_proc_getmsgport_reply");
 }

-
 /* Msg_reply server routines.  We only use msg_sig_post_untraced_reply.  */

 error_t
@@ -1930,7 +2000,6 @@ S_msg_sig_post_untraced_reply (mach_port_t
reply, error_t err)
     inf->stopped = 1;
   else
     inf->wait.suppress = 1;
-
   return 0;
 }

@@ -1940,7 +2009,6 @@ S_msg_sig_post_reply (mach_port_t reply, error_t err)
   return ill_rpc ("S_msg_sig_post_reply");
 }

-
 /* Returns the number of messages queued for the receive right PORT.  */
 static mach_port_msgcount_t
 port_msgs_queued (mach_port_t port)
@@ -1955,7 +2023,6 @@ port_msgs_queued (mach_port_t port)
     return status.mps_msgcount;
 }

-
 /* Resume execution of the inferior process.

    If STEP is nonzero, single-step it.
@@ -1973,8 +2040,13 @@ port_msgs_queued (mach_port_t port)
    in multiple events returned by wait).  */

 static void
+#ifndef GDBSERVER
 gnu_resume (struct target_ops *ops,
     ptid_t ptid, int step, enum gdb_signal sig)
+#else
+gnu_resume_1 (struct target_ops *ops,
+      ptid_t ptid, int step, enum gdb_signal sig)
+#endif
 {
   struct proc *step_thread = 0;
   int resume_all;
@@ -1997,9 +2069,11 @@ gnu_resume (struct target_ops *ops,
        abort the faulting thread, which will perhaps retake it.  */
     {
       proc_abort (inf->wait.thread, 1);
+#ifndef GDBSERVER
       warning (_("Aborting %s with unforwarded exception %s."),
        proc_string (inf->wait.thread),
        gdb_signal_to_name (inf->wait.status.value.sig));
+#endif
     }

   if (port_msgs_queued (inf->event_port))
@@ -2022,7 +2096,12 @@ gnu_resume (struct target_ops *ops,
   else
     /* Just allow a single thread to run.  */
     {
+#ifdef GDBSERVER
+      struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
+#else
       struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+#endif
+

       if (!thread)
  error (_("Can't run single thread id %s: no such thread!"),
@@ -2033,7 +2112,12 @@ gnu_resume (struct target_ops *ops,

   if (step)
     {
+#ifdef GDBSERVER
+      step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
+#else
       step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+#endif
+
       if (!step_thread)
  warning (_("Can't step thread id %s: no such thread."),
  target_pid_to_str (ptid));
@@ -2047,7 +2131,7 @@ gnu_resume (struct target_ops *ops,
   inf_resume (inf);
 }

-
+#ifndef GDBSERVER
 static void
 gnu_kill_inferior (struct target_ops *ops)
 {
@@ -2061,8 +2145,29 @@ gnu_kill_inferior (struct target_ops *ops)
     }
   target_mourn_inferior ();
 }
+#else
+static int
+gnu_kill (int pid)
+{
+  struct proc *task = gnu_current_inf->task;
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+
+  if (task)
+    {
+      proc_debug (task, "terminating...");
+      task_terminate (task->port);
+      inf_set_pid (gnu_current_inf, -1);
+    }
+  the_target->mourn (process);
+  return 0;
+}
+#endif
+

 /* Clean up after the inferior dies.  */
+#ifndef GDBSERVER
 static void
 gnu_mourn_inferior (struct target_ops *ops)
 {
@@ -2071,8 +2176,18 @@ gnu_mourn_inferior (struct target_ops *ops)
   unpush_target (ops);
   generic_mourn_inferior ();
 }
+#else
+static void
+gnu_mourn (struct process_info *process)
+{
+  /* Free our private data.  */
+  free (process->private);
+  process->private = NULL;
+
+  clear_inferiors ();
+}
+#endif

-
 /* Fork an inferior process, and start debugging it.  */

 /* Set INFERIOR_PID to the first thread available in the child, if any.  */
@@ -2095,6 +2210,7 @@ cur_inf (void)
   return gnu_current_inf;
 }

+#ifndef GDBSERVER
 static void
 gnu_create_inferior (struct target_ops *ops,
      char *exec_file, char *allargs, char **env,
@@ -2148,10 +2264,34 @@ gnu_create_inferior (struct target_ops *ops,
   else
     inf_restore_exc_ports (inf);
 }
+#else
+static int
+gnu_create_inferior (char *program, char **allargs)
+{
+  int pid;
+  pid = fork ();
+  if (pid < 0)
+    perror_with_name ("fork");
+
+  if (pid == 0)
+    {
+      ptrace (PTRACE_TRACEME);
+      setpgid (0, 0);
+      execv (program, allargs);
+
+      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  gnu_add_process (pid, 0);
+  return pid;
+}
+#endif

-
 /* Attach to process PID, then initialize for debugging it
    and wait for the trace-trap that results from attaching.  */
+#ifndef GDBSERVER
 static void
 gnu_attach (struct target_ops *ops, char *args, int from_tty)
 {
@@ -2207,8 +2347,14 @@ gnu_attach (struct target_ops *ops, char *args,
int from_tty)
   renumber_threads (0); /* Give our threads reasonable names.  */
 #endif
 }
+#else
+static int
+gnu_attach (unsigned long pid)
+{
+  return -1; //not support now
+}
+#endif

-
 /* Take a program previously attached to and detaches it.
    The program resumes execution and will no longer stop
    on signals, etc.  We'd better not have left any breakpoints
@@ -2216,6 +2362,7 @@ gnu_attach (struct target_ops *ops, char *args,
int from_tty)
    to work, it may be necessary for the process to have been
    previously attached.  It *might* work if the program was
    started via fork.  */
+#ifndef GDBSERVER
 static void
 gnu_detach (struct target_ops *ops, char *args, int from_tty)
 {
@@ -2255,7 +2402,25 @@ gnu_stop (ptid_t ptid)
 {
   error (_("to_stop target function not implemented"));
 }
+#else
+static int
+gnu_detach (int pid)
+{
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
+
+  inf_detach (gnu_current_inf);

+  inferior_ptid = null_ptid;
+  the_target->mourn (process);
+  return 0;
+}
+#endif
+
+#ifndef GDBSERVER
 static int
 gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
@@ -2263,8 +2428,15 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
   return !!inf_tid_to_thread (gnu_current_inf,
       ptid_get_tid (ptid));
 }
+#else
+static int
+gnu_thread_alive (ptid_t ptid)
+{
+  /* this function is copyed from lynx-low.c */
+  return (find_thread_ptid (ptid) != NULL);
+}
+#endif

-
 /* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in
    gdb's address space.  Return 0 on failure; number of bytes read
    otherwise.  */
@@ -2310,7 +2482,9 @@ struct vm_region_list
   vm_size_t length;
 };

+#ifndef GDBSERVER
 struct obstack region_obstack;
+#endif

 /* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
    task's address space.  */
@@ -2344,7 +2518,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr,
char *myaddr, int length)
    myaddr, length);
   CHK_GOTO_OUT ("Write to inferior faulted", err);

+#ifndef GDBSERVER
   obstack_init (&region_obstack);
+#endif

   /* Do writes atomically.
      First check for holes and unwritable memory.  */
@@ -2399,7 +2575,11 @@ gnu_write_inferior (task_t task, CORE_ADDR
addr, char *myaddr, int length)
  /* Chain the regions for later use.  */
  region_element =
   (struct vm_region_list *)
+#ifndef GDBSERVER
   obstack_alloc (&region_obstack, sizeof (struct vm_region_list));
+#else
+  malloc (sizeof (struct vm_region_list));
+#endif

  region_element->protection = protection;
  region_element->start = region_address;
@@ -2454,7 +2634,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr,
char *myaddr, int length)
 out:
   if (deallocate)
     {
+#ifndef GDBSERVER
       obstack_free (&region_obstack, 0);
+#endif

       (void) vm_deallocate (mach_task_self (),
     copied,
@@ -2470,7 +2652,7 @@ out:
   return length;
 }

-
+#ifndef GDBSERVER
 /* Return 0 on failure, number of bytes handled otherwise.  TARGET
    is ignored.  */
 static int
@@ -2576,8 +2758,7 @@ gnu_find_memory_regions
(find_memory_region_ftype func, void *data)

   return 0;
 }
-
-
+#endif
 /* Return printable description of proc.  */
 char *
 proc_string (struct proc *proc)
@@ -2592,6 +2773,7 @@ proc_string (struct proc *proc)
   return tid_str;
 }

+#ifndef GDBSERVER
 static char *
 gnu_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
@@ -3452,3 +3634,214 @@ flush_inferior_icache (CORE_ADDR pc, int amount)
     warning (_("Error flushing inferior's cache : %s"), safe_strerror (ret));
 }
 #endif /* FLUSH_INFERIOR_CACHE */
+
+#else
+
+static ptid_t
+gnu_ptid_build (int pid, long lwp, long tid)
+{
+  return ptid_build (pid, tid, 0);
+}
+
+static long
+gnu_get_tid (ptid_t ptid)
+{
+  return ptid_get_lwp (ptid);
+}
+
+static struct process_info *
+gnu_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  proc = add_process (pid, attached);
+  proc->tdesc = gnu_tdesc;
+  proc->private = xcalloc (1, sizeof (*proc->private));
+  proc->private->inf = cur_inf ();
+  struct inf *inf = gnu_current_inf;
+
+  inf_attach (inf, pid);
+  inf->pending_execs = 2;
+  inf->nomsg = 1;
+  inf->traced = 1;
+
+  inf_resume (inf);
+
+  return proc;
+}
+
+static void
+gnu_join (int pid)
+{
+  /* doesn't need */
+}
+
+static void
+gnu_resume (struct thread_resume *resume_info, size_t n)
+{
+  /* FIXME: Assume for now that n == 1.  */
+  ptid_t ptid = resume_info[0].thread;
+  const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1
means step, 0 means contiune
+  const int signal = resume_info[0].sig;
+  if (ptid_equal (ptid, minus_one_ptid))
+    ptid = thread_to_gdb_id (current_inferior);
+
+  regcache_invalidate ();
+
+  gnu_debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step,
+     signal);
+
+  /*my_resume(); */
+  /*static void gnu_resume_1 (struct target_ops *ops,ptid_t ptid, int
step, enum gdb_signal sig) */
+  gnu_resume_1 (NULL, ptid, step, signal);
+
+}
+
+static ptid_t
+gnu_wait (ptid_t ptid, struct target_waitstatus *status, int target_options)
+{
+  ptid_t event_ptid;
+  gnu_debug ("gnu_wait: [%s]", target_pid_to_str (ptid));
+  event_ptid = gnu_wait_1 (ptid, status, target_options);
+  gnu_debug ("          -> (status->kind = %d)\n", status->kind);
+  return event_ptid;
+}
+
+void
+gnu_fetch_registers_wrap (struct regcache *regcache, int regno)
+{
+  gnu_debug ("gnu_fetch_registers() regno=%d\n", regno);
+  return gnu_fetch_registers (NULL, regcache, regno);
+}
+
+void
+gnu_store_registers_wrap (struct regcache *regcache, int regno)
+{
+  gnu_debug ("gnu_store_registers() regno=%d\n", regno);
+  return gnu_store_registers (NULL, regcache, regno);
+}
+
+static int
+gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_read_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret);
+      return -1;
+    }
+  return 0;
+}
+
+static int
+gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_write_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length,
+ ret);
+      return -1;
+    }
+  return 0;
+}
+
+static void
+gnu_request_interrupt (void)
+{
+  printf ("gnu_request_interrupt not support!\n");
+  exit (-1);
+}
+
+/* Helper function for child_wait and the derivatives of child_wait.
+   HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
+   translation of that in OURSTATUS.  */
+void
+store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
+{
+  if (WIFEXITED (hoststatus))
+    {
+      ourstatus->kind = TARGET_WAITKIND_EXITED;
+      ourstatus->value.integer = WEXITSTATUS (hoststatus);
+    }
+  else if (!WIFSTOPPED (hoststatus))
+    {
+      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+      ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus));
+    }
+  else
+    {
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus));
+    }
+}
+
+static struct target_ops gnu_target_ops = {
+  gnu_create_inferior,
+  gnu_attach,
+  gnu_kill,
+  gnu_detach,
+  gnu_mourn,
+  gnu_join,
+  gnu_thread_alive,
+  gnu_resume,
+  gnu_wait,
+  gnu_fetch_registers_wrap,
+  gnu_store_registers_wrap,
+  NULL, /* prepare_to_access_memory */
+  NULL, /* done_accessing_memory */
+  gnu_read_memory,
+  gnu_write_memory,
+  NULL, /* look_up_symbols */
+  gnu_request_interrupt,
+  NULL, /* read_auxv */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* read_offsets */
+  NULL, /* get_tls_address */
+  NULL, /* qxfer_spu */
+  NULL, /* hostio_last_error */
+  NULL, /* qxfer_osdata */
+  NULL, /* qxfer_siginfo */
+  NULL, /* supports_non_stop */
+  NULL, /* async */
+  NULL, /* start_non_stop */
+  NULL, /* supports_multi_process */
+  NULL, /* handle_monitor_command */
+};
+
+void
+_initialize_gnu_nat (void)
+{
+  proc_server = getproc ();
+}
+
+static void
+initialize_low_arch ()
+{
+  init_registers_i386 ();
+  gnu_tdesc = tdesc_i386;
+}
+
+void
+initialize_low (void)
+{
+  set_target_ops (&gnu_target_ops);
+  initialize_low_arch ();
+  _initialize_gnu_nat ();
+}
+#endif
diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h
index f896bd2..84f507d 100644
--- a/gdb/gnu-nat.h
+++ b/gdb/gnu-nat.h
@@ -93,13 +93,83 @@ extern char *proc_string (struct proc *proc);

 extern int gnu_debug_flag;

+#ifndef GDBSERVER
 #define debug(msg, args...) \
  do { if (gnu_debug_flag) \
         fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", \
     __FILE__ , __LINE__ , ##args); } while (0)
+#else
+#define debug(msg, args...) \
+ do { if (gnu_debug_flag) \
+        printf ("%s:%d: " msg "\r\n", \
+    __FILE__ , __LINE__ , ##args); } while (0)
+#endif

 /* Create a prototype generic GNU/Hurd target.  The client can
    override it with local methods.  */
 struct target_ops *gnu_target (void);

+#ifdef GDBSERVER
+
+/* All info needed to access an architecture/mode's registers.  */
+
+struct regs_info
+{
+  /* Regset support bitmap: 1 for registers that are transferred as a part
+     of a regset, 0 for ones that need to be handled individually.  This
+     can be NULL if all registers are transferred with regsets or regsets
+     are not supported.  */
+  unsigned char *regset_bitmap;
+
+  /* Info used when accessing registers with PTRACE_PEEKUSER /
+     PTRACE_POKEUSER.  This can be NULL if all registers are
+     transferred with regsets  .*/
+  struct usrregs_info *usrregs;
+
+#ifdef HAVE_gnu_REGSETS
+  /* Info used when accessing registers with regsets.  */
+  struct regsets_info *regsets_info;
+#endif
+};
+
+#define ptid_of(proc) ((proc)->head.id)
+#define pid_of(proc) ptid_get_pid ((proc)->head.id)
+#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
+
+#define get_lwp(inf) ((struct lwp_info *)(inf))
+#define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr)))
+#define get_lwp_thread(proc) ((struct thread_info *) \
+      find_inferior_id (&all_threads, \
+ get_lwp (proc)->head.id))
+
+#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE
+#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT
+#define THREAD_STATE_SET_TRACED(state) \
+   ((struct i386_thread_state *) (state))->efl |= 0x100
+#define THREAD_STATE_CLEAR_TRACED(state) \
+   ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1)
+
+
+#ifndef PIDGET
+#define PIDGET(PTID) (ptid_get_pid (PTID))
+#define TIDGET(PTID) (ptid_get_lwp (PTID))
+#define MERGEPID(PID, TID) ptid_build (PID, TID, 0)
+#endif
+//gdbserver use ptid_t not the same as gdb does!
+static ptid_t gnu_ptid_build(int pid,long lwp,long tid);
+
+//add for erase warning
+extern const char * host_address_to_string (const void *addr);
+
+/* Return printable description of proc.  */
+extern char *proc_string (struct proc *proc);
+
+
+#ifndef safe_strerror
+#define safe_strerror(err) \
+ ""
+#endif
+#endif
+
 #endif /* __GNU_NAT_H__ */
+
diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c
index 0fd8d91..51ca679 100644
--- a/gdb/i386gnu-nat.c
+++ b/gdb/i386gnu-nat.c
@@ -17,24 +17,17 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

+#ifndef GDBSERVER
 #include "defs.h"
 #include "inferior.h"
 #include "floatformat.h"
 #include "regcache.h"

 #include "gdb_assert.h"
-#include <errno.h>
-#include <stdio.h>
 #include "gdb_string.h"

-#include <mach.h>
-#include <mach_error.h>
-#include <mach/message.h>
-#include <mach/exception.h>
-
 #include "i386-tdep.h"

-#include "gnu-nat.h"
 #include "i387-tdep.h"

 #ifdef HAVE_SYS_PROCFS_H
@@ -42,6 +35,24 @@
 # include "gregset.h"
 #endif

+#else /* GDBSERVER */
+#include "server.h"
+#include "target.h"
+#include "gdb_wait.h"
+
+#define I386_NUM_GREGS 16
+#endif /* GDBSERVER */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/message.h>
+#include <mach/exception.h>
+#include "gnu-nat.h"
+/*#include "gnu-low.h"*/
+
 /* Offset to the thread_state_t location where REG is stored.  */
 #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)

@@ -78,6 +89,7 @@ static int creg_offset[] =
 static void
 fetch_fpregs (struct regcache *regcache, struct proc *thread)
 {
+#ifndef GDBSERVER
   mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
   struct i386_float_state state;
   error_t err;
@@ -101,8 +113,12 @@ fetch_fpregs (struct regcache *regcache, struct
proc *thread)
       /* Supply the floating-point registers.  */
       i387_supply_fsave (regcache, -1, state.hw_state);
     }
+#else
+  gnu_debug ("fetch_fpregs() not support now\n");
+#endif
 }

+#ifndef GDBSERVER
 #ifdef HAVE_SYS_PROCFS_H
 /* These two calls are used by the core-regset.c code for
    reading ELF core files.  */
@@ -120,9 +136,16 @@ supply_fpregset (struct regcache *regcache, const
gdb_fpregset_t *fpregs)
   i387_supply_fsave (regcache, -1, fpregs);
 }
 #endif
+#endif

+extern struct inf *gnu_current_inf;
+extern ptid_t inferior_ptid;
 /* Fetch register REGNO, or all regs if REGNO is -1.  */
+#ifndef GDBSERVER
 static void
+#else
+void
+#endif
 gnu_fetch_registers (struct target_ops *ops,
      struct regcache *regcache, int regno)
 {
@@ -132,7 +155,11 @@ gnu_fetch_registers (struct target_ops *ops,
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
+#ifndef GDBSERVER
       ptid_get_tid (inferior_ptid));
+#else
+      TIDGET (inferior_ptid));
+#endif
   if (!thread)
     error (_("Can't fetch registers from thread %s: No such thread"),
    target_pid_to_str (inferior_ptid));
@@ -157,17 +184,25 @@ gnu_fetch_registers (struct target_ops *ops,
   proc_debug (thread, "fetching all register");

   for (i = 0; i < I386_NUM_GREGS; i++)
+#ifndef GDBSERVER
     regcache_raw_supply (regcache, i, REG_ADDR (state, i));
+#else
+    supply_register (regcache, i, REG_ADDR (state, i));
+#endif
   thread->fetched_regs = ~0;
  }
       else
  {
+#ifndef GDBSERVER
   proc_debug (thread, "fetching register %s",
       gdbarch_register_name (get_regcache_arch (regcache),
      regno));

   regcache_raw_supply (regcache, regno,
        REG_ADDR (state, regno));
+#else
+  supply_register (regcache, regno, REG_ADDR (state, regno));
+#endif
   thread->fetched_regs |= (1 << regno);
  }
     }
@@ -183,9 +218,14 @@ gnu_fetch_registers (struct target_ops *ops,

 /* Store the whole floating-point state into THREAD using information
    from the corresponding (pseudo) registers.  */
+#ifndef GDBSERVER
 static void
+#else
+void
+#endif
 store_fpregs (const struct regcache *regcache, struct proc *thread, int regno)
 {
+#ifndef GDBSERVER
   mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
   struct i386_float_state state;
   error_t err;
@@ -211,21 +251,36 @@ store_fpregs (const struct regcache *regcache,
struct proc *thread, int regno)
        proc_string (thread));
       return;
     }
+#else
+  gnu_debug ("store_fpregs() not support now\n");
+#endif
 }

 /* Store at least register REGNO, or all regs if REGNO == -1.  */
+#ifndef GDBSERVER
 static void
+#else
+void
+#endif
 gnu_store_registers (struct target_ops *ops,
      struct regcache *regcache, int regno)
 {
   struct proc *thread;
+#ifndef GDBSERVER
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+#else
+  const struct target_desc *gdbarch = regcache->tdesc;
+#endif

   /* Make sure we know about new threads.  */
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
+#ifndef GDBSERVER
       ptid_get_tid (inferior_ptid));
+#else
+        TIDGET (inferior_ptid));
+#endif
   if (!thread)
     error (_("Couldn't store registers into thread %s: No such thread"),
    target_pid_to_str (inferior_ptid));
@@ -265,12 +320,19 @@ gnu_store_registers (struct target_ops *ops,
    register_size (gdbarch, check_regno)))
       /* Register CHECK_REGNO has changed!  Ack!  */
       {
+#ifndef GDBSERVER
  warning (_("Register %s changed after the thread was aborted"),
  gdbarch_register_name (gdbarch, check_regno));
+#endif
  if (regno >= 0 && regno != check_regno)
   /* Update GDB's copy of the register.  */
+#ifndef GDBSERVER
   regcache_raw_supply (regcache, check_regno,
        REG_ADDR (state, check_regno));
+#else
+  supply_register (regcache, check_regno,
+   REG_ADDR (state, check_regno));
+#endif
  else
   warning (_("... also writing this register!  "
      "Suspicious..."));
@@ -284,16 +346,24 @@ gnu_store_registers (struct target_ops *ops,
   proc_debug (thread, "storing all registers");

   for (i = 0; i < I386_NUM_GREGS; i++)
+#ifndef GDBSERVER
     if (REG_VALID == regcache_register_status (regcache, i))
       regcache_raw_collect (regcache, i, REG_ADDR (state, i));
+#else
+    collect_register (regcache, i, REG_ADDR (state, i));
+#endif
  }
       else
  {
+#ifndef GDBSERVER
   proc_debug (thread, "storing register %s",
       gdbarch_register_name (gdbarch, regno));

   gdb_assert (REG_VALID == regcache_register_status (regcache, regno));
   regcache_raw_collect (regcache, regno, REG_ADDR (state, regno));
+#else
+  collect_register (regcache, regno, REG_ADDR (state, regno));
+#endif
  }

       /* Restore the T bit.  */
@@ -309,6 +379,7 @@ gnu_store_registers (struct target_ops *ops,
     }
 }

+#ifndef GDBSERVER
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_i386gnu_nat;

@@ -326,3 +397,4 @@ _initialize_i386gnu_nat (void)
   /* Register the target.  */
   add_target (t);
 }
+#endif

======================================================================
gdbserver
        * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load
        i386gnu.mh.
        * configure.srv (srv_tgtobj): Add gnu-nat.o i386gnu-nat.o.o for
        GNU/Hurd.
        (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd.
        (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd.
        * configure: Regenerate.
        * Makefile.in (OBS): Add $(NATDEPFILES).
        (generated_files): Add $(NAT_GENERATED_FILES).
        (@host_makefile_frag@): New rule, add gnui386.mh.
        (MIG): New tools.
        (AWK): New tools.
        * exc_request.defs: New file. Softlink to [gdb]/gdb/exc_request.defs.
        * i386gnu-nat.c: New file. Softlink to [gdb]/gdb/i386gnu-nat.c.
        * gnu-low.c: New file. Softlink to [gdb]/gdb/gnu-nat.c.
        * gnu-low.h: New file. Softlink to [gdb]/gdb/gnu-nat.h.
        * hostio.c: Add macro define PATH_MAX 512.
        * i386gnu.mh: New file. Softlink to [gdb]/gdb/config/i386/i386gnu.mh.
        * msg.defs: New file. Softlink to [gdb]/gdb/msg.defs.
        * msg_reply.defs: New file. Softlink to [gdb]/gdb/msg_reply.defs.
        * notify.defs: New file. Softlink to [gdb]/gdb/notify.defs.
        * process_reply.defs: New file. Softlink to
[gdb]/gdb/process_reply.defs.
        * reply_mid_hack.awk: New file. Softlink to
[gdb]/gdb/reply_mid_hack.awk.
        * server.h: Add typedef long CORE_ADDR;
        * utils.c (host_address_to_string): New functions, copy from
        [gdb]/gdb/utils.c.

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index e8470a8..967cf57 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@
 RANLIB = @RANLIB@

 CC = @CC@
+MIG = @MIG@
+AWK = @AWK@

 # Dependency tracking information.
 DEPMODE = @CCDEPMODE@
@@ -172,7 +174,7 @@ OBS = agent.o ax.o inferiors.o regcache.o
remote-utils.o server.o signals.o targ
  xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \
  dll.o notif.o tdesc.o \
  $(XML_BUILTIN) \
- $(DEPFILES) $(LIBOBJS)
+ $(DEPFILES) $(LIBOBJS) $(NATDEPFILES)
 GDBREPLAY_OBS = gdbreplay.o version.o
 GDBSERVER_LIBS = @GDBSERVER_LIBS@
 XM_CLIBS = @LIBS@
@@ -195,6 +197,11 @@ CLEANDIRS = $(SUBDIRS)
 # The format here is for the `case' shell command.
 REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR)

+# Host-dependent makefile fragment comes in here.
+GDBSERVER=@GDBSERVER@
+@host_makefile_frag@
+# End of host-dependent makefile fragment
+
 FLAGS_TO_PASS = \
  "prefix=$(prefix)" \
  "exec_prefix=$(exec_prefix)" \
@@ -228,7 +235,7 @@ FLAGS_TO_PASS = \
  "RUNTESTFLAGS=$(RUNTESTFLAGS)"

 # All generated files which can be included by another file.
-generated_files = config.h $(GNULIB_H)
+generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES)

 .c.o:
  $(COMPILE) $<
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index b9928d7..21685db 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -456,6 +456,31 @@ if $want_ipa ; then
    fi
 fi

+frags=
+GDBSERVER=1
+case $host_os in
+  gnu*)
+    #Needed for GNU Hurd hosts.
+    AC_PROG_AWK
+    AC_CHECK_TOOL(MIG, mig)
+    if test x"$MIG" = x; then
+      AC_MSG_ERROR([MIG not found but required for $host hosts])
+    fi
+    host_makefile_frag=${srcdir}/i386gnu.mh
+    if test ! -f ${host_makefile_frag}; then
+       AC_MSG_ERROR("*** Gdb does not support native target ${host}")
+    fi
+    frags="$frags $host_makefile_frag"
+    ;;
+  *)
+    host_makefile_frag=/dev/null
+    ;;
+esac
+
+AC_SUBST_FILE(host_makefile_frag)
+AC_SUBST(frags)
+AC_SUBST(GDBSERVER)
+
 AC_SUBST(GDBSERVER_DEPFILES)
 AC_SUBST(GDBSERVER_LIBS)
 AC_SUBST(srv_xmlbuiltin)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 879d0de..1d9bf7a 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -118,6 +118,11 @@ case "${target}" in
  srv_linux_btrace=yes
  ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
  ;;
+  i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj"
+ srv_tgtobj="gnu-nat.o i386gnu-nat.o"
+ srv_xmlfiles="$srv_i386_xmlfiles"
+ ;;
+
   i[34567]86-*-lynxos*) srv_regobj="i386.o"
  srv_tgtobj="lynx-low.o lynx-i386-low.o"
  srv_xmlfiles="i386/i386.xml"
diff --git a/gdb/gdbserver/exc_request.defs b/gdb/gdbserver/exc_request.defs
new file mode 120000
index 0000000..1b8d3cd
--- /dev/null
+++ b/gdb/gdbserver/exc_request.defs
@@ -0,0 +1 @@
+../exc_request.defs
\ No newline at end of file
diff --git a/gdb/gdbserver/gnu-nat.c b/gdb/gdbserver/gnu-nat.c
new file mode 120000
index 0000000..d72e184
--- /dev/null
+++ b/gdb/gdbserver/gnu-nat.c
@@ -0,0 +1 @@
+../gnu-nat.c
\ No newline at end of file
diff --git a/gdb/gdbserver/gnu-nat.h b/gdb/gdbserver/gnu-nat.h
new file mode 120000
index 0000000..397c15c
--- /dev/null
+++ b/gdb/gdbserver/gnu-nat.h
@@ -0,0 +1 @@
+../gnu-nat.h
\ No newline at end of file
diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c
index df94d31..f3af499 100644
--- a/gdb/gdbserver/hostio.c
+++ b/gdb/gdbserver/hostio.c
@@ -25,6 +25,10 @@
 #include <limits.h>
 #include <unistd.h>

+#ifndef PATH_MAX
+#define PATH_MAX 512
+#endif
+
 extern int remote_debug;

 struct fd_list
diff --git a/gdb/gdbserver/i386gnu-nat.c b/gdb/gdbserver/i386gnu-nat.c
new file mode 120000
index 0000000..c547b9b
--- /dev/null
+++ b/gdb/gdbserver/i386gnu-nat.c
@@ -0,0 +1 @@
+../i386gnu-nat.c
\ No newline at end of file
diff --git a/gdb/gdbserver/i386gnu.mh b/gdb/gdbserver/i386gnu.mh
new file mode 120000
index 0000000..0497c22
--- /dev/null
+++ b/gdb/gdbserver/i386gnu.mh
@@ -0,0 +1 @@
+../config/i386/i386gnu.mh
\ No newline at end of file
diff --git a/gdb/gdbserver/msg.defs b/gdb/gdbserver/msg.defs
new file mode 120000
index 0000000..a663adb
--- /dev/null
+++ b/gdb/gdbserver/msg.defs
@@ -0,0 +1 @@
+../msg.defs
\ No newline at end of file
diff --git a/gdb/gdbserver/msg_reply.defs b/gdb/gdbserver/msg_reply.defs
new file mode 120000
index 0000000..61e8053
--- /dev/null
+++ b/gdb/gdbserver/msg_reply.defs
@@ -0,0 +1 @@
+../msg_reply.defs
\ No newline at end of file
diff --git a/gdb/gdbserver/notify.defs b/gdb/gdbserver/notify.defs
new file mode 120000
index 0000000..8a2c79d
--- /dev/null
+++ b/gdb/gdbserver/notify.defs
@@ -0,0 +1 @@
+../notify.defs
\ No newline at end of file
diff --git a/gdb/gdbserver/process_reply.defs b/gdb/gdbserver/process_reply.defs
new file mode 120000
index 0000000..7106ac0
--- /dev/null
+++ b/gdb/gdbserver/process_reply.defs
@@ -0,0 +1 @@
+../process_reply.defs
\ No newline at end of file
diff --git a/gdb/gdbserver/reply_mig_hack.awk b/gdb/gdbserver/reply_mig_hack.awk
new file mode 120000
index 0000000..fa7d33a
--- /dev/null
+++ b/gdb/gdbserver/reply_mig_hack.awk
@@ -0,0 +1 @@
+../reply_mig_hack.awk
\ No newline at end of file
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 18d060c..20e88bf 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -91,7 +91,8 @@ typedef unsigned char gdb_byte;

 /* FIXME: This should probably be autoconf'd for.  It's an integer type at
    least the size of a (void *).  */
-typedef long long CORE_ADDR;
+//typedef long long CORE_ADDR;
+typedef long CORE_ADDR;

 typedef long long LONGEST;
 typedef unsigned long long ULONGEST;
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 9706d74..d6dd4f9 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -170,7 +170,6 @@ internal_error (const char *file, int line, const
char *fmt, ...)
 #define CELLSIZE 50

 /* Return the next entry in the circular buffer.  */
-
 static char *
 get_cell (void)
 {
@@ -181,6 +180,15 @@ get_cell (void)
   return buf[cell];
 }

+const char *
+host_address_to_string (const void *addr)
+{
+  char *str = get_cell ();
+
+  xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long)
addr, sizeof (addr)));
+  return str;
+}
+
 static char *
 decimal2str (char *sign, ULONGEST addr)
 {

-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 10:54       ` Yue Lu
@ 2013-09-05 19:29         ` Pedro Alves
  2013-09-05 19:39           ` Joel Brobecker
                             ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: Pedro Alves @ 2013-09-05 19:29 UTC (permalink / raw)
  To: Yue Lu; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

On 09/05/2013 11:53 AM, Yue Lu wrote:
> Hi,
> 
> This is the my new patch.

Thanks.  Follows a few comments, by no means an in depth review.
We'll probably need to iterate a few times.  I'm counting on
Thomas and others to help as well!

I'm actually very excited to see gdb and gdbserver sharing
a single target backend, even if we still have many wrinkles
in the interfaces to iron out!  It does looks like this way
results in lots of less work, and makes me believe we can
port other targets to gdbserver already without unsurmountable
effort.

It'd be very useful if you send and maintain along
with the patch the rationale for all design divergences between
the ports you found necessary.  E.g., it seems that gdbserver's
task/proc bookkeeping is different from gdb's.  Why?

> I have put some soft link in directory gdbserver like *.defs which
> point to [gdb]/gdb/*.defs.

We'll need to adjust the Makefile etc. instead to use the original
files instead of that.  No symlinks please.

> 2013-09-03  Yue Lu  <hacklu.newborn@gmail.com>
> gdb
>         * configure.tgt: Set build_gdbserver=yes for GNU/Hurd hosts.
>         * configure: Regenerate.
>         * config/i386/i386gnu.mh: Add #ifdef to determine which rule
> to use in gdbserver.
>         * i386gnu-nat.c: Add macor GDBSERVER to support build gdbserver.
>         * gnu-nat.h: Add macor GDBSERVER to support build gdbserver.
>         * gnu-nat.c: Add macor GDBSERVER to support build gdbserver.
>         (gnu_debug): New function, use for debug printf.
>         (gnu_wait_1): wait for inferior used in gdbserver.
>         (gnu_resume_1): resume inferior used in gdbserver.
>         (gnu_kill): New function, used in gdbserver.
>         (gnu_mourn): New function, clean up after inferior dies, used
> in gdbserver.
>         (gnu_create_inferior): New function, use for create inferior
> in gdbserver.
>         (gnu_attach): New function, a placeholder.
>         (gnu_detach): New function, used in gdbserver detach from inferior.
>         (gnu_thread_alive): New function, call find_thread_ptid().
>         (gnu_ptid_build): New function, build structure ptid_t from
> pid, and tid.
>         (gnu_get_tid): New function, return lwp from structure ptid_t,
> this is different with gdb's behavior.
>         (gnu_add_process): New function, add a new process to process list.
>         (gnu_join): New function, a placeholder.
>         (gnu_resume): New function, a wrap function, just call gnu_resume_1().
>         (gnu_wait): New function, a wrap function, just call gnu_wait_1().
>         (gnu_fetch_registers_wrap): New function, a wrap function,
> just call gnu_fetch_registers().
>         (gnu_store_registers_wrap): New function, a wrap function,
> just call gnu_store_registers().
>         (gnu_read_memory): New function, a wrap function, just call
> gnu_read_inferior().
>         (gnu_write_memory): New function, a wrap function, just call
> gnu_write_inferior().
>         (gnu_request_interrupt): New function, a placeholder.
>         (store_waitstatus): New function, helper function, copy from
> [gdb]/gdb/inf-child.c.
>         (initialize_low): New function, use for initialize gdbserver's
> target_ops.
>         (initialize_low_arch): New function, used by initialize_low().
>         (_initialize_gnu_nat): New function, used by initialize_low().
> 
> diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh
> index a3ea122..224cf0f 100644
> --- a/gdb/config/i386/i386gnu.mh
> +++ b/gdb/config/i386/i386gnu.mh
> @@ -1,4 +1,5 @@
>  # Host: Intel 386 running the GNU Hurd
> +ifndef GDBSERVER
>  NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \
>       notify_S.o process_reply_S.o msg_reply_S.o \
>       msg_U.o exc_request_U.o exc_request_S.o
> @@ -12,6 +13,10 @@ XM_CLIBS = -lshouldbeinlibc
>  # Use our own user stubs for the msg rpcs, so we can make them time out, in
>  # case the program is fucked, or we guess the wrong signal thread.
>  msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;'
> +else
> +NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \
> +      exc_request_U.o exc_request_S.o
> +endif
> 
>  # ick
>  MIGCOM = $(MIG) -cc cat - /dev/null
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index b0bee47..3eb2ff7 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -231,6 +231,7 @@ i[34567]86-*-linux*)
>  i[34567]86-*-gnu*)
>   # Target: Intel 386 running the GNU Hurd
>   gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o"
> + build_gdbserver=yes
>   ;;
>  i[34567]86-*-cygwin*)
>   # Target: Intel 386 running win32
> diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
> index 59d2f23..1cdcd1d 100644
> --- a/gdb/gnu-nat.c
> +++ b/gdb/gnu-nat.c
> @@ -1,6 +1,7 @@
>  /* Interface GDB to the GNU Hurd.
>     Copyright (C) 1992-2013 Free Software Foundation, Inc.
> 
> +
>     This file is part of GDB.

Please go through the patch and remove spurious whitespace
changes line these.

> 
>     Written by Miles Bader <miles@gnu.ai.mit.edu>
> @@ -20,6 +21,7 @@
>     You should have received a copy of the GNU General Public License
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> 
> +#ifndef GDBSERVER
>  #include "defs.h"
> 
>  #include <ctype.h>
> @@ -31,18 +33,6 @@
>  #include "gdb_string.h"
>  #include <sys/ptrace.h>
> 
> -#include <mach.h>
> -#include <mach_error.h>
> -#include <mach/exception.h>
> -#include <mach/message.h>
> -#include <mach/notify.h>
> -#include <mach/vm_attributes.h>
> -
> -#include <hurd.h>
> -#include <hurd/interrupt.h>
> -#include <hurd/msg.h>
> -#include <hurd/msg_request.h>
> -#include <hurd/process.h>
>  /* Defined in <hurd/process.h>, but we need forward declarations from
>     <hurd/process_request.h> as well.  */
>  #undef _process_user_
> @@ -64,17 +54,55 @@
>  #include "gdb_assert.h"
>  #include "gdb_obstack.h"
> 
> -#include "gnu-nat.h"
>  #include "inf-child.h"
> 
> +#include "exc_request_U.h"
> +#include "msg_U.h"
> +
> +#else /* GDBSERVER */
> +#include "server.h"
> +#include "target.h"
> +
> +#include <limits.h>
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include <sys/types.h>
> +#include "gdb_wait.h"
> +#include <signal.h>
> +#include <sys/ptrace.h>
> +#endif /* GDBSERVER */
> +
> +#include <mach.h>
> +#include <mach_error.h>
> +#include <mach/exception.h>
> +#include <mach/message.h>
> +
> +#include <mach/notify.h>
> +#include <mach/vm_attributes.h>
> +
> +#include <hurd.h>
> +#include <hurd/interrupt.h>
> +#include <hurd/msg.h>
> +#include <hurd/msg_request.h>
> +#include <hurd/process.h>
> +
> +#include "gnu-nat.h"
>  #include "exc_request_S.h"
>  #include "notify_S.h"
>  #include "process_reply_S.h"
>  #include "msg_reply_S.h"
> -#include "exc_request_U.h"
> -#include "msg_U.h"
> 
>  static process_t proc_server = MACH_PORT_NULL;
> +#ifdef GDBSERVER
> +/* this should move into gnu-i386-low.c ?*/

I guess that means i386gnu-nat.c now, but it sounds like
it, yes.

> +/* Defined in auto-generated file i386.c.  */
> +extern void init_registers_i386 (void);
> +extern const struct target_desc *tdesc_i386;
> +const struct target_desc *gnu_tdesc;
> +int using_threads = 1;
> +ptid_t inferior_ptid;
> +static struct target_ops gnu_target_ops;
> +#endif
> 
>  /* If we've sent a proc_wait_request to the proc server, the pid of the
>     process we asked about.  We can only ever have one outstanding.  */
> @@ -114,6 +142,12 @@ void inf_continue (struct inf *inf);
>         debug ("{inf %d %s}: " msg, __inf->pid, \
>         host_address_to_string (__inf) , ##args); } while (0)
> 
> +#ifdef GDBSERVER
> +static ptid_t gnu_ptid_build (int pid, long lwp, long tid);
> +static long gnu_get_tid (ptid_t ptid);

These should be used unconditionally throughout, but implemented
differently on gdb vs gdbserver.  Any other similar case should
have a similar solution.  The goal should be to have the fewest
#ifdefs in the core gnu target code as possible, with the
differences being in the interfacing to gdb/gdbserver core.

Actually,

> +static ptid_t
> +gnu_ptid_build (int pid, long lwp, long tid)
> +{
> +  return ptid_build (pid, tid, 0);
> +}
> +
> +static long
> +gnu_get_tid (ptid_t ptid)
> +{
> +  return ptid_get_lwp (ptid);
> +}
> +

in this case, the difference is that GDB uses the tid
field, while gdbserver uses the lwp field.  But, (correct me if
I'm wrong here), the Hurd's threads are kernel threads, so it'd
be better to just make the GDB side use the lwp field too.
It's really a simple and mechanic change.  Nothing in GDB core
actually cares which field is used.  So in this case, it'd be
better if you send a preparatory patch that does that change
(and nothing else), and then rebase the port on top of that
patch.

> +


> +static struct process_info * gnu_add_process (int pid, int attached);
> +#endif
> +
>  void proc_abort (struct proc *proc, int force);
>  struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
>  struct proc *_proc_free (struct proc *proc);
> @@ -145,7 +179,27 @@ int proc_trace (struct proc *proc, int set);
>   __e; }) \
>     : EIEIO)
> 
> -
> +#ifdef GDBSERVER
> +struct process_info_private
> +{
> +  struct inf *inf;
> +};
> +
> +void
> +gnu_debug (char *string, ...)
> +{

Sounds like another candidate for always being
available, but with minor differences in implementation.

> +  va_list args;
> +
> +  if (!gnu_debug_flag)
> +    return;
> +  va_start (args, string);
> +  fprintf (stderr, "DEBUG(gnu): ");
> +  vfprintf (stderr, string, args);
> +  fprintf (stderr, "\n");
> +  va_end (args);
> +}
> +#endif
> +
>  /* The state passed by an exception message.  */
>  struct exc_state
>    {
> @@ -242,14 +296,12 @@ struct inf
>      int want_exceptions;
>    };
> 
> -
>  int
>  __proc_pid (struct proc *proc)
>  {
>    return proc->inf->pid;
>  }
> 
> -
>  /* Update PROC's real suspend count to match it's desired one.  Returns true
>     if we think PROC is now in a runnable state.  */
>  int
> @@ -313,7 +365,6 @@ proc_update_sc (struct proc *proc)
>    return running;
>  }
> 
> -
>  /* Thread_abort is called on PROC if needed.  PROC must be a thread proc.
>     If PROC is deemed `precious', then nothing is done unless FORCE is true.
>     In particular, a thread is precious if it's running (in which case forcing
> @@ -390,7 +441,6 @@ proc_get_state (struct proc *proc, int will_modify)
>      return 0;
>  }
> 
> -
>  /* Set PORT to PROC's exception port.  */
>  error_t
>  proc_get_exception_port (struct proc * proc, mach_port_t * port)
> @@ -506,7 +556,6 @@ proc_restore_exc_port (struct proc *proc)
>      }
>  }
> 
> -
>  /* Turns hardware tracing in PROC on or off when SET is true or false,
>     respectively.  Returns true on success.  */
>  int
> @@ -533,7 +582,6 @@ proc_trace (struct proc *proc, int set)
>    return 1;
>  }
> 
> -
>  /* A variable from which to assign new TIDs.  */
>  static int next_thread_id = 1;
> 
> @@ -610,7 +658,6 @@ _proc_free (struct proc *proc)
>    struct proc *next = proc->next;
> 
>    proc_debug (proc, "freeing...");
> -
>    if (proc == inf->step_thread)
>      /* Turn off single stepping.  */
>      inf_set_step_thread (inf, 0);
> @@ -637,7 +684,6 @@ _proc_free (struct proc *proc)
>    return next;
>  }
> 
> -
>  struct inf *
>  make_inf (void)
>  {
> @@ -691,7 +737,6 @@ inf_clear_wait (struct inf *inf)
>      }
>  }
> 
> -
>  void
>  inf_cleanup (struct inf *inf)
>  {
> @@ -736,7 +781,6 @@ inf_startup (struct inf *inf, int pid)
>    inf_set_pid (inf, pid);
>  }
> 
> -
>  /* Close current process, if any, and attach INF to process PORT.  */
>  void
>  inf_set_pid (struct inf *inf, pid_t pid)
> @@ -786,7 +830,6 @@ inf_set_pid (struct inf *inf, pid_t pid)
>      inf->pid = -1;
>  }
> 
> -
>  /* Validates INF's stopped, nomsg and traced field from the actual
>     proc server state.  Note that the traced field is only updated from
>     the proc server state if we do not have a message port.  If we do
> @@ -855,6 +898,7 @@ inf_validate_task_sc (struct inf *inf)
> 
>    if (inf->task->cur_sc < suspend_count)
>      {
> +#ifndef GDBSERVER
>        int abort;
> 
>        target_terminal_ours (); /* Allow I/O.  */
> @@ -865,7 +909,9 @@ inf_validate_task_sc (struct inf *inf)
> 
>        if (abort)
>   error (_("Additional task suspend count left untouched."));
> +#endif
> 
> +      //need fix!

What's the plan here?

>        inf->task->cur_sc = suspend_count;
>      }
>  }
> @@ -905,7 +951,6 @@ inf_set_traced (struct inf *inf, int on)
>      inf->traced = on;
>  }
> 
> -
>  /* Makes all the real suspend count deltas of all the procs in INF
>     match the desired values.  Careful to always do thread/task suspend
>     counts in the safe order.  Returns true if at least one thread is
> @@ -959,7 +1004,6 @@ inf_update_suspends (struct inf *inf)
>    return 0;
>  }
> 
> -
>  /* Converts a GDB pid to a struct proc.  */
>  struct proc *
>  inf_tid_to_thread (struct inf *inf, int tid)
> @@ -988,7 +1032,6 @@ inf_port_to_thread (struct inf *inf, mach_port_t port)
>    return 0;
>  }
> 
> -
>  /* Make INF's list of threads be consistent with reality of TASK.  */
>  void
>  inf_validate_procs (struct inf *inf)
> @@ -1056,6 +1099,12 @@ inf_validate_procs (struct inf *inf)
>   if (!left)
>    {
>      proc_debug (thread, "died!");
> +#ifdef GDBSERVER
> +    ptid_t ptid;
> +    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
> +    if (find_thread_ptid (ptid))
> +      remove_thread (find_thread_ptid (ptid));
> +#endif
>      thread->port = MACH_PORT_NULL;
>      thread = _proc_free (thread); /* THREAD is dead.  */
>      if (last)
> @@ -1083,10 +1132,15 @@ inf_validate_procs (struct inf *inf)
>      last = thread;
>      proc_debug (thread, "new thread: %d", threads[i]);
> 
> +#ifndef GDBSERVER
>      ptid = ptid_build (inf->pid, 0, thread->tid);
> +#else
> +    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
> +#endif
> 
>      /* Tell GDB's generic thread code.  */
> 
> +#ifndef GDBSERVER
>      if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid)))
>        /* This is the first time we're hearing about thread
>   ids, after a fork-child.  */
> @@ -1096,6 +1150,15 @@ inf_validate_procs (struct inf *inf)
>        add_thread_silent (ptid);
>      else
>        add_thread (ptid);
> +#else
> +    if (!find_thread_ptid (ptid))
> +      {
> + gnu_debug ("New thread, pid=%d, tid=%d\n", inf->pid,
> +   thread->tid);
> + add_thread (ptid, thread);
> + inferior_ptid = ptid; // need fix!!!!!!!!!!!!!
> +      }
> +#endif
>    }
>        }
> 
> @@ -1104,7 +1167,6 @@ inf_validate_procs (struct inf *inf)
>    }
>  }
> 
> -
>  /* Makes sure that INF's thread list is synced with the actual process.  */
>  int
>  inf_update_procs (struct inf *inf)
> @@ -1135,7 +1197,6 @@ inf_set_threads_resume_sc (struct inf *inf,
>        thread->resume_sc = thread->pause_sc;
>  }
> 
> -
>  /* Cause INF to continue execution immediately; individual threads may still
>     be suspended (but their suspend counts will be updated).  */
>  void
> @@ -1179,7 +1240,6 @@ inf_suspend (struct inf *inf)
>    inf_update_suspends (inf);
>  }
> 
> -
>  /* INF has one thread PROC that is in single-stepping mode.  This
>     function changes it to be PROC, changing any old step_thread to be
>     a normal one.  A PROC of 0 clears any existing value.  */
> @@ -1205,7 +1265,6 @@ inf_set_step_thread (struct inf *inf, struct proc *thread)
>      }
>  }
> 
> -
>  /* Set up the thread resume_sc's so that only the signal thread is running
>     (plus whatever other thread are set to always run).  Returns true if we
>     did so, or false if we can't find a signal thread.  */
> @@ -1221,6 +1280,7 @@ inf_set_threads_resume_sc_for_signal_thread
> (struct inf *inf)
>      return 0;
>  }
> 
> +#ifndef GDBSERVER
>  static void
>  inf_update_signal_thread (struct inf *inf)
>  {
> @@ -1229,7 +1289,7 @@ inf_update_signal_thread (struct inf *inf)
>    inf->signal_thread = inf->threads ? inf->threads->next : 0;
>  }
> 
> -
> +#endif
>  /* Detachs from INF's inferior task, letting it run once again...  */
>  void
>  inf_detach (struct inf *inf)
> @@ -1284,7 +1344,7 @@ inf_attach (struct inf *inf, int pid)
>    inf_startup (inf, pid);
>  }
> 
> -
> +#ifndef GDBSERVER
>  /* Makes sure that we've got our exception ports entrenched in the process.  */
>  void
>  inf_steal_exc_ports (struct inf *inf)
> @@ -1314,8 +1374,8 @@ inf_restore_exc_ports (struct inf *inf)
>    for (thread = inf->threads; thread; thread = thread->next)
>      proc_restore_exc_port (thread);
>  }
> +#endif
> 
> -
>  /* Deliver signal SIG to INF.  If INF is stopped, delivering a signal, even
>     signal 0, will continue it.  INF is assumed to be in a paused state, and
>     the resume_sc's of INF's threads may be affected.  */
> @@ -1404,7 +1464,6 @@ inf_signal (struct inf *inf, enum gdb_signal sig)
>  #undef NAME
>  }
> 
> -
>  /* Continue INF without delivering a signal.  This is meant to be used
>     when INF does not have a message port.  */
>  void
> @@ -1433,7 +1492,6 @@ inf_continue (struct inf *inf)
>      warning (_("Can't continue process: %s"), safe_strerror (err));
>  }
> 
> -
>  /* The inferior used for all gdb target ops.  */
>  struct inf *gnu_current_inf = 0;
> 
> @@ -1443,8 +1501,13 @@ struct inf *waiting_inf;
> 
>  /* Wait for something to happen in the inferior, returning what in STATUS.  */
>  static ptid_t
> +#ifdef GDBSERVER
> +gnu_wait_1 (ptid_t ptid, struct target_waitstatus *status,
> +    int target_options)
> +#else
>  gnu_wait (struct target_ops *ops,
>    ptid_t ptid, struct target_waitstatus *status, int options)
> +#endif

What's the rationale for this, and what's the rationale for
doing it only on the gdbserver side?

>  {
>    struct msg
>      {
> @@ -1613,19 +1676,29 @@ rewait:
> 
>    thread = inf->wait.thread;
>    if (thread)
> +#ifndef GDBSERVER
>      ptid = ptid_build (inf->pid, 0, thread->tid);
> +#else
> +    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
> +#endif
>    else if (ptid_equal (ptid, minus_one_ptid))
>      thread = inf_tid_to_thread (inf, -1);
>    else
> +#ifndef GDBSERVER
>      thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
> +#else
> +    thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
> +#endif
> 
>    if (!thread || thread->port == MACH_PORT_NULL)
>      {
>        /* TID is dead; try and find a new thread.  */
>        if (inf_update_procs (inf) && inf->threads)
> - ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first
> -       available
> -       thread.  */
> +#ifndef GDBSERVER
> + ptid = ptid_build (inf->pid, 0, inf->threads->tid);
> +#else
> + ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid);
> +#endif /* The first available thread*/
>        else
>   ptid = inferior_ptid; /* let wait_for_inferior handle exit case */
>      }
> @@ -1651,10 +1724,12 @@ rewait:
>       : "?",
>       status->value.integer);
> 
> +#ifdef GDBSERVER
> +  inferior_ptid = ptid;
> +#endif

This is surprising.  What's this needed for?

>    return ptid;
>  }
> 
> -
>  /* The rpc handler called by exc_server.  */
>  error_t
>  S_exception_raise_request (mach_port_t port, mach_port_t reply_port,
> @@ -1736,11 +1811,9 @@ S_exception_raise_request (mach_port_t port,
> mach_port_t reply_port,
>        inf->wait.suppress = 1;
>        mach_port_deallocate (mach_task_self (), reply_port);
>      }
> -
>    return 0;
>  }
> 
> -
>  /* Fill in INF's wait field after a task has died without giving us more
>     detailed information.  */
>  void
> @@ -1794,7 +1867,6 @@ do_mach_notify_dead_name (mach_port_t notify,
> mach_port_t dead_port)
>    return 0;
>  }
> 
> -
>  static error_t
>  ill_rpc (char *fun)
>  {
> @@ -1832,7 +1904,6 @@ do_mach_notify_send_once (mach_port_t notify)
>    return ill_rpc ("do_mach_notify_send_once");
>  }
> 
> -
>  /* Process_reply server routines.  We only use process_wait_reply.  */
> 
>  error_t
> @@ -1901,7 +1972,6 @@ S_proc_getmsgport_reply (mach_port_t reply,
> error_t err, mach_port_t msg_port)
>    return ill_rpc ("S_proc_getmsgport_reply");
>  }
> 
> -
>  /* Msg_reply server routines.  We only use msg_sig_post_untraced_reply.  */
> 
>  error_t
> @@ -1930,7 +2000,6 @@ S_msg_sig_post_untraced_reply (mach_port_t
> reply, error_t err)
>      inf->stopped = 1;
>    else
>      inf->wait.suppress = 1;
> -
>    return 0;
>  }
> 
> @@ -1940,7 +2009,6 @@ S_msg_sig_post_reply (mach_port_t reply, error_t err)
>    return ill_rpc ("S_msg_sig_post_reply");
>  }
> 
> -
>  /* Returns the number of messages queued for the receive right PORT.  */
>  static mach_port_msgcount_t
>  port_msgs_queued (mach_port_t port)
> @@ -1955,7 +2023,6 @@ port_msgs_queued (mach_port_t port)
>      return status.mps_msgcount;
>  }
> 
> -
>  /* Resume execution of the inferior process.
> 
>     If STEP is nonzero, single-step it.
> @@ -1973,8 +2040,13 @@ port_msgs_queued (mach_port_t port)
>     in multiple events returned by wait).  */
> 
>  static void
> +#ifndef GDBSERVER
>  gnu_resume (struct target_ops *ops,
>      ptid_t ptid, int step, enum gdb_signal sig)
> +#else
> +gnu_resume_1 (struct target_ops *ops,
> +      ptid_t ptid, int step, enum gdb_signal sig)
> +#endif

Again, why is this conditional?

>  {
>    struct proc *step_thread = 0;
>    int resume_all;
> @@ -1997,9 +2069,11 @@ gnu_resume (struct target_ops *ops,
>         abort the faulting thread, which will perhaps retake it.  */
>      {
>        proc_abort (inf->wait.thread, 1);
> +#ifndef GDBSERVER
>        warning (_("Aborting %s with unforwarded exception %s."),
>         proc_string (inf->wait.thread),
>         gdb_signal_to_name (inf->wait.status.value.sig));
> +#endif

Ditto.

>      }
> 
>    if (port_msgs_queued (inf->event_port))
> @@ -2022,7 +2096,12 @@ gnu_resume (struct target_ops *ops,
>    else
>      /* Just allow a single thread to run.  */
>      {
> +#ifdef GDBSERVER
> +      struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
> +#else
>        struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
> +#endif
> +
> 
>        if (!thread)
>   error (_("Can't run single thread id %s: no such thread!"),
> @@ -2033,7 +2112,12 @@ gnu_resume (struct target_ops *ops,
> 
>    if (step)
>      {
> +#ifdef GDBSERVER
> +      step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
> +#else
>        step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
> +#endif
> +
>        if (!step_thread)
>   warning (_("Can't step thread id %s: no such thread."),
>   target_pid_to_str (ptid));
> @@ -2047,7 +2131,7 @@ gnu_resume (struct target_ops *ops,
>    inf_resume (inf);
>  }
> 
> -
> +#ifndef GDBSERVER
>  static void
>  gnu_kill_inferior (struct target_ops *ops)
>  {
> @@ -2061,8 +2145,29 @@ gnu_kill_inferior (struct target_ops *ops)
>      }
>    target_mourn_inferior ();
>  }
> +#else
> +static int
> +gnu_kill (int pid)
> +{
> +  struct proc *task = gnu_current_inf->task;
> +  struct process_info *process;
> +
> +  process = find_process_pid (pid);
> +
> +  if (task)
> +    {
> +      proc_debug (task, "terminating...");
> +      task_terminate (task->port);
> +      inf_set_pid (gnu_current_inf, -1);
> +    }
> +  the_target->mourn (process);
> +  return 0;
> +}

Looks like the differences between gdb and gdbserver here
are really minor.  We should be able to merge them better.

> +#endif
> +
> 
>  /* Clean up after the inferior dies.  */
> +#ifndef GDBSERVER
>  static void
>  gnu_mourn_inferior (struct target_ops *ops)
>  {
> @@ -2071,8 +2176,18 @@ gnu_mourn_inferior (struct target_ops *ops)
>    unpush_target (ops);
>    generic_mourn_inferior ();
>  }
> +#else
> +static void
> +gnu_mourn (struct process_info *process)
> +{
> +  /* Free our private data.  */
> +  free (process->private);
> +  process->private = NULL;
> +
> +  clear_inferiors ();
> +}
> +#endif
> 
> -
>  /* Fork an inferior process, and start debugging it.  */
> 
>  /* Set INFERIOR_PID to the first thread available in the child, if any.  */
> @@ -2095,6 +2210,7 @@ cur_inf (void)
>    return gnu_current_inf;
>  }
> 
> +#ifndef GDBSERVER
>  static void
>  gnu_create_inferior (struct target_ops *ops,
>       char *exec_file, char *allargs, char **env,
> @@ -2148,10 +2264,34 @@ gnu_create_inferior (struct target_ops *ops,
>    else
>      inf_restore_exc_ports (inf);
>  }
> +#else
> +static int
> +gnu_create_inferior (char *program, char **allargs)
> +{
> +  int pid;
> +  pid = fork ();
> +  if (pid < 0)
> +    perror_with_name ("fork");
> +
> +  if (pid == 0)
> +    {
> +      ptrace (PTRACE_TRACEME);
> +      setpgid (0, 0);
> +      execv (program, allargs);
> +
> +      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
> +      fflush (stderr);
> +      _exit (0177);
> +    }
> +
> +  gnu_add_process (pid, 0);
> +  return pid;
> +}
> +#endif
> 
> -
>  /* Attach to process PID, then initialize for debugging it
>     and wait for the trace-trap that results from attaching.  */
> +#ifndef GDBSERVER
>  static void
>  gnu_attach (struct target_ops *ops, char *args, int from_tty)
>  {
> @@ -2207,8 +2347,14 @@ gnu_attach (struct target_ops *ops, char *args,
> int from_tty)
>    renumber_threads (0); /* Give our threads reasonable names.  */
>  #endif
>  }
> +#else
> +static int
> +gnu_attach (unsigned long pid)
> +{
> +  return -1; //not support now

Doesn't look like this should be hard to get going.

> +}
> +#endif
> 
> -
>  /* Take a program previously attached to and detaches it.
>     The program resumes execution and will no longer stop
>     on signals, etc.  We'd better not have left any breakpoints
> @@ -2216,6 +2362,7 @@ gnu_attach (struct target_ops *ops, char *args,
> int from_tty)
>     to work, it may be necessary for the process to have been
>     previously attached.  It *might* work if the program was
>     started via fork.  */
> +#ifndef GDBSERVER
>  static void
>  gnu_detach (struct target_ops *ops, char *args, int from_tty)
>  {
> @@ -2255,7 +2402,25 @@ gnu_stop (ptid_t ptid)
>  {
>    error (_("to_stop target function not implemented"));
>  }
> +#else
> +static int
> +gnu_detach (int pid)
> +{

Eheh, we have detach but not attach.  ;-)

> +  struct process_info *process;
> +
> +  process = find_process_pid (pid);
> +  if (process == NULL)
> +    return -1;
> +
> +  inf_detach (gnu_current_inf);
> 
> +  inferior_ptid = null_ptid;

I'm seeing inferior_ptid references in the gdbserver side,
but gdbserver doesn't have that global.  What's that needed for?

> +  the_target->mourn (process);
> +  return 0;
> +}
> +#endif
> +
> +#ifndef GDBSERVER
>  static int
>  gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
>  {
> @@ -2263,8 +2428,15 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
>    return !!inf_tid_to_thread (gnu_current_inf,
>        ptid_get_tid (ptid));
>  }
> +#else
> +static int
> +gnu_thread_alive (ptid_t ptid)
> +{
> +  /* this function is copyed from lynx-low.c */

Why?  Why not use the same scheme as the gdb side?

> +  return (find_thread_ptid (ptid) != NULL);
> +}
> +#endif
> 
> -
>  /* Read inferior task's LEN bytes from ADDR and copy it to MYADDR in
>     gdb's address space.  Return 0 on failure; number of bytes read
>     otherwise.  */
> @@ -2310,7 +2482,9 @@ struct vm_region_list
>    vm_size_t length;
>  };
> 
> +#ifndef GDBSERVER
>  struct obstack region_obstack;
> +#endif
> 
>  /* Write gdb's LEN bytes from MYADDR and copy it to ADDR in inferior
>     task's address space.  */
> @@ -2344,7 +2518,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr,
> char *myaddr, int length)
>     myaddr, length);
>    CHK_GOTO_OUT ("Write to inferior faulted", err);
> 
> +#ifndef GDBSERVER
>    obstack_init (&region_obstack);
> +#endif
> 
>    /* Do writes atomically.
>       First check for holes and unwritable memory.  */
> @@ -2399,7 +2575,11 @@ gnu_write_inferior (task_t task, CORE_ADDR
> addr, char *myaddr, int length)
>   /* Chain the regions for later use.  */
>   region_element =
>    (struct vm_region_list *)
> +#ifndef GDBSERVER
>    obstack_alloc (&region_obstack, sizeof (struct vm_region_list));
> +#else
> +  malloc (sizeof (struct vm_region_list));

Err, malloc without storing the result anywhere is just a leak.

We'll need to do something about this.  We could hack/build libiberty's
obstack.c on gdbserver, like we vasprintf.c (see Makefile.in), or
use struct buffer on both sides.  I think the former would be better.
We already have too many ways to do the same, and we that
would probably allow getting rid of struct buffer.


> +#endif
> 
>   region_element->protection = protection;
>   region_element->start = region_address;
> @@ -2454,7 +2634,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr,
> char *myaddr, int length)
>  out:
>    if (deallocate)
>      {
> +#ifndef GDBSERVER
>        obstack_free (&region_obstack, 0);
> +#endif
> 
>        (void) vm_deallocate (mach_task_self (),
>      copied,
> @@ -2470,7 +2652,7 @@ out:
>    return length;
>  }
> 
> -
> +#ifndef GDBSERVER
>  /* Return 0 on failure, number of bytes handled otherwise.  TARGET
>     is ignored.  */
>  static int
> @@ -2576,8 +2758,7 @@ gnu_find_memory_regions
> (find_memory_region_ftype func, void *data)
> 
>    return 0;
>  }
> -
> -
> +#endif
>  /* Return printable description of proc.  */
>  char *
>  proc_string (struct proc *proc)
> @@ -2592,6 +2773,7 @@ proc_string (struct proc *proc)
>    return tid_str;
>  }
> 
> +#ifndef GDBSERVER
>  static char *
>  gnu_pid_to_str (struct target_ops *ops, ptid_t ptid)
>  {
> @@ -3452,3 +3634,214 @@ flush_inferior_icache (CORE_ADDR pc, int amount)
>      warning (_("Error flushing inferior's cache : %s"), safe_strerror (ret));
>  }
>  #endif /* FLUSH_INFERIOR_CACHE */
> +
> +#else
> +
> +static ptid_t
> +gnu_ptid_build (int pid, long lwp, long tid)
> +{
> +  return ptid_build (pid, tid, 0);
> +}
> +
> +static long
> +gnu_get_tid (ptid_t ptid)
> +{
> +  return ptid_get_lwp (ptid);
> +}
> +
> +static struct process_info *
> +gnu_add_process (int pid, int attached)
> +{
> +  struct process_info *proc;
> +
> +  proc = add_process (pid, attached);
> +  proc->tdesc = gnu_tdesc;
> +  proc->private = xcalloc (1, sizeof (*proc->private));
> +  proc->private->inf = cur_inf ();
> +  struct inf *inf = gnu_current_inf;
> +
> +  inf_attach (inf, pid);
> +  inf->pending_execs = 2;
> +  inf->nomsg = 1;
> +  inf->traced = 1;
> +
> +  inf_resume (inf);
> +
> +  return proc;
> +}
> +
> +static void
> +gnu_join (int pid)
> +{
> +  /* doesn't need */
> +}
> +
> +static void
> +gnu_resume (struct thread_resume *resume_info, size_t n)
> +{
> +  /* FIXME: Assume for now that n == 1.  */
> +  ptid_t ptid = resume_info[0].thread;
> +  const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1
> means step, 0 means contiune
> +  const int signal = resume_info[0].sig;
> +  if (ptid_equal (ptid, minus_one_ptid))
> +    ptid = thread_to_gdb_id (current_inferior);
> +
> +  regcache_invalidate ();
> +
> +  gnu_debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step,
> +     signal);
> +
> +  /*my_resume(); */
> +  /*static void gnu_resume_1 (struct target_ops *ops,ptid_t ptid, int
> step, enum gdb_signal sig) */
> +  gnu_resume_1 (NULL, ptid, step, signal);
> +
> +}
> +
> +static ptid_t
> +gnu_wait (ptid_t ptid, struct target_waitstatus *status, int target_options)
> +{
> +  ptid_t event_ptid;
> +  gnu_debug ("gnu_wait: [%s]", target_pid_to_str (ptid));
> +  event_ptid = gnu_wait_1 (ptid, status, target_options);
> +  gnu_debug ("          -> (status->kind = %d)\n", status->kind);
> +  return event_ptid;
> +}
> +
> +void
> +gnu_fetch_registers_wrap (struct regcache *regcache, int regno)
> +{
> +  gnu_debug ("gnu_fetch_registers() regno=%d\n", regno);
> +  return gnu_fetch_registers (NULL, regcache, regno);
> +}
> +
> +void
> +gnu_store_registers_wrap (struct regcache *regcache, int regno)
> +{
> +  gnu_debug ("gnu_store_registers() regno=%d\n", regno);
> +  return gnu_store_registers (NULL, regcache, regno);
> +}
> +
> +static int
> +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
> +{
> +  int ret = 0;
> +  task_t task = (gnu_current_inf
> + ? (gnu_current_inf->task
> +    ? gnu_current_inf->task->port : 0) : 0);
> +  if (task == MACH_PORT_NULL)
> +    return 0;
> +  ret = gnu_read_inferior (task, addr, myaddr, length);
> +  if (length != ret)
> +    {
> +      gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret);
> +      return -1;
> +    }
> +  return 0;
> +}
> +
> +static int
> +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length)
> +{
> +  int ret = 0;
> +  task_t task = (gnu_current_inf
> + ? (gnu_current_inf->task
> +    ? gnu_current_inf->task->port : 0) : 0);
> +  if (task == MACH_PORT_NULL)
> +    return 0;
> +  ret = gnu_write_inferior (task, addr, myaddr, length);
> +  if (length != ret)
> +    {
> +      gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length,
> + ret);
> +      return -1;
> +    }
> +  return 0;
> +}
> +

These should reall be wrappers around a common shared function.  I have
a patch that I think helps here.  I'll post it in soon.

> +static void
> +gnu_request_interrupt (void)
> +{
> +  printf ("gnu_request_interrupt not support!\n");
> +  exit (-1);

That's quite limiting.  :-/  Doesn't sending a SIGINT
work?

> +}
> +
> +/* Helper function for child_wait and the derivatives of child_wait.
> +   HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
> +   translation of that in OURSTATUS.  */
> +void
> +store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
> +{
> +  if (WIFEXITED (hoststatus))
> +    {
> +      ourstatus->kind = TARGET_WAITKIND_EXITED;
> +      ourstatus->value.integer = WEXITSTATUS (hoststatus);
> +    }
> +  else if (!WIFSTOPPED (hoststatus))
> +    {
> +      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
> +      ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus));
> +    }
> +  else
> +    {
> +      ourstatus->kind = TARGET_WAITKIND_STOPPED;
> +      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus));
> +    }
> +}
> +
> +static struct target_ops gnu_target_ops = {
> +  gnu_create_inferior,
> +  gnu_attach,
> +  gnu_kill,
> +  gnu_detach,
> +  gnu_mourn,
> +  gnu_join,
> +  gnu_thread_alive,
> +  gnu_resume,
> +  gnu_wait,
> +  gnu_fetch_registers_wrap,
> +  gnu_store_registers_wrap,
> +  NULL, /* prepare_to_access_memory */
> +  NULL, /* done_accessing_memory */
> +  gnu_read_memory,
> +  gnu_write_memory,
> +  NULL, /* look_up_symbols */
> +  gnu_request_interrupt,
> +  NULL, /* read_auxv */
> +  NULL, /* insert_point */
> +  NULL, /* remove_point */
> +  NULL, /* stopped_by_watchpoint */
> +  NULL, /* stopped_data_address */
> +  NULL, /* read_offsets */
> +  NULL, /* get_tls_address */
> +  NULL, /* qxfer_spu */
> +  NULL, /* hostio_last_error */
> +  NULL, /* qxfer_osdata */
> +  NULL, /* qxfer_siginfo */
> +  NULL, /* supports_non_stop */
> +  NULL, /* async */
> +  NULL, /* start_non_stop */
> +  NULL, /* supports_multi_process */
> +  NULL, /* handle_monitor_command */
> +};
> +
> +void
> +_initialize_gnu_nat (void)
> +{
> +  proc_server = getproc ();
> +}
> +
> +static void
> +initialize_low_arch ()
> +{
> +  init_registers_i386 ();
> +  gnu_tdesc = tdesc_i386;
> +}
> +
> +void
> +initialize_low (void)
> +{
> +  set_target_ops (&gnu_target_ops);
> +  initialize_low_arch ();
> +  _initialize_gnu_nat ();
> +}
> +#endif
> diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h
> index f896bd2..84f507d 100644
> --- a/gdb/gnu-nat.h
> +++ b/gdb/gnu-nat.h
> @@ -93,13 +93,83 @@ extern char *proc_string (struct proc *proc);
> 
>  extern int gnu_debug_flag;
> 
> +#ifndef GDBSERVER
>  #define debug(msg, args...) \
>   do { if (gnu_debug_flag) \
>          fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", \
>      __FILE__ , __LINE__ , ##args); } while (0)
> +#else
> +#define debug(msg, args...) \
> + do { if (gnu_debug_flag) \
> +        printf ("%s:%d: " msg "\r\n", \
> +    __FILE__ , __LINE__ , ##args); } while (0)
> +#endif

Wasn't there already a gnu_debug function?

> 
>  /* Create a prototype generic GNU/Hurd target.  The client can
>     override it with local methods.  */
>  struct target_ops *gnu_target (void);
> 
> +#ifdef GDBSERVER
> +
> +/* All info needed to access an architecture/mode's registers.  */
> +
> +struct regs_info
> +{
> +  /* Regset support bitmap: 1 for registers that are transferred as a part
> +     of a regset, 0 for ones that need to be handled individually.  This
> +     can be NULL if all registers are transferred with regsets or regsets
> +     are not supported.  */
> +  unsigned char *regset_bitmap;
> +
> +  /* Info used when accessing registers with PTRACE_PEEKUSER /
> +     PTRACE_POKEUSER.  This can be NULL if all registers are
> +     transferred with regsets  .*/
> +  struct usrregs_info *usrregs;
> +
> +#ifdef HAVE_gnu_REGSETS
> +  /* Info used when accessing registers with regsets.  */
> +  struct regsets_info *regsets_info;
> +#endif

Why's all this needed?

> +};
> +
> +#define ptid_of(proc) ((proc)->head.id)
> +#define pid_of(proc) ptid_get_pid ((proc)->head.id)
> +#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
> +
> +#define get_lwp(inf) ((struct lwp_info *)(inf))
> +#define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr)))
> +#define get_lwp_thread(proc) ((struct thread_info *) \
> +      find_inferior_id (&all_threads, \
> + get_lwp (proc)->head.id))

There seems to be some amount of blind copy&paste from
the linux target here.  struct lwp_info certainly has no
business in this port?  You should go through every line
in the patch, and make sure you're able to justify it.
If you can't, or if you're not sure, revert the change.

> +
> +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE
> +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT
> +#define THREAD_STATE_SET_TRACED(state) \
> +   ((struct i386_thread_state *) (state))->efl |= 0x100
> +#define THREAD_STATE_CLEAR_TRACED(state) \
> +   ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1)
> +
> +
> +#ifndef PIDGET
> +#define PIDGET(PTID) (ptid_get_pid (PTID))
> +#define TIDGET(PTID) (ptid_get_lwp (PTID))
> +#define MERGEPID(PID, TID) ptid_build (PID, TID, 0)
> +#endif
> +//gdbserver use ptid_t not the same as gdb does!
> +static ptid_t gnu_ptid_build(int pid,long lwp,long tid);

As said, best would be to make them the same.

> +
> +//add for erase warning
> +extern const char * host_address_to_string (const void *addr);

This should be put in a proper place.  Probably utils.h,
once I commit yesterday's series to split server.h.

> +
> +/* Return printable description of proc.  */
> +extern char *proc_string (struct proc *proc);
> +
> +
> +#ifndef safe_strerror
> +#define safe_strerror(err) \
> + ""
> +#endif
> +#endif
> +
>  #endif /* __GNU_NAT_H__ */
> +
> diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c
> index 0fd8d91..51ca679 100644
> --- a/gdb/i386gnu-nat.c
> +++ b/gdb/i386gnu-nat.c
> @@ -17,24 +17,17 @@
>     You should have received a copy of the GNU General Public License
>     along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> 
> +#ifndef GDBSERVER
>  #include "defs.h"
>  #include "inferior.h"
>  #include "floatformat.h"
>  #include "regcache.h"
> 
>  #include "gdb_assert.h"
> -#include <errno.h>
> -#include <stdio.h>
>  #include "gdb_string.h"
> 
> -#include <mach.h>
> -#include <mach_error.h>
> -#include <mach/message.h>
> -#include <mach/exception.h>
> -
>  #include "i386-tdep.h"
> 
> -#include "gnu-nat.h"
>  #include "i387-tdep.h"
> 
>  #ifdef HAVE_SYS_PROCFS_H
> @@ -42,6 +35,24 @@
>  # include "gregset.h"
>  #endif
> 
> +#else /* GDBSERVER */
> +#include "server.h"
> +#include "target.h"
> +#include "gdb_wait.h"
> +
> +#define I386_NUM_GREGS 16
> +#endif /* GDBSERVER */
> +
> +#include <errno.h>
> +#include <stdio.h>
> +
> +#include <mach.h>
> +#include <mach_error.h>
> +#include <mach/message.h>
> +#include <mach/exception.h>
> +#include "gnu-nat.h"
> +/*#include "gnu-low.h"*/
> +
>  /* Offset to the thread_state_t location where REG is stored.  */
>  #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
> 
> @@ -78,6 +89,7 @@ static int creg_offset[] =
>  static void
>  fetch_fpregs (struct regcache *regcache, struct proc *thread)
>  {
> +#ifndef GDBSERVER
>    mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
>    struct i386_float_state state;
>    error_t err;
> @@ -101,8 +113,12 @@ fetch_fpregs (struct regcache *regcache, struct
> proc *thread)
>        /* Supply the floating-point registers.  */
>        i387_supply_fsave (regcache, -1, state.hw_state);
>      }
> +#else
> +  gnu_debug ("fetch_fpregs() not support now\n");
> +#endif
>  }
> 
> +#ifndef GDBSERVER
>  #ifdef HAVE_SYS_PROCFS_H
>  /* These two calls are used by the core-regset.c code for
>     reading ELF core files.  */
> @@ -120,9 +136,16 @@ supply_fpregset (struct regcache *regcache, const
> gdb_fpregset_t *fpregs)
>    i387_supply_fsave (regcache, -1, fpregs);
>  }
>  #endif
> +#endif
> 
> +extern struct inf *gnu_current_inf;
> +extern ptid_t inferior_ptid;
>  /* Fetch register REGNO, or all regs if REGNO is -1.  */
> +#ifndef GDBSERVER
>  static void
> +#else
> +void
> +#endif
>  gnu_fetch_registers (struct target_ops *ops,
>       struct regcache *regcache, int regno)
>  {
> @@ -132,7 +155,11 @@ gnu_fetch_registers (struct target_ops *ops,
>    inf_update_procs (gnu_current_inf);
> 
>    thread = inf_tid_to_thread (gnu_current_inf,
> +#ifndef GDBSERVER
>        ptid_get_tid (inferior_ptid));
> +#else
> +      TIDGET (inferior_ptid));
> +#endif
>    if (!thread)
>      error (_("Can't fetch registers from thread %s: No such thread"),
>     target_pid_to_str (inferior_ptid));
> @@ -157,17 +184,25 @@ gnu_fetch_registers (struct target_ops *ops,
>    proc_debug (thread, "fetching all register");
> 
>    for (i = 0; i < I386_NUM_GREGS; i++)
> +#ifndef GDBSERVER
>      regcache_raw_supply (regcache, i, REG_ADDR (state, i));
> +#else
> +    supply_register (regcache, i, REG_ADDR (state, i));
> +#endif

I think it'd be better to add a wrapper function that adapts
the interfaces in one of the directions.

>    thread->fetched_regs = ~0;
>   }
>        else
>   {
> +#ifndef GDBSERVER
>    proc_debug (thread, "fetching register %s",
>        gdbarch_register_name (get_regcache_arch (regcache),
>       regno));
> 
>    regcache_raw_supply (regcache, regno,
>         REG_ADDR (state, regno));
> +#else
> +  supply_register (regcache, regno, REG_ADDR (state, regno));
> +#endif
>    thread->fetched_regs |= (1 << regno);
>   }
>      }
> @@ -183,9 +218,14 @@ gnu_fetch_registers (struct target_ops *ops,
> 
>  /* Store the whole floating-point state into THREAD using information
>     from the corresponding (pseudo) registers.  */
> +#ifndef GDBSERVER
>  static void
> +#else
> +void
> +#endif
>  store_fpregs (const struct regcache *regcache, struct proc *thread, int regno)
>  {
> +#ifndef GDBSERVER
>    mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
>    struct i386_float_state state;
>    error_t err;
> @@ -211,21 +251,36 @@ store_fpregs (const struct regcache *regcache,
> struct proc *thread, int regno)
>         proc_string (thread));
>        return;
>      }
> +#else
> +  gnu_debug ("store_fpregs() not support now\n");
> +#endif
>  }
> 
>  /* Store at least register REGNO, or all regs if REGNO == -1.  */
> +#ifndef GDBSERVER
>  static void
> +#else
> +void
> +#endif
>  gnu_store_registers (struct target_ops *ops,
>       struct regcache *regcache, int regno)
>  {
>    struct proc *thread;
> +#ifndef GDBSERVER
>    struct gdbarch *gdbarch = get_regcache_arch (regcache);
> +#else
> +  const struct target_desc *gdbarch = regcache->tdesc;
> +#endif
> 
>    /* Make sure we know about new threads.  */
>    inf_update_procs (gnu_current_inf);
> 
>    thread = inf_tid_to_thread (gnu_current_inf,
> +#ifndef GDBSERVER
>        ptid_get_tid (inferior_ptid));
> +#else
> +        TIDGET (inferior_ptid));
> +#endif
>    if (!thread)
>      error (_("Couldn't store registers into thread %s: No such thread"),
>     target_pid_to_str (inferior_ptid));
> @@ -265,12 +320,19 @@ gnu_store_registers (struct target_ops *ops,
>     register_size (gdbarch, check_regno)))
>        /* Register CHECK_REGNO has changed!  Ack!  */
>        {
> +#ifndef GDBSERVER
>   warning (_("Register %s changed after the thread was aborted"),
>   gdbarch_register_name (gdbarch, check_regno));
> +#endif
>   if (regno >= 0 && regno != check_regno)
>    /* Update GDB's copy of the register.  */
> +#ifndef GDBSERVER
>    regcache_raw_supply (regcache, check_regno,
>         REG_ADDR (state, check_regno));
> +#else
> +  supply_register (regcache, check_regno,
> +   REG_ADDR (state, check_regno));
> +#endif
>   else
>    warning (_("... also writing this register!  "
>       "Suspicious..."));
> @@ -284,16 +346,24 @@ gnu_store_registers (struct target_ops *ops,
>    proc_debug (thread, "storing all registers");
> 
>    for (i = 0; i < I386_NUM_GREGS; i++)
> +#ifndef GDBSERVER
>      if (REG_VALID == regcache_register_status (regcache, i))
>        regcache_raw_collect (regcache, i, REG_ADDR (state, i));
> +#else
> +    collect_register (regcache, i, REG_ADDR (state, i));
> +#endif
>   }
>        else
>   {
> +#ifndef GDBSERVER
>    proc_debug (thread, "storing register %s",
>        gdbarch_register_name (gdbarch, regno));
> 
>    gdb_assert (REG_VALID == regcache_register_status (regcache, regno));
>    regcache_raw_collect (regcache, regno, REG_ADDR (state, regno));
> +#else
> +  collect_register (regcache, regno, REG_ADDR (state, regno));
> +#endif
>   }
> 
>        /* Restore the T bit.  */
> @@ -309,6 +379,7 @@ gnu_store_registers (struct target_ops *ops,
>      }
>  }
> 
> +#ifndef GDBSERVER
>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>  extern initialize_file_ftype _initialize_i386gnu_nat;
> 
> @@ -326,3 +397,4 @@ _initialize_i386gnu_nat (void)
>    /* Register the target.  */
>    add_target (t);
>  }
> +#endif
> 
> ======================================================================
> gdbserver
>         * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load
>         i386gnu.mh.
>         * configure.srv (srv_tgtobj): Add gnu-nat.o i386gnu-nat.o.o for
>         GNU/Hurd.
>         (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd.
>         (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd.
>         * configure: Regenerate.
>         * Makefile.in (OBS): Add $(NATDEPFILES).
>         (generated_files): Add $(NAT_GENERATED_FILES).
>         (@host_makefile_frag@): New rule, add gnui386.mh.
>         (MIG): New tools.
>         (AWK): New tools.
>         * exc_request.defs: New file. Softlink to [gdb]/gdb/exc_request.defs.
>         * i386gnu-nat.c: New file. Softlink to [gdb]/gdb/i386gnu-nat.c.
>         * gnu-low.c: New file. Softlink to [gdb]/gdb/gnu-nat.c.
>         * gnu-low.h: New file. Softlink to [gdb]/gdb/gnu-nat.h.
>         * hostio.c: Add macro define PATH_MAX 512.
>         * i386gnu.mh: New file. Softlink to [gdb]/gdb/config/i386/i386gnu.mh.
>         * msg.defs: New file. Softlink to [gdb]/gdb/msg.defs.
>         * msg_reply.defs: New file. Softlink to [gdb]/gdb/msg_reply.defs.
>         * notify.defs: New file. Softlink to [gdb]/gdb/notify.defs.
>         * process_reply.defs: New file. Softlink to
> [gdb]/gdb/process_reply.defs.
>         * reply_mid_hack.awk: New file. Softlink to
> [gdb]/gdb/reply_mid_hack.awk.
>         * server.h: Add typedef long CORE_ADDR;
>         * utils.c (host_address_to_string): New functions, copy from
>         [gdb]/gdb/utils.c.
> 
> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index e8470a8..967cf57 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@
>  RANLIB = @RANLIB@
> 
>  CC = @CC@
> +MIG = @MIG@
> +AWK = @AWK@
> 
>  # Dependency tracking information.
>  DEPMODE = @CCDEPMODE@
> @@ -172,7 +174,7 @@ OBS = agent.o ax.o inferiors.o regcache.o
> remote-utils.o server.o signals.o targ
>   xml-utils.o common-utils.o ptid.o buffer.o format.o filestuff.o \
>   dll.o notif.o tdesc.o \
>   $(XML_BUILTIN) \
> - $(DEPFILES) $(LIBOBJS)
> + $(DEPFILES) $(LIBOBJS) $(NATDEPFILES)
>  GDBREPLAY_OBS = gdbreplay.o version.o
>  GDBSERVER_LIBS = @GDBSERVER_LIBS@
>  XM_CLIBS = @LIBS@
> @@ -195,6 +197,11 @@ CLEANDIRS = $(SUBDIRS)
>  # The format here is for the `case' shell command.
>  REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR)
> 
> +# Host-dependent makefile fragment comes in here.
> +GDBSERVER=@GDBSERVER@
> +@host_makefile_frag@
> +# End of host-dependent makefile fragment
> +
>  FLAGS_TO_PASS = \
>   "prefix=$(prefix)" \
>   "exec_prefix=$(exec_prefix)" \
> @@ -228,7 +235,7 @@ FLAGS_TO_PASS = \
>   "RUNTESTFLAGS=$(RUNTESTFLAGS)"
> 
>  # All generated files which can be included by another file.
> -generated_files = config.h $(GNULIB_H)
> +generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES)
> 
>  .c.o:
>   $(COMPILE) $<
> diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
> index b9928d7..21685db 100644
> --- a/gdb/gdbserver/configure.ac
> +++ b/gdb/gdbserver/configure.ac
> @@ -456,6 +456,31 @@ if $want_ipa ; then
>     fi
>  fi
> 
> +frags=
> +GDBSERVER=1
> +case $host_os in
> +  gnu*)
> +    #Needed for GNU Hurd hosts.
> +    AC_PROG_AWK
> +    AC_CHECK_TOOL(MIG, mig)
> +    if test x"$MIG" = x; then
> +      AC_MSG_ERROR([MIG not found but required for $host hosts])
> +    fi
> +    host_makefile_frag=${srcdir}/i386gnu.mh
> +    if test ! -f ${host_makefile_frag}; then
> +       AC_MSG_ERROR("*** Gdb does not support native target ${host}")
> +    fi
> +    frags="$frags $host_makefile_frag"
> +    ;;
> +  *)
> +    host_makefile_frag=/dev/null
> +    ;;
> +esac
> +
> +AC_SUBST_FILE(host_makefile_frag)
> +AC_SUBST(frags)
> +AC_SUBST(GDBSERVER)
> +
>  AC_SUBST(GDBSERVER_DEPFILES)
>  AC_SUBST(GDBSERVER_LIBS)
>  AC_SUBST(srv_xmlbuiltin)
> diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
> index 879d0de..1d9bf7a 100644
> --- a/gdb/gdbserver/configure.srv
> +++ b/gdb/gdbserver/configure.srv
> @@ -118,6 +118,11 @@ case "${target}" in
>   srv_linux_btrace=yes
>   ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
>   ;;
> +  i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj"
> + srv_tgtobj="gnu-nat.o i386gnu-nat.o"
> + srv_xmlfiles="$srv_i386_xmlfiles"
> + ;;
> +
>    i[34567]86-*-lynxos*) srv_regobj="i386.o"
>   srv_tgtobj="lynx-low.o lynx-i386-low.o"
>   srv_xmlfiles="i386/i386.xml"
> diff --git a/gdb/gdbserver/exc_request.defs b/gdb/gdbserver/exc_request.defs
> new file mode 120000
> index 0000000..1b8d3cd
> --- /dev/null
> +++ b/gdb/gdbserver/exc_request.defs
> @@ -0,0 +1 @@
> +../exc_request.defs
> \ No newline at end of file
> diff --git a/gdb/gdbserver/gnu-nat.c b/gdb/gdbserver/gnu-nat.c
> new file mode 120000
> index 0000000..d72e184
> --- /dev/null
> +++ b/gdb/gdbserver/gnu-nat.c
> @@ -0,0 +1 @@
> +../gnu-nat.c
> \ No newline at end of file
> diff --git a/gdb/gdbserver/gnu-nat.h b/gdb/gdbserver/gnu-nat.h
> new file mode 120000
> index 0000000..397c15c
> --- /dev/null
> +++ b/gdb/gdbserver/gnu-nat.h
> @@ -0,0 +1 @@
> +../gnu-nat.h
> \ No newline at end of file
> diff --git a/gdb/gdbserver/hostio.c b/gdb/gdbserver/hostio.c
> index df94d31..f3af499 100644
> --- a/gdb/gdbserver/hostio.c
> +++ b/gdb/gdbserver/hostio.c
> @@ -25,6 +25,10 @@
>  #include <limits.h>
>  #include <unistd.h>
> 
> +#ifndef PATH_MAX
> +#define PATH_MAX 512
> +#endif

This should not be necessary anymore.  If your patch
against current mainline?

> +
>  extern int remote_debug;
> 
>  struct fd_list
> diff --git a/gdb/gdbserver/i386gnu-nat.c b/gdb/gdbserver/i386gnu-nat.c
> new file mode 120000
> index 0000000..c547b9b
> --- /dev/null
> +++ b/gdb/gdbserver/i386gnu-nat.c
> @@ -0,0 +1 @@
> +../i386gnu-nat.c
> \ No newline at end of file
> diff --git a/gdb/gdbserver/i386gnu.mh b/gdb/gdbserver/i386gnu.mh
> new file mode 120000
> index 0000000..0497c22
> --- /dev/null
> +++ b/gdb/gdbserver/i386gnu.mh
> @@ -0,0 +1 @@
> +../config/i386/i386gnu.mh
> \ No newline at end of file
> diff --git a/gdb/gdbserver/msg.defs b/gdb/gdbserver/msg.defs
> new file mode 120000
> index 0000000..a663adb
> --- /dev/null
> +++ b/gdb/gdbserver/msg.defs
> @@ -0,0 +1 @@
> +../msg.defs
> \ No newline at end of file
> diff --git a/gdb/gdbserver/msg_reply.defs b/gdb/gdbserver/msg_reply.defs
> new file mode 120000
> index 0000000..61e8053
> --- /dev/null
> +++ b/gdb/gdbserver/msg_reply.defs
> @@ -0,0 +1 @@
> +../msg_reply.defs
> \ No newline at end of file
> diff --git a/gdb/gdbserver/notify.defs b/gdb/gdbserver/notify.defs
> new file mode 120000
> index 0000000..8a2c79d
> --- /dev/null
> +++ b/gdb/gdbserver/notify.defs
> @@ -0,0 +1 @@
> +../notify.defs
> \ No newline at end of file
> diff --git a/gdb/gdbserver/process_reply.defs b/gdb/gdbserver/process_reply.defs
> new file mode 120000
> index 0000000..7106ac0
> --- /dev/null
> +++ b/gdb/gdbserver/process_reply.defs
> @@ -0,0 +1 @@
> +../process_reply.defs
> \ No newline at end of file
> diff --git a/gdb/gdbserver/reply_mig_hack.awk b/gdb/gdbserver/reply_mig_hack.awk
> new file mode 120000
> index 0000000..fa7d33a
> --- /dev/null
> +++ b/gdb/gdbserver/reply_mig_hack.awk
> @@ -0,0 +1 @@
> +../reply_mig_hack.awk
> \ No newline at end of file
> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
> index 18d060c..20e88bf 100644
> --- a/gdb/gdbserver/server.h
> +++ b/gdb/gdbserver/server.h
> @@ -91,7 +91,8 @@ typedef unsigned char gdb_byte;
> 
>  /* FIXME: This should probably be autoconf'd for.  It's an integer type at
>     least the size of a (void *).  */
> -typedef long long CORE_ADDR;
> +//typedef long long CORE_ADDR;
> +typedef long CORE_ADDR;
> 
>  typedef long long LONGEST;
>  typedef unsigned long long ULONGEST;
> diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
> index 9706d74..d6dd4f9 100644
> --- a/gdb/gdbserver/utils.c
> +++ b/gdb/gdbserver/utils.c
> @@ -170,7 +170,6 @@ internal_error (const char *file, int line, const
> char *fmt, ...)
>  #define CELLSIZE 50
> 
>  /* Return the next entry in the circular buffer.  */
> -
>  static char *
>  get_cell (void)
>  {
> @@ -181,6 +180,15 @@ get_cell (void)
>    return buf[cell];
>  }
> 
> +const char *
> +host_address_to_string (const void *addr)
> +{
> +  char *str = get_cell ();
> +
> +  xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long)
> addr, sizeof (addr)));
> +  return str;
> +}
> +
>  static char *
>  decimal2str (char *sign, ULONGEST addr)
>  {
> 

Thanks,
-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 19:29         ` Pedro Alves
@ 2013-09-05 19:39           ` Joel Brobecker
  2013-09-05 21:38           ` Thomas Schwinge
                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 25+ messages in thread
From: Joel Brobecker @ 2013-09-05 19:39 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Yue Lu, Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

> I'm actually very excited to see gdb and gdbserver sharing
> a single target backend, even if we still have many wrinkles
> in the interfaces to iron out!

Mee too!

-- 
Joel


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 19:29         ` Pedro Alves
  2013-09-05 19:39           ` Joel Brobecker
@ 2013-09-05 21:38           ` Thomas Schwinge
  2013-09-08 13:35             ` Yue Lu
  2013-09-22 12:58             ` Yue Lu
  2013-09-06 18:53           ` Pedro Alves
  2013-09-09 10:21           ` [PATCH 1/2] Port gdbserver to GNU/Hurd Yue Lu
  3 siblings, 2 replies; 25+ messages in thread
From: Thomas Schwinge @ 2013-09-05 21:38 UTC (permalink / raw)
  To: Pedro Alves, Yue Lu; +Cc: gdb-patches, Luis Machado, bug-hurd

[-- Attachment #1: Type: text/plain, Size: 7195 bytes --]

Hi!

Just a very quick one; short on time.

On Thu, 05 Sep 2013 20:29:43 +0100, Pedro Alves <palves@redhat.com> wrote:
> On 09/05/2013 11:53 AM, Yue Lu wrote:
> > This is the my new patch.

You've received quite some positive feedback, good!  :-)

> Thanks.  Follows a few comments, by no means an in depth review.

Thanks for those reviews -- helps a lot.

> We'll probably need to iterate a few times.  I'm counting on
> Thomas and others to help as well!

Yes, but unfortunately not immediatelly.  Anyway, the more the code
converges towards using the present gnu-nat.c code on the one hand (which
I'll try to help with) as well as the present gdbserver code on the other
hand (which I don't have experience with, but Pedro has already pointed
out several items), the easier it will be to review.  And, we've made
quite a step forward with this revision of the patch, as far as I can
tell!

> It'd be very useful if you send and maintain along
> with the patch the rationale for all design divergences between
> the ports you found necessary.  E.g., it seems that gdbserver's
> task/proc bookkeeping is different from gdb's.  Why?

Yes, it'd be useful to have some source code comments next to (some of)
the »#ifdef GDBSERVER« (as well as elsewhere, of course).

> > --- a/gdb/config/i386/i386gnu.mh
> > +++ b/gdb/config/i386/i386gnu.mh
> > @@ -1,4 +1,5 @@
> >  # Host: Intel 386 running the GNU Hurd
> > +ifndef GDBSERVER
> >  NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \
> >       notify_S.o process_reply_S.o msg_reply_S.o \
> >       msg_U.o exc_request_U.o exc_request_S.o
> > @@ -12,6 +13,10 @@ XM_CLIBS = -lshouldbeinlibc
> >  # Use our own user stubs for the msg rpcs, so we can make them time out, in
> >  # case the program is fucked, or we guess the wrong signal thread.
> >  msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;'
> > +else
> > +NATDEPFILES= notify_S.o process_reply_S.o msg_reply_S.o \
> > +      exc_request_U.o exc_request_S.o
> > +endif

Pedro, is the idea that this file should also be shared with gdbserver?
Well, probably yes (for the moment), and the idea really is to move the
shared bits into common/, as with the other shared code.  So, I guess
this is fine for the moment.

> > --- a/gdb/gnu-nat.c
> > +++ b/gdb/gnu-nat.c
> > @@ -1,6 +1,7 @@
> >  /* Interface GDB to the GNU Hurd.
> >     Copyright (C) 1992-2013 Free Software Foundation, Inc.
> > 
> > +
> >     This file is part of GDB.
> 
> Please go through the patch and remove spurious whitespace
> changes line these.

Yes, this is generally good advise -- I (try to...) re-read every patch
I'm about to send by email or directly commit, and avoid any such
"spurious" changes.  GDB (as other GNU projects, too) tend to set a high
standard on code quality, which is good, and this also includes such
discipline when doing changes to the code.

> > +#ifdef GDBSERVER
> > +/* this should move into gnu-i386-low.c ?*/
> 
> I guess that means i386gnu-nat.c now, but it sounds like
> it, yes.
> 
> > +/* Defined in auto-generated file i386.c.  */
> > +extern void init_registers_i386 (void);
> > +extern const struct target_desc *tdesc_i386;

Yes, something with a i386 tag in it can't be in the generic gnu-nat.c
file.  (Not that there'd be any other GNU Hurd ports available, but you
get the idea.)

> (correct me if
> I'm wrong here), the Hurd's threads are kernel threads

Correct.

> so it'd
> be better to just make the GDB side use the lwp field too.
> It's really a simple and mechanic change.  Nothing in GDB core
> actually cares which field is used.  So in this case, it'd be
> better if you send a preparatory patch

Based on the current upstream master branch.

> that does that change
> (and nothing else)

Confirm that you haven't caused any regressions by running the GDB
testsuite (natively) without and then with your change (don't forget to
apply the testsuite patch I gave you earlier, to avoid the testsuite
hanging (known Hurd issue)), and diff the *.sum files to see that there
are no (major) differences (post them with your patch).

> and then rebase the port on top of that
> patch.

Please tell if you need help with how to use Git to rebase your current
patch onto the upstream master branch.  Also, did you figure out your
earlier question about how to merge several Git commits into one?

> >  /* Attach to process PID, then initialize for debugging it
> >     and wait for the trace-trap that results from attaching.  */
> > +#ifndef GDBSERVER
> >  static void
> >  gnu_attach (struct target_ops *ops, char *args, int from_tty)
> >  {
> > @@ -2207,8 +2347,14 @@ gnu_attach (struct target_ops *ops, char *args,
> > int from_tty)
> >    renumber_threads (0); /* Give our threads reasonable names.  */
> >  #endif
> >  }
> > +#else
> > +static int
> > +gnu_attach (unsigned long pid)
> > +{
> > +  return -1; //not support now
> 
> Doesn't look like this should be hard to get going.

With the native GDB port, there is a known issue when attaching to a
running processes (specifically if that process is currently doing a
kernel call (Mach RPC)), so I suggested to not spend time on this
functionality for the moment, and we can fix (native GDB) and implement
(gdbserver) that it later.

> >  /* Take a program previously attached to and detaches it.
> >     The program resumes execution and will no longer stop
> >     on signals, etc.  We'd better not have left any breakpoints
> > @@ -2216,6 +2362,7 @@ gnu_attach (struct target_ops *ops, char *args,
> > int from_tty)
> >     to work, it may be necessary for the process to have been
> >     previously attached.  It *might* work if the program was
> >     started via fork.  */
> > +#ifndef GDBSERVER
> >  static void
> >  gnu_detach (struct target_ops *ops, char *args, int from_tty)
> >  {
> > @@ -2255,7 +2402,25 @@ gnu_stop (ptid_t ptid)
> >  {
> >    error (_("to_stop target function not implemented"));
> >  }
> > +#else
> > +static int
> > +gnu_detach (int pid)
> > +{
> 
> Eheh, we have detach but not attach.  ;-)

Even if attaching doesn't, detaching from a process started with
gdbserver does work.  ;-)

> > +static void
> > +gnu_request_interrupt (void)
> > +{
> > +  printf ("gnu_request_interrupt not support!\n");
> > +  exit (-1);
> 
> That's quite limiting.  :-/  Doesn't sending a SIGINT
> work?

Please give that a try, but if it's more difficult, I again suggest we
finish that later.

> > --- a/gdb/gnu-nat.h
> > +++ b/gdb/gnu-nat.h

> > +#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE
> > +#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT
> > +#define THREAD_STATE_SET_TRACED(state) \
> > +   ((struct i386_thread_state *) (state))->efl |= 0x100
> > +#define THREAD_STATE_CLEAR_TRACED(state) \
> > +   ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1)

That's again for a i386 file.

Further review to come later.


Now, please try to address the comments raised (especially also Pedro's),
and don't hesitate to ask if there are any questions.


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 19:29         ` Pedro Alves
  2013-09-05 19:39           ` Joel Brobecker
  2013-09-05 21:38           ` Thomas Schwinge
@ 2013-09-06 18:53           ` Pedro Alves
  2013-09-12  3:05             ` Yue Lu
  2013-09-09 10:21           ` [PATCH 1/2] Port gdbserver to GNU/Hurd Yue Lu
  3 siblings, 1 reply; 25+ messages in thread
From: Pedro Alves @ 2013-09-06 18:53 UTC (permalink / raw)
  To: gdb-patches; +Cc: Yue Lu, Thomas Schwinge, Luis Machado, bug-hurd

Hi!

On 09/05/2013 08:29 PM, Pedro Alves wrote:
>> > +static int
>> > +gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
>> > +{
>> > +  int ret = 0;
>> > +  task_t task = (gnu_current_inf
>> > + ? (gnu_current_inf->task
>> > +    ? gnu_current_inf->task->port : 0) : 0);
>> > +  if (task == MACH_PORT_NULL)
>> > +    return 0;
>> > +  ret = gnu_read_inferior (task, addr, myaddr, length);
>> > +  if (length != ret)
>> > +    {
>> > +      gnu_debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret);
>> > +      return -1;
>> > +    }
>> > +  return 0;
>> > +}
>> > +
>> > +static int
>> > +gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length)
>> > +{
>> > +  int ret = 0;
>> > +  task_t task = (gnu_current_inf
>> > + ? (gnu_current_inf->task
>> > +    ? gnu_current_inf->task->port : 0) : 0);
>> > +  if (task == MACH_PORT_NULL)
>> > +    return 0;
>> > +  ret = gnu_write_inferior (task, addr, myaddr, length);
>> > +  if (length != ret)
>> > +    {
>> > +      gnu_debug ("gnu_write_inferior,length=%d, but return %d\n", length,
>> > + ret);
>> > +      return -1;
>> > +    }
>> > +  return 0;
>> > +}
>> > +
> These should reall be wrappers around a common shared function.  I have
> a patch that I think helps here.  I'll post it in soon.
> 

This is what I meant:
https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html

I was thinking you'd wrap gnu_xfer_memory.

But I have to say I don't really understand the real need for
all those:

  task_t task = (gnu_current_inf
		 ? (gnu_current_inf->task
		    ? gnu_current_inf->task->port : 0)
		 : 0);
  int res;

  if (task == MACH_PORT_NULL)
    return 0;

checks in the existing code.  I mean, why would we reach here with
an invalid inferior/task/port selected?
It just reads as workaround for some bug to me.

Thanks,
-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 21:38           ` Thomas Schwinge
@ 2013-09-08 13:35             ` Yue Lu
  2013-09-09  9:58               ` Thomas Schwinge
  2013-09-22 12:58             ` Yue Lu
  1 sibling, 1 reply; 25+ messages in thread
From: Yue Lu @ 2013-09-08 13:35 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Pedro Alves, gdb-patches, Luis Machado, bug-hurd

Hi,

On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote:
>> (correct me if
>> I'm wrong here), the Hurd's threads are kernel threads
>
> Correct.
>
>> so it'd
>> be better to just make the GDB side use the lwp field too.
>> It's really a simple and mechanic change.  Nothing in GDB core
>> actually cares which field is used.  So in this case, it'd be
>> better if you send a preparatory patch
>
> Based on the current upstream master branch.
>

Should I change the gdb use lwp filed instead of tid field? There are
too many functions use tid. Like
make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field
named tid in the structure proc also.

We can define a macro for gdbserver to use another ptid_build function
to use lwp instead of tid, if this, we only need do a little change.

Because of there are a lot of place to improve in my patch, I will
submit my next patch a little later.  Now I have only finished
removing the spurious blank and the soft link.

-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-08 13:35             ` Yue Lu
@ 2013-09-09  9:58               ` Thomas Schwinge
  2013-09-18 12:12                 ` Pedro Alves
  0 siblings, 1 reply; 25+ messages in thread
From: Thomas Schwinge @ 2013-09-09  9:58 UTC (permalink / raw)
  To: Yue Lu, Pedro Alves; +Cc: gdb-patches, Luis Machado, bug-hurd

[-- Attachment #1: Type: text/plain, Size: 2443 bytes --]

Hi!

On Sun, 8 Sep 2013 21:35:05 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
> On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote:
> >> (correct me if
> >> I'm wrong here), the Hurd's threads are kernel threads
> >
> > Correct.
> >
> >> so it'd
> >> be better to just make the GDB side use the lwp field too.
> >> It's really a simple and mechanic change.  Nothing in GDB core
> >> actually cares which field is used.  So in this case, it'd be

In GDB's parlance, a lightweight process (identified by a LWP) is a
thread that always has a corresponding kernel thread, and in contrast a
"generic" thread (identified by a TID) is not required to always have a
corresponding kernel thread, for example, when managed by a run-time
library?  Then, yes, conceptually the native Hurd port should be switched
to using LWPs instead of TIDs.

> >> better if you send a preparatory patch
> >
> > Based on the current upstream master branch.
> 
> Should I change the gdb use lwp filed instead of tid field? There are
> too many functions use tid. Like
> make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field
> named tid in the structure proc also.

As you have found, there is a lot of TID usage in gnu-nat.c.  TIDs are
assigned based on the next_thread_id variable:

    /* A variable from which to assign new TIDs.  */
    static int next_thread_id = 1;
    [...]
              /* THREADS[I] is a thread we don't know about yet!  */
              {
                ptid_t ptid;
    
                thread = make_proc (inf, threads[i], next_thread_id++);

Five years ago, we've already concluded this is due for some cleanup,
<http://www.gnu.org/software/hurd/open_issues/gdb_thread_ids.html>.  But
I don't want to require this cleanup to happen before/in context of the
Google Summer of Code project's code submission discussed here.

> We can define a macro for gdbserver to use another ptid_build function
> to use lwp instead of tid, if this, we only need do a little change.

That seems like a sensible approach to me, for the moment.  And then do
the cleanup later on.


> Because of there are a lot of place to improve in my patch, I will
> submit my next patch a little later.  Now I have only finished
> removing the spurious blank and the soft link.

That's fine.  Such tasks always takes longer than expected.  ;-)


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 19:29         ` Pedro Alves
                             ` (2 preceding siblings ...)
  2013-09-06 18:53           ` Pedro Alves
@ 2013-09-09 10:21           ` Yue Lu
  3 siblings, 0 replies; 25+ messages in thread
From: Yue Lu @ 2013-09-09 10:21 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

Hi,

On Fri, Sep 6, 2013 at 3:29 AM, Pedro Alves <palves@redhat.com> wrote:
> I'm actually very excited to see gdb and gdbserver sharing
> a single target backend, even if we still have many wrinkles
> in the interfaces to iron out!  It does looks like this way
> results in lots of less work, and makes me believe we can
> port other targets to gdbserver already without unsurmountable
> effort.

Do you mean there should be only one structure target_obj in both gdb
and gdbserver?
But I have found that, the structure has been declared different
between gdb and gdbserver, How can I integrate them into single one.
Or just I have got the wrong understand.


-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-06 18:53           ` Pedro Alves
@ 2013-09-12  3:05             ` Yue Lu
  2013-09-18 12:30               ` Pedro Alves
  2013-09-18 12:37               ` Pedro Alves
  0 siblings, 2 replies; 25+ messages in thread
From: Yue Lu @ 2013-09-12  3:05 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd

Hi,

On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote:
> This is what I meant:
> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html
>
> I was thinking you'd wrap gnu_xfer_memory.
>

I have study your patch, but I found there is no to_xfer_partial field
or something similar in gdbserver's structure target_obj, how can I
do? Please give me more hints, thanks.

> But I have to say I don't really understand the real need for
> all those:
>
>   task_t task = (gnu_current_inf
>                  ? (gnu_current_inf->task
>                     ? gnu_current_inf->task->port : 0)
>                  : 0);
>   int res;
>
>   if (task == MACH_PORT_NULL)
>     return 0;
>
> checks in the existing code.  I mean, why would we reach here with
> an invalid inferior/task/port selected?
> It just reads as workaround for some bug to me.

Honestly to say, I have copied them from function gnu_xfer_memory. But
I think, before reference a pointer, check whether it was a NULL seems
not a bad way :-).

And this is my update patch which is base on the current upstream master branch.
======================================================================
gdbserver
        * configure.ac (host_makefile_frag): New rule for GNU/Hurd to load
        i386gnu.mh.
        * configure.srv (srv_tgtobj): Add gnu-nat.o i386gnu-nat.o. for
        GNU/Hurd.
        (srv_regobj): Add $(srv_i386_regobj) for GNU/Hurd.
        (srv_xmlfiles): Add $(srv_i386_xmlfiles) for GNU/Hurd.
        * configure: Regenerate.
        * Makefile.in (OBS): Add $(NATDEPFILES).
        (generated_files): Add $(NAT_GENERATED_FILES).
        (@host_makefile_frag@): New rule, add i386gnu.mh.
        (MIG): New tools.
        (AWK): New tools.
        * utils.c (host_address_to_string): New functions, copy from
        [gdb]/gdb/utils.c.

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 1805e5a..6da44d1 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -50,6 +50,8 @@ INSTALL_DATA = @INSTALL_DATA@
 RANLIB = @RANLIB@

 CC = @CC@
+MIG = @MIG@
+AWK = @AWK@

 # Dependency tracking information.
 DEPMODE = @CCDEPMODE@
@@ -176,7 +178,7 @@ OBS = agent.o ax.o inferiors.o regcache.o
remote-utils.o server.o signals.o \
       target.o waitstatus.o utils.o version.o vec.o gdb_vecs.o \
       mem-break.o hostio.o event-loop.o tracepoint.o xml-utils.o \
       common-utils.o ptid.o buffer.o format.o filestuff.o dll.o notif.o \
-      tdesc.o $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS)
+      tdesc.o $(XML_BUILTIN) $(DEPFILES) $(LIBOBJS) $(NATDEPFILES)
 GDBREPLAY_OBS = gdbreplay.o version.o
 GDBSERVER_LIBS = @GDBSERVER_LIBS@
 XM_CLIBS = @LIBS@
@@ -199,6 +201,11 @@ CLEANDIRS = $(SUBDIRS)
 # The format here is for the `case' shell command.
 REQUIRED_SUBDIRS = $(GNULIB_BUILDDIR)

+# Host-dependent makefile fragment comes in here.
+GDBSERVER_HURD=@GDBSERVER_HURD@
+@host_makefile_frag@
+# End of host-dependent makefile fragment
+
 FLAGS_TO_PASS = \
  "prefix=$(prefix)" \
  "exec_prefix=$(exec_prefix)" \
@@ -232,7 +239,7 @@ FLAGS_TO_PASS = \
  "RUNTESTFLAGS=$(RUNTESTFLAGS)"

 # All generated files which can be included by another file.
-generated_files = config.h $(GNULIB_H)
+generated_files = config.h $(GNULIB_H) $(NAT_GENERATED_FILES)

 .c.o:
  $(COMPILE) $<
@@ -522,6 +529,16 @@ mips-linux-watch.o: ../common/mips-linux-watch.c
  $(COMPILE) $<
  $(POSTCOMPILE)

+ifdef GDBSERVER_HURD
+#fixme, if use i386gnu-nat.o here will complain that can't find rule
for target i386gnu-gnu.c
+i386gnu-nat_foo.o: $(srcdir)/../i386gnu-nat.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+gnu-nat.o: $(srcdir)/../gnu-nat.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+endif
+
 # Native object files rules from ../nat

 linux-waitpid.o: ../nat/linux-waitpid.c
@@ -535,6 +552,9 @@ linux-waitpid.o: ../nat/linux-waitpid.c
 vasprintf.o: $(srcdir)/../../libiberty/vasprintf.c
  $(COMPILE) $< -DHAVE_CONFIG_H
  $(POSTCOMPILE)
+obstack.o: $(srcdir)/../../libiberty/obstack.c
+ $(COMPILE) $< -DHAVE_CONFIG_H
+ $(POSTCOMPILE)
 vsnprintf.o: $(srcdir)/../../libiberty/vsnprintf.c
  $(COMPILE) $<
  $(POSTCOMPILE)
diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac
index 456a1f7..7d4eb75 100644
--- a/gdb/gdbserver/configure.ac
+++ b/gdb/gdbserver/configure.ac
@@ -471,6 +471,31 @@ if $want_ipa ; then
    fi
 fi

+frags=
+GDBSERVER_HURD=1
+case $host_os in
+  gnu*)
+    #Needed for GNU Hurd hosts.
+    AC_PROG_AWK
+    AC_CHECK_TOOL(MIG, mig)
+    if test x"$MIG" = x; then
+      AC_MSG_ERROR([MIG not found but required for $host hosts])
+    fi
+    host_makefile_frag=${srcdir}/../config/i386/i386gnu.mh
+    if test ! -f ${host_makefile_frag}; then
+       AC_MSG_ERROR("*** Gdb does not support native target ${host}")
+    fi
+    frags="$frags $host_makefile_frag"
+    ;;
+  *)
+    host_makefile_frag=/dev/null
+    ;;
+esac
+
+AC_SUBST_FILE(host_makefile_frag)
+AC_SUBST(frags)
+AC_SUBST(GDBSERVER_HURD)
+
 AC_SUBST(GDBSERVER_DEPFILES)
 AC_SUBST(GDBSERVER_LIBS)
 AC_SUBST(srv_xmlbuiltin)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index b3c0421..d370e4a 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -116,6 +116,10 @@ case "${target}" in
  srv_linux_btrace=yes
  ipa_obj="${ipa_i386_linux_regobj} linux-i386-ipa.o"
  ;;
+  i[34567]86-*-gnu*) srv_regobj="$srv_i386_regobj"
+ srv_tgtobj=""
+ srv_xmlfiles="$srv_i386_xmlfiles"
+ ;;
   i[34567]86-*-lynxos*) srv_regobj="i386.o"
  srv_tgtobj="lynx-low.o lynx-i386-low.o"
  srv_xmlfiles="i386/i386.xml"
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 9706d74..a181d06 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -181,6 +181,15 @@ get_cell (void)
   return buf[cell];
 }

+const char *
+host_address_to_string (const void *addr)
+{
+  char *str = get_cell ();
+
+  xsnprintf (str, CELLSIZE, "0x%s", phex_nz ((unsigned long long)
addr, sizeof (addr)));
+  return str;
+}
+
 static char *
 decimal2str (char *sign, ULONGEST addr)
 {

======================================================================
gdb
        * configure.tgt: Set build_gdbserver=yes for GNU/Hurd hosts.
        * configure: Regenerate.
        * config/i386/i386gnu.mh: Add #ifdef to determine which rule
to use in gdbserver.
        * i386gnu-nat.c: Add macor GDBSERVER to support build gdbserver.
        * gnu-nat.h: Add macor GDBSERVER to support build gdbserver.
        * gnu-nat.c: Add macor GDBSERVER to support build gdbserver.
        (gnu_kill): New function, used in gdbserver.
        (gnu_mourn): New function, clean up after inferior dies, used
in gdbserver.
        (gnu_create_inferior): New function, use for create inferior
in gdbserver.
        (gnu_attach): New function, a placeholder.
        (gnu_detach): New function, used in gdbserver detach from inferior.
        (gnu_thread_alive): New function, call find_thread_ptid().
        (gnu_ptid_build): New function, build structure ptid_t from
pid, and tid when has GDBSERVER defined.
        (gnu_get_tid): New function, return lwp from structure ptid_t,when has
GDBSERVER defined.
        (gnu_add_process): New function, add a new process to process list.
        (gnu_join): New function, a placeholder.
        (gnu_resume_wrap): New function, a wrap function, just call
gnu_resume().
        (gnu_wait_wrap): New function, a wrap function, just call gnu_wait().
        (gnu_fetch_registers_wrap): New function, a wrap function,
just call gnu_fetch_registers().
        (gnu_store_registers_wrap): New function, a wrap function,
just call gnu_store_registers().
        (gnu_read_memory): New function, a wrap function, just call
gnu_read_inferior().
        (gnu_write_memory): New function, a wrap function, just call
gnu_write_inferior().
        (gnu_request_interrupt): New function, used in gdbserver.
        (store_waitstatus): New function, helper function, copy from
[gdb]/gdb/inf-child.c.
        (initialize_low): New function, use for initialize gdbserver's
target_ops.
        (initialize_low_arch): New function, used by initialize_low().
        (_initialize_gnu_nat): New function, used by initialize_low().

diff --git a/gdb/config/i386/i386gnu.mh b/gdb/config/i386/i386gnu.mh
index a3ea122..4b9d64d 100644
--- a/gdb/config/i386/i386gnu.mh
+++ b/gdb/config/i386/i386gnu.mh
@@ -1,5 +1,6 @@
 # Host: Intel 386 running the GNU Hurd
-NATDEPFILES= i386gnu-nat.o gnu-nat.o core-regset.o fork-child.o \
+ifndef GDBSERVER_HURD
+NATDEPFILES= gnu-nat.o i386gnu-nat.o core-regset.o fork-child.o \
      notify_S.o process_reply_S.o msg_reply_S.o \
      msg_U.o exc_request_U.o exc_request_S.o
 HAVE_NATIVE_GCORE_HOST = 1
@@ -12,22 +13,41 @@ XM_CLIBS = -lshouldbeinlibc
 # Use our own user stubs for the msg rpcs, so we can make them time out, in
 # case the program is fucked, or we guess the wrong signal thread.
 msg-MIGUFLAGS = -D'MSG_IMPORTS=waittime 1000;'
+else
+NATDEPFILES= gnu-nat.o i386gnu-nat_foo.o obstack.o notify_S.o
process_reply_S.o msg_reply_S.o \
+      exc_request_U.o exc_request_S.o
+endif

 # ick
 MIGCOM = $(MIG) -cc cat - /dev/null

 # Reply servers need special massaging of the code mig generates, to make
 # them work correctly for error returns in some cases.
+ifndef GDBSERVER_HURD
 %_reply_S.h %_reply_S.c: %_reply.defs
  $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \
  | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user
/dev/null -header /dev/null \
  && $(AWK) -f $(srcdir)/reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c
+else
+%_reply_S.h %_reply_S.c: %_reply.defs
+ $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \
+ | $(MIGCOM) -sheader $*_reply_S.h -server $*_reply_S.raw -user
/dev/null -header /dev/null \
+ && $(AWK) -f $(srcdir)/../reply_mig_hack.awk < $*_reply_S.raw > $*_reply_S.c
+endif
 # Normal servers
+ifndef GDBSERVER_HURD
 %_S.h %_S.c: %.defs
+else
+%_S.h %_S.c: $(srcdir)/../%.defs
+endif
  $(CPP) $(CPPFLAGS) -DSERVERPREFIX=S_ -x c $< \
  | $(MIGCOM) -sheader $*_S.h -server $*_S.c -user /dev/null -header /dev/null
 # User rpc stubs
+ifndef GDBSERVER_HURD
 %_U.h %_U.c: %.defs
+else
+%_U.h %_U.c: $(srcdir)/../%.defs
+endif
  $(CPP) $(CPPFLAGS) $($*-MIGUFLAGS) -x c $< \
  | $(MIGCOM) -sheader /dev/null -server /dev/null -user $*_U.c -header $*_U.h

diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 95c7217..e841a9a 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -231,6 +231,7 @@ i[34567]86-*-linux*)
 i[34567]86-*-gnu*)
  # Target: Intel 386 running the GNU Hurd
  gdb_target_obs="i386-tdep.o i387-tdep.o i386gnu-tdep.o solib-svr4.o"
+ build_gdbserver=yes
  ;;
 i[34567]86-*-cygwin*)
  # Target: Intel 386 running win32
diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 59d2f23..9e37e2b 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -20,29 +20,16 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

+#ifndef GDBSERVER
 #include "defs.h"

 #include <ctype.h>
 #include <errno.h>
-#include <limits.h>
 #include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
 #include "gdb_string.h"
-#include <sys/ptrace.h>
-
-#include <mach.h>
-#include <mach_error.h>
-#include <mach/exception.h>
-#include <mach/message.h>
-#include <mach/notify.h>
-#include <mach/vm_attributes.h>

-#include <hurd.h>
-#include <hurd/interrupt.h>
-#include <hurd/msg.h>
-#include <hurd/msg_request.h>
-#include <hurd/process.h>
 /* Defined in <hurd/process.h>, but we need forward declarations from
    <hurd/process_request.h> as well.  */
 #undef _process_user_
@@ -56,25 +43,63 @@
 #include "symtab.h"
 #include "value.h"
 #include "language.h"
-#include "target.h"
-#include "gdb_wait.h"
 #include "gdbcmd.h"
 #include "gdbcore.h"
 #include "gdbthread.h"
 #include "gdb_assert.h"
-#include "gdb_obstack.h"

-#include "gnu-nat.h"
 #include "inf-child.h"

+#include "exc_request_U.h"
+#include "msg_U.h"
+
+#else /* GDBSERVER */
+#include "server.h"
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <signal.h>
+#endif /* GDBSERVER */
+
+#include "target.h"
+
+#include <limits.h>
+#include <sys/ptrace.h>
+#include "gdb_obstack.h"
+#include "gdb_wait.h"
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/exception.h>
+#include <mach/message.h>
+
+#include <mach/notify.h>
+#include <mach/vm_attributes.h>
+
+#include <hurd.h>
+#include <hurd/interrupt.h>
+#include <hurd/msg.h>
+#include <hurd/msg_request.h>
+#include <hurd/process.h>
+
+#include "gnu-nat.h"
 #include "exc_request_S.h"
 #include "notify_S.h"
 #include "process_reply_S.h"
 #include "msg_reply_S.h"
-#include "exc_request_U.h"
-#include "msg_U.h"

 static process_t proc_server = MACH_PORT_NULL;
+#ifdef GDBSERVER
+/* this should move into i386gnu-nat.c ?*/
+/* Defined in auto-generated file i386.c.  */
+extern void init_registers_i386 (void);
+extern const struct target_desc *tdesc_i386;
+const struct target_desc *gnu_tdesc;
+int using_threads = 1;
+ptid_t inferior_ptid;
+static struct target_ops gnu_target_ops;
+#endif

 /* If we've sent a proc_wait_request to the proc server, the pid of the
    process we asked about.  We can only ever have one outstanding.  */
@@ -114,6 +139,9 @@ void inf_continue (struct inf *inf);
        debug ("{inf %d %s}: " msg, __inf->pid, \
        host_address_to_string (__inf) , ##args); } while (0)

+#ifdef GDBSERVER
+static struct process_info * gnu_add_process (int pid, int attached);
+#endif
 void proc_abort (struct proc *proc, int force);
 struct proc *make_proc (struct inf *inf, mach_port_t port, int tid);
 struct proc *_proc_free (struct proc *proc);
@@ -145,6 +173,13 @@ int proc_trace (struct proc *proc, int set);
  __e; }) \
    : EIEIO)

+#ifdef GDBSERVER
+struct process_info_private
+{
+  struct inf *inf;
+};
+#endif
+

 /* The state passed by an exception message.  */
 struct exc_state
@@ -242,6 +277,25 @@ struct inf
     int want_exceptions;
   };

+static ptid_t
+gnu_ptid_build (int pid, long lwp, long tid)
+{
+#ifndef GDBSERVER
+  return ptid_build (pid, lwp, tid);
+#else
+  return ptid_build (pid, tid, lwp);
+#endif
+}
+
+long
+gnu_get_tid (ptid_t ptid)
+{
+#ifndef GDBSERVER
+  return ptid_get_tid(ptid);
+#else
+  return ptid_get_lwp (ptid);
+#endif
+}

 int
 __proc_pid (struct proc *proc)
@@ -855,6 +909,7 @@ inf_validate_task_sc (struct inf *inf)

   if (inf->task->cur_sc < suspend_count)
     {
+#ifndef GDBSERVER //need fix, I am not sure whether gdbserver need this or not?
       int abort;

       target_terminal_ours (); /* Allow I/O.  */
@@ -865,7 +920,7 @@ inf_validate_task_sc (struct inf *inf)

       if (abort)
  error (_("Additional task suspend count left untouched."));
-
+#endif
       inf->task->cur_sc = suspend_count;
     }
 }
@@ -1056,6 +1111,12 @@ inf_validate_procs (struct inf *inf)
  if (!left)
   {
     proc_debug (thread, "died!");
+#ifdef GDBSERVER
+    ptid_t ptid;
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
+    if (find_thread_ptid (ptid))
+      remove_thread (find_thread_ptid (ptid));
+#endif
     thread->port = MACH_PORT_NULL;
     thread = _proc_free (thread); /* THREAD is dead.  */
     if (last)
@@ -1083,10 +1144,11 @@ inf_validate_procs (struct inf *inf)
     last = thread;
     proc_debug (thread, "new thread: %d", threads[i]);

-    ptid = ptid_build (inf->pid, 0, thread->tid);
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);

     /* Tell GDB's generic thread code.  */

+#ifndef GDBSERVER
     if (ptid_equal (inferior_ptid, pid_to_ptid (inf->pid)))
       /* This is the first time we're hearing about thread
  ids, after a fork-child.  */
@@ -1096,6 +1158,15 @@ inf_validate_procs (struct inf *inf)
       add_thread_silent (ptid);
     else
       add_thread (ptid);
+#else
+    if (!find_thread_ptid (ptid))
+      {
+ debug ("New thread, pid=%d, tid=%d\n", inf->pid,
+   thread->tid);
+ add_thread (ptid, thread);
+ //inferior_ptid = ptid; /* need fix; seems this line not need, but I
can't explain why*/
+      }
+#endif
   }
       }

@@ -1221,6 +1292,7 @@ inf_set_threads_resume_sc_for_signal_thread
(struct inf *inf)
     return 0;
 }

+#ifndef GDBSERVER
 static void
 inf_update_signal_thread (struct inf *inf)
 {
@@ -1229,6 +1301,7 @@ inf_update_signal_thread (struct inf *inf)
   inf->signal_thread = inf->threads ? inf->threads->next : 0;
 }

+#endif

 /* Detachs from INF's inferior task, letting it run once again...  */
 void
@@ -1284,6 +1357,7 @@ inf_attach (struct inf *inf, int pid)
   inf_startup (inf, pid);
 }

+#ifndef GDBSERVER

 /* Makes sure that we've got our exception ports entrenched in the process.  */
 void
@@ -1314,6 +1388,7 @@ inf_restore_exc_ports (struct inf *inf)
   for (thread = inf->threads; thread; thread = thread->next)
     proc_restore_exc_port (thread);
 }
+#endif


 /* Deliver signal SIG to INF.  If INF is stopped, delivering a signal, even
@@ -1613,19 +1688,17 @@ rewait:

   thread = inf->wait.thread;
   if (thread)
-    ptid = ptid_build (inf->pid, 0, thread->tid);
+    ptid = gnu_ptid_build (inf->pid, 0, thread->tid);
   else if (ptid_equal (ptid, minus_one_ptid))
     thread = inf_tid_to_thread (inf, -1);
   else
-    thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+    thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));

   if (!thread || thread->port == MACH_PORT_NULL)
     {
       /* TID is dead; try and find a new thread.  */
       if (inf_update_procs (inf) && inf->threads)
- ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first
-       available
-       thread.  */
+ ptid = gnu_ptid_build (inf->pid, 0, inf->threads->tid);/* The first
available thread*/
       else
  ptid = inferior_ptid; /* let wait_for_inferior handle exit case */
     }
@@ -1651,6 +1724,12 @@ rewait:
      : "?",
      status->value.integer);

+#ifdef GDBSERVER
+  inferior_ptid = ptid;
+/* why this? because in gdb, the inferior_ptid is used in all over world,
+ if gdbserver use another one to do the same thing, we will need a lot of
+#ifdef GDBSERVER in this file, so we re-used this in gdbserver */
+#endif
   return ptid;
 }

@@ -2022,7 +2101,7 @@ gnu_resume (struct target_ops *ops,
   else
     /* Just allow a single thread to run.  */
     {
-      struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      struct proc *thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));

       if (!thread)
  error (_("Can't run single thread id %s: no such thread!"),
@@ -2033,7 +2112,7 @@ gnu_resume (struct target_ops *ops,

   if (step)
     {
-      step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      step_thread = inf_tid_to_thread (inf, gnu_get_tid (ptid));
       if (!step_thread)
  warning (_("Can't step thread id %s: no such thread."),
  target_pid_to_str (ptid));
@@ -2047,6 +2126,7 @@ gnu_resume (struct target_ops *ops,
   inf_resume (inf);
 }

+#ifndef GDBSERVER

 static void
 gnu_kill_inferior (struct target_ops *ops)
@@ -2061,8 +2141,29 @@ gnu_kill_inferior (struct target_ops *ops)
     }
   target_mourn_inferior ();
 }
+#else
+static int
+gnu_kill (int pid)
+{
+  struct proc *task = gnu_current_inf->task;
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+
+  if (task)
+    {
+      proc_debug (task, "terminating...");
+      task_terminate (task->port);
+      inf_set_pid (gnu_current_inf, -1);
+    }
+  the_target->mourn (process);
+  return 0;
+}
+#endif
+

 /* Clean up after the inferior dies.  */
+#ifndef GDBSERVER
 static void
 gnu_mourn_inferior (struct target_ops *ops)
 {
@@ -2071,6 +2172,17 @@ gnu_mourn_inferior (struct target_ops *ops)
   unpush_target (ops);
   generic_mourn_inferior ();
 }
+#else
+static void
+gnu_mourn (struct process_info *process)
+{
+  /* Free our private data.  */
+  free (process->private);
+  process->private = NULL;
+
+  clear_inferiors ();
+}
+#endif


 /* Fork an inferior process, and start debugging it.  */
@@ -2095,6 +2207,7 @@ cur_inf (void)
   return gnu_current_inf;
 }

+#ifndef GDBSERVER
 static void
 gnu_create_inferior (struct target_ops *ops,
      char *exec_file, char *allargs, char **env,
@@ -2148,10 +2261,35 @@ gnu_create_inferior (struct target_ops *ops,
   else
     inf_restore_exc_ports (inf);
 }
+#else
+static int
+gnu_create_inferior (char *program, char **allargs)
+{
+  int pid;
+  pid = fork ();
+  if (pid < 0)
+    perror_with_name ("fork");
+
+  if (pid == 0)
+    {
+      ptrace (PTRACE_TRACEME);
+      setpgid (0, 0);
+      execv (program, allargs);
+
+      fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno));
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  gnu_add_process (pid, 0);
+  return pid;
+}
+#endif


 /* Attach to process PID, then initialize for debugging it
    and wait for the trace-trap that results from attaching.  */
+#ifndef GDBSERVER
 static void
 gnu_attach (struct target_ops *ops, char *args, int from_tty)
 {
@@ -2207,6 +2345,13 @@ gnu_attach (struct target_ops *ops, char *args,
int from_tty)
   renumber_threads (0); /* Give our threads reasonable names.  */
 #endif
 }
+#else
+static int
+gnu_attach (unsigned long pid)
+{
+  return -1; //not support now
+}
+#endif


 /* Take a program previously attached to and detaches it.
@@ -2216,6 +2361,7 @@ gnu_attach (struct target_ops *ops, char *args,
int from_tty)
    to work, it may be necessary for the process to have been
    previously attached.  It *might* work if the program was
    started via fork.  */
+#ifndef GDBSERVER
 static void
 gnu_detach (struct target_ops *ops, char *args, int from_tty)
 {
@@ -2255,6 +2401,23 @@ gnu_stop (ptid_t ptid)
 {
   error (_("to_stop target function not implemented"));
 }
+#else
+static int
+gnu_detach (int pid)
+{
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
+
+  inf_detach (gnu_current_inf);
+
+  inferior_ptid = null_ptid;
+  the_target->mourn (process);
+  return 0;
+}
+#endif

 static int
 gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
@@ -2454,7 +2617,9 @@ gnu_write_inferior (task_t task, CORE_ADDR addr,
char *myaddr, int length)
 out:
   if (deallocate)
     {
+#ifdef GDBSERVER
       obstack_free (&region_obstack, 0);
+#endif

       (void) vm_deallocate (mach_task_self (),
     copied,
@@ -2470,6 +2635,7 @@ out:
   return length;
 }

+#ifndef GDBSERVER

 /* Return 0 on failure, number of bytes handled otherwise.  TARGET
    is ignored.  */
@@ -2576,6 +2742,7 @@ gnu_find_memory_regions
(find_memory_region_ftype func, void *data)

   return 0;
 }
+#endif


 /* Return printable description of proc.  */
@@ -2592,6 +2759,7 @@ proc_string (struct proc *proc)
   return tid_str;
 }

+#ifndef GDBSERVER
 static char *
 gnu_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
@@ -3452,3 +3620,203 @@ flush_inferior_icache (CORE_ADDR pc, int amount)
     warning (_("Error flushing inferior's cache : %s"), safe_strerror (ret));
 }
 #endif /* FLUSH_INFERIOR_CACHE */
+
+#else
+static struct process_info *
+gnu_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  proc = add_process (pid, attached);
+  proc->tdesc = gnu_tdesc;
+  proc->private = xcalloc (1, sizeof (*proc->private));
+  proc->private->inf = cur_inf ();
+  struct inf *inf = gnu_current_inf;
+
+  inf_attach (inf, pid);
+  inf->pending_execs = 2;
+  inf->nomsg = 1;
+  inf->traced = 1;
+
+  inf_resume (inf);
+
+  return proc;
+}
+
+static void
+gnu_join (int pid)
+{
+  /* doesn't need */
+}
+
+static void
+gnu_resume_wrap (struct thread_resume *resume_info, size_t n)
+{
+  /* FIXME: Assume for now that n == 1.  */
+  ptid_t ptid = resume_info[0].thread;
+  const int step = (resume_info[0].kind == resume_step ? 1 : 0); //1
means step, 0 means contiune
+  const int signal = resume_info[0].sig;
+  if (ptid_equal (ptid, minus_one_ptid))
+    ptid = thread_to_gdb_id (current_inferior);
+
+  regcache_invalidate ();
+
+  debug ("in gnu_resume: ptid=%d, step=%d, signal=%d\n", ptid, step,
+     signal);
+  gnu_resume (NULL, ptid, step, signal);
+}
+
+static ptid_t
+gnu_wait_wrap (ptid_t ptid, struct target_waitstatus *status, int
target_options)
+{
+  ptid_t event_ptid;
+  debug ("gnu_wait: [%s]", target_pid_to_str (ptid));
+  event_ptid = gnu_wait (NULL, ptid, status, target_options);
+  debug ("          -> (status->kind = %d)\n", status->kind);
+  return event_ptid;
+}
+
+void
+gnu_fetch_registers_wrap (struct regcache *regcache, int regno)
+{
+  debug ("gnu_fetch_registers() regno=%d\n", regno);
+  return gnu_fetch_registers (NULL, regcache, regno);
+}
+
+void
+gnu_store_registers_wrap (struct regcache *regcache, int regno)
+{
+  debug ("gnu_store_registers() regno=%d\n", regno);
+  return gnu_store_registers (NULL, regcache, regno);
+}
+
+static int
+gnu_thread_alive_wrap (ptid_t ptid)
+{
+ return gnu_thread_alive(NULL, ptid);
+}
+
+static int
+gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_read_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret);
+      return -1;
+    }
+  return 0;
+}
+
+static int
+gnu_write_memory (CORE_ADDR addr, const unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_write_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      debug ("gnu_write_inferior,length=%d, but return %d\n", length,
+ ret);
+      return -1;
+    }
+  return 0;
+}
+
+static void
+gnu_request_interrupt (void)
+{
+  ptid_t inferior_ptid = thread_to_gdb_id (current_inferior);
+  kill (ptid_get_pid (inferior_ptid), SIGINT);
+}
+
+/* Helper function for child_wait and the derivatives of child_wait.
+   HOSTSTATUS is the waitstatus from wait() or the equivalent; store our
+   translation of that in OURSTATUS.  */
+void
+store_waitstatus (struct target_waitstatus *ourstatus, int hoststatus)
+{
+  if (WIFEXITED (hoststatus))
+    {
+      ourstatus->kind = TARGET_WAITKIND_EXITED;
+      ourstatus->value.integer = WEXITSTATUS (hoststatus);
+    }
+  else if (!WIFSTOPPED (hoststatus))
+    {
+      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+      ourstatus->value.sig = gdb_signal_from_host (WTERMSIG (hoststatus));
+    }
+  else
+    {
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (hoststatus));
+    }
+}
+
+static struct target_ops gnu_target_ops = {
+  gnu_create_inferior,
+  gnu_attach,
+  gnu_kill,
+  gnu_detach,
+  gnu_mourn,
+  gnu_join,
+  gnu_thread_alive_wrap,
+  gnu_resume_wrap,
+  gnu_wait_wrap,
+  gnu_fetch_registers_wrap,
+  gnu_store_registers_wrap,
+  NULL, /* prepare_to_access_memory */
+  NULL, /* done_accessing_memory */
+  gnu_read_memory,
+  gnu_write_memory,
+  NULL, /* look_up_symbols */
+  gnu_request_interrupt,
+  NULL, /* read_auxv */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* read_offsets */
+  NULL, /* get_tls_address */
+  NULL, /* qxfer_spu */
+  NULL, /* hostio_last_error */
+  NULL, /* qxfer_osdata */
+  NULL, /* qxfer_siginfo */
+  NULL, /* supports_non_stop */
+  NULL, /* async */
+  NULL, /* start_non_stop */
+  NULL, /* supports_multi_process */
+  NULL, /* handle_monitor_command */
+};
+
+void
+_initialize_gnu_nat (void)
+{
+  proc_server = getproc ();
+}
+
+static void
+initialize_low_arch ()
+{
+  init_registers_i386 ();
+  gnu_tdesc = tdesc_i386;
+}
+
+void
+initialize_low (void)
+{
+  set_target_ops (&gnu_target_ops);
+  initialize_low_arch ();
+  _initialize_gnu_nat ();
+}
+#endif
diff --git a/gdb/gnu-nat.h b/gdb/gnu-nat.h
index f896bd2..45f2d6b 100644
--- a/gdb/gnu-nat.h
+++ b/gdb/gnu-nat.h
@@ -93,13 +93,44 @@ extern char *proc_string (struct proc *proc);

 extern int gnu_debug_flag;

+#ifndef GDBSERVER
 #define debug(msg, args...) \
  do { if (gnu_debug_flag) \
         fprintf_unfiltered (gdb_stdlog, "%s:%d: " msg "\r\n", \
     __FILE__ , __LINE__ , ##args); } while (0)
+#else
+#define debug(msg, args...) \
+ do { if (gnu_debug_flag) \
+        printf ("%s:%d: " msg "\r\n", \
+    __FILE__ , __LINE__ , ##args); } while (0)
+#endif

 /* Create a prototype generic GNU/Hurd target.  The client can
    override it with local methods.  */
 struct target_ops *gnu_target (void);

+#ifdef GDBSERVER
+#define THREAD_STATE_FLAVOR i386_REGS_SEGS_STATE
+#define THREAD_STATE_SIZE i386_THREAD_STATE_COUNT
+#define THREAD_STATE_SET_TRACED(state) \
+   ((struct i386_thread_state *) (state))->efl |= 0x100
+#define THREAD_STATE_CLEAR_TRACED(state) \
+   ((((struct i386_thread_state *) (state))->efl &= ~0x100), 1)
+
+#ifndef PIDGET
+#define PIDGET(PTID) (ptid_get_pid (PTID))
+#endif
+
+static ptid_t gnu_ptid_build(int pid,long lwp,long tid);
+long gnu_get_tid (ptid_t ptid);
+
+/* Return printable description of proc.  */
+extern char *proc_string (struct proc *proc);
+
+#ifndef safe_strerror
+#define safe_strerror(err) \
+ ""
+#endif
+#endif
+
 #endif /* __GNU_NAT_H__ */
diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c
index 0fd8d91..5d46255 100644
--- a/gdb/i386gnu-nat.c
+++ b/gdb/i386gnu-nat.c
@@ -17,24 +17,17 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

+#ifndef GDBSERVER
 #include "defs.h"
 #include "inferior.h"
 #include "floatformat.h"
 #include "regcache.h"

 #include "gdb_assert.h"
-#include <errno.h>
-#include <stdio.h>
 #include "gdb_string.h"

-#include <mach.h>
-#include <mach_error.h>
-#include <mach/message.h>
-#include <mach/exception.h>
-
 #include "i386-tdep.h"

-#include "gnu-nat.h"
 #include "i387-tdep.h"

 #ifdef HAVE_SYS_PROCFS_H
@@ -42,6 +35,23 @@
 # include "gregset.h"
 #endif

+#else /* GDBSERVER */
+#include "server.h"
+#include "target.h"
+#include "gdb_wait.h"
+
+#define I386_NUM_GREGS 16
+#endif /* GDBSERVER */
+
+#include <errno.h>
+#include <stdio.h>
+
+#include <mach.h>
+#include <mach_error.h>
+#include <mach/message.h>
+#include <mach/exception.h>
+#include "gnu-nat.h"
+
 /* Offset to the thread_state_t location where REG is stored.  */
 #define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)

@@ -78,6 +88,7 @@ static int creg_offset[] =
 static void
 fetch_fpregs (struct regcache *regcache, struct proc *thread)
 {
+#ifndef GDBSERVER
   mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
   struct i386_float_state state;
   error_t err;
@@ -101,8 +112,12 @@ fetch_fpregs (struct regcache *regcache, struct
proc *thread)
       /* Supply the floating-point registers.  */
       i387_supply_fsave (regcache, -1, state.hw_state);
     }
+#else
+  debug ("fetch_fpregs() not support now\n");
+#endif
 }

+#ifndef GDBSERVER
 #ifdef HAVE_SYS_PROCFS_H
 /* These two calls are used by the core-regset.c code for
    reading ELF core files.  */
@@ -120,9 +135,16 @@ supply_fpregset (struct regcache *regcache, const
gdb_fpregset_t *fpregs)
   i387_supply_fsave (regcache, -1, fpregs);
 }
 #endif
+#endif

+extern struct inf *gnu_current_inf;
+extern ptid_t inferior_ptid;
 /* Fetch register REGNO, or all regs if REGNO is -1.  */
+#ifndef GDBSERVER
 static void
+#else
+void
+#endif
 gnu_fetch_registers (struct target_ops *ops,
      struct regcache *regcache, int regno)
 {
@@ -132,7 +154,7 @@ gnu_fetch_registers (struct target_ops *ops,
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
-      ptid_get_tid (inferior_ptid));
+      gnu_get_tid (inferior_ptid));
   if (!thread)
     error (_("Can't fetch registers from thread %s: No such thread"),
    target_pid_to_str (inferior_ptid));
@@ -157,17 +179,25 @@ gnu_fetch_registers (struct target_ops *ops,
   proc_debug (thread, "fetching all register");

   for (i = 0; i < I386_NUM_GREGS; i++)
+#ifndef GDBSERVER
     regcache_raw_supply (regcache, i, REG_ADDR (state, i));
+#else
+    supply_register (regcache, i, REG_ADDR (state, i));
+#endif
   thread->fetched_regs = ~0;
  }
       else
  {
+#ifndef GDBSERVER
   proc_debug (thread, "fetching register %s",
       gdbarch_register_name (get_regcache_arch (regcache),
      regno));

   regcache_raw_supply (regcache, regno,
        REG_ADDR (state, regno));
+#else
+  supply_register (regcache, regno, REG_ADDR (state, regno));
+#endif
   thread->fetched_regs |= (1 << regno);
  }
     }
@@ -183,9 +213,14 @@ gnu_fetch_registers (struct target_ops *ops,

 /* Store the whole floating-point state into THREAD using information
    from the corresponding (pseudo) registers.  */
+#ifndef GDBSERVER
 static void
+#else
+void
+#endif
 store_fpregs (const struct regcache *regcache, struct proc *thread, int regno)
 {
+#ifndef GDBSERVER
   mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
   struct i386_float_state state;
   error_t err;
@@ -211,21 +246,32 @@ store_fpregs (const struct regcache *regcache,
struct proc *thread, int regno)
        proc_string (thread));
       return;
     }
+#else
+  debug ("store_fpregs() not support now\n");
+#endif
 }

 /* Store at least register REGNO, or all regs if REGNO == -1.  */
+#ifndef GDBSERVER
 static void
+#else
+void
+#endif
 gnu_store_registers (struct target_ops *ops,
      struct regcache *regcache, int regno)
 {
   struct proc *thread;
+#ifndef GDBSERVER
   struct gdbarch *gdbarch = get_regcache_arch (regcache);
+#else
+  const struct target_desc *gdbarch = regcache->tdesc;
+#endif

   /* Make sure we know about new threads.  */
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
-      ptid_get_tid (inferior_ptid));
+      gnu_get_tid (inferior_ptid));
   if (!thread)
     error (_("Couldn't store registers into thread %s: No such thread"),
    target_pid_to_str (inferior_ptid));
@@ -265,12 +311,19 @@ gnu_store_registers (struct target_ops *ops,
    register_size (gdbarch, check_regno)))
       /* Register CHECK_REGNO has changed!  Ack!  */
       {
+#ifndef GDBSERVER
  warning (_("Register %s changed after the thread was aborted"),
  gdbarch_register_name (gdbarch, check_regno));
+#endif
  if (regno >= 0 && regno != check_regno)
   /* Update GDB's copy of the register.  */
+#ifndef GDBSERVER
   regcache_raw_supply (regcache, check_regno,
        REG_ADDR (state, check_regno));
+#else
+  supply_register (regcache, check_regno,
+   REG_ADDR (state, check_regno));
+#endif
  else
   warning (_("... also writing this register!  "
      "Suspicious..."));
@@ -284,16 +337,24 @@ gnu_store_registers (struct target_ops *ops,
   proc_debug (thread, "storing all registers");

   for (i = 0; i < I386_NUM_GREGS; i++)
+#ifndef GDBSERVER
     if (REG_VALID == regcache_register_status (regcache, i))
       regcache_raw_collect (regcache, i, REG_ADDR (state, i));
+#else
+    collect_register (regcache, i, REG_ADDR (state, i));
+#endif
  }
       else
  {
+#ifndef GDBSERVER
   proc_debug (thread, "storing register %s",
       gdbarch_register_name (gdbarch, regno));

   gdb_assert (REG_VALID == regcache_register_status (regcache, regno));
   regcache_raw_collect (regcache, regno, REG_ADDR (state, regno));
+#else
+  collect_register (regcache, regno, REG_ADDR (state, regno));
+#endif
  }

       /* Restore the T bit.  */
@@ -309,6 +370,7 @@ gnu_store_registers (struct target_ops *ops,
     }
 }

+#ifndef GDBSERVER
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_i386gnu_nat;

@@ -326,3 +388,4 @@ _initialize_i386gnu_nat (void)
   /* Register the target.  */
   add_target (t);
 }
+#endif


thanks.
-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-09  9:58               ` Thomas Schwinge
@ 2013-09-18 12:12                 ` Pedro Alves
  2013-09-18 13:48                   ` Yue Lu
  0 siblings, 1 reply; 25+ messages in thread
From: Pedro Alves @ 2013-09-18 12:12 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Yue Lu, gdb-patches, Luis Machado, bug-hurd

On 09/09/2013 10:58 AM, Thomas Schwinge wrote:
> Hi!
> 
> On Sun, 8 Sep 2013 21:35:05 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
>> On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote:
>>>> (correct me if
>>>> I'm wrong here), the Hurd's threads are kernel threads
>>>
>>> Correct.
>>>
>>>> so it'd
>>>> be better to just make the GDB side use the lwp field too.
>>>> It's really a simple and mechanic change.  Nothing in GDB core
>>>> actually cares which field is used.  So in this case, it'd be
> 
> In GDB's parlance, a lightweight process (identified by a LWP) is a
> thread that always has a corresponding kernel thread, and in contrast a
> "generic" thread (identified by a TID) is not required to always have a
> corresponding kernel thread, for example, when managed by a run-time
> library?  Then, yes, conceptually the native Hurd port should be switched
> to using LWPs instead of TIDs.
> 
>>>> better if you send a preparatory patch
>>>
>>> Based on the current upstream master branch.
>>
>> Should I change the gdb use lwp filed instead of tid field? There are
>> too many functions use tid. Like
>> make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field
>> named tid in the structure proc also.
> 
> As you have found, there is a lot of TID usage in gnu-nat.c.  TIDs are
> assigned based on the next_thread_id variable:
> 
>     /* A variable from which to assign new TIDs.  */
>     static int next_thread_id = 1;
>     [...]
>               /* THREADS[I] is a thread we don't know about yet!  */
>               {
>                 ptid_t ptid;
>     
>                 thread = make_proc (inf, threads[i], next_thread_id++);
> 
> Five years ago, we've already concluded this is due for some cleanup,
> <http://www.gnu.org/software/hurd/open_issues/gdb_thread_ids.html>.  But
> I don't want to require this cleanup to happen before/in context of the
> Google Summer of Code project's code submission discussed here.

That's not what I'm suggesting at all.  I'm just talking about storing
the thread id in the lwpid field.  It's always the target that
stores and extracts the fields of a ptid -- the ptid_t struct is mostly
opaque to the core.  It should really be a small change.

(while looking at this, I noticed a bug, and fixed it:
http://sourceware.org/ml/gdb-patches/2013-09/msg00579.html)

/me gives it a try.

I grepped for ptid_build and ptid_get_tid in *gnu* files, and
adjusted all I found.

-----------
Subject: [PATCH] [Hurd/gnu-nat.c] Use ptid_t.lwpid to store thread ids
 instead of ptid_t.tid.

In preparation for reusing gnu-nat.c in gdbserver, switch to storing
thread ids in the lwpid field of ptid_t rather than in the tid
field.  The Hurd's thread model is 1:1, so it doesn't feel wrong
anyway.

gdb/
2013-09-18  Pedro Alves  <palves@redhat.com>

	* gnu-nat.c (inf_validate_procs, gnu_wait, gnu_resume)
	(gnu_create_inferior)
	(gnu_attach, gnu_thread_alive, gnu_pid_to_str, cur_thread)
	(set_sig_thread_cmd): Use the lwpid field of ptids to store the
	thread id instead of the tid field.
---
 gdb/gnu-nat.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index fa55b10..b4f99f8 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1083,7 +1083,7 @@ inf_validate_procs (struct inf *inf)
 	    last = thread;
 	    proc_debug (thread, "new thread: %d", threads[i]);
 
-	    ptid = ptid_build (inf->pid, 0, thread->tid);
+	    ptid = ptid_build (inf->pid, thread->tid, 0);
 
 	    /* Tell GDB's generic thread code.  */
 
@@ -1613,17 +1613,17 @@ rewait:
 
   thread = inf->wait.thread;
   if (thread)
-    ptid = ptid_build (inf->pid, 0, thread->tid);
+    ptid = ptid_build (inf->pid, thread->tid, 0);
   else if (ptid_equal (ptid, minus_one_ptid))
     thread = inf_tid_to_thread (inf, -1);
   else
-    thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+    thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));
 
   if (!thread || thread->port == MACH_PORT_NULL)
     {
       /* TID is dead; try and find a new thread.  */
       if (inf_update_procs (inf) && inf->threads)
-	ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first
+	ptid = ptid_build (inf->pid, inf->threads->tid, 0); /* The first
 							       available
 							       thread.  */
       else
@@ -2022,7 +2022,7 @@ gnu_resume (struct target_ops *ops,
   else
     /* Just allow a single thread to run.  */
     {
-      struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      struct proc *thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));
 
       if (!thread)
 	error (_("Can't run single thread id %s: no such thread!"),
@@ -2033,7 +2033,7 @@ gnu_resume (struct target_ops *ops,
 
   if (step)
     {
-      step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      step_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));
       if (!step_thread)
 	warning (_("Can't step thread id %s: no such thread."),
 		 target_pid_to_str (ptid));
@@ -2133,7 +2133,7 @@ gnu_create_inferior (struct target_ops *ops,
 
   /* We now have thread info.  */
   thread_change_ptid (inferior_ptid,
-		      ptid_build (inf->pid, 0, inf_pick_first_thread ()));
+		      ptid_build (inf->pid, inf_pick_first_thread (), 0));
 
   startup_inferior (inf->pending_execs);
 
@@ -2190,7 +2190,7 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty)
 
   inf_update_procs (inf);
 
-  inferior_ptid = ptid_build (pid, 0, inf_pick_first_thread ());
+  inferior_ptid = ptid_build (pid, inf_pick_first_thread (), 0);
 
   /* We have to initialize the terminal settings now, since the code
      below might try to restore them.  */
@@ -2261,7 +2261,7 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
   inf_update_procs (gnu_current_inf);
   return !!inf_tid_to_thread (gnu_current_inf,
-			      ptid_get_tid (ptid));
+			      ptid_get_lwp (ptid));
 }
 
 \f
@@ -2596,7 +2596,7 @@ static char *
 gnu_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
   struct inf *inf = gnu_current_inf;
-  int tid = ptid_get_tid (ptid);
+  int tid = ptid_get_lwp (ptid);
   struct proc *thread = inf_tid_to_thread (inf, tid);
 
   if (thread)
@@ -2729,7 +2729,7 @@ cur_thread (void)
 {
   struct inf *inf = cur_inf ();
   struct proc *thread = inf_tid_to_thread (inf,
-					   ptid_get_tid (inferior_ptid));
+					   ptid_get_lwp (inferior_ptid));
   if (!thread)
     error (_("No current thread."));
   return thread;
@@ -2928,7 +2928,7 @@ set_sig_thread_cmd (char *args, int from_tty)
 	error (_("Thread ID %s not known.  "
 		 "Use the \"info threads\" command to\n"
 	       "see the IDs of currently known threads."), args);
-      inf->signal_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      inf->signal_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));
     }
 }
 
-- 
1.7.11.7



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-12  3:05             ` Yue Lu
@ 2013-09-18 12:30               ` Pedro Alves
  2013-09-18 12:37               ` Pedro Alves
  1 sibling, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2013-09-18 12:30 UTC (permalink / raw)
  To: Yue Lu; +Cc: Pedro Alves, gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd

On 09/12/2013 04:05 AM, Yue Lu wrote:
> Honestly to say, I have copied them from function gnu_xfer_memory. But
> I think, before reference a pointer, check whether it was a NULL seems
> not a bad way :-).

We don't go around checking for NULL before _every_ pointer
dereference.  :-)

NULL pointer checks are used when the function's semantics
give special meaning to NULL, like for example, for optional
parameters.  If that's not the function's semantics, and you still
may see a NULL pointer, then that tells there's actually a bug
that triggered already elsewhere before the function in question
was called.  IOW, a NULL check in these cases is just masking out a
bug in some caller.  In some cases, we might add a gdb_assert to
catch the bug in a nicer way instead of just crashing.

I suspect that what may happen is that at some point it
was possible for GDB to select a no-longer-existing-thread
(though I can't see how in the current code), and then setting
breakpoints, or other operations that require reading memory
would crash.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-12  3:05             ` Yue Lu
  2013-09-18 12:30               ` Pedro Alves
@ 2013-09-18 12:37               ` Pedro Alves
  2013-09-19  7:41                 ` Yue Lu
  1 sibling, 1 reply; 25+ messages in thread
From: Pedro Alves @ 2013-09-18 12:37 UTC (permalink / raw)
  To: Yue Lu; +Cc: gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd

On 09/12/2013 04:05 AM, Yue Lu wrote:

> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote:
>> This is what I meant:
>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html
>>
>> I was thinking you'd wrap gnu_xfer_memory.
>>
> 
> I have study your patch, 

Thanks.  Did you try building gdb with it, and does the
resulting GDB still work?

> but I found there is no to_xfer_partial field
> or something similar in gdbserver's structure target_obj, how can I
> do? Please give me more hints, thanks.

Right, there's no such function in gdbserver today.  I mean, instead of:

+
+static int
+gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
+{
+  int ret = 0;
+  task_t task = (gnu_current_inf
+ ? (gnu_current_inf->task
+    ? gnu_current_inf->task->port : 0) : 0);
+  if (task == MACH_PORT_NULL)
+    return 0;
+  ret = gnu_read_inferior (task, addr, myaddr, length);
+  if (length != ret)
+    {
+      debug ("gnu_read_inferior,length=%d, but return %d\n", length, ret);
+      return -1;
+    }
+  return 0;
+}

you'll have a simpler:

static int
gnu_read_memory (CORE_ADDR addr, unsigned char *myaddr, int length)
{
  LONGEST res;

  res = gnu_xfer_memory (...);
  if (res != length)
   return -1;
  return 0;
}

gnu_xfer_memory already has the task == MACH_PORT_NULL check
inside it, so this means there's no need to duplicate it
in gnu_read|write_memory.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-18 12:12                 ` Pedro Alves
@ 2013-09-18 13:48                   ` Yue Lu
  2013-09-18 14:52                     ` [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) Pedro Alves
  2013-09-18 14:57                     ` [PATCH 1/2] Port gdbserver to GNU/Hurd Pedro Alves
  0 siblings, 2 replies; 25+ messages in thread
From: Yue Lu @ 2013-09-18 13:48 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

Hi,

On Wed, Sep 18, 2013 at 8:11 PM, Pedro Alves <palves@redhat.com> wrote:
> On 09/09/2013 10:58 AM, Thomas Schwinge wrote:
>> Hi!
>>
>> On Sun, 8 Sep 2013 21:35:05 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
>>> On Fri, Sep 6, 2013 at 5:37 AM, Thomas Schwinge <thomas@codesourcery.com> wrote:
>>>>> (correct me if
>>>>> I'm wrong here), the Hurd's threads are kernel threads
>>>>
>>>> Correct.
>>>>
>>>>> so it'd
>>>>> be better to just make the GDB side use the lwp field too.
>>>>> It's really a simple and mechanic change.  Nothing in GDB core
>>>>> actually cares which field is used.  So in this case, it'd be
>>
>> In GDB's parlance, a lightweight process (identified by a LWP) is a
>> thread that always has a corresponding kernel thread, and in contrast a
>> "generic" thread (identified by a TID) is not required to always have a
>> corresponding kernel thread, for example, when managed by a run-time
>> library?  Then, yes, conceptually the native Hurd port should be switched
>> to using LWPs instead of TIDs.
>>
>>>>> better if you send a preparatory patch
>>>>
>>>> Based on the current upstream master branch.
>>>
>>> Should I change the gdb use lwp filed instead of tid field? There are
>>> too many functions use tid. Like
>>> make_proc(),inf_tid_to_thread(),ptid_build(), and there is a field
>>> named tid in the structure proc also.
>>
>> As you have found, there is a lot of TID usage in gnu-nat.c.  TIDs are
>> assigned based on the next_thread_id variable:
>>
>>     /* A variable from which to assign new TIDs.  */
>>     static int next_thread_id = 1;
>>     [...]
>>               /* THREADS[I] is a thread we don't know about yet!  */
>>               {
>>                 ptid_t ptid;
>>
>>                 thread = make_proc (inf, threads[i], next_thread_id++);
>>
>> Five years ago, we've already concluded this is due for some cleanup,
>> <http://www.gnu.org/software/hurd/open_issues/gdb_thread_ids.html>.  But
>> I don't want to require this cleanup to happen before/in context of the
>> Google Summer of Code project's code submission discussed here.
>
> That's not what I'm suggesting at all.  I'm just talking about storing
> the thread id in the lwpid field.  It's always the target that
> stores and extracts the fields of a ptid -- the ptid_t struct is mostly
> opaque to the core.  It should really be a small change.
>
> (while looking at this, I noticed a bug, and fixed it:
> http://sourceware.org/ml/gdb-patches/2013-09/msg00579.html)
>
> /me gives it a try.
>
> I grepped for ptid_build and ptid_get_tid in *gnu* files, and
> adjusted all I found.

I have tried this way before, but it doesn't work.
After apply your patch, the gdb can't use, it says "Can't fetch
registers from thread Thread 29826.3: No such thread". (btw, with
unknown reason, I can't patch your patch automatically, I have to
modify the gnu-nat.c line by line according to your patch).

As before, I thought it is a big problem, so I don't dig into it. Your
last email has reminder me, both you and I  forgot to patch the
i386gnu-nat.c which also used the tid filed.

Add this everything is ok.

diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c
index 0fd8d91..2b93fee 100644
--- a/gdb/i386gnu-nat.c
+++ b/gdb/i386gnu-nat.c
@@ -132,7 +132,7 @@ gnu_fetch_registers (struct target_ops *ops,
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
-                             ptid_get_tid (inferior_ptid));
+                             ptid_get_lwp (inferior_ptid));
   if (!thread)
     error (_("Can't fetch registers from thread %s: No such thread"),
           target_pid_to_str (inferior_ptid));
@@ -225,7 +225,7 @@ gnu_store_registers (struct target_ops *ops,
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
-                             ptid_get_tid (inferior_ptid));
+                             ptid_get_lwp (inferior_ptid));
   if (!thread)
     error (_("Couldn't store registers into thread %s: No such thread"),
           target_pid_to_str (inferior_ptid));


-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids  instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd)
  2013-09-18 13:48                   ` Yue Lu
@ 2013-09-18 14:52                     ` Pedro Alves
  2013-09-18 14:57                     ` [PATCH 1/2] Port gdbserver to GNU/Hurd Pedro Alves
  1 sibling, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2013-09-18 14:52 UTC (permalink / raw)
  To: Yue Lu; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

On 09/18/2013 02:48 PM, Yue Lu wrote:
> On Wed, Sep 18, 2013 at 8:11 PM, Pedro Alves <palves@redhat.com> wrote:
>>
>> /me gives it a try.
>>
>> I grepped for ptid_build and ptid_get_tid in *gnu* files, and
>> adjusted all I found.
> 
> I have tried this way before, but it doesn't work.
> After apply your patch, the gdb can't use, it says "Can't fetch
> registers from thread Thread 29826.3: No such thread".
...
> As before, I thought it is a big problem, so I don't dig into it. Your
> last email has reminder me, both you and I  forgot to patch the
> i386gnu-nat.c which also used the tid filed.

Eh, grep-fail then.

> 
> Add this everything is ok.

Nice, thanks.  I've merged that in, and applied it.

---------
Subject: [Hurd/gnu-nat.c] Use ptid_t.lwpid to store
 thread ids instead of ptid_t.tid.

In preparation for reusing gnu-nat.c in gdbserver, switch to storing
thread ids in the lwpid field of ptid_t rather than in the tid
field.  The Hurd's thread model is 1:1, so it doesn't feel wrong
anyway.

gdb/
2013-09-18  Pedro Alves  <palves@redhat.com>
	    Yue Lu  <hacklu.newborn@gmail.com>

	* gnu-nat.c (inf_validate_procs, gnu_wait, gnu_resume)
	(gnu_create_inferior)
	(gnu_attach, gnu_thread_alive, gnu_pid_to_str, cur_thread)
	(set_sig_thread_cmd): Use the lwpid field of ptids to
	store/extract thread ids instead of the tid field.
	* i386gnu-nat.c (gnu_fetch_registers): Adjust.
---
 gdb/gnu-nat.c     | 24 ++++++++++++------------
 gdb/i386gnu-nat.c |  4 ++--
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index fa55b10..b4f99f8 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -1083,7 +1083,7 @@ inf_validate_procs (struct inf *inf)
 	    last = thread;
 	    proc_debug (thread, "new thread: %d", threads[i]);

-	    ptid = ptid_build (inf->pid, 0, thread->tid);
+	    ptid = ptid_build (inf->pid, thread->tid, 0);

 	    /* Tell GDB's generic thread code.  */

@@ -1613,17 +1613,17 @@ rewait:

   thread = inf->wait.thread;
   if (thread)
-    ptid = ptid_build (inf->pid, 0, thread->tid);
+    ptid = ptid_build (inf->pid, thread->tid, 0);
   else if (ptid_equal (ptid, minus_one_ptid))
     thread = inf_tid_to_thread (inf, -1);
   else
-    thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+    thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));

   if (!thread || thread->port == MACH_PORT_NULL)
     {
       /* TID is dead; try and find a new thread.  */
       if (inf_update_procs (inf) && inf->threads)
-	ptid = ptid_build (inf->pid, 0, inf->threads->tid); /* The first
+	ptid = ptid_build (inf->pid, inf->threads->tid, 0); /* The first
 							       available
 							       thread.  */
       else
@@ -2022,7 +2022,7 @@ gnu_resume (struct target_ops *ops,
   else
     /* Just allow a single thread to run.  */
     {
-      struct proc *thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      struct proc *thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));

       if (!thread)
 	error (_("Can't run single thread id %s: no such thread!"),
@@ -2033,7 +2033,7 @@ gnu_resume (struct target_ops *ops,

   if (step)
     {
-      step_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      step_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));
       if (!step_thread)
 	warning (_("Can't step thread id %s: no such thread."),
 		 target_pid_to_str (ptid));
@@ -2133,7 +2133,7 @@ gnu_create_inferior (struct target_ops *ops,

   /* We now have thread info.  */
   thread_change_ptid (inferior_ptid,
-		      ptid_build (inf->pid, 0, inf_pick_first_thread ()));
+		      ptid_build (inf->pid, inf_pick_first_thread (), 0));

   startup_inferior (inf->pending_execs);

@@ -2190,7 +2190,7 @@ gnu_attach (struct target_ops *ops, char *args, int from_tty)

   inf_update_procs (inf);

-  inferior_ptid = ptid_build (pid, 0, inf_pick_first_thread ());
+  inferior_ptid = ptid_build (pid, inf_pick_first_thread (), 0);

   /* We have to initialize the terminal settings now, since the code
      below might try to restore them.  */
@@ -2261,7 +2261,7 @@ gnu_thread_alive (struct target_ops *ops, ptid_t ptid)
 {
   inf_update_procs (gnu_current_inf);
   return !!inf_tid_to_thread (gnu_current_inf,
-			      ptid_get_tid (ptid));
+			      ptid_get_lwp (ptid));
 }

 \f
@@ -2596,7 +2596,7 @@ static char *
 gnu_pid_to_str (struct target_ops *ops, ptid_t ptid)
 {
   struct inf *inf = gnu_current_inf;
-  int tid = ptid_get_tid (ptid);
+  int tid = ptid_get_lwp (ptid);
   struct proc *thread = inf_tid_to_thread (inf, tid);

   if (thread)
@@ -2729,7 +2729,7 @@ cur_thread (void)
 {
   struct inf *inf = cur_inf ();
   struct proc *thread = inf_tid_to_thread (inf,
-					   ptid_get_tid (inferior_ptid));
+					   ptid_get_lwp (inferior_ptid));
   if (!thread)
     error (_("No current thread."));
   return thread;
@@ -2928,7 +2928,7 @@ set_sig_thread_cmd (char *args, int from_tty)
 	error (_("Thread ID %s not known.  "
 		 "Use the \"info threads\" command to\n"
 	       "see the IDs of currently known threads."), args);
-      inf->signal_thread = inf_tid_to_thread (inf, ptid_get_tid (ptid));
+      inf->signal_thread = inf_tid_to_thread (inf, ptid_get_lwp (ptid));
     }
 }

diff --git a/gdb/i386gnu-nat.c b/gdb/i386gnu-nat.c
index 0fd8d91..2b93fee 100644
--- a/gdb/i386gnu-nat.c
+++ b/gdb/i386gnu-nat.c
@@ -132,7 +132,7 @@ gnu_fetch_registers (struct target_ops *ops,
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
-			      ptid_get_tid (inferior_ptid));
+			      ptid_get_lwp (inferior_ptid));
   if (!thread)
     error (_("Can't fetch registers from thread %s: No such thread"),
 	   target_pid_to_str (inferior_ptid));
@@ -225,7 +225,7 @@ gnu_store_registers (struct target_ops *ops,
   inf_update_procs (gnu_current_inf);

   thread = inf_tid_to_thread (gnu_current_inf,
-			      ptid_get_tid (inferior_ptid));
+			      ptid_get_lwp (inferior_ptid));
   if (!thread)
     error (_("Couldn't store registers into thread %s: No such thread"),
 	   target_pid_to_str (inferior_ptid));
-- 
1.7.11.7



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-18 13:48                   ` Yue Lu
  2013-09-18 14:52                     ` [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) Pedro Alves
@ 2013-09-18 14:57                     ` Pedro Alves
  1 sibling, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2013-09-18 14:57 UTC (permalink / raw)
  To: Yue Lu; +Cc: Thomas Schwinge, gdb-patches, Luis Machado, bug-hurd

On 09/18/2013 02:48 PM, Yue Lu wrote:
> (btw, with
> unknown reason, I can't patch your patch automatically, I have to
> modify the gnu-nat.c line by line according to your patch).

I'm going to guess you copy/pasted the patch to a new file,
and while doing that, something (your editor or mailer?)
line-wrapped the patch.  I just now tried saving the
whole email as an mbox file, and then applied it to a pristine
tree with "git am", and saw no issues.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-18 12:37               ` Pedro Alves
@ 2013-09-19  7:41                 ` Yue Lu
  2013-09-19  8:30                   ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) Thomas Schwinge
  0 siblings, 1 reply; 25+ messages in thread
From: Yue Lu @ 2013-09-19  7:41 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, Thomas Schwinge, Luis Machado, bug-hurd

Hi,


On Wed, Sep 18, 2013 at 8:37 PM, Pedro Alves <palves@redhat.com> wrote:
> On 09/12/2013 04:05 AM, Yue Lu wrote:
>
>> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote:
>>> This is what I meant:
>>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html
>>>
>>> I was thinking you'd wrap gnu_xfer_memory.
>>>
>>
>> I have study your patch,
>
> Thanks.  Did you try building gdb with it, and does the
> resulting GDB still work?

First thank you to tell me how to apply patch from email. I used
webmail of gmail and directly copy patch from the email which often
apply failed, then I had to patch line by line. Now I used mutt to
save email to mbox file then apply it, life changed! Before you told
me this, I never imaged this, so thanks!

I have test your patch, seems need a tiny fix. This is just a spelling
mistaken I think.

diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c
index 07fe603..bc37bb8 100644
--- a/gdb/gnu-nat.c
+++ b/gdb/gnu-nat.c
@@ -2493,14 +2493,14 @@ gnu_xfer_memory (gdb_byte *readbuf, const char
*writebuf,
     {
       inf_debug (gnu_current_inf, "writing %s[%s] <-- %s",
                 paddress (target_gdbarch (), memaddr), plongest (len),
-                host_address_to_string (myaddr));
+                host_address_to_string (writebuf));
       res = gnu_write_inferior (task, memaddr, writebuf, len);
     }
   else
     {
       inf_debug (gnu_current_inf, "reading %s[%s] --> %s",
                 paddress (target_gdbarch (), memaddr), plongest (len),
-                host_address_to_string (myaddr));
+                host_address_to_string (readbuf));
       res = gnu_read_inferior (task, memaddr, readbuf, len);
     }
   if (res == 0)

After add this change, the gdb can work. But I have found a little
strange from the origin gdb.
When I set a breakpoint, then I run the inferior, after hit the
breakpoint, I just input next next until the inferior exit, then the
gdb will complain this:
[Inferior 1 (bogus thread id 0) exited normally]
Thread-specific breakpoint -37 deleted - thread 4 is gone.
Thread-specific breakpoint -38 deleted - thread 4 is gone.
Thread-specific breakpoint -39 deleted - thread 4 is gone.
Thread-specific breakpoint 0 deleted - thread 4 is gone.

I am not sure why this will output or is reasonable.

I got this output like this:
$./gdb gdb
$b main
$r
$n
$n
...
$q  (quit the debugged gdb)

-- 
Yue Lu (陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd)
  2013-09-19  7:41                 ` Yue Lu
@ 2013-09-19  8:30                   ` Thomas Schwinge
  2013-09-19  8:44                     ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) Pedro Alves
  0 siblings, 1 reply; 25+ messages in thread
From: Thomas Schwinge @ 2013-09-19  8:30 UTC (permalink / raw)
  To: Yue Lu, Pedro Alves; +Cc: gdb-patches, Luis Machado, bug-hurd

[-- Attachment #1: Type: text/plain, Size: 2803 bytes --]

Hi!

On Thu, 19 Sep 2013 15:40:40 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
> On Wed, Sep 18, 2013 at 8:37 PM, Pedro Alves <palves@redhat.com> wrote:
> > On 09/12/2013 04:05 AM, Yue Lu wrote:
> >
> >> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote:
> >>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html

> First thank you to tell me how to apply patch from email. I used
> webmail of gmail and directly copy patch from the email which often
> apply failed, then I had to patch line by line. Now I used mutt to
> save email to mbox file then apply it, life changed! Before you told
> me this, I never imaged this, so thanks!

Well, never assume that we'd use any convoluted procedures, such as
manually copying a patch's text.  ;-) Never hesitate to ask if you think
some process is too complicated to be done manually -- there will always
be someone who is happy to tell you about his creative solution.

> I have test your patch, seems need a tiny fix. This is just a spelling
> mistaken I think.

Right; I had come to the same conclusion, see my message in the other
thread.


> After add this change, the gdb can work. But I have found a little
> strange from the origin gdb.
> When I set a breakpoint, then I run the inferior, after hit the
> breakpoint, I just input next next until the inferior exit, then the
> gdb will complain this:
> [Inferior 1 (bogus thread id 0) exited normally]
> Thread-specific breakpoint -37 deleted - thread 4 is gone.
> Thread-specific breakpoint -38 deleted - thread 4 is gone.
> Thread-specific breakpoint -39 deleted - thread 4 is gone.
> Thread-specific breakpoint 0 deleted - thread 4 is gone.
> 
> I am not sure why this will output or is reasonable.
> 
> I got this output like this:
> $./gdb gdb
> $b main
> $r
> $n
> $n
> ...
> $q  (quit the debugged gdb)

"As of recently", I notice the same behavior for GDB on both x86
GNU/Linux and GNU/Hurd, also resulting in the gdb.base/nextoverexit.exp
test failing.  So, I don't think this is related to any Hurd
patches/behavior, but instead a general issue.

Quoting from the x86 GNU/Linux' gdb/testsuite/gdb.base2/gdb.log:

    Breakpoint 1, main () at ../../../Ferry_Tagscherer/gdb/testsuite/gdb.base/nextoverexit.c:21
    21        exit (0);
    (gdb) next
    [Inferior 1 (process 25208) exited normally]
    Thread-specific breakpoint -5 deleted - thread 1 is gone.
    Thread-specific breakpoint -6 deleted - thread 1 is gone.
    Thread-specific breakpoint -7 deleted - thread 1 is gone.
    Thread-specific breakpoint 0 deleted - thread 1 is gone.
    (gdb) FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited)

Can others confirm this/is this a known issue?


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 489 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited)
  2013-09-19  8:30                   ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) Thomas Schwinge
@ 2013-09-19  8:44                     ` Pedro Alves
  0 siblings, 0 replies; 25+ messages in thread
From: Pedro Alves @ 2013-09-19  8:44 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Yue Lu, gdb-patches, Luis Machado, bug-hurd

On 09/19/2013 09:30 AM, Thomas Schwinge wrote:
> Hi!
> 
> On Thu, 19 Sep 2013 15:40:40 +0800, Yue Lu <hacklu.newborn@gmail.com> wrote:
>> On Wed, Sep 18, 2013 at 8:37 PM, Pedro Alves <palves@redhat.com> wrote:
>>> On 09/12/2013 04:05 AM, Yue Lu wrote:
>>>
>>>> On Sat, Sep 7, 2013 at 2:53 AM, Pedro Alves <palves@redhat.com> wrote:
>>>>> https://sourceware.org/ml/gdb-patches/2013-09/msg00253.html
> 
>> First thank you to tell me how to apply patch from email. I used
>> webmail of gmail and directly copy patch from the email which often
>> apply failed, then I had to patch line by line. Now I used mutt to
>> save email to mbox file then apply it, life changed! Before you told
>> me this, I never imaged this, so thanks!
> 
> Well, never assume that we'd use any convoluted procedures, such as
> manually copying a patch's text.  ;-) Never hesitate to ask if you think
> some process is too complicated to be done manually -- there will always
> be someone who is happy to tell you about his creative solution.
> 
>> I have test your patch, seems need a tiny fix. This is just a spelling
>> mistaken I think.
> 
> Right; I had come to the same conclusion, see my message in the other
> thread.
> 
> 
>> After add this change, the gdb can work. But I have found a little
>> strange from the origin gdb.
>> When I set a breakpoint, then I run the inferior, after hit the
>> breakpoint, I just input next next until the inferior exit, then the
>> gdb will complain this:
>> [Inferior 1 (bogus thread id 0) exited normally]
>> Thread-specific breakpoint -37 deleted - thread 4 is gone.
>> Thread-specific breakpoint -38 deleted - thread 4 is gone.
>> Thread-specific breakpoint -39 deleted - thread 4 is gone.
>> Thread-specific breakpoint 0 deleted - thread 4 is gone.
>>
>> I am not sure why this will output or is reasonable.
>>
>> I got this output like this:
>> $./gdb gdb
>> $b main
>> $r
>> $n
>> $n
>> ...
>> $q  (quit the debugged gdb)
> 
> "As of recently", I notice the same behavior for GDB on both x86
> GNU/Linux and GNU/Hurd, also resulting in the gdb.base/nextoverexit.exp
> test failing.  So, I don't think this is related to any Hurd
> patches/behavior, but instead a general issue.
> 
> Quoting from the x86 GNU/Linux' gdb/testsuite/gdb.base2/gdb.log:
> 
>     Breakpoint 1, main () at ../../../Ferry_Tagscherer/gdb/testsuite/gdb.base/nextoverexit.c:21
>     21        exit (0);
>     (gdb) next
>     [Inferior 1 (process 25208) exited normally]
>     Thread-specific breakpoint -5 deleted - thread 1 is gone.
>     Thread-specific breakpoint -6 deleted - thread 1 is gone.
>     Thread-specific breakpoint -7 deleted - thread 1 is gone.
>     Thread-specific breakpoint 0 deleted - thread 1 is gone.
>     (gdb) FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited)
> 
> Can others confirm this/is this a known issue?

Hmm, that message is new, but we shouldn't be seeing it for
internal breakpoints...  That'll be my fault.  I'll take a look.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 1/2] Port gdbserver to GNU/Hurd
  2013-09-05 21:38           ` Thomas Schwinge
  2013-09-08 13:35             ` Yue Lu
@ 2013-09-22 12:58             ` Yue Lu
  1 sibling, 0 replies; 25+ messages in thread
From: Yue Lu @ 2013-09-22 12:58 UTC (permalink / raw)
  To: Thomas Schwinge; +Cc: Pedro Alves, gdb-patches, Luis Machado, bug-hurd

Hi!

On Thu, Sep 05, 2013 at 11:37:36PM +0200, Thomas Schwinge wrote:
> Confirm that you haven't caused any regressions by running the GDB
> testsuite (natively) without and then with your change (don't forget to
> apply the testsuite patch I gave you earlier, to avoid the testsuite
> hanging (known Hurd issue)), and diff the *.sum files to see that there
> are no (major) differences (post them with your patch).
> 
These days I have try to run the testcase server times( And I have found 
there are 5 cases got failed or passed just by chance.) I
have found this, when apply my patch, the native gdb seems pass more
tests and failed more too :/ 

What's more, the gdbserver can't finish the testcase, it just just complain make
error and stoped. Like this:
=== gdb Summary ===

# of expected passes            21731
# of unexpected failures        659
# of unexpected successes       1
# of expected failures          31
# of known failures             75
# of unresolved testcases       12
# of untested testcases         2594
# of unsupported tests          265
/home/hacklu/code/gdb/build.gdbserver/gdb/testsuite/../../gdb/gdb
version  7.6.50.20130911-cvs -nw -nx -data-directory
/home/hacklu/code/gdb/build.gdbserver/gdb/testsuite/../data-directory

make[1]: *** [check-single] Error 1
make[1]: Leaving directory
`/home/hacklu/code/gdb/build.gdbserver/gdb/testsuite'
make: *** [check] Error 2

I do the check according to native-gdbserver.exp's comment.

It is the whole diff file between upstream branch and the one plus my patch
below.
(ps: the build.git2 contains the upstream one, and build.gdb3 contains
the topic one).

--- build.git2/gdb/testsuite/gdb.base1/gdb.sum	2013-09-18 21:10:20.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.base1/gdb.sum	2013-09-21 22:01:37.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 20:56:22 2013
+Test Run By hacklu on Sat Sep 21 21:47:36 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -3679,7 +3679,7 @@
 PASS: gdb.base/cvexpr.exp: (struct t_struct const * const)
 PASS: gdb.base/cvexpr.exp: (union t_union const * const)
 Running ../../../gdb/testsuite/gdb.base/comprdebug.exp ...
-ERROR: Couldn't load /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb.
+ERROR: Couldn't load /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb.
 UNRESOLVED: gdb.base/comprdebug.exp: file comprdebug0.o
 Running ../../../gdb/testsuite/gdb.base/call-ar-st.exp ...
 PASS: gdb.base/call-ar-st.exp: set print sevenbit-strings
@@ -4918,5 +4918,5 @@
 # of unresolved testcases	1
 # of untested testcases		5
 # of unsupported tests		16
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.ada/gdb.sum	2013-09-18 21:24:02.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.ada/gdb.sum	2013-09-21 22:15:28.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:23:49 2013
+Test Run By hacklu on Sat Sep 21 22:15:18 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -188,5 +188,5 @@
 # of expected passes		10
 # of untested testcases		1
 # of unsupported tests		80
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.arch/gdb.sum	2013-09-18 21:24:41.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.arch/gdb.sum	2013-09-21 22:16:04.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:24:04 2013
+Test Run By hacklu on Sat Sep 21 22:15:30 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -257,5 +257,5 @@
 # of expected passes		144
 # of unexpected failures	41
 # of known failures		1
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.asm/gdb.sum	2013-09-18 21:28:55.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.asm/gdb.sum	2013-09-21 22:20:20.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:24:42 2013
+Test Run By hacklu on Sat Sep 21 22:16:05 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -41,5 +41,5 @@
 
 # of expected passes		3
 # of unexpected failures	25
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.btrace/gdb.sum	2013-09-18 21:28:58.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.btrace/gdb.sum	2013-09-21 22:20:25.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:28:55 2013
+Test Run By hacklu on Sat Sep 21 22:20:21 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -13,5 +13,5 @@
 
 		=== gdb Summary ===
 
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.cell/gdb.sum	2013-09-18 21:28:59.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.cell/gdb.sum	2013-09-21 22:20:27.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:28:58 2013
+Test Run By hacklu on Sat Sep 21 22:20:26 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -28,5 +28,5 @@
 
 		=== gdb Summary ===
 
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.cp/gdb.sum	2013-09-18 21:38:20.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.cp/gdb.sum	2013-09-21 22:29:27.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:29:00 2013
+Test Run By hacklu on Sat Sep 21 22:20:28 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -4190,5 +4190,5 @@
 # of known failures		20
 # of untested testcases		1
 # of unsupported tests		1
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.disasm/gdb.sum	2013-09-18 21:38:23.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.disasm/gdb.sum	2013-09-21 22:29:30.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:38:21 2013
+Test Run By hacklu on Sat Sep 21 22:29:28 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -28,5 +28,5 @@
 
 		=== gdb Summary ===
 
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.dwarf2/gdb.sum	2013-09-18 21:41:30.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.dwarf2/gdb.sum	2013-09-21 22:32:26.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:38:24 2013
+Test Run By hacklu on Sat Sep 21 22:29:31 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -32,7 +32,7 @@
 PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: ptype f
 PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: is alive
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-basic.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-basic.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-basic.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-basic.exp: ptype func_cu1
@@ -54,7 +54,7 @@
 PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: list gcc43
 PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: info source gcc43
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-compressed.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-compressed.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-compressed.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-compressed.exp: ptype func_cu1
@@ -328,13 +328,13 @@
 PASS: gdb.dwarf2/dw2-inline-param.exp: info addr break_at
 PASS: gdb.dwarf2/dw2-inline-param.exp: bt
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intercu.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-intercu.exp: ptype int2
 PASS: gdb.dwarf2/dw2-intercu.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-intercu.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-intercu.exp: ptype func_cu1
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intermix.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-intermix.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-intermix.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-intermix.exp: ptype func_cu1
@@ -439,7 +439,7 @@
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-param-error.exp ...
 PASS: gdb.dwarf2/dw2-param-error.exp: frame
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-producer.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-producer.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-producer.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-producer.exp: ptype func_cu1
@@ -547,7 +547,7 @@
 Running ../../../gdb/testsuite/gdb.dwarf2/implptrpiece.exp ...
 PASS: gdb.dwarf2/implptrpiece.exp: print/d p[-1]
 Running ../../../gdb/testsuite/gdb.dwarf2/mac-fileno.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/mac-fileno.exp: set listsize 1
 FAIL: gdb.dwarf2/mac-fileno.exp: list func_cu1
 PASS: gdb.dwarf2/mac-fileno.exp: ptype func_cu1
@@ -658,5 +658,5 @@
 # of unresolved testcases	6
 # of untested testcases		9
 # of unsupported tests		1
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.fortran/gdb.sum	2013-09-18 21:42:09.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.fortran/gdb.sum	2013-09-21 22:33:01.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:41:31 2013
+Test Run By hacklu on Sat Sep 21 22:32:27 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -269,5 +269,5 @@
 
 # of expected passes		243
 # of unexpected failures	2
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.go/gdb.sum	2013-09-18 21:44:23.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.go/gdb.sum	2013-09-21 22:35:15.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:44:17 2013
+Test Run By hacklu on Sat Sep 21 22:35:10 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -90,5 +90,5 @@
 # of expected passes		44
 # of expected failures		4
 # of untested testcases		9
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.server/gdb.sum	2013-09-18 21:50:17.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.server/gdb.sum	2013-09-21 22:41:15.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:50:16 2013
+Test Run By hacklu on Sat Sep 21 22:40:35 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -8,16 +8,85 @@
 
 Running target unix
 Running ../../../gdb/testsuite/gdb.server/ext-attach.exp ...
+PASS: gdb.server/ext-attach.exp: disconnect
+PASS: gdb.server/ext-attach.exp: set remote exec-file
+FAIL: gdb.server/ext-attach.exp: attach to remote program 1
+FAIL: gdb.server/ext-attach.exp: backtrace 1
+FAIL: gdb.server/ext-attach.exp: detach (the program is no longer running)
+PASS: gdb.server/ext-attach.exp: backtrace with no program
+FAIL: gdb.server/ext-attach.exp: attach to remote program 2
+FAIL: gdb.server/ext-attach.exp: backtrace 2
+PASS: gdb.server/ext-attach.exp: kill
+PASS: gdb.server/ext-attach.exp: monitor exit
 Running ../../../gdb/testsuite/gdb.server/ext-run.exp ...
+PASS: gdb.server/ext-run.exp: disconnect
+PASS: gdb.server/ext-run.exp: set remote exec-file
+PASS: gdb.server/ext-run.exp: continue to main
+PASS: gdb.server/ext-run.exp: kill
+PASS: gdb.server/ext-run.exp: load new file without any gdbserver inferior
+PASS: gdb.server/ext-run.exp: monitor exit
 Running ../../../gdb/testsuite/gdb.server/file-transfer.exp ...
+PASS: gdb.server/file-transfer.exp: disconnect
+PASS: gdb.server/file-transfer.exp: put binary file
+FAIL: gdb.server/file-transfer.exp: get binary file
+PASS: gdb.server/file-transfer.exp: compare intermediate binary file
+FAIL: gdb.server/file-transfer.exp: compare binary file
+FAIL: gdb.server/file-transfer.exp: deleted binary file
+FAIL: gdb.server/file-transfer.exp: verified deleted binary file
+FAIL: gdb.server/file-transfer.exp: put text file
+FAIL: gdb.server/file-transfer.exp: get text file
+FAIL: gdb.server/file-transfer.exp: compare intermediate text file
+FAIL: gdb.server/file-transfer.exp: compare text file
+FAIL: gdb.server/file-transfer.exp: deleted text file
+FAIL: gdb.server/file-transfer.exp: verified deleted text file
 Running ../../../gdb/testsuite/gdb.server/no-thread-db.exp ...
+PASS: gdb.server/no-thread-db.exp: successfully compiled posix threads test case
+PASS: gdb.server/no-thread-db.exp: disconnect
+FAIL: gdb.server/no-thread-db.exp: libthread-db is now unresolvable
+PASS: gdb.server/no-thread-db.exp: continue to breakpoint: after tls assignment
+FAIL: gdb.server/no-thread-db.exp: print foo
 Running ../../../gdb/testsuite/gdb.server/server-exec-info.exp ...
+PASS: gdb.server/server-exec-info.exp: file
+PASS: gdb.server/server-exec-info.exp: set sysroot remote:
+FAIL: gdb.server/server-exec-info.exp: info files
 Running ../../../gdb/testsuite/gdb.server/server-kill.exp ...
+PASS: gdb.server/server-kill.exp: disconnect
+FAIL: gdb.server/server-kill.exp: tstatus
 Running ../../../gdb/testsuite/gdb.server/server-mon.exp ...
+PASS: gdb.server/server-mon.exp: disconnect
+PASS: gdb.server/server-mon.exp: monitor help
+PASS: gdb.server/server-mon.exp: monitor
+PASS: gdb.server/server-mon.exp: monitor set debug 1
+PASS: gdb.server/server-mon.exp: monitor set debug 0
+PASS: gdb.server/server-mon.exp: monitor set remote-debug 1
+PASS: gdb.server/server-mon.exp: monitor set remote-debug 0
 Running ../../../gdb/testsuite/gdb.server/server-run.exp ...
+PASS: gdb.server/server-run.exp: disconnect
+PASS: gdb.server/server-run.exp: continue to main
 Running ../../../gdb/testsuite/gdb.server/solib-list.exp ...
+PASS: gdb.server/solib-list.exp: non-stop 0: disconnect
+PASS: gdb.server/solib-list.exp: non-stop 0: set non-stop 0
+PASS: gdb.server/solib-list.exp: non-stop 0: set target-async 0
+PASS: gdb.server/solib-list.exp: non-stop 0: set displaced-stepping off
+PASS: gdb.server/solib-list.exp: non-stop 0: file binfile
+PASS: gdb.server/solib-list.exp: non-stop 0: target remote
+PASS: gdb.server/solib-list.exp: non-stop 0: continue
+PASS: gdb.server/solib-list.exp: non-stop 0: sharedlibrary
+PASS: gdb.server/solib-list.exp: non-stop 0: p libvar
+PASS: gdb.server/solib-list.exp: non-stop 1: disconnect
+PASS: gdb.server/solib-list.exp: non-stop 1: set non-stop 1
+PASS: gdb.server/solib-list.exp: non-stop 1: set target-async 1
+PASS: gdb.server/solib-list.exp: non-stop 1: set displaced-stepping off
+PASS: gdb.server/solib-list.exp: non-stop 1: file binfile
+PASS: gdb.server/solib-list.exp: non-stop 1: target remote
+FAIL: gdb.server/solib-list.exp: non-stop 1: non-stop interior stop (timeout)
+FAIL: gdb.server/solib-list.exp: non-stop 1: continue (the program is no longer running)
+PASS: gdb.server/solib-list.exp: non-stop 1: sharedlibrary
+FAIL: gdb.server/solib-list.exp: non-stop 1: p libvar
 
 		=== gdb Summary ===
 
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+# of expected passes		45
+# of unexpected failures	22
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.java/gdb.sum	2013-09-18 21:44:26.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.java/gdb.sum	2013-09-21 22:35:18.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:44:24 2013
+Test Run By hacklu on Sat Sep 21 22:35:15 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -84,5 +84,5 @@
 # of expected passes		60
 # of untested testcases		1
 # of unsupported tests		4
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.linespec/gdb.sum	2013-09-18 21:45:13.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.linespec/gdb.sum	2013-09-21 22:35:47.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:44:27 2013
+Test Run By hacklu on Sat Sep 21 22:35:19 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -222,5 +222,5 @@
 		=== gdb Summary ===
 
 # of expected passes		204
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.mi/gdb.sum	2013-09-18 21:48:21.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.mi/gdb.sum	2013-09-21 22:38:42.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:45:14 2013
+Test Run By hacklu on Sat Sep 21 22:35:48 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -331,6 +331,12 @@
 PASS: gdb.mi/mi-eval.exp: eval A+3
 PASS: gdb.mi/mi-eval.exp: eval A + 3
 Running ../../../gdb/testsuite/gdb.mi/mi-file-transfer.exp ...
+PASS: gdb.mi/mi-file-transfer.exp: put binary file
+FAIL: gdb.mi/mi-file-transfer.exp: get binary file
+PASS: gdb.mi/mi-file-transfer.exp: compare intermediate binary file
+FAIL: gdb.mi/mi-file-transfer.exp: compare binary file
+FAIL: gdb.mi/mi-file-transfer.exp: deleted binary file
+FAIL: gdb.mi/mi-file-transfer.exp: verified deleted binary file
 Running ../../../gdb/testsuite/gdb.mi/mi-file.exp ...
 PASS: gdb.mi/mi-file.exp: request path info of current source file (basics.c)
 PASS: gdb.mi/mi-file.exp: Getting a list of source files.
@@ -1779,11 +1785,11 @@
 
 		=== gdb Summary ===
 
-# of expected passes		1654
-# of unexpected failures	29
+# of expected passes		1656
+# of unexpected failures	33
 # of unexpected successes	1
 # of expected failures		8
 # of known failures		6
 # of unsupported tests		9
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.modula2/gdb.sum	2013-09-18 21:48:25.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.modula2/gdb.sum	2013-09-21 22:38:46.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:48:22 2013
+Test Run By hacklu on Sat Sep 21 22:38:43 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -20,5 +20,5 @@
 		=== gdb Summary ===
 
 # of expected passes		8
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.multi/gdb.sum	2013-09-18 21:48:34.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.multi/gdb.sum	2013-09-21 22:38:56.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:48:26 2013
+Test Run By hacklu on Sat Sep 21 22:38:47 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -63,5 +63,5 @@
 # of expected passes		31
 # of unexpected failures	10
 # of untested testcases		2
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.objc/gdb.sum	2013-09-18 21:48:39.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.objc/gdb.sum	2013-09-21 22:39:01.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:48:35 2013
+Test Run By hacklu on Sat Sep 21 22:38:57 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -32,5 +32,5 @@
 
 # of expected passes		13
 # of unsupported tests		3
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.opencl/gdb.sum	2013-09-18 21:48:44.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.opencl/gdb.sum	2013-09-21 22:39:05.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:48:40 2013
+Test Run By hacklu on Sat Sep 21 22:39:02 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -15,5 +15,5 @@
 
 		=== gdb Summary ===
 
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.opt/gdb.sum	2013-09-18 21:49:03.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.opt/gdb.sum	2013-09-21 22:39:23.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:48:45 2013
+Test Run By hacklu on Sat Sep 21 22:39:05 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -115,5 +115,5 @@
 # of expected passes		95
 # of expected failures		1
 # of known failures		1
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.pascal/gdb.sum	2013-09-18 21:49:05.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.pascal/gdb.sum	2013-09-21 22:39:26.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:49:04 2013
+Test Run By hacklu on Sat Sep 21 22:39:24 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -50,5 +50,5 @@
 # of known failures		1
 # of untested testcases		2
 # of unsupported tests		4
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.python/gdb.sum	2013-09-18 21:50:14.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.python/gdb.sum	2013-09-21 22:40:32.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:49:07 2013
+Test Run By hacklu on Sat Sep 21 22:39:26 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -96,5 +96,5 @@
 
 # of expected passes		2
 # of unsupported tests		41
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.reverse/gdb.sum	2013-09-18 21:50:16.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.reverse/gdb.sum	2013-09-21 22:40:34.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:50:15 2013
+Test Run By hacklu on Sat Sep 21 22:40:33 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -37,5 +37,5 @@
 
 		=== gdb Summary ===
 
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.stabs/gdb.sum	2013-09-18 21:50:33.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.stabs/gdb.sum	2013-09-21 22:41:29.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:50:18 2013
+Test Run By hacklu on Sat Sep 21 22:41:16 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -234,5 +234,5 @@
 
 # of expected passes		212
 # of expected failures		7
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.threads/gdb.sum	2013-09-18 22:02:21.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.threads/gdb.sum	2013-09-21 22:53:16.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:50:34 2013
+Test Run By hacklu on Sat Sep 21 22:41:30 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -463,5 +463,5 @@
 # of unresolved testcases	1
 # of untested testcases		3
 # of unsupported tests		9
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.trace/gdb.sum	2013-09-18 22:03:51.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.trace/gdb.sum	2013-09-21 22:54:48.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 22:02:21 2013
+Test Run By hacklu on Sat Sep 21 22:53:17 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -300,7 +300,7 @@
 PASS: gdb.trace/tracecmd.exp: 1.14: help trace
 PASS: gdb.trace/tracecmd.exp: Declined to set a fast tracepoint
 Running ../../../gdb/testsuite/gdb.trace/tspeed.exp ...
-gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.git2/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory
+gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory
 UNTESTED: gdb.trace/tspeed.exp: tspeed.exp
 Running ../../../gdb/testsuite/gdb.trace/tstatus.exp ...
 UNSUPPORTED: gdb.trace/tstatus.exp: target does not support trace
@@ -343,5 +343,5 @@
 # of expected passes		251
 # of untested testcases		3
 # of unsupported tests		32
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.xml/gdb.sum	2013-09-18 22:03:53.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.xml/gdb.sum	2013-09-21 22:54:51.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 22:03:52 2013
+Test Run By hacklu on Sat Sep 21 22:54:49 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -21,5 +21,5 @@
 		=== gdb Summary ===
 
 # of unsupported tests		5
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.base2/gdb.sum	2013-09-18 21:23:48.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.base2/gdb.sum	2013-09-21 22:15:17.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:10:21 2013
+Test Run By hacklu on Sat Sep 21 22:01:39 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -4255,5 +4255,5 @@
 # of known failures		2
 # of untested testcases		7
 # of unsupported tests		4
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.gdb/gdb.sum	2013-09-18 21:44:16.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.gdb/gdb.sum	2013-09-21 22:35:09.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 21:42:10 2013
+Test Run By hacklu on Sat Sep 21 22:33:02 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -171,7 +171,7 @@
 PASS: gdb.gdb/selftest.exp: Set xgdb prompt
 PASS: gdb.gdb/selftest.exp: send ^C to child process
 PASS: gdb.gdb/selftest.exp: send SIGINT signal to child process
-PASS: gdb.gdb/selftest.exp: backtrace through signal handler
+FAIL: gdb.gdb/selftest.exp: backtrace through signal handler (timeout)
 Running ../../../gdb/testsuite/gdb.gdb/xfullpath.exp ...
 PASS: gdb.gdb/xfullpath.exp: breakpoint in captured_main
 PASS: gdb.gdb/xfullpath.exp: run until breakpoint at captured_main
@@ -185,8 +185,8 @@
 
 		=== gdb Summary ===
 
-# of expected passes		165
-# of unexpected failures	3
+# of expected passes		164
+# of unexpected failures	4
 # of unsupported tests		1
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--- build.git2/gdb/testsuite/gdb.sum	2013-09-18 22:04:53.000000000 +0800
+++ build.gdb3/gdb/testsuite/gdb.sum	2013-09-21 22:55:52.000000000 +0800
@@ -1,4 +1,4 @@
-Test Run By hacklu on Wed Sep 18 20:56:22 2013
+Test Run By hacklu on Sat Sep 21 21:47:36 2013
 Native configuration is i686-unknown-gnu0.3
 
 		=== gdb tests ===
@@ -2231,7 +2231,7 @@
 PASS: gdb.base/complex.exp: print complex packed value in C
 PASS: gdb.base/complex.exp: print complex value in C
 Running ../../../gdb/testsuite/gdb.base/comprdebug.exp ...
-ERROR: Couldn't load /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb.
+ERROR: Couldn't load /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.base/comprdebug0.o into /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb.
 UNRESOLVED: gdb.base/comprdebug.exp: file comprdebug0.o
 Running ../../../gdb/testsuite/gdb.base/condbreak.exp ...
 PASS: gdb.base/condbreak.exp: breakpoint function
@@ -13833,7 +13833,7 @@
 PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: ptype f
 PASS: gdb.dwarf2/dw2-bad-parameter-type.exp: is alive
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-basic.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-basic.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-basic.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-basic.exp: ptype func_cu1
@@ -13855,7 +13855,7 @@
 PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: list gcc43
 PASS: gdb.dwarf2/dw2-compdir-oldgcc.exp: info source gcc43
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-compressed.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-compressed.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-compressed.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-compressed.exp: ptype func_cu1
@@ -14129,13 +14129,13 @@
 PASS: gdb.dwarf2/dw2-inline-param.exp: info addr break_at
 PASS: gdb.dwarf2/dw2-inline-param.exp: bt
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intercu.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-intercu.exp: ptype int2
 PASS: gdb.dwarf2/dw2-intercu.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-intercu.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-intercu.exp: ptype func_cu1
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-intermix.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-intermix.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-intermix.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-intermix.exp: ptype func_cu1
@@ -14240,7 +14240,7 @@
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-param-error.exp ...
 PASS: gdb.dwarf2/dw2-param-error.exp: frame
 Running ../../../gdb/testsuite/gdb.dwarf2/dw2-producer.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/dw2-producer.exp: set listsize 1
 FAIL: gdb.dwarf2/dw2-producer.exp: list func_cu1
 PASS: gdb.dwarf2/dw2-producer.exp: ptype func_cu1
@@ -14348,7 +14348,7 @@
 Running ../../../gdb/testsuite/gdb.dwarf2/implptrpiece.exp ...
 PASS: gdb.dwarf2/implptrpiece.exp: print/d p[-1]
 Running ../../../gdb/testsuite/gdb.dwarf2/mac-fileno.exp ...
-ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.git2/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
+ERROR: remote_download to host of ../../../gdb/testsuite/gdb.dwarf2/file1.txt to /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/gdb.dwarf2/file1.txt: cp: cannot stat `../../../gdb/testsuite/gdb.dwarf2/file1.txt': No such file or directory
 UNRESOLVED: gdb.dwarf2/mac-fileno.exp: set listsize 1
 FAIL: gdb.dwarf2/mac-fileno.exp: list func_cu1
 PASS: gdb.dwarf2/mac-fileno.exp: ptype func_cu1
@@ -14871,7 +14871,7 @@
 PASS: gdb.gdb/selftest.exp: Set xgdb prompt
 PASS: gdb.gdb/selftest.exp: send ^C to child process
 PASS: gdb.gdb/selftest.exp: send SIGINT signal to child process
-PASS: gdb.gdb/selftest.exp: backtrace through signal handler
+FAIL: gdb.gdb/selftest.exp: backtrace through signal handler (timeout)
 Running ../../../gdb/testsuite/gdb.gdb/xfullpath.exp ...
 PASS: gdb.gdb/xfullpath.exp: breakpoint in captured_main
 PASS: gdb.gdb/xfullpath.exp: run until breakpoint at captured_main
@@ -15866,6 +15866,12 @@
 PASS: gdb.mi/mi-file.exp: request path info of current source file (basics.c)
 PASS: gdb.mi/mi-file.exp: Getting a list of source files.
 Running ../../../gdb/testsuite/gdb.mi/mi-file-transfer.exp ...
+PASS: gdb.mi/mi-file-transfer.exp: put binary file
+FAIL: gdb.mi/mi-file-transfer.exp: get binary file
+PASS: gdb.mi/mi-file-transfer.exp: compare intermediate binary file
+FAIL: gdb.mi/mi-file-transfer.exp: compare binary file
+FAIL: gdb.mi/mi-file-transfer.exp: deleted binary file
+FAIL: gdb.mi/mi-file-transfer.exp: verified deleted binary file
 Running ../../../gdb/testsuite/gdb.mi/mi-fill-memory.exp ...
 PASS: gdb.mi/mi-fill-memory.exp: breakpoint at main
 PASS: gdb.mi/mi-fill-memory.exp: mi runto main
@@ -17344,14 +17350,81 @@
 Running ../../../gdb/testsuite/gdb.reverse/watch-precsave.exp ...
 Running ../../../gdb/testsuite/gdb.reverse/watch-reverse.exp ...
 Running ../../../gdb/testsuite/gdb.server/ext-attach.exp ...
+PASS: gdb.server/ext-attach.exp: disconnect
+PASS: gdb.server/ext-attach.exp: set remote exec-file
+FAIL: gdb.server/ext-attach.exp: attach to remote program 1
+FAIL: gdb.server/ext-attach.exp: backtrace 1
+FAIL: gdb.server/ext-attach.exp: detach (the program is no longer running)
+PASS: gdb.server/ext-attach.exp: backtrace with no program
+FAIL: gdb.server/ext-attach.exp: attach to remote program 2
+FAIL: gdb.server/ext-attach.exp: backtrace 2
+PASS: gdb.server/ext-attach.exp: kill
+PASS: gdb.server/ext-attach.exp: monitor exit
 Running ../../../gdb/testsuite/gdb.server/ext-run.exp ...
+PASS: gdb.server/ext-run.exp: disconnect
+PASS: gdb.server/ext-run.exp: set remote exec-file
+PASS: gdb.server/ext-run.exp: continue to main
+PASS: gdb.server/ext-run.exp: kill
+PASS: gdb.server/ext-run.exp: load new file without any gdbserver inferior
+PASS: gdb.server/ext-run.exp: monitor exit
 Running ../../../gdb/testsuite/gdb.server/file-transfer.exp ...
+PASS: gdb.server/file-transfer.exp: disconnect
+PASS: gdb.server/file-transfer.exp: put binary file
+FAIL: gdb.server/file-transfer.exp: get binary file
+PASS: gdb.server/file-transfer.exp: compare intermediate binary file
+FAIL: gdb.server/file-transfer.exp: compare binary file
+FAIL: gdb.server/file-transfer.exp: deleted binary file
+FAIL: gdb.server/file-transfer.exp: verified deleted binary file
+FAIL: gdb.server/file-transfer.exp: put text file
+FAIL: gdb.server/file-transfer.exp: get text file
+FAIL: gdb.server/file-transfer.exp: compare intermediate text file
+FAIL: gdb.server/file-transfer.exp: compare text file
+FAIL: gdb.server/file-transfer.exp: deleted text file
+FAIL: gdb.server/file-transfer.exp: verified deleted text file
 Running ../../../gdb/testsuite/gdb.server/no-thread-db.exp ...
+PASS: gdb.server/no-thread-db.exp: successfully compiled posix threads test case
+PASS: gdb.server/no-thread-db.exp: disconnect
+FAIL: gdb.server/no-thread-db.exp: libthread-db is now unresolvable
+PASS: gdb.server/no-thread-db.exp: continue to breakpoint: after tls assignment
+FAIL: gdb.server/no-thread-db.exp: print foo
 Running ../../../gdb/testsuite/gdb.server/server-exec-info.exp ...
+PASS: gdb.server/server-exec-info.exp: file
+PASS: gdb.server/server-exec-info.exp: set sysroot remote:
+FAIL: gdb.server/server-exec-info.exp: info files
 Running ../../../gdb/testsuite/gdb.server/server-kill.exp ...
+PASS: gdb.server/server-kill.exp: disconnect
+FAIL: gdb.server/server-kill.exp: tstatus
 Running ../../../gdb/testsuite/gdb.server/server-mon.exp ...
+PASS: gdb.server/server-mon.exp: disconnect
+PASS: gdb.server/server-mon.exp: monitor help
+PASS: gdb.server/server-mon.exp: monitor
+PASS: gdb.server/server-mon.exp: monitor set debug 1
+PASS: gdb.server/server-mon.exp: monitor set debug 0
+PASS: gdb.server/server-mon.exp: monitor set remote-debug 1
+PASS: gdb.server/server-mon.exp: monitor set remote-debug 0
 Running ../../../gdb/testsuite/gdb.server/server-run.exp ...
+PASS: gdb.server/server-run.exp: disconnect
+PASS: gdb.server/server-run.exp: continue to main
 Running ../../../gdb/testsuite/gdb.server/solib-list.exp ...
+PASS: gdb.server/solib-list.exp: non-stop 0: disconnect
+PASS: gdb.server/solib-list.exp: non-stop 0: set non-stop 0
+PASS: gdb.server/solib-list.exp: non-stop 0: set target-async 0
+PASS: gdb.server/solib-list.exp: non-stop 0: set displaced-stepping off
+PASS: gdb.server/solib-list.exp: non-stop 0: file binfile
+PASS: gdb.server/solib-list.exp: non-stop 0: target remote
+PASS: gdb.server/solib-list.exp: non-stop 0: continue
+PASS: gdb.server/solib-list.exp: non-stop 0: sharedlibrary
+PASS: gdb.server/solib-list.exp: non-stop 0: p libvar
+PASS: gdb.server/solib-list.exp: non-stop 1: disconnect
+PASS: gdb.server/solib-list.exp: non-stop 1: set non-stop 1
+PASS: gdb.server/solib-list.exp: non-stop 1: set target-async 1
+PASS: gdb.server/solib-list.exp: non-stop 1: set displaced-stepping off
+PASS: gdb.server/solib-list.exp: non-stop 1: file binfile
+PASS: gdb.server/solib-list.exp: non-stop 1: target remote
+FAIL: gdb.server/solib-list.exp: non-stop 1: non-stop interior stop (timeout)
+FAIL: gdb.server/solib-list.exp: non-stop 1: continue (the program is no longer running)
+PASS: gdb.server/solib-list.exp: non-stop 1: sharedlibrary
+FAIL: gdb.server/solib-list.exp: non-stop 1: p libvar
 Running ../../../gdb/testsuite/gdb.stabs/exclfwd.exp ...
 PASS: gdb.stabs/exclfwd.exp: ptype v1
 PASS: gdb.stabs/exclfwd.exp: ptype v2
@@ -18315,7 +18388,7 @@
 PASS: gdb.trace/trace-mt.exp: successfully compiled posix threads test case
 UNSUPPORTED: gdb.trace/trace-mt.exp: target does not support trace
 Running ../../../gdb/testsuite/gdb.trace/tspeed.exp ...
-gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.git2/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory
+gdb compile failed, gcc: error: /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../gdbserver/libinproctrace.so: No such file or directory
 UNTESTED: gdb.trace/tspeed.exp: tspeed.exp
 Running ../../../gdb/testsuite/gdb.trace/tstatus.exp ...
 UNSUPPORTED: gdb.trace/tstatus.exp: target does not support trace
@@ -18365,13 +18438,13 @@
 
 		=== gdb Summary ===
 
-# of expected passes		16427
-# of unexpected failures	529
+# of expected passes		16473
+# of unexpected failures	556
 # of unexpected successes	1
 # of expected failures		33
 # of known failures		52
 # of untested testcases		43
 # of unresolved testcases	8
 # of unsupported tests		210
-/home/hacklu/code/gdb/build.git2/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.git2/gdb/testsuite/../data-directory 
+/home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../../gdb/gdb version  7.6.50.20130911-cvs -nw -nx -data-directory /home/hacklu/code/gdb/build.gdb3/gdb/testsuite/../data-directory 
 
--
Yue Lu(陆岳)


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2013-09-22 12:58 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CAB8fV=jJ64i91VW52ZmdnEDZhd1ZGTAykDqoFyPJanCP=5beqA@mail.gmail.com>
2013-09-03  8:03 ` [PATCH 2/2] Port gdbserver to GNU/Hurd Yue Lu
2013-09-03  9:38   ` [PATCH 1/2] " Thomas Schwinge
2013-09-03 11:11     ` Pedro Alves
2013-09-03 13:09       ` Thomas Schwinge
2013-09-04  1:47         ` Yue Lu
2013-09-04  1:38       ` Yue Lu
2013-09-05 10:54       ` Yue Lu
2013-09-05 19:29         ` Pedro Alves
2013-09-05 19:39           ` Joel Brobecker
2013-09-05 21:38           ` Thomas Schwinge
2013-09-08 13:35             ` Yue Lu
2013-09-09  9:58               ` Thomas Schwinge
2013-09-18 12:12                 ` Pedro Alves
2013-09-18 13:48                   ` Yue Lu
2013-09-18 14:52                     ` [Hurd/gnu-nat.c] Use ptid_t.lwpid to store, thread ids instead of ptid_t.tid. (was: Re: [PATCH 1/2] Port gdbserver to GNU/Hurd) Pedro Alves
2013-09-18 14:57                     ` [PATCH 1/2] Port gdbserver to GNU/Hurd Pedro Alves
2013-09-22 12:58             ` Yue Lu
2013-09-06 18:53           ` Pedro Alves
2013-09-12  3:05             ` Yue Lu
2013-09-18 12:30               ` Pedro Alves
2013-09-18 12:37               ` Pedro Alves
2013-09-19  7:41                 ` Yue Lu
2013-09-19  8:30                   ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) (was: [PATCH 1/2] Port gdbserver to GNU/Hurd) Thomas Schwinge
2013-09-19  8:44                     ` FAIL: gdb.base/nextoverexit.exp: next over exit (the program exited) Pedro Alves
2013-09-09 10:21           ` [PATCH 1/2] Port gdbserver to GNU/Hurd Yue Lu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox