2
* Execute ClamAV bytecode.
4
* Copyright (C) 2009-2010 Sourcefire, Inc.
6
* Authors: Tƶrƶk Edvin
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2 as
10
* published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23
#include "clamav-config.h"
28
#include "bytecode_priv.h"
29
#include "type_desc.h"
35
#include "bytecode_api_impl.h"
36
#include "disasm-common.h"
38
/* Enable this to catch more bugs in the RC phase */
39
#define CL_BYTECODE_SAFE
41
#ifdef CL_BYTECODE_SAFE
42
/* These checks will also be done by the bytecode verifier, but for
43
* debugging purposes we have explicit checks, these should never fail! */
45
static int never_inline bcfail(const char *msg, long a, long b,
46
const char *file, unsigned line)
48
cli_warnmsg("bytecode: check failed %s (%lx and %lx) at %s:%u\n", msg, a, b, file, line);
52
#define bcfail(msg,a,b,f,l) CL_EBYTECODE
55
#define CHECK_FUNCID(funcid) do { if (funcid >= bc->num_func) return \
56
bcfail("funcid out of bounds!",funcid, bc->num_func,__FILE__,__LINE__); } while(0)
57
#define CHECK_APIID(funcid) do { if (funcid >= cli_apicall_maxapi) return \
58
bcfail("APIid out of bounds!",funcid, cli_apicall_maxapi,__FILE__,__LINE__); } while(0)
59
#define CHECK_EQ(a, b) do { if ((a) != (b)) return \
60
bcfail("Values "#a" and "#b" don't match!",(a),(b),__FILE__,__LINE__); } while(0)
61
#define CHECK_GT(a, b) do {if ((a) <= (b)) return \
62
bcfail("Condition failed "#a" > "#b,(a),(b), __FILE__, __LINE__); } while(0)
65
static inline int bcfail(const char *msg, long a, long b,
66
const char *file, unsigned line) {}
67
#define CHECK_FUNCID(x);
68
#define CHECK_APIID(x);
73
#define CHECK_UNREACHABLE do { cli_dbgmsg("bytecode: unreachable executed!\n"); return CL_EBYTECODE; } while(0)
74
#define TRACE_PTR(ptr, s) cli_dbgmsg("bytecode trace: ptr %llx, +%x\n", ptr, s);
75
#define TRACE_R(x) cli_dbgmsg("bytecode trace: %u, read %llx\n", pc, (long long)x);
76
#define TRACE_W(x, w, p) cli_dbgmsg("bytecode trace: %u, write%d @%u %llx\n", pc, p, w, (long long)(x));
77
#define TRACE_EXEC(id, dest, ty, stack) cli_dbgmsg("bytecode trace: executing %d, -> %u (%u); %u\n", id, dest, ty, stack)
78
#define TRACE_API(s, dest, ty, stack) cli_dbgmsg("bytecode trace: executing %s, -> %u (%u); %u\n", s, dest, ty, stack)
80
#define CHECK_UNREACHABLE return CL_EBYTECODE
81
#define TRACE_PTR(ptr, s)
83
#define TRACE_W(x, w, p)
84
#define TRACE_EXEC(id, dest, ty, stack)
85
#define TRACE_API(s, dest, ty, stack)
88
#define SIGNEXT(a, from) CLI_SRS(((int64_t)(a)) << (64-(from)), (64-(from)))
95
static always_inline int jump(const struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, const struct cli_bc_inst **inst,
98
CHECK_GT(func->numBB, bbid);
99
*bb = &func->BB[bbid];
100
*inst = (*bb)->insts;
105
#define STACK_CHUNKSIZE 65536
108
struct stack_chunk *prev;
112
char data[STACK_CHUNKSIZE];
117
struct stack_chunk* chunk;
121
/* type with largest alignment that we use (in general it is a long double, but
122
* thats too big alignment for us) */
123
typedef uint64_t align_t;
125
static always_inline void* cli_stack_alloc(struct stack *stack, unsigned bytes)
127
struct stack_chunk *chunk = stack->chunk;
128
uint16_t last_size_off;
130
/* last_size is stored after data */
131
/* align bytes to pointer size */
132
bytes = (bytes + sizeof(uint16_t) + sizeof(align_t)) & ~(sizeof(align_t)-1);
133
last_size_off = bytes - 2;
135
if (chunk && (chunk->used + bytes <= STACK_CHUNKSIZE)) {
136
/* there is still room in this chunk */
139
*(uint16_t*)&chunk->u.data[chunk->used + last_size_off] = stack->last_size;
140
stack->last_size = bytes/sizeof(align_t);
142
ret = chunk->u.data + chunk->used;
143
chunk->used += bytes;
147
if(bytes >= STACK_CHUNKSIZE) {
148
cli_warnmsg("cli_stack_alloc: Attempt to allocate more than STACK_CHUNKSIZE bytes: %u!\n", bytes);
151
/* not enough room here, allocate new chunk */
152
chunk = cli_malloc(sizeof(*stack->chunk));
156
*(uint16_t*)&chunk->u.data[last_size_off] = stack->last_size;
157
stack->last_size = bytes/sizeof(align_t);
160
chunk->prev = stack->chunk;
161
stack->chunk = chunk;
162
return chunk->u.data;
165
static always_inline void cli_stack_free(struct stack *stack, void *data)
168
struct stack_chunk *chunk = stack->chunk;
170
cli_warnmsg("cli_stack_free: stack empty!\n");
173
if ((chunk->u.data + chunk->used) != ((char*)data + stack->last_size*sizeof(align_t))) {
174
cli_warnmsg("cli_stack_free: wrong free order: %p, expected %p\n",
175
data, chunk->u.data + chunk->used - stack->last_size*sizeof(align_t));
178
last_size = *(uint16_t*)&chunk->u.data[chunk->used-2];
179
if (chunk->used < stack->last_size*sizeof(align_t)) {
180
cli_warnmsg("cli_stack_free: last_size is corrupt!\n");
183
chunk->used -= stack->last_size*sizeof(align_t);
184
stack->last_size = last_size;
186
stack->chunk = chunk->prev;
191
static void cli_stack_destroy(struct stack *stack)
193
struct stack_chunk *chunk = stack->chunk;
195
stack->chunk = chunk->prev;
197
chunk = stack->chunk;
202
struct stack_entry *prev;
203
const struct cli_bc_func *func;
206
struct cli_bc_bb *bb;
210
static always_inline struct stack_entry *allocate_stack(struct stack *stack,
211
struct stack_entry *prev,
212
const struct cli_bc_func *func,
213
const struct cli_bc_func *func_old,
215
struct cli_bc_bb *bb,
219
struct stack_entry *entry = cli_stack_alloc(stack, sizeof(*entry) + sizeof(*values)*func->numBytes);
223
entry->func = func_old;
226
entry->bb_inst = bb_inst;
227
/* we allocated room for values right after stack_entry! */
228
entry->values = values = (char*)&entry[1];
229
memcpy(&values[func->numBytes - func->numConstants*8], func->constants,
230
sizeof(*values)*func->numConstants*8);
234
static always_inline struct stack_entry *pop_stack(struct stack *stack,
235
struct stack_entry *stack_entry,
236
const struct cli_bc_func **func,
238
struct cli_bc_bb **bb,
242
*func = stack_entry->func;
243
*ret = stack_entry->ret;
244
*bb = stack_entry->bb;
245
*bb_inst = stack_entry->bb_inst;
247
stack_entry = stack_entry->prev;
248
cli_stack_free(stack, data);
255
* p, p+1, p+2, p+3 <- gt
260
#define WRITE8(p, x) CHECK_GT(func->numBytes, p);\
262
*(uint8_t*)&values[p] = x
263
#define WRITE16(p, x) CHECK_GT(func->numBytes, p+1);\
266
*(uint16_t*)&values[p] = x
267
#define WRITE32(p, x) CHECK_GT(func->numBytes, p+3);\
270
*(uint32_t*)&values[p] = x
271
#define WRITE64(p, x) CHECK_GT(func->numBytes, p+7);\
274
*(uint64_t*)&values[p] = x
275
#define WRITEP(x, p) CHECK_GT(func->numBytes, p+PSIZE-1);\
276
CHECK_EQ((p)&(PSIZE-1), 0);\
277
TRACE_W(x, p, PSIZE*8);\
278
*(void**)&values[p] = x
280
#define uint_type(n) uint##n##_t
281
#define READNfrom(maxBytes, from, x, n, p)\
282
CHECK_GT((maxBytes), (p)+(n/8)-1);\
283
CHECK_EQ((p)&(n/8-1), 0);\
284
x = *(uint_type(n)*)&(from)[(p)];\
287
#define READN(x, n, p)\
290
uint32_t pg = p&0x7fffffff;\
294
READNfrom(bc->numGlobalBytes, bc->globalBytes, x, n, pg);\
297
READNfrom(func->numBytes, values, x, n, p);\
301
#define READ1(x, p) READN(x, 8, p);\
303
#define READ8(x, p) READN(x, 8, p)
304
#define READ16(x, p) READN(x, 16, p)
305
#define READ32(x, p) READN(x, 32, p)
306
#define READ64(x, p) READN(x, 64, p)
308
#define PSIZE sizeof(int64_t)
309
#define READP(x, p, asize) { int64_t iptr__;\
310
READN(iptr__, 64, p);\
311
x = ptr_torealptr(&ptrinfos, iptr__, (asize));\
313
stop = CL_EBYTECODE;\
318
#define READPOP(x, p, asize) {\
319
if ((p)&0x40000000) {\
320
unsigned ptr__ = (p)&0xbfffffff;\
321
CHECK_GT(func->numBytes, ptr__);\
322
TRACE_PTR(ptr__, asize);\
323
x = (void*)&values[ptr__];\
329
#define READOLD8(x, p) CHECK_GT(func->numBytes, p);\
330
x = *(uint8_t*)&old_values[p];\
332
#define READOLD16(x, p) CHECK_GT(func->numBytes, p+1);\
334
x = *(uint16_t*)&old_values[p];\
336
#define READOLD32(x, p) CHECK_GT(func->numBytes, p+3);\
338
x = *(uint32_t*)&old_values[p];\
340
#define READOLD64(x, p) CHECK_GT(func->numBytes, p+7);\
342
x = *(uint64_t*)&old_values[p];\
345
#define BINOP(i) inst->u.binop[i]
347
#define DEFINE_BINOP_BC_HELPER(opc, OP, W0, W1, W2, W3, W4) \
349
uint8_t op0, op1, res;\
351
READ1(op0, BINOP(0));\
352
READ1(op1, BINOP(1));\
353
sop0 = op0; sop1 = op1;\
355
W0(inst->dest, res);\
359
uint8_t op0, op1, res;\
361
READ8(op0, BINOP(0));\
362
READ8(op1, BINOP(1));\
363
sop0 = op0; sop1 = op1;\
365
W1(inst->dest, res);\
369
uint16_t op0, op1, res;\
371
READ16(op0, BINOP(0));\
372
READ16(op1, BINOP(1));\
373
sop0 = op0; sop1 = op1;\
375
W2(inst->dest, res);\
379
uint32_t op0, op1, res;\
381
READ32(op0, BINOP(0));\
382
READ32(op1, BINOP(1));\
383
sop0 = op0; sop1 = op1;\
385
W3(inst->dest, res);\
389
uint64_t op0, op1, res;\
391
READ64(op0, BINOP(0));\
392
READ64(op1, BINOP(1));\
393
sop0 = op0; sop1 = op1;\
395
W4(inst->dest, res);\
399
#define DEFINE_BINOP(opc, OP) DEFINE_BINOP_BC_HELPER(opc, OP, WRITE8, WRITE8, WRITE16, WRITE32, WRITE64)
400
#define DEFINE_ICMPOP(opc, OP) DEFINE_BINOP_BC_HELPER(opc, OP, WRITE8, WRITE8, WRITE8, WRITE8, WRITE8)
402
#define CHECK_OP(cond, msg) if((cond)) { cli_dbgmsg(msg); stop = CL_EBYTECODE; break;}
404
#define DEFINE_SCASTOP(opc, OP) \
409
WRITE8(inst->dest, res);\
416
WRITE8(inst->dest, res);\
423
WRITE16(inst->dest, res);\
430
WRITE32(inst->dest, res);\
437
WRITE64(inst->dest, res);\
440
#define DEFINE_CASTOP(opc, OP) DEFINE_SCASTOP(opc, OP; (void)sres)
442
#define DEFINE_OP(opc) \
443
case opc*5: /* fall-through */\
444
case opc*5+1: /* fall-through */\
445
case opc*5+2: /* fall-through */\
446
case opc*5+3: /* fall-through */\
449
#define CHOOSE(OP0, OP1, OP2, OP3, OP4) \
450
switch (inst->u.cast.size) {\
456
default: CHECK_UNREACHABLE;\
459
#define DEFINE_OP_BC_RET_N(OP, T, R0, W0) \
462
R0(tmp, inst->u.unaryop);\
463
CHECK_GT(stack_depth, 0);\
465
stack_entry = pop_stack(&stack, stack_entry, &func, &i, &bb,\
467
values = stack_entry ? stack_entry->values : ctx->values;\
468
CHECK_GT(func->numBytes, i);\
474
stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes)>>32;\
475
inst = &bb->insts[bb_inst];\
485
struct ptr_info *stack_infos;
486
struct ptr_info *glob_infos;
487
unsigned nstacks, nglobs;
490
static inline int64_t ptr_compose(int32_t id, uint32_t offset)
493
return (i << 32) | offset;
496
static inline int32_t ptr_diff32(int64_t ptr1, int64_t ptr2)
498
int32_t ptrid1 = ptr1 >> 32;
499
int32_t ptrid2 = ptr2 >> 32;
500
if (ptrid1 != ptrid2) {
501
(void)bcfail("difference of pointers not pointing to same object!", ptrid1, ptrid2, __FILE__, __LINE__);
505
return (uint32_t)ptr1 - (uint32_t)ptr2;
508
static inline int64_t ptr_register_stack(struct ptr_infos *infos,
510
uint32_t off, uint32_t size)
512
unsigned n = infos->nstacks + 1;
513
struct ptr_info *sinfos = cli_realloc(infos->stack_infos,
517
infos->stack_infos = sinfos;
519
sinfos = &sinfos[n-1];
520
sinfos->base = (uint8_t*)values + off;
522
return ptr_compose(-n, 0);
525
static inline int64_t ptr_register_glob_fixedid(struct ptr_infos *infos,
526
void *values, uint32_t size, unsigned n)
528
struct ptr_info *sinfos;
529
if (n > infos->nglobs) {
530
sinfos = cli_realloc(infos->glob_infos, sizeof(*sinfos)*n);
533
memset(sinfos + infos->nglobs, 0, (n - infos->nglobs)*sizeof(*sinfos));
534
infos->glob_infos = sinfos;
537
sinfos = &infos->glob_infos[n-1];
540
sinfos->base = values;
542
cli_dbgmsg("bytecode: registered ctx variable at %p (+%u) id %u\n", values,
544
return ptr_compose(n, 0);
547
static inline int64_t ptr_register_glob(struct ptr_infos *infos,
548
void *values, uint32_t size)
552
return ptr_register_glob_fixedid(infos, values, size, infos->nglobs+1);
555
static inline int64_t ptr_index(int64_t ptr, uint32_t off)
557
int32_t ptrid = ptr >> 32;
558
uint32_t ptroff = (uint32_t)ptr;
559
return ptr_compose(ptrid, ptroff+off);
562
static inline void* ptr_torealptr(const struct ptr_infos *infos, int64_t ptr,
565
struct ptr_info *info;
566
int32_t ptrid = ptr >> 32;
567
uint32_t ptroff = (uint32_t)ptr;
568
TRACE_PTR(ptr, read_size);
569
if (UNLIKELY(!ptrid)) {
570
(void)bcfail("nullptr", ptrid, 0, __FILE__, __LINE__);
575
if (UNLIKELY(ptrid >= infos->nstacks)) {
576
(void)bcfail("ptr", ptrid, infos->nstacks, __FILE__, __LINE__);
579
info = &infos->stack_infos[ptrid];
582
if (UNLIKELY(ptrid >= infos->nglobs)) {
583
(void)bcfail("ptr", ptrid, infos->nglobs, __FILE__, __LINE__);
586
info = &infos->glob_infos[ptrid];
588
if (LIKELY(ptroff < info->size &&
589
read_size <= info->size &&
590
ptroff + read_size <= info->size)) {
591
return info->base+ptroff;
594
(void)bcfail("ptr1", ptroff, info->size, __FILE__, __LINE__);
595
(void)bcfail("ptr2", read_size, info->size, __FILE__, __LINE__);
596
(void)bcfail("ptr3", ptroff+read_size, info->size, __FILE__, __LINE__);
600
static always_inline int check_sdivops(int64_t op0, int64_t op1)
602
return op1 == 0 || (op0 == -1 && op1 == (-9223372036854775807LL-1LL));
605
static unsigned globaltypesize(uint16_t id)
607
const struct cli_bc_type *ty;
612
ty = &cli_apicall_types[id - 69];
615
return ty->numElements*globaltypesize(ty->containedTypes[0]);
617
case DPackedStructType:
620
for (i=0;i<ty->numElements;i++)
621
s += globaltypesize(ty->containedTypes[i]);
629
/* TODO: fix the APIs too */
631
cli_apicall_pointer api;
632
uint32_t override_size;
633
} apisize_override[] = {
634
{(void*)cli_bcapi_disasm_x86, sizeof(struct DISASM_RESULT)},
635
{(void*)cli_bcapi_get_pe_section, sizeof(struct cli_exe_section)},
638
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
640
unsigned i, j, stack_depth=0, bb_inst=0, stop=0, pc=0;
641
struct cli_bc_func *func2;
643
struct stack_entry *stack_entry = NULL;
644
struct cli_bc_bb *bb = NULL;
645
char *values = ctx->values;
647
struct ptr_infos ptrinfos;
648
struct timeval tv0, tv1, timeout;
651
memset(&ptrinfos, 0, sizeof(ptrinfos));
652
memset(&stack, 0, sizeof(stack));
653
for (i=0;i < cli_apicall_maxglobal - _FIRST_GLOBAL; i++) {
656
const struct cli_apiglobal *g = &cli_globals[i];
657
void **apiglobal = (void**)(((char*)ctx) + g->offset);
661
size = globaltypesize(g->type);
662
ptr_register_glob_fixedid(&ptrinfos, apiptr, size, g->globalid - _FIRST_GLOBAL+1);
664
ptr_register_glob_fixedid(&ptrinfos, bc->globalBytes, bc->numGlobalBytes,
665
cli_apicall_maxglobal - _FIRST_GLOBAL + 2);
667
gettimeofday(&tv0, NULL);
668
timeout.tv_usec = tv0.tv_usec + ctx->bytecode_timeout*1000;
669
timeout.tv_sec = tv0.tv_sec + timeout.tv_usec/1000000;
670
timeout.tv_usec %= 1000000;
675
gettimeofday(&tv1, NULL);
676
if (tv1.tv_sec > timeout.tv_sec ||
677
(tv1.tv_sec == timeout.tv_sec &&
678
tv1.tv_usec > timeout.tv_usec)) {
679
cli_warnmsg("Bytecode run timed out in interpreter after %u opcodes\n", pc);
684
switch (inst->interp_op) {
685
DEFINE_BINOP(OP_BC_ADD, res = op0 + op1);
686
DEFINE_BINOP(OP_BC_SUB, res = op0 - op1);
687
DEFINE_BINOP(OP_BC_MUL, res = op0 * op1);
689
DEFINE_BINOP(OP_BC_UDIV, CHECK_OP(op1 == 0, "bytecode attempted to execute udiv#0\n");
691
DEFINE_BINOP(OP_BC_SDIV, CHECK_OP(check_sdivops(sop0, sop1), "bytecode attempted to execute sdiv#0\n");
693
DEFINE_BINOP(OP_BC_UREM, CHECK_OP(op1 == 0, "bytecode attempted to execute urem#0\n");
695
DEFINE_BINOP(OP_BC_SREM, CHECK_OP(check_sdivops(sop0,sop1), "bytecode attempted to execute urem#0\n");
698
DEFINE_BINOP(OP_BC_SHL, CHECK_OP(op1 > inst->type, "bytecode attempted to execute shl greater than bitwidth\n");
700
DEFINE_BINOP(OP_BC_LSHR, CHECK_OP(op1 > inst->type, "bytecode attempted to execute lshr greater than bitwidth\n");
702
DEFINE_BINOP(OP_BC_ASHR, CHECK_OP(op1 > inst->type, "bytecode attempted to execute ashr greater than bitwidth\n");
703
res = CLI_SRS(sop0, op1));
705
DEFINE_BINOP(OP_BC_AND, res = op0 & op1);
706
DEFINE_BINOP(OP_BC_OR, res = op0 | op1);
707
DEFINE_BINOP(OP_BC_XOR, res = op0 ^ op1);
709
DEFINE_SCASTOP(OP_BC_SEXT,
710
CHOOSE(READ1(sres, inst->u.cast.source); res = sres ? ~0ull : 0,
711
READ8(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
712
READ16(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
713
READ32(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
714
READ64(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask)));
715
DEFINE_CASTOP(OP_BC_ZEXT,
716
CHOOSE(READ1(res, inst->u.cast.source),
717
READ8(res, inst->u.cast.source),
718
READ16(res, inst->u.cast.source),
719
READ32(res, inst->u.cast.source),
720
READ64(res, inst->u.cast.source)));
721
DEFINE_CASTOP(OP_BC_TRUNC,
722
CHOOSE(READ1(res, inst->u.cast.source),
723
READ8(res, inst->u.cast.source),
724
READ16(res, inst->u.cast.source),
725
READ32(res, inst->u.cast.source),
726
READ64(res, inst->u.cast.source)));
728
DEFINE_OP(OP_BC_BRANCH)
729
stop = jump(func, (values[inst->u.branch.condition]&1) ?
730
inst->u.branch.br_true : inst->u.branch.br_false,
731
&bb, &inst, &bb_inst);
735
stop = jump(func, inst->u.jump, &bb, &inst, &bb_inst);
738
DEFINE_OP_BC_RET_N(OP_BC_RET*5, uint8_t, READ1, WRITE8);
739
DEFINE_OP_BC_RET_N(OP_BC_RET*5+1, uint8_t, READ8, WRITE8);
740
DEFINE_OP_BC_RET_N(OP_BC_RET*5+2, uint16_t, READ16, WRITE16);
741
DEFINE_OP_BC_RET_N(OP_BC_RET*5+3, uint32_t, READ32, WRITE32);
742
DEFINE_OP_BC_RET_N(OP_BC_RET*5+4, uint64_t, READ64, WRITE64);
744
DEFINE_ICMPOP(OP_BC_ICMP_EQ, res = (op0 == op1));
745
DEFINE_ICMPOP(OP_BC_ICMP_NE, res = (op0 != op1));
746
DEFINE_ICMPOP(OP_BC_ICMP_UGT, res = (op0 > op1));
747
DEFINE_ICMPOP(OP_BC_ICMP_UGE, res = (op0 >= op1));
748
DEFINE_ICMPOP(OP_BC_ICMP_ULT, res = (op0 < op1));
749
DEFINE_ICMPOP(OP_BC_ICMP_ULE, res = (op0 <= op1));
750
DEFINE_ICMPOP(OP_BC_ICMP_SGT, res = (sop0 > sop1));
751
DEFINE_ICMPOP(OP_BC_ICMP_SGE, res = (sop0 >= sop1));
752
DEFINE_ICMPOP(OP_BC_ICMP_SLE, res = (sop0 <= sop1));
753
DEFINE_ICMPOP(OP_BC_ICMP_SLT, res = (sop0 < sop1));
758
READ1(t0, inst->u.three[0]);
759
READ1(t1, inst->u.three[1]);
760
READ1(t2, inst->u.three[2]);
761
WRITE8(inst->dest, t0 ? t1 : t2);
764
case OP_BC_SELECT*5+1:
767
READ1(t0, inst->u.three[0]);
768
READ8(t1, inst->u.three[1]);
769
READ8(t2, inst->u.three[2]);
770
WRITE8(inst->dest, t0 ? t1 : t2);
773
case OP_BC_SELECT*5+2:
777
READ1(t0, inst->u.three[0]);
778
READ16(t1, inst->u.three[1]);
779
READ16(t2, inst->u.three[2]);
780
WRITE16(inst->dest, t0 ? t1 : t2);
783
case OP_BC_SELECT*5+3:
787
READ1(t0, inst->u.three[0]);
788
READ32(t1, inst->u.three[1]);
789
READ32(t2, inst->u.three[2]);
790
WRITE32(inst->dest, t0 ? t1 : t2);
793
case OP_BC_SELECT*5+4:
797
READ1(t0, inst->u.three[0]);
798
READ64(t1, inst->u.three[1]);
799
READ64(t2, inst->u.three[2]);
800
WRITE64(inst->dest, t0 ? t1 : t2);
804
DEFINE_OP(OP_BC_CALL_API) {
805
const struct cli_apicall *api = &cli_apicalls[inst->u.ops.funcid];
808
CHECK_APIID(inst->u.ops.funcid);
809
TRACE_API(api->name, inst->dest, inst->type, stack_depth);
813
READ32(a, inst->u.ops.ops[0]);
814
READ32(b, inst->u.ops.ops[1]);
815
res32 = cli_apicalls0[api->idx](ctx, a, b);
816
WRITE32(inst->dest, res32);
822
unsigned arg2, arg1size;
823
READ32(arg2, inst->u.ops.ops[1]);
824
/* check that arg2 is size of arg1 */
826
for (i=0;i<sizeof(apisize_override)/sizeof(apisize_override[0]);i++) {
827
if (cli_apicalls1[api->idx] == apisize_override[i].api) {
828
arg1size = apisize_override[i].override_size;
832
READPOP(arg1, inst->u.ops.ops[0], arg1size);
833
res32 = cli_apicalls1[api->idx](ctx, arg1, arg2);
834
WRITE32(inst->dest, res32);
839
READ32(a, inst->u.ops.ops[0]);
840
res32 = cli_apicalls2[api->idx](ctx, a);
841
WRITE32(inst->dest, res32);
847
READ32(a, inst->u.ops.ops[0]);
848
resp = cli_apicalls3[api->idx](ctx, a);
849
res64 = ptr_register_glob(&ptrinfos, resp, a);
850
WRITE64(inst->dest, res64);
854
int32_t arg2, arg3, arg4, arg5;
856
READ32(arg2, inst->u.ops.ops[1]);
857
/* check that arg2 is size of arg1 */
858
READP(arg1, inst->u.ops.ops[0], arg2);
859
READ32(arg3, inst->u.ops.ops[2]);
860
READ32(arg4, inst->u.ops.ops[3]);
861
READ32(arg5, inst->u.ops.ops[4]);
862
res32 = cli_apicalls4[api->idx](ctx, arg1, arg2, arg3, arg4, arg5);
863
WRITE32(inst->dest, res32);
867
res32 = cli_apicalls5[api->idx](ctx);
868
WRITE32(inst->dest, res32);
874
READ32(arg1, inst->u.ops.ops[0]);
875
READ32(arg2, inst->u.ops.ops[1]);
876
resp = cli_apicalls6[api->idx](ctx, arg1, arg2);
877
res64 = ptr_register_glob(&ptrinfos, resp, arg2);
878
WRITE64(inst->dest, res64);
882
int32_t arg1,arg2,arg3;
883
READ32(arg1, inst->u.ops.ops[0]);
884
READ32(arg2, inst->u.ops.ops[1]);
885
READ32(arg3, inst->u.ops.ops[2]);
886
res32 = cli_apicalls7[api->idx](ctx, arg1, arg2, arg3);
887
WRITE32(inst->dest, res32);
894
READ32(arg2, inst->u.ops.ops[1]);
895
/* check that arg2 is size of arg1 */
896
READP(arg1, inst->u.ops.ops[0], arg2);
897
READ32(arg4, inst->u.ops.ops[3]);
898
READP(arg3, inst->u.ops.ops[2], arg4);
899
resp = cli_apicalls8[api->idx](ctx, arg1, arg2, arg3, arg4);
900
WRITE32(inst->dest, resp);
907
READ32(arg2, inst->u.ops.ops[1]);
908
/* check that arg2 is size of arg1 */
909
READP(arg1, inst->u.ops.ops[0], arg2);
910
READ32(arg3, inst->u.ops.ops[2]);
911
resp = cli_apicalls9[api->idx](ctx, arg1, arg2, arg3);
912
WRITE32(inst->dest, resp);
916
cli_warnmsg("bytecode: type %u apicalls not yet implemented!\n", api->kind);
922
DEFINE_OP(OP_BC_CALL_DIRECT)
923
CHECK_FUNCID(inst->u.ops.funcid);
924
func2 = &bc->funcs[inst->u.ops.funcid];
925
CHECK_EQ(func2->numArgs, inst->u.ops.numOps);
927
stack_entry = allocate_stack(&stack, stack_entry, func2, func, inst->dest,
933
values = stack_entry->values;
934
/* TODO: unregister on ret */
935
TRACE_EXEC(inst->u.ops.funcid, inst->dest, inst->type, stack_depth);
936
if (stack_depth > 10000) {
937
cli_warnmsg("bytecode: stack depth exceeded\n");
942
for (i=0;i<func2->numArgs;i++) {
943
switch (inst->u.ops.opsizes[i]) {
946
READOLD8(v, inst->u.ops.ops[i]);
947
CHECK_GT(func2->numBytes, j);
953
READOLD16(v, inst->u.ops.ops[i]);
955
CHECK_GT(func2->numBytes, j);
956
*(uint16_t*)&values[j] = v;
962
READOLD32(v, inst->u.ops.ops[i]);
964
CHECK_GT(func2->numBytes, j);
965
*(uint32_t*)&values[j] = v;
971
READOLD64(v, inst->u.ops.ops[i]);
973
CHECK_GT(func2->numBytes, j);
974
*(uint64_t*)&values[j] = v;
981
stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes)>>32;
982
CHECK_GT(func->numBB, 0);
983
stop = jump(func, 0, &bb, &inst, &bb_inst);
991
WRITE8(BINOP(1), op);
998
WRITE8(BINOP(1), op);
1001
case OP_BC_COPY*5+2:
1004
READ16(op, BINOP(0));
1005
WRITE16(BINOP(1), op);
1008
case OP_BC_COPY*5+3:
1011
READ32(op, BINOP(0));
1012
WRITE32(BINOP(1), op);
1015
case OP_BC_COPY*5+4:
1018
READ64(op, BINOP(0));
1019
WRITE64(BINOP(1), op);
1024
case OP_BC_LOAD*5+1:
1027
READPOP(ptr, inst->u.unaryop, 1);
1028
WRITE8(inst->dest, (*ptr));
1031
case OP_BC_LOAD*5+2:
1033
const union unaligned_16 *ptr;
1034
READPOP(ptr, inst->u.unaryop, 2);
1035
WRITE16(inst->dest, (ptr->una_u16));
1038
case OP_BC_LOAD*5+3:
1040
const union unaligned_32 *ptr;
1041
READPOP(ptr, inst->u.unaryop, 4);
1042
WRITE32(inst->dest, (ptr->una_u32));
1045
case OP_BC_LOAD*5+4:
1047
const union unaligned_64 *ptr;
1048
READPOP(ptr, inst->u.unaryop, 8);
1049
WRITE64(inst->dest, (ptr->una_u64));
1057
READP(ptr, BINOP(1), 1);
1062
case OP_BC_STORE*5+1:
1066
READP(ptr, BINOP(1), 1);
1071
case OP_BC_STORE*5+2:
1073
union unaligned_16 *ptr;
1075
READP(ptr, BINOP(1), 2);
1076
READ16(v, BINOP(0));
1080
case OP_BC_STORE*5+3:
1082
union unaligned_32 *ptr;
1084
READP(ptr, BINOP(1), 4);
1085
READ32(v, BINOP(0));
1089
case OP_BC_STORE*5+4:
1091
union unaligned_64 *ptr;
1093
READP(ptr, BINOP(1), 8);
1094
READ64(v, BINOP(0));
1098
DEFINE_OP(OP_BC_ISBIGENDIAN) {
1099
WRITE8(inst->dest, WORDS_BIGENDIAN);
1102
DEFINE_OP(OP_BC_GEPZ) {
1104
if (!(inst->interp_op%5)) {
1106
READ32(off, inst->u.three[2]);
1107
WRITE64(inst->dest, ptr_compose(stackid,
1108
inst->u.three[1]+off));
1111
READ32(off, inst->u.three[2]);
1112
READ64(ptr, inst->u.three[1]);
1113
WRITE64(inst->dest, ptr+off);
1117
DEFINE_OP(OP_BC_MEMCMP) {
1120
READ32(arg3, inst->u.three[2]);
1121
READPOP(arg1, inst->u.three[0], arg3);
1122
READPOP(arg2, inst->u.three[1], arg3);
1123
WRITE32(inst->dest, memcmp(arg1, arg2, arg3));
1126
DEFINE_OP(OP_BC_MEMCPY) {
1131
READ32(arg3, inst->u.three[2]);
1132
READPOP(arg1, inst->u.three[0], arg3);
1133
READPOP(arg2, inst->u.three[1], arg3);
1134
memcpy(arg1, arg2, (int32_t)arg3);
1135
/* READ64(res, inst->u.three[0]);*/
1136
WRITE64(inst->dest, res);
1139
DEFINE_OP(OP_BC_MEMMOVE) {
1144
READ64(arg3, inst->u.three[2]);
1145
READPOP(arg1, inst->u.three[0], arg3);
1146
READPOP(arg2, inst->u.three[1], arg3);
1147
memmove(arg1, arg2, (int32_t)arg3);
1148
/* READ64(res, inst->u.three[0]);*/
1149
WRITE64(inst->dest, res);
1152
DEFINE_OP(OP_BC_MEMSET) {
1158
READ64(arg3, inst->u.three[2]);
1159
READPOP(arg1, inst->u.three[0], arg3);
1160
READ32(arg2, inst->u.three[1]);
1161
memset(arg1, arg2, (int32_t)arg3);
1162
/* READ64(res, inst->u.three[0]);*/
1163
WRITE64(inst->dest, res);
1166
DEFINE_OP(OP_BC_BSWAP16) {
1168
READ16(arg1, inst->u.unaryop);
1169
WRITE16(inst->dest, cbswap16(arg1));
1172
DEFINE_OP(OP_BC_BSWAP32) {
1174
READ32(arg1, inst->u.unaryop);
1175
WRITE32(inst->dest, cbswap32(arg1));
1178
DEFINE_OP(OP_BC_BSWAP64) {
1180
READ64(arg1, inst->u.unaryop);
1181
WRITE64(inst->dest, cbswap64(arg1));
1184
DEFINE_OP(OP_BC_PTRDIFF32) {
1186
if (BINOP(0)&0x40000000)
1187
ptr1 = ptr_compose(stackid, BINOP(0)&0xbfffffff);
1189
READ64(ptr1, BINOP(0));
1190
if (BINOP(1)&0x40000000)
1191
ptr2 = ptr_compose(stackid, BINOP(1)&0xbfffffff);
1193
READ64(ptr2, BINOP(1));
1194
WRITE32(inst->dest, ptr_diff32(ptr1, ptr2));
1197
DEFINE_OP(OP_BC_PTRTOINT64) {
1199
if (inst->u.unaryop&0x40000000)
1200
ptr = ptr_compose(stackid, inst->u.unaryop&0xbfffffff);
1202
READ64(ptr, BINOP(0));
1203
WRITE64(inst->dest, ptr);
1206
DEFINE_OP(OP_BC_GEP1) {
1208
if (!(inst->interp_op%5)) {
1210
READ32(off, inst->u.three[2]);
1211
WRITE64(inst->dest, ptr_compose(stackid,
1212
inst->u.three[1]+off*inst->u.three[0]));
1215
READ32(off, inst->u.three[2]);
1216
READ64(ptr, inst->u.three[1]);
1217
WRITE64(inst->dest, ptr+off*inst->u.three[0]);
1221
/* TODO: implement OP_BC_GEP1, OP_BC_GEP2, OP_BC_GEPN */
1223
cli_errmsg("Opcode %u of type %u is not implemented yet!\n",
1224
inst->interp_op/5, inst->interp_op%5);
1231
CHECK_GT(bb->numInsts, bb_inst);
1233
} while (stop == CL_SUCCESS);
1234
if (cli_debug_flag) {
1235
gettimeofday(&tv1, NULL);
1236
tv1.tv_sec -= tv0.tv_sec;
1237
tv1.tv_usec -= tv0.tv_usec;
1238
cli_dbgmsg("intepreter bytecode run finished in %luus, after executing %u opcodes\n",
1239
tv1.tv_sec*1000000 + tv1.tv_usec, pc);
1241
if (stop == CL_EBYTECODE) {
1242
cli_event_error_str(ctx->bc_events, "interpreter finished with error\n");
1243
cli_dbgmsg("intepreter finished with error\n");
1246
cli_stack_destroy(&stack);
1247
free(ptrinfos.stack_infos);
1248
free(ptrinfos.glob_infos);
1249
return stop == CL_BREAK ? CL_SUCCESS : stop;