Browse code

Implement more opcodes and checking.

Török Edvin authored on 2009/07/08 18:45:06
Showing 5 changed files
... ...
@@ -126,5 +126,6 @@ int main(int argc, char *argv[])
126 126
     cli_bytecode_destroy(bc);
127 127
     free(bc);
128 128
     optfree(opts);
129
+    printf("Exiting\n");
129 130
     return 0;
130 131
 }
... ...
@@ -67,12 +67,12 @@ int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, un
67 67
     ctx->bc = bc;
68 68
     ctx->numParams = func->numArgs;
69 69
     ctx->funcid = funcid;
70
+    ctx->values = cli_malloc(sizeof(*ctx->values)*(func->numArgs+1));
71
+    if (!ctx->values) {
72
+	cli_errmsg("bytecode: error allocating memory for parameters\n");
73
+	return CL_EMEM;
74
+    }
70 75
     if (func->numArgs) {
71
-	ctx->values = cli_malloc(sizeof(*ctx->values)*func->numArgs);
72
-	if (!ctx->values) {
73
-	    cli_errmsg("bytecode: error allocating memory for parameters\n");
74
-	    return CL_EMEM;
75
-	}
76 76
 	ctx->operands = cli_malloc(sizeof(*ctx->operands)*func->numArgs);
77 77
 	if (!ctx->operands) {
78 78
 	    cli_errmsg("bytecode: error allocating memory for parameters\n");
... ...
@@ -81,7 +81,7 @@ int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, struct cli_bc *bc, un
81 81
     }
82 82
     for (i=0;i<func->numArgs;i++) {
83 83
 	ctx->values[i].ref = MAX_OP;
84
-	ctx->operands[i] = i;
84
+	ctx->operands[i+1] = i;
85 85
     }
86 86
     return CL_SUCCESS;
87 87
 }
... ...
@@ -168,7 +168,7 @@ static inline operand_t readOperand(struct cli_bc_func *func, unsigned char *p,
168 168
 {
169 169
     uint64_t v;
170 170
     unsigned numValues = func->numArgs + func->numInsts + func->numConstants;
171
-    if ((p[*off]&0xf0) == 0x40) {
171
+    if ((p[*off]&0xf0) == 0x40 || p[*off] == 0x50) {
172 172
 	p[*off] |= 0x20;
173 173
 	/* TODO: unique constants */
174 174
 	func->values = cli_realloc2(func->values, (numValues+1)*sizeof(*func->values));
... ...
@@ -229,8 +229,10 @@ static inline unsigned char *readData(const unsigned char *p, unsigned *off, uns
229 229
     }
230 230
     (*off)++;
231 231
     l = readNumber(p, off, len, ok);
232
-    if (!l)
232
+    if (!l) {
233
+	*datalen = l;
233 234
 	return NULL;
235
+    }
234 236
     newoff = *off + l;
235 237
     if (newoff > len) {
236 238
 	cli_errmsg("Line ended while reading data\n");
... ...
@@ -610,7 +612,6 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx)
610 610
 {
611 611
     struct cli_bc_inst inst;
612 612
     struct cli_bc_func func;
613
-    struct cli_bc_value value;
614 613
     unsigned i;
615 614
     if (!ctx || !ctx->bc || !ctx->func)
616 615
 	return CL_ENULLARG;
... ...
@@ -624,13 +625,14 @@ int cli_bytecode_run(struct cli_bc *bc, struct cli_bc_ctx *ctx)
624 624
     }
625 625
     memset(&func, 0, sizeof(func));
626 626
     func.values = ctx->values;
627
+    func.numInsts = 1;
627 628
 
628 629
     inst.opcode = OP_CALL_DIRECT;
629 630
     inst.type = 0;/* TODO: support toplevel functions with return values */
630 631
     inst.u.ops.numOps = ctx->numParams;
631 632
     inst.u.ops.funcid = ctx->funcid;
632 633
     inst.u.ops.ops = ctx->operands;
633
-    return cli_vm_execute(ctx->bc, ctx, &func, &inst, &value);
634
+    return cli_vm_execute(ctx->bc, ctx, &func, &inst, func.values);
634 635
 }
635 636
 
636 637
 void cli_bytecode_destroy(struct cli_bc *bc)
... ...
@@ -57,6 +57,35 @@ struct stack_entry {
57 57
     unsigned bb_inst;
58 58
 };
59 59
 
60
+
61
+/* Get the operand of a binary operator, upper bits
62
+ * (beyond the size of the operand) may have random values.
63
+ * Use this when the active bits of the result of a binop are the same
64
+ * regardless of the state of the inactive (high) bits of their operands.
65
+ * For example (a + b)&mask == ((a&mask) + (b&mask))
66
+ * but (a / b)&mask != ((a&mask) / (b&mask))
67
+ * */
68
+#define BINOPNOMOD(i) (values[inst->u.binop[i]].v)
69
+#define UNOPNOMOD(i) (values[inst->u.binop[i]].v)
70
+
71
+/* get the operand of a binary operator, upper bits are cleared */
72
+#define BINOP(i) (BINOPNOMOD(i)&((1 << inst->type)-1))
73
+#define UNOP(x) (UNOPNOMOD(i)&((1 << inst->type)-1))
74
+
75
+/* get the operand as a signed value */
76
+#define SIGNEXT(a) CLI_SRS(((int64_t)(a)) << (64-inst->type), (64-inst->type))
77
+#define BINOPS(i) SIGNEXT(BINOPNOMOD(i))
78
+
79
+static void jump(struct cli_bc_func *func, uint16_t bbid, struct cli_bc_bb **bb, struct cli_bc_inst **inst,
80
+		 struct cli_bc_value **value, unsigned *bb_inst)
81
+{
82
+    CHECK_GT(func->numBB, bbid);
83
+    *bb = &func->BB[bbid];
84
+    *inst = (*bb)->insts;
85
+    *value = &func->values[*inst - func->allinsts];
86
+    *bb_inst = 0;
87
+}
88
+
60 89
 int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func *func, struct cli_bc_inst *inst, struct cli_bc_value *value)
61 90
 {
62 91
     unsigned i, stack_depth=0, bb_inst=0, stop=0;
... ...
@@ -68,33 +97,93 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
68 68
     do {
69 69
 	switch (inst->opcode) {
70 70
 	    case OP_ADD:
71
-		values->v = values[inst->u.binop[0]].v + values[inst->u.binop[1]].v;
71
+		values->v = BINOPNOMOD(0) + BINOPNOMOD(1);
72 72
 		break;
73 73
 	    case OP_SUB:
74
-		values->v = values[inst->u.binop[0]].v - values[inst->u.binop[1]].v;
74
+		values->v = BINOPNOMOD(0) - BINOPNOMOD(1);
75 75
 		break;
76 76
 	    case OP_MUL:
77
-		values->v = values[inst->u.binop[0]].v * values[inst->u.binop[1]].v;
77
+		values->v = BINOPNOMOD(0) * BINOPNOMOD(1);
78
+		break;
79
+	    case OP_UDIV:
80
+		{
81
+		    uint64_t d = BINOP(1);
82
+		    if (UNLIKELY(!d))
83
+			return CL_EBYTECODE;
84
+		    values->v = BINOP(0) / d;
85
+		    break;
86
+		}
87
+	    case OP_SDIV:
88
+		{
89
+		    int64_t a = BINOPS(0);
90
+		    int64_t b = BINOPS(1);
91
+		    if (UNLIKELY(b == 0 || (b == -1 && a == (-9223372036854775807LL-1LL))))
92
+			return CL_EBYTECODE;
93
+		    values->v = a / b;
94
+		    break;
95
+		}
96
+	    case OP_UREM:
97
+		{
98
+		    uint64_t d = BINOP(1);
99
+		    if (UNLIKELY(!d))
100
+			return CL_EBYTECODE;
101
+		    values->v = BINOP(0) % d;
102
+		    break;
103
+		}
104
+	    case OP_SREM:
105
+		{
106
+		    int64_t a = BINOPS(0);
107
+		    int64_t b = BINOPS(1);
108
+		    if (UNLIKELY(b == 0 || (b == -1 && (a == -9223372036854775807LL-1LL))))
109
+			return CL_EBYTECODE;
110
+		    values->v = a % b;
111
+		    break;
112
+		}
113
+	    case OP_SHL:
114
+		values->v = BINOPNOMOD(0) << BINOP(1);
78 115
 		break;
116
+	    case OP_LSHR:
117
+		values->v = BINOP(0) >> BINOP(1);
118
+		break;
119
+	    case OP_ASHR:
120
+		{
121
+		    int64_t v = BINOPS(0);
122
+		    values->v = CLI_SRS(v, BINOP(1));
123
+		    break;
124
+		}
79 125
 	    case OP_AND:
80
-		values->v = values[inst->u.binop[0]].v & values[inst->u.binop[1]].v;
126
+		values->v = BINOPNOMOD(0) & BINOPNOMOD(1);
81 127
 		break;
82 128
 	    case OP_OR:
83
-		values->v = values[inst->u.binop[0]].v | values[inst->u.binop[1]].v;
129
+		values->v = BINOPNOMOD(0) | BINOPNOMOD(1);
84 130
 		break;
85 131
 	    case OP_XOR:
86
-		values->v = values[inst->u.binop[0]].v ^ values[inst->u.binop[1]].v;
132
+		values->v = BINOPNOMOD(0) ^ BINOPNOMOD(1);
133
+		break;
134
+	    case OP_SEXT:
135
+		values->v = SIGNEXT(values[inst->u.cast.source].v);
87 136
 		break;
88
-	    case OP_ZEXT:
89 137
 	    case OP_TRUNC:
138
+		/* fall-through */
139
+	    case OP_ZEXT:
90 140
 		values->v = values[inst->u.cast.source].v & values[inst->u.cast.mask].v;
91 141
 		break;
142
+	    case OP_BRANCH:
143
+		jump(func, (values[inst->u.branch.condition].v&1) ?
144
+		     inst->u.branch.br_true : inst->u.branch.br_false,
145
+		     &bb, &inst, &value, &bb_inst);
146
+		continue;
147
+	    case OP_JMP:
148
+		jump(func, inst->u.jump, &bb, &inst, &value, &bb_inst);
149
+		continue;
92 150
 	    case OP_RET:
93 151
 		CHECK_GT(stack_depth, 0);
94 152
 		stack_depth--;
95 153
 		value = stack[stack_depth].ret;
96
-		value->v = values[inst->u.unaryop].v;
97 154
 		func = stack[stack_depth].func;
155
+		CHECK_GT(func->values + func->numArgs+func->numInsts+func->numConstants, value);
156
+		CHECK_GT(value, &func->values[-1]);
157
+		value->v = values[inst->u.unaryop].v;
98 158
 		values = func->values;
99 159
 		if (!stack[stack_depth].bb) {
100 160
 		    stop = CL_BREAK;
... ...
@@ -106,10 +195,37 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
106 106
 		inst = &bb->insts[bb_inst];
107 107
 		break;
108 108
 	    case OP_ICMP_EQ:
109
-		value->v = values[inst->u.binop[0]].v == values[inst->u.binop[1]].v ? 1 : 0;
109
+		value->v = BINOP(0) == BINOP(1) ? 1 : 0;
110
+		break;
111
+	    case OP_ICMP_NE:
112
+		value->v = BINOP(0) != BINOP(1) ? 1 : 0;
113
+		break;
114
+	    case OP_ICMP_UGT:
115
+		value->v = BINOP(0) > BINOP(1) ? 1 : 0;
116
+		break;
117
+	    case OP_ICMP_UGE:
118
+		value->v = BINOP(0) >= BINOP(1) ? 1 : 0;
119
+		break;
120
+	    case OP_ICMP_ULT:
121
+		value->v = BINOP(0) < BINOP(1) ? 1 : 0;
122
+		break;
123
+	    case OP_ICMP_ULE:
124
+		value->v = BINOP(0) <= BINOP(1) ? 1 : 0;
125
+		break;
126
+	    case OP_ICMP_SGT:
127
+		value->v = BINOPS(0) > BINOPS(1) ? 1 : 0;
128
+		break;
129
+	    case OP_ICMP_SGE:
130
+		value->v = BINOPS(0) >= BINOPS(1) ? 1 : 0;
131
+		break;
132
+	    case OP_ICMP_SLE:
133
+		value->v = BINOPS(0) <= BINOPS(1) ? 1 : 0;
134
+		break;
135
+	    case OP_ICMP_SLT:
136
+		value->v = BINOPS(0) < BINOPS(1) ? 1 : 0;
110 137
 		break;
111 138
 	    case OP_SELECT:
112
-		values->v = values[inst->u.three[0]].v ?
139
+		values->v = (values[inst->u.three[0]].v&1) ?
113 140
 		    values[inst->u.three[1]].v : values[inst->u.three[2]].v;
114 141
 		break;
115 142
 	    case OP_CALL_DIRECT:
... ...
@@ -126,13 +242,15 @@ int cli_vm_execute(struct cli_bc *bc, struct cli_bc_ctx *ctx, struct cli_bc_func
126 126
 		stack[stack_depth].bb = bb;
127 127
 		stack[stack_depth].bb_inst = bb_inst;
128 128
 		stack_depth++;
129
+		cli_dbgmsg("Executing %d\n", inst->u.ops.funcid);
129 130
 		func = func2;
130 131
 		values = func->values;
131 132
 		CHECK_GT(func->numBB, 0);
132
-		bb = &func->BB[0];
133
-		inst = &bb->insts[0];
134
-		bb_inst = 0;
133
+		jump(func, 0, &bb, &inst, &value, &bb_inst);
135 134
 		continue;
135
+	    case OP_COPY:
136
+		BINOPNOMOD(1) = BINOPNOMOD(0);
137
+		break;
136 138
 	    default:
137 139
 		cli_errmsg("Opcode %u is not implemented yet!\n", inst->opcode);
138 140
 		stop = CL_EARG;
... ...
@@ -65,7 +65,8 @@ typedef enum {
65 65
     CL_EMAXREC,
66 66
     CL_EMAXSIZE,
67 67
     CL_EMAXFILES,
68
-    CL_EFORMAT
68
+    CL_EFORMAT,
69
+    CL_EBYTECODE
69 70
 } cl_error_t;
70 71
 
71 72
 /* db options */
... ...
@@ -259,6 +259,8 @@ const char *cl_strerror(int clerror)
259 259
 	    return "CL_EMAXFILES";
260 260
 	case CL_EFORMAT:
261 261
 	    return "CL_EFORMAT: Bad format or broken data";
262
+	case CL_EBYTECODE:
263
+	    return "CL_EBYTECODE: error during bytecode execution";
262 264
 	default:
263 265
 	    return "Unknown error code";
264 266
     }