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