19#include "gdbsupport/common-defs.h"
23#ifdef HAVE_SYS_PROCFS_H
24#include <sys/procfs.h>
42 string_appendf (result,
43 _(
"process %d is already traced by process %d"),
44 (
int) pid, (
int) tracerpid);
47 string_appendf (result,
48 _(
"process %d is a zombie - the process has already "
60 long lwpid = ptid.lwp ();
64 return string_printf (
"%s (%d), %s", safe_strerror (err), err,
67 return string_printf (
"%s (%d)", safe_strerror (err), err);
70#if defined __i386__ || defined __x86_64__
73EXTERN_C
void linux_ptrace_test_ret_to_nx_instr (
void);
89 if (kill (child, SIGKILL) != 0)
91 warning (_(
"%s: failed to kill child pid %ld %s"),
92 who, (
long) child, safe_strerror (errno));
101 "kill waitpid returned %ld: %s"),
102 who, (
long) got_pid, safe_strerror (errno));
105 if (!WIFSIGNALED (kill_status))
108 "kill status %d is not WIFSIGNALED!"),
122#if defined __i386__ || defined __x86_64__
123 pid_t child, got_pid;
124 gdb_byte *return_address, *pc;
130 = (gdb_byte *) mmap (NULL, 2, PROT_READ | PROT_WRITE,
131 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
132 if (return_address == MAP_FAILED)
134 warning (_(
"linux_ptrace_test_ret_to_nx: Cannot mmap: %s"),
135 safe_strerror (errno));
140 *return_address = 0xcc;
146 warning (_(
"linux_ptrace_test_ret_to_nx: Cannot fork: %s"),
147 safe_strerror (errno));
154 warning (_(
"linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"),
155 safe_strerror (errno));
159 asm volatile (
"pushl %0;"
160 ".globl linux_ptrace_test_ret_to_nx_instr;"
161 "linux_ptrace_test_ret_to_nx_instr:"
163 : :
"r" (return_address) :
"memory");
164#elif defined __x86_64__
165 asm volatile (
"pushq %0;"
166 ".globl linux_ptrace_test_ret_to_nx_instr;"
167 "linux_ptrace_test_ret_to_nx_instr:"
169 : :
"r" ((uint64_t) (uintptr_t) return_address)
172# error "!__i386__ && !__x86_64__"
174 gdb_assert_not_reached (
"asm block did not terminate");
181 got_pid = waitpid (child, &status, 0);
182 if (got_pid != child)
184 warning (_(
"linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
185 (
long) got_pid, safe_strerror (errno));
189 if (WIFSIGNALED (status))
191 if (WTERMSIG (status) != SIGKILL)
192 warning (_(
"linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
193 (
int) WTERMSIG (status));
195 warning (_(
"Cannot call inferior functions, Linux kernel PaX "
196 "protection forbids return to non-executable pages!"));
200 if (!WIFSTOPPED (status))
202 warning (_(
"linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
204 kill_child (child,
"linux_ptrace_test_ret_to_nx");
209 if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
211 warning (_(
"linux_ptrace_test_ret_to_nx: "
212 "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
213 (
int) WSTOPSIG (status));
214 kill_child (child,
"linux_ptrace_test_ret_to_nx");
221 warning (_(
"linux_ptrace_test_ret_to_nx: Cannot PTRACE_GETREGS: %s"),
222 safe_strerror (errno));
225 pc = (gdb_byte *) (uintptr_t) regs[EIP];
226#elif defined __x86_64__
227 pc = (gdb_byte *) (uintptr_t) regs[RIP];
229# error "!__i386__ && !__x86_64__"
232 kill_child (child,
"linux_ptrace_test_ret_to_nx");
235 if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1)
242 if (WSTOPSIG (status) == SIGSEGV && pc == return_address)
248 if ((
void (*) (
void)) pc != &linux_ptrace_test_ret_to_nx_instr)
249 warning (_(
"linux_ptrace_test_ret_to_nx: PC %p is neither near return "
250 "address %p nor is the return instruction %p!"),
251 pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
253 warning (_(
"Cannot call inferior functions on this system - "
254 "Linux kernel with broken i386 NX (non-executable pages) "
255 "support detected!"));
273 gdb_assert (function != NULL);
275#if defined(__UCLIBC__) && defined(HAS_NOMMU)
276#define STACK_SIZE 4096
278 if (child_stack == NULL)
279 child_stack = (gdb_byte *) xmalloc (STACK_SIZE * 4);
283 child_pid = __clone2 (function, child_stack, STACK_SIZE,
284 CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
286 child_pid = clone (function, child_stack + STACK_SIZE,
287 CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
297 perror_with_name ((
"fork"));
310 kill (getpid (), SIGSTOP);
324 int child_pid, ret, status;
344 perror_with_name ((
"waitpid"));
345 else if (ret != child_pid)
346 error (_(
"linux_check_ptrace_features: waitpid: unexpected result %d."),
348 if (! WIFSTOPPED (status))
349 error (_(
"linux_check_ptrace_features: waitpid: unexpected status %d."),
355 kill_child (child_pid,
"linux_check_ptrace_features");
411 static int warned = 0;
425 return (wstat >> 16);
441 return (WIFSTOPPED (wstat)
442 && (WSTOPSIG (wstat) == SIGTRAP
445 || WSTOPSIG (wstat) == SIGILL
446 || WSTOPSIG (wstat) == SIGSEGV));
#define ptrace(request, pid, addr, data)
int linux_proc_pid_is_zombie_nowarn(pid_t pid)
pid_t linux_proc_get_tracerpid_nowarn(pid_t lwpid)
static void linux_ptrace_test_ret_to_nx(void)
static int linux_fork_to_function(gdb_byte *child_stack, int(*function)(void *))
static void linux_test_for_exitkill(int child_pid)
int linux_is_extended_waitstatus(int wstat)
static void kill_child(pid_t child, const char *who)
void linux_enable_event_reporting(pid_t pid, int options)
static int supported_ptrace_options
static int linux_child_function(void *child_stack)
void linux_check_ptrace_features(void)
int linux_ptrace_get_extended_event(int wstat)
int linux_wstatus_maybe_breakpoint(int wstat)
void linux_ptrace_init_warnings(void)
void linux_disable_event_reporting(pid_t pid)
std::string linux_ptrace_attach_fail_reason_string(ptid_t ptid, int err)
std::string linux_ptrace_attach_fail_reason(pid_t pid)
#define PTRACE_O_TRACEEXEC
#define PTRACE_O_TRACEFORK
#define PTRACE_SETOPTIONS
#define PTRACE_O_TRACECLONE
#define PTRACE_O_EXITKILL
#define PTRACE_O_TRACEVFORK
#define PTRACE_O_TRACESYSGOOD
#define PTRACE_O_TRACEVFORKDONE
int my_waitpid(int pid, int *status, int flags)