From 1b440bf9d22207fd6de0c656a435c9a7593631de Mon Sep 17 00:00:00 2001 From: pancake Date: Tue, 20 Sep 2011 01:53:15 +0200 Subject: [PATCH] * Add ragg2 -I to prepend include path directories * Enhacements in r_egg library - Add support for including files - bla.r@include($PATH); - Proper support for goto() keyword - Add support to get and set environment variables (need more work) - PATH@env(/bin); - Fix /* */ comment parsing code --- binr/ragg2/ragg2.c | 15 +++-- libr/egg/egg.c | 9 ++- libr/egg/lang.c | 154 ++++++++++++++++++++++++++++++++++++------- libr/egg/t/inc.r | 20 +++++- libr/egg/t/loop.r | 13 ++-- libr/egg/t/sys.r | 7 ++ libr/include/r_egg.h | 5 ++ libr/util/str.c | 3 +- 8 files changed, 188 insertions(+), 38 deletions(-) create mode 100644 libr/egg/t/sys.r diff --git a/binr/ragg2/ragg2.c b/binr/ragg2/ragg2.c index e64fa0ca66..9a46e525ca 100644 --- a/binr/ragg2/ragg2.c +++ b/binr/ragg2/ragg2.c @@ -12,6 +12,7 @@ static int usage () { " -F output native format (osx=mach0, linux=elf, ..)\n" " -o [file] output file\n" " -O use default output file (filename without extension or a.out)\n" + " -I add include path\n" " -s show assembler\n" " -x show hexpairs (enabled by default)\n" " -X execute\n" @@ -59,10 +60,10 @@ int main(int argc, char **argv) { const char *ofile = NULL; int ofileauto = 0; RBuffer *b; - REgg *egg; int c, i; + REgg *egg = r_egg_new (); - while ((c = getopt (argc, argv, "ha:b:f:o:sxXk:FO")) != -1) { + while ((c = getopt (argc, argv, "ha:b:f:o:sxXk:FOI:")) != -1) { switch (c) { case 'a': arch = optarg; @@ -80,6 +81,9 @@ int main(int argc, char **argv) { case 'O': ofileauto = 1; break; + case 'I': + r_egg_lang_include_path (egg, optarg); + break; case 'F': #if __APPLE__ format = "mach0"; @@ -129,17 +133,16 @@ int main(int argc, char **argv) { free (p); if (fd == -1) { eprintf ("cannot open file '%s'\n", optarg); - exit (1); + goto fail; } } if (ofile) { if (openfile (ofile, ISEXEC) == -1) { eprintf ("cannot open file '%s'\n", optarg); - return 1; + goto fail; } } - egg = r_egg_new (); r_egg_setup (egg, arch, bits, 0, os); if (!strcmp (argv[optind], "-")) { char buf[1024]; @@ -151,7 +154,7 @@ int main(int argc, char **argv) { } else { if (!r_egg_include (egg, argv[optind], 0)) { eprintf ("Cannot open '%s'\n", argv[optind]); - return 1; + goto fail; } } r_egg_compile (egg); diff --git a/libr/egg/egg.c b/libr/egg/egg.c index c038521588..d1807a53f9 100644 --- a/libr/egg/egg.c +++ b/libr/egg/egg.c @@ -33,7 +33,11 @@ R_API void r_egg_free (REgg *egg) { } R_API void r_egg_reset (REgg *egg) { - // XXX: memory leak + r_egg_lang_include_init (egg); + r_buf_free (egg->src); + r_buf_free (egg->buf); + egg->src = r_buf_new (); + egg->buf = r_buf_new (); } R_API int r_egg_setup(REgg *egg, const char *arch, int bits, int endian, const char *os) { @@ -71,9 +75,8 @@ R_API int r_egg_setup(REgg *egg, const char *arch, int bits, int endian, const c egg->endian = endian; } if (egg->emit) { - if (egg->emit->init) { + if (egg->emit->init) egg->emit->init (egg); - } return 1; } return 0; diff --git a/libr/egg/lang.c b/libr/egg/lang.c index f2f0ff96f1..8b1b439007 100644 --- a/libr/egg/lang.c +++ b/libr/egg/lang.c @@ -27,6 +27,7 @@ enum { INLINE, SYSCALL, SYSCALLBODY, + GOTO, LAST }; @@ -34,6 +35,8 @@ enum { static int pushargs = 0; static int nsyscalls = 0; static char *syscallbody = NULL; +static char *includefile = NULL; +static char *setenviron = NULL; static int commentmode = 0; static int varsize = 'l'; static int varxs = 0; @@ -64,28 +67,57 @@ static int stackfixed = 0; static int oc = '\n'; static int mode = NORMAL; -static char *trim(char *s) { - char *o; - for (o=s; *s; s++) - if (isspace (*s)) { - *s = 0; - break; +static char *find_include(const char *prefix, const char *file) { + char *pfx, *ret, *env = r_sys_getenv (R_EGG_INCDIR_ENV); + //eprintf ("find_include (%s,%s)\n", prefix, file); + if (!prefix) prefix = ""; + else if (*prefix=='$') { + char *out = r_sys_getenv (prefix+1); + pfx = out? out: strdup (""); + } else pfx = strdup (prefix); + + if (env) { + char *str, *ptr = strchr (env, ':'); + // eprintf ("MUST FIND IN PATH (%s)\n", env); + str = env; + while (str) { + if (ptr) { + *ptr = 0; + } + ret = r_str_concatf (NULL, "%s/%s", pfx, file); + { + char *filepath = r_str_concatf (NULL, "%s/%s/%s", str, pfx, file); + // eprintf ("try (%s)\n", filepath); + if (r_file_exist (filepath)) { + free (env); + free (pfx); + return filepath; + } + free (filepath); + } + if (!ptr) break; + str = ptr+1; + ptr = strchr (str, ':'); } - return o; + free (env); + } else ret = r_str_concatf (NULL, "%s/%s", pfx, file); + free (pfx); + return ret; } -static void rcc_set_callname(const char *s) { - free (callname); - callname = NULL; - nargs = 0; - while (*s==' '||*s=='\t') s++; // skip prefixed spaces (should never happen) - callname = trim (strdup (s)); - pushargs = !((!strcmp (s, "goto")) || (!strcmp (s, "break"))); +R_API void r_egg_lang_include_path (REgg *egg, const char *path) { + char *env = r_sys_getenv (R_EGG_INCDIR_ENV); + if (!env || !*env) { + r_egg_lang_include_init (egg); + env = r_sys_getenv (R_EGG_INCDIR_ENV); + } + env = r_str_concatf (NULL, "%s:%s", path, env); + r_sys_setenv (R_EGG_INCDIR_ENV, env); + free (env); } -static void rcc_reset_callname() { - R_FREE (callname); - nargs = 0; +R_API void r_egg_lang_include_init (REgg *egg) { + r_sys_setenv (R_EGG_INCDIR_ENV, ".:"R_EGG_INCDIR_PATH); } static const char *skipspaces(const char *s) { @@ -102,6 +134,29 @@ static const char *skipspaces(const char *s) { return s; } +static char *trim(char *s) { + char *o; + for (o=s; *s; s++) + if (isspace (*s)) { + *s = 0; + break; + } + return o; +} + +static void rcc_set_callname(const char *s) { + free (callname); + callname = NULL; + nargs = 0; + callname = trim (strdup (skipspaces (s))); + pushargs = !((!strcmp (s, "goto")) || (!strcmp (s, "break"))); +} + +static void rcc_reset_callname() { + R_FREE (callname); + nargs = 0; +} + #define SYNTAX_ATT 0 #if SYNTAX_ATT #define FRAME_FMT ".LC%d_%d_frame%d" @@ -152,6 +207,8 @@ static void rcc_element(REgg *egg, char *str) { if (context) { nargs = 0; + if (mode == GOTO) + mode = NORMAL; // XXX while (p) { *p = '\0'; p = (char *)skipspaces (p+1); @@ -181,6 +238,10 @@ static void rcc_element(REgg *egg, char *str) { nsyscalls++; R_FREE (dstvar); break; + case GOTO: + elem[elem_n] = 0; + e->jmp (egg, elem, 0); + break; default: p = strchr (str, ','); if (p) { @@ -333,6 +394,12 @@ static void rcc_fun(REgg *egg, const char *str) { if (ptr) { *ptr++ = '\0'; mode = NORMAL; + if (strstr (ptr, "env")) { + //eprintf ("SETENV (%s)\n", str); + free (setenviron); + setenviron = strdup (skipspaces (str)); + slurp = 0; + } else if (strstr (ptr, "fastcall")) { /* TODO : not yet implemented */ } else @@ -351,7 +418,9 @@ static void rcc_fun(REgg *egg, const char *str) { } } else if (strstr (ptr, "include")) { - eprintf ("TODO: include directive\n"); + free (includefile); + includefile = strdup (skipspaces (str)); + slurp = 0; } else if (strstr (ptr, "alias")) { mode = ALIAS; @@ -377,11 +446,16 @@ static void rcc_fun(REgg *egg, const char *str) { } else { //e->jmp (egg, ctxpush[context], 0); if (context>0) { + // WTF? eprintf ("LABEL %d\n", context); r_egg_printf (egg, "\n%s:\n", str); } else { - // goto() - e->jmp (egg, str, 0); + if (!strcmp (str, "goto")) { + mode = GOTO; + } else { + // call() // or maybe jmp? + e->call (egg, str, 0); + } } } } @@ -414,7 +488,6 @@ static void rcc_context(REgg *egg, int delta) { emit->get_while_end (egg, str, ctxpush[context-1], get_frame_label (2)); free (endframe); endframe = strdup (str); - free (callname); rcc_set_callname ("if"); } if (!strcmp (callname, "if")) { @@ -530,6 +603,38 @@ static void rcc_next(REgg *egg) { char *str, *p, *ptr, buf[64]; int i; + if (setenviron) { + elem[elem_n-1] = 0; + r_sys_setenv (setenviron, elem); + R_FREE (setenviron); + return; + } + if (includefile) { + char *p, *q, *path; + // TODO: add support for directories + elem[elem_n-1] = 0; + path = find_include (elem, includefile); + if (!path) { + eprintf ("Cannot find include file '%s'\n", elem); + return; + } + free (includefile); + includefile = NULL; + rcc_reset_callname (); + p = q = r_file_slurp (path, NULL); + if (p) { + int oline = ++line; + elem[0] = 0; // TODO: this must be a separate function + elem_n = 0; + line = 0; + for (; *p; p++) + r_egg_lang_parsechar (egg, *p); + free (q); + line = oline; + } else eprintf ("Cannot find '%s'\n", path); + free (path); + return; + } docall = 1; if (callname) { if (!strcmp (callname, "goto")) { @@ -686,8 +791,10 @@ R_API int r_egg_lang_parsechar(REgg *egg, char c) { } /* comments */ if (skipline) { - if (c != '\n') + if (c != '\n') { + oc = c; return 0; + } skipline = 0; } if (mode == DATA) @@ -710,6 +817,7 @@ R_API int r_egg_lang_parsechar(REgg *egg, char c) { quotelinevar = 1; } else r_egg_printf (egg, "%c", c); } + oc = c; return 0; } else { r_egg_printf (egg, "\n"); @@ -720,6 +828,7 @@ R_API int r_egg_lang_parsechar(REgg *egg, char c) { if (commentmode) { if (c=='/' && oc == '*') commentmode = 0; + oc = c; return 0; } else if (c=='*' && oc == '/') commentmode = 1; @@ -782,6 +891,7 @@ R_API int r_egg_lang_parsechar(REgg *egg, char c) { case '/': if (oc == '/') skipline = 1; + else elem[elem_n++] = c; break; default: elem[elem_n++] = c; diff --git a/libr/egg/t/inc.r b/libr/egg/t/inc.r index f0074304e8..40da0a4718 100644 --- a/libr/egg/t/inc.r +++ b/libr/egg/t/inc.r @@ -1,2 +1,18 @@ -INCDIR@alias(i/); -sys.r@include(INCDIR); +#INCDIR@alias(i/); + +/* + TODO: we need ragg2 to setup OS ARCH BITS environs + use environment to set/get values + OS@env(osx); + syscalls.r@include($OS); + + use ragg2 -I to add new include path +*/ + +#INCDIR@env(/usr/include/r_egg); +INCDIR@env(t); # INCDIR=t +sys.r@include($INCDIR); # find t/sys.r + +main@global() { + exit(43); +} diff --git a/libr/egg/t/loop.r b/libr/egg/t/loop.r index 2822296836..c5cbcad78f 100644 --- a/libr/egg/t/loop.r +++ b/libr/egg/t/loop.r @@ -1,8 +1,12 @@ /* TODO: all bins must contain a jmp main */ /* entrypoint */ -:jmp main +//main(); +goto(main); +//:jmp main + puts@global() { + //write(1,.arg0); /* do nothing */ : mov edx, 3 /* : mov ecx, 0x10000002a */ @@ -15,20 +19,21 @@ puts@global() { } exit@global() { + : mov ebx, `.arg0` : mov eax, 1 : push eax : int 0x80 } -main@global(128) -{ +main@global(128) { .var0 = 3; .var4 = "counter"; + exit(0); { puts(.var4); .var0 -= 1; } while(.var0); - exit() + /* comment */ .var0 = 3; .var4 = "coconut"; diff --git a/libr/egg/t/sys.r b/libr/egg/t/sys.r new file mode 100644 index 0000000000..281671ba65 --- /dev/null +++ b/libr/egg/t/sys.r @@ -0,0 +1,7 @@ +exit@syscall(1); +@syscall() { + : int 0x88 +} +main@global() { + exit(0); +} diff --git a/libr/include/r_egg.h b/libr/include/r_egg.h index 20eacd7540..c1449a7a0c 100644 --- a/libr/include/r_egg.h +++ b/libr/include/r_egg.h @@ -5,6 +5,9 @@ #include #include +#define R_EGG_INCDIR_ENV "EGG_INCDIR" +#define R_EGG_INCDIR_PATH PREFIX"/lib/radare2/"R2_VERSION"/egg" + typedef struct r_egg_t { RBuffer *src; RBuffer *buf; @@ -102,5 +105,7 @@ R_API void r_egg_append(REgg *egg, const char *src); /* lang.c */ R_API char *r_egg_mkvar(REgg *egg, char *out, const char *_str, int delta); R_API int r_egg_lang_parsechar(REgg *egg, char c); +R_API void r_egg_lang_include_path (REgg *egg, const char *path); +R_API void r_egg_lang_include_init (REgg *egg); #endif #endif diff --git a/libr/util/str.c b/libr/util/str.c index 5145c74c08..9001106560 100644 --- a/libr/util/str.c +++ b/libr/util/str.c @@ -471,6 +471,7 @@ R_API void r_str_writef(int fd, const char *fmt, ...) { } /* + * first argument must be allocated * return: the pointer ptr resized to string size. */ R_API char *r_str_concat(char *ptr, const char *string) { @@ -487,7 +488,7 @@ R_API char *r_str_concat(char *ptr, const char *string) { } R_API char *r_str_concatf(char *ptr, const char *fmt, ...) { - char string[1024]; + char string[4096]; va_list ap; va_start (ap, fmt); vsnprintf (string, sizeof (string), fmt, ap);