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 #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
     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
     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
     83 thread_free_all_states (Dwfl_Thread *thread)
     84 {
     85   while (thread->unwound)
     86     state_free (thread->unwound);
     87 }
     88 
     89 static Dwfl_Frame *
     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
    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
    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
    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 }
    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 }
    232 INTDEF(dwfl_pid)
    233 
    234 Dwfl *
    235 dwfl_thread_dwfl (Dwfl_Thread *thread)
    236 {
    237   return thread->process->dwfl;
    238 }
    239 INTDEF(dwfl_thread_dwfl)
    240 
    241 pid_t
    242 dwfl_thread_tid (Dwfl_Thread *thread)
    243 {
    244   return thread->tid;
    245 }
    246 INTDEF(dwfl_thread_tid)
    247 
    248 Dwfl_Thread *
    249 dwfl_frame_thread (Dwfl_Frame *state)
    250 {
    251   return state->thread;
    252 }
    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
    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
    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
    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
    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 }
    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