... | ... |
@@ -30,18 +30,29 @@ |
30 | 30 |
#include "readdb.h" |
31 | 31 |
#include <string.h> |
32 | 32 |
|
33 |
+typedef uint32_t operand_t; |
|
34 |
+ |
|
33 | 35 |
struct cli_bc_varop { |
34 | 36 |
uint8_t numOps; |
35 |
- uint16_t* ops; |
|
37 |
+ operand_t* ops; |
|
38 |
+}; |
|
39 |
+ |
|
40 |
+struct branch { |
|
41 |
+ operand_t condition; |
|
42 |
+ struct cli_bc_bb *br_true; |
|
43 |
+ struct cli_bc_bb *br_false; |
|
36 | 44 |
}; |
37 | 45 |
|
38 | 46 |
struct cli_bc_inst { |
39 | 47 |
enum bc_opcode opcode; |
40 | 48 |
uint16_t type; |
41 | 49 |
union { |
42 |
- uint16_t unaryop; |
|
43 |
- uint16_t binop[2]; |
|
50 |
+ operand_t unaryop; |
|
51 |
+ operand_t binop[2]; |
|
52 |
+ operand_t three[3]; |
|
44 | 53 |
struct cli_bc_varop ops; |
54 |
+ struct branch branch; |
|
55 |
+ struct cli_bc_bb *jump; |
|
45 | 56 |
} u; |
46 | 57 |
}; |
47 | 58 |
|
... | ... |
@@ -148,7 +159,7 @@ static inline unsigned readFixedNumber(const unsigned char *p, unsigned *off, |
148 | 148 |
return n; |
149 | 149 |
} |
150 | 150 |
|
151 |
-static inline char *readData(const unsigned char *p, unsigned *off, unsigned len, char *ok) |
|
151 |
+static inline unsigned char *readData(const unsigned char *p, unsigned *off, unsigned len, char *ok, unsigned *datalen) |
|
152 | 152 |
{ |
153 | 153 |
unsigned char *dat, *q; |
154 | 154 |
unsigned l, newoff, i; |
... | ... |
@@ -184,10 +195,22 @@ static inline char *readData(const unsigned char *p, unsigned *off, unsigned len |
184 | 184 |
*q++ = v; |
185 | 185 |
} |
186 | 186 |
*off = newoff; |
187 |
+ *datalen = l; |
|
187 | 188 |
return dat; |
188 | 189 |
} |
189 | 190 |
|
190 |
-static int parseHeader(struct cli_bc *bc, char *buffer) |
|
191 |
+static inline char *readString(const unsigned char *p, unsigned *off, unsigned len, char *ok) |
|
192 |
+{ |
|
193 |
+ unsigned stringlen; |
|
194 |
+ char *str = (char*)readData(p, off, len, ok, &stringlen); |
|
195 |
+ if (*ok && stringlen && str[stringlen-1] != '\0') { |
|
196 |
+ free(str); |
|
197 |
+ *ok = 0; |
|
198 |
+ return NULL; |
|
199 |
+ } |
|
200 |
+ return str; |
|
201 |
+} |
|
202 |
+static int parseHeader(struct cli_bc *bc, unsigned char *buffer) |
|
191 | 203 |
{ |
192 | 204 |
uint64_t magic1; |
193 | 205 |
unsigned magic2; |
... | ... |
@@ -198,7 +221,7 @@ static int parseHeader(struct cli_bc *bc, char *buffer) |
198 | 198 |
return CL_EMALFDB; |
199 | 199 |
} |
200 | 200 |
offset = sizeof(BC_HEADER)-1; |
201 |
- len = strlen(buffer); |
|
201 |
+ len = strlen((const char*)buffer); |
|
202 | 202 |
flevel = readNumber(buffer, &offset, len, &ok); |
203 | 203 |
if (!ok) { |
204 | 204 |
cli_errmsg("Unable to parse functionality level in bytecode header\n"); |
... | ... |
@@ -210,15 +233,15 @@ static int parseHeader(struct cli_bc *bc, char *buffer) |
210 | 210 |
} |
211 | 211 |
// Optimistic parsing, check for error only at the end. |
212 | 212 |
bc->verifier = readNumber(buffer, &offset, len, &ok); |
213 |
- bc->sigmaker = readData(buffer, &offset, len, &ok); |
|
213 |
+ bc->sigmaker = readString(buffer, &offset, len, &ok); |
|
214 | 214 |
bc->id = readNumber(buffer, &offset, len, &ok); |
215 | 215 |
bc->metadata.maxStack = readNumber(buffer, &offset, len, &ok); |
216 | 216 |
bc->metadata.maxMem = readNumber(buffer, &offset, len, &ok); |
217 | 217 |
bc->metadata.maxTime = readNumber(buffer, &offset, len, &ok); |
218 |
- bc->metadata.targetExclude = readData(buffer, &offset, len, &ok); |
|
218 |
+ bc->metadata.targetExclude = readString(buffer, &offset, len, &ok); |
|
219 | 219 |
bc->num_func = readNumber(buffer, &offset, len, &ok); |
220 | 220 |
if (!ok) { |
221 |
- cli_errmsg("Invalid bytecode header\n", offset); |
|
221 |
+ cli_errmsg("Invalid bytecode header at %u\n", offset); |
|
222 | 222 |
return CL_EMALFDB; |
223 | 223 |
} |
224 | 224 |
magic1 = readNumber(buffer, &offset, len, &ok); |
... | ... |
@@ -243,7 +266,7 @@ static int parseHeader(struct cli_bc *bc, char *buffer) |
243 | 243 |
return CL_SUCCESS; |
244 | 244 |
} |
245 | 245 |
|
246 |
-static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, char *buffer) |
|
246 |
+static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *buffer) |
|
247 | 247 |
{ |
248 | 248 |
char ok=1; |
249 | 249 |
unsigned offset, len, all_locals=0, i; |
... | ... |
@@ -255,7 +278,7 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, char *buffer) |
255 | 255 |
return CL_EMALFDB; |
256 | 256 |
} |
257 | 257 |
func = &bc->funcs[fn]; |
258 |
- len = strlen(buffer); |
|
258 |
+ len = strlen((const char*)buffer); |
|
259 | 259 |
|
260 | 260 |
if (buffer[0] != 'A') { |
261 | 261 |
cli_errmsg("Invalid function arguments header: %c\n", buffer[0]); |
... | ... |
@@ -304,20 +327,32 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, char *buffer) |
304 | 304 |
return CL_SUCCESS; |
305 | 305 |
} |
306 | 306 |
|
307 |
-static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, char *buffer) |
|
307 |
+static struct cli_bc_bb *readBBID(struct cli_bc_func *func, const unsigned char *buffer, unsigned *off, unsigned len, char *ok) { |
|
308 |
+ unsigned id = readNumber(buffer, off, len, ok); |
|
309 |
+ if (!id || id >= func->numBB) { |
|
310 |
+ cli_errmsg("Basic block ID out of range: %u\n", id); |
|
311 |
+ *ok = 0; |
|
312 |
+ } |
|
313 |
+ if (!*ok) |
|
314 |
+ return NULL; |
|
315 |
+ return &func->BB[id]; |
|
316 |
+} |
|
317 |
+ |
|
318 |
+static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char *buffer) |
|
308 | 319 |
{ |
309 | 320 |
char ok=1; |
310 | 321 |
unsigned offset, len, last = 0; |
311 | 322 |
struct cli_bc_bb *BB; |
323 |
+ struct cli_bc_func *bcfunc = &bc->funcs[func]; |
|
312 | 324 |
struct cli_bc_inst inst; |
313 | 325 |
|
314 |
- if (bb >= bc->funcs[func].numBB) { |
|
326 |
+ if (bb >= bcfunc->numBB) { |
|
315 | 327 |
cli_errmsg("Found too many basic blocks\n"); |
316 | 328 |
return CL_EMALFDB; |
317 | 329 |
} |
318 | 330 |
|
319 |
- BB = &bc->funcs[func].BB[bb]; |
|
320 |
- len = strlen(buffer); |
|
331 |
+ BB = &bcfunc->BB[bb]; |
|
332 |
+ len = strlen((const char*) buffer); |
|
321 | 333 |
if (buffer[0] != 'B') { |
322 | 334 |
cli_errmsg("Invalid basic block header: %c\n", buffer[0]); |
323 | 335 |
return CL_EMALFDB; |
... | ... |
@@ -344,26 +379,42 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, char *buffer) |
344 | 344 |
cli_errmsg("Invalid opcode: %u\n", inst.opcode); |
345 | 345 |
return CL_EMALFDB; |
346 | 346 |
} |
347 |
- numOp = operand_counts[inst.opcode]; |
|
348 |
- switch (numOp) { |
|
349 |
- case 1: |
|
350 |
- inst.u.unaryop = readOperand(buffer, &offset, len, &ok); |
|
347 |
+ switch (inst.opcode) { |
|
348 |
+ case OP_JMP: |
|
349 |
+ inst.u.jump = readBBID(bcfunc, buffer, &offset, len, &ok); |
|
351 | 350 |
break; |
352 |
- case 2: |
|
353 |
- inst.u.binop[0] = readOperand(buffer, &offset, len, &ok); |
|
354 |
- inst.u.binop[1] = readOperand(buffer, &offset, len, &ok); |
|
351 |
+ case OP_BRANCH: |
|
352 |
+ inst.u.branch.condition = readOperand(buffer, &offset, len, &ok); |
|
353 |
+ inst.u.branch.br_true = readBBID(bcfunc, buffer, &offset, len, &ok); |
|
354 |
+ inst.u.branch.br_false = readBBID(bcfunc, buffer, &offset, len, &ok); |
|
355 | 355 |
break; |
356 | 356 |
default: |
357 |
- inst.u.ops.numOps = numOp; |
|
358 |
- inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops)); |
|
359 |
- if (!inst.u.ops.ops) { |
|
360 |
- cli_errmsg("Out of memory allocating operands\n"); |
|
361 |
- return CL_EMALFDB; |
|
362 |
- } |
|
363 |
- for (i=0;i<numOp;i++) { |
|
364 |
- inst.u.ops.ops[i] = readOperand(buffer, &offset, len, &ok); |
|
357 |
+ numOp = operand_counts[inst.opcode]; |
|
358 |
+ switch (numOp) { |
|
359 |
+ case 1: |
|
360 |
+ inst.u.unaryop = readOperand(buffer, &offset, len, &ok); |
|
361 |
+ break; |
|
362 |
+ case 2: |
|
363 |
+ inst.u.binop[0] = readOperand(buffer, &offset, len, &ok); |
|
364 |
+ inst.u.binop[1] = readOperand(buffer, &offset, len, &ok); |
|
365 |
+ break; |
|
366 |
+ case 3: |
|
367 |
+ inst.u.three[0] = readOperand(buffer, &offset, len, &ok); |
|
368 |
+ inst.u.three[1] = readOperand(buffer, &offset, len, &ok); |
|
369 |
+ inst.u.three[2] = readOperand(buffer, &offset, len, &ok); |
|
370 |
+ break; |
|
371 |
+ default: |
|
372 |
+ inst.u.ops.numOps = numOp; |
|
373 |
+ inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops)); |
|
374 |
+ if (!inst.u.ops.ops) { |
|
375 |
+ cli_errmsg("Out of memory allocating operands\n"); |
|
376 |
+ return CL_EMALFDB; |
|
377 |
+ } |
|
378 |
+ for (i=0;i<numOp;i++) { |
|
379 |
+ inst.u.ops.ops[i] = readOperand(buffer, &offset, len, &ok); |
|
380 |
+ } |
|
381 |
+ break; |
|
365 | 382 |
} |
366 |
- break; |
|
367 | 383 |
} |
368 | 384 |
if (!ok) { |
369 | 385 |
cli_errmsg("Invalid instructions or operands\n"); |
... | ... |
@@ -415,7 +466,7 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio) |
415 | 415 |
cli_chomp(buffer); |
416 | 416 |
switch (state) { |
417 | 417 |
case PARSE_BC_HEADER: |
418 |
- rc = parseHeader(bc, buffer); |
|
418 |
+ rc = parseHeader(bc, (unsigned char*)buffer); |
|
419 | 419 |
if (rc == CL_BREAK) /* skip */ |
420 | 420 |
return CL_SUCCESS; |
421 | 421 |
if (rc != CL_SUCCESS) |
... | ... |
@@ -423,14 +474,14 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio) |
423 | 423 |
state = PARSE_FUNC_HEADER; |
424 | 424 |
break; |
425 | 425 |
case PARSE_FUNC_HEADER: |
426 |
- rc = parseFunctionHeader(bc, current_func, buffer); |
|
426 |
+ rc = parseFunctionHeader(bc, current_func, (unsigned char*)buffer); |
|
427 | 427 |
if (rc != CL_SUCCESS) |
428 | 428 |
return rc; |
429 | 429 |
bb = 0; |
430 | 430 |
state = PARSE_BB; |
431 | 431 |
break; |
432 | 432 |
case PARSE_BB: |
433 |
- rc = parseBB(bc, current_func, bb++, buffer); |
|
433 |
+ rc = parseBB(bc, current_func, bb++, (unsigned char*)buffer); |
|
434 | 434 |
if (rc != CL_SUCCESS) |
435 | 435 |
return rc; |
436 | 436 |
if (bb >= bc->funcs[current_func].numBB) { |
... | ... |
@@ -462,7 +513,7 @@ void cli_bytecode_destroy(struct cli_bc *bc) |
462 | 462 |
struct cli_bc_bb *BB = &f->BB[j]; |
463 | 463 |
for(k=0;k<BB->numInsts;k++) { |
464 | 464 |
struct cli_bc_inst *i = &BB->insts[k]; |
465 |
- if (operand_counts[i->opcode] > 2) |
|
465 |
+ if (operand_counts[i->opcode] > 3) |
|
466 | 466 |
free(i->u.ops.ops); |
467 | 467 |
} |
468 | 468 |
free(BB->insts); |
... | ... |
@@ -49,6 +49,9 @@ enum bc_opcode { |
49 | 49 |
OP_TRUNC, |
50 | 50 |
OP_SEXT, |
51 | 51 |
OP_ZEXT, |
52 |
+ |
|
53 |
+ OP_BRANCH, |
|
54 |
+ OP_JMP, |
|
52 | 55 |
OP_RET, |
53 | 56 |
|
54 | 57 |
OP_ICMP_EQ, |
... | ... |
@@ -71,8 +74,8 @@ static const unsigned char operand_counts[] = { |
71 | 71 |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
72 | 72 |
/* TRUNC -> ZEXT */ |
73 | 73 |
2, 2, 2, |
74 |
- /* RET */ |
|
75 |
- 1, |
|
74 |
+ /* BRANCH, JMP, RET */ |
|
75 |
+ 3, 1, 1, |
|
76 | 76 |
/* ICMP */ |
77 | 77 |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, |
78 | 78 |
/* SELECT */ |