diff options
Diffstat (limited to 'lib/runtime_tools/c_src')
| -rw-r--r-- | lib/runtime_tools/c_src/Makefile.in | 136 | ||||
| -rw-r--r-- | lib/runtime_tools/c_src/dtrace_user.d | 21 | ||||
| -rw-r--r-- | lib/runtime_tools/c_src/dyntrace.c | 637 | ||||
| -rw-r--r-- | lib/runtime_tools/c_src/dyntrace_lttng.h | 367 | ||||
| -rw-r--r-- | lib/runtime_tools/c_src/trace_file_drv.c | 64 | ||||
| -rw-r--r-- | lib/runtime_tools/c_src/trace_ip_drv.c | 64 | 
6 files changed, 1092 insertions, 197 deletions
| diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in index 754e6ccd78..4530a83aee 100644 --- a/lib/runtime_tools/c_src/Makefile.in +++ b/lib/runtime_tools/c_src/Makefile.in @@ -1,18 +1,19 @@  #  # %CopyrightBegin%  # -# Copyright Ericsson AB 1999-2012. All Rights Reserved. +# Copyright Ericsson AB 1999-2016. 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/. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at  # -# 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. +#     http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License.  #  # %CopyrightEnd%  # @@ -21,11 +22,6 @@ 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 @@ -37,24 +33,18 @@ VSN=$(RUNTIME_TOOLS_VSN)  # be set for that system only.  # ----------------------------------------------------  CC = $(DED_CC) -CFLAGS = $(DED_CFLAGS) +CFLAGS = $(DED_CFLAGS) -I./  LD = $(DED_LD)  SHELL = /bin/sh  LIBS = $(DED_LIBS)  LDFLAGS += $(DED_LDFLAGS) -DTRACE_LIBNAME = dyntrace +TRACE_LIBNAME = dyntrace trace_file_drv trace_ip_drv  SYSINCLUDE = $(DED_SYS_INCLUDE) -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -	SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks -endif  TRACE_DRV_INCLUDES = $(SYSINCLUDE) -ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \ -	-I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET) -  ifeq ($(TYPE),debug)  TYPEMARKER = .debug  TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG @DEBUG_FLAGS@ @@ -68,6 +58,9 @@ TYPE_FLAGS = $(CFLAGS)  endif  endif +ALL_CFLAGS = @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \ +	-I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET) +  ROOTDIR = $(ERL_TOP)/lib  PRIVDIR = ../priv  LIBDIR = $(PRIVDIR)/lib/$(TARGET) @@ -81,62 +74,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@ +TRACE_LIBS = $(foreach LIB, $(TRACE_LIBNAME), $(LIBDIR)/$(LIB)$(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 - -TRACE_FILE_DRV_OBJS = \ -	$(OBJDIR)/trace_file_drv.o - -ifeq ($(findstring win32,$(TARGET)), win32) -SOLIBS = $(LIBDIR)/trace_ip_drv.dll $(LIBDIR)/trace_file_drv.dll -LN=cp -else -ifeq ($(findstring vxworks,$(TARGET)),vxworks) -SOLIBS = $(LIBDIR)/trace_ip_drv.eld $(LIBDIR)/trace_file_drv.eld -else -SOLIBS = $(LIBDIR)/trace_ip_drv.so $(LIBDIR)/trace_file_drv.so -endif -endif  # ----------------------------------------------------  # Targets  # ----------------------------------------------------  _create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) -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) +debug opt valgrind: $(SOLIBS) $(OBJDIR) $(LIBDIR) $(TRACE_LIBS)  $(OBJDIR):  	-@mkdir -p $(OBJDIR) @@ -144,59 +91,26 @@ $(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)/%$(TYPEMARKER).o: %.c dyntrace_lttng.h +	$(V_CC) -c -o $@ $(ALL_CFLAGS) $< -$(OBJDIR)/%.o: %.c -	$(CC) -c -o $@ $(ALL_CFLAGS) $< - -$(LIBDIR)/trace_ip_drv.so: $(TRACE_IP_DRV_OBJS) -	$(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS) - -$(LIBDIR)/trace_file_drv.so: $(TRACE_FILE_DRV_OBJS) -	$(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS) - -$(LIBDIR)/trace_ip_drv.dll: $(TRACE_IP_DRV_OBJS) -	$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) -$(LIBDIR)/trace_file_drv.dll: $(TRACE_FILE_DRV_OBJS) -	$(LD) $(LDFLAGS) -o $@ $^ $(LIBS) -# -# VxWorks is simply to different from Unix in this sense. -# Here are the inference rules for VxWorks -# -$(LIBDIR)/trace_ip_drv.eld: $(TRACE_IP_DRV_OBJS) -	$(LD) $(LDFLAGS) -o $@ $^  - -$(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS) -	$(LD) $(LDFLAGS) -o $@ $^  +$(LIBDIR)/%$(TYPEMARKER).@DED_EXT@: $(OBJDIR)/%$(TYPEMARKER).o +	$(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS)  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 $(TRACE_LIBS)  	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_PROGRAM) $(DYNTRACE_OBJS) "$(RELSYSDIR)/priv/obj" -	$(INSTALL_PROGRAM) $(NIF_LIB) $(SOLIBS) "$(RELSYSDIR)/priv/lib" +	$(INSTALL_PROGRAM) $(TRACE_LIBS) "$(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 index 9e180a3cb2..2b74e9ef6f 100644 --- a/lib/runtime_tools/c_src/dtrace_user.d +++ b/lib/runtime_tools/c_src/dtrace_user.d @@ -1,19 +1,20 @@  /*   * %CopyrightBegin%   * - * Copyright Scott Lystig Fritchie 2011-2012. + * Copyright Scott Lystig Fritchie 2011-2016.   * 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/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at   * - * 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. + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License.   *   * %CopyrightEnd%   */ diff --git a/lib/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c index eef03afd1c..3d2de9c21c 100644 --- a/lib/runtime_tools/c_src/dyntrace.c +++ b/lib/runtime_tools/c_src/dyntrace.c @@ -1,18 +1,19 @@  /*   * %CopyrightBegin%   * - * Copyright Scott Lystig Fritchie 2011-2012. All Rights Reserved. + * Copyright Scott Lystig Fritchie 2011-2016. 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/. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at   * - * 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. + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License.   *   * %CopyrightEnd%   */ @@ -28,10 +29,13 @@  #include "sys.h"  #include "dtrace-wrapper.h"  #if defined(USE_DYNAMIC_TRACE) && (defined(USE_DTRACE) || defined(USE_SYSTEMTAP)) -#define HAVE_USE_DTRACE 1 +#  define HAVE_USE_DTRACE 1  #endif -#ifdef  HAVE_USE_DTRACE -#include "dtrace_user.h" +#if defined(USE_LTTNG) +#  define HAVE_USE_LTTNG 1 +#  define TRACEPOINT_DEFINE +#  define TRACEPOINT_CREATE_PROBES +#  include "dyntrace_lttng.h"  #endif  void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf); @@ -62,11 +66,55 @@ static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM a  static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);  static ERL_NIF_TERM user_trace_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +#ifdef HAVE_USE_LTTNG +static ERL_NIF_TERM trace_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_running_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_running_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_receive(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_garbage_collection(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ERL_NIF_TERM enabled_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_running_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_running_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_receive(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM enabled_garbage_collection(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +#endif + +  static ErlNifFunc nif_funcs[] = {      {"available", 0, available},      {"user_trace_s1", 1, user_trace_s1},      {"user_trace_i4s4", 9, user_trace_i4s4}, -    {"user_trace_n", 10, user_trace_n} +    {"user_trace_n", 10, user_trace_n}, +#ifdef HAVE_USE_LTTNG +    {"trace_procs", 5, trace_procs}, +    {"trace_ports", 5, trace_ports}, +    {"trace_running_procs", 5, trace_running_procs}, +    {"trace_running_ports", 5, trace_running_ports}, +    {"trace_call", 5, trace_call}, +    {"trace_send", 5, trace_send}, +    {"trace_receive", 5, trace_receive}, +    {"trace_garbage_collection", 5, trace_garbage_collection}, +    {"enabled_procs", 3, enabled_procs}, +    {"enabled_ports", 3, enabled_ports}, +    {"enabled_running_procs", 3, enabled_running_procs}, +    {"enabled_running_ports", 3, enabled_running_ports}, +    {"enabled_call", 3, enabled_call}, +    {"enabled_send", 3, enabled_send}, +    {"enabled_receive", 3, enabled_receive}, +    {"enabled_garbage_collection", 3, enabled_garbage_collection}, +#endif +    {"enabled", 3, enabled}, +    {"trace", 5, trace}  };  ERL_NIF_INIT(dyntrace, nif_funcs, load, NULL, NULL, NULL) @@ -74,19 +122,131 @@ 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_extra;  static ERL_NIF_TERM atom_not_available;  static ERL_NIF_TERM atom_badarg;  static ERL_NIF_TERM atom_ok; +static ERL_NIF_TERM atom_trace; +static ERL_NIF_TERM atom_seq_trace; +static ERL_NIF_TERM atom_remove; +static ERL_NIF_TERM atom_discard; + +#ifdef HAVE_USE_LTTNG + +/* gc atoms */ + +static ERL_NIF_TERM atom_gc_minor_start; +static ERL_NIF_TERM atom_gc_minor_end; +static ERL_NIF_TERM atom_gc_major_start; +static ERL_NIF_TERM atom_gc_major_end; + +static ERL_NIF_TERM atom_old_heap_block_size; /* for debug */ +static ERL_NIF_TERM atom_heap_block_size;     /* for debug */ + +/* process 'procs' */ + +static ERL_NIF_TERM atom_spawn; +static ERL_NIF_TERM atom_exit; +static ERL_NIF_TERM atom_register; +static ERL_NIF_TERM atom_unregister; +static ERL_NIF_TERM atom_link; +static ERL_NIF_TERM atom_unlink; +static ERL_NIF_TERM atom_getting_linked; +static ERL_NIF_TERM atom_getting_unlinked; + +/* process 'running' and 'exiting' */ + +static ERL_NIF_TERM atom_in; +static ERL_NIF_TERM atom_out; +static ERL_NIF_TERM atom_in_exiting; +static ERL_NIF_TERM atom_out_exiting; +static ERL_NIF_TERM atom_out_exited; + +/* process messages 'send' and 'receive' */ + +static ERL_NIF_TERM atom_send; +static ERL_NIF_TERM atom_receive; +static ERL_NIF_TERM atom_send_to_non_existing_process; + +/* ports 'ports' */ + +static ERL_NIF_TERM atom_open; +static ERL_NIF_TERM atom_closed; + +/* 'call' */ + +static ERL_NIF_TERM atom_call; +static ERL_NIF_TERM atom_return_from; +static ERL_NIF_TERM atom_return_to; +static ERL_NIF_TERM atom_exception_from; +#endif +  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_extra = enif_make_atom(env,"extra");      atom_not_available = enif_make_atom(env,"not_available");      atom_badarg = enif_make_atom(env,"badarg");      atom_ok = enif_make_atom(env,"ok"); +    atom_trace = enif_make_atom(env,"trace"); +    atom_seq_trace = enif_make_atom(env,"seq_trace"); +    atom_remove = enif_make_atom(env,"remove"); +    atom_discard = enif_make_atom(env,"discard"); + +#ifdef HAVE_USE_LTTNG + +    /* gc */ + +    atom_gc_minor_start = enif_make_atom(env,"gc_minor_start"); +    atom_gc_minor_end   = enif_make_atom(env,"gc_minor_end"); +    atom_gc_major_start = enif_make_atom(env,"gc_major_start"); +    atom_gc_major_end   = enif_make_atom(env,"gc_major_end"); + +    atom_old_heap_block_size = enif_make_atom(env,"old_heap_block_size");  +    atom_heap_block_size     = enif_make_atom(env,"heap_block_size"); + +    /* process 'proc' */ + +    atom_spawn = enif_make_atom(env,"spawn"); +    atom_exit = enif_make_atom(env,"exit"); +    atom_register = enif_make_atom(env,"register"); +    atom_unregister = enif_make_atom(env,"unregister"); +    atom_link = enif_make_atom(env,"link"); +    atom_unlink = enif_make_atom(env,"unlink"); +    atom_getting_unlinked = enif_make_atom(env,"getting_unlinked"); +    atom_getting_linked = enif_make_atom(env,"getting_linked"); + +    /* process 'running' and 'exiting' */ + +    atom_in = enif_make_atom(env,"in"); +    atom_out = enif_make_atom(env,"out"); +    atom_in_exiting = enif_make_atom(env,"in_exiting"); +    atom_out_exiting = enif_make_atom(env,"out_exiting"); +    atom_out_exited = enif_make_atom(env,"out_exited"); + +    /* process messages 'send' and 'receive' */ + +    atom_send = enif_make_atom(env,"send"); +    atom_receive = enif_make_atom(env,"receive"); +    atom_send_to_non_existing_process = enif_make_atom(env,"send_to_non_existing_process"); + +    /* ports 'ports' */ + +    atom_open = enif_make_atom(env,"open"); +    atom_closed = enif_make_atom(env,"closed"); + +    /* 'call' */ + +    atom_call = enif_make_atom(env,"call"); +    atom_return_from = enif_make_atom(env,"return_from"); +    atom_return_to = enif_make_atom(env,"return_to"); +    atom_exception_from = enif_make_atom(env,"exception_from"); +#endif +      return 0;  } @@ -125,3 +285,452 @@ static ERL_NIF_TERM user_trace_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar      return atom_error;  #endif  } + +static ERL_NIF_TERM enabled(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_LTTNG +    ASSERT(argc == 3); +    return atom_trace; +#endif +    return atom_remove; +} + +static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    return atom_ok; +} + +#ifdef HAVE_USE_LTTNG +static ERL_NIF_TERM enabled_garbage_collection(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); + +    if (argv[0] == atom_gc_minor_start && LTTNG_ENABLED(gc_minor_start)) { +        return atom_trace; +    } else if (argv[0] == atom_gc_minor_end && LTTNG_ENABLED(gc_minor_end)) { +        return atom_trace; +    } else if (argv[0] == atom_gc_major_start && LTTNG_ENABLED(gc_major_start)) { +        return atom_trace; +    } else if (argv[0] == atom_gc_major_end && LTTNG_ENABLED(gc_major_end)) { +        return atom_trace; +    } + +    return atom_discard; +} + +static ERL_NIF_TERM trace_garbage_collection(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    lttng_decl_procbuf(pid); +    ERL_NIF_TERM gci, tup; +    const ERL_NIF_TERM *vals; +    int arity; +    unsigned long ohbsz, nhbsz, size; + +    ASSERT(argc == 5); + +    /* Assume gc info order does not change */ +    gci = argv[3]; + +    /* get reclaimed or need */ +    enif_get_list_cell(env, gci, &tup, &gci); +    enif_get_tuple(env, tup, &arity, &vals); +    ASSERT(arity == 2); +    enif_get_ulong(env, vals[1], &size); + +    /* get old heap block size */ +    enif_get_list_cell(env, gci, &tup, &gci); +    enif_get_tuple(env, tup, &arity, &vals); +    ASSERT(arity == 2); +    ASSERT(vals[0] == atom_old_heap_block_size); +    enif_get_ulong(env, vals[1], &ohbsz); + +    /* get new heap block size */ +    enif_get_list_cell(env, gci, &tup, &gci); +    enif_get_tuple(env, tup, &arity, &vals); +    ASSERT(arity == 2); +    ASSERT(vals[0] == atom_heap_block_size); +    enif_get_ulong(env, vals[1], &nhbsz); + +    lttng_pid_to_str(argv[2], pid); + +    if (argv[0] == atom_gc_minor_start) { +        LTTNG4(gc_minor_start, pid, size, nhbsz, ohbsz); +    } else if (argv[0] == atom_gc_minor_end) { +        LTTNG4(gc_minor_end, pid, size, nhbsz, ohbsz); +    } else if (argv[0] == atom_gc_major_start) { +        LTTNG4(gc_major_start, pid, size, nhbsz, ohbsz); +    } else if (argv[0] == atom_gc_major_end) { +        LTTNG4(gc_major_end, pid, size, nhbsz, ohbsz); +    } +    return atom_ok; +} + +static ERL_NIF_TERM enabled_call(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); + +    if (argv[0] == atom_call && LTTNG_ENABLED(function_call)) +        return atom_trace; +    else if (argv[0] == atom_return_from && LTTNG_ENABLED(function_return)) +        return atom_trace; +    else if (argv[0] == atom_exception_from && LTTNG_ENABLED(function_exception)) +        return atom_trace; + +    return atom_discard; +} + +static ERL_NIF_TERM trace_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    lttng_decl_procbuf(pid); +    unsigned int len; +    char undef[] = "undefined"; + +    lttng_pid_to_str(argv[2], pid); + +    if (argv[0] == atom_call) { +        const ERL_NIF_TERM* tuple; +        int arity; +        lttng_decl_mfabuf(mfa); + +        if (enif_get_tuple(env, argv[3], &arity, &tuple)) { +            if (enif_is_list(env, tuple[2])) { +                enif_get_list_length(env, tuple[2], &len); +            } else { +                enif_get_uint(env, tuple[2], &len); +            } +            lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); +            LTTNG3(function_call, pid, mfa, 0); +        } else { +            LTTNG3(function_call, pid, undef, 0); +        } +    } else if (argv[0] == atom_return_from) { +        const ERL_NIF_TERM* tuple; +        int arity; +        lttng_decl_mfabuf(mfa); + +        if (enif_get_tuple(env, argv[3], &arity, &tuple)) { +            enif_get_uint(env, tuple[2], &len); +            lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); +            LTTNG3(function_return, pid, mfa, 0); +        } else { +            LTTNG3(function_return, pid, undef, 0); +        } +    } else if (argv[0] == atom_return_to) { +        const ERL_NIF_TERM* tuple; +        int arity; +        lttng_decl_mfabuf(mfa); + +        if (enif_get_tuple(env, argv[3], &arity, &tuple)) { +            enif_get_uint(env, tuple[2], &len); +            lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); +            LTTNG3(function_return, pid, mfa, 0); +        } else { +            LTTNG3(function_return, pid, undef, 0); +        } +    } else if (argv[0] == atom_exception_from) { +        const ERL_NIF_TERM* tuple; +        ERL_NIF_TERM extra; +        int arity; +        lttng_decl_mfabuf(mfa); +        char class[LTTNG_BUFFER_SZ]; + +        enif_get_map_value(env, argv[4], atom_extra, &extra); +        enif_get_tuple(env, extra, &arity, &tuple); +        enif_snprintf(class, LTTNG_BUFFER_SZ, "%T", tuple[0]); + +        if (enif_get_tuple(env, argv[3], &arity, &tuple)) { +            enif_get_uint(env, tuple[2], &len); +            lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); +            LTTNG3(function_exception, pid, mfa, class); +        } else { +            LTTNG3(function_exception, pid, undef, class); +        } +    } +    return atom_ok; +} + +static ERL_NIF_TERM enabled_send(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); +    if (LTTNG_ENABLED(message_send)) +        return atom_trace; + +    return atom_discard; +} + +static ERL_NIF_TERM trace_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    ERL_NIF_TERM extra; +    lttng_decl_procbuf(pid); +    lttng_pid_to_str(argv[2], pid); + +    enif_get_map_value(env, argv[4], atom_extra, &extra); + +    if (argv[0] == atom_send) { +        lttng_decl_procbuf(to); +        char msg[LTTNG_BUFFER_SZ]; + +        lttng_pid_to_str(extra, to); +        enif_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); + +        LTTNG3(message_send, pid, to, msg); +    } else if (argv[0] == atom_send_to_non_existing_process) { +        lttng_decl_procbuf(to); +        char msg[LTTNG_BUFFER_SZ]; + +        lttng_pid_to_str(extra, to); +        enif_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); +        /* mark it as non existing ? */ + +        LTTNG3(message_send, pid, to, msg); +    } +    return atom_ok; +} + +static ERL_NIF_TERM enabled_receive(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    if (LTTNG_ENABLED(message_receive)) +        return atom_trace; + +    return atom_discard; +} + +static ERL_NIF_TERM trace_receive(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    if (argv[0] == atom_receive) { +        lttng_decl_procbuf(pid); +        char msg[LTTNG_BUFFER_SZ]; + +        lttng_pid_to_str(argv[2], pid); +        enif_snprintf(msg, LTTNG_BUFFER_SZ, "%T", argv[3]); + +        LTTNG2(message_receive, pid, msg); +    } +    return atom_ok; +} + +static ERL_NIF_TERM enabled_procs(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); + +    if (argv[0] == atom_spawn && LTTNG_ENABLED(process_spawn)) { +        return atom_trace; +    } else if (argv[0] == atom_register && LTTNG_ENABLED(process_register)) { +        return atom_trace; +    } else if (argv[0] == atom_unregister && LTTNG_ENABLED(process_register)) { +        return atom_trace; +    } else if (argv[0] == atom_link && LTTNG_ENABLED(process_link)) { +        return atom_trace; +    } else if (argv[0] == atom_unlink && LTTNG_ENABLED(process_link)) { +        return atom_trace; +    } else if (argv[0] == atom_getting_linked && LTTNG_ENABLED(process_link)) { +        return atom_trace; +    } else if (argv[0] == atom_getting_unlinked && LTTNG_ENABLED(process_link)) { +        return atom_trace; +    } else if (argv[0] == atom_exit && LTTNG_ENABLED(process_exit)) { +        return atom_trace; +    } + +    return atom_discard; +} + +static ERL_NIF_TERM trace_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    lttng_decl_procbuf(pid); +    lttng_decl_procbuf(to); + +    lttng_pid_to_str(argv[2], pid); + +    /* spawn */ +    if (argv[0] == atom_spawn) { +        ERL_NIF_TERM extra; +        char undef[] = "undefined"; +        const ERL_NIF_TERM* tuple; +        int arity; +        unsigned int len; +        lttng_decl_mfabuf(mfa); + +        lttng_pid_to_str(argv[3], to); + +        enif_get_map_value(env, argv[4], atom_extra, &extra); + +        if (enif_get_tuple(env, extra, &arity, &tuple)) { +            if (enif_is_list(env, tuple[2])) { +                enif_get_list_length(env, tuple[2], &len); +            } else { +                enif_get_uint(env, tuple[2], &len); +            } +            lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); +            LTTNG3(process_spawn, to, pid, mfa); +        } else { +            LTTNG3(process_spawn, to, pid, undef); +        } + +    /* register */ +    } else if (argv[0] == atom_register) { +        char name[LTTNG_BUFFER_SZ]; +        enif_snprintf(name, LTTNG_BUFFER_SZ, "%T", argv[3]); +        LTTNG3(process_register, pid, name, "register"); +    } else if (argv[0] == atom_unregister) { +        char name[LTTNG_BUFFER_SZ]; +        enif_snprintf(name, LTTNG_BUFFER_SZ, "%T", argv[3]); +        LTTNG3(process_register, pid, name, "unregister"); +    /* link */ +    } else if (argv[0] == atom_link) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(process_link, pid, to, "link"); +    } else if (argv[0] == atom_unlink) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(process_link, pid, to, "unlink"); +    } else if (argv[0] == atom_getting_linked) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(process_link, to, pid, "link"); +    } else if (argv[0] == atom_getting_unlinked) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(process_link, to, pid, "unlink"); +    /* exit */ +    } else if (argv[0] == atom_exit) { +        char reason[LTTNG_BUFFER_SZ]; +        enif_snprintf(reason, LTTNG_BUFFER_SZ, "%T", argv[3]); +        LTTNG2(process_exit, pid, reason); +    } +    return atom_ok; +} + +static ERL_NIF_TERM enabled_ports(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); + +    if (argv[0] == atom_open && LTTNG_ENABLED(port_open)) { +        return atom_trace; +    } else if (argv[0] == atom_link && LTTNG_ENABLED(port_link)) { +        return atom_trace; +    } else if (argv[0] == atom_unlink && LTTNG_ENABLED(port_link)) { +        return atom_trace; +    } else if (argv[0] == atom_getting_linked && LTTNG_ENABLED(port_link)) { +        return atom_trace; +    } else if (argv[0] == atom_getting_unlinked && LTTNG_ENABLED(port_link)) { +        return atom_trace; +    } else if (argv[0] == atom_closed && LTTNG_ENABLED(port_exit)) { +        return atom_trace; +    } + +    return atom_discard; +} + +static ERL_NIF_TERM trace_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    lttng_decl_portbuf(port); +    lttng_decl_procbuf(to); + +    lttng_portid_to_str(argv[2], port); + +    /* open and closed */ +    if (argv[0] == atom_open) { +        ERL_NIF_TERM extra; +        char driver[LTTNG_BUFFER_SZ]; +        lttng_decl_procbuf(pid); +        lttng_pid_to_str(argv[3], pid); +        enif_get_map_value(env, argv[4], atom_extra, &extra); + +        enif_snprintf(driver, LTTNG_BUFFER_SZ, "%T", extra); +        LTTNG3(port_open, pid, driver, port); +    } else if (argv[0] == atom_closed) { +        char reason[LTTNG_BUFFER_SZ]; +        enif_snprintf(reason, LTTNG_BUFFER_SZ, "%T", argv[3]); + +        LTTNG2(port_exit, port, reason); +    /* link */ +    } else if (argv[0] == atom_link) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(port_link, port, to, "link"); +    } else if (argv[0] == atom_unlink) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(port_link, port, to, "unlink"); +    } else if (argv[0] == atom_getting_linked) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(port_link, to, port, "link"); +    } else if (argv[0] == atom_getting_unlinked) { +        lttng_pid_to_str(argv[3], to); +        LTTNG3(port_link, to, port, "unlink"); +    } +    return atom_ok; +} + +static ERL_NIF_TERM enabled_running_procs(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); + +    if (LTTNG_ENABLED(process_scheduled)) +        return atom_trace; +  +    return atom_discard; +} + +static ERL_NIF_TERM trace_running_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    lttng_decl_procbuf(pid); +    const ERL_NIF_TERM* tuple; +    char *mfastr = "undefined"; +    int arity; +    lttng_decl_mfabuf(mfa); + +    lttng_pid_to_str(argv[2], pid); + +    if (enif_get_tuple(env, argv[3], &arity, &tuple)) { +        int val; +        enif_get_int(env, tuple[2], &val); +        lttng_mfa_to_str(tuple[0], tuple[1], val, mfa); +        mfastr = mfa; +    } +    /* running processes */ +    if (argv[0] == atom_in) { +        LTTNG3(process_scheduled, pid, mfastr, "in"); +    } else if (argv[0] == atom_out) { +        LTTNG3(process_scheduled, pid, mfastr, "out"); +    /* exiting */ +    } else if (argv[0] == atom_in_exiting) { +        LTTNG3(process_scheduled, pid, mfastr, "in_exiting"); +    } else if (argv[0] == atom_out_exiting) { +        LTTNG3(process_scheduled, pid, mfastr, "out_exiting"); +    } else if (argv[0] == atom_out_exited) { +        LTTNG3(process_scheduled, pid, mfastr, "out_exited"); +    } + +    return atom_ok; +} + +static ERL_NIF_TERM enabled_running_ports(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) +{ +    ASSERT(argc == 3); + +    if (LTTNG_ENABLED(port_scheduled)) +        return atom_trace; + +    return atom_discard; +} + +static ERL_NIF_TERM trace_running_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +    lttng_decl_procbuf(pid); +    lttng_decl_mfabuf(where); + +    lttng_portid_to_str(argv[2], pid); +    enif_snprintf(where, LTTNG_BUFFER_SZ, "%T", argv[3]); + +    /* running  ports */ +    if (argv[0] == atom_in) { +        LTTNG3(port_scheduled, pid, where, "in"); +    } else if (argv[0] == atom_out) { +        LTTNG3(port_scheduled, pid, where, "out"); +        /* exiting */ +    } else if (argv[0] == atom_in_exiting) { +        LTTNG3(port_scheduled, pid, where, "in_exiting"); +    } else if (argv[0] == atom_out_exiting) { +        LTTNG3(port_scheduled, pid, where, "out_exiting"); +    } else if (argv[0] == atom_out_exited) { +        LTTNG3(port_scheduled, pid, where, "out_exited"); +    } +    return atom_ok; +} +#endif diff --git a/lib/runtime_tools/c_src/dyntrace_lttng.h b/lib/runtime_tools/c_src/dyntrace_lttng.h new file mode 100644 index 0000000000..5e838892d6 --- /dev/null +++ b/lib/runtime_tools/c_src/dyntrace_lttng.h @@ -0,0 +1,367 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2016. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + */ + +#undef TRACEPOINT_PROVIDER +#define TRACEPOINT_PROVIDER org_erlang_dyntrace + +#if !defined(DYNTRACE_LTTNG_H) || defined(TRACEPOINT_HEADER_MULTI_READ) +#define DYNTRACE_LTTNG_H + +#include <lttng/tracepoint.h> + +#define LTTNG1(Name, Arg1) \ +    tracepoint(org_erlang_dyntrace, Name, (Arg1)) + +#define LTTNG2(Name, Arg1, Arg2) \ +    tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2)) + +#define LTTNG3(Name, Arg1, Arg2, Arg3) \ +    tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3)) + +#define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) \ +    tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4)) + +#define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) \ +    tracepoint(org_erlang_dyntrace, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5)) + +#define LTTNG_ENABLED(Name) \ +    tracepoint_enabled(org_erlang_dyntrace, Name) + +#define LTTNG_BUFFER_SZ      (256) +#define LTTNG_PROC_BUFFER_SZ (16) +#define LTTNG_PORT_BUFFER_SZ (20) +#define LTTNG_MFA_BUFFER_SZ  (256) + +#define lttng_decl_procbuf(Name) \ +    char Name[LTTNG_PROC_BUFFER_SZ] + +#define lttng_decl_portbuf(Name) \ +    char Name[LTTNG_PORT_BUFFER_SZ] + +#define lttng_decl_mfabuf(Name) \ +    char Name[LTTNG_MFA_BUFFER_SZ] + +#define lttng_pid_to_str(pid, name) \ +    enif_snprintf(name, LTTNG_PROC_BUFFER_SZ, "%T", (pid)) + +#define lttng_portid_to_str(pid, name) \ +    enif_snprintf(name, LTTNG_PORT_BUFFER_SZ, "%T", (pid)) + +#define lttng_proc_to_str(p, name) \ +    lttng_pid_to_str(((p) ? (p)->common.id : ERTS_INVALID_PID), name) + +#define lttng_port_to_str(p, name) \ +    lttng_portid_to_str(((p) ? (p)->common.id : ERTS_INVALID_PORT), name) + +#define lttng_mfa_to_str(m,f,a, Name) \ +    enif_snprintf(Name, LTTNG_MFA_BUFFER_SZ, "%T:%T/%lu", (Eterm)(m), (Eterm)(f), (Uint)(a)) + +/* Process scheduling */ + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    process_spawn, +    TP_ARGS( +        char*, p, +        char*, parent, +        char*, mfa +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_string(parent, parent) +        ctf_string(entry, mfa) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    process_link, +    TP_ARGS( +        char*, from, +        char*, to, +        char*, type +    ), +    TP_FIELDS( +        ctf_string(from, from) +        ctf_string(to, to) +        ctf_string(type, type) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    process_exit, +    TP_ARGS( +        char*, p, +        char*, reason +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_string(reason, reason) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    process_register, +    TP_ARGS( +        char*, pid, +        char*, name, +        char*, type +    ), +    TP_FIELDS( +        ctf_string(pid, pid) +        ctf_string(name, name) +        ctf_string(type, type) +    ) +) + +/* Scheduled */ + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    process_scheduled, +    TP_ARGS( +        char*, p, +        char*, mfa, +        char*, type +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_string(entry, mfa) +        ctf_string(type, type) +    ) +) + +/* Ports */ + + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    port_open, +    TP_ARGS( +        char*, pid, +        char*, driver, +        char*, port +    ), +    TP_FIELDS( +        ctf_string(pid, pid) +        ctf_string(driver, driver) +        ctf_string(port, port) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    port_exit, +    TP_ARGS( +        char*, port, +        char*, reason +    ), +    TP_FIELDS( +        ctf_string(port, port) +        ctf_string(reason, reason) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    port_link, +    TP_ARGS( +        char*, from, +        char*, to, +        char*, type +    ), +    TP_FIELDS( +        ctf_string(from, from) +        ctf_string(to, to) +        ctf_string(type, type) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    port_scheduled, +    TP_ARGS( +        char*, p, +        char*, op, +        char*, type +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_string(entry, op) +        ctf_string(type, type) +    ) +) + +/* Call tracing */ + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    function_call, +    TP_ARGS( +        char*, pid, +        char*, mfa, +        unsigned int, depth +    ), +    TP_FIELDS( +        ctf_string(pid, pid) +        ctf_string(entry, mfa) +        ctf_integer(unsigned int, depth, depth) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    function_return, +    TP_ARGS( +        char*, pid, +        char*, mfa, +        unsigned int, depth +    ), +    TP_FIELDS( +        ctf_string(pid, pid) +        ctf_string(entry, mfa) +        ctf_integer(unsigned int, depth, depth) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    function_exception, +    TP_ARGS( +        char*, pid, +        char*, mfa, +        char*, type +    ), +    TP_FIELDS( +        ctf_string(pid, pid) +        ctf_string(entry, mfa) +        ctf_string(class, type) +    ) +) + +/* Process messages */ + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    message_send, +    TP_ARGS( +        char*, sender, +        char*, receiver, +        char*, msg +    ), +    TP_FIELDS( +        ctf_string(from, sender) +        ctf_string(to, receiver) +        ctf_string(message, msg) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    message_receive, +    TP_ARGS( +        char*, receiver, +        char*, msg +    ), +    TP_FIELDS( +        ctf_string(to, receiver) +        ctf_string(message, msg) +    ) +) + +/* Process Memory */ + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    gc_minor_start, +    TP_ARGS( +        char*, p, +        unsigned long, need, +        unsigned long, nh, +        unsigned long, oh +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_integer(unsigned long, need, need) +        ctf_integer(unsigned long, heap, nh) +        ctf_integer(unsigned long, old_heap, oh) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    gc_minor_end, +    TP_ARGS( +        char*, p, +        unsigned long, reclaimed, +        unsigned long, nh, +        unsigned long, oh +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_integer(unsigned long, reclaimed, reclaimed) +        ctf_integer(unsigned long, heap, nh) +        ctf_integer(unsigned long, old_heap, oh) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    gc_major_start, +    TP_ARGS( +        char*, p, +        unsigned long, need, +        unsigned long, nh, +        unsigned long, oh +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_integer(unsigned long, need, need) +        ctf_integer(unsigned long, heap, nh) +        ctf_integer(unsigned long, old_heap, oh) +    ) +) + +TRACEPOINT_EVENT( +    org_erlang_dyntrace, +    gc_major_end, +    TP_ARGS( +        char*, p, +        unsigned long, reclaimed, +        unsigned long, nh, +        unsigned long, oh +    ), +    TP_FIELDS( +        ctf_string(pid, p) +        ctf_integer(unsigned long, reclaimed, reclaimed) +        ctf_integer(unsigned long, heap, nh) +        ctf_integer(unsigned long, old_heap, oh) +    ) +) + +#endif /* DYNTRACE_LTTNG_H */ + +#undef TRACEPOINT_INCLUDE +#define TRACEPOINT_INCLUDE "./dyntrace_lttng.h" + +/* This part must be outside protection */ +#include <lttng/tracepoint-event.h> diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c index 08bace80ef..e7fd5968c1 100644 --- a/lib/runtime_tools/c_src/trace_file_drv.c +++ b/lib/runtime_tools/c_src/trace_file_drv.c @@ -1,18 +1,19 @@  /*   * %CopyrightBegin%   *  - * Copyright Ericsson AB 1999-2011. All Rights Reserved. + * Copyright Ericsson AB 1999-2016. 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License.   *    * %CopyrightEnd%   */ @@ -74,12 +75,8 @@  #ifdef DEBUG -#ifndef __WIN32__ -#define ASSERT(X) do {if (!(X)) {erl_exit(1,"%s",#X);} } while(0) -#else  #include <assert.h>  #define ASSERT(X) assert(X) -#endif  #else  #define ASSERT(X)  #endif @@ -175,6 +172,7 @@ static ErlDrvData trace_file_start(ErlDrvPort port, char *buff);  static void trace_file_stop(ErlDrvData handle);  static void trace_file_output(ErlDrvData handle, char *buff,  			      ErlDrvSizeT bufflen); +static void trace_file_outputv(ErlDrvData handle, ErlIOVec *ev);  static void trace_file_finish(void);  static ErlDrvSSizeT trace_file_control(ErlDrvData handle,  				      unsigned int command,  @@ -217,7 +215,7 @@ ErlDrvEntry trace_file_driver_entry = {      NULL,                  /* void * that is not used (BC) */      trace_file_control,    /* F_PTR control, port_control callback */      trace_file_timeout,    /* F_PTR timeout, driver_set_timer callback */ -    NULL,                  /* F_PTR outputv, reserved */ +    trace_file_outputv,    /* F_PTR outputv, reserved */      NULL, /* ready_async */      NULL, /* flush */      NULL, /* call */ @@ -326,9 +324,11 @@ static ErlDrvData trace_file_start(ErlDrvPort port, char *buff)  		   | O_BINARY  #endif  		   , 0777)) < 0) { +	int saved_errno = errno;  	if (wrap)  	    driver_free(wrap);  	driver_free(data); +	errno = saved_errno;  	return ERL_DRV_ERROR_ERRNO;      }  @@ -364,6 +364,16 @@ static void trace_file_stop(ErlDrvData handle)  /*  ** Data sent from erlang to port.  */ +static void trace_file_outputv(ErlDrvData handle, ErlIOVec *ev) +{ +    int i; +    for (i = 0; i < ev->vsize; i++) { +        if (ev->iov[i].iov_len) +            trace_file_output(handle, ev->iov[i].iov_base, +                              ev->iov[i].iov_len); +    } +} +  static void trace_file_output(ErlDrvData handle, char *buff,  			      ErlDrvSizeT bufflen)  { @@ -524,14 +534,19 @@ static void *my_alloc(size_t size)  ** A write wrapper that regards it as an error if not all data was written.  */  static int do_write(FILETYPE fd, unsigned char *buff, int siz) { -    int w = write(fd, buff, siz); -    if (w != siz) { -	if (w >= 0) { -	    errno = ENOSPC; +    int w; +    while (1) { +	w = write(fd, buff, siz); +	if (w < 0 && errno == EINTR) +	    continue; +	else if (w != siz) { +	    if (w >= 0) { +		errno = ENOSPC; +	    } +	    return -1;  	} -	return -1; +	return siz;      } -    return siz;  }  /* @@ -626,8 +641,10 @@ static void close_unlink_port(TraceFileData *data)  */  static int wrap_file(TraceFileData *data) {      if (my_flush(data) < 0) { +	int saved_errno = errno;  	close(data->fd);  	data->fd = -1; +	errno = saved_errno;  	return -1;      }      close(data->fd); @@ -643,12 +660,15 @@ static int wrap_file(TraceFileData *data) {  	next_name(&data->wrap->del);      }      next_name(&data->wrap->cur); +try_open:      data->fd = open(data->wrap->cur.name, O_WRONLY | O_TRUNC | O_CREAT  #ifdef O_BINARY  	      | O_BINARY  #endif  	      , 0777);      if (data->fd < 0) { +	if (errno == EINTR) +	    goto try_open;  	data->fd = -1;  	return -1;      } diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index 6b77128761..195558f958 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -1,18 +1,19 @@  /*   * %CopyrightBegin%   *  - * Copyright Ericsson AB 1999-2012. All Rights Reserved. + * Copyright Ericsson AB 1999-2016. 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License.   *    * %CopyrightEnd%   */ @@ -34,37 +35,17 @@  #include <stdlib.h>  #include <string.h>  #ifndef __WIN32__ -#    ifdef VXWORKS -#        include <sockLib.h> -#        include <sys/times.h> -#        include <iosLib.h> -#        include <taskLib.h> -#        include <selectLib.h> -#        include <ioLib.h> -#        include "reclaim.h" -#    endif  -#        include <unistd.h> -#        include <errno.h> -#        include <sys/types.h> -#        include <sys/socket.h> -#        include <netinet/in.h> -#        include <fcntl.h> +# include <unistd.h> +# include <errno.h> +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <fcntl.h>  #endif  #ifdef DEBUG -#    ifndef __WIN32__ -         /* erl_exit is not available to dll_drivers on windows. */ -         void erl_exit(int, char *, ...); -#        define ASSERT(X)                               \ -                    do {				\ -                        if (!(X)) {			\ -                            erl_exit(1,"%s",#X);	\ -                        } 				\ -                    } while(0)  -#    else  -#        include <assert.h> -#        define ASSERT(X) assert(X) -#    endif +#    include <assert.h> +#    define ASSERT(X) assert(X)  #else   #    define ASSERT(X)  #endif  @@ -393,6 +374,7 @@ static void trace_ip_output(ErlDrvData handle, char *buff, ErlDrvSizeT bufflen)  	}  	return;      } +    ASSERT(!IS_INVALID_SOCKET(data->fd));      if (data->que[data->questart] != NULL) {  	trace_ip_ready_output(handle, sock2event(data->fd));      } @@ -431,6 +413,7 @@ static void trace_ip_ready_input(ErlDrvData handle, ErlDrvEvent fd)  	/*  	** Maybe accept, we are a listen port...  	*/ +        ASSERT(IS_INVALID_SOCKET(data->fd));  	if (!IS_INVALID_SOCKET((client = my_accept(data->listenfd)))) {  	    data->fd = client;  	    set_nonblocking(client); @@ -754,6 +737,7 @@ static void close_client(TraceIpData *data)  {      my_driver_select(data, data->fd, FLAG_WRITE | FLAG_READ, SELECT_CLOSE);      data->flags |= FLAG_LISTEN_PORT; +    data->fd = INVALID_SOCKET;      if (!(data->flags & FLAG_FILL_ALWAYS)) {  	clean_que(data);      } @@ -910,7 +894,7 @@ static void stop_select(ErlDrvEvent event, void* _)      WSACloseEvent((HANDLE)event);  } -#else /* UNIX/VXWORKS */ +#else /* UNIX */  static int my_driver_select(TraceIpData *desc, SOCKET fd, int flags, enum MySelectOp op)  { | 
