Line data Source code
1 : /* Get Dwarf Frame state for target PID or core file.
2 : Copyright (C) 2013, 2014 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 : #ifdef HAVE_CONFIG_H
30 : # include <config.h>
31 : #endif
32 :
33 : #include "libdwflP.h"
34 : #include <unistd.h>
35 :
36 : /* Set STATE->pc_set from STATE->regs according to the backend. Return true on
37 : success, false on error. */
38 : static bool
39 47 : state_fetch_pc (Dwfl_Frame *state)
40 : {
41 47 : switch (state->pc_state)
42 : {
43 : case DWFL_FRAME_STATE_PC_SET:
44 : return true;
45 : case DWFL_FRAME_STATE_PC_UNDEFINED:
46 0 : abort ();
47 : case DWFL_FRAME_STATE_ERROR:
48 : {
49 33 : Ebl *ebl = state->thread->process->ebl;
50 : Dwarf_CIE abi_info;
51 33 : if (ebl_abi_cfi (ebl, &abi_info) != 0)
52 : {
53 0 : __libdwfl_seterrno (DWFL_E_LIBEBL);
54 0 : return false;
55 : }
56 33 : unsigned ra = abi_info.return_address_register;
57 : /* dwarf_frame_state_reg_is_set is not applied here. */
58 33 : if (ra >= ebl_frame_nregs (ebl))
59 : {
60 0 : __libdwfl_seterrno (DWFL_E_LIBEBL_BAD);
61 0 : return false;
62 : }
63 33 : state->pc = state->regs[ra] + ebl_ra_offset (ebl);
64 33 : state->pc_state = DWFL_FRAME_STATE_PC_SET;
65 : }
66 33 : return true;
67 : }
68 0 : abort ();
69 : }
70 :
71 : /* Do not call it on your own, to be used by thread_* functions only. */
72 :
73 : static void
74 257 : state_free (Dwfl_Frame *state)
75 : {
76 257 : Dwfl_Thread *thread = state->thread;
77 257 : assert (thread->unwound == state);
78 257 : thread->unwound = state->unwound;
79 257 : free (state);
80 257 : }
81 :
82 : static void
83 : thread_free_all_states (Dwfl_Thread *thread)
84 : {
85 111 : while (thread->unwound)
86 34 : state_free (thread->unwound);
87 : }
88 :
89 : static Dwfl_Frame *
90 47 : state_alloc (Dwfl_Thread *thread)
91 : {
92 47 : assert (thread->unwound == NULL);
93 47 : Ebl *ebl = thread->process->ebl;
94 47 : size_t nregs = ebl_frame_nregs (ebl);
95 47 : if (nregs == 0)
96 : return NULL;
97 47 : assert (nregs < sizeof (((Dwfl_Frame *) NULL)->regs_set) * 8);
98 47 : Dwfl_Frame *state = malloc (sizeof (*state) + sizeof (*state->regs) * nregs);
99 47 : if (state == NULL)
100 : return NULL;
101 47 : state->thread = thread;
102 47 : state->signal_frame = false;
103 47 : state->initial_frame = true;
104 47 : state->pc_state = DWFL_FRAME_STATE_ERROR;
105 47 : memset (state->regs_set, 0, sizeof (state->regs_set));
106 47 : thread->unwound = state;
107 47 : state->unwound = NULL;
108 47 : return state;
109 : }
110 :
111 : void
112 : internal_function
113 46 : __libdwfl_process_free (Dwfl_Process *process)
114 : {
115 46 : Dwfl *dwfl = process->dwfl;
116 46 : if (process->callbacks->detach != NULL)
117 45 : process->callbacks->detach (dwfl, process->callbacks_arg);
118 46 : assert (dwfl->process == process);
119 46 : dwfl->process = NULL;
120 46 : if (process->ebl_close)
121 45 : ebl_closebackend (process->ebl);
122 46 : free (process);
123 46 : dwfl->attacherr = DWFL_E_NOERROR;
124 46 : }
125 :
126 : /* Allocate new Dwfl_Process for DWFL. */
127 : static void
128 : process_alloc (Dwfl *dwfl)
129 : {
130 49 : Dwfl_Process *process = malloc (sizeof (*process));
131 49 : if (process == NULL)
132 : return;
133 49 : process->dwfl = dwfl;
134 49 : dwfl->process = process;
135 : }
136 :
137 : bool
138 49 : dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid,
139 : const Dwfl_Thread_Callbacks *thread_callbacks, void *arg)
140 : {
141 49 : if (dwfl->process != NULL)
142 : {
143 0 : __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
144 0 : return false;
145 : }
146 :
147 : /* Reset any previous error, we are just going to try again. */
148 49 : dwfl->attacherr = DWFL_E_NOERROR;
149 : /* thread_callbacks is declared NN */
150 49 : if (thread_callbacks->next_thread == NULL
151 49 : || thread_callbacks->set_initial_registers == NULL)
152 : {
153 0 : dwfl->attacherr = DWFL_E_INVALID_ARGUMENT;
154 : fail:
155 0 : dwfl->attacherr = __libdwfl_canon_error (dwfl->attacherr);
156 0 : __libdwfl_seterrno (dwfl->attacherr);
157 0 : return false;
158 : }
159 :
160 : Ebl *ebl;
161 : bool ebl_close;
162 49 : if (elf != NULL)
163 : {
164 48 : ebl = ebl_openbackend (elf);
165 48 : ebl_close = true;
166 : }
167 : else
168 : {
169 1 : ebl = NULL;
170 1 : for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
171 : {
172 : /* Reading of the vDSO or (deleted) modules may fail as
173 : /proc/PID/mem is unreadable without PTRACE_ATTACH and
174 : we may not be PTRACE_ATTACH-ed now. MOD would not be
175 : re-read later to unwind it when we are already
176 : PTRACE_ATTACH-ed to PID. This happens when this function
177 : is called from dwfl_linux_proc_attach with elf == NULL.
178 : __libdwfl_module_getebl will call __libdwfl_getelf which
179 : will call the find_elf callback. */
180 1 : if (strncmp (mod->name, "[vdso: ", 7) == 0
181 1 : || strcmp (strrchr (mod->name, ' ') ?: "",
182 : " (deleted)") == 0)
183 0 : continue;
184 1 : Dwfl_Error error = __libdwfl_module_getebl (mod);
185 1 : if (error != DWFL_E_NOERROR)
186 0 : continue;
187 1 : ebl = mod->ebl;
188 1 : break;
189 : }
190 : ebl_close = false;
191 : }
192 49 : if (ebl == NULL)
193 : {
194 : /* Not identified EBL from any of the modules. */
195 0 : dwfl->attacherr = DWFL_E_PROCESS_NO_ARCH;
196 0 : goto fail;
197 : }
198 : process_alloc (dwfl);
199 49 : Dwfl_Process *process = dwfl->process;
200 49 : if (process == NULL)
201 : {
202 0 : if (ebl_close)
203 0 : ebl_closebackend (ebl);
204 0 : dwfl->attacherr = DWFL_E_NOMEM;
205 0 : goto fail;
206 : }
207 49 : process->ebl = ebl;
208 49 : process->ebl_close = ebl_close;
209 49 : process->pid = pid;
210 49 : process->callbacks = thread_callbacks;
211 49 : process->callbacks_arg = arg;
212 49 : return true;
213 : }
214 : INTDEF(dwfl_attach_state)
215 :
216 : pid_t
217 56 : dwfl_pid (Dwfl *dwfl)
218 : {
219 56 : if (dwfl->attacherr != DWFL_E_NOERROR)
220 : {
221 0 : __libdwfl_seterrno (dwfl->attacherr);
222 0 : return -1;
223 : }
224 :
225 56 : if (dwfl->process == NULL)
226 : {
227 0 : __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
228 0 : return -1;
229 : }
230 56 : return dwfl->process->pid;
231 : }
232 : INTDEF(dwfl_pid)
233 :
234 : Dwfl *
235 197 : dwfl_thread_dwfl (Dwfl_Thread *thread)
236 : {
237 197 : return thread->process->dwfl;
238 : }
239 : INTDEF(dwfl_thread_dwfl)
240 :
241 : pid_t
242 286 : dwfl_thread_tid (Dwfl_Thread *thread)
243 : {
244 286 : return thread->tid;
245 : }
246 : INTDEF(dwfl_thread_tid)
247 :
248 : Dwfl_Thread *
249 196 : dwfl_frame_thread (Dwfl_Frame *state)
250 : {
251 196 : return state->thread;
252 : }
253 : INTDEF(dwfl_frame_thread)
254 :
255 : int
256 32 : dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg),
257 : void *arg)
258 : {
259 32 : if (dwfl->attacherr != DWFL_E_NOERROR)
260 : {
261 0 : __libdwfl_seterrno (dwfl->attacherr);
262 0 : return -1;
263 : }
264 :
265 32 : Dwfl_Process *process = dwfl->process;
266 32 : if (process == NULL)
267 : {
268 0 : __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
269 0 : return -1;
270 : }
271 :
272 : Dwfl_Thread thread;
273 32 : thread.process = process;
274 32 : thread.unwound = NULL;
275 32 : thread.callbacks_arg = NULL;
276 : for (;;)
277 : {
278 81 : thread.tid = process->callbacks->next_thread (dwfl,
279 : process->callbacks_arg,
280 : &thread.callbacks_arg);
281 81 : if (thread.tid < 0)
282 : {
283 0 : Dwfl_Error saved_errno = dwfl_errno ();
284 0 : thread_free_all_states (&thread);
285 0 : __libdwfl_seterrno (saved_errno);
286 0 : return -1;
287 : }
288 81 : if (thread.tid == 0)
289 : {
290 : thread_free_all_states (&thread);
291 31 : __libdwfl_seterrno (DWFL_E_NOERROR);
292 31 : return 0;
293 : }
294 50 : int err = callback (&thread, arg);
295 49 : if (err != DWARF_CB_OK)
296 : {
297 : thread_free_all_states (&thread);
298 : return err;
299 : }
300 49 : assert (thread.unwound == NULL);
301 : }
302 : /* NOTREACHED */
303 : }
304 : INTDEF(dwfl_getthreads)
305 :
306 : struct one_arg
307 : {
308 : pid_t tid;
309 : bool seen;
310 : int (*callback) (Dwfl_Thread *thread, void *arg);
311 : void *arg;
312 : int ret;
313 : };
314 :
315 : static int
316 0 : get_one_thread_cb (Dwfl_Thread *thread, void *arg)
317 : {
318 0 : struct one_arg *oa = (struct one_arg *) arg;
319 0 : if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid)
320 : {
321 0 : oa->seen = true;
322 0 : oa->ret = oa->callback (thread, oa->arg);
323 0 : return DWARF_CB_ABORT;
324 : }
325 :
326 : return DWARF_CB_OK;
327 : }
328 :
329 : /* Note not currently exported, will be when there are more Dwfl_Thread
330 : properties to query. Use dwfl_getthread_frames for now directly. */
331 : static int
332 0 : getthread (Dwfl *dwfl, pid_t tid,
333 : int (*callback) (Dwfl_Thread *thread, void *arg),
334 : void *arg)
335 : {
336 0 : if (dwfl->attacherr != DWFL_E_NOERROR)
337 : {
338 0 : __libdwfl_seterrno (dwfl->attacherr);
339 0 : return -1;
340 : }
341 :
342 0 : Dwfl_Process *process = dwfl->process;
343 0 : if (process == NULL)
344 : {
345 0 : __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
346 0 : return -1;
347 : }
348 :
349 0 : if (process->callbacks->get_thread != NULL)
350 : {
351 : Dwfl_Thread thread;
352 0 : thread.process = process;
353 0 : thread.unwound = NULL;
354 0 : thread.callbacks_arg = NULL;
355 :
356 0 : if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
357 : &thread.callbacks_arg))
358 : {
359 : int err;
360 0 : thread.tid = tid;
361 0 : err = callback (&thread, arg);
362 0 : thread_free_all_states (&thread);
363 : return err;
364 : }
365 :
366 : return -1;
367 : }
368 :
369 0 : struct one_arg oa = { .tid = tid, .callback = callback,
370 : .arg = arg, .seen = false };
371 0 : int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa);
372 :
373 0 : if (err == DWARF_CB_ABORT && oa.seen)
374 0 : return oa.ret;
375 :
376 0 : if (err == DWARF_CB_OK && ! oa.seen)
377 : {
378 0 : errno = ESRCH;
379 0 : __libdwfl_seterrno (DWFL_E_ERRNO);
380 0 : return -1;
381 : }
382 :
383 : return err;
384 : }
385 :
386 : struct one_thread
387 : {
388 : int (*callback) (Dwfl_Frame *frame, void *arg);
389 : void *arg;
390 : };
391 :
392 : static int
393 0 : get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg)
394 : {
395 0 : struct one_thread *ot = (struct one_thread *) arg;
396 0 : return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg);
397 : }
398 :
399 : int
400 0 : dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
401 : int (*callback) (Dwfl_Frame *frame, void *arg),
402 : void *arg)
403 : {
404 0 : struct one_thread ot = { .callback = callback, .arg = arg };
405 0 : return getthread (dwfl, tid, get_one_thread_frames_cb, &ot);
406 : }
407 : INTDEF(dwfl_getthread_frames)
408 :
409 : int
410 47 : dwfl_thread_getframes (Dwfl_Thread *thread,
411 : int (*callback) (Dwfl_Frame *state, void *arg),
412 : void *arg)
413 : {
414 47 : if (thread->unwound != NULL)
415 : {
416 : /* We had to be called from inside CALLBACK. */
417 0 : __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
418 0 : return -1;
419 : }
420 47 : Ebl *ebl = thread->process->ebl;
421 47 : if (ebl_frame_nregs (ebl) == 0)
422 : {
423 0 : __libdwfl_seterrno (DWFL_E_NO_UNWIND);
424 0 : return -1;
425 : }
426 47 : if (state_alloc (thread) == NULL)
427 : {
428 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
429 0 : return -1;
430 : }
431 47 : Dwfl_Process *process = thread->process;
432 47 : if (! process->callbacks->set_initial_registers (thread,
433 : thread->callbacks_arg))
434 : {
435 : thread_free_all_states (thread);
436 : return -1;
437 : }
438 47 : if (! state_fetch_pc (thread->unwound))
439 : {
440 0 : if (process->callbacks->thread_detach)
441 0 : process->callbacks->thread_detach (thread, thread->callbacks_arg);
442 : thread_free_all_states (thread);
443 : return -1;
444 : }
445 :
446 : Dwfl_Frame *state;
447 : do
448 : {
449 231 : state = thread->unwound;
450 231 : int err = callback (state, arg);
451 230 : if (err != DWARF_CB_OK)
452 : {
453 7 : if (process->callbacks->thread_detach)
454 0 : process->callbacks->thread_detach (thread, thread->callbacks_arg);
455 : thread_free_all_states (thread);
456 : return err;
457 : }
458 223 : __libdwfl_frame_unwind (state);
459 : /* The old frame is no longer needed. */
460 223 : state_free (thread->unwound);
461 223 : state = thread->unwound;
462 : }
463 223 : while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
464 :
465 39 : Dwfl_Error err = dwfl_errno ();
466 39 : if (process->callbacks->thread_detach)
467 5 : process->callbacks->thread_detach (thread, thread->callbacks_arg);
468 39 : if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
469 : {
470 : thread_free_all_states (thread);
471 19 : __libdwfl_seterrno (err);
472 19 : return -1;
473 : }
474 20 : assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
475 : thread_free_all_states (thread);
476 : return 0;
477 : }
478 : INTDEF(dwfl_thread_getframes)
|