mirror of
https://github.com/radareorg/radare2.git
synced 2025-03-01 18:57:20 +00:00
181 lines
4.1 KiB
C
181 lines
4.1 KiB
C
/* radare - LGPL - Copyright 2021 pancake */
|
|
|
|
#include "r_lib.h"
|
|
#include "r_core.h"
|
|
#include "r_lang.h"
|
|
|
|
static const char *r2go_sym = "entry";
|
|
|
|
static bool lang_go_file(RLang *lang, const char *file);
|
|
|
|
static const char *r2go_head = \
|
|
"package main\n"
|
|
"\n"
|
|
"// #cgo pkg-config: r_core\n"
|
|
"// char *r_core_cmd_str(void *p, const char *cmd);\n"
|
|
"import \"C\"\n";
|
|
|
|
static const char *r2go_body = \
|
|
"import \"unsafe\"\n"
|
|
"\n"
|
|
"func r2cmd(core unsafe.Pointer, c string) string {\n"
|
|
" return C.GoString(C.r_core_cmd_str(core, C.CString(c)))\n"
|
|
"}\n"
|
|
"\n"
|
|
"func main() {}\n";
|
|
|
|
typedef struct GOParse {
|
|
RStrBuf *head;
|
|
RStrBuf *body;
|
|
} GOParse;
|
|
|
|
static void gocode_fini(GOParse *p) {
|
|
r_strbuf_free (p->head);
|
|
r_strbuf_free (p->body);
|
|
}
|
|
|
|
static GOParse gocode_parse(const char *code) {
|
|
GOParse vp = {0};
|
|
vp.head = r_strbuf_new ("");
|
|
vp.body = r_strbuf_new ("");
|
|
char *c = strdup (code);
|
|
char *p = c;
|
|
char *cp = c;
|
|
for (; *cp; cp++) {
|
|
if (*cp == '\n') {
|
|
*cp = 0;
|
|
if (r_str_startswith (p, "package")) {
|
|
// ignore r_strbuf_appendf (vp.head, "%s\n", p);
|
|
} else if (r_str_startswith (p, "import")) {
|
|
if (strchr (p, '(')) {
|
|
r_strbuf_append (vp.head, "\n");
|
|
}
|
|
char *end = strchr (p, ')');
|
|
if (end) {
|
|
*end = 0;
|
|
cp = end + 1;
|
|
}
|
|
r_strbuf_appendf (vp.head, "%s\n", p);
|
|
} else {
|
|
r_strbuf_appendf (vp.body, "%s\n", p);
|
|
}
|
|
p = cp + 1;
|
|
}
|
|
}
|
|
if (*p) {
|
|
r_strbuf_appendf (vp.body, "%s\n", p);
|
|
}
|
|
free (c);
|
|
return vp;
|
|
}
|
|
|
|
static void gorunlib(void *user, const char *lib) {
|
|
void *vl = r_lib_dl_open (lib);
|
|
if (vl) {
|
|
void (*fcn)(RCore *, int argc, const char **argv);
|
|
fcn = r_lib_dl_sym (vl, r2go_sym);
|
|
if (fcn) {
|
|
fcn (user, 0, NULL);
|
|
} else {
|
|
eprintf ("Cannot find '%s' symbol in library.\n", r2go_sym);
|
|
}
|
|
// dlclosing causes a crash, this is a know issue by Golang
|
|
// https://github.com/golang/go/issues/32497
|
|
// https://github.com/golang/go/issues/11100
|
|
// r_lib_dl_close (vl);
|
|
} else {
|
|
eprintf ("Cannot open '%s' library.\n", lib);
|
|
}
|
|
}
|
|
|
|
static bool __gorun(RLang *lang, const char *code, int len) {
|
|
// r_file_rm ("tmp.go");
|
|
FILE *fd = r_sandbox_fopen ("tmp.go", "w");
|
|
if (fd) {
|
|
GOParse gocode = gocode_parse (code);
|
|
fputs (r2go_head, fd);
|
|
fputs (r_strbuf_get (gocode.head), fd);
|
|
fputs (r2go_body, fd);
|
|
const char *body = r_strbuf_get (gocode.body);
|
|
bool has_entry = strstr (body, "func entry");
|
|
if (!has_entry) {
|
|
fputs ("//export entry\n", fd);
|
|
fputs ("func entry(r2 unsafe.Pointer) {\n", fd);
|
|
}
|
|
fputs (body, fd);
|
|
if (!has_entry) {
|
|
fputs ("}\n", fd);
|
|
}
|
|
fclose (fd);
|
|
// system ("cat tmp.go");
|
|
lang_go_file (lang, "tmp.go");
|
|
gorunlib (lang->user, "tmp."R_LIB_EXT);
|
|
r_file_rm ("tmp.go");
|
|
r_file_rm ("tmp."R_LIB_EXT);
|
|
gocode_fini (&gocode);
|
|
return true;
|
|
}
|
|
eprintf ("Cannot open tmp.go\n");
|
|
return false;
|
|
}
|
|
|
|
static bool lang_go_file(RLang *lang, const char *file) {
|
|
if (!lang || R_STR_ISEMPTY (file)) {
|
|
return false;
|
|
}
|
|
if (!r_str_endswith (file, ".go")) {
|
|
return false;
|
|
}
|
|
if (strcmp (file, "tmp.go")) {
|
|
char *code = r_file_slurp (file, NULL);
|
|
bool r = __gorun (lang, code, -1);
|
|
free (code);
|
|
return r;
|
|
}
|
|
if (!r_file_exists (file)) {
|
|
eprintf ("file not found (%s)\n", file);
|
|
return false;
|
|
}
|
|
r_sys_setenv ("PKG_CONFIG_PATH", R2_LIBDIR"/pkgconfig");
|
|
char *lib = r_str_replace (strdup (file), ".go", "."R_LIB_EXT, 1);
|
|
char *buf = r_str_newf ("go build -buildmode=c-shared -o %s %s", lib, file);
|
|
if (r_sandbox_system (buf, 1) != 0) {
|
|
free (buf);
|
|
free (lib);
|
|
return false;
|
|
}
|
|
free (buf);
|
|
// gorunlib (lang->user, lib);
|
|
// r_file_rm (lib);
|
|
free (lib);
|
|
return 0;
|
|
}
|
|
|
|
static bool lang_go_run(RLang *lang, const char *code, int len) {
|
|
return __gorun (lang, code, len);
|
|
}
|
|
|
|
#define r_lang_go_example ""\
|
|
"pub fn entry(r2 &R2) {\n" \
|
|
" println(r2.cmd('?E Hello World'))\n" \
|
|
"}\n"
|
|
|
|
static RLangPlugin r_lang_plugin_go = {
|
|
.name = "go",
|
|
.ext = "go",
|
|
.example = r_lang_go_example,
|
|
.desc = "GO language extension",
|
|
.license = "MIT",
|
|
.run = lang_go_run,
|
|
.run_file = (void*)lang_go_file,
|
|
};
|
|
|
|
/*
|
|
#ifndef CORELIB
|
|
RLibStruct radare_plugin = {
|
|
.type = R_LIB_TYPE_LANG,
|
|
.data = &r_lang_plugin_go,
|
|
};
|
|
#endif
|
|
*/
|