gdb/
authorJan Kratochvil <jan.kratochvil@redhat.com>
Sat, 7 Jul 2012 12:13:57 +0000 (12:13 +0000)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Sat, 7 Jul 2012 12:13:57 +0000 (12:13 +0000)
* 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.

gdb/ChangeLog
gdb/common/linux-ptrace.c
gdb/common/linux-ptrace.h
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/linux-nat.c

index 4ebefcc..cab30f7 100644 (file)
@@ -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.
 
index 600dcb9..fdec5d6 100644 (file)
@@ -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 ();
+}
index 6315b13..96ad33d 100644 (file)
@@ -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 */
index 43e5240..3757add 100644 (file)
@@ -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
index 48134c3..a476031 100644 (file)
@@ -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++)
     ;
index 8078a80..7ed666f 100644 (file)
@@ -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.  */