libclamav/bytecode_vm.c
e0c4fd85
 /*
  *  Execute ClamAV bytecode.
  *
847d7fc1
  *  Copyright (C) 2009-2010 Sourcefire, Inc.
e0c4fd85
  *
  *  Authors: Török Edvin
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  *  This program 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 this program; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  *  MA 02110-1301, USA.
  */
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 #include "clamav.h"
 #include "others.h"
 #include "bytecode.h"
 #include "bytecode_priv.h"
cf0cd429
 #include "type_desc.h"
e0c4fd85
 #include "readdb.h"
 #include <string.h>
145ca5cb
 #ifndef _WIN32
 #include <sys/time.h>
 #endif
a15fc904
 #include "bytecode_api_impl.h"
 #include "disasm-common.h"
e0c4fd85
 
8596e278
 /* Enable this to catch more bugs in the RC phase */
15fd260a
 #define CL_BYTECODE_SAFE
8596e278
 
15fd260a
 #ifdef CL_BYTECODE_SAFE
e0c4fd85
 /* These checks will also be done by the bytecode verifier, but for
  * debugging purposes we have explicit checks, these should never fail! */
15fd260a
 #ifdef CL_DEBUG
9cbece5c
 static int never_inline bcfail(const char *msg, long a, long b,
e0c4fd85
 		  const char *file, unsigned line)
 {
7f6b55a1
     cli_warnmsg("bytecode: check failed %s (%lx and %lx) at %s:%u\n", msg, a, b, file, line);
e0c4fd85
     return CL_EARG;
 }
15fd260a
 #else
 #define bcfail(msg,a,b,f,l) CL_EBYTECODE
 #endif
82ca2ab4
 
e0c4fd85
 #define CHECK_FUNCID(funcid) do { if (funcid >= bc->num_func) return \
     bcfail("funcid out of bounds!",funcid, bc->num_func,__FILE__,__LINE__); } while(0)
cf0cd429
 #define CHECK_APIID(funcid) do { if (funcid >= cli_apicall_maxapi) return \
     bcfail("APIid out of bounds!",funcid, cli_apicall_maxapi,__FILE__,__LINE__); } while(0)
ec5cccc7
 #define CHECK_EQ(a, b) do { if ((a) != (b)) return \
     bcfail("Values "#a" and "#b" don't match!",(a),(b),__FILE__,__LINE__); } while(0)
 #define CHECK_GT(a, b) do {if ((a) <= (b)) return \
     bcfail("Condition failed "#a" > "#b,(a),(b), __FILE__, __LINE__); } while(0)
15fd260a
 
e0c4fd85
 #else
9cbece5c
 static inline int bcfail(const char *msg, long a, long b,
 			 const char *file, unsigned line) {}
82ca2ab4
 #define CHECK_FUNCID(x);
cf0cd429
 #define CHECK_APIID(x);
e0c4fd85
 #define CHECK_EQ(a,b)
 #define CHECK_GT(a,b)
 #endif
15fd260a
 #ifdef CL_DEBUG
 #define CHECK_UNREACHABLE do { cli_dbgmsg("bytecode: unreachable executed!\n"); return CL_EBYTECODE; } while(0)
a15fc904
 #define TRACE_PTR(ptr, s) cli_dbgmsg("bytecode trace: ptr %llx, +%x\n", ptr, s);
15fd260a
 #define TRACE_R(x) cli_dbgmsg("bytecode trace: %u, read %llx\n", pc, (long long)x);
 #define TRACE_W(x, w, p) cli_dbgmsg("bytecode trace: %u, write%d @%u %llx\n", pc, p, w, (long long)(x));
 #define TRACE_EXEC(id, dest, ty, stack) cli_dbgmsg("bytecode trace: executing %d, -> %u (%u); %u\n", id, dest, ty, stack)
1678ef9e
 #define TRACE_API(s, dest, ty, stack) cli_dbgmsg("bytecode trace: executing %s, -> %u (%u); %u\n", s, dest, ty, stack)
15fd260a
 #else
 #define CHECK_UNREACHABLE return CL_EBYTECODE
a15fc904
 #define TRACE_PTR(ptr, s)
15fd260a
 #define TRACE_R(x)
 #define TRACE_W(x, w, p)
 #define TRACE_EXEC(id, dest, ty, stack)
1678ef9e
 #define TRACE_API(s, dest, ty, stack)
15fd260a
 #endif
 
cfec3d90
 #define SIGNEXT(a, from) CLI_SRS(((int64_t)(a)) << (64-(from)), (64-(from)))
 
6922903a
 #ifdef CL_DEBUG
 #undef always_inline
 #define always_inline
 #endif
 
cfec3d90
 static always_inline int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
ec5cccc7
 		unsigned *bb_inst)
8c0933ce
 {
     CHECK_GT(func->numBB, bbid);
     *bb = &func->BB[bbid];
     *inst = (*bb)->insts;
     *bb_inst = 0;
ec5cccc7
     return 0;
8c0933ce
 }
 
349e6e11
 #define STACK_CHUNKSIZE 65536
cfec3d90
 
 struct stack_chunk {
     struct stack_chunk *prev;
     unsigned used;
     union {
 	void *align;
 	char data[STACK_CHUNKSIZE];
     } u;
 };
 
 struct stack {
     struct stack_chunk* chunk;
     uint16_t last_size;
 };
 
ac17fc6c
 /* type with largest alignment that we use (in general it is a long double, but
  * thats too big alignment for us) */
 typedef uint64_t align_t;
 
cfec3d90
 static always_inline void* cli_stack_alloc(struct stack *stack, unsigned bytes)
 {
     struct stack_chunk *chunk = stack->chunk;
     uint16_t last_size_off;
 
     /* last_size is stored after data */
     /* align bytes to pointer size */
ac17fc6c
     bytes = (bytes + sizeof(uint16_t) + sizeof(align_t)) & ~(sizeof(align_t)-1);
cfec3d90
     last_size_off = bytes - 2;
 
     if (chunk && (chunk->used + bytes <= STACK_CHUNKSIZE)) {
 	/* there is still room in this chunk */
 	void *ret;
 
 	*(uint16_t*)&chunk->u.data[chunk->used + last_size_off] = stack->last_size;
ac17fc6c
 	stack->last_size = bytes/sizeof(align_t);
cfec3d90
 
 	ret = chunk->u.data + chunk->used;
 	chunk->used += bytes;
 	return ret;
     }
 
     if(bytes >= STACK_CHUNKSIZE) {
349e6e11
 	cli_warnmsg("cli_stack_alloc: Attempt to allocate more than STACK_CHUNKSIZE bytes: %u!\n", bytes);
cfec3d90
 	return NULL;
     }
     /* not enough room here, allocate new chunk */
     chunk = cli_malloc(sizeof(*stack->chunk));
     if (!chunk)
 	return NULL;
 
     *(uint16_t*)&chunk->u.data[last_size_off] = stack->last_size;
ac17fc6c
     stack->last_size = bytes/sizeof(align_t);
cfec3d90
 
     chunk->used = bytes;
     chunk->prev = stack->chunk;
     stack->chunk = chunk;
     return chunk->u.data;
 }
 
 static always_inline void cli_stack_free(struct stack *stack, void *data)
 {
     uint16_t last_size;
     struct stack_chunk *chunk = stack->chunk;
     if (!chunk) {
7f6b55a1
 	cli_warnmsg("cli_stack_free: stack empty!\n");
cfec3d90
 	return;
     }
ac17fc6c
     if ((chunk->u.data + chunk->used) != ((char*)data + stack->last_size*sizeof(align_t))) {
7f6b55a1
 	cli_warnmsg("cli_stack_free: wrong free order: %p, expected %p\n",
ac17fc6c
 		   data, chunk->u.data + chunk->used - stack->last_size*sizeof(align_t));
cfec3d90
 	return;
     }
     last_size = *(uint16_t*)&chunk->u.data[chunk->used-2];
ac17fc6c
     if (chunk->used < stack->last_size*sizeof(align_t)) {
7f6b55a1
 	cli_warnmsg("cli_stack_free: last_size is corrupt!\n");
cfec3d90
 	return;
     }
ac17fc6c
     chunk->used -= stack->last_size*sizeof(align_t);
cfec3d90
     stack->last_size = last_size;
     if (!chunk->used) {
 	stack->chunk = chunk->prev;
 	free(chunk);
     }
 }
 
 static void cli_stack_destroy(struct stack *stack)
 {
     struct stack_chunk *chunk = stack->chunk;
     while (chunk) {
 	stack->chunk = chunk->prev;
 	free(chunk);
 	chunk = stack->chunk;
     }
 }
 
 struct stack_entry {
     struct stack_entry *prev;
     const struct cli_bc_func *func;
6922903a
     operand_t ret;
cfec3d90
     unsigned bb_inst;
2545f976
     struct cli_bc_bb *bb;
6922903a
     char *values;
cfec3d90
 };
 
 static always_inline struct stack_entry *allocate_stack(struct stack *stack,
 							struct stack_entry *prev,
 							const struct cli_bc_func *func,
 							const struct cli_bc_func *func_old,
6922903a
 							operand_t ret,
cfec3d90
 							struct cli_bc_bb *bb,
 							unsigned bb_inst)
ec5cccc7
 {
6922903a
     char *values;
     struct stack_entry *entry = cli_stack_alloc(stack, sizeof(*entry) + sizeof(*values)*func->numBytes);
cfec3d90
     if (!entry)
ec5cccc7
 	return NULL;
cfec3d90
     entry->prev = prev;
     entry->func = func_old;
     entry->ret = ret;
     entry->bb = bb;
     entry->bb_inst = bb_inst;
     /* we allocated room for values right after stack_entry! */
6922903a
     entry->values = values = (char*)&entry[1];
     memcpy(&values[func->numBytes - func->numConstants*8], func->constants,
 	   sizeof(*values)*func->numConstants*8);
cfec3d90
     return entry;
 }
 
 static always_inline struct stack_entry *pop_stack(struct stack *stack,
 						   struct stack_entry *stack_entry,
 						   const struct cli_bc_func **func,
6922903a
 						   operand_t *ret,
cfec3d90
 						   struct cli_bc_bb **bb,
 						   unsigned *bb_inst)
 {
     void *data;
     *func = stack_entry->func;
     *ret = stack_entry->ret;
     *bb = stack_entry->bb;
     *bb_inst = stack_entry->bb_inst;
     data = stack_entry;
     stack_entry = stack_entry->prev;
     cli_stack_free(stack, data);
     return stack_entry;
ec5cccc7
 }
 
82ca2ab4
 
 /*
  *
  * p, p+1, p+2, p+3 <- gt
     CHECK_EQ((p)&1, 0); 
     CHECK_EQ((p)&3, 0); 
     CHECK_EQ((p)&7, 0); 
 */
6922903a
 #define WRITE8(p, x) CHECK_GT(func->numBytes, p);\
11e86f8c
     TRACE_W(x, p, 8);\
6922903a
     *(uint8_t*)&values[p] = x
 #define WRITE16(p, x) CHECK_GT(func->numBytes, p+1);\
     CHECK_EQ((p)&1, 0);\
11e86f8c
     TRACE_W(x, p, 16);\
6922903a
     *(uint16_t*)&values[p] = x
 #define WRITE32(p, x) CHECK_GT(func->numBytes, p+3);\
     CHECK_EQ((p)&3, 0);\
11e86f8c
     TRACE_W(x, p, 32);\
6922903a
     *(uint32_t*)&values[p] = x
 #define WRITE64(p, x) CHECK_GT(func->numBytes, p+7);\
     CHECK_EQ((p)&7, 0);\
11e86f8c
     TRACE_W(x, p, 64);\
     *(uint64_t*)&values[p] = x
72617ba2
 #define WRITEP(x, p) CHECK_GT(func->numBytes, p+PSIZE-1);\
     CHECK_EQ((p)&(PSIZE-1), 0);\
     TRACE_W(x, p, PSIZE*8);\
     *(void**)&values[p] = x
6922903a
 
df5c921d
 #define uint_type(n) uint##n##_t
18204a67
 #define READNfrom(maxBytes, from, x, n, p)\
     CHECK_GT((maxBytes), (p)+(n/8)-1);\
c6c464e5
     CHECK_EQ((p)&(n/8-1), 0);\
18204a67
     x = *(uint_type(n)*)&(from)[(p)];\
11e86f8c
     TRACE_R(x)
df5c921d
 
bc157ce3
 #define READN(x, n, p)\
  do {\
      if (p&0x80000000) {\
 	 uint32_t pg = p&0x7fffffff;\
9d39dc93
 	 if (!pg) {\
 	 x = 0;\
 	 } else {\
52d0d8bc
 	 READNfrom(bc->numGlobalBytes, bc->globalBytes, x, n, pg);\
9d39dc93
 	 }\
bc157ce3
      } else {\
 	 READNfrom(func->numBytes, values, x, n, p);\
      }\
  } while (0)
18204a67
 
df5c921d
 #define READ1(x, p) READN(x, 8, p);\
     x = x&1
 #define READ8(x, p) READN(x, 8, p)
 #define READ16(x, p) READN(x, 16, p)
 #define READ32(x, p) READN(x, 32, p)
 #define READ64(x, p) READN(x, 64, p)
 
9cbece5c
 #define PSIZE sizeof(int64_t)
 #define READP(x, p, asize) { int64_t iptr__;\
52d0d8bc
     READN(iptr__, 64, p);\
9cbece5c
     x = ptr_torealptr(&ptrinfos, iptr__, (asize));\
     if (!x) {\
 	stop = CL_EBYTECODE;\
 	break;\
     }\
     TRACE_R(x)\
 }
0d9b99f4
 #define READPOP(x, p, asize) {\
     if ((p)&0x40000000) {\
 	unsigned ptr__ = (p)&0xbfffffff;\
 	CHECK_GT(func->numBytes, ptr__);\
a15fc904
 	TRACE_PTR(ptr__, asize);\
0d9b99f4
 	x = (void*)&values[ptr__];\
     } else {\
 	READP(x, p, asize)\
     }\
 }
6922903a
 
 #define READOLD8(x, p) CHECK_GT(func->numBytes, p);\
11e86f8c
     x = *(uint8_t*)&old_values[p];\
     TRACE_R(x)
6922903a
 #define READOLD16(x, p) CHECK_GT(func->numBytes, p+1);\
     CHECK_EQ((p)&1, 0);\
11e86f8c
     x = *(uint16_t*)&old_values[p];\
     TRACE_R(x)
6922903a
 #define READOLD32(x, p) CHECK_GT(func->numBytes, p+3);\
     CHECK_EQ((p)&3, 0);\
11e86f8c
     x = *(uint32_t*)&old_values[p];\
     TRACE_R(x)
6922903a
 #define READOLD64(x, p) CHECK_GT(func->numBytes, p+7);\
     CHECK_EQ((p)&7, 0);\
11e86f8c
     x = *(uint64_t*)&old_values[p];\
     TRACE_R(x)
82ca2ab4
 
 #define BINOP(i) inst->u.binop[i]
 
52dd3a6b
 #define DEFINE_BINOP_BC_HELPER(opc, OP, W0, W1, W2, W3, W4) \
82ca2ab4
     case opc*5: {\
 		    uint8_t op0, op1, res;\
 		    int8_t sop0, sop1;\
 		    READ1(op0, BINOP(0));\
 		    READ1(op1, BINOP(1));\
 		    sop0 = op0; sop1 = op1;\
 		    OP;\
 		    W0(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+1: {\
 		    uint8_t op0, op1, res;\
 		    int8_t sop0, sop1;\
 		    READ8(op0, BINOP(0));\
 		    READ8(op1, BINOP(1));\
 		    sop0 = op0; sop1 = op1;\
 		    OP;\
 		    W1(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+2: {\
 		    uint16_t op0, op1, res;\
 		    int16_t sop0, sop1;\
 		    READ16(op0, BINOP(0));\
 		    READ16(op1, BINOP(1));\
 		    sop0 = op0; sop1 = op1;\
 		    OP;\
 		    W2(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+3: {\
 		    uint32_t op0, op1, res;\
 		    int32_t sop0, sop1;\
 		    READ32(op0, BINOP(0));\
 		    READ32(op1, BINOP(1));\
 		    sop0 = op0; sop1 = op1;\
 		    OP;\
 		    W3(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+4: {\
 		    uint64_t op0, op1, res;\
 		    int64_t sop0, sop1;\
11e86f8c
 		    READ64(op0, BINOP(0));\
 		    READ64(op1, BINOP(1));\
82ca2ab4
 		    sop0 = op0; sop1 = op1;\
 		    OP;\
 		    W4(inst->dest, res);\
 		    break;\
6922903a
 		}
82ca2ab4
 
52dd3a6b
 #define DEFINE_BINOP(opc, OP) DEFINE_BINOP_BC_HELPER(opc, OP, WRITE8, WRITE8, WRITE16, WRITE32, WRITE64)
 #define DEFINE_ICMPOP(opc, OP) DEFINE_BINOP_BC_HELPER(opc, OP, WRITE8, WRITE8, WRITE8, WRITE8, WRITE8)
82ca2ab4
 
4e2959f2
 #define CHECK_OP(cond, msg) if((cond)) { cli_dbgmsg(msg); stop = CL_EBYTECODE; break;}
82ca2ab4
 
e4a0f2c9
 #define DEFINE_SCASTOP(opc, OP) \
82ca2ab4
     case opc*5: {\
 		    uint8_t res;\
 		    int8_t sres;\
 		    OP;\
 		    WRITE8(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+1: {\
 		    uint8_t res;\
 		    int8_t sres;\
 		    OP;\
 		    WRITE8(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+2: {\
 		    uint16_t res;\
 		    int16_t sres;\
 		    OP;\
 		    WRITE16(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+3: {\
 		    uint32_t res;\
 		    int32_t sres;\
 		    OP;\
 		    WRITE32(inst->dest, res);\
 		    break;\
 		}\
     case opc*5+4: {\
 		    uint64_t res;\
 		    int64_t sres;\
 		    OP;\
 		    WRITE64(inst->dest, res);\
 		    break;\
6922903a
 		}
e4a0f2c9
 #define DEFINE_CASTOP(opc, OP) DEFINE_SCASTOP(opc, OP; (void)sres)
82ca2ab4
 
 #define DEFINE_OP(opc) \
     case opc*5: /* fall-through */\
     case opc*5+1: /* fall-through */\
     case opc*5+2: /* fall-through */\
     case opc*5+3: /* fall-through */\
     case opc*5+4:
 
 #define CHOOSE(OP0, OP1, OP2, OP3, OP4) \
     switch (inst->u.cast.size) {\
 	case 0: OP0; break;\
 	case 1: OP1; break;\
 	case 2: OP2; break;\
 	case 3: OP3; break;\
 	case 4: OP4; break;\
 	default: CHECK_UNREACHABLE;\
     }
 
52dd3a6b
 #define DEFINE_OP_BC_RET_N(OP, T, R0, W0) \
6922903a
     case OP: {\
 		T tmp;\
 		R0(tmp, inst->u.unaryop);\
 		CHECK_GT(stack_depth, 0);\
 		stack_depth--;\
 		stack_entry = pop_stack(&stack, stack_entry, &func, &i, &bb,\
 					&bb_inst);\
 		values = stack_entry ? stack_entry->values : ctx->values;\
 		CHECK_GT(func->numBytes, i);\
 		W0(i, tmp);\
 		if (!bb) {\
 		    stop = CL_BREAK;\
 		    continue;\
 		}\
2cad69f7
 		stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes)>>32;\
6922903a
 		inst = &bb->insts[bb_inst];\
 		break;\
 	    }
 
9cbece5c
 struct ptr_info {
     uint8_t *base;
     uint32_t size;
 };
 
 struct ptr_infos {
     struct ptr_info *stack_infos;
     struct ptr_info *glob_infos;
     unsigned nstacks, nglobs;
 };
 
 static inline int64_t ptr_compose(int32_t id, uint32_t offset)
 {
     uint64_t i = id;
     return (i << 32) | offset;
 }
 
44e13431
 static inline int32_t ptr_diff32(int64_t ptr1, int64_t ptr2)
 {
     int32_t ptrid1 = ptr1 >> 32;
     int32_t ptrid2 = ptr2 >> 32;
     if (ptrid1 != ptrid2) {
e4a0f2c9
 	(void)bcfail("difference of pointers not pointing to same object!", ptrid1, ptrid2, __FILE__, __LINE__);
44e13431
 	/* invalid diff */
 	return 0x40000000;
     }
     return (uint32_t)ptr1 - (uint32_t)ptr2;
 }
 
4993d6cf
 static inline int64_t ptr_register_stack(struct ptr_infos *infos,
e4a0f2c9
 					 char *values,
9cbece5c
 					 uint32_t off, uint32_t size)
 {
     unsigned n = infos->nstacks + 1;
     struct ptr_info *sinfos = cli_realloc(infos->stack_infos,
 					  sizeof(*sinfos)*n);
     if (!sinfos)
 	return 0;
     infos->stack_infos = sinfos;
     infos->nstacks = n;
     sinfos = &sinfos[n-1];
e4a0f2c9
     sinfos->base = (uint8_t*)values + off;
9cbece5c
     sinfos->size = size;
4993d6cf
     return ptr_compose(-n, 0);
9cbece5c
 }
 
52d0d8bc
 static inline int64_t ptr_register_glob_fixedid(struct ptr_infos *infos,
 						void *values, uint32_t size, unsigned n)
9cbece5c
 {
52d0d8bc
     struct ptr_info *sinfos;
     if (n > infos->nglobs) {
 	sinfos = cli_realloc(infos->glob_infos, sizeof(*sinfos)*n);
 	if (!sinfos)
 	    return 0;
598d7eda
         memset(sinfos + infos->nglobs, 0, (n - infos->nglobs)*sizeof(*sinfos));
52d0d8bc
 	infos->glob_infos = sinfos;
 	infos->nglobs = n;
     }
     sinfos = &infos->glob_infos[n-1];
74f5816c
     if (!values)
 	size = 0;
9cbece5c
     sinfos->base = values;
     sinfos->size = size;
74f5816c
     cli_dbgmsg("bytecode: registered ctx variable at %p (+%u) id %u\n", values,
 	       size, n);
9cbece5c
     return ptr_compose(n, 0);
 }
 
52d0d8bc
 static inline int64_t ptr_register_glob(struct ptr_infos *infos,
 					void *values, uint32_t size)
 {
9d39dc93
     if (!values)
 	return 0;
52d0d8bc
     return ptr_register_glob_fixedid(infos, values, size, infos->nglobs+1);
 }
 
9cbece5c
 static inline int64_t ptr_index(int64_t ptr, uint32_t off)
 {
     int32_t ptrid = ptr >> 32;
     uint32_t ptroff = (uint32_t)ptr;
     return ptr_compose(ptrid, ptroff+off);
 }
 
 static inline void* ptr_torealptr(const struct ptr_infos *infos, int64_t ptr,
 				  uint32_t read_size)
 {
     struct ptr_info *info;
     int32_t ptrid = ptr >> 32;
     uint32_t ptroff = (uint32_t)ptr;
a15fc904
     TRACE_PTR(ptr, read_size);
9cbece5c
     if (UNLIKELY(!ptrid)) {
e4a0f2c9
 	(void)bcfail("nullptr", ptrid, 0, __FILE__, __LINE__);
9cbece5c
 	return NULL;
     }
     if (ptrid < 0) {
4993d6cf
 	ptrid = -ptrid-1;
9cbece5c
 	if (UNLIKELY(ptrid >= infos->nstacks)) {
e4a0f2c9
 	    (void)bcfail("ptr", ptrid, infos->nstacks, __FILE__, __LINE__);
9cbece5c
 	    return NULL;
 	}
 	info = &infos->stack_infos[ptrid];
     } else {
 	ptrid--;
 	if (UNLIKELY(ptrid >= infos->nglobs)) {
e4a0f2c9
 	    (void)bcfail("ptr", ptrid, infos->nglobs, __FILE__, __LINE__);
9cbece5c
 	    return NULL;
 	}
 	info = &infos->glob_infos[ptrid];
     }
     if (LIKELY(ptroff < info->size &&
1678ef9e
 	read_size <= info->size &&
9cbece5c
 	ptroff + read_size <= info->size)) {
 	return info->base+ptroff;
     }
 
e4a0f2c9
     (void)bcfail("ptr1", ptroff, info->size, __FILE__, __LINE__);
     (void)bcfail("ptr2", read_size, info->size, __FILE__, __LINE__);
     (void)bcfail("ptr3", ptroff+read_size, info->size, __FILE__, __LINE__);
9cbece5c
     return NULL;
 }
 
82ca2ab4
 static always_inline int check_sdivops(int64_t op0, int64_t op1)
 {
     return op1 == 0 || (op0 == -1 && op1 ==  (-9223372036854775807LL-1LL));
 }
 
52d0d8bc
 static unsigned globaltypesize(uint16_t id)
 {
     const struct cli_bc_type *ty;
     if (id <= 64)
 	return (id + 7)/8;
50829fbf
     if (id < 69)
52d0d8bc
 	return 8; /* ptr */
     ty = &cli_apicall_types[id - 69];
     switch (ty->kind) {
 	case DArrayType:
 	    return ty->numElements*globaltypesize(ty->containedTypes[0]);
 	case DStructType:
 	case DPackedStructType:
 	    {
 		unsigned i, s = 0;
 		for (i=0;i<ty->numElements;i++)
 		    s += globaltypesize(ty->containedTypes[i]);
 		return s;
 	    }
e4a0f2c9
 	default:
 	    return 0;
52d0d8bc
     }
 }
 
a15fc904
 /* TODO: fix the APIs too */
 static struct {
     cli_apicall_pointer api;
     uint32_t override_size;
 } apisize_override[] = {
     {(void*)cli_bcapi_disasm_x86, sizeof(struct DISASM_RESULT)},
     {(void*)cli_bcapi_get_pe_section, sizeof(struct cli_exe_section)},
 };
 
ec5cccc7
 int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
e0c4fd85
 {
11e86f8c
     unsigned i, j, stack_depth=0, bb_inst=0, stop=0, pc=0;
e0c4fd85
     struct cli_bc_func *func2;
cfec3d90
     struct stack stack;
     struct stack_entry *stack_entry = NULL;
e0c4fd85
     struct cli_bc_bb *bb = NULL;
6922903a
     char *values = ctx->values;
     char *old_values;
9cbece5c
     struct ptr_infos ptrinfos;
74f5816c
     struct timeval tv0, tv1, timeout;
4993d6cf
     int stackid = 0;
e0c4fd85
 
9cbece5c
     memset(&ptrinfos, 0, sizeof(ptrinfos));
cfec3d90
     memset(&stack, 0, sizeof(stack));
52d0d8bc
     for (i=0;i < cli_apicall_maxglobal - _FIRST_GLOBAL; i++) {
145ca5cb
 	void *apiptr;
 	uint32_t size;
52d0d8bc
 	const struct cli_apiglobal *g = &cli_globals[i];
74f5816c
 	void **apiglobal = (void**)(((char*)ctx) + g->offset);
 	if (!apiglobal)
 	    continue;
145ca5cb
 	apiptr = *apiglobal;
 	size = globaltypesize(g->type);
74f5816c
 	ptr_register_glob_fixedid(&ptrinfos, apiptr, size, g->globalid - _FIRST_GLOBAL+1);
52d0d8bc
     }
74f5816c
     ptr_register_glob_fixedid(&ptrinfos, bc->globalBytes, bc->numGlobalBytes,
 			      cli_apicall_maxglobal - _FIRST_GLOBAL + 2);
 
     gettimeofday(&tv0, NULL);
     timeout.tv_usec = tv0.tv_usec + ctx->bytecode_timeout*1000;
     timeout.tv_sec = tv0.tv_sec + timeout.tv_usec/1000000;
     timeout.tv_usec %= 1000000;
52d0d8bc
 
e0c4fd85
     do {
11e86f8c
 	pc++;
74f5816c
 	if (!(pc % 5000)) {
 	    gettimeofday(&tv1, NULL);
 	    if (tv1.tv_sec > timeout.tv_sec ||
 		(tv1.tv_sec == timeout.tv_sec &&
 		 tv1.tv_usec > timeout.tv_usec)) {
44e13431
 		cli_warnmsg("Bytecode run timed out in interpreter after %u opcodes\n", pc);
74f5816c
 		stop = CL_ETIMEOUT;
 		break;
 	    }
 	}
82ca2ab4
 	switch (inst->interp_op) {
52dd3a6b
 	    DEFINE_BINOP(OP_BC_ADD, res = op0 + op1);
 	    DEFINE_BINOP(OP_BC_SUB, res = op0 - op1);
 	    DEFINE_BINOP(OP_BC_MUL, res = op0 * op1);
82ca2ab4
 
52dd3a6b
 	    DEFINE_BINOP(OP_BC_UDIV, CHECK_OP(op1 == 0, "bytecode attempted to execute udiv#0\n");
82ca2ab4
 			 res=op0/op1);
52dd3a6b
 	    DEFINE_BINOP(OP_BC_SDIV, CHECK_OP(check_sdivops(sop0, sop1), "bytecode attempted to execute sdiv#0\n");
82ca2ab4
 			 res=sop0/sop1);
52dd3a6b
 	    DEFINE_BINOP(OP_BC_UREM, CHECK_OP(op1 == 0, "bytecode attempted to execute urem#0\n");
82ca2ab4
 			 res=op0 % op1);
52dd3a6b
 	    DEFINE_BINOP(OP_BC_SREM, CHECK_OP(check_sdivops(sop0,sop1), "bytecode attempted to execute urem#0\n");
82ca2ab4
 			 res=sop0 % sop1);
 
52dd3a6b
 	    DEFINE_BINOP(OP_BC_SHL, CHECK_OP(op1 > inst->type, "bytecode attempted to execute shl greater than bitwidth\n");
82ca2ab4
 			 res = op0 << op1);
52dd3a6b
 	    DEFINE_BINOP(OP_BC_LSHR, CHECK_OP(op1 > inst->type, "bytecode attempted to execute lshr greater than bitwidth\n");
82ca2ab4
 			 res = op0 >> op1);
52dd3a6b
 	    DEFINE_BINOP(OP_BC_ASHR, CHECK_OP(op1 > inst->type, "bytecode attempted to execute ashr greater than bitwidth\n");
82ca2ab4
 			 res = CLI_SRS(sop0, op1));
 
52dd3a6b
 	    DEFINE_BINOP(OP_BC_AND, res = op0 & op1);
 	    DEFINE_BINOP(OP_BC_OR, res = op0 | op1);
 	    DEFINE_BINOP(OP_BC_XOR, res = op0 ^ op1);
82ca2ab4
 
e4a0f2c9
 	    DEFINE_SCASTOP(OP_BC_SEXT,
82ca2ab4
 			  CHOOSE(READ1(sres, inst->u.cast.source); res = sres ? ~0ull : 0,
 				 READ8(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
 				 READ16(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
 				 READ32(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
 				 READ64(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask)));
52dd3a6b
 	    DEFINE_CASTOP(OP_BC_ZEXT,
82ca2ab4
 			  CHOOSE(READ1(res, inst->u.cast.source),
 				 READ8(res, inst->u.cast.source),
 				 READ16(res, inst->u.cast.source),
 				 READ32(res, inst->u.cast.source),
 				 READ64(res, inst->u.cast.source)));
52dd3a6b
 	    DEFINE_CASTOP(OP_BC_TRUNC,
82ca2ab4
 			  CHOOSE(READ1(res, inst->u.cast.source),
 				 READ8(res, inst->u.cast.source),
 				 READ16(res, inst->u.cast.source),
 				 READ32(res, inst->u.cast.source),
 				 READ64(res, inst->u.cast.source)));
 
52dd3a6b
 	    DEFINE_OP(OP_BC_BRANCH)
6922903a
 		stop = jump(func, (values[inst->u.branch.condition]&1) ?
ec5cccc7
 			  inst->u.branch.br_true : inst->u.branch.br_false,
 			  &bb, &inst, &bb_inst);
8c0933ce
 		continue;
82ca2ab4
 
52dd3a6b
 	    DEFINE_OP(OP_BC_JMP)
ec5cccc7
 		stop = jump(func, inst->u.jump, &bb, &inst, &bb_inst);
8c0933ce
 		continue;
82ca2ab4
 
52dd3a6b
 	    DEFINE_OP_BC_RET_N(OP_BC_RET*5, uint8_t, READ1, WRITE8);
 	    DEFINE_OP_BC_RET_N(OP_BC_RET*5+1, uint8_t, READ8, WRITE8);
 	    DEFINE_OP_BC_RET_N(OP_BC_RET*5+2, uint16_t, READ16, WRITE16);
 	    DEFINE_OP_BC_RET_N(OP_BC_RET*5+3, uint32_t, READ32, WRITE32);
 	    DEFINE_OP_BC_RET_N(OP_BC_RET*5+4, uint64_t, READ64, WRITE64);
 
174ecd3c
 	    DEFINE_OP_BC_RET_N(OP_BC_RET_VOID*5, uint8_t, (void), (void));
 	    DEFINE_OP_BC_RET_N(OP_BC_RET_VOID*5+1, uint8_t, (void), (void));
 	    DEFINE_OP_BC_RET_N(OP_BC_RET_VOID*5+2, uint8_t, (void), (void));
 	    DEFINE_OP_BC_RET_N(OP_BC_RET_VOID*5+3, uint8_t, (void), (void));
 	    DEFINE_OP_BC_RET_N(OP_BC_RET_VOID*5+4, uint8_t, (void), (void));
 
52dd3a6b
 	    DEFINE_ICMPOP(OP_BC_ICMP_EQ, res = (op0 == op1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_NE, res = (op0 != op1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_UGT, res = (op0 > op1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_UGE, res = (op0 >= op1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_ULT, res = (op0 < op1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_ULE, res = (op0 <= op1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_SGT, res = (sop0 > sop1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_SGE, res = (sop0 >= sop1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_SLE, res = (sop0 <= sop1));
 	    DEFINE_ICMPOP(OP_BC_ICMP_SLT, res = (sop0 < sop1));
 
 	    case OP_BC_SELECT*5:
82ca2ab4
 	    {
 		uint8_t t0, t1, t2;
 		READ1(t0, inst->u.three[0]);
 		READ1(t1, inst->u.three[1]);
 		READ1(t2, inst->u.three[2]);
 		WRITE8(inst->dest, t0 ? t1 : t2);
8c0933ce
 		break;
82ca2ab4
 	    }
52dd3a6b
 	    case OP_BC_SELECT*5+1:
82ca2ab4
 	    {
 	        uint8_t t0, t1, t2;
 		READ1(t0, inst->u.three[0]);
 		READ8(t1, inst->u.three[1]);
 		READ8(t2, inst->u.three[2]);
 		WRITE8(inst->dest, t0 ? t1 : t2);
8c0933ce
 		break;
82ca2ab4
 	    }
52dd3a6b
 	    case OP_BC_SELECT*5+2:
82ca2ab4
 	    {
 	        uint8_t t0;
 		uint16_t t1, t2;
 		READ1(t0, inst->u.three[0]);
 		READ16(t1, inst->u.three[1]);
 		READ16(t2, inst->u.three[2]);
 		WRITE16(inst->dest, t0 ? t1 : t2);
8c0933ce
 		break;
82ca2ab4
 	    }
52dd3a6b
 	    case OP_BC_SELECT*5+3:
82ca2ab4
 	    {
 	        uint8_t t0;
 		uint32_t t1, t2;
 		READ1(t0, inst->u.three[0]);
 		READ32(t1, inst->u.three[1]);
 		READ32(t2, inst->u.three[2]);
 		WRITE32(inst->dest, t0 ? t1 : t2);
e0c4fd85
 		break;
82ca2ab4
 	    }
52dd3a6b
 	    case OP_BC_SELECT*5+4:
82ca2ab4
 	    {
 	        uint8_t t0;
 		uint64_t t1, t2;
 		READ1(t0, inst->u.three[0]);
 		READ64(t1, inst->u.three[1]);
 		READ64(t2, inst->u.three[2]);
 		WRITE64(inst->dest, t0 ? t1 : t2);
e0c4fd85
 		break;
82ca2ab4
 	    }
 
52dd3a6b
 	    DEFINE_OP(OP_BC_CALL_API) {
cf0cd429
 		const struct cli_apicall *api = &cli_apicalls[inst->u.ops.funcid];
1678ef9e
 		int32_t res32;
 		int64_t res64;
cf0cd429
 		CHECK_APIID(inst->u.ops.funcid);
1678ef9e
 		TRACE_API(api->name, inst->dest, inst->type, stack_depth);
cf0cd429
 	        switch (api->kind) {
 		    case 0: {
e4a0f2c9
 			int32_t a, b;
cf0cd429
 			READ32(a, inst->u.ops.ops[0]);
 			READ32(b, inst->u.ops.ops[1]);
1678ef9e
 			res32 = cli_apicalls0[api->idx](ctx, a, b);
 			WRITE32(inst->dest, res32);
cf0cd429
 			break;
 		    }
 		    case 1: {
a15fc904
 			unsigned i;
74f5816c
 			void* arg1;
a15fc904
 			unsigned arg2, arg1size;
74f5816c
 			READ32(arg2, inst->u.ops.ops[1]);
a15fc904
 			/* check that arg2 is size of arg1 */
 			arg1size = arg2;
 			for (i=0;i<sizeof(apisize_override)/sizeof(apisize_override[0]);i++) {
 			    if (cli_apicalls1[api->idx] == apisize_override[i].api) {
 				arg1size = apisize_override[i].override_size;
 				break;
 			    }
 			}
 			READPOP(arg1, inst->u.ops.ops[0], arg1size);
1678ef9e
 			res32 = cli_apicalls1[api->idx](ctx, arg1, arg2);
 			WRITE32(inst->dest, res32);
74f5816c
 			break;
cf0cd429
 		    }
2d45ef06
 		    case 2: {
 			int32_t a;
 			READ32(a, inst->u.ops.ops[0]);
1678ef9e
 			res32 = cli_apicalls2[api->idx](ctx, a);
 			WRITE32(inst->dest, res32);
2d45ef06
 			break;
 		    }
50829fbf
 		    case 3: {
 			int32_t a;
 			void *resp;
 			READ32(a, inst->u.ops.ops[0]);
 			resp = cli_apicalls3[api->idx](ctx, a);
1678ef9e
 			res64 = ptr_register_glob(&ptrinfos, resp, a);
 			WRITE64(inst->dest, res64);
50829fbf
 			break;
 		    }
 		    case 4: {
 			int32_t arg2, arg3, arg4, arg5;
 			void *arg1;
 			READ32(arg2, inst->u.ops.ops[1]);
a15fc904
 			/* check that arg2 is size of arg1 */
50829fbf
 			READP(arg1, inst->u.ops.ops[0], arg2);
 			READ32(arg3, inst->u.ops.ops[2]);
 			READ32(arg4, inst->u.ops.ops[3]);
 			READ32(arg5, inst->u.ops.ops[4]);
1678ef9e
 			res32 = cli_apicalls4[api->idx](ctx, arg1, arg2, arg3, arg4, arg5);
 			WRITE32(inst->dest, res32);
50829fbf
 			break;
 		    }
 		    case 5: {
1678ef9e
 			res32 = cli_apicalls5[api->idx](ctx);
 			WRITE32(inst->dest, res32);
50829fbf
 			break;
 		    }
 		    case 6: {
 			int32_t arg1, arg2;
 			void *resp;
 			READ32(arg1, inst->u.ops.ops[0]);
 			READ32(arg2, inst->u.ops.ops[1]);
 			resp = cli_apicalls6[api->idx](ctx, arg1, arg2);
1678ef9e
 			res64 = ptr_register_glob(&ptrinfos, resp, arg2);
 			WRITE64(inst->dest, res64);
50829fbf
 			break;
 		    }
 		    case 7: {
 			int32_t arg1,arg2,arg3;
 			READ32(arg1, inst->u.ops.ops[0]);
 			READ32(arg2, inst->u.ops.ops[1]);
 			READ32(arg3, inst->u.ops.ops[2]);
1678ef9e
 			res32 = cli_apicalls7[api->idx](ctx, arg1, arg2, arg3);
 			WRITE32(inst->dest, res32);
50829fbf
 			break;
 		    }
7ebca3d7
 		    case 8: {
 			int32_t arg2, arg4;
 			void *arg1, *arg3;
 			int32_t resp;
 			READ32(arg2, inst->u.ops.ops[1]);
a15fc904
 			/* check that arg2 is size of arg1 */
7ebca3d7
 			READP(arg1, inst->u.ops.ops[0], arg2);
 			READ32(arg4, inst->u.ops.ops[3]);
9eb82c24
 			READP(arg3, inst->u.ops.ops[2], arg4);
7ebca3d7
 			resp = cli_apicalls8[api->idx](ctx, arg1, arg2, arg3, arg4);
 			WRITE32(inst->dest, resp);
 			break;
 		    }
 		    case 9: {
 			int32_t arg2, arg3;
 			void *arg1;
 			int32_t resp;
 			READ32(arg2, inst->u.ops.ops[1]);
a15fc904
 			/* check that arg2 is size of arg1 */
7ebca3d7
 			READP(arg1, inst->u.ops.ops[0], arg2);
9d39dc93
 			READ32(arg3, inst->u.ops.ops[2]);
7ebca3d7
 			resp = cli_apicalls9[api->idx](ctx, arg1, arg2, arg3);
 			WRITE32(inst->dest, resp);
 			break;
 		    };
74f5816c
 		    default:
7f6b55a1
 			cli_warnmsg("bytecode: type %u apicalls not yet implemented!\n", api->kind);
2d45ef06
 			stop = CL_EBYTECODE;
cf0cd429
 		}
 		break;
 	    }
 
52dd3a6b
 	    DEFINE_OP(OP_BC_CALL_DIRECT)
e0c4fd85
 		CHECK_FUNCID(inst->u.ops.funcid);
 		func2 = &bc->funcs[inst->u.ops.funcid];
 		CHECK_EQ(func2->numArgs, inst->u.ops.numOps);
ac7c0544
 		old_values = values;
6922903a
 		stack_entry = allocate_stack(&stack, stack_entry, func2, func, inst->dest,
cfec3d90
 					     bb, bb_inst);
7a14dc4c
 		if (!stack_entry) {
 		    stop = CL_EMEM;
 		    break;
 		}
cfec3d90
 		values = stack_entry->values;
4993d6cf
 		/* TODO: unregister on ret */
11e86f8c
 		TRACE_EXEC(inst->u.ops.funcid, inst->dest, inst->type, stack_depth);
6922903a
 		if (stack_depth > 10000) {
7f6b55a1
 		    cli_warnmsg("bytecode: stack depth exceeded\n");
6922903a
 		    stop = CL_EBYTECODE;
 		    break;
 		}
 		j = 0;
 		for (i=0;i<func2->numArgs;i++) {
 		    switch (inst->u.ops.opsizes[i]) {
 			case 1: {
 			    uint8_t v;
 			    READOLD8(v, inst->u.ops.ops[i]);
 			    CHECK_GT(func2->numBytes, j);
 			    values[j++] = v;
 			    break;
 			}
 			case 2: {
 			    uint16_t v;
 			    READOLD16(v, inst->u.ops.ops[i]);
 			    j = (j+1)&~1;
 			    CHECK_GT(func2->numBytes, j);
 			    *(uint16_t*)&values[j] = v;
 			    j += 2;
 			    break;
 			}
 			case 4: {
 			    uint32_t v;
 			    READOLD32(v, inst->u.ops.ops[i]);
 			    j = (j+3)&~3;
 			    CHECK_GT(func2->numBytes, j);
 			    *(uint32_t*)&values[j] = v;
 			    j += 4;
 			    break;
 			}
 			case 8: {
 			    uint64_t v;
 			    READOLD64(v, inst->u.ops.ops[i]);
 			    j = (j+7)&~7;
 			    CHECK_GT(func2->numBytes, j);
 			    *(uint64_t*)&values[j] = v;
 			    j += 8;
 			    break;
 			}
 		    }
 		}
e0c4fd85
 		func = func2;
4993d6cf
 		stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes)>>32;
e0c4fd85
 		CHECK_GT(func->numBB, 0);
ec5cccc7
 		stop = jump(func, 0, &bb, &inst, &bb_inst);
cfec3d90
 		stack_depth++;
e0c4fd85
 		continue;
82ca2ab4
 
52dd3a6b
 	    case OP_BC_COPY*5:
82ca2ab4
 	    {
 		uint8_t op;
 		READ1(op, BINOP(0));
 		WRITE8(BINOP(1), op);
8c0933ce
 		break;
82ca2ab4
 	    }
52dd3a6b
 	    case OP_BC_COPY*5+1:
82ca2ab4
 	    {
 		uint8_t op;
 		READ8(op, BINOP(0));
 		WRITE8(BINOP(1), op);
 		break;
 	    }
52dd3a6b
 	    case OP_BC_COPY*5+2:
82ca2ab4
 	    {
 		uint16_t op;
 		READ16(op, BINOP(0));
 		WRITE16(BINOP(1), op);
 		break;
 	    }
52dd3a6b
 	    case OP_BC_COPY*5+3:
82ca2ab4
 	    {
 		uint32_t op;
 		READ32(op, BINOP(0));
 		WRITE32(BINOP(1), op);
 		break;
 	    }
52dd3a6b
 	    case OP_BC_COPY*5+4:
82ca2ab4
 	    {
 		uint64_t op;
44e13431
 		READ64(op, BINOP(0));
 		WRITE64(BINOP(1), op);
82ca2ab4
 		break;
 	    }
 
52dd3a6b
 	    case OP_BC_LOAD*5:
 	    case OP_BC_LOAD*5+1:
72617ba2
 	    {
 		uint8_t *ptr;
0d9b99f4
 		READPOP(ptr, inst->u.unaryop, 1);
72617ba2
 		WRITE8(inst->dest, (*ptr));
 		break;
 	    }
52dd3a6b
 	    case OP_BC_LOAD*5+2:
72617ba2
 	    {
 		const union unaligned_16 *ptr;
0d9b99f4
 		READPOP(ptr, inst->u.unaryop, 2);
72617ba2
 		WRITE16(inst->dest, (ptr->una_u16));
 		break;
 	    }
52dd3a6b
 	    case OP_BC_LOAD*5+3:
72617ba2
 	    {
 		const union unaligned_32 *ptr;
0d9b99f4
 		READPOP(ptr, inst->u.unaryop, 4);
72617ba2
 		WRITE32(inst->dest, (ptr->una_u32));
 		break;
 	    }
52dd3a6b
 	    case OP_BC_LOAD*5+4:
72617ba2
 	    {
 		const union unaligned_64 *ptr;
0d9b99f4
 		READPOP(ptr, inst->u.unaryop, 8);
72617ba2
 		WRITE64(inst->dest, (ptr->una_u64));
 		break;
 	    }
 
52dd3a6b
 	    case OP_BC_STORE*5:
72617ba2
 	    {
 		uint8_t *ptr;
 		uint8_t v;
5dfb4bf1
 		READP(ptr, BINOP(1), 1);
 		READ1(v, BINOP(0));
72617ba2
 		*ptr = v;
 		break;
 	    }
52dd3a6b
 	    case OP_BC_STORE*5+1:
72617ba2
 	    {
 		uint8_t *ptr;
 		uint8_t v;
5dfb4bf1
 		READP(ptr, BINOP(1), 1);
 		READ8(v, BINOP(0));
72617ba2
 		*ptr = v;
 		break;
 	    }
52dd3a6b
 	    case OP_BC_STORE*5+2:
72617ba2
 	    {
 		union unaligned_16 *ptr;
 		uint16_t v;
5dfb4bf1
 		READP(ptr, BINOP(1), 2);
 		READ16(v, BINOP(0));
72617ba2
 		ptr->una_s16 = v;
 		break;
 	    }
52dd3a6b
 	    case OP_BC_STORE*5+3:
72617ba2
 	    {
 		union unaligned_32 *ptr;
 		uint32_t v;
5dfb4bf1
 		READP(ptr, BINOP(1), 4);
 		READ32(v, BINOP(0));
72617ba2
 		ptr->una_u32 = v;
 		break;
 	    }
52dd3a6b
 	    case OP_BC_STORE*5+4:
72617ba2
 	    {
 		union unaligned_64 *ptr;
 		uint64_t v;
5dfb4bf1
 		READP(ptr, BINOP(1), 8);
 		READ64(v, BINOP(0));
72617ba2
 		ptr->una_u64 = v;
 		break;
 	    }
7a5e93a0
 	    DEFINE_OP(OP_BC_ISBIGENDIAN) {
 		WRITE8(inst->dest, WORDS_BIGENDIAN);
 		break;
 	    }
4993d6cf
 	    DEFINE_OP(OP_BC_GEPZ) {
 		int64_t ptr;
 		if (!(inst->interp_op%5)) {
0dd40a54
 		    int32_t off;
 		    READ32(off, inst->u.three[2]);
4993d6cf
 		    WRITE64(inst->dest, ptr_compose(stackid,
0dd40a54
 						    inst->u.three[1]+off));
4993d6cf
 		} else {
b9697ed8
 		    int32_t off;
 		    READ32(off, inst->u.three[2]);
1c7c6194
 		    READ64(ptr, inst->u.three[1]);
b9697ed8
 		    WRITE64(inst->dest, ptr+off);
4993d6cf
 		}
 		break;
 	    }
5dfb4bf1
 	    DEFINE_OP(OP_BC_MEMCMP) {
 		int32_t arg3;
 		void *arg1, *arg2;
 		READ32(arg3, inst->u.three[2]);
0d9b99f4
 		READPOP(arg1, inst->u.three[0], arg3);
 		READPOP(arg2, inst->u.three[1], arg3);
5dfb4bf1
 		WRITE32(inst->dest, memcmp(arg1, arg2, arg3));
 		break;
 	    }
 	    DEFINE_OP(OP_BC_MEMCPY) {
ecedf8a9
 		int64_t arg3;
e4a0f2c9
 		void *arg1, *arg2;
0d9b99f4
 		int64_t res=0;
5dfb4bf1
 
7493b2f3
 		READ32(arg3, inst->u.three[2]);
0d9b99f4
 		READPOP(arg1, inst->u.three[0], arg3);
 		READPOP(arg2, inst->u.three[1], arg3);
ecedf8a9
 		memcpy(arg1, arg2, (int32_t)arg3);
0d9b99f4
 /*		READ64(res, inst->u.three[0]);*/
5dfb4bf1
 		WRITE64(inst->dest, res);
 		break;
 	    }
 	    DEFINE_OP(OP_BC_MEMMOVE) {
ecedf8a9
 		int64_t arg3;
e4a0f2c9
 		void *arg1, *arg2;
0d9b99f4
 		int64_t res=0;
5dfb4bf1
 
ecedf8a9
 		READ64(arg3, inst->u.three[2]);
0d9b99f4
 		READPOP(arg1, inst->u.three[0], arg3);
 		READPOP(arg2, inst->u.three[1], arg3);
ecedf8a9
 		memmove(arg1, arg2, (int32_t)arg3);
0d9b99f4
 /*		READ64(res, inst->u.three[0]);*/
5dfb4bf1
 		WRITE64(inst->dest, res);
 		break;
 	    }
 	    DEFINE_OP(OP_BC_MEMSET) {
ecedf8a9
 		int64_t arg3;
 		int32_t arg2;
5dfb4bf1
 		void *arg1;
0d9b99f4
 		int64_t res=0;
5dfb4bf1
 
ecedf8a9
 		READ64(arg3, inst->u.three[2]);
0d9b99f4
 		READPOP(arg1, inst->u.three[0], arg3);
5dfb4bf1
 		READ32(arg2, inst->u.three[1]);
ecedf8a9
 		memset(arg1, arg2, (int32_t)arg3);
0d9b99f4
 /*		READ64(res, inst->u.three[0]);*/
5dfb4bf1
 		WRITE64(inst->dest, res);
 		break;
 	    }
 	    DEFINE_OP(OP_BC_BSWAP16) {
 		int16_t arg1;
 		READ16(arg1, inst->u.unaryop);
 		WRITE16(inst->dest, cbswap16(arg1));
 		break;
 	    }
 	    DEFINE_OP(OP_BC_BSWAP32) {
 		int32_t arg1;
 		READ32(arg1, inst->u.unaryop);
 		WRITE32(inst->dest, cbswap32(arg1));
 		break;
 	    }
 	    DEFINE_OP(OP_BC_BSWAP64) {
f85ae23a
 		int64_t arg1;
5dfb4bf1
 		READ64(arg1, inst->u.unaryop);
 		WRITE64(inst->dest, cbswap64(arg1));
 		break;
 	    }
44e13431
 	    DEFINE_OP(OP_BC_PTRDIFF32) {
 		int64_t ptr1, ptr2;
 		if (BINOP(0)&0x40000000)
 		    ptr1 = ptr_compose(stackid, BINOP(0)&0xbfffffff);
 		else
 		    READ64(ptr1, BINOP(0));
 		if (BINOP(1)&0x40000000)
 		    ptr2 = ptr_compose(stackid, BINOP(1)&0xbfffffff);
 		else
 		    READ64(ptr2, BINOP(1));
 		WRITE32(inst->dest, ptr_diff32(ptr1, ptr2));
 		break;
 	    }
 	    DEFINE_OP(OP_BC_PTRTOINT64) {
 		int64_t ptr;
 		if (inst->u.unaryop&0x40000000)
 		    ptr = ptr_compose(stackid, inst->u.unaryop&0xbfffffff);
 		else
 		    READ64(ptr, BINOP(0));
 		WRITE64(inst->dest, ptr);
 		break;
 	    }
 	    DEFINE_OP(OP_BC_GEP1) {
 		int64_t ptr;
 		if (!(inst->interp_op%5)) {
 		    int32_t off;
 		    READ32(off, inst->u.three[2]);
 		    WRITE64(inst->dest, ptr_compose(stackid,
b9697ed8
 						    inst->u.three[1]+off*inst->u.three[0]));
44e13431
 		} else {
b9697ed8
 		    int32_t off;
 		    READ32(off, inst->u.three[2]);
44e13431
 		    READ64(ptr, inst->u.three[1]);
b9697ed8
 		    WRITE64(inst->dest, ptr+off*inst->u.three[0]);
44e13431
 		}
 		break;
 	    }
52dd3a6b
 	    /* TODO: implement OP_BC_GEP1, OP_BC_GEP2, OP_BC_GEPN */
e0c4fd85
 	    default:
82ca2ab4
 		cli_errmsg("Opcode %u of type %u is not implemented yet!\n",
 			   inst->interp_op/5, inst->interp_op%5);
e0c4fd85
 		stop = CL_EARG;
82ca2ab4
 		continue;
e0c4fd85
 	}
 	bb_inst++;
 	inst++;
29227461
 	if (bb) {
7a14dc4c
 	    CHECK_GT(bb->numInsts, bb_inst);
29227461
 	}
e0c4fd85
     } while (stop == CL_SUCCESS);
74f5816c
     if (cli_debug_flag) {
 	gettimeofday(&tv1, NULL);
 	tv1.tv_sec -= tv0.tv_sec;
 	tv1.tv_usec -= tv0.tv_usec;
44e13431
 	cli_dbgmsg("intepreter bytecode run finished in %luus, after executing %u opcodes\n",
 		   tv1.tv_sec*1000000 + tv1.tv_usec, pc);
74f5816c
     }
1c00d0ac
     if (stop == CL_EBYTECODE) {
 	cli_event_error_str(ctx->bc_events, "interpreter finished with error\n");
 	cli_dbgmsg("intepreter finished with error\n");
     }
e0c4fd85
 
cfec3d90
     cli_stack_destroy(&stack);
48fc8b98
     free(ptrinfos.stack_infos);
     free(ptrinfos.glob_infos);
e0c4fd85
     return stop == CL_BREAK ? CL_SUCCESS : stop;
 }