]> Zhao Yanbai Git Server - minix.git/commitdiff
libvassert: vmware VAssert support.
authorBen Gras <ben@minix3.org>
Wed, 22 Jun 2011 15:22:57 +0000 (17:22 +0200)
committerBen Gras <ben@minix3.org>
Thu, 28 Jul 2011 03:23:10 +0000 (03:23 +0000)
- BSD-licensed Code gratefully taken from the project at
  http://en.sourceforge.jp/projects/sfnet_vassertlinuxsdk/

- For more information on vmware VAssert, a powerful debugging
  facility usable under vmware, see:
  www.vmware.com/pdf/ws65_vassert_programming.pdf

lib/Makefile
lib/libvassert/Makefile [new file with mode: 0644]
lib/libvassert/backdoor.S [new file with mode: 0644]
lib/libvassert/vassert.c [new file with mode: 0644]
lib/libvassert/vassert.h [new file with mode: 0644]

index afa06c13bcc764345d8d0c6ecd7fc90cc77909bf..7b884d597ea98e32b11c641d7403170ea6a739f5 100644 (file)
@@ -21,7 +21,7 @@ SUBDIR= csu ${LIBCOMPAT_DIR} ${LIBC_DIR} libdriver libnetdriver \
        libddekit
 
 .if defined(NBSD_LIBC) && (${NBSD_LIBC} != "no")
-SUBDIR+= libelf libminc libcrypt libterminfo libcurses
+SUBDIR+= libelf libminc libcrypt libterminfo libcurses libvassert
 .endif
 
 .if ${COMPILER_TYPE} == "ack"
diff --git a/lib/libvassert/Makefile b/lib/libvassert/Makefile
new file mode 100644 (file)
index 0000000..6a022c9
--- /dev/null
@@ -0,0 +1,8 @@
+# Makefile for libvassert library
+
+LIB=    vassert
+SRCS=  backdoor.S vassert.c
+INCS+= vassert.h
+INCSDIR= /usr/include/minix
+
+.include <bsd.lib.mk>
diff --git a/lib/libvassert/backdoor.S b/lib/libvassert/backdoor.S
new file mode 100644 (file)
index 0000000..2973e26
--- /dev/null
@@ -0,0 +1,22 @@
+
+.global libvassert_process_backdoor 
+
+libvassert_process_backdoor:
+       push   %ebx
+       push   %esi
+       mov    0xc(%esp),%ecx
+       mov    0x14(%esp),%edx
+       mov    0x10(%esp),%ebx
+       mov    $0x564d5868,%eax
+       out    %eax,(%dx)
+       mov    0x18(%esp),%esi
+       mov    %eax,(%esi)
+       mov    0x20(%esp),%eax
+       mov    %ecx,(%eax)
+       mov    0x24(%esp),%eax
+       mov    %edx,(%eax)
+       mov    0x1c(%esp),%eax
+       mov    %ebx,(%eax)
+       pop    %esi
+       pop    %ebx
+       ret
diff --git a/lib/libvassert/vassert.c b/lib/libvassert/vassert.c
new file mode 100644 (file)
index 0000000..3720551
--- /dev/null
@@ -0,0 +1,298 @@
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <minix/config.h>
+#include <minix/const.h>
+#include <minix/ipc.h>
+#include <minix/com.h>
+#include "vassert.h"
+
+VAssert_StateWrapper vassert_state ALIGNED(VASSERT_PAGE_SIZE);
+
+#define TRUE 1
+#define FALSE 0
+
+#define MAGIC_CMD  0x564d5868
+#define MAGIC_PORT 0x5658
+#define HIGH_BAND_PORT 0x5659
+
+#define BACKDOOR_PORT          51
+#define BACKDOOR_HB_PORT       1
+#define CMD_SET_ADDRESS        BACKDOOR_PORT|(1<<16)
+#define CMD_RETURN_REPLAY      BACKDOOR_PORT|(2<<16)
+#define CMD_GO_LIVE            BACKDOOR_PORT|(3<<16)
+#define CMD_LOG                        BACKDOOR_HB_PORT|(4<<16)
+#define CMD_SET_RECORD         47
+
+#define LOG_MAX 512
+
+typedef char Bool;
+typedef unsigned int uint32;
+typedef unsigned long long uint64;
+
+#ifdef VM_X86_64
+typedef uint64 VA;
+#else
+typedef uint32 VA;
+#endif
+
+static sigjmp_buf segv_jmp;
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * sig_segv --
+ * 
+ *    Customed SEGV signal handler for VAssert_IsInVM.
+ *
+ * Results:
+ *
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+static void
+sig_segv(int sig_no)
+{
+   /* jumping to error handling in VAssert_IsInVM. */
+   siglongjmp(segv_jmp, 1);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_IsInVM --
+ * 
+ *    Check if we are in virtual world.
+ *
+ * Results:
+ *
+ *    Return TRUE on success, or FALSE on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *---------------------------------------------------------------------
+ */
+
+static Bool
+VAssert_IsInVM(void)
+{
+   uint32 eax, ebx, ecx, edx;
+   static Bool inVM = FALSE;
+   static Bool tested = FALSE;
+   if (!tested) {
+      /* Error handling. */
+      if (sigsetjmp(segv_jmp, 0) != 0) {
+         signal(SIGSEGV, SIG_DFL);
+         inVM = FALSE;
+         return inVM;
+      }
+      tested = TRUE;
+      /* Install custom handler. */
+      signal(SIGSEGV, sig_segv);
+      /* Test if we are in a VM. */
+      libvassert_process_backdoor(0x0a, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+      signal(SIGSEGV, SIG_DFL);
+      inVM = TRUE;
+   }
+   return inVM;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_Init --
+ * 
+ *    Tell vmx that vassert is inited.
+ *
+ * Results:
+ *
+ *    Return 0 on success, or -1 on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *---------------------------------------------------------------------
+ */
+
+char
+VAssert_Init(void)
+{
+   uint32 eax, ebx, ecx, edx;
+   VA page_address = (VA) &vassert_state.inReplay, ph;
+   if (!VAssert_IsInVM()) {
+      return -1;
+   }
+   bzero((char*) &vassert_state, sizeof vassert_state);
+#ifndef __minix
+   /* Lock the page. */
+   if (mlock(&vassert_state, sizeof vassert_state)) {
+      return -1;
+   }
+#endif
+
+   /* vmware expects a linear address (or is simply forgetting
+    * to adjust the given address for segments)
+    */
+
+   if(sys_umap(SELF, D, page_address, 1, &ph)) {
+       printf("VAssert_Init: sys_umap failed\n");
+       return -1;
+   }
+
+   libvassert_process_backdoor(CMD_SET_ADDRESS, ph,
+       MAGIC_PORT|(1<<16), &eax, &ebx, &ecx, &edx);
+
+   return (eax != -1) ? 0 : -1;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_Uninit --
+ * 
+ *    Tell vmx that vassert is finalized.
+ *
+ * Results:
+ *
+ *    Return 0 on success, or -1 on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *---------------------------------------------------------------------
+ */
+
+char
+VAssert_Uninit(void)
+{
+   unsigned int eax, ebx, ecx, edx;
+   if (!VAssert_IsInVM()) {
+      return -1;
+   }
+   libvassert_process_backdoor(CMD_SET_ADDRESS, 0, MAGIC_PORT|(0<<16), &eax, &ebx, &ecx, &edx);
+   return (eax != -1) ? 0 : 1;
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_LogMain --
+ * 
+ *    Print message to a text file on host side.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    Write to a text file with fixed name.
+ *    If the file exists, host UI will ask for append/replace/ignore
+ *
+ *---------------------------------------------------------------------
+ */
+
+void
+VAssert_LogMain(const char *format, ...)
+{
+   unsigned int eax, ebx, ecx, edx;
+   char buf[LOG_MAX];
+   unsigned int len = 0;
+   va_list ap;
+   va_start(ap, format);
+   len = vsnprintf(buf, LOG_MAX, format, ap);
+   va_end(ap);
+   __asm__ __volatile__("cld; rep outsb;"
+                        : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) 
+                        : "0"(MAGIC_CMD), "1"(CMD_LOG), "2"(len), "d"(HIGH_BAND_PORT), "S"(buf)
+                        : "memory"
+                       );
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_GoLiveMain --
+ * 
+ *    Make the vm which is in replay exit replay.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    Replay is stopped.
+ *
+ *---------------------------------------------------------------------
+ */
+
+void
+VAssert_GoLiveMain()
+{
+   unsigned int eax, ebx, ecx, edx;
+   vassert_state.inReplay = 0;
+   libvassert_process_backdoor(CMD_GO_LIVE, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_ReturnToReplayMain --
+ * 
+ *    Called after the custom work is done, and replay is to continue.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    Replay is continued from pause.
+ *
+ *---------------------------------------------------------------------
+ */
+
+void
+VAssert_ReturnToReplayMain()
+{
+   unsigned int eax, ebx, ecx, edx;
+   libvassert_process_backdoor(CMD_RETURN_REPLAY, 0, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+}
+
+
+/*
+ *---------------------------------------------------------------------
+ *
+ * VAssert_SetRecordingMain --
+ * 
+ *    Ask vmx for starting or stopping recording.
+ *
+ * Results:
+ *
+ *    Return TRUE on success, or FALSE on failure.
+ *
+ * Side effects:
+ *    Recording is started or stopped.
+ *
+ *---------------------------------------------------------------------
+ */
+
+char
+VAssert_SetRecordingMain(char start)
+{
+   uint32 eax, ebx, ecx, edx;
+   if (!VAssert_IsInVM()) {
+      return FALSE;
+   }
+   libvassert_process_backdoor(CMD_SET_RECORD, start ? 1 : 2, MAGIC_PORT, &eax, &ebx, &ecx, &edx);
+   return (eax == 1) ? TRUE : FALSE;
+}
+
diff --git a/lib/libvassert/vassert.h b/lib/libvassert/vassert.h
new file mode 100644 (file)
index 0000000..a18c564
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef _VASSERT_H_
+#define _VASSERT_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /*__cplusplus*/
+
+#define ALIGNED(n) __attribute__((__aligned__(n)))
+#define VASSERT_TRIGGER_OFFSET 1221
+#define VASSERT_PAGE_SIZE      4096
+
+/* Need to align at 4K. */
+/* Ensure the inReplay flag is on its own page. */
+#pragma pack(1)
+typedef struct VAssert_StateWrapper {
+   char space1[VASSERT_TRIGGER_OFFSET];
+   volatile char inReplay;
+   char space[VASSERT_PAGE_SIZE - VASSERT_TRIGGER_OFFSET - sizeof(char)];
+} VAssert_StateWrapper;
+#pragma pack()
+
+extern VAssert_StateWrapper vassert_state;
+
+/*
+ * User-selectable standard functions.
+ * XXX: Document these, in coordination with the SDK docs.
+ */
+
+#if defined(__KERNEL__)
+#  define KERNEL_VASSERT
+#endif
+
+#ifdef KERNEL_VASSERT
+
+#  ifndef VASSERT_CUSTOM_ASSERT
+#     define VASSERT_CUSTOM_ASSERT(expr)
+#  endif
+
+#  ifndef VASSERT_CUSTOM_ABORT
+#     include <linux/kernel.h>
+#     define VASSERT_CUSTOM_ABORT() ((void)0) // printk(KERN_ALERT"VAssert abort at %s: %d", __FILE__, __LINE__)
+#  endif
+
+#  ifndef VASSERT_CUSTOM_LOG
+#     include <linux/kernel.h>
+#     define VASSERT_CUSTOM_LOG printk
+#  endif
+
+#else
+#  ifndef VASSERT_CUSTOM_ASSERT
+#     include <assert.h>
+#     define VASSERT_CUSTOM_ASSERT assert
+#  endif
+
+#  ifndef VASSERT_CUSTOM_ABORT
+#     include <stdlib.h>
+#     define VASSERT_CUSTOM_ABORT abort
+#  endif
+
+#  ifndef VASSERT_CUSTOM_LOG
+#     include <stdio.h>
+#     define VASSERT_CUSTOM_LOG printf
+#  endif
+#endif
+
+/* Results: 0 if successful, -1 if not. */
+// XXX need to automatic de-register trigger page when the program quits
+extern char VAssert_Init(void);
+extern char VAssert_Uninit(void);
+
+/*
+ * These functions should not be called directly; they need to be wrapped.
+ */
+extern void VAssert_LogMain(const char *format, ...);
+extern void VAssert_GoLiveMain(void);
+extern void VAssert_ReturnToReplayMain(void);
+extern char VAssert_Trace(size_t max_size);
+
+#ifdef VASSERT_ALWAYS_EXECUTE
+
+#define VAssert_Assert(expr)              \
+do {                                      \
+   VASSERT_CUSTOM_ASSERT(expr);           \
+} while (0)
+
+#define VAssert_Log(args)                 \
+do {                                      \
+   VASSERT_CUSTOM_LOG args;               \
+} while (0)
+
+#define VAssert_BeginBlock
+#define VAssert_EndBlock
+
+#else /* VASSERT_ALWAYS_EXECUTE */
+
+#define VAssert_Assert(expr)              \
+do {                                      \
+   if (vassert_state.inReplay) {          \
+      if (!(expr)) {                      \
+         VAssert_GoLiveMain();            \
+         VASSERT_CUSTOM_ABORT();          \
+      } else {                            \
+         VAssert_ReturnToReplayMain();    \
+      }                                   \
+   }                                      \
+} while (0)
+
+#define VAssert_Log(args)                 \
+do {                                      \
+   if (vassert_state.inReplay) {          \
+      VAssert_LogMain args;               \
+      VAssert_ReturnToReplayMain();       \
+   }                                      \
+} while (0)
+
+#define VAssert_BeginBlock if (vassert_state.inReplay)
+#define VAssert_EndBlock VAssert_ReturnToReplayMain()
+
+#endif /* VASSERT_ALWAYS_EXECUTE */
+
+/* 
+ * Record/Replay functionality
+ */
+/*
+ * Results: True if successful, false if not.
+ * Input: True to start recording, false to stop.
+ */
+extern char VAssert_SetRecordingMain(char start);
+
+#define VAssert_StartRecording() VAssert_SetRecordingMain(1)
+#define VAssert_StopRecording() VAssert_SetRecordingMain(0)
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus*/
+
+#endif /*_VASSERT_H_*/