xref: /dflybsd-src/contrib/gdb-7/gdb/common/linux-ptrace.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
1*ef5ccd6cSJohn Marino /* Linux-specific ptrace manipulation routines.
2*ef5ccd6cSJohn Marino    Copyright (C) 2012-2013 Free Software Foundation, Inc.
3*ef5ccd6cSJohn Marino 
4*ef5ccd6cSJohn Marino    This file is part of GDB.
5*ef5ccd6cSJohn Marino 
6*ef5ccd6cSJohn Marino    This program is free software; you can redistribute it and/or modify
7*ef5ccd6cSJohn Marino    it under the terms of the GNU General Public License as published by
8*ef5ccd6cSJohn Marino    the Free Software Foundation; either version 3 of the License, or
9*ef5ccd6cSJohn Marino    (at your option) any later version.
10*ef5ccd6cSJohn Marino 
11*ef5ccd6cSJohn Marino    This program is distributed in the hope that it will be useful,
12*ef5ccd6cSJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*ef5ccd6cSJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*ef5ccd6cSJohn Marino    GNU General Public License for more details.
15*ef5ccd6cSJohn Marino 
16*ef5ccd6cSJohn Marino    You should have received a copy of the GNU General Public License
17*ef5ccd6cSJohn Marino    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18*ef5ccd6cSJohn Marino 
19*ef5ccd6cSJohn Marino #ifdef GDBSERVER
20*ef5ccd6cSJohn Marino #include "server.h"
21*ef5ccd6cSJohn Marino #else
22*ef5ccd6cSJohn Marino #include "defs.h"
23*ef5ccd6cSJohn Marino #include "gdb_string.h"
24*ef5ccd6cSJohn Marino #endif
25*ef5ccd6cSJohn Marino 
26*ef5ccd6cSJohn Marino #include "linux-ptrace.h"
27*ef5ccd6cSJohn Marino #include "linux-procfs.h"
28*ef5ccd6cSJohn Marino #include "buffer.h"
29*ef5ccd6cSJohn Marino #include "gdb_assert.h"
30*ef5ccd6cSJohn Marino #include "gdb_wait.h"
31*ef5ccd6cSJohn Marino 
32*ef5ccd6cSJohn Marino /* Find all possible reasons we could fail to attach PID and append these
33*ef5ccd6cSJohn Marino    newline terminated reason strings to initialized BUFFER.  '\0' termination
34*ef5ccd6cSJohn Marino    of BUFFER must be done by the caller.  */
35*ef5ccd6cSJohn Marino 
36*ef5ccd6cSJohn Marino void
linux_ptrace_attach_warnings(pid_t pid,struct buffer * buffer)37*ef5ccd6cSJohn Marino linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer)
38*ef5ccd6cSJohn Marino {
39*ef5ccd6cSJohn Marino   pid_t tracerpid;
40*ef5ccd6cSJohn Marino 
41*ef5ccd6cSJohn Marino   tracerpid = linux_proc_get_tracerpid (pid);
42*ef5ccd6cSJohn Marino   if (tracerpid > 0)
43*ef5ccd6cSJohn Marino     buffer_xml_printf (buffer, _("warning: process %d is already traced "
44*ef5ccd6cSJohn Marino 				 "by process %d\n"),
45*ef5ccd6cSJohn Marino 		       (int) pid, (int) tracerpid);
46*ef5ccd6cSJohn Marino 
47*ef5ccd6cSJohn Marino   if (linux_proc_pid_is_zombie (pid))
48*ef5ccd6cSJohn Marino     buffer_xml_printf (buffer, _("warning: process %d is a zombie "
49*ef5ccd6cSJohn Marino 				 "- the process has already terminated\n"),
50*ef5ccd6cSJohn Marino 		       (int) pid);
51*ef5ccd6cSJohn Marino }
52*ef5ccd6cSJohn Marino 
53*ef5ccd6cSJohn Marino #if defined __i386__ || defined __x86_64__
54*ef5ccd6cSJohn Marino 
55*ef5ccd6cSJohn Marino /* Address of the 'ret' instruction in asm code block below.  */
56*ef5ccd6cSJohn Marino extern void (linux_ptrace_test_ret_to_nx_instr) (void);
57*ef5ccd6cSJohn Marino 
58*ef5ccd6cSJohn Marino #include <sys/reg.h>
59*ef5ccd6cSJohn Marino #include <sys/mman.h>
60*ef5ccd6cSJohn Marino #include <signal.h>
61*ef5ccd6cSJohn Marino #include <stdint.h>
62*ef5ccd6cSJohn Marino 
63*ef5ccd6cSJohn Marino #endif /* defined __i386__ || defined __x86_64__ */
64*ef5ccd6cSJohn Marino 
65*ef5ccd6cSJohn Marino /* Test broken off-trunk Linux kernel patchset for NX support on i386.  It was
66*ef5ccd6cSJohn Marino    removed in Fedora kernel 88fa1f0332d188795ed73d7ac2b1564e11a0b4cd.
67*ef5ccd6cSJohn Marino 
68*ef5ccd6cSJohn Marino    Test also x86_64 arch for PaX support.  */
69*ef5ccd6cSJohn Marino 
70*ef5ccd6cSJohn Marino static void
linux_ptrace_test_ret_to_nx(void)71*ef5ccd6cSJohn Marino linux_ptrace_test_ret_to_nx (void)
72*ef5ccd6cSJohn Marino {
73*ef5ccd6cSJohn Marino #if defined __i386__ || defined __x86_64__
74*ef5ccd6cSJohn Marino   pid_t child, got_pid;
75*ef5ccd6cSJohn Marino   gdb_byte *return_address, *pc;
76*ef5ccd6cSJohn Marino   long l;
77*ef5ccd6cSJohn Marino   int status, kill_status;
78*ef5ccd6cSJohn Marino 
79*ef5ccd6cSJohn Marino   return_address = mmap (NULL, 2, PROT_READ | PROT_WRITE,
80*ef5ccd6cSJohn Marino 			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
81*ef5ccd6cSJohn Marino   if (return_address == MAP_FAILED)
82*ef5ccd6cSJohn Marino     {
83*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: Cannot mmap: %s"),
84*ef5ccd6cSJohn Marino 	       strerror (errno));
85*ef5ccd6cSJohn Marino       return;
86*ef5ccd6cSJohn Marino     }
87*ef5ccd6cSJohn Marino 
88*ef5ccd6cSJohn Marino   /* Put there 'int3'.  */
89*ef5ccd6cSJohn Marino   *return_address = 0xcc;
90*ef5ccd6cSJohn Marino 
91*ef5ccd6cSJohn Marino   child = fork ();
92*ef5ccd6cSJohn Marino   switch (child)
93*ef5ccd6cSJohn Marino     {
94*ef5ccd6cSJohn Marino     case -1:
95*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: Cannot fork: %s"),
96*ef5ccd6cSJohn Marino 	       strerror (errno));
97*ef5ccd6cSJohn Marino       return;
98*ef5ccd6cSJohn Marino 
99*ef5ccd6cSJohn Marino     case 0:
100*ef5ccd6cSJohn Marino       l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
101*ef5ccd6cSJohn Marino       if (l != 0)
102*ef5ccd6cSJohn Marino 	warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"),
103*ef5ccd6cSJohn Marino 		 strerror (errno));
104*ef5ccd6cSJohn Marino       else
105*ef5ccd6cSJohn Marino 	{
106*ef5ccd6cSJohn Marino #if defined __i386__
107*ef5ccd6cSJohn Marino 	  asm volatile ("pushl %0;"
108*ef5ccd6cSJohn Marino 			".globl linux_ptrace_test_ret_to_nx_instr;"
109*ef5ccd6cSJohn Marino 			"linux_ptrace_test_ret_to_nx_instr:"
110*ef5ccd6cSJohn Marino 			"ret"
111*ef5ccd6cSJohn Marino 			: : "r" (return_address) : "%esp", "memory");
112*ef5ccd6cSJohn Marino #elif defined __x86_64__
113*ef5ccd6cSJohn Marino 	  asm volatile ("pushq %0;"
114*ef5ccd6cSJohn Marino 			".globl linux_ptrace_test_ret_to_nx_instr;"
115*ef5ccd6cSJohn Marino 			"linux_ptrace_test_ret_to_nx_instr:"
116*ef5ccd6cSJohn Marino 			"ret"
117*ef5ccd6cSJohn Marino 			: : "r" ((uint64_t) (uintptr_t) return_address)
118*ef5ccd6cSJohn Marino 			: "%rsp", "memory");
119*ef5ccd6cSJohn Marino #else
120*ef5ccd6cSJohn Marino # error "!__i386__ && !__x86_64__"
121*ef5ccd6cSJohn Marino #endif
122*ef5ccd6cSJohn Marino 	  gdb_assert_not_reached ("asm block did not terminate");
123*ef5ccd6cSJohn Marino 	}
124*ef5ccd6cSJohn Marino 
125*ef5ccd6cSJohn Marino       _exit (1);
126*ef5ccd6cSJohn Marino     }
127*ef5ccd6cSJohn Marino 
128*ef5ccd6cSJohn Marino   errno = 0;
129*ef5ccd6cSJohn Marino   got_pid = waitpid (child, &status, 0);
130*ef5ccd6cSJohn Marino   if (got_pid != child)
131*ef5ccd6cSJohn Marino     {
132*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: waitpid returned %ld: %s"),
133*ef5ccd6cSJohn Marino 	       (long) got_pid, strerror (errno));
134*ef5ccd6cSJohn Marino       return;
135*ef5ccd6cSJohn Marino     }
136*ef5ccd6cSJohn Marino 
137*ef5ccd6cSJohn Marino   if (WIFSIGNALED (status))
138*ef5ccd6cSJohn Marino     {
139*ef5ccd6cSJohn Marino       if (WTERMSIG (status) != SIGKILL)
140*ef5ccd6cSJohn Marino 	warning (_("linux_ptrace_test_ret_to_nx: WTERMSIG %d is not SIGKILL!"),
141*ef5ccd6cSJohn Marino 		 (int) WTERMSIG (status));
142*ef5ccd6cSJohn Marino       else
143*ef5ccd6cSJohn Marino 	warning (_("Cannot call inferior functions, Linux kernel PaX "
144*ef5ccd6cSJohn Marino 		   "protection forbids return to non-executable pages!"));
145*ef5ccd6cSJohn Marino       return;
146*ef5ccd6cSJohn Marino     }
147*ef5ccd6cSJohn Marino 
148*ef5ccd6cSJohn Marino   if (!WIFSTOPPED (status))
149*ef5ccd6cSJohn Marino     {
150*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: status %d is not WIFSTOPPED!"),
151*ef5ccd6cSJohn Marino 	       status);
152*ef5ccd6cSJohn Marino       return;
153*ef5ccd6cSJohn Marino     }
154*ef5ccd6cSJohn Marino 
155*ef5ccd6cSJohn Marino   /* We may get SIGSEGV due to missing PROT_EXEC of the return_address.  */
156*ef5ccd6cSJohn Marino   if (WSTOPSIG (status) != SIGTRAP && WSTOPSIG (status) != SIGSEGV)
157*ef5ccd6cSJohn Marino     {
158*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: "
159*ef5ccd6cSJohn Marino 		 "WSTOPSIG %d is neither SIGTRAP nor SIGSEGV!"),
160*ef5ccd6cSJohn Marino 	       (int) WSTOPSIG (status));
161*ef5ccd6cSJohn Marino       return;
162*ef5ccd6cSJohn Marino     }
163*ef5ccd6cSJohn Marino 
164*ef5ccd6cSJohn Marino   errno = 0;
165*ef5ccd6cSJohn Marino #if defined __i386__
166*ef5ccd6cSJohn Marino   l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL);
167*ef5ccd6cSJohn Marino #elif defined __x86_64__
168*ef5ccd6cSJohn Marino   l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (RIP * 8), NULL);
169*ef5ccd6cSJohn Marino #else
170*ef5ccd6cSJohn Marino # error "!__i386__ && !__x86_64__"
171*ef5ccd6cSJohn Marino #endif
172*ef5ccd6cSJohn Marino   if (errno != 0)
173*ef5ccd6cSJohn Marino     {
174*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_PEEKUSER: %s"),
175*ef5ccd6cSJohn Marino 	       strerror (errno));
176*ef5ccd6cSJohn Marino       return;
177*ef5ccd6cSJohn Marino     }
178*ef5ccd6cSJohn Marino   pc = (void *) (uintptr_t) l;
179*ef5ccd6cSJohn Marino 
180*ef5ccd6cSJohn Marino   kill (child, SIGKILL);
181*ef5ccd6cSJohn Marino   ptrace (PTRACE_KILL, child, NULL, NULL);
182*ef5ccd6cSJohn Marino 
183*ef5ccd6cSJohn Marino   errno = 0;
184*ef5ccd6cSJohn Marino   got_pid = waitpid (child, &kill_status, 0);
185*ef5ccd6cSJohn Marino   if (got_pid != child)
186*ef5ccd6cSJohn Marino     {
187*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: "
188*ef5ccd6cSJohn Marino 		 "PTRACE_KILL waitpid returned %ld: %s"),
189*ef5ccd6cSJohn Marino 	       (long) got_pid, strerror (errno));
190*ef5ccd6cSJohn Marino       return;
191*ef5ccd6cSJohn Marino     }
192*ef5ccd6cSJohn Marino   if (!WIFSIGNALED (kill_status))
193*ef5ccd6cSJohn Marino     {
194*ef5ccd6cSJohn Marino       warning (_("linux_ptrace_test_ret_to_nx: "
195*ef5ccd6cSJohn Marino 		 "PTRACE_KILL status %d is not WIFSIGNALED!"),
196*ef5ccd6cSJohn Marino 	       status);
197*ef5ccd6cSJohn Marino       return;
198*ef5ccd6cSJohn Marino     }
199*ef5ccd6cSJohn Marino 
200*ef5ccd6cSJohn Marino   /* + 1 is there as x86* stops after the 'int3' instruction.  */
201*ef5ccd6cSJohn Marino   if (WSTOPSIG (status) == SIGTRAP && pc == return_address + 1)
202*ef5ccd6cSJohn Marino     {
203*ef5ccd6cSJohn Marino       /* PASS */
204*ef5ccd6cSJohn Marino       return;
205*ef5ccd6cSJohn Marino     }
206*ef5ccd6cSJohn Marino 
207*ef5ccd6cSJohn Marino   /* We may get SIGSEGV due to missing PROT_EXEC of the RETURN_ADDRESS page.  */
208*ef5ccd6cSJohn Marino   if (WSTOPSIG (status) == SIGSEGV && pc == return_address)
209*ef5ccd6cSJohn Marino     {
210*ef5ccd6cSJohn Marino       /* PASS */
211*ef5ccd6cSJohn Marino       return;
212*ef5ccd6cSJohn Marino     }
213*ef5ccd6cSJohn Marino 
214*ef5ccd6cSJohn Marino   if ((void (*) (void)) pc != &linux_ptrace_test_ret_to_nx_instr)
215*ef5ccd6cSJohn Marino     warning (_("linux_ptrace_test_ret_to_nx: PC %p is neither near return "
216*ef5ccd6cSJohn Marino 	       "address %p nor is the return instruction %p!"),
217*ef5ccd6cSJohn Marino 	     pc, return_address, &linux_ptrace_test_ret_to_nx_instr);
218*ef5ccd6cSJohn Marino   else
219*ef5ccd6cSJohn Marino     warning (_("Cannot call inferior functions on this system - "
220*ef5ccd6cSJohn Marino 	       "Linux kernel with broken i386 NX (non-executable pages) "
221*ef5ccd6cSJohn Marino 	       "support detected!"));
222*ef5ccd6cSJohn Marino #endif /* defined __i386__ || defined __x86_64__ */
223*ef5ccd6cSJohn Marino }
224*ef5ccd6cSJohn Marino 
225*ef5ccd6cSJohn Marino /* Display possible problems on this system.  Display them only once per GDB
226*ef5ccd6cSJohn Marino    execution.  */
227*ef5ccd6cSJohn Marino 
228*ef5ccd6cSJohn Marino void
linux_ptrace_init_warnings(void)229*ef5ccd6cSJohn Marino linux_ptrace_init_warnings (void)
230*ef5ccd6cSJohn Marino {
231*ef5ccd6cSJohn Marino   static int warned = 0;
232*ef5ccd6cSJohn Marino 
233*ef5ccd6cSJohn Marino   if (warned)
234*ef5ccd6cSJohn Marino     return;
235*ef5ccd6cSJohn Marino   warned = 1;
236*ef5ccd6cSJohn Marino 
237*ef5ccd6cSJohn Marino   linux_ptrace_test_ret_to_nx ();
238*ef5ccd6cSJohn Marino }
239