+ int nldt, i;
+ static int nalloc = 0;
+
+ /* Get the number of LDT entries. */
+ if (ioctl (pi->ctl_fd, PIOCNLDT, &nldt) < 0)
+ {
+ proc_warn (pi, "proc_get_LDT_entry (PIOCNLDT)", __LINE__);
+ return NULL;
+ }
+
+ /* Allocate space for the number of LDT entries. */
+ /* This alloc has to persist, 'cause we return a pointer to it. */
+ if (nldt > nalloc)
+ {
+ ldt_entry = (struct ssd *)
+ xrealloc (ldt_entry, (nldt + 1) * sizeof (struct ssd));
+ nalloc = nldt;
+ }
+
+ /* Read the whole table in one gulp. */
+ if (ioctl (pi->ctl_fd, PIOCLDT, ldt_entry) < 0)
+ {
+ proc_warn (pi, "proc_get_LDT_entry (PIOCLDT)", __LINE__);
+ return NULL;
+ }
+
+ /* Search the table and return the (first) entry matching 'key'. */
+ for (i = 0; i < nldt; i++)
+ if (ldt_entry[i].sel == key)
+ return &ldt_entry[i];
+
+ /* Loop ended, match not found. */
+ return NULL;
+#endif
+}
+
+#endif /* TM_I386SOL2_H */
+
+/* =============== END, non-thread part of /proc "MODULE" =============== */
+
+/* =================== Thread "MODULE" =================== */
+
+/* NOTE: you'll see more ifdefs and duplication of functions here,
+ since there is a different way to do threads on every OS. */
+
+/*
+ * Function: proc_get_nthreads
+ *
+ * Return the number of threads for the process
+ */
+
+#if defined (PIOCNTHR) && defined (PIOCTLIST)
+/*
+ * OSF version
+ */
+int
+proc_get_nthreads (procinfo *pi)
+{
+ int nthreads = 0;
+
+ if (ioctl (pi->ctl_fd, PIOCNTHR, &nthreads) < 0)
+ proc_warn (pi, "procfs: PIOCNTHR failed", __LINE__);
+
+ return nthreads;
+}
+
+#else
+#if defined (SYS_lwpcreate) || defined (SYS_lwp_create) /* FIXME: multiple */
+/*
+ * Solaris and Unixware version
+ */
+int
+proc_get_nthreads (procinfo *pi)
+{
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+ /*
+ * NEW_PROC_API: only works for the process procinfo,
+ * because the LWP procinfos do not get prstatus filled in.
+ */
+#ifdef NEW_PROC_API
+ if (pi->tid != 0) /* find the parent process procinfo */
+ pi = find_procinfo_or_die (pi->pid, 0);
+#endif
+ return pi->prstatus.pr_nlwp;
+}
+
+#else
+/*
+ * Default version
+ */
+int
+proc_get_nthreads (procinfo *pi)
+{
+ return 0;
+}
+#endif
+#endif
+
+/*
+ * Function: proc_get_current_thread (LWP version)
+ *
+ * Return the ID of the thread that had an event of interest.
+ * (ie. the one that hit a breakpoint or other traced event).
+ * All other things being equal, this should be the ID of a
+ * thread that is currently executing.
+ */
+
+#if defined (SYS_lwpcreate) || defined (SYS_lwp_create) /* FIXME: multiple */
+/*
+ * Solaris and Unixware version
+ */
+int
+proc_get_current_thread (procinfo *pi)
+{
+ /*
+ * Note: this should be applied to the root procinfo for the process,
+ * not to the procinfo for an LWP. If applied to the procinfo for
+ * an LWP, it will simply return that LWP's ID. In that case,
+ * find the parent process procinfo.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ if (!pi->status_valid)
+ if (!proc_get_status (pi))
+ return 0;
+
+#ifdef NEW_PROC_API
+ return pi->prstatus.pr_lwp.pr_lwpid;
+#else
+ return pi->prstatus.pr_who;
+#endif
+}
+
+#else
+#if defined (PIOCNTHR) && defined (PIOCTLIST)
+/*
+ * OSF version
+ */
+int
+proc_get_current_thread (procinfo *pi)
+{
+#if 0 /* FIXME: not ready for prime time? */
+ return pi->prstatus.pr_tid;
+#else
+ return 0;
+#endif
+}
+
+#else
+/*
+ * Default version
+ */
+int
+proc_get_current_thread (procinfo *pi)
+{
+ return 0;
+}
+
+#endif
+#endif
+
+/*
+ * Function: proc_update_threads
+ *
+ * Discover the IDs of all the threads within the process, and
+ * create a procinfo for each of them (chained to the parent).
+ *
+ * This unfortunately requires a different method on every OS.
+ *
+ * Return: non-zero for success, zero for failure.
+ */
+
+int
+proc_delete_dead_threads (procinfo *parent, procinfo *thread, void *ignore)
+{
+ if (thread && parent) /* sanity */
+ {
+ thread->status_valid = 0;
+ if (!proc_get_status (thread))
+ destroy_one_procinfo (&parent->thread_list, thread);
+ }
+ return 0; /* keep iterating */
+}
+
+#if defined (PIOCLSTATUS)
+/*
+ * Solaris 2.5 (ioctl) version
+ */
+int
+proc_update_threads (procinfo *pi)
+{
+ gdb_prstatus_t *prstatus;
+ struct cleanup *old_chain = NULL;
+ procinfo *thread;
+ int nlwp, i;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
+
+ if ((nlwp = proc_get_nthreads (pi)) <= 1)
+ return 1; /* Process is not multi-threaded; nothing to do. */
+
+ prstatus = xmalloc (sizeof (gdb_prstatus_t) * (nlwp + 1));
+
+ old_chain = make_cleanup (xfree, prstatus);
+ if (ioctl (pi->ctl_fd, PIOCLSTATUS, prstatus) < 0)
+ proc_error (pi, "update_threads (PIOCLSTATUS)", __LINE__);
+
+ /* Skip element zero, which represents the process as a whole. */
+ for (i = 1; i < nlwp + 1; i++)
+ {
+ if ((thread = create_procinfo (pi->pid, prstatus[i].pr_who)) == NULL)
+ proc_error (pi, "update_threads, create_procinfo", __LINE__);
+
+ memcpy (&thread->prstatus, &prstatus[i], sizeof (*prstatus));
+ thread->status_valid = 1;
+ }
+ pi->threads_valid = 1;
+ do_cleanups (old_chain);
+ return 1;
+}
+#else
+#ifdef NEW_PROC_API
+/*
+ * Unixware and Solaris 6 (and later) version
+ */
+static void
+do_closedir_cleanup (void *dir)
+{
+ closedir (dir);
+}
+
+int
+proc_update_threads (procinfo *pi)
+{
+ char pathname[MAX_PROC_NAME_SIZE + 16];
+ struct dirent *direntry;
+ struct cleanup *old_chain = NULL;
+ procinfo *thread;
+ DIR *dirp;
+ int lwpid;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
+
+ /*
+ * Unixware
+ *
+ * Note: this brute-force method is the only way I know of
+ * to accomplish this task on Unixware. This method will
+ * also work on Solaris 2.6 and 2.7. There is a much simpler
+ * and more elegant way to do this on Solaris, but the margins
+ * of this manuscript are too small to write it here... ;-)
+ */
+
+ strcpy (pathname, pi->pathname);
+ strcat (pathname, "/lwp");
+ if ((dirp = opendir (pathname)) == NULL)
+ proc_error (pi, "update_threads, opendir", __LINE__);
+
+ old_chain = make_cleanup (do_closedir_cleanup, dirp);
+ while ((direntry = readdir (dirp)) != NULL)
+ if (direntry->d_name[0] != '.') /* skip '.' and '..' */
+ {
+ lwpid = atoi (&direntry->d_name[0]);
+ if ((thread = create_procinfo (pi->pid, lwpid)) == NULL)
+ proc_error (pi, "update_threads, create_procinfo", __LINE__);
+ }
+ pi->threads_valid = 1;
+ do_cleanups (old_chain);
+ return 1;
+}
+#else
+#ifdef PIOCTLIST
+/*
+ * OSF version
+ */
+int
+proc_update_threads (procinfo *pi)
+{
+ int nthreads, i;
+ tid_t *threads;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ proc_iterate_over_threads (pi, proc_delete_dead_threads, NULL);
+
+ nthreads = proc_get_nthreads (pi);
+ if (nthreads < 2)
+ return 0; /* nothing to do for 1 or fewer threads */
+
+ threads = xmalloc (nthreads * sizeof (tid_t));
+
+ if (ioctl (pi->ctl_fd, PIOCTLIST, threads) < 0)
+ proc_error (pi, "procfs: update_threads (PIOCTLIST)", __LINE__);
+
+ for (i = 0; i < nthreads; i++)
+ {
+ if (!find_procinfo (pi->pid, threads[i]))
+ if (!create_procinfo (pi->pid, threads[i]))
+ proc_error (pi, "update_threads, create_procinfo", __LINE__);
+ }
+ pi->threads_valid = 1;
+ return 1;
+}
+#else
+/*
+ * Default version
+ */
+int
+proc_update_threads (procinfo *pi)
+{
+ return 0;
+}
+#endif /* OSF PIOCTLIST */
+#endif /* NEW_PROC_API */
+#endif /* SOL 2.5 PIOCLSTATUS */
+
+/*
+ * Function: proc_iterate_over_threads
+ *
+ * Description:
+ * Given a pointer to a function, call that function once
+ * for each lwp in the procinfo list, until the function
+ * returns non-zero, in which event return the value
+ * returned by the function.
+ *
+ * Note: this function does NOT call update_threads.
+ * If you want to discover new threads first, you must
+ * call that function explicitly. This function just makes
+ * a quick pass over the currently-known procinfos.
+ *
+ * Arguments:
+ * pi - parent process procinfo
+ * func - per-thread function
+ * ptr - opaque parameter for function.
+ *
+ * Return:
+ * First non-zero return value from the callee, or zero.
+ */
+
+int
+proc_iterate_over_threads (procinfo *pi,
+ int (*func) (procinfo *, procinfo *, void *),
+ void *ptr)
+{
+ procinfo *thread, *next;
+ int retval = 0;
+
+ /*
+ * We should never have to apply this operation to any procinfo
+ * except the one for the main process. If that ever changes
+ * for any reason, then take out the following clause and
+ * replace it with one that makes sure the ctl_fd is open.
+ */
+
+ if (pi->tid != 0)
+ pi = find_procinfo_or_die (pi->pid, 0);
+
+ for (thread = pi->thread_list; thread != NULL; thread = next)
+ {
+ next = thread->next; /* in case thread is destroyed */
+ if ((retval = (*func) (pi, thread, ptr)) != 0)
+ break;
+ }
+
+ return retval;
+}
+
+/* =================== END, Thread "MODULE" =================== */
+
+/* =================== END, /proc "MODULE" =================== */
+
+/* =================== GDB "MODULE" =================== */
+
+/*
+ * Here are all of the gdb target vector functions and their friends.
+ */
+
+static ptid_t do_attach (ptid_t ptid);
+static void do_detach (int signo);
+static int register_gdb_signals (procinfo *, gdb_sigset_t *);
+
+/*
+ * Function: procfs_debug_inferior
+ *
+ * Sets up the inferior to be debugged.
+ * Registers to trace signals, hardware faults, and syscalls.
+ * Note: does not set RLC flag: caller may want to customize that.
+ *
+ * Returns: zero for success (note! unlike most functions in this module)
+ * On failure, returns the LINE NUMBER where it failed!
+ */
+
+static int
+procfs_debug_inferior (procinfo *pi)
+{
+ fltset_t traced_faults;
+ gdb_sigset_t traced_signals;
+ sysset_t *traced_syscall_entries;
+ sysset_t *traced_syscall_exits;
+ int status;
+
+#ifdef PROCFS_DONT_TRACE_FAULTS
+ /* On some systems (OSF), we don't trace hardware faults.
+ Apparently it's enough that we catch them as signals.
+ Wonder why we don't just do that in general? */
+ premptyset (&traced_faults); /* don't trace faults. */
+#else
+ /* Register to trace hardware faults in the child. */
+ prfillset (&traced_faults); /* trace all faults... */
+ prdelset (&traced_faults, FLTPAGE); /* except page fault. */
+#endif
+ if (!proc_set_traced_faults (pi, &traced_faults))
+ return __LINE__;
+
+ /* Register to trace selected signals in the child. */
+ premptyset (&traced_signals);
+ if (!register_gdb_signals (pi, &traced_signals))
+ return __LINE__;
+
+
+ /* Register to trace the 'exit' system call (on entry). */
+ traced_syscall_entries = sysset_t_alloc (pi);
+ gdb_premptysysset (traced_syscall_entries);
+#ifdef SYS_exit
+ gdb_praddsysset (traced_syscall_entries, SYS_exit);
+#endif
+#ifdef SYS_lwpexit
+ gdb_praddsysset (traced_syscall_entries, SYS_lwpexit); /* And _lwp_exit... */
+#endif
+#ifdef SYS_lwp_exit
+ gdb_praddsysset (traced_syscall_entries, SYS_lwp_exit);
+#endif
+#ifdef DYNAMIC_SYSCALLS
+ {
+ int callnum = find_syscall (pi, "_exit");
+ if (callnum >= 0)
+ gdb_praddsysset (traced_syscall_entries, callnum);
+ }
+#endif
+
+ status = proc_set_traced_sysentry (pi, traced_syscall_entries);
+ xfree (traced_syscall_entries);
+ if (!status)
+ return __LINE__;
+
+#ifdef PRFS_STOPEXEC /* defined on OSF */
+ /* OSF method for tracing exec syscalls. Quoting:
+ Under Alpha OSF/1 we have to use a PIOCSSPCACT ioctl to trace
+ exits from exec system calls because of the user level loader. */
+ /* FIXME: make nice and maybe move into an access function. */
+ {
+ int prfs_flags;
+
+ if (ioctl (pi->ctl_fd, PIOCGSPCACT, &prfs_flags) < 0)
+ return __LINE__;
+
+ prfs_flags |= PRFS_STOPEXEC;
+
+ if (ioctl (pi->ctl_fd, PIOCSSPCACT, &prfs_flags) < 0)
+ return __LINE__;
+ }
+#else /* not PRFS_STOPEXEC */
+ /* Everyone else's (except OSF) method for tracing exec syscalls */
+ /* GW: Rationale...
+ Not all systems with /proc have all the exec* syscalls with the same
+ names. On the SGI, for example, there is no SYS_exec, but there
+ *is* a SYS_execv. So, we try to account for that. */
+
+ traced_syscall_exits = sysset_t_alloc (pi);
+ gdb_premptysysset (traced_syscall_exits);
+#ifdef SYS_exec
+ gdb_praddsysset (traced_syscall_exits, SYS_exec);
+#endif
+#ifdef SYS_execve
+ gdb_praddsysset (traced_syscall_exits, SYS_execve);
+#endif
+#ifdef SYS_execv
+ gdb_praddsysset (traced_syscall_exits, SYS_execv);
+#endif
+
+#ifdef SYS_lwpcreate
+ gdb_praddsysset (traced_syscall_exits, SYS_lwpcreate);
+ gdb_praddsysset (traced_syscall_exits, SYS_lwpexit);
+#endif
+
+#ifdef SYS_lwp_create /* FIXME: once only, please */
+ gdb_praddsysset (traced_syscall_exits, SYS_lwp_create);
+ gdb_praddsysset (traced_syscall_exits, SYS_lwp_exit);
+#endif
+
+#ifdef DYNAMIC_SYSCALLS
+ {
+ int callnum = find_syscall (pi, "execve");
+ if (callnum >= 0)
+ gdb_praddsysset (traced_syscall_exits, callnum);
+ callnum = find_syscall (pi, "ra_execve");
+ if (callnum >= 0)
+ gdb_praddsysset (traced_syscall_exits, callnum);
+ }
+#endif
+
+ status = proc_set_traced_sysexit (pi, traced_syscall_exits);
+ xfree (traced_syscall_exits);
+ if (!status)
+ return __LINE__;
+
+#endif /* PRFS_STOPEXEC */
+ return 0;
+}
+
+static void
+procfs_attach (char *args, int from_tty)
+{
+ char *exec_file;
+ int pid;
+
+ if (!args)
+ error_no_arg ("process-id to attach");
+
+ pid = atoi (args);
+ if (pid == getpid ())
+ error ("Attaching GDB to itself is not a good idea...");
+
+ if (from_tty)
+ {
+ exec_file = get_exec_file (0);
+
+ if (exec_file)
+ printf_filtered ("Attaching to program `%s', %s\n",
+ exec_file, target_pid_to_str (pid_to_ptid (pid)));
+ else
+ printf_filtered ("Attaching to %s\n",
+ target_pid_to_str (pid_to_ptid (pid)));
+
+ fflush (stdout);
+ }
+ inferior_ptid = do_attach (pid_to_ptid (pid));
+ push_target (&procfs_ops);
+}
+
+static void
+procfs_detach (char *args, int from_tty)
+{
+ char *exec_file;
+ int signo = 0;
+
+ if (from_tty)
+ {
+ exec_file = get_exec_file (0);
+ if (exec_file == 0)
+ exec_file = "";
+ printf_filtered ("Detaching from program: %s %s\n",
+ exec_file, target_pid_to_str (inferior_ptid));
+ fflush (stdout);
+ }
+ if (args)
+ signo = atoi (args);
+
+ do_detach (signo);
+ inferior_ptid = null_ptid;
+ unpush_target (&procfs_ops); /* Pop out of handling an inferior */
+}
+
+static ptid_t
+do_attach (ptid_t ptid)
+{
+ procinfo *pi;
+ int fail;
+
+ if ((pi = create_procinfo (PIDGET (ptid), 0)) == NULL)
+ perror ("procfs: out of memory in 'attach'");
+
+ if (!open_procinfo_files (pi, FD_CTL))
+ {
+ fprintf_filtered (gdb_stderr, "procfs:%d -- ", __LINE__);
+ sprintf (errmsg, "do_attach: couldn't open /proc file for process %d",
+ PIDGET (ptid));
+ dead_procinfo (pi, errmsg, NOKILL);
+ }
+
+ /* Stop the process (if it isn't already stopped). */
+ if (proc_flags (pi) & (PR_STOPPED | PR_ISTOP))
+ {
+ pi->was_stopped = 1;
+ proc_prettyprint_why (proc_why (pi), proc_what (pi), 1);
+ }
+ else
+ {
+ pi->was_stopped = 0;
+ /* Set the process to run again when we close it. */
+ if (!proc_set_run_on_last_close (pi))
+ dead_procinfo (pi, "do_attach: couldn't set RLC.", NOKILL);
+
+ /* Now stop the process. */
+ if (!proc_stop_process (pi))
+ dead_procinfo (pi, "do_attach: couldn't stop the process.", NOKILL);
+ pi->ignore_next_sigstop = 1;
+ }
+ /* Save some of the /proc state to be restored if we detach. */
+ if (!proc_get_traced_faults (pi, &pi->saved_fltset))
+ dead_procinfo (pi, "do_attach: couldn't save traced faults.", NOKILL);
+ if (!proc_get_traced_signals (pi, &pi->saved_sigset))
+ dead_procinfo (pi, "do_attach: couldn't save traced signals.", NOKILL);
+ if (!proc_get_traced_sysentry (pi, pi->saved_entryset))
+ dead_procinfo (pi, "do_attach: couldn't save traced syscall entries.",
+ NOKILL);
+ if (!proc_get_traced_sysexit (pi, pi->saved_exitset))
+ dead_procinfo (pi, "do_attach: couldn't save traced syscall exits.",
+ NOKILL);
+ if (!proc_get_held_signals (pi, &pi->saved_sighold))
+ dead_procinfo (pi, "do_attach: couldn't save held signals.", NOKILL);
+
+ if ((fail = procfs_debug_inferior (pi)) != 0)
+ dead_procinfo (pi, "do_attach: failed in procfs_debug_inferior", NOKILL);
+
+ /* Let GDB know that the inferior was attached. */
+ attach_flag = 1;
+ return MERGEPID (pi->pid, proc_get_current_thread (pi));
+}
+
+static void
+do_detach (int signo)
+{
+ procinfo *pi;
+
+ /* Find procinfo for the main process */
+ pi = find_procinfo_or_die (PIDGET (inferior_ptid), 0); /* FIXME: threads */
+ if (signo)
+ if (!proc_set_current_signal (pi, signo))
+ proc_warn (pi, "do_detach, set_current_signal", __LINE__);
+
+ if (!proc_set_traced_signals (pi, &pi->saved_sigset))
+ proc_warn (pi, "do_detach, set_traced_signal", __LINE__);
+
+ if (!proc_set_traced_faults (pi, &pi->saved_fltset))
+ proc_warn (pi, "do_detach, set_traced_faults", __LINE__);
+
+ if (!proc_set_traced_sysentry (pi, pi->saved_entryset))
+ proc_warn (pi, "do_detach, set_traced_sysentry", __LINE__);
+
+ if (!proc_set_traced_sysexit (pi, pi->saved_exitset))
+ proc_warn (pi, "do_detach, set_traced_sysexit", __LINE__);
+
+ if (!proc_set_held_signals (pi, &pi->saved_sighold))
+ proc_warn (pi, "do_detach, set_held_signals", __LINE__);
+
+ if (signo || (proc_flags (pi) & (PR_STOPPED | PR_ISTOP)))
+ if (signo || !(pi->was_stopped) ||
+ query ("Was stopped when attached, make it runnable again? "))
+ {
+ /* Clear any pending signal. */
+ if (!proc_clear_current_fault (pi))
+ proc_warn (pi, "do_detach, clear_current_fault", __LINE__);
+
+ if (signo == 0 && !proc_clear_current_signal (pi))
+ proc_warn (pi, "do_detach, clear_current_signal", __LINE__);
+
+ if (!proc_set_run_on_last_close (pi))
+ proc_warn (pi, "do_detach, set_rlc", __LINE__);
+ }
+
+ attach_flag = 0;
+ destroy_procinfo (pi);
+}
+
+/*
+ * fetch_registers
+ *
+ * Since the /proc interface cannot give us individual registers,
+ * we pay no attention to the (regno) argument, and just fetch them all.
+ * This results in the possibility that we will do unnecessarily many
+ * fetches, since we may be called repeatedly for individual registers.
+ * So we cache the results, and mark the cache invalid when the process
+ * is resumed.
+ */
+
+static void
+procfs_fetch_registers (int regno)
+{
+ gdb_fpregset_t *fpregs;
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid;
+ int tid;
+
+ pid = PIDGET (inferior_ptid);
+ tid = TIDGET (inferior_ptid);
+
+ /* First look up procinfo for the main process. */
+ pi = find_procinfo_or_die (pid, 0);
+
+ /* If the event thread is not the same as GDB's requested thread
+ (ie. inferior_ptid), then look up procinfo for the requested
+ thread. */
+ if ((tid != 0) &&
+ (tid != proc_get_current_thread (pi)))
+ pi = find_procinfo_or_die (pid, tid);
+
+ if (pi == NULL)
+ error ("procfs: fetch_registers failed to find procinfo for %s",
+ target_pid_to_str (inferior_ptid));
+
+ if ((gregs = proc_get_gregs (pi)) == NULL)
+ proc_error (pi, "fetch_registers, get_gregs", __LINE__);
+
+ supply_gregset (gregs);
+
+ if (FP0_REGNUM >= 0) /* need floating point? */
+ {
+ if ((regno >= 0 && regno < FP0_REGNUM) ||
+ regno == PC_REGNUM ||
+ (NPC_REGNUM >= 0 && regno == NPC_REGNUM) ||
+ regno == FP_REGNUM ||
+ regno == SP_REGNUM)
+ return; /* not a floating point register */
+
+ if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ proc_error (pi, "fetch_registers, get_fpregs", __LINE__);
+
+ supply_fpregset (fpregs);
+ }
+}
+
+/* Get ready to modify the registers array. On machines which store
+ individual registers, this doesn't need to do anything. On
+ machines which store all the registers in one fell swoop, such as
+ /proc, this makes sure that registers contains all the registers
+ from the program being debugged. */
+
+static void
+procfs_prepare_to_store (void)
+{
+#ifdef CHILD_PREPARE_TO_STORE
+ CHILD_PREPARE_TO_STORE ();
+#endif
+}
+
+/*
+ * store_registers
+ *
+ * Since the /proc interface will not read individual registers,
+ * we will cache these requests until the process is resumed, and
+ * only then write them back to the inferior process.
+ *
+ * FIXME: is that a really bad idea? Have to think about cases
+ * where writing one register might affect the value of others, etc.
+ */
+
+static void
+procfs_store_registers (int regno)
+{
+ gdb_fpregset_t *fpregs;
+ gdb_gregset_t *gregs;
+ procinfo *pi;
+ int pid;
+ int tid;
+
+ pid = PIDGET (inferior_ptid);
+ tid = TIDGET (inferior_ptid);
+
+ /* First find procinfo for main process */
+ pi = find_procinfo_or_die (pid, 0);
+
+ /* If current lwp for process is not the same as requested thread
+ (ie. inferior_ptid), then find procinfo for the requested thread. */
+
+ if ((tid != 0) &&
+ (tid != proc_get_current_thread (pi)))
+ pi = find_procinfo_or_die (pid, tid);
+
+ if (pi == NULL)
+ error ("procfs: store_registers: failed to find procinfo for %s",
+ target_pid_to_str (inferior_ptid));
+
+ if ((gregs = proc_get_gregs (pi)) == NULL)
+ proc_error (pi, "store_registers, get_gregs", __LINE__);
+
+ fill_gregset (gregs, regno);
+ if (!proc_set_gregs (pi))
+ proc_error (pi, "store_registers, set_gregs", __LINE__);
+
+ if (FP0_REGNUM >= 0) /* need floating point? */
+ {
+ if ((regno >= 0 && regno < FP0_REGNUM) ||
+ regno == PC_REGNUM ||
+ (NPC_REGNUM >= 0 && regno == NPC_REGNUM) ||
+ regno == FP_REGNUM ||
+ regno == SP_REGNUM)
+ return; /* not a floating point register */
+
+ if ((fpregs = proc_get_fpregs (pi)) == NULL)
+ proc_error (pi, "store_registers, get_fpregs", __LINE__);
+
+ fill_fpregset (fpregs, regno);
+ if (!proc_set_fpregs (pi))
+ proc_error (pi, "store_registers, set_fpregs", __LINE__);
+ }
+}
+
+static int
+syscall_is_lwp_exit (procinfo *pi, int scall)
+{
+
+#ifdef SYS_lwp_exit
+ if (scall == SYS_lwp_exit)
+ return 1;
+#endif
+#ifdef SYS_lwpexit
+ if (scall == SYS_lwpexit)
+ return 1;
+#endif
+ return 0;
+}
+
+static int
+syscall_is_exit (procinfo *pi, int scall)
+{
+#ifdef SYS_exit
+ if (scall == SYS_exit)
+ return 1;
+#endif
+#ifdef DYNAMIC_SYSCALLS
+ if (find_syscall (pi, "_exit") == scall)
+ return 1;
+#endif
+ return 0;
+}
+
+static int
+syscall_is_exec (procinfo *pi, int scall)
+{
+#ifdef SYS_exec
+ if (scall == SYS_exec)
+ return 1;
+#endif
+#ifdef SYS_execv
+ if (scall == SYS_execv)
+ return 1;