X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finf-ptrace.c;h=44216c45d621df4899147acfe1ae72e9de25104c;hb=6bd6f3b6569945700386847f624dc9e8b7f57450;hp=f3c510555ff34ae229bfbbdd04044cc27ed06560;hpb=e379037592ff71dc633c6d3de0828babe805ae96;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c index f3c510555f..44216c45d6 100644 --- a/gdb/inf-ptrace.c +++ b/gdb/inf-ptrace.c @@ -1,6 +1,6 @@ /* Low-level child interface to ptrace. - Copyright (C) 1988-2015 Free Software Foundation, Inc. + Copyright (C) 1988-2018 Free Software Foundation, Inc. This file is part of GDB. @@ -31,6 +31,8 @@ #include "inf-ptrace.h" #include "inf-child.h" #include "gdbthread.h" +#include "nat/fork-inferior.h" +#include "utils.h" @@ -79,7 +81,8 @@ static void inf_ptrace_me (void) { /* "Trace me, Dr. Memory!" */ - ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3)0, 0); + if (ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3) 0, 0) < 0) + trace_start_error_with_name ("ptrace"); } /* Start a new inferior Unix child process. EXEC_FILE is the file to @@ -89,10 +92,11 @@ inf_ptrace_me (void) static void inf_ptrace_create_inferior (struct target_ops *ops, - char *exec_file, char *allargs, char **env, - int from_tty) + const char *exec_file, const std::string &allargs, + char **env, int from_tty) { - int pid; + pid_t pid; + ptid_t ptid; /* Do not change either targets above or the same target if already present. The reason is the target stack is shared across multiple inferiors. */ @@ -109,13 +113,19 @@ inf_ptrace_create_inferior (struct target_ops *ops, pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL, NULL, NULL, NULL); + ptid = pid_to_ptid (pid); + /* We have something that executes now. We'll be running through + the shell at this point (if startup-with-shell is true), but the + pid shouldn't change. */ + add_thread_silent (ptid); + discard_cleanups (back_to); - startup_inferior (START_INFERIOR_TRAPS_EXPECTED); + gdb_startup_inferior (pid, START_INFERIOR_TRAPS_EXPECTED); /* On some targets, there must be some explicit actions taken after the inferior has been started up. */ - target_post_startup_inferior (pid_to_ptid (pid)); + target_post_startup_inferior (ptid); } #ifdef PT_GET_PROCESS_STATE @@ -231,26 +241,14 @@ inf_ptrace_post_attach (struct target_ops *self, int pid) #endif -/* Detach from the inferior, optionally passing it the signal - specified by ARGS. If FROM_TTY is non-zero, be chatty about it. */ +/* Detach from the inferior. If FROM_TTY is non-zero, be chatty about it. */ static void -inf_ptrace_detach (struct target_ops *ops, const char *args, int from_tty) +inf_ptrace_detach (struct target_ops *ops, int from_tty) { pid_t pid = ptid_get_pid (inferior_ptid); - int sig = 0; - if (from_tty) - { - char *exec_file = get_exec_file (0); - if (exec_file == 0) - exec_file = ""; - printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file, - target_pid_to_str (pid_to_ptid (pid))); - gdb_flush (gdb_stdout); - } - if (args) - sig = atoi (args); + target_announce_detach (from_tty); #ifdef PT_DETACH /* We'd better not have left any breakpoints in the program or it'll @@ -258,13 +256,23 @@ inf_ptrace_detach (struct target_ops *ops, const char *args, int from_tty) previously attached to the inferior. It *might* work if we started the process ourselves. */ errno = 0; - ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, sig); + ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0); if (errno != 0) perror_with_name (("ptrace")); #else error (_("This system does not support detaching from a process")); #endif + inf_ptrace_detach_success (ops); +} + +/* See inf-ptrace.h. */ + +void +inf_ptrace_detach_success (struct target_ops *ops) +{ + pid_t pid = ptid_get_pid (inferior_ptid); + inferior_ptid = null_ptid; detach_inferior (pid); @@ -285,13 +293,13 @@ inf_ptrace_kill (struct target_ops *ops) ptrace (PT_KILL, pid, (PTRACE_TYPE_ARG3)0, 0); waitpid (pid, &status, 0); - target_mourn_inferior (); + target_mourn_inferior (inferior_ptid); } -/* Stop the inferior. */ +/* Interrupt the inferior. */ static void -inf_ptrace_stop (struct target_ops *self, ptid_t ptid) +inf_ptrace_interrupt (struct target_ops *self, ptid_t ptid) { /* Send a SIGINT to the process group. This acts just like the user typed a ^C on the controlling terminal. Note that using a @@ -304,7 +312,7 @@ inf_ptrace_stop (struct target_ops *self, ptid_t ptid) /* Return which PID to pass to ptrace in order to observe/control the tracee identified by PTID. */ -static pid_t +pid_t get_ptrace_pid (ptid_t ptid) { pid_t pid; @@ -443,6 +451,72 @@ inf_ptrace_wait (struct target_ops *ops, return pid_to_ptid (pid); } +/* Transfer data via ptrace into process PID's memory from WRITEBUF, or + from process PID's memory into READBUF. Start at target address ADDR + and transfer up to LEN bytes. Exactly one of READBUF and WRITEBUF must + be non-null. Return the number of transferred bytes. */ + +static ULONGEST +inf_ptrace_peek_poke (pid_t pid, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST addr, ULONGEST len) +{ + ULONGEST n; + unsigned int chunk; + + /* We transfer aligned words. Thus align ADDR down to a word + boundary and determine how many bytes to skip at the + beginning. */ + ULONGEST skip = addr & (sizeof (PTRACE_TYPE_RET) - 1); + addr -= skip; + + for (n = 0; + n < len; + n += chunk, addr += sizeof (PTRACE_TYPE_RET), skip = 0) + { + /* Restrict to a chunk that fits in the current word. */ + chunk = std::min (sizeof (PTRACE_TYPE_RET) - skip, len - n); + + /* Use a union for type punning. */ + union + { + PTRACE_TYPE_RET word; + gdb_byte byte[sizeof (PTRACE_TYPE_RET)]; + } buf; + + /* Read the word, also when doing a partial word write. */ + if (readbuf != NULL || chunk < sizeof (PTRACE_TYPE_RET)) + { + errno = 0; + buf.word = ptrace (PT_READ_I, pid, + (PTRACE_TYPE_ARG3)(uintptr_t) addr, 0); + if (errno != 0) + break; + if (readbuf != NULL) + memcpy (readbuf + n, buf.byte + skip, chunk); + } + if (writebuf != NULL) + { + memcpy (buf.byte + skip, writebuf + n, chunk); + errno = 0; + ptrace (PT_WRITE_D, pid, (PTRACE_TYPE_ARG3)(uintptr_t) addr, + buf.word); + if (errno != 0) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WRITE_I, pid, (PTRACE_TYPE_ARG3)(uintptr_t) addr, + buf.word); + if (errno != 0) + break; + } + } + } + + return n; +} + /* Implement the to_xfer_partial target_ops method. */ static enum target_xfer_status @@ -451,7 +525,7 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object, const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { - pid_t pid = ptid_get_pid (inferior_ptid); + pid_t pid = get_ptrace_pid (inferior_ptid); switch (object) { @@ -488,79 +562,9 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object, return TARGET_XFER_EOF; } #endif - { - union - { - PTRACE_TYPE_RET word; - gdb_byte byte[sizeof (PTRACE_TYPE_RET)]; - } buffer; - ULONGEST rounded_offset; - ULONGEST partial_len; - - /* Round the start offset down to the next long word - boundary. */ - rounded_offset = offset & -(ULONGEST) sizeof (PTRACE_TYPE_RET); - - /* Since ptrace will transfer a single word starting at that - rounded_offset the partial_len needs to be adjusted down to - that (remember this function only does a single transfer). - Should the required length be even less, adjust it down - again. */ - partial_len = (rounded_offset + sizeof (PTRACE_TYPE_RET)) - offset; - if (partial_len > len) - partial_len = len; - - if (writebuf) - { - /* If OFFSET:PARTIAL_LEN is smaller than - ROUNDED_OFFSET:WORDSIZE then a read/modify write will - be needed. Read in the entire word. */ - if (rounded_offset < offset - || (offset + partial_len - < rounded_offset + sizeof (PTRACE_TYPE_RET))) - /* Need part of initial word -- fetch it. */ - buffer.word = ptrace (PT_READ_I, pid, - (PTRACE_TYPE_ARG3)(uintptr_t) - rounded_offset, 0); - - /* Copy data to be written over corresponding part of - buffer. */ - memcpy (buffer.byte + (offset - rounded_offset), - writebuf, partial_len); - - errno = 0; - ptrace (PT_WRITE_D, pid, - (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset, - buffer.word); - if (errno) - { - /* Using the appropriate one (I or D) is necessary for - Gould NP1, at least. */ - errno = 0; - ptrace (PT_WRITE_I, pid, - (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset, - buffer.word); - if (errno) - return TARGET_XFER_EOF; - } - } - - if (readbuf) - { - errno = 0; - buffer.word = ptrace (PT_READ_I, pid, - (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset, - 0); - if (errno) - return TARGET_XFER_EOF; - /* Copy appropriate bytes out of the buffer. */ - memcpy (readbuf, buffer.byte + (offset - rounded_offset), - partial_len); - } - - *xfered_len = partial_len; - return TARGET_XFER_OK; - } + *xfered_len = inf_ptrace_peek_poke (pid, readbuf, writebuf, + offset, len); + return *xfered_len != 0 ? TARGET_XFER_OK : TARGET_XFER_EOF; case TARGET_OBJECT_UNWIND_TABLE: return TARGET_XFER_E_IO; @@ -620,7 +624,7 @@ inf_ptrace_files_info (struct target_ops *ignore) target_pid_to_str (inferior_ptid)); } -static char * +static const char * inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid) { return normal_pid_to_str (ptid); @@ -686,7 +690,7 @@ inf_ptrace_target (void) t->to_mourn_inferior = inf_ptrace_mourn_inferior; t->to_thread_alive = inf_ptrace_thread_alive; t->to_pid_to_str = inf_ptrace_pid_to_str; - t->to_stop = inf_ptrace_stop; + t->to_interrupt = inf_ptrace_interrupt; t->to_xfer_partial = inf_ptrace_xfer_partial; #if defined (PT_IO) && defined (PIOD_READ_AUXV) t->to_auxv_parse = inf_ptrace_auxv_parse; @@ -705,11 +709,12 @@ static CORE_ADDR (*inf_ptrace_register_u_offset)(struct gdbarch *, int, int); static void inf_ptrace_fetch_register (struct regcache *regcache, int regnum) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); CORE_ADDR addr; size_t size; PTRACE_TYPE_RET *buf; - int pid, i; + pid_t pid; + int i; /* This isn't really an address, but ptrace thinks of it as one. */ addr = inf_ptrace_register_u_offset (gdbarch, regnum, 0); @@ -720,15 +725,11 @@ inf_ptrace_fetch_register (struct regcache *regcache, int regnum) return; } - /* Cater for systems like GNU/Linux, that implement threads as - separate processes. */ - pid = ptid_get_lwp (inferior_ptid); - if (pid == 0) - pid = ptid_get_pid (inferior_ptid); + pid = get_ptrace_pid (regcache_get_ptid (regcache)); size = register_size (gdbarch, regnum); gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0); - buf = alloca (size); + buf = (PTRACE_TYPE_RET *) alloca (size); /* Read the register contents from the inferior a chunk at a time. */ for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) @@ -754,7 +755,7 @@ inf_ptrace_fetch_registers (struct target_ops *ops, { if (regnum == -1) for (regnum = 0; - regnum < gdbarch_num_regs (get_regcache_arch (regcache)); + regnum < gdbarch_num_regs (regcache->arch ()); regnum++) inf_ptrace_fetch_register (regcache, regnum); else @@ -766,11 +767,12 @@ inf_ptrace_fetch_registers (struct target_ops *ops, static void inf_ptrace_store_register (const struct regcache *regcache, int regnum) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); CORE_ADDR addr; size_t size; PTRACE_TYPE_RET *buf; - int pid, i; + pid_t pid; + int i; /* This isn't really an address, but ptrace thinks of it as one. */ addr = inf_ptrace_register_u_offset (gdbarch, regnum, 1); @@ -778,15 +780,11 @@ inf_ptrace_store_register (const struct regcache *regcache, int regnum) || gdbarch_cannot_store_register (gdbarch, regnum)) return; - /* Cater for systems like GNU/Linux, that implement threads as - separate processes. */ - pid = ptid_get_lwp (inferior_ptid); - if (pid == 0) - pid = ptid_get_pid (inferior_ptid); + pid = get_ptrace_pid (regcache_get_ptid (regcache)); size = register_size (gdbarch, regnum); gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0); - buf = alloca (size); + buf = (PTRACE_TYPE_RET *) alloca (size); /* Write the register contents into the inferior a chunk at a time. */ regcache_raw_collect (regcache, regnum, buf); @@ -812,7 +810,7 @@ inf_ptrace_store_registers (struct target_ops *ops, { if (regnum == -1) for (regnum = 0; - regnum < gdbarch_num_regs (get_regcache_arch (regcache)); + regnum < gdbarch_num_regs (regcache->arch ()); regnum++) inf_ptrace_store_register (regcache, regnum); else