This commit was generated by cvs2svn to compensate for changes in r178479,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
John Birrell 2008-04-25 09:04:09 +00:00
commit 6ff6d951ad
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=178480
64 changed files with 40194 additions and 0 deletions

View File

@ -0,0 +1,500 @@
/*
* 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
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/zmod.h>
#include <ctf_impl.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#if defined(sun)
#include <dlfcn.h>
#else
#include <zlib.h>
#endif
#include <gelf.h>
#if defined(sun)
#ifdef _LP64
static const char *_libctf_zlib = "/usr/lib/64/libz.so";
#else
static const char *_libctf_zlib = "/usr/lib/libz.so";
#endif
#endif
static struct {
int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t);
const char *(*z_error)(int);
void *z_dlp;
} zlib;
static size_t _PAGESIZE;
static size_t _PAGEMASK;
#if defined(sun)
#pragma init(_libctf_init)
#else
void _libctf_init(void) __attribute__ ((constructor));
#endif
void
_libctf_init(void)
{
#if defined(sun)
const char *p = getenv("LIBCTF_DECOMPRESSOR");
if (p != NULL)
_libctf_zlib = p; /* use alternate decompression library */
#endif
_libctf_debug = getenv("LIBCTF_DEBUG") != NULL;
_PAGESIZE = getpagesize();
_PAGEMASK = ~(_PAGESIZE - 1);
}
/*
* Attempt to dlopen the decompression library and locate the symbols of
* interest that we will need to call. This information in cached so
* that multiple calls to ctf_bufopen() do not need to reopen the library.
*/
void *
ctf_zopen(int *errp)
{
#if defined(sun)
ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib);
if (zlib.z_dlp != NULL)
return (zlib.z_dlp); /* library is already loaded */
if (access(_libctf_zlib, R_OK) == -1)
return (ctf_set_open_errno(errp, ECTF_ZMISSING));
if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL)
return (ctf_set_open_errno(errp, ECTF_ZINIT));
zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress");
zlib.z_error = (const char *(*)(int)) dlsym(zlib.z_dlp, "zError");
if (zlib.z_uncompress == NULL || zlib.z_error == NULL) {
(void) dlclose(zlib.z_dlp);
bzero(&zlib, sizeof (zlib));
return (ctf_set_open_errno(errp, ECTF_ZINIT));
}
#else
zlib.z_uncompress = uncompress;
zlib.z_error = zError;
/* Dummy return variable as 'no error' */
zlib.z_dlp = (void *) (uintptr_t) 1;
#endif
return (zlib.z_dlp);
}
/*
* The ctf_bufopen() routine calls these subroutines, defined by <sys/zmod.h>,
* which we then patch through to the functions in the decompression library.
*/
int
z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
{
return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen));
}
const char *
z_strerror(int err)
{
return (zlib.z_error(err));
}
/*
* Convert a 32-bit ELF file header into GElf.
*/
static void
ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst)
{
bcopy(src->e_ident, dst->e_ident, EI_NIDENT);
dst->e_type = src->e_type;
dst->e_machine = src->e_machine;
dst->e_version = src->e_version;
dst->e_entry = (Elf64_Addr)src->e_entry;
dst->e_phoff = (Elf64_Off)src->e_phoff;
dst->e_shoff = (Elf64_Off)src->e_shoff;
dst->e_flags = src->e_flags;
dst->e_ehsize = src->e_ehsize;
dst->e_phentsize = src->e_phentsize;
dst->e_phnum = src->e_phnum;
dst->e_shentsize = src->e_shentsize;
dst->e_shnum = src->e_shnum;
dst->e_shstrndx = src->e_shstrndx;
}
/*
* Convert a 32-bit ELF section header into GElf.
*/
static void
shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst)
{
dst->sh_name = src->sh_name;
dst->sh_type = src->sh_type;
dst->sh_flags = src->sh_flags;
dst->sh_addr = src->sh_addr;
dst->sh_offset = src->sh_offset;
dst->sh_size = src->sh_size;
dst->sh_link = src->sh_link;
dst->sh_info = src->sh_info;
dst->sh_addralign = src->sh_addralign;
dst->sh_entsize = src->sh_entsize;
}
/*
* In order to mmap a section from the ELF file, we must round down sh_offset
* to the previous page boundary, and mmap the surrounding page. We store
* the pointer to the start of the actual section data back into sp->cts_data.
*/
const void *
ctf_sect_mmap(ctf_sect_t *sp, int fd)
{
size_t pageoff = sp->cts_offset & ~_PAGEMASK;
caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ,
MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK);
if (base != MAP_FAILED)
sp->cts_data = base + pageoff;
return (base);
}
/*
* Since sp->cts_data has the adjusted offset, we have to again round down
* to get the actual mmap address and round up to get the size.
*/
void
ctf_sect_munmap(const ctf_sect_t *sp)
{
uintptr_t addr = (uintptr_t)sp->cts_data;
uintptr_t pageoff = addr & ~_PAGEMASK;
(void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff);
}
/*
* Open the specified file descriptor and return a pointer to a CTF container.
* The file can be either an ELF file or raw CTF file. The caller is
* responsible for closing the file descriptor when it is no longer needed.
*/
ctf_file_t *
ctf_fdopen(int fd, int *errp)
{
ctf_sect_t ctfsect, symsect, strsect;
ctf_file_t *fp = NULL;
struct stat64 st;
ssize_t nbytes;
union {
ctf_preamble_t ctf;
Elf32_Ehdr e32;
GElf_Ehdr e64;
} hdr;
bzero(&ctfsect, sizeof (ctf_sect_t));
bzero(&symsect, sizeof (ctf_sect_t));
bzero(&strsect, sizeof (ctf_sect_t));
bzero(&hdr.ctf, sizeof (hdr));
if (fstat64(fd, &st) == -1)
return (ctf_set_open_errno(errp, errno));
if ((nbytes = pread64(fd, &hdr.ctf, sizeof (hdr), 0)) <= 0)
return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT));
/*
* If we have read enough bytes to form a CTF header and the magic
* string matches, attempt to interpret the file as raw CTF.
*/
if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) &&
hdr.ctf.ctp_magic == CTF_MAGIC) {
if (hdr.ctf.ctp_version > CTF_VERSION)
return (ctf_set_open_errno(errp, ECTF_CTFVERS));
ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ,
MAP_PRIVATE, fd, 0);
if (ctfsect.cts_data == MAP_FAILED)
return (ctf_set_open_errno(errp, errno));
ctfsect.cts_name = _CTF_SECTION;
ctfsect.cts_type = SHT_PROGBITS;
ctfsect.cts_flags = SHF_ALLOC;
ctfsect.cts_size = (size_t)st.st_size;
ctfsect.cts_entsize = 1;
ctfsect.cts_offset = 0;
if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL)
ctf_sect_munmap(&ctfsect);
return (fp);
}
/*
* If we have read enough bytes to form an ELF header and the magic
* string matches, attempt to interpret the file as an ELF file. We
* do our own largefile ELF processing, and convert everything to
* GElf structures so that clients can operate on any data model.
*/
if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) &&
bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) {
#ifdef _BIG_ENDIAN
uchar_t order = ELFDATA2MSB;
#else
uchar_t order = ELFDATA2LSB;
#endif
GElf_Half i, n;
GElf_Shdr *sp;
void *strs_map;
size_t strs_mapsz;
char *strs;
if (hdr.e32.e_ident[EI_DATA] != order)
return (ctf_set_open_errno(errp, ECTF_ENDIAN));
if (hdr.e32.e_version != EV_CURRENT)
return (ctf_set_open_errno(errp, ECTF_ELFVERS));
if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) {
if (nbytes < (ssize_t) sizeof (GElf_Ehdr))
return (ctf_set_open_errno(errp, ECTF_FMT));
} else {
Elf32_Ehdr e32 = hdr.e32;
ehdr_to_gelf(&e32, &hdr.e64);
}
if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
return (ctf_set_open_errno(errp, ECTF_CORRUPT));
n = hdr.e64.e_shnum;
nbytes = sizeof (GElf_Shdr) * n;
if ((sp = malloc(nbytes)) == NULL)
return (ctf_set_open_errno(errp, errno));
/*
* Read in and convert to GElf the array of Shdr structures
* from e_shoff so we can locate sections of interest.
*/
if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) {
Elf32_Shdr *sp32;
nbytes = sizeof (Elf32_Shdr) * n;
if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
free(sp);
return (ctf_set_open_errno(errp, errno));
}
for (i = 0; i < n; i++)
shdr_to_gelf(&sp32[i], &sp[i]);
free(sp32);
} else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) {
free(sp);
return (ctf_set_open_errno(errp, errno));
}
/*
* Now mmap the section header strings section so that we can
* perform string comparison on the section names.
*/
strs_mapsz = sp[hdr.e64.e_shstrndx].sh_size +
(sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);
strs = (char *)strs_map +
(sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);
if (strs_map == MAP_FAILED) {
free(sp);
return (ctf_set_open_errno(errp, ECTF_MMAP));
}
/*
* Iterate over the section header array looking for the CTF
* section and symbol table. The strtab is linked to symtab.
*/
for (i = 0; i < n; i++) {
const GElf_Shdr *shp = &sp[i];
const GElf_Shdr *lhp = &sp[shp->sh_link];
if (shp->sh_link >= hdr.e64.e_shnum)
continue; /* corrupt sh_link field */
if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
lhp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size)
continue; /* corrupt sh_name field */
if (shp->sh_type == SHT_PROGBITS &&
strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) {
ctfsect.cts_name = strs + shp->sh_name;
ctfsect.cts_type = shp->sh_type;
ctfsect.cts_flags = shp->sh_flags;
ctfsect.cts_size = shp->sh_size;
ctfsect.cts_entsize = shp->sh_entsize;
ctfsect.cts_offset = (off64_t)shp->sh_offset;
} else if (shp->sh_type == SHT_SYMTAB) {
symsect.cts_name = strs + shp->sh_name;
symsect.cts_type = shp->sh_type;
symsect.cts_flags = shp->sh_flags;
symsect.cts_size = shp->sh_size;
symsect.cts_entsize = shp->sh_entsize;
symsect.cts_offset = (off64_t)shp->sh_offset;
strsect.cts_name = strs + lhp->sh_name;
strsect.cts_type = lhp->sh_type;
strsect.cts_flags = lhp->sh_flags;
strsect.cts_size = lhp->sh_size;
strsect.cts_entsize = lhp->sh_entsize;
strsect.cts_offset = (off64_t)lhp->sh_offset;
}
}
free(sp); /* free section header array */
if (ctfsect.cts_type == SHT_NULL) {
(void) munmap(strs_map, strs_mapsz);
return (ctf_set_open_errno(errp, ECTF_NOCTFDATA));
}
/*
* Now mmap the CTF data, symtab, and strtab sections and
* call ctf_bufopen() to do the rest of the work.
*/
if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) {
(void) munmap(strs_map, strs_mapsz);
return (ctf_set_open_errno(errp, ECTF_MMAP));
}
if (symsect.cts_type != SHT_NULL &&
strsect.cts_type != SHT_NULL) {
if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED ||
ctf_sect_mmap(&strsect, fd) == MAP_FAILED) {
(void) ctf_set_open_errno(errp, ECTF_MMAP);
goto bad; /* unmap all and abort */
}
fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp);
} else
fp = ctf_bufopen(&ctfsect, NULL, NULL, errp);
bad:
if (fp == NULL) {
ctf_sect_munmap(&ctfsect);
ctf_sect_munmap(&symsect);
ctf_sect_munmap(&strsect);
} else
fp->ctf_flags |= LCTF_MMAP;
(void) munmap(strs_map, strs_mapsz);
return (fp);
}
return (ctf_set_open_errno(errp, ECTF_FMT));
}
/*
* Open the specified file and return a pointer to a CTF container. The file
* can be either an ELF file or raw CTF file. This is just a convenient
* wrapper around ctf_fdopen() for callers.
*/
ctf_file_t *
ctf_open(const char *filename, int *errp)
{
ctf_file_t *fp;
int fd;
if ((fd = open64(filename, O_RDONLY)) == -1) {
if (errp != NULL)
*errp = errno;
return (NULL);
}
fp = ctf_fdopen(fd, errp);
(void) close(fd);
return (fp);
}
/*
* Write the uncompressed CTF data stream to the specified file descriptor.
* This is useful for saving the results of dynamic CTF containers.
*/
int
ctf_write(ctf_file_t *fp, int fd)
{
const uchar_t *buf = fp->ctf_base;
ssize_t resid = fp->ctf_size;
ssize_t len;
while (resid != 0) {
if ((len = write(fd, buf, resid)) <= 0)
return (ctf_set_errno(fp, errno));
resid -= len;
buf += len;
}
return (0);
}
/*
* Set the CTF library client version to the specified version. If version is
* zero, we just return the default library version number.
*/
int
ctf_version(int version)
{
if (version < 0) {
errno = EINVAL;
return (-1);
}
if (version > 0) {
if (version > CTF_VERSION) {
errno = ENOTSUP;
return (-1);
}
ctf_dprintf("ctf_version: client using version %d\n", version);
_libctf_version = version;
}
return (_libctf_version);
}

View File

@ -0,0 +1,83 @@
/*
* 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
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <ctf_impl.h>
#include <sys/mman.h>
#include <stdarg.h>
void *
ctf_data_alloc(size_t size)
{
return (mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0));
}
void
ctf_data_free(void *buf, size_t size)
{
(void) munmap(buf, size);
}
void
ctf_data_protect(void *buf, size_t size)
{
(void) mprotect(buf, size, PROT_READ);
}
void *
ctf_alloc(size_t size)
{
return (malloc(size));
}
/*ARGSUSED*/
void
ctf_free(void *buf, __unused size_t size)
{
free(buf);
}
const char *
ctf_strerror(int err)
{
return ((const char *) strerror(err));
}
/*PRINTFLIKE1*/
void
ctf_dprintf(const char *format, ...)
{
if (_libctf_debug) {
va_list alist;
va_start(alist, format);
(void) fputs("libctf DEBUG: ", stderr);
(void) vfprintf(stderr, format, alist);
va_end(alist);
}
}

View File

@ -0,0 +1,60 @@
/*
* 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
*/
/*
* Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This header file defines the interfaces available from the CTF debugger
* library, libctf. This library provides functions that a debugger can
* use to operate on data in the Compact ANSI-C Type Format (CTF). This
* is NOT a public interface, although it may eventually become one in
* the fullness of time after we gain more experience with the interfaces.
*
* In the meantime, be aware that any program linked with libctf in this
* release of Solaris is almost guaranteed to break in the next release.
*
* In short, do not user this header file or libctf for any purpose.
*/
#ifndef _LIBCTF_H
#define _LIBCTF_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/ctf_api.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* This flag can be used to enable debug messages.
*/
extern int _libctf_debug;
#ifdef __cplusplus
}
#endif
#endif /* _LIBCTF_H */

View File

@ -0,0 +1,206 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <link.h>
#include <sys/dtrace.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/*
* In Solaris 10 GA, the only mechanism for communicating helper information
* is through the DTrace helper pseudo-device node in /devices; there is
* no /dev link. Because of this, USDT providers and helper actions don't
* work inside of non-global zones. This issue was addressed by adding
* the /dev and having this initialization code use that /dev link. If the
* /dev link doesn't exist it falls back to looking for the /devices node
* as this code may be embedded in a binary which runs on Solaris 10 GA.
*
* Users may set the following environment variable to affect the way
* helper initialization takes place:
*
* DTRACE_DOF_INIT_DEBUG enable debugging output
* DTRACE_DOF_INIT_DISABLE disable helper loading
* DTRACE_DOF_INIT_DEVNAME set the path to the helper node
*/
static const char *devnamep = "/dev/dtrace/helper";
static const char *olddevname = "/devices/pseudo/dtrace@0:helper";
static const char *modname; /* Name of this load object */
static int gen; /* DOF helper generation */
extern dof_hdr_t __SUNW_dof; /* DOF defined in the .SUNW_dof section */
static void
dprintf(int debug, const char *fmt, ...)
{
va_list ap;
if (debug && getenv("DTRACE_DOF_INIT_DEBUG") == NULL)
return;
va_start(ap, fmt);
if (modname == NULL)
(void) fprintf(stderr, "dtrace DOF: ");
else
(void) fprintf(stderr, "dtrace DOF %s: ", modname);
(void) vfprintf(stderr, fmt, ap);
if (fmt[strlen(fmt) - 1] != '\n')
(void) fprintf(stderr, ": %s\n", strerror(errno));
va_end(ap);
}
#if defined(sun)
#pragma init(dtrace_dof_init)
#else
static void dtrace_dof_init(void) __attribute__ ((constructor));
#endif
static void
dtrace_dof_init(void)
{
dof_hdr_t *dof = &__SUNW_dof;
#ifdef _LP64
Elf64_Ehdr *elf;
#else
Elf32_Ehdr *elf;
#endif
dof_helper_t dh;
#if defined(sun)
Link_map *lmp;
Lmid_t lmid;
#else
struct link_map *lmp;
u_long lmid = 0;
#endif
int fd;
const char *p;
if (getenv("DTRACE_DOF_INIT_DISABLE") != NULL)
return;
if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &lmp) == -1 || lmp == NULL) {
dprintf(1, "couldn't discover module name or address\n");
return;
}
#if defined(sun)
if (dlinfo(RTLD_SELF, RTLD_DI_LMID, &lmid) == -1) {
dprintf(1, "couldn't discover link map ID\n");
return;
}
#endif
if ((modname = strrchr(lmp->l_name, '/')) == NULL)
modname = lmp->l_name;
else
modname++;
if (dof->dofh_ident[DOF_ID_MAG0] != DOF_MAG_MAG0 ||
dof->dofh_ident[DOF_ID_MAG1] != DOF_MAG_MAG1 ||
dof->dofh_ident[DOF_ID_MAG2] != DOF_MAG_MAG2 ||
dof->dofh_ident[DOF_ID_MAG3] != DOF_MAG_MAG3) {
dprintf(0, ".SUNW_dof section corrupt\n");
return;
}
elf = (void *)lmp->l_addr;
dh.dofhp_dof = (uintptr_t)dof;
dh.dofhp_addr = elf->e_type == ET_DYN ? (uintptr_t) lmp->l_addr : 0;
if (lmid == 0) {
(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
"%s", modname);
} else {
(void) snprintf(dh.dofhp_mod, sizeof (dh.dofhp_mod),
"LM%lu`%s", lmid, modname);
}
if ((p = getenv("DTRACE_DOF_INIT_DEVNAME")) != NULL)
devnamep = p;
if ((fd = open64(devnamep, O_RDWR)) < 0) {
dprintf(1, "failed to open helper device %s", devnamep);
/*
* If the device path wasn't explicitly set, try again with
* the old device path.
*/
if (p != NULL)
return;
devnamep = olddevname;
if ((fd = open64(devnamep, O_RDWR)) < 0) {
dprintf(1, "failed to open helper device %s", devnamep);
return;
}
}
if ((gen = ioctl(fd, DTRACEHIOC_ADDDOF, &dh)) == -1)
dprintf(1, "DTrace ioctl failed for DOF at %p", dof);
else
dprintf(1, "DTrace ioctl succeeded for DOF at %p\n", dof);
(void) close(fd);
}
#if defined(sun)
#pragma fini(dtrace_dof_fini)
#else
static void dtrace_dof_fini(void) __attribute__ ((destructor));
#endif
static void
dtrace_dof_fini(void)
{
int fd;
if ((fd = open64(devnamep, O_RDWR)) < 0) {
dprintf(1, "failed to open helper device %s", devnamep);
return;
}
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);
(void) close(fd);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,501 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <strings.h>
#include <stdlib.h>
#include <assert.h>
#include <dt_impl.h>
#include <dt_parser.h>
#include <dt_as.h>
void
dt_irlist_create(dt_irlist_t *dlp)
{
bzero(dlp, sizeof (dt_irlist_t));
dlp->dl_label = 1;
}
void
dt_irlist_destroy(dt_irlist_t *dlp)
{
dt_irnode_t *dip, *nip;
for (dip = dlp->dl_list; dip != NULL; dip = nip) {
nip = dip->di_next;
free(dip);
}
}
void
dt_irlist_append(dt_irlist_t *dlp, dt_irnode_t *dip)
{
if (dlp->dl_last != NULL)
dlp->dl_last->di_next = dip;
else
dlp->dl_list = dip;
dlp->dl_last = dip;
if (dip->di_label == DT_LBL_NONE || dip->di_instr != DIF_INSTR_NOP)
dlp->dl_len++; /* don't count forward refs in instr count */
}
uint_t
dt_irlist_label(dt_irlist_t *dlp)
{
return (dlp->dl_label++);
}
/*ARGSUSED*/
static int
dt_countvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
size_t *np = data;
if (idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW))
(*np)++; /* include variable in vartab */
return (0);
}
/*ARGSUSED*/
static int
dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
dt_pcb_t *pcb = data;
dtrace_difv_t *dvp;
ssize_t stroff;
dt_node_t dn;
if (!(idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW)))
return (0); /* omit variable from vartab */
dvp = &pcb->pcb_difo->dtdo_vartab[pcb->pcb_asvidx++];
stroff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);
if (stroff == -1L)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
if (stroff > DIF_STROFF_MAX)
longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);
dvp->dtdv_name = (uint_t)stroff;
dvp->dtdv_id = idp->di_id;
dvp->dtdv_flags = 0;
dvp->dtdv_kind = (idp->di_kind == DT_IDENT_ARRAY) ?
DIFV_KIND_ARRAY : DIFV_KIND_SCALAR;
if (idp->di_flags & DT_IDFLG_LOCAL)
dvp->dtdv_scope = DIFV_SCOPE_LOCAL;
else if (idp->di_flags & DT_IDFLG_TLS)
dvp->dtdv_scope = DIFV_SCOPE_THREAD;
else
dvp->dtdv_scope = DIFV_SCOPE_GLOBAL;
if (idp->di_flags & DT_IDFLG_DIFR)
dvp->dtdv_flags |= DIFV_F_REF;
if (idp->di_flags & DT_IDFLG_DIFW)
dvp->dtdv_flags |= DIFV_F_MOD;
bzero(&dn, sizeof (dn));
dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type);
dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type);
idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);
return (0);
}
static ssize_t
dt_copystr(const char *s, size_t n, size_t off, dt_pcb_t *pcb)
{
bcopy(s, pcb->pcb_difo->dtdo_strtab + off, n);
return (n);
}
/*
* Rewrite the xlate/xlarg instruction at dtdo_buf[i] so that the instruction's
* xltab index reflects the offset 'xi' of the assigned dtdo_xlmtab[] location.
* We track the cumulative references to translators and members in the pcb's
* pcb_asxrefs[] array, a two-dimensional array of bitmaps indexed by the
* global translator id and then by the corresponding translator member id.
*/
static void
dt_as_xlate(dt_pcb_t *pcb, dtrace_difo_t *dp,
uint_t i, uint_t xi, dt_node_t *dnp)
{
dtrace_hdl_t *dtp = pcb->pcb_hdl;
dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
assert(i < dp->dtdo_len);
assert(xi < dp->dtdo_xlmlen);
assert(dnp->dn_kind == DT_NODE_MEMBER);
assert(dnp->dn_membexpr->dn_kind == DT_NODE_XLATOR);
assert(dxp->dx_id < dtp->dt_xlatorid);
assert(dnp->dn_membid < dxp->dx_nmembers);
if (pcb->pcb_asxrefs == NULL) {
pcb->pcb_asxreflen = dtp->dt_xlatorid;
pcb->pcb_asxrefs =
dt_zalloc(dtp, sizeof (ulong_t *) * pcb->pcb_asxreflen);
if (pcb->pcb_asxrefs == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
}
if (pcb->pcb_asxrefs[dxp->dx_id] == NULL) {
pcb->pcb_asxrefs[dxp->dx_id] =
dt_zalloc(dtp, BT_SIZEOFMAP(dxp->dx_nmembers));
if (pcb->pcb_asxrefs[dxp->dx_id] == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
}
dp->dtdo_buf[i] = DIF_INSTR_XLATE(
DIF_INSTR_OP(dp->dtdo_buf[i]), xi, DIF_INSTR_RD(dp->dtdo_buf[i]));
BT_SET(pcb->pcb_asxrefs[dxp->dx_id], dnp->dn_membid);
dp->dtdo_xlmtab[xi] = dnp;
}
static void
dt_as_undef(const dt_ident_t *idp, uint_t offset)
{
const char *kind, *mark = (idp->di_flags & DT_IDFLG_USER) ? "``" : "`";
const dtrace_syminfo_t *dts = idp->di_data;
if (idp->di_flags & DT_IDFLG_USER)
kind = "user";
else if (idp->di_flags & DT_IDFLG_PRIM)
kind = "primary kernel";
else
kind = "loadable kernel";
yylineno = idp->di_lineno;
xyerror(D_ASRELO, "relocation remains against %s symbol %s%s%s (offset "
"0x%x)\n", kind, dts->dts_object, mark, dts->dts_name, offset);
}
dtrace_difo_t *
dt_as(dt_pcb_t *pcb)
{
dtrace_hdl_t *dtp = pcb->pcb_hdl;
dt_irlist_t *dlp = &pcb->pcb_ir;
uint_t *labels = NULL;
dt_irnode_t *dip;
dtrace_difo_t *dp;
dt_ident_t *idp;
size_t n = 0;
uint_t i;
uint_t kmask, kbits, umask, ubits;
uint_t krel = 0, urel = 0, xlrefs = 0;
/*
* Select bitmasks based upon the desired symbol linking policy. We
* test (di_extern->di_flags & xmask) == xbits to determine if the
* symbol should have a relocation entry generated in the loop below.
*
* DT_LINK_KERNEL = kernel symbols static, user symbols dynamic
* DT_LINK_PRIMARY = primary kernel symbols static, others dynamic
* DT_LINK_DYNAMIC = all symbols dynamic
* DT_LINK_STATIC = all symbols static
*
* By 'static' we mean that we use the symbol's value at compile-time
* in the final DIF. By 'dynamic' we mean that we create a relocation
* table entry for the symbol's value so it can be relocated later.
*/
switch (dtp->dt_linkmode) {
case DT_LINK_KERNEL:
kmask = 0;
kbits = -1u;
umask = DT_IDFLG_USER;
ubits = DT_IDFLG_USER;
break;
case DT_LINK_PRIMARY:
kmask = DT_IDFLG_USER | DT_IDFLG_PRIM;
kbits = 0;
umask = DT_IDFLG_USER;
ubits = DT_IDFLG_USER;
break;
case DT_LINK_DYNAMIC:
kmask = DT_IDFLG_USER;
kbits = 0;
umask = DT_IDFLG_USER;
ubits = DT_IDFLG_USER;
break;
case DT_LINK_STATIC:
kmask = umask = 0;
kbits = ubits = -1u;
break;
default:
xyerror(D_UNKNOWN, "internal error -- invalid link mode %u\n",
dtp->dt_linkmode);
}
assert(pcb->pcb_difo == NULL);
pcb->pcb_difo = dt_zalloc(dtp, sizeof (dtrace_difo_t));
if ((dp = pcb->pcb_difo) == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * dlp->dl_len);
if (dp->dtdo_buf == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
if ((labels = dt_alloc(dtp, sizeof (uint_t) * dlp->dl_label)) == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
/*
* Make an initial pass through the instruction list, filling in the
* instruction buffer with valid instructions and skipping labeled nops.
* While doing this, we also fill in our labels[] translation table
* and we count up the number of relocation table entries we will need.
*/
for (i = 0, dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
if (dip->di_label != DT_LBL_NONE)
labels[dip->di_label] = i;
if (dip->di_label == DT_LBL_NONE ||
dip->di_instr != DIF_INSTR_NOP)
dp->dtdo_buf[i++] = dip->di_instr;
if (dip->di_extern == NULL)
continue; /* no external references needed */
switch (DIF_INSTR_OP(dip->di_instr)) {
case DIF_OP_SETX:
idp = dip->di_extern;
if ((idp->di_flags & kmask) == kbits)
krel++;
else if ((idp->di_flags & umask) == ubits)
urel++;
break;
case DIF_OP_XLATE:
case DIF_OP_XLARG:
xlrefs++;
break;
default:
xyerror(D_UNKNOWN, "unexpected assembler relocation "
"for opcode 0x%x\n", DIF_INSTR_OP(dip->di_instr));
}
}
assert(i == dlp->dl_len);
dp->dtdo_len = dlp->dl_len;
/*
* Make a second pass through the instructions, relocating each branch
* label to the index of the final instruction in the buffer and noting
* any other instruction-specific DIFO flags such as dtdo_destructive.
*/
for (i = 0; i < dp->dtdo_len; i++) {
dif_instr_t instr = dp->dtdo_buf[i];
uint_t op = DIF_INSTR_OP(instr);
if (op == DIF_OP_CALL) {
if (DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUT ||
DIF_INSTR_SUBR(instr) == DIF_SUBR_COPYOUTSTR)
dp->dtdo_destructive = 1;
continue;
}
if (op >= DIF_OP_BA && op <= DIF_OP_BLEU) {
assert(DIF_INSTR_LABEL(instr) < dlp->dl_label);
dp->dtdo_buf[i] = DIF_INSTR_BRANCH(op,
labels[DIF_INSTR_LABEL(instr)]);
}
}
dt_free(dtp, labels);
pcb->pcb_asvidx = 0;
/*
* Allocate memory for the appropriate number of variable records and
* then fill in each variable record. As we populate the variable
* table we insert the corresponding variable names into the strtab.
*/
(void) dt_idhash_iter(dtp->dt_tls, dt_countvar, &n);
(void) dt_idhash_iter(dtp->dt_globals, dt_countvar, &n);
(void) dt_idhash_iter(pcb->pcb_locals, dt_countvar, &n);
if (n != 0) {
dp->dtdo_vartab = dt_alloc(dtp, n * sizeof (dtrace_difv_t));
dp->dtdo_varlen = (uint32_t)n;
if (dp->dtdo_vartab == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
(void) dt_idhash_iter(dtp->dt_tls, dt_copyvar, pcb);
(void) dt_idhash_iter(dtp->dt_globals, dt_copyvar, pcb);
(void) dt_idhash_iter(pcb->pcb_locals, dt_copyvar, pcb);
}
/*
* Allocate memory for the appropriate number of relocation table
* entries based upon our kernel and user counts from the first pass.
*/
if (krel != 0) {
dp->dtdo_kreltab = dt_alloc(dtp,
krel * sizeof (dof_relodesc_t));
dp->dtdo_krelen = krel;
if (dp->dtdo_kreltab == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
}
if (urel != 0) {
dp->dtdo_ureltab = dt_alloc(dtp,
urel * sizeof (dof_relodesc_t));
dp->dtdo_urelen = urel;
if (dp->dtdo_ureltab == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
}
if (xlrefs != 0) {
dp->dtdo_xlmtab = dt_zalloc(dtp, sizeof (dt_node_t *) * xlrefs);
dp->dtdo_xlmlen = xlrefs;
if (dp->dtdo_xlmtab == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
}
/*
* If any relocations are needed, make another pass through the
* instruction list and fill in the relocation table entries.
*/
if (krel + urel + xlrefs != 0) {
uint_t knodef = pcb->pcb_cflags & DTRACE_C_KNODEF;
uint_t unodef = pcb->pcb_cflags & DTRACE_C_UNODEF;
dof_relodesc_t *krp = dp->dtdo_kreltab;
dof_relodesc_t *urp = dp->dtdo_ureltab;
dt_node_t **xlp = dp->dtdo_xlmtab;
i = 0; /* dtdo_buf[] index */
for (dip = dlp->dl_list; dip != NULL; dip = dip->di_next) {
dof_relodesc_t *rp;
ssize_t soff;
uint_t nodef;
if (dip->di_label != DT_LBL_NONE &&
dip->di_instr == DIF_INSTR_NOP)
continue; /* skip label declarations */
i++; /* advance dtdo_buf[] index */
if (DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLATE ||
DIF_INSTR_OP(dip->di_instr) == DIF_OP_XLARG) {
assert(dp->dtdo_buf[i - 1] == dip->di_instr);
dt_as_xlate(pcb, dp, i - 1, (uint_t)
(xlp++ - dp->dtdo_xlmtab), dip->di_extern);
continue;
}
if ((idp = dip->di_extern) == NULL)
continue; /* no relocation entry needed */
if ((idp->di_flags & kmask) == kbits) {
nodef = knodef;
rp = krp++;
} else if ((idp->di_flags & umask) == ubits) {
nodef = unodef;
rp = urp++;
} else
continue;
if (!nodef)
dt_as_undef(idp, i);
assert(DIF_INSTR_OP(dip->di_instr) == DIF_OP_SETX);
soff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);
if (soff == -1L)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
if (soff > DIF_STROFF_MAX)
longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);
rp->dofr_name = (dof_stridx_t)soff;
rp->dofr_type = DOF_RELO_SETX;
rp->dofr_offset = DIF_INSTR_INTEGER(dip->di_instr) *
sizeof (uint64_t);
rp->dofr_data = 0;
}
assert(krp == dp->dtdo_kreltab + dp->dtdo_krelen);
assert(urp == dp->dtdo_ureltab + dp->dtdo_urelen);
assert(xlp == dp->dtdo_xlmtab + dp->dtdo_xlmlen);
assert(i == dp->dtdo_len);
}
/*
* Allocate memory for the compiled string table and then copy the
* chunks from the string table into the final string buffer.
*/
if ((n = dt_strtab_size(pcb->pcb_strtab)) != 0) {
if ((dp->dtdo_strtab = dt_alloc(dtp, n)) == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
(void) dt_strtab_write(pcb->pcb_strtab,
(dt_strtab_write_f *)dt_copystr, pcb);
dp->dtdo_strlen = (uint32_t)n;
}
/*
* Allocate memory for the compiled integer table and then copy the
* integer constants from the table into the final integer buffer.
*/
if ((n = dt_inttab_size(pcb->pcb_inttab)) != 0) {
if ((dp->dtdo_inttab = dt_alloc(dtp,
n * sizeof (uint64_t))) == NULL)
longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
dt_inttab_write(pcb->pcb_inttab, dp->dtdo_inttab);
dp->dtdo_intlen = (uint32_t)n;
}
/*
* Fill in the DIFO return type from the type associated with the
* node saved in pcb_dret, and then clear pcb_difo and pcb_dret
* now that the assembler has completed successfully.
*/
dt_node_diftype(dtp, pcb->pcb_dret, &dp->dtdo_rtype);
pcb->pcb_difo = NULL;
pcb->pcb_dret = NULL;
if (pcb->pcb_cflags & DTRACE_C_DIFV)
dt_dis(dp, stderr);
return (dp);
}

View File

@ -0,0 +1,64 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_AS_H
#define _DT_AS_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/dtrace.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_irnode {
uint_t di_label; /* label number or DT_LBL_NONE */
dif_instr_t di_instr; /* instruction opcode */
void *di_extern; /* opcode-specific external reference */
struct dt_irnode *di_next; /* next instruction */
} dt_irnode_t;
#define DT_LBL_NONE 0 /* no label on this instruction */
typedef struct dt_irlist {
dt_irnode_t *dl_list; /* pointer to first node in list */
dt_irnode_t *dl_last; /* pointer to last node in list */
uint_t dl_len; /* number of valid instructions */
uint_t dl_label; /* next label number to assign */
} dt_irlist_t;
extern void dt_irlist_create(dt_irlist_t *);
extern void dt_irlist_destroy(dt_irlist_t *);
extern void dt_irlist_append(dt_irlist_t *, dt_irnode_t *);
extern uint_t dt_irlist_label(dt_irlist_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_AS_H */

View File

@ -0,0 +1,177 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* DTrace Memory Buffer Routines
*
* The routines in this file are used to create an automatically resizing
* memory buffer that can be written to like a file. Memory buffers are
* used to construct DOF to ioctl() to dtrace(7D), and provide semantics that
* simplify caller code. Specifically, any allocation errors result in an
* error code being set inside the buffer which is maintained persistently and
* propagates to another buffer if the buffer in error is concatenated. These
* semantics permit callers to execute a large series of writes without needing
* to check for errors and then perform a single check before using the buffer.
*/
#include <sys/sysmacros.h>
#include <strings.h>
#include <dt_impl.h>
#include <dt_buf.h>
void
dt_buf_create(dtrace_hdl_t *dtp, dt_buf_t *bp, const char *name, size_t len)
{
if (len == 0)
len = _dtrace_bufsize;
bp->dbu_buf = bp->dbu_ptr = dt_zalloc(dtp, len);
bp->dbu_len = len;
if (bp->dbu_buf == NULL)
bp->dbu_err = dtrace_errno(dtp);
else
bp->dbu_err = 0;
bp->dbu_resizes = 0;
bp->dbu_name = name;
}
void
dt_buf_destroy(dtrace_hdl_t *dtp, dt_buf_t *bp)
{
dt_dprintf("dt_buf_destroy(%s): size=%lu resizes=%u\n",
bp->dbu_name, (ulong_t)bp->dbu_len, bp->dbu_resizes);
dt_free(dtp, bp->dbu_buf);
}
void
dt_buf_reset(dtrace_hdl_t *dtp, dt_buf_t *bp)
{
if ((bp->dbu_ptr = bp->dbu_buf) != NULL)
bp->dbu_err = 0;
else
dt_buf_create(dtp, bp, bp->dbu_name, bp->dbu_len);
}
void
dt_buf_write(dtrace_hdl_t *dtp, dt_buf_t *bp,
const void *buf, size_t len, size_t align)
{
size_t off = (size_t)(bp->dbu_ptr - bp->dbu_buf);
size_t adj = roundup(off, align) - off;
if (bp->dbu_err != 0) {
(void) dt_set_errno(dtp, bp->dbu_err);
return; /* write silently fails */
}
if (bp->dbu_ptr + adj + len > bp->dbu_buf + bp->dbu_len) {
size_t new_len = bp->dbu_len * 2;
uchar_t *new_buf;
uint_t r = 1;
while (bp->dbu_ptr + adj + len > bp->dbu_buf + new_len) {
new_len *= 2;
r++;
}
if ((new_buf = dt_zalloc(dtp, new_len)) == NULL) {
bp->dbu_err = dtrace_errno(dtp);
return;
}
bcopy(bp->dbu_buf, new_buf, off);
dt_free(dtp, bp->dbu_buf);
bp->dbu_buf = new_buf;
bp->dbu_ptr = new_buf + off;
bp->dbu_len = new_len;
bp->dbu_resizes += r;
}
bp->dbu_ptr += adj;
bcopy(buf, bp->dbu_ptr, len);
bp->dbu_ptr += len;
}
void
dt_buf_concat(dtrace_hdl_t *dtp, dt_buf_t *dst,
const dt_buf_t *src, size_t align)
{
if (dst->dbu_err == 0 && src->dbu_err != 0) {
(void) dt_set_errno(dtp, src->dbu_err);
dst->dbu_err = src->dbu_err;
} else {
dt_buf_write(dtp, dst, src->dbu_buf,
(size_t)(src->dbu_ptr - src->dbu_buf), align);
}
}
size_t
dt_buf_offset(const dt_buf_t *bp, size_t align)
{
size_t off = (size_t)(bp->dbu_ptr - bp->dbu_buf);
return (roundup(off, align));
}
size_t
dt_buf_len(const dt_buf_t *bp)
{
return (bp->dbu_ptr - bp->dbu_buf);
}
int
dt_buf_error(const dt_buf_t *bp)
{
return (bp->dbu_err);
}
void *
dt_buf_ptr(const dt_buf_t *bp)
{
return (bp->dbu_buf);
}
void *
dt_buf_claim(dtrace_hdl_t *dtp, dt_buf_t *bp)
{
void *buf = bp->dbu_buf;
if (bp->dbu_err != 0) {
dt_free(dtp, buf);
buf = NULL;
}
bp->dbu_buf = bp->dbu_ptr = NULL;
bp->dbu_len = 0;
return (buf);
}

View File

@ -0,0 +1,69 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_BUF_H
#define _DT_BUF_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
#include <dtrace.h>
typedef struct dt_buf {
const char *dbu_name; /* string name for debugging */
uchar_t *dbu_buf; /* buffer base address */
uchar_t *dbu_ptr; /* current buffer location */
size_t dbu_len; /* buffer size in bytes */
int dbu_err; /* errno value if error */
int dbu_resizes; /* number of resizes */
} dt_buf_t;
extern void dt_buf_create(dtrace_hdl_t *, dt_buf_t *, const char *, size_t);
extern void dt_buf_destroy(dtrace_hdl_t *, dt_buf_t *);
extern void dt_buf_reset(dtrace_hdl_t *, dt_buf_t *);
extern void dt_buf_write(dtrace_hdl_t *, dt_buf_t *,
const void *, size_t, size_t);
extern void dt_buf_concat(dtrace_hdl_t *, dt_buf_t *,
const dt_buf_t *, size_t);
extern size_t dt_buf_offset(const dt_buf_t *, size_t);
extern size_t dt_buf_len(const dt_buf_t *);
extern int dt_buf_error(const dt_buf_t *);
extern void *dt_buf_ptr(const dt_buf_t *);
extern void *dt_buf_claim(dtrace_hdl_t *, dt_buf_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_BUF_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_DECL_H
#define _DT_DECL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <libctf.h>
#include <dtrace.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
struct dt_node; /* forward declaration of dt_node_t */
typedef struct dt_decl {
ushort_t dd_kind; /* declaration kind (CTF_K_* kind) */
ushort_t dd_attr; /* attributes (DT_DA_* flags) */
ctf_file_t *dd_ctfp; /* CTF container for decl's type */
ctf_id_t dd_type; /* CTF identifier for decl's type */
char *dd_name; /* string name of this decl (or NULL) */
struct dt_node *dd_node; /* node for array size or parm list */
struct dt_decl *dd_next; /* next declaration in list */
} dt_decl_t;
#define DT_DA_SIGNED 0x0001 /* signed integer value */
#define DT_DA_UNSIGNED 0x0002 /* unsigned integer value */
#define DT_DA_SHORT 0x0004 /* short integer value */
#define DT_DA_LONG 0x0008 /* long integer or double */
#define DT_DA_LONGLONG 0x0010 /* long long integer value */
#define DT_DA_CONST 0x0020 /* qualify type as const */
#define DT_DA_RESTRICT 0x0040 /* qualify type as restrict */
#define DT_DA_VOLATILE 0x0080 /* qualify type as volatile */
#define DT_DA_PAREN 0x0100 /* parenthesis tag */
typedef enum dt_dclass {
DT_DC_DEFAULT, /* no storage class specified */
DT_DC_AUTO, /* automatic storage */
DT_DC_REGISTER, /* register storage */
DT_DC_STATIC, /* static storage */
DT_DC_EXTERN, /* extern storage */
DT_DC_TYPEDEF, /* type definition */
DT_DC_SELF, /* thread-local storage */
DT_DC_THIS /* clause-local storage */
} dt_dclass_t;
typedef struct dt_scope {
dt_decl_t *ds_decl; /* pointer to top of decl stack */
struct dt_scope *ds_next; /* pointer to next scope */
char *ds_ident; /* identifier for this scope (if any) */
ctf_file_t *ds_ctfp; /* CTF container for this scope */
ctf_id_t ds_type; /* CTF id of enclosing type */
dt_dclass_t ds_class; /* declaration class for this scope */
int ds_enumval; /* most recent enumerator value */
} dt_scope_t;
extern dt_decl_t *dt_decl_alloc(ushort_t, char *);
extern void dt_decl_free(dt_decl_t *);
extern void dt_decl_reset(void);
extern dt_decl_t *dt_decl_push(dt_decl_t *);
extern dt_decl_t *dt_decl_pop(void);
extern dt_decl_t *dt_decl_pop_param(char **);
extern dt_decl_t *dt_decl_top(void);
extern dt_decl_t *dt_decl_ident(char *);
extern void dt_decl_class(dt_dclass_t);
#define DT_DP_VARARGS 0x1 /* permit varargs in prototype */
#define DT_DP_DYNAMIC 0x2 /* permit dynamic type in prototype */
#define DT_DP_VOID 0x4 /* permit void type in prototype */
#define DT_DP_ANON 0x8 /* permit anonymous parameters */
extern int dt_decl_prototype(struct dt_node *, struct dt_node *,
const char *, uint_t);
extern dt_decl_t *dt_decl_spec(ushort_t, char *);
extern dt_decl_t *dt_decl_attr(ushort_t);
extern dt_decl_t *dt_decl_array(struct dt_node *);
extern dt_decl_t *dt_decl_func(dt_decl_t *, struct dt_node *);
extern dt_decl_t *dt_decl_ptr(void);
extern dt_decl_t *dt_decl_sou(uint_t, char *);
extern void dt_decl_member(struct dt_node *);
extern dt_decl_t *dt_decl_enum(char *);
extern void dt_decl_enumerator(char *, struct dt_node *);
extern int dt_decl_type(dt_decl_t *, dtrace_typeinfo_t *);
extern void dt_scope_create(dt_scope_t *);
extern void dt_scope_destroy(dt_scope_t *);
extern void dt_scope_push(ctf_file_t *, ctf_id_t);
extern dt_decl_t *dt_scope_pop(void);
#ifdef __cplusplus
}
#endif
#endif /* _DT_DECL_H */

View File

@ -0,0 +1,511 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <strings.h>
#include <stdio.h>
#include <dt_impl.h>
#include <dt_ident.h>
/*ARGSUSED*/
static void
dt_dis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u, %%r%u, %%r%u", name,
DIF_INSTR_R1(in), DIF_INSTR_R2(in), DIF_INSTR_RD(in));
}
/*ARGSUSED*/
static void
dt_dis_branch(const dtrace_difo_t *dp, const char *name,
dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %u", name, DIF_INSTR_LABEL(in));
}
/*ARGSUSED*/
static void
dt_dis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s [%%r%u], %%r%u", name,
DIF_INSTR_R1(in), DIF_INSTR_RD(in));
}
/*ARGSUSED*/
static void
dt_dis_store(const dtrace_difo_t *dp, const char *name,
dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u, [%%r%u]", name,
DIF_INSTR_R1(in), DIF_INSTR_RD(in));
}
/*ARGSUSED*/
static void
dt_dis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%s", name);
}
/*ARGSUSED*/
static void
dt_dis_r1rd(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u, %%r%u", name,
DIF_INSTR_R1(in), DIF_INSTR_RD(in));
}
/*ARGSUSED*/
static void
dt_dis_cmp(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u, %%r%u", name,
DIF_INSTR_R1(in), DIF_INSTR_R2(in));
}
/*ARGSUSED*/
static void
dt_dis_tst(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u", name, DIF_INSTR_R1(in));
}
static const char *
dt_dis_varname(const dtrace_difo_t *dp, uint_t id, uint_t scope)
{
const dtrace_difv_t *dvp = dp->dtdo_vartab;
uint_t i;
for (i = 0; i < dp->dtdo_varlen; i++, dvp++) {
if (dvp->dtdv_id == id && dvp->dtdv_scope == scope) {
if (dvp->dtdv_name < dp->dtdo_strlen)
return (dp->dtdo_strtab + dvp->dtdv_name);
break;
}
}
return (NULL);
}
static uint_t
dt_dis_scope(const char *name)
{
switch (name[2]) {
case 'l': return (DIFV_SCOPE_LOCAL);
case 't': return (DIFV_SCOPE_THREAD);
case 'g': return (DIFV_SCOPE_GLOBAL);
default: return (-1u);
}
}
static void
dt_dis_lda(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t var = DIF_INSTR_R1(in);
const char *vname;
(void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u, %%r%u", name,
var, DIF_INSTR_R2(in), DIF_INSTR_RD(in));
if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
(void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
}
static void
dt_dis_ldv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t var = DIF_INSTR_VAR(in);
const char *vname;
(void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u",
name, var, DIF_INSTR_RD(in));
if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
(void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
}
static void
dt_dis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t var = DIF_INSTR_VAR(in);
const char *vname;
(void) fprintf(fp, "%-4s %%r%u, DT_VAR(%u)",
name, DIF_INSTR_RS(in), var);
if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL)
(void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname);
}
static void
dt_dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t intptr = DIF_INSTR_INTEGER(in);
(void) fprintf(fp, "%-4s DT_INTEGER[%u], %%r%u", name,
intptr, DIF_INSTR_RD(in));
if (intptr < dp->dtdo_intlen) {
(void) fprintf(fp, "\t\t! 0x%llx",
(u_longlong_t)dp->dtdo_inttab[intptr]);
}
}
static void
dt_dis_sets(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t strptr = DIF_INSTR_STRING(in);
(void) fprintf(fp, "%-4s DT_STRING[%u], %%r%u", name,
strptr, DIF_INSTR_RD(in));
if (strptr < dp->dtdo_strlen)
(void) fprintf(fp, "\t\t! \"%s\"", dp->dtdo_strtab + strptr);
}
/*ARGSUSED*/
static void
dt_dis_ret(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
(void) fprintf(fp, "%-4s %%r%u", name, DIF_INSTR_RD(in));
}
/*ARGSUSED*/
static void
dt_dis_call(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp)
{
uint_t subr = DIF_INSTR_SUBR(in);
(void) fprintf(fp, "%-4s DIF_SUBR(%u), %%r%u\t\t! %s",
name, subr, DIF_INSTR_RD(in), dtrace_subrstr(NULL, subr));
}
/*ARGSUSED*/
static void
dt_dis_pushts(const dtrace_difo_t *dp,
const char *name, dif_instr_t in, FILE *fp)
{
static const char *const tnames[] = { "D type", "string" };
uint_t type = DIF_INSTR_TYPE(in);
(void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u",
name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in));
if (type < sizeof (tnames) / sizeof (tnames[0]))
(void) fprintf(fp, "\t! DT_TYPE(%u) = %s", type, tnames[type]);
}
static void
dt_dis_xlate(const dtrace_difo_t *dp,
const char *name, dif_instr_t in, FILE *fp)
{
uint_t xlr = DIF_INSTR_XLREF(in);
(void) fprintf(fp, "%-4s DT_XLREF[%u], %%r%u",
name, xlr, DIF_INSTR_RD(in));
if (xlr < dp->dtdo_xlmlen) {
(void) fprintf(fp, "\t\t! DT_XLREF[%u] = %u.%s", xlr,
(uint_t)dp->dtdo_xlmtab[xlr]->dn_membexpr->dn_xlator->dx_id,
dp->dtdo_xlmtab[xlr]->dn_membname);
}
}
static char *
dt_dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len)
{
char kind[16], ckind[16];
switch (t->dtdt_kind) {
case DIF_TYPE_CTF:
(void) strcpy(kind, "D type");
break;
case DIF_TYPE_STRING:
(void) strcpy(kind, "string");
break;
default:
(void) snprintf(kind, sizeof (kind), "0x%x", t->dtdt_kind);
}
switch (t->dtdt_ckind) {
case CTF_K_UNKNOWN:
(void) strcpy(ckind, "unknown");
break;
case CTF_K_INTEGER:
(void) strcpy(ckind, "integer");
break;
case CTF_K_FLOAT:
(void) strcpy(ckind, "float");
break;
case CTF_K_POINTER:
(void) strcpy(ckind, "pointer");
break;
case CTF_K_ARRAY:
(void) strcpy(ckind, "array");
break;
case CTF_K_FUNCTION:
(void) strcpy(ckind, "function");
break;
case CTF_K_STRUCT:
(void) strcpy(ckind, "struct");
break;
case CTF_K_UNION:
(void) strcpy(ckind, "union");
break;
case CTF_K_ENUM:
(void) strcpy(ckind, "enum");
break;
case CTF_K_FORWARD:
(void) strcpy(ckind, "forward");
break;
case CTF_K_TYPEDEF:
(void) strcpy(ckind, "typedef");
break;
case CTF_K_VOLATILE:
(void) strcpy(ckind, "volatile");
break;
case CTF_K_CONST:
(void) strcpy(ckind, "const");
break;
case CTF_K_RESTRICT:
(void) strcpy(ckind, "restrict");
break;
default:
(void) snprintf(ckind, sizeof (ckind), "0x%x", t->dtdt_ckind);
}
if (t->dtdt_flags & DIF_TF_BYREF) {
(void) snprintf(buf, len, "%s (%s) by ref (size %lu)",
kind, ckind, (ulong_t)t->dtdt_size);
} else {
(void) snprintf(buf, len, "%s (%s) (size %lu)",
kind, ckind, (ulong_t)t->dtdt_size);
}
return (buf);
}
static void
dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp,
const dof_relodesc_t *rp, uint32_t len)
{
(void) fprintf(fp, "\n%-4s %-8s %-8s %s\n",
rtag, "OFFSET", "DATA", "NAME");
for (; len != 0; len--, rp++) {
(void) fprintf(fp, "%-4u %-8llu %-8llu %s\n",
rp->dofr_type, (u_longlong_t)rp->dofr_offset,
(u_longlong_t)rp->dofr_data,
&dp->dtdo_strtab[rp->dofr_name]);
}
}
void
dt_dis(const dtrace_difo_t *dp, FILE *fp)
{
static const struct opent {
const char *op_name;
void (*op_func)(const dtrace_difo_t *, const char *,
dif_instr_t, FILE *);
} optab[] = {
{ "(illegal opcode)", dt_dis_str },
{ "or", dt_dis_log }, /* DIF_OP_OR */
{ "xor", dt_dis_log }, /* DIF_OP_XOR */
{ "and", dt_dis_log }, /* DIF_OP_AND */
{ "sll", dt_dis_log }, /* DIF_OP_SLL */
{ "srl", dt_dis_log }, /* DIF_OP_SRL */
{ "sub", dt_dis_log }, /* DIF_OP_SUB */
{ "add", dt_dis_log }, /* DIF_OP_ADD */
{ "mul", dt_dis_log }, /* DIF_OP_MUL */
{ "sdiv", dt_dis_log }, /* DIF_OP_SDIV */
{ "udiv", dt_dis_log }, /* DIF_OP_UDIV */
{ "srem", dt_dis_log }, /* DIF_OP_SREM */
{ "urem", dt_dis_log }, /* DIF_OP_UREM */
{ "not", dt_dis_r1rd }, /* DIF_OP_NOT */
{ "mov", dt_dis_r1rd }, /* DIF_OP_MOV */
{ "cmp", dt_dis_cmp }, /* DIF_OP_CMP */
{ "tst", dt_dis_tst }, /* DIF_OP_TST */
{ "ba", dt_dis_branch }, /* DIF_OP_BA */
{ "be", dt_dis_branch }, /* DIF_OP_BE */
{ "bne", dt_dis_branch }, /* DIF_OP_BNE */
{ "bg", dt_dis_branch }, /* DIF_OP_BG */
{ "bgu", dt_dis_branch }, /* DIF_OP_BGU */
{ "bge", dt_dis_branch }, /* DIF_OP_BGE */
{ "bgeu", dt_dis_branch }, /* DIF_OP_BGEU */
{ "bl", dt_dis_branch }, /* DIF_OP_BL */
{ "blu", dt_dis_branch }, /* DIF_OP_BLU */
{ "ble", dt_dis_branch }, /* DIF_OP_BLE */
{ "bleu", dt_dis_branch }, /* DIF_OP_BLEU */
{ "ldsb", dt_dis_load }, /* DIF_OP_LDSB */
{ "ldsh", dt_dis_load }, /* DIF_OP_LDSH */
{ "ldsw", dt_dis_load }, /* DIF_OP_LDSW */
{ "ldub", dt_dis_load }, /* DIF_OP_LDUB */
{ "lduh", dt_dis_load }, /* DIF_OP_LDUH */
{ "lduw", dt_dis_load }, /* DIF_OP_LDUW */
{ "ldx", dt_dis_load }, /* DIF_OP_LDX */
{ "ret", dt_dis_ret }, /* DIF_OP_RET */
{ "nop", dt_dis_str }, /* DIF_OP_NOP */
{ "setx", dt_dis_setx }, /* DIF_OP_SETX */
{ "sets", dt_dis_sets }, /* DIF_OP_SETS */
{ "scmp", dt_dis_cmp }, /* DIF_OP_SCMP */
{ "ldga", dt_dis_lda }, /* DIF_OP_LDGA */
{ "ldgs", dt_dis_ldv }, /* DIF_OP_LDGS */
{ "stgs", dt_dis_stv }, /* DIF_OP_STGS */
{ "ldta", dt_dis_lda }, /* DIF_OP_LDTA */
{ "ldts", dt_dis_ldv }, /* DIF_OP_LDTS */
{ "stts", dt_dis_stv }, /* DIF_OP_STTS */
{ "sra", dt_dis_log }, /* DIF_OP_SRA */
{ "call", dt_dis_call }, /* DIF_OP_CALL */
{ "pushtr", dt_dis_pushts }, /* DIF_OP_PUSHTR */
{ "pushtv", dt_dis_pushts }, /* DIF_OP_PUSHTV */
{ "popts", dt_dis_str }, /* DIF_OP_POPTS */
{ "flushts", dt_dis_str }, /* DIF_OP_FLUSHTS */
{ "ldgaa", dt_dis_ldv }, /* DIF_OP_LDGAA */
{ "ldtaa", dt_dis_ldv }, /* DIF_OP_LDTAA */
{ "stgaa", dt_dis_stv }, /* DIF_OP_STGAA */
{ "sttaa", dt_dis_stv }, /* DIF_OP_STTAA */
{ "ldls", dt_dis_ldv }, /* DIF_OP_LDLS */
{ "stls", dt_dis_stv }, /* DIF_OP_STLS */
{ "allocs", dt_dis_r1rd }, /* DIF_OP_ALLOCS */
{ "copys", dt_dis_log }, /* DIF_OP_COPYS */
{ "stb", dt_dis_store }, /* DIF_OP_STB */
{ "sth", dt_dis_store }, /* DIF_OP_STH */
{ "stw", dt_dis_store }, /* DIF_OP_STW */
{ "stx", dt_dis_store }, /* DIF_OP_STX */
{ "uldsb", dt_dis_load }, /* DIF_OP_ULDSB */
{ "uldsh", dt_dis_load }, /* DIF_OP_ULDSH */
{ "uldsw", dt_dis_load }, /* DIF_OP_ULDSW */
{ "uldub", dt_dis_load }, /* DIF_OP_ULDUB */
{ "ulduh", dt_dis_load }, /* DIF_OP_ULDUH */
{ "ulduw", dt_dis_load }, /* DIF_OP_ULDUW */
{ "uldx", dt_dis_load }, /* DIF_OP_ULDX */
{ "rldsb", dt_dis_load }, /* DIF_OP_RLDSB */
{ "rldsh", dt_dis_load }, /* DIF_OP_RLDSH */
{ "rldsw", dt_dis_load }, /* DIF_OP_RLDSW */
{ "rldub", dt_dis_load }, /* DIF_OP_RLDUB */
{ "rlduh", dt_dis_load }, /* DIF_OP_RLDUH */
{ "rlduw", dt_dis_load }, /* DIF_OP_RLDUW */
{ "rldx", dt_dis_load }, /* DIF_OP_RLDX */
{ "xlate", dt_dis_xlate }, /* DIF_OP_XLATE */
{ "xlarg", dt_dis_xlate }, /* DIF_OP_XLARG */
};
const struct opent *op;
ulong_t i = 0;
char type[DT_TYPE_NAMELEN];
(void) fprintf(fp, "\nDIFO 0x%p returns %s\n", (void *)dp,
dt_dis_typestr(&dp->dtdo_rtype, type, sizeof (type)));
(void) fprintf(fp, "%-3s %-8s %s\n",
"OFF", "OPCODE", "INSTRUCTION");
for (i = 0; i < dp->dtdo_len; i++) {
dif_instr_t instr = dp->dtdo_buf[i];
dif_instr_t opcode = DIF_INSTR_OP(instr);
if (opcode >= sizeof (optab) / sizeof (optab[0]))
opcode = 0; /* force invalid opcode message */
op = &optab[opcode];
(void) fprintf(fp, "%02lu: %08x ", i, instr);
op->op_func(dp, op->op_name, instr, fp);
(void) fprintf(fp, "\n");
}
if (dp->dtdo_varlen != 0) {
(void) fprintf(fp, "\n%-16s %-4s %-3s %-3s %-4s %s\n",
"NAME", "ID", "KND", "SCP", "FLAG", "TYPE");
}
for (i = 0; i < dp->dtdo_varlen; i++) {
dtrace_difv_t *v = &dp->dtdo_vartab[i];
char kind[4], scope[4], flags[16] = { 0 };
switch (v->dtdv_kind) {
case DIFV_KIND_ARRAY:
(void) strcpy(kind, "arr");
break;
case DIFV_KIND_SCALAR:
(void) strcpy(kind, "scl");
break;
default:
(void) snprintf(kind, sizeof (kind),
"%u", v->dtdv_kind);
}
switch (v->dtdv_scope) {
case DIFV_SCOPE_GLOBAL:
(void) strcpy(scope, "glb");
break;
case DIFV_SCOPE_THREAD:
(void) strcpy(scope, "tls");
break;
case DIFV_SCOPE_LOCAL:
(void) strcpy(scope, "loc");
break;
default:
(void) snprintf(scope, sizeof (scope),
"%u", v->dtdv_scope);
}
if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) {
(void) snprintf(flags, sizeof (flags), "/0x%x",
v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD));
}
if (v->dtdv_flags & DIFV_F_REF)
(void) strcat(flags, "/r");
if (v->dtdv_flags & DIFV_F_MOD)
(void) strcat(flags, "/w");
(void) fprintf(fp, "%-16s %-4x %-3s %-3s %-4s %s\n",
&dp->dtdo_strtab[v->dtdv_name],
v->dtdv_id, kind, scope, flags + 1,
dt_dis_typestr(&v->dtdv_type, type, sizeof (type)));
}
if (dp->dtdo_xlmlen != 0) {
(void) fprintf(fp, "\n%-4s %-3s %-12s %s\n",
"XLID", "ARG", "MEMBER", "TYPE");
}
for (i = 0; i < dp->dtdo_xlmlen; i++) {
dt_node_t *dnp = dp->dtdo_xlmtab[i];
dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
(void) fprintf(fp, "%-4u %-3d %-12s %s\n",
(uint_t)dxp->dx_id, dxp->dx_arg, dnp->dn_membname,
dt_node_type_name(dnp, type, sizeof (type)));
}
if (dp->dtdo_krelen != 0)
dt_dis_rtab("KREL", dp, fp, dp->dtdo_kreltab, dp->dtdo_krelen);
if (dp->dtdo_urelen != 0)
dt_dis_rtab("UREL", dp, fp, dp->dtdo_ureltab, dp->dtdo_urelen);
}

View File

@ -0,0 +1,969 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#if defined(sun)
#include <sys/sysmacros.h>
#endif
#include <strings.h>
#if defined(sun)
#include <alloca.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <dt_impl.h>
#include <dt_strtab.h>
#include <dt_program.h>
#include <dt_provider.h>
#include <dt_xlator.h>
#include <dt_dof.h>
void
dt_dof_init(dtrace_hdl_t *dtp)
{
dt_dof_t *ddo = &dtp->dt_dof;
ddo->ddo_hdl = dtp;
ddo->ddo_nsecs = 0;
ddo->ddo_strsec = DOF_SECIDX_NONE;
ddo->ddo_xlimport = NULL;
ddo->ddo_xlexport = NULL;
dt_buf_create(dtp, &ddo->ddo_secs, "section headers", 0);
dt_buf_create(dtp, &ddo->ddo_strs, "string table", 0);
dt_buf_create(dtp, &ddo->ddo_ldata, "loadable data", 0);
dt_buf_create(dtp, &ddo->ddo_udata, "unloadable data", 0);
dt_buf_create(dtp, &ddo->ddo_probes, "probe data", 0);
dt_buf_create(dtp, &ddo->ddo_args, "probe args", 0);
dt_buf_create(dtp, &ddo->ddo_offs, "probe offs", 0);
dt_buf_create(dtp, &ddo->ddo_enoffs, "probe is-enabled offs", 0);
dt_buf_create(dtp, &ddo->ddo_rels, "probe rels", 0);
dt_buf_create(dtp, &ddo->ddo_xlms, "xlate members", 0);
}
void
dt_dof_fini(dtrace_hdl_t *dtp)
{
dt_dof_t *ddo = &dtp->dt_dof;
dt_free(dtp, ddo->ddo_xlimport);
dt_free(dtp, ddo->ddo_xlexport);
dt_buf_destroy(dtp, &ddo->ddo_secs);
dt_buf_destroy(dtp, &ddo->ddo_strs);
dt_buf_destroy(dtp, &ddo->ddo_ldata);
dt_buf_destroy(dtp, &ddo->ddo_udata);
dt_buf_destroy(dtp, &ddo->ddo_probes);
dt_buf_destroy(dtp, &ddo->ddo_args);
dt_buf_destroy(dtp, &ddo->ddo_offs);
dt_buf_destroy(dtp, &ddo->ddo_enoffs);
dt_buf_destroy(dtp, &ddo->ddo_rels);
dt_buf_destroy(dtp, &ddo->ddo_xlms);
}
static int
dt_dof_reset(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
{
dt_dof_t *ddo = &dtp->dt_dof;
uint_t i, nx = dtp->dt_xlatorid;
assert(ddo->ddo_hdl == dtp);
ddo->ddo_pgp = pgp;
ddo->ddo_nsecs = 0;
ddo->ddo_strsec = DOF_SECIDX_NONE;
dt_free(dtp, ddo->ddo_xlimport);
dt_free(dtp, ddo->ddo_xlexport);
ddo->ddo_xlimport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx);
ddo->ddo_xlexport = dt_alloc(dtp, sizeof (dof_secidx_t) * nx);
if (nx != 0 && (ddo->ddo_xlimport == NULL || ddo->ddo_xlexport == NULL))
return (-1); /* errno is set for us */
for (i = 0; i < nx; i++) {
ddo->ddo_xlimport[i] = DOF_SECIDX_NONE;
ddo->ddo_xlexport[i] = DOF_SECIDX_NONE;
}
dt_buf_reset(dtp, &ddo->ddo_secs);
dt_buf_reset(dtp, &ddo->ddo_strs);
dt_buf_reset(dtp, &ddo->ddo_ldata);
dt_buf_reset(dtp, &ddo->ddo_udata);
dt_buf_reset(dtp, &ddo->ddo_probes);
dt_buf_reset(dtp, &ddo->ddo_args);
dt_buf_reset(dtp, &ddo->ddo_offs);
dt_buf_reset(dtp, &ddo->ddo_enoffs);
dt_buf_reset(dtp, &ddo->ddo_rels);
dt_buf_reset(dtp, &ddo->ddo_xlms);
return (0);
}
/*
* Add a loadable DOF section to the file using the specified data buffer and
* the specified DOF section attributes. DOF_SECF_LOAD must be set in flags.
* If 'data' is NULL, the caller is responsible for manipulating the ldata buf.
*/
static dof_secidx_t
dof_add_lsect(dt_dof_t *ddo, const void *data, uint32_t type,
uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size)
{
dtrace_hdl_t *dtp = ddo->ddo_hdl;
dof_sec_t s;
s.dofs_type = type;
s.dofs_align = align;
s.dofs_flags = flags | DOF_SECF_LOAD;
s.dofs_entsize = entsize;
s.dofs_offset = dt_buf_offset(&ddo->ddo_ldata, align);
s.dofs_size = size;
dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t));
if (data != NULL)
dt_buf_write(dtp, &ddo->ddo_ldata, data, size, align);
return (ddo->ddo_nsecs++);
}
/*
* Add an unloadable DOF section to the file using the specified data buffer
* and DOF section attributes. DOF_SECF_LOAD must *not* be set in flags.
* If 'data' is NULL, the caller is responsible for manipulating the udata buf.
*/
static dof_secidx_t
dof_add_usect(dt_dof_t *ddo, const void *data, uint32_t type,
uint32_t align, uint32_t flags, uint32_t entsize, uint64_t size)
{
dtrace_hdl_t *dtp = ddo->ddo_hdl;
dof_sec_t s;
s.dofs_type = type;
s.dofs_align = align;
s.dofs_flags = flags & ~DOF_SECF_LOAD;
s.dofs_entsize = entsize;
s.dofs_offset = dt_buf_offset(&ddo->ddo_udata, align);
s.dofs_size = size;
dt_buf_write(dtp, &ddo->ddo_secs, &s, sizeof (s), sizeof (uint64_t));
if (data != NULL)
dt_buf_write(dtp, &ddo->ddo_udata, data, size, align);
return (ddo->ddo_nsecs++);
}
/*
* Add a string to the global string table associated with the DOF. The offset
* of the string is returned as an index into the string table.
*/
static dof_stridx_t
dof_add_string(dt_dof_t *ddo, const char *s)
{
dt_buf_t *bp = &ddo->ddo_strs;
dof_stridx_t i = dt_buf_len(bp);
if (i != 0 && (s == NULL || *s == '\0'))
return (0); /* string table has \0 at offset 0 */
dt_buf_write(ddo->ddo_hdl, bp, s, strlen(s) + 1, sizeof (char));
return (i);
}
static dof_attr_t
dof_attr(const dtrace_attribute_t *ap)
{
return (DOF_ATTR(ap->dtat_name, ap->dtat_data, ap->dtat_class));
}
static dof_secidx_t
dof_add_difo(dt_dof_t *ddo, const dtrace_difo_t *dp)
{
dof_secidx_t dsecs[5]; /* enough for all possible DIFO sections */
uint_t nsecs = 0;
dof_difohdr_t *dofd;
dof_relohdr_t dofr;
dof_secidx_t relsec;
dof_secidx_t strsec = DOF_SECIDX_NONE;
dof_secidx_t intsec = DOF_SECIDX_NONE;
dof_secidx_t hdrsec = DOF_SECIDX_NONE;
if (dp->dtdo_buf != NULL) {
dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_buf,
DOF_SECT_DIF, sizeof (dif_instr_t), 0,
sizeof (dif_instr_t), sizeof (dif_instr_t) * dp->dtdo_len);
}
if (dp->dtdo_inttab != NULL) {
dsecs[nsecs++] = intsec = dof_add_lsect(ddo, dp->dtdo_inttab,
DOF_SECT_INTTAB, sizeof (uint64_t), 0,
sizeof (uint64_t), sizeof (uint64_t) * dp->dtdo_intlen);
}
if (dp->dtdo_strtab != NULL) {
dsecs[nsecs++] = strsec = dof_add_lsect(ddo, dp->dtdo_strtab,
DOF_SECT_STRTAB, sizeof (char), 0, 0, dp->dtdo_strlen);
}
if (dp->dtdo_vartab != NULL) {
dsecs[nsecs++] = dof_add_lsect(ddo, dp->dtdo_vartab,
DOF_SECT_VARTAB, sizeof (uint_t), 0, sizeof (dtrace_difv_t),
sizeof (dtrace_difv_t) * dp->dtdo_varlen);
}
if (dp->dtdo_xlmtab != NULL) {
dof_xlref_t *xlt, *xlp;
dt_node_t **pnp;
xlt = alloca(sizeof (dof_xlref_t) * dp->dtdo_xlmlen);
pnp = dp->dtdo_xlmtab;
/*
* dtdo_xlmtab contains pointers to the translator members.
* The translator itself is in sect ddo_xlimport[dxp->dx_id].
* The XLMEMBERS entries are in order by their dn_membid, so
* the member section offset is the population count of bits
* in ddo_pgp->dp_xlrefs[] up to and not including dn_membid.
*/
for (xlp = xlt; xlp < xlt + dp->dtdo_xlmlen; xlp++) {
dt_node_t *dnp = *pnp++;
dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator;
xlp->dofxr_xlator = ddo->ddo_xlimport[dxp->dx_id];
xlp->dofxr_member = dt_popcb(
ddo->ddo_pgp->dp_xrefs[dxp->dx_id], dnp->dn_membid);
xlp->dofxr_argn = (uint32_t)dxp->dx_arg;
}
dsecs[nsecs++] = dof_add_lsect(ddo, xlt, DOF_SECT_XLTAB,
sizeof (dof_secidx_t), 0, sizeof (dof_xlref_t),
sizeof (dof_xlref_t) * dp->dtdo_xlmlen);
}
/*
* Copy the return type and the array of section indices that form the
* DIFO into a single dof_difohdr_t and then add DOF_SECT_DIFOHDR.
*/
assert(nsecs <= sizeof (dsecs) / sizeof (dsecs[0]));
dofd = alloca(sizeof (dtrace_diftype_t) + sizeof (dsecs));
bcopy(&dp->dtdo_rtype, &dofd->dofd_rtype, sizeof (dtrace_diftype_t));
bcopy(dsecs, &dofd->dofd_links, sizeof (dof_secidx_t) * nsecs);
hdrsec = dof_add_lsect(ddo, dofd, DOF_SECT_DIFOHDR,
sizeof (dof_secidx_t), 0, 0,
sizeof (dtrace_diftype_t) + sizeof (dof_secidx_t) * nsecs);
/*
* Add any other sections related to dtrace_difo_t. These are not
* referenced in dof_difohdr_t because they are not used by emulation.
*/
if (dp->dtdo_kreltab != NULL) {
relsec = dof_add_lsect(ddo, dp->dtdo_kreltab, DOF_SECT_RELTAB,
sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
sizeof (dof_relodesc_t) * dp->dtdo_krelen);
/*
* This code assumes the target of all relocations is the
* integer table 'intsec' (DOF_SECT_INTTAB). If other sections
* need relocation in the future this will need to change.
*/
dofr.dofr_strtab = strsec;
dofr.dofr_relsec = relsec;
dofr.dofr_tgtsec = intsec;
(void) dof_add_lsect(ddo, &dofr, DOF_SECT_KRELHDR,
sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));
}
if (dp->dtdo_ureltab != NULL) {
relsec = dof_add_lsect(ddo, dp->dtdo_ureltab, DOF_SECT_RELTAB,
sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
sizeof (dof_relodesc_t) * dp->dtdo_urelen);
/*
* This code assumes the target of all relocations is the
* integer table 'intsec' (DOF_SECT_INTTAB). If other sections
* need relocation in the future this will need to change.
*/
dofr.dofr_strtab = strsec;
dofr.dofr_relsec = relsec;
dofr.dofr_tgtsec = intsec;
(void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,
sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));
}
return (hdrsec);
}
static void
dof_add_translator(dt_dof_t *ddo, const dt_xlator_t *dxp, uint_t type)
{
dtrace_hdl_t *dtp = ddo->ddo_hdl;
dof_xlmember_t dofxm;
dof_xlator_t dofxl;
dof_secidx_t *xst;
char buf[DT_TYPE_NAMELEN];
dt_node_t *dnp;
uint_t i = 0;
assert(type == DOF_SECT_XLIMPORT || type == DOF_SECT_XLEXPORT);
xst = type == DOF_SECT_XLIMPORT ? ddo->ddo_xlimport : ddo->ddo_xlexport;
if (xst[dxp->dx_id] != DOF_SECIDX_NONE)
return; /* translator has already been emitted */
dt_buf_reset(dtp, &ddo->ddo_xlms);
/*
* Generate an array of dof_xlmember_t's into ddo_xlms. If we are
* importing the translator, add only those members referenced by the
* program and set the dofxm_difo reference of each member to NONE. If
* we're exporting the translator, add all members and a DIFO for each.
*/
for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list, i++) {
if (type == DOF_SECT_XLIMPORT) {
if (!BT_TEST(ddo->ddo_pgp->dp_xrefs[dxp->dx_id], i))
continue; /* member is not referenced */
dofxm.dofxm_difo = DOF_SECIDX_NONE;
} else {
dofxm.dofxm_difo = dof_add_difo(ddo,
dxp->dx_membdif[dnp->dn_membid]);
}
dofxm.dofxm_name = dof_add_string(ddo, dnp->dn_membname);
dt_node_diftype(dtp, dnp, &dofxm.dofxm_type);
dt_buf_write(dtp, &ddo->ddo_xlms,
&dofxm, sizeof (dofxm), sizeof (uint32_t));
}
dofxl.dofxl_members = dof_add_lsect(ddo, NULL, DOF_SECT_XLMEMBERS,
sizeof (uint32_t), 0, sizeof (dofxm), dt_buf_len(&ddo->ddo_xlms));
dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_xlms, sizeof (uint32_t));
dofxl.dofxl_strtab = ddo->ddo_strsec;
dofxl.dofxl_argv = dof_add_string(ddo, ctf_type_name(
dxp->dx_src_ctfp, dxp->dx_src_type, buf, sizeof (buf)));
dofxl.dofxl_argc = 1;
dofxl.dofxl_type = dof_add_string(ddo, ctf_type_name(
dxp->dx_dst_ctfp, dxp->dx_dst_type, buf, sizeof (buf)));
dofxl.dofxl_attr = dof_attr(&dxp->dx_souid.di_attr);
xst[dxp->dx_id] = dof_add_lsect(ddo, &dofxl, type,
sizeof (uint32_t), 0, 0, sizeof (dofxl));
}
/*ARGSUSED*/
static int
dof_add_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
dt_dof_t *ddo = data;
dtrace_hdl_t *dtp = ddo->ddo_hdl;
dt_probe_t *prp = idp->di_data;
dof_probe_t dofpr;
dof_relodesc_t dofr;
dt_probe_instance_t *pip;
dt_node_t *dnp;
char buf[DT_TYPE_NAMELEN];
uint_t i;
dofpr.dofpr_addr = 0;
dofpr.dofpr_name = dof_add_string(ddo, prp->pr_name);
dofpr.dofpr_nargv = dt_buf_len(&ddo->ddo_strs);
for (dnp = prp->pr_nargs; dnp != NULL; dnp = dnp->dn_list) {
(void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp,
dnp->dn_type, buf, sizeof (buf)));
}
dofpr.dofpr_xargv = dt_buf_len(&ddo->ddo_strs);
for (dnp = prp->pr_xargs; dnp != NULL; dnp = dnp->dn_list) {
(void) dof_add_string(ddo, ctf_type_name(dnp->dn_ctfp,
dnp->dn_type, buf, sizeof (buf)));
}
dofpr.dofpr_argidx = dt_buf_len(&ddo->ddo_args) / sizeof (uint8_t);
for (i = 0; i < prp->pr_xargc; i++) {
dt_buf_write(dtp, &ddo->ddo_args, &prp->pr_mapping[i],
sizeof (uint8_t), sizeof (uint8_t));
}
dofpr.dofpr_nargc = prp->pr_nargc;
dofpr.dofpr_xargc = prp->pr_xargc;
dofpr.dofpr_pad1 = 0;
dofpr.dofpr_pad2 = 0;
for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
dt_dprintf("adding probe for %s:%s\n", pip->pi_fname,
prp->pr_name);
dofpr.dofpr_func = dof_add_string(ddo, pip->pi_fname);
/*
* There should be one probe offset or is-enabled probe offset
* or else this probe instance won't have been created. The
* kernel will reject DOF which has a probe with no offsets.
*/
assert(pip->pi_noffs + pip->pi_nenoffs > 0);
dofpr.dofpr_offidx =
dt_buf_len(&ddo->ddo_offs) / sizeof (uint32_t);
dofpr.dofpr_noffs = pip->pi_noffs;
dt_buf_write(dtp, &ddo->ddo_offs, pip->pi_offs,
pip->pi_noffs * sizeof (uint32_t), sizeof (uint32_t));
dofpr.dofpr_enoffidx =
dt_buf_len(&ddo->ddo_enoffs) / sizeof (uint32_t);
dofpr.dofpr_nenoffs = pip->pi_nenoffs;
dt_buf_write(dtp, &ddo->ddo_enoffs, pip->pi_enoffs,
pip->pi_nenoffs * sizeof (uint32_t), sizeof (uint32_t));
/*
* If pi_rname isn't set, the relocation will be against the
* function name. If it is, the relocation will be against
* pi_rname. This will be used if the function is scoped
* locally so an alternate symbol is added for the purpose
* of this relocation.
*/
if (pip->pi_rname[0] == '\0')
dofr.dofr_name = dofpr.dofpr_func;
else
dofr.dofr_name = dof_add_string(ddo, pip->pi_rname);
dofr.dofr_type = DOF_RELO_SETX;
dofr.dofr_offset = dt_buf_len(&ddo->ddo_probes);
dofr.dofr_data = 0;
dt_buf_write(dtp, &ddo->ddo_rels, &dofr,
sizeof (dofr), sizeof (uint64_t));
dt_buf_write(dtp, &ddo->ddo_probes, &dofpr,
sizeof (dofpr), sizeof (uint64_t));
}
return (0);
}
static void
dof_add_provider(dt_dof_t *ddo, const dt_provider_t *pvp)
{
dtrace_hdl_t *dtp = ddo->ddo_hdl;
dof_provider_t dofpv;
dof_relohdr_t dofr;
dof_secidx_t *dofs;
ulong_t xr, nxr;
size_t sz;
id_t i;
if (pvp->pv_flags & DT_PROVIDER_IMPL)
return; /* ignore providers that are exported by dtrace(7D) */
nxr = dt_popcb(pvp->pv_xrefs, pvp->pv_xrmax);
dofs = alloca(sizeof (dof_secidx_t) * (nxr + 1));
xr = 1; /* reserve dofs[0] for the provider itself */
/*
* For each translator referenced by the provider (pv_xrefs), emit an
* exported translator section for it if one hasn't been created yet.
*/
for (i = 0; i < pvp->pv_xrmax; i++) {
if (BT_TEST(pvp->pv_xrefs, i) &&
dtp->dt_xlatemode == DT_XL_DYNAMIC) {
dof_add_translator(ddo,
dt_xlator_lookup_id(dtp, i), DOF_SECT_XLEXPORT);
dofs[xr++] = ddo->ddo_xlexport[i];
}
}
dt_buf_reset(dtp, &ddo->ddo_probes);
dt_buf_reset(dtp, &ddo->ddo_args);
dt_buf_reset(dtp, &ddo->ddo_offs);
dt_buf_reset(dtp, &ddo->ddo_enoffs);
dt_buf_reset(dtp, &ddo->ddo_rels);
(void) dt_idhash_iter(pvp->pv_probes, dof_add_probe, ddo);
dofpv.dofpv_probes = dof_add_lsect(ddo, NULL, DOF_SECT_PROBES,
sizeof (uint64_t), 0, sizeof (dof_probe_t),
dt_buf_len(&ddo->ddo_probes));
dt_buf_concat(dtp, &ddo->ddo_ldata,
&ddo->ddo_probes, sizeof (uint64_t));
dofpv.dofpv_prargs = dof_add_lsect(ddo, NULL, DOF_SECT_PRARGS,
sizeof (uint8_t), 0, sizeof (uint8_t), dt_buf_len(&ddo->ddo_args));
dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_args, sizeof (uint8_t));
dofpv.dofpv_proffs = dof_add_lsect(ddo, NULL, DOF_SECT_PROFFS,
sizeof (uint_t), 0, sizeof (uint_t), dt_buf_len(&ddo->ddo_offs));
dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_offs, sizeof (uint_t));
if ((sz = dt_buf_len(&ddo->ddo_enoffs)) != 0) {
dofpv.dofpv_prenoffs = dof_add_lsect(ddo, NULL,
DOF_SECT_PRENOFFS, sizeof (uint_t), 0, sizeof (uint_t), sz);
} else {
dofpv.dofpv_prenoffs = DOF_SECT_NONE;
}
dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_enoffs, sizeof (uint_t));
dofpv.dofpv_strtab = ddo->ddo_strsec;
dofpv.dofpv_name = dof_add_string(ddo, pvp->pv_desc.dtvd_name);
dofpv.dofpv_provattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_provider);
dofpv.dofpv_modattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_mod);
dofpv.dofpv_funcattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_func);
dofpv.dofpv_nameattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_name);
dofpv.dofpv_argsattr = dof_attr(&pvp->pv_desc.dtvd_attr.dtpa_args);
dofs[0] = dof_add_lsect(ddo, &dofpv, DOF_SECT_PROVIDER,
sizeof (dof_secidx_t), 0, 0, sizeof (dof_provider_t));
dofr.dofr_strtab = dofpv.dofpv_strtab;
dofr.dofr_tgtsec = dofpv.dofpv_probes;
dofr.dofr_relsec = dof_add_lsect(ddo, NULL, DOF_SECT_RELTAB,
sizeof (uint64_t), 0, sizeof (dof_relodesc_t),
dt_buf_len(&ddo->ddo_rels));
dt_buf_concat(dtp, &ddo->ddo_ldata, &ddo->ddo_rels, sizeof (uint64_t));
(void) dof_add_lsect(ddo, &dofr, DOF_SECT_URELHDR,
sizeof (dof_secidx_t), 0, 0, sizeof (dof_relohdr_t));
if (nxr != 0 && dtp->dt_xlatemode == DT_XL_DYNAMIC) {
(void) dof_add_lsect(ddo, dofs, DOF_SECT_PREXPORT,
sizeof (dof_secidx_t), 0, sizeof (dof_secidx_t),
sizeof (dof_secidx_t) * (nxr + 1));
}
}
static int
dof_hdr(dtrace_hdl_t *dtp, uint8_t dofversion, dof_hdr_t *hp)
{
/*
* If our config values cannot fit in a uint8_t, we can't generate a
* DOF header since the values won't fit. This can only happen if the
* user forcibly compiles a program with an artificial configuration.
*/
if (dtp->dt_conf.dtc_difversion > UINT8_MAX ||
dtp->dt_conf.dtc_difintregs > UINT8_MAX ||
dtp->dt_conf.dtc_diftupregs > UINT8_MAX)
return (dt_set_errno(dtp, EOVERFLOW));
bzero(hp, sizeof (dof_hdr_t));
hp->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;
hp->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;
hp->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;
hp->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;
if (dtp->dt_conf.dtc_ctfmodel == CTF_MODEL_LP64)
hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_LP64;
else
hp->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_ILP32;
hp->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;
hp->dofh_ident[DOF_ID_VERSION] = dofversion;
hp->dofh_ident[DOF_ID_DIFVERS] = dtp->dt_conf.dtc_difversion;
hp->dofh_ident[DOF_ID_DIFIREG] = dtp->dt_conf.dtc_difintregs;
hp->dofh_ident[DOF_ID_DIFTREG] = dtp->dt_conf.dtc_diftupregs;
hp->dofh_hdrsize = sizeof (dof_hdr_t);
hp->dofh_secsize = sizeof (dof_sec_t);
hp->dofh_secoff = sizeof (dof_hdr_t);
return (0);
}
void *
dtrace_dof_create(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, uint_t flags)
{
dt_dof_t *ddo = &dtp->dt_dof;
const dtrace_ecbdesc_t *edp, *last;
const dtrace_probedesc_t *pdp;
const dtrace_actdesc_t *ap;
const dt_stmt_t *stp;
uint_t maxacts = 0;
uint_t maxfmt = 0;
dt_provider_t *pvp;
dt_xlator_t *dxp;
dof_actdesc_t *dofa;
dof_sec_t *sp;
size_t ssize, lsize;
dof_hdr_t h;
dt_buf_t dof;
char *fmt;
uint_t i;
if (flags & ~DTRACE_D_MASK) {
(void) dt_set_errno(dtp, EINVAL);
return (NULL);
}
flags |= dtp->dt_dflags;
if (dof_hdr(dtp, pgp->dp_dofversion, &h) != 0)
return (NULL);
if (dt_dof_reset(dtp, pgp) != 0)
return (NULL);
/*
* Iterate through the statement list computing the maximum number of
* actions and the maximum format string for allocating local buffers.
*/
for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);
stp != NULL; stp = dt_list_next(stp), last = edp) {
dtrace_stmtdesc_t *sdp = stp->ds_desc;
dtrace_actdesc_t *ap = sdp->dtsd_action;
if (sdp->dtsd_fmtdata != NULL) {
i = dtrace_printf_format(dtp,
sdp->dtsd_fmtdata, NULL, 0);
maxfmt = MAX(maxfmt, i);
}
if ((edp = sdp->dtsd_ecbdesc) == last)
continue; /* same ecb as previous statement */
for (i = 0, ap = edp->dted_action; ap; ap = ap->dtad_next)
i++;
maxacts = MAX(maxacts, i);
}
dofa = alloca(sizeof (dof_actdesc_t) * maxacts);
fmt = alloca(maxfmt + 1);
ddo->ddo_strsec = dof_add_lsect(ddo, NULL, DOF_SECT_STRTAB, 1, 0, 0, 0);
(void) dof_add_string(ddo, "");
/*
* If there are references to dynamic translators in the program, add
* an imported translator table entry for each referenced translator.
*/
if (pgp->dp_xrefslen != 0) {
for (dxp = dt_list_next(&dtp->dt_xlators);
dxp != NULL; dxp = dt_list_next(dxp)) {
if (dxp->dx_id < pgp->dp_xrefslen &&
pgp->dp_xrefs[dxp->dx_id] != NULL)
dof_add_translator(ddo, dxp, DOF_SECT_XLIMPORT);
}
}
/*
* Now iterate through the statement list, creating the DOF section
* headers and data for each one and adding them to our buffers.
*/
for (last = NULL, stp = dt_list_next(&pgp->dp_stmts);
stp != NULL; stp = dt_list_next(stp), last = edp) {
dof_secidx_t probesec = DOF_SECIDX_NONE;
dof_secidx_t prdsec = DOF_SECIDX_NONE;
dof_secidx_t actsec = DOF_SECIDX_NONE;
const dt_stmt_t *next = stp;
dtrace_stmtdesc_t *sdp = stp->ds_desc;
dof_stridx_t strndx = 0;
dof_probedesc_t dofp;
dof_ecbdesc_t dofe;
uint_t i;
if ((edp = stp->ds_desc->dtsd_ecbdesc) == last)
continue; /* same ecb as previous statement */
pdp = &edp->dted_probe;
/*
* Add a DOF_SECT_PROBEDESC for the ECB's probe description,
* and copy the probe description strings into the string table.
*/
dofp.dofp_strtab = ddo->ddo_strsec;
dofp.dofp_provider = dof_add_string(ddo, pdp->dtpd_provider);
dofp.dofp_mod = dof_add_string(ddo, pdp->dtpd_mod);
dofp.dofp_func = dof_add_string(ddo, pdp->dtpd_func);
dofp.dofp_name = dof_add_string(ddo, pdp->dtpd_name);
dofp.dofp_id = pdp->dtpd_id;
probesec = dof_add_lsect(ddo, &dofp, DOF_SECT_PROBEDESC,
sizeof (dof_secidx_t), 0,
sizeof (dof_probedesc_t), sizeof (dof_probedesc_t));
/*
* If there is a predicate DIFO associated with the ecbdesc,
* write out the DIFO sections and save the DIFO section index.
*/
if (edp->dted_pred.dtpdd_difo != NULL)
prdsec = dof_add_difo(ddo, edp->dted_pred.dtpdd_difo);
/*
* Now iterate through the action list generating DIFOs as
* referenced therein and adding action descriptions to 'dofa'.
*/
for (i = 0, ap = edp->dted_action;
ap != NULL; ap = ap->dtad_next, i++) {
if (ap->dtad_difo != NULL) {
dofa[i].dofa_difo =
dof_add_difo(ddo, ap->dtad_difo);
} else
dofa[i].dofa_difo = DOF_SECIDX_NONE;
/*
* If the first action in a statement has format data,
* add the format string to the global string table.
*/
if (sdp != NULL && ap == sdp->dtsd_action) {
if (sdp->dtsd_fmtdata != NULL) {
(void) dtrace_printf_format(dtp,
sdp->dtsd_fmtdata, fmt, maxfmt + 1);
strndx = dof_add_string(ddo, fmt);
} else
strndx = 0; /* use dtad_arg instead */
if ((next = dt_list_next(next)) != NULL)
sdp = next->ds_desc;
else
sdp = NULL;
}
if (strndx != 0) {
dofa[i].dofa_arg = strndx;
dofa[i].dofa_strtab = ddo->ddo_strsec;
} else {
dofa[i].dofa_arg = ap->dtad_arg;
dofa[i].dofa_strtab = DOF_SECIDX_NONE;
}
dofa[i].dofa_kind = ap->dtad_kind;
dofa[i].dofa_ntuple = ap->dtad_ntuple;
dofa[i].dofa_uarg = ap->dtad_uarg;
}
if (i > 0) {
actsec = dof_add_lsect(ddo, dofa, DOF_SECT_ACTDESC,
sizeof (uint64_t), 0, sizeof (dof_actdesc_t),
sizeof (dof_actdesc_t) * i);
}
/*
* Now finally, add the DOF_SECT_ECBDESC referencing all the
* previously created sub-sections.
*/
dofe.dofe_probes = probesec;
dofe.dofe_pred = prdsec;
dofe.dofe_actions = actsec;
dofe.dofe_pad = 0;
dofe.dofe_uarg = edp->dted_uarg;
(void) dof_add_lsect(ddo, &dofe, DOF_SECT_ECBDESC,
sizeof (uint64_t), 0, 0, sizeof (dof_ecbdesc_t));
}
/*
* If any providers are user-defined, output DOF sections corresponding
* to the providers and the probes and arguments that they define.
*/
if (flags & DTRACE_D_PROBES) {
for (pvp = dt_list_next(&dtp->dt_provlist);
pvp != NULL; pvp = dt_list_next(pvp))
dof_add_provider(ddo, pvp);
}
/*
* If we're not stripping unloadable sections, generate compiler
* comments and any other unloadable miscellany.
*/
if (!(flags & DTRACE_D_STRIP)) {
(void) dof_add_usect(ddo, _dtrace_version, DOF_SECT_COMMENTS,
sizeof (char), 0, 0, strlen(_dtrace_version) + 1);
(void) dof_add_usect(ddo, &dtp->dt_uts, DOF_SECT_UTSNAME,
sizeof (char), 0, 0, sizeof (struct utsname));
}
/*
* Compute and fill in the appropriate values for the dof_hdr_t's
* dofh_secnum, dofh_loadsz, and dofh_filez values.
*/
h.dofh_secnum = ddo->ddo_nsecs;
ssize = sizeof (h) + dt_buf_len(&ddo->ddo_secs);
assert(ssize == sizeof (h) + sizeof (dof_sec_t) * ddo->ddo_nsecs);
h.dofh_loadsz = ssize +
dt_buf_len(&ddo->ddo_ldata) +
dt_buf_len(&ddo->ddo_strs);
if (dt_buf_len(&ddo->ddo_udata) != 0) {
lsize = roundup(h.dofh_loadsz, sizeof (uint64_t));
h.dofh_filesz = lsize + dt_buf_len(&ddo->ddo_udata);
} else {
lsize = h.dofh_loadsz;
h.dofh_filesz = lsize;
}
/*
* Set the global DOF_SECT_STRTAB's offset to be after the header,
* section headers, and other loadable data. Since we're going to
* iterate over the buffer data directly, we must check for errors.
*/
if ((i = dt_buf_error(&ddo->ddo_secs)) != 0) {
(void) dt_set_errno(dtp, i);
return (NULL);
}
sp = dt_buf_ptr(&ddo->ddo_secs);
assert(sp[ddo->ddo_strsec].dofs_type == DOF_SECT_STRTAB);
sp[ddo->ddo_strsec].dofs_offset = ssize + dt_buf_len(&ddo->ddo_ldata);
sp[ddo->ddo_strsec].dofs_size = dt_buf_len(&ddo->ddo_strs);
/*
* Now relocate all the other section headers by adding the appropriate
* delta to their respective dofs_offset values.
*/
for (i = 0; i < ddo->ddo_nsecs; i++, sp++) {
if (i == ddo->ddo_strsec)
continue; /* already relocated above */
if (sp->dofs_flags & DOF_SECF_LOAD)
sp->dofs_offset += ssize;
else
sp->dofs_offset += lsize;
}
/*
* Finally, assemble the complete in-memory DOF buffer by writing the
* header and then concatenating all our buffers. dt_buf_concat() will
* propagate any errors and cause dt_buf_claim() to return NULL.
*/
dt_buf_create(dtp, &dof, "dof", h.dofh_filesz);
dt_buf_write(dtp, &dof, &h, sizeof (h), sizeof (uint64_t));
dt_buf_concat(dtp, &dof, &ddo->ddo_secs, sizeof (uint64_t));
dt_buf_concat(dtp, &dof, &ddo->ddo_ldata, sizeof (uint64_t));
dt_buf_concat(dtp, &dof, &ddo->ddo_strs, sizeof (char));
dt_buf_concat(dtp, &dof, &ddo->ddo_udata, sizeof (uint64_t));
return (dt_buf_claim(dtp, &dof));
}
void
dtrace_dof_destroy(dtrace_hdl_t *dtp, void *dof)
{
dt_free(dtp, dof);
}
void *
dtrace_getopt_dof(dtrace_hdl_t *dtp)
{
dof_hdr_t *dof;
dof_sec_t *sec;
dof_optdesc_t *dofo;
int i, nopts = 0, len = sizeof (dof_hdr_t) +
roundup(sizeof (dof_sec_t), sizeof (uint64_t));
for (i = 0; i < DTRACEOPT_MAX; i++) {
if (dtp->dt_options[i] != DTRACEOPT_UNSET)
nopts++;
}
len += sizeof (dof_optdesc_t) * nopts;
if ((dof = dt_zalloc(dtp, len)) == NULL ||
dof_hdr(dtp, DOF_VERSION, dof) != 0) {
dt_free(dtp, dof);
return (NULL);
}
dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */
dof->dofh_loadsz = len;
dof->dofh_filesz = len;
/*
* Fill in the option section header...
*/
sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t));
sec->dofs_type = DOF_SECT_OPTDESC;
sec->dofs_align = sizeof (uint64_t);
sec->dofs_flags = DOF_SECF_LOAD;
sec->dofs_entsize = sizeof (dof_optdesc_t);
dofo = (dof_optdesc_t *)((uintptr_t)sec +
roundup(sizeof (dof_sec_t), sizeof (uint64_t)));
sec->dofs_offset = (uintptr_t)dofo - (uintptr_t)dof;
sec->dofs_size = sizeof (dof_optdesc_t) * nopts;
for (i = 0; i < DTRACEOPT_MAX; i++) {
if (dtp->dt_options[i] == DTRACEOPT_UNSET)
continue;
dofo->dofo_option = i;
dofo->dofo_strtab = DOF_SECIDX_NONE;
dofo->dofo_value = dtp->dt_options[i];
dofo++;
}
return (dof);
}
void *
dtrace_geterr_dof(dtrace_hdl_t *dtp)
{
if (dtp->dt_errprog != NULL)
return (dtrace_dof_create(dtp, dtp->dt_errprog, 0));
(void) dt_set_errno(dtp, EDT_BADERROR);
return (NULL);
}

View File

@ -0,0 +1,66 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_DOF_H
#define _DT_DOF_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dtrace.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <dt_buf.h>
typedef struct dt_dof {
dtrace_hdl_t *ddo_hdl; /* libdtrace handle */
dtrace_prog_t *ddo_pgp; /* current program */
uint_t ddo_nsecs; /* number of sections */
dof_secidx_t ddo_strsec; /* global strings section index */
dof_secidx_t *ddo_xlimport; /* imported xlator section indices */
dof_secidx_t *ddo_xlexport; /* exported xlator section indices */
dt_buf_t ddo_secs; /* section headers */
dt_buf_t ddo_strs; /* global strings */
dt_buf_t ddo_ldata; /* loadable section data */
dt_buf_t ddo_udata; /* unloadable section data */
dt_buf_t ddo_probes; /* probe section data */
dt_buf_t ddo_args; /* probe arguments section data */
dt_buf_t ddo_offs; /* probe offsets section data */
dt_buf_t ddo_enoffs; /* is-enabled offsets section data */
dt_buf_t ddo_rels; /* probe relocation section data */
dt_buf_t ddo_xlms; /* xlate members section data */
} dt_dof_t;
extern void dt_dof_init(dtrace_hdl_t *);
extern void dt_dof_fini(dtrace_hdl_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_DOF_H */

View File

@ -0,0 +1,235 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <strings.h>
#include <dt_impl.h>
static const struct {
int err;
const char *msg;
} _dt_errlist[] = {
{ EDT_VERSION, "Client requested version newer than library" },
{ EDT_VERSINVAL, "Version is not properly formatted or is too large" },
{ EDT_VERSUNDEF, "Requested version is not supported by compiler" },
{ EDT_VERSREDUCED, "Requested version conflicts with earlier setting" },
{ EDT_CTF, "Unexpected libctf error" },
{ EDT_COMPILER, "Error in D program compilation" },
{ EDT_NOREG, "Insufficient registers to generate code" },
{ EDT_NOTUPREG, "Insufficient tuple registers to generate code" },
{ EDT_NOMEM, "Memory allocation failure" },
{ EDT_INT2BIG, "Integer constant table limit exceeded" },
{ EDT_STR2BIG, "String constant table limit exceeded" },
{ EDT_NOMOD, "Unknown module name" },
{ EDT_NOPROV, "Unknown provider name" },
{ EDT_NOPROBE, "No probe matches description" },
{ EDT_NOSYM, "Unknown symbol name" },
{ EDT_NOSYMADDR, "No symbol corresponds to address" },
{ EDT_NOTYPE, "Unknown type name" },
{ EDT_NOVAR, "Unknown variable name" },
{ EDT_NOAGG, "Unknown aggregation name" },
{ EDT_BADSCOPE, "Improper use of scoping operator in type name" },
{ EDT_BADSPEC, "Overspecified probe description" },
{ EDT_BADSPCV, "Undefined macro variable in probe description" },
{ EDT_BADID, "Unknown probe identifier" },
{ EDT_NOTLOADED, "Module is no longer loaded" },
{ EDT_NOCTF, "Module does not contain any CTF data" },
{ EDT_DATAMODEL, "Module and program data models do not match" },
{ EDT_DIFVERS, "Library uses newer DIF version than kernel" },
{ EDT_BADAGG, "Unknown aggregating action" },
{ EDT_FIO, "Error occurred while reading from input stream" },
{ EDT_DIFINVAL, "DIF program content is invalid" },
{ EDT_DIFSIZE, "DIF program exceeds maximum program size" },
{ EDT_DIFFAULT, "DIF program contains invalid pointer" },
{ EDT_BADPROBE, "Invalid probe specification" },
{ EDT_BADPGLOB, "Probe description has too many globbing characters" },
{ EDT_NOSCOPE, "Declaration scope stack underflow" },
{ EDT_NODECL, "Declaration stack underflow" },
{ EDT_DMISMATCH, "Data record list does not match statement" },
{ EDT_DOFFSET, "Data record offset exceeds buffer boundary" },
{ EDT_DALIGN, "Data record has inappropriate alignment" },
{ EDT_BADOPTNAME, "Invalid option name" },
{ EDT_BADOPTVAL, "Invalid value for specified option" },
{ EDT_BADOPTCTX, "Option cannot be used from within a D program" },
{ EDT_CPPFORK, "Failed to fork preprocessor" },
{ EDT_CPPEXEC, "Failed to exec preprocessor" },
{ EDT_CPPENT, "Preprocessor not found" },
{ EDT_CPPERR, "Preprocessor failed to process input program" },
{ EDT_SYMOFLOW, "Symbol table identifier space exhausted" },
{ EDT_ACTIVE, "Operation illegal when tracing is active" },
{ EDT_DESTRUCTIVE, "Destructive actions not allowed" },
{ EDT_NOANON, "No anonymous tracing state" },
{ EDT_ISANON, "Can't claim anonymous state and enable probes" },
{ EDT_ENDTOOBIG, "END enablings exceed size of principal buffer" },
{ EDT_NOCONV, "Failed to load type for printf conversion" },
{ EDT_BADCONV, "Incomplete printf conversion" },
{ EDT_BADERROR, "Invalid library ERROR action" },
{ EDT_ERRABORT, "Abort due to error" },
{ EDT_DROPABORT, "Abort due to drop" },
{ EDT_DIRABORT, "Abort explicitly directed" },
{ EDT_BADRVAL, "Invalid return value from callback" },
{ EDT_BADNORMAL, "Invalid normalization" },
{ EDT_BUFTOOSMALL, "Enabling exceeds size of buffer" },
{ EDT_BADTRUNC, "Invalid truncation" },
{ EDT_BUSY, "DTrace cannot be used when kernel debugger is active" },
{ EDT_ACCESS, "DTrace requires additional privileges" },
{ EDT_NOENT, "DTrace device not available on system" },
{ EDT_BRICKED, "Abort due to systemic unresponsiveness" },
{ EDT_HARDWIRE, "Failed to load language definitions" },
{ EDT_ELFVERSION, "libelf is out-of-date with respect to libdtrace" },
{ EDT_NOBUFFERED, "Attempt to buffer output without handler" },
{ EDT_UNSTABLE, "Description matched an unstable set of probes" },
{ EDT_BADSETOPT, "Invalid setopt() library action" },
{ EDT_BADSTACKPC, "Invalid stack program counter size" },
{ EDT_BADAGGVAR, "Invalid aggregation variable identifier" },
{ EDT_OVERSION, "Client requested deprecated version of library" }
};
static const int _dt_nerr = sizeof (_dt_errlist) / sizeof (_dt_errlist[0]);
const char *
dtrace_errmsg(dtrace_hdl_t *dtp, int error)
{
const char *str;
int i;
if (error == EDT_COMPILER && dtp != NULL && dtp->dt_errmsg[0] != '\0')
str = dtp->dt_errmsg;
else if (error == EDT_CTF && dtp != NULL && dtp->dt_ctferr != 0)
str = ctf_errmsg(dtp->dt_ctferr);
else if (error >= EDT_BASE && (error - EDT_BASE) < _dt_nerr) {
for (i = 0; i < _dt_nerr; i++) {
if (_dt_errlist[i].err == error)
return (_dt_errlist[i].msg);
}
str = NULL;
} else
str = strerror(error);
return (str ? str : "Unknown error");
}
int
dtrace_errno(dtrace_hdl_t *dtp)
{
return (dtp->dt_errno);
}
#if defined(sun)
int
dt_set_errno(dtrace_hdl_t *dtp, int err)
{
dtp->dt_errno = err;
return (-1);
}
#else
int
_dt_set_errno(dtrace_hdl_t *dtp, int err, const char *errfile, int errline)
{
dtp->dt_errno = err;
dtp->dt_errfile = errfile;
dtp->dt_errline = errline;
return (-1);
}
void dt_get_errloc(dtrace_hdl_t *dtp, const char **p_errfile, int *p_errline)
{
*p_errfile = dtp->dt_errfile;
*p_errline = dtp->dt_errline;
}
#endif
void
dt_set_errmsg(dtrace_hdl_t *dtp, const char *errtag, const char *region,
const char *filename, int lineno, const char *format, va_list ap)
{
size_t len, n;
char *p, *s;
s = dtp->dt_errmsg;
n = sizeof (dtp->dt_errmsg);
if (errtag != NULL && (yypcb->pcb_cflags & DTRACE_C_ETAGS))
(void) snprintf(s, n, "[%s] ", errtag);
else
s[0] = '\0';
len = strlen(dtp->dt_errmsg);
s = dtp->dt_errmsg + len;
n = sizeof (dtp->dt_errmsg) - len;
if (filename == NULL)
filename = dtp->dt_filetag;
if (filename != NULL)
(void) snprintf(s, n, "\"%s\", line %d: ", filename, lineno);
else if (lineno != 0)
(void) snprintf(s, n, "line %d: ", lineno);
else if (region != NULL)
(void) snprintf(s, n, "in %s: ", region);
len = strlen(dtp->dt_errmsg);
s = dtp->dt_errmsg + len;
n = sizeof (dtp->dt_errmsg) - len;
(void) vsnprintf(s, n, format, ap);
if ((p = strrchr(dtp->dt_errmsg, '\n')) != NULL)
*p = '\0'; /* remove trailing \n from message buffer */
dtp->dt_errtag = errtag;
}
/*ARGSUSED*/
const char *
dtrace_faultstr(dtrace_hdl_t *dtp, int fault)
{
int i;
static const struct {
int code;
const char *str;
} faults[] = {
{ DTRACEFLT_BADADDR, "invalid address" },
{ DTRACEFLT_BADALIGN, "invalid alignment" },
{ DTRACEFLT_ILLOP, "illegal operation" },
{ DTRACEFLT_DIVZERO, "divide-by-zero" },
{ DTRACEFLT_NOSCRATCH, "out of scratch space" },
{ DTRACEFLT_KPRIV, "invalid kernel access" },
{ DTRACEFLT_UPRIV, "invalid user access" },
{ DTRACEFLT_TUPOFLOW, "tuple stack overflow" },
{ DTRACEFLT_BADSTACK, "bad stack" },
{ DTRACEFLT_LIBRARY, "library-level fault" },
{ 0, NULL }
};
for (i = 0; faults[i].str != NULL; i++) {
if (faults[i].code == fault)
return (faults[i].str);
}
return ("unknown fault");
}

View File

@ -0,0 +1,251 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_ERRTAGS_H
#define _DT_ERRTAGS_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
/*
* This enum definition is used to define a set of error tags associated with
* the D compiler's various error conditions. The shell script mkerrtags.sh is
* used to parse this file and create a corresponding dt_errtags.c source file.
* If you do something other than add a new error tag here, you may need to
* update the mkerrtags shell script as it is based upon simple regexps.
*/
typedef enum {
D_UNKNOWN, /* unknown D compiler error */
D_SYNTAX, /* syntax error in input stream */
D_EMPTY, /* empty translation unit */
D_TYPE_ERR, /* type definition missing */
D_TYPE_MEMBER, /* type member not found */
D_ASRELO, /* relocation remains against symbol */
D_CG_EXPR, /* tracing function called from expr */
D_CG_DYN, /* expression returns dynamic result */
D_ATTR_MIN, /* attributes less than amin setting */
D_ID_OFLOW, /* identifier space overflow */
D_PDESC_ZERO, /* probedesc matches zero probes */
D_PDESC_INVAL, /* probedesc is not valid */
D_PRED_SCALAR, /* predicate must be of scalar type */
D_FUNC_IDENT, /* function designator is not ident */
D_FUNC_UNDEF, /* function ident is not defined */
D_FUNC_IDKIND, /* function ident is of wrong idkind */
D_OFFSETOF_TYPE, /* offsetof arg is not sou type */
D_OFFSETOF_BITFIELD, /* offsetof applied to field member */
D_SIZEOF_TYPE, /* invalid sizeof type */
D_SIZEOF_BITFIELD, /* sizeof applied to field member */
D_STRINGOF_TYPE, /* invalid stringof type */
D_OP_IDENT, /* operand must be an identifier */
D_OP_INT, /* operand must be integral type */
D_OP_SCALAR, /* operand must be scalar type */
D_OP_ARITH, /* operand must be arithmetic type */
D_OP_WRITE, /* operand must be writable variable */
D_OP_LVAL, /* operand must be lvalue */
D_OP_INCOMPAT, /* operand types are not compatible */
D_OP_VFPTR, /* operand cannot be void or func ptr */
D_OP_ARRFUN, /* operand cannot be array or func */
D_OP_PTR, /* operand must be a pointer */
D_OP_SOU, /* operand must be struct or union */
D_OP_INCOMPLETE, /* operand is an incomplete type */
D_OP_DYN, /* operand cannot be of dynamic type */
D_OP_ACT, /* operand cannot be action */
D_AGG_REDEF, /* aggregation cannot be redefined */
D_AGG_FUNC, /* aggregating function required */
D_AGG_MDIM, /* aggregation used as multi-dim arr */
D_ARR_BADREF, /* access non-array using tuple */
D_ARR_LOCAL, /* cannot define local assc array */
D_DIV_ZERO, /* division by zero detected */
D_DEREF_NONPTR, /* dereference non-pointer type */
D_DEREF_VOID, /* dereference void pointer */
D_DEREF_FUNC, /* dereference function pointer */
D_ADDROF_LVAL, /* unary & applied to non-lvalue */
D_ADDROF_VAR, /* unary & applied to variable */
D_ADDROF_BITFIELD, /* unary & applied to field member */
D_XLATE_REDECL, /* translator redeclared */
D_XLATE_NOCONV, /* no conversion for member defined */
D_XLATE_NONE, /* no translator for type combo */
D_XLATE_SOU, /* dst must be struct or union type */
D_XLATE_INCOMPAT, /* translator member type incompat */
D_XLATE_MEMB, /* translator member is not valid */
D_CAST_INVAL, /* invalid cast expression */
D_PRAGERR, /* #pragma error message */
D_PRAGCTL_INVAL, /* invalid control directive */
D_PRAGMA_INVAL, /* invalid compiler pragma */
D_PRAGMA_UNUSED, /* unused compiler pragma */
D_PRAGMA_MALFORM, /* malformed #pragma argument list */
D_PRAGMA_OPTSET, /* failed to set #pragma option */
D_PRAGMA_SCOPE, /* #pragma identifier scope error */
D_PRAGMA_DEPEND, /* #pragma dependency not satisfied */
D_MACRO_UNDEF, /* macro parameter is not defined */
D_MACRO_OFLOW, /* macro parameter integer overflow */
D_MACRO_UNUSED, /* macro parameter is never used */
D_INT_OFLOW, /* integer constant overflow */
D_INT_DIGIT, /* integer digit is not valid */
D_STR_NL, /* newline in string literal */
D_CHR_NL, /* newline in character constant */
D_CHR_NULL, /* empty character constant */
D_CHR_OFLOW, /* character constant is too long */
D_IDENT_BADREF, /* identifier expected type mismatch */
D_IDENT_UNDEF, /* identifier is not known/defined */
D_IDENT_AMBIG, /* identifier is ambiguous (var/enum) */
D_SYM_BADREF, /* kernel/user symbol ref mismatch */
D_SYM_NOTYPES, /* no CTF data available for sym ref */
D_SYM_MODEL, /* module/program data model mismatch */
D_VAR_UNDEF, /* reference to undefined variable */
D_VAR_UNSUP, /* unsupported variable specification */
D_PROTO_LEN, /* prototype length mismatch */
D_PROTO_ARG, /* prototype argument mismatch */
D_ARGS_MULTI, /* description matches unstable set */
D_ARGS_XLATOR, /* no args[] translator defined */
D_ARGS_NONE, /* no args[] available */
D_ARGS_TYPE, /* invalid args[] type */
D_ARGS_IDX, /* invalid args[] index */
D_REGS_IDX, /* invalid regs[] index */
D_KEY_TYPE, /* invalid agg or array key type */
D_PRINTF_DYN_PROTO, /* dynamic size argument missing */
D_PRINTF_DYN_TYPE, /* dynamic size type mismatch */
D_PRINTF_AGG_CONV, /* improper use of %@ conversion */
D_PRINTF_ARG_PROTO, /* conversion missing value argument */
D_PRINTF_ARG_TYPE, /* conversion arg has wrong type */
D_PRINTF_ARG_EXTRA, /* extra arguments specified */
D_PRINTF_ARG_FMT, /* format string is not a constant */
D_PRINTF_FMT_EMPTY, /* format string is empty */
D_DECL_CHARATTR, /* bad attributes for char decl */
D_DECL_VOIDATTR, /* bad attributes for void decl */
D_DECL_SIGNINT, /* sign/unsign with non-integer decl */
D_DECL_LONGINT, /* long with non-arithmetic decl */
D_DECL_IDENT, /* old-style declaration or bad type */
D_DECL_CLASS, /* more than one storage class given */
D_DECL_BADCLASS, /* decl class not supported in D */
D_DECL_PARMCLASS, /* invalid class for parameter type */
D_DECL_COMBO, /* bad decl specifier combination */
D_DECL_ARRSUB, /* const int required for array size */
D_DECL_ARRNULL, /* array decl requires dim or tuple */
D_DECL_ARRBIG, /* array size too big */
D_DECL_IDRED, /* decl identifier redeclared */
D_DECL_TYPERED, /* decl type redeclared */
D_DECL_MNAME, /* member name missing */
D_DECL_SCOPE, /* scoping operator used in decl */
D_DECL_BFCONST, /* bit-field requires const size expr */
D_DECL_BFSIZE, /* bit-field size too big for type */
D_DECL_BFTYPE, /* bit-field type is not valid */
D_DECL_ENCONST, /* enum tag requires const size expr */
D_DECL_ENOFLOW, /* enumerator value overflows INT_MAX */
D_DECL_USELESS, /* useless external declaration */
D_DECL_LOCASSC, /* attempt to decl local assc array */
D_DECL_VOIDOBJ, /* attempt to decl void object */
D_DECL_DYNOBJ, /* attempt to decl dynamic object */
D_DECL_INCOMPLETE, /* declaration uses incomplete type */
D_DECL_PROTO_VARARGS, /* varargs not allowed in prototype */
D_DECL_PROTO_TYPE, /* type not allowed in prototype */
D_DECL_PROTO_VOID, /* void must be sole parameter */
D_DECL_PROTO_NAME, /* void parameter may not have a name */
D_DECL_PROTO_FORM, /* parameter name has no formal */
D_COMM_COMM, /* commit() after commit() */
D_COMM_DREC, /* commit() after data action */
D_SPEC_SPEC, /* speculate() after speculate() */
D_SPEC_COMM, /* speculate() after commit() */
D_SPEC_DREC, /* speculate() after data action */
D_AGG_COMM, /* aggregating act after commit() */
D_AGG_SPEC, /* aggregating act after speculate() */
D_AGG_NULL, /* aggregation stmt has null effect */
D_AGG_SCALAR, /* aggregating function needs scalar */
D_ACT_SPEC, /* destructive action after speculate */
D_EXIT_SPEC, /* exit() action after speculate */
D_DREC_COMM, /* data action after commit() */
D_PRINTA_PROTO, /* printa() prototype mismatch */
D_PRINTA_AGGARG, /* aggregation arg type mismatch */
D_PRINTA_AGGBAD, /* printa() aggregation not defined */
D_PRINTA_AGGKEY, /* printa() aggregation key mismatch */
D_PRINTA_AGGPROTO, /* printa() aggregation mismatch */
D_TRACE_VOID, /* trace() argument has void type */
D_TRACE_DYN, /* trace() argument has dynamic type */
D_TRACEMEM_ADDR, /* tracemem() address bad type */
D_TRACEMEM_SIZE, /* tracemem() size bad type */
D_STACK_PROTO, /* stack() prototype mismatch */
D_STACK_SIZE, /* stack() size argument bad type */
D_USTACK_FRAMES, /* ustack() frames arg bad type */
D_USTACK_STRSIZE, /* ustack() strsize arg bad type */
D_USTACK_PROTO, /* ustack() prototype mismatch */
D_LQUANT_BASETYPE, /* lquantize() bad base type */
D_LQUANT_BASEVAL, /* lquantize() bad base value */
D_LQUANT_LIMTYPE, /* lquantize() bad limit type */
D_LQUANT_LIMVAL, /* lquantize() bad limit value */
D_LQUANT_MISMATCH, /* lquantize() limit < base */
D_LQUANT_STEPTYPE, /* lquantize() bad step type */
D_LQUANT_STEPVAL, /* lquantize() bad step value */
D_LQUANT_STEPLARGE, /* lquantize() step too large */
D_LQUANT_STEPSMALL, /* lquantize() step too small */
D_QUANT_PROTO, /* quantize() prototype mismatch */
D_PROC_OFF, /* byte offset exceeds function size */
D_PROC_ALIGN, /* byte offset has invalid alignment */
D_PROC_NAME, /* invalid process probe name */
D_PROC_GRAB, /* failed to grab process */
D_PROC_DYN, /* process is not dynamically linked */
D_PROC_LIB, /* invalid process library name */
D_PROC_FUNC, /* no such function in process */
D_PROC_CREATEFAIL, /* pid probe creation failed */
D_PROC_NODEV, /* fasttrap device is not installed */
D_PROC_BADPID, /* user probe pid invalid */
D_PROC_BADPROV, /* user probe provider invalid */
D_PROC_USDT, /* problem initializing usdt */
D_CLEAR_PROTO, /* clear() prototype mismatch */
D_CLEAR_AGGARG, /* aggregation arg type mismatch */
D_CLEAR_AGGBAD, /* clear() aggregation not defined */
D_NORMALIZE_PROTO, /* normalize() prototype mismatch */
D_NORMALIZE_SCALAR, /* normalize() value must be scalar */
D_NORMALIZE_AGGARG, /* aggregation arg type mismatch */
D_NORMALIZE_AGGBAD, /* normalize() aggregation not def. */
D_TRUNC_PROTO, /* trunc() prototype mismatch */
D_TRUNC_SCALAR, /* trunc() value must be scalar */
D_TRUNC_AGGARG, /* aggregation arg type mismatch */
D_TRUNC_AGGBAD, /* trunc() aggregation not def. */
D_PROV_BADNAME, /* invalid provider name */
D_PROV_INCOMPAT, /* provider/probe interface mismatch */
D_PROV_PRDUP, /* duplicate probe declaration */
D_PROV_PRARGLEN, /* probe argument list too long */
D_PROV_PRXLATOR, /* probe argument translator missing */
D_FREOPEN_INVALID, /* frename() filename is invalid */
D_LQUANT_MATCHBASE, /* lquantize() mismatch on base */
D_LQUANT_MATCHLIM, /* lquantize() mismatch on limit */
D_LQUANT_MATCHSTEP, /* lquantize() mismatch on step */
D_PRINTM_ADDR, /* printm() memref bad type */
D_PRINTM_SIZE, /* printm() size bad type */
D_PRINTT_ADDR, /* printt() typeref bad type */
D_PRINTT_SIZE /* printt() size bad type */
} dt_errtag_t;
extern const char *dt_errtag(dt_errtag_t);
#ifdef __cplusplus
}
#endif
#endif /* _DT_ERRTAGS_H */

View File

@ -0,0 +1,834 @@
%{
/*
* 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
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dt_impl.h>
#define OP1(op, c) dt_node_op1(op, c)
#define OP2(op, l, r) dt_node_op2(op, l, r)
#define OP3(x, y, z) dt_node_op3(x, y, z)
#define LINK(l, r) dt_node_link(l, r)
#define DUP(s) strdup(s)
%}
%union {
dt_node_t *l_node;
dt_decl_t *l_decl;
char *l_str;
uintmax_t l_int;
int l_tok;
}
%token DT_TOK_COMMA DT_TOK_ELLIPSIS
%token DT_TOK_ASGN DT_TOK_ADD_EQ DT_TOK_SUB_EQ DT_TOK_MUL_EQ
%token DT_TOK_DIV_EQ DT_TOK_MOD_EQ DT_TOK_AND_EQ DT_TOK_XOR_EQ DT_TOK_OR_EQ
%token DT_TOK_LSH_EQ DT_TOK_RSH_EQ DT_TOK_QUESTION DT_TOK_COLON
%token DT_TOK_LOR DT_TOK_LXOR DT_TOK_LAND
%token DT_TOK_BOR DT_TOK_XOR DT_TOK_BAND DT_TOK_EQU DT_TOK_NEQ
%token DT_TOK_LT DT_TOK_LE DT_TOK_GT DT_TOK_GE DT_TOK_LSH DT_TOK_RSH
%token DT_TOK_ADD DT_TOK_SUB DT_TOK_MUL DT_TOK_DIV DT_TOK_MOD
%token DT_TOK_LNEG DT_TOK_BNEG DT_TOK_ADDADD DT_TOK_SUBSUB
%token DT_TOK_PREINC DT_TOK_POSTINC DT_TOK_PREDEC DT_TOK_POSTDEC
%token DT_TOK_IPOS DT_TOK_INEG DT_TOK_DEREF DT_TOK_ADDROF
%token DT_TOK_OFFSETOF DT_TOK_SIZEOF DT_TOK_STRINGOF DT_TOK_XLATE
%token DT_TOK_LPAR DT_TOK_RPAR DT_TOK_LBRAC DT_TOK_RBRAC DT_TOK_PTR DT_TOK_DOT
%token <l_str> DT_TOK_STRING
%token <l_str> DT_TOK_IDENT
%token <l_str> DT_TOK_PSPEC
%token <l_str> DT_TOK_AGG
%token <l_str> DT_TOK_TNAME
%token <l_int> DT_TOK_INT
%token DT_KEY_AUTO
%token DT_KEY_BREAK
%token DT_KEY_CASE
%token DT_KEY_CHAR
%token DT_KEY_CONST
%token DT_KEY_CONTINUE
%token DT_KEY_COUNTER
%token DT_KEY_DEFAULT
%token DT_KEY_DO
%token DT_KEY_DOUBLE
%token DT_KEY_ELSE
%token DT_KEY_ENUM
%token DT_KEY_EXTERN
%token DT_KEY_FLOAT
%token DT_KEY_FOR
%token DT_KEY_GOTO
%token DT_KEY_IF
%token DT_KEY_IMPORT
%token DT_KEY_INLINE
%token DT_KEY_INT
%token DT_KEY_LONG
%token DT_KEY_PROBE
%token DT_KEY_PROVIDER
%token DT_KEY_REGISTER
%token DT_KEY_RESTRICT
%token DT_KEY_RETURN
%token DT_KEY_SELF
%token DT_KEY_SHORT
%token DT_KEY_SIGNED
%token DT_KEY_STATIC
%token DT_KEY_STRING
%token DT_KEY_STRUCT
%token DT_KEY_SWITCH
%token DT_KEY_THIS
%token DT_KEY_TYPEDEF
%token DT_KEY_UNION
%token DT_KEY_UNSIGNED
%token DT_KEY_VOID
%token DT_KEY_VOLATILE
%token DT_KEY_WHILE
%token DT_KEY_XLATOR
%token DT_TOK_EPRED
%token DT_CTX_DEXPR
%token DT_CTX_DPROG
%token DT_CTX_DTYPE
%token DT_TOK_EOF 0
%left DT_TOK_COMMA
%right DT_TOK_ASGN DT_TOK_ADD_EQ DT_TOK_SUB_EQ DT_TOK_MUL_EQ DT_TOK_DIV_EQ
DT_TOK_MOD_EQ DT_TOK_AND_EQ DT_TOK_XOR_EQ DT_TOK_OR_EQ DT_TOK_LSH_EQ
DT_TOK_RSH_EQ
%left DT_TOK_QUESTION DT_TOK_COLON
%left DT_TOK_LOR
%left DT_TOK_LXOR
%left DT_TOK_LAND
%left DT_TOK_BOR
%left DT_TOK_XOR
%left DT_TOK_BAND
%left DT_TOK_EQU DT_TOK_NEQ
%left DT_TOK_LT DT_TOK_LE DT_TOK_GT DT_TOK_GE
%left DT_TOK_LSH DT_TOK_RSH
%left DT_TOK_ADD DT_TOK_SUB
%left DT_TOK_MUL DT_TOK_DIV DT_TOK_MOD
%right DT_TOK_LNEG DT_TOK_BNEG DT_TOK_ADDADD DT_TOK_SUBSUB
DT_TOK_IPOS DT_TOK_INEG
%right DT_TOK_DEREF DT_TOK_ADDROF DT_TOK_SIZEOF DT_TOK_STRINGOF DT_TOK_XLATE
%left DT_TOK_LPAR DT_TOK_RPAR DT_TOK_LBRAC DT_TOK_RBRAC DT_TOK_PTR DT_TOK_DOT
%type <l_node> d_expression
%type <l_node> d_program
%type <l_node> d_type
%type <l_node> translation_unit
%type <l_node> external_declaration
%type <l_node> inline_definition
%type <l_node> translator_definition
%type <l_node> translator_member_list
%type <l_node> translator_member
%type <l_node> provider_definition
%type <l_node> provider_probe_list
%type <l_node> provider_probe
%type <l_node> probe_definition
%type <l_node> probe_specifiers
%type <l_node> probe_specifier_list
%type <l_node> probe_specifier
%type <l_node> statement_list
%type <l_node> statement
%type <l_node> declaration
%type <l_node> init_declarator_list
%type <l_node> init_declarator
%type <l_decl> type_specifier
%type <l_decl> type_qualifier
%type <l_decl> struct_or_union_specifier
%type <l_decl> specifier_qualifier_list
%type <l_decl> enum_specifier
%type <l_decl> declarator
%type <l_decl> direct_declarator
%type <l_decl> pointer
%type <l_decl> type_qualifier_list
%type <l_decl> type_name
%type <l_decl> abstract_declarator
%type <l_decl> direct_abstract_declarator
%type <l_node> parameter_type_list
%type <l_node> parameter_list
%type <l_node> parameter_declaration
%type <l_node> array
%type <l_node> array_parameters
%type <l_node> function
%type <l_node> function_parameters
%type <l_node> expression
%type <l_node> assignment_expression
%type <l_node> conditional_expression
%type <l_node> constant_expression
%type <l_node> logical_or_expression
%type <l_node> logical_xor_expression
%type <l_node> logical_and_expression
%type <l_node> inclusive_or_expression
%type <l_node> exclusive_or_expression
%type <l_node> and_expression
%type <l_node> equality_expression
%type <l_node> relational_expression
%type <l_node> shift_expression
%type <l_node> additive_expression
%type <l_node> multiplicative_expression
%type <l_node> cast_expression
%type <l_node> unary_expression
%type <l_node> postfix_expression
%type <l_node> primary_expression
%type <l_node> argument_expression_list
%type <l_tok> assignment_operator
%type <l_tok> unary_operator
%type <l_tok> struct_or_union
%%
dtrace_program: d_expression DT_TOK_EOF { return (dt_node_root($1)); }
| d_program DT_TOK_EOF { return (dt_node_root($1)); }
| d_type DT_TOK_EOF { return (dt_node_root($1)); }
;
d_expression: DT_CTX_DEXPR { $$ = NULL; }
| DT_CTX_DEXPR expression { $$ = $2; }
;
d_program: DT_CTX_DPROG { $$ = dt_node_program(NULL); }
| DT_CTX_DPROG translation_unit { $$ = dt_node_program($2); }
;
d_type: DT_CTX_DTYPE { $$ = NULL; }
| DT_CTX_DTYPE type_name { $$ = (dt_node_t *)$2; }
;
translation_unit:
external_declaration
| translation_unit external_declaration { $$ = LINK($1, $2); }
;
external_declaration:
inline_definition
| translator_definition
| provider_definition
| probe_definition
| declaration
;
inline_definition:
DT_KEY_INLINE declaration_specifiers declarator
{ dt_scope_push(NULL, CTF_ERR); } DT_TOK_ASGN
assignment_expression ';' {
/*
* We push a new declaration scope before shifting the
* assignment_expression in order to preserve ds_class
* and ds_ident for use in dt_node_inline(). Once the
* entire inline_definition rule is matched, pop the
* scope and construct the inline using the saved decl.
*/
dt_scope_pop();
$$ = dt_node_inline($6);
}
;
translator_definition:
DT_KEY_XLATOR type_name DT_TOK_LT type_name
DT_TOK_IDENT DT_TOK_GT '{' translator_member_list '}' ';' {
$$ = dt_node_xlator($2, $4, $5, $8);
}
| DT_KEY_XLATOR type_name DT_TOK_LT type_name
DT_TOK_IDENT DT_TOK_GT '{' '}' ';' {
$$ = dt_node_xlator($2, $4, $5, NULL);
}
;
translator_member_list:
translator_member
| translator_member_list translator_member { $$ = LINK($1,$2); }
;
translator_member:
DT_TOK_IDENT DT_TOK_ASGN assignment_expression ';' {
$$ = dt_node_member(NULL, $1, $3);
}
;
provider_definition:
DT_KEY_PROVIDER DT_TOK_IDENT '{' provider_probe_list '}' ';' {
$$ = dt_node_provider($2, $4);
}
| DT_KEY_PROVIDER DT_TOK_IDENT '{' '}' ';' {
$$ = dt_node_provider($2, NULL);
}
;
provider_probe_list:
provider_probe
| provider_probe_list provider_probe { $$ = LINK($1, $2); }
;
provider_probe:
DT_KEY_PROBE DT_TOK_IDENT function DT_TOK_COLON function ';' {
$$ = dt_node_probe($2, 2, $3, $5);
}
| DT_KEY_PROBE DT_TOK_IDENT function ';' {
$$ = dt_node_probe($2, 1, $3, NULL);
}
;
probe_definition:
probe_specifiers {
/*
* If the input stream is a file, do not permit a probe
* specification without / <pred> / or { <act> } after
* it. This can only occur if the next token is EOF or
* an ambiguous predicate was slurped up as a comment.
* We cannot perform this check if input() is a string
* because dtrace(1M) [-fmnP] also use the compiler and
* things like dtrace -n BEGIN have to be accepted.
*/
if (yypcb->pcb_fileptr != NULL) {
dnerror($1, D_SYNTAX, "expected predicate and/"
"or actions following probe description\n");
}
$$ = dt_node_clause($1, NULL, NULL);
}
| probe_specifiers '{' statement_list '}' {
$$ = dt_node_clause($1, NULL, $3);
}
| probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED {
dnerror($3, D_SYNTAX, "expected actions { } following "
"probe description and predicate\n");
}
| probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED
'{' statement_list '}' {
$$ = dt_node_clause($1, $3, $6);
}
;
probe_specifiers:
probe_specifier_list { yybegin(YYS_EXPR); $$ = $1; }
;
probe_specifier_list:
probe_specifier
| probe_specifier_list DT_TOK_COMMA probe_specifier {
$$ = LINK($1, $3);
}
;
probe_specifier:
DT_TOK_PSPEC { $$ = dt_node_pdesc_by_name($1); }
| DT_TOK_INT { $$ = dt_node_pdesc_by_id($1); }
;
statement_list: statement { $$ = $1; }
| statement_list ';' statement { $$ = LINK($1, $3); }
;
statement: /* empty */ { $$ = NULL; }
| expression { $$ = dt_node_statement($1); }
;
argument_expression_list:
assignment_expression
| argument_expression_list DT_TOK_COMMA assignment_expression {
$$ = LINK($1, $3);
}
;
primary_expression:
DT_TOK_IDENT { $$ = dt_node_ident($1); }
| DT_TOK_AGG { $$ = dt_node_ident($1); }
| DT_TOK_INT { $$ = dt_node_int($1); }
| DT_TOK_STRING { $$ = dt_node_string($1); }
| DT_KEY_SELF { $$ = dt_node_ident(DUP("self")); }
| DT_KEY_THIS { $$ = dt_node_ident(DUP("this")); }
| DT_TOK_LPAR expression DT_TOK_RPAR { $$ = $2; }
;
postfix_expression:
primary_expression
| postfix_expression
DT_TOK_LBRAC argument_expression_list DT_TOK_RBRAC {
$$ = OP2(DT_TOK_LBRAC, $1, $3);
}
| postfix_expression DT_TOK_LPAR DT_TOK_RPAR {
$$ = dt_node_func($1, NULL);
}
| postfix_expression
DT_TOK_LPAR argument_expression_list DT_TOK_RPAR {
$$ = dt_node_func($1, $3);
}
| postfix_expression DT_TOK_DOT DT_TOK_IDENT {
$$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_DOT DT_TOK_TNAME {
$$ = OP2(DT_TOK_DOT, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_PTR DT_TOK_IDENT {
$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_PTR DT_TOK_TNAME {
$$ = OP2(DT_TOK_PTR, $1, dt_node_ident($3));
}
| postfix_expression DT_TOK_ADDADD {
$$ = OP1(DT_TOK_POSTINC, $1);
}
| postfix_expression DT_TOK_SUBSUB {
$$ = OP1(DT_TOK_POSTDEC, $1);
}
| DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
DT_TOK_IDENT DT_TOK_RPAR {
$$ = dt_node_offsetof($3, $5);
}
| DT_TOK_OFFSETOF DT_TOK_LPAR type_name DT_TOK_COMMA
DT_TOK_TNAME DT_TOK_RPAR {
$$ = dt_node_offsetof($3, $5);
}
| DT_TOK_XLATE DT_TOK_LT type_name DT_TOK_GT
DT_TOK_LPAR expression DT_TOK_RPAR {
$$ = OP2(DT_TOK_XLATE, dt_node_type($3), $6);
}
;
unary_expression:
postfix_expression
| DT_TOK_ADDADD unary_expression { $$ = OP1(DT_TOK_PREINC, $2); }
| DT_TOK_SUBSUB unary_expression { $$ = OP1(DT_TOK_PREDEC, $2); }
| unary_operator cast_expression { $$ = OP1($1, $2); }
| DT_TOK_SIZEOF unary_expression { $$ = OP1(DT_TOK_SIZEOF, $2); }
| DT_TOK_SIZEOF DT_TOK_LPAR type_name DT_TOK_RPAR {
$$ = OP1(DT_TOK_SIZEOF, dt_node_type($3));
}
| DT_TOK_STRINGOF unary_expression {
$$ = OP1(DT_TOK_STRINGOF, $2);
}
;
unary_operator: DT_TOK_BAND { $$ = DT_TOK_ADDROF; }
| DT_TOK_MUL { $$ = DT_TOK_DEREF; }
| DT_TOK_ADD { $$ = DT_TOK_IPOS; }
| DT_TOK_SUB { $$ = DT_TOK_INEG; }
| DT_TOK_BNEG { $$ = DT_TOK_BNEG; }
| DT_TOK_LNEG { $$ = DT_TOK_LNEG; }
;
cast_expression:
unary_expression
| DT_TOK_LPAR type_name DT_TOK_RPAR cast_expression {
$$ = OP2(DT_TOK_LPAR, dt_node_type($2), $4);
}
;
multiplicative_expression:
cast_expression
| multiplicative_expression DT_TOK_MUL cast_expression {
$$ = OP2(DT_TOK_MUL, $1, $3);
}
| multiplicative_expression DT_TOK_DIV cast_expression {
$$ = OP2(DT_TOK_DIV, $1, $3);
}
| multiplicative_expression DT_TOK_MOD cast_expression {
$$ = OP2(DT_TOK_MOD, $1, $3);
}
;
additive_expression:
multiplicative_expression
| additive_expression DT_TOK_ADD multiplicative_expression {
$$ = OP2(DT_TOK_ADD, $1, $3);
}
| additive_expression DT_TOK_SUB multiplicative_expression {
$$ = OP2(DT_TOK_SUB, $1, $3);
}
;
shift_expression:
additive_expression
| shift_expression DT_TOK_LSH additive_expression {
$$ = OP2(DT_TOK_LSH, $1, $3);
}
| shift_expression DT_TOK_RSH additive_expression {
$$ = OP2(DT_TOK_RSH, $1, $3);
}
;
relational_expression:
shift_expression
| relational_expression DT_TOK_LT shift_expression {
$$ = OP2(DT_TOK_LT, $1, $3);
}
| relational_expression DT_TOK_GT shift_expression {
$$ = OP2(DT_TOK_GT, $1, $3);
}
| relational_expression DT_TOK_LE shift_expression {
$$ = OP2(DT_TOK_LE, $1, $3);
}
| relational_expression DT_TOK_GE shift_expression {
$$ = OP2(DT_TOK_GE, $1, $3);
}
;
equality_expression:
relational_expression
| equality_expression DT_TOK_EQU relational_expression {
$$ = OP2(DT_TOK_EQU, $1, $3);
}
| equality_expression DT_TOK_NEQ relational_expression {
$$ = OP2(DT_TOK_NEQ, $1, $3);
}
;
and_expression:
equality_expression
| and_expression DT_TOK_BAND equality_expression {
$$ = OP2(DT_TOK_BAND, $1, $3);
}
;
exclusive_or_expression:
and_expression
| exclusive_or_expression DT_TOK_XOR and_expression {
$$ = OP2(DT_TOK_XOR, $1, $3);
}
;
inclusive_or_expression:
exclusive_or_expression
| inclusive_or_expression DT_TOK_BOR exclusive_or_expression {
$$ = OP2(DT_TOK_BOR, $1, $3);
}
;
logical_and_expression:
inclusive_or_expression
| logical_and_expression DT_TOK_LAND inclusive_or_expression {
$$ = OP2(DT_TOK_LAND, $1, $3);
}
;
logical_xor_expression:
logical_and_expression
| logical_xor_expression DT_TOK_LXOR logical_and_expression {
$$ = OP2(DT_TOK_LXOR, $1, $3);
}
;
logical_or_expression:
logical_xor_expression
| logical_or_expression DT_TOK_LOR logical_xor_expression {
$$ = OP2(DT_TOK_LOR, $1, $3);
}
;
constant_expression: conditional_expression
;
conditional_expression:
logical_or_expression
| logical_or_expression DT_TOK_QUESTION expression DT_TOK_COLON
conditional_expression { $$ = OP3($1, $3, $5); }
;
assignment_expression:
conditional_expression
| unary_expression assignment_operator assignment_expression {
$$ = OP2($2, $1, $3);
}
;
assignment_operator:
DT_TOK_ASGN { $$ = DT_TOK_ASGN; }
| DT_TOK_MUL_EQ { $$ = DT_TOK_MUL_EQ; }
| DT_TOK_DIV_EQ { $$ = DT_TOK_DIV_EQ; }
| DT_TOK_MOD_EQ { $$ = DT_TOK_MOD_EQ; }
| DT_TOK_ADD_EQ { $$ = DT_TOK_ADD_EQ; }
| DT_TOK_SUB_EQ { $$ = DT_TOK_SUB_EQ; }
| DT_TOK_LSH_EQ { $$ = DT_TOK_LSH_EQ; }
| DT_TOK_RSH_EQ { $$ = DT_TOK_RSH_EQ; }
| DT_TOK_AND_EQ { $$ = DT_TOK_AND_EQ; }
| DT_TOK_XOR_EQ { $$ = DT_TOK_XOR_EQ; }
| DT_TOK_OR_EQ { $$ = DT_TOK_OR_EQ; }
;
expression: assignment_expression
| expression DT_TOK_COMMA assignment_expression {
$$ = OP2(DT_TOK_COMMA, $1, $3);
}
;
declaration: declaration_specifiers ';' {
$$ = dt_node_decl();
dt_decl_free(dt_decl_pop());
yybegin(YYS_CLAUSE);
}
| declaration_specifiers init_declarator_list ';' {
$$ = $2;
dt_decl_free(dt_decl_pop());
yybegin(YYS_CLAUSE);
}
;
declaration_specifiers:
d_storage_class_specifier
| d_storage_class_specifier declaration_specifiers
| type_specifier
| type_specifier declaration_specifiers
| type_qualifier
| type_qualifier declaration_specifiers
;
parameter_declaration_specifiers:
storage_class_specifier
| storage_class_specifier declaration_specifiers
| type_specifier
| type_specifier declaration_specifiers
| type_qualifier
| type_qualifier declaration_specifiers
;
storage_class_specifier:
DT_KEY_AUTO { dt_decl_class(DT_DC_AUTO); }
| DT_KEY_REGISTER { dt_decl_class(DT_DC_REGISTER); }
| DT_KEY_STATIC { dt_decl_class(DT_DC_STATIC); }
| DT_KEY_EXTERN { dt_decl_class(DT_DC_EXTERN); }
| DT_KEY_TYPEDEF { dt_decl_class(DT_DC_TYPEDEF); }
;
d_storage_class_specifier:
storage_class_specifier
| DT_KEY_SELF { dt_decl_class(DT_DC_SELF); }
| DT_KEY_THIS { dt_decl_class(DT_DC_THIS); }
;
type_specifier: DT_KEY_VOID { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("void")); }
| DT_KEY_CHAR { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("char")); }
| DT_KEY_SHORT { $$ = dt_decl_attr(DT_DA_SHORT); }
| DT_KEY_INT { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("int")); }
| DT_KEY_LONG { $$ = dt_decl_attr(DT_DA_LONG); }
| DT_KEY_FLOAT { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("float")); }
| DT_KEY_DOUBLE { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("double")); }
| DT_KEY_SIGNED { $$ = dt_decl_attr(DT_DA_SIGNED); }
| DT_KEY_UNSIGNED { $$ = dt_decl_attr(DT_DA_UNSIGNED); }
| DT_KEY_STRING {
$$ = dt_decl_spec(CTF_K_TYPEDEF, DUP("string"));
}
| DT_TOK_TNAME { $$ = dt_decl_spec(CTF_K_TYPEDEF, $1); }
| struct_or_union_specifier
| enum_specifier
;
type_qualifier: DT_KEY_CONST { $$ = dt_decl_attr(DT_DA_CONST); }
| DT_KEY_RESTRICT { $$ = dt_decl_attr(DT_DA_RESTRICT); }
| DT_KEY_VOLATILE { $$ = dt_decl_attr(DT_DA_VOLATILE); }
;
struct_or_union_specifier:
struct_or_union_definition struct_declaration_list '}' {
$$ = dt_scope_pop();
}
| struct_or_union DT_TOK_IDENT { $$ = dt_decl_spec($1, $2); }
| struct_or_union DT_TOK_TNAME { $$ = dt_decl_spec($1, $2); }
;
struct_or_union_definition:
struct_or_union '{' { dt_decl_sou($1, NULL); }
| struct_or_union DT_TOK_IDENT '{' { dt_decl_sou($1, $2); }
| struct_or_union DT_TOK_TNAME '{' { dt_decl_sou($1, $2); }
;
struct_or_union:
DT_KEY_STRUCT { $$ = CTF_K_STRUCT; }
| DT_KEY_UNION { $$ = CTF_K_UNION; }
;
struct_declaration_list:
struct_declaration
| struct_declaration_list struct_declaration
;
init_declarator_list:
init_declarator
| init_declarator_list DT_TOK_COMMA init_declarator {
$$ = LINK($1, $3);
}
;
init_declarator:
declarator {
$$ = dt_node_decl();
dt_decl_reset();
}
;
struct_declaration:
specifier_qualifier_list struct_declarator_list ';' {
dt_decl_free(dt_decl_pop());
}
;
specifier_qualifier_list:
type_specifier
| type_specifier specifier_qualifier_list { $$ = $2; }
| type_qualifier
| type_qualifier specifier_qualifier_list { $$ = $2; }
;
struct_declarator_list:
struct_declarator
| struct_declarator_list DT_TOK_COMMA struct_declarator
;
struct_declarator:
declarator { dt_decl_member(NULL); }
| DT_TOK_COLON constant_expression { dt_decl_member($2); }
| declarator DT_TOK_COLON constant_expression {
dt_decl_member($3);
}
;
enum_specifier:
enum_definition enumerator_list '}' { $$ = dt_scope_pop(); }
| DT_KEY_ENUM DT_TOK_IDENT { $$ = dt_decl_spec(CTF_K_ENUM, $2); }
| DT_KEY_ENUM DT_TOK_TNAME { $$ = dt_decl_spec(CTF_K_ENUM, $2); }
;
enum_definition:
DT_KEY_ENUM '{' { dt_decl_enum(NULL); }
| DT_KEY_ENUM DT_TOK_IDENT '{' { dt_decl_enum($2); }
| DT_KEY_ENUM DT_TOK_TNAME '{' { dt_decl_enum($2); }
;
enumerator_list:
enumerator
| enumerator_list DT_TOK_COMMA enumerator
;
enumerator: DT_TOK_IDENT { dt_decl_enumerator($1, NULL); }
| DT_TOK_IDENT DT_TOK_ASGN expression {
dt_decl_enumerator($1, $3);
}
;
declarator: direct_declarator
| pointer direct_declarator
;
direct_declarator:
DT_TOK_IDENT { $$ = dt_decl_ident($1); }
| lparen declarator DT_TOK_RPAR { $$ = $2; }
| direct_declarator array { dt_decl_array($2); }
| direct_declarator function { dt_decl_func($1, $2); }
;
lparen: DT_TOK_LPAR { dt_decl_top()->dd_attr |= DT_DA_PAREN; }
;
pointer: DT_TOK_MUL { $$ = dt_decl_ptr(); }
| DT_TOK_MUL type_qualifier_list { $$ = dt_decl_ptr(); }
| DT_TOK_MUL pointer { $$ = dt_decl_ptr(); }
| DT_TOK_MUL type_qualifier_list pointer { $$ = dt_decl_ptr(); }
;
type_qualifier_list:
type_qualifier
| type_qualifier_list type_qualifier { $$ = $2; }
;
parameter_type_list:
parameter_list
| DT_TOK_ELLIPSIS { $$ = dt_node_vatype(); }
| parameter_list DT_TOK_COMMA DT_TOK_ELLIPSIS {
$$ = LINK($1, dt_node_vatype());
}
;
parameter_list: parameter_declaration
| parameter_list DT_TOK_COMMA parameter_declaration {
$$ = LINK($1, $3);
}
;
parameter_declaration:
parameter_declaration_specifiers {
$$ = dt_node_type(NULL);
}
| parameter_declaration_specifiers declarator {
$$ = dt_node_type(NULL);
}
| parameter_declaration_specifiers abstract_declarator {
$$ = dt_node_type(NULL);
}
;
type_name: specifier_qualifier_list {
$$ = dt_decl_pop();
}
| specifier_qualifier_list abstract_declarator {
$$ = dt_decl_pop();
}
;
abstract_declarator:
pointer
| direct_abstract_declarator
| pointer direct_abstract_declarator
;
direct_abstract_declarator:
lparen abstract_declarator DT_TOK_RPAR { $$ = $2; }
| direct_abstract_declarator array { dt_decl_array($2); }
| array { dt_decl_array($1); $$ = NULL; }
| direct_abstract_declarator function { dt_decl_func($1, $2); }
| function { dt_decl_func(NULL, $1); }
;
array: DT_TOK_LBRAC { dt_scope_push(NULL, CTF_ERR); }
array_parameters DT_TOK_RBRAC {
dt_scope_pop();
$$ = $3;
}
;
array_parameters:
/* empty */ { $$ = NULL; }
| constant_expression { $$ = $1; }
| parameter_type_list { $$ = $1; }
;
function: DT_TOK_LPAR { dt_scope_push(NULL, CTF_ERR); }
function_parameters DT_TOK_RPAR {
dt_scope_pop();
$$ = $3;
}
;
function_parameters:
/* empty */ { $$ = NULL; }
| parameter_type_list { $$ = $1; }
;
%%

View File

@ -0,0 +1,483 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stddef.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#if defined(sun)
#include <alloca.h>
#endif
#include <dt_impl.h>
#include <dt_program.h>
static const char _dt_errprog[] =
"dtrace:::ERROR"
"{"
" trace(arg1);"
" trace(arg2);"
" trace(arg3);"
" trace(arg4);"
" trace(arg5);"
"}";
int
dtrace_handle_err(dtrace_hdl_t *dtp, dtrace_handle_err_f *hdlr, void *arg)
{
dtrace_prog_t *pgp = NULL;
dt_stmt_t *stp;
dtrace_ecbdesc_t *edp;
/*
* We don't currently support multiple error handlers.
*/
if (dtp->dt_errhdlr != NULL)
return (dt_set_errno(dtp, EALREADY));
/*
* If the DTRACEOPT_GRABANON is enabled, the anonymous enabling will
* already have a dtrace:::ERROR probe enabled; save 'hdlr' and 'arg'
* but do not bother compiling and enabling _dt_errprog.
*/
if (dtp->dt_options[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET)
goto out;
if ((pgp = dtrace_program_strcompile(dtp, _dt_errprog,
DTRACE_PROBESPEC_NAME, DTRACE_C_ZDEFS, 0, NULL)) == NULL)
return (dt_set_errno(dtp, dtrace_errno(dtp)));
stp = dt_list_next(&pgp->dp_stmts);
assert(stp != NULL);
edp = stp->ds_desc->dtsd_ecbdesc;
assert(edp != NULL);
edp->dted_uarg = DT_ECB_ERROR;
out:
dtp->dt_errhdlr = hdlr;
dtp->dt_errarg = arg;
dtp->dt_errprog = pgp;
return (0);
}
int
dtrace_handle_drop(dtrace_hdl_t *dtp, dtrace_handle_drop_f *hdlr, void *arg)
{
if (dtp->dt_drophdlr != NULL)
return (dt_set_errno(dtp, EALREADY));
dtp->dt_drophdlr = hdlr;
dtp->dt_droparg = arg;
return (0);
}
int
dtrace_handle_proc(dtrace_hdl_t *dtp, dtrace_handle_proc_f *hdlr, void *arg)
{
if (dtp->dt_prochdlr != NULL)
return (dt_set_errno(dtp, EALREADY));
dtp->dt_prochdlr = hdlr;
dtp->dt_procarg = arg;
return (0);
}
int
dtrace_handle_buffered(dtrace_hdl_t *dtp, dtrace_handle_buffered_f *hdlr,
void *arg)
{
if (dtp->dt_bufhdlr != NULL)
return (dt_set_errno(dtp, EALREADY));
if (hdlr == NULL)
return (dt_set_errno(dtp, EINVAL));
dtp->dt_bufhdlr = hdlr;
dtp->dt_bufarg = arg;
return (0);
}
int
dtrace_handle_setopt(dtrace_hdl_t *dtp, dtrace_handle_setopt_f *hdlr,
void *arg)
{
if (hdlr == NULL)
return (dt_set_errno(dtp, EINVAL));
dtp->dt_setopthdlr = hdlr;
dtp->dt_setoptarg = arg;
return (0);
}
#define DT_REC(type, ndx) *((type *)((uintptr_t)data->dtpda_data + \
epd->dtepd_rec[(ndx)].dtrd_offset))
static int
dt_handle_err(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
{
dtrace_eprobedesc_t *epd = data->dtpda_edesc, *errepd;
dtrace_probedesc_t *pd = data->dtpda_pdesc, *errpd;
dtrace_errdata_t err;
dtrace_epid_t epid;
char where[30];
char details[30];
char offinfo[30];
const int slop = 80;
const char *faultstr;
char *str;
int len;
assert(epd->dtepd_uarg == DT_ECB_ERROR);
if (epd->dtepd_nrecs != 5 || strcmp(pd->dtpd_provider, "dtrace") != 0 ||
strcmp(pd->dtpd_name, "ERROR") != 0)
return (dt_set_errno(dtp, EDT_BADERROR));
/*
* This is an error. We have the following items here: EPID,
* faulting action, DIF offset, fault code and faulting address.
*/
epid = (uint32_t)DT_REC(uint64_t, 0);
if (dt_epid_lookup(dtp, epid, &errepd, &errpd) != 0)
return (dt_set_errno(dtp, EDT_BADERROR));
err.dteda_edesc = errepd;
err.dteda_pdesc = errpd;
err.dteda_cpu = data->dtpda_cpu;
err.dteda_action = (int)DT_REC(uint64_t, 1);
err.dteda_offset = (int)DT_REC(uint64_t, 2);
err.dteda_fault = (int)DT_REC(uint64_t, 3);
err.dteda_addr = DT_REC(uint64_t, 4);
faultstr = dtrace_faultstr(dtp, err.dteda_fault);
len = sizeof (where) + sizeof (offinfo) + strlen(faultstr) +
strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) +
strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) +
slop;
str = (char *)alloca(len);
if (err.dteda_action == 0) {
(void) sprintf(where, "predicate");
} else {
(void) sprintf(where, "action #%d", err.dteda_action);
}
if (err.dteda_offset != -1) {
(void) sprintf(offinfo, " at DIF offset %d", err.dteda_offset);
} else {
offinfo[0] = 0;
}
switch (err.dteda_fault) {
case DTRACEFLT_BADADDR:
case DTRACEFLT_BADALIGN:
case DTRACEFLT_BADSTACK:
(void) sprintf(details, " (0x%llx)",
(u_longlong_t)err.dteda_addr);
break;
default:
details[0] = 0;
}
(void) snprintf(str, len, "error on enabled probe ID %u "
"(ID %u: %s:%s:%s:%s): %s%s in %s%s\n",
epid, errpd->dtpd_id, errpd->dtpd_provider,
errpd->dtpd_mod, errpd->dtpd_func,
errpd->dtpd_name, dtrace_faultstr(dtp, err.dteda_fault),
details, where, offinfo);
err.dteda_msg = str;
if (dtp->dt_errhdlr == NULL)
return (dt_set_errno(dtp, EDT_ERRABORT));
if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT)
return (dt_set_errno(dtp, EDT_ERRABORT));
return (0);
}
int
dt_handle_liberr(dtrace_hdl_t *dtp, const dtrace_probedata_t *data,
const char *faultstr)
{
dtrace_probedesc_t *errpd = data->dtpda_pdesc;
dtrace_errdata_t err;
const int slop = 80;
char *str;
int len;
err.dteda_edesc = data->dtpda_edesc;
err.dteda_pdesc = errpd;
err.dteda_cpu = data->dtpda_cpu;
err.dteda_action = -1;
err.dteda_offset = -1;
err.dteda_fault = DTRACEFLT_LIBRARY;
err.dteda_addr = 0;
len = strlen(faultstr) +
strlen(errpd->dtpd_provider) + strlen(errpd->dtpd_mod) +
strlen(errpd->dtpd_name) + strlen(errpd->dtpd_func) +
slop;
str = alloca(len);
(void) snprintf(str, len, "error on enabled probe ID %u "
"(ID %u: %s:%s:%s:%s): %s\n",
data->dtpda_edesc->dtepd_epid,
errpd->dtpd_id, errpd->dtpd_provider,
errpd->dtpd_mod, errpd->dtpd_func,
errpd->dtpd_name, faultstr);
err.dteda_msg = str;
if (dtp->dt_errhdlr == NULL)
return (dt_set_errno(dtp, EDT_ERRABORT));
if ((*dtp->dt_errhdlr)(&err, dtp->dt_errarg) == DTRACE_HANDLE_ABORT)
return (dt_set_errno(dtp, EDT_ERRABORT));
return (0);
}
#define DROPTAG(x) x, #x
static const struct {
dtrace_dropkind_t dtdrg_kind;
char *dtdrg_tag;
} _dt_droptags[] = {
{ DROPTAG(DTRACEDROP_PRINCIPAL) },
{ DROPTAG(DTRACEDROP_AGGREGATION) },
{ DROPTAG(DTRACEDROP_DYNAMIC) },
{ DROPTAG(DTRACEDROP_DYNRINSE) },
{ DROPTAG(DTRACEDROP_DYNDIRTY) },
{ DROPTAG(DTRACEDROP_SPEC) },
{ DROPTAG(DTRACEDROP_SPECBUSY) },
{ DROPTAG(DTRACEDROP_SPECUNAVAIL) },
{ DROPTAG(DTRACEDROP_DBLERROR) },
{ DROPTAG(DTRACEDROP_STKSTROVERFLOW) },
{ 0, NULL }
};
static const char *
dt_droptag(dtrace_dropkind_t kind)
{
int i;
for (i = 0; _dt_droptags[i].dtdrg_tag != NULL; i++) {
if (_dt_droptags[i].dtdrg_kind == kind)
return (_dt_droptags[i].dtdrg_tag);
}
return ("DTRACEDROP_UNKNOWN");
}
int
dt_handle_cpudrop(dtrace_hdl_t *dtp, processorid_t cpu,
dtrace_dropkind_t what, uint64_t howmany)
{
dtrace_dropdata_t drop;
char str[80], *s;
int size;
assert(what == DTRACEDROP_PRINCIPAL || what == DTRACEDROP_AGGREGATION);
bzero(&drop, sizeof (drop));
drop.dtdda_handle = dtp;
drop.dtdda_cpu = cpu;
drop.dtdda_kind = what;
drop.dtdda_drops = howmany;
drop.dtdda_msg = str;
if (dtp->dt_droptags) {
(void) snprintf(str, sizeof (str), "[%s] ", dt_droptag(what));
s = &str[strlen(str)];
size = sizeof (str) - (s - str);
} else {
s = str;
size = sizeof (str);
}
(void) snprintf(s, size, "%llu %sdrop%s on CPU %d\n",
howmany, what == DTRACEDROP_PRINCIPAL ? "" : "aggregation ",
howmany > 1 ? "s" : "", cpu);
if (dtp->dt_drophdlr == NULL)
return (dt_set_errno(dtp, EDT_DROPABORT));
if ((*dtp->dt_drophdlr)(&drop, dtp->dt_droparg) == DTRACE_HANDLE_ABORT)
return (dt_set_errno(dtp, EDT_DROPABORT));
return (0);
}
static const struct {
dtrace_dropkind_t dtdrt_kind;
uintptr_t dtdrt_offset;
const char *dtdrt_str;
const char *dtdrt_msg;
} _dt_droptab[] = {
{ DTRACEDROP_DYNAMIC,
offsetof(dtrace_status_t, dtst_dyndrops),
"dynamic variable drop" },
{ DTRACEDROP_DYNRINSE,
offsetof(dtrace_status_t, dtst_dyndrops_rinsing),
"dynamic variable drop", " with non-empty rinsing list" },
{ DTRACEDROP_DYNDIRTY,
offsetof(dtrace_status_t, dtst_dyndrops_dirty),
"dynamic variable drop", " with non-empty dirty list" },
{ DTRACEDROP_SPEC,
offsetof(dtrace_status_t, dtst_specdrops),
"speculative drop" },
{ DTRACEDROP_SPECBUSY,
offsetof(dtrace_status_t, dtst_specdrops_busy),
"failed speculation", " (available buffer(s) still busy)" },
{ DTRACEDROP_SPECUNAVAIL,
offsetof(dtrace_status_t, dtst_specdrops_unavail),
"failed speculation", " (no speculative buffer available)" },
{ DTRACEDROP_STKSTROVERFLOW,
offsetof(dtrace_status_t, dtst_stkstroverflows),
"jstack()/ustack() string table overflow" },
{ DTRACEDROP_DBLERROR,
offsetof(dtrace_status_t, dtst_dblerrors),
"error", " in ERROR probe enabling" },
{ 0, 0, NULL }
};
int
dt_handle_status(dtrace_hdl_t *dtp, dtrace_status_t *old, dtrace_status_t *new)
{
dtrace_dropdata_t drop;
char str[80], *s;
uintptr_t base = (uintptr_t)new, obase = (uintptr_t)old;
int i, size;
bzero(&drop, sizeof (drop));
drop.dtdda_handle = dtp;
drop.dtdda_cpu = DTRACE_CPUALL;
drop.dtdda_msg = str;
/*
* First, check to see if we've been killed -- in which case we abort.
*/
if (new->dtst_killed && !old->dtst_killed)
return (dt_set_errno(dtp, EDT_BRICKED));
for (i = 0; _dt_droptab[i].dtdrt_str != NULL; i++) {
uintptr_t naddr = base + _dt_droptab[i].dtdrt_offset;
uintptr_t oaddr = obase + _dt_droptab[i].dtdrt_offset;
uint64_t nval = *((uint64_t *)naddr);
uint64_t oval = *((uint64_t *)oaddr);
if (nval == oval)
continue;
if (dtp->dt_droptags) {
(void) snprintf(str, sizeof (str), "[%s] ",
dt_droptag(_dt_droptab[i].dtdrt_kind));
s = &str[strlen(str)];
size = sizeof (str) - (s - str);
} else {
s = str;
size = sizeof (str);
}
(void) snprintf(s, size, "%llu %s%s%s\n", nval - oval,
_dt_droptab[i].dtdrt_str, (nval - oval > 1) ? "s" : "",
_dt_droptab[i].dtdrt_msg != NULL ?
_dt_droptab[i].dtdrt_msg : "");
drop.dtdda_kind = _dt_droptab[i].dtdrt_kind;
drop.dtdda_total = nval;
drop.dtdda_drops = nval - oval;
if (dtp->dt_drophdlr == NULL)
return (dt_set_errno(dtp, EDT_DROPABORT));
if ((*dtp->dt_drophdlr)(&drop,
dtp->dt_droparg) == DTRACE_HANDLE_ABORT)
return (dt_set_errno(dtp, EDT_DROPABORT));
}
return (0);
}
int
dt_handle_setopt(dtrace_hdl_t *dtp, dtrace_setoptdata_t *data)
{
void *arg = dtp->dt_setoptarg;
if (dtp->dt_setopthdlr == NULL)
return (0);
if ((*dtp->dt_setopthdlr)(data, arg) == DTRACE_HANDLE_ABORT)
return (dt_set_errno(dtp, EDT_DIRABORT));
return (0);
}
int
dt_handle(dtrace_hdl_t *dtp, dtrace_probedata_t *data)
{
dtrace_eprobedesc_t *epd = data->dtpda_edesc;
int rval;
switch (epd->dtepd_uarg) {
case DT_ECB_ERROR:
rval = dt_handle_err(dtp, data);
break;
default:
return (DTRACE_CONSUME_THIS);
}
if (rval == 0)
return (DTRACE_CONSUME_NEXT);
return (DTRACE_CONSUME_ERROR);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_IDENT_H
#define _DT_IDENT_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libctf.h>
#include <dtrace.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <dt_list.h>
struct dt_node;
struct dt_ident;
struct dt_idhash;
struct dt_irlist;
struct dt_regset;
typedef struct dt_idsig {
int dis_varargs; /* argument index of start of varargs (or -1) */
int dis_optargs; /* argument index of start of optargs (or -1) */
int dis_argc; /* number of types in this signature */
struct dt_node *dis_args; /* array of nodes representing formal types */
uint64_t dis_auxinfo; /* auxiliary signature information, if any */
} dt_idsig_t;
typedef struct dt_idnode {
struct dt_node *din_list; /* allocation list for parse tree nodes */
struct dt_node *din_root; /* root of this identifier's parse tree */
struct dt_idhash *din_hash; /* identifiers private to this subtree */
struct dt_ident **din_argv; /* identifiers in din_hash for arguments */
int din_argc; /* length of din_argv[] array */
} dt_idnode_t;
typedef struct dt_idops {
void (*di_cook)(struct dt_node *, struct dt_ident *,
int, struct dt_node *);
void (*di_dtor)(struct dt_ident *);
size_t (*di_size)(struct dt_ident *);
} dt_idops_t;
typedef struct dt_ident {
char *di_name; /* identifier name */
ushort_t di_kind; /* identifier kind (see below) */
ushort_t di_flags; /* identifier flags (see below) */
uint_t di_id; /* variable or subr id (see <sys/dtrace.h>) */
dtrace_attribute_t di_attr; /* identifier stability attributes */
uint_t di_vers; /* identifier version number (dt_version_t) */
const dt_idops_t *di_ops; /* identifier's class-specific ops vector */
void *di_iarg; /* initial argument pointer for ops vector */
void *di_data; /* private data pointer for ops vector */
ctf_file_t *di_ctfp; /* CTF container for the variable data type */
ctf_id_t di_type; /* CTF identifier for the variable data type */
struct dt_ident *di_next; /* pointer to next ident in hash chain */
ulong_t di_gen; /* generation number (pass that created me) */
int di_lineno; /* line number that defined this identifier */
} dt_ident_t;
#define DT_IDENT_ARRAY 0 /* identifier is an array variable */
#define DT_IDENT_SCALAR 1 /* identifier is a scalar variable */
#define DT_IDENT_PTR 2 /* identifier is a magic pointer */
#define DT_IDENT_FUNC 3 /* identifier is a built-in function */
#define DT_IDENT_AGG 4 /* identifier is an aggregation */
#define DT_IDENT_AGGFUNC 5 /* identifier is an aggregating function */
#define DT_IDENT_ACTFUNC 6 /* identifier is an action function */
#define DT_IDENT_XLSOU 7 /* identifier is a translated struct or union */
#define DT_IDENT_XLPTR 8 /* identifier is a translated pointer */
#define DT_IDENT_SYMBOL 9 /* identifier is an external symbol */
#define DT_IDENT_ENUM 10 /* identifier is an enumerator */
#define DT_IDENT_PRAGAT 11 /* identifier is #pragma attributes */
#define DT_IDENT_PRAGBN 12 /* identifier is #pragma binding */
#define DT_IDENT_PROBE 13 /* identifier is a probe definition */
#define DT_IDFLG_TLS 0x0001 /* variable is thread-local storage */
#define DT_IDFLG_LOCAL 0x0002 /* variable is local storage */
#define DT_IDFLG_WRITE 0x0004 /* variable is writable (can be modified) */
#define DT_IDFLG_INLINE 0x0008 /* variable is an inline definition */
#define DT_IDFLG_REF 0x0010 /* variable is referenced by this program */
#define DT_IDFLG_MOD 0x0020 /* variable is modified by this program */
#define DT_IDFLG_DIFR 0x0040 /* variable is referenced by current DIFO */
#define DT_IDFLG_DIFW 0x0080 /* variable is modified by current DIFO */
#define DT_IDFLG_CGREG 0x0100 /* variable is inlined by code generator */
#define DT_IDFLG_USER 0x0200 /* variable is associated with userland */
#define DT_IDFLG_PRIM 0x0400 /* variable is associated with primary object */
#define DT_IDFLG_DECL 0x0800 /* variable is associated with explicit decl */
#define DT_IDFLG_ORPHAN 0x1000 /* variable is in a dt_node and not dt_idhash */
typedef struct dt_idhash {
dt_list_t dh_list; /* list prev/next pointers for dt_idstack */
const char *dh_name; /* name of this hash table */
void (*dh_defer)(struct dt_idhash *, dt_ident_t *); /* defer callback */
const dt_ident_t *dh_tmpl; /* template for initial ident population */
uint_t dh_nextid; /* next id to be returned by idhash_nextid() */
uint_t dh_minid; /* min id to be returned by idhash_nextid() */
uint_t dh_maxid; /* max id to be returned by idhash_nextid() */
ulong_t dh_nelems; /* number of identifiers in hash table */
ulong_t dh_hashsz; /* number of entries in dh_buckets array */
dt_ident_t *dh_hash[1]; /* array of hash table bucket pointers */
} dt_idhash_t;
typedef struct dt_idstack {
dt_list_t dids_list; /* list meta-data for dt_idhash_t stack */
} dt_idstack_t;
extern const dt_idops_t dt_idops_assc; /* associative array or aggregation */
extern const dt_idops_t dt_idops_func; /* function call built-in */
extern const dt_idops_t dt_idops_args; /* args[] built-in */
extern const dt_idops_t dt_idops_regs; /* regs[]/uregs[] built-in */
extern const dt_idops_t dt_idops_type; /* predefined type name string */
extern const dt_idops_t dt_idops_thaw; /* prefrozen type identifier */
extern const dt_idops_t dt_idops_inline; /* inline variable */
extern const dt_idops_t dt_idops_probe; /* probe definition */
extern dt_idhash_t *dt_idhash_create(const char *, const dt_ident_t *,
uint_t, uint_t);
extern void dt_idhash_destroy(dt_idhash_t *);
extern void dt_idhash_update(dt_idhash_t *);
extern dt_ident_t *dt_idhash_lookup(dt_idhash_t *, const char *);
extern int dt_idhash_nextid(dt_idhash_t *, uint_t *);
extern ulong_t dt_idhash_size(const dt_idhash_t *);
extern const char *dt_idhash_name(const dt_idhash_t *);
extern dt_ident_t *dt_idhash_insert(dt_idhash_t *, const char *, ushort_t,
ushort_t, uint_t, dtrace_attribute_t, uint_t,
const dt_idops_t *, void *, ulong_t);
extern void dt_idhash_xinsert(dt_idhash_t *, dt_ident_t *);
extern void dt_idhash_delete(dt_idhash_t *, dt_ident_t *);
typedef int dt_idhash_f(dt_idhash_t *, dt_ident_t *, void *);
extern int dt_idhash_iter(dt_idhash_t *, dt_idhash_f *, void *);
extern dt_ident_t *dt_idstack_lookup(dt_idstack_t *, const char *);
extern void dt_idstack_push(dt_idstack_t *, dt_idhash_t *);
extern void dt_idstack_pop(dt_idstack_t *, dt_idhash_t *);
extern dt_ident_t *dt_ident_create(const char *, ushort_t, ushort_t, uint_t,
dtrace_attribute_t, uint_t, const dt_idops_t *, void *, ulong_t);
extern void dt_ident_destroy(dt_ident_t *);
extern void dt_ident_morph(dt_ident_t *, ushort_t, const dt_idops_t *, void *);
extern dtrace_attribute_t dt_ident_cook(struct dt_node *,
dt_ident_t *, struct dt_node **);
extern void dt_ident_type_assign(dt_ident_t *, ctf_file_t *, ctf_id_t);
extern dt_ident_t *dt_ident_resolve(dt_ident_t *);
extern size_t dt_ident_size(dt_ident_t *);
extern int dt_ident_unref(const dt_ident_t *);
extern const char *dt_idkind_name(uint_t);
#ifdef __cplusplus
}
#endif
#endif /* _DT_IDENT_H */

View File

@ -0,0 +1,691 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_IMPL_H
#define _DT_IMPL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/param.h>
#include <sys/objfs.h>
#if !defined(sun)
#include <sys/bitmap.h>
#include <sys/utsname.h>
#include <sys/ioccom.h>
#include <sys/time.h>
#include <string.h>
#endif
#include <setjmp.h>
#include <libctf.h>
#include <dtrace.h>
#include <gelf.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <dt_parser.h>
#include <dt_regset.h>
#include <dt_inttab.h>
#include <dt_strtab.h>
#include <dt_ident.h>
#include <dt_list.h>
#include <dt_decl.h>
#include <dt_as.h>
#include <dt_proc.h>
#include <dt_dof.h>
#include <dt_pcb.h>
struct dt_module; /* see below */
struct dt_pfdict; /* see <dt_printf.h> */
struct dt_arg; /* see below */
struct dt_provider; /* see <dt_provider.h> */
struct dt_xlator; /* see <dt_xlator.h> */
typedef struct dt_intrinsic {
const char *din_name; /* string name of the intrinsic type */
ctf_encoding_t din_data; /* integer or floating-point CTF encoding */
uint_t din_kind; /* CTF type kind to instantiate */
} dt_intrinsic_t;
typedef struct dt_typedef {
const char *dty_src; /* string name of typedef source type */
const char *dty_dst; /* string name of typedef destination type */
} dt_typedef_t;
typedef struct dt_intdesc {
const char *did_name; /* string name of the integer type */
ctf_file_t *did_ctfp; /* CTF container for this type reference */
ctf_id_t did_type; /* CTF type reference for this type */
uintmax_t did_limit; /* maximum positive value held by type */
} dt_intdesc_t;
typedef struct dt_modops {
uint_t (*do_syminit)(struct dt_module *);
void (*do_symsort)(struct dt_module *);
GElf_Sym *(*do_symname)(struct dt_module *,
const char *, GElf_Sym *, uint_t *);
GElf_Sym *(*do_symaddr)(struct dt_module *,
GElf_Addr, GElf_Sym *, uint_t *);
} dt_modops_t;
typedef struct dt_arg {
int da_ndx; /* index of this argument */
int da_mapping; /* mapping of argument indices to arguments */
ctf_id_t da_type; /* type of argument */
ctf_file_t *da_ctfp; /* CTF container for type */
dt_ident_t *da_xlator; /* translator, if any */
struct dt_arg *da_next; /* next argument */
} dt_arg_t;
typedef struct dt_sym {
uint_t ds_symid; /* id of corresponding symbol */
uint_t ds_next; /* index of next element in hash chain */
} dt_sym_t;
typedef struct dt_module {
dt_list_t dm_list; /* list forward/back pointers */
char dm_name[DTRACE_MODNAMELEN]; /* string name of module */
char dm_file[MAXPATHLEN]; /* file path of module (if any) */
struct dt_module *dm_next; /* pointer to next module in hash chain */
const dt_modops_t *dm_ops; /* pointer to data model's ops vector */
Elf *dm_elf; /* libelf handle for module object */
objfs_info_t dm_info; /* object filesystem private info */
ctf_sect_t dm_symtab; /* symbol table for module */
ctf_sect_t dm_strtab; /* string table for module */
ctf_sect_t dm_ctdata; /* CTF data for module */
ctf_file_t *dm_ctfp; /* CTF container handle */
uint_t *dm_symbuckets; /* symbol table hash buckets (chain indices) */
dt_sym_t *dm_symchains; /* symbol table hash chains buffer */
void *dm_asmap; /* symbol pointers sorted by value */
uint_t dm_symfree; /* index of next free hash element */
uint_t dm_nsymbuckets; /* number of elements in bucket array */
uint_t dm_nsymelems; /* number of elements in hash table */
uint_t dm_asrsv; /* actual reserved size of dm_asmap */
uint_t dm_aslen; /* number of entries in dm_asmap */
uint_t dm_flags; /* module flags (see below) */
int dm_modid; /* modinfo(1M) module identifier */
GElf_Addr dm_text_va; /* virtual address of text section */
GElf_Xword dm_text_size; /* size in bytes of text section */
GElf_Addr dm_data_va; /* virtual address of data section */
GElf_Xword dm_data_size; /* size in bytes of data section */
GElf_Addr dm_bss_va; /* virtual address of BSS */
GElf_Xword dm_bss_size; /* size in bytes of BSS */
dt_idhash_t *dm_extern; /* external symbol definitions */
#if !defined(sun)
caddr_t dm_reloc_offset; /* Symbol relocation offset. */
#endif
} dt_module_t;
#define DT_DM_LOADED 0x1 /* module symbol and type data is loaded */
#define DT_DM_KERNEL 0x2 /* module is associated with a kernel object */
#define DT_DM_PRIMARY 0x4 /* module is a krtld primary kernel object */
typedef struct dt_provmod {
char *dp_name; /* name of provider module */
struct dt_provmod *dp_next; /* next module */
} dt_provmod_t;
typedef struct dt_ahashent {
struct dt_ahashent *dtahe_prev; /* prev on hash chain */
struct dt_ahashent *dtahe_next; /* next on hash chain */
struct dt_ahashent *dtahe_prevall; /* prev on list of all */
struct dt_ahashent *dtahe_nextall; /* next on list of all */
uint64_t dtahe_hashval; /* hash value */
size_t dtahe_size; /* size of data */
dtrace_aggdata_t dtahe_data; /* data */
void (*dtahe_aggregate)(int64_t *, int64_t *, size_t); /* function */
} dt_ahashent_t;
typedef struct dt_ahash {
dt_ahashent_t **dtah_hash; /* hash table */
dt_ahashent_t *dtah_all; /* list of all elements */
size_t dtah_size; /* size of hash table */
} dt_ahash_t;
typedef struct dt_aggregate {
dtrace_bufdesc_t dtat_buf; /* buf aggregation snapshot */
int dtat_flags; /* aggregate flags */
processorid_t dtat_ncpus; /* number of CPUs in aggregate */
processorid_t *dtat_cpus; /* CPUs in aggregate */
processorid_t dtat_ncpu; /* size of dtat_cpus array */
processorid_t dtat_maxcpu; /* maximum number of CPUs */
dt_ahash_t dtat_hash; /* aggregate hash table */
} dt_aggregate_t;
typedef struct dt_print_aggdata {
dtrace_hdl_t *dtpa_dtp; /* pointer to libdtrace handle */
dtrace_aggvarid_t dtpa_id; /* aggregation variable of interest */
FILE *dtpa_fp; /* file pointer */
int dtpa_allunprint; /* print only unprinted aggregations */
} dt_print_aggdata_t;
typedef struct dt_dirpath {
dt_list_t dir_list; /* linked-list forward/back pointers */
char *dir_path; /* directory pathname */
} dt_dirpath_t;
typedef struct dt_lib_depend {
dt_list_t dtld_deplist; /* linked-list forward/back pointers */
char *dtld_library; /* library name */
char *dtld_libpath; /* library pathname */
uint_t dtld_finish; /* completion time in tsort for lib */
uint_t dtld_start; /* starting time in tsort for lib */
uint_t dtld_loaded; /* boolean: is this library loaded */
dt_list_t dtld_dependencies; /* linked-list of lib dependencies */
dt_list_t dtld_dependents; /* linked-list of lib dependents */
} dt_lib_depend_t;
typedef uint32_t dt_version_t; /* encoded version (see below) */
struct dtrace_hdl {
const dtrace_vector_t *dt_vector; /* library vector, if vectored open */
void *dt_varg; /* vector argument, if vectored open */
dtrace_conf_t dt_conf; /* DTrace driver configuration profile */
char dt_errmsg[BUFSIZ]; /* buffer for formatted syntax error msgs */
const char *dt_errtag; /* tag used with last call to dt_set_errmsg() */
dt_pcb_t *dt_pcb; /* pointer to current parsing control block */
ulong_t dt_gen; /* compiler generation number */
dt_list_t dt_programs; /* linked list of dtrace_prog_t's */
dt_list_t dt_xlators; /* linked list of dt_xlator_t's */
struct dt_xlator **dt_xlatormap; /* dt_xlator_t's indexed by dx_id */
id_t dt_xlatorid; /* next dt_xlator_t id to assign */
dt_ident_t *dt_externs; /* linked list of external symbol identifiers */
dt_idhash_t *dt_macros; /* hash table of macro variable identifiers */
dt_idhash_t *dt_aggs; /* hash table of aggregation identifiers */
dt_idhash_t *dt_globals; /* hash table of global identifiers */
dt_idhash_t *dt_tls; /* hash table of thread-local identifiers */
dt_list_t dt_modlist; /* linked list of dt_module_t's */
dt_module_t **dt_mods; /* hash table of dt_module_t's */
uint_t dt_modbuckets; /* number of module hash buckets */
uint_t dt_nmods; /* number of modules in hash and list */
dt_provmod_t *dt_provmod; /* linked list of provider modules */
dt_module_t *dt_exec; /* pointer to executable module */
dt_module_t *dt_rtld; /* pointer to run-time linker module */
dt_module_t *dt_cdefs; /* pointer to C dynamic type module */
dt_module_t *dt_ddefs; /* pointer to D dynamic type module */
dt_list_t dt_provlist; /* linked list of dt_provider_t's */
struct dt_provider **dt_provs; /* hash table of dt_provider_t's */
uint_t dt_provbuckets; /* number of provider hash buckets */
uint_t dt_nprovs; /* number of providers in hash and list */
dt_proc_hash_t *dt_procs; /* hash table of grabbed process handles */
dt_intdesc_t dt_ints[6]; /* cached integer type descriptions */
ctf_id_t dt_type_func; /* cached CTF identifier for function type */
ctf_id_t dt_type_fptr; /* cached CTF identifier for function pointer */
ctf_id_t dt_type_str; /* cached CTF identifier for string type */
ctf_id_t dt_type_dyn; /* cached CTF identifier for <DYN> type */
ctf_id_t dt_type_stack; /* cached CTF identifier for stack type */
ctf_id_t dt_type_symaddr; /* cached CTF identifier for _symaddr type */
ctf_id_t dt_type_usymaddr; /* cached CTF ident. for _usymaddr type */
size_t dt_maxprobe; /* max enabled probe ID */
dtrace_eprobedesc_t **dt_edesc; /* enabled probe descriptions */
dtrace_probedesc_t **dt_pdesc; /* probe descriptions for enabled prbs */
size_t dt_maxagg; /* max aggregation ID */
dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */
int dt_maxformat; /* max format ID */
void **dt_formats; /* pointer to format array */
dt_aggregate_t dt_aggregate; /* aggregate */
dtrace_bufdesc_t dt_buf; /* staging buffer */
struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
dt_version_t dt_vmax; /* optional ceiling on program API binding */
dtrace_attribute_t dt_amin; /* optional floor on program attributes */
char *dt_cpp_path; /* pathname of cpp(1) to invoke if needed */
char **dt_cpp_argv; /* argument vector for exec'ing cpp(1) */
int dt_cpp_argc; /* count of initialized cpp(1) arguments */
int dt_cpp_args; /* size of dt_cpp_argv[] array */
char *dt_ld_path; /* pathname of ld(1) to invoke if needed */
dt_list_t dt_lib_path; /* linked-list forming library search path */
uint_t dt_lazyload; /* boolean: set via -xlazyload */
uint_t dt_droptags; /* boolean: set via -xdroptags */
uint_t dt_active; /* boolean: set once tracing is active */
uint_t dt_stopped; /* boolean: set once tracing is stopped */
processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */
processorid_t dt_endedon; /* CPU that executed END probe (if any) */
uint_t dt_oflags; /* dtrace open-time options (see dtrace.h) */
uint_t dt_cflags; /* dtrace compile-time options (see dtrace.h) */
uint_t dt_dflags; /* dtrace link-time options (see dtrace.h) */
uint_t dt_prcmode; /* dtrace process create mode (see dt_proc.h) */
uint_t dt_linkmode; /* dtrace symbol linking mode (see below) */
uint_t dt_linktype; /* dtrace link output file type (see below) */
uint_t dt_xlatemode; /* dtrace translator linking mode (see below) */
uint_t dt_stdcmode; /* dtrace stdc compatibility mode (see below) */
uint_t dt_treedump; /* dtrace tree debug bitmap (see below) */
uint64_t dt_options[DTRACEOPT_MAX]; /* dtrace run-time options */
int dt_version; /* library version requested by client */
int dt_ctferr; /* error resulting from last CTF failure */
int dt_errno; /* error resulting from last failed operation */
#if !defined(sun)
const char *dt_errfile;
int dt_errline;
#endif
int dt_fd; /* file descriptor for dtrace pseudo-device */
int dt_ftfd; /* file descriptor for fasttrap pseudo-device */
int dt_fterr; /* saved errno from failed open of dt_ftfd */
int dt_cdefs_fd; /* file descriptor for C CTF debugging cache */
int dt_ddefs_fd; /* file descriptor for D CTF debugging cache */
#if defined(sun)
int dt_stdout_fd; /* file descriptor for saved stdout */
#else
FILE *dt_freopen_fp; /* file pointer for freopened stdout */
#endif
dtrace_handle_err_f *dt_errhdlr; /* error handler, if any */
void *dt_errarg; /* error handler argument */
dtrace_prog_t *dt_errprog; /* error handler program, if any */
dtrace_handle_drop_f *dt_drophdlr; /* drop handler, if any */
void *dt_droparg; /* drop handler argument */
dtrace_handle_proc_f *dt_prochdlr; /* proc handler, if any */
void *dt_procarg; /* proc handler argument */
dtrace_handle_setopt_f *dt_setopthdlr; /* setopt handler, if any */
void *dt_setoptarg; /* setopt handler argument */
dtrace_status_t dt_status[2]; /* status cache */
int dt_statusgen; /* current status generation */
hrtime_t dt_laststatus; /* last status */
hrtime_t dt_lastswitch; /* last switch of buffer data */
hrtime_t dt_lastagg; /* last snapshot of aggregation data */
char *dt_sprintf_buf; /* buffer for dtrace_sprintf() */
int dt_sprintf_buflen; /* length of dtrace_sprintf() buffer */
const char *dt_filetag; /* default filetag for dt_set_errmsg() */
char *dt_buffered_buf; /* buffer for buffered output */
size_t dt_buffered_offs; /* current offset into buffered buffer */
size_t dt_buffered_size; /* size of buffered buffer */
dtrace_handle_buffered_f *dt_bufhdlr; /* buffered handler, if any */
void *dt_bufarg; /* buffered handler argument */
dt_dof_t dt_dof; /* DOF generation buffers (see dt_dof.c) */
struct utsname dt_uts; /* uname(2) information for system */
dt_list_t dt_lib_dep; /* scratch linked-list of lib dependencies */
dt_list_t dt_lib_dep_sorted; /* dependency sorted library list */
};
/*
* Values for the user arg of the ECB.
*/
#define DT_ECB_DEFAULT 0
#define DT_ECB_ERROR 1
/*
* Values for the dt_linkmode property, which is used by the assembler when
* processing external symbol references. User can set using -xlink=<mode>.
*/
#define DT_LINK_KERNEL 0 /* kernel syms static, user syms dynamic */
#define DT_LINK_PRIMARY 1 /* primary kernel syms static, others dynamic */
#define DT_LINK_DYNAMIC 2 /* all symbols dynamic */
#define DT_LINK_STATIC 3 /* all symbols static */
/*
* Values for the dt_linktype property, which is used by dtrace_program_link()
* to determine the type of output file that is desired by the client.
*/
#define DT_LTYP_ELF 0 /* produce ELF containing DOF */
#define DT_LTYP_DOF 1 /* produce stand-alone DOF */
/*
* Values for the dt_xlatemode property, which is used to determine whether
* references to dynamic translators are permitted. Set using -xlate=<mode>.
*/
#define DT_XL_STATIC 0 /* require xlators to be statically defined */
#define DT_XL_DYNAMIC 1 /* produce references to dynamic translators */
/*
* Values for the dt_stdcmode property, which is used by the compiler when
* running cpp to determine the presence and setting of the __STDC__ macro.
*/
#define DT_STDC_XA 0 /* ISO C + K&R C compat w/o ISO: __STDC__=0 */
#define DT_STDC_XC 1 /* Strict ISO C: __STDC__=1 */
#define DT_STDC_XS 2 /* K&R C: __STDC__ not defined */
#define DT_STDC_XT 3 /* ISO C + K&R C compat with ISO: __STDC__=0 */
/*
* Macro to test whether a given pass bit is set in the dt_treedump bit-vector.
* If the bit for pass 'p' is set, the D compiler displays the parse tree for
* the program by printing it to stderr at the end of compiler pass 'p'.
*/
#define DT_TREEDUMP_PASS(dtp, p) ((dtp)->dt_treedump & (1 << ((p) - 1)))
/*
* Macros for accessing the cached CTF container and type ID for the common
* types "int", "string", and <DYN>, which we need to use frequently in the D
* compiler. The DT_INT_* macro relies upon "int" being at index 0 in the
* _dtrace_ints_* tables in dt_open.c; the others are also set up there.
*/
#define DT_INT_CTFP(dtp) ((dtp)->dt_ints[0].did_ctfp)
#define DT_INT_TYPE(dtp) ((dtp)->dt_ints[0].did_type)
#define DT_FUNC_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_FUNC_TYPE(dtp) ((dtp)->dt_type_func)
#define DT_FPTR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_FPTR_TYPE(dtp) ((dtp)->dt_type_fptr)
#define DT_STR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_STR_TYPE(dtp) ((dtp)->dt_type_str)
#define DT_DYN_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_DYN_TYPE(dtp) ((dtp)->dt_type_dyn)
#define DT_STACK_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_STACK_TYPE(dtp) ((dtp)->dt_type_stack)
#define DT_SYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_SYMADDR_TYPE(dtp) ((dtp)->dt_type_symaddr)
#define DT_USYMADDR_CTFP(dtp) ((dtp)->dt_ddefs->dm_ctfp)
#define DT_USYMADDR_TYPE(dtp) ((dtp)->dt_type_usymaddr)
/*
* Actions and subroutines are both DT_NODE_FUNC nodes; to avoid confusing
* an action for a subroutine (or vice versa), we assure that the DT_ACT_*
* constants and the DIF_SUBR_* constants occupy non-overlapping ranges by
* starting the DT_ACT_* constants at DIF_SUBR_MAX + 1.
*/
#define DT_ACT_BASE DIF_SUBR_MAX + 1
#define DT_ACT(n) (DT_ACT_BASE + (n))
#define DT_ACT_PRINTF DT_ACT(0) /* printf() action */
#define DT_ACT_TRACE DT_ACT(1) /* trace() action */
#define DT_ACT_TRACEMEM DT_ACT(2) /* tracemem() action */
#define DT_ACT_STACK DT_ACT(3) /* stack() action */
#define DT_ACT_STOP DT_ACT(4) /* stop() action */
#define DT_ACT_BREAKPOINT DT_ACT(5) /* breakpoint() action */
#define DT_ACT_PANIC DT_ACT(6) /* panic() action */
#define DT_ACT_SPECULATE DT_ACT(7) /* speculate() action */
#define DT_ACT_COMMIT DT_ACT(8) /* commit() action */
#define DT_ACT_DISCARD DT_ACT(9) /* discard() action */
#define DT_ACT_CHILL DT_ACT(10) /* chill() action */
#define DT_ACT_EXIT DT_ACT(11) /* exit() action */
#define DT_ACT_USTACK DT_ACT(12) /* ustack() action */
#define DT_ACT_PRINTA DT_ACT(13) /* printa() action */
#define DT_ACT_RAISE DT_ACT(14) /* raise() action */
#define DT_ACT_CLEAR DT_ACT(15) /* clear() action */
#define DT_ACT_NORMALIZE DT_ACT(16) /* normalize() action */
#define DT_ACT_DENORMALIZE DT_ACT(17) /* denormalize() action */
#define DT_ACT_TRUNC DT_ACT(18) /* trunc() action */
#define DT_ACT_SYSTEM DT_ACT(19) /* system() action */
#define DT_ACT_JSTACK DT_ACT(20) /* jstack() action */
#define DT_ACT_FTRUNCATE DT_ACT(21) /* ftruncate() action */
#define DT_ACT_FREOPEN DT_ACT(22) /* freopen() action */
#define DT_ACT_SYM DT_ACT(23) /* sym()/func() actions */
#define DT_ACT_MOD DT_ACT(24) /* mod() action */
#define DT_ACT_USYM DT_ACT(25) /* usym()/ufunc() actions */
#define DT_ACT_UMOD DT_ACT(26) /* umod() action */
#define DT_ACT_UADDR DT_ACT(27) /* uaddr() action */
#define DT_ACT_SETOPT DT_ACT(28) /* setopt() action */
#define DT_ACT_PRINTM DT_ACT(29) /* printm() action */
#define DT_ACT_PRINTT DT_ACT(30) /* printt() action */
/*
* Sentinel to tell freopen() to restore the saved stdout. This must not
* be ever valid for opening for write access via freopen(3C), which of
* course, "." never is.
*/
#define DT_FREOPEN_RESTORE "."
#define EDT_BASE 1000 /* base value for libdtrace errnos */
enum {
EDT_VERSION = EDT_BASE, /* client is requesting unsupported version */
EDT_VERSINVAL, /* version string is invalid or overflows */
EDT_VERSUNDEF, /* requested API version is not defined */
EDT_VERSREDUCED, /* requested API version has been reduced */
EDT_CTF, /* libctf called failed (dt_ctferr has more) */
EDT_COMPILER, /* error in D program compilation */
EDT_NOREG, /* register allocation failure */
EDT_NOTUPREG, /* tuple register allocation failure */
EDT_NOMEM, /* memory allocation failure */
EDT_INT2BIG, /* integer limit exceeded */
EDT_STR2BIG, /* string limit exceeded */
EDT_NOMOD, /* unknown module name */
EDT_NOPROV, /* unknown provider name */
EDT_NOPROBE, /* unknown probe name */
EDT_NOSYM, /* unknown symbol name */
EDT_NOSYMADDR, /* no symbol corresponds to address */
EDT_NOTYPE, /* unknown type name */
EDT_NOVAR, /* unknown variable name */
EDT_NOAGG, /* unknown aggregation name */
EDT_BADSCOPE, /* improper use of type name scoping operator */
EDT_BADSPEC, /* overspecified probe description */
EDT_BADSPCV, /* bad macro variable in probe description */
EDT_BADID, /* invalid probe identifier */
EDT_NOTLOADED, /* module is not currently loaded */
EDT_NOCTF, /* module does not contain any CTF data */
EDT_DATAMODEL, /* module and program data models don't match */
EDT_DIFVERS, /* library has newer DIF version than driver */
EDT_BADAGG, /* unrecognized aggregating action */
EDT_FIO, /* file i/o error */
EDT_DIFINVAL, /* invalid DIF program */
EDT_DIFSIZE, /* invalid DIF size */
EDT_DIFFAULT, /* failed to copyin DIF program */
EDT_BADPROBE, /* bad probe description */
EDT_BADPGLOB, /* bad probe description globbing pattern */
EDT_NOSCOPE, /* declaration scope stack underflow */
EDT_NODECL, /* declaration stack underflow */
EDT_DMISMATCH, /* record list does not match statement */
EDT_DOFFSET, /* record data offset error */
EDT_DALIGN, /* record data alignment error */
EDT_BADOPTNAME, /* invalid dtrace_setopt option name */
EDT_BADOPTVAL, /* invalid dtrace_setopt option value */
EDT_BADOPTCTX, /* invalid dtrace_setopt option context */
EDT_CPPFORK, /* failed to fork preprocessor */
EDT_CPPEXEC, /* failed to exec preprocessor */
EDT_CPPENT, /* preprocessor not found */
EDT_CPPERR, /* unknown preprocessor error */
EDT_SYMOFLOW, /* external symbol table overflow */
EDT_ACTIVE, /* operation illegal when tracing is active */
EDT_DESTRUCTIVE, /* destructive actions not allowed */
EDT_NOANON, /* no anonymous tracing state */
EDT_ISANON, /* can't claim anon state and enable probes */
EDT_ENDTOOBIG, /* END enablings exceed size of prncpl buffer */
EDT_NOCONV, /* failed to load type for printf conversion */
EDT_BADCONV, /* incomplete printf conversion */
EDT_BADERROR, /* invalid library ERROR action */
EDT_ERRABORT, /* abort due to error */
EDT_DROPABORT, /* abort due to drop */
EDT_DIRABORT, /* abort explicitly directed */
EDT_BADRVAL, /* invalid return value from callback */
EDT_BADNORMAL, /* invalid normalization */
EDT_BUFTOOSMALL, /* enabling exceeds size of buffer */
EDT_BADTRUNC, /* invalid truncation */
EDT_BUSY, /* device busy (active kernel debugger) */
EDT_ACCESS, /* insufficient privileges to use DTrace */
EDT_NOENT, /* dtrace device not available */
EDT_BRICKED, /* abort due to systemic unresponsiveness */
EDT_HARDWIRE, /* failed to load hard-wired definitions */
EDT_ELFVERSION, /* libelf is out-of-date w.r.t libdtrace */
EDT_NOBUFFERED, /* attempt to buffer output without handler */
EDT_UNSTABLE, /* description matched unstable set of probes */
EDT_BADSETOPT, /* invalid setopt library action */
EDT_BADSTACKPC, /* invalid stack program counter size */
EDT_BADAGGVAR, /* invalid aggregation variable identifier */
EDT_OVERSION /* client is requesting deprecated version */
};
/*
* Interfaces for parsing and comparing DTrace attribute tuples, which describe
* stability and architectural binding information. The dtrace_attribute_t
* structure and associated constant definitions are found in <sys/dtrace.h>.
*/
extern dtrace_attribute_t dt_attr_min(dtrace_attribute_t, dtrace_attribute_t);
extern dtrace_attribute_t dt_attr_max(dtrace_attribute_t, dtrace_attribute_t);
extern char *dt_attr_str(dtrace_attribute_t, char *, size_t);
extern int dt_attr_cmp(dtrace_attribute_t, dtrace_attribute_t);
/*
* Interfaces for parsing and handling DTrace version strings. Version binding
* is a feature of the D compiler that is handled completely independently of
* the DTrace kernel infrastructure, so the definitions are here in libdtrace.
* Version strings are compiled into an encoded uint32_t which can be compared
* using C comparison operators. Version definitions are found in dt_open.c.
*/
#define DT_VERSION_STRMAX 16 /* enough for "255.4095.4095\0" */
#define DT_VERSION_MAJMAX 0xFF /* maximum major version number */
#define DT_VERSION_MINMAX 0xFFF /* maximum minor version number */
#define DT_VERSION_MICMAX 0xFFF /* maximum micro version number */
#define DT_VERSION_NUMBER(M, m, u) \
((((M) & 0xFF) << 24) | (((m) & 0xFFF) << 12) | ((u) & 0xFFF))
#define DT_VERSION_MAJOR(v) (((v) & 0xFF000000) >> 24)
#define DT_VERSION_MINOR(v) (((v) & 0x00FFF000) >> 12)
#define DT_VERSION_MICRO(v) ((v) & 0x00000FFF)
extern char *dt_version_num2str(dt_version_t, char *, size_t);
extern int dt_version_str2num(const char *, dt_version_t *);
extern int dt_version_defined(dt_version_t);
/*
* Miscellaneous internal libdtrace interfaces. The definitions below are for
* libdtrace routines that do not yet merit their own separate header file.
*/
extern char *dt_cpp_add_arg(dtrace_hdl_t *, const char *);
extern char *dt_cpp_pop_arg(dtrace_hdl_t *);
#if defined(sun)
extern int dt_set_errno(dtrace_hdl_t *, int);
#else
int _dt_set_errno(dtrace_hdl_t *, int, const char *, int);
void dt_get_errloc(dtrace_hdl_t *, const char **, int *);
#define dt_set_errno(_a,_b) _dt_set_errno(_a,_b,__FILE__,__LINE__)
#endif
extern void dt_set_errmsg(dtrace_hdl_t *, const char *, const char *,
const char *, int, const char *, va_list);
#if defined(sun)
extern int dt_ioctl(dtrace_hdl_t *, int, void *);
#else
extern int dt_ioctl(dtrace_hdl_t *, u_long, void *);
#endif
extern int dt_status(dtrace_hdl_t *, processorid_t);
extern long dt_sysconf(dtrace_hdl_t *, int);
extern ssize_t dt_write(dtrace_hdl_t *, int, const void *, size_t);
extern int dt_printf(dtrace_hdl_t *, FILE *, const char *, ...);
extern void *dt_zalloc(dtrace_hdl_t *, size_t);
extern void *dt_alloc(dtrace_hdl_t *, size_t);
extern void dt_free(dtrace_hdl_t *, void *);
extern void dt_difo_free(dtrace_hdl_t *, dtrace_difo_t *);
extern int dt_gmatch(const char *, const char *);
extern char *dt_basename(char *);
extern ulong_t dt_popc(ulong_t);
extern ulong_t dt_popcb(const ulong_t *, ulong_t);
extern int dt_buffered_enable(dtrace_hdl_t *);
extern int dt_buffered_flush(dtrace_hdl_t *, dtrace_probedata_t *,
const dtrace_recdesc_t *, const dtrace_aggdata_t *, uint32_t flags);
extern void dt_buffered_disable(dtrace_hdl_t *);
extern void dt_buffered_destroy(dtrace_hdl_t *);
extern int dt_rw_read_held(pthread_rwlock_t *);
extern int dt_rw_write_held(pthread_rwlock_t *);
extern int dt_mutex_held(pthread_mutex_t *);
extern uint64_t dt_stddev(uint64_t *, uint64_t);
#define DT_RW_READ_HELD(x) dt_rw_read_held(x)
#define DT_RW_WRITE_HELD(x) dt_rw_write_held(x)
#define DT_RW_LOCK_HELD(x) (DT_RW_READ_HELD(x) || DT_RW_WRITE_HELD(x))
#define DT_MUTEX_HELD(x) dt_mutex_held(x)
extern int dt_options_load(dtrace_hdl_t *);
extern void dt_dprintf(const char *, ...);
extern void dt_setcontext(dtrace_hdl_t *, dtrace_probedesc_t *);
extern void dt_endcontext(dtrace_hdl_t *);
extern void dt_pragma(dt_node_t *);
extern int dt_reduce(dtrace_hdl_t *, dt_version_t);
extern void dt_cg(dt_pcb_t *, dt_node_t *);
extern dtrace_difo_t *dt_as(dt_pcb_t *);
extern void dt_dis(const dtrace_difo_t *, FILE *);
extern int dt_aggregate_go(dtrace_hdl_t *);
extern int dt_aggregate_init(dtrace_hdl_t *);
extern void dt_aggregate_destroy(dtrace_hdl_t *);
extern int dt_epid_lookup(dtrace_hdl_t *, dtrace_epid_t,
dtrace_eprobedesc_t **, dtrace_probedesc_t **);
extern void dt_epid_destroy(dtrace_hdl_t *);
extern int dt_aggid_lookup(dtrace_hdl_t *, dtrace_aggid_t, dtrace_aggdesc_t **);
extern void dt_aggid_destroy(dtrace_hdl_t *);
extern void *dt_format_lookup(dtrace_hdl_t *, int);
extern void dt_format_destroy(dtrace_hdl_t *);
extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,
const void *, size_t, uint64_t);
extern int dt_print_agg(const dtrace_aggdata_t *, void *);
extern int dt_handle(dtrace_hdl_t *, dtrace_probedata_t *);
extern int dt_handle_liberr(dtrace_hdl_t *,
const dtrace_probedata_t *, const char *);
extern int dt_handle_cpudrop(dtrace_hdl_t *, processorid_t,
dtrace_dropkind_t, uint64_t);
extern int dt_handle_status(dtrace_hdl_t *,
dtrace_status_t *, dtrace_status_t *);
extern int dt_handle_setopt(dtrace_hdl_t *, dtrace_setoptdata_t *);
extern int dt_lib_depend_add(dtrace_hdl_t *, dt_list_t *, const char *);
extern dt_lib_depend_t *dt_lib_depend_lookup(dt_list_t *, const char *);
extern dt_pcb_t *yypcb; /* pointer to current parser control block */
extern char yyintprefix; /* int token prefix for macros (+/-) */
extern char yyintsuffix[4]; /* int token suffix ([uUlL]*) */
extern int yyintdecimal; /* int token is decimal (1) or octal/hex (0) */
extern char yytext[]; /* lex input buffer */
extern int yylineno; /* lex line number */
extern int yydebug; /* lex debugging */
extern dt_node_t *yypragma; /* lex token list for control lines */
extern const dtrace_attribute_t _dtrace_maxattr; /* maximum attributes */
extern const dtrace_attribute_t _dtrace_defattr; /* default attributes */
extern const dtrace_attribute_t _dtrace_symattr; /* symbol ref attributes */
extern const dtrace_attribute_t _dtrace_typattr; /* type ref attributes */
extern const dtrace_attribute_t _dtrace_prvattr; /* provider attributes */
extern const dtrace_pattr_t _dtrace_prvdesc; /* provider attribute bundle */
extern const dt_version_t _dtrace_versions[]; /* array of valid versions */
extern const char *const _dtrace_version; /* current version string */
extern int _dtrace_strbuckets; /* number of hash buckets for strings */
extern int _dtrace_intbuckets; /* number of hash buckets for ints */
extern uint_t _dtrace_stkindent; /* default indent for stack/ustack */
extern uint_t _dtrace_pidbuckets; /* number of hash buckets for pids */
extern uint_t _dtrace_pidlrulim; /* number of proc handles to cache */
extern int _dtrace_debug; /* debugging messages enabled */
extern size_t _dtrace_bufsize; /* default dt_buf_create() size */
extern int _dtrace_argmax; /* default maximum probe arguments */
extern const char *_dtrace_libdir; /* default library directory */
extern const char *_dtrace_moddir; /* default kernel module directory */
#ifdef __cplusplus
}
#endif
#endif /* _DT_IMPL_H */

View File

@ -0,0 +1,115 @@
/*
* 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
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
#include <dt_inttab.h>
#include <dt_impl.h>
dt_inttab_t *
dt_inttab_create(dtrace_hdl_t *dtp)
{
uint_t len = _dtrace_intbuckets;
dt_inttab_t *ip;
assert((len & (len - 1)) == 0);
if ((ip = dt_zalloc(dtp, sizeof (dt_inttab_t))) == NULL ||
(ip->int_hash = dt_zalloc(dtp, sizeof (void *) * len)) == NULL) {
dt_free(dtp, ip);
return (NULL);
}
ip->int_hdl = dtp;
ip->int_hashlen = len;
return (ip);
}
void
dt_inttab_destroy(dt_inttab_t *ip)
{
dt_inthash_t *hp, *np;
for (hp = ip->int_head; hp != NULL; hp = np) {
np = hp->inh_next;
dt_free(ip->int_hdl, hp);
}
dt_free(ip->int_hdl, ip->int_hash);
dt_free(ip->int_hdl, ip);
}
int
dt_inttab_insert(dt_inttab_t *ip, uint64_t value, uint_t flags)
{
uint_t h = value & (ip->int_hashlen - 1);
dt_inthash_t *hp;
if (flags & DT_INT_SHARED) {
for (hp = ip->int_hash[h]; hp != NULL; hp = hp->inh_hash) {
if (hp->inh_value == value && hp->inh_flags == flags)
return (hp->inh_index);
}
}
if ((hp = dt_alloc(ip->int_hdl, sizeof (dt_inthash_t))) == NULL)
return (-1);
hp->inh_hash = ip->int_hash[h];
hp->inh_next = NULL;
hp->inh_value = value;
hp->inh_index = ip->int_index++;
hp->inh_flags = flags;
ip->int_hash[h] = hp;
ip->int_nelems++;
if (ip->int_head == NULL)
ip->int_head = hp;
else
ip->int_tail->inh_next = hp;
ip->int_tail = hp;
return (hp->inh_index);
}
uint_t
dt_inttab_size(const dt_inttab_t *ip)
{
return (ip->int_nelems);
}
void
dt_inttab_write(const dt_inttab_t *ip, uint64_t *dst)
{
const dt_inthash_t *hp;
for (hp = ip->int_head; hp != NULL; hp = hp->inh_next)
*dst++ = hp->inh_value;
}

View File

@ -0,0 +1,69 @@
/*
* 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
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_INTTAB_H
#define _DT_INTTAB_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dtrace.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_inthash {
struct dt_inthash *inh_hash; /* next dt_inthash in hash chain */
struct dt_inthash *inh_next; /* next dt_inthash in output table */
uint64_t inh_value; /* value associated with this element */
uint_t inh_index; /* index associated with this element */
uint_t inh_flags; /* flags (see below) */
} dt_inthash_t;
typedef struct dt_inttab {
dtrace_hdl_t *int_hdl; /* pointer back to library handle */
dt_inthash_t **int_hash; /* array of hash buckets */
uint_t int_hashlen; /* size of hash bucket array */
uint_t int_nelems; /* number of elements hashed */
dt_inthash_t *int_head; /* head of table in index order */
dt_inthash_t *int_tail; /* tail of table in index order */
uint_t int_index; /* next index to hand out */
} dt_inttab_t;
#define DT_INT_PRIVATE 0 /* only a single ref for this entry */
#define DT_INT_SHARED 1 /* multiple refs can share entry */
extern dt_inttab_t *dt_inttab_create(dtrace_hdl_t *);
extern void dt_inttab_destroy(dt_inttab_t *);
extern int dt_inttab_insert(dt_inttab_t *, uint64_t, uint_t);
extern uint_t dt_inttab_size(const dt_inttab_t *);
extern void dt_inttab_write(const dt_inttab_t *, uint64_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_INTTAB_H */

View File

@ -0,0 +1,860 @@
%{
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <dt_impl.h>
#include <dt_grammar.h>
#include <dt_parser.h>
#include <dt_string.h>
/*
* We need to undefine lex's input and unput macros so that references to these
* call the functions provided at the end of this source file.
*/
#if defined(sun)
#undef input
#undef unput
#else
/*
* Define YY_INPUT for flex since input() can't be re-defined.
*/
#define YY_INPUT(buf,result,max_size) \
if (yypcb->pcb_fileptr != NULL) { \
if (((result = fread(buf, 1, max_size, yypcb->pcb_fileptr)) == 0) \
&& ferror(yypcb->pcb_fileptr)) \
longjmp(yypcb->pcb_jmpbuf, EDT_FIO); \
} else { \
int n; \
for (n = 0; n < max_size && \
yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen; n++) \
buf[n] = *yypcb->pcb_strptr++; \
result = n; \
}
#endif
static int id_or_type(const char *);
#if defined(sun)
static int input(void);
static void unput(int);
#endif
/*
* We first define a set of labeled states for use in the D lexer and then a
* set of regular expressions to simplify things below. The lexer states are:
*
* S0 - D program clause and expression lexing
* S1 - D comments (i.e. skip everything until end of comment)
* S2 - D program outer scope (probe specifiers and declarations)
* S3 - D control line parsing (i.e. after ^# is seen but before \n)
* S4 - D control line scan (locate control directives only and invoke S3)
*/
%}
%e 1500 /* maximum nodes */
%p 3700 /* maximum positions */
%n 600 /* maximum states */
%s S0 S1 S2 S3 S4
RGX_AGG "@"[a-zA-Z_][0-9a-zA-Z_]*
RGX_PSPEC [-$:a-zA-Z_.?*\\\[\]!][-$:0-9a-zA-Z_.`?*\\\[\]!]*
RGX_IDENT [a-zA-Z_`][0-9a-zA-Z_`]*
RGX_INT ([0-9]+|0[xX][0-9A-Fa-f]+)[uU]?[lL]?[lL]?
RGX_FP ([0-9]+("."?)[0-9]*|"."[0-9]+)((e|E)("+"|-)?[0-9]+)?[fFlL]?
RGX_WS [\f\n\r\t\v ]
RGX_STR ([^"\\\n]|\\[^"\n]|\\\")*
RGX_CHR ([^'\\\n]|\\[^'\n]|\\')*
RGX_INTERP ^[\f\t\v ]*#!.*
RGX_CTL ^[\f\t\v ]*#
%%
%{
/*
* We insert a special prologue into yylex() itself: if the pcb contains a
* context token, we return that prior to running the normal lexer. This
* allows libdtrace to force yacc into one of our three parsing contexts: D
* expression (DT_CTX_DEXPR), D program (DT_CTX_DPROG) or D type (DT_CTX_DTYPE).
* Once the token is returned, we clear it so this only happens once.
*/
if (yypcb->pcb_token != 0) {
int tok = yypcb->pcb_token;
yypcb->pcb_token = 0;
return (tok);
}
%}
<S0>auto return (DT_KEY_AUTO);
<S0>break return (DT_KEY_BREAK);
<S0>case return (DT_KEY_CASE);
<S0>char return (DT_KEY_CHAR);
<S0>const return (DT_KEY_CONST);
<S0>continue return (DT_KEY_CONTINUE);
<S0>counter return (DT_KEY_COUNTER);
<S0>default return (DT_KEY_DEFAULT);
<S0>do return (DT_KEY_DO);
<S0>double return (DT_KEY_DOUBLE);
<S0>else return (DT_KEY_ELSE);
<S0>enum return (DT_KEY_ENUM);
<S0>extern return (DT_KEY_EXTERN);
<S0>float return (DT_KEY_FLOAT);
<S0>for return (DT_KEY_FOR);
<S0>goto return (DT_KEY_GOTO);
<S0>if return (DT_KEY_IF);
<S0>import return (DT_KEY_IMPORT);
<S0>inline return (DT_KEY_INLINE);
<S0>int return (DT_KEY_INT);
<S0>long return (DT_KEY_LONG);
<S0>offsetof return (DT_TOK_OFFSETOF);
<S0>probe return (DT_KEY_PROBE);
<S0>provider return (DT_KEY_PROVIDER);
<S0>register return (DT_KEY_REGISTER);
<S0>restrict return (DT_KEY_RESTRICT);
<S0>return return (DT_KEY_RETURN);
<S0>self return (DT_KEY_SELF);
<S0>short return (DT_KEY_SHORT);
<S0>signed return (DT_KEY_SIGNED);
<S0>sizeof return (DT_TOK_SIZEOF);
<S0>static return (DT_KEY_STATIC);
<S0>string return (DT_KEY_STRING);
<S0>stringof return (DT_TOK_STRINGOF);
<S0>struct return (DT_KEY_STRUCT);
<S0>switch return (DT_KEY_SWITCH);
<S0>this return (DT_KEY_THIS);
<S0>translator return (DT_KEY_XLATOR);
<S0>typedef return (DT_KEY_TYPEDEF);
<S0>union return (DT_KEY_UNION);
<S0>unsigned return (DT_KEY_UNSIGNED);
<S0>void return (DT_KEY_VOID);
<S0>volatile return (DT_KEY_VOLATILE);
<S0>while return (DT_KEY_WHILE);
<S0>xlate return (DT_TOK_XLATE);
<S2>auto { yybegin(YYS_EXPR); return (DT_KEY_AUTO); }
<S2>char { yybegin(YYS_EXPR); return (DT_KEY_CHAR); }
<S2>const { yybegin(YYS_EXPR); return (DT_KEY_CONST); }
<S2>counter { yybegin(YYS_DEFINE); return (DT_KEY_COUNTER); }
<S2>double { yybegin(YYS_EXPR); return (DT_KEY_DOUBLE); }
<S2>enum { yybegin(YYS_EXPR); return (DT_KEY_ENUM); }
<S2>extern { yybegin(YYS_EXPR); return (DT_KEY_EXTERN); }
<S2>float { yybegin(YYS_EXPR); return (DT_KEY_FLOAT); }
<S2>import { yybegin(YYS_EXPR); return (DT_KEY_IMPORT); }
<S2>inline { yybegin(YYS_DEFINE); return (DT_KEY_INLINE); }
<S2>int { yybegin(YYS_EXPR); return (DT_KEY_INT); }
<S2>long { yybegin(YYS_EXPR); return (DT_KEY_LONG); }
<S2>provider { yybegin(YYS_DEFINE); return (DT_KEY_PROVIDER); }
<S2>register { yybegin(YYS_EXPR); return (DT_KEY_REGISTER); }
<S2>restrict { yybegin(YYS_EXPR); return (DT_KEY_RESTRICT); }
<S2>self { yybegin(YYS_EXPR); return (DT_KEY_SELF); }
<S2>short { yybegin(YYS_EXPR); return (DT_KEY_SHORT); }
<S2>signed { yybegin(YYS_EXPR); return (DT_KEY_SIGNED); }
<S2>static { yybegin(YYS_EXPR); return (DT_KEY_STATIC); }
<S2>string { yybegin(YYS_EXPR); return (DT_KEY_STRING); }
<S2>struct { yybegin(YYS_EXPR); return (DT_KEY_STRUCT); }
<S2>this { yybegin(YYS_EXPR); return (DT_KEY_THIS); }
<S2>translator { yybegin(YYS_DEFINE); return (DT_KEY_XLATOR); }
<S2>typedef { yybegin(YYS_EXPR); return (DT_KEY_TYPEDEF); }
<S2>union { yybegin(YYS_EXPR); return (DT_KEY_UNION); }
<S2>unsigned { yybegin(YYS_EXPR); return (DT_KEY_UNSIGNED); }
<S2>void { yybegin(YYS_EXPR); return (DT_KEY_VOID); }
<S2>volatile { yybegin(YYS_EXPR); return (DT_KEY_VOLATILE); }
<S0>"$$"[0-9]+ {
int i = atoi(yytext + 2);
char *v = "";
/*
* A macro argument reference substitutes the text of
* an argument in place of the current token. When we
* see $$<d> we fetch the saved string from pcb_sargv
* (or use the default argument if the option has been
* set and the argument hasn't been specified) and
* return a token corresponding to this string.
*/
if (i < 0 || (i >= yypcb->pcb_sargc &&
!(yypcb->pcb_cflags & DTRACE_C_DEFARG))) {
xyerror(D_MACRO_UNDEF, "macro argument %s is "
"not defined\n", yytext);
}
if (i < yypcb->pcb_sargc) {
v = yypcb->pcb_sargv[i]; /* get val from pcb */
yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
}
if ((yylval.l_str = strdup(v)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
(void) stresc2chr(yylval.l_str);
return (DT_TOK_STRING);
}
<S0>"$"[0-9]+ {
int i = atoi(yytext + 1);
char *p, *v = "0";
/*
* A macro argument reference substitutes the text of
* one identifier or integer pattern for another. When
* we see $<d> we fetch the saved string from pcb_sargv
* (or use the default argument if the option has been
* set and the argument hasn't been specified) and
* return a token corresponding to this string.
*/
if (i < 0 || (i >= yypcb->pcb_sargc &&
!(yypcb->pcb_cflags & DTRACE_C_DEFARG))) {
xyerror(D_MACRO_UNDEF, "macro argument %s is "
"not defined\n", yytext);
}
if (i < yypcb->pcb_sargc) {
v = yypcb->pcb_sargv[i]; /* get val from pcb */
yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
}
/*
* If the macro text is not a valid integer or ident,
* then we treat it as a string. The string may be
* optionally enclosed in quotes, which we strip.
*/
if (strbadidnum(v)) {
size_t len = strlen(v);
if (len != 1 && *v == '"' && v[len - 1] == '"')
yylval.l_str = strndup(v + 1, len - 2);
else
yylval.l_str = strndup(v, len);
if (yylval.l_str == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
(void) stresc2chr(yylval.l_str);
return (DT_TOK_STRING);
}
/*
* If the macro text is not a string an begins with a
* digit or a +/- sign, process it as an integer token.
*/
if (isdigit(v[0]) || v[0] == '-' || v[0] == '+') {
if (isdigit(v[0]))
yyintprefix = 0;
else
yyintprefix = *v++;
errno = 0;
yylval.l_int = strtoull(v, &p, 0);
(void) strncpy(yyintsuffix, p,
sizeof (yyintsuffix));
yyintdecimal = *v != '0';
if (errno == ERANGE) {
xyerror(D_MACRO_OFLOW, "macro argument"
" %s constant %s results in integer"
" overflow\n", yytext, v);
}
return (DT_TOK_INT);
}
return (id_or_type(v));
}
<S0>"$$"{RGX_IDENT} {
dt_ident_t *idp = dt_idhash_lookup(
yypcb->pcb_hdl->dt_macros, yytext + 2);
char s[16]; /* enough for UINT_MAX + \0 */
if (idp == NULL) {
xyerror(D_MACRO_UNDEF, "macro variable %s "
"is not defined\n", yytext);
}
/*
* For the moment, all current macro variables are of
* type id_t (refer to dtrace_update() for details).
*/
(void) snprintf(s, sizeof (s), "%u", idp->di_id);
if ((yylval.l_str = strdup(s)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
return (DT_TOK_STRING);
}
<S0>"$"{RGX_IDENT} {
dt_ident_t *idp = dt_idhash_lookup(
yypcb->pcb_hdl->dt_macros, yytext + 1);
if (idp == NULL) {
xyerror(D_MACRO_UNDEF, "macro variable %s "
"is not defined\n", yytext);
}
/*
* For the moment, all current macro variables are of
* type id_t (refer to dtrace_update() for details).
*/
yylval.l_int = (intmax_t)(int)idp->di_id;
yyintprefix = 0;
yyintsuffix[0] = '\0';
yyintdecimal = 1;
return (DT_TOK_INT);
}
<S0>{RGX_IDENT} {
return (id_or_type(yytext));
}
<S0>{RGX_AGG} {
if ((yylval.l_str = strdup(yytext)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
return (DT_TOK_AGG);
}
<S0>"@" {
if ((yylval.l_str = strdup("@_")) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
return (DT_TOK_AGG);
}
<S0>{RGX_INT} |
<S2>{RGX_INT} |
<S3>{RGX_INT} {
char *p;
errno = 0;
yylval.l_int = strtoull(yytext, &p, 0);
yyintprefix = 0;
(void) strncpy(yyintsuffix, p, sizeof (yyintsuffix));
yyintdecimal = yytext[0] != '0';
if (errno == ERANGE) {
xyerror(D_INT_OFLOW, "constant %s results in "
"integer overflow\n", yytext);
}
if (*p != '\0' && strchr("uUlL", *p) == NULL) {
xyerror(D_INT_DIGIT, "constant %s contains "
"invalid digit %c\n", yytext, *p);
}
if ((YYSTATE) != S3)
return (DT_TOK_INT);
yypragma = dt_node_link(yypragma,
dt_node_int(yylval.l_int));
}
<S0>{RGX_FP} yyerror("floating-point constants are not permitted\n");
<S0>\"{RGX_STR}$ |
<S3>\"{RGX_STR}$ xyerror(D_STR_NL, "newline encountered in string literal");
<S0>\"{RGX_STR}\" |
<S3>\"{RGX_STR}\" {
/*
* Quoted string -- convert C escape sequences and
* return the string as a token.
*/
yylval.l_str = strndup(yytext + 1, yyleng - 2);
if (yylval.l_str == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
(void) stresc2chr(yylval.l_str);
if ((YYSTATE) != S3)
return (DT_TOK_STRING);
yypragma = dt_node_link(yypragma,
dt_node_string(yylval.l_str));
}
<S0>'{RGX_CHR}$ xyerror(D_CHR_NL, "newline encountered in character constant");
<S0>'{RGX_CHR}' {
char *s, *p, *q;
size_t nbytes;
/*
* Character constant -- convert C escape sequences and
* return the character as an integer immediate value.
*/
if (yyleng == 2)
xyerror(D_CHR_NULL, "empty character constant");
s = yytext + 1;
yytext[yyleng - 1] = '\0';
nbytes = stresc2chr(s);
yylval.l_int = 0;
yyintprefix = 0;
yyintsuffix[0] = '\0';
yyintdecimal = 1;
if (nbytes > sizeof (yylval.l_int)) {
xyerror(D_CHR_OFLOW, "character constant is "
"too long");
}
#if BYTE_ORDER == _LITTLE_ENDIAN
p = ((char *)&yylval.l_int) + nbytes - 1;
for (q = s; nbytes != 0; nbytes--)
*p-- = *q++;
#else
bcopy(s, ((char *)&yylval.l_int) +
sizeof (yylval.l_int) - nbytes, nbytes);
#endif
return (DT_TOK_INT);
}
<S0>"/*" |
<S2>"/*" {
yypcb->pcb_cstate = (YYSTATE);
BEGIN(S1);
}
<S0>{RGX_INTERP} |
<S2>{RGX_INTERP} ; /* discard any #! lines */
<S0>{RGX_CTL} |
<S2>{RGX_CTL} |
<S4>{RGX_CTL} {
assert(yypragma == NULL);
yypcb->pcb_cstate = (YYSTATE);
BEGIN(S3);
}
<S4>. ; /* discard */
<S4>"\n" ; /* discard */
<S0>"/" {
int c, tok;
/*
* The use of "/" as the predicate delimiter and as the
* integer division symbol requires special lookahead
* to avoid a shift/reduce conflict in the D grammar.
* We look ahead to the next non-whitespace character.
* If we encounter EOF, ";", "{", or "/", then this "/"
* closes the predicate and we return DT_TOK_EPRED.
* If we encounter anything else, it's DT_TOK_DIV.
*/
while ((c = input()) != 0) {
if (strchr("\f\n\r\t\v ", c) == NULL)
break;
}
if (c == 0 || c == ';' || c == '{' || c == '/') {
if (yypcb->pcb_parens != 0) {
yyerror("closing ) expected in "
"predicate before /\n");
}
if (yypcb->pcb_brackets != 0) {
yyerror("closing ] expected in "
"predicate before /\n");
}
tok = DT_TOK_EPRED;
} else
tok = DT_TOK_DIV;
unput(c);
return (tok);
}
<S0>"(" {
yypcb->pcb_parens++;
return (DT_TOK_LPAR);
}
<S0>")" {
if (--yypcb->pcb_parens < 0)
yyerror("extra ) in input stream\n");
return (DT_TOK_RPAR);
}
<S0>"[" {
yypcb->pcb_brackets++;
return (DT_TOK_LBRAC);
}
<S0>"]" {
if (--yypcb->pcb_brackets < 0)
yyerror("extra ] in input stream\n");
return (DT_TOK_RBRAC);
}
<S0>"{" |
<S2>"{" {
yypcb->pcb_braces++;
return ('{');
}
<S0>"}" {
if (--yypcb->pcb_braces < 0)
yyerror("extra } in input stream\n");
return ('}');
}
<S0>"|" return (DT_TOK_BOR);
<S0>"^" return (DT_TOK_XOR);
<S0>"&" return (DT_TOK_BAND);
<S0>"&&" return (DT_TOK_LAND);
<S0>"^^" return (DT_TOK_LXOR);
<S0>"||" return (DT_TOK_LOR);
<S0>"==" return (DT_TOK_EQU);
<S0>"!=" return (DT_TOK_NEQ);
<S0>"<" return (DT_TOK_LT);
<S0>"<=" return (DT_TOK_LE);
<S0>">" return (DT_TOK_GT);
<S0>">=" return (DT_TOK_GE);
<S0>"<<" return (DT_TOK_LSH);
<S0>">>" return (DT_TOK_RSH);
<S0>"+" return (DT_TOK_ADD);
<S0>"-" return (DT_TOK_SUB);
<S0>"*" return (DT_TOK_MUL);
<S0>"%" return (DT_TOK_MOD);
<S0>"~" return (DT_TOK_BNEG);
<S0>"!" return (DT_TOK_LNEG);
<S0>"?" return (DT_TOK_QUESTION);
<S0>":" return (DT_TOK_COLON);
<S0>"." return (DT_TOK_DOT);
<S0>"->" return (DT_TOK_PTR);
<S0>"=" return (DT_TOK_ASGN);
<S0>"+=" return (DT_TOK_ADD_EQ);
<S0>"-=" return (DT_TOK_SUB_EQ);
<S0>"*=" return (DT_TOK_MUL_EQ);
<S0>"/=" return (DT_TOK_DIV_EQ);
<S0>"%=" return (DT_TOK_MOD_EQ);
<S0>"&=" return (DT_TOK_AND_EQ);
<S0>"^=" return (DT_TOK_XOR_EQ);
<S0>"|=" return (DT_TOK_OR_EQ);
<S0>"<<=" return (DT_TOK_LSH_EQ);
<S0>">>=" return (DT_TOK_RSH_EQ);
<S0>"++" return (DT_TOK_ADDADD);
<S0>"--" return (DT_TOK_SUBSUB);
<S0>"..." return (DT_TOK_ELLIPSIS);
<S0>"," return (DT_TOK_COMMA);
<S0>";" return (';');
<S0>{RGX_WS} ; /* discard */
<S0>"\\"\n ; /* discard */
<S0>. yyerror("syntax error near \"%c\"\n", yytext[0]);
<S1>"/*" yyerror("/* encountered inside a comment\n");
<S1>"*/" BEGIN(yypcb->pcb_cstate);
<S1>.|\n ; /* discard */
<S2>{RGX_PSPEC} {
/*
* S2 has an ambiguity because RGX_PSPEC includes '*'
* as a glob character and '*' also can be DT_TOK_STAR.
* Since lex always matches the longest token, this
* rule can be matched by an input string like "int*",
* which could begin a global variable declaration such
* as "int*x;" or could begin a RGX_PSPEC with globbing
* such as "int* { trace(timestamp); }". If C_PSPEC is
* not set, we must resolve the ambiguity in favor of
* the type and perform lexer pushback if the fragment
* before '*' or entire fragment matches a type name.
* If C_PSPEC is set, we always return a PSPEC token.
* If C_PSPEC is off, the user can avoid ambiguity by
* including a ':' delimiter in the specifier, which
* they should be doing anyway to specify the provider.
*/
if (!(yypcb->pcb_cflags & DTRACE_C_PSPEC) &&
strchr(yytext, ':') == NULL) {
char *p = strchr(yytext, '*');
char *q = yytext + yyleng - 1;
if (p != NULL && p > yytext)
*p = '\0'; /* prune yytext */
if (dt_type_lookup(yytext, NULL) == 0) {
yylval.l_str = strdup(yytext);
if (yylval.l_str == NULL) {
longjmp(yypcb->pcb_jmpbuf,
EDT_NOMEM);
}
if (p != NULL && p > yytext) {
for (*p = '*'; q >= p; q--)
unput(*q);
}
yybegin(YYS_EXPR);
return (DT_TOK_TNAME);
}
if (p != NULL && p > yytext)
*p = '*'; /* restore yytext */
}
if ((yylval.l_str = strdup(yytext)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
return (DT_TOK_PSPEC);
}
<S2>"/" return (DT_TOK_DIV);
<S2>"," return (DT_TOK_COMMA);
<S2>{RGX_WS} ; /* discard */
<S2>. yyerror("syntax error near \"%c\"\n", yytext[0]);
<S3>\n {
dt_pragma(yypragma);
yypragma = NULL;
BEGIN(yypcb->pcb_cstate);
}
<S3>[\f\t\v ]+ ; /* discard */
<S3>[^\f\n\t\v "]+ {
dt_node_t *dnp;
if ((yylval.l_str = strdup(yytext)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
/*
* We want to call dt_node_ident() here, but we can't
* because it will expand inlined identifiers, which we
* don't want to do from #pragma context in order to
* support pragmas that apply to the ident itself. We
* call dt_node_string() and then reset dn_op instead.
*/
dnp = dt_node_string(yylval.l_str);
dnp->dn_kind = DT_NODE_IDENT;
dnp->dn_op = DT_TOK_IDENT;
yypragma = dt_node_link(yypragma, dnp);
}
<S3>. yyerror("syntax error near \"%c\"\n", yytext[0]);
%%
/*
* yybegin provides a wrapper for use from C code around the lex BEGIN() macro.
* We use two main states for lexing because probe descriptions use a syntax
* that is incompatible with the normal D tokens (e.g. names can contain "-").
* yybegin also handles the job of switching between two lists of dt_nodes
* as we allocate persistent definitions, like inlines, and transient nodes
* that will be freed once we are done parsing the current program file.
*/
void
yybegin(yystate_t state)
{
#ifdef YYDEBUG
yydebug = _dtrace_debug;
#endif
if (yypcb->pcb_yystate == state)
return; /* nothing to do if we're in the state already */
if (yypcb->pcb_yystate == YYS_DEFINE) {
yypcb->pcb_list = yypcb->pcb_hold;
yypcb->pcb_hold = NULL;
}
switch (state) {
case YYS_CLAUSE:
BEGIN(S2);
break;
case YYS_DEFINE:
assert(yypcb->pcb_hold == NULL);
yypcb->pcb_hold = yypcb->pcb_list;
yypcb->pcb_list = NULL;
/*FALLTHRU*/
case YYS_EXPR:
BEGIN(S0);
break;
case YYS_DONE:
break;
case YYS_CONTROL:
BEGIN(S4);
break;
default:
xyerror(D_UNKNOWN, "internal error -- bad yystate %d\n", state);
}
yypcb->pcb_yystate = state;
}
void
yyinit(dt_pcb_t *pcb)
{
yypcb = pcb;
yylineno = 1;
yypragma = NULL;
#if defined(sun)
yysptr = yysbuf;
#endif
}
/*
* Given a lexeme 's' (typically yytext), set yylval and return an appropriate
* token to the parser indicating either an identifier or a typedef name.
* User-defined global variables always take precedence over types, but we do
* use some heuristics because D programs can look at an ever-changing set of
* kernel types and also can implicitly instantiate variables by assignment,
* unlike in C. The code here is ordered carefully as lookups are not cheap.
*/
static int
id_or_type(const char *s)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dt_decl_t *ddp = yypcb->pcb_dstack.ds_decl;
int c0, c1, ttok = DT_TOK_TNAME;
dt_ident_t *idp;
if ((s = yylval.l_str = strdup(s)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
/*
* If the lexeme is a global variable or likely identifier or *not* a
* type_name, then it is an identifier token.
*/
if (dt_idstack_lookup(&yypcb->pcb_globals, s) != NULL ||
dt_idhash_lookup(yypcb->pcb_idents, s) != NULL ||
dt_type_lookup(s, NULL) != 0)
return (DT_TOK_IDENT);
/*
* If we're in the midst of parsing a declaration and a type_specifier
* has already been shifted, then return DT_TOK_IDENT instead of TNAME.
* This semantic is necessary to permit valid ISO C code such as:
*
* typedef int foo;
* struct s { foo foo; };
*
* without causing shift/reduce conflicts in the direct_declarator part
* of the grammar. The result is that we must check for conflicting
* redeclarations of the same identifier as part of dt_node_decl().
*/
if (ddp != NULL && ddp->dd_name != NULL)
return (DT_TOK_IDENT);
/*
* If the lexeme is a type name and we are not in a program clause,
* then always interpret it as a type and return DT_TOK_TNAME.
*/
if ((YYSTATE) != S0)
return (DT_TOK_TNAME);
/*
* If the lexeme matches a type name but is in a program clause, then
* it could be a type or it could be an undefined variable. Peek at
* the next token to decide. If we see ++, --, [, or =, we know there
* might be an assignment that is trying to create a global variable,
* so we optimistically return DT_TOK_IDENT. There is no harm in being
* wrong: a type_name followed by ++, --, [, or = is a syntax error.
*/
while ((c0 = input()) != 0) {
if (strchr("\f\n\r\t\v ", c0) == NULL)
break;
}
switch (c0) {
case '+':
case '-':
if ((c1 = input()) == c0)
ttok = DT_TOK_IDENT;
unput(c1);
break;
case '=':
if ((c1 = input()) != c0)
ttok = DT_TOK_IDENT;
unput(c1);
break;
case '[':
ttok = DT_TOK_IDENT;
break;
}
if (ttok == DT_TOK_IDENT) {
idp = dt_idhash_insert(yypcb->pcb_idents, s, DT_IDENT_SCALAR, 0,
0, _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
if (idp == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
}
unput(c0);
return (ttok);
}
#if defined(sun)
static int
input(void)
{
int c;
if (yysptr > yysbuf)
c = *--yysptr;
else if (yypcb->pcb_fileptr != NULL)
c = fgetc(yypcb->pcb_fileptr);
else if (yypcb->pcb_strptr < yypcb->pcb_string + yypcb->pcb_strlen)
c = *yypcb->pcb_strptr++;
else
c = EOF;
if (c == '\n')
yylineno++;
if (c != EOF)
return (c);
if ((YYSTATE) == S1)
yyerror("end-of-file encountered before matching */\n");
if ((YYSTATE) == S3)
yyerror("end-of-file encountered before end of control line\n");
if (yypcb->pcb_fileptr != NULL && ferror(yypcb->pcb_fileptr))
longjmp(yypcb->pcb_jmpbuf, EDT_FIO);
return (0); /* EOF */
}
static void
unput(int c)
{
if (c == '\n')
yylineno--;
*yysptr++ = c;
yytchar = c;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,111 @@
/*
* 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
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Simple doubly-linked list implementation. This implementation assumes that
* each list element contains an embedded dt_list_t (previous and next
* pointers), which is typically the first member of the element struct.
* An additional dt_list_t is used to store the head (dl_next) and tail
* (dl_prev) pointers. The current head and tail list elements have their
* previous and next pointers set to NULL, respectively.
*/
#include <unistd.h>
#include <assert.h>
#include <dt_list.h>
void
dt_list_append(dt_list_t *dlp, void *new)
{
dt_list_t *p = dlp->dl_prev; /* p = tail list element */
dt_list_t *q = new; /* q = new list element */
dlp->dl_prev = q;
q->dl_prev = p;
q->dl_next = NULL;
if (p != NULL) {
assert(p->dl_next == NULL);
p->dl_next = q;
} else {
assert(dlp->dl_next == NULL);
dlp->dl_next = q;
}
}
void
dt_list_prepend(dt_list_t *dlp, void *new)
{
dt_list_t *p = new; /* p = new list element */
dt_list_t *q = dlp->dl_next; /* q = head list element */
dlp->dl_next = p;
p->dl_prev = NULL;
p->dl_next = q;
if (q != NULL) {
assert(q->dl_prev == NULL);
q->dl_prev = p;
} else {
assert(dlp->dl_prev == NULL);
dlp->dl_prev = p;
}
}
void
dt_list_insert(dt_list_t *dlp, void *after_me, void *new)
{
dt_list_t *p = after_me;
dt_list_t *q = new;
if (p == NULL || p->dl_next == NULL) {
dt_list_append(dlp, new);
return;
}
q->dl_next = p->dl_next;
q->dl_prev = p;
p->dl_next = q;
q->dl_next->dl_prev = q;
}
void
dt_list_delete(dt_list_t *dlp, void *existing)
{
dt_list_t *p = existing;
if (p->dl_prev != NULL)
p->dl_prev->dl_next = p->dl_next;
else
dlp->dl_next = p->dl_next;
if (p->dl_next != NULL)
p->dl_next->dl_prev = p->dl_prev;
else
dlp->dl_prev = p->dl_prev;
}

View File

@ -0,0 +1,53 @@
/*
* 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
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_LIST_H
#define _DT_LIST_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_list {
struct dt_list *dl_prev;
struct dt_list *dl_next;
} dt_list_t;
#define dt_list_prev(elem) ((void *)(((dt_list_t *)(elem))->dl_prev))
#define dt_list_next(elem) ((void *)(((dt_list_t *)(elem))->dl_next))
extern void dt_list_append(dt_list_t *, void *);
extern void dt_list_prepend(dt_list_t *, void *);
extern void dt_list_insert(dt_list_t *, void *, void *);
extern void dt_list_delete(dt_list_t *, void *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_LIST_H */

View File

@ -0,0 +1,442 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <dt_impl.h>
#include <dt_printf.h>
static int
dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
{
dtrace_id_t max;
int rval, i, maxformat;
dtrace_eprobedesc_t *enabled, *nenabled;
dtrace_probedesc_t *probe;
while (id >= (max = dtp->dt_maxprobe) || dtp->dt_pdesc == NULL) {
dtrace_id_t new_max = max ? (max << 1) : 1;
size_t nsize = new_max * sizeof (void *);
dtrace_probedesc_t **new_pdesc;
dtrace_eprobedesc_t **new_edesc;
if ((new_pdesc = malloc(nsize)) == NULL ||
(new_edesc = malloc(nsize)) == NULL) {
free(new_pdesc);
return (dt_set_errno(dtp, EDT_NOMEM));
}
bzero(new_pdesc, nsize);
bzero(new_edesc, nsize);
if (dtp->dt_pdesc != NULL) {
size_t osize = max * sizeof (void *);
bcopy(dtp->dt_pdesc, new_pdesc, osize);
free(dtp->dt_pdesc);
bcopy(dtp->dt_edesc, new_edesc, osize);
free(dtp->dt_edesc);
}
dtp->dt_pdesc = new_pdesc;
dtp->dt_edesc = new_edesc;
dtp->dt_maxprobe = new_max;
}
if (dtp->dt_pdesc[id] != NULL)
return (0);
if ((enabled = malloc(sizeof (dtrace_eprobedesc_t))) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
bzero(enabled, sizeof (dtrace_eprobedesc_t));
enabled->dtepd_epid = id;
enabled->dtepd_nrecs = 1;
#if defined(sun)
if (dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled) == -1) {
#else
if (dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled) == -1) {
#endif
rval = dt_set_errno(dtp, errno);
free(enabled);
return (rval);
}
if (DTRACE_SIZEOF_EPROBEDESC(enabled) != sizeof (*enabled)) {
/*
* There must be more than one action. Allocate the
* appropriate amount of space and try again.
*/
if ((nenabled =
malloc(DTRACE_SIZEOF_EPROBEDESC(enabled))) != NULL)
bcopy(enabled, nenabled, sizeof (*enabled));
free(enabled);
if ((enabled = nenabled) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
#if defined(sun)
rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, enabled);
#else
rval = dt_ioctl(dtp, DTRACEIOC_EPROBE, &enabled);
#endif
if (rval == -1) {
rval = dt_set_errno(dtp, errno);
free(enabled);
return (rval);
}
}
if ((probe = malloc(sizeof (dtrace_probedesc_t))) == NULL) {
free(enabled);
return (dt_set_errno(dtp, EDT_NOMEM));
}
probe->dtpd_id = enabled->dtepd_probeid;
if (dt_ioctl(dtp, DTRACEIOC_PROBES, probe) == -1) {
rval = dt_set_errno(dtp, errno);
goto err;
}
for (i = 0; i < enabled->dtepd_nrecs; i++) {
dtrace_fmtdesc_t fmt;
dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
continue;
if (rec->dtrd_format == 0)
continue;
if (rec->dtrd_format <= dtp->dt_maxformat &&
dtp->dt_formats[rec->dtrd_format - 1] != NULL)
continue;
bzero(&fmt, sizeof (fmt));
fmt.dtfd_format = rec->dtrd_format;
fmt.dtfd_string = NULL;
fmt.dtfd_length = 0;
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
rval = dt_set_errno(dtp, errno);
goto err;
}
if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
rval = dt_set_errno(dtp, EDT_NOMEM);
goto err;
}
if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
rval = dt_set_errno(dtp, errno);
free(fmt.dtfd_string);
goto err;
}
while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
int new_max = maxformat ? (maxformat << 1) : 1;
size_t nsize = new_max * sizeof (void *);
size_t osize = maxformat * sizeof (void *);
void **new_formats = malloc(nsize);
if (new_formats == NULL) {
rval = dt_set_errno(dtp, EDT_NOMEM);
free(fmt.dtfd_string);
goto err;
}
bzero(new_formats, nsize);
bcopy(dtp->dt_formats, new_formats, osize);
free(dtp->dt_formats);
dtp->dt_formats = new_formats;
dtp->dt_maxformat = new_max;
}
dtp->dt_formats[rec->dtrd_format - 1] =
rec->dtrd_action == DTRACEACT_PRINTA ?
dtrace_printa_create(dtp, fmt.dtfd_string) :
dtrace_printf_create(dtp, fmt.dtfd_string);
free(fmt.dtfd_string);
if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
rval = -1; /* dt_errno is set for us */
goto err;
}
}
dtp->dt_pdesc[id] = probe;
dtp->dt_edesc[id] = enabled;
return (0);
err:
/*
* If we failed, free our allocated probes. Note that if we failed
* while allocating formats, we aren't going to free formats that
* we have already allocated. This is okay; these formats are
* hanging off of dt_formats and will therefore not be leaked.
*/
free(enabled);
free(probe);
return (rval);
}
int
dt_epid_lookup(dtrace_hdl_t *dtp, dtrace_epid_t epid,
dtrace_eprobedesc_t **epdp, dtrace_probedesc_t **pdp)
{
int rval;
if (epid >= dtp->dt_maxprobe || dtp->dt_pdesc[epid] == NULL) {
if ((rval = dt_epid_add(dtp, epid)) != 0)
return (rval);
}
assert(epid < dtp->dt_maxprobe);
assert(dtp->dt_edesc[epid] != NULL);
assert(dtp->dt_pdesc[epid] != NULL);
*epdp = dtp->dt_edesc[epid];
*pdp = dtp->dt_pdesc[epid];
return (0);
}
void
dt_epid_destroy(dtrace_hdl_t *dtp)
{
size_t i;
assert((dtp->dt_pdesc != NULL && dtp->dt_edesc != NULL &&
dtp->dt_maxprobe > 0) || (dtp->dt_pdesc == NULL &&
dtp->dt_edesc == NULL && dtp->dt_maxprobe == 0));
if (dtp->dt_pdesc == NULL)
return;
for (i = 0; i < dtp->dt_maxprobe; i++) {
if (dtp->dt_edesc[i] == NULL) {
assert(dtp->dt_pdesc[i] == NULL);
continue;
}
assert(dtp->dt_pdesc[i] != NULL);
free(dtp->dt_edesc[i]);
free(dtp->dt_pdesc[i]);
}
free(dtp->dt_pdesc);
dtp->dt_pdesc = NULL;
free(dtp->dt_edesc);
dtp->dt_edesc = NULL;
dtp->dt_maxprobe = 0;
}
void *
dt_format_lookup(dtrace_hdl_t *dtp, int format)
{
if (format == 0 || format > dtp->dt_maxformat)
return (NULL);
if (dtp->dt_formats == NULL)
return (NULL);
return (dtp->dt_formats[format - 1]);
}
void
dt_format_destroy(dtrace_hdl_t *dtp)
{
int i;
for (i = 0; i < dtp->dt_maxformat; i++) {
if (dtp->dt_formats[i] != NULL)
dt_printf_destroy(dtp->dt_formats[i]);
}
free(dtp->dt_formats);
dtp->dt_formats = NULL;
}
static int
dt_aggid_add(dtrace_hdl_t *dtp, dtrace_aggid_t id)
{
dtrace_id_t max;
dtrace_epid_t epid;
int rval;
while (id >= (max = dtp->dt_maxagg) || dtp->dt_aggdesc == NULL) {
dtrace_id_t new_max = max ? (max << 1) : 1;
size_t nsize = new_max * sizeof (void *);
dtrace_aggdesc_t **new_aggdesc;
if ((new_aggdesc = malloc(nsize)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
bzero(new_aggdesc, nsize);
if (dtp->dt_aggdesc != NULL) {
bcopy(dtp->dt_aggdesc, new_aggdesc,
max * sizeof (void *));
free(dtp->dt_aggdesc);
}
dtp->dt_aggdesc = new_aggdesc;
dtp->dt_maxagg = new_max;
}
if (dtp->dt_aggdesc[id] == NULL) {
dtrace_aggdesc_t *agg, *nagg;
if ((agg = malloc(sizeof (dtrace_aggdesc_t))) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
bzero(agg, sizeof (dtrace_aggdesc_t));
agg->dtagd_id = id;
agg->dtagd_nrecs = 1;
#if defined(sun)
if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg) == -1) {
#else
if (dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg) == -1) {
#endif
rval = dt_set_errno(dtp, errno);
free(agg);
return (rval);
}
if (DTRACE_SIZEOF_AGGDESC(agg) != sizeof (*agg)) {
/*
* There must be more than one action. Allocate the
* appropriate amount of space and try again.
*/
if ((nagg = malloc(DTRACE_SIZEOF_AGGDESC(agg))) != NULL)
bcopy(agg, nagg, sizeof (*agg));
free(agg);
if ((agg = nagg) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
#if defined(sun)
rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, agg);
#else
rval = dt_ioctl(dtp, DTRACEIOC_AGGDESC, &agg);
#endif
if (rval == -1) {
rval = dt_set_errno(dtp, errno);
free(agg);
return (rval);
}
}
/*
* If we have a uarg, it's a pointer to the compiler-generated
* statement; we'll use this value to get the name and
* compiler-generated variable ID for the aggregation. If
* we're grabbing an anonymous enabling, this pointer value
* is obviously meaningless -- and in this case, we can't
* provide the compiler-generated aggregation information.
*/
if (dtp->dt_options[DTRACEOPT_GRABANON] == DTRACEOPT_UNSET &&
agg->dtagd_rec[0].dtrd_uarg != 0) {
dtrace_stmtdesc_t *sdp;
dt_ident_t *aid;
sdp = (dtrace_stmtdesc_t *)(uintptr_t)
agg->dtagd_rec[0].dtrd_uarg;
aid = sdp->dtsd_aggdata;
agg->dtagd_name = aid->di_name;
agg->dtagd_varid = aid->di_id;
} else {
agg->dtagd_varid = DTRACE_AGGVARIDNONE;
}
if ((epid = agg->dtagd_epid) >= dtp->dt_maxprobe ||
dtp->dt_pdesc[epid] == NULL) {
if ((rval = dt_epid_add(dtp, epid)) != 0) {
free(agg);
return (rval);
}
}
dtp->dt_aggdesc[id] = agg;
}
return (0);
}
int
dt_aggid_lookup(dtrace_hdl_t *dtp, dtrace_aggid_t aggid,
dtrace_aggdesc_t **adp)
{
int rval;
if (aggid >= dtp->dt_maxagg || dtp->dt_aggdesc[aggid] == NULL) {
if ((rval = dt_aggid_add(dtp, aggid)) != 0)
return (rval);
}
assert(aggid < dtp->dt_maxagg);
assert(dtp->dt_aggdesc[aggid] != NULL);
*adp = dtp->dt_aggdesc[aggid];
return (0);
}
void
dt_aggid_destroy(dtrace_hdl_t *dtp)
{
size_t i;
assert((dtp->dt_aggdesc != NULL && dtp->dt_maxagg != 0) ||
(dtp->dt_aggdesc == NULL && dtp->dt_maxagg == 0));
if (dtp->dt_aggdesc == NULL)
return;
for (i = 0; i < dtp->dt_maxagg; i++) {
if (dtp->dt_aggdesc[i] != NULL)
free(dtp->dt_aggdesc[i]);
}
free(dtp->dt_aggdesc);
dtp->dt_aggdesc = NULL;
dtp->dt_maxagg = 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
/*
* 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
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_MODULE_H
#define _DT_MODULE_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dt_impl.h>
#ifdef __cplusplus
extern "C" {
#endif
extern dt_module_t *dt_module_create(dtrace_hdl_t *, const char *);
extern int dt_module_load(dtrace_hdl_t *, dt_module_t *);
extern void dt_module_unload(dtrace_hdl_t *, dt_module_t *);
extern void dt_module_destroy(dtrace_hdl_t *, dt_module_t *);
extern dt_module_t *dt_module_lookup_by_name(dtrace_hdl_t *, const char *);
extern dt_module_t *dt_module_lookup_by_ctf(dtrace_hdl_t *, ctf_file_t *);
extern ctf_file_t *dt_module_getctf(dtrace_hdl_t *, dt_module_t *);
extern dt_ident_t *dt_module_extern(dtrace_hdl_t *, dt_module_t *,
const char *, const dtrace_typeinfo_t *);
extern const char *dt_module_modelname(dt_module_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_MODULE_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,285 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PARSER_H
#define _DT_PARSER_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/dtrace.h>
#include <libctf.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <dt_errtags.h>
#include <dt_ident.h>
#include <dt_decl.h>
#include <dt_xlator.h>
#include <dt_list.h>
typedef struct dt_node {
ctf_file_t *dn_ctfp; /* CTF type container for node's type */
ctf_id_t dn_type; /* CTF type reference for node's type */
uchar_t dn_kind; /* node kind (DT_NODE_*, defined below) */
uchar_t dn_flags; /* node flags (DT_NF_*, defined below) */
ushort_t dn_op; /* operator (DT_TOK_*, defined by lex) */
int dn_line; /* line number for error messages */
int dn_reg; /* register allocated by cg */
dtrace_attribute_t dn_attr; /* node stability attributes */
/*
* D compiler nodes, as is the usual style, contain a union of the
* different sub-elements required by the various kinds of nodes.
* These sub-elements are accessed using the macros defined below.
*/
union {
struct {
uintmax_t _value; /* integer value */
char *_string; /* string value */
} _const;
struct {
dt_ident_t *_ident; /* identifier reference */
struct dt_node *_links[3]; /* child node pointers */
} _nodes;
struct {
struct dt_node *_descs; /* list of descriptions */
struct dt_node *_pred; /* predicate expression */
struct dt_node *_acts; /* action statement list */
dt_idhash_t *_locals; /* local variable hash */
dtrace_attribute_t _attr; /* context attributes */
} _clause;
struct {
char *_spec; /* specifier string (if any) */
dtrace_probedesc_t *_desc; /* final probe description */
} _pdesc;
struct {
char *_name; /* string name of member */
struct dt_node *_expr; /* expression node pointer */
dt_xlator_t *_xlator; /* translator reference */
uint_t _id; /* member identifier */
} _member;
struct {
dt_xlator_t *_xlator; /* translator reference */
struct dt_node *_xmemb; /* individual xlator member */
struct dt_node *_membs; /* list of member nodes */
} _xlator;
struct {
char *_name; /* string name of provider */
struct dt_provider *_pvp; /* provider references */
struct dt_node *_probes; /* list of probe nodes */
int _redecl; /* provider redeclared */
} _provider;
} dn_u;
struct dt_node *dn_list; /* parse tree list link */
struct dt_node *dn_link; /* allocation list link */
} dt_node_t;
#define dn_value dn_u._const._value /* DT_NODE_INT */
#define dn_string dn_u._const._string /* STRING, IDENT, TYPE */
#define dn_ident dn_u._nodes._ident /* VAR,SYM,FUN,AGG,INL,PROBE */
#define dn_args dn_u._nodes._links[0] /* DT_NODE_VAR, FUNC */
#define dn_child dn_u._nodes._links[0] /* DT_NODE_OP1 */
#define dn_left dn_u._nodes._links[0] /* DT_NODE_OP2, OP3 */
#define dn_right dn_u._nodes._links[1] /* DT_NODE_OP2, OP3 */
#define dn_expr dn_u._nodes._links[2] /* DT_NODE_OP3, DEXPR */
#define dn_aggfun dn_u._nodes._links[0] /* DT_NODE_AGG */
#define dn_aggtup dn_u._nodes._links[1] /* DT_NODE_AGG */
#define dn_pdescs dn_u._clause._descs /* DT_NODE_CLAUSE */
#define dn_pred dn_u._clause._pred /* DT_NODE_CLAUSE */
#define dn_acts dn_u._clause._acts /* DT_NODE_CLAUSE */
#define dn_locals dn_u._clause._locals /* DT_NODE_CLAUSE */
#define dn_ctxattr dn_u._clause._attr /* DT_NODE_CLAUSE */
#define dn_spec dn_u._pdesc._spec /* DT_NODE_PDESC */
#define dn_desc dn_u._pdesc._desc /* DT_NODE_PDESC */
#define dn_membname dn_u._member._name /* DT_NODE_MEMBER */
#define dn_membexpr dn_u._member._expr /* DT_NODE_MEMBER */
#define dn_membxlator dn_u._member._xlator /* DT_NODE_MEMBER */
#define dn_membid dn_u._member._id /* DT_NODE_MEMBER */
#define dn_xlator dn_u._xlator._xlator /* DT_NODE_XLATOR */
#define dn_xmember dn_u._xlator._xmemb /* DT_NODE_XLATOR */
#define dn_members dn_u._xlator._membs /* DT_NODE_XLATOR */
#define dn_provname dn_u._provider._name /* DT_NODE_PROVIDER */
#define dn_provider dn_u._provider._pvp /* DT_NODE_PROVIDER */
#define dn_provred dn_u._provider._redecl /* DT_NODE_PROVIDER */
#define dn_probes dn_u._provider._probes /* DT_NODE_PROVIDER */
#define DT_NODE_FREE 0 /* unused node (waiting to be freed) */
#define DT_NODE_INT 1 /* integer value */
#define DT_NODE_STRING 2 /* string value */
#define DT_NODE_IDENT 3 /* identifier */
#define DT_NODE_VAR 4 /* variable reference */
#define DT_NODE_SYM 5 /* symbol reference */
#define DT_NODE_TYPE 6 /* type reference or formal parameter */
#define DT_NODE_FUNC 7 /* function call */
#define DT_NODE_OP1 8 /* unary operator */
#define DT_NODE_OP2 9 /* binary operator */
#define DT_NODE_OP3 10 /* ternary operator */
#define DT_NODE_DEXPR 11 /* D expression action */
#define DT_NODE_DFUNC 12 /* D function action */
#define DT_NODE_AGG 13 /* aggregation */
#define DT_NODE_PDESC 14 /* probe description */
#define DT_NODE_CLAUSE 15 /* clause definition */
#define DT_NODE_INLINE 16 /* inline definition */
#define DT_NODE_MEMBER 17 /* member definition */
#define DT_NODE_XLATOR 18 /* translator definition */
#define DT_NODE_PROBE 19 /* probe definition */
#define DT_NODE_PROVIDER 20 /* provider definition */
#define DT_NODE_PROG 21 /* program translation unit */
#define DT_NF_SIGNED 0x01 /* data is a signed quantity (else unsigned) */
#define DT_NF_COOKED 0x02 /* data is a known type (else still cooking) */
#define DT_NF_REF 0x04 /* pass by reference (array, struct, union) */
#define DT_NF_LVALUE 0x08 /* node is an l-value according to ANSI-C */
#define DT_NF_WRITABLE 0x10 /* node is writable (can be modified) */
#define DT_NF_BITFIELD 0x20 /* node is an integer bitfield */
#define DT_NF_USERLAND 0x40 /* data is a userland address */
#define DT_TYPE_NAMELEN 128 /* reasonable size for ctf_type_name() */
extern int dt_node_is_integer(const dt_node_t *);
extern int dt_node_is_float(const dt_node_t *);
extern int dt_node_is_scalar(const dt_node_t *);
extern int dt_node_is_arith(const dt_node_t *);
extern int dt_node_is_vfptr(const dt_node_t *);
extern int dt_node_is_dynamic(const dt_node_t *);
extern int dt_node_is_stack(const dt_node_t *);
extern int dt_node_is_symaddr(const dt_node_t *);
extern int dt_node_is_usymaddr(const dt_node_t *);
extern int dt_node_is_string(const dt_node_t *);
extern int dt_node_is_strcompat(const dt_node_t *);
extern int dt_node_is_pointer(const dt_node_t *);
extern int dt_node_is_void(const dt_node_t *);
extern int dt_node_is_ptrcompat(const dt_node_t *, const dt_node_t *,
ctf_file_t **, ctf_id_t *);
extern int dt_node_is_argcompat(const dt_node_t *, const dt_node_t *);
extern int dt_node_is_posconst(const dt_node_t *);
extern int dt_node_is_actfunc(const dt_node_t *);
extern dt_node_t *dt_node_int(uintmax_t);
extern dt_node_t *dt_node_string(char *);
extern dt_node_t *dt_node_ident(char *);
extern dt_node_t *dt_node_type(dt_decl_t *);
extern dt_node_t *dt_node_vatype(void);
extern dt_node_t *dt_node_decl(void);
extern dt_node_t *dt_node_func(dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_offsetof(dt_decl_t *, char *);
extern dt_node_t *dt_node_op1(int, dt_node_t *);
extern dt_node_t *dt_node_op2(int, dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_op3(dt_node_t *, dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_statement(dt_node_t *);
extern dt_node_t *dt_node_pdesc_by_name(char *);
extern dt_node_t *dt_node_pdesc_by_id(uintmax_t);
extern dt_node_t *dt_node_clause(dt_node_t *, dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_inline(dt_node_t *);
extern dt_node_t *dt_node_member(dt_decl_t *, char *, dt_node_t *);
extern dt_node_t *dt_node_xlator(dt_decl_t *, dt_decl_t *, char *, dt_node_t *);
extern dt_node_t *dt_node_probe(char *, int, dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_provider(char *, dt_node_t *);
extern dt_node_t *dt_node_program(dt_node_t *);
extern dt_node_t *dt_node_link(dt_node_t *, dt_node_t *);
extern dt_node_t *dt_node_cook(dt_node_t *, uint_t);
extern dt_node_t *dt_node_xalloc(dtrace_hdl_t *, int);
extern void dt_node_free(dt_node_t *);
extern dtrace_attribute_t dt_node_list_cook(dt_node_t **, uint_t);
extern void dt_node_list_free(dt_node_t **);
extern void dt_node_link_free(dt_node_t **);
extern void dt_node_attr_assign(dt_node_t *, dtrace_attribute_t);
extern void dt_node_type_assign(dt_node_t *, ctf_file_t *, ctf_id_t);
extern void dt_node_type_propagate(const dt_node_t *, dt_node_t *);
extern const char *dt_node_type_name(const dt_node_t *, char *, size_t);
extern size_t dt_node_type_size(const dt_node_t *);
extern dt_ident_t *dt_node_resolve(const dt_node_t *, uint_t);
extern size_t dt_node_sizeof(const dt_node_t *);
extern void dt_node_promote(dt_node_t *, dt_node_t *, dt_node_t *);
extern void dt_node_diftype(dtrace_hdl_t *,
const dt_node_t *, dtrace_diftype_t *);
extern void dt_node_printr(dt_node_t *, FILE *, int);
extern const char *dt_node_name(const dt_node_t *, char *, size_t);
extern int dt_node_root(dt_node_t *);
struct dtrace_typeinfo; /* see <dtrace.h> */
struct dt_pcb; /* see <dt_impl.h> */
#define IS_CHAR(e) \
(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
#define IS_VOID(e) \
((e).cte_offset == 0 && (e).cte_bits == 0)
extern int dt_type_lookup(const char *, struct dtrace_typeinfo *);
extern int dt_type_pointer(struct dtrace_typeinfo *);
extern const char *dt_type_name(ctf_file_t *, ctf_id_t, char *, size_t);
typedef enum {
YYS_CLAUSE, /* lex/yacc state for finding program clauses */
YYS_DEFINE, /* lex/yacc state for parsing persistent definitions */
YYS_EXPR, /* lex/yacc state for parsing D expressions */
YYS_DONE, /* lex/yacc state for indicating parse tree is done */
YYS_CONTROL /* lex/yacc state for parsing control lines */
} yystate_t;
extern void dnerror(const dt_node_t *, dt_errtag_t, const char *, ...);
extern void dnwarn(const dt_node_t *, dt_errtag_t, const char *, ...);
extern void xyerror(dt_errtag_t, const char *, ...);
extern void xywarn(dt_errtag_t, const char *, ...);
extern void xyvwarn(dt_errtag_t, const char *, va_list);
extern void yyerror(const char *, ...);
extern void yywarn(const char *, ...);
extern void yyvwarn(const char *, va_list);
extern void yylabel(const char *);
extern void yybegin(yystate_t);
extern void yyinit(struct dt_pcb *);
extern int yyparse(void);
extern int yyinput(void);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PARSER_H */

View File

@ -0,0 +1,187 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* DTrace Parsing Control Block
*
* A DTrace Parsing Control Block (PCB) contains all of the state that is used
* by a single pass of the D compiler, other than the global variables used by
* lex and yacc. The routines in this file are used to set up and tear down
* PCBs, which are kept on a stack pointed to by the libdtrace global 'yypcb'.
* The main engine of the compiler, dt_compile(), is located in dt_cc.c and is
* responsible for calling these routines to begin and end a compilation pass.
*
* Sun's lex/yacc are not MT-safe or re-entrant, but we permit limited nested
* use of dt_compile() once the entire parse tree has been constructed but has
* not yet executed the "cooking" pass (see dt_cc.c for more information). The
* PCB design also makes it easier to debug (since all global state is kept in
* one place) and could permit us to make the D compiler MT-safe or re-entrant
* in the future by adding locks to libdtrace or switching to Flex and Bison.
*/
#include <strings.h>
#include <stdlib.h>
#include <assert.h>
#include <dt_impl.h>
#include <dt_program.h>
#include <dt_provider.h>
#include <dt_pcb.h>
/*
* Initialize the specified PCB by zeroing it and filling in a few default
* members, and then pushing it on to the top of the PCB stack and setting
* yypcb to point to it. Increment the current handle's generation count.
*/
void
dt_pcb_push(dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
/*
* Since lex/yacc are not re-entrant and we don't implement state save,
* assert that if another PCB is active, it is from the same handle and
* has completed execution of yyparse(). If the first assertion fires,
* the caller is calling libdtrace without proper MT locking. If the
* second assertion fires, dt_compile() is being called recursively
* from an illegal location in libdtrace, or a dt_pcb_pop() is missing.
*/
if (yypcb != NULL) {
assert(yypcb->pcb_hdl == dtp);
assert(yypcb->pcb_yystate == YYS_DONE);
}
bzero(pcb, sizeof (dt_pcb_t));
dt_scope_create(&pcb->pcb_dstack);
dt_idstack_push(&pcb->pcb_globals, dtp->dt_globals);
dt_irlist_create(&pcb->pcb_ir);
pcb->pcb_hdl = dtp;
pcb->pcb_prev = dtp->dt_pcb;
dtp->dt_pcb = pcb;
dtp->dt_gen++;
yyinit(pcb);
}
static int
dt_pcb_pop_ident(dt_idhash_t *dhp, dt_ident_t *idp, void *arg)
{
dtrace_hdl_t *dtp = arg;
if (idp->di_gen == dtp->dt_gen)
dt_idhash_delete(dhp, idp);
return (0);
}
/*
* Pop the topmost PCB from the PCB stack and destroy any data structures that
* are associated with it. If 'err' is non-zero, destroy any intermediate
* state that is left behind as part of a compilation that has failed.
*/
void
dt_pcb_pop(dtrace_hdl_t *dtp, int err)
{
dt_pcb_t *pcb = yypcb;
uint_t i;
assert(pcb != NULL);
assert(pcb == dtp->dt_pcb);
while (pcb->pcb_dstack.ds_next != NULL)
(void) dt_scope_pop();
dt_scope_destroy(&pcb->pcb_dstack);
dt_irlist_destroy(&pcb->pcb_ir);
dt_node_link_free(&pcb->pcb_list);
dt_node_link_free(&pcb->pcb_hold);
if (err != 0) {
dt_xlator_t *dxp, *nxp;
dt_provider_t *pvp, *nvp;
if (pcb->pcb_prog != NULL)
dt_program_destroy(dtp, pcb->pcb_prog);
if (pcb->pcb_stmt != NULL)
dtrace_stmt_destroy(dtp, pcb->pcb_stmt);
if (pcb->pcb_ecbdesc != NULL)
dt_ecbdesc_release(dtp, pcb->pcb_ecbdesc);
for (dxp = dt_list_next(&dtp->dt_xlators); dxp; dxp = nxp) {
nxp = dt_list_next(dxp);
if (dxp->dx_gen == dtp->dt_gen)
dt_xlator_destroy(dtp, dxp);
}
for (pvp = dt_list_next(&dtp->dt_provlist); pvp; pvp = nvp) {
nvp = dt_list_next(pvp);
if (pvp->pv_gen == dtp->dt_gen)
dt_provider_destroy(dtp, pvp);
}
(void) dt_idhash_iter(dtp->dt_aggs, dt_pcb_pop_ident, dtp);
dt_idhash_update(dtp->dt_aggs);
(void) dt_idhash_iter(dtp->dt_globals, dt_pcb_pop_ident, dtp);
dt_idhash_update(dtp->dt_globals);
(void) dt_idhash_iter(dtp->dt_tls, dt_pcb_pop_ident, dtp);
dt_idhash_update(dtp->dt_tls);
(void) ctf_discard(dtp->dt_cdefs->dm_ctfp);
(void) ctf_discard(dtp->dt_ddefs->dm_ctfp);
}
if (pcb->pcb_pragmas != NULL)
dt_idhash_destroy(pcb->pcb_pragmas);
if (pcb->pcb_locals != NULL)
dt_idhash_destroy(pcb->pcb_locals);
if (pcb->pcb_idents != NULL)
dt_idhash_destroy(pcb->pcb_idents);
if (pcb->pcb_inttab != NULL)
dt_inttab_destroy(pcb->pcb_inttab);
if (pcb->pcb_strtab != NULL)
dt_strtab_destroy(pcb->pcb_strtab);
if (pcb->pcb_regs != NULL)
dt_regset_destroy(pcb->pcb_regs);
for (i = 0; i < pcb->pcb_asxreflen; i++)
dt_free(dtp, pcb->pcb_asxrefs[i]);
dt_free(dtp, pcb->pcb_asxrefs);
dt_difo_free(dtp, pcb->pcb_difo);
free(pcb->pcb_filetag);
free(pcb->pcb_sflagv);
dtp->dt_pcb = pcb->pcb_prev;
bzero(pcb, sizeof (dt_pcb_t));
yyinit(dtp->dt_pcb);
}

View File

@ -0,0 +1,103 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PCB_H
#define _DT_PCB_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dtrace.h>
#include <setjmp.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <dt_parser.h>
#include <dt_regset.h>
#include <dt_inttab.h>
#include <dt_strtab.h>
#include <dt_decl.h>
#include <dt_as.h>
typedef struct dt_pcb {
dtrace_hdl_t *pcb_hdl; /* pointer to library handle */
struct dt_pcb *pcb_prev; /* pointer to previous pcb in stack */
FILE *pcb_fileptr; /* pointer to input file (or NULL) */
char *pcb_filetag; /* optional file name string (or NULL) */
const char *pcb_string; /* pointer to input string (or NULL) */
const char *pcb_strptr; /* pointer to input position */
size_t pcb_strlen; /* length of pcb_string */
int pcb_sargc; /* number of script arguments (if any) */
char *const *pcb_sargv; /* script argument strings (if any) */
ushort_t *pcb_sflagv; /* script argument flags (DT_IDFLG_* bits) */
dt_scope_t pcb_dstack; /* declaration processing stack */
dt_node_t *pcb_list; /* list of allocated parse tree nodes */
dt_node_t *pcb_hold; /* parse tree nodes on hold until end of defn */
dt_node_t *pcb_root; /* root of current parse tree */
dt_idstack_t pcb_globals; /* stack of global identifier hash tables */
dt_idhash_t *pcb_locals; /* current hash table of local identifiers */
dt_idhash_t *pcb_idents; /* current hash table of ambiguous idents */
dt_idhash_t *pcb_pragmas; /* current hash table of pending pragmas */
dt_inttab_t *pcb_inttab; /* integer table for constant references */
dt_strtab_t *pcb_strtab; /* string table for string references */
dt_regset_t *pcb_regs; /* register set for code generation */
dt_irlist_t pcb_ir; /* list of unrelocated IR instructions */
uint_t pcb_asvidx; /* assembler vartab index (see dt_as.c) */
ulong_t **pcb_asxrefs; /* assembler imported xlators (see dt_as.c) */
uint_t pcb_asxreflen; /* assembler xlator map length (see dt_as.c) */
const dtrace_probedesc_t *pcb_pdesc; /* probedesc for current context */
struct dt_probe *pcb_probe; /* probe associated with current context */
dtrace_probeinfo_t pcb_pinfo; /* info associated with current context */
dtrace_attribute_t pcb_amin; /* stability minimum for compilation */
dt_node_t *pcb_dret; /* node containing return type for assembler */
dtrace_difo_t *pcb_difo; /* intermediate DIF object made by assembler */
dtrace_prog_t *pcb_prog; /* intermediate program made by compiler */
dtrace_stmtdesc_t *pcb_stmt; /* intermediate stmt made by compiler */
dtrace_ecbdesc_t *pcb_ecbdesc; /* intermediate ecbdesc made by cmplr */
jmp_buf pcb_jmpbuf; /* setjmp(3C) buffer for error return */
const char *pcb_region; /* optional region name for yyerror() suffix */
dtrace_probespec_t pcb_pspec; /* probe description evaluation context */
uint_t pcb_cflags; /* optional compilation flags (see dtrace.h) */
uint_t pcb_idepth; /* preprocessor #include nesting depth */
yystate_t pcb_yystate; /* lex/yacc parsing state (see yybegin()) */
int pcb_context; /* yyparse() rules context (DT_CTX_* value) */
int pcb_token; /* token to be returned by yylex() (if != 0) */
int pcb_cstate; /* state to be restored by lexer at state end */
int pcb_braces; /* number of open curly braces in lexer */
int pcb_brackets; /* number of open square brackets in lexer */
int pcb_parens; /* number of open parentheses in lexer */
} dt_pcb_t;
extern void dt_pcb_push(dtrace_hdl_t *, dt_pcb_t *);
extern void dt_pcb_pop(dtrace_hdl_t *, int);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PCB_H */

View File

@ -0,0 +1,863 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#if defined(sun)
#include <alloca.h>
#endif
#include <libgen.h>
#include <stddef.h>
#include <dt_impl.h>
#include <dt_program.h>
#include <dt_pid.h>
#include <dt_string.h>
typedef struct dt_pid_probe {
dtrace_hdl_t *dpp_dtp;
dt_pcb_t *dpp_pcb;
dt_proc_t *dpp_dpr;
struct ps_prochandle *dpp_pr;
const char *dpp_mod;
char *dpp_func;
const char *dpp_name;
const char *dpp_obj;
uintptr_t dpp_pc;
size_t dpp_size;
Lmid_t dpp_lmid;
uint_t dpp_nmatches;
uint64_t dpp_stret[4];
GElf_Sym dpp_last;
uint_t dpp_last_taken;
} dt_pid_probe_t;
/*
* Compose the lmid and object name into the canonical representation. We
* omit the lmid for the default link map for convenience.
*/
static void
dt_pid_objname(char *buf, size_t len, Lmid_t lmid, const char *obj)
{
#if defined(sun)
if (lmid == LM_ID_BASE)
(void) strncpy(buf, obj, len);
else
(void) snprintf(buf, len, "LM%lx`%s", lmid, obj);
#else
(void) strncpy(buf, obj, len);
#endif
}
static int
dt_pid_error(dtrace_hdl_t *dtp, dt_pcb_t *pcb, dt_proc_t *dpr,
fasttrap_probe_spec_t *ftp, dt_errtag_t tag, const char *fmt, ...)
{
va_list ap;
int len;
if (ftp != NULL)
dt_free(dtp, ftp);
va_start(ap, fmt);
if (pcb == NULL) {
assert(dpr != NULL);
len = vsnprintf(dpr->dpr_errmsg, sizeof (dpr->dpr_errmsg),
fmt, ap);
assert(len >= 2);
if (dpr->dpr_errmsg[len - 2] == '\n')
dpr->dpr_errmsg[len - 2] = '\0';
} else {
dt_set_errmsg(dtp, dt_errtag(tag), pcb->pcb_region,
pcb->pcb_filetag, pcb->pcb_fileptr ? yylineno : 0, fmt, ap);
}
va_end(ap);
return (1);
}
static int
dt_pid_per_sym(dt_pid_probe_t *pp, const GElf_Sym *symp, const char *func)
{
dtrace_hdl_t *dtp = pp->dpp_dtp;
dt_pcb_t *pcb = pp->dpp_pcb;
dt_proc_t *dpr = pp->dpp_dpr;
fasttrap_probe_spec_t *ftp;
uint64_t off;
char *end;
uint_t nmatches = 0;
ulong_t sz;
int glob, err;
int isdash = strcmp("-", func) == 0;
pid_t pid;
#if defined(sun)
pid = Pstatus(pp->dpp_pr)->pr_pid;
#else
pid = proc_getpid(pp->dpp_pr);
#endif
dt_dprintf("creating probe pid%d:%s:%s:%s\n", (int)pid, pp->dpp_obj,
func, pp->dpp_name);
sz = sizeof (fasttrap_probe_spec_t) + (isdash ? 4 :
(symp->st_size - 1) * sizeof (ftp->ftps_offs[0]));
if ((ftp = dt_alloc(dtp, sz)) == NULL) {
dt_dprintf("proc_per_sym: dt_alloc(%lu) failed\n", sz);
return (1); /* errno is set for us */
}
ftp->ftps_pid = pid;
(void) strncpy(ftp->ftps_func, func, sizeof (ftp->ftps_func));
dt_pid_objname(ftp->ftps_mod, sizeof (ftp->ftps_mod), pp->dpp_lmid,
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,
D_PROC_CREATEFAIL, "failed to create return probe "
"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++;
}
glob = strisglob(pp->dpp_name);
if (!glob && nmatches == 0) {
off = strtoull(pp->dpp_name, &end, 16);
if (*end != '\0') {
return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_NAME,
"'%s' is an invalid probe name", pp->dpp_name));
}
if (off >= symp->st_size) {
return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_OFF,
"offset 0x%llx outside of function '%s'",
(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,
D_PROC_CREATEFAIL, "failed to create probe at "
"'%s+0x%llx': %s", func, (u_longlong_t)off,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
if (err == DT_PROC_ALIGN) {
return (dt_pid_error(dtp, pcb, dpr, ftp, D_PROC_ALIGN,
"offset 0x%llx is not aligned on an instruction",
(u_longlong_t)off));
}
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,
D_PROC_CREATEFAIL,
"failed to create offset probes in '%s': %s", func,
dtrace_errmsg(dtp, dtrace_errno(dtp))));
}
#endif
nmatches++;
}
pp->dpp_nmatches += nmatches;
dt_free(dtp, ftp);
return (0);
}
static int
dt_pid_sym_filt(void *arg, const GElf_Sym *symp, const char *func)
{
dt_pid_probe_t *pp = arg;
if (symp->st_shndx == SHN_UNDEF)
return (0);
if (symp->st_size == 0) {
dt_dprintf("st_size of %s is zero\n", func);
return (0);
}
if (pp->dpp_last_taken == 0 ||
symp->st_value != pp->dpp_last.st_value ||
symp->st_size != pp->dpp_last.st_size) {
/*
* Due to 4524008, _init and _fini may have a bloated st_size.
* While this bug has been fixed for a while, old binaries
* may exist that still exhibit this problem. As a result, we
* don't match _init and _fini though we allow users to
* specify them explicitly.
*/
if (strcmp(func, "_init") == 0 || strcmp(func, "_fini") == 0)
return (0);
if ((pp->dpp_last_taken = gmatch(func, pp->dpp_func)) != 0) {
pp->dpp_last = *symp;
return (dt_pid_per_sym(pp, symp, func));
}
}
return (0);
}
static int
dt_pid_per_mod(void *arg, const prmap_t *pmp, const char *obj)
{
dt_pid_probe_t *pp = arg;
dtrace_hdl_t *dtp = pp->dpp_dtp;
dt_pcb_t *pcb = pp->dpp_pcb;
dt_proc_t *dpr = pp->dpp_dpr;
GElf_Sym sym;
if (obj == NULL)
return (0);
#if defined(sun)
(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
#endif
if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
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)
pp->dpp_stret[0] = sym.st_value;
else
pp->dpp_stret[0] = 0;
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret2", &sym,
NULL) == 0)
pp->dpp_stret[1] = sym.st_value;
else
pp->dpp_stret[1] = 0;
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret4", &sym,
NULL) == 0)
pp->dpp_stret[2] = sym.st_value;
else
pp->dpp_stret[2] = 0;
if (Pxlookup_by_name(pp->dpp_pr, pp->dpp_lmid, obj, ".stret8", &sym,
NULL) == 0)
pp->dpp_stret[3] = sym.st_value;
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;
#endif
dt_dprintf("%s stret %llx %llx %llx %llx\n", obj,
(u_longlong_t)pp->dpp_stret[0], (u_longlong_t)pp->dpp_stret[1],
(u_longlong_t)pp->dpp_stret[2], (u_longlong_t)pp->dpp_stret[3]);
/*
* If pp->dpp_func contains any globbing meta-characters, we need
* to iterate over the symbol table and compare each function name
* against the pattern.
*/
if (!strisglob(pp->dpp_func)) {
/*
* If we fail to lookup the symbol, try interpreting the
* function as the special "-" function that indicates that the
* probe name should be interpreted as a absolute virtual
* address. If that fails and we were matching a specific
* function in a specific module, report the error, otherwise
* 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 =
GELF_ST_INFO(STB_LOCAL, STT_FUNC);
sym.st_other = 0;
sym.st_value = 0;
#if defined(sun)
sym.st_size = Pstatus(pp->dpp_pr)->pr_dmodel ==
PR_MODEL_ILP32 ? -1U : -1ULL;
#else
sym.st_size = ~((Elf64_Xword) 0);
#endif
} else if (!strisglob(pp->dpp_mod)) {
return (dt_pid_error(dtp, pcb, dpr, NULL,
D_PROC_FUNC,
"failed to lookup '%s' in module '%s'",
pp->dpp_func, pp->dpp_mod));
} else {
return (0);
}
}
/*
* Only match defined functions of non-zero size.
*/
if (GELF_ST_TYPE(sym.st_info) != STT_FUNC ||
sym.st_shndx == SHN_UNDEF || sym.st_size == 0)
return (0);
/*
* We don't instrument PLTs -- they're dynamically rewritten,
* and, so, inherently dicey to instrument.
*/
#ifdef DOODAD
if (Ppltdest(pp->dpp_pr, sym.st_value) != NULL)
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,
BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
return (1);
if (nmatches == pp->dpp_nmatches) {
/*
* If we didn't match anything in the PR_SYMTAB, try
* the PR_DYNSYM.
*/
if (Psymbol_iter_by_addr(pp->dpp_pr, obj, PR_DYNSYM,
BIND_ANY | TYPE_FUNC, dt_pid_sym_filt, pp) == 1)
return (1);
}
#endif
}
return (0);
}
static int
dt_pid_mod_filt(void *arg, const prmap_t *pmp, const char *obj)
{
char name[DTRACE_MODNAMELEN];
dt_pid_probe_t *pp = arg;
if (gmatch(obj, pp->dpp_mod))
return (dt_pid_per_mod(pp, pmp, obj));
#if defined(sun)
(void) Plmid(pp->dpp_pr, pmp->pr_vaddr, &pp->dpp_lmid);
#else
pp->dpp_lmid = 0;
#endif
if ((pp->dpp_obj = strrchr(obj, '/')) == NULL)
pp->dpp_obj = obj;
else
pp->dpp_obj++;
dt_pid_objname(name, sizeof (name), pp->dpp_lmid, obj);
if (gmatch(name, pp->dpp_mod))
return (dt_pid_per_mod(pp, pmp, obj));
return (0);
}
static const prmap_t *
dt_pid_fix_mod(dtrace_probedesc_t *pdp, struct ps_prochandle *P)
{
#ifdef DOODAD
char m[MAXPATHLEN];
Lmid_t lmid = PR_LMID_EVERY;
const char *obj;
#endif
const prmap_t *pmp;
#ifdef DOODAD
/*
* Pick apart the link map from the library name.
*/
if (strchr(pdp->dtpd_mod, '`') != NULL) {
char *end;
if (strncmp(pdp->dtpd_mod, "LM", 2) != 0 ||
!isdigit(pdp->dtpd_mod[2]))
return (NULL);
lmid = strtoul(&pdp->dtpd_mod[2], &end, 16);
obj = end + 1;
if (*end != '`' || strchr(obj, '`') != NULL)
return (NULL);
} else {
obj = pdp->dtpd_mod;
}
if ((pmp = Plmid_to_map(P, lmid, obj)) == NULL)
return (NULL);
(void) Pobjname(P, pmp->pr_vaddr, m, sizeof (m));
if ((obj = strrchr(m, '/')) == NULL)
obj = &m[0];
else
obj++;
(void) Plmid(P, pmp->pr_vaddr, &lmid);
dt_pid_objname(pdp->dtpd_mod, sizeof (pdp->dtpd_mod), lmid, obj);
#else
pmp = NULL;
#endif
return (pmp);
}
static int
dt_pid_create_pid_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
dt_pcb_t *pcb, dt_proc_t *dpr)
{
dt_pid_probe_t pp;
int ret = 0;
pp.dpp_dtp = dtp;
pp.dpp_dpr = dpr;
pp.dpp_pr = dpr->dpr_proc;
pp.dpp_pcb = pcb;
#ifdef DOODAD
/*
* We can only trace dynamically-linked executables (since we've
* hidden some magic in ld.so.1 as well as libc.so.1).
*/
if (Pname_to_map(pp.dpp_pr, PR_OBJ_LDSO) == NULL) {
return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_DYN,
"process %s is not a dynamically-linked executable",
&pdp->dtpd_provider[3]));
}
#endif
pp.dpp_mod = pdp->dtpd_mod[0] != '\0' ? pdp->dtpd_mod : "*";
pp.dpp_func = pdp->dtpd_func[0] != '\0' ? pdp->dtpd_func : "*";
pp.dpp_name = pdp->dtpd_name[0] != '\0' ? pdp->dtpd_name : "*";
pp.dpp_last_taken = 0;
if (strcmp(pp.dpp_func, "-") == 0) {
const prmap_t *aout, *pmp;
if (pdp->dtpd_mod[0] == '\0') {
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 "
"'-' function"));
}
if (strisglob(pp.dpp_name)) {
return (dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_NAME,
"only individual addresses may be specified "
"with the '-' function"));
}
}
/*
* If pp.dpp_mod contains any globbing meta-characters, we need
* 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 {
const prmap_t *pmp;
char *obj;
/*
* If we can't find a matching module, don't sweat it -- either
* we'll fail the enabling because the probes don't exist or
* we'll wait for that module to come along.
*/
if ((pmp = dt_pid_fix_mod(pdp, pp.dpp_pr)) != NULL) {
if ((obj = strchr(pdp->dtpd_mod, '`')) == NULL)
obj = pdp->dtpd_mod;
else
obj++;
ret = dt_pid_per_mod(&pp, pmp, obj);
}
}
#endif
return (ret);
}
static int
dt_pid_usdt_mapping(void *data, const prmap_t *pmp, const char *oname)
{
struct ps_prochandle *P = data;
GElf_Sym sym;
#if defined(sun)
prsyminfo_t sip;
#endif
dof_helper_t dh;
GElf_Half e_type;
const char *mname;
const char *syms[] = { "___SUNW_dof", "__SUNW_dof" };
int i, fd = -1;
/*
* The symbol ___SUNW_dof is for lazy-loaded DOF sections, and
* __SUNW_dof is for actively-loaded DOF sections. We try to force
* in both types of DOF section since the process may not yet have
* 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;
}
if ((mname = strrchr(oname, '/')) == NULL)
mname = oname;
else
mname++;
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;
dt_pid_objname(dh.dofhp_mod, sizeof (dh.dofhp_mod),
#if defined(sun)
sip.prs_lmid, mname);
#else
0, mname);
#endif
#ifdef DOODAD
if (fd == -1 &&
(fd = pr_open(P, "/dev/dtrace/helper", O_RDWR, 0)) < 0) {
dt_dprintf("pr_open of helper device failed: %s\n",
strerror(errno));
return (-1); /* errno is set for us */
}
if (pr_ioctl(P, fd, DTRACEHIOC_ADDDOF, &dh, sizeof (dh)) < 0)
dt_dprintf("DOF was rejected for %s\n", dh.dofhp_mod);
#endif
}
#ifdef DOODAD
if (fd != -1)
(void) pr_close(P, fd);
#endif
return (0);
}
static int
dt_pid_create_usdt_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp,
dt_pcb_t *pcb, dt_proc_t *dpr)
{
struct ps_prochandle *P = dpr->dpr_proc;
int ret = 0;
assert(DT_MUTEX_HELD(&dpr->dpr_lock));
#ifdef DOODAD
(void) Pupdate_maps(P);
if (Pobject_iter(P, dt_pid_usdt_mapping, P) != 0) {
ret = -1;
(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_USDT,
"failed to instantiate probes for pid %d: %s",
#if defined(sun)
(int)Pstatus(P)->pr_pid, strerror(errno));
#else
(int)proc_getpid(P), strerror(errno));
#endif
}
#endif
/*
* Put the module name in its canonical form.
*/
(void) dt_pid_fix_mod(pdp, P);
return (ret);
}
static pid_t
dt_pid_get_pid(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb,
dt_proc_t *dpr)
{
pid_t pid;
char *c, *last = NULL, *end;
for (c = &pdp->dtpd_provider[0]; *c != '\0'; c++) {
if (!isdigit(*c))
last = c;
}
if (last == NULL || (*(++last) == '\0')) {
(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPROV,
"'%s' is not a valid provider", pdp->dtpd_provider);
return (-1);
}
errno = 0;
pid = strtol(last, &end, 10);
if (errno != 0 || end == last || end[0] != '\0' || pid <= 0) {
(void) dt_pid_error(dtp, pcb, dpr, NULL, D_PROC_BADPID,
"'%s' does not contain a valid pid", pdp->dtpd_provider);
return (-1);
}
return (pid);
}
int
dt_pid_create_probes(dtrace_probedesc_t *pdp, dtrace_hdl_t *dtp, dt_pcb_t *pcb)
{
char provname[DTRACE_PROVNAMELEN];
struct ps_prochandle *P;
dt_proc_t *dpr;
pid_t pid;
int err = 0;
assert(pcb != NULL);
if ((pid = dt_pid_get_pid(pdp, dtp, pcb, NULL)) == -1)
return (-1);
if (dtp->dt_ftfd == -1) {
if (dtp->dt_fterr == ENOENT) {
(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
"pid provider is not installed on this system");
} else {
(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_NODEV,
"pid provider is not available: %s",
strerror(dtp->dt_fterr));
}
return (-1);
}
(void) snprintf(provname, sizeof (provname), "pid%d", (int)pid);
if (gmatch(provname, pdp->dtpd_provider) != 0) {
if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE,
0)) == NULL) {
(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
"failed to grab process %d", (int)pid);
return (-1);
}
dpr = dt_proc_lookup(dtp, P, 0);
assert(dpr != NULL);
(void) pthread_mutex_lock(&dpr->dpr_lock);
if ((err = dt_pid_create_pid_probes(pdp, dtp, pcb, dpr)) == 0) {
/*
* Alert other retained enablings which may match
* against the newly created probes.
*/
(void) dt_ioctl(dtp, DTRACEIOC_ENABLE, NULL);
}
(void) pthread_mutex_unlock(&dpr->dpr_lock);
dt_proc_release(dtp, P);
}
/*
* If it's not strictly a pid provider, we might match a USDT provider.
*/
if (strcmp(provname, pdp->dtpd_provider) != 0) {
if ((P = dt_proc_grab(dtp, pid, 0, 1)) == NULL) {
(void) dt_pid_error(dtp, pcb, NULL, NULL, D_PROC_GRAB,
"failed to grab process %d", (int)pid);
return (-1);
}
dpr = dt_proc_lookup(dtp, P, 0);
assert(dpr != NULL);
(void) pthread_mutex_lock(&dpr->dpr_lock);
if (!dpr->dpr_usdt) {
err = dt_pid_create_usdt_probes(pdp, dtp, pcb, dpr);
dpr->dpr_usdt = B_TRUE;
}
(void) pthread_mutex_unlock(&dpr->dpr_lock);
dt_proc_release(dtp, P);
}
return (err ? -1 : 0);
}
int
dt_pid_create_probes_module(dtrace_hdl_t *dtp, dt_proc_t *dpr)
{
dtrace_enable_io_t args;
dtrace_prog_t *pgp;
dt_stmt_t *stp;
dtrace_probedesc_t *pdp, pd;
pid_t pid;
int ret = 0, found = B_FALSE;
char provname[DTRACE_PROVNAMELEN];
(void) snprintf(provname, sizeof (provname), "pid%d",
(int)dpr->dpr_pid);
for (pgp = dt_list_next(&dtp->dt_programs); pgp != NULL;
pgp = dt_list_next(pgp)) {
for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL;
stp = dt_list_next(stp)) {
pdp = &stp->ds_desc->dtsd_ecbdesc->dted_probe;
pid = dt_pid_get_pid(pdp, dtp, NULL, dpr);
if (pid != dpr->dpr_pid)
continue;
found = B_TRUE;
pd = *pdp;
if (gmatch(provname, pdp->dtpd_provider) != 0 &&
dt_pid_create_pid_probes(&pd, dtp, NULL, dpr) != 0)
ret = 1;
/*
* If it's not strictly a pid provider, we might match
* a USDT provider.
*/
if (strcmp(provname, pdp->dtpd_provider) != 0 &&
dt_pid_create_usdt_probes(&pd, dtp, NULL, dpr) != 0)
ret = 1;
}
}
if (found) {
/*
* Give DTrace a shot to the ribs to get it to check
* out the newly created probes.
*/
args.dof = NULL;
args.n_matched = 0;
(void) dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
}
return (ret);
}

View File

@ -0,0 +1,64 @@
/*
* 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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PID_H
#define _DT_PID_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libproc.h>
#include <sys/fasttrap.h>
#include <dt_impl.h>
#ifdef __cplusplus
extern "C" {
#endif
#define DT_PROC_ERR (-1)
#define DT_PROC_ALIGN (-2)
extern int dt_pid_create_probes(dtrace_probedesc_t *, dtrace_hdl_t *,
dt_pcb_t *pcb);
extern int dt_pid_create_probes_module(dtrace_hdl_t *, dt_proc_t *);
extern int dt_pid_create_entry_probe(struct ps_prochandle *, dtrace_hdl_t *,
fasttrap_probe_spec_t *, const GElf_Sym *);
extern int dt_pid_create_return_probe(struct ps_prochandle *, dtrace_hdl_t *,
fasttrap_probe_spec_t *, const GElf_Sym *, uint64_t *);
extern int dt_pid_create_offset_probe(struct ps_prochandle *, dtrace_hdl_t *,
fasttrap_probe_spec_t *, const GElf_Sym *, ulong_t);
extern int dt_pid_create_glob_offset_probes(struct ps_prochandle *,
dtrace_hdl_t *, fasttrap_probe_spec_t *, const GElf_Sym *, const char *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PID_H */

View File

@ -0,0 +1,507 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <assert.h>
#include <strings.h>
#if defined(sun)
#include <alloca.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <dt_parser.h>
#include <dt_impl.h>
#include <dt_provider.h>
#include <dt_module.h>
/*
* This callback function is installed in a given identifier hash to search for
* and apply deferred pragmas that are pending for a given new identifier name.
* Multiple pragmas may be pending for a given name; we processs all of them.
*/
/*ARGSUSED*/
static void
dt_pragma_apply(dt_idhash_t *dhp, dt_ident_t *idp)
{
dt_idhash_t *php;
dt_ident_t *pdp;
if ((php = yypcb->pcb_pragmas) == NULL)
return; /* no pragmas pending for current compilation pass */
while ((pdp = dt_idhash_lookup(php, idp->di_name)) != NULL) {
switch (pdp->di_kind) {
case DT_IDENT_PRAGAT:
idp->di_attr = pdp->di_attr;
break;
case DT_IDENT_PRAGBN:
idp->di_vers = pdp->di_vers;
break;
}
dt_idhash_delete(php, pdp);
}
}
/*
* The #pragma attributes directive can be used to reset stability attributes
* on a global identifier or inline definition. If the identifier is already
* defined, we can just change di_attr. If not, we insert the pragma into a
* hash table of the current pcb's deferred pragmas for later processing.
*/
static void
dt_pragma_attributes(const char *prname, dt_node_t *dnp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dtrace_attribute_t attr, *a;
dt_provider_t *pvp;
const char *name, *part;
dt_ident_t *idp;
if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT ||
dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
"<attributes> <ident>\n", prname);
}
if (dtrace_str2attr(dnp->dn_string, &attr) == -1) {
xyerror(D_PRAGMA_INVAL, "invalid attributes "
"specified by #pragma %s\n", prname);
}
dnp = dnp->dn_list;
name = dnp->dn_string;
if (strcmp(name, "provider") == 0) {
dnp = dnp->dn_list;
name = dnp->dn_string;
dnp = dnp->dn_list;
part = dnp->dn_string;
if ((pvp = dt_provider_lookup(dtp, name)) != NULL) {
if (strcmp(part, "provider") == 0) {
a = &pvp->pv_desc.dtvd_attr.dtpa_provider;
} else if (strcmp(part, "module") == 0) {
a = &pvp->pv_desc.dtvd_attr.dtpa_mod;
} else if (strcmp(part, "function") == 0) {
a = &pvp->pv_desc.dtvd_attr.dtpa_func;
} else if (strcmp(part, "name") == 0) {
a = &pvp->pv_desc.dtvd_attr.dtpa_name;
} else if (strcmp(part, "args") == 0) {
a = &pvp->pv_desc.dtvd_attr.dtpa_args;
} else {
xyerror(D_PRAGMA_INVAL, "invalid component "
"\"%s\" in attribute #pragma "
"for provider %s\n", name, part);
}
*a = attr;
return;
}
} else if ((idp = dt_idstack_lookup(
&yypcb->pcb_globals, name)) != NULL) {
if (idp->di_gen != dtp->dt_gen) {
xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
"entity defined outside program scope\n", prname);
}
idp->di_attr = attr;
return;
}
if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGAT, 0, 0,
attr, 0, &dt_idops_thaw, (void *)prname, dtp->dt_gen);
if (idp == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
if (dtp->dt_globals->dh_defer == NULL)
dtp->dt_globals->dh_defer = &dt_pragma_apply;
}
/*
* The #pragma binding directive can be used to reset the version binding
* on a global identifier or inline definition. If the identifier is already
* defined, we can just change di_vers. If not, we insert the pragma into a
* hash table of the current pcb's deferred pragmas for later processing.
*/
static void
dt_pragma_binding(const char *prname, dt_node_t *dnp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dt_version_t vers;
const char *name;
dt_ident_t *idp;
if (dnp == NULL || dnp->dn_kind != DT_NODE_STRING ||
dnp->dn_list == NULL || dnp->dn_list->dn_kind != DT_NODE_IDENT) {
xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
"\"version\" <ident>\n", prname);
}
if (dt_version_str2num(dnp->dn_string, &vers) == -1) {
xyerror(D_PRAGMA_INVAL, "invalid version string "
"specified by #pragma %s\n", prname);
}
name = dnp->dn_list->dn_string;
idp = dt_idstack_lookup(&yypcb->pcb_globals, name);
if (idp != NULL) {
if (idp->di_gen != dtp->dt_gen) {
xyerror(D_PRAGMA_SCOPE, "#pragma %s cannot modify "
"entity defined outside program scope\n", prname);
}
idp->di_vers = vers;
return;
}
if (yypcb->pcb_pragmas == NULL && (yypcb->pcb_pragmas =
dt_idhash_create("pragma", NULL, 0, 0)) == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
idp = dt_idhash_insert(yypcb->pcb_pragmas, name, DT_IDENT_PRAGBN, 0, 0,
_dtrace_defattr, vers, &dt_idops_thaw, (void *)prname, dtp->dt_gen);
if (idp == NULL)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
if (dtp->dt_globals->dh_defer == NULL)
dtp->dt_globals->dh_defer = &dt_pragma_apply;
}
/*
* The #pragma depends_on directive can be used to express a dependency on a
* module, provider or library which if not present will cause processing to
* abort.
*/
static void
dt_pragma_depends(const char *prname, dt_node_t *cnp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
dt_node_t *nnp = cnp ? cnp->dn_list : NULL;
int found;
dt_lib_depend_t *dld;
char lib[MAXPATHLEN];
if (cnp == NULL || nnp == NULL ||
cnp->dn_kind != DT_NODE_IDENT || nnp->dn_kind != DT_NODE_IDENT) {
xyerror(D_PRAGMA_MALFORM, "malformed #pragma %s "
"<class> <name>\n", prname);
}
if (strcmp(cnp->dn_string, "provider") == 0)
found = dt_provider_lookup(dtp, nnp->dn_string) != NULL;
else if (strcmp(cnp->dn_string, "module") == 0) {
dt_module_t *mp = dt_module_lookup_by_name(dtp, nnp->dn_string);
found = mp != NULL && dt_module_getctf(dtp, mp) != NULL;
} else if (strcmp(cnp->dn_string, "library") == 0) {
if (yypcb->pcb_cflags & DTRACE_C_CTL) {
assert(dtp->dt_filetag != NULL);
/*
* We have the file we are working on in dtp->dt_filetag
* so find that node and add the dependency in.
*/
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
dtp->dt_filetag);
assert(dld != NULL);
(void) snprintf(lib, sizeof (lib), "%s%s",
dld->dtld_libpath, nnp->dn_string);
if ((dt_lib_depend_add(dtp, &dld->dtld_dependencies,
lib)) != 0) {
xyerror(D_PRAGMA_DEPEND,
"failed to add dependency %s:%s\n", lib,
dtrace_errmsg(dtp, dtrace_errno(dtp)));
}
} else {
/*
* By this point we have already performed a topological
* sort of the dependencies; we process this directive
* as satisfied as long as the dependency was properly
* loaded.
*/
if (dtp->dt_filetag == NULL)
xyerror(D_PRAGMA_DEPEND, "main program may "
"not explicitly depend on a library");
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep,
dtp->dt_filetag);
assert(dld != NULL);
(void) snprintf(lib, sizeof (lib), "%s%s",
dld->dtld_libpath, nnp->dn_string);
dld = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted,
lib);
assert(dld != NULL);
if (!dld->dtld_loaded)
xyerror(D_PRAGMA_DEPEND, "program requires "
"library \"%s\" which failed to load",
lib);
}
found = B_TRUE;
} else {
xyerror(D_PRAGMA_INVAL, "invalid class %s "
"specified by #pragma %s\n", cnp->dn_string, prname);
}
if (!found) {
xyerror(D_PRAGMA_DEPEND, "program requires %s %s\n",
cnp->dn_string, nnp->dn_string);
}
}
/*
* The #pragma error directive can be followed by any list of tokens, which we
* just concatenate and print as part of our error message.
*/
static void
dt_pragma_error(const char *prname, dt_node_t *dnp)
{
dt_node_t *enp;
size_t n = 0;
char *s;
for (enp = dnp; enp != NULL; enp = enp->dn_list) {
if (enp->dn_kind == DT_NODE_IDENT ||
enp->dn_kind == DT_NODE_STRING)
n += strlen(enp->dn_string) + 1;
}
s = alloca(n + 1);
s[0] = '\0';
for (enp = dnp; enp != NULL; enp = enp->dn_list) {
if (enp->dn_kind == DT_NODE_IDENT ||
enp->dn_kind == DT_NODE_STRING) {
(void) strcat(s, enp->dn_string);
(void) strcat(s, " ");
}
}
xyerror(D_PRAGERR, "#%s: %s\n", prname, s);
}
/*ARGSUSED*/
static void
dt_pragma_ident(const char *prname, dt_node_t *dnp)
{
/* ignore any #ident or #pragma ident lines */
}
static void
dt_pragma_option(const char *prname, dt_node_t *dnp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
char *opt, *val;
if (dnp == NULL || dnp->dn_kind != DT_NODE_IDENT) {
xyerror(D_PRAGMA_MALFORM,
"malformed #pragma %s <option>=<val>\n", prname);
}
if (dnp->dn_list != NULL) {
xyerror(D_PRAGMA_MALFORM,
"superfluous arguments specified for #pragma %s\n", prname);
}
opt = alloca(strlen(dnp->dn_string) + 1);
(void) strcpy(opt, dnp->dn_string);
if ((val = strchr(opt, '=')) != NULL)
*val++ = '\0';
if (dtrace_setopt(dtp, opt, val) == -1) {
if (val == NULL) {
xyerror(D_PRAGMA_OPTSET,
"failed to set option '%s': %s\n", opt,
dtrace_errmsg(dtp, dtrace_errno(dtp)));
} else {
xyerror(D_PRAGMA_OPTSET,
"failed to set option '%s' to '%s': %s\n",
opt, val, dtrace_errmsg(dtp, dtrace_errno(dtp)));
}
}
}
/*
* The #line directive is used to reset the input line number and to optionally
* note the file name for use in error messages. Sun cpp(1) also produces a
* third integer token after the filename which is one of the following:
*
* 0 - line change has nothing to do with an #include file
* 1 - line change because we just entered a #include file
* 2 - line change because we just exited a #include file
*
* We use these state tokens to adjust pcb_idepth, which in turn controls
* whether type lookups access the global type space or not.
*/
static void
dt_pragma_line(const char *prname, dt_node_t *dnp)
{
dt_node_t *fnp = dnp ? dnp->dn_list : NULL;
dt_node_t *inp = fnp ? fnp->dn_list : NULL;
if ((dnp == NULL || dnp->dn_kind != DT_NODE_INT) ||
(fnp != NULL && fnp->dn_kind != DT_NODE_STRING) ||
(inp != NULL && inp->dn_kind != DT_NODE_INT)) {
xyerror(D_PRAGMA_MALFORM, "malformed #%s "
"<line> [ [\"file\"] state ]\n", prname);
}
/*
* If a file is specified, free any old pcb_filetag and swap fnp's
* dn_string into pcb_filetag as the new filename for error messages.
*/
if (fnp != NULL) {
if (yypcb->pcb_filetag != NULL)
free(yypcb->pcb_filetag);
/*
* This is not pretty, but is a necessary evil until we either
* write "dpp" or get a useful standalone cpp from DevPro. If
* the filename begins with /dev/fd, we know it's the master
* input file (see dt_preproc() in dt_cc.c), so just clear the
* dt_filetag pointer so error messages refer to the main file.
*/
if (strncmp(fnp->dn_string, "/dev/fd/", 8) != 0) {
yypcb->pcb_filetag = fnp->dn_string;
fnp->dn_string = NULL;
} else
yypcb->pcb_filetag = NULL;
}
if (inp != NULL) {
if (inp->dn_value == 1)
yypcb->pcb_idepth++;
else if (inp->dn_value == 2 && yypcb->pcb_idepth != 0)
yypcb->pcb_idepth--;
}
yylineno = dnp->dn_value;
}
/*
* D compiler pragma types range from control directives to common pragmas to
* D custom pragmas, in order of specificity. Similar to gcc, we use #pragma D
* as a special prefix for our pragmas so they can be used in mixed headers.
*/
#define DT_PRAGMA_DIR 0 /* pragma directive may be used after naked # */
#define DT_PRAGMA_SUB 1 /* pragma directive may be used after #pragma */
#define DT_PRAGMA_DCP 2 /* pragma may only be used after #pragma D */
static const struct dt_pragmadesc {
const char *dpd_name;
void (*dpd_func)(const char *, dt_node_t *);
int dpd_kind;
} dt_pragmas[] = {
{ "attributes", dt_pragma_attributes, DT_PRAGMA_DCP },
{ "binding", dt_pragma_binding, DT_PRAGMA_DCP },
{ "depends_on", dt_pragma_depends, DT_PRAGMA_DCP },
{ "error", dt_pragma_error, DT_PRAGMA_DIR },
{ "ident", dt_pragma_ident, DT_PRAGMA_DIR },
{ "line", dt_pragma_line, DT_PRAGMA_DIR },
{ "option", dt_pragma_option, DT_PRAGMA_DCP },
{ NULL, NULL }
};
/*
* Process a control line #directive by looking up the directive name in our
* lookup table and invoking the corresponding function with the token list.
* According to K&R[A12.9], we silently ignore null directive lines.
*/
void
dt_pragma(dt_node_t *pnp)
{
const struct dt_pragmadesc *dpd;
dt_node_t *dnp;
int kind = DT_PRAGMA_DIR;
for (dnp = pnp; dnp != NULL; dnp = dnp->dn_list) {
if (dnp->dn_kind == DT_NODE_INT) {
dt_pragma_line("line", dnp);
break;
}
if (dnp->dn_kind != DT_NODE_IDENT)
xyerror(D_PRAGCTL_INVAL, "invalid control directive\n");
if (kind == DT_PRAGMA_DIR &&
strcmp(dnp->dn_string, "pragma") == 0) {
kind = DT_PRAGMA_SUB;
continue;
}
if (kind == DT_PRAGMA_SUB &&
strcmp(dnp->dn_string, "D") == 0) {
kind = DT_PRAGMA_DCP;
continue;
}
for (dpd = dt_pragmas; dpd->dpd_name != NULL; dpd++) {
if (dpd->dpd_kind <= kind &&
strcmp(dpd->dpd_name, dnp->dn_string) == 0)
break;
}
yylineno--; /* since we've already seen \n */
if (dpd->dpd_name != NULL) {
dpd->dpd_func(dpd->dpd_name, dnp->dn_list);
yylineno++;
break;
}
switch (kind) {
case DT_PRAGMA_DIR:
xyerror(D_PRAGCTL_INVAL, "invalid control directive: "
"#%s\n", dnp->dn_string);
/*NOTREACHED*/
case DT_PRAGMA_SUB:
break; /* K&R[A12.8] says to ignore unknown pragmas */
case DT_PRAGMA_DCP:
default:
xyerror(D_PRAGMA_INVAL, "invalid D pragma: %s\n",
dnp->dn_string);
}
yylineno++;
break;
}
dt_node_list_free(&pnp);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PRINTF_H
#define _DT_PRINTF_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <libctf.h>
#include <dtrace.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
struct dt_node;
struct dt_ident;
struct dt_pfconv;
struct dt_pfargv;
struct dt_pfargd;
typedef int dt_pfcheck_f(struct dt_pfargv *,
struct dt_pfargd *, struct dt_node *);
typedef int dt_pfprint_f(dtrace_hdl_t *, FILE *, const char *,
const struct dt_pfargd *, const void *, size_t, uint64_t);
typedef struct dt_pfconv {
const char *pfc_name; /* string name of input conversion */
const char *pfc_ofmt; /* string name of output conversion */
const char *pfc_tstr; /* string name for conversion type */
dt_pfcheck_f *pfc_check; /* function to use for type checking */
dt_pfprint_f *pfc_print; /* function to use for formatting */
ctf_file_t *pfc_cctfp; /* CTF container for "C" defn of type */
ctf_id_t pfc_ctype; /* CTF type ID for "C" defn of type */
ctf_file_t *pfc_dctfp; /* CTF container for "D" defn of type */
ctf_id_t pfc_dtype; /* CTF type ID for "D" defn of type */
struct dt_pfconv *pfc_next; /* next conversion in hash chain */
} dt_pfconv_t;
typedef struct dt_pfdict {
dt_pfconv_t **pdi_buckets; /* hash bucket array */
uint_t pdi_nbuckets; /* size of hash bucket array */
} dt_pfdict_t;
typedef struct dt_pfargd {
const char *pfd_prefix; /* prefix string pointer (or NULL) */
size_t pfd_preflen; /* length of prefix in bytes */
char pfd_fmt[8]; /* output format name to use */
uint_t pfd_flags; /* format flags (see below) */
int pfd_width; /* field width (or 0) */
int pfd_dynwidth; /* dynamic field width (or 0) */
int pfd_prec; /* field precision (or 0) */
const dt_pfconv_t *pfd_conv; /* conversion specification */
const dtrace_recdesc_t *pfd_rec; /* pointer to current record */
struct dt_pfargd *pfd_next; /* pointer to next arg descriptor */
} dt_pfargd_t;
#define DT_PFCONV_ALT 0x0001 /* alternate print format (%#) */
#define DT_PFCONV_ZPAD 0x0002 /* zero-pad integer field (%0) */
#define DT_PFCONV_LEFT 0x0004 /* left-align field (%-) */
#define DT_PFCONV_SPOS 0x0008 /* sign positive values (%+) */
#define DT_PFCONV_DYNWIDTH 0x0010 /* dynamic width (%*.) */
#define DT_PFCONV_DYNPREC 0x0020 /* dynamic precision (%.*) */
#define DT_PFCONV_GROUP 0x0040 /* group thousands (%') */
#define DT_PFCONV_SPACE 0x0080 /* insert leading space (% ) */
#define DT_PFCONV_AGG 0x0100 /* use aggregation result (%@) */
#define DT_PFCONV_SIGNED 0x0200 /* arg is a signed integer */
typedef struct dt_pfargv {
dtrace_hdl_t *pfv_dtp; /* libdtrace client handle */
char *pfv_format; /* format string pointer */
dt_pfargd_t *pfv_argv; /* list of argument descriptors */
uint_t pfv_argc; /* number of argument descriptors */
uint_t pfv_flags; /* flags used for validation */
} dt_pfargv_t;
typedef struct dt_pfwalk {
const dt_pfargv_t *pfw_argv; /* argument description list */
uint_t pfw_aid; /* aggregation variable identifier */
FILE *pfw_fp; /* file pointer to use for output */
int pfw_err; /* error status code */
} dt_pfwalk_t;
extern int dt_pfdict_create(dtrace_hdl_t *);
extern void dt_pfdict_destroy(dtrace_hdl_t *);
extern dt_pfargv_t *dt_printf_create(dtrace_hdl_t *, const char *);
extern void dt_printf_destroy(dt_pfargv_t *);
#define DT_PRINTF_EXACTLEN 0x1 /* do not permit extra arguments */
#define DT_PRINTF_AGGREGATION 0x2 /* enable aggregation conversion */
extern void dt_printf_validate(dt_pfargv_t *, uint_t,
struct dt_ident *, int, dtrace_actkind_t, struct dt_node *);
extern void dt_printa_validate(struct dt_node *, struct dt_node *);
extern int dt_print_stack(dtrace_hdl_t *, FILE *,
const char *, caddr_t, int, int);
extern int dt_print_ustack(dtrace_hdl_t *, FILE *,
const char *, caddr_t, uint64_t);
extern int dt_print_mod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
extern int dt_print_umod(dtrace_hdl_t *, FILE *, const char *, caddr_t);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PRINTF_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,118 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PROC_H
#define _DT_PROC_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libproc.h>
#include <dtrace.h>
#include <pthread.h>
#include <dt_list.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_proc {
dt_list_t dpr_list; /* prev/next pointers for lru chain */
struct dt_proc *dpr_hash; /* next pointer for pid hash chain */
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 */
uint_t dpr_refs; /* reference count */
uint8_t dpr_cacheable; /* cache handle using lru list */
uint8_t dpr_stop; /* stop mask: see flag bits below */
uint8_t dpr_quit; /* quit flag: ctl thread should quit */
uint8_t dpr_done; /* done flag: ctl thread has exited */
uint8_t dpr_usdt; /* usdt flag: usdt initialized */
uint8_t dpr_stale; /* proc flag: been deprecated */
uint8_t dpr_rdonly; /* proc flag: opened read-only */
pthread_t dpr_tid; /* control thread (or zero if none) */
dt_list_t dpr_bps; /* list of dt_bkpt_t structures */
} dt_proc_t;
typedef struct dt_proc_notify {
dt_proc_t *dprn_dpr; /* process associated with the event */
char dprn_errmsg[BUFSIZ]; /* error message */
struct dt_proc_notify *dprn_next; /* next pointer */
} dt_proc_notify_t;
#define DT_PROC_STOP_IDLE 0x01 /* idle on owner's stop request */
#define DT_PROC_STOP_CREATE 0x02 /* wait on dpr_cv at process exec */
#define DT_PROC_STOP_GRAB 0x04 /* wait on dpr_cv at process grab */
#define DT_PROC_STOP_PREINIT 0x08 /* wait on dpr_cv at rtld preinit */
#define DT_PROC_STOP_POSTINIT 0x10 /* wait on dpr_cv at rtld postinit */
#define DT_PROC_STOP_MAIN 0x20 /* wait on dpr_cv at a.out`main() */
typedef void dt_bkpt_f(dtrace_hdl_t *, dt_proc_t *, void *);
typedef struct dt_bkpt {
dt_list_t dbp_list; /* prev/next pointers for bkpt list */
dt_bkpt_f *dbp_func; /* callback function to execute */
void *dbp_data; /* callback function private data */
uintptr_t dbp_addr; /* virtual address of breakpoint */
ulong_t dbp_instr; /* saved instruction from breakpoint */
ulong_t dbp_hits; /* count of breakpoint hits for debug */
int dbp_active; /* flag indicating breakpoint is on */
} dt_bkpt_t;
typedef struct dt_proc_hash {
pthread_mutex_t dph_lock; /* lock protecting dph_notify list */
pthread_cond_t dph_cv; /* cond for waiting for dph_notify */
dt_proc_notify_t *dph_notify; /* list of pending proc notifications */
dt_list_t dph_lrulist; /* list of dt_proc_t's in lru order */
uint_t dph_lrulim; /* limit on number of procs to hold */
uint_t dph_lrucnt; /* count of cached process handles */
uint_t dph_hashlen; /* size of hash chains array */
dt_proc_t *dph_hash[1]; /* hash chains array */
} dt_proc_hash_t;
extern struct ps_prochandle *dt_proc_create(dtrace_hdl_t *,
const char *, char *const *);
extern struct ps_prochandle *dt_proc_grab(dtrace_hdl_t *, pid_t, int, int);
extern void dt_proc_release(dtrace_hdl_t *, struct ps_prochandle *);
extern void dt_proc_continue(dtrace_hdl_t *, struct ps_prochandle *);
extern void dt_proc_lock(dtrace_hdl_t *, struct ps_prochandle *);
extern void dt_proc_unlock(dtrace_hdl_t *, struct ps_prochandle *);
extern dt_proc_t *dt_proc_lookup(dtrace_hdl_t *, struct ps_prochandle *, int);
extern void dt_proc_hash_create(dtrace_hdl_t *);
extern void dt_proc_hash_destroy(dtrace_hdl_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PROC_H */

View File

@ -0,0 +1,606 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h>
#include <strings.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#if defined(sun)
#include <alloca.h>
#endif
#include <dt_impl.h>
#include <dt_program.h>
#include <dt_printf.h>
#include <dt_provider.h>
dtrace_prog_t *
dt_program_create(dtrace_hdl_t *dtp)
{
dtrace_prog_t *pgp = dt_zalloc(dtp, sizeof (dtrace_prog_t));
if (pgp != NULL)
dt_list_append(&dtp->dt_programs, pgp);
else
(void) dt_set_errno(dtp, EDT_NOMEM);
/*
* By default, programs start with DOF version 1 so that output files
* containing DOF are backward compatible. If a program requires new
* DOF features, the version is increased as needed.
*/
pgp->dp_dofversion = DOF_VERSION_1;
return (pgp);
}
void
dt_program_destroy(dtrace_hdl_t *dtp, dtrace_prog_t *pgp)
{
dt_stmt_t *stp, *next;
uint_t i;
for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
next = dt_list_next(stp);
dtrace_stmt_destroy(dtp, stp->ds_desc);
dt_free(dtp, stp);
}
for (i = 0; i < pgp->dp_xrefslen; i++)
dt_free(dtp, pgp->dp_xrefs[i]);
dt_free(dtp, pgp->dp_xrefs);
dt_list_delete(&dtp->dt_programs, pgp);
dt_free(dtp, pgp);
}
/*ARGSUSED*/
void
dtrace_program_info(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
dtrace_proginfo_t *pip)
{
dt_stmt_t *stp;
dtrace_actdesc_t *ap;
dtrace_ecbdesc_t *last = NULL;
if (pip == NULL)
return;
bzero(pip, sizeof (dtrace_proginfo_t));
if (dt_list_next(&pgp->dp_stmts) != NULL) {
pip->dpi_descattr = _dtrace_maxattr;
pip->dpi_stmtattr = _dtrace_maxattr;
} else {
pip->dpi_descattr = _dtrace_defattr;
pip->dpi_stmtattr = _dtrace_defattr;
}
for (stp = dt_list_next(&pgp->dp_stmts); stp; stp = dt_list_next(stp)) {
dtrace_ecbdesc_t *edp = stp->ds_desc->dtsd_ecbdesc;
if (edp == last)
continue;
last = edp;
pip->dpi_descattr =
dt_attr_min(stp->ds_desc->dtsd_descattr, pip->dpi_descattr);
pip->dpi_stmtattr =
dt_attr_min(stp->ds_desc->dtsd_stmtattr, pip->dpi_stmtattr);
/*
* If there aren't any actions, account for the fact that
* recording the epid will generate a record.
*/
if (edp->dted_action == NULL)
pip->dpi_recgens++;
for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
if (ap->dtad_kind == DTRACEACT_SPECULATE) {
pip->dpi_speculations++;
continue;
}
if (DTRACEACT_ISAGG(ap->dtad_kind)) {
pip->dpi_recgens -= ap->dtad_arg;
pip->dpi_aggregates++;
continue;
}
if (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind))
continue;
if (ap->dtad_kind == DTRACEACT_DIFEXPR &&
ap->dtad_difo->dtdo_rtype.dtdt_kind ==
DIF_TYPE_CTF &&
ap->dtad_difo->dtdo_rtype.dtdt_size == 0)
continue;
pip->dpi_recgens++;
}
}
}
int
dtrace_program_exec(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
dtrace_proginfo_t *pip)
{
dtrace_enable_io_t args;
void *dof;
int n, err;
dtrace_program_info(dtp, pgp, pip);
if ((dof = dtrace_dof_create(dtp, pgp, DTRACE_D_STRIP)) == NULL)
return (-1);
args.dof = dof;
args.n_matched = 0;
n = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
dtrace_dof_destroy(dtp, dof);
if (n == -1) {
switch (errno) {
case EINVAL:
err = EDT_DIFINVAL;
break;
case EFAULT:
err = EDT_DIFFAULT;
break;
case E2BIG:
err = EDT_DIFSIZE;
break;
default:
err = errno;
}
return (dt_set_errno(dtp, err));
}
if (pip != NULL)
pip->dpi_matches += args.n_matched;
return (0);
}
static void
dt_ecbdesc_hold(dtrace_ecbdesc_t *edp)
{
edp->dted_refcnt++;
}
void
dt_ecbdesc_release(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
{
if (--edp->dted_refcnt > 0)
return;
dt_difo_free(dtp, edp->dted_pred.dtpdd_difo);
assert(edp->dted_action == NULL);
dt_free(dtp, edp);
}
dtrace_ecbdesc_t *
dt_ecbdesc_create(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp)
{
dtrace_ecbdesc_t *edp;
if ((edp = dt_zalloc(dtp, sizeof (dtrace_ecbdesc_t))) == NULL) {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
edp->dted_probe = *pdp;
dt_ecbdesc_hold(edp);
return (edp);
}
dtrace_stmtdesc_t *
dtrace_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp)
{
dtrace_stmtdesc_t *sdp;
if ((sdp = dt_zalloc(dtp, sizeof (dtrace_stmtdesc_t))) == NULL)
return (NULL);
dt_ecbdesc_hold(edp);
sdp->dtsd_ecbdesc = edp;
sdp->dtsd_descattr = _dtrace_defattr;
sdp->dtsd_stmtattr = _dtrace_defattr;
return (sdp);
}
dtrace_actdesc_t *
dtrace_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
{
dtrace_actdesc_t *new;
dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
if ((new = dt_alloc(dtp, sizeof (dtrace_actdesc_t))) == NULL)
return (NULL);
if (sdp->dtsd_action_last != NULL) {
assert(sdp->dtsd_action != NULL);
assert(sdp->dtsd_action_last->dtad_next == NULL);
sdp->dtsd_action_last->dtad_next = new;
} else {
dtrace_actdesc_t *ap = edp->dted_action;
assert(sdp->dtsd_action == NULL);
sdp->dtsd_action = new;
while (ap != NULL && ap->dtad_next != NULL)
ap = ap->dtad_next;
if (ap == NULL)
edp->dted_action = new;
else
ap->dtad_next = new;
}
sdp->dtsd_action_last = new;
bzero(new, sizeof (dtrace_actdesc_t));
new->dtad_uarg = (uintptr_t)sdp;
return (new);
}
int
dtrace_stmt_add(dtrace_hdl_t *dtp, dtrace_prog_t *pgp, dtrace_stmtdesc_t *sdp)
{
dt_stmt_t *stp = dt_alloc(dtp, sizeof (dt_stmt_t));
if (stp == NULL)
return (-1); /* errno is set for us */
dt_list_append(&pgp->dp_stmts, stp);
stp->ds_desc = sdp;
return (0);
}
int
dtrace_stmt_iter(dtrace_hdl_t *dtp, dtrace_prog_t *pgp,
dtrace_stmt_f *func, void *data)
{
dt_stmt_t *stp, *next;
int status = 0;
for (stp = dt_list_next(&pgp->dp_stmts); stp != NULL; stp = next) {
next = dt_list_next(stp);
if ((status = func(dtp, pgp, stp->ds_desc, data)) != 0)
break;
}
return (status);
}
void
dtrace_stmt_destroy(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp)
{
dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc;
/*
* We need to remove any actions that we have on this ECB, and
* remove our hold on the ECB itself.
*/
if (sdp->dtsd_action != NULL) {
dtrace_actdesc_t *last = sdp->dtsd_action_last;
dtrace_actdesc_t *ap, *next;
assert(last != NULL);
for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) {
if (ap == sdp->dtsd_action)
break;
if (ap->dtad_next == sdp->dtsd_action)
break;
}
assert(ap != NULL);
if (ap == edp->dted_action)
edp->dted_action = last->dtad_next;
else
ap->dtad_next = last->dtad_next;
/*
* We have now removed our action list from its ECB; we can
* safely destroy the list.
*/
last->dtad_next = NULL;
for (ap = sdp->dtsd_action; ap != NULL; ap = next) {
assert(ap->dtad_uarg == (uintptr_t)sdp);
dt_difo_free(dtp, ap->dtad_difo);
next = ap->dtad_next;
dt_free(dtp, ap);
}
}
if (sdp->dtsd_fmtdata != NULL)
dt_printf_destroy(sdp->dtsd_fmtdata);
dt_ecbdesc_release(dtp, sdp->dtsd_ecbdesc);
dt_free(dtp, sdp);
}
typedef struct dt_header_info {
dtrace_hdl_t *dthi_dtp; /* consumer handle */
FILE *dthi_out; /* output file */
char *dthi_pmname; /* provider macro name */
char *dthi_pfname; /* provider function name */
int dthi_empty; /* should we generate empty macros */
} dt_header_info_t;
static void
dt_header_fmt_macro(char *buf, const char *str)
{
for (;;) {
if (islower(*str)) {
*buf++ = *str++ + 'A' - 'a';
} else if (*str == '-') {
*buf++ = '_';
str++;
} else if (*str == '.') {
*buf++ = '_';
str++;
} else if ((*buf++ = *str++) == '\0') {
break;
}
}
}
static void
dt_header_fmt_func(char *buf, const char *str)
{
for (;;) {
if (*str == '-') {
*buf++ = '_';
*buf++ = '_';
str++;
} else if ((*buf++ = *str++) == '\0') {
break;
}
}
}
/*ARGSUSED*/
static int
dt_header_decl(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
dt_header_info_t *infop = data;
dtrace_hdl_t *dtp = infop->dthi_dtp;
dt_probe_t *prp = idp->di_data;
dt_node_t *dnp;
char buf[DT_TYPE_NAMELEN];
char *fname;
const char *p;
int i;
p = prp->pr_name;
for (i = 0; (p = strchr(p, '-')) != NULL; i++)
p++;
fname = alloca(strlen(prp->pr_name) + 1 + i);
dt_header_fmt_func(fname, prp->pr_name);
if (fprintf(infop->dthi_out, "extern void __dtrace_%s___%s(",
infop->dthi_pfname, fname) < 0)
return (dt_set_errno(dtp, errno));
for (dnp = prp->pr_nargs, i = 0; dnp != NULL; dnp = dnp->dn_list, i++) {
if (fprintf(infop->dthi_out, "%s",
ctf_type_name(dnp->dn_ctfp, dnp->dn_type,
buf, sizeof (buf))) < 0)
return (dt_set_errno(dtp, errno));
if (i + 1 != prp->pr_nargc &&
fprintf(infop->dthi_out, ", ") < 0)
return (dt_set_errno(dtp, errno));
}
if (i == 0 && fprintf(infop->dthi_out, "void") < 0)
return (dt_set_errno(dtp, errno));
if (fprintf(infop->dthi_out, ");\n") < 0)
return (dt_set_errno(dtp, errno));
if (fprintf(infop->dthi_out, "extern int "
"__dtraceenabled_%s___%s(void);\n", infop->dthi_pfname, fname) < 0)
return (dt_set_errno(dtp, errno));
return (0);
}
/*ARGSUSED*/
static int
dt_header_probe(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
dt_header_info_t *infop = data;
dtrace_hdl_t *dtp = infop->dthi_dtp;
dt_probe_t *prp = idp->di_data;
char *mname, *fname;
const char *p;
int i;
p = prp->pr_name;
for (i = 0; (p = strchr(p, '-')) != NULL; i++)
p++;
mname = alloca(strlen(prp->pr_name) + 1);
dt_header_fmt_macro(mname, prp->pr_name);
fname = alloca(strlen(prp->pr_name) + 1 + i);
dt_header_fmt_func(fname, prp->pr_name);
if (fprintf(infop->dthi_out, "#define\t%s_%s(",
infop->dthi_pmname, mname) < 0)
return (dt_set_errno(dtp, errno));
for (i = 0; i < prp->pr_nargc; i++) {
if (fprintf(infop->dthi_out, "arg%d", i) < 0)
return (dt_set_errno(dtp, errno));
if (i + 1 != prp->pr_nargc &&
fprintf(infop->dthi_out, ", ") < 0)
return (dt_set_errno(dtp, errno));
}
if (!infop->dthi_empty) {
if (fprintf(infop->dthi_out, ") \\\n\t") < 0)
return (dt_set_errno(dtp, errno));
if (fprintf(infop->dthi_out, "__dtrace_%s___%s(",
infop->dthi_pfname, fname) < 0)
return (dt_set_errno(dtp, errno));
for (i = 0; i < prp->pr_nargc; i++) {
if (fprintf(infop->dthi_out, "arg%d", i) < 0)
return (dt_set_errno(dtp, errno));
if (i + 1 != prp->pr_nargc &&
fprintf(infop->dthi_out, ", ") < 0)
return (dt_set_errno(dtp, errno));
}
}
if (fprintf(infop->dthi_out, ")\n") < 0)
return (dt_set_errno(dtp, errno));
if (!infop->dthi_empty) {
if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() \\\n",
infop->dthi_pmname, mname) < 0)
return (dt_set_errno(dtp, errno));
if (fprintf(infop->dthi_out, "\t__dtraceenabled_%s___%s()\n",
infop->dthi_pfname, fname) < 0)
return (dt_set_errno(dtp, errno));
} else {
if (fprintf(infop->dthi_out, "#define\t%s_%s_ENABLED() (0)\n",
infop->dthi_pmname, mname) < 0)
return (dt_set_errno(dtp, errno));
}
return (0);
}
static int
dt_header_provider(dtrace_hdl_t *dtp, dt_provider_t *pvp, FILE *out)
{
dt_header_info_t info;
const char *p;
int i;
if (pvp->pv_flags & DT_PROVIDER_IMPL)
return (0);
/*
* Count the instances of the '-' character since we'll need to double
* those up.
*/
p = pvp->pv_desc.dtvd_name;
for (i = 0; (p = strchr(p, '-')) != NULL; i++)
p++;
info.dthi_dtp = dtp;
info.dthi_out = out;
info.dthi_empty = 0;
info.dthi_pmname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1);
dt_header_fmt_macro(info.dthi_pmname, pvp->pv_desc.dtvd_name);
info.dthi_pfname = alloca(strlen(pvp->pv_desc.dtvd_name) + 1 + i);
dt_header_fmt_func(info.dthi_pfname, pvp->pv_desc.dtvd_name);
if (fprintf(out, "#if _DTRACE_VERSION\n\n") < 0)
return (dt_set_errno(dtp, errno));
if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
return (-1); /* dt_errno is set for us */
if (fprintf(out, "\n\n") < 0)
return (dt_set_errno(dtp, errno));
if (dt_idhash_iter(pvp->pv_probes, dt_header_decl, &info) != 0)
return (-1); /* dt_errno is set for us */
if (fprintf(out, "\n#else\n\n") < 0)
return (dt_set_errno(dtp, errno));
info.dthi_empty = 1;
if (dt_idhash_iter(pvp->pv_probes, dt_header_probe, &info) != 0)
return (-1); /* dt_errno is set for us */
if (fprintf(out, "\n#endif\n\n") < 0)
return (dt_set_errno(dtp, errno));
return (0);
}
int
dtrace_program_header(dtrace_hdl_t *dtp, FILE *out, const char *fname)
{
dt_provider_t *pvp;
char *mfname, *p;
if (fname != NULL) {
if ((p = strrchr(fname, '/')) != NULL)
fname = p + 1;
mfname = alloca(strlen(fname) + 1);
dt_header_fmt_macro(mfname, fname);
if (fprintf(out, "#ifndef\t_%s\n#define\t_%s\n\n",
mfname, mfname) < 0)
return (dt_set_errno(dtp, errno));
}
if (fprintf(out, "#include <unistd.h>\n\n") < 0)
return (-1);
if (fprintf(out, "#ifdef\t__cplusplus\nextern \"C\" {\n#endif\n\n") < 0)
return (-1);
for (pvp = dt_list_next(&dtp->dt_provlist);
pvp != NULL; pvp = dt_list_next(pvp)) {
if (dt_header_provider(dtp, pvp, out) != 0)
return (-1); /* dt_errno is set for us */
}
if (fprintf(out, "\n#ifdef\t__cplusplus\n}\n#endif\n") < 0)
return (dt_set_errno(dtp, errno));
if (fname != NULL && fprintf(out, "\n#endif\t/* _%s */\n", mfname) < 0)
return (dt_set_errno(dtp, errno));
return (0);
}

View File

@ -0,0 +1,63 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PROGRAM_H
#define _DT_PROGRAM_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
#include <dtrace.h>
#include <dt_list.h>
typedef struct dt_stmt {
dt_list_t ds_list; /* list forward/back pointers */
dtrace_stmtdesc_t *ds_desc; /* pointer to statement description */
} dt_stmt_t;
struct dtrace_prog {
dt_list_t dp_list; /* list forward/back pointers */
dt_list_t dp_stmts; /* linked list of dt_stmt_t's */
ulong_t **dp_xrefs; /* array of translator reference bitmaps */
uint_t dp_xrefslen; /* length of dp_xrefs array */
uint8_t dp_dofversion; /* DOF version this program requires */
};
extern dtrace_prog_t *dt_program_create(dtrace_hdl_t *);
extern void dt_program_destroy(dtrace_hdl_t *, dtrace_prog_t *);
extern dtrace_ecbdesc_t *dt_ecbdesc_create(dtrace_hdl_t *,
const dtrace_probedesc_t *);
extern void dt_ecbdesc_release(dtrace_hdl_t *, dtrace_ecbdesc_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PROGRAM_H */

View File

@ -0,0 +1,883 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#if defined(sun)
#include <sys/sysmacros.h>
#endif
#include <assert.h>
#include <limits.h>
#include <strings.h>
#include <stdlib.h>
#if defined(sun)
#include <alloca.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <dt_provider.h>
#include <dt_module.h>
#include <dt_string.h>
#include <dt_list.h>
static dt_provider_t *
dt_provider_insert(dtrace_hdl_t *dtp, dt_provider_t *pvp, uint_t h)
{
dt_list_append(&dtp->dt_provlist, pvp);
pvp->pv_next = dtp->dt_provs[h];
dtp->dt_provs[h] = pvp;
dtp->dt_nprovs++;
return (pvp);
}
dt_provider_t *
dt_provider_lookup(dtrace_hdl_t *dtp, const char *name)
{
uint_t h = dt_strtab_hash(name, NULL) % dtp->dt_provbuckets;
dtrace_providerdesc_t desc;
dt_provider_t *pvp;
for (pvp = dtp->dt_provs[h]; pvp != NULL; pvp = pvp->pv_next) {
if (strcmp(pvp->pv_desc.dtvd_name, name) == 0)
return (pvp);
}
if (strisglob(name) || name[0] == '\0') {
(void) dt_set_errno(dtp, EDT_NOPROV);
return (NULL);
}
bzero(&desc, sizeof (desc));
(void) strlcpy(desc.dtvd_name, name, DTRACE_PROVNAMELEN);
if (dt_ioctl(dtp, DTRACEIOC_PROVIDER, &desc) == -1) {
(void) dt_set_errno(dtp, errno == ESRCH ? EDT_NOPROV : errno);
return (NULL);
}
if ((pvp = dt_provider_create(dtp, name)) == NULL)
return (NULL); /* dt_errno is set for us */
bcopy(&desc, &pvp->pv_desc, sizeof (desc));
pvp->pv_flags |= DT_PROVIDER_IMPL;
return (pvp);
}
dt_provider_t *
dt_provider_create(dtrace_hdl_t *dtp, const char *name)
{
dt_provider_t *pvp;
if ((pvp = dt_zalloc(dtp, sizeof (dt_provider_t))) == NULL)
return (NULL);
(void) strlcpy(pvp->pv_desc.dtvd_name, name, DTRACE_PROVNAMELEN);
pvp->pv_probes = dt_idhash_create(pvp->pv_desc.dtvd_name, NULL, 0, 0);
pvp->pv_gen = dtp->dt_gen;
pvp->pv_hdl = dtp;
if (pvp->pv_probes == NULL) {
dt_free(dtp, pvp);
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
pvp->pv_desc.dtvd_attr.dtpa_provider = _dtrace_prvattr;
pvp->pv_desc.dtvd_attr.dtpa_mod = _dtrace_prvattr;
pvp->pv_desc.dtvd_attr.dtpa_func = _dtrace_prvattr;
pvp->pv_desc.dtvd_attr.dtpa_name = _dtrace_prvattr;
pvp->pv_desc.dtvd_attr.dtpa_args = _dtrace_prvattr;
return (dt_provider_insert(dtp, pvp,
dt_strtab_hash(name, NULL) % dtp->dt_provbuckets));
}
void
dt_provider_destroy(dtrace_hdl_t *dtp, dt_provider_t *pvp)
{
dt_provider_t **pp;
uint_t h;
assert(pvp->pv_hdl == dtp);
h = dt_strtab_hash(pvp->pv_desc.dtvd_name, NULL) % dtp->dt_provbuckets;
pp = &dtp->dt_provs[h];
while (*pp != NULL && *pp != pvp)
pp = &(*pp)->pv_next;
assert(*pp != NULL && *pp == pvp);
*pp = pvp->pv_next;
dt_list_delete(&dtp->dt_provlist, pvp);
dtp->dt_nprovs--;
if (pvp->pv_probes != NULL)
dt_idhash_destroy(pvp->pv_probes);
dt_node_link_free(&pvp->pv_nodes);
dt_free(dtp, pvp->pv_xrefs);
dt_free(dtp, pvp);
}
int
dt_provider_xref(dtrace_hdl_t *dtp, dt_provider_t *pvp, id_t id)
{
size_t oldsize = BT_SIZEOFMAP(pvp->pv_xrmax);
size_t newsize = BT_SIZEOFMAP(dtp->dt_xlatorid);
assert(id >= 0 && id < dtp->dt_xlatorid);
if (newsize > oldsize) {
ulong_t *xrefs = dt_zalloc(dtp, newsize);
if (xrefs == NULL)
return (-1);
bcopy(pvp->pv_xrefs, xrefs, oldsize);
dt_free(dtp, pvp->pv_xrefs);
pvp->pv_xrefs = xrefs;
pvp->pv_xrmax = dtp->dt_xlatorid;
}
BT_SET(pvp->pv_xrefs, id);
return (0);
}
static uint8_t
dt_probe_argmap(dt_node_t *xnp, dt_node_t *nnp)
{
uint8_t i;
for (i = 0; nnp != NULL; i++) {
if (nnp->dn_string != NULL &&
strcmp(nnp->dn_string, xnp->dn_string) == 0)
break;
else
nnp = nnp->dn_list;
}
return (i);
}
static dt_node_t *
dt_probe_alloc_args(dt_provider_t *pvp, int argc)
{
dt_node_t *args = NULL, *pnp = NULL, *dnp;
int i;
for (i = 0; i < argc; i++, pnp = dnp) {
if ((dnp = dt_node_xalloc(pvp->pv_hdl, DT_NODE_TYPE)) == NULL)
return (NULL);
dnp->dn_link = pvp->pv_nodes;
pvp->pv_nodes = dnp;
if (args == NULL)
args = dnp;
else
pnp->dn_list = dnp;
}
return (args);
}
static size_t
dt_probe_keylen(const dtrace_probedesc_t *pdp)
{
return (strlen(pdp->dtpd_mod) + 1 +
strlen(pdp->dtpd_func) + 1 + strlen(pdp->dtpd_name) + 1);
}
static char *
dt_probe_key(const dtrace_probedesc_t *pdp, char *s)
{
(void) snprintf(s, INT_MAX, "%s:%s:%s",
pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
return (s);
}
/*
* If a probe was discovered from the kernel, ask dtrace(7D) for a description
* of each of its arguments, including native and translated types.
*/
static dt_probe_t *
dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
{
dtrace_hdl_t *dtp = pvp->pv_hdl;
char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp)));
dt_node_t *xargs, *nargs;
dt_ident_t *idp;
dt_probe_t *prp;
dtrace_typeinfo_t dtt;
int i, nc, xc;
int adc = _dtrace_argmax;
dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc);
dtrace_argdesc_t *adp = adv;
assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0);
assert(pdp->dtpd_id != DTRACE_IDNONE);
dt_dprintf("discovering probe %s:%s id=%d\n",
pvp->pv_desc.dtvd_name, name, pdp->dtpd_id);
for (nc = -1, i = 0; i < adc; i++, adp++) {
bzero(adp, sizeof (dtrace_argdesc_t));
adp->dtargd_ndx = i;
adp->dtargd_id = pdp->dtpd_id;
if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) {
(void) dt_set_errno(dtp, errno);
return (NULL);
}
if (adp->dtargd_ndx == DTRACE_ARGNONE)
break; /* all argument descs have been retrieved */
nc = MAX(nc, adp->dtargd_mapping);
}
xc = i;
nc++;
/*
* Now that we have discovered the number of native and translated
* arguments from the argument descriptions, allocate a new probe ident
* and corresponding dt_probe_t and hash it into the provider.
*/
xargs = dt_probe_alloc_args(pvp, xc);
nargs = dt_probe_alloc_args(pvp, nc);
if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL))
return (NULL); /* dt_errno is set for us */
idp = dt_ident_create(name, DT_IDENT_PROBE,
DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0,
&dt_idops_probe, NULL, dtp->dt_gen);
if (idp == NULL) {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
if ((prp = dt_probe_create(dtp, idp, 2,
nargs, nc, xargs, xc)) == NULL) {
dt_ident_destroy(idp);
return (NULL);
}
dt_probe_declare(pvp, prp);
/*
* Once our new dt_probe_t is fully constructed, iterate over the
* cached argument descriptions and assign types to prp->pr_nargv[]
* and prp->pr_xargv[] and assign mappings to prp->pr_mapping[].
*/
for (adp = adv, i = 0; i < xc; i++, adp++) {
if (dtrace_type_strcompile(dtp,
adp->dtargd_native, &dtt) != 0) {
dt_dprintf("failed to resolve input type %s "
"for %s:%s arg #%d: %s\n", adp->dtargd_native,
pvp->pv_desc.dtvd_name, name, i + 1,
dtrace_errmsg(dtp, dtrace_errno(dtp)));
dtt.dtt_object = NULL;
dtt.dtt_ctfp = NULL;
dtt.dtt_type = CTF_ERR;
} else {
dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
dtt.dtt_ctfp, dtt.dtt_type);
}
if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) {
dt_node_type_propagate(prp->pr_nargv[
adp->dtargd_mapping], prp->pr_xargv[i]);
} else if (dtrace_type_strcompile(dtp,
adp->dtargd_xlate, &dtt) != 0) {
dt_dprintf("failed to resolve output type %s "
"for %s:%s arg #%d: %s\n", adp->dtargd_xlate,
pvp->pv_desc.dtvd_name, name, i + 1,
dtrace_errmsg(dtp, dtrace_errno(dtp)));
dtt.dtt_object = NULL;
dtt.dtt_ctfp = NULL;
dtt.dtt_type = CTF_ERR;
} else {
dt_node_type_assign(prp->pr_xargv[i],
dtt.dtt_ctfp, dtt.dtt_type);
}
prp->pr_mapping[i] = adp->dtargd_mapping;
prp->pr_argv[i] = dtt;
}
return (prp);
}
/*
* Lookup a probe declaration based on a known provider and full or partially
* specified module, function, and name. If the probe is not known to us yet,
* ask dtrace(7D) to match the description and then cache any useful results.
*/
dt_probe_t *
dt_probe_lookup(dt_provider_t *pvp, const char *s)
{
dtrace_hdl_t *dtp = pvp->pv_hdl;
dtrace_probedesc_t pd;
dt_ident_t *idp;
size_t keylen;
char *key;
if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0)
return (NULL); /* dt_errno is set for us */
keylen = dt_probe_keylen(&pd);
key = dt_probe_key(&pd, alloca(keylen));
/*
* If the probe is already declared, then return the dt_probe_t from
* the existing identifier. This could come from a static declaration
* or it could have been cached from an earlier call to this function.
*/
if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
return (idp->di_data);
/*
* If the probe isn't known, use the probe description computed above
* to ask dtrace(7D) to find the first matching probe.
*/
if (dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) == 0)
return (dt_probe_discover(pvp, &pd));
if (errno == ESRCH || errno == EBADF)
(void) dt_set_errno(dtp, EDT_NOPROBE);
else
(void) dt_set_errno(dtp, errno);
return (NULL);
}
dt_probe_t *
dt_probe_create(dtrace_hdl_t *dtp, dt_ident_t *idp, int protoc,
dt_node_t *nargs, uint_t nargc, dt_node_t *xargs, uint_t xargc)
{
dt_module_t *dmp;
dt_probe_t *prp;
const char *p;
uint_t i;
assert(idp->di_kind == DT_IDENT_PROBE);
assert(idp->di_data == NULL);
/*
* If only a single prototype is given, set xargc/s to nargc/s to
* simplify subsequent use. Note that we can have one or both of nargs
* and xargs be specified but set to NULL, indicating a void prototype.
*/
if (protoc < 2) {
assert(xargs == NULL);
assert(xargc == 0);
xargs = nargs;
xargc = nargc;
}
if ((prp = dt_alloc(dtp, sizeof (dt_probe_t))) == NULL)
return (NULL);
prp->pr_pvp = NULL;
prp->pr_ident = idp;
p = strrchr(idp->di_name, ':');
assert(p != NULL);
prp->pr_name = p + 1;
prp->pr_nargs = nargs;
prp->pr_nargv = dt_alloc(dtp, sizeof (dt_node_t *) * nargc);
prp->pr_nargc = nargc;
prp->pr_xargs = xargs;
prp->pr_xargv = dt_alloc(dtp, sizeof (dt_node_t *) * xargc);
prp->pr_xargc = xargc;
prp->pr_mapping = dt_alloc(dtp, sizeof (uint8_t) * xargc);
prp->pr_inst = NULL;
prp->pr_argv = dt_alloc(dtp, sizeof (dtrace_typeinfo_t) * xargc);
prp->pr_argc = xargc;
if ((prp->pr_nargc != 0 && prp->pr_nargv == NULL) ||
(prp->pr_xargc != 0 && prp->pr_xargv == NULL) ||
(prp->pr_xargc != 0 && prp->pr_mapping == NULL) ||
(prp->pr_argc != 0 && prp->pr_argv == NULL)) {
dt_probe_destroy(prp);
return (NULL);
}
for (i = 0; i < xargc; i++, xargs = xargs->dn_list) {
if (xargs->dn_string != NULL)
prp->pr_mapping[i] = dt_probe_argmap(xargs, nargs);
else
prp->pr_mapping[i] = i;
prp->pr_xargv[i] = xargs;
if ((dmp = dt_module_lookup_by_ctf(dtp,
xargs->dn_ctfp)) != NULL)
prp->pr_argv[i].dtt_object = dmp->dm_name;
else
prp->pr_argv[i].dtt_object = NULL;
prp->pr_argv[i].dtt_ctfp = xargs->dn_ctfp;
prp->pr_argv[i].dtt_type = xargs->dn_type;
}
for (i = 0; i < nargc; i++, nargs = nargs->dn_list)
prp->pr_nargv[i] = nargs;
idp->di_data = prp;
return (prp);
}
void
dt_probe_declare(dt_provider_t *pvp, dt_probe_t *prp)
{
assert(prp->pr_ident->di_kind == DT_IDENT_PROBE);
assert(prp->pr_ident->di_data == prp);
assert(prp->pr_pvp == NULL);
if (prp->pr_xargs != prp->pr_nargs)
pvp->pv_flags &= ~DT_PROVIDER_INTF;
prp->pr_pvp = pvp;
dt_idhash_xinsert(pvp->pv_probes, prp->pr_ident);
}
void
dt_probe_destroy(dt_probe_t *prp)
{
dt_probe_instance_t *pip, *pip_next;
dtrace_hdl_t *dtp;
if (prp->pr_pvp != NULL)
dtp = prp->pr_pvp->pv_hdl;
else
dtp = yypcb->pcb_hdl;
dt_node_list_free(&prp->pr_nargs);
dt_node_list_free(&prp->pr_xargs);
dt_free(dtp, prp->pr_nargv);
dt_free(dtp, prp->pr_xargv);
for (pip = prp->pr_inst; pip != NULL; pip = pip_next) {
pip_next = pip->pi_next;
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip->pi_enoffs);
dt_free(dtp, pip);
}
dt_free(dtp, prp->pr_mapping);
dt_free(dtp, prp->pr_argv);
dt_free(dtp, prp);
}
int
dt_probe_define(dt_provider_t *pvp, dt_probe_t *prp,
const char *fname, const char *rname, uint32_t offset, int isenabled)
{
dtrace_hdl_t *dtp = pvp->pv_hdl;
dt_probe_instance_t *pip;
uint32_t **offs;
uint_t *noffs, *maxoffs;
assert(fname != NULL);
for (pip = prp->pr_inst; pip != NULL; pip = pip->pi_next) {
if (strcmp(pip->pi_fname, fname) == 0 &&
((rname == NULL && pip->pi_rname[0] == '\0') ||
(rname != NULL && strcmp(pip->pi_rname, rname)) == 0))
break;
}
if (pip == NULL) {
if ((pip = dt_zalloc(dtp, sizeof (*pip))) == NULL)
return (-1);
if ((pip->pi_offs = dt_zalloc(dtp,
sizeof (uint32_t))) == NULL) {
dt_free(dtp, pip);
return (-1);
}
if ((pip->pi_enoffs = dt_zalloc(dtp,
sizeof (uint32_t))) == NULL) {
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip);
return (-1);
}
(void) strlcpy(pip->pi_fname, fname, sizeof (pip->pi_fname));
if (rname != NULL) {
if (strlen(rname) + 1 > sizeof (pip->pi_rname)) {
dt_free(dtp, pip->pi_offs);
dt_free(dtp, pip);
return (dt_set_errno(dtp, EDT_COMPILER));
}
(void) strcpy(pip->pi_rname, rname);
}
pip->pi_noffs = 0;
pip->pi_maxoffs = 1;
pip->pi_nenoffs = 0;
pip->pi_maxenoffs = 1;
pip->pi_next = prp->pr_inst;
prp->pr_inst = pip;
}
if (isenabled) {
offs = &pip->pi_enoffs;
noffs = &pip->pi_nenoffs;
maxoffs = &pip->pi_maxenoffs;
} else {
offs = &pip->pi_offs;
noffs = &pip->pi_noffs;
maxoffs = &pip->pi_maxoffs;
}
if (*noffs == *maxoffs) {
uint_t new_max = *maxoffs * 2;
uint32_t *new_offs = dt_alloc(dtp, sizeof (uint32_t) * new_max);
if (new_offs == NULL)
return (-1);
bcopy(*offs, new_offs, sizeof (uint32_t) * *maxoffs);
dt_free(dtp, *offs);
*maxoffs = new_max;
*offs = new_offs;
}
dt_dprintf("defined probe %s %s:%s %s() +0x%x (%s)\n",
isenabled ? "(is-enabled)" : "",
pvp->pv_desc.dtvd_name, prp->pr_ident->di_name, fname, offset,
rname != NULL ? rname : fname);
assert(*noffs < *maxoffs);
(*offs)[(*noffs)++] = offset;
return (0);
}
/*
* Lookup the dynamic translator type tag for the specified probe argument and
* assign the type to the specified node. If the type is not yet defined, add
* it to the "D" module's type container as a typedef for an unknown type.
*/
dt_node_t *
dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
{
dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl;
dtrace_typeinfo_t dtt;
size_t len;
char *tag;
len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u",
prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);
tag = alloca(len + 1);
(void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u",
prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);
if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) {
dtt.dtt_object = DTRACE_OBJ_DDEFS;
dtt.dtt_ctfp = DT_DYN_CTFP(dtp);
dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp),
CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp));
if (dtt.dtt_type == CTF_ERR ||
ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
xyerror(D_UNKNOWN, "cannot define type %s: %s\n",
tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
}
}
bzero(dnp, sizeof (dt_node_t));
dnp->dn_kind = DT_NODE_TYPE;
dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type);
dt_node_attr_assign(dnp, _dtrace_defattr);
return (dnp);
}
/*ARGSUSED*/
static int
dt_probe_desc(dtrace_hdl_t *dtp, const dtrace_probedesc_t *pdp, void *arg)
{
if (((dtrace_probedesc_t *)arg)->dtpd_id == DTRACE_IDNONE) {
bcopy(pdp, arg, sizeof (dtrace_probedesc_t));
return (0);
}
return (1);
}
dt_probe_t *
dt_probe_info(dtrace_hdl_t *dtp,
const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
{
int m_is_glob = pdp->dtpd_mod[0] == '\0' || strisglob(pdp->dtpd_mod);
int f_is_glob = pdp->dtpd_func[0] == '\0' || strisglob(pdp->dtpd_func);
int n_is_glob = pdp->dtpd_name[0] == '\0' || strisglob(pdp->dtpd_name);
dt_probe_t *prp = NULL;
const dtrace_pattr_t *pap;
dt_provider_t *pvp;
dt_ident_t *idp;
/*
* Attempt to lookup the probe in our existing cache for this provider.
* If none is found and an explicit probe ID was specified, discover
* that specific probe and cache its description and arguments.
*/
if ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) != NULL) {
size_t keylen = dt_probe_keylen(pdp);
char *key = dt_probe_key(pdp, alloca(keylen));
if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
prp = idp->di_data;
else if (pdp->dtpd_id != DTRACE_IDNONE)
prp = dt_probe_discover(pvp, pdp);
}
/*
* If no probe was found in our cache, convert the caller's partial
* probe description into a fully-formed matching probe description by
* iterating over up to at most two probes that match 'pdp'. We then
* call dt_probe_discover() on the resulting probe identifier.
*/
if (prp == NULL) {
dtrace_probedesc_t pd;
int m;
bzero(&pd, sizeof (pd));
pd.dtpd_id = DTRACE_IDNONE;
/*
* Call dtrace_probe_iter() to find matching probes. Our
* dt_probe_desc() callback will produce the following results:
*
* m < 0 dtrace_probe_iter() found zero matches (or failed).
* m > 0 dtrace_probe_iter() found more than one match.
* m = 0 dtrace_probe_iter() found exactly one match.
*/
if ((m = dtrace_probe_iter(dtp, pdp, dt_probe_desc, &pd)) < 0)
return (NULL); /* dt_errno is set for us */
if ((pvp = dt_provider_lookup(dtp, pd.dtpd_provider)) == NULL)
return (NULL); /* dt_errno is set for us */
/*
* If more than one probe was matched, then do not report probe
* information if either of the following conditions is true:
*
* (a) The Arguments Data stability of the matched provider is
* less than Evolving.
*
* (b) Any description component that is at least Evolving is
* empty or is specified using a globbing expression.
*
* These conditions imply that providers that provide Evolving
* or better Arguments Data stability must guarantee that all
* probes with identical field names in a field of Evolving or
* better Name stability have identical argument signatures.
*/
if (m > 0) {
if (pvp->pv_desc.dtvd_attr.dtpa_args.dtat_data <
DTRACE_STABILITY_EVOLVING) {
(void) dt_set_errno(dtp, EDT_UNSTABLE);
return (NULL);
}
if (pvp->pv_desc.dtvd_attr.dtpa_mod.dtat_name >=
DTRACE_STABILITY_EVOLVING && m_is_glob) {
(void) dt_set_errno(dtp, EDT_UNSTABLE);
return (NULL);
}
if (pvp->pv_desc.dtvd_attr.dtpa_func.dtat_name >=
DTRACE_STABILITY_EVOLVING && f_is_glob) {
(void) dt_set_errno(dtp, EDT_UNSTABLE);
return (NULL);
}
if (pvp->pv_desc.dtvd_attr.dtpa_name.dtat_name >=
DTRACE_STABILITY_EVOLVING && n_is_glob) {
(void) dt_set_errno(dtp, EDT_UNSTABLE);
return (NULL);
}
}
/*
* If we matched a probe exported by dtrace(7D), then discover
* the real attributes. Otherwise grab the static declaration.
*/
if (pd.dtpd_id != DTRACE_IDNONE)
prp = dt_probe_discover(pvp, &pd);
else
prp = dt_probe_lookup(pvp, pd.dtpd_name);
if (prp == NULL)
return (NULL); /* dt_errno is set for us */
}
assert(pvp != NULL && prp != NULL);
/*
* Compute the probe description attributes by taking the minimum of
* the attributes of the specified fields. If no provider is specified
* or a glob pattern is used for the provider, use Unstable attributes.
*/
if (pdp->dtpd_provider[0] == '\0' || strisglob(pdp->dtpd_provider))
pap = &_dtrace_prvdesc;
else
pap = &pvp->pv_desc.dtvd_attr;
pip->dtp_attr = pap->dtpa_provider;
if (!m_is_glob)
pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_mod);
if (!f_is_glob)
pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_func);
if (!n_is_glob)
pip->dtp_attr = dt_attr_min(pip->dtp_attr, pap->dtpa_name);
pip->dtp_arga = pap->dtpa_args;
pip->dtp_argv = prp->pr_argv;
pip->dtp_argc = prp->pr_argc;
return (prp);
}
int
dtrace_probe_info(dtrace_hdl_t *dtp,
const dtrace_probedesc_t *pdp, dtrace_probeinfo_t *pip)
{
return (dt_probe_info(dtp, pdp, pip) != NULL ? 0 : -1);
}
/*ARGSUSED*/
static int
dt_probe_iter(dt_idhash_t *ihp, dt_ident_t *idp, dt_probe_iter_t *pit)
{
const dt_probe_t *prp = idp->di_data;
if (!dt_gmatch(prp->pr_name, pit->pit_pat))
return (0); /* continue on and examine next probe in hash */
(void) strlcpy(pit->pit_desc.dtpd_name, prp->pr_name, DTRACE_NAMELEN);
pit->pit_desc.dtpd_id = idp->di_id;
pit->pit_matches++;
return (pit->pit_func(pit->pit_hdl, &pit->pit_desc, pit->pit_arg));
}
int
dtrace_probe_iter(dtrace_hdl_t *dtp,
const dtrace_probedesc_t *pdp, dtrace_probe_f *func, void *arg)
{
const char *provider = pdp ? pdp->dtpd_provider : NULL;
dtrace_id_t id = DTRACE_IDNONE;
dtrace_probedesc_t pd;
dt_probe_iter_t pit;
int cmd, rv;
bzero(&pit, sizeof (pit));
pit.pit_hdl = dtp;
pit.pit_func = func;
pit.pit_arg = arg;
pit.pit_pat = pdp ? pdp->dtpd_name : NULL;
for (pit.pit_pvp = dt_list_next(&dtp->dt_provlist);
pit.pit_pvp != NULL; pit.pit_pvp = dt_list_next(pit.pit_pvp)) {
if (pit.pit_pvp->pv_flags & DT_PROVIDER_IMPL)
continue; /* we'll get these later using dt_ioctl() */
if (!dt_gmatch(pit.pit_pvp->pv_desc.dtvd_name, provider))
continue;
(void) strlcpy(pit.pit_desc.dtpd_provider,
pit.pit_pvp->pv_desc.dtvd_name, DTRACE_PROVNAMELEN);
if ((rv = dt_idhash_iter(pit.pit_pvp->pv_probes,
(dt_idhash_f *)dt_probe_iter, &pit)) != 0)
return (rv);
}
if (pdp != NULL)
cmd = DTRACEIOC_PROBEMATCH;
else
cmd = DTRACEIOC_PROBES;
for (;;) {
if (pdp != NULL)
bcopy(pdp, &pd, sizeof (pd));
pd.dtpd_id = id;
if (dt_ioctl(dtp, cmd, &pd) != 0)
break;
else if ((rv = func(dtp, &pd, arg)) != 0)
return (rv);
pit.pit_matches++;
id = pd.dtpd_id + 1;
}
switch (errno) {
case ESRCH:
case EBADF:
return (pit.pit_matches ? 0 : dt_set_errno(dtp, EDT_NOPROBE));
case EINVAL:
return (dt_set_errno(dtp, EDT_BADPGLOB));
default:
return (dt_set_errno(dtp, errno));
}
}

View File

@ -0,0 +1,118 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_PROVIDER_H
#define _DT_PROVIDER_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dt_impl.h>
#include <dt_ident.h>
#include <dt_list.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_provider {
dt_list_t pv_list; /* list forward/back pointers */
struct dt_provider *pv_next; /* pointer to next provider in hash */
dtrace_providerdesc_t pv_desc; /* provider name and attributes */
dt_idhash_t *pv_probes; /* probe defs (if user-declared) */
dt_node_t *pv_nodes; /* parse node allocation list */
ulong_t *pv_xrefs; /* translator reference bitmap */
ulong_t pv_xrmax; /* number of valid bits in pv_xrefs */
ulong_t pv_gen; /* generation # that created me */
dtrace_hdl_t *pv_hdl; /* pointer to containing dtrace_hdl */
uint_t pv_flags; /* flags (see below) */
} dt_provider_t;
#define DT_PROVIDER_INTF 0x1 /* provider interface declaration */
#define DT_PROVIDER_IMPL 0x2 /* provider implementation is loaded */
typedef struct dt_probe_iter {
dtrace_probedesc_t pit_desc; /* description storage */
dtrace_hdl_t *pit_hdl; /* libdtrace handle */
dt_provider_t *pit_pvp; /* current provider */
const char *pit_pat; /* caller's name pattern (or NULL) */
dtrace_probe_f *pit_func; /* caller's function */
void *pit_arg; /* caller's argument */
uint_t pit_matches; /* number of matches */
} dt_probe_iter_t;
typedef struct dt_probe_instance {
char pi_fname[DTRACE_FUNCNAMELEN]; /* function name */
char pi_rname[DTRACE_FUNCNAMELEN + 20]; /* mangled relocation name */
uint32_t *pi_offs; /* offsets into the function */
uint32_t *pi_enoffs; /* is-enabled offsets */
uint_t pi_noffs; /* number of offsets */
uint_t pi_maxoffs; /* size of pi_offs allocation */
uint_t pi_nenoffs; /* number of is-enabled offsets */
uint_t pi_maxenoffs; /* size of pi_enoffs allocation */
struct dt_probe_instance *pi_next; /* next instance in the list */
} dt_probe_instance_t;
typedef struct dt_probe {
dt_provider_t *pr_pvp; /* pointer to containing provider */
dt_ident_t *pr_ident; /* pointer to probe identifier */
const char *pr_name; /* pointer to name component */
dt_node_t *pr_nargs; /* native argument list */
dt_node_t **pr_nargv; /* native argument vector */
uint_t pr_nargc; /* native argument count */
dt_node_t *pr_xargs; /* translated argument list */
dt_node_t **pr_xargv; /* translated argument vector */
uint_t pr_xargc; /* translated argument count */
uint8_t *pr_mapping; /* translated argument mapping */
dt_probe_instance_t *pr_inst; /* list of functions and offsets */
dtrace_typeinfo_t *pr_argv; /* output argument types */
int pr_argc; /* output argument count */
} dt_probe_t;
extern dt_provider_t *dt_provider_lookup(dtrace_hdl_t *, const char *);
extern dt_provider_t *dt_provider_create(dtrace_hdl_t *, const char *);
extern void dt_provider_destroy(dtrace_hdl_t *, dt_provider_t *);
extern int dt_provider_xref(dtrace_hdl_t *, dt_provider_t *, id_t);
extern dt_probe_t *dt_probe_create(dtrace_hdl_t *, dt_ident_t *, int,
dt_node_t *, uint_t, dt_node_t *, uint_t);
extern dt_probe_t *dt_probe_info(dtrace_hdl_t *,
const dtrace_probedesc_t *, dtrace_probeinfo_t *);
extern dt_probe_t *dt_probe_lookup(dt_provider_t *, const char *);
extern void dt_probe_declare(dt_provider_t *, dt_probe_t *);
extern void dt_probe_destroy(dt_probe_t *);
extern int dt_probe_define(dt_provider_t *, dt_probe_t *,
const char *, const char *, uint32_t, int);
extern dt_node_t *dt_probe_tag(dt_probe_t *, uint_t, dt_node_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_PROVIDER_H */

View File

@ -0,0 +1,107 @@
/*
* 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
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/bitmap.h>
#include <assert.h>
#include <strings.h>
#include <stdlib.h>
#include <dt_regset.h>
dt_regset_t *
dt_regset_create(ulong_t size)
{
ulong_t n = BT_BITOUL(size + 1); /* + 1 for %r0 */
dt_regset_t *drp = malloc(sizeof (dt_regset_t));
if (drp == NULL)
return (NULL);
drp->dr_bitmap = malloc(sizeof (ulong_t) * n);
drp->dr_size = size + 1;
if (drp->dr_bitmap == NULL) {
dt_regset_destroy(drp);
return (NULL);
}
bzero(drp->dr_bitmap, sizeof (ulong_t) * n);
return (drp);
}
void
dt_regset_destroy(dt_regset_t *drp)
{
free(drp->dr_bitmap);
free(drp);
}
void
dt_regset_reset(dt_regset_t *drp)
{
bzero(drp->dr_bitmap, sizeof (ulong_t) * BT_BITOUL(drp->dr_size));
}
int
dt_regset_alloc(dt_regset_t *drp)
{
ulong_t nbits = drp->dr_size - 1;
ulong_t maxw = nbits >> BT_ULSHIFT;
ulong_t wx;
for (wx = 0; wx <= maxw; wx++) {
if (drp->dr_bitmap[wx] != ~0UL)
break;
}
if (wx <= maxw) {
ulong_t maxb = (wx == maxw) ? nbits & BT_ULMASK : BT_NBIPUL - 1;
ulong_t word = drp->dr_bitmap[wx];
ulong_t bit, bx;
int reg;
for (bit = 1, bx = 0; bx <= maxb; bx++, bit <<= 1) {
if ((word & bit) == 0) {
reg = (int)((wx << BT_ULSHIFT) | bx);
BT_SET(drp->dr_bitmap, reg);
return (reg);
}
}
}
return (-1); /* no available registers */
}
void
dt_regset_free(dt_regset_t *drp, int reg)
{
assert(reg > 0 && reg < drp->dr_size);
assert(BT_TEST(drp->dr_bitmap, reg) != 0);
BT_CLEAR(drp->dr_bitmap, reg);
}

View File

@ -0,0 +1,53 @@
/*
* 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
*/
/*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_REGSET_H
#define _DT_REGSET_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_regset {
ulong_t dr_size; /* number of registers in set */
ulong_t *dr_bitmap; /* bitmap of active registers */
} dt_regset_t;
extern dt_regset_t *dt_regset_create(ulong_t);
extern void dt_regset_destroy(dt_regset_t *);
extern void dt_regset_reset(dt_regset_t *);
extern int dt_regset_alloc(dt_regset_t *);
extern void dt_regset_free(dt_regset_t *, int);
#ifdef __cplusplus
}
#endif
#endif /* _DT_REGSET_H */

View File

@ -0,0 +1,325 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <strings.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <dt_string.h>
/*
* Create a copy of string s, but only duplicate the first n bytes.
*/
char *
strndup(const char *s, size_t n)
{
char *s2 = malloc(n + 1);
(void) strncpy(s2, s, n);
s2[n] = '\0';
return (s2);
}
/*
* Transform string s inline, converting each embedded C escape sequence string
* to the corresponding character. For example, the substring "\n" is replaced
* by an inline '\n' character. The length of the resulting string is returned.
*/
size_t
stresc2chr(char *s)
{
char *p, *q, c;
int esc = 0;
int x;
for (p = q = s; (c = *p) != '\0'; p++) {
if (esc) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c -= '0';
p++;
if (*p >= '0' && *p <= '7') {
c = c * 8 + *p++ - '0';
if (*p >= '0' && *p <= '7')
c = c * 8 + *p - '0';
else
p--;
} else
p--;
*q++ = c;
break;
case 'a':
*q++ = '\a';
break;
case 'b':
*q++ = '\b';
break;
case 'f':
*q++ = '\f';
break;
case 'n':
*q++ = '\n';
break;
case 'r':
*q++ = '\r';
break;
case 't':
*q++ = '\t';
break;
case 'v':
*q++ = '\v';
break;
case 'x':
for (x = 0; (c = *++p) != '\0'; ) {
if (c >= '0' && c <= '9')
x = x * 16 + c - '0';
else if (c >= 'a' && c <= 'f')
x = x * 16 + c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
x = x * 16 + c - 'A' + 10;
else
break;
}
*q++ = (char)x;
p--;
break;
case '"':
case '\\':
*q++ = c;
break;
default:
*q++ = '\\';
*q++ = c;
}
esc = 0;
} else {
if ((esc = c == '\\') == 0)
*q++ = c;
}
}
*q = '\0';
return ((size_t)(q - s));
}
/*
* Create a copy of string s in which certain unprintable or special characters
* have been converted to the string representation of their C escape sequence.
* For example, the newline character is expanded to the string "\n".
*/
char *
strchr2esc(const char *s, size_t n)
{
const char *p;
char *q, *s2, c;
size_t addl = 0;
for (p = s; p < s + n; p++) {
switch (c = *p) {
case '\0':
case '\a':
case '\b':
case '\f':
case '\n':
case '\r':
case '\t':
case '\v':
case '"':
case '\\':
addl++; /* 1 add'l char needed to follow \ */
break;
case ' ':
break;
default:
if (c < '!' || c > '~')
addl += 3; /* 3 add'l chars following \ */
}
}
if ((s2 = malloc(n + addl + 1)) == NULL)
return (NULL);
for (p = s, q = s2; p < s + n; p++) {
switch (c = *p) {
case '\0':
*q++ = '\\';
*q++ = '0';
break;
case '\a':
*q++ = '\\';
*q++ = 'a';
break;
case '\b':
*q++ = '\\';
*q++ = 'b';
break;
case '\f':
*q++ = '\\';
*q++ = 'f';
break;
case '\n':
*q++ = '\\';
*q++ = 'n';
break;
case '\r':
*q++ = '\\';
*q++ = 'r';
break;
case '\t':
*q++ = '\\';
*q++ = 't';
break;
case '\v':
*q++ = '\\';
*q++ = 'v';
break;
case '"':
*q++ = '\\';
*q++ = '"';
break;
case '\\':
*q++ = '\\';
*q++ = '\\';
break;
case ' ':
*q++ = c;
break;
default:
if (c < '!' || c > '~') {
*q++ = '\\';
*q++ = ((c >> 6) & 3) + '0';
*q++ = ((c >> 3) & 7) + '0';
*q++ = (c & 7) + '0';
} else
*q++ = c;
}
if (c == '\0')
break; /* don't continue past \0 even if p < s + n */
}
*q = '\0';
return (s2);
}
/*
* Return the basename (name after final /) of the given string. We use
* strbasename rather than basename to avoid conflicting with libgen.h's
* non-const function prototype.
*/
const char *
strbasename(const char *s)
{
const char *p = strrchr(s, '/');
if (p == NULL)
return (s);
return (++p);
}
/*
* This function tests a string against the regular expression used for idents
* and integers in the D lexer, and should match the superset of RGX_IDENT and
* RGX_INT in dt_lex.l. If an invalid character is found, the function returns
* a pointer to it. Otherwise NULL is returned for a valid string.
*/
const char *
strbadidnum(const char *s)
{
char *p;
int c;
if (*s == '\0')
return (s);
errno = 0;
(void) strtoull(s, &p, 0);
if (errno == 0 && *p == '\0')
return (NULL); /* matches RGX_INT */
while ((c = *s++) != '\0') {
if (isalnum(c) == 0 && c != '_' && c != '`')
return (s - 1);
}
return (NULL); /* matches RGX_IDENT */
}
/*
* Determine whether the string contains a glob matching pattern or is just a
* simple string. See gmatch(3GEN) and sh(1) for the glob syntax definition.
*/
int
strisglob(const char *s)
{
char c;
while ((c = *s++) != '\0') {
if (c == '[' || c == '?' || c == '*' || c == '\\')
return (1);
}
return (0);
}
/*
* Hyphenate a string in-place by converting any instances of "__" to "-",
* which we use for probe names to improve readability, and return the string.
*/
char *
strhyphenate(char *s)
{
char *p, *q;
for (p = s, q = p + strlen(p); p < q; p++) {
if (p[0] == '_' && p[1] == '_') {
p[0] = '-';
bcopy(p + 2, p + 1, (size_t)(q - p) - 1);
}
}
return (s);
}

View File

@ -0,0 +1,51 @@
/*
* 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
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_STRING_H
#define _DT_STRING_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <strings.h>
#ifdef __cplusplus
extern "C" {
#endif
extern char *strndup(const char *, size_t);
extern size_t stresc2chr(char *);
extern char *strchr2esc(const char *, size_t);
extern const char *strbasename(const char *);
extern const char *strbadidnum(const char *);
extern int strisglob(const char *);
extern char *strhyphenate(char *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_STRING_H */

View File

@ -0,0 +1,293 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <strings.h>
#include <stdlib.h>
#include <assert.h>
#include <dt_strtab.h>
#include <dt_impl.h>
static int
dt_strtab_grow(dt_strtab_t *sp)
{
char *ptr, **bufs;
if ((ptr = malloc(sp->str_bufsz)) == NULL)
return (-1);
bufs = realloc(sp->str_bufs, (sp->str_nbufs + 1) * sizeof (char *));
if (bufs == NULL) {
free(ptr);
return (-1);
}
sp->str_nbufs++;
sp->str_bufs = bufs;
sp->str_ptr = ptr;
sp->str_bufs[sp->str_nbufs - 1] = sp->str_ptr;
return (0);
}
dt_strtab_t *
dt_strtab_create(size_t bufsz)
{
dt_strtab_t *sp = malloc(sizeof (dt_strtab_t));
uint_t nbuckets = _dtrace_strbuckets;
assert(bufsz != 0);
if (sp == NULL)
return (NULL);
bzero(sp, sizeof (dt_strtab_t));
sp->str_hash = malloc(nbuckets * sizeof (dt_strhash_t *));
if (sp->str_hash == NULL)
goto err;
bzero(sp->str_hash, nbuckets * sizeof (dt_strhash_t *));
sp->str_hashsz = nbuckets;
sp->str_bufs = NULL;
sp->str_ptr = NULL;
sp->str_nbufs = 0;
sp->str_bufsz = bufsz;
sp->str_nstrs = 1;
sp->str_size = 1;
if (dt_strtab_grow(sp) == -1)
goto err;
*sp->str_ptr++ = '\0';
return (sp);
err:
dt_strtab_destroy(sp);
return (NULL);
}
void
dt_strtab_destroy(dt_strtab_t *sp)
{
dt_strhash_t *hp, *hq;
ulong_t i;
for (i = 0; i < sp->str_hashsz; i++) {
for (hp = sp->str_hash[i]; hp != NULL; hp = hq) {
hq = hp->str_next;
free(hp);
}
}
for (i = 0; i < sp->str_nbufs; i++)
free(sp->str_bufs[i]);
if (sp->str_hash != NULL)
free(sp->str_hash);
if (sp->str_bufs != NULL)
free(sp->str_bufs);
free(sp);
}
ulong_t
dt_strtab_hash(const char *key, size_t *len)
{
ulong_t g, h = 0;
const char *p;
size_t n = 0;
for (p = key; *p != '\0'; p++, n++) {
h = (h << 4) + *p;
if ((g = (h & 0xf0000000)) != 0) {
h ^= (g >> 24);
h ^= g;
}
}
if (len != NULL)
*len = n;
return (h);
}
static int
dt_strtab_compare(dt_strtab_t *sp, dt_strhash_t *hp,
const char *str, size_t len)
{
ulong_t b = hp->str_buf;
const char *buf = hp->str_data;
size_t resid, n;
int rv;
while (len != 0) {
if (buf == sp->str_bufs[b] + sp->str_bufsz)
buf = sp->str_bufs[++b];
resid = sp->str_bufs[b] + sp->str_bufsz - buf;
n = MIN(resid, len);
if ((rv = strncmp(buf, str, n)) != 0)
return (rv);
buf += n;
str += n;
len -= n;
}
return (0);
}
static int
dt_strtab_copyin(dt_strtab_t *sp, const char *str, size_t len)
{
char *old_p = sp->str_ptr;
ulong_t old_n = sp->str_nbufs;
ulong_t b = sp->str_nbufs - 1;
size_t resid, n;
while (len != 0) {
if (sp->str_ptr == sp->str_bufs[b] + sp->str_bufsz) {
if (dt_strtab_grow(sp) == -1)
goto err;
b++;
}
resid = sp->str_bufs[b] + sp->str_bufsz - sp->str_ptr;
n = MIN(resid, len);
bcopy(str, sp->str_ptr, n);
sp->str_ptr += n;
str += n;
len -= n;
}
return (0);
err:
while (sp->str_nbufs != old_n)
free(sp->str_bufs[--sp->str_nbufs]);
sp->str_ptr = old_p;
return (-1);
}
ssize_t
dt_strtab_index(dt_strtab_t *sp, const char *str)
{
dt_strhash_t *hp;
size_t len;
ulong_t h;
if (str == NULL || str[0] == '\0')
return (0); /* we keep a \0 at offset 0 to simplify things */
h = dt_strtab_hash(str, &len) % sp->str_hashsz;
for (hp = sp->str_hash[h]; hp != NULL; hp = hp->str_next) {
if (dt_strtab_compare(sp, hp, str, len + 1) == 0)
return (hp->str_off);
}
return (-1);
}
ssize_t
dt_strtab_insert(dt_strtab_t *sp, const char *str)
{
dt_strhash_t *hp;
size_t len;
ssize_t off;
ulong_t h;
if ((off = dt_strtab_index(sp, str)) != -1)
return (off);
h = dt_strtab_hash(str, &len) % sp->str_hashsz;
/*
* Create a new hash bucket, initialize it, and insert it at the front
* of the hash chain for the appropriate bucket.
*/
if ((hp = malloc(sizeof (dt_strhash_t))) == NULL)
return (-1L);
hp->str_data = sp->str_ptr;
hp->str_buf = sp->str_nbufs - 1;
hp->str_off = sp->str_size;
hp->str_len = len;
hp->str_next = sp->str_hash[h];
/*
* Now copy the string data into our buffer list, and then update
* the global counts of strings and bytes. Return str's byte offset.
*/
if (dt_strtab_copyin(sp, str, len + 1) == -1)
return (-1L);
sp->str_nstrs++;
sp->str_size += len + 1;
sp->str_hash[h] = hp;
return (hp->str_off);
}
size_t
dt_strtab_size(const dt_strtab_t *sp)
{
return (sp->str_size);
}
ssize_t
dt_strtab_write(const dt_strtab_t *sp, dt_strtab_write_f *func, void *private)
{
ssize_t res, total = 0;
ulong_t i;
size_t n;
for (i = 0; i < sp->str_nbufs; i++, total += res) {
if (i == sp->str_nbufs - 1)
n = sp->str_ptr - sp->str_bufs[i];
else
n = sp->str_bufsz;
if ((res = func(sp->str_bufs[i], n, total, private)) <= 0)
break;
}
if (total == 0 && sp->str_size != 0)
return (-1);
return (total);
}

View File

@ -0,0 +1,72 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_STRTAB_H
#define _DT_STRTAB_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dt_strhash {
const char *str_data; /* pointer to actual string data */
ulong_t str_buf; /* index of string data buffer */
size_t str_off; /* offset in bytes of this string */
size_t str_len; /* length in bytes of this string */
struct dt_strhash *str_next; /* next string in hash chain */
} dt_strhash_t;
typedef struct dt_strtab {
dt_strhash_t **str_hash; /* array of hash buckets */
ulong_t str_hashsz; /* size of hash bucket array */
char **str_bufs; /* array of buffer pointers */
char *str_ptr; /* pointer to current buffer location */
ulong_t str_nbufs; /* size of buffer pointer array */
size_t str_bufsz; /* size of individual buffer */
ulong_t str_nstrs; /* total number of strings in strtab */
size_t str_size; /* total size of strings in bytes */
} dt_strtab_t;
typedef ssize_t dt_strtab_write_f(const char *, size_t, size_t, void *);
extern dt_strtab_t *dt_strtab_create(size_t);
extern void dt_strtab_destroy(dt_strtab_t *);
extern ssize_t dt_strtab_index(dt_strtab_t *, const char *);
extern ssize_t dt_strtab_insert(dt_strtab_t *, const char *);
extern size_t dt_strtab_size(const dt_strtab_t *);
extern ssize_t dt_strtab_write(const dt_strtab_t *,
dt_strtab_write_f *, void *);
extern ulong_t dt_strtab_hash(const char *, size_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_STRTAB_H */

View File

@ -0,0 +1,997 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(sun)
#include <sys/sysmacros.h>
#endif
#include <strings.h>
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#if defined(sun)
#include <alloca.h>
#else
#include <sys/sysctl.h>
#endif
#include <assert.h>
#include <libgen.h>
#include <limits.h>
#include <dt_impl.h>
static const struct {
size_t dtps_offset;
size_t dtps_len;
} dtrace_probespecs[] = {
{ offsetof(dtrace_probedesc_t, dtpd_provider), DTRACE_PROVNAMELEN },
{ offsetof(dtrace_probedesc_t, dtpd_mod), DTRACE_MODNAMELEN },
{ offsetof(dtrace_probedesc_t, dtpd_func), DTRACE_FUNCNAMELEN },
{ offsetof(dtrace_probedesc_t, dtpd_name), DTRACE_NAMELEN }
};
int
dtrace_xstr2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec,
const char *s, int argc, char *const argv[], dtrace_probedesc_t *pdp)
{
size_t off, len, vlen;
const char *p, *q, *v;
char buf[32]; /* for id_t as %d (see below) */
if (spec < DTRACE_PROBESPEC_NONE || spec > DTRACE_PROBESPEC_NAME)
return (dt_set_errno(dtp, EINVAL));
bzero(pdp, sizeof (dtrace_probedesc_t));
p = s + strlen(s) - 1;
do {
for (len = 0; p >= s && *p != ':'; len++)
p--; /* move backward until we find a delimiter */
q = p + 1;
vlen = 0;
if ((v = strchr(q, '$')) != NULL && v < q + len) {
/*
* Set vlen to the length of the variable name and then
* reset len to the length of the text prior to '$'. If
* the name begins with a digit, interpret it using the
* the argv[] array. Otherwise we look in dt_macros.
* For the moment, all dt_macros variables are of type
* id_t (see dtrace_update() for more details on that).
*/
vlen = (size_t)(q + len - v);
len = (size_t)(v - q);
/*
* If the variable string begins with $$, skip past the
* leading dollar sign since $ and $$ are equivalent
* macro reference operators in a probe description.
*/
if (vlen > 2 && v[1] == '$') {
vlen--;
v++;
}
if (isdigit(v[1])) {
char *end;
long i;
errno = 0;
i = strtol(v + 1, &end, 10);
if (i < 0 || i >= argc ||
errno != 0 || end != v + vlen)
return (dt_set_errno(dtp, EDT_BADSPCV));
v = argv[i];
vlen = strlen(v);
if (yypcb != NULL && yypcb->pcb_sargv == argv)
yypcb->pcb_sflagv[i] |= DT_IDFLG_REF;
} else if (vlen > 1) {
char *vstr = alloca(vlen);
dt_ident_t *idp;
(void) strncpy(vstr, v + 1, vlen - 1);
vstr[vlen - 1] = '\0';
idp = dt_idhash_lookup(dtp->dt_macros, vstr);
if (idp == NULL)
return (dt_set_errno(dtp, EDT_BADSPCV));
v = buf;
vlen = snprintf(buf, 32, "%d", idp->di_id);
} else
return (dt_set_errno(dtp, EDT_BADSPCV));
}
if (spec == DTRACE_PROBESPEC_NONE)
return (dt_set_errno(dtp, EDT_BADSPEC));
if (len + vlen >= dtrace_probespecs[spec].dtps_len)
return (dt_set_errno(dtp, ENAMETOOLONG));
off = dtrace_probespecs[spec--].dtps_offset;
bcopy(q, (char *)pdp + off, len);
bcopy(v, (char *)pdp + off + len, vlen);
} while (--p >= s);
pdp->dtpd_id = DTRACE_IDNONE;
return (0);
}
int
dtrace_str2desc(dtrace_hdl_t *dtp, dtrace_probespec_t spec,
const char *s, dtrace_probedesc_t *pdp)
{
return (dtrace_xstr2desc(dtp, spec, s, 0, NULL, pdp));
}
int
dtrace_id2desc(dtrace_hdl_t *dtp, dtrace_id_t id, dtrace_probedesc_t *pdp)
{
bzero(pdp, sizeof (dtrace_probedesc_t));
pdp->dtpd_id = id;
if (dt_ioctl(dtp, DTRACEIOC_PROBES, pdp) == -1 ||
pdp->dtpd_id != id)
return (dt_set_errno(dtp, EDT_BADID));
return (0);
}
char *
dtrace_desc2str(const dtrace_probedesc_t *pdp, char *buf, size_t len)
{
if (pdp->dtpd_id == 0) {
(void) snprintf(buf, len, "%s:%s:%s:%s", pdp->dtpd_provider,
pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name);
} else
(void) snprintf(buf, len, "%u", pdp->dtpd_id);
return (buf);
}
char *
dtrace_attr2str(dtrace_attribute_t attr, char *buf, size_t len)
{
const char *name = dtrace_stability_name(attr.dtat_name);
const char *data = dtrace_stability_name(attr.dtat_data);
const char *class = dtrace_class_name(attr.dtat_class);
if (name == NULL || data == NULL || class == NULL)
return (NULL); /* one or more invalid attributes */
(void) snprintf(buf, len, "%s/%s/%s", name, data, class);
return (buf);
}
static char *
dt_getstrattr(char *p, char **qp)
{
char *q;
if (*p == '\0')
return (NULL);
if ((q = strchr(p, '/')) == NULL)
q = p + strlen(p);
else
*q++ = '\0';
*qp = q;
return (p);
}
int
dtrace_str2attr(const char *str, dtrace_attribute_t *attr)
{
dtrace_stability_t s;
dtrace_class_t c;
char *p, *q;
if (str == NULL || attr == NULL)
return (-1); /* invalid function arguments */
*attr = _dtrace_maxattr;
p = alloca(strlen(str) + 1);
(void) strcpy(p, str);
if ((p = dt_getstrattr(p, &q)) == NULL)
return (0);
for (s = 0; s <= DTRACE_STABILITY_MAX; s++) {
if (strcasecmp(p, dtrace_stability_name(s)) == 0) {
attr->dtat_name = s;
break;
}
}
if (s > DTRACE_STABILITY_MAX)
return (-1);
if ((p = dt_getstrattr(q, &q)) == NULL)
return (0);
for (s = 0; s <= DTRACE_STABILITY_MAX; s++) {
if (strcasecmp(p, dtrace_stability_name(s)) == 0) {
attr->dtat_data = s;
break;
}
}
if (s > DTRACE_STABILITY_MAX)
return (-1);
if ((p = dt_getstrattr(q, &q)) == NULL)
return (0);
for (c = 0; c <= DTRACE_CLASS_MAX; c++) {
if (strcasecmp(p, dtrace_class_name(c)) == 0) {
attr->dtat_class = c;
break;
}
}
if (c > DTRACE_CLASS_MAX || (p = dt_getstrattr(q, &q)) != NULL)
return (-1);
return (0);
}
const char *
dtrace_stability_name(dtrace_stability_t s)
{
switch (s) {
case DTRACE_STABILITY_INTERNAL: return ("Internal");
case DTRACE_STABILITY_PRIVATE: return ("Private");
case DTRACE_STABILITY_OBSOLETE: return ("Obsolete");
case DTRACE_STABILITY_EXTERNAL: return ("External");
case DTRACE_STABILITY_UNSTABLE: return ("Unstable");
case DTRACE_STABILITY_EVOLVING: return ("Evolving");
case DTRACE_STABILITY_STABLE: return ("Stable");
case DTRACE_STABILITY_STANDARD: return ("Standard");
default: return (NULL);
}
}
const char *
dtrace_class_name(dtrace_class_t c)
{
switch (c) {
case DTRACE_CLASS_UNKNOWN: return ("Unknown");
case DTRACE_CLASS_CPU: return ("CPU");
case DTRACE_CLASS_PLATFORM: return ("Platform");
case DTRACE_CLASS_GROUP: return ("Group");
case DTRACE_CLASS_ISA: return ("ISA");
case DTRACE_CLASS_COMMON: return ("Common");
default: return (NULL);
}
}
dtrace_attribute_t
dt_attr_min(dtrace_attribute_t a1, dtrace_attribute_t a2)
{
dtrace_attribute_t am;
am.dtat_name = MIN(a1.dtat_name, a2.dtat_name);
am.dtat_data = MIN(a1.dtat_data, a2.dtat_data);
am.dtat_class = MIN(a1.dtat_class, a2.dtat_class);
return (am);
}
dtrace_attribute_t
dt_attr_max(dtrace_attribute_t a1, dtrace_attribute_t a2)
{
dtrace_attribute_t am;
am.dtat_name = MAX(a1.dtat_name, a2.dtat_name);
am.dtat_data = MAX(a1.dtat_data, a2.dtat_data);
am.dtat_class = MAX(a1.dtat_class, a2.dtat_class);
return (am);
}
/*
* Compare two attributes and return an integer value in the following ranges:
*
* <0 if any of a1's attributes are less than a2's attributes
* =0 if all of a1's attributes are equal to a2's attributes
* >0 if all of a1's attributes are greater than or equal to a2's attributes
*
* To implement this function efficiently, we subtract a2's attributes from
* a1's to obtain a negative result if an a1 attribute is less than its a2
* counterpart. We then OR the intermediate results together, relying on the
* twos-complement property that if any result is negative, the bitwise union
* will also be negative since the highest bit will be set in the result.
*/
int
dt_attr_cmp(dtrace_attribute_t a1, dtrace_attribute_t a2)
{
return (((int)a1.dtat_name - a2.dtat_name) |
((int)a1.dtat_data - a2.dtat_data) |
((int)a1.dtat_class - a2.dtat_class));
}
char *
dt_attr_str(dtrace_attribute_t a, char *buf, size_t len)
{
static const char stability[] = "ipoxuesS";
static const char class[] = "uCpgIc";
if (a.dtat_name < sizeof (stability) &&
a.dtat_data < sizeof (stability) && a.dtat_class < sizeof (class)) {
(void) snprintf(buf, len, "[%c/%c/%c]", stability[a.dtat_name],
stability[a.dtat_data], class[a.dtat_class]);
} else {
(void) snprintf(buf, len, "[%u/%u/%u]",
a.dtat_name, a.dtat_data, a.dtat_class);
}
return (buf);
}
char *
dt_version_num2str(dt_version_t v, char *buf, size_t len)
{
uint_t M = DT_VERSION_MAJOR(v);
uint_t m = DT_VERSION_MINOR(v);
uint_t u = DT_VERSION_MICRO(v);
if (u == 0)
(void) snprintf(buf, len, "%u.%u", M, m);
else
(void) snprintf(buf, len, "%u.%u.%u", M, m, u);
return (buf);
}
int
dt_version_str2num(const char *s, dt_version_t *vp)
{
int i = 0, n[3] = { 0, 0, 0 };
char c;
while ((c = *s++) != '\0') {
if (isdigit(c))
n[i] = n[i] * 10 + c - '0';
else if (c != '.' || i++ >= sizeof (n) / sizeof (n[0]) - 1)
return (-1);
}
if (n[0] > DT_VERSION_MAJMAX ||
n[1] > DT_VERSION_MINMAX ||
n[2] > DT_VERSION_MICMAX)
return (-1);
if (vp != NULL)
*vp = DT_VERSION_NUMBER(n[0], n[1], n[2]);
return (0);
}
int
dt_version_defined(dt_version_t v)
{
int i;
for (i = 0; _dtrace_versions[i] != 0; i++) {
if (_dtrace_versions[i] == v)
return (1);
}
return (0);
}
char *
dt_cpp_add_arg(dtrace_hdl_t *dtp, const char *str)
{
char *arg;
if (dtp->dt_cpp_argc == dtp->dt_cpp_args) {
int olds = dtp->dt_cpp_args;
int news = olds * 2;
char **argv = realloc(dtp->dt_cpp_argv, sizeof (char *) * news);
if (argv == NULL)
return (NULL);
bzero(&argv[olds], sizeof (char *) * olds);
dtp->dt_cpp_argv = argv;
dtp->dt_cpp_args = news;
}
if ((arg = strdup(str)) == NULL)
return (NULL);
assert(dtp->dt_cpp_argc < dtp->dt_cpp_args);
dtp->dt_cpp_argv[dtp->dt_cpp_argc++] = arg;
return (arg);
}
char *
dt_cpp_pop_arg(dtrace_hdl_t *dtp)
{
char *arg;
if (dtp->dt_cpp_argc <= 1)
return (NULL); /* dt_cpp_argv[0] cannot be popped */
arg = dtp->dt_cpp_argv[--dtp->dt_cpp_argc];
dtp->dt_cpp_argv[dtp->dt_cpp_argc] = NULL;
return (arg);
}
/*PRINTFLIKE1*/
void
dt_dprintf(const char *format, ...)
{
if (_dtrace_debug) {
va_list alist;
va_start(alist, format);
(void) fputs("libdtrace DEBUG: ", stderr);
(void) vfprintf(stderr, format, alist);
va_end(alist);
}
}
int
#if defined(sun)
dt_ioctl(dtrace_hdl_t *dtp, int val, void *arg)
#else
dt_ioctl(dtrace_hdl_t *dtp, u_long val, void *arg)
#endif
{
const dtrace_vector_t *v = dtp->dt_vector;
#if !defined(sun)
/* Avoid sign extension. */
val &= 0xffffffff;
#endif
if (v != NULL)
return (v->dtv_ioctl(dtp->dt_varg, val, arg));
if (dtp->dt_fd >= 0)
return (ioctl(dtp->dt_fd, val, arg));
errno = EBADF;
return (-1);
}
int
dt_status(dtrace_hdl_t *dtp, processorid_t cpu)
{
const dtrace_vector_t *v = dtp->dt_vector;
if (v == NULL) {
#if defined(sun)
return (p_online(cpu, P_STATUS));
#else
int maxid = 0;
size_t len = sizeof(maxid);
if (sysctlbyname("kern.smp.maxid", &maxid, &len, NULL, 0) != 0)
return (cpu == 0 ? 1 : -1);
else
return (cpu <= maxid ? 1 : -1);
#endif
}
return (v->dtv_status(dtp->dt_varg, cpu));
}
long
dt_sysconf(dtrace_hdl_t *dtp, int name)
{
const dtrace_vector_t *v = dtp->dt_vector;
if (v == NULL)
return (sysconf(name));
return (v->dtv_sysconf(dtp->dt_varg, name));
}
/*
* Wrapper around write(2) to handle partial writes. For maximum safety of
* output files and proper error reporting, we continuing writing in the
* face of partial writes until write(2) fails or 'buf' is completely written.
* We also record any errno in the specified dtrace_hdl_t as well as 'errno'.
*/
ssize_t
dt_write(dtrace_hdl_t *dtp, int fd, const void *buf, size_t n)
{
ssize_t resid = n;
ssize_t len;
while (resid != 0) {
if ((len = write(fd, buf, resid)) <= 0)
break;
resid -= len;
buf = (char *)buf + len;
}
if (resid == n && n != 0)
return (dt_set_errno(dtp, errno));
return (n - resid);
}
/*
* This function handles all output from libdtrace, as well as the
* dtrace_sprintf() case. If we're here due to dtrace_sprintf(), then
* dt_sprintf_buflen will be non-zero; in this case, we sprintf into the
* specified buffer and return. Otherwise, if output is buffered (denoted by
* a NULL fp), we sprintf the desired output into the buffered buffer
* (expanding the buffer if required). If we don't satisfy either of these
* conditions (that is, if we are to actually generate output), then we call
* fprintf with the specified fp. In this case, we need to deal with one of
* the more annoying peculiarities of libc's printf routines: any failed
* write persistently sets an error flag inside the FILE causing every
* subsequent write to fail, but only the caller that initiated the error gets
* the errno. Since libdtrace clients often intercept SIGINT, this case is
* particularly frustrating since we don't want the EINTR on one attempt to
* write to the output file to preclude later attempts to write. This
* function therefore does a clearerr() if any error occurred, and saves the
* errno for the caller inside the specified dtrace_hdl_t.
*/
/*PRINTFLIKE3*/
int
dt_printf(dtrace_hdl_t *dtp, FILE *fp, const char *format, ...)
{
va_list ap;
int n;
#if !defined(sun)
/*
* On FreeBSD, check if output is currently being re-directed
* to another file. If so, output to that file instead of the
* one the caller has specified.
*/
if (dtp->dt_freopen_fp != NULL)
fp = dtp->dt_freopen_fp;
#endif
va_start(ap, format);
if (dtp->dt_sprintf_buflen != 0) {
int len;
char *buf;
assert(dtp->dt_sprintf_buf != NULL);
buf = &dtp->dt_sprintf_buf[len = strlen(dtp->dt_sprintf_buf)];
len = dtp->dt_sprintf_buflen - len;
assert(len >= 0);
if ((n = vsnprintf(buf, len, format, ap)) < 0)
n = dt_set_errno(dtp, errno);
va_end(ap);
return (n);
}
if (fp == NULL) {
int needed, rval;
size_t avail;
/*
* It's not legal to use buffered ouput if there is not a
* handler for buffered output.
*/
if (dtp->dt_bufhdlr == NULL) {
va_end(ap);
return (dt_set_errno(dtp, EDT_NOBUFFERED));
}
if (dtp->dt_buffered_buf == NULL) {
assert(dtp->dt_buffered_size == 0);
dtp->dt_buffered_size = 1;
dtp->dt_buffered_buf = malloc(dtp->dt_buffered_size);
if (dtp->dt_buffered_buf == NULL) {
va_end(ap);
return (dt_set_errno(dtp, EDT_NOMEM));
}
dtp->dt_buffered_offs = 0;
dtp->dt_buffered_buf[0] = '\0';
}
if ((needed = vsnprintf(NULL, 0, format, ap)) < 0) {
rval = dt_set_errno(dtp, errno);
va_end(ap);
return (rval);
}
if (needed == 0) {
va_end(ap);
return (0);
}
for (;;) {
char *newbuf;
assert(dtp->dt_buffered_offs < dtp->dt_buffered_size);
avail = dtp->dt_buffered_size - dtp->dt_buffered_offs;
if (needed + 1 < avail)
break;
if ((newbuf = realloc(dtp->dt_buffered_buf,
dtp->dt_buffered_size << 1)) == NULL) {
va_end(ap);
return (dt_set_errno(dtp, EDT_NOMEM));
}
dtp->dt_buffered_buf = newbuf;
dtp->dt_buffered_size <<= 1;
}
if (vsnprintf(&dtp->dt_buffered_buf[dtp->dt_buffered_offs],
avail, format, ap) < 0) {
rval = dt_set_errno(dtp, errno);
va_end(ap);
return (rval);
}
dtp->dt_buffered_offs += needed;
assert(dtp->dt_buffered_buf[dtp->dt_buffered_offs] == '\0');
return (0);
}
n = vfprintf(fp, format, ap);
fflush(fp);
va_end(ap);
if (n < 0) {
clearerr(fp);
return (dt_set_errno(dtp, errno));
}
return (n);
}
int
dt_buffered_flush(dtrace_hdl_t *dtp, dtrace_probedata_t *pdata,
const dtrace_recdesc_t *rec, const dtrace_aggdata_t *agg, uint32_t flags)
{
dtrace_bufdata_t data;
if (dtp->dt_buffered_offs == 0)
return (0);
data.dtbda_handle = dtp;
data.dtbda_buffered = dtp->dt_buffered_buf;
data.dtbda_probe = pdata;
data.dtbda_recdesc = rec;
data.dtbda_aggdata = agg;
data.dtbda_flags = flags;
if ((*dtp->dt_bufhdlr)(&data, dtp->dt_bufarg) == DTRACE_HANDLE_ABORT)
return (dt_set_errno(dtp, EDT_DIRABORT));
dtp->dt_buffered_offs = 0;
dtp->dt_buffered_buf[0] = '\0';
return (0);
}
void
dt_buffered_destroy(dtrace_hdl_t *dtp)
{
free(dtp->dt_buffered_buf);
dtp->dt_buffered_buf = NULL;
dtp->dt_buffered_offs = 0;
dtp->dt_buffered_size = 0;
}
void *
dt_zalloc(dtrace_hdl_t *dtp, size_t size)
{
void *data;
if (size > 16 * 1024 * 1024) {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
if ((data = malloc(size)) == NULL)
(void) dt_set_errno(dtp, EDT_NOMEM);
else
bzero(data, size);
return (data);
}
void *
dt_alloc(dtrace_hdl_t *dtp, size_t size)
{
void *data;
if (size > 16 * 1024 * 1024) {
(void) dt_set_errno(dtp, EDT_NOMEM);
return (NULL);
}
if ((data = malloc(size)) == NULL)
(void) dt_set_errno(dtp, EDT_NOMEM);
return (data);
}
void
dt_free(dtrace_hdl_t *dtp, void *data)
{
assert(dtp != NULL); /* ensure sane use of this interface */
free(data);
}
void
dt_difo_free(dtrace_hdl_t *dtp, dtrace_difo_t *dp)
{
if (dp == NULL)
return; /* simplify caller code */
dt_free(dtp, dp->dtdo_buf);
dt_free(dtp, dp->dtdo_inttab);
dt_free(dtp, dp->dtdo_strtab);
dt_free(dtp, dp->dtdo_vartab);
dt_free(dtp, dp->dtdo_kreltab);
dt_free(dtp, dp->dtdo_ureltab);
dt_free(dtp, dp->dtdo_xlmtab);
dt_free(dtp, dp);
}
/*
* dt_gmatch() is similar to gmatch(3GEN) and dtrace(7D) globbing, but also
* implements the behavior that an empty pattern matches any string.
*/
int
dt_gmatch(const char *s, const char *p)
{
return (p == NULL || *p == '\0' || gmatch(s, p));
}
char *
dt_basename(char *str)
{
char *last = strrchr(str, '/');
if (last == NULL)
return (str);
return (last + 1);
}
/*
* dt_popc() is a fast implementation of population count. The algorithm is
* from "Hacker's Delight" by Henry Warren, Jr with a 64-bit equivalent added.
*/
ulong_t
dt_popc(ulong_t x)
{
#ifdef _ILP32
x = x - ((x >> 1) & 0x55555555UL);
x = (x & 0x33333333UL) + ((x >> 2) & 0x33333333UL);
x = (x + (x >> 4)) & 0x0F0F0F0FUL;
x = x + (x >> 8);
x = x + (x >> 16);
return (x & 0x3F);
#endif
#ifdef _LP64
x = x - ((x >> 1) & 0x5555555555555555ULL);
x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
x = (x + (x >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
x = x + (x >> 8);
x = x + (x >> 16);
x = x + (x >> 32);
return (x & 0x7F);
#endif
}
/*
* dt_popcb() is a bitmap-based version of population count that returns the
* number of one bits in the specified bitmap 'bp' at bit positions below 'n'.
*/
ulong_t
dt_popcb(const ulong_t *bp, ulong_t n)
{
ulong_t maxb = n & BT_ULMASK;
ulong_t maxw = n >> BT_ULSHIFT;
ulong_t w, popc = 0;
if (n == 0)
return (0);
for (w = 0; w < maxw; w++)
popc += dt_popc(bp[w]);
return (popc + dt_popc(bp[maxw] & ((1UL << maxb) - 1)));
}
#if defined(sun)
struct _rwlock;
struct _lwp_mutex;
int
dt_rw_read_held(pthread_rwlock_t *lock)
{
extern int _rw_read_held(struct _rwlock *);
return (_rw_read_held((struct _rwlock *)lock));
}
int
dt_rw_write_held(pthread_rwlock_t *lock)
{
extern int _rw_write_held(struct _rwlock *);
return (_rw_write_held((struct _rwlock *)lock));
}
#endif
int
dt_mutex_held(pthread_mutex_t *lock)
{
#if defined(sun)
extern int _mutex_held(struct _lwp_mutex *);
return (_mutex_held((struct _lwp_mutex *)lock));
#else
return (1);
#endif
}
static int
dt_string2str(char *s, char *str, int nbytes)
{
int len = strlen(s);
if (nbytes == 0) {
/*
* Like snprintf(3C), we don't check the value of str if the
* number of bytes is 0.
*/
return (len);
}
if (nbytes <= len) {
(void) strncpy(str, s, nbytes - 1);
/*
* Like snprintf(3C) (and unlike strncpy(3C)), we guarantee
* that the string is null-terminated.
*/
str[nbytes - 1] = '\0';
} else {
(void) strcpy(str, s);
}
return (len);
}
int
dtrace_addr2str(dtrace_hdl_t *dtp, uint64_t addr, char *str, int nbytes)
{
dtrace_syminfo_t dts;
GElf_Sym sym;
size_t n = 20; /* for 0x%llx\0 */
char *s;
int err;
if ((err = dtrace_lookup_by_addr(dtp, addr, &sym, &dts)) == 0)
n += strlen(dts.dts_object) + strlen(dts.dts_name) + 2; /* +` */
s = alloca(n);
if (err == 0 && addr != sym.st_value) {
(void) snprintf(s, n, "%s`%s+0x%llx", dts.dts_object,
dts.dts_name, (u_longlong_t)addr - sym.st_value);
} else if (err == 0) {
(void) snprintf(s, n, "%s`%s",
dts.dts_object, dts.dts_name);
} else {
/*
* We'll repeat the lookup, but this time we'll specify a NULL
* GElf_Sym -- indicating that we're only interested in the
* containing module.
*/
if (dtrace_lookup_by_addr(dtp, addr, NULL, &dts) == 0) {
(void) snprintf(s, n, "%s`0x%llx", dts.dts_object,
(u_longlong_t)addr);
} else {
(void) snprintf(s, n, "0x%llx", (u_longlong_t)addr);
}
}
return (dt_string2str(s, str, nbytes));
}
int
dtrace_uaddr2str(dtrace_hdl_t *dtp, pid_t pid,
uint64_t addr, char *str, int nbytes)
{
char name[PATH_MAX], objname[PATH_MAX], c[PATH_MAX * 2];
struct ps_prochandle *P = NULL;
GElf_Sym sym;
char *obj;
if (pid != 0)
P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0);
if (P == NULL) {
(void) snprintf(c, sizeof (c), "0x%llx", addr);
return (dt_string2str(c, str, nbytes));
}
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);
if (addr > sym.st_value) {
(void) snprintf(c, sizeof (c), "%s`%s+0x%llx", obj,
name, (u_longlong_t)(addr - sym.st_value));
} 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 {
(void) snprintf(c, sizeof (c), "0x%llx", addr);
}
dt_proc_unlock(dtp, P);
dt_proc_release(dtp, P);
return (dt_string2str(c, str, nbytes));
}

View File

@ -0,0 +1,319 @@
/*
* 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
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <dt_impl.h>
#include <stddef.h>
#include <errno.h>
#include <assert.h>
#include <time.h>
static const struct {
int dtslt_option;
size_t dtslt_offs;
} _dtrace_sleeptab[] = {
{ DTRACEOPT_STATUSRATE, offsetof(dtrace_hdl_t, dt_laststatus) },
{ DTRACEOPT_AGGRATE, offsetof(dtrace_hdl_t, dt_lastagg) },
{ DTRACEOPT_SWITCHRATE, offsetof(dtrace_hdl_t, dt_lastswitch) },
{ DTRACEOPT_MAX, 0 }
};
void
dtrace_sleep(dtrace_hdl_t *dtp)
{
dt_proc_hash_t *dph = dtp->dt_procs;
dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY];
dt_proc_notify_t *dprn;
hrtime_t earliest = INT64_MAX;
struct timespec tv;
hrtime_t now;
int i;
for (i = 0; _dtrace_sleeptab[i].dtslt_option < DTRACEOPT_MAX; i++) {
uintptr_t a = (uintptr_t)dtp + _dtrace_sleeptab[i].dtslt_offs;
int opt = _dtrace_sleeptab[i].dtslt_option;
dtrace_optval_t interval = dtp->dt_options[opt];
/*
* If the buffering policy is set to anything other than
* "switch", we ignore the aggrate and switchrate -- they're
* meaningless.
*/
if (policy != DTRACEOPT_BUFPOLICY_SWITCH &&
_dtrace_sleeptab[i].dtslt_option != DTRACEOPT_STATUSRATE)
continue;
if (*((hrtime_t *)a) + interval < earliest)
earliest = *((hrtime_t *)a) + interval;
}
(void) pthread_mutex_lock(&dph->dph_lock);
now = gethrtime();
if (earliest < now) {
(void) pthread_mutex_unlock(&dph->dph_lock);
return; /* sleep duration has already past */
}
#if defined(sun)
tv.tv_sec = (earliest - now) / NANOSEC;
tv.tv_nsec = (earliest - now) % NANOSEC;
/*
* Wait for either 'tv' nanoseconds to pass or to receive notification
* that a process is in an interesting state. Regardless of why we
* awaken, iterate over any pending notifications and process them.
*/
(void) pthread_cond_reltimedwait_np(&dph->dph_cv, &dph->dph_lock, &tv);
#else
earliest -= now;
clock_gettime(CLOCK_REALTIME,&tv);
tv.tv_sec += earliest / NANOSEC;
tv.tv_nsec += earliest % NANOSEC;
while (tv.tv_nsec > NANOSEC) {
tv.tv_sec += 1;
tv.tv_nsec -= NANOSEC;
}
/*
* Wait for either 'tv' nanoseconds to pass or to receive notification
* that a process is in an interesting state. Regardless of why we
* awaken, iterate over any pending notifications and process them.
*/
(void) pthread_cond_timedwait(&dph->dph_cv, &dph->dph_lock, &tv);
#endif
while ((dprn = dph->dph_notify) != NULL) {
if (dtp->dt_prochdlr != NULL) {
char *err = dprn->dprn_errmsg;
if (*err == '\0')
err = NULL;
dtp->dt_prochdlr(dprn->dprn_dpr->dpr_proc, err,
dtp->dt_procarg);
}
dph->dph_notify = dprn->dprn_next;
dt_free(dtp, dprn);
}
(void) pthread_mutex_unlock(&dph->dph_lock);
}
int
dtrace_status(dtrace_hdl_t *dtp)
{
int gen = dtp->dt_statusgen;
dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_STATUSRATE];
hrtime_t now = gethrtime();
if (!dtp->dt_active)
return (DTRACE_STATUS_NONE);
if (dtp->dt_stopped)
return (DTRACE_STATUS_STOPPED);
if (dtp->dt_laststatus != 0) {
if (now - dtp->dt_laststatus < interval)
return (DTRACE_STATUS_NONE);
dtp->dt_laststatus += interval;
} else {
dtp->dt_laststatus = now;
}
if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
return (dt_set_errno(dtp, errno));
dtp->dt_statusgen ^= 1;
if (dt_handle_status(dtp, &dtp->dt_status[dtp->dt_statusgen],
&dtp->dt_status[gen]) == -1)
return (-1);
if (dtp->dt_status[gen].dtst_exiting) {
if (!dtp->dt_stopped)
(void) dtrace_stop(dtp);
return (DTRACE_STATUS_EXITED);
}
if (dtp->dt_status[gen].dtst_filled == 0)
return (DTRACE_STATUS_OKAY);
if (dtp->dt_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL)
return (DTRACE_STATUS_OKAY);
if (!dtp->dt_stopped) {
if (dtrace_stop(dtp) == -1)
return (-1);
}
return (DTRACE_STATUS_FILLED);
}
int
dtrace_go(dtrace_hdl_t *dtp)
{
dtrace_enable_io_t args;
void *dof;
int err;
if (dtp->dt_active)
return (dt_set_errno(dtp, EINVAL));
/*
* If a dtrace:::ERROR program and callback are registered, enable the
* program before we start tracing. If this fails for a vector open
* with ENOTTY, we permit dtrace_go() to succeed so that vector clients
* such as mdb's dtrace module can execute the rest of dtrace_go() even
* though they do not provide support for the DTRACEIOC_ENABLE ioctl.
*/
if (dtp->dt_errprog != NULL &&
dtrace_program_exec(dtp, dtp->dt_errprog, NULL) == -1 && (
dtp->dt_errno != ENOTTY || dtp->dt_vector == NULL))
return (-1); /* dt_errno has been set for us */
if ((dof = dtrace_getopt_dof(dtp)) == NULL)
return (-1); /* dt_errno has been set for us */
args.dof = dof;
args.n_matched = 0;
err = dt_ioctl(dtp, DTRACEIOC_ENABLE, &args);
dtrace_dof_destroy(dtp, dof);
if (err == -1 && (errno != ENOTTY || dtp->dt_vector == NULL))
return (dt_set_errno(dtp, errno));
if (dt_ioctl(dtp, DTRACEIOC_GO, &dtp->dt_beganon) == -1) {
if (errno == EACCES)
return (dt_set_errno(dtp, EDT_DESTRUCTIVE));
if (errno == EALREADY)
return (dt_set_errno(dtp, EDT_ISANON));
if (errno == ENOENT)
return (dt_set_errno(dtp, EDT_NOANON));
if (errno == E2BIG)
return (dt_set_errno(dtp, EDT_ENDTOOBIG));
if (errno == ENOSPC)
return (dt_set_errno(dtp, EDT_BUFTOOSMALL));
return (dt_set_errno(dtp, errno));
}
dtp->dt_active = 1;
if (dt_options_load(dtp) == -1)
return (dt_set_errno(dtp, errno));
return (dt_aggregate_go(dtp));
}
int
dtrace_stop(dtrace_hdl_t *dtp)
{
int gen = dtp->dt_statusgen;
if (dtp->dt_stopped)
return (0);
if (dt_ioctl(dtp, DTRACEIOC_STOP, &dtp->dt_endedon) == -1)
return (dt_set_errno(dtp, errno));
dtp->dt_stopped = 1;
/*
* Now that we're stopped, we're going to get status one final time.
*/
if (dt_ioctl(dtp, DTRACEIOC_STATUS, &dtp->dt_status[gen]) == -1)
return (dt_set_errno(dtp, errno));
if (dt_handle_status(dtp, &dtp->dt_status[gen ^ 1],
&dtp->dt_status[gen]) == -1)
return (-1);
return (0);
}
dtrace_workstatus_t
dtrace_work(dtrace_hdl_t *dtp, FILE *fp,
dtrace_consume_probe_f *pfunc, dtrace_consume_rec_f *rfunc, void *arg)
{
int status = dtrace_status(dtp);
dtrace_optval_t policy = dtp->dt_options[DTRACEOPT_BUFPOLICY];
dtrace_workstatus_t rval;
switch (status) {
case DTRACE_STATUS_EXITED:
case DTRACE_STATUS_FILLED:
case DTRACE_STATUS_STOPPED:
/*
* Tracing is stopped. We now want to force dtrace_consume()
* and dtrace_aggregate_snap() to proceed, regardless of
* switchrate and aggrate. We do this by clearing the times.
*/
dtp->dt_lastswitch = 0;
dtp->dt_lastagg = 0;
rval = DTRACE_WORKSTATUS_DONE;
break;
case DTRACE_STATUS_NONE:
case DTRACE_STATUS_OKAY:
rval = DTRACE_WORKSTATUS_OKAY;
break;
case -1:
return (DTRACE_WORKSTATUS_ERROR);
}
if ((status == DTRACE_STATUS_NONE || status == DTRACE_STATUS_OKAY) &&
policy != DTRACEOPT_BUFPOLICY_SWITCH) {
/*
* There either isn't any status or things are fine -- and
* this is a "ring" or "fill" buffer. We don't want to consume
* any of the trace data or snapshot the aggregations; we just
* return.
*/
assert(rval == DTRACE_WORKSTATUS_OKAY);
return (rval);
}
if (dtrace_aggregate_snap(dtp) == -1)
return (DTRACE_WORKSTATUS_ERROR);
if (dtrace_consume(dtp, fp, pfunc, rfunc, arg) == -1)
return (DTRACE_WORKSTATUS_ERROR);
return (rval);
}

View File

@ -0,0 +1,383 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <strings.h>
#include <assert.h>
#include <dt_xlator.h>
#include <dt_parser.h>
#include <dt_grammar.h>
#include <dt_module.h>
#include <dt_impl.h>
/*
* Create a member node corresponding to one of the output members of a dynamic
* translator. We set the member's dn_membexpr to a DT_NODE_XLATOR node that
* has dn_op set to DT_TOK_XLATE and refers back to the translator itself. The
* code generator will then use this as the indicator for dynamic translation.
*/
/*ARGSUSED*/
static int
dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
{
dt_xlator_t *dxp = arg;
dtrace_hdl_t *dtp = dxp->dx_hdl;
dt_node_t *enp, *mnp;
if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
enp->dn_link = dxp->dx_nodes;
dxp->dx_nodes = enp;
if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
mnp->dn_link = dxp->dx_nodes;
dxp->dx_nodes = mnp;
/*
* For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
* xlator refers back to the translator and whose dn_xmember refers to
* the current member. These refs will be used by dt_cg.c and dt_as.c.
*/
enp->dn_op = DT_TOK_XLATE;
enp->dn_xlator = dxp;
enp->dn_xmember = mnp;
dt_node_type_assign(enp, dxp->dx_dst_ctfp, type);
/*
* For the member itself, we use a DT_NODE_MEMBER as usual with the
* appropriate name, output type, and member expression set to 'enp'.
*/
if (dxp->dx_members != NULL) {
assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
enp->dn_link->dn_list = mnp;
} else
dxp->dx_members = mnp;
mnp->dn_membname = strdup(name);
mnp->dn_membexpr = enp;
dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type);
if (mnp->dn_membname == NULL)
return (dt_set_errno(dtp, EDT_NOMEM));
return (0);
}
dt_xlator_t *
dt_xlator_create(dtrace_hdl_t *dtp,
const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst,
const char *name, dt_node_t *members, dt_node_t *nodes)
{
dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t));
dtrace_typeinfo_t ptr = *dst;
dt_xlator_t **map;
dt_node_t *dnp;
uint_t kind;
if (dxp == NULL)
return (NULL);
dxp->dx_hdl = dtp;
dxp->dx_id = dtp->dt_xlatorid++;
dxp->dx_gen = dtp->dt_gen;
dxp->dx_arg = -1;
if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) {
dt_free(dtp, dxp);
return (NULL);
}
dt_list_append(&dtp->dt_xlators, dxp);
bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id);
dt_free(dtp, dtp->dt_xlatormap);
dtp->dt_xlatormap = map;
dtp->dt_xlatormap[dxp->dx_id] = dxp;
if (dt_type_pointer(&ptr) == -1) {
ptr.dtt_ctfp = NULL;
ptr.dtt_type = CTF_ERR;
}
dxp->dx_ident = dt_ident_create(name ? name : "T",
DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0,
_dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
if (dxp->dx_ident == NULL)
goto err; /* no memory for identifier */
dxp->dx_ident->di_ctfp = src->dtt_ctfp;
dxp->dx_ident->di_type = src->dtt_type;
/*
* If an input parameter name is given, this is a static translator
* definition: create an idhash and identifier for the parameter.
*/
if (name != NULL) {
dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0);
if (dxp->dx_locals == NULL)
goto err; /* no memory for identifier hash */
dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident);
}
dxp->dx_souid.di_name = "translator";
dxp->dx_souid.di_kind = DT_IDENT_XLSOU;
dxp->dx_souid.di_flags = DT_IDFLG_REF;
dxp->dx_souid.di_id = dxp->dx_id;
dxp->dx_souid.di_attr = _dtrace_defattr;
dxp->dx_souid.di_ops = &dt_idops_thaw;
dxp->dx_souid.di_data = dxp;
dxp->dx_souid.di_ctfp = dst->dtt_ctfp;
dxp->dx_souid.di_type = dst->dtt_type;
dxp->dx_souid.di_gen = dtp->dt_gen;
dxp->dx_ptrid.di_name = "translator";
dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR;
dxp->dx_ptrid.di_flags = DT_IDFLG_REF;
dxp->dx_ptrid.di_id = dxp->dx_id;
dxp->dx_ptrid.di_attr = _dtrace_defattr;
dxp->dx_ptrid.di_ops = &dt_idops_thaw;
dxp->dx_ptrid.di_data = dxp;
dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp;
dxp->dx_ptrid.di_type = ptr.dtt_type;
dxp->dx_ptrid.di_gen = dtp->dt_gen;
/*
* If a deferred pragma is pending on the keyword "translator", run all
* the deferred pragmas on dx_souid and then copy results to dx_ptrid.
* See the code in dt_pragma.c for details on deferred ident pragmas.
*/
if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL &&
dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) {
dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid);
dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr;
dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers;
}
dxp->dx_src_ctfp = src->dtt_ctfp;
dxp->dx_src_type = src->dtt_type;
dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type);
dxp->dx_dst_ctfp = dst->dtt_ctfp;
dxp->dx_dst_type = dst->dtt_type;
dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type);
kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base);
assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
/*
* If no input parameter is given, we're making a dynamic translator:
* create member nodes for every member of the output type. Otherwise
* retain the member and allocation node lists presented by the parser.
*/
if (name == NULL) {
if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base,
dt_xlator_create_member, dxp) != 0)
goto err;
} else {
dxp->dx_members = members;
dxp->dx_nodes = nodes;
}
/*
* Assign member IDs to each member and allocate space for DIFOs
* if and when this translator is eventually compiled.
*/
for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
dnp->dn_membxlator = dxp;
dnp->dn_membid = dxp->dx_nmembers++;
}
dxp->dx_membdif = dt_zalloc(dtp,
sizeof (dtrace_difo_t *) * dxp->dx_nmembers);
if (dxp->dx_membdif == NULL) {
dxp->dx_nmembers = 0;
goto err;
}
return (dxp);
err:
dt_xlator_destroy(dtp, dxp);
return (NULL);
}
void
dt_xlator_destroy(dtrace_hdl_t *dtp, dt_xlator_t *dxp)
{
uint_t i;
dt_node_link_free(&dxp->dx_nodes);
if (dxp->dx_locals != NULL)
dt_idhash_destroy(dxp->dx_locals);
else if (dxp->dx_ident != NULL)
dt_ident_destroy(dxp->dx_ident);
for (i = 0; i < dxp->dx_nmembers; i++)
dt_difo_free(dtp, dxp->dx_membdif[i]);
dt_free(dtp, dxp->dx_membdif);
dt_list_delete(&dtp->dt_xlators, dxp);
dt_free(dtp, dxp);
}
dt_xlator_t *
dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
{
ctf_file_t *src_ctfp = src->dn_ctfp;
ctf_id_t src_type = src->dn_type;
ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);
ctf_file_t *dst_ctfp = dst->dn_ctfp;
ctf_id_t dst_type = dst->dn_type;
ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);
int ptr = dst_kind == CTF_K_POINTER;
dtrace_typeinfo_t src_dtt, dst_dtt;
dt_node_t xn = { 0 };
dt_xlator_t *dxp = NULL;
if (src_base == CTF_ERR || dst_base == CTF_ERR)
return (NULL); /* fail if these are unresolvable types */
/*
* Translators are always defined using a struct or union type, so if
* we are attempting to translate to type "T *", we internally look
* for a translation to type "T" by following the pointer reference.
*/
if (ptr) {
dst_type = ctf_type_reference(dst_ctfp, dst_type);
dst_base = ctf_type_resolve(dst_ctfp, dst_type);
dst_kind = ctf_type_kind(dst_ctfp, dst_base);
}
if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
return (NULL); /* fail if the output isn't a struct or union */
/*
* In order to find a matching translator, we iterate over the set of
* available translators in three passes. First, we look for a
* translation from the exact source type to the resolved destination.
* Second, we look for a translation from the resolved source type to
* the resolved destination. Third, we look for a translation from a
* compatible source type (using the same rules as parameter formals)
* to the resolved destination. If all passes fail, return NULL.
*/
for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
dxp = dt_list_next(dxp)) {
if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
src_ctfp, src_type) &&
ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
dst_ctfp, dst_base))
goto out;
}
if (flags & DT_XLATE_EXACT)
goto out; /* skip remaining passes if exact match required */
for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
dxp = dt_list_next(dxp)) {
if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
src_ctfp, src_type) &&
ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
dst_ctfp, dst_base))
goto out;
}
for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
dxp = dt_list_next(dxp)) {
dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type);
if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
goto out;
}
out:
if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
return (NULL); /* no translation available to pointer type */
if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
dtp->dt_xlatemode == DT_XL_STATIC)
return (dxp); /* we succeeded or not allowed to extern */
/*
* If we get here, then we didn't find an existing translator, but the
* caller and xlatemode permit us to create an extern to a dynamic one.
*/
src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
src_dtt.dtt_ctfp = src_ctfp;
src_dtt.dtt_type = src_type;
dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name;
dst_dtt.dtt_ctfp = dst_ctfp;
dst_dtt.dtt_type = dst_type;
return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
}
dt_xlator_t *
dt_xlator_lookup_id(dtrace_hdl_t *dtp, id_t id)
{
assert(id >= 0 && id < dtp->dt_xlatorid);
return (dtp->dt_xlatormap[id]);
}
dt_ident_t *
dt_xlator_ident(dt_xlator_t *dxp, ctf_file_t *ctfp, ctf_id_t type)
{
if (ctf_type_kind(ctfp, ctf_type_resolve(ctfp, type)) == CTF_K_POINTER)
return (&dxp->dx_ptrid);
else
return (&dxp->dx_souid);
}
dt_node_t *
dt_xlator_member(dt_xlator_t *dxp, const char *name)
{
dt_node_t *dnp;
for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
if (strcmp(dnp->dn_membname, name) == 0)
return (dnp);
}
return (NULL);
}
int
dt_xlator_dynamic(const dt_xlator_t *dxp)
{
return (dxp->dx_locals == NULL);
}

View File

@ -0,0 +1,87 @@
/*
* 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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DT_XLATOR_H
#define _DT_XLATOR_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <libctf.h>
#include <dtrace.h>
#include <dt_ident.h>
#include <dt_list.h>
#ifdef __cplusplus
extern "C" {
#endif
struct dt_node;
typedef struct dt_xlator {
dt_list_t dx_list; /* list forward/back pointers */
dt_idhash_t *dx_locals; /* hash of local scope identifiers */
dt_ident_t *dx_ident; /* identifier ref for input param */
dt_ident_t dx_souid; /* fake identifier for sou output */
dt_ident_t dx_ptrid; /* fake identifier for ptr output */
ctf_file_t *dx_src_ctfp; /* CTF container for input type */
ctf_id_t dx_src_type; /* CTF reference for input type */
ctf_id_t dx_src_base; /* CTF reference for input base */
ctf_file_t *dx_dst_ctfp; /* CTF container for output type */
ctf_id_t dx_dst_type; /* CTF reference for output type */
ctf_id_t dx_dst_base; /* CTF reference for output base */
struct dt_node *dx_members; /* list of member translations */
uint_t dx_nmembers; /* length of dx_members list */
dtrace_difo_t **dx_membdif; /* DIF for member expressions */
struct dt_node *dx_nodes; /* list of parse tree nodes */
dtrace_hdl_t *dx_hdl; /* back pointer to containing handle */
ulong_t dx_gen; /* generation number that created me */
id_t dx_id; /* global translator id */
int dx_arg; /* dynamic argument index */
} dt_xlator_t;
extern dt_xlator_t *dt_xlator_create(dtrace_hdl_t *,
const dtrace_typeinfo_t *, const dtrace_typeinfo_t *,
const char *, struct dt_node *, struct dt_node *);
extern void dt_xlator_destroy(dtrace_hdl_t *, dt_xlator_t *);
#define DT_XLATE_FUZZY 0x0 /* lookup any matching translator */
#define DT_XLATE_EXACT 0x1 /* lookup only exact type matches */
#define DT_XLATE_EXTERN 0x2 /* extern translator if none exists */
extern dt_xlator_t *dt_xlator_lookup(dtrace_hdl_t *,
struct dt_node *, struct dt_node *, int);
extern dt_xlator_t *dt_xlator_lookup_id(dtrace_hdl_t *, id_t);
extern dt_ident_t *dt_xlator_ident(dt_xlator_t *, ctf_file_t *, ctf_id_t);
extern struct dt_node *dt_xlator_member(dt_xlator_t *, const char *);
extern int dt_xlator_dynamic(const dt_xlator_t *);
#ifdef __cplusplus
}
#endif
#endif /* _DT_XLATOR_H */

View File

@ -0,0 +1,580 @@
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _DTRACE_H
#define _DTRACE_H
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/dtrace.h>
#include <stdarg.h>
#include <stdio.h>
#include <gelf.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* DTrace Dynamic Tracing Software: Library Interfaces
*
* Note: The contents of this file are private to the implementation of the
* Solaris system and DTrace subsystem and are subject to change at any time
* without notice. Applications and drivers using these interfaces will fail
* to run on future releases. These interfaces should not be used for any
* purpose except those expressly outlined in dtrace(7D) and libdtrace(3LIB).
* Please refer to the "Solaris Dynamic Tracing Guide" for more information.
*/
#define DTRACE_VERSION 3 /* library ABI interface version */
struct ps_prochandle;
typedef struct dtrace_hdl dtrace_hdl_t;
typedef struct dtrace_prog dtrace_prog_t;
typedef struct dtrace_vector dtrace_vector_t;
typedef struct dtrace_aggdata dtrace_aggdata_t;
#define DTRACE_O_NODEV 0x01 /* do not open dtrace(7D) device */
#define DTRACE_O_NOSYS 0x02 /* do not load /system/object modules */
#define DTRACE_O_LP64 0x04 /* force D compiler to be LP64 */
#define DTRACE_O_ILP32 0x08 /* force D compiler to be ILP32 */
#define DTRACE_O_MASK 0x0f /* mask of valid flags to dtrace_open */
extern dtrace_hdl_t *dtrace_open(int, int, int *);
extern dtrace_hdl_t *dtrace_vopen(int, int, int *,
const dtrace_vector_t *, void *);
extern int dtrace_go(dtrace_hdl_t *);
extern int dtrace_stop(dtrace_hdl_t *);
extern void dtrace_sleep(dtrace_hdl_t *);
extern void dtrace_close(dtrace_hdl_t *);
extern int dtrace_errno(dtrace_hdl_t *);
extern const char *dtrace_errmsg(dtrace_hdl_t *, int);
extern const char *dtrace_faultstr(dtrace_hdl_t *, int);
extern const char *dtrace_subrstr(dtrace_hdl_t *, int);
extern int dtrace_setopt(dtrace_hdl_t *, const char *, const char *);
extern int dtrace_getopt(dtrace_hdl_t *, const char *, dtrace_optval_t *);
extern void dtrace_update(dtrace_hdl_t *);
extern int dtrace_ctlfd(dtrace_hdl_t *);
/*
* DTrace Program Interface
*
* DTrace programs can be created by compiling ASCII text files containing
* D programs or by compiling in-memory C strings that specify a D program.
* Once created, callers can examine the list of program statements and
* enable the probes and actions described by these statements.
*/
typedef struct dtrace_proginfo {
dtrace_attribute_t dpi_descattr; /* minimum probedesc attributes */
dtrace_attribute_t dpi_stmtattr; /* minimum statement attributes */
uint_t dpi_aggregates; /* number of aggregates specified in program */
uint_t dpi_recgens; /* number of record generating probes in prog */
uint_t dpi_matches; /* number of probes matched by program */
uint_t dpi_speculations; /* number of speculations specified in prog */
} dtrace_proginfo_t;
#define DTRACE_C_DIFV 0x0001 /* DIF verbose mode: show each compiled DIFO */
#define DTRACE_C_EMPTY 0x0002 /* Permit compilation of empty D source files */
#define DTRACE_C_ZDEFS 0x0004 /* Permit probe defs that match zero probes */
#define DTRACE_C_EATTR 0x0008 /* Error if program attributes less than min */
#define DTRACE_C_CPP 0x0010 /* Preprocess input file with cpp(1) utility */
#define DTRACE_C_KNODEF 0x0020 /* Permit unresolved kernel symbols in DIFO */
#define DTRACE_C_UNODEF 0x0040 /* Permit unresolved user symbols in DIFO */
#define DTRACE_C_PSPEC 0x0080 /* Intepret ambiguous specifiers as probes */
#define DTRACE_C_ETAGS 0x0100 /* Prefix error messages with error tags */
#define DTRACE_C_ARGREF 0x0200 /* Do not require all macro args to be used */
#define DTRACE_C_DEFARG 0x0800 /* Use 0/"" as value for unspecified args */
#define DTRACE_C_NOLIBS 0x1000 /* Do not process D system libraries */
#define DTRACE_C_CTL 0x2000 /* Only process control directives */
#define DTRACE_C_MASK 0x3bff /* mask of all valid flags to dtrace_*compile */
extern dtrace_prog_t *dtrace_program_strcompile(dtrace_hdl_t *,
const char *, dtrace_probespec_t, uint_t, int, char *const []);
extern dtrace_prog_t *dtrace_program_fcompile(dtrace_hdl_t *,
FILE *, uint_t, int, char *const []);
extern int dtrace_program_exec(dtrace_hdl_t *, dtrace_prog_t *,
dtrace_proginfo_t *);
extern void dtrace_program_info(dtrace_hdl_t *, dtrace_prog_t *,
dtrace_proginfo_t *);
#define DTRACE_D_STRIP 0x01 /* strip non-loadable sections from program */
#define DTRACE_D_PROBES 0x02 /* include provider and probe definitions */
#define DTRACE_D_MASK 0x03 /* mask of valid flags to dtrace_dof_create */
extern int dtrace_program_link(dtrace_hdl_t *, dtrace_prog_t *,
uint_t, const char *, int, char *const []);
extern int dtrace_program_header(dtrace_hdl_t *, FILE *, const char *);
extern void *dtrace_dof_create(dtrace_hdl_t *, dtrace_prog_t *, uint_t);
extern void dtrace_dof_destroy(dtrace_hdl_t *, void *);
extern void *dtrace_getopt_dof(dtrace_hdl_t *);
extern void *dtrace_geterr_dof(dtrace_hdl_t *);
typedef struct dtrace_stmtdesc {
dtrace_ecbdesc_t *dtsd_ecbdesc; /* ECB description */
dtrace_actdesc_t *dtsd_action; /* action list */
dtrace_actdesc_t *dtsd_action_last; /* last action in action list */
void *dtsd_aggdata; /* aggregation data */
void *dtsd_fmtdata; /* type-specific output data */
void (*dtsd_callback)(void); /* callback function for EPID */
void *dtsd_data; /* callback data pointer */
dtrace_attribute_t dtsd_descattr; /* probedesc attributes */
dtrace_attribute_t dtsd_stmtattr; /* statement attributes */
} dtrace_stmtdesc_t;
typedef int dtrace_stmt_f(dtrace_hdl_t *, dtrace_prog_t *,
dtrace_stmtdesc_t *, void *);
extern dtrace_stmtdesc_t *dtrace_stmt_create(dtrace_hdl_t *,
dtrace_ecbdesc_t *);
extern dtrace_actdesc_t *dtrace_stmt_action(dtrace_hdl_t *,
dtrace_stmtdesc_t *);
extern int dtrace_stmt_add(dtrace_hdl_t *, dtrace_prog_t *,
dtrace_stmtdesc_t *);
extern int dtrace_stmt_iter(dtrace_hdl_t *, dtrace_prog_t *,
dtrace_stmt_f *, void *);
extern void dtrace_stmt_destroy(dtrace_hdl_t *, dtrace_stmtdesc_t *);
/*
* DTrace Data Consumption Interface
*/
typedef enum {
DTRACEFLOW_ENTRY,
DTRACEFLOW_RETURN,
DTRACEFLOW_NONE
} dtrace_flowkind_t;
#define DTRACE_CONSUME_ERROR -1 /* error while processing */
#define DTRACE_CONSUME_THIS 0 /* consume this probe/record */
#define DTRACE_CONSUME_NEXT 1 /* advance to next probe/rec */
#define DTRACE_CONSUME_ABORT 2 /* abort consumption */
typedef struct dtrace_probedata {
dtrace_hdl_t *dtpda_handle; /* handle to DTrace library */
dtrace_eprobedesc_t *dtpda_edesc; /* enabled probe description */
dtrace_probedesc_t *dtpda_pdesc; /* probe description */
processorid_t dtpda_cpu; /* CPU for data */
caddr_t dtpda_data; /* pointer to raw data */
dtrace_flowkind_t dtpda_flow; /* flow kind */
const char *dtpda_prefix; /* recommended flow prefix */
int dtpda_indent; /* recommended flow indent */
} dtrace_probedata_t;
typedef int dtrace_consume_probe_f(const dtrace_probedata_t *, void *);
typedef int dtrace_consume_rec_f(const dtrace_probedata_t *,
const dtrace_recdesc_t *, void *);
extern int dtrace_consume(dtrace_hdl_t *, FILE *,
dtrace_consume_probe_f *, dtrace_consume_rec_f *, void *);
#define DTRACE_STATUS_NONE 0 /* no status; not yet time */
#define DTRACE_STATUS_OKAY 1 /* status okay */
#define DTRACE_STATUS_EXITED 2 /* exit() was called; tracing stopped */
#define DTRACE_STATUS_FILLED 3 /* fill buffer filled; tracing stoped */
#define DTRACE_STATUS_STOPPED 4 /* tracing already stopped */
extern int dtrace_status(dtrace_hdl_t *);
/*
* DTrace Formatted Output Interfaces
*
* To format output associated with a given dtrace_stmtdesc, the caller can
* invoke one of the following functions, passing the opaque dtsd_fmtdata and a
* list of record descriptions. These functions return either -1 to indicate
* an error, or a positive integer indicating the number of records consumed.
* For anonymous enablings, the consumer can use the dtrd_format member of
* the record description to obtain a format description. The dtfd_string
* member of the format description may be passed to dtrace_print{fa}_create()
* to create the opaque format data.
*/
extern void *dtrace_printf_create(dtrace_hdl_t *, const char *);
extern void *dtrace_printa_create(dtrace_hdl_t *, const char *);
extern size_t dtrace_printf_format(dtrace_hdl_t *, void *, char *, size_t);
extern int dtrace_fprintf(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
const void *, size_t);
extern int dtrace_fprinta(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
const void *, size_t);
extern int dtrace_system(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
const void *, size_t);
extern int dtrace_freopen(dtrace_hdl_t *, FILE *, void *,
const dtrace_probedata_t *, const dtrace_recdesc_t *, uint_t,
const void *, size_t);
/*
* DTrace Work Interface
*/
typedef enum {
DTRACE_WORKSTATUS_ERROR = -1,
DTRACE_WORKSTATUS_OKAY,
DTRACE_WORKSTATUS_DONE
} dtrace_workstatus_t;
extern dtrace_workstatus_t dtrace_work(dtrace_hdl_t *, FILE *,
dtrace_consume_probe_f *, dtrace_consume_rec_f *, void *);
/*
* DTrace Handler Interface
*/
#define DTRACE_HANDLE_ABORT -1 /* abort current operation */
#define DTRACE_HANDLE_OK 0 /* handled okay; continue */
typedef struct dtrace_errdata {
dtrace_hdl_t *dteda_handle; /* handle to DTrace library */
dtrace_eprobedesc_t *dteda_edesc; /* enabled probe inducing err */
dtrace_probedesc_t *dteda_pdesc; /* probe inducing error */
processorid_t dteda_cpu; /* CPU of error */
int dteda_action; /* action inducing error */
int dteda_offset; /* offset in DIFO of error */
int dteda_fault; /* specific fault */
uint64_t dteda_addr; /* address of fault, if any */
const char *dteda_msg; /* preconstructed message */
} dtrace_errdata_t;
typedef int dtrace_handle_err_f(const dtrace_errdata_t *, void *);
extern int dtrace_handle_err(dtrace_hdl_t *, dtrace_handle_err_f *, void *);
typedef enum {
DTRACEDROP_PRINCIPAL, /* drop to principal buffer */
DTRACEDROP_AGGREGATION, /* drop to aggregation buffer */
DTRACEDROP_DYNAMIC, /* dynamic drop */
DTRACEDROP_DYNRINSE, /* dyn drop due to rinsing */
DTRACEDROP_DYNDIRTY, /* dyn drop due to dirty */
DTRACEDROP_SPEC, /* speculative drop */
DTRACEDROP_SPECBUSY, /* spec drop due to busy */
DTRACEDROP_SPECUNAVAIL, /* spec drop due to unavail */
DTRACEDROP_STKSTROVERFLOW, /* stack string tab overflow */
DTRACEDROP_DBLERROR /* error in ERROR probe */
} dtrace_dropkind_t;
typedef struct dtrace_dropdata {
dtrace_hdl_t *dtdda_handle; /* handle to DTrace library */
processorid_t dtdda_cpu; /* CPU, if any */
dtrace_dropkind_t dtdda_kind; /* kind of drop */
uint64_t dtdda_drops; /* number of drops */
uint64_t dtdda_total; /* total drops */
const char *dtdda_msg; /* preconstructed message */
} dtrace_dropdata_t;
typedef int dtrace_handle_drop_f(const dtrace_dropdata_t *, void *);
extern int dtrace_handle_drop(dtrace_hdl_t *, dtrace_handle_drop_f *, void *);
typedef void dtrace_handle_proc_f(struct ps_prochandle *, const char *, void *);
extern int dtrace_handle_proc(dtrace_hdl_t *, dtrace_handle_proc_f *, void *);
#define DTRACE_BUFDATA_AGGKEY 0x0001 /* aggregation key */
#define DTRACE_BUFDATA_AGGVAL 0x0002 /* aggregation value */
#define DTRACE_BUFDATA_AGGFORMAT 0x0004 /* aggregation format data */
#define DTRACE_BUFDATA_AGGLAST 0x0008 /* last for this key/val */
typedef struct dtrace_bufdata {
dtrace_hdl_t *dtbda_handle; /* handle to DTrace library */
const char *dtbda_buffered; /* buffered output */
dtrace_probedata_t *dtbda_probe; /* probe data */
const dtrace_recdesc_t *dtbda_recdesc; /* record description */
const dtrace_aggdata_t *dtbda_aggdata; /* aggregation data, if agg. */
uint32_t dtbda_flags; /* flags; see above */
} dtrace_bufdata_t;
typedef int dtrace_handle_buffered_f(const dtrace_bufdata_t *, void *);
extern int dtrace_handle_buffered(dtrace_hdl_t *,
dtrace_handle_buffered_f *, void *);
typedef struct dtrace_setoptdata {
dtrace_hdl_t *dtsda_handle; /* handle to DTrace library */
const dtrace_probedata_t *dtsda_probe; /* probe data */
const char *dtsda_option; /* option that was set */
dtrace_optval_t dtsda_oldval; /* old value */
dtrace_optval_t dtsda_newval; /* new value */
} dtrace_setoptdata_t;
typedef int dtrace_handle_setopt_f(const dtrace_setoptdata_t *, void *);
extern int dtrace_handle_setopt(dtrace_hdl_t *,
dtrace_handle_setopt_f *, void *);
/*
* DTrace Aggregate Interface
*/
#define DTRACE_A_PERCPU 0x0001
#define DTRACE_A_KEEPDELTA 0x0002
#define DTRACE_A_ANONYMOUS 0x0004
#define DTRACE_AGGWALK_ERROR -1 /* error while processing */
#define DTRACE_AGGWALK_NEXT 0 /* proceed to next element */
#define DTRACE_AGGWALK_ABORT 1 /* abort aggregation walk */
#define DTRACE_AGGWALK_CLEAR 2 /* clear this element */
#define DTRACE_AGGWALK_NORMALIZE 3 /* normalize this element */
#define DTRACE_AGGWALK_DENORMALIZE 4 /* denormalize this element */
#define DTRACE_AGGWALK_REMOVE 5 /* remove this element */
struct dtrace_aggdata {
dtrace_hdl_t *dtada_handle; /* handle to DTrace library */
dtrace_aggdesc_t *dtada_desc; /* aggregation description */
dtrace_eprobedesc_t *dtada_edesc; /* enabled probe description */
dtrace_probedesc_t *dtada_pdesc; /* probe description */
caddr_t dtada_data; /* pointer to raw data */
uint64_t dtada_normal; /* the normal -- 1 for denorm */
size_t dtada_size; /* total size of the data */
caddr_t dtada_delta; /* delta data, if available */
caddr_t *dtada_percpu; /* per CPU data, if avail */
caddr_t *dtada_percpu_delta; /* per CPU delta, if avail */
};
typedef int dtrace_aggregate_f(const dtrace_aggdata_t *, void *);
typedef int dtrace_aggregate_walk_f(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
typedef int dtrace_aggregate_walk_joined_f(const dtrace_aggdata_t **,
const int, void *);
extern void dtrace_aggregate_clear(dtrace_hdl_t *);
extern int dtrace_aggregate_snap(dtrace_hdl_t *);
extern int dtrace_aggregate_print(dtrace_hdl_t *, FILE *,
dtrace_aggregate_walk_f *);
extern int dtrace_aggregate_walk(dtrace_hdl_t *, dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_joined(dtrace_hdl_t *,
dtrace_aggvarid_t *, int, dtrace_aggregate_walk_joined_f *, void *);
extern int dtrace_aggregate_walk_sorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_keysorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_valsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
extern int dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *,
dtrace_aggregate_f *, void *);
#define DTRACE_AGD_PRINTED 0x1 /* aggregation printed in program */
/*
* DTrace Process Control Interface
*
* Library clients who wish to have libdtrace create or grab processes for
* monitoring of their symbol table changes may use these interfaces to
* request that libdtrace obtain control of the process using libproc.
*/
extern struct ps_prochandle *dtrace_proc_create(dtrace_hdl_t *,
const char *, char *const *);
extern struct ps_prochandle *dtrace_proc_grab(dtrace_hdl_t *, pid_t, int);
extern void dtrace_proc_release(dtrace_hdl_t *, struct ps_prochandle *);
extern void dtrace_proc_continue(dtrace_hdl_t *, struct ps_prochandle *);
/*
* DTrace Object, Symbol, and Type Interfaces
*
* Library clients can use libdtrace to perform symbol and C type information
* lookups by symbol name, symbol address, or C type name, or to lookup meta-
* information cached for each of the program objects in use by DTrace. The
* resulting struct contain pointers to arbitrary-length strings, including
* object, symbol, and type names, that are persistent until the next call to
* dtrace_update(). Once dtrace_update() is called, any cached values must
* be flushed and not used subsequently by the client program.
*/
#define DTRACE_OBJ_EXEC ((const char *)0L) /* primary executable file */
#define DTRACE_OBJ_RTLD ((const char *)1L) /* run-time link-editor */
#define DTRACE_OBJ_CDEFS ((const char *)2L) /* C include definitions */
#define DTRACE_OBJ_DDEFS ((const char *)3L) /* D program definitions */
#define DTRACE_OBJ_EVERY ((const char *)-1L) /* all known objects */
#define DTRACE_OBJ_KMODS ((const char *)-2L) /* all kernel objects */
#define DTRACE_OBJ_UMODS ((const char *)-3L) /* all user objects */
typedef struct dtrace_objinfo {
const char *dto_name; /* object file scope name */
const char *dto_file; /* object file path (if any) */
int dto_id; /* object file id (if any) */
uint_t dto_flags; /* object flags (see below) */
GElf_Addr dto_text_va; /* address of text section */
GElf_Xword dto_text_size; /* size of text section */
GElf_Addr dto_data_va; /* address of data section */
GElf_Xword dto_data_size; /* size of data section */
GElf_Addr dto_bss_va; /* address of BSS */
GElf_Xword dto_bss_size; /* size of BSS */
} dtrace_objinfo_t;
#define DTRACE_OBJ_F_KERNEL 0x1 /* object is a kernel module */
#define DTRACE_OBJ_F_PRIMARY 0x2 /* object is a primary module */
typedef int dtrace_obj_f(dtrace_hdl_t *, const dtrace_objinfo_t *, void *);
extern int dtrace_object_iter(dtrace_hdl_t *, dtrace_obj_f *, void *);
extern int dtrace_object_info(dtrace_hdl_t *, const char *, dtrace_objinfo_t *);
typedef struct dtrace_syminfo {
const char *dts_object; /* object name */
const char *dts_name; /* symbol name */
ulong_t dts_id; /* symbol id */
} dtrace_syminfo_t;
extern int dtrace_lookup_by_name(dtrace_hdl_t *, const char *, const char *,
GElf_Sym *, dtrace_syminfo_t *);
extern int dtrace_lookup_by_addr(dtrace_hdl_t *, GElf_Addr addr,
GElf_Sym *, dtrace_syminfo_t *);
typedef struct dtrace_typeinfo {
const char *dtt_object; /* object containing type */
ctf_file_t *dtt_ctfp; /* CTF container handle */
ctf_id_t dtt_type; /* CTF type identifier */
} dtrace_typeinfo_t;
extern int dtrace_lookup_by_type(dtrace_hdl_t *, const char *, const char *,
dtrace_typeinfo_t *);
extern int dtrace_symbol_type(dtrace_hdl_t *, const GElf_Sym *,
const dtrace_syminfo_t *, dtrace_typeinfo_t *);
extern int dtrace_type_strcompile(dtrace_hdl_t *,
const char *, dtrace_typeinfo_t *);
extern int dtrace_type_fcompile(dtrace_hdl_t *,
FILE *, dtrace_typeinfo_t *);
/*
* DTrace Probe Interface
*
* Library clients can use these functions to iterate over the set of available
* probe definitions and inquire as to their attributes. The probe iteration
* interfaces report probes that are declared as well as those from dtrace(7D).
*/
typedef struct dtrace_probeinfo {
dtrace_attribute_t dtp_attr; /* name attributes */
dtrace_attribute_t dtp_arga; /* arg attributes */
const dtrace_typeinfo_t *dtp_argv; /* arg types */
int dtp_argc; /* arg count */
} dtrace_probeinfo_t;
typedef int dtrace_probe_f(dtrace_hdl_t *, const dtrace_probedesc_t *, void *);
extern int dtrace_probe_iter(dtrace_hdl_t *,
const dtrace_probedesc_t *pdp, dtrace_probe_f *, void *);
extern int dtrace_probe_info(dtrace_hdl_t *,
const dtrace_probedesc_t *, dtrace_probeinfo_t *);
/*
* DTrace Vector Interface
*
* The DTrace library normally speaks directly to dtrace(7D). However,
* this communication may be vectored elsewhere. Consumers who wish to
* perform a vectored open must fill in the vector, and use the dtrace_vopen()
* entry point to obtain a library handle.
*/
struct dtrace_vector {
#if defined(sun)
int (*dtv_ioctl)(void *, int, void *);
#else
int (*dtv_ioctl)(void *, u_long, void *);
#endif
int (*dtv_lookup_by_addr)(void *, GElf_Addr, GElf_Sym *,
dtrace_syminfo_t *);
int (*dtv_status)(void *, processorid_t);
long (*dtv_sysconf)(void *, int);
};
/*
* DTrace Utility Functions
*
* Library clients can use these functions to convert addresses strings, to
* convert between string and integer probe descriptions and the
* dtrace_probedesc_t representation, and to perform similar conversions on
* stability attributes.
*/
extern int dtrace_addr2str(dtrace_hdl_t *, uint64_t, char *, int);
extern int dtrace_uaddr2str(dtrace_hdl_t *, pid_t, uint64_t, char *, int);
extern int dtrace_xstr2desc(dtrace_hdl_t *, dtrace_probespec_t,
const char *, int, char *const [], dtrace_probedesc_t *);
extern int dtrace_str2desc(dtrace_hdl_t *, dtrace_probespec_t,
const char *, dtrace_probedesc_t *);
extern int dtrace_id2desc(dtrace_hdl_t *, dtrace_id_t, dtrace_probedesc_t *);
#define DTRACE_DESC2STR_MAX 1024 /* min buf size for dtrace_desc2str() */
extern char *dtrace_desc2str(const dtrace_probedesc_t *, char *, size_t);
#define DTRACE_ATTR2STR_MAX 64 /* min buf size for dtrace_attr2str() */
extern char *dtrace_attr2str(dtrace_attribute_t, char *, size_t);
extern int dtrace_str2attr(const char *, dtrace_attribute_t *);
extern const char *dtrace_stability_name(dtrace_stability_t);
extern const char *dtrace_class_name(dtrace_class_t);
extern int dtrace_provider_modules(dtrace_hdl_t *, const char **, int);
extern const char *const _dtrace_version;
extern int _dtrace_debug;
#ifdef __cplusplus
}
#endif
#if !defined(sun)
#define _SC_CPUID_MAX _SC_NPROCESSORS_CONF
#define _SC_NPROCESSORS_MAX _SC_NPROCESSORS_CONF
#endif
#endif /* _DTRACE_H */

View File

@ -0,0 +1,59 @@
#!/bin/sh
#
# 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
#
#
# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
BSDECHO=-e
echo ${BSDECHO} "\
/*\n\
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.\n\
* Use is subject to license terms.\n\
*/\n\
\n\
#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n\
\n\
#include <dt_errtags.h>
\n\
static const char *const _dt_errtags[] = {"
pattern='^ \(D_[A-Z0-9_]*\),*'
replace=' "\1",'
sed -n "s/$pattern/$replace/p" || exit 1
echo ${BSDECHO} "\
};\n\
\n\
static const int _dt_ntag = sizeof (_dt_errtags) / sizeof (_dt_errtags[0]);\n\
\n\
const char *
dt_errtag(dt_errtag_t tag)
{
return (_dt_errtags[(tag > 0 && tag < _dt_ntag) ? tag : 0]);
}"
exit 0

View File

@ -0,0 +1,55 @@
#!/bin/sh
#
# 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
#
#
# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
BSDECHO=-e
echo ${BSDECHO} "\
/*\n\
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.\n\
* Use is subject to license terms.\n\
*/\n\
\n\
#pragma ident\t\"%Z%%M%\t%I%\t%E% SMI\"\n\
\n\
#include <dtrace.h>\n\
\n\
/*ARGSUSED*/
const char *\n\
dtrace_subrstr(dtrace_hdl_t *dtp, int subr)\n\
{\n\
switch (subr) {"
nawk '
/^#define[ ]*DIF_SUBR_/ && $2 != "DIF_SUBR_MAX" {
printf("\tcase %s: return (\"%s\");\n", $2, tolower(substr($2, 10)));
}'
echo ${BSDECHO} "\
default: return (\"unknown\");\n\
}\n\
}"

View File

@ -0,0 +1,179 @@
/*
* 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
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1.5.2 */
/*LINTLIBRARY*/
#if defined(sun)
#pragma weak gmatch = _gmatch
#endif
#if defined(sun)
#include "gen_synonyms.h"
#endif
#include <sys/types.h>
#include <libgen.h>
#include <stdlib.h>
#include <limits.h>
#if defined(sun)
#include <widec.h>
#include "_range.h"
#else
/* DOODAD */ static int multibyte = 0;
#define WCHAR_CSMASK 0x30000000
#define valid_range(c1, c2) \
(((c1) & WCHAR_CSMASK) == ((c2) & WCHAR_CSMASK) && \
((c1) > 0xff || !iscntrl((int)c1)) && ((c2) > 0xff || \
!iscntrl((int)c2)))
#endif
#define Popwchar(p, c) \
n = mbtowc(&cl, p, MB_LEN_MAX); \
c = cl; \
if (n <= 0) \
return (0); \
p += n;
int
gmatch(const char *s, const char *p)
{
const char *olds;
wchar_t scc, c;
int n;
wchar_t cl;
olds = s;
n = mbtowc(&cl, s, MB_LEN_MAX);
if (n <= 0) {
s++;
scc = n;
} else {
scc = cl;
s += n;
}
n = mbtowc(&cl, p, MB_LEN_MAX);
if (n < 0)
return (0);
if (n == 0)
return (scc == 0);
p += n;
c = cl;
switch (c) {
case '[':
if (scc <= 0)
return (0);
{
int ok;
wchar_t lc = 0;
int notflag = 0;
ok = 0;
if (*p == '!') {
notflag = 1;
p++;
}
Popwchar(p, c)
do
{
if (c == '-' && lc && *p != ']') {
Popwchar(p, c)
if (c == '\\') {
Popwchar(p, c)
}
if (notflag) {
if (!multibyte ||
valid_range(lc, c)) {
if (scc < lc || scc > c)
ok++;
else
return (0);
}
} else {
if (!multibyte ||
valid_range(lc, c))
if (lc <= scc &&
scc <= c)
ok++;
}
} else if (c == '\\') {
/* skip to quoted character */
Popwchar(p, c)
}
lc = c;
if (notflag) {
if (scc != lc)
ok++;
else
return (0);
}
else
{
if (scc == lc)
ok++;
}
Popwchar(p, c)
} while (c != ']');
return (ok ? gmatch(s, p) : 0);
}
case '\\':
/* skip to quoted character and see if it matches */
Popwchar(p, c)
default:
if (c != scc)
return (0);
/*FALLTHRU*/
case '?':
return (scc > 0 ? gmatch(s, p) : 0);
case '*':
while (*p == '*')
p++;
if (*p == 0)
return (1);
s = olds;
while (*s) {
if (gmatch(s, p))
return (1);
n = mbtowc(&cl, s, MB_LEN_MAX);
if (n < 0)
/* skip past illegal byte sequence */
s++;
else
s += n;
}
return (0);
}
}