New version of libproc. Changes are:
* breakpoint setup support * register query * symbol to address mapping and vice-versa * more misc utility functions based on their Solaris counterpart Also, I've written some test cases. Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
4579930d2e
commit
8eb20f364f
@ -2,9 +2,11 @@
|
||||
|
||||
LIB= proc
|
||||
|
||||
SRCS= \
|
||||
SRCS= proc_bkpt.c \
|
||||
proc_create.c \
|
||||
proc_regs.c \
|
||||
proc_sym.c \
|
||||
proc_rtld.c \
|
||||
proc_util.c
|
||||
|
||||
INCS= libproc.h
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <rtld_db.h>
|
||||
|
||||
#include "libproc.h"
|
||||
|
||||
@ -39,5 +40,16 @@ struct proc_handle {
|
||||
int kq; /* Kernel event queue ID. */
|
||||
int flags; /* Process flags. */
|
||||
int status; /* Process status (PS_*). */
|
||||
int wstat; /* Process wait status. */
|
||||
rd_agent_t *rdap; /* librtld_db agent */
|
||||
rd_loadobj_t *rdobjs;
|
||||
size_t rdobjsz;
|
||||
size_t nobjs;
|
||||
struct lwpstatus lwps;
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINTF(fmt, ...) warn(fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
@ -1,7 +1,11 @@
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* Copyright (c) 2008 John Birrell (jb@freebsd.org)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Rui Paulo under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -30,6 +34,8 @@
|
||||
#define _LIBPROC_H_
|
||||
|
||||
#include <gelf.h>
|
||||
#include <rtld_db.h>
|
||||
#include <limits.h>
|
||||
|
||||
struct proc_handle;
|
||||
|
||||
@ -43,30 +49,100 @@ typedef void (*proc_child_func)(void *);
|
||||
#define PS_DEAD 5
|
||||
#define PS_LOST 6
|
||||
|
||||
/* Reason values for proc_detach(). */
|
||||
#define PRELEASE_HANG 1
|
||||
#define PRELEASE_KILL 2
|
||||
|
||||
typedef struct prmap {
|
||||
uintptr_t pr_vaddr; /* Virtual address. */
|
||||
size_t pr_size; /* Mapping size in bytes */
|
||||
size_t pr_offset; /* Mapping offset in object */
|
||||
char pr_mapname[PATH_MAX]; /* Mapping filename */
|
||||
uint8_t pr_mflags; /* Protection flags */
|
||||
#define MA_READ 0x01
|
||||
#define MA_WRITE 0x02
|
||||
#define MA_EXEC 0x04
|
||||
#define MA_COW 0x08
|
||||
#define MA_NEEDS_COPY 0x10
|
||||
#define MA_NOCOREDUMP 0x20
|
||||
} prmap_t;
|
||||
|
||||
typedef int proc_map_f(void *, const prmap_t *, const char *);
|
||||
typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
|
||||
|
||||
/* Values for ELF sections */
|
||||
#define PR_SYMTAB 1
|
||||
#define PR_DYNSYM 2
|
||||
|
||||
/* Values for the 'mask' parameter in the iteration functions */
|
||||
#define BIND_LOCAL 0x0001
|
||||
#define BIND_GLOBAL 0x0002
|
||||
#define BIND_WEAK 0x0004
|
||||
#define BIND_ANY (BIND_LOCAL|BIND_GLOBAL|BIND_WEAK)
|
||||
#define TYPE_NOTYPE 0x0100
|
||||
#define TYPE_OBJECT 0x0200
|
||||
#define TYPE_FUNC 0x0400
|
||||
#define TYPE_SECTION 0x0800
|
||||
#define TYPE_FILE 0x1000
|
||||
#define TYPE_ANY (TYPE_NOTYPE|TYPE_OBJECT|TYPE_FUNC|TYPE_SECTION|\
|
||||
TYPE_FILE)
|
||||
|
||||
typedef enum {
|
||||
REG_PC,
|
||||
REG_SP,
|
||||
REG_RVAL1,
|
||||
REG_RVAL2
|
||||
} proc_reg_t;
|
||||
|
||||
#define SIG2STR_MAX 8
|
||||
|
||||
typedef struct lwpstatus {
|
||||
int pr_why;
|
||||
#define PR_REQUESTED 1
|
||||
#define PR_FAULTED 2
|
||||
#define PR_SYSENTRY 3
|
||||
#define PR_SYSEXIT 4
|
||||
int pr_what;
|
||||
#define FLTBPT -1
|
||||
} lwpstatus_t;
|
||||
|
||||
/* Function prototype definitions. */
|
||||
__BEGIN_DECLS
|
||||
|
||||
const prmap_t *proc_addr2map(struct proc_handle *, uintptr_t);
|
||||
const prmap_t *proc_name2map(struct proc_handle *, const char *);
|
||||
prmap_t *proc_addr2map(struct proc_handle *, uintptr_t);
|
||||
prmap_t *proc_name2map(struct proc_handle *, const char *);
|
||||
char *proc_objname(struct proc_handle *, uintptr_t, char *, size_t);
|
||||
prmap_t *proc_obj2map(struct proc_handle *, const char *);
|
||||
int proc_iter_objs(struct proc_handle *, proc_map_f *, void *);
|
||||
int proc_iter_symbyaddr(struct proc_handle *, const char *, int,
|
||||
int, proc_sym_f *, void *);
|
||||
int proc_addr2sym(struct proc_handle *, uintptr_t, char *, size_t, GElf_Sym *);
|
||||
int proc_attach(pid_t pid, int flags, struct proc_handle **pphdl);
|
||||
int proc_continue(struct proc_handle *);
|
||||
int proc_clearflags(struct proc_handle *, int);
|
||||
int proc_create(const char *, char * const *, proc_child_func *, void *,
|
||||
struct proc_handle **);
|
||||
int proc_detach(struct proc_handle *);
|
||||
int proc_detach(struct proc_handle *, int);
|
||||
int proc_getflags(struct proc_handle *);
|
||||
int proc_name2sym(struct proc_handle *, const char *, const char *, GElf_Sym *);
|
||||
int proc_setflags(struct proc_handle *, int);
|
||||
int proc_state(struct proc_handle *);
|
||||
int proc_wait(struct proc_handle *);
|
||||
pid_t proc_getpid(struct proc_handle *);
|
||||
int proc_wstatus(struct proc_handle *);
|
||||
int proc_getwstat(struct proc_handle *);
|
||||
char * proc_signame(int, char *, size_t);
|
||||
int proc_read(struct proc_handle *, char *, size_t, size_t);
|
||||
const lwpstatus_t *
|
||||
proc_getlwpstatus(struct proc_handle *);
|
||||
void proc_free(struct proc_handle *);
|
||||
rd_agent_t *proc_rdagent(struct proc_handle *);
|
||||
void proc_updatesyms(struct proc_handle *);
|
||||
int proc_bkptset(struct proc_handle *, uintptr_t, unsigned long *);
|
||||
int proc_bkptdel(struct proc_handle *, uintptr_t, unsigned long);
|
||||
void proc_bkptregadj(unsigned long *);
|
||||
int proc_bkptexec(struct proc_handle *, unsigned long);
|
||||
int proc_regget(struct proc_handle *, proc_reg_t, unsigned long *);
|
||||
int proc_regset(struct proc_handle *, proc_reg_t, unsigned long);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
183
lib/libproc/proc_bkpt.c
Normal file
183
lib/libproc/proc_bkpt.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Rui Paulo under sponsorship from the
|
||||
* FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <machine/_inttypes.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include "_libproc.h"
|
||||
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
#define BREAKPOINT_INSTR 0xcc /* int 0x3 */
|
||||
#define BREAKPOINT_INSTR_SZ 1
|
||||
#else
|
||||
#error "Add support for your architecture"
|
||||
#endif
|
||||
|
||||
int
|
||||
proc_bkptset(struct proc_handle *phdl, uintptr_t address,
|
||||
unsigned long *saved)
|
||||
{
|
||||
struct ptrace_io_desc piod;
|
||||
unsigned long paddr, caddr;
|
||||
|
||||
*saved = 0;
|
||||
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
|
||||
phdl->status == PS_IDLE) {
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the original instruction.
|
||||
*/
|
||||
caddr = address;
|
||||
paddr = 0;
|
||||
piod.piod_op = PIOD_READ_I;
|
||||
piod.piod_offs = (void *)caddr;
|
||||
piod.piod_addr = &paddr;
|
||||
piod.piod_len = BREAKPOINT_INSTR_SZ;
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
|
||||
DPRINTF("ERROR: couldn't read instruction at address 0x%" PRIuPTR,
|
||||
address);
|
||||
return (-1);
|
||||
}
|
||||
*saved = paddr;
|
||||
/*
|
||||
* Write a breakpoint instruction to that address.
|
||||
*/
|
||||
caddr = address;
|
||||
paddr = BREAKPOINT_INSTR;
|
||||
piod.piod_op = PIOD_WRITE_I;
|
||||
piod.piod_offs = (void *)caddr;
|
||||
piod.piod_addr = &paddr;
|
||||
piod.piod_len = BREAKPOINT_INSTR_SZ;
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
|
||||
warn("ERROR: couldn't write instruction at address 0x%" PRIuPTR,
|
||||
address);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
proc_bkptdel(struct proc_handle *phdl, uintptr_t address,
|
||||
unsigned long saved)
|
||||
{
|
||||
struct ptrace_io_desc piod;
|
||||
unsigned long paddr, caddr;
|
||||
|
||||
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
|
||||
phdl->status == PS_IDLE) {
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
DPRINTF("removing breakpoint at 0x%lx\n", address);
|
||||
/*
|
||||
* Overwrite the breakpoint instruction that we setup previously.
|
||||
*/
|
||||
caddr = address;
|
||||
paddr = saved;
|
||||
piod.piod_op = PIOD_WRITE_I;
|
||||
piod.piod_offs = (void *)caddr;
|
||||
piod.piod_addr = &paddr;
|
||||
piod.piod_len = BREAKPOINT_INSTR_SZ;
|
||||
if (ptrace(PT_IO, proc_getpid(phdl), (caddr_t)&piod, 0) < 0) {
|
||||
DPRINTF("ERROR: couldn't write instruction at address 0x%" PRIuPTR,
|
||||
address);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement pc so that we delete the breakpoint at the correct
|
||||
* address, i.e. at the BREAKPOINT_INSTR address.
|
||||
*/
|
||||
void
|
||||
proc_bkptregadj(unsigned long *pc)
|
||||
{
|
||||
*pc = *pc - BREAKPOINT_INSTR_SZ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step over the breakpoint.
|
||||
*/
|
||||
int
|
||||
proc_bkptexec(struct proc_handle *phdl, unsigned long saved)
|
||||
{
|
||||
unsigned long pc;
|
||||
unsigned long samesaved;
|
||||
int status;
|
||||
|
||||
if (proc_regget(phdl, REG_PC, &pc) < 0) {
|
||||
warn("ERROR: couldn't get PC register");
|
||||
return (-1);
|
||||
}
|
||||
proc_bkptregadj(&pc);
|
||||
if (proc_bkptdel(phdl, pc, saved) < 0) {
|
||||
warn("ERROR: couldn't delete breakpoint");
|
||||
return (-1);
|
||||
}
|
||||
/*
|
||||
* Go back in time and step over the new instruction just
|
||||
* set up by proc_bkptdel().
|
||||
*/
|
||||
proc_regset(phdl, REG_PC, pc);
|
||||
if (ptrace(PT_STEP, proc_getpid(phdl), (caddr_t)1, 0) < 0) {
|
||||
warn("ERROR: ptrace step failed");
|
||||
return (-1);
|
||||
}
|
||||
status = proc_wstatus(phdl);
|
||||
if (!WIFSTOPPED(status)) {
|
||||
warn("ERROR: don't know why process stopped");
|
||||
return (-1);
|
||||
}
|
||||
/*
|
||||
* Restore the breakpoint. The saved instruction should be
|
||||
* the same as the one that we were passed in.
|
||||
*/
|
||||
if (proc_bkptset(phdl, pc, &samesaved) < 0) {
|
||||
warn("ERROR: couldn't restore breakpoint");
|
||||
return (-1);
|
||||
}
|
||||
assert(samesaved == saved);
|
||||
|
||||
return (0);
|
||||
}
|
@ -27,6 +27,7 @@
|
||||
*/
|
||||
|
||||
#include "_libproc.h"
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
@ -40,11 +41,10 @@ int
|
||||
proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
|
||||
{
|
||||
struct proc_handle *phdl;
|
||||
struct kevent kev;
|
||||
int error = 0;
|
||||
int status;
|
||||
|
||||
if (pid == 0 || pphdl == NULL)
|
||||
if (pid == 0 || pid == getpid())
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
@ -58,26 +58,24 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
|
||||
phdl->pid = pid;
|
||||
phdl->flags = flags;
|
||||
phdl->status = PS_RUN;
|
||||
elf_version(EV_CURRENT);
|
||||
|
||||
EV_SET(&kev, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT,
|
||||
0, NULL);
|
||||
|
||||
if ((phdl->kq = kqueue()) == -1)
|
||||
err(1, "ERROR: cannot create kernel evet queue");
|
||||
|
||||
if (kevent(phdl->kq, &kev, 1, NULL, 0, NULL) < 0)
|
||||
err(2, "ERROR: cannot monitor child process %d", pid);
|
||||
|
||||
if (ptrace(PT_ATTACH, phdl->pid, NULL, 0) != 0)
|
||||
if (ptrace(PT_ATTACH, phdl->pid, 0, 0) != 0) {
|
||||
error = errno;
|
||||
DPRINTF("ERROR: cannot ptrace child process %d", pid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Wait for the child process to stop. */
|
||||
else if (waitpid(pid, &status, WUNTRACED) == -1)
|
||||
err(3, "ERROR: child process %d didn't stop as expected", pid);
|
||||
if (waitpid(pid, &status, WUNTRACED) == -1) {
|
||||
error = errno;
|
||||
DPRINTF("ERROR: child process %d didn't stop as expected", pid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check for an unexpected status. */
|
||||
else if (WIFSTOPPED(status) == 0)
|
||||
err(4, "ERROR: child process %d status 0x%x", pid, status);
|
||||
if (WIFSTOPPED(status) == 0)
|
||||
DPRINTF("ERROR: child process %d status 0x%x", pid, status);
|
||||
else
|
||||
phdl->status = PS_STOP;
|
||||
|
||||
@ -85,6 +83,7 @@ proc_attach(pid_t pid, int flags, struct proc_handle **pphdl)
|
||||
proc_free(phdl);
|
||||
else
|
||||
*pphdl = phdl;
|
||||
out:
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -94,7 +93,6 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf,
|
||||
void *child_arg, struct proc_handle **pphdl)
|
||||
{
|
||||
struct proc_handle *phdl;
|
||||
struct kevent kev;
|
||||
int error = 0;
|
||||
int status;
|
||||
pid_t pid;
|
||||
@ -106,6 +104,8 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf,
|
||||
if ((phdl = malloc(sizeof(struct proc_handle))) == NULL)
|
||||
return (ENOMEM);
|
||||
|
||||
elf_version(EV_CURRENT);
|
||||
|
||||
/* Fork a new process. */
|
||||
if ((pid = vfork()) == -1)
|
||||
error = errno;
|
||||
@ -128,31 +128,26 @@ proc_create(const char *file, char * const *argv, proc_child_func *pcf,
|
||||
phdl->pid = pid;
|
||||
phdl->status = PS_IDLE;
|
||||
|
||||
EV_SET(&kev, pid, EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT,
|
||||
0, NULL);
|
||||
|
||||
if ((phdl->kq = kqueue()) == -1)
|
||||
err(1, "ERROR: cannot create kernel evet queue");
|
||||
|
||||
if (kevent(phdl->kq, &kev, 1, NULL, 0, NULL) < 0)
|
||||
err(2, "ERROR: cannot monitor child process %d", pid);
|
||||
|
||||
/* Wait for the child process to stop. */
|
||||
if (waitpid(pid, &status, WUNTRACED) == -1)
|
||||
err(3, "ERROR: child process %d didn't stop as expected", pid);
|
||||
if (waitpid(pid, &status, WUNTRACED) == -1) {
|
||||
error = errno;
|
||||
DPRINTF("ERROR: child process %d didn't stop as expected", pid);
|
||||
goto bad;
|
||||
}
|
||||
|
||||
/* Check for an unexpected status. */
|
||||
if (WIFSTOPPED(status) == 0)
|
||||
err(4, "ERROR: child process %d status 0x%x", pid, status);
|
||||
else
|
||||
if (WIFSTOPPED(status) == 0) {
|
||||
error = errno;
|
||||
DPRINTF("ERROR: child process %d status 0x%x", pid, status);
|
||||
goto bad;
|
||||
} else
|
||||
phdl->status = PS_STOP;
|
||||
}
|
||||
|
||||
bad:
|
||||
if (error)
|
||||
proc_free(phdl);
|
||||
else
|
||||
*pphdl = phdl;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
113
lib/libproc/proc_regs.c
Normal file
113
lib/libproc/proc_regs.c
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Rui Paulo under sponsorship from the
|
||||
* FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "_libproc.h"
|
||||
|
||||
int
|
||||
proc_regget(struct proc_handle *phdl, proc_reg_t reg, unsigned long *regvalue)
|
||||
{
|
||||
struct reg regs;
|
||||
|
||||
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
|
||||
phdl->status == PS_IDLE) {
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
memset(®s, 0, sizeof(regs));
|
||||
if (ptrace(PT_GETREGS, proc_getpid(phdl), (caddr_t)®s, 0) < 0)
|
||||
return (-1);
|
||||
switch (reg) {
|
||||
case REG_PC:
|
||||
#if defined(__amd64__)
|
||||
*regvalue = regs.r_rip;
|
||||
#elif defined(__i386__)
|
||||
*regvalue = regs.r_eip;
|
||||
#endif
|
||||
break;
|
||||
case REG_SP:
|
||||
#if defined(__amd64__)
|
||||
*regvalue = regs.r_rsp;
|
||||
#elif defined(__i386__)
|
||||
*regvalue = regs.r_esp;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
warn("ERROR: no support for reg number %d", reg);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
proc_regset(struct proc_handle *phdl, proc_reg_t reg, unsigned long regvalue)
|
||||
{
|
||||
struct reg regs;
|
||||
|
||||
if (phdl->status == PS_DEAD || phdl->status == PS_UNDEAD ||
|
||||
phdl->status == PS_IDLE) {
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
if (ptrace(PT_GETREGS, proc_getpid(phdl), (caddr_t)®s, 0) < 0)
|
||||
return (-1);
|
||||
switch (reg) {
|
||||
case REG_PC:
|
||||
#if defined(__amd64__)
|
||||
regs.r_rip = regvalue;
|
||||
#elif defined(__i386__)
|
||||
regs.r_eip = regvalue;
|
||||
#endif
|
||||
break;
|
||||
case REG_SP:
|
||||
#if defined(__amd64__)
|
||||
regs.r_rsp = regvalue;
|
||||
#elif defined(__i386__)
|
||||
regs.r_esp = regvalue;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
warn("ERROR: no support for reg number %d", reg);
|
||||
return (-1);
|
||||
}
|
||||
if (ptrace(PT_SETREGS, proc_getpid(phdl), (caddr_t)®s, 0) < 0)
|
||||
return (-1);
|
||||
|
||||
return (0);
|
||||
}
|
79
lib/libproc/proc_rtld.c
Normal file
79
lib/libproc/proc_rtld.c
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Rui Paulo under sponsorship from the
|
||||
* FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <rtld_db.h>
|
||||
#include "libproc.h"
|
||||
#include "_libproc.h"
|
||||
|
||||
static int
|
||||
map_iter(const rd_loadobj_t *lop, void *arg)
|
||||
{
|
||||
struct proc_handle *phdl = arg;
|
||||
|
||||
phdl->nobjs++;
|
||||
if (phdl->nobjs >= phdl->rdobjsz) {
|
||||
phdl->rdobjsz *= 2;
|
||||
phdl->rdobjs = realloc(phdl->rdobjs, phdl->rdobjsz);
|
||||
if (phdl->rdobjs == NULL)
|
||||
return (-1);
|
||||
}
|
||||
memcpy(&phdl->rdobjs[phdl->nobjs++], lop, sizeof(*phdl->rdobjs));
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
rd_agent_t *
|
||||
proc_rdagent(struct proc_handle *phdl)
|
||||
{
|
||||
if (phdl->rdap == NULL && phdl->status != PS_UNDEAD &&
|
||||
phdl->status != PS_IDLE) {
|
||||
if ((phdl->rdap = rd_new(phdl)) != NULL) {
|
||||
phdl->rdobjs = malloc(sizeof(*phdl->rdobjs) * 64);
|
||||
if (phdl->rdobjs == NULL)
|
||||
return (phdl->rdap);
|
||||
rd_loadobj_iter(phdl->rdap, map_iter, phdl);
|
||||
}
|
||||
}
|
||||
|
||||
return (phdl->rdap);
|
||||
}
|
||||
|
||||
void
|
||||
proc_updatesyms(struct proc_handle *phdl)
|
||||
{
|
||||
memset(&phdl->rdobjs, 0, sizeof(*phdl->rdobjs) * phdl->rdobjsz);
|
||||
phdl->nobjs = 0;
|
||||
rd_loadobj_iter(phdl->rdap, map_iter, phdl);
|
||||
}
|
@ -1,7 +1,11 @@
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* Copyright (c) 2008 John Birrell (jb@freebsd.org)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Rui Paulo under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -26,43 +30,524 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "_libproc.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdio.h>
|
||||
#include <libgen.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libutil.h>
|
||||
|
||||
#include "_libproc.h"
|
||||
|
||||
static void proc_rdl2prmap(rd_loadobj_t *, prmap_t *);
|
||||
|
||||
static void
|
||||
proc_rdl2prmap(rd_loadobj_t *rdl, prmap_t *map)
|
||||
{
|
||||
map->pr_vaddr = rdl->rdl_saddr;
|
||||
map->pr_size = rdl->rdl_eaddr - rdl->rdl_saddr;
|
||||
map->pr_offset = rdl->rdl_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (rdl->rdl_prot & RD_RDL_R)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (rdl->rdl_prot & RD_RDL_W)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (rdl->rdl_prot & RD_RDL_X)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
strlcpy(map->pr_mapname, rdl->rdl_path,
|
||||
sizeof(map->pr_mapname));
|
||||
}
|
||||
|
||||
char *
|
||||
proc_objname(struct proc_handle *p, uintptr_t addr, char *objname,
|
||||
size_t objnamesz)
|
||||
{
|
||||
printf("%s(%d): Not implemented. p %p addr 0x%lx objname %p objnamesz %zd\n",__func__,__LINE__,p,(u_long) addr,objname,objnamesz);
|
||||
size_t i;
|
||||
rd_loadobj_t *rdl;
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
if (addr >= rdl->rdl_saddr && addr <= rdl->rdl_eaddr) {
|
||||
strlcpy(objname, rdl->rdl_path, objnamesz);
|
||||
return (objname);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
const prmap_t *
|
||||
prmap_t *
|
||||
proc_obj2map(struct proc_handle *p, const char *objname)
|
||||
{
|
||||
size_t i;
|
||||
prmap_t *map;
|
||||
rd_loadobj_t *rdl;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
basename_r(rdl->rdl_path, path);
|
||||
if (strcmp(path, objname) == 0) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
proc_iter_objs(struct proc_handle *p, proc_map_f *func, void *cd)
|
||||
{
|
||||
size_t i;
|
||||
rd_loadobj_t *rdl;
|
||||
prmap_t map;
|
||||
char path[MAXPATHLEN];
|
||||
|
||||
if (p->nobjs == 0)
|
||||
return (-1);
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
proc_rdl2prmap(rdl, &map);
|
||||
basename_r(rdl->rdl_path, path);
|
||||
(*func)(cd, &map, path);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
prmap_t *
|
||||
proc_addr2map(struct proc_handle *p, uintptr_t addr)
|
||||
{
|
||||
printf("%s(%d): Not implemented. p %p addr 0x%lx\n",__func__,__LINE__,p,(u_long) addr);
|
||||
size_t i;
|
||||
int cnt, lastvn = 0;
|
||||
prmap_t *map;
|
||||
rd_loadobj_t *rdl;
|
||||
struct kinfo_vmentry *kves, *kve;
|
||||
|
||||
/*
|
||||
* If we don't have a cache of listed objects, we need to query
|
||||
* it ourselves.
|
||||
*/
|
||||
if (p->nobjs == 0) {
|
||||
if ((kves = kinfo_getvmmap(p->pid, &cnt)) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < (size_t)cnt; i++) {
|
||||
kve = kves + i;
|
||||
if (kve->kve_type == KVME_TYPE_VNODE)
|
||||
lastvn = i;
|
||||
if (addr >= kve->kve_start && addr <= kve->kve_end) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL) {
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
map->pr_vaddr = kve->kve_start;
|
||||
map->pr_size = kve->kve_end - kve->kve_start;
|
||||
map->pr_offset = kve->kve_offset;
|
||||
map->pr_mflags = 0;
|
||||
if (kve->kve_protection & KVME_PROT_READ)
|
||||
map->pr_mflags |= MA_READ;
|
||||
if (kve->kve_protection & KVME_PROT_WRITE)
|
||||
map->pr_mflags |= MA_WRITE;
|
||||
if (kve->kve_protection & KVME_PROT_EXEC)
|
||||
map->pr_mflags |= MA_EXEC;
|
||||
if (kve->kve_flags & KVME_FLAG_COW)
|
||||
map->pr_mflags |= MA_COW;
|
||||
if (kve->kve_flags & KVME_FLAG_NEEDS_COPY)
|
||||
map->pr_mflags |= MA_NEEDS_COPY;
|
||||
if (kve->kve_flags & KVME_FLAG_NOCOREDUMP)
|
||||
map->pr_mflags |= MA_NOCOREDUMP;
|
||||
strlcpy(map->pr_mapname, kves[lastvn].kve_path,
|
||||
sizeof(map->pr_mapname));
|
||||
free(kves);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
if (addr >= rdl->rdl_saddr && addr <= rdl->rdl_eaddr) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
|
||||
size_t namesz, GElf_Sym *sym)
|
||||
size_t namesz, GElf_Sym *symcopy)
|
||||
{
|
||||
printf("%s(%d): Not implemented. p %p addr 0x%lx name %p namesz %zd sym %p\n",__func__,__LINE__,p,(u_long) addr,name,namesz,sym);
|
||||
return (0);
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
GElf_Ehdr ehdr;
|
||||
int fd, error = -1;
|
||||
size_t i;
|
||||
uint64_t rsym;
|
||||
prmap_t *map;
|
||||
char *s;
|
||||
unsigned long symtabstridx = 0, dynsymstridx = 0;
|
||||
|
||||
if ((map = proc_addr2map(p, addr)) == NULL)
|
||||
return (-1);
|
||||
if (!map->pr_mapname || (fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
|
||||
warn("ERROR: open %s failed", map->pr_mapname);
|
||||
goto err0;
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
warn("ERROR: elf_begin() failed");
|
||||
goto err1;
|
||||
}
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
warn("ERROR: gelf_getehdr() failed");
|
||||
goto err2;
|
||||
}
|
||||
/*
|
||||
* Find the index of the STRTAB and SYMTAB sections to locate
|
||||
* symbol names.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
switch (shdr.sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
symtabscn = scn;
|
||||
symtabstridx = shdr.sh_link;
|
||||
break;
|
||||
case SHT_DYNSYM:
|
||||
dynsymscn = scn;
|
||||
dynsymstridx = shdr.sh_link;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Iterate over the Dynamic Symbols table to find the symbol.
|
||||
* Then look up the string name in STRTAB (.dynstr)
|
||||
*/
|
||||
if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
|
||||
DPRINTF("ERROR: elf_getdata() failed");
|
||||
goto err2;
|
||||
}
|
||||
i = 0;
|
||||
while (gelf_getsym(data, i++, &sym) != NULL) {
|
||||
/*
|
||||
* Calculate the address mapped to the virtual memory
|
||||
* by rtld.
|
||||
*/
|
||||
rsym = map->pr_vaddr + sym.st_value;
|
||||
if (addr >= rsym && addr <= (rsym + sym.st_size)) {
|
||||
s = elf_strptr(e, dynsymstridx, sym.st_name);
|
||||
if (s) {
|
||||
strlcpy(name, s, namesz);
|
||||
memcpy(symcopy, &sym, sizeof(sym));
|
||||
/*
|
||||
* DTrace expects the st_value to contain
|
||||
* only the address relative to the start of
|
||||
* the function.
|
||||
*/
|
||||
symcopy->st_value = rsym;
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Iterate over the Symbols Table to find the symbol.
|
||||
* Then look up the string name in STRTAB (.dynstr)
|
||||
*/
|
||||
if (symtabscn == NULL)
|
||||
goto err2;
|
||||
if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
|
||||
DPRINTF("ERROR: elf_getdata() failed");
|
||||
goto err2;
|
||||
}
|
||||
i = 0;
|
||||
while (gelf_getsym(data, i++, &sym) != NULL) {
|
||||
/*
|
||||
* Calculate the address mapped to the virtual memory
|
||||
* by rtld.
|
||||
*/
|
||||
if (ehdr.e_type != ET_EXEC)
|
||||
rsym = map->pr_vaddr + sym.st_value;
|
||||
else
|
||||
rsym = sym.st_value;
|
||||
if (addr >= rsym && addr <= (rsym + sym.st_size)) {
|
||||
s = elf_strptr(e, symtabstridx, sym.st_name);
|
||||
if (s) {
|
||||
strlcpy(name, s, namesz);
|
||||
memcpy(symcopy, &sym, sizeof(sym));
|
||||
/*
|
||||
* DTrace expects the st_value to contain
|
||||
* only the address relative to the start of
|
||||
* the function.
|
||||
*/
|
||||
symcopy->st_value = rsym;
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
err2:
|
||||
elf_end(e);
|
||||
err1:
|
||||
close(fd);
|
||||
err0:
|
||||
free(map);
|
||||
return (error);
|
||||
}
|
||||
|
||||
const prmap_t *
|
||||
prmap_t *
|
||||
proc_name2map(struct proc_handle *p, const char *name)
|
||||
{
|
||||
printf("%s(%d): Not implemented. p %p name %p\n",__func__,__LINE__,p,name);
|
||||
size_t i;
|
||||
int cnt;
|
||||
prmap_t *map;
|
||||
char tmppath[MAXPATHLEN];
|
||||
struct kinfo_vmentry *kves, *kve;
|
||||
rd_loadobj_t *rdl;
|
||||
|
||||
/*
|
||||
* If we haven't iterated over the list of loaded objects,
|
||||
* librtld_db isn't yet initialized and it's very likely
|
||||
* that librtld_db called us. We need to do the heavy
|
||||
* lifting here to find the symbol librtld_db is looking for.
|
||||
*/
|
||||
if (p->nobjs == 0) {
|
||||
if ((kves = kinfo_getvmmap(proc_getpid(p), &cnt)) == NULL)
|
||||
return (NULL);
|
||||
for (i = 0; i < (size_t)cnt; i++) {
|
||||
kve = kves + i;
|
||||
basename_r(kve->kve_path, tmppath);
|
||||
if (strcmp(tmppath, name) == 0) {
|
||||
map = proc_addr2map(p, kve->kve_start);
|
||||
free(kves);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
free(kves);
|
||||
return (NULL);
|
||||
}
|
||||
if (name == NULL || strcmp(name, "a.out") == 0) {
|
||||
map = proc_addr2map(p, p->rdobjs[0].rdl_saddr);
|
||||
return (map);
|
||||
}
|
||||
for (i = 0; i < p->nobjs; i++) {
|
||||
rdl = &p->rdobjs[i];
|
||||
basename_r(rdl->rdl_path, tmppath);
|
||||
if (strcmp(tmppath, name) == 0) {
|
||||
if ((map = malloc(sizeof(*map))) == NULL)
|
||||
return (NULL);
|
||||
proc_rdl2prmap(rdl, map);
|
||||
return (map);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
|
||||
GElf_Sym *sym)
|
||||
GElf_Sym *symcopy)
|
||||
{
|
||||
printf("%s(%d): Not implemented. p %p object %p symbol %p sym %p\n",__func__,__LINE__,p,object,symbol,sym);
|
||||
return (0);
|
||||
Elf *e;
|
||||
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
GElf_Ehdr ehdr;
|
||||
int fd, error = -1;
|
||||
size_t i;
|
||||
prmap_t *map;
|
||||
char *s;
|
||||
unsigned long symtabstridx = 0, dynsymstridx = 0;
|
||||
|
||||
if ((map = proc_name2map(p, object)) == NULL) {
|
||||
DPRINTF("ERROR: couldn't find object %s", object);
|
||||
goto err0;
|
||||
}
|
||||
if ((fd = open(map->pr_mapname, O_RDONLY, 0)) < 0) {
|
||||
DPRINTF("ERROR: open %s failed", map->pr_mapname);
|
||||
goto err0;
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
warn("ERROR: elf_begin() failed");
|
||||
goto err1;
|
||||
}
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) {
|
||||
warn("ERROR: gelf_getehdr() failed");
|
||||
goto err2;
|
||||
}
|
||||
/*
|
||||
* Find the index of the STRTAB and SYMTAB sections to locate
|
||||
* symbol names.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
switch (shdr.sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
symtabscn = scn;
|
||||
symtabstridx = shdr.sh_link;
|
||||
break;
|
||||
case SHT_DYNSYM:
|
||||
dynsymscn = scn;
|
||||
dynsymstridx = shdr.sh_link;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Iterate over the Dynamic Symbols table to find the symbol.
|
||||
* Then look up the string name in STRTAB (.dynstr)
|
||||
*/
|
||||
if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
|
||||
DPRINTF("ERROR: elf_getdata() failed");
|
||||
goto err2;
|
||||
}
|
||||
i = 0;
|
||||
while (gelf_getsym(data, i++, &sym) != NULL) {
|
||||
s = elf_strptr(e, dynsymstridx, sym.st_name);
|
||||
if (s && strcmp(s, symbol) == 0) {
|
||||
memcpy(symcopy, &sym, sizeof(sym));
|
||||
symcopy->st_value = map->pr_vaddr + sym.st_value;
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Iterate over the Symbols Table to find the symbol.
|
||||
* Then look up the string name in STRTAB (.dynstr)
|
||||
*/
|
||||
if (symtabscn == NULL)
|
||||
goto err2;
|
||||
if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
|
||||
DPRINTF("ERROR: elf_getdata() failed");
|
||||
goto err2;
|
||||
}
|
||||
i = 0;
|
||||
while (gelf_getsym(data, i++, &sym) != NULL) {
|
||||
s = elf_strptr(e, symtabstridx, sym.st_name);
|
||||
if (s && strcmp(s, symbol) == 0) {
|
||||
memcpy(symcopy, &sym, sizeof(sym));
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
err2:
|
||||
elf_end(e);
|
||||
err1:
|
||||
close(fd);
|
||||
err0:
|
||||
free(map);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
|
||||
int mask, proc_sym_f *func, void *cd)
|
||||
{
|
||||
Elf *e;
|
||||
int i, fd;
|
||||
prmap_t *map;
|
||||
Elf_Scn *scn, *foundscn = NULL;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
unsigned long stridx = -1;
|
||||
char *s;
|
||||
int error = -1;
|
||||
|
||||
if ((map = proc_name2map(p, object)) == NULL)
|
||||
return (-1);
|
||||
if ((fd = open(map->pr_mapname, O_RDONLY)) < 0) {
|
||||
warn("ERROR: open %s failed", map->pr_mapname);
|
||||
goto err0;
|
||||
}
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
warn("ERROR: elf_begin() failed");
|
||||
goto err1;
|
||||
}
|
||||
/*
|
||||
* Find the section we are looking for.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
gelf_getshdr(scn, &shdr);
|
||||
if (which == PR_SYMTAB &&
|
||||
shdr.sh_type == SHT_SYMTAB) {
|
||||
foundscn = scn;
|
||||
break;
|
||||
} else if (which == PR_DYNSYM &&
|
||||
shdr.sh_type == SHT_DYNSYM) {
|
||||
foundscn = scn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundscn)
|
||||
return (-1);
|
||||
stridx = shdr.sh_link;
|
||||
if ((data = elf_getdata(foundscn, NULL)) == NULL) {
|
||||
DPRINTF("ERROR: elf_getdata() failed");
|
||||
goto err2;
|
||||
}
|
||||
i = 0;
|
||||
while (gelf_getsym(data, i++, &sym) != NULL) {
|
||||
if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
|
||||
(mask & BIND_LOCAL) == 0)
|
||||
continue;
|
||||
if (GELF_ST_BIND(sym.st_info) == STB_GLOBAL &&
|
||||
(mask & BIND_GLOBAL) == 0)
|
||||
continue;
|
||||
if (GELF_ST_BIND(sym.st_info) == STB_WEAK &&
|
||||
(mask & BIND_WEAK) == 0)
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym.st_info) == STT_NOTYPE &&
|
||||
(mask & TYPE_NOTYPE) == 0)
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym.st_info) == STT_OBJECT &&
|
||||
(mask & TYPE_OBJECT) == 0)
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym.st_info) == STT_FUNC &&
|
||||
(mask & TYPE_FUNC) == 0)
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
|
||||
(mask & TYPE_SECTION) == 0)
|
||||
continue;
|
||||
if (GELF_ST_TYPE(sym.st_info) == STT_FILE &&
|
||||
(mask & TYPE_FILE) == 0)
|
||||
continue;
|
||||
s = elf_strptr(e, stridx, sym.st_name);
|
||||
sym.st_value += map->pr_vaddr;
|
||||
(*func)(cd, &sym, s);
|
||||
}
|
||||
error = 0;
|
||||
err2:
|
||||
elf_end(e);
|
||||
err1:
|
||||
close(fd);
|
||||
err0:
|
||||
free(map);
|
||||
return (error);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
/*-
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* Copyright (c) 2008 John Birrell (jb@freebsd.org)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Portions of this software were developed by Rui Paulo under sponsorship
|
||||
* from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -26,16 +30,21 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include "_libproc.h"
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/wait.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include "_libproc.h"
|
||||
|
||||
int
|
||||
proc_clearflags(struct proc_handle *phdl, int mask)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
@ -44,14 +53,18 @@ proc_clearflags(struct proc_handle *phdl, int mask)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* NB: we return -1 as the Solaris libproc Psetrun() function.
|
||||
*/
|
||||
int
|
||||
proc_continue(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (EINVAL);
|
||||
return (-1);
|
||||
|
||||
if (ptrace(PT_CONTINUE, phdl->pid, (caddr_t)(uintptr_t) 1, 0) != 0)
|
||||
return (errno);
|
||||
return (-1);
|
||||
|
||||
phdl->status = PS_RUN;
|
||||
|
||||
@ -59,13 +72,25 @@ proc_continue(struct proc_handle *phdl)
|
||||
}
|
||||
|
||||
int
|
||||
proc_detach(struct proc_handle *phdl)
|
||||
proc_detach(struct proc_handle *phdl, int reason)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0)
|
||||
return (errno);
|
||||
if (reason == PRELEASE_KILL) {
|
||||
kill(phdl->pid, SIGKILL);
|
||||
return (0);
|
||||
}
|
||||
if (ptrace(PT_DETACH, phdl->pid, 0, 0) != 0 && errno == ESRCH)
|
||||
return (0);
|
||||
if (errno == EBUSY) {
|
||||
kill(phdl->pid, SIGSTOP);
|
||||
waitpid(phdl->pid, &status, WUNTRACED);
|
||||
ptrace(PT_DETACH, phdl->pid, 0, 0);
|
||||
kill(phdl->pid, SIGCONT);
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -73,6 +98,7 @@ proc_detach(struct proc_handle *phdl)
|
||||
int
|
||||
proc_getflags(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
|
||||
@ -82,6 +108,7 @@ proc_getflags(struct proc_handle *phdl)
|
||||
int
|
||||
proc_setflags(struct proc_handle *phdl, int mask)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
@ -93,41 +120,101 @@ proc_setflags(struct proc_handle *phdl, int mask)
|
||||
int
|
||||
proc_state(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
|
||||
return (phdl->status);
|
||||
}
|
||||
|
||||
int
|
||||
proc_wait(struct proc_handle *phdl)
|
||||
{
|
||||
int status = 0;
|
||||
struct kevent kev;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (kevent(phdl->kq, NULL, 0, &kev, 1, NULL) <= 0)
|
||||
return (0);
|
||||
|
||||
switch (kev.filter) {
|
||||
/* Child has exited */
|
||||
case EVFILT_PROC: /* target has exited */
|
||||
phdl->status = PS_UNDEAD;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
pid_t
|
||||
proc_getpid(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
|
||||
return (phdl->pid);
|
||||
}
|
||||
|
||||
int
|
||||
proc_wstatus(struct proc_handle *phdl)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
if (waitpid(phdl->pid, &status, WUNTRACED) < 0)
|
||||
return (-1);
|
||||
if (WIFSTOPPED(status))
|
||||
phdl->status = PS_STOP;
|
||||
if (WIFEXITED(status) || WIFSIGNALED(status))
|
||||
phdl->status = PS_UNDEAD;
|
||||
phdl->wstat = status;
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
int
|
||||
proc_getwstat(struct proc_handle *phdl)
|
||||
{
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
|
||||
return (phdl->wstat);
|
||||
}
|
||||
|
||||
char *
|
||||
proc_signame(int sig, char *name, size_t namesz)
|
||||
{
|
||||
|
||||
strlcpy(name, strsignal(sig), namesz);
|
||||
|
||||
return (name);
|
||||
}
|
||||
|
||||
int
|
||||
proc_read(struct proc_handle *phdl, char *buf, size_t size, size_t addr)
|
||||
{
|
||||
struct ptrace_io_desc piod;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (-1);
|
||||
piod.piod_op = PIOD_READ_D;
|
||||
piod.piod_len = size;
|
||||
piod.piod_addr = (void *)buf;
|
||||
piod.piod_offs = (void *)addr;
|
||||
|
||||
if (ptrace(PT_IO, phdl->pid, (caddr_t)&piod, 0) < 0)
|
||||
return (-1);
|
||||
return (piod.piod_len);
|
||||
}
|
||||
|
||||
const lwpstatus_t *
|
||||
proc_getlwpstatus(struct proc_handle *phdl)
|
||||
{
|
||||
struct ptrace_lwpinfo lwpinfo;
|
||||
lwpstatus_t *psp = &phdl->lwps;
|
||||
siginfo_t *siginfo;
|
||||
|
||||
if (phdl == NULL)
|
||||
return (NULL);
|
||||
if (ptrace(PT_LWPINFO, phdl->pid, (caddr_t)&lwpinfo,sizeof(lwpinfo)) < 0)
|
||||
return (NULL);
|
||||
siginfo = &lwpinfo.pl_siginfo;
|
||||
if (lwpinfo.pl_event == PL_EVENT_SIGNAL &&
|
||||
(lwpinfo.pl_flags & PL_FLAG_SI) &&
|
||||
siginfo->si_signo == SIGTRAP &&
|
||||
(siginfo->si_code == TRAP_BRKPT ||
|
||||
siginfo->si_code == TRAP_TRACE)) {
|
||||
psp->pr_why = PR_FAULTED;
|
||||
psp->pr_what = FLTBPT;
|
||||
} else if (lwpinfo.pl_flags & PL_FLAG_SCE) {
|
||||
psp->pr_why = PR_SYSENTRY;
|
||||
} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
|
||||
psp->pr_why = PR_SYSEXIT;
|
||||
}
|
||||
|
||||
return (psp);
|
||||
}
|
||||
|
5
lib/libproc/test/Makefile
Normal file
5
lib/libproc/test/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SUBDIR= t1-bkpt t2-name2map t3-name2sym
|
||||
|
||||
.include <bsd.subdir.mk>
|
12
lib/libproc/test/t1-bkpt/Makefile
Normal file
12
lib/libproc/test/t1-bkpt/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= t1-bkpt
|
||||
|
||||
SRCS= t1-bkpt.c
|
||||
|
||||
LDADD= -lproc -lelf -lrtld_db -lutil
|
||||
DPADD= ${LIBPROC} ${LIBELF}
|
||||
|
||||
WITHOUT_MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
71
lib/libproc/test/t1-bkpt/t1-bkpt.c
Normal file
71
lib/libproc/test/t1-bkpt/t1-bkpt.c
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Rui Paulo under sponsorship from the
|
||||
* FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <libproc.h>
|
||||
|
||||
int
|
||||
t1_bkpt_t()
|
||||
{
|
||||
printf("TEST OK\n");
|
||||
}
|
||||
|
||||
int
|
||||
t1_bkpt_d()
|
||||
{
|
||||
struct proc_handle *phdl;
|
||||
char *targv[] = { "t1-bkpt-t", NULL};
|
||||
unsigned long saved;
|
||||
|
||||
proc_create("./t1-bkpt", targv, NULL, NULL, &phdl);
|
||||
proc_bkptset(phdl, (uintptr_t)t1_bkpt_t, &saved);
|
||||
proc_continue(phdl);
|
||||
assert(WIFSTOPPED(proc_wstatus(phdl)));
|
||||
proc_bkptexec(phdl, saved);
|
||||
proc_continue(phdl);
|
||||
proc_wait(phdl);
|
||||
proc_free(phdl);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
if (!strcmp(argv[0], "t1-bkpt-t"))
|
||||
t1_bkpt_t();
|
||||
else
|
||||
t1_bkpt_d();
|
||||
}
|
||||
|
12
lib/libproc/test/t2-name2map/Makefile
Normal file
12
lib/libproc/test/t2-name2map/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= t2-name2map
|
||||
|
||||
SRCS= t2-name2map.c
|
||||
|
||||
LDADD= -lproc -lelf -lrtld_db -lutil
|
||||
DPADD= ${LIBPROC} ${LIBELF}
|
||||
|
||||
WITHOUT_MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
46
lib/libproc/test/t2-name2map/t2-name2map.c
Normal file
46
lib/libproc/test/t2-name2map/t2-name2map.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Rui Paulo under sponsorship from the
|
||||
* FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <libproc.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
prmap_t *map = NULL;
|
||||
struct proc_handle *phdl;
|
||||
|
||||
proc_create("./t2-name2map", argv, NULL, NULL, &phdl);
|
||||
map = proc_name2map(phdl, "ld-elf.so.1");
|
||||
assert(map);
|
||||
}
|
12
lib/libproc/test/t3-name2sym/Makefile
Normal file
12
lib/libproc/test/t3-name2sym/Makefile
Normal file
@ -0,0 +1,12 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= t3-name2sym
|
||||
|
||||
SRCS= t3-name2sym.c
|
||||
|
||||
LDADD= -lproc -lelf -lrtld_db -lutil
|
||||
DPADD= ${LIBPROC} ${LIBELF}
|
||||
|
||||
WITHOUT_MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
50
lib/libproc/test/t3-name2sym/t3-name2sym.c
Normal file
50
lib/libproc/test/t3-name2sym/t3-name2sym.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2010 The FreeBSD Foundation
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software was developed by Rui Paulo under sponsorship from the
|
||||
* FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <libproc.h>
|
||||
#include <gelf.h>
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
prmap_t *map = NULL;
|
||||
struct proc_handle *phdl;
|
||||
GElf_Sym sym;
|
||||
|
||||
proc_create("./t3-name2sym", argv, NULL, NULL, &phdl);
|
||||
memset(&sym, 0, sizeof(sym));
|
||||
assert(proc_name2sym(phdl, "ld-elf.so.1", "r_debug_state", &sym) == 0);
|
||||
printf("0x%lx\n", sym.st_value);
|
||||
assert(proc_name2sym(phdl, "t3-name2sym", "main", &sym) == 0);
|
||||
printf("0x%lx\n", sym.st_value);
|
||||
}
|
Loading…
Reference in New Issue
Block a user