• 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 "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
state_fetch_pc(Dwfl_Frame * state)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
state_free(Dwfl_Frame * state)74 state_free (Dwfl_Frame *state)
75 {
76   Dwfl_Thread *thread = state->thread;
77   assert (thread->unwound == state);
78   thread->unwound = state->unwound;
79   free (state);
80 }
81 
82 static void
thread_free_all_states(Dwfl_Thread * thread)83 thread_free_all_states (Dwfl_Thread *thread)
84 {
85   while (thread->unwound)
86     state_free (thread->unwound);
87 }
88 
89 static Dwfl_Frame *
state_alloc(Dwfl_Thread * thread)90 state_alloc (Dwfl_Thread *thread)
91 {
92   assert (thread->unwound == NULL);
93   Ebl *ebl = thread->process->ebl;
94   size_t nregs = ebl_frame_nregs (ebl);
95   if (nregs == 0)
96     return NULL;
97   assert (nregs < sizeof (((Dwfl_Frame *) NULL)->regs_set) * 8);
98   Dwfl_Frame *state = malloc (sizeof (*state) + sizeof (*state->regs) * nregs);
99   if (state == NULL)
100     return NULL;
101   state->thread = thread;
102   state->signal_frame = false;
103   state->initial_frame = true;
104   state->pc_state = DWFL_FRAME_STATE_ERROR;
105   memset (state->regs_set, 0, sizeof (state->regs_set));
106   thread->unwound = state;
107   state->unwound = NULL;
108   return state;
109 }
110 
111 void
112 internal_function
__libdwfl_process_free(Dwfl_Process * process)113 __libdwfl_process_free (Dwfl_Process *process)
114 {
115   Dwfl *dwfl = process->dwfl;
116   if (process->callbacks->detach != NULL)
117     process->callbacks->detach (dwfl, process->callbacks_arg);
118   assert (dwfl->process == process);
119   dwfl->process = NULL;
120   if (process->ebl_close)
121     ebl_closebackend (process->ebl);
122   free (process);
123   dwfl->attacherr = DWFL_E_NOERROR;
124 }
125 
126 /* Allocate new Dwfl_Process for DWFL.  */
127 static void
process_alloc(Dwfl * dwfl)128 process_alloc (Dwfl *dwfl)
129 {
130   Dwfl_Process *process = malloc (sizeof (*process));
131   if (process == NULL)
132     return;
133   process->dwfl = dwfl;
134   dwfl->process = process;
135 }
136 
137 bool
dwfl_attach_state(Dwfl * dwfl,Elf * elf,pid_t pid,const Dwfl_Thread_Callbacks * thread_callbacks,void * arg)138 dwfl_attach_state (Dwfl *dwfl, Elf *elf, pid_t pid,
139 		   const Dwfl_Thread_Callbacks *thread_callbacks, void *arg)
140 {
141   if (dwfl->process != NULL)
142     {
143       __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
144       return false;
145     }
146 
147   /* Reset any previous error, we are just going to try again.  */
148   dwfl->attacherr = DWFL_E_NOERROR;
149   /* thread_callbacks is declared NN */
150   if (thread_callbacks->next_thread == NULL
151       || thread_callbacks->set_initial_registers == NULL)
152     {
153       dwfl->attacherr = DWFL_E_INVALID_ARGUMENT;
154     fail:
155       dwfl->attacherr = __libdwfl_canon_error (dwfl->attacherr);
156       __libdwfl_seterrno (dwfl->attacherr);
157       return false;
158     }
159 
160   Ebl *ebl;
161   bool ebl_close;
162   if (elf != NULL)
163     {
164       ebl = ebl_openbackend (elf);
165       ebl_close = true;
166     }
167   else
168     {
169       ebl = NULL;
170       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 	  if (strncmp (mod->name, "[vdso: ", 7) == 0
181 	      || strcmp (strrchr (mod->name, ' ') ?: "",
182 			 " (deleted)") == 0)
183 	    continue;
184 	  Dwfl_Error error = __libdwfl_module_getebl (mod);
185 	  if (error != DWFL_E_NOERROR)
186 	    continue;
187 	  ebl = mod->ebl;
188 	  break;
189 	}
190       ebl_close = false;
191     }
192   if (ebl == NULL)
193     {
194       /* Not identified EBL from any of the modules.  */
195       dwfl->attacherr = DWFL_E_PROCESS_NO_ARCH;
196       goto fail;
197     }
198   process_alloc (dwfl);
199   Dwfl_Process *process = dwfl->process;
200   if (process == NULL)
201     {
202       if (ebl_close)
203 	ebl_closebackend (ebl);
204       dwfl->attacherr = DWFL_E_NOMEM;
205       goto fail;
206     }
207   process->ebl = ebl;
208   process->ebl_close = ebl_close;
209   process->pid = pid;
210   process->callbacks = thread_callbacks;
211   process->callbacks_arg = arg;
212   return true;
213 }
INTDEF(dwfl_attach_state)214 INTDEF(dwfl_attach_state)
215 
216 pid_t
217 dwfl_pid (Dwfl *dwfl)
218 {
219   if (dwfl->attacherr != DWFL_E_NOERROR)
220     {
221       __libdwfl_seterrno (dwfl->attacherr);
222       return -1;
223     }
224 
225   if (dwfl->process == NULL)
226     {
227       __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
228       return -1;
229     }
230   return dwfl->process->pid;
231 }
INTDEF(dwfl_pid)232 INTDEF(dwfl_pid)
233 
234 Dwfl *
235 dwfl_thread_dwfl (Dwfl_Thread *thread)
236 {
237   return thread->process->dwfl;
238 }
INTDEF(dwfl_thread_dwfl)239 INTDEF(dwfl_thread_dwfl)
240 
241 pid_t
242 dwfl_thread_tid (Dwfl_Thread *thread)
243 {
244   return thread->tid;
245 }
INTDEF(dwfl_thread_tid)246 INTDEF(dwfl_thread_tid)
247 
248 Dwfl_Thread *
249 dwfl_frame_thread (Dwfl_Frame *state)
250 {
251   return state->thread;
252 }
INTDEF(dwfl_frame_thread)253 INTDEF(dwfl_frame_thread)
254 
255 int
256 dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg),
257 		 void *arg)
258 {
259   if (dwfl->attacherr != DWFL_E_NOERROR)
260     {
261       __libdwfl_seterrno (dwfl->attacherr);
262       return -1;
263     }
264 
265   Dwfl_Process *process = dwfl->process;
266   if (process == NULL)
267     {
268       __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
269       return -1;
270     }
271 
272   Dwfl_Thread thread;
273   thread.process = process;
274   thread.unwound = NULL;
275   thread.callbacks_arg = NULL;
276   for (;;)
277     {
278       thread.tid = process->callbacks->next_thread (dwfl,
279 						    process->callbacks_arg,
280 						    &thread.callbacks_arg);
281       if (thread.tid < 0)
282 	{
283 	  Dwfl_Error saved_errno = dwfl_errno ();
284 	  thread_free_all_states (&thread);
285 	  __libdwfl_seterrno (saved_errno);
286 	  return -1;
287 	}
288       if (thread.tid == 0)
289 	{
290 	  thread_free_all_states (&thread);
291 	  __libdwfl_seterrno (DWFL_E_NOERROR);
292 	  return 0;
293 	}
294       int err = callback (&thread, arg);
295       if (err != DWARF_CB_OK)
296 	{
297 	  thread_free_all_states (&thread);
298 	  return err;
299 	}
300       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
get_one_thread_cb(Dwfl_Thread * thread,void * arg)316 get_one_thread_cb (Dwfl_Thread *thread, void *arg)
317 {
318   struct one_arg *oa = (struct one_arg *) arg;
319   if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid)
320     {
321       oa->seen = true;
322       oa->ret = oa->callback (thread, oa->arg);
323       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
getthread(Dwfl * dwfl,pid_t tid,int (* callback)(Dwfl_Thread * thread,void * arg),void * arg)332 getthread (Dwfl *dwfl, pid_t tid,
333 	   int (*callback) (Dwfl_Thread *thread, void *arg),
334 	   void *arg)
335 {
336   if (dwfl->attacherr != DWFL_E_NOERROR)
337     {
338       __libdwfl_seterrno (dwfl->attacherr);
339       return -1;
340     }
341 
342   Dwfl_Process *process = dwfl->process;
343   if (process == NULL)
344     {
345       __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
346       return -1;
347     }
348 
349   if (process->callbacks->get_thread != NULL)
350     {
351       Dwfl_Thread thread;
352       thread.process = process;
353       thread.unwound = NULL;
354       thread.callbacks_arg = NULL;
355 
356       if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
357 					  &thread.callbacks_arg))
358 	{
359 	  int err;
360 	  thread.tid = tid;
361 	  err = callback (&thread, arg);
362 	  thread_free_all_states (&thread);
363 	  return err;
364 	}
365 
366       return -1;
367     }
368 
369    struct one_arg oa = { .tid = tid, .callback = callback,
370 			 .arg = arg, .seen = false };
371    int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa);
372 
373    if (err == DWARF_CB_ABORT && oa.seen)
374      return oa.ret;
375 
376    if (err == DWARF_CB_OK && ! oa.seen)
377      {
378 	errno = ESRCH;
379 	__libdwfl_seterrno (DWFL_E_ERRNO);
380 	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
get_one_thread_frames_cb(Dwfl_Thread * thread,void * arg)393 get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg)
394 {
395   struct one_thread *ot = (struct one_thread *) arg;
396   return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg);
397 }
398 
399 int
dwfl_getthread_frames(Dwfl * dwfl,pid_t tid,int (* callback)(Dwfl_Frame * frame,void * arg),void * arg)400 dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
401 		       int (*callback) (Dwfl_Frame *frame, void *arg),
402 		       void *arg)
403 {
404   struct one_thread ot = { .callback = callback, .arg = arg };
405   return getthread (dwfl, tid, get_one_thread_frames_cb, &ot);
406 }
INTDEF(dwfl_getthread_frames)407 INTDEF(dwfl_getthread_frames)
408 
409 int
410 dwfl_thread_getframes (Dwfl_Thread *thread,
411 		       int (*callback) (Dwfl_Frame *state, void *arg),
412 		       void *arg)
413 {
414   if (thread->unwound != NULL)
415     {
416       /* We had to be called from inside CALLBACK.  */
417       __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
418       return -1;
419     }
420   Ebl *ebl = thread->process->ebl;
421   if (ebl_frame_nregs (ebl) == 0)
422     {
423       __libdwfl_seterrno (DWFL_E_NO_UNWIND);
424       return -1;
425     }
426   if (state_alloc (thread) == NULL)
427     {
428       __libdwfl_seterrno (DWFL_E_NOMEM);
429       return -1;
430     }
431   Dwfl_Process *process = thread->process;
432   if (! process->callbacks->set_initial_registers (thread,
433 						   thread->callbacks_arg))
434     {
435       thread_free_all_states (thread);
436       return -1;
437     }
438   if (! state_fetch_pc (thread->unwound))
439     {
440       if (process->callbacks->thread_detach)
441 	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       state = thread->unwound;
450       int err = callback (state, arg);
451       if (err != DWARF_CB_OK)
452 	{
453 	  if (process->callbacks->thread_detach)
454 	    process->callbacks->thread_detach (thread, thread->callbacks_arg);
455 	  thread_free_all_states (thread);
456 	  return err;
457 	}
458       __libdwfl_frame_unwind (state);
459       /* The old frame is no longer needed.  */
460       state_free (thread->unwound);
461       state = thread->unwound;
462     }
463   while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
464 
465   Dwfl_Error err = dwfl_errno ();
466   if (process->callbacks->thread_detach)
467     process->callbacks->thread_detach (thread, thread->callbacks_arg);
468   if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
469     {
470       thread_free_all_states (thread);
471       __libdwfl_seterrno (err);
472       return -1;
473     }
474   assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
475   thread_free_all_states (thread);
476   return 0;
477 }
478 INTDEF(dwfl_thread_getframes)
479