Re: [RFC/FYI] reliable markers (hooks/probes/taps/...)

Werner Almesberger (wa@almesberger.net)
Fri, 4 Apr 2003 22:46:52 -0300


I wrote:
> Here's a pretty light-weight approach I call "reliable markers":

Turns out that the memory clobber didn't make them particularly
reliable. Here's a better version. Usage:

MARKER(label_name,var...);

Where var... is an optional comma-separated list of arguments or
variables that may be accessed (read or modified) while at this
breakpoint.

(This is just for demonstration. For serious use, one would generate
a markers.h that can handle more than just four arguments.)

- Werner

---------------------------------- cut here -----------------------------------

--- /dev/null Thu Aug 30 17:30:55 2001
+++ linux-2.5.66/include/linux/markers.h Fri Apr 4 20:36:39 2003
@@ -0,0 +1,134 @@
+/*
+ * include/linux/markers.h - Reliable code markers (labels)
+ *
+ * Written 2003 by Werner Almesberger, Caltech Netlab FAST project
+ */
+
+#ifndef _LINUX_MARKERS_H
+#define _LINUX_MARKERS_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_MARKERS
+
+/*
+ * __marker_clobber_* macros are machine-generated. If you need to change them,
+ * use the build process from umlsim, which generates the kernel header file as
+ * umlsim/lib/markers_kernel.h
+ *
+ * umlsim can be found at http://umlsim.sourceforge.net/
+ */
+
+/*
+ * The following construct iterates over a variable-length list of variable
+ * names, and converts them to the clobber syntax.
+ */
+
+#define __marker_clobber_do_0_end(...)
+#define __marker_clobber_do_1_end(...)
+#define __marker_clobber_do_2_end(...)
+#define __marker_clobber_do_3_end(...)
+#define __marker_clobber_do_4_end(...)
+#define __marker_clobber_do_0_(car,...) \
+ , "+m"(car) __marker_clobber_map_1((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_clobber_do_1_(car,...) \
+ , "+m"(car) __marker_clobber_map_2((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_clobber_do_2_(car,...) \
+ , "+m"(car) __marker_clobber_map_3((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_clobber_do_3_(car,...) \
+ , "+m"(car) __marker_clobber_map_4((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_clobber_do_4_(car,...) \
+ , "+m"(car) __marker_clobber_map_5((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_clobber_map_0(list,op,...) __marker_clobber_do_0_##op list
+#define __marker_clobber_map_1(list,op,...) __marker_clobber_do_1_##op list
+#define __marker_clobber_map_2(list,op,...) __marker_clobber_do_2_##op list
+#define __marker_clobber_map_3(list,op,...) __marker_clobber_do_3_##op list
+#define __marker_clobber_map_4(list,op,...) __marker_clobber_do_4_##op list
+
+/* redefine, without the comma */
+#undef __marker_clobber_do_0_
+#define __marker_clobber_do_0_(car,...) \
+ "+m"(car) __marker_clobber_map_1((__VA_ARGS__), ,##__VA_ARGS__ end)
+
+#define __marker_clobbers(...) \
+ __marker_clobber_map_0((__VA_ARGS__), ,##__VA_ARGS__ end)
+
+
+/*
+ * And another one: this one simply counts the number of arguments.
+ * We need this to skip past the clobbers in the asm statement.
+ *
+ * We can't use named arguments (supported starting with gcc 3.1), because
+ * trying to do so crashes gcc ...
+ */
+
+#define __marker_count_do_0_end(...) "0"
+#define __marker_count_do_1_end(...) "1"
+#define __marker_count_do_2_end(...) "2"
+#define __marker_count_do_3_end(...) "3"
+#define __marker_count_do_4_end(...) "4"
+#define __marker_count_do_0_(car,...) \
+ __marker_count_1((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_count_do_1_(car,...) \
+ __marker_count_2((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_count_do_2_(car,...) \
+ __marker_count_3((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_count_do_3_(car,...) \
+ __marker_count_4((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_count_do_4_(car,...) \
+ __marker_count_5((__VA_ARGS__), ,##__VA_ARGS__ end)
+#define __marker_count_0(list,op,...) __marker_count_do_0_##op list
+#define __marker_count_1(list,op,...) __marker_count_do_1_##op list
+#define __marker_count_2(list,op,...) __marker_count_do_2_##op list
+#define __marker_count_3(list,op,...) __marker_count_do_3_##op list
+#define __marker_count_4(list,op,...) __marker_count_do_4_##op list
+#define __marker_count(...) __marker_count_0((__VA_ARGS__), ,##__VA_ARGS__ end)
+
+
+/*
+ * __MARKER(name,args...) generates an entry in the ".dbg_markers" section with
+ * the following content:
+ *
+ * Offset Length (bytes)
+ * 0 4 marker address
+ * 4 4 pointer to function name (__func__) in .rodata
+ * 8 >1 file name (\0-terminated)
+ * var. 0-3 padding bytes (all zero, to speed up searches)
+ * var. >1 label name (\0-terminated)
+ * var. 0-3 padding bytes (all zero, to speed up searches)
+ *
+ * The (optional) list of arguments contains the names of variables that will
+ * be accessed from the debugger while the program is stopped at this
+ * breakpoint.
+ */
+
+
+#define __MARKER(name,...) \
+ __asm__ __volatile__( \
+ "1:\n" \
+ "\t.pushsection .dbg_markers,\"\",@progbits\n" \
+ "\t.long 1b\n" \
+ "\t.long %" __marker_count(__VA_ARGS__) "\n" \
+ "\t.asciz \"" __FILE__ "\"\n" \
+ "\t.align 4,0\n" \
+ "\t.asciz \"" #name "\"\n" \
+ "\t.align 4,0\n" \
+ "\t.popsection\n" \
+ : __marker_clobbers(__VA_ARGS__) : [fn] "m" (*__func__) : "memory")
+
+/*
+ * MARKER protects __MARKER against multiple uses of the same marker name
+ * within the same function.
+ */
+
+#define MARKER(name,...) \
+ do { __marker_##name: __attribute__((unused)) \
+ __MARKER(name,__VA_ARGS__); } while (0)
+
+#else /* CONFIG_MARKERS */
+
+#define MARKER(...)
+
+#endif /* !CONFIG_MARKERS */
+
+#endif /* _LINUX_MARKERS_H */
--- linux-2.5.66/net/core/dev.c.orig Thu Apr 3 03:17:21 2003
+++ linux-2.5.66/net/core/dev.c Fri Apr 4 21:30:27 2003
@@ -107,6 +107,7 @@
#include <linux/kmod.h>
#include <linux/module.h>
#include <linux/kallsyms.h>
+#include <linux/markers.h>
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Note : will define WIRELESS_EXT */
#include <net/iw_handler.h>
@@ -1471,6 +1472,7 @@
int ret = NET_RX_DROP;
unsigned short type = skb->protocol;

+ MARKER(entry,skb);
if (!skb->stamp.tv_sec)
do_gettimeofday(&skb->stamp);

--- linux-2.5.66/arch/um/Kconfig.orig Thu Apr 3 03:50:05 2003
+++ linux-2.5.66/arch/um/Kconfig Thu Apr 3 04:20:43 2003
@@ -363,5 +363,29 @@
If you're involved in UML kernel development and want to use gcov,
say Y. If you're unsure, say N.

+config UMLSIM
+ bool "Enable umlsim support"
+ default n
+ help
+ umlsim uses a UML kernel for event-driven simulations. This
+ option adds code to support virtual time (boot command-line
+ option 'vtime'), and to inform the umlsim control program
+ when the kernel is idle.
+
+ A kernel containing umlsim support can also be used without
+ virtual time and umlsim.
+
+ See <http://umlsim.sourceforge.net/> for more details.
+
+config MARKERS
+ bool "Enable reliable markers"
+ default UMLSIM
+ help
+ Reliable markers are used to mark potential breakpoint locations.
+ Debuggers (or debugger-like programs, such as umlsim) need
+ specific code if they want to use reliable markers.
+
+ If you're not using umlsim, you probably want to say N. If you're
+ using this kernel with umlsim, say Y.
endmenu

--- linux-2.5.66/arch/um/drivers/daemon_kern.c.orig Thu Apr 3 04:26:47 2003
+++ linux-2.5.66/arch/um/drivers/daemon_kern.c Fri Apr 4 21:30:58 2003
@@ -9,6 +9,7 @@
#include "linux/init.h"
#include "linux/netdevice.h"
#include "linux/etherdevice.h"
+#include "linux/markers.h"
#include "net_kern.h"
#include "net_user.h"
#include "daemon.h"
@@ -54,6 +55,7 @@
static int daemon_write(int fd, struct sk_buff **skb,
struct uml_net_private *lp)
{
+ MARKER(entry,skb);
return(daemon_user_write(fd, (*skb)->data, (*skb)->len,
(struct daemon_data *) &lp->user));
}

-- 
  _________________________________________________________________________
 / Werner Almesberger, Buenos Aires, Argentina         wa@almesberger.net /
/_http://www.almesberger.net/____________________________________________/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/