[lttng-dev] [RFC PATCH lttng-tools 2/2] Implement dynamic instrumentation with dyninst

Zifei Tong soariez at gmail.com
Wed Sep 4 07:00:41 EDT 2013


This patch provides a *very* basic implementation of dynamic
instrumentation support using dyninst library. More tests and
refactoring need to be done.

An explicit type conversion added in rculfhash-internal.h to make the
code compile with C++ compilers.

Macros _GNU_SOURCE are wrapped with guards to bypass g++ warning:
"_GNU_SOURCE" redefined

Automake will choose g++ as linker if a c++ source file appears in the
SOURCES list conditionally regardless the actually value of condition
variable. This will prevent lttng-tools compiling without a c++ compiler.
Thus we should manually choose a proper linker in Makefile.am.

See: http://permalink.gmane.org/gmane.comp.sysutils.automake.bugs/4184

You can also view the patch at:
https://github.com/5kg/lttng-tools/commit/fc2ca02a6915a4da513d47c7386e4a13f6629538
---
 configure.ac                                      |  16 +++
 src/bin/lttng-sessiond/Makefile.am                |  12 ++
 src/bin/lttng-sessiond/ust-instrument-dyninst.cpp | 142 ++++++++++++++++++++++
 src/common/hashtable/rculfhash-internal.h         |   2 +-
 src/common/sessiond-comm/inet.h                   |   2 +
 src/common/sessiond-comm/inet6.h                  |   2 +
 src/common/sessiond-comm/sessiond-comm.h          |   2 +
 src/common/sessiond-comm/unix.h                   |   2 +
 tests/unit/Makefile.am                            |   9 ++
 9 files changed, 188 insertions(+), 1 deletion(-)
 create mode 100644 src/bin/lttng-sessiond/ust-instrument-dyninst.cpp

diff --git a/configure.ac b/configure.ac
index 32efa93..f616465 100644
--- a/configure.ac
+++ b/configure.ac
@@ -293,8 +293,24 @@ AX_CONFIG_FEATURE(
 )
 AM_CONDITIONAL([COMPAT_EPOLL], [ test "$enable_epoll" = "yes" ])
 
+# Option to build with dyninst
+# TODO: support custom prefix
+AC_ARG_WITH([dyninst],
+	AS_HELP_STRING([--with-dyninst],[Build with dyninst library [default=no]]),
+	[has_dyninst=$withval],
+	[has_dyninst=no])
+
+# TODO: check library and header
+AS_IF([test "x$has_dyninst" != "xno"], [
+	AC_DEFINE([HAVE_DYNINST], [1], [has dyninst library])
+	AC_DEFINE([HAVE_UST_INSTRUMENT_PROBE], [1], [have ust instrument probe])
+	build_with_dyninst=yes
+])
+AM_CONDITIONAL([HAVE_DYNINST], [test "x$build_with_dyninst" = "xyes"])
+
 AC_SYS_LARGEFILE
 AC_PROG_CC
+AC_PROG_CXX
 LT_INIT
 AC_PROG_YACC
 AC_PROG_LEX
diff --git a/src/bin/lttng-sessiond/Makefile.am b/src/bin/lttng-sessiond/Makefile.am
index dce17cb..4d6779c 100644
--- a/src/bin/lttng-sessiond/Makefile.am
+++ b/src/bin/lttng-sessiond/Makefile.am
@@ -33,6 +33,9 @@ if HAVE_LIBLTTNG_UST_CTL
 lttng_sessiond_SOURCES += trace-ust.c ust-registry.c ust-app.c \
 			ust-consumer.c ust-consumer.h ust-thread.c \
 			ust-metadata.c ust-clock.h
+if HAVE_DYNINST
+lttng_sessiond_SOURCES += ust-instrument-dyninst.cpp
+endif
 endif
 
 # Add main.c at the end for compile order
@@ -51,4 +54,13 @@ lttng_sessiond_LDADD = -lrt -lurcu-common -lurcu \
 
 if HAVE_LIBLTTNG_UST_CTL
 lttng_sessiond_LDADD += -llttng-ust-ctl
+if HAVE_DYNINST
+lttng_sessiond_LDADD += -ldyninstAPI
+endif
+endif
+
+if HAVE_DYNINST
+lttng_sessiond_LINK = $(CXXLINK)
+else
+lttng_sessiond_LINK = $(LINK)
 endif
diff --git a/src/bin/lttng-sessiond/ust-instrument-dyninst.cpp b/src/bin/lttng-sessiond/ust-instrument-dyninst.cpp
new file mode 100644
index 0000000..76fa345
--- /dev/null
+++ b/src/bin/lttng-sessiond/ust-instrument-dyninst.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2013 - Zifei Tong <soariez at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <dyninst/BPatch.h>
+#include <dyninst/BPatch_object.h>
+#include <dyninst/BPatch_function.h>
+#include <dyninst/BPatch_point.h>
+#include <dyninst/Symtab.h>
+
+extern "C" {
+#include "ust-app.h"
+#include "ust-instrument.h"
+}
+
+namespace {
+
+BPatch_object* findMatchObject(BPatch_image* image, const char* path)
+{
+	std::vector<BPatch_object*> objects;
+	image->getObjects(objects);
+	for (int i = 0; i < objects.size(); i++) {
+		if (objects[i]->pathName() == path) {
+			return objects[i];
+		}
+	}
+	return NULL;
+}
+
+}
+
+int ust_instrument_probe(struct ust_app* app,
+		const char* object_path,
+		const char* name,
+		enum lttng_ust_instrumentation instrumentation,
+		uint64_t addr,
+		const char *symbol,
+		uint64_t offset)
+{
+	BPatch bpatch;
+	BPatch_process *proc = bpatch.processAttach(object_path, app->pid);
+	BPatch_image *image = proc->getImage();
+	int ret;
+
+	BPatch_object *object = findMatchObject(image, object_path);
+	if (object == NULL) {
+		ERR("Can not find object %s in process %d", object_path, app->pid);
+		proc->detach(true);
+		return -1;
+	}
+
+	Dyninst::Address address;
+	if (symbol[0] != '\0') {
+		/* symbol+offset provided */
+		Dyninst::SymtabAPI::Symtab *symtab = Dyninst::SymtabAPI::convert(object);
+		std::vector<Dyninst::SymtabAPI::Symbol *> symbols;
+		ret = symtab->findSymbol(symbols, name,
+				Dyninst::SymtabAPI::Symbol::ST_UNKNOWN);
+
+		if (!ret) {
+			ERR("Can not find symbol %s in process %d", symbol, app->pid);
+			proc->detach(true);
+			return -1;
+		}
+		if (symbols.size() > 1) {
+			ERR("Multiple instances of symbol %s founded in process %d", symbol, app->pid);
+			proc->detach(true);
+			return -1;
+		}
+		address = object->fileOffsetToAddr(symbols[0]->getOffset() + offset);
+	} else {
+		/* addr (offset) provided */
+		address = object->fileOffsetToAddr(addr);
+	}
+
+	std::vector<BPatch_point*> points;
+	std::vector<BPatch_function *> functions;
+	std::vector<BPatch_point *>* func_points;
+	switch (instrumentation) {
+	case LTTNG_UST_PROBE:
+		image->findPoints(address, points);
+	case LTTNG_UST_FUNCTION:
+		image->findFunction(address, functions);
+		if (functions.size() > 1) {
+			ERR("Multiple functions founded in process %d", symbol, app->pid);
+			proc->detach(true);
+			return -1;
+		}
+
+		func_points = functions[0]->findPoint(BPatch_entry);
+		points.insert(points.end(), func_points->begin(), func_points->end());
+		func_points = functions[0]->findPoint(BPatch_exit);
+		points.insert(points.end(), func_points->begin(), func_points->end());
+	default:
+		ERR("Multiple instances of symbol %s founded in process %d", symbol, app->pid);
+		proc->detach(true);
+		return -1;
+	}
+
+	std::vector<BPatch_function *> probes;
+	/* For now, assume there is a function wrap the tracepoint, e.g.
+	 * void tptest() { tracepoint(tptest); }
+	*/
+	image->findFunction(name, probes);
+	if (probes.size() == 0) {
+		ERR("Can not find probe wrapper %s in process %d", name, app->pid);
+		proc->detach(true);
+		return -1;
+	}
+	if (probes.size() > 1) {
+		ERR("Multiple instances of probe wrapper %s founded in process %d", name, app->pid);
+		proc->detach(true);
+		return -1;
+	}
+
+	std::vector<BPatch_snippet*> args;
+	BPatch_funcCallExpr call_probe(*probes[0], args);
+
+	for (int i = 0; i < points.size(); i++) {
+		if (proc->insertSnippet(call_probe, *points[i]) == NULL) {
+			ERR("Insert snippet failed in process %d", name, app->pid);
+			proc->detach(true);
+			return -1;
+		}
+	}
+
+	proc->detach(true);
+	return 0;
+}
diff --git a/src/common/hashtable/rculfhash-internal.h b/src/common/hashtable/rculfhash-internal.h
index e3a59ba..5030779 100644
--- a/src/common/hashtable/rculfhash-internal.h
+++ b/src/common/hashtable/rculfhash-internal.h
@@ -168,7 +168,7 @@ struct cds_lfht *__default_alloc_cds_lfht(
 {
 	struct cds_lfht *ht;
 
-	ht = calloc(1, cds_lfht_size);
+	ht = (struct cds_lfht *) calloc(1, cds_lfht_size);
 	assert(ht);
 
 	ht->mm = mm;
diff --git a/src/common/sessiond-comm/inet.h b/src/common/sessiond-comm/inet.h
index 89716b8..3e8bdbe 100644
--- a/src/common/sessiond-comm/inet.h
+++ b/src/common/sessiond-comm/inet.h
@@ -18,7 +18,9 @@
 #ifndef _LTTCOMM_INET_H
 #define _LTTCOMM_INET_H
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 #include <limits.h>
 
 #include "sessiond-comm.h"
diff --git a/src/common/sessiond-comm/inet6.h b/src/common/sessiond-comm/inet6.h
index 4cb4dca..7fb8450 100644
--- a/src/common/sessiond-comm/inet6.h
+++ b/src/common/sessiond-comm/inet6.h
@@ -18,7 +18,9 @@
 #ifndef _LTTCOMM_INET6_H
 #define _LTTCOMM_INET6_H
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 #include <limits.h>
 
 #include "sessiond-comm.h"
diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h
index 294e185..2b233f9 100644
--- a/src/common/sessiond-comm/sessiond-comm.h
+++ b/src/common/sessiond-comm/sessiond-comm.h
@@ -25,7 +25,9 @@
 #ifndef _LTTNG_SESSIOND_COMM_H
 #define _LTTNG_SESSIOND_COMM_H
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 #include <limits.h>
 #include <lttng/lttng.h>
 #include <lttng/snapshot-internal.h>
diff --git a/src/common/sessiond-comm/unix.h b/src/common/sessiond-comm/unix.h
index 19b91ce..f3f98b5 100644
--- a/src/common/sessiond-comm/unix.h
+++ b/src/common/sessiond-comm/unix.h
@@ -18,7 +18,9 @@
 #ifndef _LTTCOMM_UNIX_H
 #define _LTTCOMM_UNIX_H
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 #include <limits.h>
 #include <sys/un.h>
 
diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am
index f517fdc..474db14 100644
--- a/tests/unit/Makefile.am
+++ b/tests/unit/Makefile.am
@@ -57,10 +57,19 @@ UST_DATA_TRACE=$(top_builddir)/src/bin/lttng-sessiond/trace-ust.o \
 		   $(top_builddir)/src/common/.libs/uri.o \
 		   $(top_builddir)/src/common/.libs/utils.o
 
+if HAVE_DYNINST
+UST_DATA_TRACE += $(top_builddir)/src/bin/lttng-sessiond/ust-instrument-dyninst.o
+endif
+
 test_ust_data_SOURCES = test_ust_data.c
 test_ust_data_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBSESSIOND_COMM) $(LIBHASHTABLE) \
 					  -lrt -llttng-ust-ctl
 test_ust_data_LDADD += $(UST_DATA_TRACE)
+
+if HAVE_DYNINST
+test_ust_data_LDADD += -lstdc++ -ldyninstAPI
+endif
+
 endif
 
 # Kernel data structures unit test
-- 
1.8.4




More information about the lttng-dev mailing list