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