R_API char *r_meta_get_string(RAnal *a, int type, ut64 addr) { char key[100]; const char *k, *p, *p2, *p3; snprintf (key, sizeof (key)-1, "meta.%c.0x%"PFMT64x, type, addr); k = sdb_const_get (DB, key, NULL); if (!k) { return NULL; } p = strchr (k, SDB_RS); if (!p) { return NULL; } k = p + 1; p2 = strchr (k, SDB_RS); if (!p2) { return (char *)sdb_decode (k, NULL); } k = p2 + 1; if (type == R_META_TYPE_STRING) { p3 = strchr (k, SDB_RS); if (p3) { return (char *)sdb_decode (p3 + 1, NULL); } } return (char *)sdb_decode (k, NULL); }
R_API char *r_meta_get_string(RAnal *a, int type, ut64 addr) { char key[100]; const char *k, *p, *p2; snprintf (key, sizeof (key)-1, "meta.%c.0x%"PFMT64x, 'C', addr); k = sdb_const_get (DB, key, NULL); if (!k) return NULL; p = strchr (k, SDB_RS); if (!p) return NULL; k = p+1; p2 = strchr (k, SDB_RS); if (!p2) { return (char *)sdb_decode (k, NULL); } return (char *)sdb_decode (p2+1, NULL); }
static inline int compareString(const char *a, const char *b, int blen, int flags) { const int start = flags & SDB_LIKE_START; const int end = flags & SDB_LIKE_END; char *aa = NULL; int alen, ret = 0; if (!a || !b || blen<0) return 0; if (flags & SDB_LIKE_BASE64) { aa = (char*)sdb_decode (a, &alen); if (!aa) return 0; a = (const char *)aa; } else { alen = strlen (a); } if (blen <= alen) { if (flags & SDB_LIKE_ICASE) { if (start && end) ret = (alen==blen && !mycmp (a, b, blen, 0)); else if (start) ret = !mycmp (a, b, blen, 0); else if (end) ret = !mycmp (a+(alen-blen), b, blen, 0); else ret = !mycmp (a, b, blen, 1); } else { if (start && end) ret = (alen==blen && !strncmp (a, b, blen)); else if (start) ret = !strncmp (a, b, blen); else if (end) ret = !strncmp (a+(alen-blen), b, blen); else ret = strstr2 (a, b, blen); } } free (aa); return ret; }
static int meta_print_item(void *user, const char *k, const char *v) { // const char *v; // size const char *v2; // space_idx RAnalMetaUserItem *ui = user; RAnalMetaItem it; if (strlen (k)<8) return 1; if (memcmp (k+6, ".0x", 3)) return 1; it.type = k[5]; it.size = sdb_atoi (v); it.from = sdb_atoi (k+7); v2 = strchr (v, ','); if (!v2) goto beach; it.space = atoi (v2+1); it.to = it.from + it.size; it.str = strchr (v2+1, ','); if (it.str) it.str = (char *)sdb_decode ((const char*)it.str+1, 0); else it.str = strdup (it.str); // don't break in free printmetaitem (ui->anal, &it, ui->rad); free (it.str); beach: return 1; }
// TODO: return false if array length != fmt length SDB_API int sdb_fmt_tobin(const char *_str, const char *fmt, void *stru) { int n, idx = 0; char *next, *str, *ptr, *word, *e_str; if (!_str || !*_str || !fmt) return 0; str = ptr = strdup (_str); for (; *fmt; fmt++) { word = sdb_anext (ptr, &next); if (!word || !*word) break; n = 4; // ALIGN switch (*fmt) { case 'b': *((ut8*)(stru + idx)) = (ut8)sdb_atoi (word); break; case 'd': *((int*)(stru + idx)) = (int)sdb_atoi (word); break; case 'q': *((ut64*)(stru + idx)) = sdb_atoi (word); n=8; break; case 'h': *((short*)(stru + idx)) = (short)sdb_atoi (word); break; case 's': e_str = (char*)sdb_decode (word, 0); *((char**)(stru + idx)) = (char*)strdup (e_str?e_str:word); free (e_str); break; case 'z': *((char**)(stru + idx)) = (char*)strdup (word); break; case 'p': *((void**)(stru + idx)) = (void*)(size_t)sdb_atoi (word); break; } idx += R_MAX((long)sizeof (void*), n); // align if (!next) break; ptr = next; } free (str); return 1; }
R_API bool r_meta_deserialize_val(RAnalMetaItem *it, int type, ut64 from, const char *v) { const char *v2; char *v3; it->type = type; it->subtype = 0; it->size = sdb_atoi (v); it->from = from; it->to = from + it->size; v2 = strchr (v, ','); if (!v2) { return false; } it->space = atoi (v2 + 1); it->str = strchr (v2 + 1, ','); if (it->str) { if (it->type == R_META_TYPE_STRING) { v3 = strchr (it->str + 1, ','); if (v3) { it->subtype = *(it->str + 1); it->str = v3; } } it->str = (char *)sdb_decode ((const char*)it->str + 1, 0); } return true; }
static int meta_enumerate_cb(void *user, const char *k, const char *v) { const char *v2; RAnalMetaUserItem *ui = user; RList *list = ui->user; //RAnal *a = ui->anal; RAnalMetaItem *it; if (strlen (k)<8) return 1; if (memcmp (k+6, ".0x", 3)) return 1; it = R_NEW0 (RAnalMetaItem); if (!it) return 0; it->type = k[5]; it->size = sdb_atoi (v); it->from = sdb_atoi (k+7); it->to = it->from + it->size; v2 = strchr (v, ','); if (!v2) { free (it); goto beach; } it->space = atoi (v2+1); it->str = strchr (v2+1, ','); if (it->str) it->str = (char *)sdb_decode ((const char*)it->str+1, 0); //printmetaitem (ui->anal, &it, ui->rad); r_list_append (list, it); beach: return 1; }
R_API RAnalHint *r_anal_hint_from_string(RAnal *a, ut64 addr, const char *str) { char *r, *nxt, *nxt2; int token = 0; RAnalHint *hint = R_NEW0 (RAnalHint); if (!hint) { return NULL; } hint->jump = UT64_MAX; hint->fail = UT64_MAX; char *s = strdup (str); if (!s) { free (hint); return NULL; } hint->addr = addr; token = *s; for (r = s; ; r = nxt2) { r = sdb_anext (r, &nxt); if (!nxt) { break; } sdb_anext (nxt, &nxt2); // tokenize value if (token) { switch (token) { case 'i': hint->immbase = sdb_atoi (nxt); break; case 'j': hint->jump = sdb_atoi (nxt); break; case 'f': hint->fail = sdb_atoi (nxt); break; case 'p': hint->ptr = sdb_atoi (nxt); break; case 'b': hint->bits = sdb_atoi (nxt); break; case 's': hint->size = sdb_atoi (nxt); break; case 'S': hint->syntax = (char*)sdb_decode (nxt, 0); break; case 'o': hint->opcode = (char*)sdb_decode (nxt, 0); break; case 'O': hint->offset = (char*)sdb_decode (nxt, 0); break; case 'e': hint->esil = (char*)sdb_decode (nxt, 0); break; case 'a': hint->arch = (char*)sdb_decode (nxt, 0); break; case 'h': hint->high = sdb_atoi (nxt); break; } } if (!nxt || !nxt2) { break; } token = *nxt2; } free (s); return hint; }
R_API char *r_meta_get_var_comment (RAnal *a, int type, ut64 idx, ut64 addr) { char key[100]; const char *k, *p, *p2; snprintf (key, sizeof (key) - 1, "meta.%c.0x%"PFMT64x".0x%"PFMT64x, type, addr, idx); k = sdb_const_get (DB, key, NULL); if (!k) { return NULL; } p = strchr (k, SDB_RS); if (!p) { return NULL; } k = p+1; p2 = strchr (k, SDB_RS); if (!p2) { return (char *)sdb_decode (k, NULL); } return (char *)sdb_decode (p2+1, NULL); }
R_API char *r_meta_get_string(RAnal *a, int type, ut64 addr) { char key[100]; const char *k, *p; snprintf (key, sizeof (key)-1, "meta.%c.0x%"PFMT64x, 'C', addr); k = sdb_const_get (DB, key, NULL); if (!k) return NULL; p = strchr (k, SDB_RS); if (!p) return NULL; k = p+1; // TODO : comment append has been deprecated return (char *)sdb_decode (k, NULL); }
R_API RAnalHint *r_anal_hint_from_string(RAnal *a, ut64 addr, const char *str) { char *r, *nxt; int token = 0; RAnalHint *hint = R_NEW0 (RAnalHint); char *s; if (!hint) return NULL; s = strdup (str); if (!s) { R_FREE (hint); return NULL; } hint->addr = addr; for (r = s; ; r = nxt) { r = sdb_anext (r, &nxt); if (token) { switch (token) { case 'j': hint->jump = sdb_atoi (r); break; case 'f': hint->fail = sdb_atoi (r); break; case 'p': hint->ptr = sdb_atoi (r); break; case 'b': hint->bits = sdb_atoi (r); break; case 's': hint->size = sdb_atoi (r); break; case 'S': hint->syntax = (char*)sdb_decode (r, 0); break; case 'o': hint->opcode = (char*)sdb_decode (r, 0); break; case 'e': hint->esil = (char*)sdb_decode (r, 0); break; case 'a': hint->arch = (char*)sdb_decode (r, 0); break; } token = 0; } else token = *r; if (!nxt) break; } free (s); return hint; }
R_API RAnalMetaItem *r_meta_find(RAnal *a, ut64 at, int type, int where) { const char *infos, *metas; char key[100]; Sdb *s = a->sdb_meta; static RAnalMetaItem mi = {0}; // XXX: return allocated item? wtf if (where != R_META_WHERE_HERE) { eprintf ("THIS WAS NOT SUPOSED TO HAPPEN\n"); return NULL; } snprintf (key, sizeof (key)-1, "meta.0x%"PFMT64x, at); infos = sdb_const_get (s, key, 0); if (!infos) return NULL; for (; *infos; infos++) { /* XXX wtf, must use anal.meta.deserialize() */ char *p, *q; if (*infos==',') continue; snprintf (key, sizeof (key) - 1, "meta.%c.0x%"PFMT64x, *infos, at); metas = sdb_const_get (s, key, 0); mi.size = sdb_array_get_num (s, key, 0, 0); mi.type = *infos; mi.from = at; mi.to = at + mi.size; if (type != R_META_TYPE_ANY && type != mi.type) { continue; } if (metas) { p = strchr (metas, ','); if (!p) { continue; } mi.space = atoi (p + 1); q = strchr (p + 1, ','); if (!q) { continue; } free (mi.str); mi.str = (char*)sdb_decode (q + 1, 0); return &mi; } else mi.str = NULL; } return NULL; }
static int base64decode() { ut8 *out; int len, ret = 1; char *in = (char*)stdin_slurp (&len); if (in) { out = sdb_decode (in, &len); if (out) { if (len >= 0) { write (1, out, len); ret = 0; } free (out); } free (in); } return ret; }
static int meta_print_item(void *user, const char *k, const char *v) { RAnalMetaUserItem *ui = user; RAnalMetaItem it; if (strlen (k)<8) return 1; if (k[6]!='.') return 1; it.type = k[5]; it.size = sdb_atoi (v); it.from = sdb_atoi (k+7); it.to = it.from + it.size; it.str = strchr (v, ','); if (it.str) it.str = (char *)sdb_decode ((const char*)it.str+1, 0); printmetaitem (ui->anal, &it, ui->rad); free (it.str); return 1; }
static int meta_print_item(void *user, const char *k, const char *v) { // const char *v; // size const char *v2; // space_idx RAnalMetaUserItem *ui = user; RAnalMetaItem it; if (strlen (k) < 8) { return 1; } if (memcmp (k + 6, ".0x", 3)) { return 1; } it.type = k[5]; it.size = sdb_atoi (v); it.from = sdb_atoi (k + 7); int uirad = ui->rad; if (ui->rad == 'f') { if (!r_anal_fcn_in (ui->fcn, it.from)) { goto beach; } ui->rad = 0; } v2 = strchr (v, ','); if (!v2) { goto beach; } it.space = atoi (v2 + 1); it.to = it.from + it.size; it.str = strchr (v2 + 1, ','); if (it.str) { it.str = (char *)sdb_decode ((const char*)it.str + 1, 0); } else { it.str = strdup (it.str? it.str: ""); // don't break in free if (!it.str) { goto beach; } } printmetaitem (ui->anal, &it, ui->rad); free (it.str); beach: ui->rad = uirad; return 1; }
static int cmd_seek(void *data, const char *input) { RCore *core = (RCore *) data; char *cmd, *p; ut64 off; if (!*input) { r_cons_printf ("0x%"PFMT64x "\n", core->offset); return 0; } char *ptr; if ((ptr = strstr (input, "+.")) != NULL) { char *dup = strdup (input); dup[ptr - input] = '\x00'; off = r_num_math (core->num, dup + 1); core->offset = off; free (dup); } const char *inputnum = strchr (input, ' '); { const char *u_num = inputnum? inputnum + 1: input + 1; off = r_num_math (core->num, u_num); if (*u_num == '-') { off = -off; } } int sign = 1; if (input[0] == ' ') { switch (input[1]) { case '-': sign = -1; /* pass thru */ case '+': input++; break; } } bool silent = false; if (*input == 's') { silent = true; input++; if (*input == '?') { const char *help_message[] = { "Usage: ss", "", " # Seek silently (not recorded in the seek history)", "s?", "", "Works with all s subcommands", NULL }; r_core_cmd_help (core, help_message); return 0; } } switch (*input) { case 'r': if (input[1] && input[2]) { seek_to_register (core, input + 2, silent); } else { eprintf ("|Usage| 'sr PC' seek to program counter register\n"); } break; case 'C': if (input[1] == '*') { r_core_cmd0 (core, "C*~^\"CC"); } else if (input[1] == ' ') { typedef struct { ut64 addr; char *str; } MetaCallback; int count = 0; MetaCallback cb = { 0, NULL }; ut64 addr; char key[128]; const char *val, *comma; char *list = sdb_get (core->anal->sdb_meta, "meta.C", 0); char *str, *next, *cur = list; if (list) { for (;;) { cur = sdb_anext (cur, &next); addr = sdb_atoi (cur); snprintf (key, sizeof (key) - 1, "meta.C.0x%"PFMT64x, addr); val = sdb_const_get (core->anal->sdb_meta, key, 0); if (val) { comma = strchr (val, ','); if (comma) { str = (char *) sdb_decode (comma + 1, 0); if (strstr (str, input + 2)) { r_cons_printf ("0x%08"PFMT64x " %s\n", addr, str); count++; cb.addr = addr; free (cb.str); cb.str = str; } else { free (str); } } } else { eprintf ("sdb_const_get key not found '%s'\n", key); } if (!next) { break; } cur = next; } } switch (count) { case 0: eprintf ("No matching comments\n"); break; case 1: off = cb.addr; if (!silent) { r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); } r_core_seek (core, off, 1); r_core_block_read (core); break; default: eprintf ("Too many results\n"); break; } free (cb.str); } else { const char *help_msg[] = { "Usage:", "sC", "Comment grep", "sC", "*", "List all comments", "sC", " str", "Seek to the first comment matching 'str'", NULL }; r_core_cmd_help (core, help_msg); } break; case ' ': if (!silent) { r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); } r_core_seek (core, off * sign, 1); r_core_block_read (core); break; case '/': { const char *pfx = r_config_get (core->config, "search.prefix"); ut64 from = r_config_get_i (core->config, "search.from"); // kwidx cfg var is ignored int kwidx = core->search->n_kws; // (int)r_config_get_i (core->config, "search.kwidx")-1; if (kwidx < 0) { kwidx = 0; } switch (input[1]) { case ' ': case 'v': case 'V': case 'w': case 'W': case 'z': case 'm': case 'c': case 'A': case 'e': case 'E': case 'i': case 'R': case 'r': case '/': case 'x': r_config_set_i (core->config, "search.from", core->offset + 1); r_config_set_i (core->config, "search.count", 1); r_core_cmdf (core, "s+1; %s; s-1; s %s%d_0; f-%s%d_0", input, pfx, kwidx, pfx, kwidx, pfx, kwidx); r_config_set_i (core->config, "search.from", from); r_config_set_i (core->config, "search.count", 0); break; case '?': eprintf ("Usage: s/.. arg.\n"); r_cons_printf ("/?\n"); break; default: eprintf ("unknown search method\n"); break; } } break; case '.': for (input++; *input == '.'; input++) { ; } r_core_seek_base (core, input); break; case 'j': // sj { RList /*<ut64 *>*/ *addrs = r_list_newf (free); RList /*<char *>*/ *names = r_list_newf (free); RList *list = r_io_sundo_list (core->io, '!'); ut64 lsz = 0; ut64 i; RListIter *iter; RIOUndos *undo; if (list) { r_list_foreach (list, iter, undo) { char *name = NULL; core->flags->space_strict = true; RFlagItem *f = r_flag_get_at (core->flags, undo->off, true); core->flags->space_strict = false; if (f) { if (f->offset != undo->off) { name = r_str_newf ("%s + %d\n", f->name, (int)(undo->off- f->offset)); } else { name = strdup (f->name); } } if (!name) { name = strdup (""); } ut64 *val = malloc (sizeof (ut64)); if (!val) { free (name); break; } *val = undo->off; r_list_append (addrs, val); r_list_append (names, strdup (name)); lsz++; free (name); } r_list_free (list); } r_cons_printf ("["); for (i = 0; i < lsz; ++i) { ut64 *addr = r_list_get_n (addrs, i); const char *name = r_list_get_n (names, i); // XXX(should the "name" field be optional? That might make // a bit more sense. r_cons_printf ("{\"offset\":%"PFMT64d",\"symbol\":\"%s\"}", *addr, name); if (i != lsz - 1) { r_cons_printf (","); } } r_cons_printf ("]\n"); r_list_free (addrs); r_list_free (names); } break; case '*': case '=': case '!': { RList *list = r_io_sundo_list (core->io, input[0]); RListIter *iter; RIOUndos *undo; if (list) { r_list_foreach (list, iter, undo) { char *name = NULL; core->flags->space_strict = true; RFlagItem *f = r_flag_get_at (core->flags, undo->off, true); core->flags->space_strict = false; if (f) { if (f->offset != undo->off) { name = r_str_newf ("%s + %d\n", f->name, (int)(undo->off- f->offset)); } else { name = strdup (f->name); } } if (!name) { name = strdup (""); } r_cons_printf ("0x%"PFMT64x" %s\n", undo->off, name); free (name); } r_list_free (list); } }
static int cmd_seek(void *data, const char *input) { RCore *core = (RCore *)data; char *cmd, *p; ut64 off; if (*input=='r') { if (input[1] && input[2]) { if (core->io->debug) { off = r_debug_reg_get (core->dbg, input+2); r_io_sundo_push (core->io, core->offset); r_core_seek (core, off, 1); } else { RReg *orig = core->dbg->reg; core->dbg->reg = core->anal->reg; off = r_debug_reg_get (core->dbg, input+2); core->dbg->reg = orig; r_core_seek (core, off, 1); } } else eprintf ("|Usage| 'sr pc' seek to program counter register\n"); } else if (*input) { const char *inputnum = strchr (input+1, ' '); int sign = 1; inputnum = inputnum? inputnum+1: input+1; off = r_num_math (core->num, inputnum); if (*inputnum== '-') off = -off; #if 0 if (input[0]!='/' && inputnum && isalpha (inputnum[0]) && off == 0) { if (!r_flag_get (core->flags, inputnum)) { eprintf ("Cannot find address for '%s'\n", inputnum); return R_FALSE; } } #endif if (input[0]==' ') { switch (input[1]) { case '-': sign=-1; case '+': input++; break; } } switch (*input) { case 'C': if (input[1]=='*') { r_core_cmd0 (core, "C*~^\"CC"); } else if (input[1]==' ') { typedef struct { ut64 addr; char *str; } MetaCallback; int count = 0; MetaCallback cb = { 0, NULL }; ut64 addr; char key[128]; const char *val, *comma; char *list = sdb_get (core->anal->sdb_meta, "meta.C", 0); char *str, *next, *cur = list; if (list) { for (;;) { cur = sdb_anext (cur, &next); addr = sdb_atoi (cur); snprintf (key, sizeof (key)-1, "meta.C.0x%"PFMT64x, addr); val = sdb_const_get (core->anal->sdb_meta, key, 0); if (val) { comma = strchr (val, ','); if (comma) { str = (char *)sdb_decode (comma+1, 0); if (strstr (str, input+2)) { r_cons_printf ("0x%08"PFMT64x" %s\n", addr, str); count++; cb.addr = addr; free (cb.str); cb.str = str; } else free (str); } } else eprintf ("sdb_const_get key not found '%s'\n", key); if (!next) break; cur = next; } } switch (count) { case 0: eprintf ("No matching comments\n"); break; case 1: off = cb.addr; r_io_sundo_push (core->io, core->offset); r_core_seek (core, off, 1); r_core_block_read (core, 0); break; default: eprintf ("Too many results\n"); break; } free (cb.str); } else eprintf ("Usage: sC[?*] comment-grep\n" "sC* list all comments\n" "sC const seek to comment matching 'const'\n"); break; case ' ': r_io_sundo_push (core->io, core->offset); r_core_seek (core, off*sign, 1); r_core_block_read (core, 0); break; case '/': { const char *pfx = r_config_get (core->config, "search.prefix"); //kwidx cfg var is ignored int kwidx = core->search->n_kws; //(int)r_config_get_i (core->config, "search.kwidx")-1; if (kwidx<0) kwidx = 0; switch (input[1]) { case ' ': case 'x': r_config_set_i (core->config, "search.count", 1); r_core_cmdf (core, "s+1; p8 ; .%s;s-1;s %s%d_0;f-%s%d_0", input, pfx, kwidx, pfx, kwidx, pfx, kwidx); r_config_set_i (core->config, "search.count", 0); break; default: eprintf ("unknown search method\n"); break; } } break; case '.': for (input++;*input=='.';input++); r_core_seek_base (core, input); break; case '*': r_io_sundo_list (core->io); break; case '+': if (input[1]!='\0') { int delta = (input[1]=='+')? core->blocksize: off; r_io_sundo_push (core->io, core->offset); r_core_seek_delta (core, delta); } else { off = r_io_sundo_redo (core->io); if (off != UT64_MAX) r_core_seek (core, off, 0); } break; case '-': if (input[1]!='\0') { int delta = (input[1]=='-') ? -core->blocksize: -off; r_io_sundo_push (core->io, core->offset); r_core_seek_delta (core, delta); } else { off = r_io_sundo (core->io, core->offset); if (off != UT64_MAX) r_core_seek (core, off, 0); } break; case 'n': r_io_sundo_push (core->io, core->offset); r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'p': r_io_sundo_push (core->io, core->offset); r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'a': off = core->blocksize; if (input[1]&&input[2]) { cmd = strdup (input); p = strchr (cmd+2, ' '); if (p) { off = r_num_math (core->num, p+1);; *p = '\0'; } cmd[0] = 's'; // perform real seek if provided r_cmd_call (core->rcmd, cmd); free (cmd); } r_io_sundo_push (core->io, core->offset); r_core_seek_align (core, off, 0); break; case 'b': if (off == 0) off = core->offset; r_io_sundo_push (core->io, core->offset); r_core_anal_bb_seek (core, off); break; case 'f': if (strlen(input) > 2 && input[1]==' ') { RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, input+2); if (fcn) { r_core_seek (core, fcn->addr, 1); } break; } RAnalFunction *fcn = r_anal_fcn_find (core->anal, core->offset, 0); if (fcn) { r_core_seek (core, fcn->addr+fcn->size, 1); } break; case 'o': { RAnalOp op; int val=0, ret, i, n = r_num_math (core->num, input+1); if (n==0) n = 1; if (n<0) { int ret = prevopsz (core, n); ret = r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); val += ret; } else for (val=i=0; i<n; i++) { ret = r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); if (ret<1) break; r_core_seek_delta (core, ret); val += ret; } core->num->value = val; } break; case 'g': { RIOSection *s = r_io_section_vget (core->io, core->offset); if (s) r_core_seek (core, s->vaddr, 1); else r_core_seek (core, 0, 1); } break; case 'G': { RIOSection *s = r_io_section_vget (core->io, core->offset); // XXX: this +2 is a hack. must fix gap between sections if (s) r_core_seek (core, s->vaddr+s->size+2, 1); else r_core_seek (core, core->file->size, 1); } break; case '?': { const char * help_message[] = { "Usage: s", "", " # Seek commands", "s", "", "Print current address", "s", " addr", "Seek to address", "s-", "", "Undo seek", "s-", " n", "Seek n bytes backward", "s--", "", "Seek blocksize bytes backward", "s+", "", "Redo seek", "s+", " n", "Seek n bytes forward", "s++", "", "Seek blocksize bytes forward", "s*", "", "List undo seek history", "s/", " DATA", "Search for next occurrence of 'DATA'", "s/x", " 9091", "Search for next occurrence of \\x90\\x91", "s.", "hexoff", "Seek honoring a base from core->offset", "sa", " [[+-]a] [asz]", "Seek asz (or bsize) aligned to addr", "sb", "", "Seek aligned to bb start", "sC", " string", "Seek to comment matching given string", "sf", "", "Seek to next function (f->addr+f->size)", "sf", " function", "Seek to address of specified function", "sg/sG", "", "Seek begin (sg) or end (sG) of section or file", "sn/sp", "", "Seek next/prev scr.nkey", "so", " [N]", "Seek to N next opcode(s)", "sr", " pc", "Seek to register", //"sp [page] seek page N (page = block)", NULL }; r_core_cmd_help(core, help_message); } break; } } else r_cons_printf ("0x%"PFMT64x"\n", core->offset); return 0; }
static int cmd_meta_comment(RCore *core, const char *input) { ut64 addr = core->offset; switch (input[1]) { case '?': { const char* help_msg[] = { "Usage:", "CC[-+!*au] [base64:..|str] @ addr", "", "CC", "", "list all comments in human friendly form", "CC*", "", "list all comments in r2 commands", "CC.", "", "show comment at current offset", "CC,", " [file]", "show or set comment file", "CC", " [text]", "append comment at current address", "CCf", "", "list comments in function", "CC+", " [text]", "append comment at current address", "CC!", "", "edit comment using cfg.editor (vim, ..)", "CC-", " @ cmt_addr", "remove comment at given address", "CCu", " good boy @ addr", "add good boy comment at given address", "CCu", " base64:AA== @ addr", "add comment in base64", NULL}; r_core_cmd_help (core, help_msg); } break; case ',': // "CC," if (input[2]=='?') { eprintf ("Usage: CC, [file]\n"); } else if (input[2]==' ') { const char *fn = input+2; char *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); while (*fn== ' ')fn++; if (comment && *comment) { // append filename in current comment char *nc = r_str_newf ("%s ,(%s)", comment, fn); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, nc); free (nc); } else { char *comment = r_str_newf (",(%s)", fn); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, comment); free (comment); } } else { char *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); if (comment && *comment) { char *cmtfile = r_str_between (comment, ",(", ")"); if (cmtfile && *cmtfile) { char *getcommapath(RCore *core); char *cwd = getcommapath (core); r_cons_printf ("%s"R_SYS_DIR"%s\n", cwd, cmtfile); free (cwd); } free (cmtfile); } free (comment); } break; case '.': { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (comment) { r_cons_println (comment); free (comment); } } break; case 0: // "CC" r_meta_list (core->anal, R_META_TYPE_COMMENT, 0); break; case 'f': // "CCf" r_meta_list_at (core->anal, R_META_TYPE_COMMENT, 'f', core->offset); break; case 'j': // "CCj" r_meta_list (core->anal, R_META_TYPE_COMMENT, 'j'); break; case '!': { char *out, *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); out = r_core_editor (core, NULL, comment); if (out) { //r_meta_add (core->anal->meta, R_META_TYPE_COMMENT, addr, 0, out); r_core_cmdf (core, "CC-@0x%08"PFMT64x, addr); //r_meta_del (core->anal->meta, input[0], addr, addr+1, NULL); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, out); free (out); } free (comment); } break; case '+': case ' ': { const char* newcomment = r_str_chop_ro (input + 2); char *text, *comment = r_meta_get_string (core->anal, R_META_TYPE_COMMENT, addr); char *nc = strdup (newcomment); r_str_unescape (nc); if (comment) { text = malloc (strlen (comment)+strlen (newcomment)+2); if (text) { strcpy (text, comment); strcat (text, "\n"); strcat (text, nc); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, text); free (text); } else { r_sys_perror ("malloc"); } } else { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, nc); } free (nc); } break; case '*': r_meta_list (core->anal, R_META_TYPE_COMMENT, 1); break; case '-': // "CC-" r_meta_del (core->anal, R_META_TYPE_COMMENT, core->offset, 1, NULL); break; case 'u': // { char *newcomment; const char *arg = input + 2; while (*arg && *arg == ' ') arg++; if (!strncmp (arg, "base64:", 7)) { char *s = (char *)sdb_decode (arg+7, NULL); if (s) { newcomment = s; } else { newcomment = NULL; } } else { newcomment = strdup (arg); } if (newcomment) { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (!comment || (comment && !strstr (comment, newcomment))) { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, newcomment); } free (comment); free (newcomment); } } break; case 'a': { char *s, *p; s = strchr (input, ' '); if (s) { s = strdup (s + 1); } else { eprintf ("Usage\n"); return false; } p = strchr (s, ' '); if (p) { *p++ = 0; } ut64 addr; if (input[2]=='-') { if (input[3]) { addr = r_num_math (core->num, input+3); r_meta_del (core->anal, R_META_TYPE_COMMENT, addr, 1, NULL); } else eprintf ("Usage: CCa-[address]\n"); free (s); return true; } addr = r_num_math (core->num, s); // Comment at if (p) { if (input[2]=='+') { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (comment) { char* text = r_str_newf ("%s\n%s", comment, p); r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, text); free (text); } else { r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, p); } } else { r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr + 1, p); } } else { eprintf ("Usage: CCa [address] [comment]\n"); } free (s); return true; } } return true; }
static int cmd_seek(void *data, const char *input) { RCore *core = (RCore *)data; char *cmd, *p; ut64 off; if (*input == 'r') { if (input[1] && input[2]) { if (core->io->debug) { off = r_debug_reg_get (core->dbg, input + 2); r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek (core, off, 1); } else { RReg *orig = core->dbg->reg; core->dbg->reg = core->anal->reg; off = r_debug_reg_get (core->dbg, input + 2); core->dbg->reg = orig; r_core_seek (core, off, 1); } } else eprintf ("|Usage| 'sr PC' seek to program counter register\n"); } if (*input) { char* ptr; if ((ptr = strstr(input, "+.")) != NULL) { char* dup = strdup(input); dup[ptr - input] = '\x00'; off = r_num_math (core->num, dup + 1); core->offset = off; free (dup); } const char *inputnum = strchr (input, ' '); int sign = 1; { const char *u_num = inputnum? inputnum + 1: input + 1; off = r_num_math (core->num, u_num); if (*u_num == '-') off = -off; } #if 0 if (input[0]!='/' && inputnum && isalpha (inputnum[0]) && off == 0) { if (!r_flag_get (core->flags, inputnum)) { eprintf ("Cannot find address for '%s'\n", inputnum); return false; } } #endif if (input[0]==' ') { switch (input[1]) { case '-': sign=-1; case '+': input++; break; } } switch (*input) { case 'C': if (input[1]=='*') { r_core_cmd0 (core, "C*~^\"CC"); } else if (input[1]==' ') { typedef struct { ut64 addr; char *str; } MetaCallback; int count = 0; MetaCallback cb = { 0, NULL }; ut64 addr; char key[128]; const char *val, *comma; char *list = sdb_get (core->anal->sdb_meta, "meta.C", 0); char *str, *next, *cur = list; if (list) { for (;;) { cur = sdb_anext (cur, &next); addr = sdb_atoi (cur); snprintf (key, sizeof (key)-1, "meta.C.0x%"PFMT64x, addr); val = sdb_const_get (core->anal->sdb_meta, key, 0); if (val) { comma = strchr (val, ','); if (comma) { str = (char *)sdb_decode (comma+1, 0); if (strstr (str, input+2)) { r_cons_printf ("0x%08"PFMT64x" %s\n", addr, str); count++; cb.addr = addr; free (cb.str); cb.str = str; } else free (str); } } else eprintf ("sdb_const_get key not found '%s'\n", key); if (!next) break; cur = next; } } switch (count) { case 0: eprintf ("No matching comments\n"); break; case 1: off = cb.addr; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek (core, off, 1); r_core_block_read (core); break; default: eprintf ("Too many results\n"); break; } free (cb.str); } else { const char *help_msg[] = { "Usage:", "sC", "Comment grep", "sC", "*", "List all comments", "sC", " str", "Seek to the first comment matching 'str'", NULL }; r_core_cmd_help (core, help_msg); } break; case ' ': r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek (core, off * sign, 1); r_core_block_read (core); break; case '/': { const char *pfx = r_config_get (core->config, "search.prefix"); ut64 from = r_config_get_i (core->config, "search.from"); //kwidx cfg var is ignored int kwidx = core->search->n_kws; //(int)r_config_get_i (core->config, "search.kwidx")-1; if (kwidx<0) kwidx = 0; switch (input[1]) { case ' ': case 'v': case 'V': case 'w': case 'W': case 'z': case 'm': case 'c': case 'A': case 'e': case 'E': case 'i': case 'R': case 'r': case '/': case 'x': r_config_set_i (core->config, "search.from", core->offset+1); r_config_set_i (core->config, "search.count", 1); r_core_cmdf (core, "s+1; %s; s-1; s %s%d_0; f-%s%d_0", input, pfx, kwidx, pfx, kwidx, pfx, kwidx); r_config_set_i (core->config, "search.from", from); r_config_set_i (core->config, "search.count", 0); break; case '?': eprintf ("Usage: s/.. arg.\n"); r_cons_printf ("/?\n"); break; default: eprintf ("unknown search method\n"); break; } } break; case '.': for (input++;*input=='.';input++); r_core_seek_base (core, input); break; case '*': case '=': case 'j': r_io_sundo_list (core->io, input[0]); break; case '+': if (input[1]!='\0') { int delta = (input[1]=='+')? core->blocksize: off; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_delta (core, delta); } else { RIOUndos *undo = r_io_sundo_redo (core->io); if (undo != NULL) r_core_seek (core, undo->off, 0); } break; case '-': if (input[1]!='\0') { int delta = (input[1]=='-') ? -core->blocksize: -off; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_delta (core, delta); } else { RIOUndos *undo = r_io_sundo (core->io, core->offset); if (undo) { r_core_seek (core, undo->off, 0); r_core_block_read (core); } } break; case 'n': r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_next (core, r_config_get (core->config, "scr.nkey")); break; case 'p': r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_previous (core, r_config_get (core->config, "scr.nkey")); break; case 'a': off = core->blocksize; if (input[1]&&input[2]) { cmd = strdup (input); p = strchr (cmd+2, ' '); if (p) { off = r_num_math (core->num, p+1);; *p = '\0'; } cmd[0] = 's'; // perform real seek if provided r_cmd_call (core->rcmd, cmd); free (cmd); } r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_seek_align (core, off, 0); break; case 'b': if (off == 0) off = core->offset; r_io_sundo_push (core->io, core->offset, r_print_get_cursor (core->print)); r_core_anal_bb_seek (core, off); break; case 'f': // "sf" if (strlen(input) > 2 && input[1]==' ') { RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, input+2); if (fcn) { r_core_seek (core, fcn->addr, 1); } break; } RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); if (fcn) { r_core_seek (core, fcn->addr + r_anal_fcn_size (fcn), 1); } break; case 'o': // "so" { RAnalOp op; int val=0, ret, i, n = r_num_math (core->num, input+1); if (n==0) n = 1; if (n<0) { int instr_len; ut64 addr = core->offset; int numinstr = n * -1; if (r_core_prevop_addr (core, core->offset, numinstr, &addr)) { ret = core->offset - addr; } else { ret = r_core_asm_bwdis_len (core, &instr_len, &addr, numinstr); } r_core_seek (core, addr, true); val += ret; } else { for (val=i=0; i<n; i++) { ret = r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); if (ret<1) ret = 1; r_core_seek_delta (core, ret); val += ret; } } core->num->value = val; } break; case 'g': // "sg" { RIOSection *s = r_io_section_vget (core->io, core->offset); if (s) r_core_seek (core, s->vaddr, 1); else r_core_seek (core, 0, 1); } break; case 'G': // "sG" { if (!core->file) break; RIOSection *s = r_io_section_vget (core->io, core->offset); // XXX: this +2 is a hack. must fix gap between sections if (s) r_core_seek (core, s->vaddr+s->size+2, 1); else r_core_seek (core, r_io_desc_size (core->io, core->file->desc), 1); } break; case 'l': // "sl" { int sl_arg = r_num_math (core->num, input+1); const char *help_msg[] = { "Usage:", "sl+ or sl- or slc", "", "sl", " [line]", "Seek to absolute line", "sl", "[+-][line]", "Seek to relative line", "slc", "", "Clear line cache", "sll", "", "Show total number of lines", NULL }; switch (input[1]) { case 0: if (!core->print->lines_cache) { __init_seek_line (core); } __get_current_line (core); break; case ' ': if (!core->print->lines_cache) { __init_seek_line (core); } __seek_line_absolute (core, sl_arg); break; case '+': case '-': if (!core->print->lines_cache) { __init_seek_line (core); } __seek_line_relative (core, sl_arg); break; case 'c': __clean_lines_cache (core); break; case 'l': if (!core->print->lines_cache) { __init_seek_line (core); } eprintf ("%d lines\n", core->print->lines_cache_sz-1); break; case '?': r_core_cmd_help (core, help_msg); break; } } break; case ':': printPadded (core, atoi (input + 1)); break; case '?': { const char * help_message[] = { "Usage: s", "", " # Seek commands", "s", "", "Print current address", "s:", "pad", "Print current address with N padded zeros (defaults to 8)", "s", " addr", "Seek to address", "s-", "", "Undo seek", "s-", " n", "Seek n bytes backward", "s--", "", "Seek blocksize bytes backward", "s+", "", "Redo seek", "s+", " n", "Seek n bytes forward", "s++", "", "Seek blocksize bytes forward", "s[j*=]", "", "List undo seek history (JSON, =list, *r2)", "s/", " DATA", "Search for next occurrence of 'DATA'", "s/x", " 9091", "Search for next occurrence of \\x90\\x91", "s.", "hexoff", "Seek honoring a base from core->offset", "sa", " [[+-]a] [asz]", "Seek asz (or bsize) aligned to addr", "sb", "", "Seek aligned to bb start", "sC", "[?] string", "Seek to comment matching given string", "sf", "", "Seek to next function (f->addr+f->size)", "sf", " function", "Seek to address of specified function", "sg/sG", "", "Seek begin (sg) or end (sG) of section or file", "sl", "[?] [+-]line", "Seek to line", "sn/sp", "", "Seek next/prev scr.nkey", "so", " [N]", "Seek to N next opcode(s)", "sr", " pc", "Seek to register", //"sp [page] seek page N (page = block)", NULL }; r_core_cmd_help(core, help_message); } break; } } else r_cons_printf ("0x%"PFMT64x"\n", core->offset); return 0; }
static int cmd_meta_comment(RCore *core, const char *input) { ut64 addr = core->offset; switch (input[1]) { case '?': { const char* help_msg[] = { "Usage:", "CC[-+!*au] [base64:..|str] @ addr", "", "CC", "", "list all comments in human friednly form", "CC*", "", "list all comments in r2 commands", "CC.", "", "show comment at current offset", "CC", " or maybe not", "append comment at current address", "CC+", " same as above", "append comment at current address", "CC!", "", "edit comment using cfg.editor (vim, ..)", "CC-", " @ cmt_addr", "remove comment at given address", "CCu", " good boy @ addr", "add good boy comment at given address", "CCu", " base64:AA== @ addr", "add comment in base64", NULL}; r_core_cmd_help (core, help_msg); } break; case '.': { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (comment) { r_cons_printf ("%s\n", comment); free (comment); } } break; case 0: r_meta_list (core->anal, R_META_TYPE_COMMENT, 0); break; case '!': { char *out, *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); out = r_core_editor (core, NULL, comment); if (out) { //r_meta_add (core->anal->meta, R_META_TYPE_COMMENT, addr, 0, out); r_core_cmdf (core, "CC-@0x%08"PFMT64x, addr); //r_meta_del (core->anal->meta, input[0], addr, addr+1, NULL); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, out); free (out); } free (comment); } break; case '+': case ' ': { const char* newcomment = input+2; char *text, *nc; while (*newcomment==' ') newcomment++; char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); nc = strdup (newcomment); r_str_unescape (nc); if (comment) { text = malloc (strlen (comment)+strlen (newcomment)+2); strcpy (text, comment); strcat (text, "\n"); strcat (text, nc); r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, text); free (text); } else { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, nc); } free (nc); } break; case '*': r_meta_list (core->anal, R_META_TYPE_COMMENT, 1); break; case '-': r_meta_del (core->anal, R_META_TYPE_COMMENT, core->offset, 1, NULL); break; case 'u': // { char *newcomment; const char *arg = input+2; while (*arg && *arg == ' ') arg++; if (!strncmp (arg, "base64:", 7)) { char *s = (char *)sdb_decode (arg+7, NULL); if (s) { newcomment = s; } else { newcomment = NULL; } } else { newcomment = strdup (arg); } if (newcomment) { char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (!comment || (comment && !strstr (comment, newcomment))) { r_meta_set_string (core->anal, R_META_TYPE_COMMENT, addr, newcomment); } free (comment); free (newcomment); } } break; case 'a': { char *s, *p; s = strchr (input, ' '); if (s) { s = strdup (s+1); } else { eprintf ("Usage\n"); return R_FALSE; } p = strchr (s, ' '); if (p) *p++ = 0; ut64 addr; if (input[2]=='-') { if (input[3]) { addr = r_num_math (core->num, input+3); r_meta_del (core->anal, R_META_TYPE_COMMENT, addr, 1, NULL); } else eprintf ("Usage: CCa-[address]\n"); free (s); return R_TRUE; } addr = r_num_math (core->num, s); // Comment at if (p) { if (input[2]=='+') { char *text = p; char *comment = r_meta_get_string ( core->anal, R_META_TYPE_COMMENT, addr); if (comment) { text = malloc (strlen (comment) + strlen (p)+2); strcpy (text, comment); strcat (text, "\n"); strcat (text, p); r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, text); free (text); } else { r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, p); } } else { r_meta_add (core->anal, R_META_TYPE_COMMENT, addr, addr+1, p); } } else eprintf ("Usage: CCa [address] [comment]\n"); free (s); return R_TRUE; } } return R_TRUE; }
void r_comment_vars(RCore *core, const char *input) { //TODO enable base64 and make it the default for C* RAnalFunction *fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); int idx; char *oname = NULL, *name = NULL; char *oldcomment = NULL; char *heap_comment = NULL; RAnalVar *var; if (input[1] == '?' || (input[0] != 'b' && input[0] != 'r' && input[0] != 's') ) { r_comment_var_help (core, input[0]); return; } if (!fcn) { eprintf ("Cant find function here\n"); return; } oname = name = strdup (input + 2); while (*name == ' ') { name++; } switch (input[1]) { case '*': case '\0': { RList *var_list; RListIter *iter; var_list = r_anal_var_list (core->anal, fcn, input[0]); r_list_foreach (var_list, iter, var) { oldcomment = r_meta_get_var_comment (core->anal, input[0], var->delta, fcn->addr); if (!oldcomment) { continue; } if (!input[1]) { r_cons_printf ("%s : %s\n", var->name, oldcomment); } else { r_cons_printf ("\"Cv%c %s base64:%s @ 0x%08"PFMT64x"\"\n", input[0], var->name, sdb_encode ((const ut8 *) oldcomment, strlen(oldcomment)), fcn->addr); } } } break; case ' ': { // TODO check that idx exist char *comment = strstr (name, " "); if (comment) { // new comment given if (*comment) { *comment++ = 0; } if (!strncmp (comment, "base64:", 7)) { heap_comment = (char *)sdb_decode (comment + 7, NULL); comment = heap_comment; } } var = r_anal_var_get_byname (core->anal, fcn, name); if (var) { idx = var->delta; } else if (!strncmp (name, "0x", 2)) { idx = (int) r_num_get (NULL, name); } else if (!strncmp (name, "-0x", 3)) { idx = -(int) r_num_get (NULL, name+1); } else { eprintf ("cant find variable named `%s`\n",name); free (heap_comment); break; } r_anal_var_free (var); if (!r_anal_var_get (core->anal, fcn->addr, input[0], 1, idx)) { eprintf ("cant find variable at given offset\n"); } else { oldcomment = r_meta_get_var_comment (core->anal, input[0], idx, fcn->addr); if (oldcomment) { if (comment && *comment) { char *text = r_str_newf ("%s\n%s", oldcomment, comment); r_meta_set_var_comment (core->anal, input[0], idx, fcn->addr, text); free (text); } else { r_cons_println (oldcomment); } } else { r_meta_set_var_comment (core->anal, input[0], idx, fcn->addr, comment); } } free (heap_comment); } break; case '-': var = r_anal_var_get_byname (core->anal,fcn, name); if (var) { idx = var->delta; } else if (!strncmp (name, "0x", 2)) { idx = (int) r_num_get (NULL, name); } else if (!strncmp (name, "-0x", 3)) { idx = -(int) r_num_get (NULL, name+1); }else { eprintf ("cant find variable named `%s`\n",name); break; } r_anal_var_free (var); //XXX TODO here we leak a var if (!r_anal_var_get (core->anal, fcn->addr, input[0],1,idx)) { eprintf ("cant find variable at given offset\n"); break; } r_meta_var_comment_del (core->anal, input[0], idx, fcn->addr); break; case '!': { char *comment; var = r_anal_var_get_byname (core->anal,fcn, name); if (!var) { eprintf ("cant find variable named `%s`\n",name); break; } oldcomment = r_meta_get_var_comment (core->anal, input[0], var->delta, fcn->addr); comment = r_core_editor (core, NULL, oldcomment); if (comment) { r_meta_var_comment_del (core->anal, input[0], var->delta, fcn->addr); r_meta_set_var_comment (core->anal, input[0], var->delta, fcn->addr, comment); free (comment); } r_anal_var_free (var); } break; }