aboutsummaryrefslogtreecommitdiffstats
path: root/lib/runtime_tools/c_src
diff options
context:
space:
mode:
authorPatrik Nyblom <[email protected]>2012-03-22 18:29:34 +0100
committerPatrik Nyblom <[email protected]>2012-03-22 18:30:07 +0100
commit5957a8338fe1f4e79a39277174094bbd9e978896 (patch)
tree4abcf47850e2a577b401a61bb1693d85cb137ffe /lib/runtime_tools/c_src
parentb5f6596f49db47e6dacddb2b10292a7294e13993 (diff)
parent1e653c3539423e4cfdeab1d232483bcac0e8b073 (diff)
downloadotp-5957a8338fe1f4e79a39277174094bbd9e978896.tar.gz
otp-5957a8338fe1f4e79a39277174094bbd9e978896.tar.bz2
otp-5957a8338fe1f4e79a39277174094bbd9e978896.zip
Merge branch 'pan/dtrace' into maint
* pan/dtrace: (22 commits) Use distinct function-entry probes for local and global calls Correct calculation of stack depth in call/return probes Add probes for all kind of calls Don't try to "clean up" generated fun names erl_process.c: Fix probe for process exit Remove code causing dialyzer warning from prim_file Add documentation for dyntrace and system_info changes Update slogan and add system_info for dynamic trace Update README's for dtrace and systemtap Rename dyntrace BIFs to more suiting names If VM probes are not enabled, short-circuit calls to probe BIFs beam_makeops: Add a simple preprocessor Ifdef all dynamic trace code Move dtrace erlang code and NIF into runtime_tools Correct some errors in the user tag spreading Change to more specific configure options for dtrace Add user tag spreading functionality to VM and use in file Update dtrace for changes in R15 Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 4/4 Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 3/4 ... OTP-10017
Diffstat (limited to 'lib/runtime_tools/c_src')
-rw-r--r--lib/runtime_tools/c_src/Makefile.in79
-rw-r--r--lib/runtime_tools/c_src/dtrace_user.d53
-rw-r--r--lib/runtime_tools/c_src/dyntrace.c172
3 files changed, 298 insertions, 6 deletions
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index 3d9a7ed69d..120f9b913f 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -21,6 +21,11 @@ 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
@@ -38,6 +43,8 @@ SHELL = /bin/sh
LIBS = $(DED_LIBS)
LDFLAGS += $(DED_LDFLAGS)
+DTRACE_LIBNAME = dyntrace
+
SYSINCLUDE = $(DED_SYS_INCLUDE)
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks
@@ -45,15 +52,20 @@ endif
TRACE_DRV_INCLUDES = $(SYSINCLUDE)
-ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES)
-
+ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \
+ -I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET)
ifeq ($(TYPE),debug)
TYPEMARKER = .debug
-TYPE_FLAGS = -g -DDEBUG @DEBUG_FLAGS@
+TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG @DEBUG_FLAGS@
+else
+ifeq ($(TYPE),valgrind)
+TYPEMARKER = .valgrind
+TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND
else
TYPEMARKER =
-TYPE_FLAGS = -O2
+TYPE_FLAGS = $(CFLAGS)
+endif
endif
ROOTDIR = $(ERL_TOP)/lib
@@ -69,6 +81,16 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN)
# ----------------------------------------------------
# Misc Macros
# ----------------------------------------------------
+before_DTrace_OBJS = $(OBJDIR)/dyntrace$(TYPEMARKER).o
+## NIF_MAKEFILE = $(PRIVDIR)/Makefile
+
+# Higher-level makefiles says that we can only compile on UNIX flavors
+NIF_LIB = $(LIBDIR)/dyntrace$(TYPEMARKER).@DED_EXT@
+
+ifeq ($(HOST_OS),)
+HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess)
+endif
+
TRACE_IP_DRV_OBJS = \
$(OBJDIR)/trace_ip_drv.o
@@ -91,7 +113,44 @@ endif
_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-debug opt: $(SOLIBS)
+debug opt valgrind: $(SOLIBS) $(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
+
+DTRACE_OBJS =
+ifdef DTRACE_ENABLED_2STEP
+DTRACE_OBJS += $(OBJDIR)/dtrace_user.o
+$(OBJDIR)/dtrace_user.o: $(before_DTrace_OBJS) $(OBJDIR)/dtrace_user.h
+ dtrace -G -C \
+ -s ./dtrace_user.d \
+ -o $@ $(before_DTrace_OBJS)
+endif
+
+DYNTRACE_OBJS = $(before_DTrace_OBJS) $(DTRACE_OBJS)
+
+$(OBJDIR):
+ -@mkdir -p $(OBJDIR)
+
+$(LIBDIR):
+ -@mkdir -p $(LIBDIR)
+
+$(OBJDIR)/dyntrace$(TYPEMARKER).o: dyntrace.c $(DTRACE_USER_HEADER)
+ $(INSTALL_DIR) $(OBJDIR)
+ $(CC) -c -o $@ $(ALL_CFLAGS) $<
+
+$(NIF_LIB): $(DYNTRACE_OBJS)
+ $(INSTALL_DIR) $(LIBDIR)
+ $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS)
$(OBJDIR)/%.o: %.c
$(CC) -c -o $@ $(ALL_CFLAGS) $<
@@ -118,6 +177,12 @@ $(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS)
clean:
rm -f $(SOLIBS) $(TRACE_IP_DRV_OBJS) $(TRACE_FILE_DRV_OBJS)
+ rm -f $(LIBDIR)/dyntrace.@DED_EXT@
+ rm -f $(LIBDIR)/dyntrace.debug.@DED_EXT@
+ rm -f $(LIBDIR)/dyntrace.valgrind.@DED_EXT@
+ rm -f $(OBJDIR)/dyntrace.o
+ rm -f $(OBJDIR)/dyntrace.debug.o
+ rm -f $(OBJDIR)/dyntrace.valgrind.o
rm -f core *~
docs:
@@ -128,8 +193,10 @@ docs:
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/obj
$(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib
+ $(INSTALL_PROGRAM) $(DYNTRACE_OBJS) $(RELSYSDIR)/priv/obj
+ $(INSTALL_PROGRAM) $(NIF_LIB) $(SOLIBS) $(RELSYSDIR)/priv/lib
release_docs_spec:
diff --git a/lib/runtime_tools/c_src/dtrace_user.d b/lib/runtime_tools/c_src/dtrace_user.d
new file mode 100644
index 0000000000..45d3ef3b66
--- /dev/null
+++ b/lib/runtime_tools/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/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c
new file mode 100644
index 0000000000..d94014559d
--- /dev/null
+++ b/lib/runtime_tools/c_src/dyntrace.c
@@ -0,0 +1,172 @@
+/*
+ * %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"
+#include "dtrace-wrapper.h"
+#if defined(USE_DYNAMIC_TRACE) && (defined(USE_DTRACE) || defined(USE_SYSTEMTAP))
+#define HAVE_USE_DTRACE 1
+#endif
+#ifdef HAVE_USE_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(dyntrace, 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_USE_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_USE_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_USE_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, MESSAGE_BUFSIZ);
+ 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, MESSAGE_BUFSIZ);
+ get_string_maybe(env, argv[6], &mbuf2, messagebuf2, MESSAGE_BUFSIZ);
+ get_string_maybe(env, argv[7], &mbuf3, messagebuf3, MESSAGE_BUFSIZ);
+ get_string_maybe(env, argv[8], &mbuf4, messagebuf4, MESSAGE_BUFSIZ);
+ 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
+}