1da0c48c4Sopenharmony_ci/* Get Dwarf Frame state for target live PID process.
2da0c48c4Sopenharmony_ci   Copyright (C) 2013, 2014, 2015, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include <system.h>
34da0c48c4Sopenharmony_ci
35da0c48c4Sopenharmony_ci#include "libelfP.h"
36da0c48c4Sopenharmony_ci#include "libdwflP.h"
37da0c48c4Sopenharmony_ci#include <sys/types.h>
38da0c48c4Sopenharmony_ci#include <sys/stat.h>
39da0c48c4Sopenharmony_ci#include <fcntl.h>
40da0c48c4Sopenharmony_ci#include <dirent.h>
41da0c48c4Sopenharmony_ci
42da0c48c4Sopenharmony_ci#ifdef __linux__
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_ci#include <sys/uio.h>
45da0c48c4Sopenharmony_ci#include <sys/ptrace.h>
46da0c48c4Sopenharmony_ci#include <sys/syscall.h>
47da0c48c4Sopenharmony_ci#include <sys/wait.h>
48da0c48c4Sopenharmony_ci
49da0c48c4Sopenharmony_cistatic bool
50da0c48c4Sopenharmony_cilinux_proc_pid_is_stopped (pid_t pid)
51da0c48c4Sopenharmony_ci{
52da0c48c4Sopenharmony_ci  char buffer[64];
53da0c48c4Sopenharmony_ci  FILE *procfile;
54da0c48c4Sopenharmony_ci  bool retval, have_state;
55da0c48c4Sopenharmony_ci
56da0c48c4Sopenharmony_ci  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
57da0c48c4Sopenharmony_ci  procfile = fopen (buffer, "r");
58da0c48c4Sopenharmony_ci  if (procfile == NULL)
59da0c48c4Sopenharmony_ci    return false;
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci  have_state = false;
62da0c48c4Sopenharmony_ci  while (fgets (buffer, sizeof (buffer), procfile) != NULL)
63da0c48c4Sopenharmony_ci    if (startswith (buffer, "State:"))
64da0c48c4Sopenharmony_ci      {
65da0c48c4Sopenharmony_ci	have_state = true;
66da0c48c4Sopenharmony_ci	break;
67da0c48c4Sopenharmony_ci      }
68da0c48c4Sopenharmony_ci  retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
69da0c48c4Sopenharmony_ci  fclose (procfile);
70da0c48c4Sopenharmony_ci  return retval;
71da0c48c4Sopenharmony_ci}
72da0c48c4Sopenharmony_ci
73da0c48c4Sopenharmony_cibool
74da0c48c4Sopenharmony_ciinternal_function
75da0c48c4Sopenharmony_ci__libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp)
76da0c48c4Sopenharmony_ci{
77da0c48c4Sopenharmony_ci  if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
78da0c48c4Sopenharmony_ci    {
79da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_ERRNO);
80da0c48c4Sopenharmony_ci      return false;
81da0c48c4Sopenharmony_ci    }
82da0c48c4Sopenharmony_ci  *tid_was_stoppedp = linux_proc_pid_is_stopped (tid);
83da0c48c4Sopenharmony_ci  if (*tid_was_stoppedp)
84da0c48c4Sopenharmony_ci    {
85da0c48c4Sopenharmony_ci      /* Make sure there is a SIGSTOP signal pending even when the process is
86da0c48c4Sopenharmony_ci	 already State: T (stopped).  Older kernels might fail to generate
87da0c48c4Sopenharmony_ci	 a SIGSTOP notification in that case in response to our PTRACE_ATTACH
88da0c48c4Sopenharmony_ci	 above.  Which would make the waitpid below wait forever.  So emulate
89da0c48c4Sopenharmony_ci	 it.  Since there can only be one SIGSTOP notification pending this is
90da0c48c4Sopenharmony_ci	 safe.  See also gdb/linux-nat.c linux_nat_post_attach_wait.  */
91da0c48c4Sopenharmony_ci      syscall (__NR_tkill, tid, SIGSTOP);
92da0c48c4Sopenharmony_ci      ptrace (PTRACE_CONT, tid, NULL, NULL);
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci  for (;;)
95da0c48c4Sopenharmony_ci    {
96da0c48c4Sopenharmony_ci      int status;
97da0c48c4Sopenharmony_ci      if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
98da0c48c4Sopenharmony_ci	{
99da0c48c4Sopenharmony_ci	  int saved_errno = errno;
100da0c48c4Sopenharmony_ci	  ptrace (PTRACE_DETACH, tid, NULL, NULL);
101da0c48c4Sopenharmony_ci	  errno = saved_errno;
102da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_ERRNO);
103da0c48c4Sopenharmony_ci	  return false;
104da0c48c4Sopenharmony_ci	}
105da0c48c4Sopenharmony_ci      if (WSTOPSIG (status) == SIGSTOP)
106da0c48c4Sopenharmony_ci	break;
107da0c48c4Sopenharmony_ci      if (ptrace (PTRACE_CONT, tid, NULL,
108da0c48c4Sopenharmony_ci		  (void *) (uintptr_t) WSTOPSIG (status)) != 0)
109da0c48c4Sopenharmony_ci	{
110da0c48c4Sopenharmony_ci	  int saved_errno = errno;
111da0c48c4Sopenharmony_ci	  ptrace (PTRACE_DETACH, tid, NULL, NULL);
112da0c48c4Sopenharmony_ci	  errno = saved_errno;
113da0c48c4Sopenharmony_ci	  __libdwfl_seterrno (DWFL_E_ERRNO);
114da0c48c4Sopenharmony_ci	  return false;
115da0c48c4Sopenharmony_ci	}
116da0c48c4Sopenharmony_ci    }
117da0c48c4Sopenharmony_ci  return true;
118da0c48c4Sopenharmony_ci}
119da0c48c4Sopenharmony_ci
120da0c48c4Sopenharmony_ci#ifdef HAVE_PROCESS_VM_READV
121da0c48c4Sopenharmony_ci/* Note that the result word size depends on the architecture word size.
122da0c48c4Sopenharmony_ci   That is sizeof long. */
123da0c48c4Sopenharmony_cistatic bool
124da0c48c4Sopenharmony_ciread_cached_memory (struct __libdwfl_pid_arg *pid_arg,
125da0c48c4Sopenharmony_ci		    Dwarf_Addr addr, Dwarf_Word *result)
126da0c48c4Sopenharmony_ci{
127da0c48c4Sopenharmony_ci  /* Let the ptrace fallback deal with the corner case of the address
128da0c48c4Sopenharmony_ci     possibly crossing a page boundary.  */
129da0c48c4Sopenharmony_ci  if ((addr & ((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1))
130da0c48c4Sopenharmony_ci      > (Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - sizeof (unsigned long))
131da0c48c4Sopenharmony_ci    return false;
132da0c48c4Sopenharmony_ci
133da0c48c4Sopenharmony_ci  struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
134da0c48c4Sopenharmony_ci  if (mem_cache == NULL)
135da0c48c4Sopenharmony_ci    {
136da0c48c4Sopenharmony_ci      size_t mem_cache_size = sizeof (struct __libdwfl_remote_mem_cache);
137da0c48c4Sopenharmony_ci      mem_cache = malloc (mem_cache_size);
138da0c48c4Sopenharmony_ci      if (mem_cache == NULL)
139da0c48c4Sopenharmony_ci	return false;
140da0c48c4Sopenharmony_ci
141da0c48c4Sopenharmony_ci      mem_cache->addr = 0;
142da0c48c4Sopenharmony_ci      mem_cache->len = 0;
143da0c48c4Sopenharmony_ci      pid_arg->mem_cache = mem_cache;
144da0c48c4Sopenharmony_ci    }
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_ci  unsigned char *d;
147da0c48c4Sopenharmony_ci  if (addr >= mem_cache->addr && addr - mem_cache->addr < mem_cache->len)
148da0c48c4Sopenharmony_ci    {
149da0c48c4Sopenharmony_ci      d = &mem_cache->buf[addr - mem_cache->addr];
150da0c48c4Sopenharmony_ci      if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
151da0c48c4Sopenharmony_ci	*result = *(unsigned long *) d;
152da0c48c4Sopenharmony_ci      else
153da0c48c4Sopenharmony_ci	memcpy (result, d, sizeof (unsigned long));
154da0c48c4Sopenharmony_ci      return true;
155da0c48c4Sopenharmony_ci    }
156da0c48c4Sopenharmony_ci
157da0c48c4Sopenharmony_ci  struct iovec local, remote;
158da0c48c4Sopenharmony_ci  mem_cache->addr = addr & ~((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1);
159da0c48c4Sopenharmony_ci  local.iov_base = mem_cache->buf;
160da0c48c4Sopenharmony_ci  local.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
161da0c48c4Sopenharmony_ci  remote.iov_base = (void *) (uintptr_t) mem_cache->addr;
162da0c48c4Sopenharmony_ci  remote.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
163da0c48c4Sopenharmony_ci
164da0c48c4Sopenharmony_ci  ssize_t res = process_vm_readv (pid_arg->tid_attached,
165da0c48c4Sopenharmony_ci				  &local, 1, &remote, 1, 0);
166da0c48c4Sopenharmony_ci  if (res != __LIBDWFL_REMOTE_MEM_CACHE_SIZE)
167da0c48c4Sopenharmony_ci    {
168da0c48c4Sopenharmony_ci      mem_cache->len = 0;
169da0c48c4Sopenharmony_ci      return false;
170da0c48c4Sopenharmony_ci    }
171da0c48c4Sopenharmony_ci
172da0c48c4Sopenharmony_ci  mem_cache->len = res;
173da0c48c4Sopenharmony_ci  d = &mem_cache->buf[addr - mem_cache->addr];
174da0c48c4Sopenharmony_ci  if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
175da0c48c4Sopenharmony_ci    *result = *(unsigned long *) d;
176da0c48c4Sopenharmony_ci  else
177da0c48c4Sopenharmony_ci    memcpy (result, d, sizeof (unsigned long));
178da0c48c4Sopenharmony_ci  return true;
179da0c48c4Sopenharmony_ci}
180da0c48c4Sopenharmony_ci#endif /* HAVE_PROCESS_VM_READV */
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_cistatic void
183da0c48c4Sopenharmony_ciclear_cached_memory (struct __libdwfl_pid_arg *pid_arg)
184da0c48c4Sopenharmony_ci{
185da0c48c4Sopenharmony_ci  struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
186da0c48c4Sopenharmony_ci  if (mem_cache != NULL)
187da0c48c4Sopenharmony_ci    mem_cache->len = 0;
188da0c48c4Sopenharmony_ci}
189da0c48c4Sopenharmony_ci
190da0c48c4Sopenharmony_ci/* Note that the result word size depends on the architecture word size.
191da0c48c4Sopenharmony_ci   That is sizeof long. */
192da0c48c4Sopenharmony_cistatic bool
193da0c48c4Sopenharmony_cipid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
194da0c48c4Sopenharmony_ci{
195da0c48c4Sopenharmony_ci  struct __libdwfl_pid_arg *pid_arg = arg;
196da0c48c4Sopenharmony_ci  pid_t tid = pid_arg->tid_attached;
197da0c48c4Sopenharmony_ci  Dwfl_Process *process = dwfl->process;
198da0c48c4Sopenharmony_ci  assert (tid > 0);
199da0c48c4Sopenharmony_ci
200da0c48c4Sopenharmony_ci#ifdef HAVE_PROCESS_VM_READV
201da0c48c4Sopenharmony_ci  if (read_cached_memory (pid_arg, addr, result))
202da0c48c4Sopenharmony_ci    {
203da0c48c4Sopenharmony_ci#if SIZEOF_LONG == 8
204da0c48c4Sopenharmony_ci# if BYTE_ORDER == BIG_ENDIAN
205da0c48c4Sopenharmony_ci      if (ebl_get_elfclass (process->ebl) == ELFCLASS32)
206da0c48c4Sopenharmony_ci	*result >>= 32;
207da0c48c4Sopenharmony_ci# endif
208da0c48c4Sopenharmony_ci#endif
209da0c48c4Sopenharmony_ci    return true;
210da0c48c4Sopenharmony_ci    }
211da0c48c4Sopenharmony_ci#endif
212da0c48c4Sopenharmony_ci
213da0c48c4Sopenharmony_ci  if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
214da0c48c4Sopenharmony_ci    {
215da0c48c4Sopenharmony_ci#if SIZEOF_LONG == 8
216da0c48c4Sopenharmony_ci      errno = 0;
217da0c48c4Sopenharmony_ci      *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
218da0c48c4Sopenharmony_ci      return errno == 0;
219da0c48c4Sopenharmony_ci#else /* SIZEOF_LONG != 8 */
220da0c48c4Sopenharmony_ci      /* This should not happen.  */
221da0c48c4Sopenharmony_ci      return false;
222da0c48c4Sopenharmony_ci#endif /* SIZEOF_LONG != 8 */
223da0c48c4Sopenharmony_ci    }
224da0c48c4Sopenharmony_ci#if SIZEOF_LONG == 8
225da0c48c4Sopenharmony_ci  /* We do not care about reads unaliged to 4 bytes boundary.
226da0c48c4Sopenharmony_ci     But 0x...ffc read of 8 bytes could overrun a page.  */
227da0c48c4Sopenharmony_ci  bool lowered = (addr & 4) != 0;
228da0c48c4Sopenharmony_ci  if (lowered)
229da0c48c4Sopenharmony_ci    addr -= 4;
230da0c48c4Sopenharmony_ci#endif /* SIZEOF_LONG == 8 */
231da0c48c4Sopenharmony_ci  errno = 0;
232da0c48c4Sopenharmony_ci  *result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
233da0c48c4Sopenharmony_ci  if (errno != 0)
234da0c48c4Sopenharmony_ci    return false;
235da0c48c4Sopenharmony_ci#if SIZEOF_LONG == 8
236da0c48c4Sopenharmony_ci# if BYTE_ORDER == BIG_ENDIAN
237da0c48c4Sopenharmony_ci  if (! lowered)
238da0c48c4Sopenharmony_ci    *result >>= 32;
239da0c48c4Sopenharmony_ci# else
240da0c48c4Sopenharmony_ci  if (lowered)
241da0c48c4Sopenharmony_ci    *result >>= 32;
242da0c48c4Sopenharmony_ci# endif
243da0c48c4Sopenharmony_ci#endif /* SIZEOF_LONG == 8 */
244da0c48c4Sopenharmony_ci  *result &= 0xffffffff;
245da0c48c4Sopenharmony_ci  return true;
246da0c48c4Sopenharmony_ci}
247da0c48c4Sopenharmony_ci
248da0c48c4Sopenharmony_cistatic pid_t
249da0c48c4Sopenharmony_cipid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
250da0c48c4Sopenharmony_ci		 void **thread_argp)
251da0c48c4Sopenharmony_ci{
252da0c48c4Sopenharmony_ci  struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
253da0c48c4Sopenharmony_ci  struct dirent *dirent;
254da0c48c4Sopenharmony_ci  /* Start fresh on first traversal. */
255da0c48c4Sopenharmony_ci  if (*thread_argp == NULL)
256da0c48c4Sopenharmony_ci    rewinddir (pid_arg->dir);
257da0c48c4Sopenharmony_ci  do
258da0c48c4Sopenharmony_ci    {
259da0c48c4Sopenharmony_ci      errno = 0;
260da0c48c4Sopenharmony_ci      dirent = readdir (pid_arg->dir);
261da0c48c4Sopenharmony_ci      if (dirent == NULL)
262da0c48c4Sopenharmony_ci	{
263da0c48c4Sopenharmony_ci	  if (errno != 0)
264da0c48c4Sopenharmony_ci	    {
265da0c48c4Sopenharmony_ci	      __libdwfl_seterrno (DWFL_E_ERRNO);
266da0c48c4Sopenharmony_ci	      return -1;
267da0c48c4Sopenharmony_ci	    }
268da0c48c4Sopenharmony_ci	  return 0;
269da0c48c4Sopenharmony_ci	}
270da0c48c4Sopenharmony_ci    }
271da0c48c4Sopenharmony_ci  while (strcmp (dirent->d_name, ".") == 0
272da0c48c4Sopenharmony_ci	 || strcmp (dirent->d_name, "..") == 0);
273da0c48c4Sopenharmony_ci  char *end;
274da0c48c4Sopenharmony_ci  errno = 0;
275da0c48c4Sopenharmony_ci  long tidl = strtol (dirent->d_name, &end, 10);
276da0c48c4Sopenharmony_ci  if (errno != 0)
277da0c48c4Sopenharmony_ci    {
278da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_ERRNO);
279da0c48c4Sopenharmony_ci      return -1;
280da0c48c4Sopenharmony_ci    }
281da0c48c4Sopenharmony_ci  pid_t tid = tidl;
282da0c48c4Sopenharmony_ci  if (tidl <= 0 || (end && *end) || tid != tidl)
283da0c48c4Sopenharmony_ci    {
284da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_PARSE_PROC);
285da0c48c4Sopenharmony_ci      return -1;
286da0c48c4Sopenharmony_ci    }
287da0c48c4Sopenharmony_ci  *thread_argp = dwfl_arg;
288da0c48c4Sopenharmony_ci  return tid;
289da0c48c4Sopenharmony_ci}
290da0c48c4Sopenharmony_ci
291da0c48c4Sopenharmony_ci/* Just checks that the thread id exists.  */
292da0c48c4Sopenharmony_cistatic bool
293da0c48c4Sopenharmony_cipid_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid,
294da0c48c4Sopenharmony_ci	       void *dwfl_arg, void **thread_argp)
295da0c48c4Sopenharmony_ci{
296da0c48c4Sopenharmony_ci  *thread_argp = dwfl_arg;
297da0c48c4Sopenharmony_ci  if (kill (tid, 0) < 0)
298da0c48c4Sopenharmony_ci    {
299da0c48c4Sopenharmony_ci      __libdwfl_seterrno (DWFL_E_ERRNO);
300da0c48c4Sopenharmony_ci      return false;
301da0c48c4Sopenharmony_ci    }
302da0c48c4Sopenharmony_ci  return true;
303da0c48c4Sopenharmony_ci}
304da0c48c4Sopenharmony_ci
305da0c48c4Sopenharmony_ci/* Implement the ebl_set_initial_registers_tid setfunc callback.  */
306da0c48c4Sopenharmony_ci
307da0c48c4Sopenharmony_cistatic bool
308da0c48c4Sopenharmony_cipid_thread_state_registers_cb (int firstreg, unsigned nregs,
309da0c48c4Sopenharmony_ci			       const Dwarf_Word *regs, void *arg)
310da0c48c4Sopenharmony_ci{
311da0c48c4Sopenharmony_ci  Dwfl_Thread *thread = (Dwfl_Thread *) arg;
312da0c48c4Sopenharmony_ci  if (firstreg < 0)
313da0c48c4Sopenharmony_ci    {
314da0c48c4Sopenharmony_ci      assert (firstreg == -1);
315da0c48c4Sopenharmony_ci      assert (nregs == 1);
316da0c48c4Sopenharmony_ci      INTUSE(dwfl_thread_state_register_pc) (thread, *regs);
317da0c48c4Sopenharmony_ci      return true;
318da0c48c4Sopenharmony_ci    }
319da0c48c4Sopenharmony_ci  assert (nregs > 0);
320da0c48c4Sopenharmony_ci  return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
321da0c48c4Sopenharmony_ci}
322da0c48c4Sopenharmony_ci
323da0c48c4Sopenharmony_cistatic bool
324da0c48c4Sopenharmony_cipid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
325da0c48c4Sopenharmony_ci{
326da0c48c4Sopenharmony_ci  struct __libdwfl_pid_arg *pid_arg = thread_arg;
327da0c48c4Sopenharmony_ci  assert (pid_arg->tid_attached == 0);
328da0c48c4Sopenharmony_ci  pid_t tid = INTUSE(dwfl_thread_tid) (thread);
329da0c48c4Sopenharmony_ci  if (! pid_arg->assume_ptrace_stopped
330da0c48c4Sopenharmony_ci      && ! __libdwfl_ptrace_attach (tid, &pid_arg->tid_was_stopped))
331da0c48c4Sopenharmony_ci    return false;
332da0c48c4Sopenharmony_ci  pid_arg->tid_attached = tid;
333da0c48c4Sopenharmony_ci  Dwfl_Process *process = thread->process;
334da0c48c4Sopenharmony_ci  Ebl *ebl = process->ebl;
335da0c48c4Sopenharmony_ci  return ebl_set_initial_registers_tid (ebl, tid,
336da0c48c4Sopenharmony_ci					pid_thread_state_registers_cb, thread);
337da0c48c4Sopenharmony_ci}
338da0c48c4Sopenharmony_ci
339da0c48c4Sopenharmony_cistatic void
340da0c48c4Sopenharmony_cipid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
341da0c48c4Sopenharmony_ci{
342da0c48c4Sopenharmony_ci  struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
343da0c48c4Sopenharmony_ci  elf_end (pid_arg->elf);
344da0c48c4Sopenharmony_ci  free (pid_arg->mem_cache);
345da0c48c4Sopenharmony_ci  close (pid_arg->elf_fd);
346da0c48c4Sopenharmony_ci  closedir (pid_arg->dir);
347da0c48c4Sopenharmony_ci  free (pid_arg);
348da0c48c4Sopenharmony_ci}
349da0c48c4Sopenharmony_ci
350da0c48c4Sopenharmony_civoid
351da0c48c4Sopenharmony_ciinternal_function
352da0c48c4Sopenharmony_ci__libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped)
353da0c48c4Sopenharmony_ci{
354da0c48c4Sopenharmony_ci  /* This handling is needed only on older Linux kernels such as
355da0c48c4Sopenharmony_ci     2.6.32-358.23.2.el6.ppc64.  Later kernels such as
356da0c48c4Sopenharmony_ci     3.11.7-200.fc19.x86_64 remember the T (stopped) state
357da0c48c4Sopenharmony_ci     themselves and no longer need to pass SIGSTOP during
358da0c48c4Sopenharmony_ci     PTRACE_DETACH.  */
359da0c48c4Sopenharmony_ci  ptrace (PTRACE_DETACH, tid, NULL,
360da0c48c4Sopenharmony_ci	  (void *) (intptr_t) (tid_was_stopped ? SIGSTOP : 0));
361da0c48c4Sopenharmony_ci}
362da0c48c4Sopenharmony_ci
363da0c48c4Sopenharmony_cistatic void
364da0c48c4Sopenharmony_cipid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
365da0c48c4Sopenharmony_ci{
366da0c48c4Sopenharmony_ci  struct __libdwfl_pid_arg *pid_arg = thread_arg;
367da0c48c4Sopenharmony_ci  pid_t tid = INTUSE(dwfl_thread_tid) (thread);
368da0c48c4Sopenharmony_ci  assert (pid_arg->tid_attached == tid);
369da0c48c4Sopenharmony_ci  pid_arg->tid_attached = 0;
370da0c48c4Sopenharmony_ci  clear_cached_memory (pid_arg);
371da0c48c4Sopenharmony_ci  if (! pid_arg->assume_ptrace_stopped)
372da0c48c4Sopenharmony_ci    __libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped);
373da0c48c4Sopenharmony_ci}
374da0c48c4Sopenharmony_ci
375da0c48c4Sopenharmony_cistatic const Dwfl_Thread_Callbacks pid_thread_callbacks =
376da0c48c4Sopenharmony_ci{
377da0c48c4Sopenharmony_ci  pid_next_thread,
378da0c48c4Sopenharmony_ci  pid_getthread,
379da0c48c4Sopenharmony_ci  pid_memory_read,
380da0c48c4Sopenharmony_ci  pid_set_initial_registers,
381da0c48c4Sopenharmony_ci  pid_detach,
382da0c48c4Sopenharmony_ci  pid_thread_detach,
383da0c48c4Sopenharmony_ci};
384da0c48c4Sopenharmony_ci
385da0c48c4Sopenharmony_ciint
386da0c48c4Sopenharmony_cidwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped)
387da0c48c4Sopenharmony_ci{
388da0c48c4Sopenharmony_ci  char buffer[36];
389da0c48c4Sopenharmony_ci  FILE *procfile;
390da0c48c4Sopenharmony_ci  int err = 0; /* The errno to return and set for dwfl->attcherr.  */
391da0c48c4Sopenharmony_ci
392da0c48c4Sopenharmony_ci  /* Make sure to report the actual PID (thread group leader) to
393da0c48c4Sopenharmony_ci     dwfl_attach_state.  */
394da0c48c4Sopenharmony_ci  snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
395da0c48c4Sopenharmony_ci  procfile = fopen (buffer, "r");
396da0c48c4Sopenharmony_ci  if (procfile == NULL)
397da0c48c4Sopenharmony_ci    {
398da0c48c4Sopenharmony_ci      err = errno;
399da0c48c4Sopenharmony_ci    fail:
400da0c48c4Sopenharmony_ci      if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
401da0c48c4Sopenharmony_ci	{
402da0c48c4Sopenharmony_ci	  errno = err;
403da0c48c4Sopenharmony_ci	  dwfl->attacherr = __libdwfl_canon_error (DWFL_E_ERRNO);
404da0c48c4Sopenharmony_ci	}
405da0c48c4Sopenharmony_ci      return err;
406da0c48c4Sopenharmony_ci    }
407da0c48c4Sopenharmony_ci
408da0c48c4Sopenharmony_ci  char *line = NULL;
409da0c48c4Sopenharmony_ci  size_t linelen = 0;
410da0c48c4Sopenharmony_ci  while (getline (&line, &linelen, procfile) >= 0)
411da0c48c4Sopenharmony_ci    if (startswith (line, "Tgid:"))
412da0c48c4Sopenharmony_ci      {
413da0c48c4Sopenharmony_ci	errno = 0;
414da0c48c4Sopenharmony_ci	char *endptr;
415da0c48c4Sopenharmony_ci	long val = strtol (&line[5], &endptr, 10);
416da0c48c4Sopenharmony_ci	if ((errno == ERANGE && val == LONG_MAX)
417da0c48c4Sopenharmony_ci	    || *endptr != '\n' || val < 0 || val != (pid_t) val)
418da0c48c4Sopenharmony_ci	  pid = 0;
419da0c48c4Sopenharmony_ci	else
420da0c48c4Sopenharmony_ci	  pid = (pid_t) val;
421da0c48c4Sopenharmony_ci	break;
422da0c48c4Sopenharmony_ci      }
423da0c48c4Sopenharmony_ci  free (line);
424da0c48c4Sopenharmony_ci  fclose (procfile);
425da0c48c4Sopenharmony_ci
426da0c48c4Sopenharmony_ci  if (pid == 0)
427da0c48c4Sopenharmony_ci    {
428da0c48c4Sopenharmony_ci      err = ESRCH;
429da0c48c4Sopenharmony_ci      goto fail;
430da0c48c4Sopenharmony_ci    }
431da0c48c4Sopenharmony_ci
432da0c48c4Sopenharmony_ci  char name[64];
433da0c48c4Sopenharmony_ci  int i = snprintf (name, sizeof (name), "/proc/%ld/task", (long) pid);
434da0c48c4Sopenharmony_ci  if (i <= 0 || i >= (ssize_t) sizeof (name) - 1)
435da0c48c4Sopenharmony_ci    {
436da0c48c4Sopenharmony_ci      errno = -ENOMEM;
437da0c48c4Sopenharmony_ci      goto fail;
438da0c48c4Sopenharmony_ci    }
439da0c48c4Sopenharmony_ci  DIR *dir = opendir (name);
440da0c48c4Sopenharmony_ci  if (dir == NULL)
441da0c48c4Sopenharmony_ci    {
442da0c48c4Sopenharmony_ci      err = errno;
443da0c48c4Sopenharmony_ci      goto fail;
444da0c48c4Sopenharmony_ci    }
445da0c48c4Sopenharmony_ci
446da0c48c4Sopenharmony_ci  Elf *elf;
447da0c48c4Sopenharmony_ci  i = snprintf (name, sizeof (name), "/proc/%ld/exe", (long) pid);
448da0c48c4Sopenharmony_ci  assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
449da0c48c4Sopenharmony_ci  int elf_fd = open (name, O_RDONLY);
450da0c48c4Sopenharmony_ci  if (elf_fd >= 0)
451da0c48c4Sopenharmony_ci    {
452da0c48c4Sopenharmony_ci      elf = elf_begin (elf_fd, ELF_C_READ_MMAP, NULL);
453da0c48c4Sopenharmony_ci      if (elf == NULL)
454da0c48c4Sopenharmony_ci	{
455da0c48c4Sopenharmony_ci	  /* Just ignore, dwfl_attach_state will fall back to trying
456da0c48c4Sopenharmony_ci	     to associate the Dwfl with one of the existing DWfl_Module
457da0c48c4Sopenharmony_ci	     ELF images (to know the machine/class backend to use).  */
458da0c48c4Sopenharmony_ci	  close (elf_fd);
459da0c48c4Sopenharmony_ci	  elf_fd = -1;
460da0c48c4Sopenharmony_ci	}
461da0c48c4Sopenharmony_ci    }
462da0c48c4Sopenharmony_ci  else
463da0c48c4Sopenharmony_ci    elf = NULL;
464da0c48c4Sopenharmony_ci  struct __libdwfl_pid_arg *pid_arg = malloc (sizeof *pid_arg);
465da0c48c4Sopenharmony_ci  if (pid_arg == NULL)
466da0c48c4Sopenharmony_ci    {
467da0c48c4Sopenharmony_ci      elf_end (elf);
468da0c48c4Sopenharmony_ci      close (elf_fd);
469da0c48c4Sopenharmony_ci      closedir (dir);
470da0c48c4Sopenharmony_ci      err = ENOMEM;
471da0c48c4Sopenharmony_ci      goto fail;
472da0c48c4Sopenharmony_ci    }
473da0c48c4Sopenharmony_ci  pid_arg->dir = dir;
474da0c48c4Sopenharmony_ci  pid_arg->elf = elf;
475da0c48c4Sopenharmony_ci  pid_arg->elf_fd = elf_fd;
476da0c48c4Sopenharmony_ci  pid_arg->mem_cache = NULL;
477da0c48c4Sopenharmony_ci  pid_arg->tid_attached = 0;
478da0c48c4Sopenharmony_ci  pid_arg->assume_ptrace_stopped = assume_ptrace_stopped;
479da0c48c4Sopenharmony_ci  if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks,
480da0c48c4Sopenharmony_ci				   pid_arg))
481da0c48c4Sopenharmony_ci    {
482da0c48c4Sopenharmony_ci      elf_end (elf);
483da0c48c4Sopenharmony_ci      close (elf_fd);
484da0c48c4Sopenharmony_ci      closedir (dir);
485da0c48c4Sopenharmony_ci      free (pid_arg);
486da0c48c4Sopenharmony_ci      return -1;
487da0c48c4Sopenharmony_ci    }
488da0c48c4Sopenharmony_ci  return 0;
489da0c48c4Sopenharmony_ci}
490da0c48c4Sopenharmony_ciINTDEF (dwfl_linux_proc_attach)
491da0c48c4Sopenharmony_ci
492da0c48c4Sopenharmony_cistruct __libdwfl_pid_arg *
493da0c48c4Sopenharmony_ciinternal_function
494da0c48c4Sopenharmony_ci__libdwfl_get_pid_arg (Dwfl *dwfl)
495da0c48c4Sopenharmony_ci{
496da0c48c4Sopenharmony_ci  if (dwfl != NULL && dwfl->process != NULL
497da0c48c4Sopenharmony_ci      && dwfl->process->callbacks == &pid_thread_callbacks)
498da0c48c4Sopenharmony_ci    return (struct __libdwfl_pid_arg *) dwfl->process->callbacks_arg;
499da0c48c4Sopenharmony_ci
500da0c48c4Sopenharmony_ci  return NULL;
501da0c48c4Sopenharmony_ci}
502da0c48c4Sopenharmony_ci
503da0c48c4Sopenharmony_ci#else	/* __linux__ */
504da0c48c4Sopenharmony_ci
505da0c48c4Sopenharmony_cibool
506da0c48c4Sopenharmony_ciinternal_function
507da0c48c4Sopenharmony_ci__libdwfl_ptrace_attach (pid_t tid __attribute__ ((unused)),
508da0c48c4Sopenharmony_ci			 bool *tid_was_stoppedp __attribute__ ((unused)))
509da0c48c4Sopenharmony_ci{
510da0c48c4Sopenharmony_ci  errno = ENOSYS;
511da0c48c4Sopenharmony_ci  __libdwfl_seterrno (DWFL_E_ERRNO);
512da0c48c4Sopenharmony_ci  return false;
513da0c48c4Sopenharmony_ci}
514da0c48c4Sopenharmony_ci
515da0c48c4Sopenharmony_civoid
516da0c48c4Sopenharmony_ciinternal_function
517da0c48c4Sopenharmony_ci__libdwfl_ptrace_detach (pid_t tid __attribute__ ((unused)),
518da0c48c4Sopenharmony_ci			 bool tid_was_stopped __attribute__ ((unused)))
519da0c48c4Sopenharmony_ci{
520da0c48c4Sopenharmony_ci}
521da0c48c4Sopenharmony_ci
522da0c48c4Sopenharmony_ciint
523da0c48c4Sopenharmony_cidwfl_linux_proc_attach (Dwfl *dwfl __attribute__ ((unused)),
524da0c48c4Sopenharmony_ci			pid_t pid __attribute__ ((unused)),
525da0c48c4Sopenharmony_ci			bool assume_ptrace_stopped __attribute__ ((unused)))
526da0c48c4Sopenharmony_ci{
527da0c48c4Sopenharmony_ci  return ENOSYS;
528da0c48c4Sopenharmony_ci}
529da0c48c4Sopenharmony_ciINTDEF (dwfl_linux_proc_attach)
530da0c48c4Sopenharmony_ci
531da0c48c4Sopenharmony_cistruct __libdwfl_pid_arg *
532da0c48c4Sopenharmony_ciinternal_function
533da0c48c4Sopenharmony_ci__libdwfl_get_pid_arg (Dwfl *dwfl __attribute__ ((unused)))
534da0c48c4Sopenharmony_ci{
535da0c48c4Sopenharmony_ci  return NULL;
536da0c48c4Sopenharmony_ci}
537da0c48c4Sopenharmony_ci
538da0c48c4Sopenharmony_ci#endif /* ! __linux __ */
539da0c48c4Sopenharmony_ci
540