❦  7 mai 2014 11:15 +0200, Willy Tarreau <[email protected]> :

>> haproxy does not include DTrace probes by any chance right? :)
>
> No, and I have no idea how this works either. But if you feel like it
> can provide some value and be done without too much effort, feel free
> to try :-)

Here is a proof of concept. To test, use `make TARGET=linux2628
USE_DTRACE=1`. On Linux, you need systemtap-sdt-dev or something like
that. Then, there is a quick example in example/haproxy.stp. You can try
it like this:

#+begin_src sh
sudo stap  ./examples/haproxy.stp
#+end_src

It is possible to convert the probes.d to a tapset (which is a recipe
for systemtap) to be able to name arguments and convert them in the
appropriate type. I am using this AWK script:
 
https://github.com/vincentbernat/lldpd/blob/master/src/daemon/dtrace2systemtap.awk

Only works with simple probes.

For dtrace, this would be something like that but I cannot test right
now:

#+begin_src dtrace
haproxy$target:::frontend_accept
{
   printf("Frontend %s accepted a connection", copyinstr(arg0));
}
#+end_src

The trick with those tracepoints is that they are just NOOP until you
enable them. So, even when someone compiles dtrace support, they will
not have any performance impact until trying to use the tracepoints.

While the probe arguments can be anything, it is simpler to only keep
simple types like null-terminated strings or int. Otherwise, they are
difficult to exploit. If you put struct, without the debug symbols, the
data is not exploitable.

Now, all the hard work is to put trace points everywhere. A good target
is where stuff are logged. But they can also be put in places where logs
would be too verbose. I currently don't have interest in doing that but
if someone is willing too, it is only a matter of defining the probes in
probes.d and placing them in the C code. This is really nifty to debug
stuff in production. However, I think that people interested in that can
also use debug symbols to place probe at any place they want to. GCC is
now better at providing debug symbols which work on optimized
executables. Ubuntu is providing debug symbols for almost
everything. Tracepoints are still interesting as they can be listed and
they are hand-picked.

>From 504504f2f8c13f077f09e0906cd7e7d3ca405acc Mon Sep 17 00:00:00 2001
From: Vincent Bernat <[email protected]>
Date: Wed, 7 May 2014 18:18:07 +0200
Subject: [PATCH] MINOR: dtrace: add dtrace support (WIP)

Both dtrace and systemtap are supported. Currently, only one tracepoint
is defined.
---
 .gitignore             |  1 +
 Makefile               | 18 +++++++++++++++++-
 examples/haproxy.stp   |  3 +++
 include/common/debug.h |  8 ++++++++
 src/frontend.c         |  2 ++
 src/probes.d           | 21 +++++++++++++++++++++
 6 files changed, 52 insertions(+), 1 deletion(-)
 create mode 100644 examples/haproxy.stp
 create mode 100644 src/probes.d

diff --git a/.gitignore b/.gitignore
index ec1545a7a3df..c13934c19835 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ make-*
 dlmalloc.c
 00*.patch
 *.service
+include/common/probes.h
diff --git a/Makefile b/Makefile
index f95ba03ac60f..617ab4447e69 100644
--- a/Makefile
+++ b/Makefile
@@ -33,6 +33,7 @@
 #   USE_ZLIB             : enable zlib library support.
 #   USE_CPU_AFFINITY     : enable pinning processes to CPU on Linux. Automatic.
 #   USE_TFO              : enable TCP fast open. Supported on Linux >= 3.7.
+#   USE_DTRACE           : enable DTrace/systemtap support
 #
 # Options can be forced by specifying "USE_xxx=1" or can be disabled by using
 # "USE_xxx=" (empty string).
@@ -582,6 +583,12 @@ OPTIONS_CFLAGS  += -DUSE_TFO
 BUILD_OPTIONS   += $(call ignore_implicit,USE_TFO)
 endif
 
+# DTrace
+ifneq ($(USE_DTRACE),)
+DTRACE = dtrace
+OPTIONS_CFLAGS  += -DUSE_DTRACE
+endif
+
 # This one can be changed to look for ebtree files in an external directory
 EBTREE_DIR := ebtree
 
@@ -655,6 +662,10 @@ EBTREE_OBJS = $(EBTREE_DIR)/ebtree.o \
 ifneq ($(TRACE),)
 OBJS += src/trace.o
 endif
+ifneq ($(USE_DTRACE),)
+OBJS += src/probes.o
+$(OBJS): | include/common/probes.h
+endif
 
 WRAPPER_OBJS = src/haproxy-systemd-wrapper.o
 
@@ -679,6 +690,11 @@ objsize: haproxy
 src/trace.o: src/trace.c
 	$(CC) $(TRACE_COPTS) -c -o $@ $<
 
+include/common/probes.h: src/probes.d
+	$(DTRACE) -C -h -s $< -o $@
+src/probes.o: src/probes.d
+	$(DTRACE) -C -G -s $< -o $@
+
 src/haproxy.o:	src/haproxy.c
 	$(CC) $(COPTS) \
 	      -DBUILD_TARGET='"$(strip $(TARGET))"' \
@@ -715,7 +731,7 @@ install-bin: haproxy haproxy-systemd-wrapper
 install: install-bin install-man install-doc
 
 clean:
-	rm -f *.[oas] src/*.[oas] ebtree/*.[oas] haproxy test
+	rm -f *.[oas] src/*.[oas] ebtree/*.[oas] haproxy test include/common/probes.h
 	for dir in . src include/* doc ebtree; do rm -f $$dir/*~ $$dir/*.rej $$dir/core; done
 	rm -f haproxy-$(VERSION).tar.gz haproxy-$(VERSION)$(SUBVERS).tar.gz
 	rm -f haproxy-$(VERSION) haproxy-$(VERSION)$(SUBVERS) nohup.out gmon.out
diff --git a/examples/haproxy.stp b/examples/haproxy.stp
new file mode 100644
index 000000000000..1ef59dbfe41b
--- /dev/null
+++ b/examples/haproxy.stp
@@ -0,0 +1,3 @@
+probe process("./haproxy").provider("haproxy").mark("frontend_accept") {
+    printf("Frontend %s accepted a connection\n", user_string($arg1));
+}
diff --git a/include/common/debug.h b/include/common/debug.h
index fe05a444a8df..a6cd01d61fd5 100644
--- a/include/common/debug.h
+++ b/include/common/debug.h
@@ -54,5 +54,13 @@
 		##args);                                           \
         } while (0)
 
+#ifdef USE_DTRACE
+# include "probes.h"
+# define DTRACE(probe) probe
+# define DTRACE_ENABLED(probe) probe ## _ENABLED()
+#else
+# define DTRACE(probe)
+# define DTRACE_ENABLED(probe) (0)
+#endif
 
 #endif /* _COMMON_DEBUG_H */
diff --git a/src/frontend.c b/src/frontend.c
index f94c6ab2b231..e56bada5a47e 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -57,6 +57,8 @@ int frontend_accept(struct session *s)
 	struct connection *conn = __objt_conn(s->si[0].end);
 	int cfd = conn->t.sock.fd;
 
+        DTRACE(HAPROXY_FRONTEND_ACCEPT(s->fe->id));
+
 	tv_zero(&s->logs.tv_request);
 	s->logs.t_queue = -1;
 	s->logs.t_connect = -1;
diff --git a/src/probes.d b/src/probes.d
new file mode 100644
index 000000000000..15b140569b72
--- /dev/null
+++ b/src/probes.d
@@ -0,0 +1,21 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Functions used to parse typed argument lists
+ *
+ * Copyright 2014 Willy Tarreau <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+provider haproxy {
+
+	/**
+	 * Fired when a frontend accepts a connection.
+	 * @param frontend the name of the frontend
+	 */
+	probe frontend_accept(const char *frontend);
+}
-- 
2.0.0.rc2

-- 
printk("??? No FDIV bug? Lucky you...\n");
        2.2.16 /usr/src/linux/include/asm-i386/bugs.h

Reply via email to