X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Flinux-nat.c;h=aaf55bfaa3eadcc1ab04c08c1dc0df95cda0fa91;hb=ff214e679c60368c23e4052c9efcc7457a3a2c43;hp=a34b29a11620a9f117fd237b20c4fbbb1fa2dc1f;hpb=cde33bf1035aac8e2e35c4699544dcc166f2054d;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index a34b29a116..aaf55bfaa3 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1,6 +1,6 @@ /* GNU/Linux native-dependent code common to multiple platforms. - Copyright (C) 2001-2013 Free Software Foundation, Inc. + Copyright (C) 2001-2014 Free Software Foundation, Inc. This file is part of GDB. @@ -46,7 +46,6 @@ #include "gregset.h" /* for gregset */ #include "gdbcore.h" /* for get_exec_file */ #include /* for isdigit */ -#include "gdbthread.h" /* for struct thread_info etc. */ #include /* for struct stat */ #include /* for O_RDONLY */ #include "inf-loop.h" @@ -65,7 +64,6 @@ #include "agent.h" #include "tracepoint.h" #include "exceptions.h" -#include "linux-ptrace.h" #include "buffer.h" #include "target-descriptions.h" #include "filestuff.h" @@ -200,11 +198,7 @@ static int (*linux_nat_siginfo_fixup) (siginfo_t *, /* The saved to_xfer_partial method, inherited from inf-ptrace.c. Called by our to_xfer_partial. */ -static LONGEST (*super_xfer_partial) (struct target_ops *, - enum target_object, - const char *, gdb_byte *, - const gdb_byte *, - ULONGEST, LONGEST); +static target_xfer_partial_ftype *super_xfer_partial; static unsigned int debug_linux_nat; static void @@ -268,10 +262,6 @@ async_file_mark (void) be awakened anyway. */ } -static void linux_nat_async (void (*callback) - (enum inferior_event_type event_type, - void *context), - void *context); static int kill_lwp (int lwpid, int signo); static int stop_callback (struct lwp_info *lp, void *data); @@ -339,13 +329,13 @@ linux_init_ptrace (pid_t pid) } static void -linux_child_post_attach (int pid) +linux_child_post_attach (struct target_ops *self, int pid) { linux_init_ptrace (pid); } static void -linux_child_post_startup_inferior (ptid_t ptid) +linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid) { linux_init_ptrace (ptid_get_pid (ptid)); } @@ -706,43 +696,44 @@ holding the child stopped. Try \"set detach-on-fork\" or \ static int -linux_child_insert_fork_catchpoint (int pid) +linux_child_insert_fork_catchpoint (struct target_ops *self, int pid) { return !linux_supports_tracefork (); } static int -linux_child_remove_fork_catchpoint (int pid) +linux_child_remove_fork_catchpoint (struct target_ops *self, int pid) { return 0; } static int -linux_child_insert_vfork_catchpoint (int pid) +linux_child_insert_vfork_catchpoint (struct target_ops *self, int pid) { return !linux_supports_tracefork (); } static int -linux_child_remove_vfork_catchpoint (int pid) +linux_child_remove_vfork_catchpoint (struct target_ops *self, int pid) { return 0; } static int -linux_child_insert_exec_catchpoint (int pid) +linux_child_insert_exec_catchpoint (struct target_ops *self, int pid) { return !linux_supports_tracefork (); } static int -linux_child_remove_exec_catchpoint (int pid) +linux_child_remove_exec_catchpoint (struct target_ops *self, int pid) { return 0; } static int -linux_child_set_syscall_catchpoint (int pid, int needed, int any_count, +linux_child_set_syscall_catchpoint (struct target_ops *self, + int pid, int needed, int any_count, int table_size, int *table) { if (!linux_supports_tracesysgood ()) @@ -2490,7 +2481,7 @@ save_sigtrap (struct lwp_info *lp) old_chain = save_inferior_ptid (); inferior_ptid = lp->ptid; - lp->stopped_by_watchpoint = linux_ops->to_stopped_by_watchpoint (); + lp->stopped_by_watchpoint = linux_ops->to_stopped_by_watchpoint (linux_ops); if (lp->stopped_by_watchpoint) { @@ -2508,7 +2499,7 @@ save_sigtrap (struct lwp_info *lp) /* See save_sigtrap. */ static int -linux_nat_stopped_by_watchpoint (void) +linux_nat_stopped_by_watchpoint (struct target_ops *ops) { struct lwp_info *lp = find_lwp_pid (inferior_ptid); @@ -2742,7 +2733,7 @@ cancel_breakpoint (struct lwp_info *lp) struct gdbarch *gdbarch = get_regcache_arch (regcache); CORE_ADDR pc; - pc = regcache_read_pc (regcache) - gdbarch_decr_pc_after_break (gdbarch); + pc = regcache_read_pc (regcache) - target_decr_pc_after_break (gdbarch); if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc)) { if (debug_linux_nat) @@ -2751,7 +2742,7 @@ cancel_breakpoint (struct lwp_info *lp) target_pid_to_str (lp->ptid)); /* Back up the PC if necessary. */ - if (gdbarch_decr_pc_after_break (gdbarch)) + if (target_decr_pc_after_break (gdbarch)) regcache_write_pc (regcache, pc); return 1; @@ -3868,10 +3859,11 @@ siginfo_fixup (siginfo_t *siginfo, gdb_byte *inf_siginfo, int direction) } } -static LONGEST +static enum target_xfer_status linux_xfer_siginfo (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) { int pid; siginfo_t siginfo; @@ -3885,12 +3877,12 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object, pid = ptid_get_pid (inferior_ptid); if (offset > sizeof (siginfo)) - return -1; + return TARGET_XFER_E_IO; errno = 0; ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); if (errno != 0) - return -1; + return TARGET_XFER_E_IO; /* When GDB is built as a 64-bit application, ptrace writes into SIGINFO an object with 64-bit layout. Since debugging a 32-bit @@ -3915,30 +3907,31 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object, errno = 0; ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); if (errno != 0) - return -1; + return TARGET_XFER_E_IO; } - return len; + *xfered_len = len; + return TARGET_XFER_OK; } -static LONGEST +static enum target_xfer_status linux_nat_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) + ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { struct cleanup *old_chain; - LONGEST xfer; + enum target_xfer_status xfer; if (object == TARGET_OBJECT_SIGNAL_INFO) return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf, - offset, len); + offset, len, xfered_len); /* The target is connected but no live inferior is selected. Pass this request down to a lower stratum (e.g., the executable file). */ if (object == TARGET_OBJECT_MEMORY && ptid_equal (inferior_ptid, null_ptid)) - return 0; + return TARGET_XFER_EOF; old_chain = save_inferior_ptid (); @@ -3946,7 +3939,7 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object, inferior_ptid = pid_to_ptid (ptid_get_lwp (inferior_ptid)); xfer = linux_ops->to_xfer_partial (ops, object, annex, readbuf, writebuf, - offset, len); + offset, len, xfered_len); do_cleanups (old_chain); return xfer; @@ -4116,11 +4109,11 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size) can be much more efficient than banging away at PTRACE_PEEKTEXT, but it doesn't support writes. */ -static LONGEST +static enum target_xfer_status linux_proc_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) + ULONGEST offset, LONGEST len, ULONGEST *xfered_len) { LONGEST ret; int fd; @@ -4131,7 +4124,7 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object, /* Don't bother for one word. */ if (len < 3 * sizeof (long)) - return 0; + return TARGET_XFER_EOF; /* We could keep this file open and cache it - possibly one per thread. That requires some juggling, but is even faster. */ @@ -4139,7 +4132,7 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object, ptid_get_pid (inferior_ptid)); fd = gdb_open_cloexec (filename, O_RDONLY | O_LARGEFILE, 0); if (fd == -1) - return 0; + return TARGET_XFER_EOF; /* If pread64 is available, use it. It's faster if the kernel supports it (only one syscall), and it's 64-bit safe even on @@ -4155,13 +4148,20 @@ linux_proc_xfer_partial (struct target_ops *ops, enum target_object object, ret = len; close (fd); - return ret; + + if (ret == 0) + return TARGET_XFER_EOF; + else + { + *xfered_len = ret; + return TARGET_XFER_OK; + } } /* Enumerate spufs IDs for process PID. */ static LONGEST -spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, LONGEST len) +spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, ULONGEST len) { enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); LONGEST pos = 0; @@ -4211,11 +4211,12 @@ spu_enumerate_spu_ids (int pid, gdb_byte *buf, ULONGEST offset, LONGEST len) /* Implement the to_xfer_partial interface for the TARGET_OBJECT_SPU object type, using the /proc file system. */ -static LONGEST + +static enum target_xfer_status linux_proc_xfer_spu (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, - ULONGEST offset, LONGEST len) + ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { char buf[128]; int fd = 0; @@ -4225,21 +4226,33 @@ linux_proc_xfer_spu (struct target_ops *ops, enum target_object object, if (!annex) { if (!readbuf) - return -1; + return TARGET_XFER_E_IO; else - return spu_enumerate_spu_ids (pid, readbuf, offset, len); + { + LONGEST l = spu_enumerate_spu_ids (pid, readbuf, offset, len); + + if (l < 0) + return TARGET_XFER_E_IO; + else if (l == 0) + return TARGET_XFER_EOF; + else + { + *xfered_len = (ULONGEST) l; + return TARGET_XFER_OK; + } + } } xsnprintf (buf, sizeof buf, "/proc/%d/fd/%s", pid, annex); fd = gdb_open_cloexec (buf, writebuf? O_WRONLY : O_RDONLY, 0); if (fd <= 0) - return -1; + return TARGET_XFER_E_IO; if (offset != 0 && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset) { close (fd); - return 0; + return TARGET_XFER_EOF; } if (writebuf) @@ -4248,7 +4261,16 @@ linux_proc_xfer_spu (struct target_ops *ops, enum target_object object, ret = read (fd, readbuf, (size_t) len); close (fd); - return ret; + + if (ret < 0) + return TARGET_XFER_E_IO; + else if (ret == 0) + return TARGET_XFER_EOF; + else + { + *xfered_len = (ULONGEST) ret; + return TARGET_XFER_OK; + } } @@ -4335,34 +4357,40 @@ linux_proc_pending_signals (int pid, sigset_t *pending, do_cleanups (cleanup); } -static LONGEST +static enum target_xfer_status linux_nat_xfer_osdata (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) { gdb_assert (object == TARGET_OBJECT_OSDATA); - return linux_common_xfer_osdata (annex, readbuf, offset, len); + *xfered_len = linux_common_xfer_osdata (annex, readbuf, offset, len); + if (*xfered_len == 0) + return TARGET_XFER_EOF; + else + return TARGET_XFER_OK; } -static LONGEST +static enum target_xfer_status linux_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) + const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) { - LONGEST xfer; + enum target_xfer_status xfer; if (object == TARGET_OBJECT_AUXV) return memory_xfer_auxv (ops, object, annex, readbuf, writebuf, - offset, len); + offset, len, xfered_len); if (object == TARGET_OBJECT_OSDATA) return linux_nat_xfer_osdata (ops, object, annex, readbuf, writebuf, - offset, len); + offset, len, xfered_len); if (object == TARGET_OBJECT_SPU) return linux_proc_xfer_spu (ops, object, annex, readbuf, writebuf, - offset, len); + offset, len, xfered_len); /* GDB calculates all the addresses in possibly larget width of the address. Address width needs to be masked before its final use - either by @@ -4379,12 +4407,12 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object, } xfer = linux_proc_xfer_partial (ops, object, annex, readbuf, writebuf, - offset, len); - if (xfer != 0) + offset, len, xfered_len); + if (xfer != TARGET_XFER_EOF) return xfer; return super_xfer_partial (ops, object, annex, readbuf, writebuf, - offset, len); + offset, len, xfered_len); } static void @@ -4505,7 +4533,7 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int)) /* target_is_async_p implementation. */ static int -linux_nat_is_async_p (void) +linux_nat_is_async_p (struct target_ops *ops) { /* NOTE: palves 2008-03-21: We're only async when the user requests it explicitly with the "set target-async" command. @@ -4516,7 +4544,7 @@ linux_nat_is_async_p (void) /* target_can_async_p implementation. */ static int -linux_nat_can_async_p (void) +linux_nat_can_async_p (struct target_ops *ops) { /* NOTE: palves 2008-03-21: We're only async when the user requests it explicitly with the "set target-async" command. @@ -4556,16 +4584,16 @@ static int async_terminal_is_ours = 1; /* target_terminal_inferior implementation. */ static void -linux_nat_terminal_inferior (void) +linux_nat_terminal_inferior (struct target_ops *self) { if (!target_is_async_p ()) { /* Async mode is disabled. */ - terminal_inferior (); + terminal_inferior (self); return; } - terminal_inferior (); + terminal_inferior (self); /* Calls to target_terminal_*() are meant to be idempotent. */ if (!async_terminal_is_ours) @@ -4579,19 +4607,19 @@ linux_nat_terminal_inferior (void) /* target_terminal_ours implementation. */ static void -linux_nat_terminal_ours (void) +linux_nat_terminal_ours (struct target_ops *self) { if (!target_is_async_p ()) { /* Async mode is disabled. */ - terminal_ours (); + terminal_ours (self); return; } /* GDB should never give the terminal to the inferior if the inferior is running in the background (run&, continue&, etc.), but claiming it sure should. */ - terminal_ours (); + terminal_ours (self); if (async_terminal_is_ours) return; @@ -4676,8 +4704,10 @@ linux_async_pipe (int enable) /* target_async implementation. */ static void -linux_nat_async (void (*callback) (enum inferior_event_type event_type, - void *context), void *context) +linux_nat_async (struct target_ops *ops, + void (*callback) (enum inferior_event_type event_type, + void *context), + void *context) { if (callback != NULL) { @@ -4759,14 +4789,14 @@ linux_nat_stop (ptid_t ptid) } static void -linux_nat_close (void) +linux_nat_close (struct target_ops *self) { /* Unregister from the event loop. */ - if (linux_nat_is_async_p ()) - linux_nat_async (NULL, 0); + if (linux_nat_is_async_p (NULL)) + linux_nat_async (NULL, NULL, 0); if (linux_ops->to_close) - linux_ops->to_close (); + linux_ops->to_close (linux_ops); } /* When requests are passed down from the linux-nat layer to the