Coverage Report

Created: 2024-05-20 06:31

/src/clamav/libclamav/bytecode_vm.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  Execute ClamAV bytecode.
3
 *
4
 *  Copyright (C) 2013-2024 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
5
 *  Copyright (C) 2009-2013 Sourcefire, Inc.
6
 *
7
 *  Authors: Török Edvin
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License version 2 as
11
 *  published by the Free Software Foundation.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program; if not, write to the Free Software
20
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
 *  MA 02110-1301, USA.
22
 */
23
#if HAVE_CONFIG_H
24
#include "clamav-config.h"
25
#endif
26
27
#include "clamav.h"
28
#include "others.h"
29
#include "bytecode.h"
30
#include "bytecode_priv.h"
31
#include "type_desc.h"
32
#include "readdb.h"
33
#include <string.h>
34
#ifndef _WIN32
35
#include <sys/time.h>
36
#endif
37
#include "bytecode_api_impl.h"
38
#include "disasm-common.h"
39
40
/* Enable this to catch more bugs in the RC phase */
41
#define CL_BYTECODE_SAFE
42
43
#ifdef CL_BYTECODE_SAFE
44
/* These checks will also be done by the bytecode verifier, but for
45
 * debugging purposes we have explicit checks, these should never fail! */
46
#ifdef CL_DEBUG
47
static int never_inline bcfail(const char *msg, long a, long b,
48
                               const char *file, unsigned line)
49
{
50
    cli_warnmsg("bytecode: check failed %s (%lx and %lx) at %s:%u\n", msg, a, b, file, line);
51
    return CL_EARG;
52
}
53
#else
54
0
#define bcfail(msg, a, b, f, l) CL_EBYTECODE
55
#endif
56
57
#define CHECK_FUNCID(funcid)                                                                                          \
58
0
    do {                                                                                                              \
59
0
        if (funcid >= bc->num_func) return bcfail("funcid out of bounds!", funcid, bc->num_func, __FILE__, __LINE__); \
60
0
    } while (0)
61
#define CHECK_APIID(funcid)                                                                                                      \
62
0
    do {                                                                                                                         \
63
0
        if (funcid >= cli_apicall_maxapi) return bcfail("APIid out of bounds!", funcid, cli_apicall_maxapi, __FILE__, __LINE__); \
64
0
    } while (0)
65
#define CHECK_EQ(a, b)                                                                                        \
66
0
    do {                                                                                                      \
67
0
        if ((a) != (b)) return bcfail("Values " #a " and " #b " don't match!", (a), (b), __FILE__, __LINE__); \
68
0
    } while (0)
69
#define CHECK_GT(a, b)                                                                                \
70
0
    do {                                                                                              \
71
0
        if ((a) <= (b)) return bcfail("Condition failed " #a " > " #b, (a), (b), __FILE__, __LINE__); \
72
0
    } while (0)
73
74
#else
75
static inline int bcfail(const char *msg, long a, long b,
76
                         const char *file, unsigned line) {}
77
#define CHECK_FUNCID(x) ;
78
#define CHECK_APIID(x) ;
79
#define CHECK_EQ(a, b)
80
#define CHECK_GT(a, b)
81
#endif
82
#if 0 /* too verbose, use #ifdef CL_DEBUG if needed */
83
#define CHECK_UNREACHABLE                                \
84
    do {                                                 \
85
        cli_dbgmsg("bytecode: unreachable executed!\n"); \
86
        return CL_EBYTECODE;                             \
87
    } while (0)
88
#define TRACE_PTR(ptr, s) cli_dbgmsg("bytecode trace: ptr %llx, +%x\n", ptr, s);
89
#define TRACE_R(x) cli_dbgmsg("bytecode trace: %u, read %llx\n", pc, (long long)x);
90
#define TRACE_W(x, w, p) cli_dbgmsg("bytecode trace: %u, write%d @%u %llx\n", pc, p, w, (long long)(x));
91
#define TRACE_EXEC(id, dest, ty, stack) cli_dbgmsg("bytecode trace: executing %d, -> %u (%u); %u\n", id, dest, ty, stack)
92
#define TRACE_INST(inst)                                                   \
93
    do {                                                                   \
94
        unsigned bbnum = 0;                                                \
95
        printf("LibClamAV debug: bytecode trace: executing instruction "); \
96
        cli_byteinst_describe(inst, &bbnum);                               \
97
        printf("\n");                                                      \
98
    } while (0)
99
#define TRACE_API(s, dest, ty, stack) cli_dbgmsg("bytecode trace: executing %s, -> %u (%u); %u\n", s, dest, ty, stack)
100
#else
101
#define CHECK_UNREACHABLE return CL_EBYTECODE
102
#define TRACE_PTR(ptr, s)
103
#define TRACE_R(x)
104
#define TRACE_W(x, w, p)
105
#define TRACE_EXEC(id, dest, ty, stack)
106
#define TRACE_INST(inst)
107
#define TRACE_API(s, dest, ty, stack)
108
#endif
109
110
#define SIGNEXT(a, from) CLI_SRS(((int64_t)(a)) << (64 - (from)), (64 - (from)))
111
112
#ifdef CL_DEBUG
113
#undef always_inline
114
#define always_inline
115
#endif
116
117
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,
118
                              unsigned *bb_inst)
119
0
{
120
0
    CHECK_GT(func->numBB, bbid);
121
0
    *bb      = &func->BB[bbid];
122
0
    *inst    = (*bb)->insts;
123
0
    *bb_inst = 0;
124
0
    return 0;
125
0
}
126
127
0
#define STACK_CHUNKSIZE 65536
128
129
struct stack_chunk {
130
    struct stack_chunk *prev;
131
    unsigned used;
132
    union {
133
        void *align;
134
        char data[STACK_CHUNKSIZE];
135
    } u;
136
};
137
138
struct stack {
139
    struct stack_chunk *chunk;
140
    uint16_t last_size;
141
};
142
143
/* type with largest alignment that we use (in general it is a long double, but
144
 * that's too big alignment for us) */
145
typedef uint64_t align_t;
146
147
static always_inline void *cli_stack_alloc(struct stack *stack, unsigned bytes)
148
0
{
149
0
    struct stack_chunk *chunk = stack->chunk;
150
0
    uint16_t last_size_off;
151
152
    /* last_size is stored after data */
153
    /* align bytes to pointer size */
154
0
    bytes         = (bytes + sizeof(uint16_t) + sizeof(align_t)) & ~(sizeof(align_t) - 1);
155
0
    last_size_off = bytes - 2;
156
157
0
    if (chunk && (chunk->used + bytes <= STACK_CHUNKSIZE)) {
158
        /* there is still room in this chunk */
159
0
        void *ret;
160
161
0
        *(uint16_t *)&chunk->u.data[chunk->used + last_size_off] = stack->last_size;
162
0
        stack->last_size                                         = bytes / sizeof(align_t);
163
164
0
        ret = chunk->u.data + chunk->used;
165
0
        chunk->used += bytes;
166
0
        return ret;
167
0
    }
168
169
0
    if (bytes >= STACK_CHUNKSIZE) {
170
0
        cli_warnmsg("cli_stack_alloc: Attempt to allocate more than STACK_CHUNKSIZE bytes: %u!\n", bytes);
171
0
        return NULL;
172
0
    }
173
    /* not enough room here, allocate new chunk */
174
0
    chunk = malloc(sizeof(*stack->chunk));
175
0
    if (!chunk) {
176
0
        cli_warnmsg("cli_stack_alloc: Unable to allocate memory for stack-chunk: bytes: %zu!\n", sizeof(*stack->chunk));
177
0
        return NULL;
178
0
    }
179
180
0
    *(uint16_t *)&chunk->u.data[last_size_off] = stack->last_size;
181
0
    stack->last_size                           = bytes / sizeof(align_t);
182
183
0
    chunk->used  = bytes;
184
0
    chunk->prev  = stack->chunk;
185
0
    stack->chunk = chunk;
186
0
    return chunk->u.data;
187
0
}
188
189
static always_inline void cli_stack_free(struct stack *stack, void *data)
190
0
{
191
0
    uint16_t last_size;
192
0
    struct stack_chunk *chunk = stack->chunk;
193
0
    if (!chunk) {
194
0
        cli_warnmsg("cli_stack_free: stack empty!\n");
195
0
        return;
196
0
    }
197
0
    if ((chunk->u.data + chunk->used) != ((char *)data + stack->last_size * sizeof(align_t))) {
198
0
        cli_warnmsg("cli_stack_free: wrong free order: %p, expected %p\n",
199
0
                    data, chunk->u.data + chunk->used - stack->last_size * sizeof(align_t));
200
0
        return;
201
0
    }
202
0
    last_size = *(uint16_t *)&chunk->u.data[chunk->used - 2];
203
0
    if (chunk->used < stack->last_size * sizeof(align_t)) {
204
0
        cli_warnmsg("cli_stack_free: last_size is corrupt!\n");
205
0
        return;
206
0
    }
207
0
    chunk->used -= stack->last_size * sizeof(align_t);
208
0
    stack->last_size = last_size;
209
0
    if (!chunk->used) {
210
0
        stack->chunk = chunk->prev;
211
0
        free(chunk);
212
0
    }
213
0
}
214
215
static void cli_stack_destroy(struct stack *stack)
216
0
{
217
0
    struct stack_chunk *chunk = stack->chunk;
218
0
    while (chunk) {
219
0
        stack->chunk = chunk->prev;
220
0
        free(chunk);
221
0
        chunk = stack->chunk;
222
0
    }
223
0
}
224
225
struct stack_entry {
226
    struct stack_entry *prev;
227
    const struct cli_bc_func *func;
228
    operand_t ret;
229
    unsigned bb_inst;
230
    struct cli_bc_bb *bb;
231
    char *values;
232
};
233
234
static always_inline struct stack_entry *allocate_stack(struct stack *stack,
235
                                                        struct stack_entry *prev,
236
                                                        const struct cli_bc_func *func,
237
                                                        const struct cli_bc_func *func_old,
238
                                                        operand_t ret,
239
                                                        struct cli_bc_bb *bb,
240
                                                        unsigned bb_inst)
241
0
{
242
0
    char *values;
243
0
    struct stack_entry *entry = cli_stack_alloc(stack, sizeof(*entry) + sizeof(*values) * func->numBytes);
244
0
    if (!entry)
245
0
        return NULL;
246
0
    entry->prev    = prev;
247
0
    entry->func    = func_old;
248
0
    entry->ret     = ret;
249
0
    entry->bb      = bb;
250
0
    entry->bb_inst = bb_inst;
251
    /* we allocated room for values right after stack_entry! */
252
0
    entry->values = values = (char *)&entry[1];
253
0
    memcpy(&values[func->numBytes - func->numConstants * 8], func->constants,
254
0
           sizeof(*values) * func->numConstants * 8);
255
0
    return entry;
256
0
}
257
258
static always_inline struct stack_entry *pop_stack(struct stack *stack,
259
                                                   struct stack_entry *stack_entry,
260
                                                   const struct cli_bc_func **func,
261
                                                   operand_t *ret,
262
                                                   struct cli_bc_bb **bb,
263
                                                   unsigned *bb_inst)
264
0
{
265
0
    void *data;
266
0
    *func       = stack_entry->func;
267
0
    *ret        = stack_entry->ret;
268
0
    *bb         = stack_entry->bb;
269
0
    *bb_inst    = stack_entry->bb_inst;
270
0
    data        = stack_entry;
271
0
    stack_entry = stack_entry->prev;
272
0
    cli_stack_free(stack, data);
273
0
    return stack_entry;
274
0
}
275
276
/*
277
 *
278
 * p, p+1, p+2, p+3 <- gt
279
    CHECK_EQ((p)&1, 0);
280
    CHECK_EQ((p)&3, 0);
281
    CHECK_EQ((p)&7, 0);
282
*/
283
#define WRITE8(p, x)             \
284
0
    CHECK_GT(func->numBytes, p); \
285
0
    TRACE_W(x, p, 8);            \
286
0
    *(uint8_t *)&values[p] = x
287
#define WRITE16(p, x)                \
288
0
    CHECK_GT(func->numBytes, p + 1); \
289
0
    CHECK_EQ((p)&1, 0);              \
290
0
    TRACE_W(x, p, 16);               \
291
0
    *(uint16_t *)&values[p] = x
292
#define WRITE32(p, x)                \
293
0
    CHECK_GT(func->numBytes, p + 3); \
294
0
    CHECK_EQ((p)&3, 0);              \
295
0
    TRACE_W(x, p, 32);               \
296
0
    *(uint32_t *)&values[p] = x
297
#define WRITE64(p, x)                \
298
0
    CHECK_GT(func->numBytes, p + 7); \
299
0
    CHECK_EQ((p)&7, 0);              \
300
0
    TRACE_W(x, p, 64);               \
301
0
    *(uint64_t *)&values[p] = x
302
#define WRITEP(x, p)                         \
303
    CHECK_GT(func->numBytes, p + PSIZE - 1); \
304
    CHECK_EQ((p) & (PSIZE - 1), 0);          \
305
    TRACE_W(x, p, PSIZE * 8);                \
306
    *(void **)&values[p] = x
307
308
#define uint_type(n) uint##n##_t
309
#define READNfrom(maxBytes, from, x, n, p)   \
310
0
    CHECK_GT((maxBytes), (p) + (n / 8) - 1); \
311
0
    CHECK_EQ((p) & (n / 8 - 1), 0);          \
312
0
    x = *(uint_type(n) *)&(from)[(p)];       \
313
0
    TRACE_R(x)
314
315
#define READN(x, n, p)                                                    \
316
0
    do {                                                                  \
317
0
        if (p & 0x80000000) {                                             \
318
0
            uint32_t pg = p & 0x7fffffff;                                 \
319
0
            if (!pg) {                                                    \
320
0
                x = 0;                                                    \
321
0
            } else {                                                      \
322
0
                READNfrom(bc->numGlobalBytes, bc->globalBytes, x, n, pg); \
323
0
            }                                                             \
324
0
        } else {                                                          \
325
0
            READNfrom(func->numBytes, values, x, n, p);                   \
326
0
        }                                                                 \
327
0
    } while (0)
328
329
#define READ1(x, p) \
330
0
    READN(x, 8, p); \
331
0
    x = x & 1
332
0
#define READ8(x, p) READN(x, 8, p)
333
0
#define READ16(x, p) READN(x, 16, p)
334
0
#define READ32(x, p) READN(x, 32, p)
335
0
#define READ64(x, p) READN(x, 64, p)
336
337
#define PSIZE sizeof(int64_t)
338
#define READP(x, p, asize)                             \
339
0
    {                                                  \
340
0
        int64_t iptr__;                                \
341
0
        READN(iptr__, 64, p);                          \
342
0
        x = ptr_torealptr(&ptrinfos, iptr__, (asize)); \
343
0
        if (!x) {                                      \
344
0
            stop = CL_EBYTECODE;                       \
345
0
            break;                                     \
346
0
        }                                              \
347
0
        TRACE_R(x)                                     \
348
0
    }
349
#define READPOP(x, p, asize)                 \
350
0
    {                                        \
351
0
        if ((p)&0x40000000) {                \
352
0
            unsigned ptr__ = (p)&0xbfffffff; \
353
0
            CHECK_GT(func->numBytes, ptr__); \
354
0
            TRACE_PTR(ptr__, asize);         \
355
0
            x = (void *)&values[ptr__];      \
356
0
        } else {                             \
357
0
            READP(x, p, asize)               \
358
0
        }                                    \
359
0
    }
360
361
#define READOLD8(x, p)              \
362
0
    CHECK_GT(func->numBytes, p);    \
363
0
    x = *(uint8_t *)&old_values[p]; \
364
0
    TRACE_R(x)
365
#define READOLD16(x, p)              \
366
0
    CHECK_GT(func->numBytes, p + 1); \
367
0
    CHECK_EQ((p)&1, 0);              \
368
0
    x = *(uint16_t *)&old_values[p]; \
369
0
    TRACE_R(x)
370
#define READOLD32(x, p)              \
371
0
    CHECK_GT(func->numBytes, p + 3); \
372
0
    CHECK_EQ((p)&3, 0);              \
373
0
    x = *(uint32_t *)&old_values[p]; \
374
0
    TRACE_R(x)
375
#define READOLD64(x, p)              \
376
0
    CHECK_GT(func->numBytes, p + 7); \
377
0
    CHECK_EQ((p)&7, 0);              \
378
0
    x = *(uint64_t *)&old_values[p]; \
379
0
    TRACE_R(x)
380
381
0
#define BINOP(i) inst->u.binop[i]
382
383
#define DEFINE_BINOP_BC_HELPER(opc, OP, W0, W1, W2, W3, W4) \
384
0
    case opc * 5: {                                         \
385
0
        uint8_t op0, op1, res;                              \
386
0
        int8_t sop0, sop1;                                  \
387
0
        READ1(op0, BINOP(0));                               \
388
0
        READ1(op1, BINOP(1));                               \
389
0
        sop0 = op0;                                         \
390
0
        sop1 = op1;                                         \
391
0
        (void)sop0;                                         \
392
0
        (void)sop1;                                         \
393
0
        OP;                                                 \
394
0
        W0(inst->dest, res);                                \
395
0
        break;                                              \
396
0
    }                                                       \
397
0
    case opc * 5 + 1: {                                     \
398
0
        uint8_t op0, op1, res;                              \
399
0
        int8_t sop0, sop1;                                  \
400
0
        READ8(op0, BINOP(0));                               \
401
0
        READ8(op1, BINOP(1));                               \
402
0
        sop0 = op0;                                         \
403
0
        sop1 = op1;                                         \
404
0
        (void)sop0;                                         \
405
0
        (void)sop1;                                         \
406
0
        OP;                                                 \
407
0
        W1(inst->dest, res);                                \
408
0
        break;                                              \
409
0
    }                                                       \
410
0
    case opc * 5 + 2: {                                     \
411
0
        uint16_t op0, op1, res;                             \
412
0
        int16_t sop0, sop1;                                 \
413
0
        READ16(op0, BINOP(0));                              \
414
0
        READ16(op1, BINOP(1));                              \
415
0
        sop0 = op0;                                         \
416
0
        sop1 = op1;                                         \
417
0
        (void)sop0;                                         \
418
0
        (void)sop1;                                         \
419
0
        OP;                                                 \
420
0
        W2(inst->dest, res);                                \
421
0
        break;                                              \
422
0
    }                                                       \
423
0
    case opc * 5 + 3: {                                     \
424
0
        uint32_t op0, op1, res;                             \
425
0
        int32_t sop0, sop1;                                 \
426
0
        READ32(op0, BINOP(0));                              \
427
0
        READ32(op1, BINOP(1));                              \
428
0
        sop0 = op0;                                         \
429
0
        sop1 = op1;                                         \
430
0
        (void)sop0;                                         \
431
0
        (void)sop1;                                         \
432
0
        OP;                                                 \
433
0
        W3(inst->dest, res);                                \
434
0
        break;                                              \
435
0
    }                                                       \
436
0
    case opc * 5 + 4: {                                     \
437
0
        uint64_t op0, op1, res;                             \
438
0
        int64_t sop0, sop1;                                 \
439
0
        READ64(op0, BINOP(0));                              \
440
0
        READ64(op1, BINOP(1));                              \
441
0
        sop0 = op0;                                         \
442
0
        sop1 = op1;                                         \
443
0
        (void)sop0;                                         \
444
0
        (void)sop1;                                         \
445
0
        OP;                                                 \
446
0
        W4(inst->dest, res);                                \
447
0
        break;                                              \
448
0
    }
449
450
0
#define DEFINE_BINOP(opc, OP) DEFINE_BINOP_BC_HELPER(opc, OP, WRITE8, WRITE8, WRITE16, WRITE32, WRITE64)
451
0
#define DEFINE_ICMPOP(opc, OP) DEFINE_BINOP_BC_HELPER(opc, OP, WRITE8, WRITE8, WRITE8, WRITE8, WRITE8)
452
453
#define CHECK_OP(cond, msg)  \
454
    if ((cond)) {            \
455
        cli_dbgmsg(msg);     \
456
        stop = CL_EBYTECODE; \
457
        break;               \
458
    }
459
460
#define DEFINE_SCASTOP(opc, OP)   \
461
0
    case opc * 5: {               \
462
0
        uint8_t res;              \
463
0
        int8_t sres;              \
464
0
        OP;                       \
465
0
        WRITE8(inst->dest, res);  \
466
0
        break;                    \
467
0
    }                             \
468
0
    case opc * 5 + 1: {           \
469
0
        uint8_t res;              \
470
0
        int8_t sres;              \
471
0
        OP;                       \
472
0
        WRITE8(inst->dest, res);  \
473
0
        break;                    \
474
0
    }                             \
475
0
    case opc * 5 + 2: {           \
476
0
        uint16_t res;             \
477
0
        int16_t sres;             \
478
0
        OP;                       \
479
0
        WRITE16(inst->dest, res); \
480
0
        break;                    \
481
0
    }                             \
482
0
    case opc * 5 + 3: {           \
483
0
        uint32_t res;             \
484
0
        int32_t sres;             \
485
0
        OP;                       \
486
0
        WRITE32(inst->dest, res); \
487
0
        break;                    \
488
0
    }                             \
489
0
    case opc * 5 + 4: {           \
490
0
        uint64_t res;             \
491
0
        int64_t sres;             \
492
0
        OP;                       \
493
0
        WRITE64(inst->dest, res); \
494
0
        break;                    \
495
0
    }
496
0
#define DEFINE_CASTOP(opc, OP) DEFINE_SCASTOP(opc, OP; (void)sres)
497
498
#define DEFINE_OP(opc)                   \
499
0
    case opc * 5:     /* fall-through */ \
500
0
    case opc * 5 + 1: /* fall-through */ \
501
0
    case opc * 5 + 2: /* fall-through */ \
502
0
    case opc * 5 + 3: /* fall-through */ \
503
0
    case opc * 5 + 4:
504
505
#define CHOOSE(OP0, OP1, OP2, OP3, OP4) \
506
    switch (inst->u.cast.size) {        \
507
        case 0:                         \
508
            OP0;                        \
509
            break;                      \
510
        case 1:                         \
511
            OP1;                        \
512
            break;                      \
513
        case 2:                         \
514
            OP2;                        \
515
            break;                      \
516
        case 3:                         \
517
            OP3;                        \
518
            break;                      \
519
        case 4:                         \
520
            OP4;                        \
521
            break;                      \
522
        default:                        \
523
            CHECK_UNREACHABLE;          \
524
    }
525
526
#define DEFINE_OP_BC_RET_N(OP, T, R0, W0)                                         \
527
0
    case OP: {                                                                    \
528
0
        operand_t ret;                                                            \
529
0
        T tmp;                                                                    \
530
0
        R0(tmp, inst->u.unaryop);                                                 \
531
0
        CHECK_GT(stack_depth, 0);                                                 \
532
0
        stack_depth--;                                                            \
533
0
        stack_entry = pop_stack(&stack, stack_entry, &func, &ret, &bb,            \
534
0
                                &bb_inst);                                        \
535
0
        values      = stack_entry ? stack_entry->values : ctx->values;            \
536
0
        CHECK_GT(func->numBytes, ret);                                            \
537
0
        W0(ret, tmp);                                                             \
538
0
        if (!bb) {                                                                \
539
0
            stop = CL_BREAK;                                                      \
540
0
            continue;                                                             \
541
0
        }                                                                         \
542
0
        stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes) >> 32; \
543
0
        inst    = &bb->insts[bb_inst];                                            \
544
0
        break;                                                                    \
545
0
    }
546
547
#define DEFINE_OP_BC_RET_VOID(OP, T)                                              \
548
0
    case OP: {                                                                    \
549
0
        operand_t ret;                                                            \
550
0
        CHECK_GT(stack_depth, 0);                                                 \
551
0
        stack_depth--;                                                            \
552
0
        stack_entry = pop_stack(&stack, stack_entry, &func, &ret, &bb,            \
553
0
                                &bb_inst);                                        \
554
0
        values      = stack_entry ? stack_entry->values : ctx->values;            \
555
0
        CHECK_GT(func->numBytes, ret);                                            \
556
0
        if (!bb) {                                                                \
557
0
            stop = CL_BREAK;                                                      \
558
0
            continue;                                                             \
559
0
        }                                                                         \
560
0
        stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes) >> 32; \
561
0
        inst    = &bb->insts[bb_inst];                                            \
562
0
        break;                                                                    \
563
0
    }
564
565
struct ptr_info {
566
    uint8_t *base;
567
    uint32_t size;
568
};
569
570
struct ptr_infos {
571
    struct ptr_info *stack_infos;
572
    struct ptr_info *glob_infos;
573
    unsigned nstacks, nglobs;
574
};
575
576
static inline int64_t ptr_compose(int32_t id, uint32_t offset)
577
0
{
578
0
    uint64_t i = id;
579
0
    return (i << 32) | offset;
580
0
}
581
582
static inline int32_t ptr_diff32(int64_t ptr1, int64_t ptr2)
583
0
{
584
0
    int32_t ptrid1 = ptr1 >> 32;
585
0
    int32_t ptrid2 = ptr2 >> 32;
586
0
    if (ptrid1 != ptrid2) {
587
0
        (void)bcfail("difference of pointers not pointing to same object!", ptrid1, ptrid2, __FILE__, __LINE__);
588
        /* invalid diff */
589
0
        return 0x40000000;
590
0
    }
591
0
    return (uint32_t)ptr1 - (uint32_t)ptr2;
592
0
}
593
594
static inline int64_t ptr_register_stack(struct ptr_infos *infos,
595
                                         char *values,
596
                                         uint32_t off, uint32_t size)
597
0
{
598
0
    unsigned n              = infos->nstacks + 1;
599
0
    struct ptr_info *sinfos = cli_safer_realloc(infos->stack_infos,
600
0
                                                sizeof(*sinfos) * n);
601
0
    if (!sinfos)
602
0
        return 0;
603
0
    infos->stack_infos = sinfos;
604
0
    infos->nstacks     = n;
605
0
    sinfos             = &sinfos[n - 1];
606
0
    sinfos->base       = (uint8_t *)values + off;
607
0
    sinfos->size       = size;
608
0
    return ptr_compose(-n, 0);
609
0
}
610
611
static inline int64_t ptr_register_glob_fixedid(struct ptr_infos *infos,
612
                                                void *values, uint32_t size, unsigned n)
613
0
{
614
0
    struct ptr_info *sinfos;
615
0
    if (n > infos->nglobs) {
616
0
        sinfos = cli_safer_realloc(infos->glob_infos, sizeof(*sinfos) * n);
617
0
        if (!sinfos)
618
0
            return 0;
619
0
        memset(sinfos + infos->nglobs, 0, (n - infos->nglobs) * sizeof(*sinfos));
620
0
        infos->glob_infos = sinfos;
621
0
        infos->nglobs     = n;
622
0
    }
623
0
    sinfos = &infos->glob_infos[n - 1];
624
0
    if (!values)
625
0
        size = 0;
626
0
    sinfos->base = values;
627
0
    sinfos->size = size;
628
0
    cli_dbgmsg("bytecode: registered ctx variable at %p (+%u) id %u\n", values,
629
0
               size, n);
630
0
    return ptr_compose(n, 0);
631
0
}
632
633
static inline int64_t ptr_register_glob(struct ptr_infos *infos,
634
                                        void *values, uint32_t size)
635
0
{
636
0
    if (!values)
637
0
        return 0;
638
0
    return ptr_register_glob_fixedid(infos, values, size, infos->nglobs + 1);
639
0
}
640
641
static inline void *ptr_torealptr(const struct ptr_infos *infos, int64_t ptr,
642
                                  uint32_t read_size)
643
0
{
644
0
    struct ptr_info *info;
645
0
    int32_t ptrid   = ptr >> 32;
646
0
    uint32_t ptroff = (uint32_t)ptr;
647
0
    TRACE_PTR(ptr, read_size);
648
0
    if (UNLIKELY(!ptrid)) {
649
0
        (void)bcfail("nullptr", ptrid, 0, __FILE__, __LINE__);
650
0
        return NULL;
651
0
    }
652
0
    if (ptrid < 0) {
653
0
        ptrid = -ptrid - 1;
654
0
        if (UNLIKELY((const unsigned int)ptrid >= infos->nstacks)) {
655
0
            (void)bcfail("ptr", ptrid, infos->nstacks, __FILE__, __LINE__);
656
0
            return NULL;
657
0
        }
658
0
        info = &infos->stack_infos[ptrid];
659
0
    } else {
660
0
        ptrid--;
661
0
        if (UNLIKELY((const unsigned int)ptrid >= infos->nglobs)) {
662
0
            (void)bcfail("ptr", ptrid, infos->nglobs, __FILE__, __LINE__);
663
0
            return NULL;
664
0
        }
665
0
        info = &infos->glob_infos[ptrid];
666
0
    }
667
0
    if (LIKELY(ptroff < info->size &&
668
0
               read_size <= info->size &&
669
0
               ptroff + read_size <= info->size)) {
670
0
        return info->base + ptroff;
671
0
    }
672
673
0
    (void)bcfail("ptr1", ptroff, info->size, __FILE__, __LINE__);
674
0
    (void)bcfail("ptr2", read_size, info->size, __FILE__, __LINE__);
675
0
    (void)bcfail("ptr3", ptroff + read_size, info->size, __FILE__, __LINE__);
676
0
    return NULL;
677
0
}
678
679
static always_inline int check_sdivops(int64_t op0, int64_t op1)
680
0
{
681
0
    return op1 == 0 || (op1 == -1 && op0 == (-9223372036854775807LL - 1LL));
682
0
}
683
684
static unsigned globaltypesize(uint16_t id)
685
0
{
686
0
    const struct cli_bc_type *ty;
687
0
    if (id <= 64)
688
0
        return (id + 7) / 8;
689
0
    if (id < 69)
690
0
        return 8; /* ptr */
691
0
    ty = &cli_apicall_types[id - 69];
692
0
    switch (ty->kind) {
693
0
        case DArrayType:
694
0
            return ty->numElements * globaltypesize(ty->containedTypes[0]);
695
0
        case DStructType:
696
0
        case DPackedStructType: {
697
0
            unsigned i, s = 0;
698
0
            for (i = 0; i < ty->numElements; i++)
699
0
                s += globaltypesize(ty->containedTypes[i]);
700
0
            return s;
701
0
        }
702
0
        default:
703
0
            return 0;
704
0
    }
705
0
}
706
707
/* TODO: fix the APIs too */
708
static struct {
709
    cli_apicall_pointer api;
710
    uint32_t override_size;
711
} apisize_override[] = {
712
    {(void *)cli_bcapi_disasm_x86, sizeof(struct DISASM_RESULT)},
713
    {(void *)cli_bcapi_get_pe_section, sizeof(struct cli_exe_section)},
714
};
715
716
cl_error_t 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)
717
0
{
718
0
    size_t i;
719
0
    uint32_t j;
720
0
    unsigned stack_depth = 0, bb_inst = 0, stop = 0, pc = 0;
721
0
    struct cli_bc_func *func2;
722
0
    struct stack stack;
723
0
    struct stack_entry *stack_entry = NULL;
724
0
    struct cli_bc_bb *bb            = NULL;
725
0
    char *values                    = ctx->values;
726
0
    char *old_values;
727
0
    struct ptr_infos ptrinfos;
728
0
    struct timeval tv0, tv1, timeout;
729
0
    int stackid = 0;
730
731
0
    memset(&ptrinfos, 0, sizeof(ptrinfos));
732
0
    memset(&stack, 0, sizeof(stack));
733
0
    for (i = 0; i < (size_t)cli_apicall_maxglobal - _FIRST_GLOBAL; i++) {
734
0
        void *apiptr;
735
0
        uint32_t size;
736
0
        const struct cli_apiglobal *g = &cli_globals[i];
737
0
        void **apiglobal              = (void **)(((char *)ctx) + g->offset);
738
0
        if (!apiglobal)
739
0
            continue;
740
0
        apiptr = *apiglobal;
741
0
        size   = globaltypesize(g->type);
742
0
        ptr_register_glob_fixedid(&ptrinfos, apiptr, size, g->globalid - _FIRST_GLOBAL + 1);
743
0
    }
744
0
    ptr_register_glob_fixedid(&ptrinfos, bc->globalBytes, bc->numGlobalBytes,
745
0
                              cli_apicall_maxglobal - _FIRST_GLOBAL + 2);
746
747
0
    gettimeofday(&tv0, NULL);
748
0
    timeout.tv_usec = tv0.tv_usec + ctx->bytecode_timeout * 1000;
749
0
    timeout.tv_sec  = tv0.tv_sec + timeout.tv_usec / 1000000;
750
0
    timeout.tv_usec %= 1000000;
751
752
0
    do {
753
0
        pc++;
754
0
        if (!(pc % 5000)) {
755
0
            gettimeofday(&tv1, NULL);
756
0
            if (tv1.tv_sec > timeout.tv_sec ||
757
0
                (tv1.tv_sec == timeout.tv_sec &&
758
0
                 tv1.tv_usec > timeout.tv_usec)) {
759
0
                cli_warnmsg("Bytecode run timed out in interpreter after %u opcodes\n", pc);
760
0
                stop = CL_ETIMEOUT;
761
0
                break;
762
0
            }
763
0
        }
764
765
0
        TRACE_INST(inst);
766
767
0
        switch (inst->interp_op) {
768
0
            DEFINE_BINOP(OP_BC_ADD, res = op0 + op1);
769
0
            DEFINE_BINOP(OP_BC_SUB, res = op0 - op1);
770
0
            DEFINE_BINOP(OP_BC_MUL, res = op0 * op1);
771
772
0
            DEFINE_BINOP(OP_BC_UDIV, CHECK_OP(op1 == 0, "bytecode attempted to execute udiv#0\n");
773
0
                         res = op0 / op1);
774
0
            DEFINE_BINOP(OP_BC_SDIV, CHECK_OP(check_sdivops(sop0, sop1), "bytecode attempted to execute sdiv#0\n");
775
0
                         res = sop0 / sop1);
776
0
            DEFINE_BINOP(OP_BC_UREM, CHECK_OP(op1 == 0, "bytecode attempted to execute urem#0\n");
777
0
                         res = op0 % op1);
778
0
            DEFINE_BINOP(OP_BC_SREM, CHECK_OP(check_sdivops(sop0, sop1), "bytecode attempted to execute urem#0\n");
779
0
                         res = sop0 % sop1);
780
781
0
            DEFINE_BINOP(OP_BC_SHL, CHECK_OP(op1 > inst->type, "bytecode attempted to execute shl greater than bitwidth\n");
782
0
                         res = op0 << op1);
783
0
            DEFINE_BINOP(OP_BC_LSHR, CHECK_OP(op1 > inst->type, "bytecode attempted to execute lshr greater than bitwidth\n");
784
0
                         res = op0 >> op1);
785
0
            DEFINE_BINOP(OP_BC_ASHR, CHECK_OP(op1 > inst->type, "bytecode attempted to execute ashr greater than bitwidth\n");
786
0
                         res = CLI_SRS(sop0, op1));
787
788
0
            DEFINE_BINOP(OP_BC_AND, res = op0 & op1);
789
0
            DEFINE_BINOP(OP_BC_OR, res = op0 | op1);
790
0
            DEFINE_BINOP(OP_BC_XOR, res = op0 ^ op1);
791
792
            // clang-format off
793
0
            DEFINE_SCASTOP(OP_BC_SEXT,
794
0
                          CHOOSE(READ1(sres, inst->u.cast.source); res = sres ? ~0 : 0,
795
0
                                 READ8(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
796
0
                                 READ16(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
797
0
                                 READ32(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask),
798
0
                                 READ64(sres, inst->u.cast.source); res=sres=SIGNEXT(sres, inst->u.cast.mask)));
799
            // clang-format on
800
0
            DEFINE_CASTOP(OP_BC_ZEXT,
801
0
                          CHOOSE(READ1(res, inst->u.cast.source),
802
0
                                 READ8(res, inst->u.cast.source),
803
0
                                 READ16(res, inst->u.cast.source),
804
0
                                 READ32(res, inst->u.cast.source),
805
0
                                 READ64(res, inst->u.cast.source)));
806
0
            DEFINE_CASTOP(OP_BC_TRUNC,
807
0
                          CHOOSE(READ1(res, inst->u.cast.source),
808
0
                                 READ8(res, inst->u.cast.source),
809
0
                                 READ16(res, inst->u.cast.source),
810
0
                                 READ32(res, inst->u.cast.source),
811
0
                                 READ64(res, inst->u.cast.source)));
812
813
0
            DEFINE_OP(OP_BC_BRANCH)
814
0
            stop = jump(func, (values[inst->u.branch.condition] & 1) ? inst->u.branch.br_true : inst->u.branch.br_false,
815
0
                        &bb, &inst, &bb_inst);
816
0
            continue;
817
818
0
            DEFINE_OP(OP_BC_JMP)
819
0
            stop = jump(func, inst->u.jump, &bb, &inst, &bb_inst);
820
0
            continue;
821
822
0
            DEFINE_OP_BC_RET_N(OP_BC_RET * 5, uint8_t, READ1, WRITE8);
823
0
            DEFINE_OP_BC_RET_N(OP_BC_RET * 5 + 1, uint8_t, READ8, WRITE8);
824
0
            DEFINE_OP_BC_RET_N(OP_BC_RET * 5 + 2, uint16_t, READ16, WRITE16);
825
0
            DEFINE_OP_BC_RET_N(OP_BC_RET * 5 + 3, uint32_t, READ32, WRITE32);
826
0
            DEFINE_OP_BC_RET_N(OP_BC_RET * 5 + 4, uint64_t, READ64, WRITE64);
827
828
0
            DEFINE_OP_BC_RET_VOID(OP_BC_RET_VOID * 5, uint8_t);
829
0
            DEFINE_OP_BC_RET_VOID(OP_BC_RET_VOID * 5 + 1, uint8_t);
830
0
            DEFINE_OP_BC_RET_VOID(OP_BC_RET_VOID * 5 + 2, uint8_t);
831
0
            DEFINE_OP_BC_RET_VOID(OP_BC_RET_VOID * 5 + 3, uint8_t);
832
0
            DEFINE_OP_BC_RET_VOID(OP_BC_RET_VOID * 5 + 4, uint8_t);
833
834
0
            DEFINE_ICMPOP(OP_BC_ICMP_EQ, res = (op0 == op1));
835
0
            DEFINE_ICMPOP(OP_BC_ICMP_NE, res = (op0 != op1));
836
0
            DEFINE_ICMPOP(OP_BC_ICMP_UGT, res = (op0 > op1));
837
0
            DEFINE_ICMPOP(OP_BC_ICMP_UGE, res = (op0 >= op1));
838
0
            DEFINE_ICMPOP(OP_BC_ICMP_ULT, res = (op0 < op1));
839
0
            DEFINE_ICMPOP(OP_BC_ICMP_ULE, res = (op0 <= op1));
840
0
            DEFINE_ICMPOP(OP_BC_ICMP_SGT, res = (sop0 > sop1));
841
0
            DEFINE_ICMPOP(OP_BC_ICMP_SGE, res = (sop0 >= sop1));
842
0
            DEFINE_ICMPOP(OP_BC_ICMP_SLE, res = (sop0 <= sop1));
843
0
            DEFINE_ICMPOP(OP_BC_ICMP_SLT, res = (sop0 < sop1));
844
845
0
            case OP_BC_SELECT * 5: {
846
0
                uint8_t t0, t1, t2;
847
0
                READ1(t0, inst->u.three[0]);
848
0
                READ1(t1, inst->u.three[1]);
849
0
                READ1(t2, inst->u.three[2]);
850
0
                WRITE8(inst->dest, t0 ? t1 : t2);
851
0
                break;
852
0
            }
853
0
            case OP_BC_SELECT * 5 + 1: {
854
0
                uint8_t t0, t1, t2;
855
0
                READ1(t0, inst->u.three[0]);
856
0
                READ8(t1, inst->u.three[1]);
857
0
                READ8(t2, inst->u.three[2]);
858
0
                WRITE8(inst->dest, t0 ? t1 : t2);
859
0
                break;
860
0
            }
861
0
            case OP_BC_SELECT * 5 + 2: {
862
0
                uint8_t t0;
863
0
                uint16_t t1, t2;
864
0
                READ1(t0, inst->u.three[0]);
865
0
                READ16(t1, inst->u.three[1]);
866
0
                READ16(t2, inst->u.three[2]);
867
0
                WRITE16(inst->dest, t0 ? t1 : t2);
868
0
                break;
869
0
            }
870
0
            case OP_BC_SELECT * 5 + 3: {
871
0
                uint8_t t0;
872
0
                uint32_t t1, t2;
873
0
                READ1(t0, inst->u.three[0]);
874
0
                READ32(t1, inst->u.three[1]);
875
0
                READ32(t2, inst->u.three[2]);
876
0
                WRITE32(inst->dest, t0 ? t1 : t2);
877
0
                break;
878
0
            }
879
0
            case OP_BC_SELECT * 5 + 4: {
880
0
                uint8_t t0;
881
0
                uint64_t t1, t2;
882
0
                READ1(t0, inst->u.three[0]);
883
0
                READ64(t1, inst->u.three[1]);
884
0
                READ64(t2, inst->u.three[2]);
885
0
                WRITE64(inst->dest, t0 ? t1 : t2);
886
0
                break;
887
0
            }
888
889
0
                DEFINE_OP(OP_BC_CALL_API)
890
0
                {
891
0
                    const struct cli_apicall *api = &cli_apicalls[inst->u.ops.funcid];
892
0
                    int32_t res32;
893
0
                    int64_t res64;
894
0
                    CHECK_APIID(inst->u.ops.funcid);
895
0
                    TRACE_API(api->name, inst->dest, inst->type, stack_depth);
896
0
                    switch (api->kind) {
897
0
                        case 0: {
898
0
                            int32_t a, b;
899
0
                            READ32(a, inst->u.ops.ops[0]);
900
0
                            READ32(b, inst->u.ops.ops[1]);
901
0
                            res32 = cli_apicalls0[api->idx](ctx, a, b);
902
0
                            WRITE32(inst->dest, res32);
903
0
                            break;
904
0
                        }
905
0
                        case 1: {
906
0
                            void *arg1;
907
0
                            unsigned arg2, arg1size;
908
0
                            READ32(arg2, inst->u.ops.ops[1]);
909
                            /* check that arg2 is size of arg1 */
910
0
                            arg1size = arg2;
911
0
                            for (i = 0; i < sizeof(apisize_override) / sizeof(apisize_override[0]); i++) {
912
0
                                if (cli_apicalls1[api->idx] == apisize_override[i].api) {
913
0
                                    arg1size = apisize_override[i].override_size;
914
0
                                    break;
915
0
                                }
916
0
                            }
917
0
                            READPOP(arg1, inst->u.ops.ops[0], arg1size);
918
0
                            res32 = cli_apicalls1[api->idx](ctx, arg1, arg2);
919
0
                            WRITE32(inst->dest, res32);
920
0
                            break;
921
0
                        }
922
0
                        case 2: {
923
0
                            int32_t a;
924
0
                            READ32(a, inst->u.ops.ops[0]);
925
0
                            res32 = cli_apicalls2[api->idx](ctx, a);
926
0
                            WRITE32(inst->dest, res32);
927
0
                            break;
928
0
                        }
929
0
                        case 3: {
930
0
                            int32_t a;
931
0
                            void *resp;
932
0
                            READ32(a, inst->u.ops.ops[0]);
933
0
                            resp  = cli_apicalls3[api->idx](ctx, a);
934
0
                            res64 = ptr_register_glob(&ptrinfos, resp, a);
935
0
                            WRITE64(inst->dest, res64);
936
0
                            break;
937
0
                        }
938
0
                        case 4: {
939
0
                            int32_t arg2, arg3, arg4, arg5;
940
0
                            void *arg1;
941
0
                            READ32(arg2, inst->u.ops.ops[1]);
942
                            /* check that arg2 is size of arg1 */
943
0
                            READP(arg1, inst->u.ops.ops[0], arg2);
944
0
                            READ32(arg3, inst->u.ops.ops[2]);
945
0
                            READ32(arg4, inst->u.ops.ops[3]);
946
0
                            READ32(arg5, inst->u.ops.ops[4]);
947
0
                            res32 = cli_apicalls4[api->idx](ctx, arg1, arg2, arg3, arg4, arg5);
948
0
                            WRITE32(inst->dest, res32);
949
0
                            break;
950
0
                        }
951
0
                        case 5: {
952
0
                            res32 = cli_apicalls5[api->idx](ctx);
953
0
                            WRITE32(inst->dest, res32);
954
0
                            break;
955
0
                        }
956
0
                        case 6: {
957
0
                            int32_t arg1, arg2;
958
0
                            void *resp;
959
0
                            READ32(arg1, inst->u.ops.ops[0]);
960
0
                            READ32(arg2, inst->u.ops.ops[1]);
961
0
                            resp  = cli_apicalls6[api->idx](ctx, arg1, arg2);
962
0
                            res64 = ptr_register_glob(&ptrinfos, resp, arg2);
963
0
                            WRITE64(inst->dest, res64);
964
0
                            break;
965
0
                        }
966
0
                        case 7: {
967
0
                            int32_t arg1, arg2, arg3;
968
0
                            READ32(arg1, inst->u.ops.ops[0]);
969
0
                            READ32(arg2, inst->u.ops.ops[1]);
970
0
                            READ32(arg3, inst->u.ops.ops[2]);
971
0
                            res32 = cli_apicalls7[api->idx](ctx, arg1, arg2, arg3);
972
0
                            WRITE32(inst->dest, res32);
973
0
                            break;
974
0
                        }
975
0
                        case 8: {
976
0
                            int32_t arg2, arg4;
977
0
                            void *arg1, *arg3;
978
0
                            int32_t resp;
979
0
                            READ32(arg2, inst->u.ops.ops[1]);
980
                            /* check that arg2 is size of arg1 */
981
0
                            READP(arg1, inst->u.ops.ops[0], arg2);
982
0
                            READ32(arg4, inst->u.ops.ops[3]);
983
0
                            READP(arg3, inst->u.ops.ops[2], arg4);
984
0
                            resp = cli_apicalls8[api->idx](ctx, arg1, arg2, arg3, arg4);
985
0
                            WRITE32(inst->dest, resp);
986
0
                            break;
987
0
                        }
988
0
                        case 9: {
989
0
                            int32_t arg2, arg3;
990
0
                            void *arg1;
991
0
                            int32_t resp;
992
0
                            READ32(arg2, inst->u.ops.ops[1]);
993
                            /* check that arg2 is size of arg1 */
994
0
                            READP(arg1, inst->u.ops.ops[0], arg2);
995
0
                            READ32(arg3, inst->u.ops.ops[2]);
996
0
                            resp = cli_apicalls9[api->idx](ctx, arg1, arg2, arg3);
997
0
                            WRITE32(inst->dest, resp);
998
0
                            break;
999
0
                        };
1000
0
                        default:
1001
0
                            cli_warnmsg("bytecode: type %u apicalls not yet implemented!\n", api->kind);
1002
0
                            stop = CL_EBYTECODE;
1003
0
                    }
1004
0
                    break;
1005
0
                }
1006
1007
0
                DEFINE_OP(OP_BC_CALL_DIRECT)
1008
0
                CHECK_FUNCID(inst->u.ops.funcid);
1009
0
                func2 = &bc->funcs[inst->u.ops.funcid];
1010
0
                CHECK_EQ(func2->numArgs, inst->u.ops.numOps);
1011
0
                old_values  = values;
1012
0
                stack_entry = allocate_stack(&stack, stack_entry, func2, func, inst->dest,
1013
0
                                             bb, bb_inst);
1014
0
                if (!stack_entry) {
1015
0
                    stop = CL_EMEM;
1016
0
                    break;
1017
0
                }
1018
0
                values = stack_entry->values;
1019
                /* TODO: unregister on ret */
1020
0
                TRACE_EXEC(inst->u.ops.funcid, inst->dest, inst->type, stack_depth);
1021
0
                if (stack_depth > 10000) {
1022
0
                    cli_warnmsg("bytecode: stack depth exceeded\n");
1023
0
                    stop = CL_EBYTECODE;
1024
0
                    break;
1025
0
                }
1026
0
                j = 0;
1027
0
                for (i = 0; i < func2->numArgs; i++) {
1028
0
                    switch (inst->u.ops.opsizes[i]) {
1029
0
                        case 1: {
1030
0
                            uint8_t v;
1031
0
                            READOLD8(v, inst->u.ops.ops[i]);
1032
0
                            CHECK_GT(func2->numBytes, j);
1033
0
                            values[j++] = v;
1034
0
                            break;
1035
0
                        }
1036
0
                        case 2: {
1037
0
                            uint16_t v;
1038
0
                            READOLD16(v, inst->u.ops.ops[i]);
1039
0
                            j = (j + 1) & ~1;
1040
0
                            CHECK_GT(func2->numBytes, j);
1041
0
                            *(uint16_t *)&values[j] = v;
1042
0
                            j += 2;
1043
0
                            break;
1044
0
                        }
1045
0
                        case 4: {
1046
0
                            uint32_t v;
1047
0
                            READOLD32(v, inst->u.ops.ops[i]);
1048
0
                            j = (j + 3) & ~3;
1049
0
                            CHECK_GT(func2->numBytes, j);
1050
0
                            *(uint32_t *)&values[j] = v;
1051
0
                            j += 4;
1052
0
                            break;
1053
0
                        }
1054
0
                        case 8: {
1055
0
                            uint64_t v;
1056
0
                            READOLD64(v, inst->u.ops.ops[i]);
1057
0
                            j = (j + 7) & ~7;
1058
0
                            CHECK_GT(func2->numBytes, j);
1059
0
                            *(uint64_t *)&values[j] = v;
1060
0
                            j += 8;
1061
0
                            break;
1062
0
                        }
1063
0
                    }
1064
0
                }
1065
0
                func    = func2;
1066
0
                stackid = ptr_register_stack(&ptrinfos, values, 0, func->numBytes) >> 32;
1067
0
                CHECK_GT(func->numBB, 0);
1068
0
                stop = jump(func, 0, &bb, &inst, &bb_inst);
1069
0
                stack_depth++;
1070
0
                continue;
1071
1072
0
            case OP_BC_COPY * 5: {
1073
0
                uint8_t op;
1074
0
                READ1(op, BINOP(0));
1075
0
                WRITE8(BINOP(1), op);
1076
0
                break;
1077
0
            }
1078
0
            case OP_BC_COPY * 5 + 1: {
1079
0
                uint8_t op;
1080
0
                READ8(op, BINOP(0));
1081
0
                WRITE8(BINOP(1), op);
1082
0
                break;
1083
0
            }
1084
0
            case OP_BC_COPY * 5 + 2: {
1085
0
                uint16_t op;
1086
0
                READ16(op, BINOP(0));
1087
0
                WRITE16(BINOP(1), op);
1088
0
                break;
1089
0
            }
1090
0
            case OP_BC_COPY * 5 + 3: {
1091
0
                uint32_t op;
1092
0
                READ32(op, BINOP(0));
1093
0
                WRITE32(BINOP(1), op);
1094
0
                break;
1095
0
            }
1096
0
            case OP_BC_COPY * 5 + 4: {
1097
0
                uint64_t op;
1098
0
                READ64(op, BINOP(0));
1099
0
                WRITE64(BINOP(1), op);
1100
0
                break;
1101
0
            }
1102
1103
0
            case OP_BC_LOAD * 5:
1104
0
            case OP_BC_LOAD * 5 + 1: {
1105
0
                uint8_t *ptr;
1106
0
                READPOP(ptr, inst->u.unaryop, 1);
1107
0
                WRITE8(inst->dest, (*ptr));
1108
0
                break;
1109
0
            }
1110
0
            case OP_BC_LOAD * 5 + 2: {
1111
0
                const union unaligned_16 *ptr;
1112
0
                READPOP(ptr, inst->u.unaryop, 2);
1113
0
                WRITE16(inst->dest, (ptr->una_u16));
1114
0
                break;
1115
0
            }
1116
0
            case OP_BC_LOAD * 5 + 3: {
1117
0
                const union unaligned_32 *ptr;
1118
0
                READPOP(ptr, inst->u.unaryop, 4);
1119
0
                WRITE32(inst->dest, (ptr->una_u32));
1120
0
                break;
1121
0
            }
1122
0
            case OP_BC_LOAD * 5 + 4: {
1123
0
                const union unaligned_64 *ptr;
1124
0
                READPOP(ptr, inst->u.unaryop, 8);
1125
0
                WRITE64(inst->dest, (ptr->una_u64));
1126
0
                break;
1127
0
            }
1128
1129
0
            case OP_BC_STORE * 5: {
1130
0
                uint8_t *ptr;
1131
0
                uint8_t v;
1132
0
                READP(ptr, BINOP(1), 1);
1133
0
                READ1(v, BINOP(0));
1134
0
                *ptr = v;
1135
0
                break;
1136
0
            }
1137
0
            case OP_BC_STORE * 5 + 1: {
1138
0
                uint8_t *ptr;
1139
0
                uint8_t v;
1140
0
                READP(ptr, BINOP(1), 1);
1141
0
                READ8(v, BINOP(0));
1142
0
                *ptr = v;
1143
0
                break;
1144
0
            }
1145
0
            case OP_BC_STORE * 5 + 2: {
1146
0
                union unaligned_16 *ptr;
1147
0
                uint16_t v;
1148
0
                READP(ptr, BINOP(1), 2);
1149
0
                READ16(v, BINOP(0));
1150
0
                ptr->una_s16 = v;
1151
0
                break;
1152
0
            }
1153
0
            case OP_BC_STORE * 5 + 3: {
1154
0
                union unaligned_32 *ptr;
1155
0
                uint32_t v;
1156
0
                READP(ptr, BINOP(1), 4);
1157
0
                READ32(v, BINOP(0));
1158
0
                ptr->una_u32 = v;
1159
0
                break;
1160
0
            }
1161
0
            case OP_BC_STORE * 5 + 4: {
1162
0
                union unaligned_64 *ptr;
1163
0
                uint64_t v;
1164
0
                READP(ptr, BINOP(1), 8);
1165
0
                READ64(v, BINOP(0));
1166
0
                ptr->una_u64 = v;
1167
0
                break;
1168
0
            }
1169
0
                DEFINE_OP(OP_BC_ISBIGENDIAN)
1170
0
                {
1171
0
                    WRITE8(inst->dest, WORDS_BIGENDIAN);
1172
0
                    break;
1173
0
                }
1174
0
                DEFINE_OP(OP_BC_GEPZ)
1175
0
                {
1176
0
                    int64_t ptr, iptr;
1177
0
                    int32_t off;
1178
0
                    READ32(off, inst->u.three[2]);
1179
1180
                    // negative values checking, valid for intermediate GEP calculations
1181
0
                    if (off < 0) {
1182
0
                        cli_dbgmsg("bytecode warning: found GEP with negative offset %d!\n", off);
1183
0
                    }
1184
1185
0
                    if (!(inst->interp_op % 5)) {
1186
                        // how do negative offsets affect pointer initialization?
1187
0
                        WRITE64(inst->dest, ptr_compose(stackid,
1188
0
                                                        inst->u.three[1] + off));
1189
0
                    } else {
1190
0
                        READ64(ptr, inst->u.three[1]);
1191
0
                        off += (ptr & 0x00000000ffffffffULL);
1192
0
                        iptr = (ptr & 0xffffffff00000000ULL) + (uint64_t)(off);
1193
0
                        WRITE64(inst->dest, iptr);
1194
0
                    }
1195
0
                    break;
1196
0
                }
1197
0
                DEFINE_OP(OP_BC_MEMCMP)
1198
0
                {
1199
0
                    int32_t arg3;
1200
0
                    void *arg1, *arg2;
1201
0
                    READ32(arg3, inst->u.three[2]);
1202
0
                    READPOP(arg1, inst->u.three[0], arg3);
1203
0
                    READPOP(arg2, inst->u.three[1], arg3);
1204
0
                    WRITE32(inst->dest, memcmp(arg1, arg2, arg3));
1205
0
                    break;
1206
0
                }
1207
0
                DEFINE_OP(OP_BC_MEMCPY)
1208
0
                {
1209
0
                    int64_t arg3;
1210
0
                    void *arg1, *arg2;
1211
1212
0
                    READ32(arg3, inst->u.three[2]);
1213
0
                    READPOP(arg1, inst->u.three[0], arg3);
1214
0
                    READPOP(arg2, inst->u.three[1], arg3);
1215
0
                    memcpy(arg1, arg2, (int32_t)arg3);
1216
0
                    break;
1217
0
                }
1218
0
                DEFINE_OP(OP_BC_MEMMOVE)
1219
0
                {
1220
0
                    int64_t arg3;
1221
0
                    void *arg1, *arg2;
1222
1223
0
                    READ64(arg3, inst->u.three[2]);
1224
0
                    READPOP(arg1, inst->u.three[0], arg3);
1225
0
                    READPOP(arg2, inst->u.three[1], arg3);
1226
0
                    memmove(arg1, arg2, (int32_t)arg3);
1227
0
                    break;
1228
0
                }
1229
0
                DEFINE_OP(OP_BC_MEMSET)
1230
0
                {
1231
0
                    int64_t arg3;
1232
0
                    int32_t arg2;
1233
0
                    void *arg1;
1234
1235
0
                    READ64(arg3, inst->u.three[2]);
1236
0
                    READPOP(arg1, inst->u.three[0], arg3);
1237
0
                    READ32(arg2, inst->u.three[1]);
1238
0
                    memset(arg1, arg2, (int32_t)arg3);
1239
0
                    break;
1240
0
                }
1241
0
                DEFINE_OP(OP_BC_BSWAP16)
1242
0
                {
1243
0
                    int16_t arg1;
1244
0
                    READ16(arg1, inst->u.unaryop);
1245
0
                    WRITE16(inst->dest, cbswap16(arg1));
1246
0
                    break;
1247
0
                }
1248
0
                DEFINE_OP(OP_BC_BSWAP32)
1249
0
                {
1250
0
                    int32_t arg1;
1251
0
                    READ32(arg1, inst->u.unaryop);
1252
0
                    WRITE32(inst->dest, cbswap32(arg1));
1253
0
                    break;
1254
0
                }
1255
0
                DEFINE_OP(OP_BC_BSWAP64)
1256
0
                {
1257
0
                    int64_t arg1;
1258
0
                    READ64(arg1, inst->u.unaryop);
1259
0
                    WRITE64(inst->dest, cbswap64(arg1));
1260
0
                    break;
1261
0
                }
1262
0
                DEFINE_OP(OP_BC_PTRDIFF32)
1263
0
                {
1264
0
                    int64_t ptr1, ptr2;
1265
0
                    if (BINOP(0) & 0x40000000)
1266
0
                        ptr1 = ptr_compose(stackid, BINOP(0) & 0xbfffffff);
1267
0
                    else
1268
0
                        READ64(ptr1, BINOP(0));
1269
0
                    if (BINOP(1) & 0x40000000)
1270
0
                        ptr2 = ptr_compose(stackid, BINOP(1) & 0xbfffffff);
1271
0
                    else
1272
0
                        READ64(ptr2, BINOP(1));
1273
0
                    WRITE32(inst->dest, ptr_diff32(ptr1, ptr2));
1274
0
                    break;
1275
0
                }
1276
0
                DEFINE_OP(OP_BC_PTRTOINT64)
1277
0
                {
1278
0
                    int64_t ptr;
1279
0
                    if (inst->u.unaryop & 0x40000000)
1280
0
                        ptr = ptr_compose(stackid, inst->u.unaryop & 0xbfffffff);
1281
0
                    else
1282
0
                        READ64(ptr, BINOP(0));
1283
0
                    WRITE64(inst->dest, ptr);
1284
0
                    break;
1285
0
                }
1286
0
                DEFINE_OP(OP_BC_GEP1)
1287
0
                {
1288
0
                    int64_t ptr, iptr;
1289
0
                    int32_t off;
1290
0
                    READ32(off, inst->u.three[2]);
1291
1292
                    // negative values checking, valid for intermediate GEP calculations
1293
0
                    if (off < 0) {
1294
0
                        cli_dbgmsg("bytecode warning: GEP with negative offset %d!\n", off);
1295
0
                    }
1296
1297
0
                    if (!(inst->interp_op % 5)) {
1298
                        // how do negative offsets affect pointer initialization?
1299
0
                        cli_dbgmsg("bytecode warning: untested case for GEP1\n");
1300
0
                        off *= inst->u.three[0];
1301
0
                        WRITE64(inst->dest, ptr_compose(stackid,
1302
0
                                                        inst->u.three[1] + off));
1303
0
                    } else {
1304
0
                        READ64(ptr, inst->u.three[1]);
1305
0
                        off *= inst->u.three[0];
1306
0
                        off += (ptr & 0x00000000ffffffffULL);
1307
0
                        iptr = (ptr & 0xffffffff00000000ULL) + (uint64_t)(off);
1308
0
                        WRITE64(inst->dest, iptr);
1309
0
                    }
1310
0
                    break;
1311
0
                }
1312
            /* TODO: implement OP_BC_GEP1, OP_BC_GEP2, OP_BC_GEPN */
1313
0
            default:
1314
0
                cli_errmsg("Opcode %u of type %u is not implemented yet!\n",
1315
0
                           inst->interp_op / 5, inst->interp_op % 5);
1316
0
                stop = CL_EARG;
1317
0
                continue;
1318
0
        }
1319
0
        bb_inst++;
1320
0
        inst++;
1321
0
        if (bb) {
1322
0
            CHECK_GT(bb->numInsts, bb_inst);
1323
0
        }
1324
0
    } while (stop == CL_SUCCESS);
1325
0
    if (cli_debug_flag) {
1326
0
        gettimeofday(&tv1, NULL);
1327
0
        tv1.tv_sec -= tv0.tv_sec;
1328
0
        tv1.tv_usec -= tv0.tv_usec;
1329
0
        cli_dbgmsg("interpreter bytecode run finished in %luus, after executing %u opcodes\n",
1330
0
                   tv1.tv_sec * 1000000 + tv1.tv_usec, pc);
1331
0
    }
1332
0
    if (stop == CL_EBYTECODE) {
1333
0
        cli_event_error_str(ctx->bc_events, "interpreter finished with error\n");
1334
0
        cli_dbgmsg("interpreter finished with error\n");
1335
0
    }
1336
1337
0
    cli_stack_destroy(&stack);
1338
0
    free(ptrinfos.stack_infos);
1339
0
    free(ptrinfos.glob_infos);
1340
0
    return stop == CL_BREAK ? CL_SUCCESS : stop;
1341
0
}