/*
* 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
* 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) 2012 by Delphix. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <strings.h>
#include <unistd.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <alloca.h>
#include <assert.h>
#include <libgen.h>
#include <limits.h>
#include <dt_impl.h>
static const struct {
} dtrace_probespecs[] = {
};
int
{
const char *p, *q, *v, *w;
p = s + strlen(s) - 1;
do {
p--; /* move backward until we find a delimiter */
q = p + 1;
vlen = 0;
w = NULL;
wlen = 0;
/*
* 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).
*/
/*
* If the variable string begins with $$, skip past the
* leading dollar sign since $ and $$ are equivalent
* macro reference operators in a probe description.
*/
vlen--;
v++;
}
if (isdigit(v[1])) {
long i;
errno = 0;
v = argv[i];
} else if (vlen > 1) {
v = buf;
} else
}
if (spec == DTRACE_PROBESPEC_NONE)
} while (--p >= s);
return (0);
}
int
const char *s, dtrace_probedesc_t *pdp)
{
}
int
{
return (0);
}
char *
{
} else
return (buf);
}
char *
{
return (NULL); /* one or more invalid attributes */
return (buf);
}
static char *
{
char *q;
if (*p == '\0')
return (NULL);
q = p + strlen(p);
else
*q++ = '\0';
*qp = q;
return (p);
}
int
{
char *p, *q;
return (-1); /* invalid function arguments */
*attr = _dtrace_maxattr;
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) {
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) {
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;
}
}
return (-1);
return (0);
}
const char *
{
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 *
{
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);
}
}
{
return (am);
}
{
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
{
}
char *
{
} else {
}
return (buf);
}
char *
{
uint_t M = DT_VERSION_MAJOR(v);
uint_t m = DT_VERSION_MINOR(v);
uint_t u = DT_VERSION_MICRO(v);
if (u == 0)
else
return (buf);
}
int
{
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);
return (0);
}
int
{
int i;
for (i = 0; _dtrace_versions[i] != 0; i++) {
if (_dtrace_versions[i] == v)
return (1);
}
return (0);
}
char *
{
char *arg;
return (NULL);
}
return (NULL);
return (arg);
}
char *
{
char *arg;
return (NULL); /* dt_cpp_argv[0] cannot be popped */
return (arg);
}
/*PRINTFLIKE1*/
void
{
if (_dtrace_debug) {
}
}
int
{
if (v != NULL)
return (-1);
}
int
{
if (v == NULL)
}
long
{
if (v == NULL)
}
/*
* 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'.
*/
{
while (resid != 0) {
break;
}
if (resid == n && n != 0)
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
{
int n;
if (dtp->dt_sprintf_buflen != 0) {
int len;
char *buf;
return (n);
}
/*
* Using buffered output is not allowed if a handler has
* not been installed.
*/
}
}
dtp->dt_buffered_offs = 0;
}
return (rval);
}
if (needed == 0) {
return (0);
}
for (;;) {
char *newbuf;
break;
}
}
return (rval);
}
return (0);
}
if (n < 0) {
}
return (n);
}
int
{
if (dtp->dt_buffered_offs == 0)
return (0);
dtp->dt_buffered_offs = 0;
return (0);
}
void
{
dtp->dt_buffered_offs = 0;
dtp->dt_buffered_size = 0;
}
void *
{
void *data;
else
return (data);
}
void *
{
void *data;
return (data);
}
void
{
}
void
{
return; /* simplify caller code */
}
/*
* 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)
{
}
char *
{
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.
*/
{
#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'.
*/
{
if (n == 0)
return (0);
for (w = 0; w < maxw; w++)
}
static int
{
if (nbytes == 0) {
/*
* Like snprintf(3C), we don't check the value of str if the
* number of bytes is 0.
*/
return (len);
}
/*
* Like snprintf(3C) (and unlike strncpy(3C)), we guarantee
* that the string is null-terminated.
*/
} else {
}
return (len);
}
int
{
char *s;
int err;
s = alloca(n);
} else if (err == 0) {
(void) snprintf(s, n, "%s`%s",
} 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.
*/
(u_longlong_t)addr);
} else {
}
}
}
int
{
struct ps_prochandle *P = NULL;
char *obj;
if (pid != 0)
if (P == NULL) {
}
dt_proc_lock(dtp, P);
} else {
}
(void) snprintf(c, sizeof (c), "%s`0x%llx",
} else {
}
dt_proc_unlock(dtp, P);
dt_proc_release(dtp, P);
}