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