|
Packit Service |
97d2fb |
/* Get Dwarf Frame state for target live PID process.
|
|
Packit Service |
97d2fb |
Copyright (C) 2013, 2014, 2015, 2018 Red Hat, Inc.
|
|
Packit Service |
97d2fb |
This file is part of elfutils.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
This file is free software; you can redistribute it and/or modify
|
|
Packit Service |
97d2fb |
it under the terms of either
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
* the GNU Lesser General Public License as published by the Free
|
|
Packit Service |
97d2fb |
Software Foundation; either version 3 of the License, or (at
|
|
Packit Service |
97d2fb |
your option) any later version
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
or
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
* the GNU General Public License as published by the Free
|
|
Packit Service |
97d2fb |
Software Foundation; either version 2 of the License, or (at
|
|
Packit Service |
97d2fb |
your option) any later version
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
or both in parallel, as here.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
elfutils is distributed in the hope that it will be useful, but
|
|
Packit Service |
97d2fb |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
97d2fb |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
97d2fb |
General Public License for more details.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
You should have received copies of the GNU General Public License and
|
|
Packit Service |
97d2fb |
the GNU Lesser General Public License along with this program. If
|
|
Packit Service |
97d2fb |
not, see <http://www.gnu.org/licenses/>. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
97d2fb |
# include <config.h>
|
|
Packit Service |
97d2fb |
#endif
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include "libelfP.h"
|
|
Packit Service |
97d2fb |
#include "libdwflP.h"
|
|
Packit Service |
97d2fb |
#include <sys/types.h>
|
|
Packit Service |
97d2fb |
#include <sys/stat.h>
|
|
Packit Service |
97d2fb |
#include <fcntl.h>
|
|
Packit Service |
97d2fb |
#include <dirent.h>
|
|
Packit Service |
97d2fb |
#include <unistd.h>
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef __linux__
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include <sys/uio.h>
|
|
Packit Service |
97d2fb |
#include <sys/ptrace.h>
|
|
Packit Service |
97d2fb |
#include <sys/syscall.h>
|
|
Packit Service |
97d2fb |
#include <sys/wait.h>
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
linux_proc_pid_is_stopped (pid_t pid)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
char buffer[64];
|
|
Packit Service |
97d2fb |
FILE *procfile;
|
|
Packit Service |
97d2fb |
bool retval, have_state;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
|
|
Packit Service |
97d2fb |
procfile = fopen (buffer, "r");
|
|
Packit Service |
97d2fb |
if (procfile == NULL)
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
have_state = false;
|
|
Packit Service |
97d2fb |
while (fgets (buffer, sizeof (buffer), procfile) != NULL)
|
|
Packit Service |
97d2fb |
if (strncmp (buffer, "State:", 6) == 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
have_state = true;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
retval = (have_state && strstr (buffer, "T (stopped)") != NULL);
|
|
Packit Service |
97d2fb |
fclose (procfile);
|
|
Packit Service |
97d2fb |
return retval;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
bool
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_ptrace_attach (pid_t tid, bool *tid_was_stoppedp)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (ptrace (PTRACE_ATTACH, tid, NULL, NULL) != 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
*tid_was_stoppedp = linux_proc_pid_is_stopped (tid);
|
|
Packit Service |
97d2fb |
if (*tid_was_stoppedp)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Make sure there is a SIGSTOP signal pending even when the process is
|
|
Packit Service |
97d2fb |
already State: T (stopped). Older kernels might fail to generate
|
|
Packit Service |
97d2fb |
a SIGSTOP notification in that case in response to our PTRACE_ATTACH
|
|
Packit Service |
97d2fb |
above. Which would make the waitpid below wait forever. So emulate
|
|
Packit Service |
97d2fb |
it. Since there can only be one SIGSTOP notification pending this is
|
|
Packit Service |
97d2fb |
safe. See also gdb/linux-nat.c linux_nat_post_attach_wait. */
|
|
Packit Service |
97d2fb |
syscall (__NR_tkill, tid, SIGSTOP);
|
|
Packit Service |
97d2fb |
ptrace (PTRACE_CONT, tid, NULL, NULL);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
for (;;)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
int status;
|
|
Packit Service |
97d2fb |
if (waitpid (tid, &status, __WALL) != tid || !WIFSTOPPED (status))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
int saved_errno = errno;
|
|
Packit Service |
97d2fb |
ptrace (PTRACE_DETACH, tid, NULL, NULL);
|
|
Packit Service |
97d2fb |
errno = saved_errno;
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
if (WSTOPSIG (status) == SIGSTOP)
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
if (ptrace (PTRACE_CONT, tid, NULL,
|
|
Packit Service |
97d2fb |
(void *) (uintptr_t) WSTOPSIG (status)) != 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
int saved_errno = errno;
|
|
Packit Service |
97d2fb |
ptrace (PTRACE_DETACH, tid, NULL, NULL);
|
|
Packit Service |
97d2fb |
errno = saved_errno;
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef HAVE_PROCESS_VM_READV
|
|
Packit Service |
97d2fb |
/* Note that the result word size depends on the architecture word size.
|
|
Packit Service |
97d2fb |
That is sizeof long. */
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
read_cached_memory (struct __libdwfl_pid_arg *pid_arg,
|
|
Packit Service |
97d2fb |
Dwarf_Addr addr, Dwarf_Word *result)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Let the ptrace fallback deal with the corner case of the address
|
|
Packit Service |
97d2fb |
possibly crossing a page boundery. */
|
|
Packit Service |
97d2fb |
if ((addr & ((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1))
|
|
Packit Service |
97d2fb |
> (Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - sizeof (unsigned long))
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
|
|
Packit Service |
97d2fb |
if (mem_cache == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
size_t mem_cache_size = sizeof (struct __libdwfl_remote_mem_cache);
|
|
Packit Service |
97d2fb |
mem_cache = (struct __libdwfl_remote_mem_cache *) malloc (mem_cache_size);
|
|
Packit Service |
97d2fb |
if (mem_cache == NULL)
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
mem_cache->addr = 0;
|
|
Packit Service |
97d2fb |
mem_cache->len = 0;
|
|
Packit Service |
97d2fb |
pid_arg->mem_cache = mem_cache;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
unsigned char *d;
|
|
Packit Service |
97d2fb |
if (addr >= mem_cache->addr && addr - mem_cache->addr < mem_cache->len)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
d = &mem_cache->buf[addr - mem_cache->addr];
|
|
Packit Service |
97d2fb |
if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
|
|
Packit Service |
97d2fb |
*result = *(unsigned long *) d;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
memcpy (result, d, sizeof (unsigned long));
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct iovec local, remote;
|
|
Packit Service |
97d2fb |
mem_cache->addr = addr & ~((Dwarf_Addr)__LIBDWFL_REMOTE_MEM_CACHE_SIZE - 1);
|
|
Packit Service |
97d2fb |
local.iov_base = mem_cache->buf;
|
|
Packit Service |
97d2fb |
local.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
|
|
Packit Service |
97d2fb |
remote.iov_base = (void *) (uintptr_t) mem_cache->addr;
|
|
Packit Service |
97d2fb |
remote.iov_len = __LIBDWFL_REMOTE_MEM_CACHE_SIZE;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
ssize_t res = process_vm_readv (pid_arg->tid_attached,
|
|
Packit Service |
97d2fb |
&local, 1, &remote, 1, 0);
|
|
Packit Service |
97d2fb |
if (res != __LIBDWFL_REMOTE_MEM_CACHE_SIZE)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
mem_cache->len = 0;
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
mem_cache->len = res;
|
|
Packit Service |
97d2fb |
d = &mem_cache->buf[addr - mem_cache->addr];
|
|
Packit Service |
97d2fb |
if ((((uintptr_t) d) & (sizeof (unsigned long) - 1)) == 0)
|
|
Packit Service |
97d2fb |
*result = *(unsigned long *) d;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
memcpy (result, d, sizeof (unsigned long));
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
#endif /* HAVE_PROCESS_VM_READV */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static void
|
|
Packit Service |
97d2fb |
clear_cached_memory (struct __libdwfl_pid_arg *pid_arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct __libdwfl_remote_mem_cache *mem_cache = pid_arg->mem_cache;
|
|
Packit Service |
97d2fb |
if (mem_cache != NULL)
|
|
Packit Service |
97d2fb |
mem_cache->len = 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Note that the result word size depends on the architecture word size.
|
|
Packit Service |
97d2fb |
That is sizeof long. */
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
pid_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *pid_arg = arg;
|
|
Packit Service |
97d2fb |
pid_t tid = pid_arg->tid_attached;
|
|
Packit Service |
97d2fb |
assert (tid > 0);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef HAVE_PROCESS_VM_READV
|
|
Packit Service |
97d2fb |
if (read_cached_memory (pid_arg, addr, result))
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
#endif
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Dwfl_Process *process = dwfl->process;
|
|
Packit Service |
97d2fb |
if (ebl_get_elfclass (process->ebl) == ELFCLASS64)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
#if SIZEOF_LONG == 8
|
|
Packit Service |
97d2fb |
errno = 0;
|
|
Packit Service |
97d2fb |
*result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
|
|
Packit Service |
97d2fb |
return errno == 0;
|
|
Packit Service |
97d2fb |
#else /* SIZEOF_LONG != 8 */
|
|
Packit Service |
97d2fb |
/* This should not happen. */
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
#endif /* SIZEOF_LONG != 8 */
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
#if SIZEOF_LONG == 8
|
|
Packit Service |
97d2fb |
/* We do not care about reads unaliged to 4 bytes boundary.
|
|
Packit Service |
97d2fb |
But 0x...ffc read of 8 bytes could overrun a page. */
|
|
Packit Service |
97d2fb |
bool lowered = (addr & 4) != 0;
|
|
Packit Service |
97d2fb |
if (lowered)
|
|
Packit Service |
97d2fb |
addr -= 4;
|
|
Packit Service |
97d2fb |
#endif /* SIZEOF_LONG == 8 */
|
|
Packit Service |
97d2fb |
errno = 0;
|
|
Packit Service |
97d2fb |
*result = ptrace (PTRACE_PEEKDATA, tid, (void *) (uintptr_t) addr, NULL);
|
|
Packit Service |
97d2fb |
if (errno != 0)
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
#if SIZEOF_LONG == 8
|
|
Packit Service |
97d2fb |
# if BYTE_ORDER == BIG_ENDIAN
|
|
Packit Service |
97d2fb |
if (! lowered)
|
|
Packit Service |
97d2fb |
*result >>= 32;
|
|
Packit Service |
97d2fb |
# else
|
|
Packit Service |
97d2fb |
if (lowered)
|
|
Packit Service |
97d2fb |
*result >>= 32;
|
|
Packit Service |
97d2fb |
# endif
|
|
Packit Service |
97d2fb |
#endif /* SIZEOF_LONG == 8 */
|
|
Packit Service |
97d2fb |
*result &= 0xffffffff;
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static pid_t
|
|
Packit Service |
97d2fb |
pid_next_thread (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg,
|
|
Packit Service |
97d2fb |
void **thread_argp)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
|
|
Packit Service |
97d2fb |
struct dirent *dirent;
|
|
Packit Service |
97d2fb |
/* Start fresh on first traversal. */
|
|
Packit Service |
97d2fb |
if (*thread_argp == NULL)
|
|
Packit Service |
97d2fb |
rewinddir (pid_arg->dir);
|
|
Packit Service |
97d2fb |
do
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
errno = 0;
|
|
Packit Service |
97d2fb |
dirent = readdir (pid_arg->dir);
|
|
Packit Service |
97d2fb |
if (dirent == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (errno != 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return -1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
while (strcmp (dirent->d_name, ".") == 0
|
|
Packit Service |
97d2fb |
|| strcmp (dirent->d_name, "..") == 0);
|
|
Packit Service |
97d2fb |
char *end;
|
|
Packit Service |
97d2fb |
errno = 0;
|
|
Packit Service |
97d2fb |
long tidl = strtol (dirent->d_name, &end, 10);
|
|
Packit Service |
97d2fb |
if (errno != 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return -1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
pid_t tid = tidl;
|
|
Packit Service |
97d2fb |
if (tidl <= 0 || (end && *end) || tid != tidl)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_PARSE_PROC);
|
|
Packit Service |
97d2fb |
return -1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
*thread_argp = dwfl_arg;
|
|
Packit Service |
97d2fb |
return tid;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Just checks that the thread id exists. */
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
pid_getthread (Dwfl *dwfl __attribute__ ((unused)), pid_t tid,
|
|
Packit Service |
97d2fb |
void *dwfl_arg, void **thread_argp)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
*thread_argp = dwfl_arg;
|
|
Packit Service |
97d2fb |
if (kill (tid, 0) < 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Implement the ebl_set_initial_registers_tid setfunc callback. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
pid_thread_state_registers_cb (int firstreg, unsigned nregs,
|
|
Packit Service |
97d2fb |
const Dwarf_Word *regs, void *arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Dwfl_Thread *thread = (Dwfl_Thread *) arg;
|
|
Packit Service |
97d2fb |
if (firstreg < 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
assert (firstreg == -1);
|
|
Packit Service |
97d2fb |
assert (nregs == 1);
|
|
Packit Service |
97d2fb |
INTUSE(dwfl_thread_state_register_pc) (thread, *regs);
|
|
Packit Service |
97d2fb |
return true;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
assert (nregs > 0);
|
|
Packit Service |
97d2fb |
return INTUSE(dwfl_thread_state_registers) (thread, firstreg, nregs, regs);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static bool
|
|
Packit Service |
97d2fb |
pid_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *pid_arg = thread_arg;
|
|
Packit Service |
97d2fb |
assert (pid_arg->tid_attached == 0);
|
|
Packit Service |
97d2fb |
pid_t tid = INTUSE(dwfl_thread_tid) (thread);
|
|
Packit Service |
97d2fb |
if (! pid_arg->assume_ptrace_stopped
|
|
Packit Service |
97d2fb |
&& ! __libdwfl_ptrace_attach (tid, &pid_arg->tid_was_stopped))
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
pid_arg->tid_attached = tid;
|
|
Packit Service |
97d2fb |
Dwfl_Process *process = thread->process;
|
|
Packit Service |
97d2fb |
Ebl *ebl = process->ebl;
|
|
Packit Service |
97d2fb |
return ebl_set_initial_registers_tid (ebl, tid,
|
|
Packit Service |
97d2fb |
pid_thread_state_registers_cb, thread);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static void
|
|
Packit Service |
97d2fb |
pid_detach (Dwfl *dwfl __attribute__ ((unused)), void *dwfl_arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *pid_arg = dwfl_arg;
|
|
Packit Service |
97d2fb |
elf_end (pid_arg->elf);
|
|
Packit Service |
97d2fb |
free (pid_arg->mem_cache);
|
|
Packit Service |
97d2fb |
close (pid_arg->elf_fd);
|
|
Packit Service |
97d2fb |
closedir (pid_arg->dir);
|
|
Packit Service |
97d2fb |
free (pid_arg);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
void
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_ptrace_detach (pid_t tid, bool tid_was_stopped)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* This handling is needed only on older Linux kernels such as
|
|
Packit Service |
97d2fb |
2.6.32-358.23.2.el6.ppc64. Later kernels such as
|
|
Packit Service |
97d2fb |
3.11.7-200.fc19.x86_64 remember the T (stopped) state
|
|
Packit Service |
97d2fb |
themselves and no longer need to pass SIGSTOP during
|
|
Packit Service |
97d2fb |
PTRACE_DETACH. */
|
|
Packit Service |
97d2fb |
ptrace (PTRACE_DETACH, tid, NULL,
|
|
Packit Service |
97d2fb |
(void *) (intptr_t) (tid_was_stopped ? SIGSTOP : 0));
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static void
|
|
Packit Service |
97d2fb |
pid_thread_detach (Dwfl_Thread *thread, void *thread_arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *pid_arg = thread_arg;
|
|
Packit Service |
97d2fb |
pid_t tid = INTUSE(dwfl_thread_tid) (thread);
|
|
Packit Service |
97d2fb |
assert (pid_arg->tid_attached == tid);
|
|
Packit Service |
97d2fb |
pid_arg->tid_attached = 0;
|
|
Packit Service |
97d2fb |
clear_cached_memory (pid_arg);
|
|
Packit Service |
97d2fb |
if (! pid_arg->assume_ptrace_stopped)
|
|
Packit Service |
97d2fb |
__libdwfl_ptrace_detach (tid, pid_arg->tid_was_stopped);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static const Dwfl_Thread_Callbacks pid_thread_callbacks =
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
pid_next_thread,
|
|
Packit Service |
97d2fb |
pid_getthread,
|
|
Packit Service |
97d2fb |
pid_memory_read,
|
|
Packit Service |
97d2fb |
pid_set_initial_registers,
|
|
Packit Service |
97d2fb |
pid_detach,
|
|
Packit Service |
97d2fb |
pid_thread_detach,
|
|
Packit Service |
97d2fb |
};
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
int
|
|
Packit Service |
97d2fb |
dwfl_linux_proc_attach (Dwfl *dwfl, pid_t pid, bool assume_ptrace_stopped)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
char buffer[36];
|
|
Packit Service |
97d2fb |
FILE *procfile;
|
|
Packit Service |
97d2fb |
int err = 0; /* The errno to return and set for dwfl->attcherr. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Make sure to report the actual PID (thread group leader) to
|
|
Packit Service |
97d2fb |
dwfl_attach_state. */
|
|
Packit Service |
97d2fb |
snprintf (buffer, sizeof (buffer), "/proc/%ld/status", (long) pid);
|
|
Packit Service |
97d2fb |
procfile = fopen (buffer, "r");
|
|
Packit Service |
97d2fb |
if (procfile == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
err = errno;
|
|
Packit Service |
97d2fb |
fail:
|
|
Packit Service |
97d2fb |
if (dwfl->process == NULL && dwfl->attacherr == DWFL_E_NOERROR)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
errno = err;
|
|
Packit Service |
97d2fb |
dwfl->attacherr = __libdwfl_canon_error (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return err;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
char *line = NULL;
|
|
Packit Service |
97d2fb |
size_t linelen = 0;
|
|
Packit Service |
97d2fb |
while (getline (&line, &linelen, procfile) >= 0)
|
|
Packit Service |
97d2fb |
if (strncmp (line, "Tgid:", 5) == 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
errno = 0;
|
|
Packit Service |
97d2fb |
char *endptr;
|
|
Packit Service |
97d2fb |
long val = strtol (&line[5], &endptr, 10);
|
|
Packit Service |
97d2fb |
if ((errno == ERANGE && val == LONG_MAX)
|
|
Packit Service |
97d2fb |
|| *endptr != '\n' || val < 0 || val != (pid_t) val)
|
|
Packit Service |
97d2fb |
pid = 0;
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
pid = (pid_t) val;
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
free (line);
|
|
Packit Service |
97d2fb |
fclose (procfile);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (pid == 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
err = ESRCH;
|
|
Packit Service |
97d2fb |
goto fail;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
char name[64];
|
|
Packit Service |
97d2fb |
int i = snprintf (name, sizeof (name), "/proc/%ld/task", (long) pid);
|
|
Packit Service |
97d2fb |
if (i <= 0 || i >= (ssize_t) sizeof (name) - 1)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
errno = -ENOMEM;
|
|
Packit Service |
97d2fb |
goto fail;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
DIR *dir = opendir (name);
|
|
Packit Service |
97d2fb |
if (dir == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
err = errno;
|
|
Packit Service |
97d2fb |
goto fail;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Elf *elf;
|
|
Packit Service |
97d2fb |
i = snprintf (name, sizeof (name), "/proc/%ld/exe", (long) pid);
|
|
Packit Service |
97d2fb |
assert (i > 0 && i < (ssize_t) sizeof (name) - 1);
|
|
Packit Service |
97d2fb |
int elf_fd = open (name, O_RDONLY);
|
|
Packit Service |
97d2fb |
if (elf_fd >= 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
elf = elf_begin (elf_fd, ELF_C_READ_MMAP, NULL);
|
|
Packit Service |
97d2fb |
if (elf == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Just ignore, dwfl_attach_state will fall back to trying
|
|
Packit Service |
97d2fb |
to associate the Dwfl with one of the existing DWfl_Module
|
|
Packit Service |
97d2fb |
ELF images (to know the machine/class backend to use). */
|
|
Packit Service |
97d2fb |
close (elf_fd);
|
|
Packit Service |
97d2fb |
elf_fd = -1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
elf = NULL;
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *pid_arg = malloc (sizeof *pid_arg);
|
|
Packit Service |
97d2fb |
if (pid_arg == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
elf_end (elf);
|
|
Packit Service |
97d2fb |
close (elf_fd);
|
|
Packit Service |
97d2fb |
closedir (dir);
|
|
Packit Service |
97d2fb |
err = ENOMEM;
|
|
Packit Service |
97d2fb |
goto fail;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
pid_arg->dir = dir;
|
|
Packit Service |
97d2fb |
pid_arg->elf = elf;
|
|
Packit Service |
97d2fb |
pid_arg->elf_fd = elf_fd;
|
|
Packit Service |
97d2fb |
pid_arg->mem_cache = NULL;
|
|
Packit Service |
97d2fb |
pid_arg->tid_attached = 0;
|
|
Packit Service |
97d2fb |
pid_arg->assume_ptrace_stopped = assume_ptrace_stopped;
|
|
Packit Service |
97d2fb |
if (! INTUSE(dwfl_attach_state) (dwfl, elf, pid, &pid_thread_callbacks,
|
|
Packit Service |
97d2fb |
pid_arg))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
elf_end (elf);
|
|
Packit Service |
97d2fb |
close (elf_fd);
|
|
Packit Service |
97d2fb |
closedir (dir);
|
|
Packit Service |
97d2fb |
free (pid_arg);
|
|
Packit Service |
97d2fb |
return -1;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
return 0;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
INTDEF (dwfl_linux_proc_attach)
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_get_pid_arg (Dwfl *dwfl)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (dwfl != NULL && dwfl->process != NULL
|
|
Packit Service |
97d2fb |
&& dwfl->process->callbacks == &pid_thread_callbacks)
|
|
Packit Service |
97d2fb |
return (struct __libdwfl_pid_arg *) dwfl->process->callbacks_arg;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
return NULL;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#else /* __linux__ */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
bool
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_ptrace_attach (pid_t tid __attribute__ ((unused)),
|
|
Packit Service |
97d2fb |
bool *tid_was_stoppedp __attribute__ ((unused)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
errno = ENOSYS;
|
|
Packit Service |
97d2fb |
__libdwfl_seterrno (DWFL_E_ERRNO);
|
|
Packit Service |
97d2fb |
return false;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
void
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_ptrace_detach (pid_t tid __attribute__ ((unused)),
|
|
Packit Service |
97d2fb |
bool tid_was_stopped __attribute__ ((unused)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
int
|
|
Packit Service |
97d2fb |
dwfl_linux_proc_attach (Dwfl *dwfl __attribute__ ((unused)),
|
|
Packit Service |
97d2fb |
pid_t pid __attribute__ ((unused)),
|
|
Packit Service |
97d2fb |
bool assume_ptrace_stopped __attribute__ ((unused)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
return ENOSYS;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
INTDEF (dwfl_linux_proc_attach)
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct __libdwfl_pid_arg *
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_get_pid_arg (Dwfl *dwfl __attribute__ ((unused)))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
return NULL;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#endif /* ! __linux __ */
|
|
Packit Service |
97d2fb |
|