gdbserver_genode.patch

From: Christian Prochaska <christian.prochaska@genode-labs.com>


---
 gdb/gdbserver/linux-arm-low.c |    4 +
 gdb/gdbserver/linux-low.c     |  223 ++++++++++++++++++++++++++++++++++-------
 gdb/gdbserver/linux-low.h     |    5 +
 gdb/gdbserver/linux-x86-low.c |   43 +++++++-
 gdb/gdbserver/remote-utils.c  |   80 +++++++++++++++
 gdb/gdbserver/server.c        |   52 ++++++++--
 gdb/gdbserver/server.h        |    4 -
 7 files changed, 356 insertions(+), 55 deletions(-)

diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index babb20c..d14c8cc 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -25,6 +25,7 @@
 #ifndef ELFMAG0
 #include <elf.h>
 #endif
+#include <sys/procfs.h>
 #include <sys/ptrace.h>
 
 /* Defined in auto-generated files.  */
@@ -306,6 +307,7 @@ static void
 arm_arch_setup (void)
 {
   arm_hwcap = 0;
+#if 0
   if (arm_get_hwcap (&arm_hwcap) == 0)
     {
       init_registers_arm ();
@@ -347,7 +349,7 @@ arm_arch_setup (void)
 
       return;
     }
-
+#endif
   /* The default configuration uses legacy FPA registers, probably
      simulated.  */
   init_registers_arm ();
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 81b8540..5b31da5 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -19,6 +19,7 @@
 
 #include "server.h"
 #include "linux-low.h"
+#include "genode-low.h"
 
 #include <sys/wait.h>
 #include <stdio.h>
@@ -281,6 +282,7 @@ elf_64_file_p (const char *file)
 static void
 delete_lwp (struct lwp_info *lwp)
 {
+  if (debug_threads) printf("delete_lwp()\n");
   remove_thread (get_lwp_thread (lwp));
   remove_inferior (&all_lwps, &lwp->head);
   free (lwp->arch_private);
@@ -535,6 +537,8 @@ get_stop_pc (struct lwp_info *lwp)
 static void *
 add_lwp (ptid_t ptid)
 {
+  printf("add_lwp(%u, %lu, %lu)\n", ptid.pid, ptid.lwp, ptid.tid);
+
   struct lwp_info *lwp;
 
   lwp = (struct lwp_info *) xmalloc (sizeof (*lwp));
@@ -547,6 +551,9 @@ add_lwp (ptid_t ptid)
 
   add_inferior_to_list (&all_lwps, &lwp->head);
 
+  /* FIXME: this is not always true? */
+  lwp->stopped = 1;
+
   return lwp;
 }
 
@@ -606,6 +613,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
   ptid_t ptid;
   struct lwp_info *new_lwp;
 
+#if 0
   if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0)
     {
       if (!initial)
@@ -621,6 +629,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
 	error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid,
 	       strerror (errno), errno);
     }
+#endif
 
   if (initial)
     /* NOTE/FIXME: This lwp might have not been the tgid.  */
@@ -637,10 +646,11 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
   new_lwp = (struct lwp_info *) add_lwp (ptid);
   add_thread (ptid, new_lwp);
 
+#if 0
   /* We need to wait for SIGSTOP before being able to make the next
      ptrace call on this LWP.  */
   new_lwp->must_set_ptrace_flags = 1;
-
+#endif
   /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
      brings it to a halt.
 
@@ -689,6 +699,10 @@ linux_attach (unsigned long pid)
   linux_attach_lwp_1 (pid, 1);
   linux_add_process (pid, 1);
 
+  /* must be called after 'add_thread()', because 'current_inferior' must be set */
+  the_low_target.arch_setup();
+
+#if 0
   if (!non_stop)
     {
       struct thread_info *thread;
@@ -698,7 +712,7 @@ linux_attach (unsigned long pid)
       thread = find_thread_ptid (ptid_build (pid, pid, 0));
       thread->last_resume_kind = resume_stop;
     }
-
+#endif
   return 0;
 }
 
@@ -812,7 +826,11 @@ linux_kill (int pid)
   return 0;
 }
 
+#ifdef __GENODE__
+int
+#else
 static int
+#endif
 linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
 {
   struct thread_info *thread = (struct thread_info *) entry;
@@ -822,6 +840,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
   if (ptid_get_pid (entry->id) != pid)
     return 0;
 
+#if 0
   /* If this process is stopped but is expecting a SIGSTOP, then make
      sure we take care of that now.  This isn't absolutely guaranteed
      to collect the SIGSTOP, but is fairly likely to.  */
@@ -833,13 +852,15 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
       linux_resume_one_lwp (lwp, 0, 0, NULL);
       linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     }
-
+#endif
   /* Flush any pending changes to the process's registers.  */
   regcache_invalidate_one ((struct inferior_list_entry *)
 			   get_lwp_thread (lwp));
 
+#if 0
   /* Finally, let it resume.  */
   ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
+#endif
 
   delete_lwp (lwp);
   return 0;
@@ -2460,6 +2481,13 @@ async_file_mark (void)
      be awakened anyway.  */
 }
 
+static int mark_as_stopped(struct inferior_list_entry *entry, void *arg)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  lwp->stopped = 1;
+  return 0;
+}
+
 static ptid_t
 linux_wait (ptid_t ptid,
 	    struct target_waitstatus *ourstatus, int target_options)
@@ -2469,18 +2497,28 @@ linux_wait (ptid_t ptid,
   if (debug_threads)
     fprintf (stderr, "linux_wait: [%s]\n", target_pid_to_str (ptid));
 
+#ifndef __GENODE__
   /* Flush the async file first.  */
   if (target_is_async_p ())
     async_file_flush ();
+#endif
 
+#ifdef __GENODE__
+  /* TODO: get some information from wait_for_signal_or_gdb_interrupt() */
+  event_ptid = genode_wait_for_signal_or_gdb_interrupt(ourstatus);
+  find_inferior (&all_lwps, mark_as_stopped, NULL);
+#else
   event_ptid = linux_wait_1 (ptid, ourstatus, target_options);
+#endif
 
+#ifndef __GENODE__
   /* If at least one stop was reported, there may be more.  A single
      SIGCHLD can signal more than one child stop.  */
   if (target_is_async_p ()
       && (target_options & TARGET_WNOHANG) != 0
       && !ptid_equal (event_ptid, null_ptid))
     async_file_mark ();
+#endif
 
   return event_ptid;
 }
@@ -2785,6 +2823,8 @@ static void
 linux_resume_one_lwp (struct lwp_info *lwp,
 		      int step, int signal, siginfo_t *info)
 {
+  printf("linux_resume_one_lwp(step = %d, signal = %d)\n", step, signal);
+
   struct thread_info *saved_inferior;
   int fast_tp_collecting;
 
@@ -2958,10 +2998,15 @@ lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n",
   lwp->stopped = 0;
   lwp->stopped_by_watchpoint = 0;
   lwp->stepping = step;
+
+#ifdef __GENODE__
+  genode_continue_thread(lwpid_of(lwp), step);
+#else
   ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp), 0,
 	  /* Coerce to a uintptr_t first to avoid potential gcc warning
 	     of coercing an 8 byte integer to a 4 byte pointer.  */
 	  (PTRACE_ARG4_TYPE) (uintptr_t) signal);
+#endif
 
   current_inferior = saved_inferior;
   if (errno)
@@ -3325,6 +3370,8 @@ finish_step_over (struct lwp_info *lwp)
 static int
 linux_resume_one_thread (struct inferior_list_entry *entry, void *arg)
 {
+  if (debug_threads) printf("linux_resume_one_thread()\n");
+
   struct lwp_info *lwp;
   struct thread_info *thread;
   int step;
@@ -3436,6 +3483,8 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg)
 static void
 linux_resume (struct thread_resume *resume_info, size_t n)
 {
+  if (debug_threads) printf("linux_resume(%zd)\n", n);
+
   struct thread_resume_array array = { resume_info, n };
   struct lwp_info *need_step_over = NULL;
   int any_pending;
@@ -3484,6 +3533,8 @@ linux_resume (struct thread_resume *resume_info, size_t n)
 
   if (need_step_over)
     start_step_over (need_step_over);
+
+  if (debug_threads) printf("linux_resume() finished\n");
 }
 
 /* This function is called once per thread.  We check the thread's
@@ -3958,6 +4009,26 @@ linux_fetch_registers (struct regcache *regcache, int regno)
 #endif
 }
 
+static void
+genode_fetch_registers (struct regcache *regcache, int regno)
+{
+	unsigned long reg_content = 0;
+
+	if (regno == -1) {
+		for (regno = 0; regno < the_low_target.num_regs; regno++) {
+			if (genode_fetch_register(regno, &reg_content) == 0)
+				supply_register(regcache, regno, &reg_content);
+			else
+				supply_register(regcache, regno, 0);
+		}
+	} else {
+		if (genode_fetch_register(regno, &reg_content) == 0)
+			supply_register(regcache, regno, &reg_content);
+		else
+			supply_register(regcache, regno, 0);
+	}
+}
+
 void
 linux_store_registers (struct regcache *regcache, int regno)
 {
@@ -3970,6 +4041,28 @@ linux_store_registers (struct regcache *regcache, int regno)
 #endif
 }
 
+void
+genode_store_registers (struct regcache *regcache, int regno)
+{
+	if (debug_threads) printf("genode_store_registers(): regno = %d\n", regno);
+
+	unsigned long reg_content = 0;
+
+	if (regno == -1) {
+		for (regno = 0; regno < the_low_target.num_regs; regno++) {
+			if (register_size(regno) <= sizeof(reg_content)) {
+				collect_register(regcache, regno, &reg_content);
+				genode_store_register(regno, reg_content);
+			}
+		}
+	} else {
+		if (register_size(regno) <= sizeof(reg_content)) {
+			collect_register(regcache, regno, &reg_content);
+			genode_store_register(regno, reg_content);
+		}
+	}
+}
+
 
 /* Copy LEN bytes from inferior's memory starting at MEMADDR
    to debugger memory starting at MYADDR.  */
@@ -4040,6 +4133,17 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
   return 0;
 }
 
+static int
+genode_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+	int i;
+	if (debug_threads) printf("genode_read_memory(%llx, %p, %d)\n", memaddr, myaddr, len);
+	if (myaddr)
+		for (i = 0; i < len; i++)
+		  myaddr[i] = genode_read_memory_byte((void*)(unsigned long)memaddr + i);
+	return 0;
+}
+
 /* Copy LEN bytes of data from debugger memory at MYADDR to inferior's
    memory at MEMADDR.  On failure (cannot write to the inferior)
    returns the value of errno.  */
@@ -4121,6 +4225,34 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
   return 0;
 }
 
+static int
+genode_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+	int i;
+	
+	if (debug_threads)
+		printf("genode_write_memory(%llx, %p, %d)\n", memaddr, myaddr, len);
+
+	if (myaddr && (len > 0)) {
+		if (debug_threads)
+		{
+			/* Dump up to four bytes.  */
+			unsigned int val = * (unsigned int *) myaddr;
+			if (len == 1)
+				val = val & 0xff;
+			else if (len == 2)
+				val = val & 0xffff;
+			else if (len == 3)
+				val = val & 0xffffff;
+			fprintf (stderr, "Writing %0*x to 0x%08lx\n", 2 * ((len < 4) ? len : 4),
+					 val, (long)memaddr);
+		}
+		for (i = 0; i < len; i++)
+		   genode_write_memory_byte((void*)(unsigned long)memaddr + i, myaddr[i]);
+	}
+	return 0;
+}
+
 /* Non-zero if the kernel supports PTRACE_O_TRACEFORK.  */
 static int linux_supports_tracefork_flag;
 
@@ -4296,6 +4428,10 @@ linux_look_up_symbols (void)
 static void
 linux_request_interrupt (void)
 {
+  /* FIXME: currently all threads get interrupted */
+  genode_stop_all_threads();
+
+#if 0
   extern unsigned long signal_pid;
 
   if (!ptid_equal (cont_thread, null_ptid)
@@ -4306,10 +4442,19 @@ linux_request_interrupt (void)
 
       lwp = get_thread_lwp (current_inferior);
       lwpid = lwpid_of (lwp);
+#ifdef __GENODE__
+      genode_interrupt_thread(lwpid);
+#else
       kill_lwp (lwpid, SIGINT);
+#endif /* __GENODE__ */
     }
   else
-    kill_lwp (signal_pid, SIGINT);
+#ifdef __GENODE__
+    genode_interrupt_thread(lwpid);
+#else
+    kill_lwp (lwpid, SIGINT);
+#endif /* __GENODE__ */
+#endif
 }
 
 /* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
@@ -5108,28 +5253,28 @@ linux_emit_ops (void)
 }
 
 static struct target_ops linux_target_ops = {
-  linux_create_inferior,
+  /*linux_create_inferior*/NULL,
   linux_attach,
-  linux_kill,
-  linux_detach,
-  linux_mourn,
-  linux_join,
+  genode_kill,
+  genode_detach,
+  /*linux_mourn*/NULL,
+  /*linux_join*/NULL,
   linux_thread_alive,
   linux_resume,
   linux_wait,
-  linux_fetch_registers,
-  linux_store_registers,
+  genode_fetch_registers,
+  genode_store_registers,
   linux_prepare_to_access_memory,
   linux_done_accessing_memory,
-  linux_read_memory,
-  linux_write_memory,
-  linux_look_up_symbols,
+  genode_read_memory,
+  genode_write_memory,
+  /*linux_look_up_symbols*/NULL,
   linux_request_interrupt,
-  linux_read_auxv,
+  /*linux_read_auxv*/NULL,
   linux_insert_point,
   linux_remove_point,
-  linux_stopped_by_watchpoint,
-  linux_stopped_data_address,
+  /*linux_stopped_by_watchpoint*/NULL,
+  /*linux_stopped_data_address*/NULL,
 #if defined(__UCLIBC__) && defined(HAS_NOMMU)
   linux_read_offsets,
 #else
@@ -5140,32 +5285,32 @@ static struct target_ops linux_target_ops = {
 #else
   NULL,
 #endif
-  linux_qxfer_spu,
-  hostio_last_error_from_errno,
-  linux_qxfer_osdata,
-  linux_xfer_siginfo,
-  linux_supports_non_stop,
-  linux_async,
-  linux_start_non_stop,
-  linux_supports_multi_process,
+  /*linux_qxfer_spu*/NULL,
+  /*hostio_last_error_from_errno*/NULL,
+  /*linux_qxfer_osdata*/NULL,
+  /*linux_xfer_siginfo*/NULL,
+  /*linux_supports_non_stop*/NULL,
+  /*linux_async*/NULL,
+  /*linux_start_non_stop*/NULL,
+  /*linux_supports_multi_process*/NULL,
 #ifdef USE_THREAD_DB
   thread_db_handle_monitor_command,
 #else
   NULL,
 #endif
-  linux_core_of_thread,
-  linux_process_qsupported,
-  linux_supports_tracepoints,
-  linux_read_pc,
-  linux_write_pc,
-  linux_thread_stopped,
+  /*linux_core_of_thread*/NULL,
+  /*linux_process_qsupported*/NULL,
+  /*linux_supports_tracepoints*/NULL,
+  /*linux_read_pc*/NULL,
+  /*linux_write_pc*/NULL,
+  /*linux_thread_stopped*/NULL,
   NULL,
-  linux_pause_all,
-  linux_unpause_all,
-  linux_cancel_breakpoints,
-  linux_stabilize_threads,
-  linux_install_fast_tracepoint_jump_pad,
-  linux_emit_ops
+  /*linux_pause_all*/NULL,
+  /*linux_unpause_all*/NULL,
+  /*linux_cancel_breakpoints*/NULL,
+  /*linux_stabilize_threads*/NULL,
+  /*linux_install_fast_tracepoint_jump_pad*/NULL,
+  /*linux_emit_ops*/NULL
 };
 
 static void
@@ -5181,11 +5326,14 @@ linux_init_signals ()
 void
 initialize_low (void)
 {
+#if 0
   struct sigaction sigchld_action;
   memset (&sigchld_action, 0, sizeof (sigchld_action));
+#endif
   set_target_ops (&linux_target_ops);
   set_breakpoint_data (the_low_target.breakpoint,
 		       the_low_target.breakpoint_len);
+#if 0
   linux_init_signals ();
   linux_test_for_tracefork ();
 #ifdef HAVE_LINUX_REGSETS
@@ -5198,4 +5346,5 @@ initialize_low (void)
   sigemptyset (&sigchld_action.sa_mask);
   sigchld_action.sa_flags = SA_RESTART;
   sigaction (SIGCHLD, &sigchld_action, NULL);
+#endif
 }
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 6635bc6..ae172bd 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -21,7 +21,7 @@
 #include <thread_db.h>
 #endif
 
-#include "gdb_proc_service.h"
+//#include "gdb_proc_service.h"
 
 #ifdef HAVE_LINUX_REGSETS
 typedef void (*regset_fill_func) (struct regcache *, void *);
@@ -56,6 +56,9 @@ struct process_info_private
   /* libthread_db-specific additions.  Not NULL if this process has loaded
      thread_db, and it is active.  */
   struct thread_db *thread_db;
+
+  /* Genode-specific additions */
+  void *gdb_stub_thread;
 };
 
 struct lwp_info;
diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c
index 69c6b57..cffa803 100644
--- a/gdb/gdbserver/linux-x86-low.c
+++ b/gdb/gdbserver/linux-x86-low.c
@@ -28,8 +28,15 @@
 #include "i386-xstate.h"
 #include "elf/common.h"
 
-#include "gdb_proc_service.h"
-
+//#include "gdb_proc_service.h"
+
+#ifdef __GENODE__
+/* Defined in auto-generated file i386.c.  */
+void init_registers_i386 (void);
+static inline void init_registers_i386_linux(void) { init_registers_i386(); }
+void init_registers_i386_avx (void);
+static inline void init_registers_i386_avx_linux(void) { init_registers_i386_avx(); }
+#else
 /* Defined in auto-generated file i386-linux.c.  */
 void init_registers_i386_linux (void);
 /* Defined in auto-generated file amd64-linux.c.  */
@@ -40,11 +47,22 @@ void init_registers_i386_avx_linux (void);
 void init_registers_amd64_avx_linux (void);
 /* Defined in auto-generated file i386-mmx-linux.c.  */
 void init_registers_i386_mmx_linux (void);
+#endif
 
 static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 };
 
 /* Backward compatibility for gdb without XML support.  */
+#ifdef __GENODE__
+static const char *xmltarget_i386_linux_no_xml = "@<target>\
+<architecture>i386</architecture>\
+</target>";
 
+#ifdef __x86_64__
+static const char *xmltarget_amd64_linux_no_xml = "@<target>\
+<architecture>i386:x86-64</architecture>\
+</target>";
+#endif
+#else
 static const char *xmltarget_i386_linux_no_xml = "@<target>\
 <architecture>i386</architecture>\
 <osabi>GNU/Linux</osabi>\
@@ -56,8 +74,15 @@ static const char *xmltarget_amd64_linux_no_xml = "@<target>\
 <osabi>GNU/Linux</osabi>\
 </target>";
 #endif
+#endif /* __GENODE__ */
 
+#ifdef __GENODE__
+#ifndef __x86_64__
+#include "i386.h"
+#endif /* __x86_64__ */
+#else
 #include <sys/reg.h>
+#endif /* __GENODE__ */
 #include <sys/procfs.h>
 #include <sys/ptrace.h>
 #include <sys/uio.h>
@@ -273,8 +298,10 @@ x86_fill_gregset (struct regcache *regcache, void *buf)
   for (i = 0; i < I386_NUM_REGS; i++)
     collect_register (regcache, i, ((char *) buf) + i386_regmap[i]);
 
+#ifndef __GENODE__
   collect_register_by_name (regcache, "orig_eax",
 			    ((char *) buf) + ORIG_EAX * 4);
+#endif
 }
 
 static void
@@ -295,8 +322,10 @@ x86_store_gregset (struct regcache *regcache, const void *buf)
   for (i = 0; i < I386_NUM_REGS; i++)
     supply_register (regcache, i, ((char *) buf) + i386_regmap[i]);
 
+#ifndef __GENODE__
   supply_register_by_name (regcache, "orig_eax",
 			   ((char *) buf) + ORIG_EAX * 4);
+#endif
 }
 
 static void
@@ -414,7 +443,15 @@ x86_set_pc (struct regcache *regcache, CORE_ADDR pc)
     }
 }
 
+#ifdef __GENODE__
+/* The 'INT3' instruction is used by some kernel debuggers and thus cannot
+ * serve as breakpoint instruction for the GDB monitor. Instead, the 'HLT'
+ * instruction gets used. It's a privileged instruction which triggers an
+ * exception when executed in user mode */
+static const unsigned char x86_breakpoint[] = { 0xF4 };
+#else
 static const unsigned char x86_breakpoint[] = { 0xCC };
+#endif
 #define x86_breakpoint_len 1
 
 static int
@@ -2576,7 +2613,7 @@ struct linux_target_ops the_low_target =
   x86_siginfo_fixup,
   x86_linux_new_process,
   x86_linux_new_thread,
-  x86_linux_prepare_to_resume,
+  /*x86_linux_prepare_to_resume*/NULL,
   x86_linux_process_qsupported,
   x86_supports_tracepoints,
   x86_get_thread_area,
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 650ddf8..728da30 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -18,11 +18,14 @@
    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 "genode-low.h"
+
 #include "server.h"
 #include "terminal.h"
 #include "target.h"
 #include <stdio.h>
 #include <string.h>
+#include <sys/types.h>
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -171,7 +174,6 @@ handle_accept_event (int err, gdb_client_data client_data)
 
 #ifndef USE_WIN32API
   close (listen_desc);		/* No longer need this */
-
   signal (SIGPIPE, SIG_IGN);	/* If we don't do this, then gdbserver simply
 				   exits when the remote side dies.  */
 #else
@@ -186,6 +188,12 @@ handle_accept_event (int err, gdb_client_data client_data)
 
   enable_async_notification (remote_desc);
 
+  /* stop all threads */
+  genode_stop_all_threads();
+
+  /* find all existing threads and tell gdbserver about it */
+  genode_detect_all_threads();
+
   /* Register the event loop handler.  */
   add_file_handler (remote_desc, handle_serial_event, NULL);
 
@@ -280,6 +288,14 @@ remote_open (char *name)
 
       /* Register the event loop handler.  */
       add_file_handler (remote_desc, handle_serial_event, NULL);
+
+#ifdef __GENODE__
+      /* FIXME: find better place */
+      genode_stop_all_threads();
+      /* find all existing threads and tell gdbserver about it */
+      genode_detect_all_threads();
+#endif
+
 #endif /* USE_WIN32API */
     }
   else
@@ -857,6 +873,68 @@ input_interrupt (int unused)
     }
 }
 
+
+ptid_t
+genode_wait_for_signal_or_gdb_interrupt (struct target_waitstatus *status)
+{
+  printf("genode_wait_for_signal_or_gdb_interrupt\n");
+
+  ptid_t event_ptid;
+
+  fd_set readset;
+
+  FD_ZERO (&readset);
+  FD_SET (remote_desc, &readset);
+  FD_SET (genode_signal_fd(), &readset);
+
+  while(1) {
+  if (select ((remote_desc > genode_signal_fd() ? remote_desc : genode_signal_fd()) + 1, &readset, 0, 0, NULL) > 0)
+    {
+	  if (debug_threads) printf("select() returned\n");
+	  int cc;
+	  char c = 0;
+	  if (FD_ISSET(remote_desc, &readset)) {
+		  /* received input from GDB */
+		  cc = read (remote_desc, &c, 1);
+
+		  if (cc == 1 && c == '\003' && current_inferior != NULL) {
+			  (*the_target->request_interrupt) ();
+			  event_ptid = current_inferior->entry.id;
+			  status->kind = TARGET_WAITKIND_STOPPED;
+			  status->value.sig = TARGET_SIGNAL_INT;
+			  return event_ptid;
+		  } else
+		{
+		  fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n",
+			   cc, c, c);
+		}
+	  } else {
+		  /* received a signal */
+		  unsigned long sig;
+		  read(genode_signal_fd(), &sig, sizeof(sig));
+		  printf("received signal %ld\n", sig);
+		  if (current_inferior == NULL) continue;
+
+		  event_ptid.pid = GENODE_LWP_BASE;
+		  event_ptid.tid = 0;
+		  genode_stop_all_threads();
+
+		  if (sig > 0) {
+			  event_ptid.lwp    = sig;
+			  status->kind      = TARGET_WAITKIND_STOPPED;
+			  status->value.sig = TARGET_SIGNAL_TRAP;
+		  } else {
+			  event_ptid.lwp    = genode_find_segfault_lwpid();
+			  status->kind      = TARGET_WAITKIND_STOPPED;
+			  status->value.sig = TARGET_SIGNAL_SEGV;
+		  }
+		  return event_ptid;
+	  }
+    }
+  }
+}
+
+
 /* Check if the remote side sent us an interrupt request (^C).  */
 void
 check_remote_input_interrupt_request (void)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 2f4484f..79c89d4 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -18,8 +18,13 @@
    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 "genode-low.h"
+
 #include "server.h"
 
+#include "linux-low.h"
+
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -47,7 +52,7 @@ static char **program_argv, **wrapper_argv;
 
 /* Enable miscellaneous debugging output.  The name is historical - it
    was originally used to debug LinuxThreads support.  */
-int debug_threads;
+int debug_threads = 0;
 
 /* Enable debugging of h/w breakpoint/watchpoint support.  */
 int debug_hw_points;
@@ -1740,6 +1745,7 @@ static void gdb_wants_all_threads_stopped (void);
 void
 handle_v_cont (char *own_buf)
 {
+  if (debug_threads) printf("handle_v_cont()\n");
   char *p, *q;
   int n = 0, i = 0;
   struct thread_resume *resume_info;
@@ -2055,11 +2061,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 	  return;
 	}
     }
-
+#if 0
   if (strncmp (own_buf, "vFile:", 6) == 0
       && handle_vFile (own_buf, packet_len, new_packet_len))
     return;
-
+#endif
   if (strncmp (own_buf, "vAttach;", 8) == 0)
     {
       if (!multi_process && target_running ())
@@ -2114,6 +2120,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 static void
 myresume (char *own_buf, int step, int sig)
 {
+  if (debug_threads) printf("myresume()\n");
   struct thread_resume resume_info[2];
   int n = 0;
   int valid_cont_thread;
@@ -2250,6 +2257,7 @@ gdb_reattached_process (struct inferior_list_entry *entry)
 static void
 handle_status (char *own_buf)
 {
+	if (debug_threads) printf("handle_status()\n");
   /* GDB is connected, don't forward events to the target anymore.  */
   for_each_inferior (&all_processes, gdb_reattached_process);
 
@@ -2286,7 +2294,7 @@ handle_status (char *own_buf)
 	strcpy (own_buf, "W00");
     }
 }
-
+#if 0
 static void
 gdbserver_version (void)
 {
@@ -2328,7 +2336,7 @@ gdbserver_show_disableable (FILE *stream)
 	   "T stop reply packet\n"
 	   "  threads     \tAll of the above\n");
 }
-
+#endif
 
 #undef require_running
 #define require_running(BUF)			\
@@ -2449,8 +2457,9 @@ join_inferiors_callback (struct inferior_list_entry *entry)
 }
 
 int
-main (int argc, char *argv[])
+gdbserver_main(char *port, void *gdb_stub_thread)
 {
+#if 0
   int bad_attach;
   int pid;
   char *arg_end, *port;
@@ -2584,7 +2593,7 @@ main (int argc, char *argv[])
       gdbserver_usage (stderr);
       exit (1);
     }
-
+#endif
   initialize_inferiors ();
   initialize_async_io ();
   initialize_low ();
@@ -2594,6 +2603,7 @@ main (int argc, char *argv[])
   own_buf = xmalloc (PBUFSIZ + 1);
   mem_buf = xmalloc (PBUFSIZ);
 
+#if 0
   if (pid == 0 && *next_arg != NULL)
     {
       int i, n;
@@ -2647,6 +2657,12 @@ main (int argc, char *argv[])
       fprintf (stderr, "No program to debug.  GDBserver exiting.\n");
       exit (1);
     }
+#endif
+
+#ifdef __GENODE__
+  /* wait until the target's main thread is ready */
+  genode_wait_for_target_main_thread();
+#endif
 
   while (1)
     {
@@ -2655,6 +2671,15 @@ main (int argc, char *argv[])
       /* Be sure we're out of tfind mode.  */
       current_traceframe = -1;
 
+#ifdef __GENODE__
+      /* attach to child */
+	  myattach(GENODE_LWP_BASE);
+	  signal_pid = GENODE_LWP_BASE;
+	  struct process_info *pi = current_process();
+	  struct process_info_private *pip = pi->private;
+	  pip->gdb_stub_thread = gdb_stub_thread;
+#endif
+
       remote_open (port);
 
       if (setjmp (toplevel) != 0)
@@ -2755,6 +2780,7 @@ process_serial_event (void)
 
   i = 0;
   ch = own_buf[i++];
+  //if (debug_threads) printf("GDB command = %s\n", own_buf);
   switch (ch)
     {
     case 'q':
@@ -2844,7 +2870,9 @@ process_serial_event (void)
 		 gone.  */
 	      for_each_inferior (&all_processes,
 				 join_inferiors_callback);
+#if 0
 	      exit (0);
+#endif
 	    }
 	}
       break;
@@ -3076,7 +3104,11 @@ process_serial_event (void)
 	  return 0;
 	}
       else
+#if 0
 	exit (0);
+#else
+      return 0;
+#endif
 
     case 'T':
       {
@@ -3140,14 +3172,14 @@ process_serial_event (void)
       own_buf[0] = '\0';
       break;
     }
-
+  if (debug_threads) printf("GDBserver response = %s\n", own_buf);
   if (new_packet_len != -1)
     putpkt_binary (own_buf, new_packet_len);
   else
     putpkt (own_buf);
 
   response_needed = 0;
-
+#if 0
   if (!extended_protocol && have_ran && !target_running ())
     {
       /* In non-stop, defer exiting until GDB had a chance to query
@@ -3159,7 +3191,7 @@ process_serial_event (void)
 	  exit (0);
 	}
     }
-
+#endif
   if (exit_requested)
     return -1;
 
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 77f5dd6..897abed 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -664,8 +664,8 @@ struct emit_ops
 /* Returns the address of the get_raw_reg function in the IPA.  */
 CORE_ADDR get_raw_reg_func_addr (void);
 
-CORE_ADDR current_insn_ptr;
-int emit_error;
+extern CORE_ADDR current_insn_ptr;
+extern int emit_error;
 
 /* Version information, from version.c.  */
 extern const char version[];
