Vendor import of libraries for DTrace from OpenSolaris.
This commit is contained in:
parent
12456ea875
commit
c53d354ffe
500
lib/libctf/common/ctf_lib.c
Normal file
500
lib/libctf/common/ctf_lib.c
Normal 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);
|
||||
}
|
83
lib/libctf/common/ctf_subr.c
Normal file
83
lib/libctf/common/ctf_subr.c
Normal 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);
|
||||
}
|
||||
}
|
60
lib/libctf/common/libctf.h
Normal file
60
lib/libctf/common/libctf.h
Normal 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 */
|
206
lib/libdtrace/common/drti.c
Normal file
206
lib/libdtrace/common/drti.c
Normal 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);
|
||||
}
|
1886
lib/libdtrace/common/dt_aggregate.c
Normal file
1886
lib/libdtrace/common/dt_aggregate.c
Normal file
File diff suppressed because it is too large
Load Diff
501
lib/libdtrace/common/dt_as.c
Normal file
501
lib/libdtrace/common/dt_as.c
Normal 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);
|
||||
}
|
64
lib/libdtrace/common/dt_as.h
Normal file
64
lib/libdtrace/common/dt_as.h
Normal 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 */
|
177
lib/libdtrace/common/dt_buf.c
Normal file
177
lib/libdtrace/common/dt_buf.c
Normal 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);
|
||||
}
|
69
lib/libdtrace/common/dt_buf.h
Normal file
69
lib/libdtrace/common/dt_buf.h
Normal 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 */
|
2349
lib/libdtrace/common/dt_cc.c
Normal file
2349
lib/libdtrace/common/dt_cc.c
Normal file
File diff suppressed because it is too large
Load Diff
2006
lib/libdtrace/common/dt_cg.c
Normal file
2006
lib/libdtrace/common/dt_cg.c
Normal file
File diff suppressed because it is too large
Load Diff
2646
lib/libdtrace/common/dt_consume.c
Normal file
2646
lib/libdtrace/common/dt_consume.c
Normal file
File diff suppressed because it is too large
Load Diff
1127
lib/libdtrace/common/dt_decl.c
Normal file
1127
lib/libdtrace/common/dt_decl.c
Normal file
File diff suppressed because it is too large
Load Diff
126
lib/libdtrace/common/dt_decl.h
Normal file
126
lib/libdtrace/common/dt_decl.h
Normal 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 */
|
511
lib/libdtrace/common/dt_dis.c
Normal file
511
lib/libdtrace/common/dt_dis.c
Normal 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);
|
||||
}
|
969
lib/libdtrace/common/dt_dof.c
Normal file
969
lib/libdtrace/common/dt_dof.c
Normal 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);
|
||||
}
|
66
lib/libdtrace/common/dt_dof.h
Normal file
66
lib/libdtrace/common/dt_dof.h
Normal 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 */
|
235
lib/libdtrace/common/dt_error.c
Normal file
235
lib/libdtrace/common/dt_error.c
Normal 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");
|
||||
}
|
251
lib/libdtrace/common/dt_errtags.h
Normal file
251
lib/libdtrace/common/dt_errtags.h
Normal 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 */
|
834
lib/libdtrace/common/dt_grammar.y
Normal file
834
lib/libdtrace/common/dt_grammar.y
Normal 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; }
|
||||
;
|
||||
|
||||
%%
|
483
lib/libdtrace/common/dt_handle.c
Normal file
483
lib/libdtrace/common/dt_handle.c
Normal 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);
|
||||
}
|
1047
lib/libdtrace/common/dt_ident.c
Normal file
1047
lib/libdtrace/common/dt_ident.c
Normal file
File diff suppressed because it is too large
Load Diff
183
lib/libdtrace/common/dt_ident.h
Normal file
183
lib/libdtrace/common/dt_ident.h
Normal 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 */
|
691
lib/libdtrace/common/dt_impl.h
Normal file
691
lib/libdtrace/common/dt_impl.h
Normal 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 */
|
115
lib/libdtrace/common/dt_inttab.c
Normal file
115
lib/libdtrace/common/dt_inttab.c
Normal 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;
|
||||
}
|
69
lib/libdtrace/common/dt_inttab.h
Normal file
69
lib/libdtrace/common/dt_inttab.h
Normal 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 */
|
860
lib/libdtrace/common/dt_lex.l
Normal file
860
lib/libdtrace/common/dt_lex.l
Normal 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
|
1774
lib/libdtrace/common/dt_link.c
Normal file
1774
lib/libdtrace/common/dt_link.c
Normal file
File diff suppressed because it is too large
Load Diff
111
lib/libdtrace/common/dt_list.c
Normal file
111
lib/libdtrace/common/dt_list.c
Normal 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;
|
||||
}
|
53
lib/libdtrace/common/dt_list.h
Normal file
53
lib/libdtrace/common/dt_list.h
Normal 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 */
|
442
lib/libdtrace/common/dt_map.c
Normal file
442
lib/libdtrace/common/dt_map.c
Normal 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;
|
||||
}
|
1383
lib/libdtrace/common/dt_module.c
Normal file
1383
lib/libdtrace/common/dt_module.c
Normal file
File diff suppressed because it is too large
Load Diff
56
lib/libdtrace/common/dt_module.h
Normal file
56
lib/libdtrace/common/dt_module.h
Normal 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 */
|
1643
lib/libdtrace/common/dt_open.c
Normal file
1643
lib/libdtrace/common/dt_open.c
Normal file
File diff suppressed because it is too large
Load Diff
1031
lib/libdtrace/common/dt_options.c
Normal file
1031
lib/libdtrace/common/dt_options.c
Normal file
File diff suppressed because it is too large
Load Diff
4893
lib/libdtrace/common/dt_parser.c
Normal file
4893
lib/libdtrace/common/dt_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
285
lib/libdtrace/common/dt_parser.h
Normal file
285
lib/libdtrace/common/dt_parser.h
Normal 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 */
|
187
lib/libdtrace/common/dt_pcb.c
Normal file
187
lib/libdtrace/common/dt_pcb.c
Normal 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);
|
||||
}
|
103
lib/libdtrace/common/dt_pcb.h
Normal file
103
lib/libdtrace/common/dt_pcb.h
Normal 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 */
|
863
lib/libdtrace/common/dt_pid.c
Normal file
863
lib/libdtrace/common/dt_pid.c
Normal 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);
|
||||
}
|
64
lib/libdtrace/common/dt_pid.h
Normal file
64
lib/libdtrace/common/dt_pid.h
Normal 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 */
|
507
lib/libdtrace/common/dt_pragma.c
Normal file
507
lib/libdtrace/common/dt_pragma.c
Normal 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);
|
||||
}
|
1979
lib/libdtrace/common/dt_printf.c
Normal file
1979
lib/libdtrace/common/dt_printf.c
Normal file
File diff suppressed because it is too large
Load Diff
135
lib/libdtrace/common/dt_printf.h
Normal file
135
lib/libdtrace/common/dt_printf.h
Normal 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 */
|
1223
lib/libdtrace/common/dt_proc.c
Normal file
1223
lib/libdtrace/common/dt_proc.c
Normal file
File diff suppressed because it is too large
Load Diff
118
lib/libdtrace/common/dt_proc.h
Normal file
118
lib/libdtrace/common/dt_proc.h
Normal 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 */
|
606
lib/libdtrace/common/dt_program.c
Normal file
606
lib/libdtrace/common/dt_program.c
Normal 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);
|
||||
}
|
63
lib/libdtrace/common/dt_program.h
Normal file
63
lib/libdtrace/common/dt_program.h
Normal 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 */
|
883
lib/libdtrace/common/dt_provider.c
Normal file
883
lib/libdtrace/common/dt_provider.c
Normal 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));
|
||||
}
|
||||
}
|
118
lib/libdtrace/common/dt_provider.h
Normal file
118
lib/libdtrace/common/dt_provider.h
Normal 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 */
|
107
lib/libdtrace/common/dt_regset.c
Normal file
107
lib/libdtrace/common/dt_regset.c
Normal 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);
|
||||
}
|
53
lib/libdtrace/common/dt_regset.h
Normal file
53
lib/libdtrace/common/dt_regset.h
Normal 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 */
|
325
lib/libdtrace/common/dt_string.c
Normal file
325
lib/libdtrace/common/dt_string.c
Normal 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);
|
||||
}
|
51
lib/libdtrace/common/dt_string.h
Normal file
51
lib/libdtrace/common/dt_string.h
Normal 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 */
|
293
lib/libdtrace/common/dt_strtab.c
Normal file
293
lib/libdtrace/common/dt_strtab.c
Normal 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);
|
||||
}
|
72
lib/libdtrace/common/dt_strtab.h
Normal file
72
lib/libdtrace/common/dt_strtab.h
Normal 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 */
|
997
lib/libdtrace/common/dt_subr.c
Normal file
997
lib/libdtrace/common/dt_subr.c
Normal 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));
|
||||
}
|
319
lib/libdtrace/common/dt_work.c
Normal file
319
lib/libdtrace/common/dt_work.c
Normal 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);
|
||||
}
|
383
lib/libdtrace/common/dt_xlator.c
Normal file
383
lib/libdtrace/common/dt_xlator.c
Normal 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);
|
||||
}
|
87
lib/libdtrace/common/dt_xlator.h
Normal file
87
lib/libdtrace/common/dt_xlator.h
Normal 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 */
|
580
lib/libdtrace/common/dtrace.h
Normal file
580
lib/libdtrace/common/dtrace.h
Normal 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 */
|
59
lib/libdtrace/common/mkerrtags.sh
Normal file
59
lib/libdtrace/common/mkerrtags.sh
Normal 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
|
55
lib/libdtrace/common/mknames.sh
Normal file
55
lib/libdtrace/common/mknames.sh
Normal 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\
|
||||
}"
|
179
lib/libgen/common/gmatch.c
Normal file
179
lib/libgen/common/gmatch.c
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user