| Index: gdb/gdbserver/linux-low.c
|
| diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
|
| index a476031faf48be31b9dc5911771caf525d23cbbc..770ee1600bfd812d963feb898f7388739cb59a48 100644
|
| --- a/gdb/gdbserver/linux-low.c
|
| +++ b/gdb/gdbserver/linux-low.c
|
| @@ -1,5 +1,5 @@
|
| /* Low level interface to ptrace, for the remote server for GDB.
|
| - Copyright (C) 1995-1996, 1998-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 1995-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -21,9 +21,10 @@
|
| #include "linux-osdata.h"
|
| #include "agent.h"
|
|
|
| -#include <sys/wait.h>
|
| +#include "nat/linux-nat.h"
|
| +#include "nat/linux-waitpid.h"
|
| +#include "gdb_wait.h"
|
| #include <stdio.h>
|
| -#include <sys/param.h>
|
| #include <sys/ptrace.h>
|
| #include "linux-ptrace.h"
|
| #include "linux-procfs.h"
|
| @@ -43,6 +44,9 @@
|
| #include <sys/stat.h>
|
| #include <sys/vfs.h>
|
| #include <sys/uio.h>
|
| +#include "filestuff.h"
|
| +#include "tracepoint.h"
|
| +#include "hostio.h"
|
| #ifndef ELFMAG0
|
| /* Don't include <linux/elf.h> here. If it got included by gdb_proc_service.h
|
| then ELFMAG0 will have been defined. If it didn't get included by
|
| @@ -76,12 +80,32 @@
|
| #define __SIGRTMIN 32
|
| #endif
|
|
|
| -#ifdef __UCLIBC__
|
| -#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__))
|
| -/* PTRACE_TEXT_ADDR and friends. */
|
| -#include <asm/ptrace.h>
|
| -#define HAS_NOMMU
|
| +/* Some targets did not define these ptrace constants from the start,
|
| + so gdbserver defines them locally here. In the future, these may
|
| + be removed after they are added to asm/ptrace.h. */
|
| +#if !(defined(PT_TEXT_ADDR) \
|
| + || defined(PT_DATA_ADDR) \
|
| + || defined(PT_TEXT_END_ADDR))
|
| +#if defined(__mcoldfire__)
|
| +/* These are still undefined in 3.10 kernels. */
|
| +#define PT_TEXT_ADDR 49*4
|
| +#define PT_DATA_ADDR 50*4
|
| +#define PT_TEXT_END_ADDR 51*4
|
| +/* BFIN already defines these since at least 2.6.32 kernels. */
|
| +#elif defined(BFIN)
|
| +#define PT_TEXT_ADDR 220
|
| +#define PT_TEXT_END_ADDR 224
|
| +#define PT_DATA_ADDR 228
|
| +/* These are still undefined in 3.10 kernels. */
|
| +#elif defined(__TMS320C6X__)
|
| +#define PT_TEXT_ADDR (0x10000*4)
|
| +#define PT_DATA_ADDR (0x10004*4)
|
| +#define PT_TEXT_END_ADDR (0x10008*4)
|
| +#endif
|
| #endif
|
| +
|
| +#ifdef HAVE_LINUX_BTRACE
|
| +# include "linux-btrace.h"
|
| #endif
|
|
|
| #ifndef HAVE_ELF32_AUXV_T
|
| @@ -196,15 +220,6 @@ int using_threads = 1;
|
| jump pads). */
|
| static int stabilizing_threads;
|
|
|
| -/* 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 lwp_info *lwp,
|
| int step, int signal, siginfo_t *info);
|
| static void linux_resume (struct thread_resume *resume_info, size_t n);
|
| @@ -218,7 +233,6 @@ static void proceed_all_lwps (void);
|
| static int finish_step_over (struct lwp_info *lwp);
|
| static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
|
| static int kill_lwp (unsigned long lwpid, int signo);
|
| -static void linux_enable_event_reporting (int pid);
|
|
|
| /* True if the low target can hardware single-step. Such targets
|
| don't need a BREAKPOINT_REINSERT_ADDR callback. */
|
| @@ -248,6 +262,16 @@ supports_fast_tracepoints (void)
|
| return the_low_target.install_fast_tracepoint_jump_pad != NULL;
|
| }
|
|
|
| +/* True if LWP is stopped in its stepping range. */
|
| +
|
| +static int
|
| +lwp_in_step_range (struct lwp_info *lwp)
|
| +{
|
| + CORE_ADDR pc = lwp->stop_pc;
|
| +
|
| + return (pc >= lwp->step_range_start && pc < lwp->step_range_end);
|
| +}
|
| +
|
| struct pending_signals
|
| {
|
| int signal;
|
| @@ -255,11 +279,6 @@ struct pending_signals
|
| struct pending_signals *prev;
|
| };
|
|
|
| -#ifdef HAVE_LINUX_REGSETS
|
| -static char *disabled_regsets;
|
| -static int num_regsets;
|
| -#endif
|
| -
|
| /* The read/write ends of the pipe registered as waitable file in the
|
| event loop. */
|
| static int linux_event_pipe[2] = { -1, -1 };
|
| @@ -318,7 +337,7 @@ elf_64_file_p (const char *file, unsigned int *machine)
|
| int
|
| linux_pid_exe_is_elf_64_file (int pid, unsigned int *machine)
|
| {
|
| - char file[MAXPATHLEN];
|
| + char file[PATH_MAX];
|
|
|
| sprintf (file, "/proc/%d/exe", pid);
|
| return elf_64_file_p (file, machine);
|
| @@ -341,94 +360,18 @@ 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));
|
|
|
| + /* Set the arch when the first LWP stops. */
|
| + proc->private->new_inferior = 1;
|
| +
|
| if (the_low_target.new_process != NULL)
|
| proc->private->arch_private = the_low_target.new_process ();
|
|
|
| return proc;
|
| }
|
|
|
| -/* Wrapper function for waitpid which handles EINTR, and emulates
|
| - __WALL for systems where that is not available. */
|
| -
|
| -static int
|
| -my_waitpid (int pid, int *status, int flags)
|
| -{
|
| - int ret, out_errno;
|
| -
|
| - if (debug_threads)
|
| - fprintf (stderr, "my_waitpid (%d, 0x%x)\n", pid, flags);
|
| -
|
| - if (flags & __WALL)
|
| - {
|
| - sigset_t block_mask, org_mask, wake_mask;
|
| - int wnohang;
|
| -
|
| - wnohang = (flags & WNOHANG) != 0;
|
| - flags &= ~(__WALL | __WCLONE);
|
| - flags |= WNOHANG;
|
| -
|
| - /* Block all signals while here. This avoids knowing about
|
| - LinuxThread's signals. */
|
| - sigfillset (&block_mask);
|
| - sigprocmask (SIG_BLOCK, &block_mask, &org_mask);
|
| -
|
| - /* ... except during the sigsuspend below. */
|
| - sigemptyset (&wake_mask);
|
| -
|
| - while (1)
|
| - {
|
| - /* Since all signals are blocked, there's no need to check
|
| - for EINTR here. */
|
| - ret = waitpid (pid, status, flags);
|
| - out_errno = errno;
|
| -
|
| - if (ret == -1 && out_errno != ECHILD)
|
| - break;
|
| - else if (ret > 0)
|
| - break;
|
| -
|
| - if (flags & __WCLONE)
|
| - {
|
| - /* We've tried both flavors now. If WNOHANG is set,
|
| - there's nothing else to do, just bail out. */
|
| - if (wnohang)
|
| - break;
|
| -
|
| - if (debug_threads)
|
| - fprintf (stderr, "blocking\n");
|
| -
|
| - /* Block waiting for signals. */
|
| - sigsuspend (&wake_mask);
|
| - }
|
| -
|
| - flags ^= __WCLONE;
|
| - }
|
| -
|
| - sigprocmask (SIG_SETMASK, &org_mask, NULL);
|
| - }
|
| - else
|
| - {
|
| - do
|
| - ret = waitpid (pid, status, flags);
|
| - while (ret == -1 && errno == EINTR);
|
| - out_errno = errno;
|
| - }
|
| -
|
| - if (debug_threads)
|
| - fprintf (stderr, "my_waitpid (%d, 0x%x): status(%x), %d\n",
|
| - pid, flags, status ? *status : -1, ret);
|
| -
|
| - errno = out_errno;
|
| - return ret;
|
| -}
|
| -
|
| /* 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). */
|
| @@ -445,7 +388,8 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
|
| unsigned long new_pid;
|
| int ret, status;
|
|
|
| - ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_child), 0, &new_pid);
|
| + ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_child), (PTRACE_TYPE_ARG3) 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, &status))
|
| @@ -463,8 +407,6 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
|
| warning ("wait returned unexpected status 0x%x", status);
|
| }
|
|
|
| - linux_enable_event_reporting (new_pid);
|
| -
|
| ptid = ptid_build (pid_of (event_child), new_pid, 0);
|
| new_lwp = (struct lwp_info *) add_lwp (ptid);
|
| add_thread (ptid, new_lwp);
|
| @@ -641,7 +583,8 @@ linux_create_inferior (char *program, char **allargs)
|
|
|
| if (pid == 0)
|
| {
|
| - ptrace (PTRACE_TRACEME, 0, 0, 0);
|
| + close_most_fds ();
|
| + ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
|
|
|
| #ifndef __ANDROID__ /* Bionic doesn't use SIGRTMIN the way glibc does. */
|
| signal (__SIGRTMIN + 1, SIG_DFL);
|
| @@ -659,7 +602,9 @@ linux_create_inferior (char *program, char **allargs)
|
| dup2 (2, 1);
|
| if (write (2, "stdin/stdout redirected\n",
|
| sizeof ("stdin/stdout redirected\n") - 1) < 0)
|
| - /* Errors ignored. */;
|
| + {
|
| + /* Errors ignored. */;
|
| + }
|
| }
|
|
|
| execv (program, allargs);
|
| @@ -701,7 +646,8 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
|
| ptid_t ptid;
|
| struct lwp_info *new_lwp;
|
|
|
| - if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0)
|
| + if (ptrace (PTRACE_ATTACH, lwpid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0)
|
| + != 0)
|
| {
|
| struct buffer buffer;
|
|
|
| @@ -767,7 +713,7 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
|
| /* 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);
|
| + ptrace (PTRACE_CONT, lwpid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
|
| }
|
|
|
| /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
|
| @@ -958,7 +904,7 @@ linux_kill_one_lwp (struct lwp_info *lwp)
|
| errno ? strerror (errno) : "OK");
|
|
|
| errno = 0;
|
| - ptrace (PTRACE_KILL, pid, 0, 0);
|
| + ptrace (PTRACE_KILL, pid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
|
| if (debug_threads)
|
| fprintf (stderr,
|
| "LKL: PTRACE_KILL %s, 0, 0 (%s)\n",
|
| @@ -1163,8 +1109,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
|
| }
|
|
|
| /* Flush any pending changes to the process's registers. */
|
| - regcache_invalidate_one ((struct inferior_list_entry *)
|
| - get_lwp_thread (lwp));
|
| + regcache_invalidate_thread (get_lwp_thread (lwp));
|
|
|
| /* Pass on any pending signal for this thread. */
|
| sig = get_detach_signal (thread);
|
| @@ -1172,8 +1117,8 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
|
| /* Finally, let it resume. */
|
| if (the_low_target.prepare_to_resume != NULL)
|
| the_low_target.prepare_to_resume (lwp);
|
| - if (ptrace (PTRACE_DETACH, lwpid_of (lwp), 0,
|
| - (PTRACE_ARG4_TYPE) (long) sig) < 0)
|
| + if (ptrace (PTRACE_DETACH, lwpid_of (lwp), (PTRACE_TYPE_ARG3) 0,
|
| + (PTRACE_TYPE_ARG4) (long) sig) < 0)
|
| error (_("Can't detach %s: %s"),
|
| target_pid_to_str (ptid_of (lwp)),
|
| strerror (errno));
|
| @@ -1372,17 +1317,28 @@ retry:
|
|
|
| child->last_status = *wstatp;
|
|
|
| - /* Architecture-specific setup after inferior is running.
|
| - This needs to happen after we have attached to the inferior
|
| - and it is stopped for the first time, but before we access
|
| - any inferior registers. */
|
| - if (new_inferior)
|
| + if (WIFSTOPPED (*wstatp))
|
| {
|
| - the_low_target.arch_setup ();
|
| -#ifdef HAVE_LINUX_REGSETS
|
| - memset (disabled_regsets, 0, num_regsets);
|
| -#endif
|
| - new_inferior = 0;
|
| + struct process_info *proc;
|
| +
|
| + /* Architecture-specific setup after inferior is running. This
|
| + needs to happen after we have attached to the inferior and it
|
| + is stopped for the first time, but before we access any
|
| + inferior registers. */
|
| + proc = find_process_pid (pid_of (child));
|
| + if (proc->private->new_inferior)
|
| + {
|
| + struct thread_info *saved_inferior;
|
| +
|
| + saved_inferior = current_inferior;
|
| + current_inferior = get_lwp_thread (child);
|
| +
|
| + the_low_target.arch_setup ();
|
| +
|
| + current_inferior = saved_inferior;
|
| +
|
| + proc->private->new_inferior = 0;
|
| + }
|
| }
|
|
|
| /* Fetch the possibly triggered data watchpoint info and store it in
|
| @@ -1603,13 +1559,15 @@ Checking whether LWP %ld needs to move out of the jump pad...it does\n",
|
| || WSTOPSIG (*wstat) == SIGFPE
|
| || WSTOPSIG (*wstat) == SIGBUS
|
| || WSTOPSIG (*wstat) == SIGSEGV)
|
| - && ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), 0, &info) == 0
|
| + && ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp),
|
| + (PTRACE_TYPE_ARG3) 0, &info) == 0
|
| /* Final check just to make sure we don't clobber
|
| the siginfo of non-kernel-sent signals. */
|
| && (uintptr_t) info.si_addr == lwp->stop_pc)
|
| {
|
| info.si_addr = (void *) (uintptr_t) status.tpoint_addr;
|
| - ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), 0, &info);
|
| + ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp),
|
| + (PTRACE_TYPE_ARG3) 0, &info);
|
| }
|
|
|
| regcache = get_thread_regcache (get_lwp_thread (lwp), 1);
|
| @@ -1704,7 +1662,8 @@ Deferring signal %d for LWP %ld.\n", WSTOPSIG (*wstat), lwpid_of (lwp));
|
| p_sig->prev = lwp->pending_signals_to_report;
|
| p_sig->signal = WSTOPSIG (*wstat);
|
| memset (&p_sig->info, 0, sizeof (siginfo_t));
|
| - ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), 0, &p_sig->info);
|
| + ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), (PTRACE_TYPE_ARG3) 0,
|
| + &p_sig->info);
|
|
|
| lwp->pending_signals_to_report = p_sig;
|
| }
|
| @@ -1725,7 +1684,8 @@ dequeue_one_deferred_signal (struct lwp_info *lwp, int *wstat)
|
|
|
| *wstat = W_STOPCODE ((*p_sig)->signal);
|
| if ((*p_sig)->info.si_signo != 0)
|
| - ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), 0, &(*p_sig)->info);
|
| + ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), (PTRACE_TYPE_ARG3) 0,
|
| + &(*p_sig)->info);
|
| free (*p_sig);
|
| *p_sig = NULL;
|
|
|
| @@ -2303,6 +2263,7 @@ linux_wait_1 (ptid_t ptid,
|
| int maybe_internal_trap;
|
| int report_to_gdb;
|
| int trace_event;
|
| + int in_step_range;
|
|
|
| /* Translate generic target options into linux options. */
|
| options = __WALL;
|
| @@ -2312,6 +2273,7 @@ linux_wait_1 (ptid_t ptid,
|
| retry:
|
| bp_explains_trap = 0;
|
| trace_event = 0;
|
| + in_step_range = 0;
|
| ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
|
|
| /* If we were only supposed to resume one thread, only wait for
|
| @@ -2595,7 +2557,8 @@ Check if we're already there.\n",
|
| fprintf (stderr, "Ignored signal %d for LWP %ld.\n",
|
| WSTOPSIG (w), lwpid_of (event_child));
|
|
|
| - if (ptrace (PTRACE_GETSIGINFO, lwpid_of (event_child), 0, &info) == 0)
|
| + if (ptrace (PTRACE_GETSIGINFO, lwpid_of (event_child),
|
| + (PTRACE_TYPE_ARG3) 0, &info) == 0)
|
| info_p = &info;
|
| else
|
| info_p = NULL;
|
| @@ -2604,18 +2567,24 @@ Check if we're already there.\n",
|
| goto retry;
|
| }
|
|
|
| - /* If GDB wanted this thread to single step, we always want to
|
| - report the SIGTRAP, and let GDB handle it. Watchpoints should
|
| - always be reported. So should signals we can't explain. A
|
| - SIGTRAP we can't explain could be a GDB breakpoint --- we may or
|
| - not support Z0 breakpoints. If we do, we're be able to handle
|
| - GDB breakpoints on top of internal breakpoints, by handling the
|
| - internal breakpoint and still reporting the event to GDB. If we
|
| - don't, we're out of luck, GDB won't see the breakpoint hit. */
|
| + /* Note that all addresses are always "out of the step range" when
|
| + there's no range to begin with. */
|
| + in_step_range = lwp_in_step_range (event_child);
|
| +
|
| + /* If GDB wanted this thread to single step, and the thread is out
|
| + of the step range, we always want to report the SIGTRAP, and let
|
| + GDB handle it. Watchpoints should always be reported. So should
|
| + signals we can't explain. A SIGTRAP we can't explain could be a
|
| + GDB breakpoint --- we may or not support Z0 breakpoints. If we
|
| + do, we're be able to handle GDB breakpoints on top of internal
|
| + breakpoints, by handling the internal breakpoint and still
|
| + reporting the event to GDB. If we don't, we're out of luck, GDB
|
| + won't see the breakpoint hit. */
|
| report_to_gdb = (!maybe_internal_trap
|
| - || current_inferior->last_resume_kind == resume_step
|
| + || (current_inferior->last_resume_kind == resume_step
|
| + && !in_step_range)
|
| || event_child->stopped_by_watchpoint
|
| - || (!step_over_finished
|
| + || (!step_over_finished && !in_step_range
|
| && !bp_explains_trap && !trace_event)
|
| || (gdb_breakpoint_here (event_child->stop_pc)
|
| && gdb_condition_true_at_breakpoint (event_child->stop_pc)
|
| @@ -2636,6 +2605,11 @@ Check if we're already there.\n",
|
| fprintf (stderr, "Step-over finished.\n");
|
| if (trace_event)
|
| fprintf (stderr, "Tracepoint event.\n");
|
| + if (lwp_in_step_range (event_child))
|
| + fprintf (stderr, "Range stepping pc 0x%s [0x%s, 0x%s).\n",
|
| + paddress (event_child->stop_pc),
|
| + paddress (event_child->step_range_start),
|
| + paddress (event_child->step_range_end));
|
| }
|
|
|
| /* We're not reporting this breakpoint to GDB, so apply the
|
| @@ -2667,7 +2641,12 @@ Check if we're already there.\n",
|
| if (debug_threads)
|
| {
|
| if (current_inferior->last_resume_kind == resume_step)
|
| - fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
|
| + {
|
| + if (event_child->step_range_start == event_child->step_range_end)
|
| + fprintf (stderr, "GDB wanted to single-step, reporting event.\n");
|
| + else if (!lwp_in_step_range (event_child))
|
| + fprintf (stderr, "Out of step range, reporting event.\n");
|
| + }
|
| if (event_child->stopped_by_watchpoint)
|
| fprintf (stderr, "Stopped by watchpoint.\n");
|
| if (gdb_breakpoint_here (event_child->stop_pc))
|
| @@ -3190,7 +3169,7 @@ linux_resume_one_lwp (struct lwp_info *lwp,
|
| fprintf (stderr, " pending reinsert at 0x%s\n",
|
| paddress (lwp->bp_reinsert));
|
|
|
| - if (lwp->bp_reinsert != 0 && can_hardware_single_step ())
|
| + if (can_hardware_single_step ())
|
| {
|
| if (fast_tp_collecting == 0)
|
| {
|
| @@ -3275,7 +3254,8 @@ lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n",
|
|
|
| signal = (*p_sig)->signal;
|
| if ((*p_sig)->info.si_signo != 0)
|
| - ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), 0, &(*p_sig)->info);
|
| + ptrace (PTRACE_SETSIGINFO, lwpid_of (lwp), (PTRACE_TYPE_ARG3) 0,
|
| + &(*p_sig)->info);
|
|
|
| free (*p_sig);
|
| *p_sig = NULL;
|
| @@ -3284,16 +3264,16 @@ lwp %ld wants to get out of fast tracepoint jump pad single-stepping\n",
|
| if (the_low_target.prepare_to_resume != NULL)
|
| the_low_target.prepare_to_resume (lwp);
|
|
|
| - regcache_invalidate_one ((struct inferior_list_entry *)
|
| - get_lwp_thread (lwp));
|
| + regcache_invalidate_thread (get_lwp_thread (lwp));
|
| errno = 0;
|
| lwp->stopped = 0;
|
| lwp->stopped_by_watchpoint = 0;
|
| lwp->stepping = step;
|
| - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp), 0,
|
| + ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp),
|
| + (PTRACE_TYPE_ARG3) 0,
|
| /* Coerce to a uintptr_t first to avoid potential gcc warning
|
| of coercing an 8 byte integer to a 4 byte pointer. */
|
| - (PTRACE_ARG4_TYPE) (uintptr_t) signal);
|
| + (PTRACE_TYPE_ARG4) (uintptr_t) signal);
|
|
|
| current_inferior = saved_inferior;
|
| if (errno)
|
| @@ -3318,13 +3298,15 @@ struct thread_resume_array
|
| size_t n;
|
| };
|
|
|
| -/* This function is called once per thread. We look up the thread
|
| - in RESUME_PTR, and mark the thread with a pointer to the appropriate
|
| - resume request.
|
| +/* This function is called once per thread via find_inferior.
|
| + ARG is a pointer to a thread_resume_array struct.
|
| + We look up the thread specified by ENTRY in ARG, and mark the thread
|
| + with a pointer to the appropriate resume request.
|
|
|
| This algorithm is O(threads * resume elements), but resume elements
|
| is small (and will remain small at least until GDB supports thread
|
| suspension). */
|
| +
|
| static int
|
| linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
|
| {
|
| @@ -3364,6 +3346,9 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
|
| lwp->resume = &r->resume[ndx];
|
| thread->last_resume_kind = lwp->resume->kind;
|
|
|
| + lwp->step_range_start = lwp->resume->step_range_start;
|
| + lwp->step_range_end = lwp->resume->step_range_end;
|
| +
|
| /* If we had a deferred signal to report, dequeue one now.
|
| This can happen if LWP gets more than one signal while
|
| trying to get out of a jump pad. */
|
| @@ -3390,8 +3375,9 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
|
| return 0;
|
| }
|
|
|
| +/* find_inferior callback for linux_resume.
|
| + Set *FLAG_P if this lwp has an interesting status pending. */
|
|
|
| -/* Set *FLAG_P if this lwp has an interesting status pending. */
|
| static int
|
| resume_status_pending_p (struct inferior_list_entry *entry, void *flag_p)
|
| {
|
| @@ -3758,7 +3744,8 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg)
|
| PTRACE_SETSIGINFO. */
|
| if (WIFSTOPPED (lwp->last_status)
|
| && WSTOPSIG (lwp->last_status) == lwp->resume->sig)
|
| - ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), 0, &p_sig->info);
|
| + ptrace (PTRACE_GETSIGINFO, lwpid_of (lwp), (PTRACE_TYPE_ARG3) 0,
|
| + &p_sig->info);
|
|
|
| lwp->pending_signals = p_sig;
|
| }
|
| @@ -3988,15 +3975,38 @@ unstop_all_lwps (int unsuspend, struct lwp_info *except)
|
|
|
| #define use_linux_regsets 1
|
|
|
| +/* Returns true if REGSET has been disabled. */
|
| +
|
| static int
|
| -regsets_fetch_inferior_registers (struct regcache *regcache)
|
| +regset_disabled (struct regsets_info *info, struct regset_info *regset)
|
| +{
|
| + return (info->disabled_regsets != NULL
|
| + && info->disabled_regsets[regset - info->regsets]);
|
| +}
|
| +
|
| +/* Disable REGSET. */
|
| +
|
| +static void
|
| +disable_regset (struct regsets_info *info, struct regset_info *regset)
|
| +{
|
| + int dr_offset;
|
| +
|
| + dr_offset = regset - info->regsets;
|
| + if (info->disabled_regsets == NULL)
|
| + info->disabled_regsets = xcalloc (1, info->num_regsets);
|
| + info->disabled_regsets[dr_offset] = 1;
|
| +}
|
| +
|
| +static int
|
| +regsets_fetch_inferior_registers (struct regsets_info *regsets_info,
|
| + struct regcache *regcache)
|
| {
|
| struct regset_info *regset;
|
| int saw_general_regs = 0;
|
| int pid;
|
| struct iovec iov;
|
|
|
| - regset = target_regsets;
|
| + regset = regsets_info->regsets;
|
|
|
| pid = lwpid_of (get_thread_lwp (current_inferior));
|
| while (regset->size >= 0)
|
| @@ -4004,7 +4014,7 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
|
| void *buf, *data;
|
| int nt_type, res;
|
|
|
| - if (regset->size == 0 || disabled_regsets[regset - target_regsets])
|
| + if (regset->size == 0 || regset_disabled (regsets_info, regset))
|
| {
|
| regset ++;
|
| continue;
|
| @@ -4024,7 +4034,7 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
|
|
|
| #ifndef __sparc__
|
| res = ptrace (regset->get_request, pid,
|
| - (PTRACE_ARG3_TYPE) (long) nt_type, data);
|
| + (PTRACE_TYPE_ARG3) (long) nt_type, data);
|
| #else
|
| res = ptrace (regset->get_request, pid, data, nt_type);
|
| #endif
|
| @@ -4033,8 +4043,8 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
|
| if (errno == EIO)
|
| {
|
| /* If we get EIO on a regset, do not try it again for
|
| - this process. */
|
| - disabled_regsets[regset - target_regsets] = 1;
|
| + this process mode. */
|
| + disable_regset (regsets_info, regset);
|
| free (buf);
|
| continue;
|
| }
|
| @@ -4059,14 +4069,15 @@ regsets_fetch_inferior_registers (struct regcache *regcache)
|
| }
|
|
|
| static int
|
| -regsets_store_inferior_registers (struct regcache *regcache)
|
| +regsets_store_inferior_registers (struct regsets_info *regsets_info,
|
| + struct regcache *regcache)
|
| {
|
| struct regset_info *regset;
|
| int saw_general_regs = 0;
|
| int pid;
|
| struct iovec iov;
|
|
|
| - regset = target_regsets;
|
| + regset = regsets_info->regsets;
|
|
|
| pid = lwpid_of (get_thread_lwp (current_inferior));
|
| while (regset->size >= 0)
|
| @@ -4074,7 +4085,7 @@ regsets_store_inferior_registers (struct regcache *regcache)
|
| void *buf, *data;
|
| int nt_type, res;
|
|
|
| - if (regset->size == 0 || disabled_regsets[regset - target_regsets])
|
| + if (regset->size == 0 || regset_disabled (regsets_info, regset))
|
| {
|
| regset ++;
|
| continue;
|
| @@ -4098,7 +4109,7 @@ regsets_store_inferior_registers (struct regcache *regcache)
|
|
|
| #ifndef __sparc__
|
| res = ptrace (regset->get_request, pid,
|
| - (PTRACE_ARG3_TYPE) (long) nt_type, data);
|
| + (PTRACE_TYPE_ARG3) (long) nt_type, data);
|
| #else
|
| res = ptrace (regset->get_request, pid, data, nt_type);
|
| #endif
|
| @@ -4111,7 +4122,7 @@ regsets_store_inferior_registers (struct regcache *regcache)
|
| /* Only now do we write the register set. */
|
| #ifndef __sparc__
|
| res = ptrace (regset->set_request, pid,
|
| - (PTRACE_ARG3_TYPE) (long) nt_type, data);
|
| + (PTRACE_TYPE_ARG3) (long) nt_type, data);
|
| #else
|
| res = ptrace (regset->set_request, pid, data, nt_type);
|
| #endif
|
| @@ -4122,8 +4133,8 @@ regsets_store_inferior_registers (struct regcache *regcache)
|
| if (errno == EIO)
|
| {
|
| /* If we get EIO on a regset, do not try it again for
|
| - this process. */
|
| - disabled_regsets[regset - target_regsets] = 1;
|
| + this process mode. */
|
| + disable_regset (regsets_info, regset);
|
| free (buf);
|
| continue;
|
| }
|
| @@ -4155,8 +4166,8 @@ regsets_store_inferior_registers (struct regcache *regcache)
|
| #else /* !HAVE_LINUX_REGSETS */
|
|
|
| #define use_linux_regsets 0
|
| -#define regsets_fetch_inferior_registers(regcache) 1
|
| -#define regsets_store_inferior_registers(regcache) 1
|
| +#define regsets_fetch_inferior_registers(regsets_info, regcache) 1
|
| +#define regsets_store_inferior_registers(regsets_info, regcache) 1
|
|
|
| #endif
|
|
|
| @@ -4164,50 +4175,52 @@ regsets_store_inferior_registers (struct regcache *regcache)
|
| calls or 0 if it has to be transferred individually. */
|
|
|
| static int
|
| -linux_register_in_regsets (int regno)
|
| +linux_register_in_regsets (const struct regs_info *regs_info, 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));
|
| + && (regs_info->regset_bitmap == NULL
|
| + || (regs_info->regset_bitmap[index] & mask) != 0));
|
| }
|
|
|
| #ifdef HAVE_LINUX_USRREGS
|
|
|
| int
|
| -register_addr (int regnum)
|
| +register_addr (const struct usrregs_info *usrregs, int regnum)
|
| {
|
| int addr;
|
|
|
| - if (regnum < 0 || regnum >= the_low_target.num_regs)
|
| + if (regnum < 0 || regnum >= usrregs->num_regs)
|
| error ("Invalid register number %d.", regnum);
|
|
|
| - addr = the_low_target.regmap[regnum];
|
| + addr = usrregs->regmap[regnum];
|
|
|
| return addr;
|
| }
|
|
|
| /* Fetch one register. */
|
| static void
|
| -fetch_register (struct regcache *regcache, int regno)
|
| +fetch_register (const struct usrregs_info *usrregs,
|
| + struct regcache *regcache, int regno)
|
| {
|
| CORE_ADDR regaddr;
|
| int i, size;
|
| char *buf;
|
| int pid;
|
|
|
| - if (regno >= the_low_target.num_regs)
|
| + if (regno >= usrregs->num_regs)
|
| return;
|
| if ((*the_low_target.cannot_fetch_register) (regno))
|
| return;
|
|
|
| - regaddr = register_addr (regno);
|
| + regaddr = register_addr (usrregs, regno);
|
| if (regaddr == -1)
|
| return;
|
|
|
| - size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
|
| + size = ((register_size (regcache->tdesc, regno)
|
| + + sizeof (PTRACE_XFER_TYPE) - 1)
|
| & -sizeof (PTRACE_XFER_TYPE));
|
| buf = alloca (size);
|
|
|
| @@ -4219,7 +4232,7 @@ fetch_register (struct regcache *regcache, int regno)
|
| 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);
|
| + (PTRACE_TYPE_ARG3) (uintptr_t) regaddr, (PTRACE_TYPE_ARG4) 0);
|
| regaddr += sizeof (PTRACE_XFER_TYPE);
|
| if (errno != 0)
|
| error ("reading register %d: %s", regno, strerror (errno));
|
| @@ -4233,23 +4246,25 @@ fetch_register (struct regcache *regcache, int regno)
|
|
|
| /* Store one register. */
|
| static void
|
| -store_register (struct regcache *regcache, int regno)
|
| +store_register (const struct usrregs_info *usrregs,
|
| + struct regcache *regcache, int regno)
|
| {
|
| CORE_ADDR regaddr;
|
| int i, size;
|
| char *buf;
|
| int pid;
|
|
|
| - if (regno >= the_low_target.num_regs)
|
| + if (regno >= usrregs->num_regs)
|
| return;
|
| if ((*the_low_target.cannot_store_register) (regno))
|
| return;
|
|
|
| - regaddr = register_addr (regno);
|
| + regaddr = register_addr (usrregs, regno);
|
| if (regaddr == -1)
|
| return;
|
|
|
| - size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
|
| + size = ((register_size (regcache->tdesc, regno)
|
| + + sizeof (PTRACE_XFER_TYPE) - 1)
|
| & -sizeof (PTRACE_XFER_TYPE));
|
| buf = alloca (size);
|
| memset (buf, 0, size);
|
| @@ -4266,8 +4281,8 @@ store_register (struct regcache *regcache, int regno)
|
| 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));
|
| + (PTRACE_TYPE_ARG3) (uintptr_t) regaddr,
|
| + (PTRACE_TYPE_ARG4) *(PTRACE_XFER_TYPE *) (buf + i));
|
| if (errno != 0)
|
| {
|
| /* At this point, ESRCH should mean the process is
|
| @@ -4290,16 +4305,19 @@ store_register (struct regcache *regcache, int regno)
|
| 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)
|
| +usr_fetch_inferior_registers (const struct regs_info *regs_info,
|
| + struct regcache *regcache, int regno, int all)
|
| {
|
| + struct usrregs_info *usr = regs_info->usrregs;
|
| +
|
| if (regno == -1)
|
| {
|
| - for (regno = 0; regno < the_low_target.num_regs; regno++)
|
| - if (all || !linux_register_in_regsets (regno))
|
| - fetch_register (regcache, regno);
|
| + for (regno = 0; regno < usr->num_regs; regno++)
|
| + if (all || !linux_register_in_regsets (regs_info, regno))
|
| + fetch_register (usr, regcache, regno);
|
| }
|
| else
|
| - fetch_register (regcache, regno);
|
| + fetch_register (usr, regcache, regno);
|
| }
|
|
|
| /* Store our register values back into the inferior.
|
| @@ -4308,22 +4326,25 @@ usr_fetch_inferior_registers (struct regcache *regcache, int regno, int all)
|
| 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)
|
| +usr_store_inferior_registers (const struct regs_info *regs_info,
|
| + struct regcache *regcache, int regno, int all)
|
| {
|
| + struct usrregs_info *usr = regs_info->usrregs;
|
| +
|
| if (regno == -1)
|
| {
|
| - for (regno = 0; regno < the_low_target.num_regs; regno++)
|
| - if (all || !linux_register_in_regsets (regno))
|
| - store_register (regcache, regno);
|
| + for (regno = 0; regno < usr->num_regs; regno++)
|
| + if (all || !linux_register_in_regsets (regs_info, regno))
|
| + store_register (usr, regcache, regno);
|
| }
|
| else
|
| - store_register (regcache, regno);
|
| + store_register (usr, 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)
|
| +#define usr_fetch_inferior_registers(regs_info, regcache, regno, all) do {} while (0)
|
| +#define usr_store_inferior_registers(regs_info, regcache, regno, all) do {} while (0)
|
|
|
| #endif
|
|
|
| @@ -4333,15 +4354,18 @@ linux_fetch_registers (struct regcache *regcache, int regno)
|
| {
|
| int use_regsets;
|
| int all = 0;
|
| + const struct regs_info *regs_info = (*the_low_target.regs_info) ();
|
|
|
| if (regno == -1)
|
| {
|
| - if (the_low_target.fetch_register != NULL)
|
| - for (regno = 0; regno < the_low_target.num_regs; regno++)
|
| + if (the_low_target.fetch_register != NULL
|
| + && regs_info->usrregs != NULL)
|
| + for (regno = 0; regno < regs_info->usrregs->num_regs; regno++)
|
| (*the_low_target.fetch_register) (regcache, regno);
|
|
|
| - all = regsets_fetch_inferior_registers (regcache);
|
| - usr_fetch_inferior_registers (regcache, -1, all);
|
| + all = regsets_fetch_inferior_registers (regs_info->regsets_info, regcache);
|
| + if (regs_info->usrregs != NULL)
|
| + usr_fetch_inferior_registers (regs_info, regcache, -1, all);
|
| }
|
| else
|
| {
|
| @@ -4349,11 +4373,12 @@ linux_fetch_registers (struct regcache *regcache, int regno)
|
| && (*the_low_target.fetch_register) (regcache, regno))
|
| return;
|
|
|
| - use_regsets = linux_register_in_regsets (regno);
|
| + use_regsets = linux_register_in_regsets (regs_info, regno);
|
| if (use_regsets)
|
| - all = regsets_fetch_inferior_registers (regcache);
|
| - if (!use_regsets || all)
|
| - usr_fetch_inferior_registers (regcache, regno, 1);
|
| + all = regsets_fetch_inferior_registers (regs_info->regsets_info,
|
| + regcache);
|
| + if ((!use_regsets || all) && regs_info->usrregs != NULL)
|
| + usr_fetch_inferior_registers (regs_info, regcache, regno, 1);
|
| }
|
| }
|
|
|
| @@ -4362,19 +4387,23 @@ linux_store_registers (struct regcache *regcache, int regno)
|
| {
|
| int use_regsets;
|
| int all = 0;
|
| + const struct regs_info *regs_info = (*the_low_target.regs_info) ();
|
|
|
| if (regno == -1)
|
| {
|
| - all = regsets_store_inferior_registers (regcache);
|
| - usr_store_inferior_registers (regcache, regno, all);
|
| + all = regsets_store_inferior_registers (regs_info->regsets_info,
|
| + regcache);
|
| + if (regs_info->usrregs != NULL)
|
| + usr_store_inferior_registers (regs_info, regcache, regno, all);
|
| }
|
| else
|
| {
|
| - use_regsets = linux_register_in_regsets (regno);
|
| + use_regsets = linux_register_in_regsets (regs_info, regno);
|
| if (use_regsets)
|
| - all = regsets_store_inferior_registers (regcache);
|
| - if (!use_regsets || all)
|
| - usr_store_inferior_registers (regcache, regno, 1);
|
| + all = regsets_store_inferior_registers (regs_info->regsets_info,
|
| + regcache);
|
| + if ((!use_regsets || all) && regs_info->usrregs != NULL)
|
| + usr_store_inferior_registers (regs_info, regcache, regno, 1);
|
| }
|
| }
|
|
|
| @@ -4447,7 +4476,8 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
|
| /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning
|
| about coercing an 8 byte integer to a 4 byte pointer. */
|
| buffer[i] = ptrace (PTRACE_PEEKTEXT, pid,
|
| - (PTRACE_ARG3_TYPE) (uintptr_t) addr, 0);
|
| + (PTRACE_TYPE_ARG3) (uintptr_t) addr,
|
| + (PTRACE_TYPE_ARG4) 0);
|
| if (errno)
|
| break;
|
| }
|
| @@ -4468,7 +4498,7 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
|
|
|
| /* Copy LEN bytes of data from debugger memory at MYADDR to inferior's
|
| memory at MEMADDR. On failure (cannot write to the inferior)
|
| - returns the value of errno. */
|
| + returns the value of errno. Always succeeds if LEN is zero. */
|
|
|
| static int
|
| linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
| @@ -4487,6 +4517,12 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
|
|
| int pid = lwpid_of (get_thread_lwp (current_inferior));
|
|
|
| + if (len == 0)
|
| + {
|
| + /* Zero length write always succeeds. */
|
| + return 0;
|
| + }
|
| +
|
| if (debug_threads)
|
| {
|
| /* Dump up to four bytes. */
|
| @@ -4507,7 +4543,8 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
| /* Coerce the 3rd arg to a uintptr_t first to avoid potential gcc warning
|
| about coercing an 8 byte integer to a 4 byte pointer. */
|
| buffer[0] = ptrace (PTRACE_PEEKTEXT, pid,
|
| - (PTRACE_ARG3_TYPE) (uintptr_t) addr, 0);
|
| + (PTRACE_TYPE_ARG3) (uintptr_t) addr,
|
| + (PTRACE_TYPE_ARG4) 0);
|
| if (errno)
|
| return errno;
|
|
|
| @@ -4518,9 +4555,9 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
| = ptrace (PTRACE_PEEKTEXT, 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) (addr + (count - 1)
|
| + (PTRACE_TYPE_ARG3) (uintptr_t) (addr + (count - 1)
|
| * sizeof (PTRACE_XFER_TYPE)),
|
| - 0);
|
| + (PTRACE_TYPE_ARG4) 0);
|
| if (errno)
|
| return errno;
|
| }
|
| @@ -4538,8 +4575,8 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
| ptrace (PTRACE_POKETEXT, 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) addr,
|
| - (PTRACE_ARG4_TYPE) buffer[i]);
|
| + (PTRACE_TYPE_ARG3) (uintptr_t) addr,
|
| + (PTRACE_TYPE_ARG4) buffer[i]);
|
| if (errno)
|
| return errno;
|
| }
|
| @@ -4547,162 +4584,6 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
|
| return 0;
|
| }
|
|
|
| -/* Non-zero if the kernel supports PTRACE_O_TRACEFORK. */
|
| -static int linux_supports_tracefork_flag;
|
| -
|
| -static void
|
| -linux_enable_event_reporting (int pid)
|
| -{
|
| - if (!linux_supports_tracefork_flag)
|
| - return;
|
| -
|
| - ptrace (PTRACE_SETOPTIONS, pid, 0, (PTRACE_ARG4_TYPE) PTRACE_O_TRACECLONE);
|
| -}
|
| -
|
| -/* Helper functions for linux_test_for_tracefork, called via clone (). */
|
| -
|
| -static int
|
| -linux_tracefork_grandchild (void *arg)
|
| -{
|
| - _exit (0);
|
| -}
|
| -
|
| -#define STACK_SIZE 4096
|
| -
|
| -static int
|
| -linux_tracefork_child (void *arg)
|
| -{
|
| - ptrace (PTRACE_TRACEME, 0, 0, 0);
|
| - kill (getpid (), SIGSTOP);
|
| -
|
| -#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
|
| -
|
| - if (fork () == 0)
|
| - linux_tracefork_grandchild (NULL);
|
| -
|
| -#else /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
|
| -
|
| -#ifdef __ia64__
|
| - __clone2 (linux_tracefork_grandchild, arg, STACK_SIZE,
|
| - CLONE_VM | SIGCHLD, NULL);
|
| -#else
|
| - clone (linux_tracefork_grandchild, (char *) arg + STACK_SIZE,
|
| - CLONE_VM | SIGCHLD, NULL);
|
| -#endif
|
| -
|
| -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
|
| -
|
| - _exit (0);
|
| -}
|
| -
|
| -/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events. Make
|
| - sure that we can enable the option, and that it had the desired
|
| - effect. */
|
| -
|
| -static void
|
| -linux_test_for_tracefork (void)
|
| -{
|
| - int child_pid, ret, status;
|
| - long second_pid;
|
| -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
|
| - char *stack = xmalloc (STACK_SIZE * 4);
|
| -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
|
| -
|
| - linux_supports_tracefork_flag = 0;
|
| -
|
| -#if !(defined(__UCLIBC__) && defined(HAS_NOMMU))
|
| -
|
| - child_pid = fork ();
|
| - if (child_pid == 0)
|
| - linux_tracefork_child (NULL);
|
| -
|
| -#else /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
|
| -
|
| - /* Use CLONE_VM instead of fork, to support uClinux (no MMU). */
|
| -#ifdef __ia64__
|
| - child_pid = __clone2 (linux_tracefork_child, stack, STACK_SIZE,
|
| - CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2);
|
| -#else /* !__ia64__ */
|
| - child_pid = clone (linux_tracefork_child, stack + STACK_SIZE,
|
| - CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2);
|
| -#endif /* !__ia64__ */
|
| -
|
| -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
|
| -
|
| - if (child_pid == -1)
|
| - perror_with_name ("clone");
|
| -
|
| - ret = my_waitpid (child_pid, &status, 0);
|
| - if (ret == -1)
|
| - perror_with_name ("waitpid");
|
| - else if (ret != child_pid)
|
| - error ("linux_test_for_tracefork: waitpid: unexpected result %d.", ret);
|
| - if (! WIFSTOPPED (status))
|
| - error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status);
|
| -
|
| - ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0,
|
| - (PTRACE_ARG4_TYPE) PTRACE_O_TRACEFORK);
|
| - if (ret != 0)
|
| - {
|
| - ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
|
| - if (ret != 0)
|
| - {
|
| - warning ("linux_test_for_tracefork: failed to kill child");
|
| - return;
|
| - }
|
| -
|
| - ret = my_waitpid (child_pid, &status, 0);
|
| - if (ret != child_pid)
|
| - warning ("linux_test_for_tracefork: failed to wait for killed child");
|
| - else if (!WIFSIGNALED (status))
|
| - warning ("linux_test_for_tracefork: unexpected wait status 0x%x from "
|
| - "killed child", status);
|
| -
|
| - return;
|
| - }
|
| -
|
| - ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
|
| - if (ret != 0)
|
| - warning ("linux_test_for_tracefork: failed to resume child");
|
| -
|
| - ret = my_waitpid (child_pid, &status, 0);
|
| -
|
| - if (ret == child_pid && WIFSTOPPED (status)
|
| - && status >> 16 == PTRACE_EVENT_FORK)
|
| - {
|
| - second_pid = 0;
|
| - ret = ptrace (PTRACE_GETEVENTMSG, child_pid, 0, &second_pid);
|
| - if (ret == 0 && second_pid != 0)
|
| - {
|
| - int second_status;
|
| -
|
| - linux_supports_tracefork_flag = 1;
|
| - my_waitpid (second_pid, &second_status, 0);
|
| - ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
|
| - if (ret != 0)
|
| - warning ("linux_test_for_tracefork: failed to kill second child");
|
| - my_waitpid (second_pid, &status, 0);
|
| - }
|
| - }
|
| - else
|
| - warning ("linux_test_for_tracefork: unexpected result from waitpid "
|
| - "(%d, status 0x%x)", ret, status);
|
| -
|
| - do
|
| - {
|
| - ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
|
| - if (ret != 0)
|
| - warning ("linux_test_for_tracefork: failed to kill child");
|
| - my_waitpid (child_pid, &status, 0);
|
| - }
|
| - while (WIFSTOPPED (status));
|
| -
|
| -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
|
| - free (stack);
|
| -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */
|
| -}
|
| -
|
| -
|
| static void
|
| linux_look_up_symbols (void)
|
| {
|
| @@ -4712,10 +4593,10 @@ linux_look_up_symbols (void)
|
| if (proc->private->thread_db != NULL)
|
| return;
|
|
|
| - /* If the kernel supports tracing forks then it also supports tracing
|
| - clones, and then we don't need to use the magic thread event breakpoint
|
| - to learn about threads. */
|
| - thread_db_init (!linux_supports_tracefork_flag);
|
| + /* If the kernel supports tracing clones, then we don't need to
|
| + use the magic thread event breakpoint to learn about
|
| + threads. */
|
| + thread_db_init (!linux_supports_traceclone ());
|
| #endif
|
| }
|
|
|
| @@ -4805,25 +4686,14 @@ linux_stopped_data_address (void)
|
| return lwp->stopped_data_address;
|
| }
|
|
|
| -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
|
| -#if ! (defined(PT_TEXT_ADDR) \
|
| - || defined(PT_DATA_ADDR) \
|
| - || defined(PT_TEXT_END_ADDR))
|
| -#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
|
| -#elif defined(BFIN)
|
| -#define PT_TEXT_ADDR 220
|
| -#define PT_TEXT_END_ADDR 224
|
| -#define PT_DATA_ADDR 228
|
| -#elif defined(__TMS320C6X__)
|
| -#define PT_TEXT_ADDR (0x10000*4)
|
| -#define PT_DATA_ADDR (0x10004*4)
|
| -#define PT_TEXT_END_ADDR (0x10008*4)
|
| -#endif
|
| -#endif
|
| +#if defined(__UCLIBC__) && defined(HAS_NOMMU) \
|
| + && defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) \
|
| + && defined(PT_TEXT_END_ADDR)
|
| +
|
| +/* This is only used for targets that define PT_TEXT_ADDR,
|
| + PT_DATA_ADDR and PT_TEXT_END_ADDR. If those are not defined, supposedly
|
| + the target has different ways of acquiring this information, like
|
| + loadmaps. */
|
|
|
| /* Under uClinux, programs are loaded at non-zero offsets, which we need
|
| to tell gdb about. */
|
| @@ -4831,15 +4701,17 @@ linux_stopped_data_address (void)
|
| 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 = lwpid_of (get_thread_lwp (current_inferior));
|
|
|
| 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);
|
| + text = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_TEXT_ADDR,
|
| + (PTRACE_TYPE_ARG4) 0);
|
| + text_end = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_TEXT_END_ADDR,
|
| + (PTRACE_TYPE_ARG4) 0);
|
| + data = ptrace (PTRACE_PEEKUSER, pid, (PTRACE_TYPE_ARG3) PT_DATA_ADDR,
|
| + (PTRACE_TYPE_ARG4) 0);
|
|
|
| if (errno == 0)
|
| {
|
| @@ -4857,7 +4729,6 @@ linux_read_offsets (CORE_ADDR *text_p, CORE_ADDR *data_p)
|
|
|
| return 1;
|
| }
|
| -#endif
|
| return 0;
|
| }
|
| #endif
|
| @@ -4913,7 +4784,7 @@ linux_xfer_siginfo (const char *annex, unsigned char *readbuf,
|
| if (offset >= sizeof (siginfo))
|
| return -1;
|
|
|
| - if (ptrace (PTRACE_GETSIGINFO, pid, 0, &siginfo) != 0)
|
| + if (ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo) != 0)
|
| return -1;
|
|
|
| /* When GDBSERVER is built as a 64-bit application, ptrace writes into
|
| @@ -4934,7 +4805,7 @@ linux_xfer_siginfo (const char *annex, unsigned char *readbuf,
|
| /* Convert back to ptrace layout before flushing it out. */
|
| siginfo_fixup (&siginfo, inf_siginfo, 1);
|
|
|
| - if (ptrace (PTRACE_SETSIGINFO, pid, 0, &siginfo) != 0)
|
| + if (ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo) != 0)
|
| return -1;
|
| }
|
|
|
| @@ -5052,6 +4923,15 @@ linux_supports_agent (void)
|
| return 1;
|
| }
|
|
|
| +static int
|
| +linux_supports_range_stepping (void)
|
| +{
|
| + if (*the_low_target.supports_range_stepping == NULL)
|
| + return 0;
|
| +
|
| + return (*the_low_target.supports_range_stepping) ();
|
| +}
|
| +
|
| /* Enumerate spufs IDs for process PID. */
|
| static int
|
| spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len)
|
| @@ -5646,6 +5526,12 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
| };
|
| const struct link_map_offsets *lmo;
|
| unsigned int machine;
|
| + int ptr_size;
|
| + CORE_ADDR lm_addr = 0, lm_prev = 0;
|
| + int allocated = 1024;
|
| + char *p;
|
| + CORE_ADDR l_name, l_addr, l_ld, l_next, l_prev;
|
| + int header_done = 0;
|
|
|
| if (writebuf != NULL)
|
| return -2;
|
| @@ -5656,71 +5542,104 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
| xsnprintf (filename, sizeof filename, "/proc/%d/exe", pid);
|
| is_elf64 = elf_64_file_p (filename, &machine);
|
| lmo = is_elf64 ? &lmo_64bit_offsets : &lmo_32bit_offsets;
|
| + ptr_size = is_elf64 ? 8 : 4;
|
|
|
| - if (priv->r_debug == 0)
|
| - priv->r_debug = get_r_debug (pid, is_elf64);
|
| + while (annex[0] != '\0')
|
| + {
|
| + const char *sep;
|
| + CORE_ADDR *addrp;
|
| + int len;
|
|
|
| - /* We failed to find DT_DEBUG. Such situation will not change for this
|
| - inferior - do not retry it. Report it to GDB as E01, see for the reasons
|
| - at the GDB solib-svr4.c side. */
|
| - if (priv->r_debug == (CORE_ADDR) -1)
|
| - return -1;
|
| + sep = strchr (annex, '=');
|
| + if (sep == NULL)
|
| + break;
|
|
|
| - if (priv->r_debug == 0)
|
| - {
|
| - document = xstrdup ("<library-list-svr4 version=\"1.0\"/>\n");
|
| + len = sep - annex;
|
| + if (len == 5 && strncmp (annex, "start", 5) == 0)
|
| + addrp = &lm_addr;
|
| + else if (len == 4 && strncmp (annex, "prev", 4) == 0)
|
| + addrp = &lm_prev;
|
| + else
|
| + {
|
| + annex = strchr (sep, ';');
|
| + if (annex == NULL)
|
| + break;
|
| + annex++;
|
| + continue;
|
| + }
|
| +
|
| + annex = decode_address_to_semicolon (addrp, sep + 1);
|
| }
|
| - else
|
| +
|
| + if (lm_addr == 0)
|
| {
|
| - int allocated = 1024;
|
| - char *p;
|
| - const int ptr_size = is_elf64 ? 8 : 4;
|
| - CORE_ADDR lm_addr, lm_prev, l_name, l_addr, l_ld, l_next, l_prev;
|
| - int r_version, header_done = 0;
|
| -
|
| - document = xmalloc (allocated);
|
| - strcpy (document, "<library-list-svr4 version=\"1.0\"");
|
| - p = document + strlen (document);
|
| -
|
| - r_version = 0;
|
| - if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
|
| - (unsigned char *) &r_version,
|
| - sizeof (r_version)) != 0
|
| - || r_version != 1)
|
| + int r_version = 0;
|
| +
|
| + if (priv->r_debug == 0)
|
| + priv->r_debug = get_r_debug (pid, is_elf64);
|
| +
|
| + /* We failed to find DT_DEBUG. Such situation will not change
|
| + for this inferior - do not retry it. Report it to GDB as
|
| + E01, see for the reasons at the GDB solib-svr4.c side. */
|
| + if (priv->r_debug == (CORE_ADDR) -1)
|
| + return -1;
|
| +
|
| + if (priv->r_debug != 0)
|
| {
|
| - warning ("unexpected r_debug version %d", r_version);
|
| - goto done;
|
| + if (linux_read_memory (priv->r_debug + lmo->r_version_offset,
|
| + (unsigned char *) &r_version,
|
| + sizeof (r_version)) != 0
|
| + || r_version != 1)
|
| + {
|
| + warning ("unexpected r_debug version %d", r_version);
|
| + }
|
| + else if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
|
| + &lm_addr, ptr_size) != 0)
|
| + {
|
| + warning ("unable to read r_map from 0x%lx",
|
| + (long) priv->r_debug + lmo->r_map_offset);
|
| + }
|
| }
|
| + }
|
|
|
| - if (read_one_ptr (priv->r_debug + lmo->r_map_offset,
|
| - &lm_addr, ptr_size) != 0)
|
| + document = xmalloc (allocated);
|
| + strcpy (document, "<library-list-svr4 version=\"1.0\"");
|
| + p = document + strlen (document);
|
| +
|
| + while (lm_addr
|
| + && read_one_ptr (lm_addr + lmo->l_name_offset,
|
| + &l_name, ptr_size) == 0
|
| + && read_one_ptr (lm_addr + lmo->l_addr_offset,
|
| + &l_addr, ptr_size) == 0
|
| + && read_one_ptr (lm_addr + lmo->l_ld_offset,
|
| + &l_ld, ptr_size) == 0
|
| + && read_one_ptr (lm_addr + lmo->l_prev_offset,
|
| + &l_prev, ptr_size) == 0
|
| + && read_one_ptr (lm_addr + lmo->l_next_offset,
|
| + &l_next, ptr_size) == 0)
|
| + {
|
| + unsigned char libname[PATH_MAX];
|
| +
|
| + if (lm_prev != l_prev)
|
| {
|
| - warning ("unable to read r_map from 0x%lx",
|
| - (long) priv->r_debug + lmo->r_map_offset);
|
| - goto done;
|
| + warning ("Corrupted shared library list: 0x%lx != 0x%lx",
|
| + (long) lm_prev, (long) l_prev);
|
| + break;
|
| }
|
|
|
| - lm_prev = 0;
|
| - while (read_one_ptr (lm_addr + lmo->l_name_offset,
|
| - &l_name, ptr_size) == 0
|
| - && read_one_ptr (lm_addr + lmo->l_addr_offset,
|
| - &l_addr, ptr_size) == 0
|
| - && read_one_ptr (lm_addr + lmo->l_ld_offset,
|
| - &l_ld, ptr_size) == 0
|
| - && read_one_ptr (lm_addr + lmo->l_prev_offset,
|
| - &l_prev, ptr_size) == 0
|
| - && read_one_ptr (lm_addr + lmo->l_next_offset,
|
| - &l_next, ptr_size) == 0)
|
| + /* Ignore the first entry even if it has valid name as the first entry
|
| + corresponds to the main executable. The first entry should not be
|
| + skipped if the dynamic loader was loaded late by a static executable
|
| + (see solib-svr4.c parameter ignore_first). But in such case the main
|
| + executable does not have PT_DYNAMIC present and this function already
|
| + exited above due to failed get_r_debug. */
|
| + if (lm_prev == 0)
|
| + {
|
| + sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
|
| + p = p + strlen (p);
|
| + }
|
| + else
|
| {
|
| - unsigned char libname[PATH_MAX];
|
| -
|
| - if (lm_prev != l_prev)
|
| - {
|
| - warning ("Corrupted shared library list: 0x%lx != 0x%lx",
|
| - (long) lm_prev, (long) l_prev);
|
| - break;
|
| - }
|
| -
|
| /* Not checking for error because reading may stop before
|
| we've got PATH_MAX worth of characters. */
|
| libname[0] = '\0';
|
| @@ -5751,32 +5670,24 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
|
|
| name = xml_escape_text ((char *) libname);
|
| p += sprintf (p, "<library name=\"%s\" lm=\"0x%lx\" "
|
| - "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
|
| + "l_addr=\"0x%lx\" l_ld=\"0x%lx\"/>",
|
| name, (unsigned long) lm_addr,
|
| (unsigned long) l_addr, (unsigned long) l_ld);
|
| free (name);
|
| }
|
| - else if (lm_prev == 0)
|
| - {
|
| - sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
|
| - p = p + strlen (p);
|
| - }
|
| + }
|
|
|
| - if (l_next == 0)
|
| - break;
|
| + lm_prev = lm_addr;
|
| + lm_addr = l_next;
|
| + }
|
|
|
| - lm_prev = lm_addr;
|
| - lm_addr = l_next;
|
| - }
|
| - done:
|
| - if (!header_done)
|
| - {
|
| - /* Empty list; terminate `<library-list-svr4'. */
|
| - strcpy (p, "/>");
|
| - }
|
| - else
|
| - strcpy (p, "</library-list-svr4>");
|
| + if (!header_done)
|
| + {
|
| + /* Empty list; terminate `<library-list-svr4'. */
|
| + strcpy (p, "/>");
|
| }
|
| + else
|
| + strcpy (p, "</library-list-svr4>");
|
|
|
| document_len = strlen (document);
|
| if (offset < document_len)
|
| @@ -5792,6 +5703,53 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
|
| return len;
|
| }
|
|
|
| +#ifdef HAVE_LINUX_BTRACE
|
| +
|
| +/* Enable branch tracing. */
|
| +
|
| +static struct btrace_target_info *
|
| +linux_low_enable_btrace (ptid_t ptid)
|
| +{
|
| + struct btrace_target_info *tinfo;
|
| +
|
| + tinfo = linux_enable_btrace (ptid);
|
| +
|
| + if (tinfo != NULL)
|
| + {
|
| + struct thread_info *thread = find_thread_ptid (ptid);
|
| + struct regcache *regcache = get_thread_regcache (thread, 0);
|
| +
|
| + tinfo->ptr_bits = register_size (regcache->tdesc, 0) * 8;
|
| + }
|
| +
|
| + return tinfo;
|
| +}
|
| +
|
| +/* Read branch trace data as btrace xml document. */
|
| +
|
| +static void
|
| +linux_low_read_btrace (struct btrace_target_info *tinfo, struct buffer *buffer,
|
| + int type)
|
| +{
|
| + VEC (btrace_block_s) *btrace;
|
| + struct btrace_block *block;
|
| + int i;
|
| +
|
| + btrace = linux_read_btrace (tinfo, type);
|
| +
|
| + buffer_grow_str (buffer, "<!DOCTYPE btrace SYSTEM \"btrace.dtd\">\n");
|
| + buffer_grow_str (buffer, "<btrace version=\"1.0\">\n");
|
| +
|
| + for (i = 0; VEC_iterate (btrace_block_s, btrace, i, block); i++)
|
| + buffer_xml_printf (buffer, "<block begin=\"0x%s\" end=\"0x%s\"/>\n",
|
| + paddress (block->begin), paddress (block->end));
|
| +
|
| + buffer_grow_str (buffer, "</btrace>\n");
|
| +
|
| + VEC_free (btrace_block_s, btrace);
|
| +}
|
| +#endif /* HAVE_LINUX_BTRACE */
|
| +
|
| static struct target_ops linux_target_ops = {
|
| linux_create_inferior,
|
| linux_attach,
|
| @@ -5815,7 +5773,9 @@ static struct target_ops linux_target_ops = {
|
| linux_remove_point,
|
| linux_stopped_by_watchpoint,
|
| linux_stopped_data_address,
|
| -#if defined(__UCLIBC__) && defined(HAS_NOMMU)
|
| +#if defined(__UCLIBC__) && defined(HAS_NOMMU) \
|
| + && defined(PT_TEXT_ADDR) && defined(PT_DATA_ADDR) \
|
| + && defined(PT_TEXT_END_ADDR)
|
| linux_read_offsets,
|
| #else
|
| NULL,
|
| @@ -5856,6 +5816,18 @@ static struct target_ops linux_target_ops = {
|
| linux_get_min_fast_tracepoint_insn_len,
|
| linux_qxfer_libraries_svr4,
|
| linux_supports_agent,
|
| +#ifdef HAVE_LINUX_BTRACE
|
| + linux_supports_btrace,
|
| + linux_low_enable_btrace,
|
| + linux_disable_btrace,
|
| + linux_low_read_btrace,
|
| +#else
|
| + NULL,
|
| + NULL,
|
| + NULL,
|
| + NULL,
|
| +#endif
|
| + linux_supports_range_stepping,
|
| };
|
|
|
| static void
|
| @@ -5868,6 +5840,17 @@ linux_init_signals ()
|
| #endif
|
| }
|
|
|
| +#ifdef HAVE_LINUX_REGSETS
|
| +void
|
| +initialize_regsets_info (struct regsets_info *info)
|
| +{
|
| + for (info->num_regsets = 0;
|
| + info->regsets[info->num_regsets].size >= 0;
|
| + info->num_regsets++)
|
| + ;
|
| +}
|
| +#endif
|
| +
|
| void
|
| initialize_low (void)
|
| {
|
| @@ -5877,16 +5860,12 @@ initialize_low (void)
|
| set_breakpoint_data (the_low_target.breakpoint,
|
| the_low_target.breakpoint_len);
|
| linux_init_signals ();
|
| - linux_test_for_tracefork ();
|
| linux_ptrace_init_warnings ();
|
| -#ifdef HAVE_LINUX_REGSETS
|
| - for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++)
|
| - ;
|
| - disabled_regsets = xmalloc (num_regsets);
|
| -#endif
|
|
|
| sigchld_action.sa_handler = sigchld_handler;
|
| sigemptyset (&sigchld_action.sa_mask);
|
| sigchld_action.sa_flags = SA_RESTART;
|
| sigaction (SIGCHLD, &sigchld_action, NULL);
|
| +
|
| + initialize_low_arch ();
|
| }
|
|
|