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