Add support for branches.

0.96
Török Edvin 16 years ago
parent d6ada03c81
commit c3c97d4af2
  1. 121
      libclamav/bytecode.c
  2. 7
      libclamav/clambc.h

@ -30,18 +30,29 @@
#include "readdb.h"
#include <string.h>
typedef uint32_t operand_t;
struct cli_bc_varop {
uint8_t numOps;
uint16_t* ops;
operand_t* ops;
};
struct branch {
operand_t condition;
struct cli_bc_bb *br_true;
struct cli_bc_bb *br_false;
};
struct cli_bc_inst {
enum bc_opcode opcode;
uint16_t type;
union {
uint16_t unaryop;
uint16_t binop[2];
operand_t unaryop;
operand_t binop[2];
operand_t three[3];
struct cli_bc_varop ops;
struct branch branch;
struct cli_bc_bb *jump;
} u;
};
@ -148,7 +159,7 @@ static inline unsigned readFixedNumber(const unsigned char *p, unsigned *off,
return n;
}
static inline char *readData(const unsigned char *p, unsigned *off, unsigned len, char *ok)
static inline unsigned char *readData(const unsigned char *p, unsigned *off, unsigned len, char *ok, unsigned *datalen)
{
unsigned char *dat, *q;
unsigned l, newoff, i;
@ -184,10 +195,22 @@ static inline char *readData(const unsigned char *p, unsigned *off, unsigned len
*q++ = v;
}
*off = newoff;
*datalen = l;
return dat;
}
static int parseHeader(struct cli_bc *bc, char *buffer)
static inline char *readString(const unsigned char *p, unsigned *off, unsigned len, char *ok)
{
unsigned stringlen;
char *str = (char*)readData(p, off, len, ok, &stringlen);
if (*ok && stringlen && str[stringlen-1] != '\0') {
free(str);
*ok = 0;
return NULL;
}
return str;
}
static int parseHeader(struct cli_bc *bc, unsigned char *buffer)
{
uint64_t magic1;
unsigned magic2;
@ -198,7 +221,7 @@ static int parseHeader(struct cli_bc *bc, char *buffer)
return CL_EMALFDB;
}
offset = sizeof(BC_HEADER)-1;
len = strlen(buffer);
len = strlen((const char*)buffer);
flevel = readNumber(buffer, &offset, len, &ok);
if (!ok) {
cli_errmsg("Unable to parse functionality level in bytecode header\n");
@ -210,15 +233,15 @@ static int parseHeader(struct cli_bc *bc, char *buffer)
}
// Optimistic parsing, check for error only at the end.
bc->verifier = readNumber(buffer, &offset, len, &ok);
bc->sigmaker = readData(buffer, &offset, len, &ok);
bc->sigmaker = readString(buffer, &offset, len, &ok);
bc->id = readNumber(buffer, &offset, len, &ok);
bc->metadata.maxStack = readNumber(buffer, &offset, len, &ok);
bc->metadata.maxMem = readNumber(buffer, &offset, len, &ok);
bc->metadata.maxTime = readNumber(buffer, &offset, len, &ok);
bc->metadata.targetExclude = readData(buffer, &offset, len, &ok);
bc->metadata.targetExclude = readString(buffer, &offset, len, &ok);
bc->num_func = readNumber(buffer, &offset, len, &ok);
if (!ok) {
cli_errmsg("Invalid bytecode header\n", offset);
cli_errmsg("Invalid bytecode header at %u\n", offset);
return CL_EMALFDB;
}
magic1 = readNumber(buffer, &offset, len, &ok);
@ -243,7 +266,7 @@ static int parseHeader(struct cli_bc *bc, char *buffer)
return CL_SUCCESS;
}
static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, char *buffer)
static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *buffer)
{
char ok=1;
unsigned offset, len, all_locals=0, i;
@ -255,7 +278,7 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, char *buffer)
return CL_EMALFDB;
}
func = &bc->funcs[fn];
len = strlen(buffer);
len = strlen((const char*)buffer);
if (buffer[0] != 'A') {
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)
return CL_SUCCESS;
}
static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, char *buffer)
static struct cli_bc_bb *readBBID(struct cli_bc_func *func, const unsigned char *buffer, unsigned *off, unsigned len, char *ok) {
unsigned id = readNumber(buffer, off, len, ok);
if (!id || id >= func->numBB) {
cli_errmsg("Basic block ID out of range: %u\n", id);
*ok = 0;
}
if (!*ok)
return NULL;
return &func->BB[id];
}
static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char *buffer)
{
char ok=1;
unsigned offset, len, last = 0;
struct cli_bc_bb *BB;
struct cli_bc_func *bcfunc = &bc->funcs[func];
struct cli_bc_inst inst;
if (bb >= bc->funcs[func].numBB) {
if (bb >= bcfunc->numBB) {
cli_errmsg("Found too many basic blocks\n");
return CL_EMALFDB;
}
BB = &bc->funcs[func].BB[bb];
len = strlen(buffer);
BB = &bcfunc->BB[bb];
len = strlen((const char*) buffer);
if (buffer[0] != 'B') {
cli_errmsg("Invalid basic block header: %c\n", buffer[0]);
return CL_EMALFDB;
@ -344,26 +379,42 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, char *buffer)
cli_errmsg("Invalid opcode: %u\n", inst.opcode);
return CL_EMALFDB;
}
numOp = operand_counts[inst.opcode];
switch (numOp) {
case 1:
inst.u.unaryop = readOperand(buffer, &offset, len, &ok);
switch (inst.opcode) {
case OP_JMP:
inst.u.jump = readBBID(bcfunc, buffer, &offset, len, &ok);
break;
case 2:
inst.u.binop[0] = readOperand(buffer, &offset, len, &ok);
inst.u.binop[1] = readOperand(buffer, &offset, len, &ok);
case OP_BRANCH:
inst.u.branch.condition = readOperand(buffer, &offset, len, &ok);
inst.u.branch.br_true = readBBID(bcfunc, buffer, &offset, len, &ok);
inst.u.branch.br_false = readBBID(bcfunc, buffer, &offset, len, &ok);
break;
default:
inst.u.ops.numOps = numOp;
inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops));
if (!inst.u.ops.ops) {
cli_errmsg("Out of memory allocating operands\n");
return CL_EMALFDB;
}
for (i=0;i<numOp;i++) {
inst.u.ops.ops[i] = readOperand(buffer, &offset, len, &ok);
numOp = operand_counts[inst.opcode];
switch (numOp) {
case 1:
inst.u.unaryop = readOperand(buffer, &offset, len, &ok);
break;
case 2:
inst.u.binop[0] = readOperand(buffer, &offset, len, &ok);
inst.u.binop[1] = readOperand(buffer, &offset, len, &ok);
break;
case 3:
inst.u.three[0] = readOperand(buffer, &offset, len, &ok);
inst.u.three[1] = readOperand(buffer, &offset, len, &ok);
inst.u.three[2] = readOperand(buffer, &offset, len, &ok);
break;
default:
inst.u.ops.numOps = numOp;
inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops));
if (!inst.u.ops.ops) {
cli_errmsg("Out of memory allocating operands\n");
return CL_EMALFDB;
}
for (i=0;i<numOp;i++) {
inst.u.ops.ops[i] = readOperand(buffer, &offset, len, &ok);
}
break;
}
break;
}
if (!ok) {
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)
cli_chomp(buffer);
switch (state) {
case PARSE_BC_HEADER:
rc = parseHeader(bc, buffer);
rc = parseHeader(bc, (unsigned char*)buffer);
if (rc == CL_BREAK) /* skip */
return CL_SUCCESS;
if (rc != CL_SUCCESS)
@ -423,14 +474,14 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio)
state = PARSE_FUNC_HEADER;
break;
case PARSE_FUNC_HEADER:
rc = parseFunctionHeader(bc, current_func, buffer);
rc = parseFunctionHeader(bc, current_func, (unsigned char*)buffer);
if (rc != CL_SUCCESS)
return rc;
bb = 0;
state = PARSE_BB;
break;
case PARSE_BB:
rc = parseBB(bc, current_func, bb++, buffer);
rc = parseBB(bc, current_func, bb++, (unsigned char*)buffer);
if (rc != CL_SUCCESS)
return rc;
if (bb >= bc->funcs[current_func].numBB) {
@ -462,7 +513,7 @@ void cli_bytecode_destroy(struct cli_bc *bc)
struct cli_bc_bb *BB = &f->BB[j];
for(k=0;k<BB->numInsts;k++) {
struct cli_bc_inst *i = &BB->insts[k];
if (operand_counts[i->opcode] > 2)
if (operand_counts[i->opcode] > 3)
free(i->u.ops.ops);
}
free(BB->insts);

@ -49,6 +49,9 @@ enum bc_opcode {
OP_TRUNC,
OP_SEXT,
OP_ZEXT,
OP_BRANCH,
OP_JMP,
OP_RET,
OP_ICMP_EQ,
@ -71,8 +74,8 @@ static const unsigned char operand_counts[] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* TRUNC -> ZEXT */
2, 2, 2,
/* RET */
1,
/* BRANCH, JMP, RET */
3, 1, 1,
/* ICMP */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* SELECT */

Loading…
Cancel
Save