299 lines
6.2 KiB
C
299 lines
6.2 KiB
C
|
#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;
|
||
|
}
|
||
|
|