radare2/libr/asm/arch/whitespace/wsdis.c
2017-08-26 12:56:14 +02:00

360 lines
7.8 KiB
C

// dso, condret, pancake 2014-2017
#include <r_types.h>
#include <r_asm.h>
#include <string.h>
#ifndef WS_API
#define WS_API
#endif
enum {
WS_OP_UNK = 0,
WS_OP_NOP,
WS_OP_PREF,
WS_OP_STACK,
WS_OP_ARITH,
WS_OP_HEAP,
WS_OP_FLOW,
WS_OP_IO
};
static int get_ws_pref_optype(const ut8 *buf, int len)
{
if (len) {
switch (buf[0]) {
case ' ':
return WS_OP_STACK;
case '\t':
return WS_OP_PREF;
case 10:
return WS_OP_FLOW;
default:
return WS_OP_NOP;
}
}
return WS_OP_UNK;
}
static int get_ws_suf_optype(const ut8 *buf, int len) {
if (len > 0) {
switch (buf[0]) {
case ' ':
return WS_OP_ARITH;
case '\t':
return WS_OP_HEAP;
case 10:
return WS_OP_IO;
default:
return WS_OP_NOP;
}
}
return WS_OP_UNK;
}
WS_API int get_ws_optype(const ut8 *buf, int len) {
const ut8 *ptr;
if (get_ws_pref_optype (buf, len) == WS_OP_PREF) {
ptr = buf + 1;
while (get_ws_suf_optype (ptr, len - (ptr - buf)) == WS_OP_NOP)
ptr++;
return get_ws_suf_optype (ptr, len - (ptr - buf));
}
return get_ws_pref_optype (buf, len);
}
WS_API const ut8 *get_ws_next_token(const ut8 *buf, int len) {
const ut8 *ret;
ret = buf;
while (len - (ret - buf)) {
switch (*ret) {
case ' ':
case '\t':
case 10:
return ret;
}
ret++;
}
return NULL;
}
static st32 get_ws_val(const ut8 *buf, int len) {
ut8 sig;
const ut8 *tok;
int i, ret;
ret = 0;
tok = get_ws_next_token (buf, len);
sig = (*tok == '\t');
len = len - (tok - buf) - 1;
for (i = 0; i < 30; i++) { // XXX : conceptually wrong
tok++;
tok = get_ws_next_token (tok, len);
if (!tok || *tok == 10) {
if (sig) {
return ret * (-1);
}
return ret;
}
ret = (ret << 1);
ret = ret + (*tok == '\t');
len = len - (tok - buf) - 1;
}
return sig? ret * (-1): ret;
}
WS_API int test_ws_token_exist(const ut8 *buf, ut8 token, int len) {
const ut8 *ptr = get_ws_next_token (buf, len);
int size = 1;
while (ptr && *ptr != token && (len > 0)) {
len = len - (ptr - buf);
ptr = get_ws_next_token (ptr + 1, len - 1);
size++;
}
return size;
}
WS_API int wsdis(RAsmOp *op, const ut8 *buf, int len) {
const ut8 *ptr = buf;
switch (get_ws_optype (buf, len)) {
case WS_OP_UNK:
return op->size = 0;
case WS_OP_NOP:
sprintf (op->buf_asm, "nop");
return op->size = 1;
case WS_OP_STACK:
ptr++;
if (!get_ws_next_token (ptr, len - 1)) {
return op->size = 0;
}
switch (*get_ws_next_token (ptr, len - 1)) {
case ' ':
if (-1 == test_ws_token_exist (get_ws_next_token (ptr, len - 1), 10, len - 1)) {
return op->size = 0;
}
sprintf (op->buf_asm, "push");
{
int n = test_ws_token_exist (ptr - 1, 10, len);
sprintf (op->buf_asm + 4, " %d", n);
return op->size = n;
}
case 10:
ptr = get_ws_next_token (ptr, len - 1) + 1;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "dup");
break;
case '\t':
sprintf (op->buf_asm, "swap");
break;
case 10:
sprintf (op->buf_asm, "pop");
break;
}
return op->size = ptr - buf + 1;
case '\t':
ptr = get_ws_next_token (ptr, len - 1) + 1;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "copy");
break;
case 10:
sprintf (op->buf_asm, "slide");
break;
case '\t':
sprintf (op->buf_asm, "illegal_stack_t");
return op->size = ptr - buf + 1;
}
ptr++;
if (-1 == test_ws_token_exist (ptr, 10, len - (ptr - buf) - 1)) {
op->buf_asm[0] = '\0'; // XXX
return op->size = 0;
}
if (strlen (op->buf_asm) < 6) {
sprintf (&op->buf_asm[strlen (op->buf_asm)], " %d", get_ws_val (ptr, len - (ptr - buf) - 1));
}
return op->size = test_ws_token_exist (ptr, 10, len - (ptr - buf) - 1) + ptr - buf + 1; // +1?
}
case WS_OP_HEAP:
ptr = get_ws_next_token (ptr + 1, len - 1) + 1;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "store");
break;
case '\t':
sprintf (op->buf_asm, "load");
break;
case 10:
sprintf (op->buf_asm, "illegal_heap");
break;
}
return op->size = ptr - buf + 1;
case WS_OP_IO:
ptr = get_ws_next_token (ptr + 1, len - 1) + 1;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "putc");
return op->size = ptr - buf + 1;
case '\t':
sprintf (op->buf_asm, "puti");
return op->size = ptr - buf + 1;
}
break;
case '\t':
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "getc");
return op->size = ptr - buf + 1;
case '\t':
sprintf (op->buf_asm, "geti");
return op->size = ptr - buf + 1;
}
}
sprintf (op->buf_asm, "illegal_io");
return op->size = ptr - buf + 1;
case WS_OP_ARITH:
ptr = get_ws_next_token (ptr + 1, len - 1) + 1;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "add");
break;
case '\t':
sprintf (op->buf_asm, "sub");
break;
case 10:
sprintf (op->buf_asm, "mul");
break;
}
return op->size = ptr - buf + 1;
case '\t':
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case ' ':
sprintf (op->buf_asm, "div");
break;
case '\t':
sprintf (op->buf_asm, "mod");
break;
case 10:
sprintf (op->buf_asm, "illegal_ar_t");
}
break;
case 10:
sprintf (op->buf_asm, "illegal_ar");
}
return op->size = ptr - buf + 1;
case WS_OP_FLOW:
ptr = get_ws_next_token (ptr + 1, len - 1);
if (!ptr) { // evil
return op->size = 0;
}
switch (*ptr) {
case 10:
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
if (*ptr == 10) {
sprintf (op->buf_asm, "exit");
} else {
sprintf (op->buf_asm, "illegal_fl_lf");
}
return op->size = ptr - buf + 1;
case '\t':
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case 10:
sprintf (op->buf_asm, "ret");
return op->size = ptr - buf + 1;
case '\t':
sprintf (op->buf_asm, "jn");
break;
case ' ':
sprintf (op->buf_asm, "jz");
break;
}
ptr++;
if (-1 == test_ws_token_exist (ptr, 10, len - (ptr - buf))) {
op->buf_asm[0] = '\0';
return op->size = 0;
}
if (strlen (op->buf_asm) == 2) {
sprintf (&op->buf_asm[2], " %d", get_ws_val (ptr, len - (ptr - buf) - 1));
}
return op->size = ptr - buf + test_ws_token_exist (ptr, 10, len - (ptr - buf)) + 1;
case ' ':
ptr++;
ptr = get_ws_next_token (ptr, len - (ptr - buf));
if (!ptr) {
return op->size = 0;
}
switch (*ptr) {
case 10:
sprintf (op->buf_asm, "jmp");
break;
case '\t':
sprintf (op->buf_asm, "call");
break;
case ' ':
sprintf (op->buf_asm, "mark");
break;
}
ptr++;
if (-1 == test_ws_token_exist (ptr, 10, len - (ptr - buf))) {
op->buf_asm[0] = '\0';
return op->size = 0;
}
sprintf (&op->buf_asm[strlen (op->buf_asm)], " %d", get_ws_val (ptr, len - (ptr - buf) - 1));
return op->size = ptr - buf + test_ws_token_exist (ptr, 10, len - (ptr - buf)) + 1;
}
}
sprintf (op->buf_asm, "wtf");
return op->size = 0;
}