* 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>
* 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-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 ();
}

View 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 */

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>
* 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);
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++)
;

View 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. */