• 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
free_states(Dwfl_Frame * state)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 *
state_alloc(Dwfl_Thread * thread)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
__libdwfl_process_free(Dwfl_Process * process)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
process_alloc(Dwfl * dwfl)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
dwfl_attach_state(Dwfl * dwfl,Elf * elf,pid_t pid,const Dwfl_Thread_Callbacks * thread_callbacks,void * arg)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 }
INTDEF(dwfl_attach_state)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 }
INTDEF(dwfl_pid)227 INTDEF(dwfl_pid)
228 
229 Dwfl *
230 dwfl_thread_dwfl (Dwfl_Thread *thread)
231 {
232   return thread->process->dwfl;
233 }
INTDEF(dwfl_thread_dwfl)234 INTDEF(dwfl_thread_dwfl)
235 
236 pid_t
237 dwfl_thread_tid (Dwfl_Thread *thread)
238 {
239   return thread->tid;
240 }
INTDEF(dwfl_thread_tid)241 INTDEF(dwfl_thread_tid)
242 
243 Dwfl_Thread *
244 dwfl_frame_thread (Dwfl_Frame *state)
245 {
246   return state->thread;
247 }
INTDEF(dwfl_frame_thread)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
get_one_thread_cb(Dwfl_Thread * thread,void * arg)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
getthread(Dwfl * dwfl,pid_t tid,int (* callback)(Dwfl_Thread * thread,void * arg),void * arg)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
get_one_thread_frames_cb(Dwfl_Thread * thread,void * arg)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
dwfl_getthread_frames(Dwfl * dwfl,pid_t tid,int (* callback)(Dwfl_Frame * frame,void * arg),void * arg)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 }
INTDEF(dwfl_getthread_frames)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)
457