summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--rsyslog.h1
-rw-r--r--vm.c221
-rw-r--r--vm.h59
-rw-r--r--vmop.h3
5 files changed, 285 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index bbccb8a5..179c53f0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,6 +5,8 @@ rfc3195d_SOURCES = rfc3195d.c rsyslog.h
rsyslogd_SOURCES = \
syslogd.c \
syslogd.h \
+ vm.c \
+ vm.h \
vmstk.c \
vmstk.h \
vmprg.c \
diff --git a/rsyslog.h b/rsyslog.h
index 2d31bd14..c8b2fcfa 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -130,6 +130,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_INTERFACE_NOT_SUPPORTED = -2054, /**< interface not supported */
RS_RET_OUT_OF_STACKSPACE = -2055, /**< a stack data structure is exhausted and can not be grown */
RS_RET_STACK_EMPTY = -2056, /**< a pop was requested on a stack, but the stack was already empty */
+ RS_RET_INVALID_VMOP = -2057, /**< invalid virtual machine instruction */
RS_RET_OK_DELETE_LISTENTRY = 1, /**< operation successful, but callee requested the deletion of an entry (special state) */
RS_RET_TERMINATE_NOW = 2, /**< operation successful, function is requested to terminate (mostly used with threads) */
RS_RET_NO_RUN = 3, /**< operation successful, but function does not like to be executed */
diff --git a/vm.c b/vm.c
new file mode 100644
index 00000000..93c0d5f6
--- /dev/null
+++ b/vm.c
@@ -0,0 +1,221 @@
+/* vm.c - the arithmetic stack of a virtual machine.
+ *
+ * Module begun 2008-02-22 by Rainer Gerhards
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "vm.h"
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(vmstk)
+
+
+/* ------------------------------ instruction set implementation ------------------------------ *
+ * The following functions implement the VM's instruction set.
+ */
+#define BEGINop(instruction) \
+ static rsRetVal op##instruction(vm_t *pThis, vmop_t *pOp) \
+ { \
+ DEFiRet;
+
+#define CODESTARTop(instruction) \
+ ISOBJ_TYPE_assert(pThis, vm); \
+ ISOBJ_TYPE_assert(pOp, vmop);
+
+#define ENDop(instruction) \
+ RETiRet; \
+ }
+
+BEGINop(OR) /* remember to set the instruction also in the ENDop macro! */
+ // var_t *pVar[2];
+ var_t *operand1;
+ var_t *operand2;
+CODESTARTop(OR)
+ // Pop(2, &pVar); --> should also do the conversion outlined below
+ vmstk.Pop(pThis->pStk, &operand1);
+ vmstk.Pop(pThis->pStk, &operand2);
+ // TODO: implement
+ /* We must check data types and find out on which data type the
+ * operation needs to be performed. This may result in some data types
+ * being converted.
+ *
+ * Current school of thought:
+ * op1 op2 operation data type
+ * string string string
+ * string number number if op1 can be converted to number, string else
+ * date string date if op1 can be converted to date, string else
+ * number number number
+ * date number string (maybe we can do better?)
+ * date date date
+ *
+ * If a boolean value is required, we need to have a number inside the
+ * operand. If it is not, conversion rules to number apply. Once we
+ * have a number, things get easy: 0 is false, anything else is true.
+ * Please note that due to this conversion rules, "0" becomes false
+ * while "-4712" becomes true. Using a date as boolen is not a good
+ * idea. Depending on the ultimate conversion rules, it may always
+ * become true or false. As such, using dates as booleans is
+ * prohibited and the result defined to be undefined.
+ */
+ vmstk.Push(pThis->pStk, operand1); /* result */
+ENDop(OR)
+
+BEGINop(AND) /* remember to set the instruction also in the ENDop macro! */
+ var_t *operand1;
+ var_t *operand2;
+CODESTARTop(AND)
+ vmstk.Pop(pThis->pStk, &operand1);
+ vmstk.Pop(pThis->pStk, &operand2);
+ // TODO: implement
+ vmstk.Push(pThis->pStk, operand1); /* result */
+ENDop(AND)
+
+BEGINop(POP) /* remember to set the instruction also in the ENDop macro! */
+CODESTARTop(POP)
+/* TODO: implement */
+ENDop(POP)
+
+BEGINop(PUSHCONSTANT) /* remember to set the instruction also in the ENDop macro! */
+CODESTARTop(PUSHCONSTANT)
+ vmstk.Push(pThis->pStk, pOp->operand.pVar);
+ENDop(PUSHCONSTANT)
+
+
+/* ------------------------------ end instruction set implementation ------------------------------ */
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(vm) /* be sure to specify the object type also in END macro! */
+ENDobjConstruct(vm)
+
+
+/* ConstructionFinalizer
+ * rgerhards, 2008-01-09
+ */
+static rsRetVal
+vmConstructFinalize(vm_t __attribute__((unused)) *pThis)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, vm);
+ RETiRet;
+}
+
+
+/* destructor for the vm object */
+BEGINobjDestruct(vm) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(vm)
+ENDobjDestruct(vm)
+
+
+/* debugprint for the vm object */
+BEGINobjDebugPrint(vm) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDebugPrint(vm)
+ dbgoprint((obj_t*) pThis, "rsyslog virtual machine, currently no state info available\n");
+ENDobjDebugPrint(vm)
+
+
+/* execute a program
+ */
+static rsRetVal
+execProg(vm_t *pThis, vmprg_t *pProg)
+{
+ DEFiRet;
+ vmop_t *pCurrOp; /* virtual instruction pointer */
+
+ ISOBJ_TYPE_assert(pThis, vm);
+ ISOBJ_TYPE_assert(pProg, vmprg);
+
+#define doOP(OP) case opcode_##OP: CHKiRet(op##OP(pThis, pCurrOp)); break
+ pCurrOp = pProg->vmopRoot; /* TODO: do this via a method! */
+ while(pCurrOp != NULL && pCurrOp->opcode != opcode_END_PROG) {
+ switch(pCurrOp->opcode) {
+ doOP(OR);
+ doOP(AND);
+ doOP(POP);
+ doOP(PUSHCONSTANT);
+ default:
+ ABORT_FINALIZE(RS_RET_INVALID_VMOP);
+ dbgoprint((obj_t*) pThis, "invalid instruction %d in vmprg\n", pCurrOp->opcode);
+ break;
+ }
+ /* so far, we have plain sequential execution, so on to next... */
+ pCurrOp = pCurrOp->pNext;
+ }
+#undef doOP
+
+ /* if we reach this point, our program has intintionally terminated
+ * (no error state).
+ */
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+/* queryInterface function
+ * rgerhards, 2008-02-21
+ */
+BEGINobjQueryInterface(vm)
+CODESTARTobjQueryInterface(vm)
+ if(pIf->ifVersion != vmCURR_IF_VERSION) { /* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+ }
+
+ /* ok, we have the right interface, so let's fill it
+ * Please note that we may also do some backwards-compatibility
+ * work here (if we can support an older interface version - that,
+ * of course, also affects the "if" above).
+ */
+ pIf->oID = OBJvm;
+
+ pIf->Construct = vmConstruct;
+ pIf->ConstructFinalize = vmConstructFinalize;
+ pIf->Destruct = vmDestruct;
+ pIf->DebugPrint = vmDebugPrint;
+ pIf->ExecProg = execProg;
+finalize_it:
+ENDobjQueryInterface(vm)
+
+
+/* Initialize the vm class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+BEGINObjClassInit(vm, 1) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(vmstk));
+
+ /* set our own handlers */
+ OBJSetMethodHandler(objMethod_DEBUGPRINT, vmDebugPrint);
+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmConstructFinalize);
+ENDObjClassInit(vm)
+
+/* vi:set ai:
+ */
diff --git a/vm.h b/vm.h
new file mode 100644
index 00000000..c9173255
--- /dev/null
+++ b/vm.h
@@ -0,0 +1,59 @@
+/* The vm object.
+ *
+ * This implements the rsyslog virtual machine. The initial implementation is
+ * done to support complex user-defined expressions, but it may evolve into a
+ * much more useful thing over time.
+ *
+ * The virtual machine uses rsyslog variables as its memory storage system.
+ * All computation is done on a stack (vmstk). The vm supports a given
+ * instruction set and executes programs of type vmprg, which consist of
+ * single operations defined in vmop (which hold the instruction and the
+ * data).
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#ifndef INCLUDED_VM_H
+#define INCLUDED_VM_H
+
+#include "vmstk.h"
+#include "vmprg.h"
+
+/* the vm object */
+typedef struct vm_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ vmstk_t *pStk; /* The stack */
+} vm_t;
+
+
+/* interfaces */
+BEGINinterface(vm) /* name must also be changed in ENDinterface macro! */
+ INTERFACEObjDebugPrint(vm);
+ rsRetVal (*Construct)(vm_t **ppThis);
+ rsRetVal (*ConstructFinalize)(vm_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(vm_t **ppThis);
+ rsRetVal (*ExecProg)(vm_t *pThis, vmprg_t *pProg);
+ENDinterface(vm)
+#define vmCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+
+/* prototypes */
+PROTOTYPEObj(vm);
+
+#endif /* #ifndef INCLUDED_VM_H */
diff --git a/vmop.h b/vmop.h
index 1ea531b3..70e166e3 100644
--- a/vmop.h
+++ b/vmop.h
@@ -51,7 +51,8 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc(
opcode_PUSHSYSVAR = 1001, /* requires var operand */
opcode_PUSHMSGVAR = 1002, /* requires var operand */
opcode_PUSHCONSTANT = 1003, /* requires var operand */
- opcode_UNARY_MINUS = 1010
+ opcode_UNARY_MINUS = 1010,
+ opcode_END_PROG = 1011
} opcode_t;