Home | History | Annotate | Download | only in libdwfl
      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 #include "libdwflP.h"
     30 #include <sys/ptrace.h>
     31 #include <unistd.h>
     32 
     33 /* Set STATE->pc_set from STATE->regs according to the backend.  Return true on
     34    success, false on error.  */
     35 static bool
     36 state_fetch_pc (Dwfl_Frame *state)
     37 {
     38   switch (state->pc_state)
     39     {
     40     case DWFL_FRAME_STATE_PC_SET:
     41       return true;
     42     case DWFL_FRAME_STATE_PC_UNDEFINED:
     43       abort ();
     44     case DWFL_FRAME_STATE_ERROR:
     45       {
     46 	Ebl *ebl = state->thread->process->ebl;
     47 	Dwarf_CIE abi_info;
     48 	if (ebl_abi_cfi (ebl, &abi_info) != 0)
     49 	  {
     50 	    __libdwfl_seterrno (DWFL_E_LIBEBL);
     51 	    return false;
     52 	  }
     53 	unsigned ra = abi_info.return_address_register;
     54 	/* dwarf_frame_state_reg_is_set is not applied here.  */
     55 	if (ra >= ebl_frame_nregs (ebl))
     56 	  {
     57 	    __libdwfl_seterrno (DWFL_E_LIBEBL_BAD);
     58 	    return false;
     59 	  }
     60 	state->pc = state->regs[ra];
     61 	state->pc_state = DWFL_FRAME_STATE_PC_SET;
     62       }
     63       return true;
     64     }
     65   abort ();
     66 }
     67 
     68 /* Do not call it on your own, to be used by thread_* functions only.  */
     69 
     70 static void
     71 state_free (Dwfl_Frame *state)
     72 {
     73   Dwfl_Thread *thread = state->thread;
     74   assert (thread->unwound == state);
     75   thread->unwound = state->unwound;
     76   free (state);
     77 }
     78 
     79 static void
     80 thread_free_all_states (Dwfl_Thread *thread)
     81 {
     82   while (thread->unwound)
     83     state_free (thread->unwound);
     84 }
     85 
     86 static Dwfl_Frame *
     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
    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
    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
    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   if (thread_callbacks == NULL || 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 (strncmp (mod->name, "[vdso: ", 7) == 0
    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 }
    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 }
    228 INTDEF(dwfl_pid)
    229 
    230 Dwfl *
    231 dwfl_thread_dwfl (Dwfl_Thread *thread)
    232 {
    233   return thread->process->dwfl;
    234 }
    235 INTDEF(dwfl_thread_dwfl)
    236 
    237 pid_t
    238 dwfl_thread_tid (Dwfl_Thread *thread)
    239 {
    240   return thread->tid;
    241 }
    242 INTDEF(dwfl_thread_tid)
    243 
    244 Dwfl_Thread *
    245 dwfl_frame_thread (Dwfl_Frame *state)
    246 {
    247   return state->thread;
    248 }
    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 	{
    279 	  Dwfl_Error saved_errno = dwfl_errno ();
    280 	  thread_free_all_states (&thread);
    281 	  __libdwfl_seterrno (saved_errno);
    282 	  return -1;
    283 	}
    284       if (thread.tid == 0)
    285 	{
    286 	  thread_free_all_states (&thread);
    287 	  __libdwfl_seterrno (DWFL_E_NOERROR);
    288 	  return 0;
    289 	}
    290       int err = callback (&thread, arg);
    291       if (err != DWARF_CB_OK)
    292 	{
    293 	  thread_free_all_states (&thread);
    294 	  return err;
    295 	}
    296       assert (thread.unwound == NULL);
    297     }
    298   /* NOTREACHED */
    299 }
    300 INTDEF(dwfl_getthreads)
    301 
    302 struct one_arg
    303 {
    304   pid_t tid;
    305   bool seen;
    306   int (*callback) (Dwfl_Thread *thread, void *arg);
    307   void *arg;
    308   int ret;
    309 };
    310 
    311 static int
    312 get_one_thread_cb (Dwfl_Thread *thread, void *arg)
    313 {
    314   struct one_arg *oa = (struct one_arg *) arg;
    315   if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid)
    316     {
    317       oa->seen = true;
    318       oa->ret = oa->callback (thread, oa->arg);
    319       return DWARF_CB_ABORT;
    320     }
    321 
    322   return DWARF_CB_OK;
    323 }
    324 
    325 /* Note not currently exported, will be when there are more Dwfl_Thread
    326    properties to query.  Use dwfl_getthread_frames for now directly.  */
    327 static int
    328 getthread (Dwfl *dwfl, pid_t tid,
    329 	   int (*callback) (Dwfl_Thread *thread, void *arg),
    330 	   void *arg)
    331 {
    332   if (dwfl->attacherr != DWFL_E_NOERROR)
    333     {
    334       __libdwfl_seterrno (dwfl->attacherr);
    335       return -1;
    336     }
    337 
    338   Dwfl_Process *process = dwfl->process;
    339   if (process == NULL)
    340     {
    341       __libdwfl_seterrno (DWFL_E_NO_ATTACH_STATE);
    342       return -1;
    343     }
    344 
    345   if (process->callbacks->get_thread != NULL)
    346     {
    347       Dwfl_Thread thread;
    348       thread.process = process;
    349       thread.unwound = NULL;
    350       thread.callbacks_arg = NULL;
    351 
    352       if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg,
    353 					  &thread.callbacks_arg))
    354 	{
    355 	  int err;
    356 	  thread.tid = tid;
    357 	  err = callback (&thread, arg);
    358 	  thread_free_all_states (&thread);
    359 	  return err;
    360 	}
    361 
    362       return -1;
    363     }
    364 
    365    struct one_arg oa = { .tid = tid, .callback = callback,
    366 			 .arg = arg, .seen = false };
    367    int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa);
    368 
    369    if (err == DWARF_CB_ABORT && oa.seen)
    370      return oa.ret;
    371 
    372    if (err == DWARF_CB_OK && ! oa.seen)
    373      {
    374 	errno = ESRCH;
    375 	__libdwfl_seterrno (DWFL_E_ERRNO);
    376 	return -1;
    377      }
    378 
    379    return err;
    380 }
    381 
    382 struct one_thread
    383 {
    384   int (*callback) (Dwfl_Frame *frame, void *arg);
    385   void *arg;
    386 };
    387 
    388 static int
    389 get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg)
    390 {
    391   struct one_thread *ot = (struct one_thread *) arg;
    392   return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg);
    393 }
    394 
    395 int
    396 dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
    397 		       int (*callback) (Dwfl_Frame *frame, void *arg),
    398 		       void *arg)
    399 {
    400   struct one_thread ot = { .callback = callback, .arg = arg };
    401   return getthread (dwfl, tid, get_one_thread_frames_cb, &ot);
    402 }
    403 INTDEF(dwfl_getthread_frames)
    404 
    405 int
    406 dwfl_thread_getframes (Dwfl_Thread *thread,
    407 		       int (*callback) (Dwfl_Frame *state, void *arg),
    408 		       void *arg)
    409 {
    410   if (thread->unwound != NULL)
    411     {
    412       /* We had to be called from inside CALLBACK.  */
    413       __libdwfl_seterrno (DWFL_E_ATTACH_STATE_CONFLICT);
    414       return -1;
    415     }
    416   Ebl *ebl = thread->process->ebl;
    417   if (ebl_frame_nregs (ebl) == 0)
    418     {
    419       __libdwfl_seterrno (DWFL_E_NO_UNWIND);
    420       return -1;
    421     }
    422   if (state_alloc (thread) == NULL)
    423     {
    424       __libdwfl_seterrno (DWFL_E_NOMEM);
    425       return -1;
    426     }
    427   Dwfl_Process *process = thread->process;
    428   if (! process->callbacks->set_initial_registers (thread,
    429 						   thread->callbacks_arg))
    430     {
    431       thread_free_all_states (thread);
    432       return -1;
    433     }
    434   if (! state_fetch_pc (thread->unwound))
    435     {
    436       if (process->callbacks->thread_detach)
    437 	process->callbacks->thread_detach (thread, thread->callbacks_arg);
    438       thread_free_all_states (thread);
    439       return -1;
    440     }
    441 
    442   Dwfl_Frame *state;
    443   do
    444     {
    445       state = thread->unwound;
    446       int err = callback (state, arg);
    447       if (err != DWARF_CB_OK)
    448 	{
    449 	  if (process->callbacks->thread_detach)
    450 	    process->callbacks->thread_detach (thread, thread->callbacks_arg);
    451 	  thread_free_all_states (thread);
    452 	  return err;
    453 	}
    454       __libdwfl_frame_unwind (state);
    455       /* The old frame is no longer needed.  */
    456       state_free (thread->unwound);
    457       state = thread->unwound;
    458     }
    459   while (state && state->pc_state == DWFL_FRAME_STATE_PC_SET);
    460 
    461   Dwfl_Error err = dwfl_errno ();
    462   if (process->callbacks->thread_detach)
    463     process->callbacks->thread_detach (thread, thread->callbacks_arg);
    464   if (state == NULL || state->pc_state == DWFL_FRAME_STATE_ERROR)
    465     {
    466       thread_free_all_states (thread);
    467       __libdwfl_seterrno (err);
    468       return -1;
    469     }
    470   assert (state->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
    471   thread_free_all_states (thread);
    472   return 0;
    473 }
    474 INTDEF(dwfl_thread_getframes)
    475