diff options
Diffstat (limited to 'gdb/gdbserver/linux-low.c')
-rw-r--r-- | gdb/gdbserver/linux-low.c | 539 |
1 files changed, 395 insertions, 144 deletions
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index ba1d7b4..eccc2e1 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -90,7 +90,10 @@ representation of the thread ID. ``all_lwps'' is keyed by the process ID - which on Linux is (presently) - the same as the LWP ID. */ + the same as the LWP ID. + + ``all_processes'' is keyed by the "overall process ID", which + GNU/Linux calls tgid, "thread group ID". */ struct inferior_list all_lwps; @@ -105,24 +108,28 @@ int stopping_threads; /* FIXME make into a target method? */ int using_threads = 1; -static int thread_db_active; static int must_set_ptrace_flags; -/* This flag is true iff we've just created or attached to a new inferior - but it has not stopped yet. As soon as it does, we need to call the - low target's arch_setup callback. */ +/* This flag is true iff we've just created or attached to our first + inferior but it has not stopped yet. As soon as it does, we need + to call the low target's arch_setup callback. Doing this only on + the first inferior avoids reinializing the architecture on every + inferior, and avoids messing with the register caches of the + already running inferiors. NOTE: this assumes all inferiors under + control of gdbserver have the same architecture. */ static int new_inferior; static void linux_resume_one_lwp (struct inferior_list_entry *entry, int step, int signal, siginfo_t *info); static void linux_resume (struct thread_resume *resume_info, size_t n); static void stop_all_lwps (void); -static int linux_wait_for_event (int pid, int *wstat, int options); +static int linux_wait_for_event (ptid_t ptid, int *wstat, int options); static int check_removed_breakpoint (struct lwp_info *event_child); -static void *add_lwp (unsigned long pid); +static void *add_lwp (ptid_t ptid); static int my_waitpid (int pid, int *status, int flags); static int linux_stopped_by_watchpoint (void); +static void mark_lwp_dead (struct lwp_info *lwp, int wstat); struct pending_signals { @@ -139,9 +146,6 @@ static char *disabled_regsets; static int num_regsets; #endif -/* FIXME: Delete eventually. */ -#define inferior_pid (lwpid_of (get_thread_lwp (current_inferior))) - /* The read/write ends of the pipe registered as waitable file in the event loop. */ static int linux_event_pipe[2] = { -1, -1 }; @@ -160,6 +164,24 @@ delete_lwp (struct lwp_info *lwp) free (lwp); } +/* Add a process to the common process list, and set its private + data. */ + +static struct process_info * +linux_add_process (int pid, int attached) +{ + struct process_info *proc; + + /* Is this the 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; +} + /* Handle a GNU/Linux extended wait response. If we see a clone event, we need to add the new LWP to our list (and not report the trap to higher layers). */ @@ -172,6 +194,7 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) if (event == PTRACE_EVENT_CLONE) { + ptid_t ptid; unsigned long new_pid; int ret, status = W_STOPCODE (SIGSTOP); @@ -195,9 +218,9 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) ptrace (PTRACE_SETOPTIONS, new_pid, 0, PTRACE_O_TRACECLONE); - new_lwp = (struct lwp_info *) add_lwp (new_pid); - add_thread (new_pid, new_lwp, new_pid); - new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp))); + ptid = ptid_build (pid_of (event_child), new_pid, 0); + new_lwp = (struct lwp_info *) add_lwp (ptid); + add_thread (ptid, new_lwp); /* Normally we will get the pending SIGSTOP. But in some cases we might get another signal delivered to the group first. @@ -266,14 +289,14 @@ get_stop_pc (void) } static void * -add_lwp (unsigned long pid) +add_lwp (ptid_t ptid) { struct lwp_info *lwp; lwp = (struct lwp_info *) xmalloc (sizeof (*lwp)); memset (lwp, 0, sizeof (*lwp)); - lwp->head.id = pid; + lwp->head.id = ptid; add_inferior_to_list (&all_lwps, &lwp->head); @@ -288,6 +311,7 @@ linux_create_inferior (char *program, char **allargs) { void *new_lwp; int pid; + ptid_t ptid; #if defined(__UCLIBC__) && defined(HAS_NOMMU) pid = vfork (); @@ -315,44 +339,58 @@ linux_create_inferior (char *program, char **allargs) _exit (0177); } - new_lwp = add_lwp (pid); - add_thread (pid, new_lwp, pid); + linux_add_process (pid, 0); + + ptid = ptid_build (pid, pid, 0); + new_lwp = add_lwp (ptid); + add_thread (ptid, new_lwp); must_set_ptrace_flags = 1; - new_inferior = 1; return pid; } /* Attach to an inferior process. */ -void -linux_attach_lwp (unsigned long pid) +static void +linux_attach_lwp_1 (unsigned long lwpid, int initial) { + ptid_t ptid; struct lwp_info *new_lwp; - if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0) + if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0) { - if (all_threads.head != NULL) + if (!initial) { /* If we fail to attach to an LWP, just warn. */ - fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", pid, + fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", lwpid, strerror (errno), errno); fflush (stderr); return; } else /* If we fail to attach to a process, report an error. */ - error ("Cannot attach to lwp %ld: %s (%d)\n", pid, + error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid, strerror (errno), errno); } /* FIXME: This intermittently fails. We need to wait for SIGSTOP first. */ - ptrace (PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE); + ptrace (PTRACE_SETOPTIONS, lwpid, 0, PTRACE_O_TRACECLONE); + + if (initial) + /* NOTE/FIXME: This lwp might have not been the tgid. */ + ptid = ptid_build (lwpid, lwpid, 0); + else + { + /* Note that extracting the pid from the current inferior is + safe, since we're always called in the context of the same + process as this new thread. */ + int pid = pid_of (get_thread_lwp (current_inferior)); + ptid = ptid_build (pid, lwpid, 0); + } - new_lwp = (struct lwp_info *) add_lwp (pid); - add_thread (pid, new_lwp, pid); - new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp))); + new_lwp = (struct lwp_info *) add_lwp (ptid); + add_thread (ptid, new_lwp); /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH brings it to a halt. @@ -389,42 +427,89 @@ linux_attach_lwp (unsigned long pid) new_lwp->stop_expected = 1; } +void +linux_attach_lwp (unsigned long lwpid) +{ + linux_attach_lwp_1 (lwpid, 0); +} + int linux_attach (unsigned long pid) { struct lwp_info *lwp; - linux_attach_lwp (pid); + linux_attach_lwp_1 (pid, 1); + + linux_add_process (pid, 1); if (!non_stop) { /* Don't ignore the initial SIGSTOP if we just attached to this process. It will be collected by wait shortly. */ - lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid); + lwp = (struct lwp_info *) find_inferior_id (&all_lwps, + ptid_build (pid, pid, 0)); lwp->stop_expected = 0; } - new_inferior = 1; + return 0; +} + +struct counter +{ + int pid; + int count; +}; + +static int +second_thread_of_pid_p (struct inferior_list_entry *entry, void *args) +{ + struct counter *counter = args; + + if (ptid_get_pid (entry->id) == counter->pid) + { + if (++counter->count > 1) + return 1; + } return 0; } -/* Kill the inferior process. Make us have no inferior. */ +static int +last_thread_of_process_p (struct thread_info *thread) +{ + ptid_t ptid = ((struct inferior_list_entry *)thread)->id; + int pid = ptid_get_pid (ptid); + struct counter counter = { pid , 0 }; -static void -linux_kill_one_lwp (struct inferior_list_entry *entry) + return (find_inferior (&all_threads, + second_thread_of_pid_p, &counter) == NULL); +} + +/* Kill the inferior lwp. */ + +static int +linux_kill_one_lwp (struct inferior_list_entry *entry, void *args) { struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); - int pid; int wstat; + int pid = * (int *) args; + + if (ptid_get_pid (entry->id) != pid) + return 0; /* 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; + + if (last_thread_of_process_p (thread)) + { + if (debug_threads) + fprintf (stderr, "lkop: is last of process %s\n", + target_pid_to_str (entry->id)); + return 0; + } /* If we're killing a running inferior, make sure it is stopped first, as PTRACE_KILL will not work otherwise. */ @@ -436,29 +521,35 @@ linux_kill_one_lwp (struct inferior_list_entry *entry) ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ - pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL); + pid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); } while (pid > 0 && WIFSTOPPED (wstat)); + + return 0; } -static void -linux_kill (void) +static int +linux_kill (int pid) { - struct thread_info *thread = (struct thread_info *) all_threads.head; + struct process_info *process; struct lwp_info *lwp; + struct thread_info *thread; int wstat; - int pid; + int lwpid; - if (thread == NULL) - return; + process = find_process_pid (pid); + if (process == NULL) + return -1; - for_each_inferior (&all_threads, linux_kill_one_lwp); + find_inferior (&all_threads, linux_kill_one_lwp, &pid); /* See the comment in linux_kill_one_lwp. We did not kill the first thread in the list, so do so now. */ - lwp = get_thread_lwp (thread); + lwp = find_lwp_pid (pid_to_ptid (pid)); + thread = get_lwp_thread (lwp); if (debug_threads) - fprintf (stderr, "lk_1: killing lwp %ld\n", lwpid_of (lwp)); + fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n", + lwpid_of (lwp), pid); /* If we're killing a running inferior, make sure it is stopped first, as PTRACE_KILL will not work otherwise. */ @@ -470,24 +561,29 @@ linux_kill (void) ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ - pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL); - } while (pid > 0 && WIFSTOPPED (wstat)); + lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); + } while (lwpid > 0 && WIFSTOPPED (wstat)); delete_lwp (lwp); - clear_inferiors (); + remove_process (process); + return 0; } -static void -linux_detach_one_lwp (struct inferior_list_entry *entry) +static int +linux_detach_one_lwp (struct inferior_list_entry *entry, void *args) { struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); + int pid = * (int *) args; + + if (ptid_get_pid (entry->id) != pid) + return 0; /* If we're detaching from a running inferior, make sure it is stopped first, as PTRACE_DETACH will not work otherwise. */ if (!lwp->stopped) { - int pid = lwpid_of (lwp); + int lwpid = lwpid_of (lwp); stopping_threads = 1; send_sigstop (&lwp->head); @@ -500,9 +596,9 @@ linux_detach_one_lwp (struct inferior_list_entry *entry) /* If LWP exits while we're trying to stop it, there's nothing left to do. */ - lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid); + lwp = find_lwp_pid (pid_to_ptid (lwpid)); if (lwp == NULL) - return; + return 0; } /* Make sure the process isn't stopped at a breakpoint that's @@ -519,7 +615,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry) lwp->stop_expected = 0; if (lwp->stopped) linux_resume_one_lwp (&lwp->head, 0, 0, NULL); - linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL); + linux_wait_for_event (lwp->head.id, &wstat, __WALL); } /* Flush any pending changes to the process's registers. */ @@ -530,29 +626,50 @@ linux_detach_one_lwp (struct inferior_list_entry *entry) ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0); delete_lwp (lwp); + return 0; } static int -linux_detach (void) +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 int +linux_detach (int pid) +{ + struct process_info *process; + + process = find_process_pid (pid); + if (process == NULL) + return -1; + + current_inferior = + (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid); + delete_all_breakpoints (); - for_each_inferior (&all_threads, linux_detach_one_lwp); - clear_inferiors (); + find_inferior (&all_threads, linux_detach_one_lwp, &pid); + remove_process (process); return 0; } static void -linux_join (void) +linux_join (int pid) { int status, ret; - struct thread_info *thread; - struct lwp_info *lwp; + struct process_info *process; - thread = (struct thread_info *) all_threads.head; - lwp = get_thread_lwp (thread); + process = find_process_pid (pid); + if (process == NULL) + return; do { - ret = my_waitpid (lwpid_of (lwp), &status, 0); + ret = my_waitpid (pid, &status, 0); if (WIFEXITED (status) || WIFSIGNALED (status)) break; } while (ret != -1 || errno != ECHILD); @@ -560,10 +677,15 @@ linux_join (void) /* Return nonzero if the given thread is still alive. */ static int -linux_thread_alive (unsigned long lwpid) +linux_thread_alive (ptid_t ptid) { - if (find_inferior_id (&all_threads, lwpid) != NULL) - return 1; + struct lwp_info *lwp = find_lwp_pid (ptid); + + /* We assume we always know if a thread exits. If a whole process + exited but we still haven't been able to report it to GDB, we'll + hold on to the last lwp of the dead process. */ + if (lwp != NULL) + return !lwp->dead; else return 0; } @@ -633,9 +755,16 @@ check_removed_breakpoint (struct lwp_info *event_child) /* Return 1 if this lwp has an interesting status pending. This function may silently resume an inferior lwp. */ static int -status_pending_p (struct inferior_list_entry *entry, void *dummy) +status_pending_p (struct inferior_list_entry *entry, void *arg) { struct lwp_info *lwp = (struct lwp_info *) entry; + ptid_t ptid = * (ptid_t *) arg; + + /* Check if we're only interested in events from a specific process + or its lwps. */ + if (!ptid_equal (minus_one_ptid, ptid) + && ptid_get_pid (ptid) != ptid_get_pid (lwp->head.id)) + return 0; if (lwp->status_pending_p && !lwp->suspended) if (check_removed_breakpoint (lwp)) @@ -653,15 +782,43 @@ status_pending_p (struct inferior_list_entry *entry, void *dummy) return (lwp->status_pending_p && !lwp->suspended); } +static int +same_lwp (struct inferior_list_entry *entry, void *data) +{ + ptid_t ptid = *(ptid_t *) data; + int lwp; + + if (ptid_get_lwp (ptid) != 0) + lwp = ptid_get_lwp (ptid); + else + lwp = ptid_get_pid (ptid); + + if (ptid_get_lwp (entry->id) == lwp) + return 1; + + return 0; +} + +struct lwp_info * +find_lwp_pid (ptid_t ptid) +{ + return (struct lwp_info*) find_inferior (&all_lwps, same_lwp, &ptid); +} + static struct lwp_info * -linux_wait_for_lwp (int pid, int *wstatp, int options) +linux_wait_for_lwp (ptid_t ptid, int *wstatp, int options) { int ret; - int to_wait_for = pid; + int to_wait_for = -1; struct lwp_info *child = NULL; if (debug_threads) - fprintf (stderr, "linux_wait_for_lwp: %d\n", pid); + fprintf (stderr, "linux_wait_for_lwp: %s\n", target_pid_to_str (ptid)); + + if (ptid_equal (ptid, minus_one_ptid)) + to_wait_for = -1; /* any child */ + else + to_wait_for = ptid_get_lwp (ptid); /* this lwp only */ options |= __WALL; @@ -679,7 +836,7 @@ retry: && WSTOPSIG (*wstatp) != 33))) fprintf (stderr, "Got an event from %d (%x)\n", ret, *wstatp); - child = (struct lwp_info *) find_inferior_id (&all_lwps, ret); + child = find_lwp_pid (pid_to_ptid (ret)); /* If we didn't find a process, one of two things presumably happened: - A process we started and then detached from has exited. Ignore it. @@ -716,7 +873,7 @@ retry: { struct thread_info *saved_inferior = current_inferior; current_inferior = (struct thread_info *) - find_inferior_id (&all_threads, lwpid_of (child)); + find_inferior_id (&all_threads, child->head.id); /* For testing only; i386_stop_pc prints out a diagnostic. */ if (the_low_target.get_pc != NULL) get_stop_pc (); @@ -733,29 +890,29 @@ retry: the stopped child otherwise. */ static int -linux_wait_for_event (int pid, int *wstat, int options) +linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) { CORE_ADDR stop_pc; struct lwp_info *event_child = NULL; int bp_status; struct lwp_info *requested_child = NULL; - /* Check for a process with a pending status. */ + /* Check for a lwp with a pending status. */ /* It is possible that the user changed the pending task's registers since it stopped. We correctly handle the change of PC if we hit a breakpoint (in check_removed_breakpoint); signals should be reported anyway. */ - if (pid == -1) + if (ptid_equal (ptid, minus_one_ptid) + || ptid_equal (pid_to_ptid (ptid_get_pid (ptid)), ptid)) { event_child = (struct lwp_info *) - find_inferior (&all_lwps, status_pending_p, NULL); + find_inferior (&all_lwps, status_pending_p, &ptid); if (debug_threads && event_child) fprintf (stderr, "Got a pending child %ld\n", lwpid_of (event_child)); } else { - requested_child = (struct lwp_info *) - find_inferior_id (&all_lwps, pid); + requested_child = find_lwp_pid (ptid); if (requested_child->status_pending_p && !check_removed_breakpoint (requested_child)) event_child = requested_child; @@ -779,7 +936,7 @@ linux_wait_for_event (int pid, int *wstat, int options) events. */ while (1) { - event_child = linux_wait_for_lwp (pid, wstat, options); + event_child = linux_wait_for_lwp (ptid, wstat, options); if ((options & WNOHANG) && event_child == NULL) return 0; @@ -792,19 +949,18 @@ linux_wait_for_event (int pid, int *wstat, int options) /* Check for thread exit. */ if (! WIFSTOPPED (*wstat)) { - int lwpid = lwpid_of (event_child); if (debug_threads) - fprintf (stderr, "LWP %d exiting\n", lwpid); + fprintf (stderr, "LWP %ld exiting\n", lwpid_of (event_child)); /* If the last thread is exiting, just return. */ - if (all_threads.head == all_threads.tail) + if (last_thread_of_process_p (current_inferior)) { if (debug_threads) - fprintf (stderr, "LWP %d is last lwp of process\n", lwpid); + fprintf (stderr, "LWP %ld is last lwp of process\n", + lwpid_of (event_child)); return lwpid_of (event_child); } - dead_thread_notify (thread_id_to_gdb_id (lwpid_of (event_child))); delete_lwp (event_child); if (!non_stop) @@ -824,7 +980,7 @@ linux_wait_for_event (int pid, int *wstat, int options) /* If we were waiting for this particular child to do something... well, it did something. */ if (requested_child != NULL) - return lwpid; + return lwpid_of (event_child); /* Wait for a more interesting event. */ continue; @@ -862,7 +1018,7 @@ linux_wait_for_event (int pid, int *wstat, int options) && !event_child->stepping && ( #ifdef USE_THREAD_DB - (thread_db_active + (current_process ()->private->thread_db_active && (WSTOPSIG (*wstat) == __SIGRTMIN || WSTOPSIG (*wstat) == __SIGRTMIN + 1)) || @@ -1000,16 +1156,56 @@ linux_wait_for_event (int pid, int *wstat, int options) return 0; } +static int +linux_wait_for_event (ptid_t ptid, int *wstat, int options) +{ + ptid_t wait_ptid; + + if (ptid_is_pid (ptid)) + { + /* A request to wait for a specific tgid. This is not possible + with waitpid, so instead, we wait for any child, and leave + children we're not interested in right now with a pending + status to report later. */ + wait_ptid = minus_one_ptid; + } + else + wait_ptid = ptid; + + while (1) + { + int event_pid; + + event_pid = linux_wait_for_event_1 (wait_ptid, wstat, options); + + if (event_pid > 0 + && ptid_is_pid (ptid) && ptid_get_pid (ptid) != event_pid) + { + struct lwp_info *event_child = find_lwp_pid (pid_to_ptid (event_pid)); + + if (! WIFSTOPPED (*wstat)) + mark_lwp_dead (event_child, *wstat); + else + { + event_child->status_pending_p = 1; + event_child->status_pending = *wstat; + } + } + else + return event_pid; + } +} + /* Wait for process, returns status. */ -static unsigned long -linux_wait_1 (struct target_waitstatus *ourstatus, int target_options) +static ptid_t +linux_wait_1 (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) { int w; struct thread_info *thread = NULL; struct lwp_info *lwp = NULL; int options; - int wait_pid = -1; int pid; /* Translate generic target options into linux options. */ @@ -1026,7 +1222,9 @@ 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 (!non_stop && cont_thread != 0 && cont_thread != -1) + if (!non_stop + && !ptid_equal (cont_thread, null_ptid) + && !ptid_equal (cont_thread, minus_one_ptid)) { thread = (struct thread_info *) find_inferior_id (&all_threads, cont_thread); @@ -1035,18 +1233,18 @@ retry: if (thread == NULL) { struct thread_resume resume_info; - resume_info.thread = -1; + resume_info.thread = minus_one_ptid; resume_info.kind = resume_continue; resume_info.sig = 0; linux_resume (&resume_info, 1); } else - wait_pid = cont_thread; + ptid = cont_thread; } - pid = linux_wait_for_event (wait_pid, &w, options); + pid = linux_wait_for_event (ptid, &w, options); if (pid == 0) /* only if TARGET_WNOHANG */ - return pid; + return null_ptid; lwp = get_thread_lwp (current_inferior); @@ -1067,16 +1265,15 @@ retry: Report the exit status of the last thread to exit. This matches LinuxThreads' behavior. */ - if (all_threads.head == all_threads.tail) + if (last_thread_of_process_p (current_inferior)) { if (WIFEXITED (w) || WIFSIGNALED (w)) { - int pid; - - pid = pid_of (lwp); + int pid = pid_of (lwp); + struct process_info *process = find_process_pid (pid); delete_lwp (lwp); - clear_inferiors (); + remove_process (process); current_inferior = NULL; @@ -1098,7 +1295,7 @@ retry: } - return pid; + return pid_to_ptid (pid); } } else @@ -1135,12 +1332,12 @@ retry: } if (debug_threads) - fprintf (stderr, "linux_wait ret = %ld, %d, %d\n", - lwpid_of (lwp), + fprintf (stderr, "linux_wait ret = %s, %d, %d\n", + target_pid_to_str (lwp->head.id), ourstatus->kind, ourstatus->value.sig); - return lwpid_of (lwp); + return lwp->head.id; } /* Get rid of any pending event in the pipe. */ @@ -1171,25 +1368,26 @@ async_file_mark (void) be awakened anyway. */ } -static unsigned long -linux_wait (struct target_waitstatus *ourstatus, int target_options) +static ptid_t +linux_wait (ptid_t ptid, + struct target_waitstatus *ourstatus, int target_options) { - unsigned long event_ptid; + ptid_t event_ptid; if (debug_threads) - fprintf (stderr, "linux_wait\n"); + fprintf (stderr, "linux_wait: [%s]\n", target_pid_to_str (ptid)); /* Flush the async file first. */ if (target_is_async_p ()) async_file_flush (); - event_ptid = linux_wait_1 (ourstatus, target_options); + event_ptid = linux_wait_1 (ptid, ourstatus, target_options); /* If at least one stop was reported, there may be more. A single SIGCHLD can signal more than one child stop. */ if (target_is_async_p () && (target_options & TARGET_WNOHANG) != 0 - && event_ptid != 0) + && !ptid_equal (event_ptid, null_ptid)) async_file_mark (); return event_ptid; @@ -1251,13 +1449,34 @@ send_sigstop (struct inferior_list_entry *entry) } static void +mark_lwp_dead (struct lwp_info *lwp, int wstat) +{ + /* It's dead, really. */ + lwp->dead = 1; + + /* Store the exit status for later. */ + lwp->status_pending_p = 1; + lwp->status_pending = wstat; + + /* So that check_removed_breakpoint doesn't try to figure out if + this is stopped at a breakpoint. */ + lwp->pending_is_breakpoint = 0; + + /* Prevent trying to stop it. */ + lwp->stopped = 1; + + /* No further stops are expected from a dead lwp. */ + lwp->stop_expected = 0; +} + +static void wait_for_sigstop (struct inferior_list_entry *entry) { struct lwp_info *lwp = (struct lwp_info *) entry; struct thread_info *saved_inferior; int wstat; - unsigned long saved_tid; - unsigned long ptid; + ptid_t saved_tid; + ptid_t ptid; if (lwp->stopped) return; @@ -1266,9 +1485,9 @@ wait_for_sigstop (struct inferior_list_entry *entry) if (saved_inferior != NULL) saved_tid = ((struct inferior_list_entry *) saved_inferior)->id; else - saved_tid = 0; /* avoid bogus unused warning */ + saved_tid = null_ptid; /* avoid bogus unused warning */ - ptid = lwpid_of (lwp); + ptid = lwp->head.id; linux_wait_for_event (ptid, &wstat, __WALL); @@ -1301,6 +1520,18 @@ wait_for_sigstop (struct inferior_list_entry *entry) } lwp->stop_expected = 1; } + else if (!WIFSTOPPED (wstat)) + { + if (debug_threads) + fprintf (stderr, "Process %ld exited while stopping LWPs\n", + lwpid_of (lwp)); + + /* Leave this status pending for the next time we're able to + report it. In the mean time, we'll report this lwp as dead + to GDB, so GDB doesn't try to read registers and memory from + it. */ + mark_lwp_dead (lwp, wstat); + } if (saved_inferior == NULL || linux_thread_alive (saved_tid)) current_inferior = saved_inferior; @@ -1474,11 +1705,19 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg) r = arg; for (ndx = 0; ndx < r->n; ndx++) - if (r->resume[ndx].thread == -1 || r->resume[ndx].thread == entry->id) - { - lwp->resume = &r->resume[ndx]; - return 0; - } + { + ptid_t ptid = r->resume[ndx].thread; + if (ptid_equal (ptid, minus_one_ptid) + || ptid_equal (ptid, entry->id) + || (ptid_is_pid (ptid) + && (ptid_get_pid (ptid) == pid_of (lwp))) + || (ptid_get_lwp (ptid) == -1 + && (ptid_get_pid (ptid) == pid_of (lwp)))) + { + lwp->resume = &r->resume[ndx]; + return 0; + } + } /* No resume action for this thread. */ lwp->resume = NULL; @@ -1550,7 +1789,7 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg) if (!lwp->stopped) { if (debug_threads) - fprintf (stderr, "running -> suspending %ld\n", lwpid_of (lwp)); + fprintf (stderr, "running -> suspending LWP %ld\n", lwpid_of (lwp)); lwp->suspended = 1; send_sigstop (&lwp->head); @@ -1596,7 +1835,7 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg) if (debug_threads) fprintf (stderr, "resuming LWP %ld\n", lwpid_of (lwp)); - if (lwp->resume->thread == -1 + if (ptid_equal (lwp->resume->thread, minus_one_ptid) && lwp->stepping && lwp->pending_is_breakpoint) step = 1; @@ -1685,6 +1924,7 @@ fetch_register (int regno) CORE_ADDR regaddr; int i, size; char *buf; + int pid; if (regno >= the_low_target.num_regs) return; @@ -1694,6 +1934,8 @@ fetch_register (int regno) regaddr = register_addr (regno); if (regaddr == -1) return; + + pid = lwpid_of (get_thread_lwp (current_inferior)); size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) & - sizeof (PTRACE_XFER_TYPE)); buf = alloca (size); @@ -1701,7 +1943,7 @@ fetch_register (int regno) { errno = 0; *(PTRACE_XFER_TYPE *) (buf + i) = - ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0); + ptrace (PTRACE_PEEKUSER, pid, (PTRACE_ARG3_TYPE) regaddr, 0); regaddr += sizeof (PTRACE_XFER_TYPE); if (errno != 0) { @@ -1766,10 +2008,11 @@ usr_store_inferior_registers (int regno) else collect_register (regno, buf); + pid = lwpid_of (get_thread_lwp (current_inferior)); for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + ptrace (PTRACE_POKEUSER, pid, (PTRACE_ARG3_TYPE) regaddr, *(PTRACE_XFER_TYPE *) (buf + i)); if (errno != 0) { @@ -1808,9 +2051,11 @@ regsets_fetch_inferior_registers () { struct regset_info *regset; int saw_general_regs = 0; + int pid; regset = target_regsets; + pid = lwpid_of (get_thread_lwp (current_inferior)); while (regset->size >= 0) { void *buf; @@ -1824,9 +2069,9 @@ regsets_fetch_inferior_registers () buf = xmalloc (regset->size); #ifndef __sparc__ - res = ptrace (regset->get_request, inferior_pid, 0, buf); + res = ptrace (regset->get_request, pid, 0, buf); #else - res = ptrace (regset->get_request, inferior_pid, buf, 0); + res = ptrace (regset->get_request, pid, buf, 0); #endif if (res < 0) { @@ -1840,8 +2085,8 @@ regsets_fetch_inferior_registers () else { char s[256]; - sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%ld", - inferior_pid); + sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d", + pid); perror (s); } } @@ -1861,9 +2106,11 @@ regsets_store_inferior_registers () { struct regset_info *regset; int saw_general_regs = 0; + int pid; regset = target_regsets; + pid = lwpid_of (get_thread_lwp (current_inferior)); while (regset->size >= 0) { void *buf; @@ -1881,9 +2128,9 @@ regsets_store_inferior_registers () in case there are any items in the kernel's regset that are not in gdbserver's regcache. */ #ifndef __sparc__ - res = ptrace (regset->get_request, inferior_pid, 0, buf); + res = ptrace (regset->get_request, pid, 0, buf); #else - res = ptrace (regset->get_request, inferior_pid, buf, 0); + res = ptrace (regset->get_request, pid, buf, 0); #endif if (res == 0) @@ -1893,9 +2140,9 @@ regsets_store_inferior_registers () /* Only now do we write the register set. */ #ifndef __sparc__ - res = ptrace (regset->set_request, inferior_pid, 0, buf); + res = ptrace (regset->set_request, pid, 0, buf); #else - res = ptrace (regset->set_request, inferior_pid, buf, 0); + res = ptrace (regset->set_request, pid, buf, 0); #endif } @@ -1979,13 +2226,14 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); int fd; char filename[64]; + int pid = lwpid_of (get_thread_lwp (current_inferior)); /* Try using /proc. Don't bother for one word. */ if (len >= 3 * sizeof (long)) { /* We could keep this file open and cache it - possibly one per thread. That requires some juggling, but is even faster. */ - sprintf (filename, "/proc/%ld/mem", inferior_pid); + sprintf (filename, "/proc/%d/mem", pid); fd = open (filename, O_RDONLY | O_LARGEFILE); if (fd == -1) goto no_proc; @@ -2013,8 +2261,7 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, - (PTRACE_ARG3_TYPE) addr, 0); + buffer[i] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0); if (errno) return errno; } @@ -2043,6 +2290,7 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); + int pid = lwpid_of (get_thread_lwp (current_inferior)); if (debug_threads) { @@ -2051,13 +2299,12 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) /* Fill start and end extra bytes of buffer with existing memory data. */ - buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid, - (PTRACE_ARG3_TYPE) addr, 0); + buffer[0] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0); if (count > 1) { buffer[count - 1] - = ptrace (PTRACE_PEEKTEXT, inferior_pid, + = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE)), 0); @@ -2072,7 +2319,7 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; - ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); + ptrace (PTRACE_POKETEXT, pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); if (errno) return errno; } @@ -2278,10 +2525,13 @@ static void linux_look_up_symbols (void) { #ifdef USE_THREAD_DB - if (thread_db_active) + struct process_info *proc = current_process (); + + if (proc->private->thread_db_active) return; - thread_db_active = thread_db_init (!linux_supports_tracefork_flag); + proc->private->thread_db_active + = thread_db_init (!linux_supports_tracefork_flag); #endif } @@ -2290,7 +2540,8 @@ linux_request_interrupt (void) { extern unsigned long signal_pid; - if (cont_thread != 0 && cont_thread != -1) + if (!ptid_equal (cont_thread, null_ptid) + && !ptid_equal (cont_thread, minus_one_ptid)) { struct lwp_info *lwp; int lwpid; @@ -2311,8 +2562,9 @@ linux_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len) { char filename[PATH_MAX]; int fd, n; + int pid = lwpid_of (get_thread_lwp (current_inferior)); - snprintf (filename, sizeof filename, "/proc/%ld/auxv", inferior_pid); + snprintf (filename, sizeof filename, "/proc/%d/auxv", pid); fd = open (filename, O_RDONLY); if (fd < 0) @@ -2685,7 +2937,6 @@ initialize_low (void) { struct sigaction sigchld_action; memset (&sigchld_action, 0, sizeof (sigchld_action)); - thread_db_active = 0; set_target_ops (&linux_target_ops); set_breakpoint_data (the_low_target.breakpoint, the_low_target.breakpoint_len); |