* elf32-spu.c (spu_elf_create_sections): Properly iterate over
[deliverable/binutils-gdb.git] / gdb / gdbserver / linux-low.c
index 69b35c1032ba83575aaf2e01e73094f28902f644..067a63290f30b38660761b83dcfcf4df84872dfd 100644 (file)
@@ -1,6 +1,6 @@
 /* Low level interface to ptrace, for the remote server for GDB.
-   Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
-   Free Software Foundation, Inc.
+   Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -16,8 +16,8 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "server.h"
 #include "linux-low.h"
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <errno.h>
+#include <sys/syscall.h>
+
+#ifndef PTRACE_GETSIGINFO
+# define PTRACE_GETSIGINFO 0x4202
+# define PTRACE_SETSIGINFO 0x4203
+#endif
+
+#ifdef __UCLIBC__
+#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__))
+#define HAS_NOMMU
+#endif
+#endif
 
 /* ``all_threads'' is keyed by the LWP ID - it should be the thread ID instead,
    however.  This requires changing the ID in place when we go from !using_threads
@@ -51,7 +64,7 @@ int stopping_threads;
 int using_threads;
 
 static void linux_resume_one_process (struct inferior_list_entry *entry,
-                                     int step, int signal);
+                                     int step, int signal, siginfo_t *info);
 static void linux_resume (struct thread_resume *resume_info);
 static void stop_all_processes (void);
 static int linux_wait_for_event (struct thread_info *child);
@@ -59,6 +72,7 @@ static int linux_wait_for_event (struct thread_info *child);
 struct pending_signals
 {
   int signal;
+  siginfo_t info;
   struct pending_signals *prev;
 };
 
@@ -69,10 +83,6 @@ struct pending_signals
 static int use_regsets_p = 1;
 #endif
 
-extern int errno;
-
-int debug_threads = 0;
-
 #define pid_of(proc) ((proc)->head.id)
 
 /* FIXME: Delete eventually.  */
@@ -112,7 +122,7 @@ get_stop_pc (void)
 }
 
 static void *
-add_process (int pid)
+add_process (unsigned long pid)
 {
   struct process_info *process;
 
@@ -139,7 +149,11 @@ linux_create_inferior (char *program, char **allargs)
   void *new_process;
   int pid;
 
+#if defined(__UCLIBC__) && defined(HAS_NOMMU)
+  pid = vfork ();
+#else
   pid = fork ();
+#endif
   if (pid < 0)
     perror_with_name ("fork");
 
@@ -152,6 +166,8 @@ linux_create_inferior (char *program, char **allargs)
       setpgid (0, 0);
 
       execv (program, allargs);
+      if (errno == ENOENT)
+       execvp (program, allargs);
 
       fprintf (stderr, "Cannot exec %s: %s.\n", program,
               strerror (errno));
@@ -160,7 +176,7 @@ linux_create_inferior (char *program, char **allargs)
     }
 
   new_process = add_process (pid);
-  add_thread (pid, new_process);
+  add_thread (pid, new_process, pid);
 
   return pid;
 }
@@ -168,13 +184,13 @@ linux_create_inferior (char *program, char **allargs)
 /* Attach to an inferior process.  */
 
 void
-linux_attach_lwp (int pid, int tid)
+linux_attach_lwp (unsigned long pid, unsigned long tid)
 {
   struct process_info *new_process;
 
   if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
     {
-      fprintf (stderr, "Cannot attach to process %d: %s (%d)\n", pid,
+      fprintf (stderr, "Cannot attach to process %ld: %s (%d)\n", pid,
               strerror (errno), errno);
       fflush (stderr);
 
@@ -185,7 +201,7 @@ linux_attach_lwp (int pid, int tid)
     }
 
   new_process = (struct process_info *) add_process (pid);
-  add_thread (tid, new_process);
+  add_thread (tid, new_process, pid);
 
   /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
      brings it to a halt.  We should ignore that SIGSTOP and resume the process
@@ -202,7 +218,7 @@ linux_attach_lwp (int pid, int tid)
 }
 
 int
-linux_attach (int pid)
+linux_attach (unsigned long pid)
 {
   struct process_info *process;
 
@@ -224,6 +240,13 @@ linux_kill_one_process (struct inferior_list_entry *entry)
   struct process_info *process = get_thread_process (thread);
   int wstat;
 
+  /* We avoid killing the first thread here, because of a Linux kernel (at
+     least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before
+     the children get a chance to be reaped, it will remain a zombie
+     forever.  */
+  if (entry == all_threads.head)
+    return;
+
   do
     {
       ptrace (PTRACE_KILL, pid_of (process), 0, 0);
@@ -236,7 +259,25 @@ linux_kill_one_process (struct inferior_list_entry *entry)
 static void
 linux_kill (void)
 {
+  struct thread_info *thread = (struct thread_info *) all_threads.head;
+  struct process_info *process;
+  int wstat;
+
+  if (thread == NULL)
+    return;
+
   for_each_inferior (&all_threads, linux_kill_one_process);
+
+  /* See the comment in linux_kill_one_process.  We did not kill the first
+     thread in the list, so do so now.  */
+  process = get_thread_process (thread);
+  do
+    {
+      ptrace (PTRACE_KILL, pid_of (process), 0, 0);
+
+      /* Make sure it died.  The loop is most likely unnecessary.  */
+      wstat = linux_wait_for_event (thread);
+    } while (WIFSTOPPED (wstat));
 }
 
 static void
@@ -248,15 +289,29 @@ linux_detach_one_process (struct inferior_list_entry *entry)
   ptrace (PTRACE_DETACH, pid_of (process), 0, 0);
 }
 
-static void
+static int
 linux_detach (void)
 {
   for_each_inferior (&all_threads, linux_detach_one_process);
+  return 0;
+}
+
+static void
+linux_join (void)
+{
+  extern unsigned long signal_pid;
+  int status, ret;
+
+  do {
+    ret = waitpid (signal_pid, &status, 0);
+    if (WIFEXITED (status) || WIFSIGNALED (status))
+      break;
+  } while (ret != -1 || errno != ECHILD);
 }
 
 /* Return nonzero if the given thread is still alive.  */
 static int
-linux_thread_alive (int tid)
+linux_thread_alive (unsigned long tid)
 {
   if (find_inferior_id (&all_threads, tid) != NULL)
     return 1;
@@ -340,7 +395,7 @@ status_pending_p (struct inferior_list_entry *entry, void *dummy)
           So instead of reporting the old SIGTRAP, pretend we got to
           the breakpoint just after it was removed instead of just
           before; resume the process.  */
-       linux_resume_one_process (&process->head, 0, 0);
+       linux_resume_one_process (&process->head, 0, 0, NULL);
        return 0;
       }
 
@@ -393,6 +448,8 @@ linux_wait_for_process (struct process_info **childp, int *wstatp)
   (*childp)->stopped = 1;
   (*childp)->pending_is_breakpoint = 0;
 
+  (*childp)->last_status = *wstatp;
+
   if (debug_threads
       && WIFSTOPPED (*wstatp))
     {
@@ -420,7 +477,7 @@ linux_wait_for_event (struct thread_info *child)
       event_child = (struct process_info *)
        find_inferior (&all_processes, status_pending_p, NULL);
       if (debug_threads && event_child)
-       fprintf (stderr, "Got a pending child %d\n", event_child->lwpid);
+       fprintf (stderr, "Got a pending child %ld\n", event_child->lwpid);
     }
   else
     {
@@ -435,7 +492,7 @@ linux_wait_for_event (struct thread_info *child)
       if (event_child->status_pending_p)
        {
          if (debug_threads)
-           fprintf (stderr, "Got an event from pending child %d (%04x)\n",
+           fprintf (stderr, "Got an event from pending child %ld (%04x)\n",
                     event_child->lwpid, event_child->status_pending);
          wstat = event_child->status_pending;
          event_child->status_pending_p = 0;
@@ -464,62 +521,76 @@ linux_wait_for_event (struct thread_info *child)
       current_inferior = (struct thread_info *)
        find_inferior_id (&all_threads, event_child->tid);
 
-      if (using_threads)
+      /* Check for thread exit.  */
+      if (using_threads && ! WIFSTOPPED (wstat))
        {
-         /* Check for thread exit.  */
-         if (! WIFSTOPPED (wstat))
-           {
-             if (debug_threads)
-               fprintf (stderr, "Thread %d (LWP %d) exiting\n",
-                        event_child->tid, event_child->head.id);
+         if (debug_threads)
+           fprintf (stderr, "Thread %ld (LWP %ld) exiting\n",
+                    event_child->tid, event_child->head.id);
 
-             /* If the last thread is exiting, just return.  */
-             if (all_threads.head == all_threads.tail)
-               return wstat;
+         /* If the last thread is exiting, just return.  */
+         if (all_threads.head == all_threads.tail)
+           return wstat;
 
-             dead_thread_notify (event_child->tid);
+         dead_thread_notify (event_child->tid);
 
-             remove_inferior (&all_processes, &event_child->head);
-             free (event_child);
-             remove_thread (current_inferior);
-             current_inferior = (struct thread_info *) all_threads.head;
+         remove_inferior (&all_processes, &event_child->head);
+         free (event_child);
+         remove_thread (current_inferior);
+         current_inferior = (struct thread_info *) all_threads.head;
 
-             /* If we were waiting for this particular child to do something...
-                well, it did something.  */
-             if (child != NULL)
-               return wstat;
+         /* If we were waiting for this particular child to do something...
+            well, it did something.  */
+         if (child != NULL)
+           return wstat;
 
-             /* Wait for a more interesting event.  */
-             continue;
-           }
+         /* Wait for a more interesting event.  */
+         continue;
+       }
 
-         if (WIFSTOPPED (wstat)
-             && WSTOPSIG (wstat) == SIGSTOP
-             && event_child->stop_expected)
-           {
-             if (debug_threads)
-               fprintf (stderr, "Expected stop.\n");
-             event_child->stop_expected = 0;
-             linux_resume_one_process (&event_child->head,
-                                       event_child->stepping, 0);
-             continue;
-           }
+      if (using_threads
+         && WIFSTOPPED (wstat)
+         && WSTOPSIG (wstat) == SIGSTOP
+         && event_child->stop_expected)
+       {
+         if (debug_threads)
+           fprintf (stderr, "Expected stop.\n");
+         event_child->stop_expected = 0;
+         linux_resume_one_process (&event_child->head,
+                                   event_child->stepping, 0, NULL);
+         continue;
+       }
 
-         /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
-            thread library?  */
-         if (WIFSTOPPED (wstat)
-             && (WSTOPSIG (wstat) == __SIGRTMIN
-                 || WSTOPSIG (wstat) == __SIGRTMIN + 1))
-           {
-             if (debug_threads)
-               fprintf (stderr, "Ignored signal %d for %d (LWP %d).\n",
-                        WSTOPSIG (wstat), event_child->tid,
-                        event_child->head.id);
-             linux_resume_one_process (&event_child->head,
-                                       event_child->stepping,
-                                       WSTOPSIG (wstat));
-             continue;
-           }
+      /* If GDB is not interested in this signal, don't stop other
+        threads, and don't report it to GDB.  Just resume the
+        inferior right away.  We do this for threading-related
+        signals as well as any that GDB specifically requested
+        we ignore.  But never ignore SIGSTOP if we sent it
+        ourselves.  */
+      /* FIXME drow/2002-06-09: Get signal numbers from the inferior's
+        thread library?  */
+      if (WIFSTOPPED (wstat)
+         && ((using_threads && (WSTOPSIG (wstat) == __SIGRTMIN
+                                || WSTOPSIG (wstat) == __SIGRTMIN + 1))
+             || (pass_signals[target_signal_from_host (WSTOPSIG (wstat))]
+                 && (WSTOPSIG (wstat) != SIGSTOP
+                     || !event_child->sigstop_sent))))
+       {
+         siginfo_t info, *info_p;
+
+         if (debug_threads)
+           fprintf (stderr, "Ignored signal %d for %ld (LWP %ld).\n",
+                    WSTOPSIG (wstat), event_child->tid,
+                    event_child->head.id);
+
+         if (ptrace (PTRACE_GETSIGINFO, event_child->lwpid, 0, &info) == 0)
+           info_p = &info;
+         else
+           info_p = NULL;
+         linux_resume_one_process (&event_child->head,
+                                   event_child->stepping,
+                                   WSTOPSIG (wstat), info_p);
+         continue;
        }
 
       /* If this event was not handled above, and is not a SIGTRAP, report
@@ -546,7 +617,7 @@ linux_wait_for_event (struct thread_info *child)
          event_child->bp_reinsert = 0;
 
          /* Clear the single-stepping flag and SIGTRAP as we resume.  */
-         linux_resume_one_process (&event_child->head, 0, 0);
+         linux_resume_one_process (&event_child->head, 0, 0, NULL);
          continue;
        }
 
@@ -583,13 +654,13 @@ linux_wait_for_event (struct thread_info *child)
            {
              event_child->bp_reinsert = stop_pc;
              uninsert_breakpoint (stop_pc);
-             linux_resume_one_process (&event_child->head, 1, 0);
+             linux_resume_one_process (&event_child->head, 1, 0, NULL);
            }
          else
            {
              reinsert_breakpoint_by_bp
                (stop_pc, (*the_low_target.breakpoint_reinsert_addr) ());
-             linux_resume_one_process (&event_child->head, 0, 0);
+             linux_resume_one_process (&event_child->head, 0, 0, NULL);
            }
 
          continue;
@@ -646,7 +717,7 @@ retry:
      then we need to make sure we restart the other threads.  We could
      pick a thread at random or restart all; restarting all is less
      arbitrary.  */
-  if (cont_thread > 0)
+  if (cont_thread != 0 && cont_thread != -1)
     {
       child = (struct thread_info *) find_inferior_id (&all_threads,
                                                       cont_thread);
@@ -686,14 +757,18 @@ retry:
          fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w));
          *status = 'W';
          clear_inferiors ();
-         return ((unsigned char) WEXITSTATUS (w));
+         free (all_processes.head);
+         all_processes.head = all_processes.tail = NULL;
+         return WEXITSTATUS (w);
        }
       else if (!WIFSTOPPED (w))
        {
          fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w));
-         clear_inferiors ();
          *status = 'X';
-         return ((unsigned char) WTERMSIG (w));
+         clear_inferiors ();
+         free (all_processes.head);
+         all_processes.head = all_processes.tail = NULL;
+         return target_signal_from_host (WTERMSIG (w));
        }
     }
   else
@@ -703,7 +778,31 @@ retry:
     }
 
   *status = 'T';
-  return ((unsigned char) WSTOPSIG (w));
+  return target_signal_from_host (WSTOPSIG (w));
+}
+
+/* Send a signal to an LWP.  For LinuxThreads, kill is enough; however, if
+   thread groups are in use, we need to use tkill.  */
+
+static int
+kill_lwp (unsigned long lwpid, int signo)
+{
+  static int tkill_failed;
+
+  errno = 0;
+
+#ifdef SYS_tkill
+  if (!tkill_failed)
+    {
+      int ret = syscall (SYS_tkill, lwpid, signo);
+      if (errno != ENOSYS)
+        return ret;
+      errno = 0;
+      tkill_failed = 1;
+    }
+#endif
+
+  return kill (lwpid, signo);
 }
 
 static void
@@ -723,9 +822,9 @@ send_sigstop (struct inferior_list_entry *entry)
     }
 
   if (debug_threads)
-    fprintf (stderr, "Sending sigstop to process %d\n", process->head.id);
+    fprintf (stderr, "Sending sigstop to process %ld\n", process->head.id);
 
-  kill (process->head.id, SIGSTOP);
+  kill_lwp (process->head.id, SIGSTOP);
   process->sigstop_sent = 1;
 }
 
@@ -734,7 +833,8 @@ wait_for_sigstop (struct inferior_list_entry *entry)
 {
   struct process_info *process = (struct process_info *) entry;
   struct thread_info *saved_inferior, *thread;
-  int wstat, saved_tid;
+  int wstat;
+  unsigned long saved_tid;
 
   if (process->stopped)
     return;
@@ -785,7 +885,7 @@ stop_all_processes (void)
 
 static void
 linux_resume_one_process (struct inferior_list_entry *entry,
-                         int step, int signal)
+                         int step, int signal, siginfo_t *info)
 {
   struct process_info *process = (struct process_info *) entry;
   struct thread_info *saved_inferior;
@@ -804,6 +904,10 @@ linux_resume_one_process (struct inferior_list_entry *entry,
       p_sig = malloc (sizeof (*p_sig));
       p_sig->prev = process->pending_signals;
       p_sig->signal = signal;
+      if (info == NULL)
+       memset (&p_sig->info, 0, sizeof (siginfo_t));
+      else
+       memcpy (&p_sig->info, info, sizeof (siginfo_t));
       process->pending_signals = p_sig;
     }
 
@@ -814,7 +918,7 @@ linux_resume_one_process (struct inferior_list_entry *entry,
   current_inferior = get_process_thread (process);
 
   if (debug_threads)
-    fprintf (stderr, "Resuming process %d (%s, signal %d, stop %s)\n", inferior_pid,
+    fprintf (stderr, "Resuming process %ld (%s, signal %d, stop %s)\n", inferior_pid,
             step ? "step" : "continue", signal,
             process->stop_expected ? "expected" : "not expected");
 
@@ -845,7 +949,7 @@ linux_resume_one_process (struct inferior_list_entry *entry,
   if (debug_threads && the_low_target.get_pc != NULL)
     {
       fprintf (stderr, "  ");
-      (long) (*the_low_target.get_pc) ();
+      (*the_low_target.get_pc) ();
     }
 
   /* If we have pending signals, consume one unless we are trying to reinsert
@@ -859,6 +963,9 @@ linux_resume_one_process (struct inferior_list_entry *entry,
        p_sig = &(*p_sig)->prev;
 
       signal = (*p_sig)->signal;
+      if ((*p_sig)->info.si_signo != 0)
+       ptrace (PTRACE_SETSIGINFO, process->lwpid, 0, &(*p_sig)->info);
+
       free (*p_sig);
       *p_sig = NULL;
     }
@@ -925,7 +1032,7 @@ linux_continue_one_thread (struct inferior_list_entry *entry)
   else
     step = process->resume->step;
 
-  linux_resume_one_process (&process->head, step, process->resume->sig);
+  linux_resume_one_process (&process->head, step, process->resume->sig, NULL);
 
   process->resume = NULL;
 }
@@ -956,6 +1063,16 @@ linux_queue_one_thread (struct inferior_list_entry *entry)
       p_sig = malloc (sizeof (*p_sig));
       p_sig->prev = process->pending_signals;
       p_sig->signal = process->resume->sig;
+      memset (&p_sig->info, 0, sizeof (siginfo_t));
+
+      /* If this is the same signal we were previously stopped by,
+        make sure to queue its siginfo.  We can ignore the return
+        value of ptrace; if it fails, we'll skip
+        PTRACE_SETSIGINFO.  */
+      if (WIFSTOPPED (process->last_status)
+         && WSTOPSIG (process->last_status) == process->resume->sig)
+       ptrace (PTRACE_GETSIGINFO, process->lwpid, 0, &p_sig->info);
+
       process->pending_signals = p_sig;
     }
 
@@ -1045,7 +1162,7 @@ static void
 fetch_register (int regno)
 {
   CORE_ADDR regaddr;
-  register int i;
+  int i, size;
   char *buf;
 
   if (regno >= the_low_target.num_regs)
@@ -1056,8 +1173,10 @@ fetch_register (int regno)
   regaddr = register_addr (regno);
   if (regaddr == -1)
     return;
-  buf = alloca (register_size (regno));
-  for (i = 0; i < register_size (regno); i += sizeof (PTRACE_XFER_TYPE))
+  size = (register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
+         & - sizeof (PTRACE_XFER_TYPE);
+  buf = alloca (size);
+  for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
     {
       errno = 0;
       *(PTRACE_XFER_TYPE *) (buf + i) =
@@ -1074,7 +1193,12 @@ fetch_register (int regno)
          goto error_exit;
        }
     }
-  supply_register (regno, buf);
+  if (the_low_target.left_pad_xfer
+      && register_size (regno) < sizeof (PTRACE_XFER_TYPE))
+    supply_register (regno, (buf + sizeof (PTRACE_XFER_TYPE)
+                            - register_size (regno)));
+  else
+    supply_register (regno, buf);
 
 error_exit:;
 }
@@ -1097,7 +1221,7 @@ static void
 usr_store_inferior_registers (int regno)
 {
   CORE_ADDR regaddr;
-  int i;
+  int i, size;
   char *buf;
 
   if (regno >= 0)
@@ -1112,9 +1236,17 @@ usr_store_inferior_registers (int regno)
       if (regaddr == -1)
        return;
       errno = 0;
-      buf = alloca (register_size (regno));
-      collect_register (regno, buf);
-      for (i = 0; i < register_size (regno); i += sizeof (PTRACE_XFER_TYPE))
+      size = (register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
+            & - sizeof (PTRACE_XFER_TYPE);
+      buf = alloca (size);
+      memset (buf, 0, size);
+      if (the_low_target.left_pad_xfer
+         && register_size (regno) < sizeof (PTRACE_XFER_TYPE))
+       collect_register (regno, (buf + sizeof (PTRACE_XFER_TYPE)
+                                 - register_size (regno)));
+      else
+       collect_register (regno, buf);
+      for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
        {
          errno = 0;
          ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
@@ -1148,6 +1280,7 @@ static int
 regsets_fetch_inferior_registers ()
 {
   struct regset_info *regset;
+  int saw_general_regs = 0;
 
   regset = target_regsets;
 
@@ -1184,21 +1317,27 @@ regsets_fetch_inferior_registers ()
          else
            {
              char s[256];
-             sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
+             sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%ld",
                       inferior_pid);
              perror (s);
            }
        }
+      else if (regset->type == GENERAL_REGS)
+       saw_general_regs = 1;
       regset->store_function (buf);
       regset ++;
     }
-  return 0;
+  if (saw_general_regs)
+    return 0;
+  else
+    return 1;
 }
 
 static int
 regsets_store_inferior_registers ()
 {
   struct regset_info *regset;
+  int saw_general_regs = 0;
 
   regset = target_regsets;
 
@@ -1214,8 +1353,21 @@ regsets_store_inferior_registers ()
        }
 
       buf = malloc (regset->size);
-      regset->fill_function (buf);
-      res = ptrace (regset->set_request, inferior_pid, 0, buf);
+
+      /* First fill the buffer with the current register set contents,
+        in case there are any items in the kernel's regset that are
+        not in gdbserver's regcache.  */
+      res = ptrace (regset->get_request, inferior_pid, 0, buf);
+
+      if (res == 0)
+       {
+         /* Then overlay our cached registers on that.  */
+         regset->fill_function (buf);
+
+         /* Only now do we write the register set.  */
+         res = ptrace (regset->set_request, inferior_pid, 0, buf);
+       }
+
       if (res < 0)
        {
          if (errno == EIO)
@@ -1238,9 +1390,15 @@ regsets_store_inferior_registers ()
              perror ("Warning: ptrace(regsets_store_inferior_registers)");
            }
        }
+      else if (regset->type == GENERAL_REGS)
+       saw_general_regs = 1;
       regset ++;
       free (buf);
     }
+  if (saw_general_regs)
+    return 0;
+  else
+    return 1;
   return 0;
 }
 
@@ -1282,7 +1440,7 @@ linux_store_registers (int regno)
    to debugger memory starting at MYADDR.  */
 
 static int
-linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
+linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
 {
   register int i;
   /* Round starting address down to longword boundary.  */
@@ -1316,7 +1474,7 @@ linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
    returns the value of errno.  */
 
 static int
-linux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len)
+linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
 {
   register int i;
   /* Round starting address down to longword boundary.  */
@@ -1376,31 +1534,31 @@ linux_look_up_symbols (void)
 }
 
 static void
-linux_send_signal (int signum)
+linux_request_interrupt (void)
 {
-  extern int signal_pid;
+  extern unsigned long signal_pid;
 
-  if (cont_thread > 0)
+  if (cont_thread != 0 && cont_thread != -1)
     {
       struct process_info *process;
 
       process = get_thread_process (current_inferior);
-      kill (process->lwpid, signum);
+      kill_lwp (process->lwpid, SIGINT);
     }
   else
-    kill (signal_pid, signum);
+    kill_lwp (signal_pid, SIGINT);
 }
 
 /* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
    to debugger memory starting at MYADDR.  */
 
 static int
-linux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len)
+linux_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
 {
   char filename[PATH_MAX];
   int fd, n;
 
-  snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid);
+  snprintf (filename, sizeof filename, "/proc/%ld/auxv", inferior_pid);
 
   fd = open (filename, O_RDONLY);
   if (fd < 0)
@@ -1417,12 +1575,104 @@ linux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len)
   return n;
 }
 
-\f
+/* These watchpoint related wrapper functions simply pass on the function call
+   if the target has registered a corresponding function.  */
+
+static int
+linux_insert_watchpoint (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.insert_watchpoint != NULL)
+    return the_low_target.insert_watchpoint (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+linux_remove_watchpoint (char type, CORE_ADDR addr, int len)
+{
+  if (the_low_target.remove_watchpoint != NULL)
+    return the_low_target.remove_watchpoint (type, addr, len);
+  else
+    /* Unsupported (see target.h).  */
+    return 1;
+}
+
+static int
+linux_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
+linux_stopped_data_address (void)
+{
+  if (the_low_target.stopped_data_address != NULL)
+    return the_low_target.stopped_data_address ();
+  else
+    return 0;
+}
+
+#if defined(__UCLIBC__) && defined(HAS_NOMMU)
+#if defined(__mcoldfire__)
+/* These should really be defined in the kernel's ptrace.h header.  */
+#define PT_TEXT_ADDR 49*4
+#define PT_DATA_ADDR 50*4
+#define PT_TEXT_END_ADDR  51*4
+#endif
+
+/* Under uClinux, programs are loaded at non-zero offsets, which we need
+   to tell gdb about.  */
+
+static int
+linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p)
+{
+#if defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) && defined(PT_TEXT_END_ADDR)
+  unsigned long text, text_end, data;
+  int pid = get_thread_process (current_inferior)->head.id;
+
+  errno = 0;
+
+  text = ptrace (PTRACE_PEEKUSER, pid, (long)PT_TEXT_ADDR, 0);
+  text_end = ptrace (PTRACE_PEEKUSER, pid, (long)PT_TEXT_END_ADDR, 0);
+  data = ptrace (PTRACE_PEEKUSER, pid, (long)PT_DATA_ADDR, 0);
+
+  if (errno == 0)
+    {
+      /* Both text and data offsets produced at compile-time (and so
+         used by gdb) are relative to the beginning of the program,
+         with the data segment immediately following the text segment.
+         However, the actual runtime layout in memory may put the data
+         somewhere else, so when we send gdb a data base-address, we
+         use the real data base address and subtract the compile-time
+         data base-address from it (which is just the length of the
+         text segment).  BSS immediately follows data in both
+         cases.  */
+      *text_p = text;
+      *data_p = data - (text_end - text);
+      
+      return 1;
+    }
+#endif
+ return 0;
+}
+#endif
+
+static const char *
+linux_arch_string (void)
+{
+  return the_low_target.arch_string;
+}
+
 static struct target_ops linux_target_ops = {
   linux_create_inferior,
   linux_attach,
   linux_kill,
   linux_detach,
+  linux_join,
   linux_thread_alive,
   linux_resume,
   linux_wait,
@@ -1431,8 +1681,23 @@ static struct target_ops linux_target_ops = {
   linux_read_memory,
   linux_write_memory,
   linux_look_up_symbols,
-  linux_send_signal,
+  linux_request_interrupt,
   linux_read_auxv,
+  linux_insert_watchpoint,
+  linux_remove_watchpoint,
+  linux_stopped_by_watchpoint,
+  linux_stopped_data_address,
+#if defined(__UCLIBC__) && defined(HAS_NOMMU)
+  linux_read_offsets,
+#else
+  NULL,
+#endif
+#ifdef USE_THREAD_DB
+  thread_db_get_tls_address,
+#else
+  NULL,
+#endif
+  linux_arch_string,
 };
 
 static void
This page took 0.03462 seconds and 4 git commands to generate.