LCOV - code coverage report
Current view: top level - libdwfl - linux-pid-attach.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 126 174 72.4 %
Date: 2017-01-05 09:15:16 Functions: 11 12 91.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Get Dwarf Frame state for target live PID process.
       2             :    Copyright (C) 2013, 2014, 2015 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 "libelfP.h"
      30             : #include "libdwflP.h"
      31             : #include <sys/types.h>
      32             : #include <sys/stat.h>
      33             : #include <fcntl.h>
      34             : #include <sys/ptrace.h>
      35             : #include <sys/wait.h>
      36             : #include <dirent.h>
      37             : #include <sys/syscall.h>
      38             : #include <unistd.h>
      39             : 
      40             : #ifdef __linux__
      41             : 
      42             : static bool
      43           3 : linux_proc_pid_is_stopped (pid_t pid)
      44             : {
      45             :   char buffer[64];
      46             :   FILE *procfile;
      47             :   bool retval, have_state;
      48             : 
      49           3 :   snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
      50           3 :   procfile = fopen (buffer, "r");
      51           3 :   if (procfile == NULL)
      52             :     return false;
      53             : 
      54             :   have_state = false;
      55           9 :   while (fgets (buffer, sizeof (buffer), procfile) != NULL)
      56           9 :     if (strncmp (buffer, "State:", 6) == 0)
      57             :       {
      58             :         have_state = true;
      59             :         break;
      60             :       }
      61           3 :   retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
      62           3 :   fclose (procfile);
      63           3 :   return retval;
      64             : }
      65             : 
      66             : bool
      67             : internal_function
      68           4 : __libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp)
      69             : {
      70           4 :   if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
      71             :     {
      72           1 :       __libdwfl_seterrno (DWFL_E_ERRNO);
      73           1 :       return false;
      74             :     }
      75           3 :   *tid_was_stoppedp = linux_proc_pid_is_stopped (tid);
      76           3 :   if (*tid_was_stoppedp)
      77             :     {
      78             :       /* Make sure there is a SIGSTOP signal pending even when the process is
      79             :          already State: T (stopped).  Older kernels might fail to generate
      80             :          a SIGSTOP notification in that case in response to our PTRACE_ATTACH
      81             :          above.  Which would make the waitpid below wait forever.  So emulate
      82             :          it.  Since there can only be one SIGSTOP notification pending this is
      83             :          safe.  See also gdb/linux-nat.c linux_nat_post_attach_wait.  */
      84           0 :       syscall (__NR_tkill, tid, SIGSTOP);
      85           0 :       ptrace (PTRACE_CONT, tid, NULL, NULL);
      86             :     }
      87             :   for (;;)
      88           0 :     {
      89             :       int status;
      90           3 :       if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
      91             :         {
      92           0 :           int saved_errno = errno;
      93           0 :           ptrace (PTRACE_DETACH, tid, NULL, NULL);
      94           0 :           errno = saved_errno;
      95           0 :           __libdwfl_seterrno (DWFL_E_ERRNO);
      96           0 :           return false;
      97             :         }
      98           3 :       if (WSTOPSIG (status) == SIGSTOP)
      99             :         break;
     100           0 :       if (ptrace (PTRACE_CONT, tid, NULL,
     101           0 :                   (void *) (uintptr_t) WSTOPSIG (status)) != 0)
     102             :         {
     103           0 :           int saved_errno = errno;
     104           0 :           ptrace (PTRACE_DETACH, tid, NULL, NULL);
     105           0 :           errno = saved_errno;
     106           0 :           __libdwfl_seterrno (DWFL_E_ERRNO);
     107           0 :           return false;
     108             :         }
     109             :     }
     110           3 :   return true;
     111             : }
     112             : 
     113             : static bool
     114          78 : pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
     115             : {
     116          78 :   struct __libdwfl_pid_arg *pid_arg = arg;
     117          78 :   pid_t tid = pid_arg->tid_attached;
     118          78 :   assert (tid > 0);
     119          78 :   Dwfl_Process *process = dwfl->process;
     120          78 :   if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
     121             :     {
     122             : #if SIZEOF_LONG == 8
     123          36 :       errno = 0;
     124          36 :       *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
     125          36 :       return errno == 0;
     126             : #else /* SIZEOF_LONG != 8 */
     127             :       /* This should not happen.  */
     128             :       return false;
     129             : #endif /* SIZEOF_LONG != 8 */
     130             :     }
     131             : #if SIZEOF_LONG == 8
     132             :   /* We do not care about reads unaliged to 4 bytes boundary.
     133             :      But 0x...ffc read of 8 bytes could overrun a page.  */
     134          42 :   bool lowered = (addr & 4) != 0;
     135          42 :   if (lowered)
     136          22 :     addr -= 4;
     137             : #endif /* SIZEOF_LONG == 8 */
     138          42 :   errno = 0;
     139          42 :   *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
     140          42 :   if (errno != 0)
     141             :     return false;
     142             : #if SIZEOF_LONG == 8
     143             : # if BYTE_ORDER == BIG_ENDIAN
     144             :   if (! lowered)
     145             :     *result >>= 32;
     146             : # else
     147          42 :   if (lowered)
     148          22 :     *result >>= 32;
     149             : # endif
     150             : #endif /* SIZEOF_LONG == 8 */
     151          42 :   *result &= 0xffffffff;
     152          42 :   return true;
     153             : }
     154             : 
     155             : static pid_t
     156          13 : pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
     157             :                  void **thread_argp)
     158             : {
     159          13 :   struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
     160             :   struct dirent *dirent;
     161             :   /* Start fresh on first traversal. */
     162          13 :   if (*thread_argp == NULL)
     163           5 :     rewinddir (pid_arg->dir);
     164             :   do
     165             :     {
     166          23 :       errno = 0;
     167          23 :       dirent = readdir (pid_arg->dir);
     168          23 :       if (dirent == NULL)
     169             :         {
     170           4 :           if (errno != 0)
     171             :             {
     172           0 :               __libdwfl_seterrno (DWFL_E_ERRNO);
     173           0 :               return -1;
     174             :             }
     175             :           return 0;
     176             :         }
     177             :     }
     178          19 :   while (strcmp (dirent->d_name, ".") == 0
     179          19 :          || strcmp (dirent->d_name, "..") == 0);
     180             :   char *end;
     181           9 :   errno = 0;
     182           9 :   long tidl = strtol (dirent->d_name, &end, 10);
     183           9 :   if (errno != 0)
     184             :     {
     185           0 :       __libdwfl_seterrno (DWFL_E_ERRNO);
     186           0 :       return -1;
     187             :     }
     188           9 :   pid_t tid = tidl;
     189           9 :   if (tidl <= 0 || (end && *end) || tid != tidl)
     190             :     {
     191           0 :       __libdwfl_seterrno (DWFL_E_PARSE_PROC);
     192           0 :       return -1;
     193             :     }
     194           9 :   *thread_argp = dwfl_arg;
     195           9 :   return tid;
     196             : }
     197             : 
     198             : /* Just checks that the thread id exists.  */
     199             : static bool
     200           0 : pid_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid,
     201             :                void *dwfl_arg, void **thread_argp)
     202             : {
     203           0 :   *thread_argp = dwfl_arg;
     204           0 :   if (kill (tid, 0) < 0)
     205             :     {
     206           0 :       __libdwfl_seterrno (DWFL_E_ERRNO);
     207           0 :       return false;
     208             :     }
     209             :   return true;
     210             : }
     211             : 
     212             : /* Implement the ebl_set_initial_registers_tid setfunc callback.  */
     213             : 
     214             : static bool
     215           6 : pid_thread_state_registers_cb (int firstreg, unsigned nregs,
     216             :                                const Dwarf_Word *regs, void *arg)
     217             : {
     218           6 :   Dwfl_Thread *thread = (Dwfl_Thread *) arg;
     219           6 :   if (firstreg < 0)
     220             :     {
     221           0 :       assert (firstreg == -1);
     222           0 :       assert (nregs == 1);
     223           0 :       INTUSE(dwfl_thread_state_register_pc) (thread, *regs);
     224           0 :       return true;
     225             :     }
     226           6 :   assert (nregs > 0);
     227           6 :   return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
     228             : }
     229             : 
     230             : static bool
     231           6 : pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
     232             : {
     233           6 :   struct __libdwfl_pid_arg *pid_arg = thread_arg;
     234           6 :   assert (pid_arg->tid_attached == 0);
     235           6 :   pid_t tid = INTUSE(dwfl_thread_tid) (thread);
     236           6 :   if (! pid_arg->assume_ptrace_stopped
     237           1 :       && ! __libdwfl_ptrace_attach (tid, &pid_arg->tid_was_stopped))
     238             :     return false;
     239           6 :   pid_arg->tid_attached = tid;
     240           6 :   Dwfl_Process *process = thread->process;
     241           6 :   Ebl *ebl = process->ebl;
     242           6 :   return ebl_set_initial_registers_tid (ebl, tid,
     243             :                                         pid_thread_state_registers_cb, thread);
     244             : }
     245             : 
     246             : static void
     247           9 : pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
     248             : {
     249           9 :   struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
     250           9 :   elf_end (pid_arg->elf);
     251           9 :   close (pid_arg->elf_fd);
     252           9 :   closedir (pid_arg->dir);
     253           9 :   free (pid_arg);
     254           9 : }
     255             : 
     256             : void
     257             : internal_function
     258           2 : __libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped)
     259             : {
     260             :   /* This handling is needed only on older Linux kernels such as
     261             :      2.6.32-358.23.2.el6.ppc64.  Later kernels such as
     262             :      3.11.7-200.fc19.x86_64 remember the T (stopped) state
     263             :      themselves and no longer need to pass SIGSTOP during
     264             :      PTRACE_DETACH.  */
     265           3 :   ptrace (PTRACE_DETACH, tid, NULL,
     266             :           (void *) (intptr_t) (tid_was_stopped ? SIGSTOP : 0));
     267           2 : }
     268             : 
     269             : static void
     270           5 : pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
     271             : {
     272           5 :   struct __libdwfl_pid_arg *pid_arg = thread_arg;
     273           5 :   pid_t tid = INTUSE(dwfl_thread_tid) (thread);
     274           5 :   assert (pid_arg->tid_attached == tid);
     275           5 :   pid_arg->tid_attached = 0;
     276           5 :   if (! pid_arg->assume_ptrace_stopped)
     277           1 :     __libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped);
     278           5 : }
     279             : 
     280             : static const Dwfl_Thread_Callbacks pid_thread_callbacks =
     281             : {
     282             :   pid_next_thread,
     283             :   pid_getthread,
     284             :   pid_memory_read,
     285             :   pid_set_initial_registers,
     286             :   pid_detach,
     287             :   pid_thread_detach,
     288             : };
     289             : 
     290             : int
     291          12 : dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped)
     292             : {
     293             :   char buffer[36];
     294             :   FILE *procfile;
     295          12 :   int err = 0; /* The errno to return and set for dwfl->attcherr.  */
     296             : 
     297             :   /* Make sure to report the actual PID (thread group leader) to
     298             :      dwfl_attach_state.  */
     299          12 :   snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
     300          12 :   procfile = fopen (buffer, "r");
     301          12 :   if (procfile == NULL)
     302             :     {
     303           0 :       err = errno;
     304             :     fail:
     305           0 :       if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
     306             :         {
     307           0 :           errno = err;
     308           0 :           dwfl->attacherr = __libdwfl_canon_error (DWFL_E_ERRNO);
     309             :         }
     310             :       return err;
     311             :     }
     312             : 
     313          12 :   char *line = NULL;
     314          12 :   size_t linelen = 0;
     315          60 :   while (getline (&line, &linelen, procfile) >= 0)
     316          48 :     if (strncmp (line, "Tgid:", 5) == 0)
     317             :       {
     318          12 :         errno = 0;
     319             :         char *endptr;
     320          12 :         long val = strtol (&line[5], &endptr, 10);
     321          12 :         if ((errno == ERANGE && val == LONG_MAX)
     322          12 :             || *endptr != '\n' || val < 0 || val != (pid_t) val)
     323             :           pid = 0;
     324             :         else
     325          12 :           pid = (pid_t) val;
     326             :         break;
     327             :       }
     328          12 :   free (line);
     329          12 :   fclose (procfile);
     330             : 
     331          12 :   if (pid == 0)
     332             :     {
     333             :       err = ESRCH;
     334             :       goto fail;
     335             :     }
     336             : 
     337             :   char name[64];
     338          12 :   int i = snprintf (name, sizeof (name), "/proc/%ld/task", (long) pid);
     339          12 :   assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
     340          12 :   DIR *dir = opendir (name);
     341          12 :   if (dir == NULL)
     342             :     {
     343           0 :       err = errno;
     344           0 :       goto fail;
     345             :     }
     346             : 
     347             :   Elf *elf;
     348          12 :   i = snprintf (name, sizeof (name), "/proc/%ld/exe", (long) pid);
     349          12 :   assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
     350          12 :   int elf_fd = open (name, O_RDONLY);
     351          12 :   if (elf_fd >= 0)
     352             :     {
     353          12 :       elf = elf_begin (elf_fd, ELF_C_READ_MMAP, NULL);
     354          12 :       if (elf == NULL)
     355             :         {
     356             :           /* Just ignore, dwfl_attach_state will fall back to trying
     357             :              to associate the Dwfl with one of the existing DWfl_Module
     358             :              ELF images (to know the machine/class backend to use).  */
     359           0 :           close (elf_fd);
     360           0 :           elf_fd = -1;
     361             :         }
     362             :     }
     363             :   else
     364             :     elf = NULL;
     365          12 :   struct __libdwfl_pid_arg *pid_arg = malloc (sizeof *pid_arg);
     366          12 :   if (pid_arg == NULL)
     367             :     {
     368           0 :       elf_end (elf);
     369           0 :       close (elf_fd);
     370           0 :       closedir (dir);
     371           0 :       err = ENOMEM;
     372           0 :       goto fail;
     373             :     }
     374          12 :   pid_arg->dir = dir;
     375          12 :   pid_arg->elf = elf;
     376          12 :   pid_arg->elf_fd = elf_fd;
     377          12 :   pid_arg->tid_attached = 0;
     378          12 :   pid_arg->assume_ptrace_stopped = assume_ptrace_stopped;
     379          12 :   if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks,
     380             :                                    pid_arg))
     381             :     {
     382           0 :       elf_end (elf);
     383           0 :       close (elf_fd);
     384           0 :       closedir (dir);
     385           0 :       free (pid_arg);
     386           0 :       return -1;
     387             :     }
     388             :   return 0;
     389             : }
     390             : INTDEF (dwfl_linux_proc_attach)
     391             : 
     392             : struct __libdwfl_pid_arg *
     393             : internal_function
     394           5 : __libdwfl_get_pid_arg (Dwfl *dwfl)
     395             : {
     396           5 :   if (dwfl != NULL && dwfl->process != NULL
     397           5 :       && dwfl->process->callbacks == &pid_thread_callbacks)
     398           5 :     return (struct __libdwfl_pid_arg *) dwfl->process->callbacks_arg;
     399             : 
     400             :   return NULL;
     401             : }
     402             : 
     403             : #else   /* __linux__ */
     404             : 
     405             : bool
     406             : internal_function
     407             : __libdwfl_ptrace_attach (pid_t tid __attribute__ ((unused)),
     408             :                          bool *tid_was_stoppedp __attribute__ ((unused)))
     409             : {
     410             :   errno = ENOSYS;
     411             :   __libdwfl_seterrno (DWFL_E_ERRNO);
     412             :   return false;
     413             : }
     414             : 
     415             : void
     416             : internal_function
     417             : __libdwfl_ptrace_detach (pid_t tid __attribute__ ((unused)),
     418             :                          bool tid_was_stopped __attribute__ ((unused)))
     419             : {
     420             : }
     421             : 
     422             : int
     423             : dwfl_linux_proc_attach (Dwfl *dwfl __attribute__ ((unused)),
     424             :                         pid_t pid __attribute__ ((unused)),
     425             :                         bool assume_ptrace_stopped __attribute__ ((unused)))
     426             : {
     427             :   return ENOSYS;
     428             : }
     429             : INTDEF (dwfl_linux_proc_attach)
     430             : 
     431             : struct __libdwfl_pid_arg *
     432             : internal_function
     433             : __libdwfl_get_pid_arg (Dwfl *dwfl __attribute__ ((unused)))
     434             : {
     435             :   return NULL;
     436             : }
     437             : 
     438             : #endif /* ! __linux __ */
     439             : 

Generated by: LCOV version 1.12