linux-ptrace.c revision 1.9 1 /* Linux-specific ptrace manipulation routines.
2 Copyright (C) 2012-2024 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #include "linux-ptrace.h"
20 #include "linux-procfs.h"
21 #include "linux-waitpid.h"
22 #ifdef HAVE_SYS_PROCFS_H
23 #include <sys/procfs.h>
24 #endif
25
26 /* Stores the ptrace options supported by the running kernel.
27 A value of -1 means we did not check for features yet. A value
28 of 0 means there are no supported features. */
29 static int supported_ptrace_options = -1;
30
31 /* Find all possible reasons we could fail to attach PID and return these
32 as a string. An empty string is returned if we didn't find any reason. */
33
34 std::string
35 linux_ptrace_attach_fail_reason (pid_t pid)
36 {
37 pid_t tracerpid = linux_proc_get_tracerpid_nowarn (pid);
38 std::string result;
39
40 if (tracerpid > 0)
41 string_appendf (result,
42 _("process %d is already traced by process %d"),
43 (int) pid, (int) tracerpid);
44
45 if (linux_proc_pid_is_zombie_nowarn (pid))
46 string_appendf (result,
47 _("process %d is a zombie - the process has already "
48 "terminated"),
49 (int) pid);
50
51 return result;
52 }
53
54 /* See linux-ptrace.h. */
55
56 std::string
57 linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err)
58 {
59 long lwpid = ptid.lwp ();
60 std::string reason = linux_ptrace_attach_fail_reason (lwpid);
61
62 if (!reason.empty ())
63 return string_printf ("%s (%d), %s", safe_strerror (err), err,
64 reason.c_str ());
65 else
66 return string_printf ("%s (%d)", safe_strerror (err), err);
67 }
68
69 #if defined __i386__ || defined __x86_64__
70
71 /* Address of the 'ret' instruction in asm code block below. */
72 extern "C" void linux_ptrace_test_ret_to_nx_instr (void);
73
74 #include <sys/reg.h>
75 #include <sys/mman.h>
76 #include <signal.h>
77
78 #endif /* defined __i386__ || defined __x86_64__ */
79
80 /* Kill CHILD. WHO is used to report warnings. */
81
82 static void
83 kill_child (pid_t child, const char *who)
84 {
85 pid_t got_pid;
86 int kill_status;
87
88 if (kill (child, SIGKILL) != 0)
89 {
90 warning (_("%s: failed to kill child pid %ld %s"),
91 who, (long) child, safe_strerror (errno));
92 return;
93 }
94
95 errno = 0;
96 got_pid = my_waitpid (child, &kill_status, 0);
97 if (got_pid != child)
98 {
99 warning (_("%s: "
100 "kill waitpid returned %ld: %s"),
101 who, (long) got_pid, safe_strerror (errno));
102 return;
103 }
104 if (!WIFSIGNALED (kill_status))
105 {
106 warning (_("%s: "
107 "kill status %d is not WIFSIGNALED!"),
108 who, kill_status);
109 return;
110 }
111 }
112
113 /* Test broken off-trunk Linux kernel patchset for NX support on i386. It was
114 removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd.
115
116 Test also x86_64 arch for PaX support. */
117
118 static void
119 linux_ptrace_test_ret_to_nx (void)
120 {
121 #if defined __i386__ || defined __x86_64__
122 pid_t child, got_pid;
123 gdb_byte *return_address, *pc;
124 long l;
125 int status;
126 elf_gregset_t regs;
127
128 return_address
129 = (gdb_byte *) mmap (NULL, 2, PROT_READ | PROT_WRITE,
130 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
131 if (return_address == MAP_FAILED)
132 {
133 warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"),
134 safe_strerror (errno));
135 return;
136 }
137
138 /* Put there 'int3'. */
139 *return_address = 0xcc;
140
141 child = fork ();
142 switch (child)
143 {
144 case -1:
145 warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"),
146 safe_strerror (errno));
147 return;
148
149 case 0:
150 l = ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) NULL,
151 (PTRACE_TYPE_ARG4) NULL);
152 if (l != 0)
153 warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"),
154 safe_strerror (errno));
155 else
156 {
157 #if defined __i386__
158 asm volatile ("pushl %0;"
159 ".globl linux_ptrace_test_ret_to_nx_instr;"
160 "linux_ptrace_test_ret_to_nx_instr:"
161 "ret"
162 : : "r" (return_address) : "memory");
163 #elif defined __x86_64__
164 asm volatile ("pushq %0;"
165 ".globl linux_ptrace_test_ret_to_nx_instr;"
166 "linux_ptrace_test_ret_to_nx_instr:"
167 "ret"
168 : : "r" ((uint64_t) (uintptr_t) return_address)
169 : "memory");
170 #else
171 # error "!__i386__ && !__x86_64__"
172 #endif
173 gdb_assert_not_reached ("asm block did not terminate");
174 }
175
176 _exit (1);
177 }
178
179 errno = 0;
180 got_pid = waitpid (child, &status, 0);
181 if (got_pid != child)
182 {
183 warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
184 (long) got_pid, safe_strerror (errno));
185 return;
186 }
187
188 if (WIFSIGNALED (status))
189 {
190 if (WTERMSIG (status) != SIGKILL)
191 warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
192 (int) WTERMSIG (status));
193 else
194 warning (_("Cannot call inferior functions, Linux kernel PaX "
195 "protection forbids return to non-executable pages!"));
196 return;
197 }
198
199 if (!WIFSTOPPED (status))
200 {
201 warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
202 status);
203 kill_child (child, "linux_ptrace_test_ret_to_nx");
204 return;
205 }
206
207 /* We may get SIGSEGV due to missing PROT_EXEC of the return_address. */
208 if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
209 {
210 warning (_("linux_ptrace_test_ret_to_nx: "
211 "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
212 (int) WSTOPSIG (status));
213 kill_child (child, "linux_ptrace_test_ret_to_nx");
214 return;
215 }
216
217 if (ptrace (PTRACE_GETREGS, child, (PTRACE_TYPE_ARG3) 0,
218 (PTRACE_TYPE_ARG4) ®s) < 0)
219 {
220 warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_GETREGS: %s"),
221 safe_strerror (errno));
222 }
223 #if defined __i386__
224 pc = (gdb_byte *) (uintptr_t) regs[EIP];
225 #elif defined __x86_64__
226 pc = (gdb_byte *) (uintptr_t) regs[RIP];
227 #else
228 # error "!__i386__ && !__x86_64__"
229 #endif
230
231 kill_child (child, "linux_ptrace_test_ret_to_nx");
232
233 /* + 1 is there as x86* stops after the 'int3' instruction. */
234 if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1)
235 {
236 /* PASS */
237 return;
238 }
239
240 /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page. */
241 if (WSTOPSIG (status) == SIGSEGV && pc == return_address)
242 {
243 /* PASS */
244 return;
245 }
246
247 if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr)
248 warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return "
249 "address %p nor is the return instruction %p!"),
250 pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
251 else
252 warning (_("Cannot call inferior functions on this system - "
253 "Linux kernel with broken i386 NX (non-executable pages) "
254 "support detected!"));
255 #endif /* defined __i386__ || defined __x86_64__ */
256 }
257
258 /* Helper function to fork a process and make the child process call
259 the function FUNCTION, passing CHILD_STACK as parameter.
260
261 For MMU-less targets, clone is used instead of fork, and
262 CHILD_STACK is used as stack space for the cloned child. If NULL,
263 stack space is allocated via malloc (and subsequently passed to
264 FUNCTION). For MMU targets, CHILD_STACK is ignored. */
265
266 static int
267 linux_fork_to_function (gdb_byte *child_stack, int (*function) (void *))
268 {
269 int child_pid;
270
271 /* Sanity check the function pointer. */
272 gdb_assert (function != NULL);
273
274 #if defined(__UCLIBC__) && defined(HAS_NOMMU)
275 #define STACK_SIZE 4096
276
277 if (child_stack == NULL)
278 child_stack = (gdb_byte *) xmalloc (STACK_SIZE * 4);
279
280 /* Use CLONE_VM instead of fork, to support uClinux (no MMU). */
281 #ifdef __ia64__
282 child_pid = __clone2 (function, child_stack, STACK_SIZE,
283 CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
284 #else /* !__ia64__ */
285 child_pid = clone (function, child_stack + STACK_SIZE,
286 CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2);
287 #endif /* !__ia64__ */
288 #else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */
289 child_pid = fork ();
290
291 if (child_pid == 0)
292 function (NULL);
293 #endif /* defined(__UCLIBC) && defined(HAS_NOMMU) */
294
295 if (child_pid == -1)
296 perror_with_name (("fork"));
297
298 return child_pid;
299 }
300
301 /* A helper function for linux_check_ptrace_features, called after
302 the parent process forks a child. The child allows itself to
303 be traced by its parent. */
304
305 static int
306 linux_child_function (void *child_stack)
307 {
308 ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0);
309 kill (getpid (), SIGSTOP);
310
311 /* This code is only reachable by the child (grandchild's parent)
312 process. */
313 _exit (0);
314 }
315
316 static void linux_test_for_exitkill (int child_pid);
317
318 /* Determine ptrace features available on this target. */
319
320 void
321 linux_check_ptrace_features (void)
322 {
323 int child_pid, ret, status;
324
325 /* Initialize the options. We consider that these options are always
326 supported. */
327 supported_ptrace_options
328 = (PTRACE_O_TRACESYSGOOD
329 | PTRACE_O_TRACECLONE
330 | PTRACE_O_TRACEFORK
331 | PTRACE_O_TRACEVFORK
332 | PTRACE_O_TRACEVFORKDONE
333 | PTRACE_O_TRACEEXEC);
334
335 /* Fork a child so we can do some testing. The child will call
336 linux_child_function and will get traced. The child will
337 eventually fork a grandchild so we can test fork event
338 reporting. */
339 child_pid = linux_fork_to_function (NULL, linux_child_function);
340
341 ret = my_waitpid (child_pid, &status, 0);
342 if (ret == -1)
343 perror_with_name (("waitpid"));
344 else if (ret != child_pid)
345 error (_("linux_check_ptrace_features: waitpid: unexpected result %d."),
346 ret);
347 if (! WIFSTOPPED (status))
348 error (_("linux_check_ptrace_features: waitpid: unexpected status %d."),
349 status);
350
351 linux_test_for_exitkill (child_pid);
352
353 /* Kill child_pid. */
354 kill_child (child_pid, "linux_check_ptrace_features");
355 }
356
357 /* Determine if PTRACE_O_EXITKILL can be used. */
358
359 static void
360 linux_test_for_exitkill (int child_pid)
361 {
362 int ret;
363
364 ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
365 (PTRACE_TYPE_ARG4) PTRACE_O_EXITKILL);
366
367 if (ret == 0)
368 supported_ptrace_options |= PTRACE_O_EXITKILL;
369 }
370
371 /* Enable reporting of all currently supported ptrace events.
372 OPTIONS is a bit mask of extended features we want enabled,
373 if supported by the kernel. PTRACE_O_TRACECLONE is always
374 enabled, if supported. */
375
376 void
377 linux_enable_event_reporting (pid_t pid, int options)
378 {
379 /* Check if we have initialized the ptrace features for this
380 target. If not, do it now. */
381 if (supported_ptrace_options == -1)
382 linux_check_ptrace_features ();
383
384 /* We always want clone events. */
385 options |= PTRACE_O_TRACECLONE;
386
387 /* Filter out unsupported options. */
388 options &= supported_ptrace_options;
389
390 /* Set the options. */
391 ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0,
392 (PTRACE_TYPE_ARG4) (uintptr_t) options);
393 }
394
395 /* Disable reporting of all currently supported ptrace events. */
396
397 void
398 linux_disable_event_reporting (pid_t pid)
399 {
400 /* Set the options. */
401 ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0, 0);
402 }
403
404 /* Display possible problems on this system. Display them only once per GDB
405 execution. */
406
407 void
408 linux_ptrace_init_warnings (void)
409 {
410 static int warned = 0;
411
412 if (warned)
413 return;
414 warned = 1;
415
416 linux_ptrace_test_ret_to_nx ();
417 }
418
419 /* Extract extended ptrace event from wait status. */
420
421 int
422 linux_ptrace_get_extended_event (int wstat)
423 {
424 return (wstat >> 16);
425 }
426
427 /* Determine whether wait status denotes an extended event. */
428
429 int
430 linux_is_extended_waitstatus (int wstat)
431 {
432 return (linux_ptrace_get_extended_event (wstat) != 0);
433 }
434
435 /* Return true if the event in LP may be caused by breakpoint. */
436
437 int
438 linux_wstatus_maybe_breakpoint (int wstat)
439 {
440 return (WIFSTOPPED (wstat)
441 && (WSTOPSIG (wstat) == SIGTRAP
442 /* SIGILL and SIGSEGV are also treated as traps in case a
443 breakpoint is inserted at the current PC. */
444 || WSTOPSIG (wstat) == SIGILL
445 || WSTOPSIG (wstat) == SIGSEGV));
446 }
447