gdbserver Solaris [4/9] - gdbserver Solaris files

Pieter Maljaars pieter.maljaars@altenpts.nl
Fri Apr 23 15:12:00 GMT 2010


gdb/gdbserver ChangeLog entry:

2010-04-23  Pieter Maljaars  <pieter.maljaars@altenpts.nl>

        * solaris-i386-low.c: New file.
	* solaris-low.c: New file.
	* solaris-low.h: New file.
	* solaris-sparc-low.c: New file.
	* sol-thread-db.c: New file.

diff -upN src-orig/src/gdb/gdbserver/solaris-i386-low.c src/gdb/gdbserver/solaris-i386-low.c
--- src-orig/src/gdb/gdbserver/solaris-i386-low.c	1970-01-01 01:00:00.000000000 +0100
+++ src/gdb/gdbserver/solaris-i386-low.c	2010-04-08 15:41:51.000000000 +0200
@@ -0,0 +1,163 @@
+/* Solaris/i386 specific low level interface, for the remote server for GDB.
+   Copyright (C) 2010 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 "solaris-low.h"
+
+#include "i387-fp.h"
+
+
+extern int debug_threads;
+
+/* This module only supports access to the general purpose registers.  */
+
+#define i386_num_regs 16
+
+/* Mapping between the general-purpose registers in `struct user'
+   format and GDB's register array layout.  */
+static int i386_regmap[] = 
+{
+  EAX * 4, ECX * 4, EDX * 4, EBX * 4,
+  UESP * 4, EBP * 4, ESI * 4, EDI * 4,
+  EIP * 4, EFL * 4, CS * 4, SS * 4,
+  DS * 4, ES * 4, FS * 4, GS * 4
+};
+
+/* Defined in auto-generated file reg-sparc32.c.  */
+void init_registers_i386 (void);
+
+static int
+i386_cannot_store_register (int regno)
+{
+  return (regno >= i386_num_regs);
+}
+
+static int
+i386_cannot_fetch_register (int regno)
+{
+  return (regno >= i386_num_regs);
+}
+
+static CORE_ADDR
+i386_get_pc (struct regcache *regcache)
+{
+  unsigned long pc;
+
+  collect_register_by_name (regcache, "eip", &pc);
+
+  if (debug_threads)
+    fprintf (stderr, "stop pc (before any decrement) is %08lx\n", pc);
+  return (CORE_ADDR) pc;
+}
+
+static void
+i386_set_pc (struct regcache *regcache, CORE_ADDR newpc)
+{
+  if (debug_threads)
+    fprintf (stderr, "set pc to %08lx\n", (long) newpc);
+  supply_register_by_name (regcache, "eip", &newpc);
+}
+
+static int
+i386_breakpoint_at (CORE_ADDR pc)
+{
+  unsigned char c;
+
+  read_inferior_memory (pc, &c, 1);
+  if (c == 0xCC)
+    return 1;
+
+  return 0;
+}
+
+static void
+i386_supply_gregset (struct regcache *regcache, const void *gregs)
+{
+  int i;
+  const gdb_byte *regs = gregs;
+
+  for (i = 0; i < i386_num_regs; i++)
+    supply_register (regcache, i, ((char *) regs) + i386_regmap[i]);
+}
+
+static void
+i386_supply_fpregset (struct regcache *regcache, const void *fpregs)
+{
+  i387_fsave_to_cache (regcache, fpregs);
+}
+
+static void
+i386_collect_gregset (struct regcache *regcache, void *gregs)
+{
+  int i;
+
+  for (i = 0; i < i386_num_regs; i++)
+    collect_register (regcache, i, ((char *) gregs) + i386_regmap[i]);
+}
+
+static void
+i386_collect_fpregset (struct regcache *regcache, void *fpregs)
+{
+  i387_cache_to_fsave (regcache, fpregs);
+}
+
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs)
+{
+  i386_supply_gregset (regcache, gregs);
+}
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs)
+{
+  i386_supply_fpregset (regcache, fpregs);
+}
+
+void
+fill_gregset (struct regcache *regcache, gdb_gregset_t *gregs, int regno)
+{
+  i386_collect_gregset (regcache, gregs);
+}
+
+void
+fill_fpregset (struct regcache *regcache, prfpregset_t *fpregs, int regnum)
+{
+  i386_collect_fpregset (regcache, fpregs);
+}
+
+static const unsigned char i386_breakpoint[] = { 0xCC };
+#define i386_breakpoint_len 1
+
+struct solaris_target_ops the_low_target = {
+  init_registers_i386,
+  i386_num_regs,
+  /* No regmap needs to be provided since this impl. doesn't use USRREGS.  */
+  NULL,
+  i386_cannot_fetch_register,
+  i386_cannot_store_register,
+  i386_get_pc,
+  i386_set_pc,
+  (const unsigned char *) i386_breakpoint,
+  i386_breakpoint_len,
+  NULL,
+  0,
+  i386_breakpoint_at,
+  NULL, NULL, NULL, NULL, /* watchpoint functions */ 
+  0
+};
diff -upN src-orig/src/gdb/gdbserver/solaris-low.c src/gdb/gdbserver/solaris-low.c
--- src-orig/src/gdb/gdbserver/solaris-low.c	1970-01-01 01:00:00.000000000 +0100
+++ src/gdb/gdbserver/solaris-low.c	2010-04-08 15:41:50.000000000 +0200
@@ -0,0 +1,1006 @@
+/* Low level interface to the proc filesystem, for the remote server for GDB.
+   Copyright (C) 2009 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 "solaris-low.h"
+#include "gdb_proc_service.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <pwd.h>
+
+
+struct string_map
+{
+  int num;
+  char *str;
+};
+
+static int sol_thread_alive (ptid_t ptid);
+
+/* This is used in remote-utils.c */
+int using_threads = 1;
+
+static int new_inferior;
+
+/* This is a cached copy of the pid/waitstatus of the last event
+   returned by solaris_wait().  This information is returned by
+   get_last_target_status().  */
+static ptid_t target_last_wait_ptid;
+static struct target_waitstatus target_last_waitstatus;
+
+extern ptid_t do_attach (ptid_t ptid);
+extern void do_detach (int signo);
+extern int procfs_stop_process (ptid_t ptid);
+extern ptid_t procfs_wait (ptid_t ptid, struct target_waitstatus *status); 
+extern void procfs_resume (ptid_t, int, enum target_signal);
+extern int procfs_thread_alive (ptid_t ptid);
+extern int procfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite);
+extern void procfs_fetch_registers (struct regcache*, int);
+extern void procfs_store_registers (struct regcache*, int);
+extern void procfs_kill_inferior (ptid_t ptid);
+extern void procfs_set_exec_trap (void);
+extern void procfs_init_inferior (int pid);
+extern char *procfs_pid_to_str (ptid_t);
+
+extern void _initialize_proc_events (void);
+
+extern struct thread_info * find_thread_ptid (ptid_t gdb_id);
+
+/* Return the libthread_db error string associated with ERRCODE.  If
+   ERRCODE is unknown, return an appropriate message.  */
+extern char *thread_db_err_str (td_err_e err);
+
+/* Forward declarations  */
+void solaris_fetch_registers (struct regcache *regcache, int regno);
+
+
+/* Return the the libthread_db state string assicoated with STATECODE.
+   If STATECODE is unknown, return an appropriate message.  */
+static char *
+td_state_string (td_thr_state_e statecode)
+{
+  static struct string_map td_thr_state_table[] =
+  {
+    { TD_THR_ANY_STATE, "any state" },
+    { TD_THR_UNKNOWN, "unknown" },
+    { TD_THR_STOPPED, "stopped" },
+    { TD_THR_RUN, "run" },
+    { TD_THR_ACTIVE, "active" },
+    { TD_THR_ZOMBIE, "zombie" },
+    { TD_THR_SLEEP, "sleep" },
+    { TD_THR_STOPPED_ASLEEP, "stopped asleep" }
+  };
+  const int td_thr_state_table_size =
+    sizeof td_thr_state_table / sizeof (struct string_map);
+  int i;
+  static char buf[50];
+
+  for (i = 0; i < td_thr_state_table_size; i++)
+    if (td_thr_state_table[i].num == statecode)
+      return td_thr_state_table[i].str;
+
+  sprintf (buf, "Unknown libthread_db state code: %d", statecode);
+
+  return buf;
+}
+
+/* Get the thread ID from hte current selected inferior (the current
+   thread).  */
+static ptid_t
+current_inferior_ptid (void)
+{
+  return ((struct inferior_list_entry*) current_inferior)->id;
+}
+
+/* Convert a POSIX or Solaris thread ID into a LWP ID.  If THREAD_ID
+   doesn't exist, that's an error.  If it's an inactive thread, return
+   DEFAULT_LPW.
+
+   NOTE: This function probably shouldn't call error().  */
+
+ptid_t
+thread_to_lwp (ptid_t thread_id, int default_lwp)
+{
+  td_thrinfo_t ti;
+  td_thrhandle_t th;
+  td_err_e val;
+  struct process_info_private *proc;
+
+  if (is_lwp (thread_id))
+    return thread_id;		/* It's already an LWP ID.  */
+
+  /* It's a thread.  Convert to LWP.  */
+
+  if (!current_process ())
+    return ptid_build (ptid_get_pid (thread_id),
+		ptid_get_tid (thread_id), 0);
+
+  proc = current_process ()->private;
+
+  if (!proc->thread_agent)
+    return ptid_build (ptid_get_pid (thread_id),
+		ptid_get_tid (thread_id), 0);
+
+  val = td_ta_map_id2thr (proc->thread_agent, GET_THREAD (thread_id), &th);
+  if (val == TD_NOTHR)
+    return pid_to_ptid (-1);	/* Thread must have terminated.  */
+  else if (val != TD_OK)
+    error ("thread_to_lwp: td_ta_map_id2thr %s", td_err_string (val));
+
+  val = td_thr_get_info (&th, &ti);
+  if (val == TD_NOTHR)
+    return pid_to_ptid (-1);	/* Thread must have terminated.  */
+  else if (val != TD_OK)
+    error ("thread_to_lwp: td_thr_get_info: %s", td_err_string (val));
+
+  if (ti.ti_state != TD_THR_ACTIVE)
+    {
+      if (default_lwp != -1)
+	return pid_to_ptid (default_lwp);
+      error ("thread_to_lwp: thread state not active: %s",
+	     td_state_string (ti.ti_state));
+    }
+
+  return BUILD_LWP (ti.ti_lid, ptid_get_pid (thread_id));
+}
+
+/* Convert an LWP ID into a POSIX or Solaris thread ID.  If LWP_ID
+   doesn't exists, that's an error.
+
+   NOTE: This function probably shouldn't call error().  */
+
+ptid_t
+lwp_to_thread (ptid_t lwp)
+{
+  td_thrinfo_t ti;
+  td_thrhandle_t th;
+  td_err_e val;
+  struct process_info_private *proc;
+
+  if (is_thread (lwp))
+    return lwp;			/* It's already a thread ID.  */
+
+  /* It's an LWP.  Convert it to a thread ID.  */
+
+  if (!current_process ())
+    return ptid_build (ptid_get_pid (lwp),
+		0, ptid_get_lwp (lwp));
+
+  proc = current_process ()->private;
+
+  if (!proc->thread_agent)
+    return ptid_build (ptid_get_pid (lwp),
+		0, ptid_get_lwp (lwp));
+
+  if (!sol_thread_alive (lwp))
+    return pid_to_ptid (-1);	/* Must be a defunct LPW.  */
+
+  val = td_ta_map_lwp2thr (proc->thread_agent, GET_LWP (lwp), &th);
+  if (val == TD_NOTHR)
+    return pid_to_ptid (-1);	/* Thread must have terminated.  */
+  else if (val != TD_OK)
+    error ("lwp_to_thread: td_ta_map_lwp2thr: %s.", td_err_string (val));
+
+  val = td_thr_validate (&th);
+  if (val == TD_NOTHR)
+    return lwp;			/* Unknown to libthread; just return LPW,  */
+  else if (val != TD_OK)
+    error ("lwp_to_thread: td_thr_validate: %s.", td_err_string (val));
+
+  val = td_thr_get_info (&th, &ti);
+  if (val == TD_NOTHR)
+    return pid_to_ptid (-1);	/* Thread must have terminated.  */
+  else if (val != TD_OK)
+    error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
+
+  return BUILD_THREAD (ti.ti_tid, ptid_get_pid (lwp));
+}
+
+/* Add a process to the common process list, and sets its private
+   data.  */
+
+static struct process_info *
+solaris_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  /* Is this hte first process?  If so, then set the arch.  */
+  if (all_processes.head == NULL)
+    new_inferior = 1;
+
+  proc = add_process (pid, attached);
+  proc->private = xcalloc (1, sizeof (*proc->private));
+
+  return proc;
+}
+
+/* Remove a process from the common process list,
+   also freeing all private data.  */
+
+static void
+solaris_remove_process (struct process_info *process)
+{
+  free (process->private);
+  remove_process (process);
+}
+
+static int
+any_thread_of (struct inferior_list_entry *entry, void *args)
+{
+  int *pid_p = args;
+
+  if (ptid_get_pid (entry->id) == *pid_p)
+    return 1;
+
+  return 0;
+}
+
+static ptid_t
+pid_to_lwp (int pid)
+{    
+  struct thread_info * ti;
+
+  ti = (struct thread_info *) 
+    find_inferior (&all_threads, any_thread_of, &pid);
+      
+  if (ti != NULL)
+    return ((struct inferior_list_entry*) ti)->id;
+
+  return null_ptid;
+}
+
+/* Return the cached copy of the last pid/waitstatus returned by
+   solaris_wait().  */
+void
+get_last_target_status (ptid_t *ptidp, struct target_waitstatus *status)
+{
+  *ptidp = target_last_wait_ptid;
+  *status = target_last_waitstatus;
+}
+
+
+/* Return true if PTID is still active in the inferior.  */
+
+static int
+sol_thread_alive (ptid_t ptid)
+{
+  if (is_thread (ptid))
+    {
+      /* It's a (user-level) thread.  */
+      td_err_e val;
+      td_thrhandle_t th;
+      int pid;
+      struct process_info_private *proc = current_process ()->private;
+
+      pid = GET_THREAD (ptid);
+      if ((val = td_ta_map_id2thr (proc->thread_agent, pid, &th)) != TD_OK)
+	return 0;       /* Thread not found.  */
+      if ((val = td_thr_validate (&th)) != TD_OK)
+	return 0;       /* Thread not valid.  */
+      return 1;         /* Known thread.  */
+    }
+  else
+    {
+      /* pass the request on to procfs.  */
+      return procfs_thread_alive (ptid);
+    }
+}
+
+
+static int
+solaris_create_inferior (char *program, char **allargs)
+{
+  int pid;
+
+  pid = fork ();
+
+  if (pid < 0)
+    perror_with_name ("fork");
+
+  if (pid == 0)
+    {
+      // trace me
+      procfs_set_exec_trap ();
+
+      setpgid (0,0);
+
+      execv (program, allargs);
+      if (errno == ENOENT)
+	execvp (program, allargs);
+
+      // If we get here, it's an error. 
+      fprintf(stderr, "Cannot exec %s: %s.\n", program,
+	  strerror (errno));
+      fflush (stderr);
+      _exit (0177);
+    }
+
+  procfs_init_inferior (pid);
+  solaris_add_process (pid, 0 /* not attached */);
+  
+  inferior_ptid = ptid_build (pid, pid, 0);
+  add_thread (inferior_ptid, NULL);
+
+  cont_thread = inferior_ptid;
+
+  return pid;
+}
+
+
+int
+solaris_attach (unsigned long pid)
+{
+  inferior_ptid = do_attach (pid_to_ptid (pid));
+  cont_thread = inferior_ptid;
+
+  add_thread (inferior_ptid, NULL);
+
+  solaris_add_process (pid, 1 /* attached */);
+
+  return 0;
+}
+
+static int
+solaris_kill (int pid)
+{ 
+  ptid_t ptid;
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  ptid = pid_to_lwp (pid);
+  if (ptid_equal (ptid, null_ptid) || process == NULL)
+    return -1;
+  
+  procfs_kill_inferior (ptid);
+
+  clear_inferiors ();
+  inferior_ptid = null_ptid;
+
+  solaris_remove_process (process);
+
+  return 0;
+}
+
+static int
+solaris_detach (int pid)
+{
+  ptid_t ptid;
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  ptid = pid_to_lwp (pid);
+  if (ptid_equal (ptid, null_ptid) || process == NULL)
+    return -1;
+
+  delete_all_breakpoints ();
+
+#ifndef __sparc__
+  /* needed on x86, not on SPARC  */
+  regcache_invalidate_one (find_inferior_id (&all_threads, inferior_ptid));
+#endif
+
+  inferior_ptid = ptid;
+  
+  do_detach (0);
+
+  clear_inferiors ();
+  inferior_ptid = null_ptid;
+
+  solaris_remove_process (process);
+
+  return 0;
+}
+
+static void
+solaris_join (int pid)
+{
+  ptid_t ptid;
+  struct target_waitstatus *ourstatus = NULL;
+
+  ptid = pid_to_lwp (pid);
+  procfs_wait (ptid, ourstatus);
+}
+
+/* Return nonzero if the given thread is still alive.  */
+static int
+solaris_thread_alive (ptid_t ptid)
+{
+  return sol_thread_alive (ptid);
+}
+
+struct thread_resume_array
+{
+  struct thread_resume *resume;
+  size_t n;
+};
+
+static void
+solaris_resume (struct thread_resume *resume_info, size_t n)
+{
+  struct thread_info *saved_inferior;
+  ptid_t ptid;
+  int step = resume_continue;
+
+
+  saved_inferior = current_inferior;
+  
+  if (n > 1)
+    ptid = minus_one_ptid;
+  else
+    ptid = resume_info[0].thread;
+
+  step = (resume_info[0].kind == resume_step);
+
+  if (debug_threads)
+    printf("Resuming process [%d, %ld, %ld] (%d, signal %d)\n", 
+	      ptid_get_pid (ptid), ptid_get_lwp (ptid), ptid_get_tid (ptid),
+	      step, resume_info[0].sig);
+  
+  inferior_ptid = thread_to_lwp (inferior_ptid, 		
+      ptid_get_pid (current_inferior_ptid ()));
+  if (ptid_get_pid (inferior_ptid) == -1)
+    inferior_ptid = procfs_first_available ();
+
+  if (ptid_get_pid (ptid) != -1)
+    {
+      ptid_t save_ptid = ptid;
+
+      ptid = thread_to_lwp (ptid, -2);
+      if (ptid_get_pid (ptid) == -2)		/* Inactive thread.  */
+	error ("This version of Solaris can't start inactive threads.");
+      if (debug_threads && ptid_get_pid (ptid) == -1)
+	warning ("Specified thread %ld seems to have terminated",
+		 GET_THREAD (save_ptid));
+    }
+
+#ifndef __sparc__
+  /* needed on x86, not on SPARC  */
+  regcache_invalidate_one (find_inferior_id (&all_threads, inferior_ptid));
+#endif
+
+  procfs_resume (ptid, step, resume_info[0].sig);
+
+  current_inferior = saved_inferior;
+}
+
+/* Wait for the inferior process to change state.
+   STATUS will be filled in with a response code to send to GDB.
+   Returns the signal which caused the process to stop. */
+static ptid_t
+solaris_wait (ptid_t ptid,
+    		struct target_waitstatus *ourstatus, int target_options)
+{
+  ptid_t rtnval, save_ptid, event_ptid;
+
+  if (debug_threads)
+    printf("solaris_wait: [%s]\n", target_pid_to_str (ptid));
+
+
+  save_ptid = inferior_ptid;
+
+retry:
+  
+  inferior_ptid = thread_to_lwp (inferior_ptid, 
+      ptid_get_pid (current_inferior_ptid()));
+  if (ptid_get_pid (inferior_ptid) == -1)
+    inferior_ptid = procfs_first_available ();
+
+  if (ptid_get_pid (cont_thread) != -1)
+    {
+      ptid_t save_ptid = cont_thread;
+
+      cont_thread = thread_to_lwp (cont_thread, -2);
+      if (ptid_get_pid (cont_thread) == -2)		/* Inactive thread.  */
+        error ("This version of Solaris can't start inactive threads.");
+      if (debug_threads && ptid_get_pid (cont_thread) == -1)
+        warning ("Specified thread %ld seems to have terminated",
+         GET_THREAD (save_ptid));
+    }
+
+  event_ptid = procfs_wait (cont_thread, ourstatus);
+
+  rtnval = event_ptid;
+  inferior_ptid = event_ptid;
+
+  current_inferior = (struct thread_info *)find_inferior_id (
+ 			&all_threads, event_ptid);
+
+  if (ourstatus->kind != TARGET_WAITKIND_EXITED)
+    {
+ 
+      if (current_inferior == NULL)
+        {
+	  /* one thread has exited.  */
+	  struct thread_info *old_thread = NULL;
+
+	  current_inferior = (struct thread_info *) all_threads.head;
+	  if (debug_threads)
+	    printf("Current inferior is now %s\n",
+		procfs_pid_to_str (current_inferior_ptid()));
+
+	  /* remove thread, LWP is already removed.  */
+	  event_ptid = lwp_to_thread (event_ptid);
+
+	  if (!ptid_equal (event_ptid, minus_one_ptid) &&
+	      is_thread (event_ptid))
+	    {
+	      old_thread = find_thread_ptid (event_ptid);
+	      if (old_thread != NULL)
+		remove_thread (old_thread);
+	    }
+
+	  procfs_resume (minus_one_ptid, 0, TARGET_SIGNAL_0);
+
+	  /* wait for the next event.  */
+	  goto retry;
+	}
+
+
+      /* Map the LWP of interest back to the appropriate thread ID.  */
+      event_ptid = lwp_to_thread (event_ptid);
+
+      if (ptid_get_pid (event_ptid) == -1)
+	event_ptid = save_ptid;
+
+      /* See if we have a new thread.  */
+      if (is_thread (event_ptid)
+	  && !ptid_equal (event_ptid, save_ptid)
+	  && (find_thread_ptid (event_ptid) == NULL))	 
+        {
+	  add_thread (event_ptid, NULL);
+        
+	  /* Architecture-specific setup after inferior is running.
+	     This needs to happen after we have attached to the inferior
+	     and it is stopped for the first time, but before we access
+	     any inferior registers.  */
+	  if (new_inferior)
+	    {
+	      the_low_target.arch_setup ();
+	      new_inferior = 0;
+	    }
+        }
+
+#ifdef __sparc__
+      struct regcache *regcache;
+      regcache = get_thread_regcache (current_inferior, 1);
+      solaris_fetch_registers (regcache, -1);
+#endif
+    }
+  else
+    {
+      /* target exited, so clean up.  */
+      while (all_threads.head != NULL)
+        remove_thread ((struct thread_info *) all_threads.head);
+    }
+
+  // save the last state
+  target_last_wait_ptid = event_ptid;
+  target_last_waitstatus = *ourstatus;
+
+  return rtnval;
+}
+
+void
+solaris_fetch_registers (struct regcache *regcache, int regno)
+{  
+  if (!is_thread (inferior_ptid))
+    {
+      /* It's an LWP; pass the request on to procfs.  */
+      procfs_fetch_registers (regcache, regno);
+      return;
+    }
+  
+  /* Solaris thread: convert INFERIOR_PTID into a td_thrhandle_t.  */
+  long thread;
+  td_err_e val;
+  td_thrhandle_t thandle;
+  prgregset_t gregset;
+  prfpregset_t fpregset;
+  gdb_gregset_t *gregset_p = &gregset;
+  gdb_fpregset_t *fpregset_p = &fpregset;
+  struct process_info_private *proc = current_process ()->private;
+
+  thread = GET_THREAD (inferior_ptid);
+  if (thread == 0)
+    error ("sol_fetch_registers: thread == 0");
+
+  val = td_ta_map_id2thr (proc->thread_agent, thread, &thandle);
+  if (val != TD_OK)
+    error ("sol_fetch_registers: td_ta_map_id2thr: %s",
+	   td_err_string (val));
+
+  /* Get the general-purpose registers.  */
+
+  val = td_thr_getgregs (&thandle, gregset);
+  if (val != TD_OK && val != TD_PARTIALREG)
+    error ("sol_fetch_registers: td_thr_getgregs %s",
+	   td_err_string (val));
+
+  /* For SPARC, TD_PARTIALREG means that only %i0...%i7, %l0..%l7, %pc
+     and %sp are saved (by a thread context switch).  */
+
+  /* And, now the floating-point registers.  */
+
+  val = td_thr_getfpregs (&thandle, &fpregset);
+  if (val != TD_OK && val != TD_NOFPREGS)
+    error ("sol_fetch_registers: td_thr_getfpregs %s",
+	   td_err_string (val));
+
+  /* Note that we must call supply_gregset and supply_fpregset *after*
+     calling the td routines because the td routines call ps_lget*
+     which affect the values stored in the registers array.  */
+
+  supply_gregset (regcache, (const gdb_gregset_t *) gregset_p);
+  supply_fpregset (regcache, (const gdb_fpregset_t *) fpregset_p);
+}
+
+void
+solaris_store_registers (struct regcache *regcache, int regno)
+{
+  if (!is_thread (inferior_ptid))
+    {
+      /* It's an LWP; pass the request on to procfs.  */
+      procfs_store_registers (regcache, regno);
+      return;
+    }
+  
+  /* Solaris thread: convert INFERIOR_PTID into a td_thrhandle_t.  */
+  long thread;
+  td_err_e val;
+  td_thrhandle_t thandle;
+  prgregset_t gregset;
+  prfpregset_t fpregset;
+  struct process_info_private *proc = current_process ()->private;
+
+  thread = GET_THREAD (inferior_ptid);
+
+  val = td_ta_map_id2thr (proc->thread_agent, thread, &thandle);
+  if (val != TD_OK)
+    error ("sol_store_registers: td_ta_map_id2thr %s",
+	   td_err_string (val));
+
+  if (regno != -1)
+    {
+      /* Not writing all the registers.  */
+      char old_value[MAX_REGISTER_SIZE];
+
+      /* Save new register value.  */
+      collect_register (regcache, regno, old_value);
+
+      val = td_thr_getgregs (&thandle, gregset);
+      if (val != TD_OK)
+	error ("sol_store_registers: td_thr_getgregs %s",
+	       td_err_string (val));
+      val = td_thr_getfpregs (&thandle, &fpregset);
+      if (val != TD_OK)
+	error ("sol_store_registers: td_thr_getfpregs %s",
+	       td_err_string (val));
+
+      /* Restore new register value.  */
+      supply_register (regcache, regno, old_value);
+    }
+
+  fill_gregset (regcache, (gdb_gregset_t *) &gregset, regno);
+  fill_fpregset (regcache, (gdb_fpregset_t *) &fpregset, regno);
+
+  val = td_thr_setgregs (&thandle, gregset);
+  if (val != TD_OK)
+    error ("sol_store_registers: td_thr_setgregs %s",
+	   td_err_string (val));
+  val = td_thr_setfpregs (&thandle, &fpregset);
+  if (val != TD_OK)
+    error ("sol_store_registers: td_thr_setfpregs %s",
+	   td_err_string (val));
+}
+
+/* Copy LEN bytes from inferior's memory starting at MEMADDR
+   to debugger memory starting at MYADDR.  */
+
+static int
+solaris_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+  int retval;
+  
+  if (is_thread (inferior_ptid) || !procfs_thread_alive (inferior_ptid))
+    inferior_ptid = procfs_first_available ();
+
+  retval = procfs_xfer_memory (memaddr, myaddr, len, 0 /*read*/); 
+  if (retval != len)
+    return retval;
+
+  return 0;
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.
+   On failure (cannot write the inferior)
+   returns the value of errno.  */
+
+static int
+solaris_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+  int retval;
+
+  if (is_thread (inferior_ptid) || !procfs_thread_alive (inferior_ptid))
+    inferior_ptid = procfs_first_available ();
+
+  retval = procfs_xfer_memory (memaddr, (unsigned char *)myaddr, 
+      				len, 1 /*write*/); 
+  if (retval != len)
+    return retval;
+
+  return 0;
+}
+
+
+static void
+solaris_look_up_symbols (void)
+{
+  struct process_info *proc = current_process ();
+
+  if (proc->private->thread_db_active)
+    return;
+
+  proc->private->thread_db_active = thread_db_init (0);
+}
+
+static void
+solaris_request_interrupt (void)
+{
+  procfs_stop_process (inferior_ptid);
+}
+
+/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
+   to debugger memory starting at MYADDR.  */
+
+static int
+solaris_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
+{
+  char filename[MAX_PROC_NAME_SIZE];
+  int fd, n;
+
+  snprintf (filename, sizeof filename, "/proc/%d/auxv", 
+      ptid_get_pid (inferior_ptid));
+
+  fd = open (filename, O_RDONLY);
+  if (fd < 0)
+    return -1;
+
+  if (offset != (CORE_ADDR) 0
+      && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+    n = -1;
+  else
+    n = read (fd, myaddr, len);
+
+  close (fd);
+
+  return n;
+}
+
+/* These watchpoint related wrapper functions simply pass on the function call
+   if the target has registered a corresponding function.  */
+
+static int
+solaris_insert_point (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.insert_point != NULL)
+    return the_low_target.insert_point (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+solaris_remove_point (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.remove_point != NULL)
+    return the_low_target.remove_point (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+solaris_stopped_by_watchpoint (void)
+{
+  if (the_low_target.stopped_by_watchpoint != NULL)
+    return the_low_target.stopped_by_watchpoint ();
+  else
+    return 0;
+}
+
+static CORE_ADDR
+solaris_stopped_data_address (void)
+{
+  if (the_low_target.stopped_data_address != NULL)
+    return the_low_target.stopped_data_address ();
+  else
+    return 0;
+}
+
+static void
+show_process (int pid, const char *username, struct buffer *buffer)
+{	      
+  char pathname[128];
+  FILE *f;
+  struct psinfo ps;
+
+  sprintf (pathname, "/proc/%d/psinfo", pid);
+
+  if ((f = fopen (pathname, "rb")) != NULL) 
+    {
+      size_t len = fread (&ps, 1, sizeof (struct psinfo) - 1, f);
+      fclose (f);
+
+      if (len > 0)
+	{
+	  buffer_xml_printf (buffer,
+	      "<item>"
+	      "<column name=\"pid\">%d</column>"
+	      "<column name=\"user\">%s</column>"
+	      "<column name=\"command\">%s</column>",
+	      pid,
+	      username,
+	      ps.pr_psargs
+	      );
+	  buffer_xml_printf (buffer, "</item>");
+	}
+    }
+}
+
+/* Return a list of all processes, with pid and username.  */
+static int
+solaris_qxfer_osdata (const char *annex,
+		    unsigned char *readbuf, unsigned const char *writebuf,
+		    CORE_ADDR offset, int len)
+{
+  static const char *buf;
+  static long len_avail = -1;
+  static struct buffer buffer;
+
+  DIR *dirp;
+
+  if (!strcmp (annex, "processes") == 0)
+    return 0;
+
+  if (!readbuf || writebuf)
+    return 0;
+
+  if (offset == 0)
+    {
+      if (len_avail != -1 && len_avail != 0)
+	buffer_free (&buffer);
+      len_avail = 0;
+      buf = NULL;
+      buffer_init (&buffer);
+      buffer_grow_str (&buffer, "<osdata type=\"processes\">");
+
+      dirp = opendir ("/proc");
+      if (dirp)
+        {
+	  struct dirent *dp;
+	  while ((dp = readdir (dirp)) != NULL)
+	    {
+	      struct stat statbuf;
+	      char procentry[sizeof ("/proc/4294967295")];
+
+	      if (!isdigit (dp->d_name[0])
+		  || strlen (dp->d_name) > sizeof ("4294967295") - 1)
+		  continue;
+
+	      sprintf (procentry, "/proc/%s", dp->d_name);
+	      if (stat (procentry, &statbuf) == 0
+		  && S_ISDIR (statbuf.st_mode))
+	        {
+		  int pid = (int) strtoul (dp->d_name, NULL, 10);
+
+		  struct passwd *entry = getpwuid (statbuf.st_uid);
+		  show_process (pid, entry ? entry->pw_name : "?", &buffer);
+		}
+	    }
+
+	  closedir (dirp);
+	}
+      buffer_grow_str0 (&buffer, "</osdata>\n");
+      buf = buffer_finish (&buffer);
+      len_avail = strlen (buf);      
+    }
+
+  if (offset >= len_avail)
+    {
+      /* Done.  Get rid of the data.  */
+      buffer_free (&buffer);
+      buf = NULL;
+      len_avail = 0;
+      return 0;
+    }
+
+  if (len > len_avail - offset)
+    len = len_avail - offset;
+  memcpy (readbuf, buf + offset, len);
+
+  return len;
+}
+    
+
+static int
+solaris_supports_multi_process (void)
+{
+  return 1;
+}
+
+static int
+solaris_thread_lwp_id (ptid_t ptid, char *buf)
+{
+  ptid_t lwp = thread_to_lwp (ptid, -2);
+
+  if (GET_PID (lwp) != -1 && GET_PID (lwp) != -2)
+    write_ptid (buf, lwp);
+
+  return 0;
+}
+
+
+static struct target_ops solaris_target_ops = {
+  solaris_create_inferior,
+  solaris_attach,
+  solaris_kill,
+  solaris_detach,
+  solaris_join,
+  solaris_thread_alive,
+  solaris_resume,
+  solaris_wait,
+  solaris_fetch_registers,
+  solaris_store_registers,
+  solaris_read_memory,
+  solaris_write_memory,
+  solaris_look_up_symbols,
+  solaris_request_interrupt,
+  solaris_read_auxv,
+  solaris_insert_point,
+  solaris_remove_point,
+  solaris_stopped_by_watchpoint,
+  solaris_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, //  qxfer_spu,
+  hostio_last_error_from_errno,
+  solaris_qxfer_osdata,
+  NULL, //  qxfer_siginfo,
+  NULL, //  supports_non_stop,
+  NULL, //  async,
+  NULL, //  start_non_stop,
+  solaris_supports_multi_process,
+  NULL,	//  handle_monitor_command
+  NULL, //  core_of_thread
+  solaris_thread_lwp_id,
+};
+
+void
+initialize_low (void)
+{
+  set_target_ops (&solaris_target_ops);
+  set_breakpoint_data (the_low_target.breakpoint,
+               the_low_target.breakpoint_len);
+  _initialize_proc_events ();
+}
diff -upN src-orig/src/gdb/gdbserver/solaris-low.h src/gdb/gdbserver/solaris-low.h
--- src-orig/src/gdb/gdbserver/solaris-low.h	1970-01-01 01:00:00.000000000 +0100
+++ src/gdb/gdbserver/solaris-low.h	2010-04-08 15:41:51.000000000 +0200
@@ -0,0 +1,139 @@
+/* Internal interfaces for the Solaris specific target code for gdbserver.
+   Copyright (C) 2010 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 <thread_db.h>
+#include <procfs.h>
+
+#include "gdb_proc_service.h"
+
+/* Default definitions.  */
+
+#define MAX_REGISTER_SIZE 16
+
+#define GET_PID(ptid)		ptid_get_pid (ptid)
+#define GET_LWP(ptid)		ptid_get_lwp (ptid)
+#define GET_THREAD(ptid)	ptid_get_tid (ptid)
+
+#define is_lwp(ptid)		(GET_LWP (ptid) != 0)
+#define is_thread(ptid)		(GET_THREAD (ptid) != 0)
+
+#define BUILD_LWP(lwp, pid)	ptid_build (pid, lwp, 0)
+#define BUILD_THREAD(tid, pid)	ptid_build (pid, 0, tid)
+
+#define pid_of(proc) ptid_get_pid ((proc)->head.id)
+#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
+
+#define get_process(inf) ((struct process_info *)(inf))
+#define get_thread_process(thr) (get_process (inferior_target_data (thr)))
+
+/* format strings for /proc paths */
+# ifndef CTL_PROC_NAME_FMT
+#  define MAIN_PROC_NAME_FMT   "/proc/%d"
+#  define CTL_PROC_NAME_FMT    "/proc/%d/ctl"
+#  define AS_PROC_NAME_FMT     "/proc/%d/as"
+#  define MAP_PROC_NAME_FMT    "/proc/%d/map"
+#  define STATUS_PROC_NAME_FMT "/proc/%d/status"
+#  define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/8096/lstatus")
+# endif
+/* the name of the proc status struct depends on the implementation */
+
+#ifndef GDB_GREGSET_T
+#define GDB_GREGSET_T gregset_t
+#endif
+
+#ifndef GDB_FPREGSET_T
+#define GDB_FPREGSET_T fpregset_t
+#endif
+
+typedef GDB_GREGSET_T gdb_gregset_t;
+typedef GDB_FPREGSET_T gdb_fpregset_t;
+
+typedef pstatus_t   gdb_prstatus_t;
+
+struct process_info_private
+{
+  /* True if this process has loaded thread_db, and it is active.  */
+  int thread_db_active;
+
+  /* Structure that identifies the child proces for the
+     <proc_service.h> interface.  */
+  struct ps_prochandle proc_handle;
+
+  /* Connection to the libthread_db library.  */
+  td_thragent_t *thread_agent;
+};
+
+struct solaris_target_ops
+{
+  /* Architecture-specific setup.  */
+  void (*arch_setup) (void);
+
+  /* The number of target registers.  */
+  int num_regs;
+  int *regmap;
+  int (*cannot_fetch_register) (int);
+
+  /* Returns 0 if we can store the register, 1 if we can not
+     store the register, and 2 if failure to store the register
+     is acceptable.  */
+  int (*cannot_store_register) (int);
+  CORE_ADDR (*get_pc) (struct regcache *regcache);
+  void (*set_pc) (struct regcache *regcach, CORE_ADDR newpc);
+  const unsigned char *breakpoint;
+  int breakpoint_len;
+  CORE_ADDR (*breakpoint_reinsert_addr) (void);
+
+
+  int decr_pc_after_break;
+  int (*breakpoint_at) (CORE_ADDR pc);
+
+  /* Watchpoint related functions.  See target.h for comments.  */
+  int (*insert_point) (char type, CORE_ADDR addr, int len);
+  int (*remove_point) (char type, CORE_ADDR addr, int len);
+  int (*stopped_by_watchpoint) (void);
+  CORE_ADDR (*stopped_data_address) (void);
+
+  /* Whether to left-pad registers for PEEKUSR/POKEUSR if they are smaller
+     than an xfer unit.  */
+  int left_pad_xfer;
+};
+
+#define td_err_string thread_db_err_str
+
+struct target_waitstatus;
+
+ptid_t inferior_ptid;
+
+extern struct solaris_target_ops the_low_target;
+extern struct inferior_list all_processes;
+
+ptid_t lwp_to_thread (ptid_t lwp);
+
+int thread_db_init (int use_events);
+int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
+			       CORE_ADDR load_module, CORE_ADDR *address);
+
+void get_last_target_status (ptid_t *ptidp, struct target_waitstatus *status);
+
+extern ptid_t procfs_first_available (void);
+
+extern void supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs);
+extern void supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs);
+extern void fill_gregset (struct regcache *regcache, gdb_gregset_t *gregs, int regno);
+extern void fill_fpregset (struct regcache *regcache, gdb_fpregset_t *fpregs, int regno);
+
diff -upN src-orig/src/gdb/gdbserver/solaris-sparc-low.c src/gdb/gdbserver/solaris-sparc-low.c
--- src-orig/src/gdb/gdbserver/solaris-sparc-low.c	1970-01-01 01:00:00.000000000 +0100
+++ src/gdb/gdbserver/solaris-sparc-low.c	2010-04-08 15:41:51.000000000 +0200
@@ -0,0 +1,238 @@
+/* Solaris SPARC specific low level interface, for the remote server for GDB.
+   Copyright (C) 2010 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 "solaris-low.h"
+
+/* The stack pointer is offset from the stack frame by a BIAS of 2047
+   (0x7ff) for 64-bit code. BIAS is likely to be defined on SPARC
+   hosts, so undefine it first.  */
+#undef BIAS
+#define BIAS 2047
+
+
+#define INSN_SIZE 4
+
+#define SPARC_R_REGS_NUM 32
+#define SPARC_F_REGS_NUM 32
+#define SPARC_CONTROL_REGS_NUM 8
+
+#define sparc_num_regs (SPARC_R_REGS_NUM + SPARC_F_REGS_NUM + SPARC_CONTROL_REGS_NUM)
+
+/* Each offset is multiplied by 4, because of the register size.
+   These offsets apply to the buffer sent/filled by ptrace.
+   Additionally, the array elements order corresponds to the .dat file, and the
+   gdb's registers enumeration order.  */
+
+static int sparc_regmap[] = {	
+  /* These offsets correspond to GET/SETREGSET.  */
+  -1,  1*4,  2*4,  3*4,  4*4,  5*4,  6*4,  7*4,	   /* g0 .. g7 */
+  8*4,  9*4,  10*4, 11*4, 12*4, 13*4, 14*4, 15*4,  /* o0 .. o5, sp, o7 */
+  16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4,  /* l0 .. l7 */
+  24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4,  /* i0 .. i5, fp, i7 */
+
+  /* Floating point registers offsets correspond to GET/SETFPREGSET.  */
+   0*4,  1*4,  2*4,  3*4,  4*4,  5*4,  6*4,  7*4,	   /*  f0 ..  f7 */
+   8*4,  9*4, 10*4, 11*4, 12*4, 13*4, 14*4, 15*4,	   /*  f8 .. f15 */
+  16*4, 17*4, 18*4, 19*4, 20*4, 21*4, 22*4, 23*4,	   /* f16 .. f23 */
+  24*4, 25*4, 26*4, 27*4, 28*4, 29*4, 30*4, 31*4,	   /* f24 .. f31 */
+
+  35*4,	/* y */
+  32*4,	/* psr */
+  36*4,	/* wim */
+  37*4,	/* tbr */
+  33*4,	/* pc */
+  34*4,	/* npc */
+  33*4	/* fsr */
+  /* 32*4,*/	/* csr */
+};
+
+struct regs_range_t
+{
+  int regno_start;
+  int regno_end;
+};
+
+static const struct regs_range_t gregs_ranges[] = {
+ {  1, 31 }, /* g1 .. i7  */
+ { 64, 65 }, /* y, psr  */
+ { 68, 69 }  /* pc .. npc  */
+};
+
+#define N_GREGS_RANGES (sizeof (gregs_ranges) / sizeof (struct regs_range_t))
+
+/* Defined in auto-generated file reg-sparc32.c.  */
+void init_registers_sparc32 (void);
+
+static const struct regs_range_t fpregs_ranges[] = {
+ { 32, 63 }, /* f0 .. f31  */
+ { 70, 70 }  /* fsr */
+};
+
+#define N_FPREGS_RANGES (sizeof (fpregs_ranges) / sizeof (struct regs_range_t))
+
+static void
+sparc_fill_gregset (struct regcache *regcache, void *buf)
+{
+  int i;
+  int range;
+  gdb_byte *regs = buf;
+
+  for (range = 0; range < N_GREGS_RANGES; range++)
+    for (i = gregs_ranges[range].regno_start; i <= gregs_ranges[range].regno_end; i++)
+      if (sparc_regmap[i] != -1)
+        collect_register (regcache, i, regs + sparc_regmap[i]);
+}
+
+static void
+sparc_fill_fpregset (struct regcache *regcache, void *buf)
+{
+  int i;
+  int range;
+
+  for (range = 0; range < N_FPREGS_RANGES; range++)
+    for (i = fpregs_ranges[range].regno_start; i <= fpregs_ranges[range].regno_end; i++)
+      collect_register (regcache, i, ((char *) buf) + sparc_regmap[i]);
+
+}
+
+static void
+sparc_store_gregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+  char zerobuf[4];
+  int range;
+
+  memset (zerobuf, 0, sizeof(zerobuf));
+
+  for (range = 0; range < N_GREGS_RANGES; range++)
+    for (i = gregs_ranges[range].regno_start; i <= gregs_ranges[range].regno_end; i++)
+      if (sparc_regmap[i] != -1)
+        supply_register (regcache, i, ((char *) buf) + sparc_regmap[i]);
+      else
+        supply_register (regcache, i, zerobuf);
+
+  /* %g0 is always zero.  */
+  supply_register (regcache, 0, zerobuf);
+}
+
+static void
+sparc_store_fpregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+  int range;
+
+  for (range = 0; range < N_FPREGS_RANGES; range++)
+    for (i = fpregs_ranges[range].regno_start; i <= fpregs_ranges[range].regno_end; i++)
+      supply_register (regcache, i, ((char *) buf) + sparc_regmap[i]);
+}
+
+static int
+sparc_cannot_fetch_register (int regno)
+{
+	return (regno >= sparc_num_regs || sparc_regmap[regno] == -1);
+}
+
+static int
+sparc_cannot_store_register (int regno)
+{
+	return (regno >= sparc_num_regs || sparc_regmap[regno] == -1);
+}
+
+static CORE_ADDR
+sparc_get_pc (struct regcache *regcache)
+{
+  unsigned long pc;
+  collect_register_by_name (regcache, "pc", &pc);
+  return pc;
+}
+
+static const unsigned char sparc_breakpoint[INSN_SIZE] = { 0x91, 0xd0, 0x20, 0x01 };
+#define sparc_breakpoint_len INSN_SIZE
+
+/* We only place breakpoints in empty marker functions, and thread locking
+   is outside of the function.  So rather than importing software single-step,
+   we can just run until exit.  */
+static CORE_ADDR
+sparc_reinsert_addr (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_process, 1);
+  CORE_ADDR lr;
+  /* O7 is the equivalent to the 'lr' of other archs.  */
+  collect_register_by_name (regcache, "o7", &lr);
+  return lr;
+}
+
+static int
+sparc_breakpoint_at (CORE_ADDR where)
+{
+  unsigned char insn[INSN_SIZE];
+
+  (*the_target->read_memory) (where, (unsigned char *) insn, sizeof(insn));
+
+  if (memcmp(sparc_breakpoint, insn, sizeof(insn)) == 0)
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses TRAP Always.  */
+
+  return 0;
+}
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs)
+{
+  sparc_store_gregset (regcache, gregs);
+}
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs)
+{
+  sparc_store_fpregset (regcache, fpregs);
+}
+
+void
+fill_gregset (struct regcache *regcache, gdb_gregset_t *gregs, int regno)
+{
+  sparc_fill_gregset (regcache, gregs);
+}
+
+void
+fill_fpregset (struct regcache *regcache, gdb_fpregset_t *fpregs, int regno)
+{
+  sparc_fill_fpregset (regcache, fpregs);
+}
+
+
+struct solaris_target_ops the_low_target = {
+  init_registers_sparc32,
+  sparc_num_regs,
+  /* No regmap needs to be provided since this impl. doesn't use USRREGS.  */
+  NULL,
+  sparc_cannot_fetch_register,
+  sparc_cannot_store_register,
+  sparc_get_pc,
+  /* No sparc_set_pc is needed.  */
+  NULL,
+  (const unsigned char *) sparc_breakpoint,
+  sparc_breakpoint_len,
+  sparc_reinsert_addr,
+  0,
+  sparc_breakpoint_at,
+  NULL, NULL, NULL, NULL, /* watchpoint functions */ 
+  0
+};
diff -upN src-orig/src/gdb/gdbserver/sol-thread-db.c src/gdb/gdbserver/sol-thread-db.c
--- src-orig/src/gdb/gdbserver/sol-thread-db.c	1970-01-01 01:00:00.000000000 +0100
+++ src/gdb/gdbserver/sol-thread-db.c	2010-04-08 15:41:51.000000000 +0200
@@ -0,0 +1,171 @@
+/* Thread management interface on Solaris, for the remote server for GDB.
+   Copyright (C) 2010  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 "solaris-low.h"
+#include "gdb_proc_service.h"
+
+extern int debug_threads;
+
+#ifdef HAVE_THREAD_DB_H
+#include <thread_db.h>
+#endif
+
+#include <stdint.h>
+
+
+extern void procfs_find_new_threads (void);
+
+char *
+thread_db_err_str (td_err_e err)
+{
+  static char buf[64];
+
+  switch (err)
+    {
+    case TD_OK:
+      return "generic 'call succeeded'";
+    case TD_ERR:
+      return "generic error";
+    case TD_NOTHR:
+      return "no thread to satisfy query";
+    case TD_NOSV:
+      return "no sync handle to satisfy query";
+    case TD_NOLWP:
+      return "no LWP to satisfy query";
+    case TD_BADPH:
+      return "invalid process handle";
+    case TD_BADTH:
+      return "invalid thread handle";
+    case TD_BADSH:
+      return "invalid synchronization handle";
+    case TD_BADTA:
+      return "invalid thread agent";
+    case TD_BADKEY:
+      return "invalid key";
+    case TD_NOMSG:
+      return "no event message for getmsg";
+    case TD_NOFPREGS:
+      return "FPU register set not available";
+    case TD_NOLIBTHREAD:
+      return "application not linked with libthread";
+    case TD_NOEVENT:
+      return "requested event is not supported";
+    case TD_NOCAPAB:
+      return "capability not available";
+    case TD_DBERR:
+      return "debugger service failed";
+    case TD_NOAPLIC:
+      return "operation not applicable to";
+    case TD_NOTSD:
+      return "no thread-specific data for this thread";
+    case TD_MALLOC:
+      return "malloc failed";
+    case TD_PARTIALREG:
+      return "only part of register set was written/read";
+    case TD_NOXREGS:
+      return "X register set not available for this thread";
+#ifdef HAVE_TD_VERSION
+    case TD_VERSION:
+      return "version mismatch between libthread_db and libpthread";
+#endif
+    default:
+      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
+      return buf;
+    }
+}
+
+static int
+find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
+{
+  td_thrinfo_t ti;
+  td_err_e err;
+  ptid_t ptid;
+
+  err = td_thr_get_info (th_p, &ti);
+  if (err != TD_OK)
+    error ("Cannot get thread info: %s", thread_db_err_str (err));
+
+  /* Check for zombies.  */
+  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
+    return 0;
+
+  ptid = BUILD_THREAD (ti.ti_lid, GET_PID (inferior_ptid));
+  if (find_thread_ptid(ptid) == NULL)
+    add_thread (ptid, NULL);
+
+  return 0;
+}
+
+static void
+thread_db_find_new_threads (void)
+{
+  td_err_e err;
+  struct process_info_private *proc = current_process()->private;
+
+  /* First find any new LWP's  */
+  procfs_find_new_threads ();
+
+  /* Iterate over all user-space threads to discover new threads.  */
+  err = td_ta_thr_iter (proc->thread_agent, 
+      			find_new_threads_callback, NULL,
+			TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+			TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+}
+
+
+
+int
+thread_db_init (int use_events)
+{
+  int err;
+  struct process_info *proc = current_process ();
+  struct process_info_private *priv = proc->private;
+
+
+  /* Now, initialize libthread_db. This needs to be done after the
+     share libraries are located because it needs information from
+     the user's thread library.  */
+
+  err = td_init();
+  if (err != TD_OK)
+    {
+      warning ("thread_db_init: td_init: %s", td_err_string (err));
+      return 0;
+    }
+
+  err = td_ta_new (&priv->proc_handle, &priv->thread_agent);
+  switch (err)
+    {
+    case TD_NOLIBTHREAD:
+      /* No thread library was detected.  */
+      return 0;
+
+    case TD_OK:
+      /* The thread library was detected.  */
+      thread_db_find_new_threads ();
+      proc->all_symbols_looked_up = 1;
+      return 1;
+
+    default:
+      warning ("error initializing thread_db library: %s",
+	       thread_db_err_str (err));
+    }
+
+  return 0;
+}



More information about the Gdb-patches mailing list