X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Flinux-low.c;h=06ec5763c624d66f1be540f7268688da6b459215;hb=5f572decf9c6fe42f07706514b5056e7fc65cfef;hp=df711035a0a037cb87401d0476f155766a2c4eac;hpb=7325beb467a684cf54173330f11673ab68522c95;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index df711035a0..06ec5763c6 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -1,6 +1,5 @@ /* Low level interface to ptrace, for the remote server for GDB. - Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 1995-1996, 1998-2012 Free Software Foundation, Inc. This file is part of GDB. @@ -20,6 +19,7 @@ #include "server.h" #include "linux-low.h" #include "linux-osdata.h" +#include "agent.h" #include #include @@ -93,11 +93,54 @@ struct inferior_list all_lwps; -/* A list of all unknown processes which receive stop signals. Some other - process will presumably claim each of these as forked children - momentarily. */ +/* A list of all unknown processes which receive stop signals. Some + other process will presumably claim each of these as forked + children momentarily. */ -struct inferior_list stopped_pids; +struct simple_pid_list +{ + /* The process ID. */ + int pid; + + /* The status as reported by waitpid. */ + int status; + + /* Next in chain. */ + struct simple_pid_list *next; +}; +struct simple_pid_list *stopped_pids; + +/* Trivial list manipulation functions to keep track of a list of new + stopped processes. */ + +static void +add_to_pid_list (struct simple_pid_list **listp, int pid, int status) +{ + struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list)); + + new_pid->pid = pid; + new_pid->status = status; + new_pid->next = *listp; + *listp = new_pid; +} + +static int +pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp) +{ + struct simple_pid_list **p; + + for (p = listp; *p != NULL; p = &(*p)->next) + if ((*p)->pid == pid) + { + struct simple_pid_list *next = (*p)->next; + + *statusp = (*p)->status; + xfree (*p); + *p = next; + return 1; + } + return 0; +} /* FIXME this is a bit of a hack, and could be removed. */ int stopping_threads; @@ -187,32 +230,6 @@ static int linux_event_pipe[2] = { -1, -1 }; static void send_sigstop (struct lwp_info *lwp); static void wait_for_sigstop (struct inferior_list_entry *entry); -/* Accepts an integer PID; Returns a string representing a file that - can be opened to get info for the child process. - Space for the result is malloc'd, caller must free. */ - -char * -linux_child_pid_to_exec_file (int pid) -{ - char *name1, *name2; - - name1 = xmalloc (MAXPATHLEN); - name2 = xmalloc (MAXPATHLEN); - memset (name2, 0, MAXPATHLEN); - - sprintf (name1, "/proc/%d/exe", pid); - if (readlink (name1, name2, MAXPATHLEN) > 0) - { - free (name1); - return name2; - } - else - { - free (name2); - return name1; - } -} - /* Return non-zero if HEADER is a 64-bit ELF file. */ static int @@ -229,7 +246,7 @@ elf_64_header_p (const Elf64_Ehdr *header) zero if the file is not a 64-bit ELF file, and -1 if the file is not accessible or doesn't exist. */ -int +static int elf_64_file_p (const char *file) { Elf64_Ehdr header; @@ -249,6 +266,18 @@ elf_64_file_p (const char *file) return elf_64_header_p (&header); } +/* Accepts an integer PID; Returns true if the executable PID is + running is a 64-bit ELF file.. */ + +int +linux_pid_exe_is_elf_64_file (int pid) +{ + char file[MAXPATHLEN]; + + sprintf (file, "/proc/%d/exe", pid); + return elf_64_file_p (file); +} + static void delete_lwp (struct lwp_info *lwp) { @@ -368,12 +397,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat) { ptid_t ptid; unsigned long new_pid; - int ret, status = W_STOPCODE (SIGSTOP); + int ret, status; ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_child), 0, &new_pid); /* If we haven't already seen the new PID stop, wait for it now. */ - if (! pull_pid_from_list (&stopped_pids, new_pid)) + if (!pull_pid_from_list (&stopped_pids, new_pid, &status)) { /* The new child has a pending SIGSTOP. We can't affect it until it hits the SIGSTOP, but we're already attached. */ @@ -569,6 +598,19 @@ linux_create_inferior (char *program, char **allargs) setpgid (0, 0); + /* If gdbserver is connected to gdb via stdio, redirect the inferior's + stdout to stderr so that inferior i/o doesn't corrupt the connection. + Also, redirect stdin to /dev/null. */ + if (remote_connection_is_stdio ()) + { + close (0); + open ("/dev/null", O_RDONLY); + dup2 (2, 1); + if (write (2, "stdin/stdout redirected\n", + sizeof ("stdin/stdout redirected\n") - 1) < 0) + /* Errors ignored. */; + } + execv (program, allargs); if (errno == ENOENT) execvp (program, allargs); @@ -618,10 +660,10 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) fflush (stderr); return; } - else - /* If we fail to attach to a process, report an error. */ - error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid, - strerror (errno), errno); + + /* If we fail to attach to a process, report an error. */ + error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid, + strerror (errno), errno); } if (initial) @@ -645,6 +687,33 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial) ptrace call on this LWP. */ new_lwp->must_set_ptrace_flags = 1; + if (linux_proc_pid_is_stopped (lwpid)) + { + if (debug_threads) + fprintf (stderr, + "Attached to a stopped process\n"); + + /* The process is definitely stopped. It is in a job control + stop, unless the kernel predates the TASK_STOPPED / + TASK_TRACED distinction, in which case it might be in a + ptrace stop. Make sure it is in a ptrace stop; from there we + can kill it, signal it, et cetera. + + First make sure there is a pending SIGSTOP. Since we are + already attached, the process can not transition from stopped + to running without a PTRACE_CONT; so we know this signal will + go into the queue. The SIGSTOP generated by PTRACE_ATTACH is + probably already in the queue (unless this kernel is old + enough to use TASK_STOPPED for ptrace stops); but since + SIGSTOP is not an RT signal, it can only be queued once. */ + kill_lwp (lwpid, SIGSTOP); + + /* Finally, resume the stopped process. This will deliver the + SIGSTOP (or a higher priority signal, just like normal + PTRACE_ATTACH), which we'll catch later on. */ + ptrace (PTRACE_CONT, lwpid, 0, 0); + } + /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH brings it to a halt. @@ -803,10 +872,49 @@ last_thread_of_process_p (struct thread_info *thread) second_thread_of_pid_p, &counter) == NULL); } -/* Kill the inferior lwp. */ +/* Kill LWP. */ + +static void +linux_kill_one_lwp (struct lwp_info *lwp) +{ + int pid = lwpid_of (lwp); + + /* PTRACE_KILL is unreliable. After stepping into a signal handler, + there is no signal context, and ptrace(PTRACE_KILL) (or + ptrace(PTRACE_CONT, SIGKILL), pretty much the same) acts like + ptrace(CONT, pid, 0,0) and just resumes the tracee. A better + alternative is to kill with SIGKILL. We only need one SIGKILL + per process, not one for each thread. But since we still support + linuxthreads, and we also support debugging programs using raw + clone without CLONE_THREAD, we send one for each thread. For + years, we used PTRACE_KILL only, so we're being a bit paranoid + about some old kernels where PTRACE_KILL might work better + (dubious if there are any such, but that's why it's paranoia), so + we try SIGKILL first, PTRACE_KILL second, and so we're fine + everywhere. */ + + errno = 0; + kill (pid, SIGKILL); + if (debug_threads) + fprintf (stderr, + "LKL: kill (SIGKILL) %s, 0, 0 (%s)\n", + target_pid_to_str (ptid_of (lwp)), + errno ? strerror (errno) : "OK"); + + errno = 0; + ptrace (PTRACE_KILL, pid, 0, 0); + if (debug_threads) + fprintf (stderr, + "LKL: PTRACE_KILL %s, 0, 0 (%s)\n", + target_pid_to_str (ptid_of (lwp)), + errno ? strerror (errno) : "OK"); +} + +/* Callback for `find_inferior'. Kills an lwp of a given process, + except the leader. */ static int -linux_kill_one_lwp (struct inferior_list_entry *entry, void *args) +kill_one_lwp_callback (struct inferior_list_entry *entry, void *args) { struct thread_info *thread = (struct thread_info *) entry; struct lwp_info *lwp = get_thread_lwp (thread); @@ -831,7 +939,7 @@ linux_kill_one_lwp (struct inferior_list_entry *entry, void *args) do { - ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); + linux_kill_one_lwp (lwp); /* Make sure it died. The loop is most likely unnecessary. */ pid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); @@ -856,23 +964,32 @@ linux_kill (int pid) first, as PTRACE_KILL will not work otherwise. */ stop_all_lwps (0, NULL); - find_inferior (&all_threads, linux_kill_one_lwp, &pid); + find_inferior (&all_threads, kill_one_lwp_callback , &pid); /* See the comment in linux_kill_one_lwp. We did not kill the first thread in the list, so do so now. */ lwp = find_lwp_pid (pid_to_ptid (pid)); - if (debug_threads) - fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n", - lwpid_of (lwp), pid); - - do + if (lwp == NULL) + { + if (debug_threads) + fprintf (stderr, "lk_1: cannot find lwp %ld, for pid: %d\n", + lwpid_of (lwp), pid); + } + else { - ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0); + if (debug_threads) + fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n", + lwpid_of (lwp), pid); - /* Make sure it died. The loop is most likely unnecessary. */ - lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); - } while (lwpid > 0 && WIFSTOPPED (wstat)); + do + { + linux_kill_one_lwp (lwp); + + /* Make sure it died. The loop is most likely unnecessary. */ + lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL); + } while (lwpid > 0 && WIFSTOPPED (wstat)); + } the_target->mourn (process); @@ -882,34 +999,127 @@ linux_kill (int pid) return 0; } +/* Get pending signal of THREAD, for detaching purposes. This is the + signal the thread last stopped for, which we need to deliver to the + thread when detaching, otherwise, it'd be suppressed/lost. */ + +static int +get_detach_signal (struct thread_info *thread) +{ + enum target_signal signo = TARGET_SIGNAL_0; + int status; + struct lwp_info *lp = get_thread_lwp (thread); + + if (lp->status_pending_p) + status = lp->status_pending; + else + { + /* If the thread had been suspended by gdbserver, and it stopped + cleanly, then it'll have stopped with SIGSTOP. But we don't + want to deliver that SIGSTOP. */ + if (thread->last_status.kind != TARGET_WAITKIND_STOPPED + || thread->last_status.value.sig == TARGET_SIGNAL_0) + return 0; + + /* Otherwise, we may need to deliver the signal we + intercepted. */ + status = lp->last_status; + } + + if (!WIFSTOPPED (status)) + { + if (debug_threads) + fprintf (stderr, + "GPS: lwp %s hasn't stopped: no pending signal\n", + target_pid_to_str (ptid_of (lp))); + return 0; + } + + /* Extended wait statuses aren't real SIGTRAPs. */ + if (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0) + { + if (debug_threads) + fprintf (stderr, + "GPS: lwp %s had stopped with extended " + "status: no pending signal\n", + target_pid_to_str (ptid_of (lp))); + return 0; + } + + signo = target_signal_from_host (WSTOPSIG (status)); + + if (program_signals_p && !program_signals[signo]) + { + if (debug_threads) + fprintf (stderr, + "GPS: lwp %s had signal %s, but it is in nopass state\n", + target_pid_to_str (ptid_of (lp)), + target_signal_to_string (signo)); + return 0; + } + else if (!program_signals_p + /* If we have no way to know which signals GDB does not + want to have passed to the program, assume + SIGTRAP/SIGINT, which is GDB's default. */ + && (signo == TARGET_SIGNAL_TRAP || signo == TARGET_SIGNAL_INT)) + { + if (debug_threads) + fprintf (stderr, + "GPS: lwp %s had signal %s, " + "but we don't know if we should pass it. Default to not.\n", + target_pid_to_str (ptid_of (lp)), + target_signal_to_string (signo)); + return 0; + } + else + { + if (debug_threads) + fprintf (stderr, + "GPS: lwp %s has pending signal %s: delivering it.\n", + target_pid_to_str (ptid_of (lp)), + target_signal_to_string (signo)); + + return WSTOPSIG (status); + } +} + 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; + int sig; if (ptid_get_pid (entry->id) != pid) return 0; - /* If this process is stopped but is expecting a SIGSTOP, then make - sure we take care of that now. This isn't absolutely guaranteed - to collect the SIGSTOP, but is fairly likely to. */ + /* If there is a pending SIGSTOP, get rid of it. */ if (lwp->stop_expected) { - int wstat; - /* Clear stop_expected, so that the SIGSTOP will be reported. */ + if (debug_threads) + fprintf (stderr, + "Sending SIGCONT to %s\n", + target_pid_to_str (ptid_of (lwp))); + + kill_lwp (lwpid_of (lwp), SIGCONT); lwp->stop_expected = 0; - linux_resume_one_lwp (lwp, 0, 0, NULL); - linux_wait_for_event (lwp->head.id, &wstat, __WALL); } /* Flush any pending changes to the process's registers. */ regcache_invalidate_one ((struct inferior_list_entry *) get_lwp_thread (lwp)); + /* Pass on any pending signal for this thread. */ + sig = get_detach_signal (thread); + /* Finally, let it resume. */ - ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0); + if (the_low_target.prepare_to_resume != NULL) + the_low_target.prepare_to_resume (lwp); + if (ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, sig) < 0) + error (_("Can't detach %s: %s"), + target_pid_to_str (ptid_of (lwp)), + strerror (errno)); delete_lwp (lwp); return 0; @@ -1095,7 +1305,7 @@ retry: was reported to us by the kernel. Save its PID. */ if (child == NULL && WIFSTOPPED (*wstatp)) { - add_pid_to_list (&stopped_pids, ret); + add_to_pid_list (&stopped_pids, ret, *wstatp); goto retry; } else if (child == NULL) @@ -1272,7 +1482,7 @@ maybe_move_out_of_jump_pad (struct lwp_info *lwp, int *wstat) if ((wstat == NULL || (WIFSTOPPED (*wstat) && WSTOPSIG (*wstat) != SIGTRAP)) && supports_fast_tracepoints () - && in_process_agent_loaded ()) + && agent_loaded_p ()) { struct fast_tpoint_collect_status status; int r; @@ -1546,17 +1756,17 @@ ptid_t step_over_bkpt; the stopped child otherwise. */ static int -linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) +linux_wait_for_event (ptid_t ptid, int *wstat, int options) { struct lwp_info *event_child, *requested_child; + ptid_t wait_ptid; event_child = NULL; requested_child = NULL; /* Check for a lwp with a pending status. */ - if (ptid_equal (ptid, minus_one_ptid) - || ptid_equal (pid_to_ptid (ptid_get_pid (ptid)), ptid)) + if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid)) { event_child = (struct lwp_info *) find_inferior (&all_lwps, status_pending_p_callback, &ptid); @@ -1598,13 +1808,24 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) return lwpid_of (event_child); } + 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; + /* We only enter this loop if no process has a pending wait status. Thus any action taken in response to a wait status inside this loop is responding as soon as we detect the status, not after any pending events. */ while (1) { - event_child = linux_wait_for_lwp (ptid, wstat, options); + event_child = linux_wait_for_lwp (wait_ptid, wstat, options); if ((options & WNOHANG) && event_child == NULL) { @@ -1616,6 +1837,19 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options) if (event_child == NULL) error ("event from unknown child"); + if (ptid_is_pid (ptid) + && ptid_get_pid (ptid) != ptid_get_pid (ptid_of (event_child))) + { + if (! WIFSTOPPED (*wstat)) + mark_lwp_dead (event_child, *wstat); + else + { + event_child->status_pending_p = 1; + event_child->status_pending = *wstat; + } + continue; + } + current_inferior = get_lwp_thread (event_child); /* Check for thread exit. */ @@ -1708,48 +1942,6 @@ linux_wait_for_event_1 (ptid_t ptid, 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; - } -} - - /* Count the LWP's that have had events. */ static int @@ -2221,7 +2413,7 @@ retry: if (WIFSTOPPED (w) && WSTOPSIG (w) != SIGTRAP && supports_fast_tracepoints () - && in_process_agent_loaded ()) + && agent_loaded_p ()) { if (debug_threads) fprintf (stderr, @@ -2368,7 +2560,8 @@ Check if we're already there.\n", || event_child->stopped_by_watchpoint || (!step_over_finished && !bp_explains_trap && !trace_event) - || gdb_breakpoint_here (event_child->stop_pc)); + || (gdb_breakpoint_here (event_child->stop_pc) + && gdb_condition_true_at_breakpoint (event_child->stop_pc))); /* We found no reason GDB would want us to stop. We either hit one of our own breakpoints, or finished an internal step GDB @@ -2451,6 +2644,15 @@ Check if we're already there.\n", why. */ find_inferior (&all_lwps, cancel_breakpoints_callback, event_child); + /* If we were going a step-over, all other threads but the stepping one + had been paused in start_step_over, with their suspend counts + incremented. We don't want to do a full unstop/unpause, because we're + in all-stop mode (so we want threads stopped), but we still need to + unsuspend the other threads, to decrement their `suspended' count + back. */ + if (step_over_finished) + unsuspend_all_lwps (event_child); + /* Stabilize threads (move out of jump pads). */ stabilize_threads (); } @@ -2765,7 +2967,7 @@ stuck_in_jump_pad_callback (struct inferior_list_entry *entry, void *data) /* Allow debugging the jump pad, gdb_collect, etc.. */ return (supports_fast_tracepoints () - && in_process_agent_loaded () + && agent_loaded_p () && (gdb_breakpoint_here (lwp->stop_pc) || lwp->stopped_by_watchpoint || thread->last_resume_kind == resume_step) @@ -3231,8 +3433,10 @@ need_step_over_p (struct inferior_list_entry *entry, void *dummy) if (breakpoint_here (pc) || fast_tracepoint_jump_here (pc)) { /* Don't step over a breakpoint that GDB expects to hit - though. */ - if (gdb_breakpoint_here (pc)) + though. If the condition is being evaluated on the target's side + and it evaluate to false, step over this breakpoint as well. */ + if (gdb_breakpoint_here (pc) + && gdb_condition_true_at_breakpoint (pc)) { if (debug_threads) fprintf (stderr, @@ -3712,145 +3916,11 @@ unstop_all_lwps (int unsuspend, struct lwp_info *except) find_inferior (&all_lwps, proceed_one_lwp, except); } -#ifdef HAVE_LINUX_USRREGS - -int -register_addr (int regnum) -{ - int addr; - - if (regnum < 0 || regnum >= the_low_target.num_regs) - error ("Invalid register number %d.", regnum); - - addr = the_low_target.regmap[regnum]; - - return addr; -} - -/* Fetch one register. */ -static void -fetch_register (struct regcache *regcache, int regno) -{ - CORE_ADDR regaddr; - int i, size; - char *buf; - int pid; - - if (regno >= the_low_target.num_regs) - return; - if ((*the_low_target.cannot_fetch_register) (regno)) - return; - - 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); - for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) - { - errno = 0; - *(PTRACE_XFER_TYPE *) (buf + i) = - ptrace (PTRACE_PEEKUSER, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - of coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0); - regaddr += sizeof (PTRACE_XFER_TYPE); - if (errno != 0) - error ("reading register %d: %s", regno, strerror (errno)); - } - - if (the_low_target.supply_ptrace_register) - the_low_target.supply_ptrace_register (regcache, regno, buf); - else - supply_register (regcache, regno, buf); -} - -/* Store one register. */ -static void -store_register (struct regcache *regcache, int regno) -{ - CORE_ADDR regaddr; - int i, size; - char *buf; - int pid; - - if (regno >= the_low_target.num_regs) - return; - - if ((*the_low_target.cannot_store_register) (regno) == 1) - return; - - regaddr = register_addr (regno); - if (regaddr == -1) - return; - errno = 0; - size = (register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) - & - sizeof (PTRACE_XFER_TYPE); - buf = alloca (size); - memset (buf, 0, size); - - if (the_low_target.collect_ptrace_register) - the_low_target.collect_ptrace_register (regcache, regno, buf); - else - collect_register (regcache, 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, pid, - /* Coerce to a uintptr_t first to avoid potential gcc warning - about coercing an 8 byte integer to a 4 byte pointer. */ - (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, - (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i)); - if (errno != 0) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to change its registers. See also the related - comment in linux_resume_one_lwp. */ - if (errno == ESRCH) - return; - - if ((*the_low_target.cannot_store_register) (regno) == 0) - error ("writing register %d: %s", regno, strerror (errno)); - } - regaddr += sizeof (PTRACE_XFER_TYPE); - } -} - -/* Fetch all registers, or just one, from the child process. */ -static void -usr_fetch_inferior_registers (struct regcache *regcache, int regno) -{ - if (regno == -1) - for (regno = 0; regno < the_low_target.num_regs; regno++) - fetch_register (regcache, regno); - else - fetch_register (regcache, regno); -} - -/* Store our register values back into the inferior. - If REGNO is -1, do this for all registers. - Otherwise, REGNO specifies which register (so we can save time). */ -static void -usr_store_inferior_registers (struct regcache *regcache, int regno) -{ - if (regno == -1) - for (regno = 0; regno < the_low_target.num_regs; regno++) - store_register (regcache, regno); - else - store_register (regcache, regno); -} -#endif /* HAVE_LINUX_USRREGS */ - - #ifdef HAVE_LINUX_REGSETS +#define use_linux_regsets 1 + static int regsets_fetch_inferior_registers (struct regcache *regcache) { @@ -4010,34 +4080,224 @@ regsets_store_inferior_registers (struct regcache *regcache) return 0; else return 1; - return 0; } -#endif /* HAVE_LINUX_REGSETS */ +#else /* !HAVE_LINUX_REGSETS */ +#define use_linux_regsets 0 +#define regsets_fetch_inferior_registers(regcache) 1 +#define regsets_store_inferior_registers(regcache) 1 -void -linux_fetch_registers (struct regcache *regcache, int regno) -{ -#ifdef HAVE_LINUX_REGSETS - if (regsets_fetch_inferior_registers (regcache) == 0) - return; #endif + +/* Return 1 if register REGNO is supported by one of the regset ptrace + calls or 0 if it has to be transferred individually. */ + +static int +linux_register_in_regsets (int regno) +{ + unsigned char mask = 1 << (regno % 8); + size_t index = regno / 8; + + return (use_linux_regsets + && (the_low_target.regset_bitmap == NULL + || (the_low_target.regset_bitmap[index] & mask) != 0)); +} + #ifdef HAVE_LINUX_USRREGS - usr_fetch_inferior_registers (regcache, regno); + +int +register_addr (int regnum) +{ + int addr; + + if (regnum < 0 || regnum >= the_low_target.num_regs) + error ("Invalid register number %d.", regnum); + + addr = the_low_target.regmap[regnum]; + + return addr; +} + +/* Fetch one register. */ +static void +fetch_register (struct regcache *regcache, int regno) +{ + CORE_ADDR regaddr; + int i, size; + char *buf; + int pid; + + if (regno >= the_low_target.num_regs) + return; + if ((*the_low_target.cannot_fetch_register) (regno)) + return; + + regaddr = register_addr (regno); + if (regaddr == -1) + return; + + size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) + & -sizeof (PTRACE_XFER_TYPE)); + buf = alloca (size); + + pid = lwpid_of (get_thread_lwp (current_inferior)); + for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE)) + { + errno = 0; + *(PTRACE_XFER_TYPE *) (buf + i) = + ptrace (PTRACE_PEEKUSER, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + of coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, 0); + regaddr += sizeof (PTRACE_XFER_TYPE); + if (errno != 0) + error ("reading register %d: %s", regno, strerror (errno)); + } + + if (the_low_target.supply_ptrace_register) + the_low_target.supply_ptrace_register (regcache, regno, buf); + else + supply_register (regcache, regno, buf); +} + +/* Store one register. */ +static void +store_register (struct regcache *regcache, int regno) +{ + CORE_ADDR regaddr; + int i, size; + char *buf; + int pid; + + if (regno >= the_low_target.num_regs) + return; + if ((*the_low_target.cannot_store_register) (regno)) + return; + + regaddr = register_addr (regno); + if (regaddr == -1) + return; + + size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1) + & -sizeof (PTRACE_XFER_TYPE)); + buf = alloca (size); + memset (buf, 0, size); + + if (the_low_target.collect_ptrace_register) + the_low_target.collect_ptrace_register (regcache, regno, buf); + else + collect_register (regcache, 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, pid, + /* Coerce to a uintptr_t first to avoid potential gcc warning + about coercing an 8 byte integer to a 4 byte pointer. */ + (PTRACE_ARG3_TYPE) (uintptr_t) regaddr, + (PTRACE_ARG4_TYPE) *(PTRACE_XFER_TYPE *) (buf + i)); + if (errno != 0) + { + /* At this point, ESRCH should mean the process is + already gone, in which case we simply ignore attempts + to change its registers. See also the related + comment in linux_resume_one_lwp. */ + if (errno == ESRCH) + return; + + if ((*the_low_target.cannot_store_register) (regno) == 0) + error ("writing register %d: %s", regno, strerror (errno)); + } + regaddr += sizeof (PTRACE_XFER_TYPE); + } +} + +/* Fetch all registers, or just one, from the child process. + If REGNO is -1, do this for all registers, skipping any that are + assumed to have been retrieved by regsets_fetch_inferior_registers, + unless ALL is non-zero. + Otherwise, REGNO specifies which register (so we can save time). */ +static void +usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all) +{ + if (regno == -1) + { + for (regno = 0; regno < the_low_target.num_regs; regno++) + if (all || !linux_register_in_regsets (regno)) + fetch_register (regcache, regno); + } + else + fetch_register (regcache, regno); +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers, skipping any that are + assumed to have been saved by regsets_store_inferior_registers, + unless ALL is non-zero. + Otherwise, REGNO specifies which register (so we can save time). */ +static void +usr_store_inferior_registers (struct regcache *regcache, int regno, int all) +{ + if (regno == -1) + { + for (regno = 0; regno < the_low_target.num_regs; regno++) + if (all || !linux_register_in_regsets (regno)) + store_register (regcache, regno); + } + else + store_register (regcache, regno); +} + +#else /* !HAVE_LINUX_USRREGS */ + +#define usr_fetch_inferior_registers(regcache, regno, all) do {} while (0) +#define usr_store_inferior_registers(regcache, regno, all) do {} while (0) + #endif + + +void +linux_fetch_registers (struct regcache *regcache, int regno) +{ + int use_regsets; + int all = 0; + + if (regno == -1) + { + all = regsets_fetch_inferior_registers (regcache); + usr_fetch_inferior_registers (regcache, regno, all); + } + else + { + use_regsets = linux_register_in_regsets (regno); + if (use_regsets) + all = regsets_fetch_inferior_registers (regcache); + if (!use_regsets || all) + usr_fetch_inferior_registers (regcache, regno, 1); + } } void linux_store_registers (struct regcache *regcache, int regno) { -#ifdef HAVE_LINUX_REGSETS - if (regsets_store_inferior_registers (regcache) == 0) - return; -#endif -#ifdef HAVE_LINUX_USRREGS - usr_store_inferior_registers (regcache, regno); -#endif + int use_regsets; + int all = 0; + + if (regno == -1) + { + all = regsets_store_inferior_registers (regcache); + usr_store_inferior_registers (regcache, regno, all); + } + else + { + use_regsets = linux_register_in_regsets (regno); + if (use_regsets) + all = regsets_store_inferior_registers (regcache); + if (!use_regsets || all) + usr_store_inferior_registers (regcache, regno, 1); + } } @@ -4686,6 +4946,12 @@ linux_supports_disable_randomization (void) #endif } +static int +linux_supports_agent (void) +{ + return 1; +} + /* Enumerate spufs IDs for process PID. */ static int spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len) @@ -5075,7 +5341,16 @@ get_dynamic (const int pid, const int is_elf64) if (relocation == -1) { - warning ("Unexpected missing PT_PHDR"); + /* PT_PHDR is optional, but necessary for PIE in general. Fortunately + any real world executables, including PIE executables, have always + PT_PHDR present. PT_PHDR is not present in some shared libraries or + in fpc (Free Pascal 2.4) binaries but neither of those have a need for + or present DT_DEBUG anyway (fpc binaries are statically linked). + + Therefore if there exists DT_DEBUG there is always also PT_PHDR. + + GDB could find RELOCATION also from AT_ENTRY - e_entry. */ + return 0; } @@ -5408,6 +5683,7 @@ static struct target_ops linux_target_ops = { linux_supports_disable_randomization, linux_get_min_fast_tracepoint_insn_len, linux_qxfer_libraries_svr4, + linux_supports_agent, }; static void