* 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.
This commit is contained in:
Jan Kratochvil 2012-07-07 12:13:57 +00:00
parent 889003ed52
commit aa7c744796
6 changed files with 145 additions and 0 deletions

View File

@ -1,3 +1,15 @@
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> 2012-07-07 Jan Kratochvil <jan.kratochvil@redhat.com>
* linux-thread-db.c (thread_db_find_new_threads_silently): Do not apply * linux-thread-db.c (thread_db_find_new_threads_silently): Do not apply

View File

@ -26,6 +26,7 @@
#include "linux-ptrace.h" #include "linux-ptrace.h"
#include "linux-procfs.h" #include "linux-procfs.h"
#include "buffer.h" #include "buffer.h"
#include "gdb_assert.h"
/* Find all possible reasons we could fail to attach PID and append these /* Find all possible reasons we could fail to attach PID and append these
newline terminated reason strings to initialized BUFFER. '\0' termination 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"), "- the process has already terminated\n"),
(int) pid); (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 ();
}

View File

@ -68,5 +68,6 @@ struct buffer;
#endif #endif
extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer); extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer);
extern void linux_ptrace_init_warnings (void);
#endif /* COMMON_LINUX_PTRACE_H */ #endif /* COMMON_LINUX_PTRACE_H */

View 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> 2012-07-02 Doug Evans <dje@google.com>
* mem-break.c (gdb_no_commands_at_breakpoint): Fix cast from * mem-break.c (gdb_no_commands_at_breakpoint): Fix cast from

View File

@ -5878,6 +5878,7 @@ initialize_low (void)
the_low_target.breakpoint_len); the_low_target.breakpoint_len);
linux_init_signals (); linux_init_signals ();
linux_test_for_tracefork (); linux_test_for_tracefork ();
linux_ptrace_init_warnings ();
#ifdef HAVE_LINUX_REGSETS #ifdef HAVE_LINUX_REGSETS
for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++) for (num_regsets = 0; target_regsets[num_regsets].size >= 0; num_regsets++)
; ;

View File

@ -583,6 +583,7 @@ linux_child_post_attach (int pid)
{ {
linux_enable_event_reporting (pid_to_ptid (pid)); linux_enable_event_reporting (pid_to_ptid (pid));
linux_enable_tracesysgood (pid_to_ptid (pid)); linux_enable_tracesysgood (pid_to_ptid (pid));
linux_ptrace_init_warnings ();
} }
static void static void
@ -590,6 +591,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{ {
linux_enable_event_reporting (ptid); linux_enable_event_reporting (ptid);
linux_enable_tracesysgood (ptid); linux_enable_tracesysgood (ptid);
linux_ptrace_init_warnings ();
} }
/* Return the number of known LWPs in the tgid given by PID. */ /* Return the number of known LWPs in the tgid given by PID. */