* 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
This commit is contained in:
pancake 2011-09-20 01:53:15 +02:00
parent 8933c45e0d
commit 1b440bf9d2
8 changed files with 188 additions and 38 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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";

7
libr/egg/t/sys.r Normal file
View File

@ -0,0 +1,7 @@
exit@syscall(1);
@syscall() {
: int 0x88
}
main@global() {
exit(0);
}

View File

@ -5,6 +5,9 @@
#include <r_util.h>
#include <r_syscall.h>
#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

View File

@ -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);