/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  | }  |