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