diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/dtrace/Makefile | 36 | ||||
-rw-r--r-- | lib/dtrace/c_src/Makefile | 4 | ||||
-rw-r--r-- | lib/dtrace/c_src/Makefile.in | 152 | ||||
-rw-r--r-- | lib/dtrace/c_src/dtrace.c | 174 | ||||
-rw-r--r-- | lib/dtrace/c_src/dtrace_user.d | 53 | ||||
-rw-r--r-- | lib/dtrace/ebin/.placeholder | 0 | ||||
-rw-r--r-- | lib/dtrace/src/Makefile | 102 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.app.src | 27 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.appup.src | 19 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.erl | 216 | ||||
-rw-r--r-- | lib/dtrace/vsn.mk | 1 |
12 files changed, 785 insertions, 1 deletions
diff --git a/lib/Makefile b/lib/Makefile index aa4e074830..96ce2d1315 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -31,7 +31,7 @@ ifdef BUILD_ALL cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ xmerl edoc eunit ssh inviso typer erl_docgen \ - percept dialyzer hipe + percept dialyzer dtrace hipe EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS) EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE))) endif diff --git a/lib/dtrace/Makefile b/lib/dtrace/Makefile new file mode 100644 index 0000000000..29d463aab1 --- /dev/null +++ b/lib/dtrace/Makefile @@ -0,0 +1,36 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# +# Macros +# + +SUB_DIRECTORIES = src c_src + +include vsn.mk +VSN = $(DTRACE_VSN) + +SPECIAL_TARGETS = + +# +# Default Subdir Targets +# +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/dtrace/c_src/Makefile b/lib/dtrace/c_src/Makefile new file mode 100644 index 0000000000..f3320bb766 --- /dev/null +++ b/lib/dtrace/c_src/Makefile @@ -0,0 +1,4 @@ +# +# Invoke with GNU make or clearmake -C gnu. +# +include $(ERL_TOP)/make/run_make.mk diff --git a/lib/dtrace/c_src/Makefile.in b/lib/dtrace/c_src/Makefile.in new file mode 100644 index 0000000000..ed13684a95 --- /dev/null +++ b/lib/dtrace/c_src/Makefile.in @@ -0,0 +1,152 @@ +# +# %CopyrightBegin% +# +# Copyright Scott Lystig Fritchie 2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk + +# ---------------------------------------------------- +# Items from top-level configure +# ---------------------------------------------------- +DTRACE_ENABLED=@DTRACE_ENABLED@ +DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(DTRACE_VSN) + +# ---------------------------------------------------- +# The following variables differ between systems. +# Set by configure. +# ---------------------------------------------------- +CC = $(DED_CC) +LD = $(DED_LD) +SHELL = /bin/sh +LIBS = $(DED_LIBS) +LDFLAGS += $(DED_LDFLAGS) +CFLAGS = $(DED_CFLAGS) + +DTRACE_LIBNAME = dtrace + + +INCLUDES = $(DED_INCLUDES) + +ifeq ($(TYPE),debug) +TYPEMARKER = .debug +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG +else +ifeq ($(TYPE),valgrind) +TYPEMARKER = .valgrind +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND +else +TYPEMARKER = +TYPE_FLAGS = $(CFLAGS) +endif +endif + +ALL_CFLAGS = $(TYPE_FLAGS) $(INCLUDES) -I$(OBJDIR) \ + -I$(ERL_TOP)/erts/emulator/$(TARGET) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) + +# ---------------------------------------------------- +# Misc Macros +# ---------------------------------------------------- +OBJS = $(OBJDIR)/dtrace$(TYPEMARKER).o +## NIF_MAKEFILE = $(PRIVDIR)/Makefile + +# Higher-level makefiles says that we can only compile on UNIX flavors +NIF_LIB = $(LIBDIR)/dtrace$(TYPEMARKER).so + +ifeq ($(HOST_OS),) +HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) +endif + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt valgrind: $(OBJDIR) $(LIBDIR) $(NIF_LIB) + +ifdef DTRACE_ENABLED +DTRACE_USER_HEADER=$(OBJDIR)/dtrace_user.h +$(OBJDIR)/dtrace_user.h: ./dtrace_user.d + dtrace -h -C $(INCLUDES) \ + -s ./dtrace_user.d \ + -o ./dtrace_user.tmp + sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@ + rm ./dtrace_user.tmp +else +DTRACE_USER_HEADER= +endif + +ifdef DTRACE_ENABLED_2STEP +OBJS += $(OBJDIR)/dtrace_user.o +$(OBJDIR)/dtrace_user.o: $(OBJS) $(OBJDIR)/dtrace_user.h + touch $(OBJDIR)/erlang_dtrace.c + $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/erlang_dtrace.c + # The object file created above is immediately clobbered below. + # But creating it above avoids chicken-and-egg problem with OBJS + dtrace -G -C \ + -s ./dtrace_user.d \ + -o $@ $(OBJS) +endif + +$(OBJDIR): + -@mkdir -p $(OBJDIR) + +$(LIBDIR): + -@mkdir -p $(LIBDIR) + +$(OBJDIR)/%$(TYPEMARKER).o: %.c $(DTRACE_USER_HEADER) + $(INSTALL_DIR) $(OBJDIR) + $(CC) -c -o $@ $(ALL_CFLAGS) $< + +$(LIBDIR)/dtrace$(TYPEMARKER).so: $(OBJS) + $(INSTALL_DIR) $(LIBDIR) + $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +clean: + rm -f $(LIBDIR)/dtrace.so + rm -f $(LIBDIR)/dtrace.debug.so + rm -f $(LIBDIR)/dtrace.valgrind.so + rm -f $(OBJDIR)/dtrace.o + rm -f $(OBJDIR)/dtrace.debug.o + rm -f $(OBJDIR)/dtrace.valgrind.o + rm -f core *~ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv/obj + $(INSTALL_DIR) $(RELSYSDIR)/priv/lib + # $(INSTALL_DATA) $(NIF_MAKEFILE) $(RELSYSDIR)/priv/obj + $(INSTALL_PROGRAM) $(OBJS) $(RELSYSDIR)/priv/obj + $(INSTALL_PROGRAM) $(NIF_LIB) $(RELSYSDIR)/priv/lib + +release_docs_spec: diff --git a/lib/dtrace/c_src/dtrace.c b/lib/dtrace/c_src/dtrace.c new file mode 100644 index 0000000000..c9d25ece9c --- /dev/null +++ b/lib/dtrace/c_src/dtrace.c @@ -0,0 +1,174 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Dynamically loadable NIF library for DTrace + */ + + +#include "erl_nif.h" +#include "config.h" +#include "sys.h" +#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS +#include "dtrace-wrapper.h" +#ifdef HAVE_DTRACE +#include "dtrace_user.h" +#endif + +void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf); +void get_string_maybe(ErlNifEnv *env, const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz); + +#ifdef VALGRIND + # include <valgrind/memcheck.h> +#endif + +#ifdef __GNUC__ + # define INLINE __inline__ +#else + # define INLINE +#endif + +#define MESSAGE_BUFSIZ 1024 + +/* NIF interface declarations */ +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); + +/* The NIFs: */ +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = { + {"available", 0, available}, + {"user_trace_s1", 1, user_trace_s1}, + {"user_trace_i4s4", 9, user_trace_i4s4} +}; + +ERL_NIF_INIT(dtrace, nif_funcs, load, NULL, NULL, NULL) + +static ERL_NIF_TERM atom_true; +static ERL_NIF_TERM atom_false; +static ERL_NIF_TERM atom_error; +static ERL_NIF_TERM atom_not_available; +static ERL_NIF_TERM atom_badarg; +static ERL_NIF_TERM atom_ok; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + atom_true = enif_make_atom(env,"true"); + atom_false = enif_make_atom(env,"false"); + atom_error = enif_make_atom(env,"error"); + atom_not_available = enif_make_atom(env,"not_available"); + atom_badarg = enif_make_atom(env,"badarg"); + atom_ok = enif_make_atom(env,"ok"); + + return 0; +} + +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_DTRACE + return atom_true; +#else + return atom_false; +#endif +} + +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_DTRACE + ErlNifBinary message_bin; + DTRACE_CHARBUF(messagebuf, MESSAGE_BUFSIZ + 1); + + if (DTRACE_ENABLED(user_trace_s1)) { + if (!enif_inspect_iolist_as_binary(env, argv[0], &message_bin) || + message_bin.size > MESSAGE_BUFSIZ) { + return atom_badarg; + } + memcpy(messagebuf, (char *) message_bin.data, message_bin.size); + messagebuf[message_bin.size] = '\0'; + DTRACE1(user_trace_s1, messagebuf); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} + +void +get_string_maybe(ErlNifEnv *env, + const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz) +{ + ErlNifBinary str_bin; + + if (!enif_inspect_iolist_as_binary(env, term, &str_bin) || + str_bin.size > bufsiz) { + *ptr = NULL; + } else { + memcpy(buf, (char *) str_bin.data, str_bin.size); + buf[str_bin.size] = '\0'; + *ptr = buf; + } +} + +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_DTRACE + DTRACE_CHARBUF(procbuf, 32 + 1); + DTRACE_CHARBUF(user_tagbuf, MESSAGE_BUFSIZ + 1); + char *utbuf = NULL; + ErlNifSInt64 i1, i2, i3, i4; + DTRACE_CHARBUF(messagebuf1, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf2, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf3, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf4, MESSAGE_BUFSIZ + 1); + char *mbuf1 = NULL, *mbuf2 = NULL, *mbuf3 = NULL, *mbuf4 = NULL; + + if (DTRACE_ENABLED(user_trace_i4s4)) { + dtrace_nifenv_str(env, procbuf); + get_string_maybe(env, argv[0], &utbuf, + user_tagbuf, sizeof(user_tagbuf)-1); + if (! enif_get_int64(env, argv[1], &i1)) + i1 = 0; + if (! enif_get_int64(env, argv[2], &i2)) + i2 = 0; + if (! enif_get_int64(env, argv[3], &i3)) + i3 = 0; + if (! enif_get_int64(env, argv[4], &i4)) + i4 = 0; + get_string_maybe(env, argv[5], &mbuf1, + messagebuf1, sizeof(messagebuf1)-1); + get_string_maybe(env, argv[6], &mbuf2, + messagebuf2, sizeof(messagebuf2)-1); + get_string_maybe(env, argv[7], &mbuf3, + messagebuf3, sizeof(messagebuf3)-1); + get_string_maybe(env, argv[8], &mbuf4, + messagebuf4, sizeof(messagebuf4)-1); + DTRACE10(user_trace_i4s4, procbuf, utbuf, + i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} diff --git a/lib/dtrace/c_src/dtrace_user.d b/lib/dtrace/c_src/dtrace_user.d new file mode 100644 index 0000000000..45d3ef3b66 --- /dev/null +++ b/lib/dtrace/c_src/dtrace_user.d @@ -0,0 +1,53 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. + * All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +provider erlang { + /** + * Send a single string to a probe. + * + * @param NUL-terminated string + */ + probe user_trace__s1(char* message); + + /** + * Multi-purpose probe: up to 4 NUL-terminated strings and 4 + * 64-bit integer arguments. + * + * @param proc, the PID (string form) of the sending process + * @param user_tag, the user tag of the sender + * @param i1, integer + * @param i2, integer + * @param i3, integer + * @param i4, integer + * @param s1, string/iolist. D's arg6 is NULL if not given by Erlang + * @param s2, string/iolist. D's arg7 is NULL if not given by Erlang + * @param s3, string/iolist. D's arg8 is NULL if not given by Erlang + * @param s4, string/iolist. D's arg9 is NULL if not given by Erlang + */ + probe user_trace__i4s4(char *proc, char *user_tag, + int i1, int i2, int i3, int i4, + char *s1, char *s2, char *s3, char *s4); +}; + +#pragma D attributes Evolving/Evolving/Common provider erlang provider +#pragma D attributes Private/Private/Common provider erlang module +#pragma D attributes Private/Private/Common provider erlang function +#pragma D attributes Evolving/Evolving/Common provider erlang name +#pragma D attributes Evolving/Evolving/Common provider erlang args diff --git a/lib/dtrace/ebin/.placeholder b/lib/dtrace/ebin/.placeholder new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/dtrace/ebin/.placeholder diff --git a/lib/dtrace/src/Makefile b/lib/dtrace/src/Makefile new file mode 100644 index 0000000000..d613402a63 --- /dev/null +++ b/lib/dtrace/src/Makefile @@ -0,0 +1,102 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(DTRACE_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +MODULES= \ + dtrace + +HRL_FILES= \ + +INTERNAL_HRL_FILES= \ + +ERL_FILES= $(MODULES:%=%.erl) +EXAMPLE_FILES= \ + ../examples/* + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) + +EXECUTABLES= \ + +APP_FILE= dtrace.app + +APP_SRC= $(APP_FILE).src +APP_TARGET= $(EBIN)/$(APP_FILE) + +APPUP_FILE= dtrace.appup + +APPUP_SRC= $(APPUP_FILE).src +APPUP_TARGET= $(EBIN)/$(APPUP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += \ + -I../include \ + -I ../../et/include \ + -I ../../../libraries/et/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src + # $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + +release_docs_spec: diff --git a/lib/dtrace/src/dtrace.app.src b/lib/dtrace/src/dtrace.app.src new file mode 100644 index 0000000000..764e863559 --- /dev/null +++ b/lib/dtrace/src/dtrace.app.src @@ -0,0 +1,27 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{application, dtrace, + [{description, "DTRACE version 1"}, + {vsn, "%VSN%"}, + {modules, [ + dtrace + ]}, + {registered, []}, + {applications, [kernel, stdlib]}, + {env, []}]}. diff --git a/lib/dtrace/src/dtrace.appup.src b/lib/dtrace/src/dtrace.appup.src new file mode 100644 index 0000000000..f730a2f8df --- /dev/null +++ b/lib/dtrace/src/dtrace.appup.src @@ -0,0 +1,19 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{"%VSN%",[],[]}. diff --git a/lib/dtrace/src/dtrace.erl b/lib/dtrace/src/dtrace.erl new file mode 100644 index 0000000000..45addafc53 --- /dev/null +++ b/lib/dtrace/src/dtrace.erl @@ -0,0 +1,216 @@ +-module(dtrace). + +%%% @doc The DTrace interface module +%%% +%%% This DTrace interface module, with the corresponding NIFs, should +%%% work on any operating system platform where user-space DTrace +%%% probes are supported. +%%% +%%% Use the `dtrace:init()' function to load the NIF shared library and +%%% to initialize library's private state. +%%% +%%% It is recommended that you use the `dtrace:p()' function to add +%%% DTrace probes to your Erlang code. This function can accept up to +%%% four integer arguments and four string arguments; the integer +%%% argument(s) must come before any string argument. For example: +%%% ``` +%%% 1> put(dtrace_utag, "GGOOOAAALL!!!!!"). +%%% undefined +%%% 2> dtrace:init(). +%%% ok +%%% +%%% % % % Enable the DTrace probe using the 'dtrace' command. +%%% +%%% 3> dtrace:p(7, 8, 9, "one", "four"). +%%% true +%%% ''' +%%% +%%% Output from the example D script `user-probe.d' looks like: +%%% ``` +%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' +%%% ''' +%%% +%%% If the expected type of variable is not present, e.g. integer when +%%% integer() is expected, or an I/O list when iolist() is expected, +%%% then the driver will ignore the user's input and use a default +%%% value of 0 or NULL, respectively. + +-export([init/0, available/0, + user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 + p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). +-export([scaff/0]). % Development only +-export([user_trace_i4s4/9]). % Know what you're doing! + +-type probe_arg() :: integer() | iolist(). +-type int_p_arg() :: integer() | iolist() | undef. +%% The *_maybe() types use atom() instead of a stricter 'undef' +%% because user_trace_i4s4/9 is exposed to the outside world, and +%% because the driver will allow any atom to be used as a "not +%% present" indication, we'll allow any atom in the types. +-type integer_maybe() :: integer() | atom(). +-type iolist_maybe() :: iolist() | atom(). + +-spec init() -> ok | {error, {term(), term()}}. + +init() -> + PrivDir = code:priv_dir(dtrace), + Lib = filename:join([PrivDir, "lib", "dtrace"]), + erlang:load_nif(Lib, 0). + +%%% +%%% NIF placeholders +%%% + +-spec available() -> true | false. + +available() -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_s1(iolist()) -> true | false | error | badarg. + +user_trace_s1(Message) -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_i4s4(iolist(), + integer_maybe(), integer_maybe(), + integer_maybe(), integer_maybe(), + iolist_maybe(), iolist_maybe(), + iolist_maybe(), iolist_maybe()) -> + true | false | error | badarg. + +user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> + erlang:nif_error(nif_not_loaded). + +%%% +%%% Erlang support functions +%%% + +-spec p() -> true | false | error | badarg. + +p() -> + user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). + +-spec p(probe_arg()) -> true | false | error | badarg. + +p(I1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); +p(S1) -> + user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). + +-spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); +p(I1, S1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); +p(S1, S2) -> + user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); +p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); +p(I1, S1, S2) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); +p(S1, S2, S3) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); +p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); +p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); +p(I1, S1, S2, S3) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); +p(S1, S2, S3, S4) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); +p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); +p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); +p(I1, S1, S2, S3, S4) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); +p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); +p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); +p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). + +-spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), + int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> + true | false | error | badarg. + +user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> + UTag = prim_file:get_dtrace_utag(), + user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4). + +%% Scaffolding to write tedious code: quick brute force and not 100% correct. + +scaff_int_args(N) -> + L = lists:sublist(["I1", "I2", "I3", "I4"], N), + [string:join(L, ", ")]. + +scaff_int_guards(N) -> + L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)", + "is_integer(I4)"], N), + lists:flatten(string:join(L, ", ")). + +scaff_char_args(N) -> + L = lists:sublist(["S1", "S2", "S3", "S4"], N), + [string:join(L, ", ")]. + +scaff_fill(N) -> + [string:join(lists:duplicate(N, "undef"), ", ")]. + +scaff() -> + L = [begin + IntArgs = scaff_int_args(N_int), + IntGuards = scaff_int_guards(N_int), + IntFill = scaff_fill(4 - N_int), + CharArgs = scaff_char_args(N_char), + CharFill = scaff_fill(4 - N_char), + InArgs = string:join(IntArgs ++ CharArgs, ", "), + OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill, + ", "), + {N_int + N_char, + lists:flatten([io_lib:format("p(~s) when ~s ->\n", + [InArgs, IntGuards]), + io_lib:format(" user_trace_int(~s);\n", [OutArgs]) + ])} + end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]], + [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)]. diff --git a/lib/dtrace/vsn.mk b/lib/dtrace/vsn.mk new file mode 100644 index 0000000000..73bf983c00 --- /dev/null +++ b/lib/dtrace/vsn.mk @@ -0,0 +1 @@ +DTRACE_VSN = 0.8 |