LCOV - code coverage report
Current view: top level - libdwfl - dwfl_frame.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 122 199 61.3 %
Date: 2017-01-05 09:15:16 Functions: 11 15 73.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.12