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:
Rui Paulo 2010-07-31 16:10:20 +00:00
parent 4579930d2e
commit 8eb20f364f
16 changed files with 1323 additions and 83 deletions

View File

@ -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

View File

@ -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

View File

@ -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
View 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);
}

View File

@ -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
View 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(&regs, 0, sizeof(regs));
if (ptrace(PT_GETREGS, proc_getpid(phdl), (caddr_t)&regs, 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)&regs, 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)&regs, 0) < 0)
return (-1);
return (0);
}

79
lib/libproc/proc_rtld.c Normal file
View 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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -0,0 +1,5 @@
# $FreeBSD$
SUBDIR= t1-bkpt t2-name2map t3-name2sym
.include <bsd.subdir.mk>

View 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>

View 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();
}

View 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>

View 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);
}

View 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>

View 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);
}