diff options
author | Jan Kratochvil <jan.kratochvil@redhat.com> | 2012-07-07 12:13:57 +0000 |
---|---|---|
committer | Jan Kratochvil <jan.kratochvil@redhat.com> | 2012-07-07 12:13:57 +0000 |
commit | aa7c744796a067e1533b21e7d58aa30e6f3d12c8 (patch) | |
tree | 98ecb2c393bda1e81b72b416030ebe1f0904cedb /gdb | |
parent | 889003ed52d067a971c7e1ed8e0968d91264d273 (diff) | |
download | gdb-aa7c744796a067e1533b21e7d58aa30e6f3d12c8.zip gdb-aa7c744796a067e1533b21e7d58aa30e6f3d12c8.tar.gz gdb-aa7c744796a067e1533b21e7d58aa30e6f3d12c8.tar.bz2 |
gdb/
* common/linux-ptrace.c: Include gdb_assert.h.
<__i386__> (linux_ptrace_test_ret_to_nx_instr): New declaration.
<__i386__>: Include sys/reg.h, sys/mman.h, signal.h, sys/wait.h and
stdint.h.
(linux_ptrace_test_ret_to_nx, linux_ptrace_init_warnings): New
functions.
* common/linux-ptrace.h (linux_ptrace_init_warnings): New declarations.
* linux-nat.c (linux_child_post_attach)
(linux_child_post_startup_inferior): Call linux_ptrace_init_warnings.
gdb/gdbserver/
* gdbserver/linux-low.c (initialize_low): Call
linux_ptrace_init_warnings.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 12 | ||||
-rw-r--r-- | gdb/common/linux-ptrace.c | 124 | ||||
-rw-r--r-- | gdb/common/linux-ptrace.h | 1 | ||||
-rw-r--r-- | gdb/gdbserver/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/gdbserver/linux-low.c | 1 | ||||
-rw-r--r-- | gdb/linux-nat.c | 2 |
6 files changed, 145 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4ebefcc..cab30f7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,17 @@ 2012-07-07 Jan Kratochvil <jan.kratochvil@redhat.com> + * common/linux-ptrace.c: Include gdb_assert.h. + <__i386__> (linux_ptrace_test_ret_to_nx_instr): New declaration. + <__i386__>: Include sys/reg.h, sys/mman.h, signal.h, sys/wait.h and + stdint.h. + (linux_ptrace_test_ret_to_nx, linux_ptrace_init_warnings): New + functions. + * common/linux-ptrace.h (linux_ptrace_init_warnings): New declarations. + * linux-nat.c (linux_child_post_attach) + (linux_child_post_startup_inferior): Call linux_ptrace_init_warnings. + +2012-07-07 Jan Kratochvil <jan.kratochvil@redhat.com> + * linux-thread-db.c (thread_db_find_new_threads_silently): Do not apply nptl <2.7 bug workaround for core files. diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c index 600dcb9..fdec5d6 100644 --- a/gdb/common/linux-ptrace.c +++ b/gdb/common/linux-ptrace.c @@ -26,6 +26,7 @@ #include "linux-ptrace.h" #include "linux-procfs.h" #include "buffer.h" +#include "gdb_assert.h" /* Find all possible reasons we could fail to attach PID and append these newline terminated reason strings to initialized BUFFER. '\0' termination @@ -47,3 +48,126 @@ linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer) "- the process has already terminated\n"), (int) pid); } + +#ifdef __i386__ + +/* Address of the 'ret' instruction in asm code block below. */ +extern void (linux_ptrace_test_ret_to_nx_instr) (void); + +#include <sys/reg.h> +#include <sys/mman.h> +#include <signal.h> +#include <sys/wait.h> +#include <stdint.h> + +#endif /* __i386__ */ + +/* Test broken off-trunk Linux kernel patchset for NX support on i386. It was + removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd. */ + +static void +linux_ptrace_test_ret_to_nx (void) +{ +#ifdef __i386__ + pid_t child, got_pid; + gdb_byte *return_address, *pc; + long l; + int status; + + return_address = mmap (NULL, 2, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (return_address == MAP_FAILED) + { + warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"), + strerror (errno)); + return; + } + + /* Put there 'int3'. */ + *return_address = 0xcc; + + child = fork (); + switch (child) + { + case -1: + warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"), + strerror (errno)); + return; + + case 0: + l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + if (l != 0) + warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"), + strerror (errno)); + else + { + asm volatile ("pushl %0;" + ".globl linux_ptrace_test_ret_to_nx_instr;" + "linux_ptrace_test_ret_to_nx_instr:" + "ret" + : : "r" (return_address) : "%esp", "memory"); + gdb_assert_not_reached ("asm block did not terminate"); + } + + _exit (1); + } + + got_pid = waitpid (child, &status, 0); + gdb_assert (got_pid == child); + gdb_assert (WIFSTOPPED (status)); + + /* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */ + gdb_assert (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == SIGSEGV); + + errno = 0; + l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL); + gdb_assert (errno == 0); + pc = (void *) (uintptr_t) l; + + if (ptrace (PTRACE_KILL, child, NULL, NULL) != 0) + warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_KILL: %s"), + strerror (errno)); + else + { + int kill_status; + + got_pid = waitpid (child, &kill_status, 0); + gdb_assert (got_pid == child); + gdb_assert (WIFSIGNALED (kill_status)); + } + + /* + 1 is there as x86* stops after the 'int3' instruction. */ + if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1) + { + /* PASS */ + return; + } + + /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page. */ + if (WSTOPSIG (status) == SIGSEGV && pc == return_address) + { + /* PASS */ + return; + } + + gdb_assert ((void (*) (void)) pc == &linux_ptrace_test_ret_to_nx_instr); + + warning (_("Cannot call inferior functions, you have broken " + "Linux kernel i386 NX (non-executable pages) support!")); +#endif /* __i386__ */ +} + +/* Display possible problems on this system. Display them only once per GDB + execution. */ + +void +linux_ptrace_init_warnings (void) +{ + static int warned = 0; + + if (warned) + return; + warned = 1; + + linux_ptrace_test_ret_to_nx (); +} diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h index 6315b13..96ad33d 100644 --- a/gdb/common/linux-ptrace.h +++ b/gdb/common/linux-ptrace.h @@ -68,5 +68,6 @@ struct buffer; #endif extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer); +extern void linux_ptrace_init_warnings (void); #endif /* COMMON_LINUX_PTRACE_H */ diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 43e5240..3757add 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,8 @@ +2012-07-07 Jan Kratochvil <jan.kratochvil@redhat.com> + + * gdbserver/linux-low.c (initialize_low): Call + linux_ptrace_init_warnings. + 2012-07-02 Doug Evans <dje@google.com> * mem-break.c (gdb_no_commands_at_breakpoint): Fix cast from diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 48134c3..a476031 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -5878,6 +5878,7 @@ initialize_low (void) 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++) ; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index 8078a80..7ed666f 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -583,6 +583,7 @@ linux_child_post_attach (int pid) { linux_enable_event_reporting (pid_to_ptid (pid)); linux_enable_tracesysgood (pid_to_ptid (pid)); + linux_ptrace_init_warnings (); } static void @@ -590,6 +591,7 @@ linux_child_post_startup_inferior (ptid_t ptid) { linux_enable_event_reporting (ptid); linux_enable_tracesysgood (ptid); + linux_ptrace_init_warnings (); } /* Return the number of known LWPs in the tgid given by PID. */ |