libclamav/bytecode.c
997a1efe
 /*
7a9022c9
  *  Load, and verify ClamAV bytecode.
997a1efe
  *
847d7fc1
  *  Copyright (C) 2009-2010 Sourcefire, Inc.
997a1efe
  *
  *  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
 
c074ecec
 #include <assert.h>
b00a7cc8
 #include <fcntl.h>
6eeadbfe
 #include "dconf.h"
997a1efe
 #include "clamav.h"
 #include "others.h"
ab636570
 #include "pe.h"
997a1efe
 #include "bytecode.h"
7a9022c9
 #include "bytecode_priv.h"
88d54dcb
 #include "bytecode_detect.h"
997a1efe
 #include "readdb.h"
d0934caf
 #include "scanners.h"
3735fda1
 #include "bytecode_api.h"
9aa1d725
 #include "bytecode_api_impl.h"
0d4c9946
 #include "builtin_bytecodes.h"
997a1efe
 #include <string.h>
 
74f5816c
 /* dummy values */
 static const uint32_t nomatch[64] = {
     0xdeadbeef, 0xdeaddead, 0xbeefdead, 0xdeaddead, 0xdeadbeef, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0,
     0, 0, 0, 0, 0, 0, 0, 0
 };
1c4683ac
 static const uint32_t nooffsets[64] = {
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE,
     CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE, CLI_OFF_NONE
 };
74f5816c
 
 static const uint16_t nokind;
 static const uint32_t nofilesize;
 static const struct cli_pe_hook_data nopedata;
 
 static void context_safe(struct cli_bc_ctx *ctx)
 {
     /* make sure these are never NULL */
     if (!ctx->hooks.kind)
 	ctx->hooks.kind = &nokind;
     if (!ctx->hooks.match_counts)
 	ctx->hooks.match_counts = nomatch;
1c4683ac
     if (!ctx->hooks.match_offsets)
 	ctx->hooks.match_counts = nooffsets;
74f5816c
     if (!ctx->hooks.filesize)
 	ctx->hooks.filesize = &nofilesize;
     if (!ctx->hooks.pedata)
 	ctx->hooks.pedata = &nopedata;
 }
 
7a7365ef
 static int cli_bytecode_context_reset(struct cli_bc_ctx *ctx);
7a9022c9
 struct cli_bc_ctx *cli_bytecode_context_alloc(void)
 {
d9fbce26
     struct cli_bc_ctx *ctx = cli_calloc(1, sizeof(*ctx));
12876d3c
     ctx->bytecode_timeout = 60000;
7a7365ef
     cli_bytecode_context_reset(ctx);
7a9022c9
     return ctx;
 }
997a1efe
 
7a9022c9
 void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx)
 {
    cli_bytecode_context_clear(ctx);
    free(ctx);
 }
997a1efe
 
3ae0a76d
 int cli_bytecode_context_getresult_file(struct cli_bc_ctx *ctx, char **tempfilename)
 {
     int fd;
     *tempfilename = ctx->tempfile;
     fd  = ctx->outfd;
     ctx->tempfile = NULL;
d9fbce26
     ctx->outfd = 0;
3ae0a76d
     return fd;
 }
 
ab636570
 /* resets bytecode state, so you can run another bytecode with same ctx */
d0934caf
 static int cli_bytecode_context_reset(struct cli_bc_ctx *ctx)
7a9022c9
 {
778df8c2
     unsigned i;
 
6922903a
     free(ctx->opsizes);
778df8c2
     ctx->opsizes = NULL;
 
7a9022c9
     free(ctx->values);
778df8c2
     ctx->values = NULL;
 
7a9022c9
     free(ctx->operands);
53bd5bb1
     ctx->operands = NULL;
778df8c2
 
d9fbce26
     if (ctx->outfd) {
e5f2b2c5
 	cli_ctx *cctx = ctx->ctx;
d9fbce26
 	cli_bcapi_extract_new(ctx, -1);
 	if (ctx->outfd)
 	    close(ctx->outfd);
6cd36d95
 	if (ctx->tempfile && (!cctx || !cctx->engine->keeptmp)) {
 	    cli_unlink(ctx->tempfile);
 	}
3ae0a76d
 	free(ctx->tempfile);
 	ctx->tempfile = NULL;
d9fbce26
 	ctx->outfd = 0;
3ae0a76d
     }
b00a7cc8
     if (ctx->jsnormdir) {
 	char fullname[1025];
 	cli_ctx *cctx = ctx->ctx;
 	int fd, ret = CL_CLEAN;
 
 	if (!ctx->found) {
 	    snprintf(fullname, 1024, "%s"PATHSEP"javascript", ctx->jsnormdir);
 	    fd = open(fullname, O_RDONLY|O_BINARY);
 	    if(fd >= 0) {
ffa9b060
 		ret = cli_scandesc(fd, cctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
b00a7cc8
 		if (ret == CL_CLEAN) {
 		    lseek(fd, 0, SEEK_SET);
ffa9b060
 		    ret = cli_scandesc(fd, cctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL);
b00a7cc8
 		}
 		close(fd);
 	    }
 	}
 	if (!cctx || !cctx->engine->keeptmp) {
 	    cli_rmdirs(ctx->jsnormdir);
 	}
 	free(ctx->jsnormdir);
 	if (ret != CL_CLEAN)
 	    ctx->found = 1;
     }
778df8c2
     ctx->numParams = 0;
     ctx->funcid = 0;
     ctx->file_size = 0;
     ctx->off = 0;
d9fbce26
     ctx->written = 0;
b00a7cc8
     ctx->jsnormwritten = 0;
2d45ef06
 #if USE_MPOOL
     if (ctx->mpool) {
 	mpool_destroy(ctx->mpool);
 	ctx->mpool = NULL;
     }
 #else
c0afc517
     /*TODO: implement for no-mmap case too*/
2d45ef06
 #endif
778df8c2
     for (i=0;i<ctx->ninflates;i++)
 	cli_bcapi_inflate_done(ctx, i);
     free(ctx->inflates);
     ctx->inflates = NULL;
     ctx->ninflates = 0;
 
     for (i=0;i<ctx->nbuffers;i++)
 	cli_bcapi_buffer_pipe_done(ctx, i);
     free(ctx->buffers);
     ctx->buffers = NULL;
     ctx->nbuffers = 0;
 
     for (i=0;i<ctx->nhashsets;i++)
 	cli_bcapi_hashset_done(ctx, i);
     free(ctx->hashsets);
     ctx->hashsets = NULL;
     ctx->nhashsets = 0;
b00a7cc8
 
     for (i=0;i<ctx->njsnorms;i++)
 	cli_bcapi_jsnorm_done(ctx, i);
     free(ctx->jsnorms);
     ctx->jsnorms = NULL;
     ctx->njsnorms = 0;
     ctx->jsnormdir = NULL;
7a7365ef
 
     for (i=0;i<ctx->nmaps;i++)
 	cli_bcapi_map_done(ctx, i);
     free(ctx->maps);
     ctx->maps = NULL;
     ctx->nmaps = 0;
 
     ctx->containertype = CL_TYPE_ANY;
ab636570
     return CL_SUCCESS;
 }
 
 int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
 {
     cli_bytecode_context_reset(ctx);
f6798708
     memset(ctx, 0, sizeof(*ctx));
957bf651
     return CL_SUCCESS;
7a9022c9
 }
997a1efe
 
6922903a
 static unsigned typesize(const struct cli_bc *bc, uint16_t type)
 {
669623d5
     struct cli_bc_type *ty;
     unsigned j;
 
a45e2577
     type &= 0x7fff;
6922903a
     if (!type)
 	return 0;
     if (type <= 8)
 	return 1;
     if (type <= 16)
 	return 2;
     if (type <= 32)
 	return 4;
     if (type <= 64)
 	return 8;
669623d5
     ty = &bc->types[type-65];
     if (ty->size)
 	return ty->size;
     switch (ty->kind) {
 	case 2:
 	case 3:
 	    for (j=0;j<ty->numElements;j++)
 		ty->size += typesize(bc, ty->containedTypes[j]);
 	    break;
 	case 4:
 	    ty->size = ty->numElements * typesize(bc, ty->containedTypes[0]);
 	    break;
 	default:
 	    break;
     }
     if (!ty->size && ty->kind != DFunctionType) {
 	cli_warnmsg("type %d size is 0\n", type-65);
     }
     return ty->size;
6922903a
 }
 
 static unsigned typealign(const struct cli_bc *bc, uint16_t type)
 {
a45e2577
     type &= 0x7fff;
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);
cbb9db19
 	if (!ctx->opsizes) {
 	    cli_errmsg("bytecode: error allocating memory for opsizes\n");
 	    return CL_EMEM;
 	}
6922903a
 	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) {
ec077929
 	    /* This is a global variable */
 	    return 0x80000000 | v;
09bd9839
 	}
 	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;
 }
 
e4a0f2c9
 static inline 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);
53bd5bb1
     if (!l || !ok) {
8c0933ce
 	*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;
e4a0f2c9
     return (char*)dat;
997a1efe
 }
 
c3c97d4a
 static inline char *readString(const unsigned char *p, unsigned *off, unsigned len, char *ok)
 {
     unsigned stringlen;
e4a0f2c9
     char *str = readData(p, off, len, ok, &stringlen);
c3c97d4a
     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
 
482e97db
 static int parseHeader(struct cli_bc *bc, unsigned char *buffer, unsigned *linelength)
997a1efe
 {
     uint64_t magic1;
     unsigned magic2;
     char ok = 1;
     unsigned offset, len, flevel;
482e97db
     char *pos;
3735fda1
 
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);
3735fda1
     bc->metadata.formatlevel = readNumber(buffer, &offset, len, &ok);
997a1efe
     if (!ok) {
3735fda1
 	cli_errmsg("Unable to parse (format) functionality level in bytecode header\n");
997a1efe
 	return CL_EMALFDB;
     }
3735fda1
     /* we support 2 bytecode formats */
     if (bc->metadata.formatlevel != BC_FORMAT_096 &&
 	bc->metadata.formatlevel != BC_FORMAT_LEVEL) {
 	cli_dbgmsg("Skipping bytecode with (format) functionality level: %u (current %u)\n", 
 		   bc->metadata.formatlevel, BC_FORMAT_LEVEL);
997a1efe
 	return CL_BREAK;
     }
c0afc517
     /* Optimistic parsing, check for error only at the end.*/
a35cfe51
     bc->metadata.timestamp = readNumber(buffer, &offset, len, &ok);
     bc->metadata.sigmaker = readString(buffer, &offset, len, &ok);
     bc->metadata.targetExclude = readNumber(buffer, &offset, len, &ok);
9fac78c7
     bc->kind = readNumber(buffer, &offset, len, &ok);
3735fda1
     bc->metadata.minfunc = readNumber(buffer, &offset, len, &ok);
     bc->metadata.maxfunc = readNumber(buffer, &offset, len, &ok);
     flevel = cl_retflevel();
     /* in 0.96 these 2 fields are unused / zero, in post 0.96 these mean
      * min/max flevel.
      * So 0 for min/max means no min/max
      * Note that post 0.96 bytecode/bytecode lsig needs format 7, because
      * 0.96 doesn't check lsig functionality level.
      */
     if ((bc->metadata.minfunc && bc->metadata.minfunc > flevel) ||
         (bc->metadata.maxfunc && bc->metadata.maxfunc < flevel)) {
       cli_dbgmsg("Skipping bytecode with (engine) functionality level %u-%u (current %u)\n",
                  bc->metadata.minfunc, bc->metadata.maxfunc, flevel);
       return CL_BREAK;
     }
     bc->metadata.maxresource = readNumber(buffer, &offset, len, &ok);
a35cfe51
     bc->metadata.compiler = 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;
53bd5bb1
     bc->dbgnodes = NULL;
     bc->dbgnode_cnt = 0;
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;
     }
482e97db
     if (buffer[offset] != ':') {
 	cli_errmsg("Expected : but found: %c\n", buffer[offset]);
 	return CL_EMALFDB;
     }
     offset++;
e4a0f2c9
     *linelength = strtol((const char*)buffer+offset, &pos, 10);
c1aff5ec
     if (*pos != '\0') {
482e97db
 	cli_errmsg("Invalid number: %s\n", buffer+offset);
997a1efe
 	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;
 }
 
e4a0f2c9
 static int parseLSig(struct cli_bc *bc, char *buffer)
dcee45cc
 {
ec41017b
     const char *prefix;
     char *vnames, *vend = strchr(buffer, ';');
     if (vend) {
 	bc->lsig = cli_strdup(buffer);
a45e2577
 	*vend++ = '\0';
 	prefix = buffer;
 	vnames = strchr(vend, '{');
ec41017b
     } else {
 	/* Not a logical signature, but we still have a virusname */
 	bc->lsig = NULL;
     }
 
dcee45cc
     return CL_SUCCESS;
 }
 
8cc286f5
 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;
 
34da9ae4
     ty->numElements = readNumber(buffer, off, len, ok);
d11cced2
     if (!*ok) {
8cc286f5
 	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];
4993d6cf
 	bc->types[i].size = bc->types[i].align = 8;
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);
e32caecb
     for (i=(BC_START_TID - 65);i<bc->num_types-1;i++) {
8cc286f5
 	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;
 		}
e32caecb
 		if (!ty->numElements) {
 		    cli_errmsg("Function with no return type? %u\n", i);
 		    return CL_EMALFDB;
 		}
8cc286f5
 		break;
 	    case 2:
 	    case 3:
479fa713
 		ty->kind = (t == 2) ? DPackedStructType : DStructType;
7a14dc4c
 		ty->size = ty->align = 0;/* TODO:calculate size/align of structs */
c074ecec
 		ty->align = 8;
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) {
b3b8b6dd
 		    /* for interpreter, pointers 64-bit there */
 		    ty->size = ty->align = 8;
7a14dc4c
 		} 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;
479fa713
     const struct cli_bc_type *ty = &bc->types[tid - 65];
cf0cd429
     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;
      }
b31f2e7a
      for (i=0;i<ty->numElements;i++) {
cf0cd429
 	if (apity->containedTypes[i] < BC_START_TID) {
b31f2e7a
 	    if (ty->containedTypes[i] != apity->containedTypes[i]) {
 		cli_dbgmsg("bytecode: contained type mismatch: %u != %u\n",
 			   ty->containedTypes[i], apity->containedTypes[i]);
cf0cd429
 		return 0;
b31f2e7a
 	    }
cf0cd429
 	} else if (!types_equal(bc, apity2ty, ty->containedTypes[i], apity->containedTypes[i] - BC_START_TID))
 	    return 0;
b31f2e7a
 	if (ty->kind == DArrayType)
 	    break;/* validated the contained type already */
      }
cf0cd429
     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;
 }
 
ec077929
 static uint16_t type_components(struct cli_bc *bc, uint16_t id, char *ok)
 {
     unsigned i, sum=0;
     const struct cli_bc_type *ty;
     if (id <= 64)
 	return 1;
     ty = &bc->types[id-65];
     /* TODO: protect against recursive types */
     switch (ty->kind) {
 	case DFunctionType:
 	    cli_errmsg("bytecode: function type not accepted for constant: %u\n", id);
 	    /* don't accept functions as constant initializers */
 	    *ok = 0;
 	    return 0;
 	case DPointerType:
7189addb
 	    return 2;
ec077929
 	case DStructType:
 	case DPackedStructType:
 	    for (i=0;i<ty->numElements;i++) {
 		sum += type_components(bc, ty->containedTypes[i], ok);
 	    }
 	    return sum;
 	case DArrayType:
 	    return type_components(bc, ty->containedTypes[0], ok)*ty->numElements;
 	default:
 	    *ok = 0;
 	    return 0;
     }
 }
 
 static void readConstant(struct cli_bc *bc, unsigned i, unsigned comp,
 			 unsigned char *buffer, unsigned *offset,
 			 unsigned len, char *ok)
 {
     unsigned j=0;
dcaa4038
     if (*ok && buffer[*offset] == 0x40 &&
 	buffer [*offset+1] == 0x60) {
 	/* zero initializer */
 	memset(bc->globals[i], 0, sizeof(*bc->globals[0])*comp);
 	(*offset)+=2;
 	return;
     }
ec077929
     while (*ok && buffer[*offset] != 0x60) {
7189addb
 	if (j >= comp) {
ec077929
 	    cli_errmsg("bytecode: constant has too many subcomponents, expected %u\n", comp);
 	    *ok = 0;
 	    return;
 	}
 	buffer[*offset] |= 0x20;
 	bc->globals[i][j++] = readNumber(buffer, offset, len, ok);
     }
     if (*ok && j != comp) {
dcaa4038
 	cli_errmsg("bytecode: constant has too few subcomponents: %u < %u\n", j, comp);
 	*ok = 0;
ec077929
     }
7189addb
     (*offset)++;
ec077929
 }
 
 /* parse constant globals with constant initializers */
 static int parseGlobals(struct cli_bc *bc, unsigned char *buffer)
 {
     unsigned i, offset = 1, len = strlen((const char*)buffer), numglobals;
9fac78c7
     unsigned maxglobal;
ec077929
     char ok=1;
 
     if (buffer[0] != 'G') {
 	cli_errmsg("bytecode: Invalid globals header: %c\n", buffer[0]);
 	return CL_EMALFDB;
     }
9fac78c7
     maxglobal = readNumber(buffer, &offset, len, &ok);
     if (maxglobal > cli_apicall_maxglobal) {
 	cli_dbgmsg("bytecode using global %u, but highest global known to libclamav is %u, skipping\n", maxglobal, cli_apicall_maxglobal);
 	return CL_BREAK;
     }
ec077929
     numglobals = readNumber(buffer, &offset, len, &ok);
     bc->globals = cli_calloc(numglobals, sizeof(*bc->globals));
     if (!bc->globals) {
 	cli_errmsg("bytecode: OOM allocating memory for %u globals\n", numglobals);
 	return CL_EMEM;
     }
     bc->globaltys = cli_calloc(numglobals, sizeof(*bc->globaltys));
     if (!bc->globaltys) {
 	cli_errmsg("bytecode: OOM allocating memory for %u global types\n", numglobals);
 	return CL_EMEM;
     }
     bc->num_globals = numglobals;
     if (!ok)
 	return CL_EMALFDB;
     for (i=0;i<numglobals;i++) {
 	unsigned comp;
 	bc->globaltys[i] = readTypeID(bc, buffer, &offset, len, &ok);
 	comp = type_components(bc, bc->globaltys[i], &ok);
 	if (!ok)
 	    return CL_EMALFDB;
3ff75dbf
 	bc->globals[i] = cli_malloc(sizeof(*bc->globals[0])*comp);
ec077929
 	if (!bc->globals[i])
 	    return CL_EMEM;
 	readConstant(bc, i, comp, buffer, &offset, len, &ok);
     }
     if (!ok)
 	return CL_EMALFDB;
7189addb
     if (offset != len) {
 	cli_errmsg("Trailing garbage in globals: %d extra bytes\n",
 		   len-offset);
 	return CL_EMALFDB;
     }
ec077929
     return CL_SUCCESS;
 }
 
53bd5bb1
 static int parseMD(struct cli_bc *bc, unsigned char *buffer)
 {
e4a0f2c9
     unsigned offset = 1, len = strlen((const char*)buffer);
53bd5bb1
     unsigned numMD, i, b;
     char ok = 1;
     if (buffer[0] != 'D')
 	return CL_EMALFDB;
     numMD = readNumber(buffer, &offset, len, &ok);
     if (!ok) {
 	cli_errmsg("Unable to parse number of MD nodes\n");
 	return CL_EMALFDB;
     }
     b = bc->dbgnode_cnt;
     bc->dbgnode_cnt += numMD;
     bc->dbgnodes = cli_realloc(bc->dbgnodes, bc->dbgnode_cnt * sizeof(*bc->dbgnodes));
     if (!bc->dbgnodes)
 	return CL_EMEM;
     for (i=0;i<numMD;i++) {
 	unsigned j;
 	struct cli_bc_dbgnode_element* elts;
 	unsigned el = readNumber(buffer, &offset, len, &ok);
 	if (!ok) {
 	    cli_errmsg("Unable to parse number of elements\n");
 	    return CL_EMALFDB;
 	}
 	bc->dbgnodes[b+i].numelements = el;
 	bc->dbgnodes[b+i].elements = elts = cli_calloc(el, sizeof(*elts));
 	if (!elts)
 	    return CL_EMEM;
 	for (j=0;j<el;j++) {
 	    if (buffer[offset] == '|') {
 		elts[j].string = readData(buffer, &offset, len, &ok, &elts[j].len);
 		if (!ok)
 		    return CL_EMALFDB;
 	    } else {
 		elts[j].len = readNumber(buffer, &offset, len, &ok);
 		if (!ok)
 		    return CL_EMALFDB;
 		if (elts[j].len) {
 		    elts[j].constant = readNumber(buffer, &offset, len, &ok);
 		}
 		else
 		    elts[j].nodeid = readNumber(buffer, &offset, len, &ok);
 		if (!ok)
 		    return CL_EMALFDB;
 	    }
 	}
     }
     cli_dbgmsg("bytecode: Parsed %u nodes total\n", bc->dbgnode_cnt);
     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;
5475ec2a
     if (!all_locals) {
 	func->types = NULL;
     } else {
 	func->types = cli_calloc(all_locals, sizeof(*func->types));
 	if (!func->types) {
 	    cli_errmsg("Out of memory allocating function arguments\n");
 	    return CL_EMEM;
 	}
997a1efe
     }
     for (i=0;i<all_locals;i++) {
 	func->types[i] = readNumber(buffer, &offset, len, &ok);
a45e2577
 	if (readFixedNumber(buffer, &offset, len, &ok, 1))
 	    func->types[i] |= 0x8000;
997a1efe
     }
     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
 }*/
48fc8b98
 static int16_t get_optype(const struct cli_bc_func *bcfunc, operand_t op)
 {
     if (op >= bcfunc->numArgs + bcfunc->numLocals)
 	return 0;
     return bcfunc->types[op]&0x7fff;
 }
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;
 	}
52dd3a6b
 	if (inst.opcode >= OP_BC_INVALID) {
997a1efe
 	    cli_errmsg("Invalid opcode: %u\n", inst.opcode);
 	    return CL_EMALFDB;
 	}
09bd9839
 
c3c97d4a
 	switch (inst.opcode) {
52dd3a6b
 	    case OP_BC_JMP:
c3c97d4a
 		inst.u.jump = readBBID(bcfunc, buffer, &offset, len, &ok);
997a1efe
 		break;
52dd3a6b
 	    case OP_BC_RET:
6922903a
 		inst.type = readNumber(buffer, &offset, len, &ok);
09bd9839
 		inst.u.unaryop = readOperand(bcfunc, buffer, &offset, len, &ok);
6922903a
 		break;
52dd3a6b
 	    case OP_BC_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;
52dd3a6b
 	    case OP_BC_CALL_API:/* fall-through */
 	    case OP_BC_CALL_DIRECT:
3555ee75
 		numOp = readFixedNumber(buffer, &offset, len, &ok, 1);
a0d6fec0
 		if (ok) {
 		    inst.u.ops.numOps = numOp;
6922903a
 		    inst.u.ops.opsizes=NULL;
5475ec2a
 		    if (!numOp) {
 			inst.u.ops.ops = NULL;
 		    } else {
 			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_EMEM;
 			}
a0d6fec0
 		    }
52dd3a6b
 		    if (inst.opcode == OP_BC_CALL_DIRECT)
cf0cd429
 			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;
52dd3a6b
 	    case OP_BC_ZEXT:
 	    case OP_BC_SEXT:
 	    case OP_BC_TRUNC:
e0c4fd85
 		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 */
52dd3a6b
 		if (inst.opcode != OP_BC_SEXT)
cfec3d90
 		    inst.u.cast.mask = inst.u.cast.mask != 64 ?
 			(1ull<<inst.u.cast.mask)-1 :
 			~0ull;
e0c4fd85
 		break;
9463f9fd
 	    case OP_BC_GEP1:
 	    case OP_BC_GEPZ:
 		inst.u.three[0] = readNumber(buffer, &offset, len, &ok);
 		inst.u.three[1] = readOperand(bcfunc, buffer, &offset, len, &ok);
 		inst.u.three[2] = readOperand(bcfunc, buffer, &offset, len, &ok);
 		break;
688799d1
 	    case OP_BC_GEPN:
 		numOp = readFixedNumber(buffer, &offset, len, &ok, 1);
 		if (ok) {
9463f9fd
 		    inst.u.ops.numOps = numOp+2;
688799d1
 		    inst.u.ops.opsizes = NULL;
b31f2e7a
 		    inst.u.ops.ops = cli_calloc(numOp+2, sizeof(*inst.u.ops.ops));
688799d1
 		    if (!inst.u.ops.ops) {
 			cli_errmsg("Out of memory allocating operands\n");
 			return CL_EMEM;
 		    }
 		    inst.u.ops.ops[0] = readNumber(buffer, &offset, len, &ok);
9463f9fd
 		    for (i=1;i<numOp+2;i++)
688799d1
 			inst.u.ops.ops[i] = readOperand(bcfunc, buffer, &offset, len, &ok);
 		}
 		break;
52dd3a6b
 	    case OP_BC_ICMP_EQ:
 	    case OP_BC_ICMP_NE:
 	    case OP_BC_ICMP_UGT:
 	    case OP_BC_ICMP_UGE:
 	    case OP_BC_ICMP_ULT:
 	    case OP_BC_ICMP_ULE:
 	    case OP_BC_ICMP_SGT:
 	    case OP_BC_ICMP_SGE:
 	    case OP_BC_ICMP_SLE:
 	    case OP_BC_ICMP_SLT:
09bd9839
 		/* 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) {
d38d6dad
 		    case 0:
 			break;
c3c97d4a
 		    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:
d38d6dad
 			cli_errmsg("Opcode %u with too many operands: %u?\n", inst.opcode, numOp);
a0d6fec0
 			ok = 0;
c3c97d4a
 			break;
997a1efe
 		}
 	}
fa0a9143
 	if (inst.opcode == OP_BC_STORE) {
 	    int16_t t = get_optype(bcfunc, inst.u.binop[0]);
 	    if (t)
 		inst.type = t;
 	}
5dfb4bf1
 	if (inst.opcode == OP_BC_COPY)
48fc8b98
 	    inst.type = get_optype(bcfunc, inst.u.binop[1]);
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;
74f5816c
 	    else if (inst.type <= 65)
09bd9839
 		inst.interp_op += 4;
74f5816c
 	    else {
 		cli_dbgmsg("unknown inst type: %d\n", inst.type);
 	    }
09bd9839
 	}
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++;
     }
53bd5bb1
     if (buffer[offset] == 'D') {
 	unsigned num;
 	offset += 3;
 	if (offset >= len)
 	    return CL_EMALFDB;
 	num = readNumber(buffer, &offset, len, &ok);
 	if (!ok)
 	    return CL_EMALFDB;
 	if (num != bcfunc->numInsts) {
 	    cli_errmsg("invalid number of dbg nodes, expected: %u, got: %u\n", bcfunc->numInsts, num);
 	    return CL_EMALFDB;
 	}
 	bcfunc->dbgnodes = cli_malloc(num*sizeof(*bcfunc->dbgnodes));
 	if (!bcfunc->dbgnodes)
 	    return CL_EMEM;
 	for (i=0;i<num;i++) {
 	    bcfunc->dbgnodes[i] = readNumber(buffer, &offset, len, &ok);
 	    if (!ok)
 		return CL_EMALFDB;
 	}
     }
997a1efe
     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 {
482e97db
     PARSE_BC_TYPES=0,
8cc286f5
     PARSE_BC_APIS,
ec077929
     PARSE_BC_GLOBALS,
dcee45cc
     PARSE_BC_LSIG,
53bd5bb1
     PARSE_MD_OPT_HEADER,
997a1efe
     PARSE_FUNC_HEADER,
     PARSE_BB
 };
 
be43f951
 int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio, int trust)
997a1efe
 {
     unsigned row = 0, current_func = 0, bb=0;
482e97db
     char *buffer;
     unsigned linelength=0;
     char firstbuf[FILEBUFF];
     enum parse_state state;
9bdaf35d
     int rc, end=0;
997a1efe
 
2d45ef06
     memset(bc, 0, sizeof(*bc));
606fd6d0
     cli_dbgmsg("Loading %s bytecode\n", trust ? "trusted" : "untrusted");
be43f951
     bc->trusted = trust;
997a1efe
     if (!f && !dbio) {
 	cli_errmsg("Unable to load bytecode (null file)\n");
 	return CL_ENULLARG;
     }
482e97db
     if (!cli_dbgets(firstbuf, FILEBUFF, f, dbio)) {
 	cli_errmsg("Unable to load bytecode (empty file)\n");
 	return CL_EMALFDB;
     }
c1aff5ec
     cli_chomp(firstbuf);
482e97db
     rc = parseHeader(bc, (unsigned char*)firstbuf, &linelength);
     if (rc == CL_BREAK) {
 	bc->state = bc_skip;
 	return CL_SUCCESS;
     }
     if (rc != CL_SUCCESS) {
 	cli_errmsg("Error at bytecode line %u\n", row);
 	return rc;
     }
     buffer = cli_malloc(linelength);
     if (!buffer) {
 	cli_errmsg("Out of memory allocating line of length %u\n", linelength);
 	return CL_EMEM;
     }
     state = PARSE_BC_LSIG;
9bdaf35d
     while (cli_dbgets(buffer, linelength, f, dbio) && !end) {
997a1efe
 	cli_chomp(buffer);
f60a0e00
 	row++;
997a1efe
 	switch (state) {
dcee45cc
 	    case PARSE_BC_LSIG:
e4a0f2c9
 		rc = parseLSig(bc, buffer);
dcee45cc
 		if (rc == CL_BREAK) /* skip */ {
 		    bc->state = bc_skip;
482e97db
 		    free(buffer);
dcee45cc
 		    return CL_SUCCESS;
 		}
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
482e97db
 		    free(buffer);
dcee45cc
 		    return rc;
 		}
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);
482e97db
 		    free(buffer);
8cc286f5
 		    return rc;
 		}
 		state = PARSE_BC_APIS;
 		break;
 	    case PARSE_BC_APIS:
 		rc = parseApis(bc, (unsigned char*)buffer);
4789b8a5
 		if (rc == CL_BREAK) /* skip */ {
 		    bc->state = bc_skip;
482e97db
 		    free(buffer);
8cc286f5
 		    return CL_SUCCESS;
4789b8a5
 		}
8cc286f5
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
482e97db
 		    free(buffer);
8cc286f5
 		    return rc;
 		}
ec077929
 		state = PARSE_BC_GLOBALS;
 		break;
 	    case PARSE_BC_GLOBALS:
 		rc = parseGlobals(bc, (unsigned char*)buffer);
 		if (rc == CL_BREAK) /* skip */ {
 		    bc->state = bc_skip;
482e97db
 		    free(buffer);
ec077929
 		    return CL_SUCCESS;
 		}
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
482e97db
 		    free(buffer);
ec077929
 		    return rc;
 		}
53bd5bb1
 		state = PARSE_MD_OPT_HEADER;
997a1efe
 		break;
53bd5bb1
 	    case PARSE_MD_OPT_HEADER:
 		if (buffer[0] == 'D') {
 		    rc = parseMD(bc, (unsigned char*)buffer);
 		    if (rc != CL_SUCCESS) {
 			cli_errmsg("Error at bytecode line %u\n", row);
482e97db
 			free(buffer);
53bd5bb1
 			return rc;
 		    }
 		    break;
 		}
c0afc517
 		/* fall-through */
997a1efe
 	    case PARSE_FUNC_HEADER:
9bdaf35d
                 if (*buffer == 'S') {
 		    end = 1;
 		    break;
 		}
c3c97d4a
 		rc = parseFunctionHeader(bc, current_func, (unsigned char*)buffer);
f60a0e00
 		if (rc != CL_SUCCESS) {
 		    cli_errmsg("Error at bytecode line %u\n", row);
482e97db
 		    free(buffer);
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);
482e97db
 		    free(buffer);
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);
482e97db
 			free(buffer);
6922903a
 			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;
 	}
     }
482e97db
     free(buffer);
997a1efe
     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
     }
d5ffa2ac
     if (bc->state == bc_disabled) {
 	cli_dbgmsg("bytecode triggered but running bytecodes is disabled\n");
 	return CL_SUCCESS;
     }
     ctx->env = &bcs->env;
74f5816c
     context_safe(ctx);
85a25497
     if (bc->state == bc_interp) {
 	memset(&func, 0, sizeof(func));
 	func.numInsts = 1;
 	func.numValues = 1;
c074ecec
 	func.numConstants = 0;
85a25497
 	func.numBytes = ctx->bytes;
 	memset(ctx->values+ctx->bytes-8, 0, 8);
7a9022c9
 
52dd3a6b
 	inst.opcode = OP_BC_CALL_DIRECT;
 	inst.interp_op = OP_BC_CALL_DIRECT*5;
85a25497
 	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;
e86fe7ea
 	cli_dbgmsg("Bytecode: executing in interpeter mode\n");
d1487222
 	return cli_vm_execute(ctx->bc, ctx, &func, &inst);
85a25497
     }
e86fe7ea
     cli_dbgmsg("Bytecode: executing in JIT mode\n");
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*/
997a1efe
 }
 
 void cli_bytecode_destroy(struct cli_bc *bc)
 {
     unsigned i, j, k;
a35cfe51
     free(bc->metadata.compiler);
     free(bc->metadata.sigmaker);
997a1efe
 
f6e8bb80
     if (bc->funcs) {
 	for (i=0;i<bc->num_func;i++) {
 	    struct cli_bc_func *f = &bc->funcs[i];
 	    if (!f)
 		continue;
 	    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++) {
 		    struct cli_bc_inst *ii = &BB->insts[k];
 		    if (operand_counts[ii->opcode] > 3 ||
 			ii->opcode == OP_BC_CALL_DIRECT || ii->opcode == OP_BC_CALL_API) {
 			free(ii->u.ops.ops);
 			free(ii->u.ops.opsizes);
 		    }
6922903a
 		}
997a1efe
 	    }
f6e8bb80
 	    free(f->BB);
 	    free(f->allinsts);
 	    free(f->constants);
 	}
 	free(bc->funcs);
     }
     if (bc->types) {
 	for (i=NUM_STATIC_TYPES;i<bc->num_types;i++) {
 	    if (bc->types[i].containedTypes)
 		free(bc->types[i].containedTypes);
997a1efe
 	}
f6e8bb80
 	free(bc->types);
     }
 
     if (bc->globals) {
 	for (i=0;i<bc->num_globals;i++) {
 	    free(bc->globals[i]);
 	}
 	free(bc->globals);
     }
     if (bc->dbgnodes) {
 	for (i=0;i<bc->dbgnode_cnt;i++) {
 	    for (j=0;j<bc->dbgnodes[i].numelements;j++) {
 		struct cli_bc_dbgnode_element *el =  &bc->dbgnodes[i].elements[j];
 		if (el && el->string)
 		    free(el->string);
 	    }
53bd5bb1
 	}
f6e8bb80
 	free(bc->dbgnodes);
53bd5bb1
     }
ec077929
     free(bc->globaltys);
cf0cd429
     if (bc->uses_apis)
 	cli_bitset_free(bc->uses_apis);
dcee45cc
     free(bc->lsig);
9cbece5c
     free(bc->globalBytes);
5475ec2a
     memset(bc, 0, sizeof(*bc));
997a1efe
 }
 
6922903a
 #define MAP(val) do { operand_t o = val; \
3ff41e32
     if (o & 0x80000000) {\
 	o &= 0x7fffffff;\
20327f93
 	if (o > bc->num_globals) {\
 	    cli_errmsg("bytecode: global out of range: %u > %u, for instruction %u in function %u\n",\
db296754
 		       o, (unsigned)bc->num_globals, j, i);\
20327f93
 	    return CL_EBYTECODE;\
 	}\
 	val = 0x80000000 | gmap[o];\
 	break;\
3ff41e32
     }\
6922903a
     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)
 
0d9b99f4
 #define MAPPTR(val) {\
     if ((val < bcfunc->numValues) && bcfunc->types[val]&0x8000)\
       val = map[val] | 0x40000000;\
     else\
 	MAP(val);\
 }
 
52d0d8bc
 static inline int64_t ptr_compose(int32_t id, uint32_t offset)
 {
     uint64_t i = id;
     return (i << 32) | offset;
 }
 
44e13431
 static inline int get_geptypesize(const struct cli_bc *bc, uint16_t tid)
 {
   const struct cli_bc_type *ty;
   if (tid >= bc->num_types+65) {
     cli_errmsg("bytecode: typeid out of range %u >= %u\n", tid, bc->num_types);
     return -1;
   }
   if (tid <= 64) {
     cli_errmsg("bytecode: invalid type for gep (%u)\n", tid);
     return -1;
   }
   ty = &bc->types[tid - 65];
   if (ty->kind != DPointerType) {
     cli_errmsg("bytecode: invalid gep type, must be pointer: %u\n", tid);
     return -1;
   }
   return typesize(bc, ty->containedTypes[0]);
 }
 
b1018ea5
 static int calc_gepz(struct cli_bc *bc, struct cli_bc_func *func, uint16_t tid, operand_t op)
 {
     unsigned off = 0, i;
c09f9b29
     uint32_t *gepoff;
b1018ea5
     const struct cli_bc_type *ty;
     if (tid >= bc->num_types + 65) {
 	cli_errmsg("bytecode: typeid out of range %u >= %u\n", tid, bc->num_types);
 	return -1;
     }
     if (tid <= 65) {
 	cli_errmsg("bytecode: invalid type for gep (%u)\n", tid);
 	return -1;
     }
     ty = &bc->types[tid - 65];
     if (ty->kind != DPointerType || ty->containedTypes[0] < 65) {
 	cli_errmsg("bytecode: invalid gep type, must be pointer to nonint: %u\n", tid);
 	return -1;
     }
     ty = &bc->types[ty->containedTypes[0] - 65];
     if (ty->kind != DStructType && ty->kind != DPackedStructType)
 	return 0;
c09f9b29
     gepoff = (uint32_t*)&func->constants[op - func->numValues];
b1018ea5
     if (*gepoff >= ty->numElements) {
88d54dcb
 	cli_errmsg("bytecode: gep offset out of range: %d >= %d\n",(uint32_t)*gepoff, ty->numElements);
b1018ea5
 	return -1;
     }
     for (i=0;i<*gepoff;i++) {
 	off += typesize(bc, ty->containedTypes[i]);
     }
     *gepoff = off;
     return 1;
 }
 
6922903a
 static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
 {
dc200c6b
     unsigned i, j, k;
52d0d8bc
     uint64_t *gmap;
74f5816c
     unsigned bcglobalid = cli_apicall_maxglobal - _FIRST_GLOBAL+2;
20327f93
     bc->numGlobalBytes = 0;
     gmap = cli_malloc(bc->num_globals*sizeof(*gmap));
     if (!gmap)
 	return CL_EMEM;
     for (j=0;j<bc->num_globals;j++) {
 	uint16_t ty = bc->globaltys[j];
 	unsigned align = typealign(bc, ty);
 	assert(align);
 	bc->numGlobalBytes  = (bc->numGlobalBytes + align-1)&(~(align-1));
 	gmap[j] = bc->numGlobalBytes;
 	bc->numGlobalBytes += typesize(bc, ty);
     }
c6c464e5
     if (bc->numGlobalBytes) {
 	bc->globalBytes = cli_calloc(1, bc->numGlobalBytes);
 	if (!bc->globalBytes)
 	    return CL_EMEM;
     } else
 	bc->globalBytes = NULL;
 
52d0d8bc
     for (j=0;j<bc->num_globals;j++) {
 	struct cli_bc_type *ty;
 	if (bc->globaltys[j] < 65)
 	    continue;
 	ty = &bc->types[bc->globaltys[j]-65];
 	switch (ty->kind) {
 	    case DPointerType:
74f5816c
 		{
 		    uint64_t ptr;
 		    if (bc->globals[j][1] >= _FIRST_GLOBAL) {
 			ptr = ptr_compose(bc->globals[j][1] - _FIRST_GLOBAL + 1,
 					    bc->globals[j][0]);
 		    } else {
 			if (bc->globals[j][1] > bc->num_globals)
 			    continue;
 			ptr = ptr_compose(bcglobalid,
 					  gmap[bc->globals[j][1]] + bc->globals[j][0]);
 		    }
 		    *(uint64_t*)&bc->globalBytes[gmap[j]] = ptr;
 		    break;
 		}
 	    case DArrayType:
 		{
 		    unsigned elsize, i, off = gmap[j];
 		    /* TODO: support other than ints in arrays */
 		    elsize = typesize(bc, ty->containedTypes[0]);
 		    switch (elsize) {
 			case 1:
 			    for(i=0;i<ty->numElements;i++)
 				bc->globalBytes[off+i] = bc->globals[j][i];
 			    break;
 			case 2:
 			    for(i=0;i<ty->numElements;i++)
 				*(uint16_t*)&bc->globalBytes[off+i*2] = bc->globals[j][i];
 			    break;
 			case 4:
 			    for(i=0;i<ty->numElements;i++)
 				*(uint32_t*)&bc->globalBytes[off+i*4] = bc->globals[j][i];
 			    break;
 			case 8:
 			    for(i=0;i<ty->numElements;i++)
 				*(uint64_t*)&bc->globalBytes[off+i*8] = bc->globals[j][i];
 			    break;
 			default:
 			    cli_dbgmsg("interpreter: unsupported elsize: %u\n", elsize);
 		    }
 		    break;
 		}
52d0d8bc
 	    default:
 		/*TODO*/
 		if (!bc->globals[j][1])
 		    continue; /* null */
 		break;
 	}
     }
6eeadbfe
 
6922903a
     for (i=0;i<bc->num_func;i++) {
 	struct cli_bc_func *bcfunc = &bc->funcs[i];
3ff41e32
 	unsigned totValues = bcfunc->numValues + bcfunc->numConstants + bc->num_globals;
6922903a
 	unsigned *map = cli_malloc(sizeof(*map)*totValues);
20327f93
 	if (!map)
 	    return CL_EMEM;
c074ecec
 	bcfunc->numBytes = 0;
6922903a
 	for (j=0;j<bcfunc->numValues;j++) {
 	    uint16_t ty = bcfunc->types[j];
 	    unsigned align;
 	    align = typealign(bc, ty);
c074ecec
 	    assert(align);
6922903a
 	    bcfunc->numBytes  = (bcfunc->numBytes + align-1)&(~(align-1));
 	    map[j] = bcfunc->numBytes;
15839138
 	    /* printf("%d -> %d, %u\n", j, map[j], typesize(bc, ty)); */
6922903a
 	    bcfunc->numBytes += typesize(bc, ty);
b1018ea5
 	    /* TODO: don't allow size 0, it is always a bug! */
6922903a
 	}
 	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) {
52dd3a6b
 		case OP_BC_ADD:
 		case OP_BC_SUB:
 		case OP_BC_MUL:
 		case OP_BC_UDIV:
 		case OP_BC_SDIV:
 		case OP_BC_UREM:
 		case OP_BC_SREM:
 		case OP_BC_SHL:
 		case OP_BC_LSHR:
 		case OP_BC_ASHR:
 		case OP_BC_AND:
 		case OP_BC_OR:
 		case OP_BC_XOR:
 		case OP_BC_ICMP_EQ:
 		case OP_BC_ICMP_NE:
 		case OP_BC_ICMP_UGT:
 		case OP_BC_ICMP_UGE:
 		case OP_BC_ICMP_ULT:
 		case OP_BC_ICMP_ULE:
 		case OP_BC_ICMP_SGT:
 		case OP_BC_ICMP_SGE:
 		case OP_BC_ICMP_SLT:
 		case OP_BC_ICMP_SLE:
 		case OP_BC_COPY:
 		case OP_BC_STORE:
6922903a
 		    MAP(inst->u.binop[0]);
 		    MAP(inst->u.binop[1]);
 		    break;
52dd3a6b
 		case OP_BC_SEXT:
 		case OP_BC_ZEXT:
 		case OP_BC_TRUNC:
6922903a
 		    MAP(inst->u.cast.source);
 		    break;
52dd3a6b
 		case OP_BC_BRANCH:
6922903a
 		    MAP(inst->u.branch.condition);
 		    break;
52dd3a6b
 		case OP_BC_JMP:
6922903a
 		    break;
52dd3a6b
 		case OP_BC_RET:
6922903a
 		    MAP(inst->u.unaryop);
 		    break;
52dd3a6b
 		case OP_BC_SELECT:
6922903a
 		    MAP(inst->u.three[0]);
 		    MAP(inst->u.three[1]);
 		    MAP(inst->u.three[2]);
 		    break;
52dd3a6b
 		case OP_BC_CALL_API:/* fall-through */
 		case OP_BC_CALL_DIRECT:
6922903a
 		{
cf0cd429
 		    struct cli_bc_func *target = NULL;
52dd3a6b
 		    if (inst->opcode == OP_BC_CALL_DIRECT) {
cf0cd429
 			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 {
f451cc9a
 			/* APIs have at most 2 parameters always */
50829fbf
 			if (inst->u.ops.numOps > 5) {
cf0cd429
 			    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++) {
349e6e11
 			MAPPTR(inst->u.ops.ops[k]);
52dd3a6b
 			if (inst->opcode == OP_BC_CALL_DIRECT)
cf0cd429
 			    inst->u.ops.opsizes[k] = typesize(bc, target->types[k]);
 			else
 			    inst->u.ops.opsizes[k] = 32; /*XXX*/
6922903a
 		    }
 		    break;
 		}
52dd3a6b
 		case OP_BC_LOAD:
0d9b99f4
 		    MAPPTR(inst->u.unaryop);
72617ba2
 		    break;
52dd3a6b
 		case OP_BC_GEP1:
a3a6b813
 		    if (inst->u.three[1]&0x80000000 ||
 			bcfunc->types[inst->u.binop[1]]&0x8000) {
44e13431
                       cli_errmsg("bytecode: gep1 of alloca is not allowed\n");
                       return CL_EBYTECODE;
                     }
 		    MAP(inst->u.three[1]);
 		    MAP(inst->u.three[2]);
                     inst->u.three[0] = get_geptypesize(bc, inst->u.three[0]);
                     if (inst->u.three[0] == -1)
                       return CL_EBYTECODE;
                     break;
9463f9fd
 		case OP_BC_GEPZ:
c0afc517
 		    /*three[0] is the type*/
a3a6b813
 		    if (inst->u.three[1]&0x80000000 ||
 			bcfunc->types[inst->u.three[1]]&0x8000)
4993d6cf
 			inst->interp_op = 5*(inst->interp_op/5);
 		    else
 			inst->interp_op = 5*(inst->interp_op/5)+3;
7a14dc4c
 		    MAP(inst->u.three[1]);
b1018ea5
 		    if (calc_gepz(bc, bcfunc, inst->u.three[0], inst->u.three[2]) == -1)
 			return CL_EBYTECODE;
7a14dc4c
 		    MAP(inst->u.three[2]);
 		    break;
b1018ea5
 /*		case OP_BC_GEPN:
 		    *TODO 
 		    break;*/
f451cc9a
 		case OP_BC_MEMSET:
 		case OP_BC_MEMCPY:
 		case OP_BC_MEMMOVE:
 		case OP_BC_MEMCMP:
0d9b99f4
 		    MAPPTR(inst->u.three[0]);
 		    MAPPTR(inst->u.three[1]);
5dfb4bf1
 		    MAP(inst->u.three[2]);
f451cc9a
 		    break;
44e13431
 		case OP_BC_RET_VOID:
f451cc9a
 		case OP_BC_ISBIGENDIAN:
 		case OP_BC_ABORT:
44e13431
 		    /* no operands */
f451cc9a
 		    break;
 		case OP_BC_BSWAP16:
 		case OP_BC_BSWAP32:
 		case OP_BC_BSWAP64:
6ea339ae
 		    MAP(inst->u.unaryop);
f451cc9a
 		    break;
 		case OP_BC_PTRDIFF32:
44e13431
 		    MAPPTR(inst->u.binop[0]);
 		    MAPPTR(inst->u.binop[1]);
 		    break;
 		case OP_BC_PTRTOINT64:
 		    MAPPTR(inst->u.unaryop);
f451cc9a
 		    break;
6922903a
 		default:
b1018ea5
 		    cli_warnmsg("Bytecode: unhandled opcode: %d\n", inst->opcode);
6922903a
 		    return CL_EBYTECODE;
 	    }
 	}
 	free(map);
     }
20327f93
     free(gmap);
6922903a
     bc->state = bc_interp;
     return CL_SUCCESS;
 }
 
a5a19f45
 static int add_selfcheck(struct cli_all_bc *bcs)
 {
     struct cli_bc_func *func;
     struct cli_bc_inst *inst;
     struct cli_bc *bc;
 
     bcs->all_bcs = cli_realloc2(bcs->all_bcs, sizeof(*bcs->all_bcs)*(bcs->count+1));
     if (!bcs->all_bcs) {
 	cli_errmsg("cli_loadcbc: Can't allocate memory for bytecode entry\n");
 	return CL_EMEM;
     }
     bc = &bcs->all_bcs[bcs->count++];
     memset(bc, 0, sizeof(*bc));
 
     bc->trusted = 1;
     bc->num_globals = 1;
     bc->globals = cli_calloc(1, sizeof(*bc->globals));
     if (!bc->globals) {
 	cli_errmsg("Failed to allocate memory for globals\n");
 	return CL_EMEM;
     }
     bc->globals[0] = cli_calloc(1, sizeof(*bc->globals[0]));
     if (!bc->globals[0]) {
 	cli_errmsg("Failed to allocate memory for globals\n");
 	return CL_EMEM;
     }
     bc->globaltys = cli_calloc(1, sizeof(*bc->globaltys));
     if (!bc->globaltys) {
 	cli_errmsg("Failed to allocate memory for globaltypes\n");
 	return CL_EMEM;
     }
     bc->globaltys[0] = 32;
     *bc->globals[0] = 0;
     bc->id = ~0;
     bc->kind = 0;
     bc->num_types = 5;
     bc->num_func = 1;
     bc->funcs = cli_calloc(1, sizeof(*bc->funcs));
     if (!bc->funcs) {
 	cli_errmsg("Failed to allocate memory for func\n");
 	return CL_EMEM;
     }
     func = bc->funcs;
     func->numInsts = 2;
     func->numLocals = 1;
     func->numValues = 1;
     func->numConstants = 1;
     func->numBB = 1;
     func->returnType = 32;
     func->types = cli_calloc(1, sizeof(*func->types));
     if (!func->types) {
 	cli_errmsg("Failed to allocate memory for types\n");
 	return CL_EMEM;
     }
     func->types[0] = 32;
     func->BB = cli_calloc(1, sizeof(*func->BB));
     if (!func->BB) {
 	cli_errmsg("Failed to allocate memory for BB\n");
 	return CL_EMEM;
     }
     func->allinsts = cli_calloc(2, sizeof(*func->allinsts));
     if (!func->allinsts) {
 	cli_errmsg("Failed to allocate memory for insts\n");
 	return CL_EMEM;
     }
     func->BB->numInsts = 2;
     func->BB->insts = func->allinsts;
     func->constants = cli_calloc(1, sizeof(*func->constants));
     if (!func->constants) {
 	cli_errmsg("Failed to allocate memory for constants\n");
 	return CL_EMEM;
     }
     func->constants[0] = 0xf00d;
     inst = func->allinsts;
 
     inst->opcode = OP_BC_CALL_API;
     inst->u.ops.numOps = 1;
     inst->u.ops.opsizes = NULL;
     inst->u.ops.ops = cli_calloc(1, sizeof(*inst->u.ops.ops));
     if (!inst->u.ops.ops) {
 	cli_errmsg("Failed to allocate memory for instructions\n");
 	return CL_EMEM;
     }
     inst->u.ops.ops[0] = 1;
     inst->u.ops.funcid = 18; /* test2 */
     inst->dest = 0;
     inst->type = 32;
     inst->interp_op = inst->opcode* 5 + 3;
 
     inst = &func->allinsts[1];
     inst->opcode = OP_BC_RET;
     inst->type = 32;
     inst->u.unaryop = 0;
     inst->interp_op = inst->opcode* 5;
 
     bc->state = bc_loaded;
     return 0;
 }
 
 static int run_selfcheck(struct cli_all_bc *bcs)
 {
     struct cli_bc_ctx *ctx;
     struct cli_bc *bc = &bcs->all_bcs[bcs->count-1];
     int rc;
     if (bc->state != bc_jit && bc->state != bc_interp) {
 	cli_errmsg("Failed to prepare selfcheck bytecode\n");
 	return CL_EBYTECODE;
     }
     ctx = cli_bytecode_context_alloc();
     if (!ctx) {
 	cli_errmsg("Failed to allocate bytecode context\n");
 	return CL_EMEM;
     }
     cli_bytecode_context_setfuncid(ctx, bc, 0);
 
     cli_dbgmsg("bytecode self test running\n");
     rc = cli_bytecode_run(bcs, bc, ctx);
     cli_bytecode_context_destroy(ctx);
     if (rc != CL_SUCCESS) {
 	cli_errmsg("bytecode self test failed: %s\n",
 		   cl_strerror(rc));
     } else {
 	cli_dbgmsg("bytecode self test succeeded\n");
     }
     return rc;
 }
 
 static int selfcheck(int jit, struct cli_bcengine *engine)
 {
     struct cli_all_bc bcs;
     int rc;
 
     memset(&bcs, 0, sizeof(bcs));
     bcs.all_bcs = NULL;
     bcs.count = 0;
     bcs.engine = engine;
     rc = add_selfcheck(&bcs);
     if (rc == CL_SUCCESS) {
 	if (jit) {
 	    if (!bcs.engine) {
 		cli_dbgmsg("bytecode: JIT disabled\n");
 		rc = CL_BREAK;/* no JIT - not fatal */
 	    } else {
 		rc = cli_bytecode_prepare_jit(&bcs);
 	    }
 	} else {
 	    rc = cli_bytecode_prepare_interpreter(bcs.all_bcs);
 	}
 	if (rc == CL_SUCCESS)
 	    rc = run_selfcheck(&bcs);
 	if (rc == CL_BREAK)
 	    rc = CL_SUCCESS;
     }
     cli_bytecode_destroy(bcs.all_bcs);
     free(bcs.all_bcs);
     cli_bytecode_done_jit(&bcs, 1);
     if (rc != CL_SUCCESS) {
 	cli_errmsg("Bytecode: failed to run selfcheck in %s mode: %s\n",
 		   jit ? "JIT" : "interpreter", cl_strerror(rc));
     }
     return rc;
 }
 
d5ffa2ac
 static int set_mode(struct cl_engine *engine, enum bytecode_mode mode)
 {
     if (engine->bytecode_mode == mode)
 	return 0;
     if (engine->bytecode_mode == CL_BYTECODE_MODE_OFF) {
 	cli_errmsg("bytecode: already turned off, can't turn it on again!\n");
 	return -1;
     }
     cli_dbgmsg("Bytecode: mode changed to %d\n", mode);
     if (engine->bytecode_mode == CL_BYTECODE_MODE_TEST) {
213dfdff
 	if (mode == CL_BYTECODE_MODE_OFF || have_clamjit) {
 	    cli_errmsg("bytecode: in test mode but JIT/bytecode is about to be disabled: %d\n", mode);
 	    engine->bytecode_mode = mode;
 	    return -1;
 	}
 	return 0;
d5ffa2ac
     }
     if (engine->bytecode_mode == CL_BYTECODE_MODE_JIT) {
 	cli_errmsg("bytecode: in JIT mode but JIT is about to be disabled: %d\n", mode);
 	engine->bytecode_mode = mode;
 	return -1;
     }
     engine->bytecode_mode = mode;
     return 0;
 }
 
 /* runs the first bytecode of the specified kind, or the builtin one if no
  * bytecode of that kind is loaded */
 static int run_builtin_or_loaded(struct cli_all_bc *bcs, uint8_t kind, const char* builtin_cbc, struct cli_bc_ctx *ctx, const char *desc)
 {
     unsigned i, builtin = 0, rc = 0;
     struct cli_bc *bc = NULL;
 
     for (i=0;i<bcs->count;i++) {
 	bc = &bcs->all_bcs[i];
 	if (bc->kind == kind)
 	    break;
     }
     if (i == bcs->count)
 	bc = NULL;
     if (!bc) {
 	/* no loaded bytecode found, load the builtin one! */
 	struct cli_dbio dbio;
 	bc = cli_calloc(1, sizeof(*bc));
 	if (!bc) {
 	    cli_errmsg("Out of memory allocating bytecode\n");
 	    return CL_EMEM;
 	}
 	builtin = 1;
 
 	memset(&dbio, 0, sizeof(dbio));
 	dbio.usebuf = 1;
 	dbio.bufpt = dbio.buf = (char*)builtin_cbc;
 	dbio.bufsize = strlen(builtin_cbc)+1;
 	if (!dbio.bufsize || dbio.bufpt[dbio.bufsize-2] != '\n') {
 	    cli_errmsg("Invalid builtin bytecode: missing terminator\n");
 	    free(bc);
 	    return CL_EMALFDB;
 	}
 
 	rc = cli_bytecode_load(bc, NULL, &dbio, 1);
 	if (rc) {
 	    cli_errmsg("Failed to load builtin %s bytecode\n", desc);
 	    free(bc);
 	    return rc;
 	}
     }
     rc = cli_bytecode_prepare_interpreter(bc);
     if (rc) {
 	cli_errmsg("Failed to prepare %s %s bytecode for interpreter: %s\n",
 		   builtin ? "builtin" : "loaded", desc, cl_strerror(rc));
     }
     if (bc->state != bc_interp) {
 	cli_errmsg("Failed to prepare %s %s bytecode for interpreter\n",
 		   builtin ? "builtin" : "loaded", desc);
 	rc = CL_EMALFDB;
     }
     if (!rc) {
 	cli_bytecode_context_setfuncid(ctx, bc, 0);
 	cli_dbgmsg("Bytecode: %s running (%s)\n", desc,
 		   builtin ? "builtin" : "loaded");
 	rc = cli_bytecode_run(bcs, bc, ctx);
     }
     if (rc) {
 	cli_errmsg("Failed to execute %s %s bytecode: %s\n",builtin ? "builtin":"loaded",
 		   desc, cl_strerror(rc));
     }
     if (builtin) {
 	cli_bytecode_destroy(bc);
 	free(bc);
     }
     return rc;
 }
 
540fc128
 int cli_bytecode_prepare2(struct cl_engine *engine, struct cli_all_bc *bcs, unsigned dconfmask)
6922903a
 {
d5ffa2ac
     unsigned i, interp = 0, jitok = 0, jitcount=0;
dc200c6b
     int rc;
d5ffa2ac
     struct cli_bc_ctx *ctx;
a5a19f45
 
d5ffa2ac
     cli_detect_environment(&bcs->env);
     switch (bcs->env.arch) {
 	case arch_i386:
 	case arch_x86_64:
 	    if (!(dconfmask & BYTECODE_JIT_X86)) {
 		cli_dbgmsg("Bytecode: disabled on X86 via DCONF\n");
 		if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
 		    return CL_EBYTECODE_TESTFAIL;
 	    }
 	    break;
 	case arch_ppc32:
 	case arch_ppc64:
 	    if (!(dconfmask & BYTECODE_JIT_PPC)) {
 		cli_dbgmsg("Bytecode: disabled on PPC via DCONF\n");
 		if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
 		    return CL_EBYTECODE_TESTFAIL;
 	    }
 	    break;
 	case arch_arm:
 	    if (!(dconfmask & BYTECODE_JIT_ARM)) {
 		cli_dbgmsg("Bytecode: disabled on ARM via DCONF\n");
 		if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
 		    return CL_EBYTECODE_TESTFAIL;
 	    }
 	    break;
 	default:
 	    cli_dbgmsg("Bytecode: JIT not supported on this architecture, falling back\n");
 	    if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
 		return CL_EBYTECODE_TESTFAIL;
 	    break;
     }
     cli_dbgmsg("Bytecode: mode is %d\n", engine->bytecode_mode);
a5a19f45
 
d5ffa2ac
     ctx = cli_bytecode_context_alloc();
     if (!ctx) {
 	cli_errmsg("Bytecode: failed to allocate bytecode context\n");
 	return CL_EMEM;
     }
0d4c9946
     rc = run_builtin_or_loaded(bcs, BC_STARTUP, builtin_bc_startup, ctx, "BC_STARTUP");
d5ffa2ac
     if (rc != CL_SUCCESS) {
 	cli_warnmsg("Bytecode: BC_STARTUP failed to run, disabling ALL bytecodes! Please report to http://bugs.clamav.net\n");
 	ctx->bytecode_disable_status = 2;
     } else {
 	cli_dbgmsg("Bytecode: disable status is %d\n", ctx->bytecode_disable_status);
 	rc = cli_bytecode_context_getresult_int(ctx);
dbd3ed93
 	/* check magic number, don't use 0 here because it is too easy for a
 	 * buggy bytecode to return 0 */
 	if (rc != 0xda7aba5e) {
 	    cli_warnmsg("Bytecode: selftest failed with code %08x. Please report to http://bugs.clamav.net\n",
d5ffa2ac
 			rc);
 	    if (engine->bytecode_mode == CL_BYTECODE_MODE_TEST)
 		return CL_EBYTECODE_TESTFAIL;
 	}
     }
     switch (ctx->bytecode_disable_status) {
 	case 1:
 	    if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
 		return CL_EBYTECODE_TESTFAIL;
 	    break;
 	case 2:
 	    if (set_mode(engine, CL_BYTECODE_MODE_OFF) == -1)
 		return CL_EBYTECODE_TESTFAIL;
 	    break;
 	default:
 	    break;
     }
     cli_bytecode_context_destroy(ctx);
 
d732b5aa
 
d5ffa2ac
     if (engine->bytecode_mode != CL_BYTECODE_MODE_INTERPRETER &&
 	engine->bytecode_mode != CL_BYTECODE_MODE_OFF) {
d732b5aa
 	selfcheck(1, bcs->engine);
d5ffa2ac
 	rc = cli_bytecode_prepare_jit(bcs);
 	if (rc == CL_SUCCESS) {
 	    jitok = 1;
 	    cli_dbgmsg("Bytecode: %u bytecode prepared with JIT\n", bcs->count);
 	    if (engine->bytecode_mode != CL_BYTECODE_MODE_TEST)
 		return CL_SUCCESS;
 	}
 	if (engine->bytecode_mode == CL_BYTECODE_MODE_JIT) {
 	    cli_errmsg("Bytecode: JIT required, but not all bytecodes could be prepared with JIT\n");
 	    return CL_EMALFDB;
 	}
     } else {
 	cli_bytecode_done_jit(bcs, 0);
     }
 
     if (!(dconfmask & BYTECODE_INTERPRETER)) {
 	cli_dbgmsg("Bytecode: needs interpreter, but interpreter is disabled\n");
 	if (set_mode(engine, CL_BYTECODE_MODE_OFF) == -1)
 	    return CL_EBYTECODE_TESTFAIL;
     }
 
     if (engine->bytecode_mode == CL_BYTECODE_MODE_OFF) {
 	for (i=0;i<bcs->count;i++)
 	    bcs->all_bcs[i].state = bc_disabled;
 	cli_dbgmsg("Bytecode: ALL bytecodes disabled\n");
d1487222
 	return CL_SUCCESS;
e86fe7ea
     }
d5ffa2ac
 
d1487222
     for (i=0;i<bcs->count;i++) {
 	struct cli_bc *bc = &bcs->all_bcs[i];
d5ffa2ac
 	if (bc->state == bc_jit) {
 	    jitcount++;
d1487222
 	    continue;
d5ffa2ac
 	}
 	if (bc->state == bc_interp) {
 	    interp++;
6eeadbfe
 	    continue;
 	}
d1487222
 	rc = cli_bytecode_prepare_interpreter(bc);
d5ffa2ac
 	if (rc != CL_SUCCESS) {
 	    bc->state = bc_disabled;
 	    cli_warnmsg("Bytecode: %d failed to prepare for interpreter mode\n", bc->id);
d1487222
 	    return rc;
d5ffa2ac
 	}
 	interp++;
6922903a
     }
e86fe7ea
     cli_dbgmsg("Bytecode: %u bytecode prepared with JIT, "
d5ffa2ac
 	       "%u prepared with interpreter, %u failed\n", jitcount, interp,
 	       bcs->count - jitcount - interp);
d1487222
     return CL_SUCCESS;
6922903a
 }
 
927d0548
 int cli_bytecode_init(struct cli_all_bc *allbc)
6922903a
 {
927d0548
     int ret;
d1487222
     memset(allbc, 0, sizeof(*allbc));
927d0548
     ret = cli_bytecode_init_jit(allbc, 0/*XXX*/);
     cli_dbgmsg("Bytecode initialized in %s mode\n",
 	       allbc->engine ? "JIT" : "interpreter");
     allbc->inited = 1;
     return ret;
d1487222
 }
 
 int cli_bytecode_done(struct cli_all_bc *allbc)
 {
a5a19f45
     return cli_bytecode_done_jit(allbc, 0);
6922903a
 }
3b33bd68
 
74b00233
 int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, fmap_t *map)
a1781898
 {
74b00233
     ctx->fmap = map;
     ctx->file_size = map->len + map->offset;
0fa95ef2
     ctx->hooks.filesize = &ctx->file_size;
a1781898
     return 0;
 }
 
762d46e8
 int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
 			 const struct cli_all_bc *bcs, unsigned bc_idx,
 			 const char **virname, const uint32_t* lsigcnt,
 			 const uint32_t *lsigsuboff, fmap_t *map)
d38d6dad
 {
     int ret;
     struct cli_bc_ctx ctx;
57f14280
     const struct cli_bc *bc = &bcs->all_bcs[bc_idx-1];
762d46e8
     struct cli_pe_hook_data pehookdata;
f4e34215
 
     if (bc->hook_lsig_id) {
57f14280
 	cli_dbgmsg("hook lsig id %d matched (bc %d)\n", bc->hook_lsig_id, bc->id);
f4e34215
 	/* this is a bytecode for a hook, defer running it until hook is
 	 * executed, so that it has all the info for the hook */
 	if (cctx->hook_lsig_matches)
 	    cli_bitset_set(cctx->hook_lsig_matches, bc->hook_lsig_id-1);
70c222c9
 	/* save match counts */
 	memcpy(&ctx.lsigcnt, lsigcnt, 64*4);
 	memcpy(&ctx.lsigoff, lsigsuboff, 64*4);
f4e34215
 	return CL_SUCCESS;
     }
d38d6dad
     memset(&ctx, 0, sizeof(ctx));
     cli_bytecode_context_setfuncid(&ctx, bc, 0);
88815fd8
     ctx.hooks.match_counts = lsigcnt;
1c4683ac
     ctx.hooks.match_offsets = lsigsuboff;
92a08a03
     cli_bytecode_context_setctx(&ctx, cctx);
74b00233
     cli_bytecode_context_setfile(&ctx, map);
762d46e8
     if (tinfo && tinfo->status == 1) {
 	ctx.sections = tinfo->exeinfo.section;
 	memset(&pehookdata, 0, sizeof(pehookdata));
 	pehookdata.offset = tinfo->exeinfo.offset;
 	pehookdata.ep = tinfo->exeinfo.ep;
 	pehookdata.nsections = tinfo->exeinfo.nsections;
 	pehookdata.hdr_size = tinfo->exeinfo.hdr_size;
 	ctx.hooks.pedata = &pehookdata;
 	ctx.resaddr = tinfo->exeinfo.res_addr;
     }
d38d6dad
 
     cli_dbgmsg("Running bytecode for logical signature match\n");
     ret = cli_bytecode_run(bcs, bc, &ctx);
     if (ret != CL_SUCCESS) {
 	cli_warnmsg("Bytcode failed to run: %s\n", cl_strerror(ret));
 	return CL_SUCCESS;
     }
     if (ctx.virname) {
 	cli_dbgmsg("Bytecode found virus: %s\n", ctx.virname);
 	if (virname)
 	    *virname = ctx.virname;
 	cli_bytecode_context_clear(&ctx);
 	return CL_VIRUS;
     }
     ret = cli_bytecode_context_getresult_int(&ctx);
ab636570
     cli_dbgmsg("Bytecode %u returned code: %u\n", bc->id, ret);
d38d6dad
     cli_bytecode_context_clear(&ctx);
     return CL_SUCCESS;
 }
ab636570
 
f4e34215
 int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx,
74b00233
 			 unsigned id, fmap_t *map, const char **virname)
ab636570
 {
     const unsigned *hooks = engine->hooks[id - _BC_START_HOOKS];
     unsigned i, hooks_cnt = engine->hooks_cnt[id - _BC_START_HOOKS];
     int ret;
e86fe7ea
     unsigned executed = 0;
ab636570
 
74b00233
     cli_bytecode_context_setfile(ctx, map);
ab636570
     cli_dbgmsg("Bytecode executing hook id %u (%u hooks)\n", id, hooks_cnt);
70c222c9
     /* restore match counts */
     ctx->hooks.match_counts = ctx->lsigcnt;
     ctx->hooks.match_offsets = ctx->lsigoff;
ab636570
     for (i=0;i < hooks_cnt;i++) {
 	const struct cli_bc *bc = &engine->bcs.all_bcs[hooks[i]];
f4e34215
 	if (bc->lsig) {
 	    if (!cctx->hook_lsig_matches ||
 		!cli_bitset_test(cctx->hook_lsig_matches, bc->hook_lsig_id-1))
 		continue;
57f14280
 	    cli_dbgmsg("Bytecode: executing bytecode %u (lsig matched)\n" , bc->id);
f4e34215
 	}
ab636570
 	cli_bytecode_context_setfuncid(ctx, bc, 0);
 	ret = cli_bytecode_run(&engine->bcs, bc, ctx);
e86fe7ea
 	executed++;
ab636570
 	if (ret != CL_SUCCESS) {
 	    cli_warnmsg("Bytecode failed to run: %s\n", cl_strerror(ret));
e86fe7ea
 	    continue;
ab636570
 	}
 	if (ctx->virname) {
 	    cli_dbgmsg("Bytecode found virus: %s\n", ctx->virname);
 	    if (virname)
 		*virname = ctx->virname;
 	    cli_bytecode_context_clear(ctx);
 	    return CL_VIRUS;
 	}
 	ret = cli_bytecode_context_getresult_int(ctx);
 	/* TODO: use prefix here */
 	cli_dbgmsg("Bytecode %u returned %u\n", bc->id, ret);
3ae0a76d
 	if (!ret) {
 	    char *tempfile;
 	    int fd = cli_bytecode_context_getresult_file(ctx, &tempfile);
b28845c3
 	    if (fd && fd != -1) {
3ae0a76d
 		if (cctx && cctx->engine->keeptmp)
 		    cli_dbgmsg("Bytecode %u unpacked file saved in %s\n",
 			       bc->id, tempfile);
 		else
 		    cli_dbgmsg("Bytecode %u unpacked file\n", bc->id);
 		lseek(fd, 0, SEEK_SET);
 		cli_dbgmsg("***** Scanning unpacked file ******\n");
 		ret = cli_magic_scandesc(fd, cctx);
 		if (!cctx || !cctx->engine->keeptmp)
d0934caf
 		    if (ftruncate(fd, 0) == -1)
b28845c3
 			cli_dbgmsg("ftruncate failed on %d\n", fd);
3ae0a76d
 		close(fd);
 		if (!cctx || !cctx->engine->keeptmp) {
b28845c3
 		    if (tempfile && cli_unlink(tempfile))
3ae0a76d
 			ret = CL_EUNLINK;
 		}
 		free(tempfile);
 		if (ret != CL_CLEAN) {
 		    if (ret == CL_VIRUS)
 			cli_dbgmsg("Scanning unpacked file by bytecode %u found a virus\n", bc->id);
 		    cli_bytecode_context_clear(ctx);
 		    return ret;
 		}
 		cli_bytecode_context_reset(ctx);
 		continue;
 	    }
 	}
ab636570
 	cli_bytecode_context_reset(ctx);
     }
e86fe7ea
     if (executed)
 	cli_dbgmsg("Bytecode: executed %u bytecodes for this hook\n", executed);
     else
 	cli_dbgmsg("Bytecode: no logical signature matched, no bytecode executed\n");
ab636570
     return CL_CLEAN;
 }
 
236fb136
 int cli_bytecode_context_setpe(struct cli_bc_ctx *ctx, const struct cli_pe_hook_data *data, const struct cli_exe_section *sections)
ab636570
 {
236fb136
     ctx->sections = sections;
ab636570
     ctx->hooks.pedata = data;
     return 0;
 }
3ae0a76d
 
 void cli_bytecode_context_setctx(struct cli_bc_ctx *ctx, void *cctx)
 {
     ctx->ctx = cctx;
b63681a5
     ctx->bytecode_timeout = ((cli_ctx*)cctx)->engine->bytecode_timeout;
3ae0a76d
 }
a35cfe51
 
 void cli_bytecode_describe(const struct cli_bc *bc)
 {
     char buf[128];
     int cols;
     unsigned i;
     time_t stamp;
     int had;
 
     if (!bc) {
 	printf("(null bytecode)\n");
 	return;
     }
 
     stamp = bc->metadata.timestamp;
3735fda1
     printf("Bytecode format functionality level: %u\n", bc->metadata.formatlevel);
a35cfe51
     printf("Bytecode metadata:\n\tcompiler version: %s\n",
 	   bc->metadata.compiler ? bc->metadata.compiler : "N/A");
d5ffa2ac
     printf("\tcompiled on: (%d) %s",
88d54dcb
 	   (uint32_t)stamp,
a35cfe51
 	   cli_ctime(&stamp, buf, sizeof(buf)));
     printf("\tcompiled by: %s\n", bc->metadata.sigmaker ? bc->metadata.sigmaker : "N/A");
c0afc517
     /*TODO: parse and display arch name, also take it into account when
       JITing*/
a35cfe51
     printf("\ttarget exclude: %d\n", bc->metadata.targetExclude);
     printf("\tbytecode type: ");
     switch (bc->kind) {
 	case BC_GENERIC:
 	    puts("generic, not loadable by clamscan/clamd");
 	    break;
d5ffa2ac
 	case BC_STARTUP:
 	    puts("run on startup (unique)");
 	    break;
a35cfe51
 	case BC_LOGICAL:
 	    puts("logical only");
 	    break;
 	case BC_PE_UNPACKER:
 	    puts("PE hook");
 	    break;
 	default:
 	    printf("Unknown (type %u)", bc->kind);
 	    break;
     }
3735fda1
     /* 0 means no limit */
     printf("\tbytecode functionality level: %u - %u\n",
 	   bc->metadata.minfunc, bc->metadata.maxfunc);
a35cfe51
     printf("\tbytecode logical signature: %s\n",
 	       bc->lsig ? bc->lsig : "<none>");
     printf("\tvirusname prefix: %s\n",
 	   bc->vnameprefix);
     printf("\tvirusnames: %u\n", bc->vnames_cnt);
     printf("\tbytecode triggered on: ");
     switch (bc->kind) {
 	case BC_GENERIC:
 	    puts("N/A (loaded in clambc only)");
 	    break;
 	case BC_LOGICAL:
 	    puts("files matching logical signature");
 	    break;
 	case BC_PE_UNPACKER:
 	    if (bc->lsig)
 		puts("PE files matching logical signature");
 	    else
 		puts("all PE files!");
 	    break;
 	default:
 	    puts("N/A (unknown type)\n");
 	    break;
     }
     printf("\tnumber of functions: %u\n\tnumber of types: %u\n",
 	   bc->num_func, bc->num_types);
5297d09e
     printf("\tnumber of global constants: %u\n", (unsigned)bc->num_globals);
a35cfe51
     printf("\tnumber of debug nodes: %u\n", bc->dbgnode_cnt);
     printf("\tbytecode APIs used:");
     cols = 0; /* remaining */
     had = 0;
     for (i=0;i<cli_apicall_maxapi;i++) {
 	if (cli_bitset_test(bc->uses_apis, i)) {
 	    unsigned len = strlen(cli_apicalls[i].name);
 	    if (had)
 		printf(",");
 	    if (len > cols) {
 		printf("\n\t");
 		cols = 72;
 	    }
 	    printf(" %s", cli_apicalls[i].name);
 	    had = 1;
 	    cols -= len;
 	}
     }
     printf("\n");
 }