blob: ca8214467184838cb5cd229fbc5bc052203c9616 [file] [log] [blame]
Jan Kratochvil0b867462013-05-30 14:37:38 +02001/* Get Dwarf Frame state for target live PID process.
2 Copyright (C) 2013 Red Hat, Inc.
3 This file is part of elfutils.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
7
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
11
12 or
13
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
17
18 or both in parallel, as here.
19
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
28
29#include "libdwflP.h"
30#include <sys/ptrace.h>
31#include <sys/wait.h>
32#include <dirent.h>
33#include <sys/syscall.h>
34#include <unistd.h>
35
36#ifndef MAX
37# define MAX(a, b) ((a) > (b) ? (a) : (b))
38#endif
39
40struct pid_arg
41{
42 DIR *dir;
43 /* It is 0 if not used. */
44 pid_t tid_attached;
45};
46
47static bool
48linux_proc_pid_is_stopped (pid_t pid)
49{
50 char buffer[64];
51 FILE *procfile;
52 bool retval, have_state;
53
54 snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
55 procfile = fopen (buffer, "r");
56 if (procfile == NULL)
57 return false;
58
59 have_state = false;
60 while (fgets (buffer, sizeof (buffer), procfile) != NULL)
61 if (strncmp (buffer, "State:", 6) == 0)
62 {
63 have_state = true;
64 break;
65 }
66 retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
67 fclose (procfile);
68 return retval;
69}
70
71static bool
72ptrace_attach (pid_t tid)
73{
74 if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
75 {
76 __libdwfl_seterrno (DWFL_E_ERRNO);
77 return false;
78 }
79 if (linux_proc_pid_is_stopped (tid))
80 {
81 /* Make sure there is a SIGSTOP signal pending even when the process is
82 already State: T (stopped). Older kernels might fail to generate
83 a SIGSTOP notification in that case in response to our PTRACE_ATTACH
84 above. Which would make the waitpid below wait forever. So emulate
85 it. Since there can only be one SIGSTOP notification pending this is
86 safe. See also gdb/linux-nat.c linux_nat_post_attach_wait. */
87 syscall (__NR_tkill, tid, SIGSTOP);
88 ptrace (PTRACE_CONT, tid, NULL, NULL);
89 }
90 for (;;)
91 {
92 int status;
93 if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
94 {
95 int saved_errno = errno;
96 ptrace (PTRACE_DETACH, tid, NULL, NULL);
97 errno = saved_errno;
98 __libdwfl_seterrno (DWFL_E_ERRNO);
99 return false;
100 }
101 if (WSTOPSIG (status) == SIGSTOP)
102 break;
103 if (ptrace (PTRACE_CONT, tid, NULL,
104 (void *) (uintptr_t) WSTOPSIG (status)) != 0)
105 {
106 int saved_errno = errno;
107 ptrace (PTRACE_DETACH, tid, NULL, NULL);
108 errno = saved_errno;
109 __libdwfl_seterrno (DWFL_E_ERRNO);
110 return false;
111 }
112 }
113 return true;
114}
115
116static bool
117pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
118{
119 struct pid_arg *pid_arg = arg;
120 pid_t tid = pid_arg->tid_attached;
121 assert (tid > 0);
122 Dwfl_Process *process = dwfl->process;
123 if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
124 {
125#if SIZEOF_LONG == 8
126 errno = 0;
127 *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
128 return errno == 0;
129#else /* SIZEOF_LONG != 8 */
130 /* This should not happen. */
131 return false;
132#endif /* SIZEOF_LONG != 8 */
133 }
134#if SIZEOF_LONG == 8
135 /* We do not care about reads unaliged to 4 bytes boundary.
136 But 0x...ffc read of 8 bytes could overrun a page. */
137 bool lowered = (addr & 4) != 0;
138 if (lowered)
139 addr -= 4;
140#endif /* SIZEOF_LONG == 8 */
141 errno = 0;
142 *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
143 if (errno != 0)
144 return false;
145#if SIZEOF_LONG == 8
146# if BYTE_ORDER == BIG_ENDIAN
147 if (! lowered)
148 *result >>= 32;
149# else
150 if (lowered)
151 *result >>= 32;
152# endif
153#endif /* SIZEOF_LONG == 8 */
154 *result &= 0xffffffff;
155 return true;
156}
157
158static pid_t
159pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
160 void **thread_argp)
161{
162 struct pid_arg *pid_arg = dwfl_arg;
163 struct dirent *dirent;
164 do
165 {
166 errno = 0;
167 dirent = readdir (pid_arg->dir);
168 if (dirent == NULL)
169 {
170 if (errno != 0)
171 {
172 __libdwfl_seterrno (DWFL_E_ERRNO);
173 return -1;
174 }
175 return 0;
176 }
177 }
178 while (strcmp (dirent->d_name, ".") == 0
179 || strcmp (dirent->d_name, "..") == 0);
180 char *end;
181 errno = 0;
182 long tidl = strtol (dirent->d_name, &end, 10);
183 if (errno != 0)
184 {
185 __libdwfl_seterrno (DWFL_E_ERRNO);
186 return -1;
187 }
188 pid_t tid = tidl;
189 if (tidl <= 0 || (end && *end) || tid != tidl)
190 {
191 __libdwfl_seterrno (DWFL_E_PARSE_PROC);
192 return -1;
193 }
194 *thread_argp = dwfl_arg;
195 return tid;
196}
197
198/* Implement the ebl_set_initial_registers_tid setfunc callback. */
199
200static bool
Jan Kratochvil1c1a53b2013-11-14 20:55:41 +0100201pid_thread_state_registers_cb (int firstreg, unsigned nregs,
202 const Dwarf_Word *regs, void *arg)
Jan Kratochvil0b867462013-05-30 14:37:38 +0200203{
204 Dwfl_Thread *thread = (Dwfl_Thread *) arg;
205 return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
206}
207
208static bool
209pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
210{
211 struct pid_arg *pid_arg = thread_arg;
212 assert (pid_arg->tid_attached == 0);
213 pid_t tid = INTUSE(dwfl_thread_tid) (thread);
214 if (! ptrace_attach (tid))
215 return false;
216 pid_arg->tid_attached = tid;
217 Dwfl_Process *process = thread->process;
218 Ebl *ebl = process->ebl;
219 return ebl_set_initial_registers_tid (ebl, tid,
220 pid_thread_state_registers_cb, thread);
221}
222
223static void
224pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
225{
226 struct pid_arg *pid_arg = dwfl_arg;
227 closedir (pid_arg->dir);
228 free (pid_arg);
229}
230
231static void
232pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
233{
234 struct pid_arg *pid_arg = thread_arg;
235 pid_t tid = INTUSE(dwfl_thread_tid) (thread);
236 assert (pid_arg->tid_attached == tid);
237 pid_arg->tid_attached = 0;
238 ptrace (PTRACE_DETACH, tid, NULL, NULL);
239}
240
241static const Dwfl_Thread_Callbacks pid_thread_callbacks =
242{
243 pid_next_thread,
244 pid_memory_read,
245 pid_set_initial_registers,
246 pid_detach,
247 pid_thread_detach,
248};
249
250bool
251internal_function
252__libdwfl_attach_state_for_pid (Dwfl *dwfl, pid_t pid)
253{
254 char dirname[64];
255 int i = snprintf (dirname, sizeof (dirname), "/proc/%ld/task", (long) pid);
256 assert (i > 0 && i < (ssize_t) sizeof (dirname) - 1);
257 DIR *dir = opendir (dirname);
258 if (dir == NULL)
259 {
260 __libdwfl_seterrno (DWFL_E_ERRNO);
261 return false;
262 }
263 struct pid_arg *pid_arg = malloc (sizeof *pid_arg);
264 if (pid_arg == NULL)
265 {
266 closedir (dir);
267 __libdwfl_seterrno (DWFL_E_NOMEM);
268 return false;
269 }
270 pid_arg->dir = dir;
271 pid_arg->tid_attached = 0;
Jan Kratochviled782372013-11-14 20:53:20 +0100272 if (! INTUSE(dwfl_attach_state) (dwfl, NULL, pid, &pid_thread_callbacks,
Jan Kratochvil0b867462013-05-30 14:37:38 +0200273 pid_arg))
274 {
275 closedir (dir);
276 free (pid_arg);
277 return false;
278 }
279 return true;
280}