mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-22 23:31:26 +00:00
* Initial import of r_egg api
- Implements rarc2 as a library - Supports x86-32/64 and arm - WIP inline-egg like api * Add radiff2 -x to dump two column output
This commit is contained in:
parent
8e5fa68ec5
commit
26a070f5aa
2
TODO
2
TODO
@ -56,7 +56,7 @@ TODO
|
||||
|
||||
To wipe:
|
||||
========
|
||||
- Move mandpage from man/ to binr/*/?
|
||||
- Move manpages from man/ to binr/*/?
|
||||
- Move the content of libr/*/TODO here
|
||||
- linestyle?? for disassembly lines
|
||||
- remove libr/vm and libr/db
|
||||
|
@ -3,6 +3,15 @@
|
||||
#include <r_diff.h>
|
||||
#include <r_core.h>
|
||||
|
||||
enum {
|
||||
MODE_DIFF,
|
||||
MODE_DIST,
|
||||
MODE_LOCS,
|
||||
MODE_CODE,
|
||||
MODE_GRAPH,
|
||||
MODE_COLS
|
||||
};
|
||||
|
||||
static ut32 count = 0;
|
||||
static int useva = R_TRUE;
|
||||
|
||||
@ -85,7 +94,7 @@ static void diff_bins(RCore *c, RCore *c2) {
|
||||
}
|
||||
|
||||
static int show_help(int line) {
|
||||
printf ("Usage: radiff2 [-nsdl] [file] [file]\n");
|
||||
printf ("Usage: radiff2 [-cCdrspv] [-g sym] [file] [file]\n");
|
||||
if (!line) printf (
|
||||
// " -l diff lines of text\n"
|
||||
" -c count of changes\n"
|
||||
@ -99,13 +108,29 @@ static int show_help(int line) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum {
|
||||
MODE_DIFF,
|
||||
MODE_DIST,
|
||||
MODE_LOCS,
|
||||
MODE_CODE,
|
||||
MODE_GRAPH,
|
||||
};
|
||||
static void dump_cols (ut8 *a, int as, ut8 *b, int bs) {
|
||||
ut32 sz = R_MIN (as, bs);
|
||||
ut32 i, j;
|
||||
printf (" offset 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8\n");
|
||||
for (i=0; i<sz; i++) {
|
||||
char dch = (memcmp (a+i, b+i, 8))? ' ': '!';
|
||||
printf ("0x%08x%c ", i, dch);
|
||||
for (j=0; j<8; j++)
|
||||
printf ("%02x", a[i+j]);
|
||||
printf (" ");
|
||||
for (j=0; j<8; j++)
|
||||
printf ("%c", IS_PRINTABLE (a[i+j])?a[i+j]:'.');
|
||||
printf (" ");
|
||||
for (j=0; j<8; j++)
|
||||
printf ("%02x", b[i+j]);
|
||||
printf (" ");
|
||||
for (j=0; j<8; j++)
|
||||
printf ("%c", IS_PRINTABLE (b[i+j])? b[i+j]:'.');
|
||||
printf ("\n");
|
||||
}
|
||||
if (as != bs)
|
||||
printf ("...\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *addr = NULL;
|
||||
@ -117,7 +142,7 @@ int main(int argc, char **argv) {
|
||||
int showcount = 0, mode = MODE_DIFF;
|
||||
double sim;
|
||||
|
||||
while ((o = getopt (argc, argv, "Cpg:rhcdsv")) != -1) {
|
||||
while ((o = getopt (argc, argv, "Cpg:rhcdsvx")) != -1) {
|
||||
switch (o) {
|
||||
case 'p':
|
||||
useva = R_FALSE;
|
||||
@ -145,6 +170,9 @@ int main(int argc, char **argv) {
|
||||
case 's':
|
||||
mode = MODE_DIST;
|
||||
break;
|
||||
case 'x':
|
||||
mode = MODE_COLS;
|
||||
break;
|
||||
// case 'l':
|
||||
// mode = MODE_LOCS;
|
||||
// break;
|
||||
@ -186,6 +214,9 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case MODE_COLS:
|
||||
dump_cols (bufa, sza, bufb, szb);
|
||||
break;
|
||||
case MODE_DIFF:
|
||||
d = r_diff_new (0LL, 0LL);
|
||||
r_diff_set_delta (d, delta);
|
||||
|
@ -70,7 +70,21 @@ static int show_help() {
|
||||
//printf(" -P push file and remote execute\n");
|
||||
//printf(" -u use UDP\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int encode (const char *encoder, ut8 *dst, int dstlen, ut8 *src, int srclen) {
|
||||
if (!strcmp (encoder, "xor")) {
|
||||
// Find valid
|
||||
const ut8 *call_pop = "\xe8\xfb\xff\xff";
|
||||
const ut8 *pop_ebx = "\x5b";
|
||||
const ut8 *xor_ecx_ecx = "\x31\xc9";
|
||||
// decode:
|
||||
|
||||
// pop ebx
|
||||
} else {
|
||||
eprintf ("Encoders: xor\n");
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
char *filetostr(char *file) {
|
||||
@ -180,7 +194,11 @@ int print_shellcode() {
|
||||
/* patch addr and env */
|
||||
otf_patch ();
|
||||
|
||||
memcpy (output+A+N+E, shellcode, scsize);
|
||||
if (encoder) {
|
||||
ut8 blob[BLOCK]
|
||||
scsize = encode (encoder, blob, sizeof (blob), shellcode, scsize);
|
||||
memcpy (output+A+N+E, blob, scsize);
|
||||
} else memcpy (output+A+N+E, shellcode, scsize);
|
||||
for (i=0; i<C; i++)
|
||||
output[i+A+E+N+scsize] = '\xCC';
|
||||
|
||||
|
@ -9,7 +9,7 @@ PWD=`pwd`
|
||||
|
||||
# Libraries
|
||||
LIBLIST=util socket cons line lib io lang flags bin hash config syscall cmd
|
||||
LIBLIST+=reg asm diff anal print parse search bp sign debug fs core
|
||||
LIBLIST+=reg asm diff anal print parse search egg bp sign debug fs core
|
||||
#DEPRECATED APIS : LIBLIST+=th crypto
|
||||
# sysproxy ... common wat du?
|
||||
|
||||
|
8
libr/egg/Makefile
Normal file
8
libr/egg/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
NAME=r_egg
|
||||
DEPS=r_util r_asm
|
||||
OBJ=egg.o lang.o
|
||||
OBJ+=emit_x86.o
|
||||
OBJ+=emit_arm.o
|
||||
OBJ+=emit_x64.o
|
||||
|
||||
include ../rules.mk
|
176
libr/egg/egg.c
Normal file
176
libr/egg/egg.c
Normal file
@ -0,0 +1,176 @@
|
||||
/* radare - LGPL - Copyright 2011 pancake<@nopcode.org> */
|
||||
#include <r_egg.h>
|
||||
|
||||
extern REggEmit emit_x86;
|
||||
extern REggEmit emit_x64;
|
||||
extern REggEmit emit_arm;
|
||||
|
||||
R_API REgg *r_egg_new () {
|
||||
REgg *egg = R_NEW0 (REgg);
|
||||
egg->src = r_buf_new ();
|
||||
egg->buf = r_buf_new ();
|
||||
egg->bin = r_buf_new ();
|
||||
egg->emit = &emit_x86;
|
||||
egg->rasm = r_asm_new ();
|
||||
egg->bits = 0;
|
||||
egg->endian = 0;
|
||||
return egg;
|
||||
}
|
||||
|
||||
R_API char *r_egg_to_string (REgg *egg) {
|
||||
return strdup ((const char *)egg->buf->buf);
|
||||
}
|
||||
|
||||
R_API void r_egg_free (REgg *egg) {
|
||||
free (egg);
|
||||
}
|
||||
|
||||
R_API void r_egg_reset (REgg *egg) {
|
||||
// XXX: memory leak
|
||||
}
|
||||
|
||||
R_API int r_egg_setup(REgg *egg, const char *arch, int bits, int endian, const char *os) {
|
||||
egg->emit = NULL;
|
||||
// TODO: os ignored
|
||||
if (!strcmp (arch, "x86")) {
|
||||
switch (bits) {
|
||||
case 32:
|
||||
egg->emit = &emit_x86;
|
||||
egg->bits = bits;
|
||||
break;
|
||||
case 64:
|
||||
egg->emit = &emit_x64;
|
||||
egg->bits = bits;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
if (!strcmp (arch, "arm")) {
|
||||
switch (bits) {
|
||||
case 16:
|
||||
case 32:
|
||||
egg->emit = &emit_arm;
|
||||
egg->bits = bits;
|
||||
egg->endian = endian;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (egg->emit != NULL);
|
||||
}
|
||||
|
||||
R_API int r_egg_include(REgg *egg, const char *file, int format) {
|
||||
char *foo = r_file_slurp (file, NULL);
|
||||
if (!foo)
|
||||
return 0;
|
||||
switch (format) {
|
||||
case 'r': // raw
|
||||
// TODO: append ("\x102030202303203202", n);
|
||||
// TODO: r_buf_append_bytes (egg->buf, (const ut8*)foo, strlen (foo));
|
||||
break;
|
||||
case 'a': // assembly
|
||||
r_buf_append_bytes (egg->buf, (const ut8*)foo, strlen (foo));
|
||||
break;
|
||||
default:
|
||||
r_buf_append_bytes (egg->src, (const ut8*)foo, strlen (foo));
|
||||
}
|
||||
free (foo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
R_API void r_egg_load(REgg *egg, const char *code, int format) {
|
||||
switch (format) {
|
||||
case 'a': // assembly
|
||||
r_buf_append_bytes (egg->buf, (const ut8*)code, strlen (code));
|
||||
break;
|
||||
default:
|
||||
r_buf_append_bytes (egg->src, (const ut8*)code, strlen (code));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
R_API void r_egg_syscall(REgg *egg, const char *arg, ...) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
R_API void r_egg_alloc(REgg *egg, int n) {
|
||||
// add esp, n
|
||||
}
|
||||
|
||||
R_API REggLabel *r_egg_label(REgg *egg, const char *name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
R_API void r_egg_raw(REgg *egg, const ut8 *b, int len) {
|
||||
}
|
||||
|
||||
R_API void r_egg_if(REgg *egg, const char *reg, char cmp, int v) {
|
||||
}
|
||||
|
||||
R_API void r_egg_printf(REgg *egg, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
int len;
|
||||
char buf[1024];
|
||||
va_start (ap, fmt);
|
||||
len = vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
r_buf_append_bytes (egg->buf, (const ut8*)buf, len);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
R_API int r_egg_compile(REgg *egg) {
|
||||
const char *b = (const char *)egg->src->buf;
|
||||
if (!b || !egg->emit)
|
||||
return R_FALSE;
|
||||
for (;*b;b++) {
|
||||
r_egg_lang_parsechar (egg, *b);
|
||||
}
|
||||
// TODO: call r_asm
|
||||
if (egg->emit == &emit_x86) {
|
||||
RAsmCode *asmcode;
|
||||
char *code;
|
||||
//rasm2
|
||||
r_asm_use (egg->rasm, "x86.olly");
|
||||
r_asm_set_bits (egg->rasm, egg->bits);
|
||||
r_asm_set_big_endian (egg->rasm, 0);
|
||||
r_asm_set_syntax (egg->rasm, R_ASM_SYNTAX_INTEL);
|
||||
|
||||
code = r_buf_to_string (egg->buf);
|
||||
asmcode = r_asm_massemble (egg->rasm, code);
|
||||
if (asmcode) {
|
||||
r_buf_append_bytes (egg->bin, asmcode->buf, asmcode->len);
|
||||
// LEAK r_asm_code_free (asmcode);
|
||||
}
|
||||
free (code);
|
||||
return (asmcode != NULL);
|
||||
} else
|
||||
if (egg->emit == &emit_arm) {
|
||||
RAsmCode *asmcode;
|
||||
char *code;
|
||||
//rasm2
|
||||
r_asm_use (egg->rasm, "arm");
|
||||
r_asm_set_bits (egg->rasm, egg->bits);
|
||||
r_asm_set_big_endian (egg->rasm, egg->endian); // XXX
|
||||
r_asm_set_syntax (egg->rasm, R_ASM_SYNTAX_INTEL);
|
||||
|
||||
code = r_buf_to_string (egg->buf);
|
||||
asmcode = r_asm_massemble (egg->rasm, code);
|
||||
r_buf_append_bytes (egg->bin, asmcode->buf, asmcode->len);
|
||||
// LEAK r_asm_code_free (asmcode);
|
||||
free (code);
|
||||
return R_TRUE;
|
||||
}
|
||||
return R_FALSE;
|
||||
}
|
||||
|
||||
R_API RBuffer *r_egg_get_bin(REgg *egg) {
|
||||
// TODO increment reference
|
||||
return egg->bin;
|
||||
}
|
||||
|
||||
//R_API int r_egg_dump (REgg *egg, const char *file) { }
|
||||
|
||||
R_API char *r_egg_get_source(REgg *egg) {
|
||||
return r_buf_to_string (egg->src);
|
||||
}
|
||||
|
||||
R_API char *r_egg_get_assembly(REgg *egg) {
|
||||
return r_buf_to_string (egg->buf);
|
||||
}
|
255
libr/egg/emit_arm.c
Normal file
255
libr/egg/emit_arm.c
Normal file
@ -0,0 +1,255 @@
|
||||
/* pancake // nopcode.org 2010-2011 -- arm emiter */
|
||||
|
||||
#include <r_egg.h>
|
||||
#define attsyntax 0
|
||||
|
||||
#define EMIT_NAME emit_arm
|
||||
#define R_ARCH "arm"
|
||||
#define R_SZ 8
|
||||
#define R_SP "sp"
|
||||
#define R_BP "fp"
|
||||
#define R_AX "r0"
|
||||
#define R_GP { "r0", "r1", "r2", "r3", "r4" }
|
||||
#define R_TMP "r9"
|
||||
#define R_NGP 5
|
||||
|
||||
// no attsyntax for arm
|
||||
static char *regs[] = R_GP;
|
||||
static int lastarg = 0;
|
||||
static char lastargs[16][32];
|
||||
|
||||
static char *emit_syscall (REgg *egg, int num) {
|
||||
return strdup (": mov "R_AX", `.arg`\n: svc 0x8000\n");
|
||||
}
|
||||
|
||||
static void emit_frame (REgg *egg, int sz) {
|
||||
r_egg_printf (egg, " push {fp,lr}\n");
|
||||
if (sz>0) r_egg_printf (egg,
|
||||
//" mov "R_BP", "R_SP"\n"
|
||||
" add fp, sp, $4\n" // size of arguments
|
||||
" sub sp, $%d\n", sz); // size of stackframe 8, 16, ..
|
||||
}
|
||||
|
||||
static void emit_frame_end (REgg *egg, int sz, int ctx) {
|
||||
if (sz>0) r_egg_printf (egg, " add sp, fp, $%d\n", sz);
|
||||
if (ctx>0) r_egg_printf (egg, " pop {fp,pc}\n");
|
||||
}
|
||||
|
||||
static void emit_comment(REgg *egg, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
va_start (ap, fmt);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
r_egg_printf (egg, "# %s\n", buf);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
static void emit_equ (REgg *egg, const char *key, const char *value) {
|
||||
r_egg_printf (egg, ".equ %s,%s\n", key, value);
|
||||
}
|
||||
|
||||
static void emit_syscall_args(REgg *egg, int nargs) {
|
||||
int j, k;
|
||||
for (j=0; j<nargs; j++) {
|
||||
k = j*R_SZ;
|
||||
r_egg_printf (egg, " ldr %s, [sp, #%c%d]\n", regs[j+1], k>0?'+':' ', k);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_set_string(REgg *egg, const char *dstvar, const char *str, int j) {
|
||||
int rest, off = 0;
|
||||
off = strlen (str)+1;
|
||||
rest = (off%4);
|
||||
if (rest) rest = 4-rest;
|
||||
off += rest-8;
|
||||
r_egg_printf (egg, " add pc, $%d\n", (off));
|
||||
// XXX: does not handle \n and so on.. must use r_util
|
||||
r_egg_printf (egg, ".string \"%s\"\n", str);
|
||||
if (rest) r_egg_printf (egg, ".fill %d, 1, 0\n", (rest));
|
||||
r_egg_printf (egg, " sub r0, pc, $%d\n", off+16);
|
||||
{
|
||||
char str[32], *p = r_egg_mkvar (egg, str, dstvar, 0);
|
||||
//r_egg_printf (egg, "DSTVAR=%s --> %s\n", dstvar, p);
|
||||
r_egg_printf (egg, " str r0, [%s]\n", p);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_call(REgg *egg, const char *str, int atr) {
|
||||
int i;
|
||||
//r_egg_printf (egg, " ARGS=%d CALL(%s,%d)\n", lastarg, str, atr);
|
||||
for (i=0;i<lastarg;i++) {
|
||||
r_egg_printf (egg, " ldr r%d, [%s]\n", lastarg-1-i, lastargs[i]);
|
||||
lastargs[i][0] = 0;
|
||||
}
|
||||
|
||||
if (atr) {
|
||||
r_egg_printf (egg, " ldr r0, %s", str);
|
||||
r_egg_printf (egg, " blx r0\n");
|
||||
} else r_egg_printf (egg, " bl %s\n", str);
|
||||
}
|
||||
|
||||
static void emit_arg (REgg *egg, int xs, int num, const char *str) {
|
||||
int d = atoi (str);
|
||||
if (!attsyntax && (*str=='$'))
|
||||
str++;
|
||||
lastarg = num;
|
||||
switch (xs) {
|
||||
case 0:
|
||||
if (strchr(str, ',')) {
|
||||
//r_egg_printf (egg, ". str r0, [%s]\n", str);
|
||||
strncpy (lastargs[num-1], str, sizeof(lastargs[0]));
|
||||
} else {
|
||||
if (!atoi (str)) eprintf ("WARNING: probably a bug?\n");
|
||||
r_egg_printf (egg, " mov r0, $%s\n", str);
|
||||
snprintf( lastargs[num-1], sizeof (lastargs[0]), "fp, $-%d", 8+(num*4));
|
||||
r_egg_printf (egg, " str r0, [%s]\n", lastargs[num-1]);
|
||||
}
|
||||
break;
|
||||
case '*':
|
||||
r_egg_printf (egg, " push {%s}\n", str);
|
||||
break;
|
||||
case '&':
|
||||
if (d) r_egg_printf (egg, " add "R_BP", %d\n", d);
|
||||
r_egg_printf (egg, " push {"R_BP"}\n");
|
||||
if (d) r_egg_printf (egg, " sub "R_BP", %d\n", d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_get_result(REgg *egg, const char *ocn) {
|
||||
r_egg_printf (egg, " mov %s, r0\n", ocn);
|
||||
}
|
||||
|
||||
static void emit_restore_stack (REgg *egg, int size) {
|
||||
// XXX: must die.. or add emit_store_stack. not needed by ARM
|
||||
// r_egg_printf (egg, " add sp, %d\n", size);
|
||||
}
|
||||
|
||||
static void emit_get_while_end (REgg *egg, char *str, const char *ctxpush, const char *label) {
|
||||
sprintf (str, " push {%s}\n b %s\n", ctxpush, label);
|
||||
}
|
||||
|
||||
static void emit_while_end (REgg *egg, const char *labelback) {
|
||||
r_egg_printf (egg,
|
||||
" pop "R_AX"\n"
|
||||
" cmp "R_AX", "R_AX"\n" // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
" beq %s\n", labelback);
|
||||
}
|
||||
|
||||
static void emit_get_var (REgg *egg, int type, char *out, int idx) {
|
||||
switch (type) {
|
||||
case 0: sprintf (out, "fp,$%d", -idx); break; /* variable */
|
||||
case 1: sprintf (out, "sp,$%d", idx); break; /* argument */ // XXX: MUST BE r0, r1, r2, ..
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_trap (REgg *egg) {
|
||||
r_egg_printf (egg, " svc 3\n");
|
||||
}
|
||||
|
||||
static void emit_load_ptr(REgg *egg, const char *dst) {
|
||||
r_egg_printf (egg, " ldr r0, [fp, %d]\n", atoi (dst));
|
||||
}
|
||||
|
||||
static void emit_branch(REgg *egg, char *b, char *g, char *e, char *n, int sz, const char *dst) {
|
||||
char *p, str[64];
|
||||
char *arg = NULL;
|
||||
char *op = "beq";
|
||||
/* NOTE that jb/ja are inverted to fit cmp opcode */
|
||||
if (b) {
|
||||
*b = '\0';
|
||||
op = e?"bge":"bgt";
|
||||
arg = b+1;
|
||||
} else
|
||||
if (g) {
|
||||
*g = '\0';
|
||||
op = e?"ble":"blt";
|
||||
arg = g+1;
|
||||
}
|
||||
if (arg == NULL) {
|
||||
if (e) {
|
||||
arg = e+1;
|
||||
op = "bne";
|
||||
} else {
|
||||
arg = "0";
|
||||
op = n?"bne":"beq";
|
||||
}
|
||||
}
|
||||
|
||||
if (*arg=='=') arg++; /* for <=, >=, ... */
|
||||
p = r_egg_mkvar (egg, str, arg, 0);
|
||||
r_egg_printf (egg, " pop "R_AX"\n"); /* TODO: add support for more than one arg get arg0 */
|
||||
r_egg_printf (egg, " cmp %s, "R_AX"\n", p);
|
||||
// if (context>0)
|
||||
r_egg_printf (egg, " %s %s\n", op, dst);
|
||||
}
|
||||
|
||||
static void emit_load(REgg *egg, const char *dst, int sz) {
|
||||
switch (sz) {
|
||||
case 'l':
|
||||
r_egg_printf (egg, " mov "R_AX", %s\n", dst);
|
||||
r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n");
|
||||
case 'b':
|
||||
r_egg_printf (egg, " mov "R_AX", %s\n", dst);
|
||||
r_egg_printf (egg, " movz "R_AX", ["R_AX"]\n");
|
||||
break;
|
||||
default:
|
||||
// TODO: unhandled?!?
|
||||
r_egg_printf (egg, " mov "R_AX", %s\n", dst);
|
||||
r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_mathop(REgg *egg, int ch, int vs, int type, const char *eq, const char *p) {
|
||||
char *op;
|
||||
switch (ch) {
|
||||
case '^': op = "eor"; break;
|
||||
case '&': op = "and"; break;
|
||||
case '|': op = "orr"; break;
|
||||
case '-': op = "sub"; break;
|
||||
case '+': op = "add"; break;
|
||||
case '*': op = "mul"; break;
|
||||
case '/': op = "div"; break;
|
||||
default: op = "mov"; break;
|
||||
}
|
||||
if (eq == NULL) eq = R_AX;
|
||||
if (p == NULL) p = R_AX;
|
||||
#if 0
|
||||
// TODO:
|
||||
eprintf ("TYPE = %c\n", type);
|
||||
eprintf (" %s%c %c%s, %s\n", op, vs, type, eq, p);
|
||||
eprintf (" %s %s, [%s]\n", op, p, eq);
|
||||
#endif
|
||||
if (type == '*') r_egg_printf (egg, " %s %s, [%s]\n", op, p, eq);
|
||||
else r_egg_printf (egg, " %s %s, %s\n", op, p, eq);
|
||||
}
|
||||
|
||||
static const char* emit_regs(REgg *egg, int idx) {
|
||||
return regs[idx%R_NGP];
|
||||
}
|
||||
|
||||
REggEmit EMIT_NAME = {
|
||||
.arch = R_ARCH,
|
||||
.size = R_SZ,
|
||||
.call = emit_call,
|
||||
.equ = emit_equ,
|
||||
.regs = emit_regs,
|
||||
//.sc = emit_sc,
|
||||
.trap = emit_trap,
|
||||
.frame = emit_frame,
|
||||
.frame_end = emit_frame_end,
|
||||
.comment = emit_comment,
|
||||
.push_arg = emit_arg,
|
||||
.restore_stack = emit_restore_stack,
|
||||
.get_result = emit_get_result,
|
||||
.syscall_args = emit_syscall_args,
|
||||
.set_string = emit_set_string,
|
||||
.get_var = emit_get_var,
|
||||
.while_end = emit_while_end,
|
||||
.get_while_end = emit_get_while_end,
|
||||
.branch = emit_branch,
|
||||
.load = emit_load,
|
||||
.load_ptr = emit_load_ptr,
|
||||
.mathop = emit_mathop,
|
||||
.syscall = emit_syscall,
|
||||
};
|
4
libr/egg/emit_x64.c
Normal file
4
libr/egg/emit_x64.c
Normal file
@ -0,0 +1,4 @@
|
||||
/* pancake // nopcode.org 2010 -- emit module for rcc */
|
||||
|
||||
#define ARCH_X86_64 1
|
||||
#include "emit_x86.c"
|
324
libr/egg/emit_x86.c
Normal file
324
libr/egg/emit_x86.c
Normal file
@ -0,0 +1,324 @@
|
||||
/* pancake // nopcode.org 2010-2011 -- emit module for rcc */
|
||||
|
||||
#include <r_egg.h>
|
||||
|
||||
/* hardcoded */
|
||||
#define attsyntax 0
|
||||
|
||||
#ifdef ARCH_X86_64
|
||||
# define EMIT_NAME emit_x64
|
||||
# define R_ARCH "x64"
|
||||
# define R_SZ 8
|
||||
# define R_SP "rsp"
|
||||
# define R_BP "rbp"
|
||||
# define R_AX "rax"
|
||||
# define R_GP { "rax", "rbx", "rsi", "rdx" }
|
||||
# define R_NGP 4
|
||||
#else
|
||||
# define EMIT_NAME emit_x86
|
||||
# define R_ARCH "x86"
|
||||
# define R_SZ 4
|
||||
# define R_SP "esp"
|
||||
# define R_BP "ebp"
|
||||
# define R_AX "eax"
|
||||
# define R_GP { "eax", "ebx", "ecx", "edx" }
|
||||
# define R_NGP 4
|
||||
#endif
|
||||
|
||||
static char *regs[] = R_GP;
|
||||
|
||||
static char *emit_syscall (REgg *egg, int num) {
|
||||
if (attsyntax) return strdup (": mov $`.arg`, %"R_AX"\n: int $0x80\n");
|
||||
return strdup (": mov "R_AX", `.arg`\n: int 0x80\n");
|
||||
}
|
||||
|
||||
static void emit_frame (REgg *egg, int sz) {
|
||||
if (sz>0) {
|
||||
if (attsyntax)
|
||||
r_egg_printf (egg,
|
||||
" push %%"R_BP"\n"
|
||||
" mov %%"R_SP", %%"R_BP"\n"
|
||||
" sub $%d, %%"R_SP"\n", sz);
|
||||
else r_egg_printf (egg,
|
||||
" push "R_BP"\n"
|
||||
" mov "R_BP", "R_SP"\n"
|
||||
" sub "R_SP", %d\n", sz);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_frame_end (REgg *egg, int sz, int ctx) {
|
||||
if (sz>0) {
|
||||
if (attsyntax) {
|
||||
r_egg_printf (egg, " add $%d, %%"R_SP"\n", sz);
|
||||
r_egg_printf (egg, " pop %%"R_BP"\n");
|
||||
} else {
|
||||
r_egg_printf (egg, " add "R_SP", %d\n", sz);
|
||||
r_egg_printf (egg, " pop "R_BP"\n");
|
||||
}
|
||||
}
|
||||
if (ctx>0)
|
||||
r_egg_printf (egg, " ret\n");
|
||||
}
|
||||
|
||||
static void emit_comment(REgg *egg, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
char buf[1024];
|
||||
va_start (ap, fmt);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
if (attsyntax) r_egg_printf (egg, " /* %s */\n", buf);
|
||||
else r_egg_printf (egg, "# %s\n", buf);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
static void emit_equ (REgg *egg, const char *key, const char *value) {
|
||||
r_egg_printf (egg, ".equ %s,%s\n", key, value);
|
||||
}
|
||||
|
||||
static void emit_syscall_args(REgg *egg, int nargs) {
|
||||
int j, k;
|
||||
for (j=0; j<nargs; j++) {
|
||||
k = j*R_SZ;
|
||||
if (attsyntax)
|
||||
r_egg_printf (egg, " mov %d(%%"R_SP"), %%%s\n", k, regs[j+1]);
|
||||
else
|
||||
r_egg_printf (egg, " mov %s, dword ptr ["R_SP"%c%d]\n", regs[j+1], k>0?'+':' ', k);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_set_string(REgg *egg, const char *dstvar, const char *str, int j) {
|
||||
char *p, str2[64];
|
||||
int i, oj = j;
|
||||
for (i=0; i<oj; i+=4) {
|
||||
/* XXX endian and 32/64bit issues */
|
||||
int *n = (int *)(str+i);
|
||||
p = r_egg_mkvar (egg, str2, dstvar, j);
|
||||
if (attsyntax) r_egg_printf (egg, " movl $0x%x, %s\n", *n, p);
|
||||
else r_egg_printf (egg, " mov %s, 0x%x\n", p, *n);
|
||||
j -= 4;
|
||||
}
|
||||
p = r_egg_mkvar (egg, str2, dstvar, oj);
|
||||
if (attsyntax) r_egg_printf (egg, " lea %s, %%"R_AX"\n", p);
|
||||
else r_egg_printf (egg, " lea "R_AX", %s\n", p);
|
||||
p = r_egg_mkvar (egg, str2, dstvar, 0);
|
||||
if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", p);
|
||||
else r_egg_printf (egg, " mov %s, "R_AX"\n", p);
|
||||
}
|
||||
|
||||
static void emit_call(REgg *egg, const char *str, int atr) {
|
||||
if (atr) {
|
||||
if (attsyntax) r_egg_printf (egg, " call *%s\n", str);
|
||||
else r_egg_printf (egg, " call [%s]\n", str);
|
||||
} else r_egg_printf (egg, " call %s\n", str);
|
||||
}
|
||||
|
||||
static void emit_arg (REgg *egg, int xs, int num, const char *str) {
|
||||
int d = atoi (str);
|
||||
if (!attsyntax && (*str=='$'))
|
||||
str = str +1;
|
||||
switch (xs) {
|
||||
case 0:
|
||||
r_egg_printf (egg, " push %s\n", str);
|
||||
break;
|
||||
case '*':
|
||||
if (attsyntax) r_egg_printf (egg, " push (%s)\n", str);
|
||||
else r_egg_printf (egg, " push [%s]\n", str);
|
||||
break;
|
||||
case '&':
|
||||
if (attsyntax) {
|
||||
if (d != 0) r_egg_printf (egg, " addl $%d, %%"R_BP"\n", d);
|
||||
r_egg_printf (egg, " pushl %%"R_BP"\n");
|
||||
if (d != 0) r_egg_printf (egg, " subl $%d, %%"R_BP"\n", d);
|
||||
} else {
|
||||
if (d != 0) r_egg_printf (egg, " add "R_BP", %d\n", d);
|
||||
r_egg_printf (egg, " push "R_BP"\n");
|
||||
if (d != 0) r_egg_printf (egg, " sub "R_BP", %d\n", d);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_get_result(REgg *egg, const char *ocn) {
|
||||
if (attsyntax) r_egg_printf (egg, " mov %%"R_AX", %s\n", ocn);
|
||||
else r_egg_printf (egg, " mov %s, "R_AX"\n", ocn);
|
||||
}
|
||||
|
||||
static void emit_restore_stack (REgg *egg, int size) {
|
||||
if (attsyntax) r_egg_printf (egg, " add $%d, %%"R_SP" /* args */\n", size);
|
||||
else r_egg_printf (egg, " add "R_SP", %d\n", size);
|
||||
}
|
||||
|
||||
static void emit_get_while_end (REgg *egg, char *str, const char *ctxpush, const char *label) {
|
||||
if (attsyntax) sprintf (str, " push %s\n jmp %s /* ---- */\n", ctxpush, label);
|
||||
else sprintf (str, " push %s\n jmp %s\n", ctxpush, label);
|
||||
}
|
||||
|
||||
static void emit_while_end (REgg *egg, const char *labelback) {
|
||||
if (attsyntax) {
|
||||
r_egg_printf (egg, " pop %%"R_AX"\n");
|
||||
r_egg_printf (egg, " cmp $0, %%"R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
r_egg_printf (egg, " jnz %s\n", labelback);
|
||||
} else {
|
||||
r_egg_printf (egg, " pop "R_AX"\n");
|
||||
r_egg_printf (egg, " test "R_AX", "R_AX"\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
r_egg_printf (egg, " jnz %s\n", labelback);
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_get_var (REgg *egg, int type, char *out, int idx) {
|
||||
if (attsyntax) {
|
||||
switch (type) {
|
||||
case 0: sprintf (out, "%d(%%"R_BP")", -idx); break; /* variable */
|
||||
case 1: sprintf(out, "%d(%%"R_SP")", idx); break; /* argument */
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case 0: sprintf (out, "dword ptr ["R_BP"%c%d]", idx>0?' ':'+', -idx); break; /* variable */
|
||||
case 1: sprintf(out, "dword ptr ["R_SP"%c%d]", idx>0?'+':' ', idx); break; /* argument */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_trap (REgg *egg) {
|
||||
r_egg_printf (egg, " int3\n");
|
||||
}
|
||||
|
||||
static void emit_load_ptr(REgg *egg, const char *dst) {
|
||||
int d = atoi (dst);
|
||||
//eprintf ("emit_load_ptr: HACK\n");
|
||||
// XXX: 32/64bit care
|
||||
if (attsyntax) r_egg_printf (egg, " leal %d(%%"R_BP"), %%"R_AX"\n", d);
|
||||
else r_egg_printf (egg, " leal "R_AX", dword ptr ["R_BP"+%d]\n", d);
|
||||
//r_egg_printf (egg, " movl %%"R_BP", %%"R_AX"\n");
|
||||
//r_egg_printf (egg, " addl $%d, %%"R_AX"\n", d);
|
||||
}
|
||||
|
||||
static void emit_branch(REgg *egg, char *b, char *g, char *e, char *n, int sz, const char *dst) {
|
||||
char *p, str[64];
|
||||
char *arg = NULL;
|
||||
char *op = "jz";
|
||||
/* NOTE that jb/ja are inverted to fit cmp opcode */
|
||||
if (b) {
|
||||
*b = '\0';
|
||||
if (e) op = "jae";
|
||||
else op = "ja";
|
||||
arg = b+1;
|
||||
} else
|
||||
if (g) {
|
||||
*g = '\0';
|
||||
if (e) op = "jbe";
|
||||
else op = "jb";
|
||||
arg = g+1;
|
||||
}
|
||||
if (arg == NULL) {
|
||||
if (e) {
|
||||
arg = e+1;
|
||||
op = "jne";
|
||||
} else {
|
||||
arg = "$0";
|
||||
if (n) op = "jnz";
|
||||
else op ="jz";
|
||||
}
|
||||
}
|
||||
|
||||
if (*arg=='=') arg++; /* for <=, >=, ... */
|
||||
p = r_egg_mkvar (egg, str, arg, 0);
|
||||
if (attsyntax) {
|
||||
r_egg_printf (egg, " pop %%"R_AX"\n"); /* TODO: add support for more than one arg get arg0 */
|
||||
r_egg_printf (egg, " cmp%c %s, %%"R_AX"\n", sz, p);
|
||||
} else {
|
||||
r_egg_printf (egg, " pop "R_AX"\n"); /* TODO: add support for more than one arg get arg0 */
|
||||
r_egg_printf (egg, " cmp %s, "R_AX"\n", p);
|
||||
}
|
||||
// if (context>0)
|
||||
r_egg_printf (egg, " %s %s\n", op, dst);
|
||||
}
|
||||
|
||||
static void emit_load(REgg *egg, const char *dst, int sz) {
|
||||
if (attsyntax) {
|
||||
switch (sz) {
|
||||
case 'l':
|
||||
r_egg_printf (egg, " movl %s, %%"R_AX"\n", dst);
|
||||
r_egg_printf (egg, " movl (%%"R_AX"), %%"R_AX"\n");
|
||||
case 'b':
|
||||
r_egg_printf (egg, " movl %s, %%"R_AX"\n", dst);
|
||||
r_egg_printf (egg, " movzb (%%"R_AX"), %%"R_AX"\n");
|
||||
break;
|
||||
default:
|
||||
// TODO: unhandled?!?
|
||||
r_egg_printf (egg, " mov%c %s, %%"R_AX"\n", sz, dst);
|
||||
r_egg_printf (egg, " mov%c (%%"R_AX"), %%"R_AX"\n", sz);
|
||||
}
|
||||
} else {
|
||||
switch (sz) {
|
||||
case 'l':
|
||||
r_egg_printf (egg, " mov "R_AX", %s\n", dst);
|
||||
r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n");
|
||||
case 'b':
|
||||
r_egg_printf (egg, " mov "R_AX", %s\n", dst);
|
||||
r_egg_printf (egg, " movz "R_AX", ["R_AX"]\n");
|
||||
break;
|
||||
default:
|
||||
// TODO: unhandled?!?
|
||||
r_egg_printf (egg, " mov "R_AX", %s\n", dst);
|
||||
r_egg_printf (egg, " mov "R_AX", ["R_AX"]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_mathop(REgg *egg, int ch, int vs, int type, const char *eq, const char *p) {
|
||||
char *op;
|
||||
switch(ch) {
|
||||
case '^': op = "xor"; break;
|
||||
case '&': op = "and"; break;
|
||||
case '|': op = "or"; break;
|
||||
case '-': op = "sub"; break;
|
||||
case '+': op = "add"; break;
|
||||
case '*': op = "mul"; break;
|
||||
case '/': op = "div"; break;
|
||||
default: op = "mov"; break;
|
||||
}
|
||||
if (attsyntax) {
|
||||
if (eq == NULL) eq = "%"R_AX;
|
||||
if (p == NULL) p = "%"R_AX;
|
||||
r_egg_printf (egg, " %s%c %c%s, %s\n", op, vs, type, eq, p);
|
||||
} else {
|
||||
if (eq == NULL) eq = R_AX;
|
||||
if (p == NULL) p = R_AX;
|
||||
// TODO:
|
||||
eprintf ("TYPE = %c\n", type);
|
||||
eprintf (" %s%c %c%s, %s\n", op, vs, type, eq, p);
|
||||
eprintf (" %s %s, [%s]\n", op, p, eq);
|
||||
if (type == '*') r_egg_printf (egg, " %s %s, [%s]\n", op, p, eq);
|
||||
else r_egg_printf (egg, " %s %s, %s\n", op, p, eq);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* emit_regs(REgg *egg, int idx) {
|
||||
return regs[idx%R_NGP];
|
||||
}
|
||||
|
||||
REggEmit EMIT_NAME = {
|
||||
.arch = R_ARCH,
|
||||
.size = R_SZ,
|
||||
.call = emit_call,
|
||||
.equ = emit_equ,
|
||||
.regs = emit_regs,
|
||||
//.sc = emit_sc,
|
||||
.trap = emit_trap,
|
||||
.frame = emit_frame,
|
||||
.frame_end = emit_frame_end,
|
||||
.comment = emit_comment,
|
||||
.push_arg = emit_arg,
|
||||
.restore_stack = emit_restore_stack,
|
||||
.get_result = emit_get_result,
|
||||
.syscall_args = emit_syscall_args,
|
||||
.set_string = emit_set_string,
|
||||
.get_var = emit_get_var,
|
||||
.while_end = emit_while_end,
|
||||
.get_while_end = emit_get_while_end,
|
||||
.branch = emit_branch,
|
||||
.load = emit_load,
|
||||
.load_ptr = emit_load_ptr,
|
||||
.mathop = emit_mathop,
|
||||
.syscall = emit_syscall,
|
||||
};
|
707
libr/egg/lang.c
Normal file
707
libr/egg/lang.c
Normal file
@ -0,0 +1,707 @@
|
||||
/* radare - LGPL - Copyright 2011 pancake<@nopcode.org> */
|
||||
|
||||
#include <r_egg.h>
|
||||
|
||||
#define isspace(x) IS_WHITESPACE(x)
|
||||
#define IS_VAR(x) (x[0]=='.'||((x[0]=='*'||x[0]=='&')&&x[1]=='.'))
|
||||
|
||||
static void rcc_pushstr(REgg *egg, char *str, int filter);
|
||||
static void rcc_context(REgg *egg, int delta);
|
||||
static struct {
|
||||
char *name;
|
||||
char *body;
|
||||
//int fastcall; /* TODO: NOT YET USED */
|
||||
} inlines[256];
|
||||
static int ninlines = 0;
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
char *arg;
|
||||
//int sysnum; /* TODO: NOT YET USED */
|
||||
} syscalls[256];
|
||||
|
||||
enum {
|
||||
NORMAL = 0,
|
||||
ALIAS,
|
||||
DATA,
|
||||
INLINE,
|
||||
SYSCALL,
|
||||
SYSCALLBODY,
|
||||
LAST
|
||||
};
|
||||
// XXX
|
||||
static int nsyscalls = 0;
|
||||
static char *syscallbody = NULL;
|
||||
static int commentmode = 0;
|
||||
static int varsize = 'l';
|
||||
static int varxs = 0;
|
||||
static int lastctxdelta = 0;
|
||||
static int nargs = 0;
|
||||
static int docall = 1; /* do call or inline it ? */ // BOOL
|
||||
static int nfunctions = 0;
|
||||
static int nbrackets = 0;
|
||||
static int slurpin = 0;
|
||||
static int slurp = 0;
|
||||
static int line = 1;
|
||||
static char elem[1024];
|
||||
int attsyntax = 0;
|
||||
static int elem_n = 0;
|
||||
static int context = 0;
|
||||
static char *callname = NULL;
|
||||
static char *endframe = NULL;
|
||||
static char *ctxpush[32];
|
||||
static char *file = "stdin";
|
||||
static char *dstvar = NULL;
|
||||
static char *dstval = NULL;
|
||||
static int ndstval = 0;
|
||||
static int skipline = 0; // BOOL
|
||||
static int quoteline = 0;
|
||||
static int quotelinevar = 0;
|
||||
static int stackframe = 0;
|
||||
static int stackfixed = 0;
|
||||
static int oc = '\n';
|
||||
static int mode = NORMAL;
|
||||
|
||||
#define SYNTAX_ATT 0
|
||||
#if SYNTAX_ATT
|
||||
#define FRAME_FMT ".LC%d_%d_frame%d"
|
||||
#define FRAME_END_FMT ".LC%d_%d_end_frame%d"
|
||||
#else
|
||||
#define FRAME_FMT "__%d_%d_frame%d"
|
||||
#define FRAME_END_FMT "__%d_%d_end_frame%d"
|
||||
#endif
|
||||
|
||||
static char *get_frame_label(int type) {
|
||||
static char label[128];
|
||||
int nf = nfunctions;
|
||||
int nb = nbrackets;
|
||||
int ct = context;
|
||||
/* TODO: this type hack to substruct nb and ctx looks weird */
|
||||
if (type == 1) nb--; else
|
||||
if (type == 2) ct--;
|
||||
/* THIS IS GAS_ONLY */
|
||||
snprintf (label, sizeof (label), FRAME_FMT, nf, nb, ct);
|
||||
return label;
|
||||
}
|
||||
|
||||
static char *get_end_frame_label(REgg *egg) {
|
||||
static char label[128];
|
||||
/* THIS IS GAS_ONLY */
|
||||
snprintf (label, sizeof (label), FRAME_END_FMT,
|
||||
nfunctions, nbrackets, context-1);
|
||||
return label;
|
||||
}
|
||||
|
||||
static void rcc_pusharg(REgg *egg, char *str) {
|
||||
REggEmit *e = egg->emit;
|
||||
char buf[64], *p = r_egg_mkvar (egg, buf, str, 0);
|
||||
ctxpush[context] = strdup (p); // INDEX IT WITH NARGS OR CONTEXT?!?
|
||||
nargs++;
|
||||
e->push_arg (egg, varxs, nargs, p);
|
||||
//ctxpush[context+nbrackets] = strdup(str); // use nargs??? (in callname)
|
||||
}
|
||||
|
||||
static void rcc_element(REgg *egg, char *str) {
|
||||
REggEmit *e = egg->emit;
|
||||
char *p = strrchr (str, ',');
|
||||
int num, num2;
|
||||
|
||||
if (context) {
|
||||
nargs = 0;
|
||||
while (p) {
|
||||
*p = '\0';
|
||||
for (p=p+1; *p==' '; p=p+1);
|
||||
rcc_pusharg (egg, p);
|
||||
p = strrchr (str, ',');
|
||||
}
|
||||
if (callname)
|
||||
rcc_pusharg (egg, str);
|
||||
else
|
||||
if (mode == NORMAL) {
|
||||
if (!atoi (str)) {
|
||||
if (dstvar == NULL) /* return string */
|
||||
dstvar = strdup (".fix0");
|
||||
rcc_pushstr (egg, str, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (mode) {
|
||||
case ALIAS:
|
||||
e->equ (egg, dstvar, str);
|
||||
R_FREE (dstvar);
|
||||
mode = NORMAL;
|
||||
break;
|
||||
case SYSCALL:
|
||||
syscalls[nsyscalls].name = strdup (dstvar);
|
||||
syscalls[nsyscalls].arg = strdup (str);
|
||||
nsyscalls++;
|
||||
R_FREE (dstvar);
|
||||
break;
|
||||
default:
|
||||
p = strchr (str, ',');
|
||||
if (p) {
|
||||
*p='\0';
|
||||
num2 = atoi (p+1);
|
||||
} else num2 = 0;
|
||||
num = atoi (str) + num2;
|
||||
stackframe = num;
|
||||
stackfixed = num2;
|
||||
e->frame (egg, stackframe+stackfixed);
|
||||
}
|
||||
elem[0] = 0;
|
||||
elem_n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void rcc_pushstr(REgg *egg, char *str, int filter) {
|
||||
int dotrim = 1;
|
||||
int i, j, len;
|
||||
REggEmit *e = egg->emit;
|
||||
|
||||
e->comment (egg, "encode %s string (%s) (%s)",
|
||||
filter?"filtered":"unfiltered", str, callname);
|
||||
|
||||
if (filter)
|
||||
for (i=0; str[i]; i++) {
|
||||
if (str[i]=='\\') {
|
||||
switch (str[i+1]) {
|
||||
case 't': str[i]='\t'; break;
|
||||
case 'n': str[i]='\n'; break;
|
||||
case 'e': str[i]='\x1b'; break;
|
||||
default: dotrim = 0; break;
|
||||
}
|
||||
if (dotrim)
|
||||
memmove (str+i+1, str+i+2, strlen (str+i+2));
|
||||
}
|
||||
}
|
||||
|
||||
len = strlen (str);
|
||||
j = (len-len%e->size)+e->size;
|
||||
e->set_string (egg, dstvar, str, j);
|
||||
free (dstvar);
|
||||
dstvar = NULL;
|
||||
}
|
||||
|
||||
R_API char *r_egg_mkvar(REgg *egg, char *out, const char *_str, int delta) {
|
||||
int i, idx, len, qi;
|
||||
char *str, foo[32], *q, *ret;
|
||||
|
||||
delta += stackfixed; // XXX can be problematic
|
||||
if (_str == NULL)
|
||||
return NULL; /* fix segfault, but not badparsing */
|
||||
/* XXX memory leak */
|
||||
ret = str = strdup (_str);
|
||||
while (*str==' ') str++; /* skip spaces ...also tabs isspace()? */
|
||||
//if (num || str[0]=='0') { sprintf(out, "$%d", num); ret = out; }
|
||||
if ( (q = strchr (str, ':')) ) {
|
||||
*q = '\0';
|
||||
qi = atoi (q+1);
|
||||
varsize = (qi==1)? 'b':'l';
|
||||
} else varsize='l';
|
||||
if (*str=='*'||*str=='&') {
|
||||
varxs = *str;
|
||||
str++;
|
||||
} else varxs = 0;
|
||||
if (str[0]=='.') {
|
||||
REggEmit *e = egg->emit;
|
||||
ret = out;
|
||||
idx = atoi (str+4) + delta + e->size;
|
||||
if (!memcmp (str+1, "fix", 3)) {
|
||||
e->get_var (egg, 0, out, idx-stackfixed);
|
||||
//sprintf(out, "%d(%%"R_BP")", -(atoi(str+4)+delta+R_SZ-stackfixed));
|
||||
} else
|
||||
if (!memcmp (str+1, "var", 3)) {
|
||||
e->get_var (egg, 0, out, idx);
|
||||
//sprintf(out, "%d(%%"R_BP")", -(atoi(str+4)+delta+R_SZ));
|
||||
} else
|
||||
if (!memcmp (str+1, "arg", 3)) {
|
||||
if (str[4]) {
|
||||
if (stackframe == 0)
|
||||
e->get_var (egg, 1, out, idx);
|
||||
else {
|
||||
/* XXX: must simplify */
|
||||
if (docall)
|
||||
e->get_var (egg, 0, out,
|
||||
-(delta+e->size*2+(e->size*(atoi(str+4)))));
|
||||
else e->get_var (egg, 1, out,
|
||||
delta+(e->size*(atoi(str+4))));
|
||||
}
|
||||
} else {
|
||||
/* TODO: return size of syscall */
|
||||
if (callname==NULL) {
|
||||
eprintf ("NO CALLNAME'%s'\n", callname);
|
||||
} else {
|
||||
for (i=0; i<nsyscalls; i++)
|
||||
if (!strcmp (syscalls[i].name, callname))
|
||||
return syscalls[i].arg;
|
||||
eprintf ("Unknown arg for syscall '%s'\n", callname);
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (!memcmp (str+1, "reg", 3)) {
|
||||
// XXX: can overflow if out is small
|
||||
snprintf (out, 32, "%%%s", e->regs (egg, atoi (str+4)));
|
||||
} else {
|
||||
ret = str; /* TODO: show error, invalid var name? */
|
||||
eprintf ("FUCKED UP\n");
|
||||
}
|
||||
} else if (*str=='"' || *str=='\'') {
|
||||
int mustfilter = *str=='"';
|
||||
if (!stackfixed)
|
||||
eprintf ("WARNING: No room in the static stackframe!\n");
|
||||
/* TODO: check for room in stackfixed area */
|
||||
str++;
|
||||
len = strlen (str)-1;
|
||||
str[len]='\0';
|
||||
snprintf (foo, sizeof (foo)-1, ".fix%d", nargs*16); /* XXX FIX DELTA !!!1 */
|
||||
dstvar = strdup (foo);
|
||||
rcc_pushstr (egg, str, mustfilter);
|
||||
ret = r_egg_mkvar (egg, out, foo, 0);
|
||||
}
|
||||
//free ((void *)_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void rcc_fun(REgg *egg, char *str) {
|
||||
char *ptr, *ptr2;
|
||||
if (context) {
|
||||
ptr = strchr(str, '=');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
free (dstvar);
|
||||
dstvar = strdup (str);
|
||||
for (ptr2=ptr+1; isspace (*ptr2); ptr2++);
|
||||
if (*ptr2)
|
||||
callname = strdup (ptr+1);
|
||||
} else {
|
||||
egg->emit->comment (egg, "rcc_fun %d (%s)", context, str);
|
||||
free (callname);
|
||||
callname = strdup (str);
|
||||
}
|
||||
} else {
|
||||
ptr = strchr (str, '@');
|
||||
if (ptr) {
|
||||
ptr[0]='\0';
|
||||
mode = NORMAL;
|
||||
if (strstr (ptr+1, "fastcall")) {
|
||||
/* TODO : not yet implemented */
|
||||
} else
|
||||
if (strstr (ptr+1, "syscall")) {
|
||||
if (str[0]) {
|
||||
mode = SYSCALL;
|
||||
dstvar = strdup (str);
|
||||
} else {
|
||||
mode = INLINE;
|
||||
free (syscallbody);
|
||||
syscallbody = malloc (4096); // XXX hardcoded size
|
||||
dstval = syscallbody;
|
||||
R_FREE (dstvar);
|
||||
ndstval = 0;
|
||||
syscallbody[0] = '\0';
|
||||
}
|
||||
} else
|
||||
if (strstr(ptr+1, "alias")) {
|
||||
mode = ALIAS;
|
||||
dstvar = strdup (str);
|
||||
} else
|
||||
if (strstr(ptr+1, "data")) {
|
||||
mode = DATA;
|
||||
ndstval = 0;
|
||||
dstvar = strdup (str);
|
||||
dstval = malloc (4096);
|
||||
} else
|
||||
if (strstr (ptr+1, "inline")) {
|
||||
mode = INLINE;
|
||||
free (dstvar);
|
||||
dstvar = strdup (str);
|
||||
dstval = malloc (4096);
|
||||
ndstval = 0;
|
||||
} else r_egg_printf (egg, "\n.%s %s\n%s:\n", ptr+1, str, str);
|
||||
} else r_egg_printf (egg, "\n%s:\n", str);
|
||||
}
|
||||
}
|
||||
static void rcc_context(REgg *egg, int delta) {
|
||||
REggEmit *emit = egg->emit;
|
||||
char str[64];
|
||||
|
||||
context += delta;
|
||||
lastctxdelta = delta;
|
||||
if (context == 0 && delta < 0) {
|
||||
emit->frame_end (egg, stackframe+stackfixed, nbrackets);
|
||||
if (mode == NORMAL) /* XXX : commenting this makes hello.r unhappy! TODO: find a cleaner alternative */
|
||||
stackframe = 0;
|
||||
mode = NORMAL;
|
||||
} else {
|
||||
if (callname) {
|
||||
/* TODO: this must be an array */
|
||||
char *b = NULL; /* below */
|
||||
char *g = NULL; /* greater */
|
||||
char *e = NULL; /* equal */
|
||||
char *n = NULL; /* negate */
|
||||
/* conditional block */
|
||||
emit->comment (egg, "cond frame %s (%s)", callname, elem);
|
||||
/* TODO: simplify with a single for */
|
||||
b = strchr (elem, '<');
|
||||
g = strchr (elem, '>');
|
||||
e = strchr (elem, '=');
|
||||
n = strchr (elem, '!');
|
||||
if (strstr (callname, "while")) {
|
||||
emit->get_while_end (egg, str, ctxpush[context-1], get_frame_label (2));
|
||||
free (endframe);
|
||||
endframe = strdup (str);
|
||||
free (callname);
|
||||
callname = strdup ("if");
|
||||
}
|
||||
if (strstr (callname, "if")) {
|
||||
emit->branch (egg, b, g, e, n, varsize, get_end_frame_label (egg));
|
||||
if (context>0) {
|
||||
/* XXX .. */
|
||||
} else eprintf ("FUCKING CASE\n");
|
||||
R_FREE (callname);
|
||||
} else eprintf ("Unknown statement (%s)(%s)\n", callname, elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int parsedatachar(REgg *egg, char c) {
|
||||
static int inlinectr = 0;
|
||||
char *str;
|
||||
int i,j;
|
||||
|
||||
/* skip until '{' */
|
||||
if (c == '{') { /* XXX: repeated code!! */
|
||||
rcc_context (egg, 1);
|
||||
if (++inlinectr==1)
|
||||
return (ndstval = 0);
|
||||
} else if (inlinectr == 0) {
|
||||
/* capture value between parenthesis foo@data(NNN) { ... } */
|
||||
if (c==')') {
|
||||
stackframe = atoi (dstval);
|
||||
ndstval=0;
|
||||
} else dstval[ndstval++] = c;
|
||||
return 0;
|
||||
}
|
||||
/* capture body */
|
||||
if (c == '}') { /* XXX: repeated code!! */
|
||||
if (context < 2) {
|
||||
inlinectr = 0;
|
||||
rcc_context (egg, -1);
|
||||
slurp = 0;
|
||||
mode = NORMAL;
|
||||
/* register */
|
||||
if (dstval == NULL || dstvar == NULL) {
|
||||
eprintf ("FUCK FUCK\n");
|
||||
} else {
|
||||
dstval[ndstval]='\0';
|
||||
egg->emit->comment (egg, "data (%s)(%s)size=(%d)\n",
|
||||
dstvar, dstval, stackframe);
|
||||
r_egg_printf (egg, ".data\n");
|
||||
for (str=dstval; isspace (*str); str++);
|
||||
j = (stackframe)? stackframe:1;
|
||||
/* emit label */
|
||||
r_egg_printf (egg, "%s:\n", dstvar);
|
||||
for(i=1;i<=j;i++) {
|
||||
if (str[0]=='"')
|
||||
r_egg_printf (egg, ".ascii %s%s\n", dstval, (i==j)?"\"\\x00\"":"");
|
||||
else r_egg_printf (egg, ".long %s\n", dstval);
|
||||
}
|
||||
r_egg_printf (egg, ".text\n");
|
||||
R_FREE (dstvar);
|
||||
R_FREE (dstval);
|
||||
ndstval = 0;
|
||||
context = 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
dstval[ndstval++] = c;
|
||||
return 0;
|
||||
}
|
||||
static int parseinlinechar(REgg *egg, char c) {
|
||||
static int inlinectr = 0;
|
||||
|
||||
/* skip until '{' */
|
||||
if (c == '{') { /* XXX: repeated code!! */
|
||||
rcc_context (egg, 1);
|
||||
inlinectr++;
|
||||
if (inlinectr==1)
|
||||
return 0;
|
||||
} else
|
||||
if (inlinectr == 0)
|
||||
return 0;
|
||||
|
||||
/* capture body */
|
||||
if (c == '}') { /* XXX: repeated code!! */
|
||||
if (context < 2) {
|
||||
rcc_context (egg, -1);
|
||||
slurp = 0;
|
||||
mode = NORMAL;
|
||||
inlinectr = 0;
|
||||
if (dstvar == NULL && dstval == syscallbody) {
|
||||
dstval = NULL;
|
||||
return 1;
|
||||
} else
|
||||
/* register */
|
||||
if (dstval != NULL && dstvar != NULL) {
|
||||
dstval[ndstval]='\0';
|
||||
//printf(" /* END OF INLINE (%s)(%s) */\n", dstvar, dstval);
|
||||
inlines[ninlines].name = strdup (dstvar);
|
||||
inlines[ninlines].body = strdup (dstval);
|
||||
ninlines++;
|
||||
R_FREE (dstvar);
|
||||
R_FREE (dstval);
|
||||
return 1;
|
||||
} else eprintf ("FUCK FUCK\n");
|
||||
}
|
||||
}
|
||||
dstval[ndstval++] = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: split this function into several ones..quite long fun */
|
||||
static void rcc_next(REgg *egg) {
|
||||
REggEmit *e = egg->emit;
|
||||
char *p, buf[64];
|
||||
int i;
|
||||
|
||||
docall = 1;
|
||||
if (callname) {
|
||||
char *str, *ocn, *ptr = strchr (callname, '=');
|
||||
if (ptr) {
|
||||
*ptr = '\0';
|
||||
ocn = ptr+1;
|
||||
}
|
||||
for (ocn=callname; *ocn==' '; ocn++);
|
||||
str = r_egg_mkvar (egg, buf, ocn, 0);
|
||||
if (ocn[0]=='.')
|
||||
e->call (egg, str, 1);
|
||||
else
|
||||
if (!strcmp (str, "while")) {
|
||||
if (lastctxdelta>=0)
|
||||
exit (eprintf ("ERROR: Unsupported while syntax\n"));
|
||||
e->while_end (egg, get_frame_label (1));
|
||||
#if 0
|
||||
eprintf ("------------------------------------------ lastctx: %d\n", lastctxdelta);
|
||||
// TODO: the pushvar is required for the if(){}while(); constructions
|
||||
//char *pushvar = ctxpush[context+nbrackets-1];
|
||||
/* TODO: support to compare more than one expression (LOGICAL OR) */
|
||||
rcc_printf (" pop %%eax\n");
|
||||
rcc_printf (" cmp $0, %%eax\n"); // XXX MUST SUPPORT != 0 COMPARE HERE
|
||||
/* TODO : Simplify!! */
|
||||
//if (pushvar)
|
||||
// printf(" push %s /* wihle push */\n", pushvar);
|
||||
if (lastctxdelta<0)
|
||||
rcc_printf (" jnz %s\n", get_frame_label (1));
|
||||
else rcc_printf (" jnz %s\n", get_frame_label (0));
|
||||
//if (pushvar)
|
||||
// printf(" pop %%"R_AX" /* while pop */\n");
|
||||
#endif
|
||||
nargs = 0;
|
||||
} else {
|
||||
for (i=0; i<nsyscalls; i++) {
|
||||
if (!strcmp (str, syscalls[i].name)) {
|
||||
p = syscallbody;
|
||||
e->comment (egg, "set syscall args");
|
||||
e->syscall_args (egg, nargs);
|
||||
docall = 0;
|
||||
e->comment (egg, "syscall");
|
||||
r_egg_lang_parsechar (egg, '\n'); /* FIX parsing issue */
|
||||
for (; *p; p++)
|
||||
r_egg_lang_parsechar (egg, *p);
|
||||
docall = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (docall)
|
||||
for (i=0; i<ninlines; i++) {
|
||||
if (!strcmp (str, inlines[i].name)) {
|
||||
p = inlines[i].body;
|
||||
docall = 0;
|
||||
e->comment (egg, "inline");
|
||||
r_egg_lang_parsechar (egg, '\n'); /* FIX parsing issue */
|
||||
for (; *p; p++)
|
||||
r_egg_lang_parsechar (egg, *p);
|
||||
docall = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (docall) {
|
||||
e->comment (egg, "call in mode %d", mode);
|
||||
e->call (egg, str, 0);
|
||||
}
|
||||
}
|
||||
if (nargs>0)
|
||||
e->restore_stack (egg, nargs*e->size);
|
||||
if (ocn) { // Used to call .var0()
|
||||
/* XXX: Probably buggy and wrong */
|
||||
*buf = 0;
|
||||
str = r_egg_mkvar (egg, buf, ocn, 0);
|
||||
if (*buf)
|
||||
e->get_result (egg, buf);
|
||||
//else { eprintf("external symbol %s\n", ocn); }
|
||||
}
|
||||
/* store result of call */
|
||||
if (dstvar) {
|
||||
*buf = 0;
|
||||
str = r_egg_mkvar (egg, buf, dstvar, 0);
|
||||
if (*buf == 0)
|
||||
eprintf ("Cannot resolve variable '%s'\n", dstvar);
|
||||
else e->get_result (egg, buf);
|
||||
R_FREE (dstvar);
|
||||
}
|
||||
R_FREE (callname);
|
||||
nargs = 0;
|
||||
} else {
|
||||
int vs = 'l';
|
||||
char type, *eq, *ptr = elem;
|
||||
elem[elem_n] = '\0';
|
||||
while (isspace (ptr[0])) ptr=ptr+1; /* skip spaces */
|
||||
if (*ptr) {
|
||||
eq = strchr (ptr, '=');
|
||||
if (eq) {
|
||||
char str2[64], *p, ch = *(eq-1);
|
||||
*eq = '\0';
|
||||
for (eq=eq+1; *eq==' '; eq++);
|
||||
p = r_egg_mkvar (egg, str2, ptr, 0);
|
||||
vs = varsize;
|
||||
if (IS_VAR (eq)) {
|
||||
eq = r_egg_mkvar (egg, buf, eq, 0);
|
||||
if (varxs=='*')
|
||||
e->load (egg, eq, varsize);
|
||||
else
|
||||
/* XXX this is a hack .. must be integrated with pusharg */
|
||||
if (varxs=='&')
|
||||
e->load_ptr (egg, eq);
|
||||
eq = NULL;
|
||||
type = ' ';
|
||||
} else type = '$';
|
||||
vs = 'l'; // XXX: add support for != 'l' size
|
||||
e->mathop (egg, ch, vs, type, eq, p);
|
||||
} else e->mathop (egg, '=', vs, '$', ptr, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
R_API int r_egg_lang_parsechar(REgg *egg, char c) {
|
||||
REggEmit *e = egg->emit;
|
||||
char *ptr, str[64];
|
||||
if (c=='\n') {
|
||||
line++;
|
||||
elem_n = 0;
|
||||
}
|
||||
/* comments */
|
||||
if (skipline) {
|
||||
if (c != '\n')
|
||||
return 0;
|
||||
skipline = 0;
|
||||
}
|
||||
if (mode == DATA)
|
||||
return parsedatachar (egg, c);
|
||||
if (mode == INLINE)
|
||||
return parseinlinechar (egg, c);
|
||||
/* quotes */
|
||||
if (quoteline) {
|
||||
if (c != quoteline) {
|
||||
if (quotelinevar == 1) {
|
||||
if (c == '`') {
|
||||
elem[elem_n] = 0;
|
||||
elem_n = 0;
|
||||
r_egg_printf (egg, "%s", r_egg_mkvar (egg, str, elem, 0));
|
||||
quotelinevar = 0;
|
||||
} else elem[elem_n++] = c;
|
||||
} else {
|
||||
if (c == '`') {
|
||||
elem_n = 0;
|
||||
quotelinevar = 1;
|
||||
} else r_egg_printf (egg, "%c", c);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
r_egg_printf (egg, "\n");
|
||||
quoteline = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(commentmode) {
|
||||
if (c=='/' && oc == '*')
|
||||
commentmode = 0;
|
||||
return 0;
|
||||
} else if (c=='*' && oc == '/')
|
||||
commentmode = 1;
|
||||
if (slurp) {
|
||||
if (slurp != '"' && c == slurpin)
|
||||
exit (eprintf (
|
||||
"%s:%d Nesting of expressions not yet supported\n",
|
||||
file, line));
|
||||
if (c == slurp && oc != '\\') {
|
||||
slurp = 0;
|
||||
elem[elem_n] = '\0';
|
||||
if (elem_n > 0)
|
||||
rcc_element (egg, elem);
|
||||
else e->frame (egg, 0);
|
||||
elem_n = 0;
|
||||
} else elem[elem_n++] = c;
|
||||
elem[elem_n] = '\0';
|
||||
} else {
|
||||
switch (c) {
|
||||
case ';':
|
||||
rcc_next (egg);
|
||||
break;
|
||||
case '"':
|
||||
slurp = '"';
|
||||
break;
|
||||
case '(':
|
||||
slurpin = '(';
|
||||
slurp = ')';
|
||||
break;
|
||||
case '{':
|
||||
if (context>0)
|
||||
r_egg_printf (egg, " %s:\n", get_frame_label (0));
|
||||
rcc_context (egg, 1);
|
||||
break;
|
||||
case '}':
|
||||
if (endframe) {
|
||||
// XXX: use endframe[context]
|
||||
r_egg_printf (egg, "%s\n", endframe);
|
||||
R_FREE (endframe);
|
||||
}
|
||||
if (context>0) {
|
||||
r_egg_printf (egg, " %s:\n", get_end_frame_label (egg));
|
||||
nbrackets++;
|
||||
}
|
||||
rcc_context (egg, -1);
|
||||
if (context == 0) {
|
||||
nbrackets = 0;
|
||||
nfunctions++;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
if (oc == '\n' || oc == '}')
|
||||
quoteline = '\n';
|
||||
else elem[elem_n++] = c;
|
||||
break;
|
||||
case '#':
|
||||
if (oc == '\n')
|
||||
skipline = 1;
|
||||
break;
|
||||
case '/':
|
||||
if (oc == '/')
|
||||
skipline = 1;
|
||||
break;
|
||||
default:
|
||||
elem[elem_n++] = c;
|
||||
}
|
||||
if (slurp) {
|
||||
if (elem_n) {
|
||||
ptr = elem;
|
||||
elem[elem_n] = '\0';
|
||||
while (isspace (*ptr)) ptr++;
|
||||
rcc_fun (egg, ptr);
|
||||
}
|
||||
elem_n = 0;
|
||||
}
|
||||
}
|
||||
if (c!='\t' && c!=' ')
|
||||
oc = c;
|
||||
return 0;
|
||||
}
|
16
libr/egg/t/Makefile
Normal file
16
libr/egg/t/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
include ../../config.mk
|
||||
|
||||
BINDEPS=r_egg r_util
|
||||
|
||||
CFLAGS+=-DVERSION=\"${VERSION}\"
|
||||
CFLAGS+=-g -I../../include
|
||||
|
||||
all: test${EXT_EXE}
|
||||
|
||||
test${EXT_EXE}: test.o
|
||||
${CC} ${CFLAGS} test.o ${LDFLAGS} -o test${EXT_EXE}
|
||||
|
||||
myclean:
|
||||
rm -f test${EXT_EXE} test.o
|
||||
|
||||
include ../../rules.mk
|
28
libr/egg/t/test.c
Normal file
28
libr/egg/t/test.c
Normal file
@ -0,0 +1,28 @@
|
||||
#include <r_egg.h>
|
||||
|
||||
int main() {
|
||||
int i;
|
||||
RBuffer *b;
|
||||
REgg *egg = r_egg_new ();
|
||||
r_egg_include (egg, "test.r", 0);
|
||||
r_egg_compile (egg);
|
||||
|
||||
printf ("src (%s)\n", r_egg_get_source (egg));
|
||||
printf ("asm (%s)\n", r_egg_get_assembly (egg));
|
||||
b = r_egg_get_bin (egg);
|
||||
|
||||
printf ("BUFFER : %d\n", b->length);
|
||||
for (i=0;i<b->length;i++) {
|
||||
printf ("%02x", b->buf[i]);
|
||||
}
|
||||
printf ("\n");
|
||||
#if VALA
|
||||
var egg = new REgg ();
|
||||
egg.include ("test.r", 'r');
|
||||
egg.compile ();
|
||||
#endif
|
||||
|
||||
r_egg_syscall (egg, "close", 0);
|
||||
r_egg_free (egg);
|
||||
return 0;
|
||||
}
|
4
libr/egg/t/test.r
Normal file
4
libr/egg/t/test.r
Normal file
@ -0,0 +1,4 @@
|
||||
main@global(128) {
|
||||
printf ("Hello World\n");
|
||||
: int3
|
||||
}
|
@ -51,7 +51,9 @@ R_API int r_buf_prepend_bytes(RBuffer *b, const ut8 *buf, int length) {
|
||||
}
|
||||
|
||||
R_API char *r_buf_to_string(RBuffer *b) {
|
||||
char *s = malloc (b->length+1);
|
||||
char *s;
|
||||
if (!b) return strdup ("");
|
||||
s = malloc (b->length+1);
|
||||
memcpy (s, b->buf, b->length);
|
||||
s[b->length] = 0;
|
||||
return s;
|
||||
|
Loading…
x
Reference in New Issue
Block a user