Add libdtrace support for tracing userland programs.

Summary of changes:
* Implement a compatibility shim between Solaris libproc and our
libproc and remove several ifdefs because of this.
* Port the drti to FreeBSD.
* Implement the missing DOODAD sections
* Link with libproc and librtld_db
* Support for ustack, jstack and uregs (by sson@)
* Misc bugfixing

When writing the SUWN_dof section, we had to resort to building the ELF
file layout by "hand". This is the job of libelf, but our libelf doesn't
support this yet. When libelf is fixed, we can remove the code under
#ifdef BROKEN_LIBELF.

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Rui Paulo 2010-08-21 11:50:53 +00:00
parent e0be1c75f0
commit 0f2bd1e89d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=211554
15 changed files with 712 additions and 218 deletions

View File

@ -773,19 +773,27 @@ compile_str(dtrace_cmd_t *dcp)
static void
prochandler(struct ps_prochandle *P, const char *msg, void *arg)
{
fatal("DOODAD in function %s, file %s, line %d\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
#if defined(sun)
const psinfo_t *prp = Ppsinfo(P);
int pid = Pstatus(P)->pr_pid;
char name[SIG2STR_MAX];
#else
int wstatus = proc_getwstat(P);
int pid = proc_getpid(P);
#endif
if (msg != NULL) {
notice("pid %d: %s\n", pid, msg);
return;
}
#if defined(sun)
switch (Pstate(P)) {
#else
switch (proc_state(P)) {
#endif
case PS_UNDEAD:
#if defined(sun)
/*
* Ideally we would like to always report pr_wstat here, but it
* isn't possible given current /proc semantics. If we grabbed
@ -798,9 +806,20 @@ fatal("DOODAD in function %s, file %s, line %d\n",__FUNCTION__,__FILE__,__LINE__
notice("pid %d terminated by %s\n", pid,
proc_signame(WTERMSIG(prp->pr_wstat),
name, sizeof (name)));
#else
if (WIFSIGNALED(wstatus)) {
notice("pid %d terminated by %d\n", pid,
WTERMSIG(wstatus));
#endif
#if defined(sun)
} else if (prp != NULL && WEXITSTATUS(prp->pr_wstat) != 0) {
notice("pid %d exited with status %d\n",
pid, WEXITSTATUS(prp->pr_wstat));
#else
} else if (WEXITSTATUS(wstatus) != 0) {
notice("pid %d exited with status %d\n",
pid, WEXITSTATUS(wstatus));
#endif
} else {
notice("pid %d has exited\n", pid);
}
@ -812,7 +831,6 @@ fatal("DOODAD in function %s, file %s, line %d\n",__FUNCTION__,__FILE__,__LINE__
g_pslive--;
break;
}
#endif
}
/*ARGSUSED*/

View File

@ -34,6 +34,8 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <libelf.h>
#include <gelf.h>
/*
* In Solaris 10 GA, the only mechanism for communicating helper information
@ -53,12 +55,16 @@
*/
static const char *devnamep = "/dev/dtrace/helper";
#if defined(sun)
static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
#endif
static const char *modname; /* Name of this load object */
static int gen; /* DOF helper generation */
#if defined(sun)
extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
static boolean_t dof_init_debug = B_FALSE; /* From DTRACE_DOF_INIT_DEBUG */
#endif
static boolean_t dof_init_debug = B_TRUE; /* From DTRACE_DOF_INIT_DEBUG */
static void
dprintf(int debug, const char *fmt, ...)
@ -83,6 +89,36 @@ dprintf(int debug, const char *fmt, ...)
va_end(ap);
}
#if !defined(sun)
static void
fixsymbol(Elf *e, Elf_Data *data, size_t idx, int nprobes, char *buf,
dof_sec_t *sec, int *fixedprobes, char *dofstrtab)
{
GElf_Sym sym;
char *s;
unsigned char *funcname;
dof_probe_t *prb;
int j = 0;
int ndx;
while (gelf_getsym(data, j++, &sym) != NULL) {
prb = (dof_probe_t *)(buf + sec->dofs_offset);
for (ndx = nprobes; ndx; ndx--, prb += 1) {
funcname = dofstrtab + prb->dofpr_func;
s = elf_strptr(e, idx, sym.st_name);
if (strcmp(s, funcname) == 0) {
dprintf(1, "fixing %s() symbol\n", s);
prb->dofpr_addr = sym.st_value;
(*fixedprobes)++;
}
}
if (*fixedprobes == nprobes)
break;
}
}
#endif
#if defined(sun)
#pragma init(dtrace_dof_init)
#else
@ -92,22 +128,39 @@ static void dtrace_dof_init(void) __attribute__ ((constructor));
static void
dtrace_dof_init(void)
{
#if defined(sun)
dof_hdr_t *dof = &__SUNW_dof;
#else
dof_hdr_t *dof = NULL;
#endif
#ifdef _LP64
Elf64_Ehdr *elf;
#else
Elf32_Ehdr *elf;
#endif
dof_helper_t dh;
#if defined(sun)
Link_map *lmp;
#if defined(sun)
Lmid_t lmid;
#else
struct link_map *lmp;
u_long lmid = 0;
dof_sec_t *sec;
size_t i;
#endif
int fd;
const char *p;
#if !defined(sun)
Elf *e;
Elf_Scn *scn = NULL;
Elf_Data *symtabdata = NULL, *dynsymdata = NULL;
GElf_Shdr shdr;
int efd, nprobes;
char *s;
size_t shstridx, symtabidx = 0, dynsymidx = 0;
unsigned char *dofstrtab = NULL;
unsigned char *buf;
int fixedprobes = 0;
#endif
if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
return;
@ -127,10 +180,46 @@ dtrace_dof_init(void)
}
#endif
if ((modname = strrchr(lmp->l_name, '/')) == NULL)
modname = lmp->l_name;
else
modname++;
#if !defined(sun)
elf_version(EV_CURRENT);
if ((efd = open(lmp->l_name, O_RDONLY, 0)) < 0) {
dprintf(1, "couldn't open file for reading\n");
return;
}
if ((e = elf_begin(efd, ELF_C_READ, NULL)) == NULL) {
dprintf(1, "elf_begin failed\n");
close(efd);
return;
}
elf_getshdrstrndx(e, &shstridx);
dof = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
gelf_getshdr(scn, &shdr);
if (shdr.sh_type == SHT_SYMTAB) {
symtabidx = shdr.sh_link;
symtabdata = elf_getdata(scn, NULL);
} else if (shdr.sh_type == SHT_DYNSYM) {
dynsymidx = shdr.sh_link;
dynsymdata = elf_getdata(scn, NULL);
} else if (shdr.sh_type == SHT_PROGBITS) {
s = elf_strptr(e, shstridx, shdr.sh_name);
if (s && strcmp(s, ".SUNW_dof") == 0) {
dof = elf_getdata(scn, NULL)->d_buf;
}
}
}
if (dof == NULL) {
dprintf(1, "SUNW_dof section not found\n");
elf_end(e);
close(efd);
return;
}
#endif
if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
@ -158,7 +247,7 @@ dtrace_dof_init(void)
if ((fd = open64(devnamep, O_RDWR)) < 0) {
dprintf(1, "failed to open helper device %s", devnamep);
#if defined(sun)
/*
* If the device path wasn't explicitly set, try again with
* the old device path.
@ -172,14 +261,79 @@ dtrace_dof_init(void)
dprintf(1, "failed to open helper device %s", devnamep);
return;
}
#else
return;
#endif
}
#if !defined(sun)
/*
* We need to fix the base address of each probe since this wasn't
* done by ld(1). (ld(1) needs to grow support for parsing the
* SUNW_dof section).
*
* The complexity of this is not that great. The first for loop
* iterates over the sections inside the DOF file. There are usually
* 10 sections here. We asume the STRTAB section comes first and the
* PROBES section comes after. Since we are only interested in fixing
* data inside the PROBES section we quit the for loop after processing
* the PROBES section. It's usually the case that the first section
* is the STRTAB section and the second section is the PROBES section,
* so this for loop is not meaningful when doing complexity analysis.
*
* After finding the probes section, we iterate over the symbols
* in the symtab section. When we find a symbol name that matches
* the probe function name, we fix it. If we have fixed all the
* probes, we exit all the loops and we are done.
* The number of probes is given by the variable 'nprobes' and this
* depends entirely on the user, but some optimizations were done.
*
* We are assuming the number of probes is less than the number of
* symbols (libc can have 4k symbols, for example).
*/
sec = (dof_sec_t *)(dof + 1);
buf = (char *)dof;
for (i = 0; i < dof->dofh_secnum; i++, sec++) {
if (sec->dofs_type == DOF_SECT_STRTAB)
dofstrtab = (unsigned char *)(buf + sec->dofs_offset);
else if (sec->dofs_type == DOF_SECT_PROBES && dofstrtab)
break;
}
nprobes = sec->dofs_size / sec->dofs_entsize;
fixsymbol(e, symtabdata, symtabidx, nprobes, buf, sec, &fixedprobes,
dofstrtab);
if (fixedprobes != nprobes) {
/*
* If we haven't fixed all the probes using the
* symtab section, look inside the dynsym
* section.
*/
fixsymbol(e, dynsymdata, dynsymidx, nprobes, buf, sec,
&fixedprobes, dofstrtab);
}
if (fixedprobes != nprobes) {
fprintf(stderr, "WARNING: number of probes "
"fixed does not match the number of "
"defined probes (%d != %d, "
"respectively)\n", fixedprobes, nprobes);
fprintf(stderr, "WARNING: some probes might "
"not fire or your program might crash\n");
}
#endif
if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
else
else {
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
#if !defined(sun)
gen = dh.gen;
#endif
}
(void) close(fd);
#if !defined(sun)
elf_end(e);
(void) close(efd);
#endif
}
#if defined(sun)
@ -198,7 +352,7 @@ dtrace_dof_fini(void)
return;
}
if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, gen)) == -1)
if ((gen = ioctl(fd, DTRACEHIOC_REMOVE, &gen)) == -1)
dprintf(1, "DTrace ioctl failed to remove DOF (%d)\n", gen);
else
dprintf(1, "DTrace ioctl removed DOF (%d)\n", gen);

View File

@ -36,6 +36,7 @@
#include <alloca.h>
#else
#include <sys/sysctl.h>
#include <libproc_compat.h>
#endif
#include <limits.h>
@ -264,11 +265,7 @@ dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
dt_proc_lock(dtp, P);
#if defined(sun)
if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
#else
if (proc_addr2sym(P, *pc, NULL, 0, &sym) == 0)
#endif
*pc = sym.st_value;
dt_proc_unlock(dtp, P);
@ -291,11 +288,7 @@ dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
dt_proc_lock(dtp, P);
#if defined(sun)
if ((map = Paddr_to_map(P, *pc)) != NULL)
#else
if ((map = proc_addr2map(P, *pc)) != NULL)
#endif
*pc = map->pr_vaddr;
dt_proc_unlock(dtp, P);

View File

@ -34,6 +34,9 @@
#include <alloca.h>
#endif
#include <dt_impl.h>
#if !defined(sun)
#include <libproc_compat.h>
#endif
#define DT_MASK_LO 0x00000000FFFFFFFFULL
@ -952,17 +955,9 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
if ((err = dt_printf(dtp, fp, "%*s", indent, "")) < 0)
break;
#if defined(sun)
if (P != NULL && Plookup_by_addr(P, pc[i],
#else
if (P != NULL && proc_addr2sym(P, pc[i],
#endif
name, sizeof (name), &sym) == 0) {
#if defined(sun)
(void) Pobjname(P, pc[i], objname, sizeof (objname));
#else
(void) proc_objname(P, pc[i], objname, sizeof (objname));
#endif
if (pc[i] > sym.st_value) {
(void) snprintf(c, sizeof (c),
@ -973,12 +968,8 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
"%s`%s", dt_basename(objname), name);
}
} else if (str != NULL && str[0] != '\0' && str[0] != '@' &&
#if defined(sun)
(P != NULL && ((map = Paddr_to_map(P, pc[i])) == NULL ||
(map->pr_mflags & MA_WRITE)))) {
#else
(P != NULL && ((map = proc_addr2map(P, pc[i])) == NULL))) {
#endif
/*
* If the current string pointer in the string table
* does not point to an empty string _and_ the program
@ -994,11 +985,7 @@ dt_print_ustack(dtrace_hdl_t *dtp, FILE *fp, const char *format,
*/
(void) snprintf(c, sizeof (c), "%s", str);
} else {
#if defined(sun)
if (P != NULL && Pobjname(P, pc[i], objname,
#else
if (P != NULL && proc_objname(P, pc[i], objname,
#endif
sizeof (objname)) != 0) {
(void) snprintf(c, sizeof (c), "%s`0x%llx",
dt_basename(objname), (u_longlong_t)pc[i]);
@ -1068,11 +1055,7 @@ dt_print_usym(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr, dtrace_actkind_t act)
dt_proc_lock(dtp, P);
#if defined(sun)
if (Plookup_by_addr(P, pc, NULL, 0, &sym) == 0)
#else
if (proc_addr2sym(P, pc, NULL, 0, &sym) == 0)
#endif
pc = sym.st_value;
dt_proc_unlock(dtp, P);
@ -1115,11 +1098,7 @@ dt_print_umod(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
if (P != NULL)
dt_proc_lock(dtp, P); /* lock handle while we perform lookups */
#if defined(sun)
if (P != NULL && Pobjname(P, pc, objname, sizeof (objname)) != 0) {
#else
if (P != NULL && proc_objname(P, pc, objname, sizeof (objname)) != 0) {
#endif
(void) snprintf(c, sizeof (c), "%s", dt_basename(objname));
} else {
(void) snprintf(c, sizeof (c), "0x%llx", (u_longlong_t)pc);

View File

@ -51,6 +51,9 @@
#include <wait.h>
#else
#include <sys/wait.h>
#include <libelf.h>
#include <gelf.h>
#include <sys/mman.h>
#endif
#include <assert.h>
#include <sys/ipc.h>
@ -412,7 +415,6 @@ prepare_elf64(dtrace_hdl_t *dtp, const dof_hdr_t *dof, dof_elf64_t *dep)
s = &dofs[dofrh->dofr_tgtsec];
for (j = 0; j < nrel; j++) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
#if defined(__arm__)
/* XXX */
@ -1519,14 +1521,29 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
off = rela.r_offset - fsym.st_value;
if (dt_modtext(dtp, data_tgt->d_buf, eprobe,
&rela, &off) != 0) {
&rela, &off) != 0)
goto err;
}
if (dt_probe_define(pvp, prp, s, r, off, eprobe) != 0) {
return (dt_link_error(dtp, elf, fd, bufs,
"failed to allocate space for probe"));
}
#if !defined(sun)
/*
* Our linker doesn't understand the SUNW_IGNORE ndx and
* will try to use this relocation when we build the
* final executable. Since we are done processing this
* relocation, mark it as inexistant and let libelf
* remove it from the file.
* If this wasn't done, we would have garbage added to
* the executable file as the symbol is going to be
* change from UND to ABS.
*/
rela.r_offset = 0;
rela.r_info = 0;
rela.r_addend = 0;
(void) gelf_update_rela(data_rel, i, &rela);
#endif
mod = 1;
(void) elf_flagdata(data_tgt, ELF_C_SET, ELF_F_DIRTY);
@ -1538,13 +1555,13 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
* already been processed by an earlier link
* invocation.
*/
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
#if !defined(sun)
#define SHN_SUNW_IGNORE SHN_ABS
#endif
if (rsym.st_shndx != SHN_SUNW_IGNORE) {
rsym.st_shndx = SHN_SUNW_IGNORE;
(void) gelf_update_sym(data_sym, ndx, &rsym);
}
#endif
}
}
@ -1554,6 +1571,9 @@ printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
(void) elf_end(elf);
(void) close(fd);
#if !defined(sun)
if (nsym > 0)
#endif
while ((pair = bufs) != NULL) {
bufs = pair->dlp_next;
dt_free(dtp, pair->dlp_str);
@ -1574,6 +1594,19 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
{
#if !defined(sun)
char tfile[PATH_MAX];
Elf *e;
Elf_Scn *scn;
Elf_Data *data;
GElf_Shdr shdr;
int efd;
size_t stridx;
unsigned char *buf;
char *s;
int loc;
GElf_Ehdr ehdr;
Elf_Scn *scn0;
GElf_Shdr shdr0;
uint64_t off, rc;
#endif
char drti[PATH_MAX];
dof_hdr_t *dof;
@ -1697,12 +1730,17 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
(void) unlink(file);
#endif
#if defined(sun)
if (dtp->dt_oflags & DTRACE_O_LP64)
status = dump_elf64(dtp, dof, fd);
else
status = dump_elf32(dtp, dof, fd);
if (status != 0 || lseek(fd, 0, SEEK_SET) != 0) {
#else
/* We don't write the ELF header, just the DOF section */
if (dt_write(dtp, fd, dof, dof->dofh_filesz) < dof->dofh_filesz) {
#endif
return (dt_link_error(dtp, NULL, -1, NULL,
"failed to write %s: %s", file, strerror(errno)));
}
@ -1726,7 +1764,7 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, fd, drti);
#else
const char *fmt = "%s -o %s -r %s %s";
const char *fmt = "%s -o %s -r %s";
#if defined(__amd64__)
/*
@ -1748,11 +1786,14 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
len = snprintf(&tmp, 1, fmt, dtp->dt_ld_path, file, tfile,
drti) + 1;
#if !defined(sun)
len *= 2;
#endif
cmd = alloca(len);
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file, tfile, drti);
(void) snprintf(cmd, len, fmt, dtp->dt_ld_path, file,
drti);
#endif
if ((status = system(cmd)) == -1) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to run %s: %s", dtp->dt_ld_path,
@ -1760,8 +1801,6 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
goto done;
}
(void) close(fd); /* release temporary file */
if (WIFSIGNALED(status)) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to link %s: %s failed due to signal %d",
@ -1775,6 +1814,138 @@ dtrace_program_link(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t dflags,
file, dtp->dt_ld_path, WEXITSTATUS(status));
goto done;
}
#if !defined(sun)
#define BROKEN_LIBELF
/*
* FreeBSD's ld(1) is not instructed to interpret and add
* correctly the SUNW_dof section present in tfile.
* We use libelf to add this section manually and hope the next
* ld invocation won't remove it.
*/
elf_version(EV_CURRENT);
if ((efd = open(file, O_RDWR, 0)) < 0) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to open file %s: %s",
file, strerror(errno));
goto done;
}
if ((e = elf_begin(efd, ELF_C_RDWR, NULL)) == NULL) {
close(efd);
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to open elf file: %s",
elf_errmsg(elf_errno()));
goto done;
}
/*
* Add the string '.SUWN_dof' to the shstrtab section.
*/
#ifdef BROKEN_LIBELF
elf_flagelf(e, ELF_C_SET, ELF_F_LAYOUT);
#endif
elf_getshdrstrndx(e, &stridx);
scn = elf_getscn(e, stridx);
gelf_getshdr(scn, &shdr);
data = elf_newdata(scn);
data->d_off = shdr.sh_size;
data->d_buf = ".SUNW_dof";
data->d_size = 10;
data->d_type = ELF_T_BYTE;
loc = shdr.sh_size;
shdr.sh_size += data->d_size;
gelf_update_shdr(scn, &shdr);
#ifdef BROKEN_LIBELF
off = shdr.sh_offset;
rc = shdr.sh_offset + shdr.sh_size;
gelf_getehdr(e, &ehdr);
if (ehdr.e_shoff > off) {
off = ehdr.e_shoff + ehdr.e_shnum * ehdr.e_shentsize;
rc = roundup(rc, 8);
ehdr.e_shoff = rc;
gelf_update_ehdr(e, &ehdr);
rc += ehdr.e_shnum * ehdr.e_shentsize;
}
for (;;) {
scn0 = NULL;
scn = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
gelf_getshdr(scn, &shdr);
if (shdr.sh_type == SHT_NOBITS ||
shdr.sh_offset < off)
continue;
/* Find the immediately adjcent section. */
if (scn0 == NULL ||
shdr.sh_offset < shdr0.sh_offset) {
scn0 = scn;
gelf_getshdr(scn0, &shdr0);
}
}
if (scn0 == NULL)
break;
/* Load section data to work around another bug */
elf_getdata(scn0, NULL);
/* Update section header, assure section alignment */
off = shdr0.sh_offset + shdr0.sh_size;
rc = roundup(rc, shdr0.sh_addralign);
shdr0.sh_offset = rc;
gelf_update_shdr(scn0, &shdr0);
rc += shdr0.sh_size;
}
if (elf_update(e, ELF_C_WRITE) < 0) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to add append the shstrtab section: %s",
elf_errmsg(elf_errno()));
elf_end(e);
close(efd);
goto done;
}
elf_end(e);
e = elf_begin(efd, ELF_C_RDWR, NULL);
#endif
/*
* Construct the .SUNW_dof section.
*/
scn = elf_newscn(e);
data = elf_newdata(scn);
buf = mmap(NULL, dof->dofh_filesz, PROT_READ, MAP_SHARED,
fd, 0);
if (buf == MAP_FAILED) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to mmap buffer %s", strerror(errno));
elf_end(e);
close(efd);
goto done;
}
data->d_buf = buf;
data->d_align = 4;
data->d_size = dof->dofh_filesz;
data->d_version = EV_CURRENT;
gelf_getshdr(scn, &shdr);
shdr.sh_name = loc;
shdr.sh_flags = SHF_ALLOC;
/*
* Actually this should be SHT_SUNW_dof, but FreeBSD's ld(1)
* will remove this 'unknown' section when we try to create an
* executable using the object we are modifying, so we stop
* playing by the rules and use SHT_PROGBITS.
* Also, note that our drti has modifications to handle this.
*/
shdr.sh_type = SHT_PROGBITS;
shdr.sh_addralign = 4;
gelf_update_shdr(scn, &shdr);
if (elf_update(e, ELF_C_WRITE) < 0) {
ret = dt_link_error(dtp, NULL, -1, NULL,
"failed to add the SUNW_dof section: %s",
elf_errmsg(elf_errno()));
munmap(buf, dof->dofh_filesz);
elf_end(e);
close(efd);
goto done;
}
munmap(buf, dof->dofh_filesz);
elf_end(e);
close(efd);
#endif
(void) close(fd); /* release temporary file */
} else {
(void) close(fd);
}

View File

@ -283,10 +283,8 @@ static const dt_ident_t _dtrace_globals[] = {
DT_VERS_1_5, &dt_idops_func, "string(int, void *)" },
{ "ipl", DT_IDENT_SCALAR, 0, DIF_VAR_IPL, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_type, "uint_t" },
#if defined(sun)
{ "jstack", DT_IDENT_ACTFUNC, 0, DT_ACT_JSTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "stack(...)" },
#endif
{ "lltostr", DT_IDENT_FUNC, 0, DIF_SUBR_LLTOSTR, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_func, "string(int64_t)" },
{ "lquantize", DT_IDENT_AGGFUNC, 0, DTRACEAGG_LQUANTIZE,
@ -465,8 +463,10 @@ static const dt_ident_t _dtrace_globals[] = {
#if defined(sun)
{ "uaddr", DT_IDENT_ACTFUNC, 0, DT_ACT_UADDR, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
{ "ucaller", DT_IDENT_SCALAR, 0, DIF_VAR_UCALLER, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_type, "uint64_t" },
#if defined(sun)
{ "ufunc", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
@ -475,6 +475,7 @@ static const dt_ident_t _dtrace_globals[] = {
#if defined(sun)
{ "umod", DT_IDENT_ACTFUNC, 0, DT_ACT_UMOD, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
{ "uregs", DT_IDENT_ARRAY, 0, DIF_VAR_UREGS, DT_ATTR_STABCMN, DT_VERS_1_0,
&dt_idops_regs, NULL },
{ "ustack", DT_IDENT_ACTFUNC, 0, DT_ACT_USTACK, DT_ATTR_STABCMN, DT_VERS_1_0,
@ -482,6 +483,7 @@ static const dt_ident_t _dtrace_globals[] = {
{ "ustackdepth", DT_IDENT_SCALAR, 0, DIF_VAR_USTACKDEPTH,
DT_ATTR_STABCMN, DT_VERS_1_2,
&dt_idops_type, "uint32_t" },
#if defined(sun)
{ "usym", DT_IDENT_ACTFUNC, 0, DT_ACT_USYM, DT_ATTR_STABCMN,
DT_VERS_1_2, &dt_idops_func, "_usymaddr(uintptr_t)" },
#endif
@ -760,9 +762,7 @@ int _dtrace_argmax = 32; /* default maximum number of probe arguments */
int _dtrace_debug = 0; /* debug messages enabled (off) */
const char *const _dtrace_version = DT_VERS_STRING; /* API version string */
#if defined(sun)
int _dtrace_rdvers = RD_VERSION; /* rtld_db feature version */
#endif
typedef struct dt_fdlist {
int *df_fds; /* array of provider driver file descriptors */
@ -780,12 +780,10 @@ _dtrace_init(void)
{
_dtrace_debug = getenv("DTRACE_DEBUG") != NULL;
#if defined(sun)
for (; _dtrace_rdvers > 0; _dtrace_rdvers--) {
if (rd_init(_dtrace_rdvers) == RD_OK)
break;
}
#endif
#if defined(__i386__)
/* make long doubles 64 bits -sson */
(void) fpsetprec(FP_PE);
@ -1102,7 +1100,11 @@ dt_vopen(int version, int flags, int *errp,
bzero(dtp, sizeof (dtrace_hdl_t));
dtp->dt_oflags = flags;
#if defined(sun)
dtp->dt_prcmode = DT_PROC_STOP_PREINIT;
#else
dtp->dt_prcmode = DT_PROC_STOP_POSTINIT;
#endif
dtp->dt_linkmode = DT_LINK_KERNEL;
dtp->dt_linktype = DT_LTYP_ELF;
dtp->dt_xlatemode = DT_XL_STATIC;

View File

@ -40,6 +40,9 @@
#include <dt_program.h>
#include <dt_pid.h>
#include <dt_string.h>
#if !defined(sun)
#include <libproc_compat.h>
#endif
typedef struct dt_pid_probe {
dtrace_hdl_t *dpp_dtp;
@ -142,7 +145,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
pp->dpp_obj);
if (!isdash && gmatch("return", pp->dpp_name)) {
#ifdef DOODAD
if (dt_pid_create_return_probe(pp->dpp_pr, dtp, ftp, symp,
pp->dpp_stret) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@ -150,20 +152,17 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
"for '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
if (!isdash && gmatch("entry", pp->dpp_name)) {
#ifdef DOODAD
if (dt_pid_create_entry_probe(pp->dpp_pr, dtp, ftp, symp) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
D_PROC_CREATEFAIL, "failed to create entry probe "
"for '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
@ -182,10 +181,8 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
(u_longlong_t)off, func));
}
#ifdef DOODAD
err = dt_pid_create_offset_probe(pp->dpp_pr, pp->dpp_dtp, ftp,
symp, off);
#endif
if (err == DT_PROC_ERR) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@ -203,7 +200,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
nmatches++;
} else if (glob && !isdash) {
#ifdef DOODAD
if (dt_pid_create_glob_offset_probes(pp->dpp_pr,
pp->dpp_dtp, ftp, symp, pp->dpp_name) < 0) {
return (dt_pid_error(dtp, pcb, dpr, ftp,
@ -211,7 +207,6 @@ dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
"failed to create offset probes in '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
@ -279,7 +274,6 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
pp->dpp_obj = obj;
else
pp->dpp_obj++;
#if defined(sun)
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret1", &sym,
NULL) == 0)
@ -305,25 +299,10 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
else
pp->dpp_stret[3] = 0;
#else
if (proc_name2sym(pp->dpp_pr, obj, ".stret1", &sym) == 0)
pp->dpp_stret[0] = sym.st_value;
else
pp->dpp_stret[0] = 0;
if (proc_name2sym(pp->dpp_pr, obj, ".stret2", &sym) == 0)
pp->dpp_stret[1] = sym.st_value;
else
pp->dpp_stret[1] = 0;
if (proc_name2sym(pp->dpp_pr, obj, ".stret4", &sym) == 0)
pp->dpp_stret[2] = sym.st_value;
else
pp->dpp_stret[2] = 0;
if (proc_name2sym(pp->dpp_pr, obj, ".stret8", &sym) == 0)
pp->dpp_stret[3] = sym.st_value;
else
pp->dpp_stret[3] = 0;
pp->dpp_stret[0] = 0;
pp->dpp_stret[1] = 0;
pp->dpp_stret[2] = 0;
pp->dpp_stret[3] = 0;
#endif
dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
@ -345,12 +324,8 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
* just fail silently in the hopes that some other object will
* contain the desired symbol.
*/
#if defined(sun)
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj,
pp->dpp_func, &sym, NULL) != 0) {
#else
if (proc_name2sym(pp->dpp_pr, obj, pp->dpp_func, &sym) != 0) {
#endif
if (strcmp("-", pp->dpp_func) == 0) {
sym.st_name = 0;
sym.st_info =
@ -390,16 +365,11 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
return (0);
#endif
#if defined(sun)
(void) Plookup_by_addr(pp->dpp_pr, sym.st_value, pp->dpp_func,
#else
(void) proc_addr2sym(pp->dpp_pr, sym.st_value, pp->dpp_func,
#endif
DTRACE_FUNCNAMELEN, &sym);
return (dt_pid_per_sym(pp, &sym, pp->dpp_func));
} else {
#ifdef DOODAD
uint_t nmatches = pp->dpp_nmatches;
if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_SYMTAB,
@ -415,7 +385,6 @@ dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
return (1);
}
#endif
}
return (0);
@ -459,14 +428,16 @@ dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
static const prmap_t *
dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
{
#ifdef DOODAD
char m[MAXPATHLEN];
#if defined(sun)
Lmid_t lmid = PR_LMID_EVERY;
const char *obj;
#else
Lmid_t lmid = 0;
#endif
const char *obj;
const prmap_t *pmp;
#ifdef DOODAD
#if defined(sun)
/*
* Pick apart the link map from the library name.
*/
@ -487,10 +458,14 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
} else {
obj = pdp->dtpd_mod;
}
#else
obj = pdp->dtpd_mod;
#endif
if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
return (NULL);
#if defined(sun)
(void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
if ((obj = strrchr(m, '/')) == NULL)
obj = &m[0];
@ -498,11 +473,9 @@ dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
obj++;
(void) Plmid(P, pmp->pr_vaddr, &lmid);
#endif
dt_pid_objname(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), lmid, obj);
#else
pmp = NULL;
#endif
return (pmp);
}
@ -544,13 +517,8 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
pp.dpp_mod = pdp->dtpd_mod;
(void) strcpy(pdp->dtpd_mod, "a.out");
} else if (strisglob(pp.dpp_mod) ||
#if defined(sun)
(aout = Pname_to_map(pp.dpp_pr, "a.out")) == NULL ||
(pmp = Pname_to_map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
#else
(aout = proc_name2map(pp.dpp_pr, "a.out")) == NULL ||
(pmp = proc_name2map(pp.dpp_pr, pp.dpp_mod)) == NULL ||
#endif
aout->pr_vaddr != pmp->pr_vaddr) {
return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_LIB,
"only the a.out module is valid with the "
@ -569,7 +537,6 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
* to iterate over each module and compare its name against the
* pattern. An empty module name is treated as '*'.
*/
#ifdef DOODAD
if (strisglob(pp.dpp_mod)) {
ret = Pobject_iter(pp.dpp_pr, dt_pid_mod_filt, &pp);
} else {
@ -590,7 +557,6 @@ dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
ret = dt_pid_per_mod(&pp, pmp, obj);
}
}
#endif
return (ret);
}
@ -616,12 +582,8 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
* run the code to instantiate these providers.
*/
for (i = 0; i < 2; i++) {
#if defined(sun)
if (Pxlookup_by_name(P, PR_LMID_EVERY, oname, syms[i], &sym,
&sip) != 0) {
#else
if (proc_name2sym(P, oname, syms[i], &sym) != 0) {
#endif
continue;
}
@ -632,13 +594,11 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
dt_dprintf("lookup of %s succeeded for %s\n", syms[i], mname);
#ifdef DOODAD
if (Pread(P, &e_type, sizeof (e_type), pmp->pr_vaddr +
offsetof(Elf64_Ehdr, e_type)) != sizeof (e_type)) {
dt_dprintf("read of ELF header failed");
continue;
}
#endif
dh.dofhp_dof = sym.st_value;
dh.dofhp_addr = (e_type == ET_EXEC) ? 0 : pmp->pr_vaddr;
@ -650,7 +610,7 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
0, mname);
#endif
#ifdef DOODAD
#if defined(sun)
if (fd == -1 &&
(fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("pr_open of helper device failed: %s\n",
@ -663,7 +623,7 @@ dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
#endif
}
#ifdef DOODAD
#if defined(sun)
if (fd != -1)
(void) pr_close(P, fd);
#endif
@ -679,9 +639,9 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
int ret = 0;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#ifdef DOODAD
#if defined(sun)
(void) Pupdate_maps(P);
#endif
if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
ret = -1;
(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
@ -692,7 +652,6 @@ dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
(int)proc_getpid(P), strerror(errno));
#endif
}
#endif
/*
* Put the module name in its canonical form.

View File

@ -89,10 +89,15 @@
#include <dt_pid.h>
#include <dt_impl.h>
#if !defined(sun)
#include <sys/syscall.h>
#include <libproc_compat.h>
#define SYS_forksys SYS_fork
#endif
#define IS_SYS_EXEC(w) (w == SYS_execve)
#define IS_SYS_FORK(w) (w == SYS_vfork || w == SYS_forksys)
#ifdef DOODAD
static dt_bkpt_t *
dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
{
@ -114,53 +119,62 @@ dt_proc_bpcreate(dt_proc_t *dpr, uintptr_t addr, dt_bkpt_f *func, void *data)
return (dbp);
}
#endif
static void
dt_proc_bpdestroy(dt_proc_t *dpr, int delbkpts)
{
#if defined(sun)
int state = Pstate(dpr->dpr_proc);
#else
int state = proc_state(dpr->dpr_proc);
#endif
dt_bkpt_t *dbp, *nbp;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
for (dbp = dt_list_next(&dpr->dpr_bps); dbp != NULL; dbp = nbp) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (delbkpts && dbp->dbp_active &&
state != PS_LOST && state != PS_UNDEAD) {
(void) Pdelbkpt(dpr->dpr_proc,
dbp->dbp_addr, dbp->dbp_instr);
}
#endif
nbp = dt_list_next(dbp);
dt_list_delete(&dpr->dpr_bps, dbp);
dt_free(dpr->dpr_hdl, dbp);
}
}
#ifdef DOODAD
static void
dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
#if defined(sun)
const lwpstatus_t *psp = &Pstatus(dpr->dpr_proc)->pr_lwp;
#else
unsigned long pc;
#endif
dt_bkpt_t *dbp;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#if !defined(sun)
proc_regget(dpr->dpr_proc, REG_PC, &pc);
proc_bkptregadj(&pc);
#endif
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
#if defined(sun)
if (psp->pr_reg[R_PC] == dbp->dbp_addr)
break;
#else
if (pc == dbp->dbp_addr)
break;
#endif
}
if (dbp == NULL) {
dt_dprintf("pid %d: spurious breakpoint wakeup for %lx\n",
#if defined(sun)
(int)dpr->dpr_pid, (ulong_t)psp->pr_reg[R_PC]);
#else
(int)dpr->dpr_pid, pc);
#endif
return;
}
@ -170,7 +184,6 @@ dt_proc_bpmatch(dtrace_hdl_t *dtp, dt_proc_t *dpr)
dbp->dbp_func(dtp, dpr, dbp->dbp_data);
(void) Pxecbkpt(dpr->dpr_proc, dbp->dbp_instr);
}
#endif
static void
dt_proc_bpenable(dt_proc_t *dpr)
@ -181,12 +194,9 @@ dt_proc_bpenable(dt_proc_t *dpr)
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (!dbp->dbp_active && Psetbkpt(dpr->dpr_proc,
dbp->dbp_addr, &dbp->dbp_instr) == 0)
dbp->dbp_active = B_TRUE;
#endif
}
dt_dprintf("breakpoints enabled\n");
@ -201,12 +211,9 @@ dt_proc_bpdisable(dt_proc_t *dpr)
for (dbp = dt_list_next(&dpr->dpr_bps);
dbp != NULL; dbp = dt_list_next(dbp)) {
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
if (dbp->dbp_active && Pdelbkpt(dpr->dpr_proc,
dbp->dbp_addr, dbp->dbp_instr) == 0)
dbp->dbp_active = B_FALSE;
#endif
}
dt_dprintf("breakpoints disabled\n");
@ -279,7 +286,6 @@ dt_proc_bpmain(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *fname)
dt_proc_stop(dpr, DT_PROC_STOP_MAIN);
}
#if defined(sun)
static void
dt_proc_rdevent(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *evname)
{
@ -336,7 +342,12 @@ dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
}
(void) dt_proc_bpcreate(dpr, rdn.u.bptaddr,
#if defined(sun)
(dt_bkpt_f *)dt_proc_rdevent, (void *)evname);
#else
/* XXX ugly */
(dt_bkpt_f *)dt_proc_rdevent, __DECONST(void *, evname));
#endif
}
/*
@ -346,25 +357,34 @@ dt_proc_rdwatch(dt_proc_t *dpr, rd_event_e event, const char *evname)
static void
dt_proc_attach(dt_proc_t *dpr, int exec)
{
#if defined(sun)
const pstatus_t *psp = Pstatus(dpr->dpr_proc);
#endif
rd_err_e err;
GElf_Sym sym;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
if (exec) {
#if defined(sun)
if (psp->pr_lwp.pr_errno != 0)
return; /* exec failed: nothing needs to be done */
#endif
dt_proc_bpdestroy(dpr, B_FALSE);
#if defined(sun)
Preset_maps(dpr->dpr_proc);
#endif
}
if ((dpr->dpr_rtld = Prd_agent(dpr->dpr_proc)) != NULL &&
(err = rd_event_enable(dpr->dpr_rtld, B_TRUE)) == RD_OK) {
#if defined(sun)
dt_proc_rdwatch(dpr, RD_PREINIT, "RD_PREINIT");
#endif
dt_proc_rdwatch(dpr, RD_POSTINIT, "RD_POSTINIT");
#if defined(sun)
dt_proc_rdwatch(dpr, RD_DLACTIVITY, "RD_DLACTIVITY");
#endif
} else {
dt_dprintf("pid %d: failed to enable rtld events: %s\n",
(int)dpr->dpr_pid, dpr->dpr_rtld ? rd_errstr(err) :
@ -406,6 +426,8 @@ dt_proc_attach(dt_proc_t *dpr, int exec)
static void
dt_proc_waitrun(dt_proc_t *dpr)
{
printf("%s:%s(%d): DOODAD\n",__FUNCTION__,__FILE__,__LINE__);
#ifdef DOODAD
struct ps_prochandle *P = dpr->dpr_proc;
const lwpstatus_t *psp = &Pstatus(P)->pr_lwp;
@ -455,8 +477,8 @@ dt_proc_waitrun(dt_proc_t *dpr)
}
(void) pthread_mutex_lock(&dpr->dpr_lock);
}
#endif
}
typedef struct dt_proc_control_data {
dtrace_hdl_t *dpcd_hdl; /* DTrace handle */
@ -533,13 +555,18 @@ dt_proc_control(void *arg)
(void) Psysexit(P, SYS_forksys, B_TRUE);
Psync(P); /* enable all /proc changes */
#endif
dt_proc_attach(dpr, B_FALSE); /* enable rtld breakpoints */
/*
* If PR_KLC is set, we created the process; otherwise we grabbed it.
* Check for an appropriate stop request and wait for dt_proc_continue.
*/
#if defined(sun)
if (Pstatus(P)->pr_flags & PR_KLC)
#else
if (proc_getflags(P) & PR_KLC)
#endif
dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
else
dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
@ -548,20 +575,6 @@ dt_proc_control(void *arg)
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
}
#else
/*
* If PR_KLC is set, we created the process; otherwise we grabbed it.
* Check for an appropriate stop request and wait for dt_proc_continue.
*/
if (proc_getflags(P) & PR_KLC)
dt_proc_stop(dpr, DT_PROC_STOP_CREATE);
else
dt_proc_stop(dpr, DT_PROC_STOP_GRAB);
if (proc_continue(P) != 0)
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
#endif
(void) pthread_mutex_unlock(&dpr->dpr_lock);
@ -575,14 +588,16 @@ dt_proc_control(void *arg)
* Pwait() (which will return immediately) and do our processing.
*/
while (!dpr->dpr_quit) {
#if defined(sun)
const lwpstatus_t *psp;
#if defined(sun)
if (write(pfd, &wstop, sizeof (wstop)) == -1 && errno == EINTR)
continue; /* check dpr_quit and continue waiting */
#else
/* Wait for the process to report status. */
proc_wstatus(P);
if (errno == EINTR)
continue; /* check dpr_quit and continue waiting */
#endif
(void) pthread_mutex_lock(&dpr->dpr_lock);
@ -595,14 +610,13 @@ dt_proc_control(void *arg)
}
#endif
#if defined(sun)
switch (Pstate(P)) {
#else
switch (proc_state(P)) {
#endif
case PS_STOP:
#ifdef DOODAD
#if defined(sun)
psp = &Pstatus(P)->pr_lwp;
#else
psp = proc_getlwpstatus(P);
#endif
dt_dprintf("pid %d: proc stopped showing %d/%d\n",
pid, psp->pr_why, psp->pr_what);
@ -644,7 +658,6 @@ dt_proc_control(void *arg)
else if (psp->pr_why == PR_SYSEXIT &&
IS_SYS_EXEC(psp->pr_what))
dt_proc_attach(dpr, B_TRUE);
#endif
break;
case PS_LOST:
@ -667,12 +680,10 @@ dt_proc_control(void *arg)
break;
}
#if defined(sun)
if (Pstate(P) != PS_UNDEAD && Psetrun(P, 0, 0) == -1) {
dt_dprintf("pid %d: failed to set running: %s\n",
(int)dpr->dpr_pid, strerror(errno));
}
#endif
(void) pthread_mutex_unlock(&dpr->dpr_lock);
}
@ -712,11 +723,7 @@ dt_proc_error(dtrace_hdl_t *dtp, dt_proc_t *dpr, const char *format, ...)
va_end(ap);
if (dpr->dpr_proc != NULL)
#if defined(sun)
Prelease(dpr->dpr_proc, 0);
#else
proc_detach(dpr->dpr_proc, 0);
#endif
dt_free(dtp, dpr);
(void) dt_set_errno(dtp, EDT_COMPILER);
@ -804,7 +811,7 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
#if defined(sun)
(void) _lwp_kill(dpr->dpr_tid, SIGCANCEL);
#else
(void) pthread_kill(dpr->dpr_tid, SIGUSR1);
pthread_kill(dpr->dpr_tid, SIGUSR1);
#endif
/*
@ -853,11 +860,7 @@ dt_proc_destroy(dtrace_hdl_t *dtp, struct ps_prochandle *P)
}
dt_list_delete(&dph->dph_lrulist, dpr);
#if defined(sun)
Prelease(dpr->dpr_proc, rflag);
#else
proc_detach(dpr->dpr_proc, rflag);
#endif
dt_free(dtp, dpr);
}
@ -912,18 +915,15 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
#if defined(sun)
const psinfo_t *prp = Ppsinfo(dpr->dpr_proc);
int stat = prp ? prp->pr_wstat : 0;
#endif
int pid = dpr->dpr_pid;
#if defined(sun)
if (Pstate(dpr->dpr_proc) == PS_LOST) {
#else
if (proc_state(dpr->dpr_proc) == PS_LOST) {
int stat = proc_getwstat(dpr->dpr_proc);
int pid = proc_getpid(dpr->dpr_proc);
#endif
if (proc_state(dpr->dpr_proc) == PS_LOST) {
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process exec'd "
"set-id or unobservable program\n", pid);
#if defined(sun)
} else if (WIFSIGNALED(stat)) {
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process died "
@ -932,7 +932,6 @@ dt_proc_create_thread(dtrace_hdl_t *dtp, dt_proc_t *dpr, uint_t stop)
(void) dt_proc_error(dpr->dpr_hdl, dpr,
"failed to control pid %d: process exited "
"with status %d\n", pid, WEXITSTATUS(stat));
#endif
}
err = ESRCH; /* cause grab() or create() to fail */
@ -965,30 +964,25 @@ dt_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
#if defined(sun)
if ((dpr->dpr_proc = Pcreate(file, argv, &err, NULL, 0)) == NULL) {
#else
if ((err = proc_create(file, argv, pcf, child_arg,
&dpr->dpr_proc)) != 0) {
#endif
return (dt_proc_error(dtp, dpr,
"failed to execute %s: %s\n", file, Pcreate_error(err)));
}
dpr->dpr_hdl = dtp;
#if defined(sun)
dpr->dpr_pid = Pstatus(dpr->dpr_proc)->pr_pid;
(void) Punsetflags(dpr->dpr_proc, PR_RLC);
(void) Psetflags(dpr->dpr_proc, PR_KLC);
#else
(void) proc_clearflags(dpr->dpr_proc, PR_RLC);
(void) proc_setflags(dpr->dpr_proc, PR_KLC);
if ((err = proc_create(file, argv, pcf, child_arg, &dpr->dpr_proc)) != 0)
return (dt_proc_error(dtp, dpr,
"failed to execute %s: %s\n", file, strerror(err)));
dpr->dpr_hdl = dtp;
dpr->dpr_pid = proc_getpid(dpr->dpr_proc);
#endif
#if defined(sun)
(void) Punsetflags(dpr->dpr_proc, PR_RLC);
(void) Psetflags(dpr->dpr_proc, PR_KLC);
if (dt_proc_create_thread(dtp, dpr, dtp->dt_prcmode) != 0)
#else
if (dt_proc_create_thread(dtp, dpr, DT_PROC_STOP_IDLE) != 0)
#endif
return (NULL); /* dt_proc_error() has been called for us */
dpr->dpr_hash = dph->dph_hash[dpr->dpr_pid & (dph->dph_hashlen - 1)];
@ -1046,25 +1040,18 @@ dt_proc_grab(dtrace_hdl_t *dtp, pid_t pid, int flags, int nomonitor)
#if defined(sun)
if ((dpr->dpr_proc = Pgrab(pid, flags, &err)) == NULL) {
#else
if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0) {
#endif
return (dt_proc_error(dtp, dpr,
"failed to grab pid %d: %s\n", (int)pid, Pgrab_error(err)));
}
#else
if ((err = proc_attach(pid, flags, &dpr->dpr_proc)) != 0)
return (dt_proc_error(dtp, dpr,
"failed to grab pid %d: %s\n", (int) pid, strerror(err)));
#endif
dpr->dpr_hdl = dtp;
dpr->dpr_pid = pid;
#if defined(sun)
(void) Punsetflags(dpr->dpr_proc, PR_KLC);
(void) Psetflags(dpr->dpr_proc, PR_RLC);
#else
(void) proc_clearflags(dpr->dpr_proc, PR_KLC);
(void) proc_setflags(dpr->dpr_proc, PR_RLC);
#endif
/*
* If we are attempting to grab the process without a monitor
@ -1185,12 +1172,13 @@ dtrace_proc_create(dtrace_hdl_t *dtp, const char *file, char *const *argv,
dt_ident_t *idp = dt_idhash_lookup(dtp->dt_macros, "target");
struct ps_prochandle *P = dt_proc_create(dtp, file, argv, pcf, child_arg);
if (P != NULL && idp != NULL && idp->di_id == 0)
if (P != NULL && idp != NULL && idp->di_id == 0) {
#if defined(sun)
idp->di_id = Pstatus(P)->pr_pid; /* $target = created pid */
#else
idp->di_id = proc_getpid(P); /* $target = created pid */
#endif
}
return (P);
}

View File

@ -44,9 +44,7 @@ typedef struct dt_proc {
dtrace_hdl_t *dpr_hdl; /* back pointer to libdtrace handle */
struct ps_prochandle *dpr_proc; /* proc handle for libproc calls */
char dpr_errmsg[BUFSIZ]; /* error message */
#if defined(sun)
rd_agent_t *dpr_rtld; /* rtld handle for librtld_db calls */
#endif
pthread_mutex_t dpr_lock; /* lock for manipulating dpr_hdl */
pthread_cond_t dpr_cv; /* cond for dpr_stop/quit/done */
pid_t dpr_pid; /* pid of process */

View File

@ -40,6 +40,7 @@
#include <alloca.h>
#else
#include <sys/sysctl.h>
#include <libproc_compat.h>
#endif
#include <assert.h>
#include <libgen.h>
@ -963,13 +964,8 @@ dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
dt_proc_lock(dtp, P);
#if defined(sun)
if (Plookup_by_addr(P, addr, name, sizeof (name), &sym) == 0) {
(void) Pobjname(P, addr, objname, sizeof (objname));
#else
if (proc_addr2sym(P, addr, name, sizeof (name), &sym) == 0) {
(void) proc_objname(P, addr, objname, sizeof (objname));
#endif
obj = dt_basename(objname);
@ -979,11 +975,7 @@ dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
} else {
(void) snprintf(c, sizeof (c), "%s`%s", obj, name);
}
#if defined(sun)
} else if (Pobjname(P, addr, objname, sizeof (objname)) != 0) {
#else
} else if (proc_objname(P, addr, objname, sizeof (objname)) != 0) {
#endif
(void) snprintf(c, sizeof (c), "%s`0x%llx",
dt_basename(objname), addr);
} else {

View File

@ -34,6 +34,9 @@
#include <stdio.h>
#include <gelf.h>
#include <libproc.h>
#if !defined(sun)
#include <rtld_db.h>
#endif
#ifdef __cplusplus
extern "C" {

View File

@ -35,6 +35,12 @@
#include <dis_tables.h>
#if !defined(sun)
#define PR_MODEL_ILP32 1
#define PR_MODEL_LP64 2
#include <libproc_compat.h>
#endif
#define DT_POPL_EBP 0x5d
#define DT_RET 0xc3
#define DT_RET16 0xc2
@ -78,8 +84,17 @@ dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp,
{
ulong_t i;
int size;
#if defined(sun)
pid_t pid = Pstatus(P)->pr_pid;
char dmodel = Pstatus(P)->pr_dmodel;
#else
pid_t pid = proc_getpid(P);
#if __i386__
char dmodel = PR_MODEL_ILP32;
#elif __amd64__
char dmodel = PR_MODEL_LP64;
#endif
#endif
/*
* Take a pass through the function looking for a register-dependant
@ -98,6 +113,7 @@ dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp,
return (1);
}
#ifdef notyet
/*
* Register-dependant jmp instructions start with a 0xff byte
* and have the modrm.reg field set to 4. They can have an
@ -110,6 +126,7 @@ dt_pid_has_jump_table(struct ps_prochandle *P, dtrace_hdl_t *dtp,
ftp->ftps_func, i);
return (1);
}
#endif
}
return (0);
@ -123,8 +140,17 @@ dt_pid_create_return_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
uint8_t *text;
ulong_t i, end;
int size;
#if defined(sun)
pid_t pid = Pstatus(P)->pr_pid;
char dmodel = Pstatus(P)->pr_dmodel;
#else
pid_t pid = proc_getpid(P);
#if __i386__
char dmodel = PR_MODEL_ILP32;
#elif __amd64__
char dmodel = PR_MODEL_LP64;
#endif
#endif
/*
* We allocate a few extra bytes at the end so we don't have to check
@ -275,8 +301,17 @@ dt_pid_create_offset_probe(struct ps_prochandle *P, dtrace_hdl_t *dtp,
uint8_t *text;
ulong_t i;
int size;
#if defined(sun)
pid_t pid = Pstatus(P)->pr_pid;
char dmodel = Pstatus(P)->pr_dmodel;
#else
pid_t pid = proc_getpid(P);
#if __i386__
char dmodel = PR_MODEL_ILP32;
#elif __amd64__
char dmodel = PR_MODEL_LP64;
#endif
#endif
if ((text = malloc(symp->st_size)) == NULL) {
dt_dprintf("mr sparkle: malloc() failed\n");
@ -349,8 +384,17 @@ dt_pid_create_glob_offset_probes(struct ps_prochandle *P, dtrace_hdl_t *dtp,
uint8_t *text;
int size;
ulong_t i, end = symp->st_size;
#if defined(sun)
pid_t pid = Pstatus(P)->pr_pid;
char dmodel = Pstatus(P)->pr_dmodel;
#else
pid_t pid = proc_getpid(P);
#if __i386__
char dmodel = PR_MODEL_ILP32;
#elif __amd64__
char dmodel = PR_MODEL_LP64;
#endif
#endif
ftp->ftps_type = DTFTP_OFFSETS;
ftp->ftps_pc = (uintptr_t)symp->st_value;

View File

@ -18,6 +18,7 @@ SRCS= dt_aggregate.c \
dt_grammar.y \
dt_handle.c \
dt_ident.c \
dt_isadep.c \
dt_inttab.c \
dt_lex.l \
dt_link.c \
@ -41,7 +42,8 @@ SRCS= dt_aggregate.c \
dt_subr.c \
dt_work.c \
dt_xlator.c \
gmatch.c
gmatch.c \
dis_tables.c
DSRCS= errno.d \
psinfo.d \
@ -50,7 +52,8 @@ DSRCS= errno.d \
WARNS?= 1
CFLAGS+= -I${.OBJDIR} \
CFLAGS+= -I${.OBJDIR} -I${.CURDIR} \
-I${.CURDIR}/../../../sys/cddl/dev/dtrace/${MACHINE_ARCH} \
-I${.CURDIR}/../../../sys/cddl/compat/opensolaris \
-I${.CURDIR}/../../../cddl/compat/opensolaris/include \
-I${OPENSOLARIS_USR_DISTDIR}/head \
@ -61,14 +64,21 @@ CFLAGS+= -I${.OBJDIR} \
#CFLAGS+= -DYYDEBUG
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel -DDIS_MEM
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/i386
.PATH: ${.CURDIR}/../../../sys/cddl/dev/dtrace/${MACHINE_ARCH}
.elif ${MACHINE_ARCH} == "sparc64"
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/sparc
.PATH: ${.CURDIR}/../../../cddl/contrib/opensolaris/lib/libdtrace/sparc
.else
# temporary hack
CFLAGS+= -I${OPENSOLARIS_SYS_DISTDIR}/uts/intel
.endif
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64"
DSRCS+= regs_x86.d
.endif
LFLAGS+=-l
YFLAGS+=-d

View File

@ -0,0 +1,62 @@
/*
* 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$
*/
/*
* Compatibility functions between Solaris libproc and FreeBSD libproc.
* Functions sorted alphabetically.
*/
#define PR_LMID_EVERY 0
#define Psetrun(p, a1, a2) proc_continue((p))
#define Pxlookup_by_addr(p, a, n, s, sym, i) \
proc_addr2sym(p, a, n, s, sym)
#define Pxlookup_by_name(p, l, s1, s2, sym, a) \
proc_name2sym((p), (s1), (s2), (sym))
#define Paddr_to_map proc_addr2map
#define Pcreate_error strerror
#define Pdelbkpt proc_bkptdel
#define Pgrab_error strerror
#define Plmid_to_map(p, l, o) proc_obj2map((p), (o))
#define Plookup_by_addr proc_addr2sym
#define Pname_to_map proc_name2map
#define Pobject_iter proc_iter_objs
#define Pobjname proc_objname
#define Pread proc_read
#define Prd_agent proc_rdagent
#define Prelease proc_detach
#define Psetbkpt proc_bkptset
#define Psetflags proc_setflags
#define Pstate proc_state
#define Pstate proc_state
#define Psymbol_iter_by_addr proc_iter_symbyaddr
#define Punsetflags proc_clearflags
#define Pupdate_maps(p) do { } while (0)
#define Pupdate_syms proc_updatesyms
#define Pxecbkpt proc_bkptexec

View File

@ -0,0 +1,121 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Portions Copyright 2009 Stacey Son sson@FreeBSD.org
*
* $FreeBSD$
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)regs.d.in 1.1 04/09/28 SMI"
inline int R_GS = 0;
#pragma D binding "1.0" R_GS
inline int R_FS = 1;
#pragma D binding "1.0" R_FS
inline int R_ES = 2;
#pragma D binding "1.0" R_ES
inline int R_DS = 3;
#pragma D binding "1.0" R_DS
inline int R_EDI = 4;
#pragma D binding "1.0" R_EDI
inline int R_ESI = 5;
#pragma D binding "1.0" R_ESI
inline int R_EBP = 6;
#pragma D binding "1.0" R_EBP
inline int R_ESP = 7;
#pragma D binding "1.0" R_ESP
inline int R_EBX = 8;
#pragma D binding "1.0" R_EBX
inline int R_EDX = 9;
#pragma D binding "1.0" R_EDX
inline int R_ECX = 10;
#pragma D binding "1.0" R_ECX
inline int R_EAX = 11;
#pragma D binding "1.0" R_EAX
inline int R_TRAPNO = 12;
#pragma D binding "1.0" R_TRAPNO
inline int R_ERR = 13;
#pragma D binding "1.0" R_ERR
inline int R_EIP = 14;
#pragma D binding "1.0" R_EIP
inline int R_CS = 15;
#pragma D binding "1.0" R_CS
inline int R_EFL = 16;
#pragma D binding "1.0" R_EFL
inline int R_UESP = 17;
#pragma D binding "1.0" R_UESP
inline int R_SS = 18;
#pragma D binding "1.0" R_SS
inline int R_PC = R_EIP;
#pragma D binding "1.0" R_PC
inline int R_SP = R_UESP;
#pragma D binding "1.0" R_SP
inline int R_PS = R_EFL;
#pragma D binding "1.0" R_PS
inline int R_R0 = R_EAX;
#pragma D binding "1.0" R_R0
inline int R_R1 = R_EBX;
#pragma D binding "1.0" R_R1
inline int R_RSP = 18 + 1 + 20;
#pragma D binding "1.0" R_RSP
inline int R_RFL = 18 + 1 + 19;
#pragma D binding "1.0" R_RFL
inline int R_RIP = 18 + 1 + 17;
#pragma D binding "1.0" R_RIP
inline int R_RAX = 18 + 1 + 14;
#pragma D binding "1.0" R_RAX
inline int R_RCX = 18 + 1 + 13;
#pragma D binding "1.0" R_RCX
inline int R_RDX = 18 + 1 + 12;
#pragma D binding "1.0" R_RDX
inline int R_RBX = 18 + 1 + 11;
#pragma D binding "1.0" R_RBX
inline int R_RBP = 18 + 1 + 10;
#pragma D binding "1.0" R_RBP
inline int R_RSI = 18 + 1 + 9;
#pragma D binding "1.0" R_RSI
inline int R_RDI = 18 + 1 + 8;
#pragma D binding "1.0" R_RDI
inline int R_R8 = 18 + 1 + 7;
#pragma D binding "1.0" R_R8
inline int R_R9 = 18 + 1 + 6;
#pragma D binding "1.0" R_R9
inline int R_R10 = 18 + 1 + 5;
#pragma D binding "1.0" R_R10
inline int R_R11 = 18 + 1 + 4;
#pragma D binding "1.0" R_R11
inline int R_R12 = 18 + 1 + 3;
#pragma D binding "1.0" R_R12
inline int R_R13 = 18 + 1 + 2;
#pragma D binding "1.0" R_R13
inline int R_R14 = 18 + 1 + 1;
#pragma D binding "1.0" R_R14
inline int R_R15 = 18 + 1 + 0;
#pragma D binding "1.0" R_R15