node_modules updated, buefy add to lib folder

This commit is contained in:
2019-06-04 14:29:48 +02:00
parent 0a3f6ff240
commit 5d28bc36e1
3957 changed files with 306575 additions and 21738 deletions
+10
View File
@@ -0,0 +1,10 @@
*.o
*.a
*.gch
*~
*#
.#*
test_usdt
test_usdt32
test_usdt64
test_mem_usage
+21
View File
@@ -0,0 +1,21 @@
Copyright 2012 Chris Andrews. All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY CHRIS ANDREWS ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CHRIS ANDREWS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+158
View File
@@ -0,0 +1,158 @@
CC = gcc
CFLAGS = -O2 -Wall
# MAC_BUILD - set this to "universal" to build a 2-way fat library
MAC_BUILD = universal
# if ARCH set, disable universal build on the mac
ifdef ARCH
MAC_BUILD =
else
ARCH = $(shell uname -m)
endif
UNAME = $(shell uname -s)
ifeq ($(UNAME), Linux)
RANLIB=ranlib
CFLAGS+=-D_GNU_SOURCE -fPIC
endif
ifeq ($(UNAME), SunOS)
RANLIB=/bin/true
PATH +=:/usr/perl5/5.10.0/bin:/usr/perl5/5.12/bin
CFLAGS += -fPIC
ifeq ($(ARCH), i86pc)
ARCH = $(shell isainfo -k)
ifeq ($(ARCH), amd64)
ARCH = x86_64
else
ARCH = i386
endif
endif
ifeq ($(ARCH), x86_64)
CFLAGS += -m64
else
CFLAGS += -m32
endif
endif
ifeq ($(UNAME), FreeBSD)
RANLIB=ranlib
CFLAGS += -Wno-error=unknown-pragmas -I/usr/src/sys/cddl/compat/opensolaris -I/usr/src/sys/cddl/contrib/opensolaris/uts/common
CFLAGS += -fPIC
ifeq ($(ARCH), i386)
CFLAGS += -m32
endif
ifeq ($(ARCH), amd64)
ARCH = x86_64
endif
endif
ifeq ($(UNAME), Darwin)
RANLIB=ranlib
ifeq ($(MAC_BUILD), universal)
CFLAGS += -arch i386 -arch x86_64
else
CFLAGS += -arch $(ARCH)
endif
endif
# main library build
objects = usdt.o usdt_dof_file.o usdt_tracepoints.o usdt_probe.o usdt_dof.o usdt_dof_sections.o
headers = usdt.h usdt_internal.h
.c.o: $(headers)
all: libusdt.a
libusdt.a: $(objects) $(headers)
rm -f libusdt.a
$(AR) cru libusdt.a $(objects)
$(RANLIB) libusdt.a
# Tracepoints build.
#
# If on Darwin and building a universal library, manually assemble a
# two-way fat object file from both the 32 and 64 bit tracepoint asm
# files.
#
# Otherwise, just choose the appropriate asm file based on the build
# architecture.
ifeq ($(UNAME), Darwin)
ifeq ($(MAC_BUILD), universal)
usdt_tracepoints_i386.o: usdt_tracepoints_i386.s
$(CC) -arch i386 -o usdt_tracepoints_i386.o -c usdt_tracepoints_i386.s
usdt_tracepoints_x86_64.o: usdt_tracepoints_x86_64.s
$(CC) -arch x86_64 -o usdt_tracepoints_x86_64.o -c usdt_tracepoints_x86_64.s
usdt_tracepoints.o: usdt_tracepoints_i386.o usdt_tracepoints_x86_64.o
lipo -create -output usdt_tracepoints.o usdt_tracepoints_i386.o \
usdt_tracepoints_x86_64.o
else # Darwin, not universal
usdt_tracepoints.o: usdt_tracepoints_$(ARCH).s
$(CC) -arch $(ARCH) -o usdt_tracepoints.o -c usdt_tracepoints_$(ARCH).s
endif
else # not Darwin; FreeBSD and Illumos
ifeq ($(ARCH), x86_64)
usdt_tracepoints.o: usdt_tracepoints_x86_64.s
$(CC) $(CFLAGS) -o usdt_tracepoints.o -c usdt_tracepoints_x86_64.s
endif
ifeq ($(ARCH), i386)
usdt_tracepoints.o: usdt_tracepoints_i386.s
$(CC) $(CFLAGS) -o usdt_tracepoints.o -c usdt_tracepoints_i386.s
endif
endif
clean:
rm -f *.gch
rm -f *.o
rm -f libusdt.a
rm -f test_usdt
rm -f test_usdt32
rm -f test_usdt64
rm -f test_mem_usage
.PHONY: clean test
# testing
test_mem_usage: libusdt.a test_mem_usage.o
$(CC) $(CFLAGS) -o test_mem_usage test_mem_usage.o libusdt.a
ifeq ($(UNAME), Darwin)
ifeq ($(MAC_BUILD), universal)
test_usdt64: libusdt.a test_usdt.o
$(CC) -arch x86_64 -o test_usdt64 test_usdt.o libusdt.a
test_usdt32: libusdt.a test_usdt.o
$(CC) -arch i386 -o test_usdt32 test_usdt.o libusdt.a
else
test_usdt: libusdt.a test_usdt.o
$(CC) $(CFLAGS) -o test_usdt test_usdt.o libusdt.a
endif
else
test_usdt: libusdt.a test_usdt.o
$(CC) $(CFLAGS) -o test_usdt test_usdt.o libusdt.a
endif
ifeq ($(UNAME), Darwin)
ifeq ($(MAC_BUILD), universal)
test: test_usdt32 test_usdt64
sudo prove test.pl :: 64
sudo prove test.pl :: 32
else
test: test_usdt
sudo prove test.pl
endif
else
test: test_usdt
sudo prove test.pl
endif
+77
View File
@@ -0,0 +1,77 @@
libusdt
=======
This is "libusdt", a library for creating DTrace USDT providers.
The idea here is to allow the specification of a DTrace provider
dynamically in code and then create the provider at runtime. This
allows providers to be specified in dynamic languages, given suitable
bindings.
The general approach is to create two stub functions for each probe,
one for the is-enabled check and one for the probe itself. These
contain the appropriate instruction sequences to appear to DTrace as
compiled-in tracepoints. A minimal DOF document is built describing
the provider and indicating these stub functions as the tracepoints,
then submitted to the kernel, creating the provider. The API then
exposes the stubs, through which the probes may be fired.
Status
------
The implementation here works as shown in test_usdt.c on Mac OS X,
i386 and x86_64, on Solaris-like systems, i386 and x86_64 and on
FreeBSD and Oracle Linux, x86_64 only.
Is-enabled probes are supported and exposed in the API.
There is a "test" target which runs a number of tests of the library,
for which perl is required.
OS X builds are Universal by default, and on Solaris, the ARCH
variable may be set to either i386 or x86_64 to force a particular
build.
FreeBSD builds suffer from broken argument handling; this is a known
issue with the current state of DTrace generally on FreeBSD: only the
first five arguments work reliably. See:
http://wiki.freebsd.org/DTraceTODO
See Also
--------
There are various language bindings available:
Lua:
https://github.com/chrisa/lua-usdt
Ruby (by Kevin Chan):
https://github.com/kevinykchan/ruby-usdt
Node.JS:
https://github.com/chrisa/node-dtrace-provider
Perl:
https://github.com/chrisa/perl-Devel-DTrace-Provider
To Do
-----
Platform support:
* add support for FreeBSD 9.0 i386
* add support for Mac OS X PowerPC
* add support for Solaris SPARC
Features:
* add a "low level" API, allowing alternative provision of
tracepoints for closer integration with language VMs.
* support structured types, with close integration with the host
DTrace system.
+116
View File
@@ -0,0 +1,116 @@
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open3;
use Symbol 'gensym';
use IO::Handle;
use Test::More qw/ no_plan /;
my $USDT_ARG_MAX = 32;
if ($^O eq 'freebsd') {
# FreeBSD currently only supports 5 arguments to USDT probes
$USDT_ARG_MAX = 5;
}
my $arch;
if (scalar @ARGV == 1) {
$arch = $ARGV[0];
}
my $user_t = ($^O eq 'darwin') ? 'user_addr_t' : 'uintptr_t';
run_tests('c', 'A');
run_tests('i', 1);
sub run_tests {
my ($type, $start_arg) = @_;
for my $i (0..$USDT_ARG_MAX) {
my ($t_status, $d_status, $output) = run_dtrace('type'.$type, $i.'arg', split(//, $type x $i));
is($t_status, 0, 'test exit status is 0');
is($d_status, 0, 'dtrace exit status is 0');
like($output, qr/type[ic]:\d+arg/, 'function and name match');
my $arg = $start_arg;
for my $j (0..$i - 1) {
like($output, qr/arg$j:'\Q$arg\E'/, "type '$type' arg $j is $arg");
if ($type eq 'i') {
$arg++;
}
else {
$arg = chr(ord($arg) + 1);
}
}
}
}
# --------------------------------------------------------------------------
sub gen_d {
my (@types) = @_;
my $d = 'testlibusdt*:::{ ';
my $i = 0;
for my $type (@types) {
if ($type eq 'i') {
$d .= "printf(\"arg$i:'%i' \", args[$i]); ";
}
if ($type eq 'c') {
$d .= "printf(\"arg$i:'%s' \", copyinstr(($user_t)args[$i])); ";
}
$i++;
}
$d .= '}';
return $d;
}
sub run_dtrace {
my ($func, $name, @types) = @_;
my $d = gen_d(@types);
my @t_cmd;
if (defined $arch) {
@t_cmd = ("./test_usdt$arch", $func, $name, @types);
}
else {
@t_cmd = ("./test_usdt", $func, $name, @types);
}
my ($d_wtr, $d_rdr, $d_err);
my ($t_wtr, $t_rdr, $t_err);
$d_err = gensym;
$t_err = gensym;
#diag(join(' ', @t_cmd));
my $t_pid = open3($t_wtr, $t_rdr, $t_err, @t_cmd);
my $enabled = $t_rdr->getline;
my @d_cmd = ('/usr/sbin/dtrace', '-p', $t_pid, '-n', $d);
#diag(join(' ', @d_cmd));
my $d_pid = open3($d_wtr, $d_rdr, $d_err, @d_cmd);
my $matched = $d_err->getline; # expect "matched 1 probe"
$t_wtr->print("go\n");
$t_wtr->flush;
waitpid( $t_pid, 0 );
my $t_status = $? >> 8;
my ($header, $output) = ($d_rdr->getline, $d_rdr->getline);
chomp $header;
chomp $output;
#diag("DTrace header: $header\n");
#diag("DTrace output: $output\n");
waitpid( $d_pid, 0 );
my $d_status = $? >> 8;
while (!$d_err->eof) {
my $error = $d_err->getline;
chomp $error;
#diag "DTrace error: $error";
}
return ($t_status, $d_status, $output || '');
}
+77
View File
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
create_and_free_provider(int argc, char **argv)
{
usdt_provider_t *provider;
usdt_probedef_t *probedef;
if ((provider = usdt_create_provider("testlibusdt", "modname")) == NULL) {
fprintf(stderr, "unable to create provider\n");
exit (1);
}
if ((probedef = usdt_create_probe((const char *)argv[1],
(const char *)argv[2],
(argc-3), (const char **)&argv[3])) == NULL)
{
fprintf(stderr, "unable to create probe\n");
exit (1);
}
usdt_provider_add_probe(provider, probedef);
if ((usdt_provider_enable(provider)) < 0) {
fprintf(stderr, "unable to enable provider: %s\n", usdt_errstr(provider));
exit (1);
}
if ((usdt_provider_disable(provider)) < 0) {
fprintf(stderr, "unable to disable provider: %s\n", usdt_errstr(provider));
exit (1);
}
usdt_probe_release(probedef);
usdt_provider_free(provider);
}
int
main(int argc, char **argv)
{
char char_argv[USDT_ARG_MAX];
int int_argv[USDT_ARG_MAX * 2];
int i;
char buf[255];
for (i = 0; i < USDT_ARG_MAX; i++)
int_argv[i] = i + 1;
for (i = 0; i < USDT_ARG_MAX; i++)
char_argv[i] = (char) i + 65;
if (argc < 3) {
fprintf(stderr, "usage: %s func name [types ...]\n", argv[0]);
return(1);
}
for (i = 0; i < USDT_ARG_MAX; i++) {
if (argv[i+3] != NULL && i+3 < argc) {
if (strncmp("c", argv[i+3], 1) == 0) {
argv[i+3] = strdup("char *");
}
if (strncmp("i", argv[i+3], 1) == 0) {
argv[i+3] = strdup("int");
}
}
}
for (i = 0; i < 100000; i++)
create_and_free_provider(argc, argv);
return 0;
}
+87
View File
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
fire_probe(usdt_probedef_t *probedef, int argc, void **argv)
{
if (usdt_is_enabled(probedef->probe))
usdt_fire_probe(probedef->probe, argc, argv);
}
int main(int argc, char **argv) {
usdt_provider_t *provider;
usdt_probedef_t *probedef;
char char_argv[USDT_ARG_MAX];
int int_argv[USDT_ARG_MAX * 2];
void **args = NULL;
int i;
char buf[255];
for (i = 0; i < USDT_ARG_MAX; i++)
int_argv[i] = i + 1;
for (i = 0; i < USDT_ARG_MAX; i++)
char_argv[i] = (char) i + 65;
if (argc < 3) {
fprintf(stderr, "usage: %s func name [types ...]\n", argv[0]);
return(1);
}
if (argc > 3) {
args = malloc((argc-3) * sizeof(void *));
}
for (i = 0; i < USDT_ARG_MAX; i++) {
if (argv[i+3] != NULL && i+3 < argc) {
if (strncmp("c", argv[i+3], 1) == 0) {
args[i] = (void *)strndup(&char_argv[i], 1);
argv[i+3] = strdup("char *");
}
if (strncmp("i", argv[i+3], 1) == 0) {
args[i] = (void *)(long)int_argv[i];
argv[i+3] = strdup("int");
}
}
}
if ((provider = usdt_create_provider("testlibusdt", "modname")) == NULL) {
fprintf(stderr, "unable to create provider\n");
exit (1);
}
if ((probedef = usdt_create_probe((const char *)argv[1],
(const char *)argv[2],
(argc-3), (const char **)&argv[3])) == NULL)
{
fprintf(stderr, "unable to create probe\n");
exit (1);
}
usdt_provider_add_probe(provider, probedef);
if ((usdt_provider_enable(provider)) < 0) {
fprintf(stderr, "unable to enable provider: %s\n", usdt_errstr(provider));
exit (1);
}
fprintf(stdout, "enabled\n");
fflush(stdout);
fgets(buf, 255, stdin);
fire_probe(probedef, (argc-3), (void **)args);
usdt_probe_release(probedef);
if ((usdt_provider_disable(provider)) < 0) {
fprintf(stderr, "unable to disable provider: %s\n", usdt_errstr(provider));
exit (1);
}
usdt_provider_free(provider);
return 0;
}
+321
View File
@@ -0,0 +1,321 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt_internal.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
char *usdt_errors[] = {
"failed to allocate memory",
"failed to allocate page-aligned memory",
"no probes defined",
"failed to load DOF: %s",
"provider is already enabled",
"failed to unload DOF: %s",
"probe named %s:%s:%s:%s already exists",
"failed to remove probe %s:%s:%s:%s"
};
static void
free_probedef(usdt_probedef_t *pd)
{
int i;
switch (pd->refcnt) {
case 1:
free((char *)pd->function);
free((char *)pd->name);
if (pd->probe) {
usdt_free_tracepoints(pd->probe);
free(pd->probe);
}
for (i = 0; i < pd->argc; i++)
free(pd->types[i]);
free(pd);
break;
case 2:
pd->refcnt = 1;
break;
default:
break;
}
}
usdt_provider_t *
usdt_create_provider(const char *name, const char *module)
{
usdt_provider_t *provider;
if ((provider = malloc(sizeof *provider)) == NULL)
return NULL;
provider->name = strdup(name);
provider->module = strdup(module);
provider->probedefs = NULL;
provider->enabled = 0;
return provider;
}
usdt_probedef_t *
usdt_create_probe(const char *func, const char *name, size_t argc, const char **types)
{
int i;
usdt_probedef_t *p;
if (argc > USDT_ARG_MAX)
argc = USDT_ARG_MAX;
if ((p = malloc(sizeof *p)) == NULL)
return (NULL);
p->refcnt = 2;
p->function = strdup(func);
p->name = strdup(name);
p->argc = argc;
p->probe = NULL;
for (i = 0; i < argc; i++)
p->types[i] = strdup(types[i]);
return (p);
}
void
usdt_probe_release(usdt_probedef_t *probedef)
{
free_probedef(probedef);
}
int
usdt_provider_add_probe(usdt_provider_t *provider, usdt_probedef_t *probedef)
{
usdt_probedef_t *pd;
if (provider->probedefs != NULL) {
for (pd = provider->probedefs; (pd != NULL); pd = pd->next) {
if ((strcmp(pd->name, probedef->name) == 0) &&
(strcmp(pd->function, probedef->function) == 0)) {
usdt_error(provider, USDT_ERROR_DUP_PROBE,
provider->name, provider->module,
probedef->function, probedef->name);
return (-1);
}
}
}
probedef->next = NULL;
if (provider->probedefs == NULL)
provider->probedefs = probedef;
else {
for (pd = provider->probedefs; (pd->next != NULL); pd = pd->next) ;
pd->next = probedef;
}
return (0);
}
int
usdt_provider_remove_probe(usdt_provider_t *provider, usdt_probedef_t *probedef)
{
usdt_probedef_t *pd, *prev_pd = NULL;
if (provider->probedefs == NULL) {
usdt_error(provider, USDT_ERROR_NOPROBES);
return (-1);
}
for (pd = provider->probedefs; (pd != NULL);
prev_pd = pd, pd = pd->next) {
if ((strcmp(pd->name, probedef->name) == 0) &&
(strcmp(pd->function, probedef->function) == 0)) {
if (prev_pd == NULL)
provider->probedefs = pd->next;
else
prev_pd->next = pd->next;
return (0);
}
}
usdt_error(provider, USDT_ERROR_REMOVE_PROBE,
provider->name, provider->module,
probedef->function, probedef->name);
return (-1);
}
int
usdt_provider_enable(usdt_provider_t *provider)
{
usdt_strtab_t strtab;
usdt_dof_file_t *file;
usdt_probedef_t *pd;
int i;
size_t size;
usdt_dof_section_t sects[5];
if (provider->enabled == 1) {
usdt_error(provider, USDT_ERROR_ALREADYENABLED);
return (0); /* not fatal */
}
if (provider->probedefs == NULL) {
usdt_error(provider, USDT_ERROR_NOPROBES);
return (-1);
}
for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
if ((pd->probe = malloc(sizeof(*pd->probe))) == NULL) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
}
if ((usdt_strtab_init(&strtab, 0)) < 0) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
if ((usdt_strtab_add(&strtab, provider->name)) == 0) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
if ((usdt_dof_probes_sect(&sects[0], provider, &strtab)) < 0)
return (-1);
if ((usdt_dof_prargs_sect(&sects[1], provider)) < 0)
return (-1);
size = usdt_provider_dof_size(provider, &strtab);
if ((file = usdt_dof_file_init(provider, size)) == NULL)
return (-1);
if ((usdt_dof_proffs_sect(&sects[2], provider, file->dof)) < 0)
return (-1);
if ((usdt_dof_prenoffs_sect(&sects[3], provider, file->dof)) < 0)
return (-1);
if ((usdt_dof_provider_sect(&sects[4], provider)) < 0)
return (-1);
for (i = 0; i < 5; i++)
usdt_dof_file_append_section(file, &sects[i]);
usdt_dof_file_generate(file, &strtab);
usdt_dof_section_free((usdt_dof_section_t *)&strtab);
for (i = 0; i < 5; i++)
usdt_dof_section_free(&sects[i]);
if ((usdt_dof_file_load(file, provider->module)) < 0) {
usdt_error(provider, USDT_ERROR_LOADDOF, strerror(errno));
return (-1);
}
provider->enabled = 1;
provider->file = file;
return (0);
}
int
usdt_provider_disable(usdt_provider_t *provider)
{
usdt_probedef_t *pd;
if (provider->enabled == 0)
return (0);
if ((usdt_dof_file_unload((usdt_dof_file_t *)provider->file)) < 0) {
usdt_error(provider, USDT_ERROR_UNLOADDOF, strerror(errno));
return (-1);
}
usdt_dof_file_free(provider->file);
provider->file = NULL;
/* We would like to free the tracepoints here too, but OS X
* (and to a lesser extent Illumos) struggle with this:
*
* If a provider is repeatedly disabled and re-enabled, and is
* allowed to reuse the same memory for its tracepoints, *and*
* there's a DTrace consumer running with enablings for these
* probes, tracepoints are not always cleaned up sufficiently
* that the newly-created probes work.
*
* Here, then, we will leak the memory holding the
* tracepoints, which serves to stop us reusing the same
* memory address for new tracepoints, avoiding the bug.
*/
for (pd = provider->probedefs; (pd != NULL); pd = pd->next) {
/* may have an as yet never-enabled probe on an
otherwise enabled provider */
if (pd->probe) {
/* usdt_free_tracepoints(pd->probe); */
free(pd->probe);
pd->probe = NULL;
}
}
provider->enabled = 0;
return (0);
}
void
usdt_provider_free(usdt_provider_t *provider)
{
usdt_probedef_t *pd, *next;
for (pd = provider->probedefs; pd != NULL; pd = next) {
next = pd->next;
free_probedef(pd);
}
free((char *)provider->name);
free((char *)provider->module);
free(provider);
}
int
usdt_is_enabled(usdt_probe_t *probe)
{
if (probe != NULL)
return (*probe->isenabled_addr)();
else
return 0;
}
void
usdt_fire_probe(usdt_probe_t *probe, size_t argc, void **nargv)
{
if (probe != NULL)
usdt_probe_args(probe->probe_addr, argc, nargv);
}
static void
usdt_verror(usdt_provider_t *provider, usdt_error_t error, va_list argp)
{
vasprintf(&provider->error, usdt_errors[error], argp);
}
void
usdt_error(usdt_provider_t *provider, usdt_error_t error, ...)
{
va_list argp;
va_start(argp, error);
usdt_verror(provider, error, argp);
va_end(argp);
}
char *
usdt_errstr(usdt_provider_t *provider)
{
return (provider->error);
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include <stdint.h>
#include <unistd.h>
#define USDT_ARG_MAX 32
typedef enum usdt_error {
USDT_ERROR_MALLOC = 0,
USDT_ERROR_VALLOC,
USDT_ERROR_NOPROBES,
USDT_ERROR_LOADDOF,
USDT_ERROR_ALREADYENABLED,
USDT_ERROR_UNLOADDOF,
USDT_ERROR_DUP_PROBE,
USDT_ERROR_REMOVE_PROBE
} usdt_error_t;
typedef struct usdt_probe {
int (*isenabled_addr)(void);
void *probe_addr;
} usdt_probe_t;
int usdt_is_enabled(usdt_probe_t *probe);
void usdt_fire_probe(usdt_probe_t *probe, size_t argc, void **argv);
typedef struct usdt_probedef {
const char *name;
const char *function;
size_t argc;
char *types[USDT_ARG_MAX];
struct usdt_probe *probe;
struct usdt_probedef *next;
int refcnt;
} usdt_probedef_t;
usdt_probedef_t *usdt_create_probe(const char *func, const char *name,
size_t argc, const char **types);
void usdt_probe_release(usdt_probedef_t *probedef);
typedef struct usdt_provider {
const char *name;
const char *module;
usdt_probedef_t *probedefs;
char *error;
int enabled;
void *file;
} usdt_provider_t;
usdt_provider_t *usdt_create_provider(const char *name, const char *module);
int usdt_provider_add_probe(usdt_provider_t *provider, usdt_probedef_t *probedef);
int usdt_provider_remove_probe(usdt_provider_t *provider, usdt_probedef_t *probedef);
int usdt_provider_enable(usdt_provider_t *provider);
int usdt_provider_disable(usdt_provider_t *provider);
void usdt_provider_free(usdt_provider_t *provider);
void usdt_error(usdt_provider_t *provider, usdt_error_t error, ...);
char *usdt_errstr(usdt_provider_t *provider);
+126
View File
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt_internal.h"
int
usdt_dof_section_add_data(usdt_dof_section_t *section, void *data, size_t length)
{
int newlen = section->size + length;
if ((section->data = realloc((char *)section->data, newlen)) == NULL)
return (-1);
memcpy(section->data + section->size, data, length);
section->size = newlen;
return (0);
}
size_t
usdt_provider_dof_size(usdt_provider_t *provider, usdt_strtab_t *strtab)
{
uint8_t i, j;
int args = 0;
int probes = 0;
size_t size = 0;
usdt_probedef_t *pd;
size_t sections[8];
for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
args += pd->argc;
probes++;
}
sections[0] = sizeof(dof_hdr_t);
sections[1] = sizeof(dof_sec_t) * 6;
sections[2] = strtab->size;
sections[3] = sizeof(dof_probe_t) * probes;
sections[4] = sizeof(uint8_t) * args;
sections[5] = sizeof(uint32_t) * probes;
sections[6] = sizeof(uint32_t) * probes;
sections[7] = sizeof(dof_provider_t);
for (i = 0; i < 8; i++) {
size += sections[i];
j = size % 8;
if (j > 0)
size += (8 - j);
}
return size;
}
int
usdt_dof_section_init(usdt_dof_section_t *section, uint32_t type, dof_secidx_t index)
{
section->type = type;
section->index = index;
section->flags = DOF_SECF_LOAD;
section->offset = 0;
section->size = 0;
section->entsize = 0;
section->pad = 0;
section->next = NULL;
if ((section->data = malloc(1)) == NULL)
return (-1);
switch(type) {
case DOF_SECT_PROBES: section->align = 8; break;
case DOF_SECT_PRARGS: section->align = 1; break;
case DOF_SECT_PROFFS: section->align = 4; break;
case DOF_SECT_PRENOFFS: section->align = 4; break;
case DOF_SECT_PROVIDER: section->align = 4; break;
}
return (0);
}
void
usdt_dof_section_free(usdt_dof_section_t *section)
{
free(section->data);
}
int
usdt_strtab_init(usdt_strtab_t *strtab, dof_secidx_t index)
{
strtab->type = DOF_SECT_STRTAB;;
strtab->index = index;
strtab->flags = DOF_SECF_LOAD;
strtab->offset = 0;
strtab->size = 0;
strtab->entsize = 0;
strtab->pad = 0;
strtab->data = NULL;
strtab->align = 1;
strtab->strindex = 1;
if ((strtab->data = (char *) malloc(1)) == NULL)
return (-1);
*strtab->data = '\0';
return (0);
}
dof_stridx_t
usdt_strtab_add(usdt_strtab_t *strtab, const char *string)
{
size_t length;
int index;
length = strlen(string);
index = strtab->strindex;
strtab->strindex += (length + 1);
if ((strtab->data = realloc(strtab->data, strtab->strindex)) == NULL)
return (0);
memcpy((char *) (strtab->data + index), (char *)string, length + 1);
strtab->size = index + length + 1;
return (index);
}
+290
View File
@@ -0,0 +1,290 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt_internal.h"
#include <sys/ioctl.h>
static uint8_t
dof_version(uint8_t header_version)
{
uint8_t dof_version;
/* DOF versioning: Apple always needs version 3, but Solaris can use
1 or 2 depending on whether is-enabled probes are needed. */
#ifdef __APPLE__
dof_version = DOF_VERSION_3;
#else
switch(header_version) {
case 1:
dof_version = DOF_VERSION_1;
break;
case 2:
dof_version = DOF_VERSION_2;
break;
default:
dof_version = DOF_VERSION;
}
#endif
return dof_version;
}
#ifdef __APPLE__
static const char *helper = "/dev/dtracehelper";
static int
load_dof(int fd, dof_helper_t *dh)
{
int ret;
uint8_t buffer[sizeof(dof_ioctl_data_t) + sizeof(dof_helper_t)];
dof_ioctl_data_t* ioctlData = (dof_ioctl_data_t*)buffer;
user_addr_t val;
ioctlData->dofiod_count = 1;
memcpy(&ioctlData->dofiod_helpers[0], dh, sizeof(dof_helper_t));
val = (user_addr_t)(unsigned long)ioctlData;
ret = ioctl(fd, DTRACEHIOC_ADDDOF, &val);
if (ret < 0)
return ret;
return (int)(ioctlData->dofiod_helpers[0].dofhp_dof);
}
#else /* Solaris and FreeBSD */
/* ignore Sol10 GA ... */
static const char *helper = "/dev/dtrace/helper";
static int
load_dof(int fd, dof_helper_t *dh)
{
int ret;
ret = ioctl(fd, DTRACEHIOC_ADDDOF, dh);
#if defined(__FreeBSD__) && __FreeBSD__ <= 10
if (ret != -1)
ret = dh ->gen;
#endif
return ret;
}
#endif
static void
pad_section(usdt_dof_section_t *sec)
{
size_t i, pad;
if (sec->align > 1) {
i = sec->offset % sec->align;
if (i > 0) {
pad = sec->align - i;
sec->offset = (pad + sec->offset);
sec->pad = pad;
}
}
}
static void
dof_header(dof_hdr_t *header)
{
int i;
header->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;
header->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;
header->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;
header->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;
header->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE;
header->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;
header->dofh_ident[DOF_ID_VERSION] = dof_version(2);
header->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION;
header->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS;
header->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS;
for (i = DOF_ID_PAD; i < DOF_ID_SIZE; i++)
header->dofh_ident[i] = 0;
header->dofh_flags = 0;
header->dofh_hdrsize = sizeof(dof_hdr_t);
header->dofh_secsize = sizeof(dof_sec_t);
header->dofh_secoff = sizeof(dof_hdr_t);
header->dofh_loadsz = 0;
header->dofh_filesz = 0;
header->dofh_pad = 0;
}
static size_t
add_header(usdt_dof_file_t *file, size_t offset, usdt_dof_section_t *section)
{
dof_sec_t header;
header.dofs_flags = section->flags;
header.dofs_type = section->type;
header.dofs_offset = section->offset;
header.dofs_size = section->size;
header.dofs_entsize = section->entsize;
header.dofs_align = section->align;
memcpy((file->dof + offset), &header, sizeof(dof_sec_t));
return (offset + sizeof(dof_sec_t));
}
static size_t
add_section(usdt_dof_file_t *file, size_t offset, usdt_dof_section_t *section)
{
if (section->pad > 0) {
/* maximum padding required is 7 */
memcpy((file->dof + offset), "\0\0\0\0\0\0\0", section->pad);
offset += section->pad;
}
memcpy((file->dof + offset), section->data, section->size);
return (offset + section->size);
}
int
usdt_dof_file_unload(usdt_dof_file_t *file)
{
int fd, ret;
if ((fd = open(helper, O_RDWR)) < 0)
return (-1);
#ifdef __FreeBSD__
ret = ioctl(fd, DTRACEHIOC_REMOVE, &file->gen);
#else
ret = ioctl(fd, DTRACEHIOC_REMOVE, file->gen);
#endif
if (ret < 0)
return (-1);
if ((close(fd)) < 0)
return (-1);
return (0);
}
int
usdt_dof_file_load(usdt_dof_file_t *file, const char *module)
{
dof_helper_t dh;
dof_hdr_t *dof;
int fd;
dof = (dof_hdr_t *) file->dof;
dh.dofhp_dof = (uintptr_t)dof;
dh.dofhp_addr = (uintptr_t)dof;
#if __FreeBSD__ >= 11
dh.dofhp_pid = getpid();
#endif
(void) strncpy(dh.dofhp_mod, module, sizeof (dh.dofhp_mod));
if ((fd = open(helper, O_RDWR)) < 0)
return (-1);
file->gen = load_dof(fd, &dh);
if ((close(fd)) < 0)
return (-1);
if (file->gen < 0)
return (-1);
return (0);
}
void
usdt_dof_file_append_section(usdt_dof_file_t *file, usdt_dof_section_t *section)
{
usdt_dof_section_t *s;
if (file->sections == NULL) {
file->sections = section;
}
else {
for (s = file->sections; (s->next != NULL); s = s->next) ;
s->next = section;
}
}
void
usdt_dof_file_generate(usdt_dof_file_t *file, usdt_strtab_t *strtab)
{
dof_hdr_t header;
uint64_t filesz;
uint64_t loadsz;
usdt_dof_section_t *sec;
size_t offset;
dof_header(&header);
header.dofh_secnum = 6;
filesz = sizeof(dof_hdr_t) + (sizeof(dof_sec_t) * header.dofh_secnum);
loadsz = filesz;
strtab->offset = filesz;
pad_section((usdt_dof_section_t *)strtab);
filesz += strtab->size + strtab->pad;
if (strtab->flags & 1)
loadsz += strtab->size + strtab->pad;
for (sec = file->sections; sec != NULL; sec = sec->next) {
sec->offset = filesz;
pad_section(sec);
filesz += sec->size + sec->pad;
if (sec->flags & 1)
loadsz += sec->size + sec->pad;
}
header.dofh_loadsz = loadsz;
header.dofh_filesz = filesz;
memcpy(file->dof, &header, sizeof(dof_hdr_t));
offset = sizeof(dof_hdr_t);
offset = add_header(file, offset, (usdt_dof_section_t *)strtab);
for (sec = file->sections; sec != NULL; sec = sec->next)
offset = add_header(file, offset, sec);
offset = add_section(file, offset, (usdt_dof_section_t *)strtab);
for (sec = file->sections; sec != NULL; sec = sec->next)
offset = add_section(file, offset, sec);
}
usdt_dof_file_t *
usdt_dof_file_init(usdt_provider_t *provider, size_t size)
{
usdt_dof_file_t *file;
if ((file = malloc(sizeof(*file))) == NULL) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (NULL);
}
if ((file->dof = valloc(size)) == NULL) {
usdt_error(provider, USDT_ERROR_VALLOC);
return (NULL);
}
file->sections = NULL;
file->size = size;
return (file);
}
void
usdt_dof_file_free(usdt_dof_file_t *file)
{
free(file->dof);
free(file);
}
+180
View File
@@ -0,0 +1,180 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt_internal.h"
int
usdt_dof_probes_sect(usdt_dof_section_t *probes,
usdt_provider_t *provider, usdt_strtab_t *strtab)
{
usdt_probedef_t *pd;
dof_probe_t p;
dof_stridx_t type, argv;
uint8_t argc, i;
uint32_t argidx = 0;
uint32_t offidx = 0;
usdt_dof_section_init(probes, DOF_SECT_PROBES, 1);
for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
argc = 0;
argv = 0;
type = 0;
for (i = 0; i < pd->argc; i++) {
type = usdt_strtab_add(strtab, pd->types[i]);
argc++;
if (argv == 0)
argv = type;
}
if (usdt_create_tracepoints(pd->probe) < 0) {
usdt_error(provider, USDT_ERROR_VALLOC);
return (-1);
}
#ifdef __x86_64__
p.dofpr_addr = (uint64_t) pd->probe->isenabled_addr;
#elif __i386__ || __i386
p.dofpr_addr = (uint32_t) pd->probe->isenabled_addr;
#else
#error "only x86_64 and i386 supported"
#endif
p.dofpr_func = usdt_strtab_add(strtab, pd->function);
p.dofpr_name = usdt_strtab_add(strtab, pd->name);
p.dofpr_nargv = argv;
p.dofpr_xargv = argv;
p.dofpr_argidx = argidx;
p.dofpr_offidx = offidx;
p.dofpr_nargc = argc;
p.dofpr_xargc = argc;
p.dofpr_noffs = 1;
p.dofpr_enoffidx = offidx;
p.dofpr_nenoffs = 1;
p.dofpr_pad1 = 0;
p.dofpr_pad2 = 0;
usdt_dof_section_add_data(probes, &p, sizeof(dof_probe_t));
probes->entsize = sizeof(dof_probe_t);
argidx += argc;
offidx++;
}
return (0);
}
int
usdt_dof_prargs_sect(usdt_dof_section_t *prargs, usdt_provider_t *provider)
{
usdt_probedef_t *pd;
uint8_t i;
usdt_dof_section_init(prargs, DOF_SECT_PRARGS, 2);
prargs->entsize = 1;
for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
for (i = 0; i < pd->argc; i++)
usdt_dof_section_add_data(prargs, &i, 1);
}
if (prargs->size == 0) {
i = 0;
if (usdt_dof_section_add_data(prargs, &i, 1) < 0) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
}
return (0);
}
int
usdt_dof_proffs_sect(usdt_dof_section_t *proffs,
usdt_provider_t *provider, char *dof)
{
usdt_probedef_t *pd;
uint32_t off;
usdt_dof_section_init(proffs, DOF_SECT_PROFFS, 3);
proffs->entsize = 4;
for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
off = usdt_probe_offset(pd->probe, dof, pd->argc);
if (usdt_dof_section_add_data(proffs, &off, 4) < 0) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
}
return (0);
}
int
usdt_dof_prenoffs_sect(usdt_dof_section_t *prenoffs,
usdt_provider_t *provider, char *dof)
{
usdt_probedef_t *pd;
uint32_t off;
usdt_dof_section_init(prenoffs, DOF_SECT_PRENOFFS, 4);
prenoffs->entsize = 4;
for (pd = provider->probedefs; pd != NULL; pd = pd->next) {
off = usdt_is_enabled_offset(pd->probe, dof);
if (usdt_dof_section_add_data(prenoffs, &off, 4) < 0) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
}
return (0);
}
int
usdt_dof_provider_sect(usdt_dof_section_t *provider_s, usdt_provider_t *provider)
{
dof_provider_t p;
usdt_dof_section_init(provider_s, DOF_SECT_PROVIDER, 5);
p.dofpv_strtab = 0;
p.dofpv_probes = 1;
p.dofpv_prargs = 2;
p.dofpv_proffs = 3;
p.dofpv_prenoffs = 4;
p.dofpv_name = 1; /* provider name always first strtab entry. */
/*
* Stability is something of a hack. Everything is marked *
* "stable" here to permit use of the "args" array, which is *
* needed to access arguments past "arg9".
*
* It should be up to the creator of the provider to decide
* this, though, and it should be possible to set the
* appropriate stability at creation time.
*/
p.dofpv_provattr = DOF_ATTR(DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE);
p.dofpv_modattr = DOF_ATTR(DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE);
p.dofpv_funcattr = DOF_ATTR(DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE);
p.dofpv_nameattr = DOF_ATTR(DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE);
p.dofpv_argsattr = DOF_ATTR(DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE,
DTRACE_STABILITY_STABLE);
if ((usdt_dof_section_add_data(provider_s, &p, sizeof(p))) < 0) {
usdt_error(provider, USDT_ERROR_MALLOC);
return (-1);
}
return (0);
}
+103
View File
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#ifdef __linux__
#include <endian.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#ifndef _LITTLE_ENDIAN
#define _LITTLE_ENDIAN
#endif
#endif
#endif
#include <sys/dtrace.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#define FUNC_SIZE 32
#include "usdt.h"
extern void usdt_tracepoint_isenabled(void);
extern void usdt_tracepoint_probe(void);
extern void usdt_tracepoint_end(void);
extern void usdt_probe_args(void *, int, void**);
uint32_t usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc);
uint32_t usdt_is_enabled_offset(usdt_probe_t *probe, char *dof);
int usdt_create_tracepoints(usdt_probe_t *probe);
void usdt_free_tracepoints(usdt_probe_t *probe);
typedef struct usdt_dof_section {
dof_secidx_t index;
uint32_t type;
uint32_t flags;
uint32_t align;
uint64_t offset;
uint64_t size;
uint32_t entsize;
size_t pad;
struct usdt_dof_section *next;
char *data;
} usdt_dof_section_t;
int usdt_dof_section_init(usdt_dof_section_t *section,
uint32_t type, dof_secidx_t index);
int usdt_dof_section_add_data(usdt_dof_section_t *section,
void *data, size_t length);
void usdt_dof_section_free(usdt_dof_section_t *section);
typedef struct usdt_strtab {
dof_secidx_t index;
uint32_t type;
uint32_t flags;
uint32_t align;
uint64_t offset;
uint64_t size;
uint32_t entsize;
size_t pad;
int strindex;
char *data;
} usdt_strtab_t;
int usdt_strtab_init(usdt_strtab_t *strtab, dof_secidx_t index);
dof_stridx_t usdt_strtab_add(usdt_strtab_t *strtab, const char *string);
char *usdt_strtab_header(usdt_strtab_t *strtab);
size_t usdt_strtab_size(usdt_strtab_t *strtab);
size_t usdt_provider_dof_size(usdt_provider_t *provider, usdt_strtab_t *strtab);
typedef struct usdt_dof_file {
char *dof;
int gen;
size_t size;
usdt_dof_section_t *sections;
} usdt_dof_file_t;
usdt_dof_file_t *usdt_dof_file_init(usdt_provider_t *provider, size_t size);
void usdt_dof_file_append_section(usdt_dof_file_t *file, usdt_dof_section_t *section);
void usdt_dof_file_generate(usdt_dof_file_t *file, usdt_strtab_t *strtab);
int usdt_dof_file_load(usdt_dof_file_t *file, const char *module);
int usdt_dof_file_unload(usdt_dof_file_t *file);
void usdt_dof_file_free(usdt_dof_file_t *file);
int usdt_dof_probes_sect(usdt_dof_section_t *probes,
usdt_provider_t *provider, usdt_strtab_t *strtab);
int usdt_dof_prargs_sect(usdt_dof_section_t *prargs,
usdt_provider_t *provider);
int usdt_dof_proffs_sect(usdt_dof_section_t *proffs,
usdt_provider_t *provider, char *dof);
int usdt_dof_prenoffs_sect(usdt_dof_section_t *prenoffs,
usdt_provider_t *provider, char *dof);
int usdt_dof_provider_sect(usdt_dof_section_t *provider_s,
usdt_provider_t *provider);
+133
View File
@@ -0,0 +1,133 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
#include "usdt_internal.h"
#ifdef __APPLE__
uint32_t
usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc)
{
uint32_t offset;
#ifdef __x86_64__
offset = ((uint64_t) probe->probe_addr - (uint64_t) dof + 2);
#elif __i386__
offset = ((uint32_t) probe->probe_addr - (uint32_t) dof + 2);
#else
#error "only x86_64 and i386 supported"
#endif
return (offset);
}
uint32_t
usdt_is_enabled_offset(usdt_probe_t *probe, char *dof)
{
uint32_t offset;
#ifdef __x86_64__
offset = ((uint64_t) probe->isenabled_addr - (uint64_t) dof + 6);
#elif __i386__
offset = ((uint32_t) probe->isenabled_addr - (uint32_t) dof + 6);
#else
#error "only x86_64 and i386 supported"
#endif
return (offset);
}
#elif defined __linux__
uint32_t
usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc)
{
return (16);
}
uint32_t
usdt_is_enabled_offset(usdt_probe_t *probe, char *dof)
{
return (10);
}
#else /* solaris and freebsd */
uint32_t
usdt_probe_offset(usdt_probe_t *probe, char *dof, uint8_t argc)
{
return (16);
}
uint32_t
usdt_is_enabled_offset(usdt_probe_t *probe, char *dof)
{
return (8);
}
#endif
int
usdt_create_tracepoints(usdt_probe_t *probe)
{
/* Prepare the tracepoints - for each probe, a separate chunk
* of memory with the tracepoint code copied into it, to give
* us unique addresses for each tracepoint.
*
* On Oracle Linux, this must be an mmapped file because USDT
* probes there are implemented as uprobes, which are
* addressed by inode and offset. The file used is a small
* mkstemp'd file we immediately unlink.
*
* Elsewhere, we can use the heap directly because USDT will
* instrument any memory mapped by the process.
*/
size_t size;
#ifdef __linux__
int fd;
char tmp[20] = "/tmp/libusdtXXXXXX";
if ((fd = mkstemp(tmp)) < 0)
return (-1);
if (unlink(tmp) < 0)
return (-1);
if (write(fd, "\0", FUNC_SIZE) < FUNC_SIZE)
return (-1);
probe->isenabled_addr = (int (*)())mmap(NULL, FUNC_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE, fd, 0);
#else
probe->isenabled_addr = (int (*)())valloc(FUNC_SIZE);
#endif
if (probe->isenabled_addr == NULL)
return (-1);
/* ensure that the tracepoints will fit the heap we're allocating */
size = ((char *)usdt_tracepoint_end - (char *)usdt_tracepoint_isenabled);
assert(size < FUNC_SIZE);
size = ((char *)usdt_tracepoint_probe - (char *)usdt_tracepoint_isenabled);
probe->probe_addr = (char *)probe->isenabled_addr + size;
memcpy((void *)probe->isenabled_addr,
(const void *)usdt_tracepoint_isenabled, FUNC_SIZE);
#ifdef __linux__
mprotect((void *)probe->isenabled_addr, FUNC_SIZE,
PROT_READ | PROT_EXEC);
#else
mprotect((void *)probe->isenabled_addr, FUNC_SIZE,
PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
return (0);
}
void
usdt_free_tracepoints(usdt_probe_t *probe)
{
#ifdef __linux__
(void) munmap(probe->isenabled_addr, FUNC_SIZE);
#else
free(probe->isenabled_addr);
#endif
}
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
/*
* Stub functions containing DTrace tracepoints for probes and
* is-enabled probes. These functions are copied for each probe
* dynamically created.
*
*/
.text
.align 4, 0x90
.globl usdt_tracepoint_isenabled
.globl _usdt_tracepoint_isenabled
.globl usdt_tracepoint_probe
.globl _usdt_tracepoint_probe
.globl usdt_tracepoint_end
.globl _usdt_tracepoint_end
.globl usdt_probe_args
.globl _usdt_probe_args
usdt_tracepoint_isenabled:
_usdt_tracepoint_isenabled:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
xorl %eax, %eax
nop
nop
leave
ret
usdt_tracepoint_probe:
_usdt_tracepoint_probe:
nop
nop
nop
nop
nop
addl $0x20,%esp
leave
usdt_tracepoint_end:
_usdt_tracepoint_end:
ret
/*
* Probe argument marshalling, i386 style
*
*/
usdt_probe_args:
_usdt_probe_args:
pushl %ebp
movl %esp,%ebp
subl $8,%esp
subl $8,%esp
movl 8(%ebp),%edx
movl 0xc(%ebp),%ecx
test %ecx,%ecx
je fire
args: movl %ecx,%eax
sal $2,%eax
subl $4,%eax
addl 0x10(%ebp),%eax
pushl (%eax)
dec %ecx
jne args
fire: jmp *%edx
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2012, Chris Andrews. All rights reserved.
*/
/*
* Stub functions containing DTrace tracepoints for probes and
* is-enabled probes. These functions are copied for each probe
* dynamically created.
*
*/
.text
.align 4, 0x90
.globl usdt_tracepoint_isenabled
.globl _usdt_tracepoint_isenabled
.globl usdt_tracepoint_probe
.globl _usdt_tracepoint_probe
.globl usdt_tracepoint_end
.globl _usdt_tracepoint_end
.globl usdt_probe_args
.globl _usdt_probe_args
usdt_tracepoint_isenabled:
_usdt_tracepoint_isenabled:
pushq %rbp
movq %rsp, %rbp
addq $1, %rax
xorq %rax, %rax
nop
nop
leave
ret
usdt_tracepoint_probe:
_usdt_tracepoint_probe:
nop
nop
nop
nop
nop
addq %r14,%rsp
popq %rbx
popq %r14
popq %r13
popq %r12
leave
usdt_tracepoint_end:
_usdt_tracepoint_end:
ret
/*
* Probe argument marshalling, x86_64 style
*
*/
usdt_probe_args:
_usdt_probe_args:
pushq %rbp
movq %rsp,%rbp
pushq %r12
pushq %r13
pushq %r14
pushq %rbx
movq %rdi,%r12
movq %rsi,%rbx
movq %rdx,%r11
movq $0,%r14
test %rbx,%rbx
je fire
movq (%r11),%rdi
dec %rbx
test %rbx,%rbx
je fire
addq $8,%r11
movq (%r11),%rsi
dec %rbx
test %rbx,%rbx
je fire
addq $8,%r11
movq (%r11),%rdx
dec %rbx
test %rbx,%rbx
je fire
addq $8,%r11
movq (%r11),%rcx
dec %rbx
test %rbx,%rbx
je fire
addq $8,%r11
movq (%r11),%r8
dec %rbx
test %rbx,%rbx
je fire
addq $8,%r11
movq (%r11),%r9
movq %rbx,%r13
morestack:
dec %rbx
test %rbx,%rbx
je args
subq $16,%rsp
addq $16,%r14
dec %rbx
test %rbx,%rbx
je args
jmp morestack
args:
movq %r13,%rbx
movq $0,%r13
moreargs:
dec %rbx
test %rbx,%rbx
je fire
addq $8,%r11
movq (%r11),%rax
movq %rax,(%rsp,%r13)
addq $8,%r13
jmp moreargs
fire: jmp *%r12