libclamav/bytecode.c
997a1efe
 /*
7a9022c9
  *  Load, and verify ClamAV bytecode.
997a1efe
  *
  *  Copyright (C) 2009 Sourcefire, Inc.
  *
  *  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"
7a9022c9
 #include "bytecode_priv.h"
997a1efe
 #include "readdb.h"
 #include <string.h>
 
7a9022c9
 struct cli_bc_ctx *cli_bytecode_context_alloc(void)
 {
     struct cli_bc_ctx *ctx = cli_malloc(sizeof(*ctx));
     ctx->bc = NULL;
     ctx->func = NULL;
     ctx->values = NULL;
     ctx->operands = NULL;
6922903a
     ctx->opsizes = NULL;
7a9022c9
     return ctx;
 }
997a1efe
 
7a9022c9
 void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx)
 {
    cli_bytecode_context_clear(ctx);
    free(ctx);
 }
997a1efe
 
7a9022c9
 int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
 {
6922903a
     free(ctx->opsizes);
7a9022c9
     free(ctx->values);
     free(ctx->operands);
     memset(ctx, 0, sizeof(ctx));
957bf651
     return CL_SUCCESS;
7a9022c9
 }
997a1efe
 
6922903a
 static unsigned typesize(const struct cli_bc *bc, uint16_t type)
 {
     if (!type)
 	return 0;
     if (type <= 8)
 	return 1;
     if (type <= 16)
 	return 2;
     if (type <= 32)
 	return 4;
     if (type <= 64)
 	return 8;
7a14dc4c
     return bc->types[type-65].size;
6922903a
 }
 
 static unsigned typealign(const struct cli_bc *bc, uint16_t type)
 {
7a14dc4c
     if (type <= 64) {
 	unsigned size = typesize(bc, type);
 	return size ? size : 1;
     }
     return bc->types[type-65].align;
6922903a
 }
 
30188fcc
 int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, const struct cli_bc *bc, unsigned funcid)
7a9022c9
 {
6922903a
     unsigned i, s=0;
30188fcc
     const struct cli_bc_func *func;
7a9022c9
     if (funcid >= bc->num_func) {
 	cli_errmsg("bytecode: function ID doesn't exist: %u\n", funcid);
 	return CL_EARG;
     }
e0c4fd85
     func = ctx->func = &bc->funcs[funcid];
7a9022c9
     ctx->bc = bc;
     ctx->numParams = func->numArgs;
     ctx->funcid = funcid;
e0c4fd85
     if (func->numArgs) {
 	ctx->operands = cli_malloc(sizeof(*ctx->operands)*func->numArgs);
 	if (!ctx->operands) {
 	    cli_errmsg("bytecode: error allocating memory for parameters\n");
 	    return CL_EMEM;
 	}
6922903a
 	ctx->opsizes = cli_malloc(sizeof(*ctx->opsizes)*func->numArgs);
 	for (i=0;i<func->numArgs;i++) {
 	    unsigned al = typealign(bc, func->types[i]);
 	    s = (s+al-1)&~(al-1);
 	    ctx->operands[i] = s;
 	    s += ctx->opsizes[i] = typesize(bc, func->types[i]);
 	}
7a9022c9
     }
6922903a
     s += 8;/* return value */
     ctx->bytes = s;
     ctx->values = cli_malloc(s);
     if (!ctx->values) {
 	cli_errmsg("bytecode: error allocating memory for parameters\n");
 	return CL_EMEM;
7a9022c9
     }
     return CL_SUCCESS;
 }
997a1efe
 
7a9022c9
 static inline int type_isint(uint16_t type)
997a1efe
 {
7a9022c9
     return type > 0 && type <= 64;
997a1efe
 }
 
7a9022c9
 int cli_bytecode_context_setparam_int(struct cli_bc_ctx *ctx, unsigned i, uint64_t c)
997a1efe
 {
7a9022c9
     if (i >= ctx->numParams) {
 	cli_errmsg("bytecode: param index out of bounds: %u\n", i);
 	return CL_EARG;
     }
     if (!type_isint(ctx->func->types[i])) {
 	cli_errmsg("bytecode: parameter type mismatch\n");
 	return CL_EARG;
     }
6922903a
     switch (ctx->opsizes[i]) {
 	case 1:
 	    ctx->values[ctx->operands[i]] = c;
 	    break;
 	case 2:
 	    *(uint16_t*)&ctx->values[ctx->operands[i]] = c;
 	    break;
 	case 4:
 	    *(uint32_t*)&ctx->values[ctx->operands[i]] = c;
 	    break;
 	case 8:
 	    *(uint64_t*)&ctx->values[ctx->operands[i]] = c;
 	    break;
     }
7a9022c9
     return CL_SUCCESS;
997a1efe
 }
 
7a9022c9
 int cli_bytecode_context_setparam_ptr(struct cli_bc_ctx *ctx, unsigned i, void *data, unsigned datalen)
 {
     cli_errmsg("Pointer parameters are not implemented yet!\n");
     return CL_EARG;
 }
997a1efe
 
 static inline uint64_t readNumber(const unsigned char *p, unsigned *off, unsigned len, char *ok)
 {
     uint64_t n=0;
     unsigned i, newoff, lim, p0 = p[*off], shift=0;
 
     lim = p0 - 0x60;
     if (lim > 0x10) {
 	cli_errmsg("Invalid number type: %c\n", p0);
 	*ok = 0;
 	return 0;
     }
     newoff = *off +lim+1;
     if (newoff > len) {
 	cli_errmsg("End of line encountered while reading number\n");
 	*ok = 0;
 	return 0;
     }
 
     if (p0 == 0x60) {
 	*off = newoff;
 	return 0;
     }
 
     for (i=*off+1;i < newoff; i++) {
 	uint64_t v = p[i];
 	if (UNLIKELY((v&0xf0) != 0x60)) {
d9432eea
 	    cli_errmsg("Invalid number part: %c\n", (char)v);
997a1efe
 	    *ok = 0;
 	    return 0;
 	}
 	v &= 0xf;
 	v <<= shift;
 	n |= v;
 	shift += 4;
     }
     *off = newoff;
     return n;
 }
 
3555ee75
 static inline funcid_t readFuncID(struct cli_bc *bc, unsigned char *p,
 				  unsigned *off, unsigned len, char *ok)
997a1efe
 {
e0c4fd85
     funcid_t id = readNumber(p, off, len, ok)-1;
     if (*ok && id >= bc->num_func) {
3555ee75
 	cli_errmsg("Called function out of range: %u >= %u\n", id, bc->num_func);
 	*ok = 0;
 	return ~0;
     }
     return id;
 }
 
cf0cd429
 static inline funcid_t readAPIFuncID(struct cli_bc *bc, unsigned char *p,
 				     unsigned *off, unsigned len, char *ok)
 {
     funcid_t id = readNumber(p, off, len, ok)-1;
     if (*ok && !cli_bitset_test(bc->uses_apis, id)) {
 	cli_errmsg("Called undeclared API function: %u\n", id);
 	*ok = 0;
 	return ~0;
     }
     return id;
 }
 
997a1efe
 static inline unsigned readFixedNumber(const unsigned char *p, unsigned *off,
 				       unsigned len, char *ok, unsigned width)
 {
     unsigned i, n=0, shift=0;
     unsigned newoff = *off + width;
     if (newoff > len) {
 	cli_errmsg("Newline encountered while reading number\n");
 	*ok = 0;
 	return 0;
     }
     for (i=*off;i<newoff;i++) {
 	unsigned v = p[i];
 	if (UNLIKELY((v&0xf0) != 0x60)) {
 	    cli_errmsg("Invalid number part: %c\n", v);
 	    *ok = 0;
 	    return 0;
 	}
 	v &= 0xf;
 	v <<= shift;
 	n |= v;
 	shift += 4;
     }
     *off = newoff;
     return n;
 }
 
09bd9839
 static inline operand_t readOperand(struct cli_bc_func *func, unsigned char *p,
 				    unsigned *off, unsigned len, char *ok)
 {
     uint64_t v;
     if ((p[*off]&0xf0) == 0x40 || p[*off] == 0x50) {
 	uint64_t *dest;
 	uint16_t ty;
 	p[*off] |= 0x20;
 	/* TODO: unique constants */
 	func->constants = cli_realloc2(func->constants, (func->numConstants+1)*sizeof(*func->constants));
 	if (!func->constants) {
 	    *ok = 0;
 	    return MAX_OP;
 	}
 	v = readNumber(p, off, len, ok);
 	dest = &func->constants[func->numConstants];
 	/* Write the constant to the correct place according to its type.
 	 * This is needed on big-endian machines, because constants are always
 	 * read as u64, but accesed as one of these types: u8, u16, u32, u64 */
 	*dest= 0;
 	ty = 8*readFixedNumber(p, off, len, ok, 1);
 	if (!ty) {
 	    cli_errmsg("bytecode: void type constant is invalid!\n");
 	    *ok = 0;
 	    return MAX_OP;
 	}
 	if (ty <= 8)
 	    *(uint8_t*)dest = v;
 	else if (ty <= 16)
 	    *(uint16_t*)dest = v;
 	else if (ty <= 32)
 	    *(uint32_t*)dest = v;
 	else
 	    *dest = v;
 	return func->numValues + func->numConstants++;
     }
     v = readNumber(p, off, len, ok);
     if (!*ok)
 	return MAX_OP;
     if (v >= func->numValues) {
 	cli_errmsg("Operand index exceeds bounds: %u >= %u!\n", (unsigned)v, (unsigned)func->numValues);
 	*ok = 0;
 	return MAX_OP;
     }
     return v;
 }
 
c3c97d4a
 static inline unsigned char *readData(const unsigned char *p, unsigned *off, unsigned len, char *ok, unsigned *datalen)
997a1efe
 {
     unsigned char *dat, *q;
     unsigned l, newoff, i;
     if (p[*off] != '|') {
 	cli_errmsg("Data start marker missing: %c\n", p[*off]);
 	*ok = 0;
 	return NULL;
     }
     (*off)++;
     l = readNumber(p, off, len, ok);
8c0933ce
     if (!l) {
 	*datalen = l;
997a1efe
 	return NULL;
8c0933ce
     }
cf0cd429
     newoff = *off + 2*l;
997a1efe
     if (newoff > len) {
 	cli_errmsg("Line ended while reading data\n");
 	*ok = 0;
 	return 0;
     }
     dat = cli_malloc(l);
     if (!dat) {
 	cli_errmsg("Cannot allocate memory for data\n");
 	*ok = 0;
 	return NULL;
     }
     q = dat;
cf0cd429
     for (i=*off;i<newoff;i += 2) {
 	const unsigned char v0 = p[i];
 	const unsigned char v1 = p[i+1];
 	if (UNLIKELY((v0&0xf0) != 0x60 || (v1&0xf0) != 0x60)) {
 	    cli_errmsg("Invalid data part: %c%c\n", v0, v1);
997a1efe
 	    *ok = 0;
 	    return 0;
 	}
cf0cd429
 	*q++ = (v0&0xf) | ((v1&0xf) << 4);
997a1efe
     }
     *off = newoff;
c3c97d4a
     *datalen = l;
997a1efe
     return dat;
 }
 
c3c97d4a
 static inline char *readString(const unsigned char *p, unsigned *off, unsigned len, char *ok)
 {
     unsigned stringlen;
     char *str = (char*)readData(p, off, len, ok, &stringlen);
     if (*ok && stringlen && str[stringlen-1] != '\0') {
cf0cd429
 	str[stringlen-1] = '\0';
 	cli_errmsg("bytecode: string missing \\0 terminator: %s\n", str);
c3c97d4a
 	free(str);
 	*ok = 0;
 	return NULL;
     }
     return str;
 }
8cc286f5
 
c3c97d4a
 static int parseHeader(struct cli_bc *bc, unsigned char *buffer)
997a1efe
 {
     uint64_t magic1;
     unsigned magic2;
     char ok = 1;
     unsigned offset, len, flevel;
30188fcc
     if (strncmp((const char*)buffer, BC_HEADER, sizeof(BC_HEADER)-1)) {
997a1efe
 	cli_errmsg("Missing file magic in bytecode");
 	return CL_EMALFDB;
     }
     offset = sizeof(BC_HEADER)-1;
c3c97d4a
     len = strlen((const char*)buffer);
997a1efe
     flevel = readNumber(buffer, &offset, len, &ok);
     if (!ok) {
 	cli_errmsg("Unable to parse functionality level in bytecode header\n");
 	return CL_EMALFDB;
     }
     if (flevel > BC_FUNC_LEVEL) {
 	cli_dbgmsg("Skipping bytecode with functionality level: %u\n", flevel);
 	return CL_BREAK;
     }
     // Optimistic parsing, check for error only at the end.
     bc->verifier = readNumber(buffer, &offset, len, &ok);
c3c97d4a
     bc->sigmaker = readString(buffer, &offset, len, &ok);
997a1efe
     bc->id = readNumber(buffer, &offset, len, &ok);
     bc->metadata.maxStack = readNumber(buffer, &offset, len, &ok);
     bc->metadata.maxMem = readNumber(buffer, &offset, len, &ok);
     bc->metadata.maxTime = readNumber(buffer, &offset, len, &ok);
c3c97d4a
     bc->metadata.targetExclude = readString(buffer, &offset, len, &ok);
8cc286f5
     bc->num_types = readNumber(buffer, &offset, len, &ok);
997a1efe
     bc->num_func = readNumber(buffer, &offset, len, &ok);
6922903a
     bc->state = bc_loaded;
cf0cd429
     bc->uses_apis = NULL;
997a1efe
     if (!ok) {
c3c97d4a
 	cli_errmsg("Invalid bytecode header at %u\n", offset);
997a1efe
 	return CL_EMALFDB;
     }
     magic1 = readNumber(buffer, &offset, len, &ok);
     magic2 = readFixedNumber(buffer, &offset, len, &ok, 2);
     if (!ok || magic1 != 0x53e5493e9f3d1c30ull || magic2 != 42) {
d9432eea
       unsigned long m0 = magic1 >> 32;
       unsigned long m1 = magic1;
997a1efe
       cli_errmsg("Magic numbers don't match: %lx%lx, %u\n", m0, m1, magic2);
       return CL_EMALFDB;
     }
     if (offset != len) {
 	cli_errmsg("Trailing garbage in bytecode header: %d extra bytes\n",
 		   len-offset);
 	return CL_EMALFDB;
     }
 
     bc->funcs = cli_calloc(bc->num_func, sizeof(*bc->funcs));
     if (!bc->funcs) {
 	cli_errmsg("Out of memory allocating %u functions\n", bc->num_func);
 	return CL_EMEM;
     }
8cc286f5
     bc->types = cli_calloc(bc->num_types, sizeof(*bc->types));
     if (!bc->types) {
 	cli_errmsg("Out of memory allocating %u types\n", bc->num_types);
 	return CL_EMEM;
     }
     return CL_SUCCESS;
 }
 
 static uint16_t readTypeID(struct cli_bc *bc, unsigned char *buffer,
 			   unsigned *offset, unsigned len, char *ok)
 {
     uint64_t t = readNumber(buffer, offset, len, ok);
     if (!ok)
800a79e0
 	return ~0;
8cc286f5
     if (t >= bc->num_types + bc->start_tid) {
800a79e0
 	cli_errmsg("Invalid type id: %llu\n", (unsigned long long)t);
8cc286f5
 	*ok = 0;
800a79e0
 	return ~0;
8cc286f5
     }
     return t;
 }
 
 static void parseType(struct cli_bc *bc, struct cli_bc_type *ty,
 		      unsigned char *buffer, unsigned *off, unsigned len,
 		      char *ok)
 {
     unsigned j;
 
     ty->numElements = readFixedNumber(buffer, off, len, ok, 1);
     if (!ok) {
 	cli_errmsg("Error parsing type\n");
 	*ok = 0;
 	return;
     }
     ty->containedTypes = cli_malloc(sizeof(*ty->containedTypes)*ty->numElements);
     if (!ty->containedTypes) {
 	cli_errmsg("Out of memory allocating %u types\n", ty->numElements);
 	*ok = 0;
 	return;
     }
     for (j=0;j<ty->numElements;j++) {
 	ty->containedTypes[j] = readTypeID(bc, buffer, off, len, ok);
     }
 }
 
 static uint16_t containedTy[] = {8,16,32,64};
 
36fab4bd
 #define NUM_STATIC_TYPES 4
8cc286f5
 static void add_static_types(struct cli_bc *bc)
 {
     unsigned i;
36fab4bd
     for (i=0;i<NUM_STATIC_TYPES;i++) {
c466339d
 	bc->types[i].kind = DPointerType;
8cc286f5
 	bc->types[i].numElements = 1;
 	bc->types[i].containedTypes = &containedTy[i];
7a14dc4c
 	bc->types[i].size = bc->types[i].align = sizeof(void*);
8cc286f5
     }
 }
 
 static int parseTypes(struct cli_bc *bc, unsigned char *buffer)
 {
cf0cd429
     unsigned i, offset = 1, len = strlen((const char*)buffer);
800a79e0
     char ok=1;
 
8cc286f5
     if (buffer[0] != 'T') {
 	cli_errmsg("Invalid function types header: %c\n", buffer[0]);
 	return CL_EMALFDB;
     }
     bc->start_tid = readFixedNumber(buffer, &offset, len, &ok, 2);
     if (bc->start_tid != BC_START_TID) {
 	cli_warnmsg("Type start id mismatch: %u != %u\n", bc->start_tid,
 		    BC_START_TID);
 	return CL_BREAK;
     }
     add_static_types(bc);
     for (i=(BC_START_TID - 64);i<bc->num_types;i++) {
 	struct cli_bc_type *ty = &bc->types[i];
 	uint8_t t = readFixedNumber(buffer, &offset, len, &ok, 1);
 	if (!ok) {
 	    cli_errmsg("Error reading type kind\n");
 	    return CL_EMALFDB;
 	}
 	switch (t) {
 	    case 1:
c466339d
 		ty->kind = DFunctionType;
7a14dc4c
 		ty->size = ty->align = sizeof(void*);
8cc286f5
 		parseType(bc, ty, buffer, &offset, len, &ok);
 		if (!ok) {
 		    cli_errmsg("Error parsing type %u\n", i);
 		    return CL_EMALFDB;
 		}
 		break;
 	    case 2:
 	    case 3:
c466339d
 		ty->kind = (t == 2) ? DStructType : DPackedStructType;
7a14dc4c
 		ty->size = ty->align = 0;/* TODO:calculate size/align of structs */
8cc286f5
 		parseType(bc, ty, buffer, &offset, len, &ok);
 		if (!ok) {
 		    cli_errmsg("Error parsing type %u\n", i);
 		    return CL_EMALFDB;
 		}
 		break;
 	    case 4:
c466339d
 		ty->kind = DArrayType;
8cc286f5
 		/* number of elements of array, not subtypes! */
 		ty->numElements = readNumber(buffer, &offset, len, &ok);
 		if (!ok) {
 		    cli_errmsg("Error parsing type %u\n", i);
 		    return CL_EMALFDB;
 		}
 		/* fall-through */
 	    case 5:
 		if (t == 5) {
c466339d
 		    ty->kind = DPointerType;
8cc286f5
 		    ty->numElements = 1;
 		}
 		ty->containedTypes = cli_malloc(sizeof(*ty->containedTypes));
 		if (!ty->containedTypes) {
 		    cli_errmsg("Out of memory allocating containedType\n");
 		    return CL_EMALFDB;
 		}
 		ty->containedTypes[0] = readTypeID(bc, buffer, &offset, len, &ok);
 		if (!ok) {
 		    cli_errmsg("Error parsing type %u\n", i);
 		    return CL_EMALFDB;
 		}
7a14dc4c
 		if (t == 5) {
 		    ty->size = ty->align = sizeof(void);
 		} else {
 		    ty->size = ty->numElements*typesize(bc, ty->containedTypes[0]);
 		    ty->align = typealign(bc, ty->containedTypes[0]);
 		}
8cc286f5
 		break;
 	    default:
 		cli_errmsg("Invalid type kind: %u\n", t);
 		return CL_EMALFDB;
 	}
     }
     return CL_SUCCESS;
 }
 
cf0cd429
 /* checks whether the type described by tid is the same as the one described by
  * expectty. */
 static int types_equal(const struct cli_bc *bc, uint16_t *apity2ty, uint16_t tid, uint16_t apitid)
 {
     unsigned i;
     const struct cli_bc_type *ty = &bc->types[tid - 63];
     const struct cli_bc_type *apity = &cli_apicall_types[apitid];
     /* If we've already verified type equality, return.
      * Since we need to check equality of recursive types, we assume types are
      * equal while checking equality of contained types, unless proven
      * otherwise. */
      if (apity2ty[apitid] == tid + 1)
 	return 1;
      apity2ty[apitid] = tid+1;
 
      if (ty->kind != apity->kind) {
 	 cli_dbgmsg("bytecode: type kind mismatch: %u != %u\n", ty->kind, apity->kind);
 	 return 0;
      }
      if (ty->numElements != apity->numElements) {
 	 cli_dbgmsg("bytecode: type numElements mismatch: %u != %u\n", ty->numElements, apity->numElements);
 	 return 0;
      }
     for (i=0;i<ty->numElements;i++) {
 	if (apity->containedTypes[i] < BC_START_TID) {
 	    if (ty->containedTypes[i] != apity->containedTypes[i])
 		return 0;
 	} else if (!types_equal(bc, apity2ty, ty->containedTypes[i], apity->containedTypes[i] - BC_START_TID))
 	    return 0;
     }
     return 1;
 }
 
8cc286f5
 static int parseApis(struct cli_bc *bc, unsigned char *buffer)
 {
cf0cd429
     unsigned i, offset = 1, len = strlen((const char*)buffer), maxapi, calls;
     char ok =1;
     uint16_t *apity2ty;/*map of api type to current bytecode type ID */
 
     if (buffer[0] != 'E') {
 	cli_errmsg("bytecode: Invalid api header: %c\n", buffer[0]);
 	return CL_EMALFDB;
     }
 
     maxapi = readNumber(buffer, &offset, len, &ok);
     if (!ok)
 	return CL_EMALFDB;
     if (maxapi > cli_apicall_maxapi) {
 	cli_dbgmsg("bytecode using API %u, but highest API known to libclamav is %u, skipping\n", maxapi, cli_apicall_maxapi);
 	return CL_BREAK;
     }
     calls = readNumber(buffer, &offset, len, &ok);
     if (!ok)
 	return CL_EMALFDB;
     if (calls > maxapi) {
 	cli_errmsg("bytecode: attempting to describe more APIs than max: %u > %u\n", calls, maxapi);
 	return CL_EMALFDB;
     }
     bc->uses_apis = cli_bitset_init();
     if (!bc->uses_apis) {
 	cli_errmsg("Out of memory allocating apis bitset\n");
 	return CL_EMEM;
     }
     apity2ty = cli_calloc(cli_apicall_maxtypes, sizeof(*cli_apicall_types));
     if (!apity2ty) {
 	cli_errmsg("Out of memory allocating apity2ty\n");
 	return CL_EMEM;
     }
     for (i=0;i < calls; i++) {
 	unsigned id = readNumber(buffer, &offset, len, &ok);
 	uint16_t tid = readTypeID(bc, buffer, &offset, len, &ok);
 	char *name = readString(buffer, &offset, len, &ok);
 
 	/* validate APIcall prototype */
 	if (id > maxapi) {
 	    cli_errmsg("bytecode: API id %u out of range, max %u\n", id, maxapi);
 	    ok = 0;
 	}
 	/* API ids start from 1 */
 	id--;
 	if (ok && name && strcmp(cli_apicalls[id].name, name)) {
 	    cli_errmsg("bytecode: API %u name mismatch: %s expected %s\n", id, name, cli_apicalls[id].name);
 	    ok = 0;
 	}
 	if (ok && !types_equal(bc, apity2ty, tid, cli_apicalls[id].type)) {
 	    cli_errmsg("bytecode: API %u prototype doesn't match\n", id);
 	    ok = 0;
 	}
 	/* don't need the name anymore */
 	free(name);
 	if (!ok)
 	    return CL_EMALFDB;
 
 	/* APIcall is valid */
 	cli_bitset_set(bc->uses_apis, id);
     }
     free(apity2ty); /* free temporary map */
     cli_dbgmsg("bytecode: Parsed %u APIcalls, maxapi %u\n", calls, maxapi);
997a1efe
     return CL_SUCCESS;
 }
 
c3c97d4a
 static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *buffer)
997a1efe
 {
     char ok=1;
     unsigned offset, len, all_locals=0, i;
     struct cli_bc_func *func;
 
     if (fn >= bc->num_func) {
 	cli_errmsg("Found more functions than declared: %u >= %u\n", fn,
 		   bc->num_func);
 	return CL_EMALFDB;
     }
     func = &bc->funcs[fn];
c3c97d4a
     len = strlen((const char*)buffer);
997a1efe
 
     if (buffer[0] != 'A') {
 	cli_errmsg("Invalid function arguments header: %c\n", buffer[0]);
 	return CL_EMALFDB;
     }
     offset = 1;
     func->numArgs = readFixedNumber(buffer, &offset, len, &ok, 1);
3b33bd68
     func->returnType = readTypeID(bc, buffer, &offset, len, &ok);
997a1efe
     if (buffer[offset] != 'L') {
 	cli_errmsg("Invalid function locals header: %c\n", buffer[offset]);
 	return CL_EMALFDB;
     }
     offset++;
     func->numLocals = readNumber(buffer, &offset, len, &ok);
     if (!ok) {
 	cli_errmsg("Invalid number of arguments/locals\n");
 	return CL_EMALFDB;
     }
     all_locals = func->numArgs + func->numLocals;
     func->types = cli_calloc(all_locals, sizeof(*func->types));
     if (!func->types) {
 	cli_errmsg("Out of memory allocating function arguments\n");
 	return CL_EMEM;
     }
     for (i=0;i<all_locals;i++) {
 	func->types[i] = readNumber(buffer, &offset, len, &ok);
     }
     if (!ok) {
 	cli_errmsg("Invalid local types\n");
 	return CL_EMALFDB;
     }
     if (buffer[offset] != 'F') {
 	cli_errmsg("Invalid function body header: %c\n", buffer[offset]);
 	return CL_EMALFDB;
     }
     offset++;
3555ee75
     func->numInsts = readNumber(buffer, &offset, len, &ok);
     if (!ok ){
 	cli_errmsg("Invalid instructions count\n");
 	return CL_EMALFDB;
     }
ec5cccc7
     func->numValues = func->numArgs + func->numLocals;
3555ee75
     func->insn_idx = 0;
     func->numConstants=0;
     func->allinsts = cli_calloc(func->numInsts, sizeof(*func->allinsts));
     if (!func->allinsts) {
 	cli_errmsg("Out of memory allocating instructions\n");
 	return CL_EMEM;
     }
997a1efe
     func->numBB = readNumber(buffer, &offset, len, &ok);
     if (!ok) {
 	cli_errmsg("Invalid basic block count\n");
 	return CL_EMALFDB;
     }
     func->BB = cli_calloc(func->numBB, sizeof(*func->BB));
     if (!func->BB) {
 	cli_errmsg("Out of memory allocating basic blocks\n");
 	return CL_EMEM;
     }
     return CL_SUCCESS;
 }
 
3555ee75
 static bbid_t readBBID(struct cli_bc_func *func, const unsigned char *buffer, unsigned *off, unsigned len, char *ok) {
c3c97d4a
     unsigned id = readNumber(buffer, off, len, ok);
     if (!id || id >= func->numBB) {
 	cli_errmsg("Basic block ID out of range: %u\n", id);
 	*ok = 0;
     }
     if (!*ok)
3555ee75
 	return ~0;
     return id;
c3c97d4a
 }
 
800a79e0
 /*
6922903a
 static uint16_t get_type(struct cli_bc_func *func, operand_t op)
 {
     if (op >= func->numValues)
 	return 64;
     return func->types[op];
800a79e0
 }*/
6922903a
 
c3c97d4a
 static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char *buffer)
997a1efe
 {
     char ok=1;
6922903a
     unsigned offset, len, i, last = 0;
997a1efe
     struct cli_bc_bb *BB;
c3c97d4a
     struct cli_bc_func *bcfunc = &bc->funcs[func];
997a1efe
     struct cli_bc_inst inst;
 
c3c97d4a
     if (bb >= bcfunc->numBB) {
997a1efe
 	cli_errmsg("Found too many basic blocks\n");
 	return CL_EMALFDB;
     }
 
c3c97d4a
     BB = &bcfunc->BB[bb];
     len = strlen((const char*) buffer);
997a1efe
     if (buffer[0] != 'B') {
 	cli_errmsg("Invalid basic block header: %c\n", buffer[0]);
 	return CL_EMALFDB;
     }
     offset = 1;
     BB->numInsts = 0;
3555ee75
     BB->insts = &bcfunc->allinsts[bcfunc->insn_idx];
997a1efe
     while (!last) {
800a79e0
 	unsigned numOp;
997a1efe
 	if (buffer[offset] == 'T') {
 	    last = 1;
 	    offset++;
 	    /* terminators are void */
 	    inst.type = 0;
f3b2dc9e
 	    inst.dest = 0;
997a1efe
 	} else {
 	    inst.type = readNumber(buffer, &offset, len, &ok);
f3b2dc9e
 	    inst.dest = readNumber(buffer, &offset, len, &ok);
997a1efe
 	}
 	inst.opcode = readFixedNumber(buffer, &offset, len, &ok, 2);
 	if (!ok) {
 	    cli_errmsg("Invalid type or operand\n");
 	    return CL_EMALFDB;
 	}
 	if (inst.opcode >= OP_INVALID) {
 	    cli_errmsg("Invalid opcode: %u\n", inst.opcode);
 	    return CL_EMALFDB;
 	}
09bd9839
 
c3c97d4a
 	switch (inst.opcode) {
 	    case OP_JMP:
 		inst.u.jump = readBBID(bcfunc, buffer, &offset, len, &ok);
997a1efe
 		break;
6922903a
 	    case OP_RET:
 		inst.type = readNumber(buffer, &offset, len, &ok);
09bd9839
 		inst.u.unaryop = readOperand(bcfunc, buffer, &offset, len, &ok);
6922903a
 		break;
c3c97d4a
 	    case OP_BRANCH:
3555ee75
 		inst.u.branch.condition = readOperand(bcfunc, buffer, &offset, len, &ok);
c3c97d4a
 		inst.u.branch.br_true = readBBID(bcfunc, buffer, &offset, len, &ok);
 		inst.u.branch.br_false = readBBID(bcfunc, buffer, &offset, len, &ok);
997a1efe
 		break;
cf0cd429
 	    case OP_CALL_API:/* fall-through */
a0d6fec0
 	    case OP_CALL_DIRECT:
3555ee75
 		numOp = readFixedNumber(buffer, &offset, len, &ok, 1);
a0d6fec0
 		if (ok) {
 		    inst.u.ops.numOps = numOp;
6922903a
 		    inst.u.ops.opsizes=NULL;
a0d6fec0
 		    inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops));
 		    if (!inst.u.ops.ops) {
 			cli_errmsg("Out of memory allocating operands\n");
 			return CL_EMALFDB;
 		    }
cf0cd429
 		    if (inst.opcode == OP_CALL_DIRECT)
 			inst.u.ops.funcid = readFuncID(bc, buffer, &offset, len, &ok);
 		    else
 			inst.u.ops.funcid = readAPIFuncID(bc, buffer, &offset, len, &ok);
a0d6fec0
 		    for (i=0;i<numOp;i++) {
3555ee75
 			inst.u.ops.ops[i] = readOperand(bcfunc, buffer, &offset, len, &ok);
a0d6fec0
 		    }
 		}
 		break;
e0c4fd85
 	    case OP_ZEXT:
 	    case OP_SEXT:
 	    case OP_TRUNC:
 		inst.u.cast.source = readOperand(bcfunc, buffer, &offset, len, &ok);
cfec3d90
 		inst.u.cast.mask = bcfunc->types[inst.u.cast.source];
82ca2ab4
 		if (inst.u.cast.mask == 1)
 		    inst.u.cast.size = 0;
 		else if (inst.u.cast.mask <= 8)
 		    inst.u.cast.size = 1;
 		else if (inst.u.cast.mask <= 16)
 		    inst.u.cast.size = 2;
 		else if (inst.u.cast.mask <= 32)
 		    inst.u.cast.size = 3;
 		else if (inst.u.cast.mask <= 64)
 		    inst.u.cast.size = 4;
cfec3d90
 		/* calculate mask */
 		if (inst.opcode != OP_SEXT)
 		    inst.u.cast.mask = inst.u.cast.mask != 64 ?
 			(1ull<<inst.u.cast.mask)-1 :
 			~0ull;
e0c4fd85
 		break;
09bd9839
 	    case OP_ICMP_EQ:
 	    case OP_ICMP_NE:
 	    case OP_ICMP_UGT:
 	    case OP_ICMP_UGE:
 	    case OP_ICMP_ULT:
 	    case OP_ICMP_ULE:
 	    case OP_ICMP_SGT:
 	    case OP_ICMP_SGE:
 	    case OP_ICMP_SLE:
 	    case OP_ICMP_SLT:
 		/* instruction type must be correct before readOperand! */
 		inst.type = readNumber(buffer, &offset, len, &ok);
 		/* fall-through */
997a1efe
 	    default:
c3c97d4a
 		numOp = operand_counts[inst.opcode];
 		switch (numOp) {
 		    case 1:
3555ee75
 			inst.u.unaryop = readOperand(bcfunc, buffer, &offset, len, &ok);
c3c97d4a
 			break;
 		    case 2:
3555ee75
 			inst.u.binop[0] = readOperand(bcfunc, buffer, &offset, len, &ok);
 			inst.u.binop[1] = readOperand(bcfunc, buffer, &offset, len, &ok);
c3c97d4a
 			break;
 		    case 3:
3555ee75
 			inst.u.three[0] = readOperand(bcfunc, buffer, &offset, len, &ok);
 			inst.u.three[1] = readOperand(bcfunc, buffer, &offset, len, &ok);
 			inst.u.three[2] = readOperand(bcfunc, buffer, &offset, len, &ok);
c3c97d4a
 			break;
 		    default:
a0d6fec0
 			cli_errmsg("Opcode with too many operands: %u?\n", numOp);
 			ok = 0;
c3c97d4a
 			break;
997a1efe
 		}
 	}
 	if (!ok) {
 	    cli_errmsg("Invalid instructions or operands\n");
 	    return CL_EMALFDB;
 	}
3555ee75
 	if (bcfunc->insn_idx + BB->numInsts >= bcfunc->numInsts) {
6922903a
 	    cli_errmsg("More instructions than declared in total: %u > %u!\n",
 		       bcfunc->insn_idx+BB->numInsts, bcfunc->numInsts);
3555ee75
 	    return CL_EMALFDB;
997a1efe
 	}
82ca2ab4
 	inst.interp_op = inst.opcode*5;
09bd9839
 	if (inst.type > 1) {
 	    if (inst.type <= 8)
 		inst.interp_op += 1;
 	    else if (inst.type <= 16)
 		inst.interp_op += 2;
 	    else if (inst.type <= 32)
 		inst.interp_op += 3;
 	    else if (inst.type <= 64)
 		inst.interp_op += 4;
 	}
3555ee75
 	BB->insts[BB->numInsts++] = inst;
997a1efe
     }
2cad7c39
     if (bb+1 == bc->funcs[func].numBB) {
997a1efe
 	if (buffer[offset] != 'E') {
 	    cli_errmsg("Missing basicblock terminator, got: %c\n", buffer[offset]);
 	    return CL_EMALFDB;
 	}
 	offset++;
     }
     if (offset != len) {
 	cli_errmsg("Trailing garbage in basicblock: %d extra bytes\n",
 		   len-offset);
 	return CL_EMALFDB;
     }
6922903a
     bcfunc->numBytes = 0;
f3b2dc9e
     bcfunc->insn_idx += BB->numInsts;
997a1efe
     return CL_SUCCESS;
 }
 
 enum parse_state {
     PARSE_BC_HEADER=0,
8cc286f5
     PARSE_BC_TYPES,
     PARSE_BC_APIS,
997a1efe
     PARSE_FUNC_HEADER,
     PARSE_BB
 };
 
 int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio)
 {
     unsigned row = 0, current_func = 0, bb=0;
     char buffer[FILEBUFF];
     enum parse_state state = PARSE_BC_HEADER;
 
     if (!f && !dbio) {
 	cli_errmsg("Unable to load bytecode (null file)\n");
 	return CL_ENULLARG;
     }
     while (cli_dbgets(buffer, FILEBUFF, f, dbio)) {
 	int rc;
 	cli_chomp(buffer);
f60a0e00
 	row++;
997a1efe
 	switch (state) {
 	    case PARSE_BC_HEADER:
c3c97d4a
 		rc = parseHeader(bc, (unsigned char*)buffer);
997a1efe
 		if (rc == CL_BREAK) /* skip */
 		    return CL_SUCCESS;
f60a0e00
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
997a1efe
 		    return rc;
f60a0e00
 		}
8cc286f5
 		state = PARSE_BC_TYPES;
 		break;
 	    case PARSE_BC_TYPES:
 		rc = parseTypes(bc, (unsigned char*)buffer);
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
 		    return rc;
 		}
 		state = PARSE_BC_APIS;
 		break;
 	    case PARSE_BC_APIS:
 		rc = parseApis(bc, (unsigned char*)buffer);
 		if (rc == CL_BREAK) /* skip */
 		    return CL_SUCCESS;
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
 		    return rc;
 		}
997a1efe
 		state = PARSE_FUNC_HEADER;
 		break;
 	    case PARSE_FUNC_HEADER:
c3c97d4a
 		rc = parseFunctionHeader(bc, current_func, (unsigned char*)buffer);
f60a0e00
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
997a1efe
 		    return rc;
f60a0e00
 		}
997a1efe
 		bb = 0;
 		state = PARSE_BB;
 		break;
 	    case PARSE_BB:
c3c97d4a
 		rc = parseBB(bc, current_func, bb++, (unsigned char*)buffer);
f60a0e00
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
997a1efe
 		    return rc;
f60a0e00
 		}
997a1efe
 		if (bb >= bc->funcs[current_func].numBB) {
6922903a
 		    if (bc->funcs[current_func].insn_idx != bc->funcs[current_func].numInsts) {
 			cli_errmsg("Parsed different number of instructions than declared: %u != %u\n",
 				   bc->funcs[current_func].insn_idx, bc->funcs[current_func].numInsts);
 			return CL_EMALFDB;
 		    }
cfec3d90
 		    cli_dbgmsg("Parsed %u BBs, %u instructions\n",
 			       bb, bc->funcs[current_func].numInsts);
997a1efe
 		    state = PARSE_FUNC_HEADER;
 		    current_func++;
 		}
 		break;
 	}
     }
     cli_dbgmsg("Parsed %d functions\n", current_func);
957bf651
     if (current_func != bc->num_func) {
 	cli_errmsg("Loaded less functions than declared: %u vs. %u\n",
 		   current_func, bc->num_func);
 	return CL_EMALFDB;
     }
997a1efe
     return CL_SUCCESS;
 }
 
85a25497
 int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, struct cli_bc_ctx *ctx)
997a1efe
 {
7a9022c9
     struct cli_bc_inst inst;
     struct cli_bc_func func;
e0c4fd85
     if (!ctx || !ctx->bc || !ctx->func)
 	return CL_ENULLARG;
     if (ctx->numParams && (!ctx->values || !ctx->operands))
7a9022c9
 	return CL_ENULLARG;
6922903a
     if (bc->state == bc_loaded) {
 	cli_errmsg("bytecode has to be prepared either for interpreter or JIT!\n");
 	return CL_EARG;
7a9022c9
     }
85a25497
     if (bc->state == bc_interp) {
 	memset(&func, 0, sizeof(func));
 	func.numInsts = 1;
 	func.numValues = 1;
 	func.numBytes = ctx->bytes;
 	memset(ctx->values+ctx->bytes-8, 0, 8);
7a9022c9
 
85a25497
 	inst.opcode = OP_CALL_DIRECT;
 	inst.interp_op = OP_CALL_DIRECT*5;
 	inst.dest = func.numArgs;
 	inst.type = 0;
 	inst.u.ops.numOps = ctx->numParams;
 	inst.u.ops.funcid = ctx->funcid;
 	inst.u.ops.ops = ctx->operands;
 	inst.u.ops.opsizes = ctx->opsizes;
d1487222
 	return cli_vm_execute(ctx->bc, ctx, &func, &inst);
85a25497
     }
     return cli_vm_execute_jit(bcs, ctx, &bc->funcs[ctx->funcid]);
f3b2dc9e
 }
 
 uint64_t cli_bytecode_context_getresult_int(struct cli_bc_ctx *ctx)
 {
09bd9839
     return *(uint32_t*)ctx->values;/*XXX*/
6922903a
 //    return ctx->values[ctx->numParams];
997a1efe
 }
 
 void cli_bytecode_destroy(struct cli_bc *bc)
 {
     unsigned i, j, k;
     free(bc->sigmaker);
     free(bc->metadata.targetExclude);
 
     for (i=0;i<bc->num_func;i++) {
 	struct cli_bc_func *f = &bc->funcs[i];
 	free(f->types);
 
 	for (j=0;j<f->numBB;j++) {
 	    struct cli_bc_bb *BB = &f->BB[j];
 	    for(k=0;k<BB->numInsts;k++) {
2cad7c39
 		struct cli_bc_inst *ii = &BB->insts[k];
36fab4bd
 		if (operand_counts[ii->opcode] > 3 ||
 		    ii->opcode == OP_CALL_DIRECT || ii->opcode == OP_CALL_API) {
2cad7c39
 		    free(ii->u.ops.ops);
6922903a
 		    free(ii->u.ops.opsizes);
 		}
997a1efe
 	    }
 	}
 	free(f->BB);
3555ee75
 	free(f->allinsts);
ac7c0544
 	free(f->constants);
997a1efe
     }
     free(bc->funcs);
36fab4bd
     for (i=NUM_STATIC_TYPES;i<bc->num_types;i++) {
 	if (bc->types[i].containedTypes)
 	    free(bc->types[i].containedTypes);
     }
     free(bc->types);
cf0cd429
     if (bc->uses_apis)
 	cli_bitset_free(bc->uses_apis);
997a1efe
 }
 
6922903a
 #define MAP(val) do { operand_t o = val; \
     if (o > totValues) {\
 	cli_errmsg("bytecode: operand out of range: %u > %u, for instruction %u in function %u\n", o, totValues, j, i);\
 	return CL_EBYTECODE;\
     }\
     val = map[o]; } while (0)
 
 static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
 {
     unsigned i, j, k;
     for (i=0;i<bc->num_func;i++) {
 	struct cli_bc_func *bcfunc = &bc->funcs[i];
 	unsigned totValues = bcfunc->numValues + bcfunc->numConstants;
 	unsigned *map = cli_malloc(sizeof(*map)*totValues);
 	for (j=0;j<bcfunc->numValues;j++) {
 	    uint16_t ty = bcfunc->types[j];
 	    unsigned align;
 	    align = typealign(bc, ty);
 	    bcfunc->numBytes  = (bcfunc->numBytes + align-1)&(~(align-1));
 	    map[j] = bcfunc->numBytes;
 	    bcfunc->numBytes += typesize(bc, ty);
 	}
 	bcfunc->numBytes = (bcfunc->numBytes + 7)&~7;
 	for (j=0;j<bcfunc->numConstants;j++) {
 	    map[bcfunc->numValues+j] = bcfunc->numBytes;
 	    bcfunc->numBytes += 8;
 	}
 	for (j=0;j<bcfunc->numInsts;j++) {
 	    struct cli_bc_inst *inst = &bcfunc->allinsts[j];
 	    inst->dest = map[inst->dest];
 	    switch (inst->opcode) {
 		case OP_ADD:
 		case OP_SUB:
 		case OP_MUL:
 		case OP_UDIV:
 		case OP_SDIV:
 		case OP_UREM:
 		case OP_SREM:
 		case OP_SHL:
 		case OP_LSHR:
 		case OP_ASHR:
 		case OP_AND:
 		case OP_OR:
 		case OP_XOR:
 		case OP_ICMP_EQ:
 		case OP_ICMP_NE:
 		case OP_ICMP_UGT:
 		case OP_ICMP_UGE:
 		case OP_ICMP_ULT:
 		case OP_ICMP_ULE:
 		case OP_ICMP_SGT:
 		case OP_ICMP_SGE:
 		case OP_ICMP_SLT:
 		case OP_ICMP_SLE:
 		case OP_COPY:
72617ba2
 		case OP_STORE:
6922903a
 		    MAP(inst->u.binop[0]);
 		    MAP(inst->u.binop[1]);
 		    break;
 		case OP_SEXT:
 		case OP_ZEXT:
 		case OP_TRUNC:
 		    MAP(inst->u.cast.source);
 		    break;
 		case OP_BRANCH:
 		    MAP(inst->u.branch.condition);
 		    break;
 		case OP_JMP:
 		    break;
 		case OP_RET:
 		    MAP(inst->u.unaryop);
 		    break;
 		case OP_SELECT:
 		    MAP(inst->u.three[0]);
 		    MAP(inst->u.three[1]);
 		    MAP(inst->u.three[2]);
 		    break;
cf0cd429
 		case OP_CALL_API:/* fall-through */
6922903a
 		case OP_CALL_DIRECT:
 		{
cf0cd429
 		    struct cli_bc_func *target = NULL;
 		    if (inst->opcode == OP_CALL_DIRECT) {
 			target = &bc->funcs[inst->u.ops.funcid];
 			if (inst->u.ops.funcid > bc->num_func) {
 			    cli_errmsg("bytecode: called function out of range: %u > %u\n", inst->u.ops.funcid, bc->num_func);
 			    return CL_EBYTECODE;
 			}
 			if (inst->u.ops.numOps != target->numArgs) {
 			    cli_errmsg("bytecode: call operands don't match function prototype\n");
 			    return CL_EBYTECODE;
 			}
 		    } else {
 			/* APIs have 2 parameters always */
 			if (inst->u.ops.numOps != 2) {
 			    cli_errmsg("bytecode: call operands don't match function prototype\n");
 			    return CL_EBYTECODE;
 			}
6922903a
 		    }
 		    if (inst->u.ops.numOps) {
 			inst->u.ops.opsizes = cli_malloc(sizeof(*inst->u.ops.opsizes)*inst->u.ops.numOps);
 			if (!inst->u.ops.opsizes) {
 			    cli_errmsg("Out of memory when allocating operand sizes\n");
 			    return CL_EMEM;
 			}
36fab4bd
 		    } else
 			inst->u.ops.opsizes = NULL;
6922903a
 		    for (k=0;k<inst->u.ops.numOps;k++) {
 			MAP(inst->u.ops.ops[k]);
cf0cd429
 			if (inst->opcode == OP_CALL_DIRECT)
 			    inst->u.ops.opsizes[k] = typesize(bc, target->types[k]);
 			else
 			    inst->u.ops.opsizes[k] = 32; /*XXX*/
6922903a
 		    }
 		    break;
 		}
72617ba2
 		case OP_LOAD:
 		    MAP(inst->u.unaryop);
 		    break;
7a14dc4c
 		case OP_GEP1:
 		    MAP(inst->u.binop[0]);
 		    MAP(inst->u.binop[1]);
 		    break;
 		case OP_GEP2:
 		    MAP(inst->u.three[0]);
 		    MAP(inst->u.three[1]);
 		    MAP(inst->u.three[2]);
 		    break;
6922903a
 		default:
 		    cli_dbgmsg("Unhandled opcode: %d\n", inst->opcode);
 		    return CL_EBYTECODE;
 	    }
 	}
 	free(map);
     }
     bc->state = bc_interp;
     return CL_SUCCESS;
 }
 
d1487222
 int cli_bytecode_prepare(struct cli_all_bc *bcs)
6922903a
 {
d1487222
     unsigned i;
     int rc;
     if (cli_bytecode_prepare_jit(bcs) == CL_SUCCESS)
 	return CL_SUCCESS;
     for (i=0;i<bcs->count;i++) {
 	struct cli_bc *bc = &bcs->all_bcs[i];
 	if (bc->state == bc_interp || bc->state == bc_jit)
 	    continue;
 	rc = cli_bytecode_prepare_interpreter(bc);
 	if (rc != CL_SUCCESS)
 	    return rc;
6922903a
     }
d1487222
     return CL_SUCCESS;
6922903a
 }
 
d1487222
 int cli_bytecode_init(struct cli_all_bc *allbc)
6922903a
 {
d1487222
     memset(allbc, 0, sizeof(*allbc));
     return cli_bytecode_init_jit(allbc);
 }
 
 int cli_bytecode_done(struct cli_all_bc *allbc)
 {
     return cli_bytecode_done_jit(allbc);
6922903a
 }
3b33bd68