node_modules updated, buefy add to lib folder
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
*.o
|
||||
*.a
|
||||
*.gch
|
||||
*~
|
||||
*#
|
||||
.#*
|
||||
test_usdt
|
||||
test_usdt32
|
||||
test_usdt64
|
||||
test_mem_usage
|
||||
+21
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(§s[0], provider, &strtab)) < 0)
|
||||
return (-1);
|
||||
if ((usdt_dof_prargs_sect(§s[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(§s[2], provider, file->dof)) < 0)
|
||||
return (-1);
|
||||
if ((usdt_dof_prenoffs_sect(§s[3], provider, file->dof)) < 0)
|
||||
return (-1);
|
||||
if ((usdt_dof_provider_sect(§s[4], provider)) < 0)
|
||||
return (-1);
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
usdt_dof_file_append_section(file, §s[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(§s[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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user