commit 99bdd6f0727813454acab4a6629139acbfcf4c85
Author: Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
Date:   Tue Nov 6 20:08:51 2018 +0100

    Observer skeleton

diff --git a/Makefile.am b/Makefile.am
index 154f68f..6eaa7f3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,6 +8,7 @@ TOOLS =		memcheck \
 		callgrind \
 		massif \
 		lackey \
+		observer \
 		none \
 		helgrind \
 		drd
diff --git a/configure.ac b/configure.ac
index c18ae5f..9f04c62 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4640,6 +4640,9 @@ AC_CONFIG_FILES([
    massif/ms_print
    lackey/Makefile
    lackey/tests/Makefile
+   observer/Makefile
+   observer/docs/Makefile
+   observer/tests/Makefile
    none/Makefile
    none/tests/Makefile
    none/tests/scripts/Makefile
diff --git a/observer/Makefile.am b/observer/Makefile.am
new file mode 100644
index 0000000..c25e26d
--- /dev/null
+++ b/observer/Makefile.am
@@ -0,0 +1,56 @@
+include $(top_srcdir)/Makefile.tool.am
+
+EXTRA_DIST = docs/ob-manual.xml
+
+#----------------------------------------------------------------------------
+# observer-<platform>
+#----------------------------------------------------------------------------
+
+noinst_PROGRAMS  = observer-@VGCONF_ARCH_PRI@-@VGCONF_OS@
+if VGCONF_HAVE_PLATFORM_SEC
+noinst_PROGRAMS += observer-@VGCONF_ARCH_SEC@-@VGCONF_OS@
+endif
+
+OBSERVER_SOURCES_COMMON = ob_main.c
+
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_SOURCES      = \
+	$(OBSERVER_SOURCES_COMMON)
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CPPFLAGS     = \
+	$(AM_CPPFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS       = \
+	$(AM_CFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_DEPENDENCIES = \
+	$(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_PRI_CAPS@)
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDADD        = \
+	$(TOOL_LDADD_@VGCONF_PLATFORM_PRI_CAPS@)
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS      = \
+	$(TOOL_LDFLAGS_@VGCONF_PLATFORM_PRI_CAPS@)
+observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LINK = \
+	$(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
+	@VALT_LOAD_ADDRESS_PRI@ \
+	$(LINK) \
+	$(observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_CFLAGS) \
+	$(observer_@VGCONF_ARCH_PRI@_@VGCONF_OS@_LDFLAGS)
+
+if VGCONF_HAVE_PLATFORM_SEC
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_SOURCES      = \
+	$(OBSERVER_SOURCES_COMMON)
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CPPFLAGS     = \
+	$(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS       = \
+	$(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_DEPENDENCIES = \
+	$(TOOL_DEPENDENCIES_@VGCONF_PLATFORM_SEC_CAPS@)
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDADD        = \
+	$(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@)
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS      = \
+	$(TOOL_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
+observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LINK = \
+	$(top_builddir)/coregrind/link_tool_exe_@VGCONF_OS@ \
+	@VALT_LOAD_ADDRESS_SEC@ \
+	$(LINK) \
+	$(observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_CFLAGS) \
+	$(observer_@VGCONF_ARCH_SEC@_@VGCONF_OS@_LDFLAGS)
+endif
+
+
diff --git a/observer/docs/Makefile.am b/observer/docs/Makefile.am
new file mode 100644
index 0000000..86e90e4
--- /dev/null
+++ b/observer/docs/Makefile.am
@@ -0,0 +1 @@
+## Empty
diff --git a/observer/ob_main.c b/observer/ob_main.c
new file mode 100644
index 0000000..90a20af
--- /dev/null
+++ b/observer/ob_main.c
@@ -0,0 +1,132 @@
+#include "pub_tool_basics.h"    // needed by every tool
+#include "pub_tool_tooliface.h" // needed by every tool
+#include "pub_tool_libcprint.h" // for printing functions
+#include "pub_tool_machine.h"   // for VG_(fnptr_to_fnentry)
+
+// statistics on number of guest instructions executed
+static ULong n_guest_instrs  = 0;
+
+// Functions to be called by instrumentation.
+//
+// In Valgrind terminology, these are called "dirty helpers"
+// (dirty because they can have side effects).
+// To add an instruction for calling these helpers, use e.g.
+//
+//   IRExpr** argv = mkIRExprVec_2(Par1, Par2);
+//   IRDirty* di = unsafeIRDirty_0_N(
+//       2, /* regparms - accelerates parameter passing on x86 */
+//       "helperName",
+//       VG_(fnptr_to_fnentry)(helperFunction), argv);
+//   addStmtToIRSB(bb, IRStmt_Dirty(di));
+//
+// For more details about the intermediate representation (IR)
+// used by Valgrind as virtual instruction set (called "VEX"),
+// such as types, operations, statements, factory functions,
+// see "../VEX/pub/libvex_ir.h", or "../lackey/lk_main.c" for
+// example usage.
+
+
+// helper to increment statistics counter
+static void inc_guest_instr(void)
+{
+   n_guest_instrs++;
+}
+
+// helper to write information about guest memory stores
+//
+// VG_REGPARM(N): pass N (up to 3) arguments in registers on x86 --
+// more efficient than via stack. Ignored on other architectures.
+static VG_REGPARM(2)
+void trace_store(Addr addr, SizeT size)
+{
+    VG_(printf)("Store : %08lx, %lu\n", addr, size);
+}
+
+
+
+
+// Instrumentation function. "sbIn" is the code block passed in.
+// Other arguments are more obscure and often not needed -- see
+// include/pub_tool_tooliface.h.
+static
+IRSB* ob_instrument ( VgCallbackClosure* closure,
+		      IRSB* sbIn,
+		      const VexGuestLayout* layout,
+		      const VexGuestExtents* vge,
+		      const VexArchInfo* archinfo_host,
+		      IRType gWordTy, IRType hWordTy )
+{
+   Int i;
+   IRSB* sbOut;
+
+   /* Set up a copy of the input SB without the statements */
+   sbOut = deepCopyIRSBExceptStmts(sbIn);
+
+   // Copy verbatim any IR preamble preceding the first IMark
+   i = 0;
+   while (i < sbIn->stmts_used && sbIn->stmts[i]->tag != Ist_IMark) {
+      addStmtToIRSB( sbOut, sbIn->stmts[i] );
+      i++;
+   }
+
+   for (/*use current i*/; i < sbIn->stmts_used; i++) {
+      IRStmt* st = sbIn->stmts[i];
+      if (!st || st->tag == Ist_NoOp) continue;
+
+      // Any special instrumentation goes here
+      switch (st->tag) {
+      case Ist_IMark: {
+            // TODO: call to inc_guest_instr (see comment above!)
+         }
+	 break;
+      case Ist_Store: {
+            // TODO: call to trace_store with appropriate parameters.
+            // * use "st->Ist.Store.addr" for par1 (type is correct: IRExpr*)
+            // * use sizeofIRType(typeOfIRExpr(sbIn->tyenv, ... <IRExpr*> ))
+            //   to get the length of the data access for par2 as "Int".
+            //   Parameters need to be passed as IRExpr*, using IR type HWord.
+            //   Use mkIRExpr_HWord() to convert from Int to IRExpr*
+	 }
+	 break;
+      default:
+         break;
+      }
+
+      // always pass through original instruction
+      addStmtToIRSB( sbOut, st );
+   }
+
+   return sbOut;
+}
+
+// Finalization function
+static void ob_fini(Int exitcode)
+{
+   VG_(umsg)("Guest instructions executed: %'llu\n", n_guest_instrs);
+}
+
+// Post-option-processing initialization function
+static
+void ob_post_clo_init(void) { }
+
+// Pre-option-processing initialization function
+static void ob_pre_clo_init(void)
+{
+   // Required details for start-up message
+   VG_(details_name)            ("Observer");
+   VG_(details_version)         (NULL);
+   VG_(details_description)     ("an execution observer");
+   VG_(details_copyright_author)("Copyright (C) 2011, VT Hacker");
+   // Required detail for crash message
+   VG_(details_bug_reports_to) ("/dev/null");
+   // Name the required functions #2, #3 and #4.
+   VG_(basic_tool_funcs)        (ob_post_clo_init,
+                                 ob_instrument,
+                                 ob_fini);
+}
+
+
+// This prevents core/tool interface problems, and names the required
+// function #1, giving the core an entry point into the tool.
+VG_DETERMINE_INTERFACE_VERSION(ob_pre_clo_init)
+
diff --git a/observer/tests/Makefile.am b/observer/tests/Makefile.am
new file mode 100644
index 0000000..86e90e4
--- /dev/null
+++ b/observer/tests/Makefile.am
@@ -0,0 +1 @@
+## Empty
