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
+3
View File
@@ -0,0 +1,3 @@
[submodule "libusdt"]
path = libusdt
url = https://github.com/chrisa/libusdt
+10
View File
@@ -0,0 +1,10 @@
.lock-wscript
*.node
*~
.#*
*#
build
*.log
test
TODO.md
*.tgz
+112
View File
@@ -0,0 +1,112 @@
dtrace-provider - Changes
=========================
## HISTORY
* 0.8.7:
Known support for v0.10.48, v0.12.16, v4.6.0, v7.5.0, v8.9.4, v10.3.0 (#119)
Don't crash when attempting to fire unknown probes (#120)
* 0.8.6:
Improved compilation failure behaviour (#96)
* 0.8.5:
Reverted "Install fails on Debian due to differently named node binary" for
now
* 0.8.4:
Only log error once when DTraceProviderBindings can't be found
Install fails on Debian due to differently named node binary
* 0.8.3:
Install fails with yarn
* 0.8.2:
Error installing in 64-bit SmartOS zones with 32-bit node
* 0.8.1:
Support FreeBSD 10 & 11
* 0.8.0:
Support passing additional arguments to probe function via `.fire()`
* 0.7.1:
Update libusdt for chrisa/libusdt#12 fix
* 0.7.0: known support for v0.10.47, v0.12.16, v4.6.0.
Updated NaN dependency to remove warnings on newer Node versions.
* 0.2.8:
Add NODE_MODULE() declaration for compatibility with Node 0.9.1+
(reported by Trent Mick)
Remove execSync dependency from tests.
* 0.2.7:
Don't build on FreeBSD by default - DTrace is not yet built in releases.
* 0.2.6:
Fall back to make(1) if gmake(1) is unavailable, still expected to be GNU Make
(Trent Mick)
* 0.2.5:
Add "json" probe argument type, automatically serialising objects as JSON
Trust npm to set PATH appropriately when invoking node (reported by Dave Pacheco)
libusdt update - allow provider memory to be freed (reported by Bryan Cantrill)
Build libusdt with gmake by default (reported by Keith Wesolowski)
Turn the various scripts in test/ into a TAP-based testsuite.
* 0.2.4:
Improve Node architecture detection to support 0.6.x, and respect
npm's prefix when choosing a node binary to use (reported by Trent Mick)
* 0.2.3:
libusdt update - don't invoke ranlib on SunOS-derived systems
Disambiguate module name in probe tuple, and optionally allow it to be
specified when creating a provider. (Bryan Cantrill bcantrill@acm.org)
* 0.2.2:
libusdt update for build fixes
Respect MAKE variable in build script
* 0.2.1:
Update binding.gyp for clang on Snow Leopard - no space after -L.
* 0.2.0:
Update libusdt, and attempt to build it correctly for various platforms.
Add support for disabling providers and removing probes.
* 0.1.1:
Replace Node-specific implementation with wrappers for libusdt.
Extend argument support to 32 primitives.
Adds Solaris x86_64 support.
* 0.0.9:
Force the build architecture to x86_64 for OS X.
* 0.0.8:
Removed overridden "scripts" section from package.json, breaking Windows installs
* 0.0.7:
Fix for multiple enable() calls breaking providers.
* 0.0.6:
Fix for segfault trying to use non-enabled probes (Mark Cavage mcavage@gmail.com)
* 0.0.5:
Revert changes to make probe objects available.
* 0.0.4:
Remove unused "sys" import (Alex Whitman)
No longer builds an empty extension on non-DTrace platforms
Probe objects are made available to Javascript.
* 0.0.3:
Builds to a stubbed-out version on non-DTrace platforms (Mark Cavage <mcavage@gmail.com>)
* 0.0.2:
Solaris i386 support.
Fixes memory leaks
Improved performance, enabled- and disabled-probe.
* 0.0.1:
First working version: OSX x86_64 only.
+21
View File
@@ -0,0 +1,21 @@
Copyright 2011 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.
+230
View File
@@ -0,0 +1,230 @@
# dtrace-provider - Native DTrace providers for Node.js apps.
This extension allows you to create native DTrace providers for your
Node.js applications. That is, to create providers and probes which
expose information specific to your application, rather than
information about the node runtime.
You could use this to expose high-level information about the inner
workings of your application, or to create a specific context in which
to look at information from other runtime or system-level providers.
The provider is not created in the usual way, by declaring it and then
changing the build process to include it, but instead dynamically at
runtime. This is done entirely in-process, and there is no background
compiler or [dtrace(1M)](https://illumos.org/man/1M/dtrace) invocation.
The process creating the provider need not run as root.
## INSTALL
$ npm install dtrace-provider
## EXAMPLE
Here's a simple example of creating a provider:
```javascript
var d = require('dtrace-provider');
var dtp = d.createDTraceProvider("nodeapp");
var p1 = dtp.addProbe("probe1", "int", "int");
var p2 = dtp.addProbe("probe2", "char *");
dtp.enable();
```
Probes may be fired via the provider object:
```javascript
dtp.fire("probe1", function() {
return [1, 2];
});
dtp.fire("probe2", function() {
return ["hello, dtrace via provider", "foo"];
});
```
or via the probe objects themselves:
```javascript
p1.fire(function() {
return [1, 2, 3, 4, 5, 6];
});
p2.fire(function() {
return ["hello, dtrace via probe", "foo"];
});
```
Note that `.fire()` takes a callback that returns the arguments to be
provided when the DTrace probe actually fires. This allows you to call
`.fire()` unconditionally when you want to fire the probe, but the
callback will be invoked only when the DTrace probe is actually
enabled. This allows you to create probes whose arguments might be
expensive to construct, and only do any work when the probe is
actually enabled. (Examples might include converting a large object to
a string representation or gathering large amounts of information.)
In some cases, creating a new closure to pass to `.fire()` each time
it's called may introduce unwanted overhead. For extremely
CPU-intensive or memory-conscious workloads, you can avoid this by
lifting the closures for your hot probes into an outer scope. You can
then supply arguments to that function as additional arguments to
`.fire()`. As an example, you can convert the following program:
```javascript
function manipulateObj(largeObj) {
var count = 0;
var name = null;
...
p1.fire(function () {
return [count, keyToValue(name), JSON.stringify(largeObj)];
});
}
```
Into this one:
```javascript
function f(a, b, c) {
return [a, keyToValue(b), JSON.stringify(c)];
}
function manipulateObj(largeObj) {
var count = 0;
var name = null;
...
p1.fire(f, count, name, largeObj);
}
```
Be careful to avoid passing `.fire()` additional arguments that are
themselves expensive to construct, as that undermines the design goal
here: minimizing the effect of disabled probes.
This example creates a provider called "nodeapp", and adds two
probes. It then enables the provider, at which point the provider
becomes visible to DTrace.
The probes are then fired, which produces this output:
$ sudo dtrace -Z -n 'nodeapp*:::probe1{ trace(arg0); trace(arg1) }' \
-n 'nodeapp*:::probe2{ trace(copyinstr(arg0)); }'
dtrace: description 'nodeapp*:::probe1' matched 0 probes
dtrace: description 'nodeapp*:::probe2' matched 0 probes
CPU ID FUNCTION:NAME
1 123562 func:probe1 1 2
1 123563 func:probe2 hello, dtrace
Arguments are captured by a callback only executed when the probe is
enabled. This means you can do more expensive work to gather arguments.
The maximum number of arguments supported is 32.
Available argument types are "int", for integer numeric values,
"char *" for strings, and "json" for objects rendered into JSON strings.
Arguments typed as "json" will be created as "char *" probes in
DTrace, but objects passed to these probe arguments will be
automatically serialized to JSON before being passed to DTrace. This
feature is best used in conjunction with the json() D subroutine, but
is available whether or not the platform supports it.
# create a json probe:
var dtp = d.createDTraceProvider("nodeapp");
var p1 = dtp.addProbe("j1", "json");
dtp.enable();
p1.fire(function() { return { "foo": "bar" }; });
# on a platform supporting json():
$ sudo dtrace -Z -n 'nodeapp*:::j1{ this->j = copyinstr(arg0); \
trace(json(this->j, "foo")) }'
dtrace: description 'nodeapp$target:::j1' matched 0 probes
CPU ID FUNCTION:NAME
0 68712 j1:j1 bar
## PLATFORM SUPPORT
This libusdt-based Node.JS module supports 64 and 32 bit processes on
Mac OS X and Solaris-like systems such as illumos or SmartOS. As more
platform support is added to libusdt, those platforms will be
supported by this module. See libusdt's status at:
https://github.com/chrisa/libusdt#readme
When using Mac OS X, be aware that as of 10.11 (El Capitan), DTrace use
is restricted, and you'll probably want to
[disable SIP](http://internals.exposed/blog/dtrace-vs-sip.html) to
effectively use DTrace.
FreeBSD 10 and 11 are also supported, but you'll need to make sure that
you have the DTrace headers installed in `/usr/src` otherwise libusdt
won't be able to compile. You can
[clone them using SVN](https://www.freebsd.org/doc/handbook/svn.html),
or find the correct `src.txz`
[here](http://ftp.freebsd.org/pub/FreeBSD/releases/) and extract that.
Also note that FreeBSD 10 is restricted to only 4 working arguments per
probe.
Platforms not supporting DTrace (notably, Linux and Windows) may
install this module without building libusdt, with a stub no-op
implementation provided for compatibility. This allows cross-platform
npm modules to embed probes and include a dependency on this module.
GNU Make is required to build libusdt; the build scripts will look for
gmake in `PATH` first, and then for make.
### TROUBLESHOOTING BUILD ISSUES
If compilation fails during installation on platforms with DTrace, then
the library will fall back to the stub implementation that does nothing.
To force an installation failure when compiling fails, set the environment
variable `NODE_DTRACE_PROVIDER_REQUIRE` to `hard`:
```shell
$ NODE_DTRACE_PROVIDER_REQUIRE=hard npm install
```
This will then show you the output of the build process so you can see at
which point it's having an issue. Common issues are:
- Missing a C/C++ compiler toolchain for your platform.
- `python` is Python 3 instead of Python 2; run `npm config set python python2.7`
(or similar) to set the Python binary npm uses.
- On OS X you may need to agree to the XCode license if that's the compiler
toolchain you're using. This will usually manifest with an error like
`Agreeing to the Xcode/iOS license requires admin privileges, please re-run as root via sudo.`
To accept the license, you can run `sudo xcodebuild -license`.
Once you've found and fixed the issue, you can run `npm rebuild` to rerun
the lifecycle scripts.
## CAVEATS
There is some overhead to probes, even when disabled. Probes are
already using the "is-enabled" feature of DTrace to control execution
of the arguments-gathering callback, but some work still needs to be
done before that's checked. This overhead should not be a problem
unless probes are placed in particularly hot code paths.
## CONTRIBUTING
To clone the project's source code:
$ git clone --recursive https://github.com/chrisa/node-dtrace-provider.git
For issues, please use the [GitHub issue tracker](https://github.com/chrisa/node-dtrace-provider/issues)
linked to the repository. GitHub pull requests are very welcome.
## RUNNING THE TESTS
```shell
$ npm install
$ sudo ./node_modules/.bin/tap --tap test/*.test.js
```
## OTHER IMPLEMENTATIONS
This node extension is derived from the ruby-dtrace gem, via the Perl
module Devel::DTrace::Provider, both of which provide the same
functionality to those languages.
+35
View File
@@ -0,0 +1,35 @@
{
'conditions': [
# If we are on Mac OS X, FreeBSD, or a Solarish system, attempt
# to build the DTrace provider extension.
['OS=="mac" or OS=="solaris" or OS=="freebsd"', {
'targets': [
{
'target_name': 'ndtp',
'type': 'none',
'actions': [{
'inputs': [''],
'outputs': [''],
'action_name': 'build_ndtp',
'action': [
'bash', 'build.sh'
]
}]
}
]
},
# If we are on another system (like Windows or Linux), then DTrace is
# unavailable. This target is necessary because GYP requires at least
# one target to exist. We end up building nothing, and fall back to the
# stub implementation when the package is loaded.
{
'targets': [
{
'target_name': 'DTraceProviderStub',
'type': 'none'
}
]
}]
]
}
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env bash
set -o pipefail
if [[ -n "$V" ]]; then
set -o xtrace
fi
fail() {
if [[ -z "$NODE_DTRACE_PROVIDER_REQUIRE" && -z "$V" ]]; then
echo "-----------------------------------------------------------------"
echo "Building dtrace-provider failed with exit code $1, falling back"
echo "on stub implementation."
echo ""
echo "Re-run install with V set in your environment to see the build"
echo "output, or NODE_DTRACE_PROVIDER_REQUIRE=hard to force an"
echo "installation failure."
echo "-----------------------------------------------------------------"
fi
if [[ "$NODE_DTRACE_PROVIDER_REQUIRE" == "hard" ]]; then
exit 1
else
exit 0
fi
}
buildUSDT() {
if [[ -z "$NODE_DTRACE_PROVIDER_REQUIRE" && -z "$V" ]]; then
exec 1> /dev/null
exec 2> /dev/null
fi
# GYP's MAKEFLAGS confuses libusdt's Makefile
unset MAKEFLAGS
# Ask node what architecture it's been built for ("target_arch" in
# config.gypi), and build libusdt to match.
#
# We use node from the path; npm will have adjusted PATH for us if
# necessary, otherwise we assume the user did so when building by
# hand.
#
# (This will need to change at the point that GYP is able to build
# node extensions universal on the Mac - for now we'll go with x86_64
# on a 64 bit Mac, because that's the default architecture in that
# situation.)
export ARCH=`node -e "console.log(process.arch === 'x64' ? 'x86_64' : 'i386')"`
echo "Building libusdt for ${ARCH}"
# Respect a MAKE variable if set
if [[ -z $MAKE ]]; then
# Default to `gmake` first if available, because we require GNU make
# and `make` isn't GNU make on some plats.
MAKE=`which gmake`
if [[ -z $MAKE ]]; then
MAKE=make
fi
fi
# Build libusdt.
$MAKE -C libusdt clean all
}
buildNDTP() {
if [[ -z "$NODE_DTRACE_PROVIDER_REQUIRE" && -z "$V" ]]; then
exec 1> /dev/null
exec 2> /dev/null
fi
node-gyp rebuild -C src
}
(buildUSDT)
LIBUSDT_STATUS=$?
if [[ "$LIBUSDT_STATUS" -ne 0 ]]; then
fail $LIBUSDT_STATUS
fi
(buildNDTP)
NODE_GYP_STATUS=$?
if [[ "$NODE_GYP_STATUS" -ne 0 ]]; then
fail $NODE_GYP_STATUS
fi
exit 0
+18
View File
@@ -0,0 +1,18 @@
# This file is generated by gyp; do not edit.
TOOLSET := target
TARGET := DTraceProviderStub
### Rules for final target.
$(obj).target/DTraceProviderStub.stamp: TOOLSET := $(TOOLSET)
$(obj).target/DTraceProviderStub.stamp: FORCE_DO_CMD
$(call do_cmd,touch)
all_deps += $(obj).target/DTraceProviderStub.stamp
# Add target alias
.PHONY: DTraceProviderStub
DTraceProviderStub: $(obj).target/DTraceProviderStub.stamp
# Add target alias to "all" target.
.PHONY: all
all: DTraceProviderStub
+324
View File
@@ -0,0 +1,324 @@
# We borrow heavily from the kernel build setup, though we are simpler since
# we don't have Kconfig tweaking settings on us.
# The implicit make rules have it looking for RCS files, among other things.
# We instead explicitly write all the rules we care about.
# It's even quicker (saves ~200ms) to pass -r on the command line.
MAKEFLAGS=-r
# The source directory tree.
srcdir := ..
abs_srcdir := $(abspath $(srcdir))
# The name of the builddir.
builddir_name ?= .
# The V=1 flag on command line makes us verbosely print command lines.
ifdef V
quiet=
else
quiet=quiet_
endif
# Specify BUILDTYPE=Release on the command line for a release build.
BUILDTYPE ?= Release
# Directory all our build output goes into.
# Note that this must be two directories beneath src/ for unit tests to pass,
# as they reach into the src/ directory for data with relative paths.
builddir ?= $(builddir_name)/$(BUILDTYPE)
abs_builddir := $(abspath $(builddir))
depsdir := $(builddir)/.deps
# Object output directory.
obj := $(builddir)/obj
abs_obj := $(abspath $(obj))
# We build up a list of every single one of the targets so we can slurp in the
# generated dependency rule Makefiles in one pass.
all_deps :=
CC.target ?= $(CC)
CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS)
CXX.target ?= $(CXX)
CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS)
LINK.target ?= $(LINK)
LDFLAGS.target ?= $(LDFLAGS)
AR.target ?= $(AR)
# C++ apps need to be linked with g++.
LINK ?= $(CXX.target)
# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
# to replicate this environment fallback in make as well.
CC.host ?= gcc
CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
CXX.host ?= g++
CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
LINK.host ?= $(CXX.host)
LDFLAGS.host ?=
AR.host ?= ar
# Define a dir function that can handle spaces.
# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
# "leading spaces cannot appear in the text of the first argument as written.
# These characters can be put into the argument value by variable substitution."
empty :=
space := $(empty) $(empty)
# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
replace_spaces = $(subst $(space),?,$1)
unreplace_spaces = $(subst ?,$(space),$1)
dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
# Flags to make gcc output dependency info. Note that you need to be
# careful here to use the flags that ccache and distcc can understand.
# We write to a dep file on the side first and then rename at the end
# so we can't end up with a broken dep file.
depfile = $(depsdir)/$(call replace_spaces,$@).d
DEPFLAGS = -MMD -MF $(depfile).raw
# We have to fixup the deps output in a few ways.
# (1) the file output should mention the proper .o file.
# ccache or distcc lose the path to the target, so we convert a rule of
# the form:
# foobar.o: DEP1 DEP2
# into
# path/to/foobar.o: DEP1 DEP2
# (2) we want missing files not to cause us to fail to build.
# We want to rewrite
# foobar.o: DEP1 DEP2 \
# DEP3
# to
# DEP1:
# DEP2:
# DEP3:
# so if the files are missing, they're just considered phony rules.
# We have to do some pretty insane escaping to get those backslashes
# and dollar signs past make, the shell, and sed at the same time.
# Doesn't work with spaces, but that's fine: .d files have spaces in
# their names replaced with other characters.
define fixup_dep
# The depfile may not exist if the input file didn't have any #includes.
touch $(depfile).raw
# Fixup path as in (1).
sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
# Add extra rules as in (2).
# We remove slashes and replace spaces with new lines;
# remove blank lines;
# delete the first line and append a colon to the remaining lines.
sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
grep -v '^$$' |\
sed -e 1d -e 's|$$|:|' \
>> $(depfile)
rm $(depfile).raw
endef
# Command definitions:
# - cmd_foo is the actual command to run;
# - quiet_cmd_foo is the brief-output summary of the command.
quiet_cmd_cc = CC($(TOOLSET)) $@
cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_cxx = CXX($(TOOLSET)) $@
cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
quiet_cmd_touch = TOUCH $@
cmd_touch = touch $@
quiet_cmd_copy = COPY $@
# send stderr to /dev/null to ignore messages when linking directories.
cmd_copy = rm -rf "$@" && cp -af "$<" "$@"
quiet_cmd_alink = AR($(TOOLSET)) $@
cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
quiet_cmd_alink_thin = AR($(TOOLSET)) $@
cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
# Due to circular dependencies between libraries :(, we wrap the
# special "figure out circular dependencies" flags around the entire
# input list during linking.
quiet_cmd_link = LINK($(TOOLSET)) $@
cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) $(LIBS) -Wl,--end-group
# We support two kinds of shared objects (.so):
# 1) shared_library, which is just bundling together many dependent libraries
# into a link line.
# 2) loadable_module, which is generating a module intended for dlopen().
#
# They differ only slightly:
# In the former case, we want to package all dependent code into the .so.
# In the latter case, we want to package just the API exposed by the
# outermost module.
# This means shared_library uses --whole-archive, while loadable_module doesn't.
# (Note that --whole-archive is incompatible with the --start-group used in
# normal linking.)
# Other shared-object link notes:
# - Set SONAME to the library filename so our binaries don't reference
# the local, absolute paths used on the link command-line.
quiet_cmd_solink = SOLINK($(TOOLSET)) $@
cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
# Define an escape_quotes function to escape single quotes.
# This allows us to handle quotes properly as long as we always use
# use single quotes and escape_quotes.
escape_quotes = $(subst ','\'',$(1))
# This comment is here just to include a ' to unconfuse syntax highlighting.
# Define an escape_vars function to escape '$' variable syntax.
# This allows us to read/write command lines with shell variables (e.g.
# $LD_LIBRARY_PATH), without triggering make substitution.
escape_vars = $(subst $$,$$$$,$(1))
# Helper that expands to a shell command to echo a string exactly as it is in
# make. This uses printf instead of echo because printf's behaviour with respect
# to escape sequences is more portable than echo's across different shells
# (e.g., dash, bash).
exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
# Helper to compare the command we're about to run against the command
# we logged the last time we ran the command. Produces an empty
# string (false) when the commands match.
# Tricky point: Make has no string-equality test function.
# The kernel uses the following, but it seems like it would have false
# positives, where one string reordered its arguments.
# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
# $(filter-out $(cmd_$@), $(cmd_$(1))))
# We instead substitute each for the empty string into the other, and
# say they're equal if both substitutions produce the empty string.
# .d files contain ? instead of spaces, take that into account.
command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
$(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
# Helper that is non-empty when a prerequisite changes.
# Normally make does this implicitly, but we force rules to always run
# so we can check their command lines.
# $? -- new prerequisites
# $| -- order-only dependencies
prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
# Helper that executes all postbuilds until one fails.
define do_postbuilds
@E=0;\
for p in $(POSTBUILDS); do\
eval $$p;\
E=$$?;\
if [ $$E -ne 0 ]; then\
break;\
fi;\
done;\
if [ $$E -ne 0 ]; then\
rm -rf "$@";\
exit $$E;\
fi
endef
# do_cmd: run a command via the above cmd_foo names, if necessary.
# Should always run for a given target to handle command-line changes.
# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
# Third argument, if non-zero, makes it do POSTBUILDS processing.
# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
# spaces already and dirx strips the ? characters.
define do_cmd
$(if $(or $(command_changed),$(prereq_changed)),
@$(call exact_echo, $($(quiet)cmd_$(1)))
@mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
$(if $(findstring flock,$(word 1,$(cmd_$1))),
@$(cmd_$(1))
@echo " $(quiet_cmd_$(1)): Finished",
@$(cmd_$(1))
)
@$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
@$(if $(2),$(fixup_dep))
$(if $(and $(3), $(POSTBUILDS)),
$(call do_postbuilds)
)
)
endef
# Declare the "all" target first so it is the default,
# even though we don't have the deps yet.
.PHONY: all
all:
# make looks for ways to re-generate included makefiles, but in our case, we
# don't have a direct way. Explicitly telling make that it has nothing to do
# for them makes it go faster.
%.d: ;
# Use FORCE_DO_CMD to force a target to run. Should be coupled with
# do_cmd.
.PHONY: FORCE_DO_CMD
FORCE_DO_CMD:
TOOLSET := target
# Suffix rules, putting all outputs into $(obj).
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
# Try building from generated source, too.
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
@$(call do_cmd,cxx,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
@$(call do_cmd,cc,1)
$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
@$(call do_cmd,cc,1)
ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
$(findstring $(join ^,$(prefix)),\
$(join ^,DTraceProviderStub.target.mk)))),)
include DTraceProviderStub.target.mk
endif
quiet_cmd_regen_makefile = ACTION Regenerating $@
cmd_regen_makefile = cd $(srcdir); /home/erik/.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/dtrace-provider/build/config.gypi -I/home/erik/.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/node-gyp/addon.gypi -I/home/erik/.node-gyp/10.15.3/include/node/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/home/erik/.node-gyp/10.15.3" "-Dnode_gyp_dir=/home/erik/.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/node-gyp" "-Dnode_lib_file=/home/erik/.node-gyp/10.15.3/<(target_arch)/node.lib" "-Dmodule_root_dir=/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/dtrace-provider" "-Dnode_engine=v8" binding.gyp
Makefile: $(srcdir)/../../../../../../.node-gyp/10.15.3/include/node/common.gypi $(srcdir)/../../../../../../.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/node-gyp/addon.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp
$(call do_cmd,regen_makefile)
# "all" is a concatenation of the "all" targets from all the included
# sub-makefiles. This is just here to clarify.
all:
# Add in dependency-tracking rules. $(all_deps) is the list of every single
# target in our tree. Only consider the ones with .d (dependency) info:
d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
ifneq ($(d_files),)
include $(d_files)
endif
@@ -0,0 +1 @@
cmd_Release/obj.target/DTraceProviderStub.stamp := touch Release/obj.target/DTraceProviderStub.stamp
+6
View File
@@ -0,0 +1,6 @@
# This file is generated by gyp; do not edit.
export builddir_name ?= ./build/.
.PHONY: all
all:
$(MAKE) DTraceProviderStub
+194
View File
@@ -0,0 +1,194 @@
# Do not edit. File was generated by node-gyp's "configure" step
{
"target_defaults": {
"cflags": [],
"default_configuration": "Release",
"defines": [],
"include_dirs": [],
"libraries": []
},
"variables": {
"asan": 0,
"build_v8_with_gn": "false",
"coverage": "false",
"debug_nghttp2": "false",
"enable_lto": "false",
"enable_pgo_generate": "false",
"enable_pgo_use": "false",
"force_dynamic_crt": 0,
"gas_version": "2.27",
"host_arch": "x64",
"icu_data_in": "../../deps/icu-small/source/data/in/icudt62l.dat",
"icu_endianness": "l",
"icu_gyp_path": "tools/icu/icu-generic.gyp",
"icu_locales": "en,root",
"icu_path": "deps/icu-small",
"icu_small": "true",
"icu_ver_major": "62",
"llvm_version": 0,
"node_byteorder": "little",
"node_debug_lib": "false",
"node_enable_d8": "false",
"node_enable_v8_vtunejit": "false",
"node_install_npm": "true",
"node_module_version": 64,
"node_no_browser_globals": "false",
"node_prefix": "/",
"node_release_urlbase": "https://nodejs.org/download/release/",
"node_shared": "false",
"node_shared_cares": "false",
"node_shared_http_parser": "false",
"node_shared_libuv": "false",
"node_shared_nghttp2": "false",
"node_shared_openssl": "false",
"node_shared_zlib": "false",
"node_tag": "",
"node_target_type": "executable",
"node_use_bundled_v8": "true",
"node_use_dtrace": "false",
"node_use_etw": "false",
"node_use_large_pages": "false",
"node_use_openssl": "true",
"node_use_pch": "false",
"node_use_perfctr": "false",
"node_use_v8_platform": "true",
"node_with_ltcg": "false",
"node_without_node_options": "false",
"openssl_fips": "",
"openssl_no_asm": 0,
"shlib_suffix": "so.64",
"target_arch": "x64",
"v8_enable_gdbjit": 0,
"v8_enable_i18n_support": 1,
"v8_enable_inspector": 1,
"v8_no_strict_aliasing": 1,
"v8_optimized_debug": 0,
"v8_promise_internal_field_count": 1,
"v8_random_seed": 0,
"v8_trace_maps": 0,
"v8_typed_array_max_size_in_heap": 0,
"v8_use_snapshot": "true",
"want_separate_host_toolset": 0,
"nodedir": "/home/erik/.node-gyp/10.15.3",
"standalone_static_library": 1,
"cache_lock_stale": "60000",
"ham_it_up": "",
"legacy_bundling": "",
"sign_git_tag": "",
"user_agent": "npm/6.4.1 node/v10.15.3 linux x64",
"always_auth": "",
"bin_links": "true",
"key": "",
"allow_same_version": "",
"description": "true",
"fetch_retries": "2",
"heading": "npm",
"if_present": "",
"init_version": "1.0.0",
"user": "1000",
"prefer_online": "",
"noproxy": "",
"force": "",
"only": "",
"read_only": "",
"cache_min": "10",
"init_license": "ISC",
"editor": "vi",
"rollback": "true",
"tag_version_prefix": "v",
"cache_max": "Infinity",
"timing": "",
"userconfig": "/home/erik/.npmrc",
"engine_strict": "",
"init_author_name": "",
"init_author_url": "",
"preid": "",
"tmp": "/tmp",
"depth": "Infinity",
"package_lock_only": "",
"save_dev": "",
"usage": "",
"metrics_registry": "https://registry.npmjs.org/",
"otp": "",
"package_lock": "true",
"progress": "true",
"https_proxy": "",
"save_prod": "",
"audit": "true",
"cidr": "",
"onload_script": "",
"sso_type": "oauth",
"rebuild_bundle": "true",
"save_bundle": "",
"shell": "/bin/bash",
"dry_run": "",
"prefix": "/home/erik/.nvm/versions/node/v10.15.3",
"scope": "",
"browser": "",
"cache_lock_wait": "10000",
"ignore_prepublish": "",
"registry": "https://registry.npmjs.org/",
"save_optional": "",
"searchopts": "",
"versions": "",
"cache": "/home/erik/.npm",
"send_metrics": "",
"global_style": "",
"ignore_scripts": "",
"version": "",
"local_address": "",
"viewer": "man",
"node_gyp": "/home/erik/.nvm/versions/node/v10.15.3/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js",
"audit_level": "low",
"prefer_offline": "",
"color": "true",
"sign_git_commit": "",
"fetch_retry_mintimeout": "10000",
"maxsockets": "50",
"offline": "",
"sso_poll_frequency": "500",
"umask": "0002",
"fetch_retry_maxtimeout": "60000",
"logs_max": "10",
"message": "%s",
"ca": "",
"cert": "",
"global": "",
"link": "",
"save": "true",
"access": "",
"also": "",
"unicode": "true",
"long": "",
"production": "",
"searchlimit": "20",
"unsafe_perm": "true",
"update_notifier": "true",
"auth_type": "legacy",
"node_version": "10.15.3",
"tag": "latest",
"git_tag_version": "true",
"commit_hooks": "true",
"script_shell": "",
"shrinkwrap": "true",
"fetch_retry_factor": "10",
"save_exact": "",
"strict_ssl": "true",
"dev": "",
"globalconfig": "/home/erik/.nvm/versions/node/v10.15.3/etc/npmrc",
"init_module": "/home/erik/.npm-init.js",
"parseable": "",
"globalignorefile": "/home/erik/.nvm/versions/node/v10.15.3/etc/npmignore",
"cache_lock_retries": "10",
"searchstaleness": "900",
"node_options": "",
"save_prefix": "^",
"scripts_prepend_node_path": "warn-only",
"group": "1000",
"init_author_email": "",
"searchexclude": "",
"git": "git",
"optional": "true",
"json": ""
}
}
+41
View File
@@ -0,0 +1,41 @@
var DTraceProvider;
function DTraceProviderStub() {}
DTraceProviderStub.prototype.addProbe = function(name) {
var p = { 'fire': function () {} };
this[name] = p;
return (p);
};
DTraceProviderStub.prototype.enable = function() {};
DTraceProviderStub.prototype.fire = function() {};
DTraceProviderStub.prototype.disable = function() {};
var builds = ['Release', 'default', 'Debug'];
var err = null;
for (var i = 0; i < builds.length; i++) {
try {
var binding = require('./src/build/' + builds[i] + '/DTraceProviderBindings');
DTraceProvider = binding.DTraceProvider;
break;
} catch (e) {
if (err === null) {
err = e;
}
}
}
if (!DTraceProvider) {
if (process.env.NODE_DTRACE_PROVIDER_REQUIRE === 'hard') {
throw err;
} else {
DTraceProvider = DTraceProviderStub;
}
}
exports.DTraceProvider = DTraceProvider;
exports.createDTraceProvider = function(name, module) {
if (arguments.length == 2)
return (new exports.DTraceProvider(name, module));
return (new exports.DTraceProvider(name));
};
+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
+62
View File
@@ -0,0 +1,62 @@
{
"_from": "dtrace-provider@~0.8",
"_id": "dtrace-provider@0.8.7",
"_inBundle": false,
"_integrity": "sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ=",
"_location": "/dtrace-provider",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "dtrace-provider@~0.8",
"name": "dtrace-provider",
"escapedName": "dtrace-provider",
"rawSpec": "~0.8",
"saveSpec": null,
"fetchSpec": "~0.8"
},
"_requiredBy": [
"/bunyan",
"/ldapjs"
],
"_resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.7.tgz",
"_shasum": "dc939b4d3e0620cfe0c1cd803d0d2d7ed04ffd04",
"_spec": "dtrace-provider@~0.8",
"_where": "/home/erik/Documents/workspace_brackets/a1_BME_Project_Ohm/om/node_modules/ldapjs",
"author": {
"name": "Chris Andrews",
"email": "chris@nodnol.org"
},
"bugs": {
"url": "https://github.com/chrisa/node-dtrace-provider/issues"
},
"bundleDependencies": false,
"dependencies": {
"nan": "^2.10.0"
},
"deprecated": false,
"description": "Native DTrace providers for node.js applications",
"devDependencies": {
"tap": "0.7.1"
},
"engines": {
"node": ">=0.10"
},
"homepage": "https://github.com/chrisa/node-dtrace-provider#readme",
"keywords": [
"dtrace",
"usdt"
],
"license": "BSD-2-Clause",
"main": "./dtrace-provider.js",
"name": "dtrace-provider",
"repository": {
"type": "git",
"url": "git+https://github.com/chrisa/node-dtrace-provider.git"
},
"scripts": {
"install": "node-gyp rebuild || node suppress-error.js",
"test": "tap test/*.test.js"
},
"version": "0.8.7"
}
+47
View File
@@ -0,0 +1,47 @@
{
'conditions' : [
['OS=="mac" or OS=="solaris"', {
'variables': {
'escaped_root': '<!(printf %q "<(module_root_dir)")',
}
}],
['OS=="freebsd"', {
'variables' : {
'escaped_root': '<!(printf %s "<(module_root_dir)")'
}
}]
],
'targets': [
{
'target_name': 'DTraceProviderBindings',
'sources': [
'dtrace_provider.cc',
'dtrace_probe.cc',
'dtrace_argument.cc'
],
'conditions': [
['OS=="mac" or OS=="solaris"',
{ 'include_dirs': [
'../libusdt',
'<!(node -e "require(\'nan\')")',
]
}
],
['OS=="freebsd"',
{ 'include_dirs': [
'/usr/src/cddl/compat/opensolaris/',
'/usr/src/sys/cddl/compat/opensolaris',
'/usr/src/sys/cddl/contrib/opensolaris/uts/common/',
'../libusdt',
'<!(node -e "require(\'nan\')")'
]
}
]
],
'libraries': [
'-L<(escaped_root)/../libusdt -l usdt'
]
}
]
}
+92
View File
@@ -0,0 +1,92 @@
#include "dtrace_provider.h"
#include <nan.h>
namespace node {
using namespace v8;
// Integer Argument
#ifdef __x86_64__
# define INTMETHOD ToInteger()
#else
# define INTMETHOD ToInt32()
#endif
void * DTraceIntegerArgument::ArgumentValue(v8::Local<Value> value) {
if (value->IsUndefined())
return 0;
else
return (void *)(long) value->INTMETHOD->Value();
}
void DTraceIntegerArgument::FreeArgument(void *arg) {
}
const char * DTraceIntegerArgument::Type() {
return "int";
}
// String Argument
void * DTraceStringArgument::ArgumentValue(v8::Local<Value> value) {
if (value->IsUndefined())
return (void *) strdup("undefined");
String::Utf8Value str(value->ToString());
return (void *) strdup(*str);
}
void DTraceStringArgument::FreeArgument(void *arg) {
free(arg);
}
const char * DTraceStringArgument::Type() {
return "char *";
}
// JSON Argument
DTraceJsonArgument::DTraceJsonArgument() {
Nan::HandleScope scope;
v8::Local<Context> context = Nan::GetCurrentContext();
v8::Local<Object> global = context->Global();
v8::Local<Object> l_JSON = global->Get(Nan::New<String>("JSON").ToLocalChecked())->ToObject();
v8::Local<Function> l_JSON_stringify
= v8::Local<Function>::Cast(l_JSON->Get(Nan::New<String>("stringify").ToLocalChecked()));
JSON.Reset(l_JSON);
JSON_stringify.Reset(l_JSON_stringify);
}
DTraceJsonArgument::~DTraceJsonArgument() {
JSON.Reset();
JSON_stringify.Reset();
}
void * DTraceJsonArgument::ArgumentValue(v8::Local<Value> value) {
Nan::HandleScope scope;
if (value->IsUndefined())
return (void *) strdup("undefined");
v8::Local<Value> info[1];
info[0] = value;
v8::Local<Value> j = Nan::New<Function>(JSON_stringify)->Call(
Nan::New<Object>(JSON), 1, info);
if (*j == NULL)
return (void *) strdup("{ \"error\": \"stringify failed\" }");
String::Utf8Value json(j->ToString());
return (void *) strdup(*json);
}
void DTraceJsonArgument::FreeArgument(void *arg) {
free(arg);
}
const char * DTraceJsonArgument::Type() {
return "char *";
}
} // namespace node
+105
View File
@@ -0,0 +1,105 @@
#include "dtrace_provider.h"
#include <nan.h>
namespace node {
using namespace v8;
DTraceProbe::DTraceProbe() : Nan::ObjectWrap() {
argc = 0;
probedef = NULL;
}
DTraceProbe::~DTraceProbe() {
for (size_t i = 0; i < argc; i++)
delete(this->arguments[i]);
usdt_probe_release(probedef);
}
Nan::Persistent<FunctionTemplate> DTraceProbe::constructor_template;
void DTraceProbe::Initialize(v8::Local<Object> target) {
Nan::HandleScope scope;
Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(DTraceProbe::New);
t->InstanceTemplate()->SetInternalFieldCount(2);
t->SetClassName(Nan::New<String>("DTraceProbe").ToLocalChecked());
constructor_template.Reset(t);
Nan::SetPrototypeMethod(t, "fire", DTraceProbe::Fire);
target->Set(Nan::New<String>("DTraceProbe").ToLocalChecked(), t->GetFunction());
}
NAN_METHOD(DTraceProbe::New) {
Nan::HandleScope scope;
DTraceProbe *probe = new DTraceProbe();
probe->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
NAN_METHOD(DTraceProbe::Fire) {
Nan::HandleScope scope;
if (!info[0]->IsFunction()) {
Nan::ThrowTypeError("Must give probe value callback as first argument");
return;
}
DTraceProbe *pd = Nan::ObjectWrap::Unwrap<DTraceProbe>(info.Holder());
info.GetReturnValue().Set(pd->_fire(info, 0));
}
v8::Local<Value> DTraceProbe::_fire(Nan::NAN_METHOD_ARGS_TYPE argsinfo, size_t fnidx) {
Nan::HandleScope scope;
if (usdt_is_enabled(this->probedef->probe) == 0) {
return Nan::Undefined();
}
// invoke fire callback
Nan::TryCatch try_catch;
size_t cblen = argsinfo.Length() - fnidx - 1;
Local<Value> *cbargs = new Local<Value>[cblen];
for (size_t i = 0; i < cblen; i++) {
cbargs[i] = argsinfo[i + fnidx + 1];
}
Local<Function> cb = Local<Function>::Cast(argsinfo[fnidx]);
Local<Value> probe_args = cb->Call(this->handle(), cblen, cbargs);
delete [] cbargs;
// exception in args callback?
if (try_catch.HasCaught()) {
Nan::FatalException(try_catch);
return Nan::Undefined();
}
// check return
if (!probe_args->IsArray()) {
return Nan::Undefined();
}
Local<Array> a = Local<Array>::Cast(probe_args);
void *argv[USDT_ARG_MAX];
// convert each argument value
for (size_t i = 0; i < argc; i++) {
argv[i] = this->arguments[i]->ArgumentValue(a->Get(i));
}
// finally fire the probe
usdt_fire_probe(this->probedef->probe, argc, argv);
// free argument values
for (size_t i = 0; i < argc; i++) {
this->arguments[i]->FreeArgument(argv[i]);
}
return Nan::True();
}
} // namespace node
+225
View File
@@ -0,0 +1,225 @@
#include "dtrace_provider.h"
#include <nan.h>
#include <stdio.h>
namespace node {
using namespace v8;
DTraceProvider::DTraceProvider() : Nan::ObjectWrap() {
provider = NULL;
}
DTraceProvider::~DTraceProvider() {
usdt_provider_disable(provider);
usdt_provider_free(provider);
}
Nan::Persistent<FunctionTemplate> DTraceProvider::constructor_template;
void DTraceProvider::Initialize(v8::Local<Object> target) {
Nan::HandleScope scope;
Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(DTraceProvider::New);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(Nan::New<String>("DTraceProvider").ToLocalChecked());
constructor_template.Reset(t);
Nan::SetPrototypeMethod(t, "addProbe", DTraceProvider::AddProbe);
Nan::SetPrototypeMethod(t, "removeProbe", DTraceProvider::RemoveProbe);
Nan::SetPrototypeMethod(t, "enable", DTraceProvider::Enable);
Nan::SetPrototypeMethod(t, "disable", DTraceProvider::Disable);
Nan::SetPrototypeMethod(t, "fire", DTraceProvider::Fire);
target->Set(Nan::New<String>("DTraceProvider").ToLocalChecked(), t->GetFunction());
DTraceProbe::Initialize(target);
}
NAN_METHOD(DTraceProvider::New) {
Nan::HandleScope scope;
DTraceProvider *p = new DTraceProvider();
char module[128];
p->Wrap(info.This());
if (info.Length() < 1 || !info[0]->IsString()) {
Nan::ThrowTypeError("Must give provider name as argument");
return;
}
String::Utf8Value name(info[0]->ToString());
if (info.Length() == 2) {
if (!info[1]->IsString()) {
Nan::ThrowTypeError("Must give module name as argument");
return;
}
String::Utf8Value mod(info[1]->ToString());
(void) snprintf(module, sizeof (module), "%s", *mod);
} else if (info.Length() == 1) {
// If no module name is provided, develop a synthetic module name based
// on our address
(void) snprintf(module, sizeof (module), "mod-%p", p);
} else {
Nan::ThrowError("Expected only provider name and module as arguments");
return;
}
if ((p->provider = usdt_create_provider(*name, module)) == NULL) {
Nan::ThrowError("usdt_create_provider failed");
return;
}
info.GetReturnValue().Set(info.This());
}
NAN_METHOD(DTraceProvider::AddProbe) {
Nan::HandleScope scope;
const char *types[USDT_ARG_MAX];
v8::Local<Object> obj = info.Holder();
DTraceProvider *provider = Nan::ObjectWrap::Unwrap<DTraceProvider>(obj);
// create a DTraceProbe object
v8::Local<Function> klass =
Nan::New<FunctionTemplate>(DTraceProbe::constructor_template)->GetFunction();
v8::Local<Object> pd = Nan::NewInstance(klass).ToLocalChecked();
// store in provider object
DTraceProbe *probe = Nan::ObjectWrap::Unwrap<DTraceProbe>(pd->ToObject());
obj->Set(info[0]->ToString(), pd);
// reference the provider to avoid GC'ing it when only probes remain in scope.
Nan::ForceSet(pd, Nan::New<String>("__prov__").ToLocalChecked(), obj,
static_cast<PropertyAttribute>(DontEnum | ReadOnly | DontDelete));
// add probe to provider
for (int i = 0; i < USDT_ARG_MAX; i++) {
if (i < info.Length() - 1) {
String::Utf8Value type(info[i + 1]->ToString());
if (strncmp("json", *type, 4) == 0)
probe->arguments[i] = new DTraceJsonArgument();
else if (strncmp("char *", *type, 6) == 0)
probe->arguments[i] = new DTraceStringArgument();
else if (strncmp("int", *type, 3) == 0)
probe->arguments[i] = new DTraceIntegerArgument();
else
probe->arguments[i] = new DTraceStringArgument();
types[i] = strdup(probe->arguments[i]->Type());
probe->argc++;
}
}
String::Utf8Value name(info[0]->ToString());
probe->probedef = usdt_create_probe(*name, *name, probe->argc, types);
Nan::SetInternalFieldPointer(pd, 1, provider);
usdt_provider_add_probe(provider->provider, probe->probedef);
for (size_t i = 0; i < probe->argc; i++) {
free((char *)types[i]);
}
info.GetReturnValue().Set(pd);
}
NAN_METHOD(DTraceProvider::RemoveProbe) {
Nan::HandleScope scope;
v8::Local<Object> provider_obj = info.Holder();
DTraceProvider *provider = Nan::ObjectWrap::Unwrap<DTraceProvider>(provider_obj);
v8::Local<Object> probe_obj = Local<Object>::Cast(info[0]);
DTraceProbe *probe = Nan::ObjectWrap::Unwrap<DTraceProbe>(probe_obj);
v8::Local<String> name = Nan::New<String>(probe->probedef->name).ToLocalChecked();
provider_obj->Delete(name);
if (usdt_provider_remove_probe(provider->provider, probe->probedef) != 0) {
Nan::ThrowError(usdt_errstr(provider->provider));
return;
}
info.GetReturnValue().Set(Nan::True());
}
NAN_METHOD(DTraceProvider::Enable) {
Nan::HandleScope scope;
DTraceProvider *provider = Nan::ObjectWrap::Unwrap<DTraceProvider>(info.Holder());
if (usdt_provider_enable(provider->provider) != 0) {
Nan::ThrowError(usdt_errstr(provider->provider));
return;
}
return;
}
NAN_METHOD(DTraceProvider::Disable) {
Nan::HandleScope scope;
DTraceProvider *provider = Nan::ObjectWrap::Unwrap<DTraceProvider>(info.Holder());
if (usdt_provider_disable(provider->provider) != 0) {
Nan::ThrowError(usdt_errstr(provider->provider));
return;
}
return;
}
NAN_METHOD(DTraceProvider::Fire) {
Nan::HandleScope scope;
if (!info[0]->IsString()) {
Nan::ThrowTypeError("Must give probe name as first argument");
return;
}
if (!info[1]->IsFunction()) {
Nan::ThrowTypeError("Must give probe value callback as second argument");
return;
}
v8::Local<Object> holder = info.Holder();
DTraceProvider *provider = Nan::ObjectWrap::Unwrap<DTraceProvider>(holder);
Nan::MaybeLocal<v8::Value> maybe = Nan::Get(holder, info[0]);
if (maybe.IsEmpty()) {
return;
}
v8::Local<v8::Value> value = maybe.ToLocalChecked();
if (!value->IsObject()) {
return;
}
v8::Local<Object> probe = Local<Object>::Cast(value);
if (probe->InternalFieldCount() != 2) {
return;
}
if (Nan::GetInternalFieldPointer(probe, 1) != provider) {
return;
}
DTraceProbe *p = Nan::ObjectWrap::Unwrap<DTraceProbe>(probe);
if (p == NULL) {
return;
}
p->_fire(info, 1);
info.GetReturnValue().Set(Nan::True());
}
extern "C" void
init(v8::Local<Object> target) {
DTraceProvider::Initialize(target);
}
NODE_MODULE(DTraceProviderBindings, init)
} // namespace node
+102
View File
@@ -0,0 +1,102 @@
#include <nan.h>
#include <node_object_wrap.h>
extern "C" {
#include <usdt.h>
}
#include <sys/dtrace.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#ifndef __APPLE__
#include <stdlib.h>
#ifndef __FreeBSD__
#include <malloc.h>
#endif
#endif
namespace node {
using namespace v8;
class DTraceArgument {
public:
virtual const char *Type() = 0;
virtual void *ArgumentValue(v8::Local<Value>) = 0;
virtual void FreeArgument(void *) = 0;
virtual ~DTraceArgument() { };
};
class DTraceIntegerArgument : public DTraceArgument {
public:
const char *Type();
void *ArgumentValue(v8::Local<Value>);
void FreeArgument(void *);
};
class DTraceStringArgument : public DTraceArgument {
public:
const char *Type();
void *ArgumentValue(v8::Local<Value>);
void FreeArgument(void *);
};
class DTraceJsonArgument : public DTraceArgument {
public:
const char *Type();
void *ArgumentValue(v8::Local<Value>);
void FreeArgument(void *);
DTraceJsonArgument();
~DTraceJsonArgument();
private:
Nan::Persistent<Object> JSON;
Nan::Persistent<Function> JSON_stringify;
};
class DTraceProbe : public Nan::ObjectWrap {
public:
static void Initialize(v8::Local<v8::Object> target);
usdt_probedef_t *probedef;
size_t argc;
DTraceArgument *arguments[USDT_ARG_MAX];
static NAN_METHOD(New);
static NAN_METHOD(Fire);
v8::Local<Value> _fire(Nan::NAN_METHOD_ARGS_TYPE, size_t);
static Nan::Persistent<FunctionTemplate> constructor_template;
DTraceProbe();
~DTraceProbe();
private:
};
class DTraceProvider : public Nan::ObjectWrap {
public:
static void Initialize(v8::Local<v8::Object> target);
usdt_provider_t *provider;
static NAN_METHOD(New);
static NAN_METHOD(AddProbe);
static NAN_METHOD(RemoveProbe);
static NAN_METHOD(Enable);
static NAN_METHOD(Disable);
static NAN_METHOD(Fire);
DTraceProvider();
~DTraceProvider();
private:
static Nan::Persistent<FunctionTemplate> constructor_template;
};
void InitDTraceProvider(v8::Local<v8::Object> target);
}
+28
View File
@@ -0,0 +1,28 @@
/**
* During `npm install`, we run:
*
* node-gyp rebuild || node suppress-error.js
*
* (Note that this expression is written to work on *nix and Windows.)
*
* When we run node-gyp, we detect whether or not we're on a supported platform,
* and either compile the node addon or exit having done nothing. It's possible
* for the platform to lack the requirements to run node-gyp though (such as
* Python 2, make, Visual C++ Build Tools, and so on), in which case we fall
* back onto this script.
*
* If NODE_DTRACE_PROVIDER_REQUIRE is set to "hard", then we want to propagate
* the failure and stop the install. Otherwise, we want to suppress it and
* allow the program to fall back onto the stub code.
*
* There is one case where we might stop an install and not want to: on Debian
* and Ubuntu, where the binary is named "nodejs" instead of "node", the
* fallback will fail to run. There doesn't really seem to be a great way to
* handle this scenario, so users on those systems will need to either install
* node-gyp's requirements or set up a "node" symbolic link.
*/
if (process.env.NODE_DTRACE_PROVIDER_REQUIRE === 'hard') {
process.exit(1);
} else {
process.exit(0);
}