示例#1
0
R_API int r_core_visual_cmd(RCore *core, int ch) {
    RAsmOp op;
    ut64 offset = core->offset;
    char buf[4096];
    int i, ret, offscreen, cols = core->print->cols, delta = 0;
    ch = r_cons_arrow_to_hjkl (ch);
    ch = visual_nkey (core, ch);
    if (ch<2) return 1;

    // do we need hotkeys for data references? not only calls?
    if (ch>='0'&& ch<='9') {
        ut64 off = core->asmqjmps[ch-'0'];
        if (off != UT64_MAX) {
            int delta = R_ABS ((st64)off-(st64)offset);
            r_io_sundo_push (core->io, offset);
            if (curset && delta<100) {
                cursor = delta;
            } else {
                r_core_visual_seek_animation (core, off);
                //r_core_seek (core, off, 1);
            }
            r_core_block_read (core, 1);
        }
    } else
        switch (ch) {
        case 0x0d:
        {
            r_cons_enable_mouse (R_TRUE);
            RAnalOp *op = r_core_anal_op (core, core->offset+cursor);
            if (op) {
                if (op->type == R_ANAL_OP_TYPE_JMP	||
                        op->type == R_ANAL_OP_TYPE_CJMP ||
                        op->type == R_ANAL_OP_TYPE_CALL) {
                    r_io_sundo_push (core->io, offset);
                    r_core_visual_seek_animation(core, op->jump);
                }
            }
            r_anal_op_free (op);
        }
        break;
        case 90: // shift+tab
            if (!strcmp (printfmt[0], "x"))
                printfmt[0] = "pxa";
            else printfmt[0] = "x";
            break;
        case 9: // tab
        {   // XXX: unify diff mode detection
            ut64 f = r_config_get_i (core->config, "diff.from");
            ut64 t = r_config_get_i (core->config, "diff.to");
            if (f == t && f == 0) {
                core->print->col = core->print->col==1? 2: 1;
            } else {
                ut64 delta = offset - f;
                r_core_seek (core, t+delta, 1);
                r_config_set_i (core->config, "diff.from", t);
                r_config_set_i (core->config, "diff.to", f);
            }
        }
        break;
        case 'a':
            if (core->file && !(core->file->rwx & 2)) {
                r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n");
                r_cons_any_key ();
                return R_TRUE;
            }
            r_cons_printf ("Enter assembler opcodes separated with ';':\n");
            showcursor (core, R_TRUE);
            r_cons_flush ();
            r_cons_set_raw (R_FALSE);
            strcpy (buf, "wa ");
            r_line_set_prompt (":> ");
            if (r_cons_fgets (buf+3, 1000, 0, NULL) <0) buf[0]='\0';
            if (*buf) {
                if (curset) r_core_seek (core, core->offset + cursor, 0);
                r_core_cmd (core, buf, R_TRUE);
                if (curset) r_core_seek (core, core->offset - cursor, 1);
            }
            showcursor (core, R_FALSE);
            r_cons_set_raw (R_TRUE);
            break;
        case '!':
            r_cons_2048();
            break;
        case 'o':
            visual_offset (core);
            break;
        case 'A':
        {   int oc = curset;
            ut64 off = curset? core->offset+cursor : core->offset;
            curset = 0;
            r_core_visual_asm (core, off);
            curset = oc;
        }
        break;
        case 'c':
            setcursor (core, curset?0:1);
            break;
        case 'C':
            color = color? 0: 1;
            r_config_set_i (core->config, "scr.color", color);
            break;
        case 'd':
            r_core_visual_define (core);
            break;
        case 'D':
            setdiff (core);
            break;
        case 'f':
        {
            int range, min, max;
            char name[256], *n;
            r_line_set_prompt ("flag name: ");
            showcursor (core, R_TRUE);
            if (r_cons_fgets (name, sizeof (name), 0, NULL) >=0 && *name) {
                n = r_str_chop (name);
                if (*name=='-') {
                    if (*n) r_flag_unset (core->flags, n+1, NULL);
                } else {
                    if (ocursor != -1) {
                        min = R_MIN (cursor, ocursor);
                        max = R_MAX (cursor, ocursor);
                    } else {
                        min = max = cursor;
                    }
                    range = max-min+1;
                    if (range<1) range = 1;
                    if (*n) r_flag_set (core->flags, n,
                                            core->offset + min, range, 1);
                }
            }
        }
        showcursor (core, R_FALSE);
        break;
        case 'F':
            r_flag_unset_i (core->flags, core->offset + cursor, NULL);
            break;
        case 'n':
            r_core_seek_next (core, r_config_get (core->config, "scr.nkey"));
            break;
        case 'N':
            r_core_seek_previous (core, r_config_get (core->config, "scr.nkey"));
            break;
        case 'i':
        case 'I':
            if (core->file && !(core->file->rwx & 2)) {
                r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n");
                r_cons_any_key ();
                return R_TRUE;
            }
            showcursor (core, R_TRUE);
            r_cons_flush ();
            r_cons_set_raw (0);
            if (ch=='I') {
                strcpy (buf, "wow ");
                r_line_set_prompt ("insert hexpair block: ");
                if (r_cons_fgets (buf+4, sizeof (buf)-5, 0, NULL) <0)
                    buf[0]='\0';
                char *p = strdup (buf);
                int cur = core->print->cur;
                if (cur>=core->blocksize)
                    cur = core->print->cur-1;
                snprintf (buf, sizeof (buf), "%s @ $$0!%i", p,
                          core->blocksize-cursor);
                r_core_cmd (core, buf, 0);
                free (p);
                break;
            }
            delta = (ocursor!=-1)? R_MIN (cursor, ocursor): cursor;
            if (core->print->col==2) {
                strcpy (buf, "\"w ");
                r_line_set_prompt ("insert string: ");
                if (r_cons_fgets (buf+3, sizeof (buf)-4, 0, NULL) <0)
                    buf[0]='\0';
                strcat (buf, "\"");
            } else {
                r_line_set_prompt ("insert hex: ");
                if (ocursor != -1) {
                    int bs = R_ABS (cursor-ocursor)+1;
                    core->blocksize = bs;
                    strcpy (buf, "wow ");
                } else {
                    strcpy (buf, "wx ");
                }
                if (r_cons_fgets (buf+strlen (buf), sizeof (buf)-strlen (buf), 0, NULL) <0)
                    buf[0]='\0';
            }
            if (curset) r_core_seek (core, core->offset + delta, 0);
            r_core_cmd (core, buf, 1);
            if (curset) r_core_seek (core, offset, 1);
            r_cons_set_raw (1);
            showcursor (core, R_FALSE);
            break;
        case 'R':
            r_core_cmd0 (core, "ecr");
            break;
        case 'e':
            r_core_visual_config (core);
            break;
        case 'E':
            r_core_visual_colors (core);
            break;
        case 'M':
            r_core_visual_mounts (core);
            break;
        case 't':
            r_core_visual_trackflags (core);
            break;
        case 'x':
        {
            int count = 0;
            RList *xrefs = NULL;
            RAnalRef *refi;
            RListIter *iter;
            RAnalFunction *fun;

            if ((xrefs = r_anal_xref_get (core->anal, core->offset))) {
                r_cons_gotoxy (1, 1);
                r_cons_printf ("[GOTO XREF]> \n");
                if (r_list_empty (xrefs)) {
                    r_cons_printf ("\tNo XREF found at 0x%"PFMT64x"\n", core->offset);
                    r_cons_any_key ();
                    r_cons_clear00 ();
                } else {
                    r_list_foreach (xrefs, iter, refi) {
                        fun = r_anal_fcn_find (core->anal, refi->addr, R_ANAL_FCN_TYPE_NULL);
                        r_cons_printf (" [%i] 0x%08"PFMT64x" %s XREF 0x%08"PFMT64x" (%s)                      \n", count,
                                       refi->at,
                                       refi->type==R_ANAL_REF_TYPE_CODE?"CODE (JMP)":
                                       refi->type==R_ANAL_REF_TYPE_CALL?"CODE (CALL)":"DATA", refi->addr,
                                       fun?fun->name:"unk");
                        if (++count > 9) break;
                    }
                }
            } else xrefs = NULL;
示例#2
0
R_API int r_core_visual_cmd(RCore *core, int ch) {
	RAsmOp op;
	char buf[4096];
	int i, ret, offscreen, cols = core->print->cols;
	ch = r_cons_arrow_to_hjkl (ch);
	ch = visual_nkey (core, ch);
	if (ch<2) return 1;

	// do we need hotkeys for data references? not only calls?
	if (ch>='0'&& ch<='9') {
		r_io_sundo_push (core->io, core->offset);
		r_core_seek (core, core->asmqjmps[ch-'0'], 1);
		r_core_block_read (core, 1);
	} else
	switch (ch) {
	case 9: // tab
		{ // XXX: unify diff mode detection
		ut64 f = r_config_get_i (core->config, "diff.from");
		ut64 t = r_config_get_i (core->config, "diff.to");
		if (f == t && f == 0) {
			core->print->col = core->print->col==1? 2: 1;
		} else {
			ut64 delta = core->offset - f;
			r_core_seek (core, t+delta, 1);
			r_config_set_i (core->config, "diff.from", t);
			r_config_set_i (core->config, "diff.to", f);
		}
		}
		break;
	case 'c':
		// XXX dupped flag imho
		setcursor (core, curset ^ 1);
		break;
	case 'd':
		r_core_visual_define (core);
		break;
	case 'D':
		setdiff (core);
		break;
	case 'C':
		color ^= 1;
		if (color) flags |= R_PRINT_FLAGS_COLOR;
		else flags &= ~(flags&R_PRINT_FLAGS_COLOR);
		r_config_set_i (core->config, "scr.color", color);
		r_print_set_flags (core->print, flags);
		break;
	case 'f':
		{
		int range;
		char name[256], *n;
		r_line_set_prompt ("flag name: ");
		if (r_cons_fgets (name, sizeof (name), 0, NULL) >=0 && *name) {
			n = r_str_chop (name);
			if (*name=='-') {
				if (*n) r_flag_unset (core->flags, n+1, NULL);
			} else {
				range = curset? (R_ABS (cursor-ocursor)+1): 1;
				if (range<1) range = 1;
				if (*n) r_flag_set (core->flags, n,
					core->offset + cursor, range, 1);
			}
		} }
		break;
	case 'F':
		r_flag_unset_i (core->flags, core->offset + cursor, NULL);
		break;
	case 'n':
		r_core_seek_next (core, r_config_get (core->config, "scr.nkey"));
		break;
	case 'N':
		r_core_seek_previous (core, r_config_get (core->config, "scr.nkey"));
		break;
	case 'A':
		{ int oc = curset;
		ut64 off = curset? core->offset+cursor : core->offset;
		curset = 0;
		r_core_visual_asm (core, off);
		curset = oc;
		}
		break;
	case 'a':
		if (core->file && !(core->file->rwx & 2)) {
			r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n");
			r_cons_any_key ();
			return R_TRUE;
		}
		r_cons_printf ("Enter assembler opcodes separated with ';':\n");
		r_cons_show_cursor (R_TRUE);
		r_cons_flush ();
		r_cons_set_raw (R_FALSE);
		strcpy (buf, "wa ");
		r_line_set_prompt (":> ");
		if (r_cons_fgets (buf+3, 1000, 0, NULL) <0) buf[0]='\0';
		if (*buf) {
			if (curset) r_core_seek (core, core->offset + cursor, 0);
			r_core_cmd (core, buf, R_TRUE);
			if (curset) r_core_seek (core, core->offset - cursor, 1);
		}
		r_cons_show_cursor (R_FALSE);
		r_cons_set_raw (R_TRUE);
		break;
	case 'i':
	case 'I':
		if (core->file && !(core->file->rwx & 2)) {
			r_cons_printf ("\nFile has been opened in read-only mode. Use -w flag\n");
			r_cons_any_key ();
			return R_TRUE;
		}
		r_cons_show_cursor (R_TRUE);
		r_cons_flush ();
		r_cons_set_raw (0);
		if (ch=='I') {
			strcpy (buf, "wow ");
			r_line_set_prompt ("insert hexpair block: ");
			if (r_cons_fgets (buf+4, sizeof (buf)-3, 0, NULL) <0)
				buf[0]='\0';
			char *p = strdup (buf);
			int cur = core->print->cur;
			if (cur>=core->blocksize)
				cur = core->print->cur-1;
			snprintf (buf, sizeof (buf), "%s @ $$0!%i", p,
				core->blocksize-cursor);
			r_core_cmd (core, buf, 0);
			free (p);
			break;
		}
		if (core->print->col==2) {
			strcpy (buf, "w ");
			r_line_set_prompt ("insert string: ");
			if (r_cons_fgets (buf+2, sizeof (buf)-3, 0, NULL) <0)
				buf[0]='\0';
		} else {
			strcpy (buf, "wx ");
			r_line_set_prompt ("insert hex: ");
			if (r_cons_fgets (buf+3, sizeof (buf)-4, 0, NULL) <0)
				buf[0]='\0';
		}
		if (curset) r_core_seek (core, core->offset + cursor, 0);
		r_core_cmd (core, buf, 1);
		if (curset) r_core_seek (core, core->offset - cursor, 1);
		r_cons_set_raw (1);
		r_cons_show_cursor (R_FALSE);
		break;
	case 'e':
		r_core_visual_config (core);
		break;
	case 'M':
		r_core_visual_mounts (core);
		break;
	case 't':
		r_core_visual_trackflags (core);
		break;
	case 'x':
		{
		int count = 0;
		RList *xrefs = NULL;
		RAnalRef *refi;
		RListIter *iter;
		RAnalFunction *fun;

		if ((xrefs = r_anal_xref_get (core->anal, core->offset))) {
			r_cons_printf ("XREFS:\n");
			if (r_list_empty (xrefs)) {
				r_cons_printf ("\tNo XREF found at 0x%"PFMT64x"\n", core->offset);
				r_cons_any_key ();
				r_cons_clear00 ();
			} else {
				r_list_foreach (xrefs, iter, refi) {
					fun = r_anal_fcn_find (core->anal, refi->addr, R_ANAL_FCN_TYPE_NULL);
					r_cons_printf ("\t[%i] %s XREF 0x%08"PFMT64x" (%s)\n", count,
							refi->type==R_ANAL_REF_TYPE_CODE?"CODE (JMP)":
							refi->type==R_ANAL_REF_TYPE_CALL?"CODE (CALL)":"DATA", refi->addr,
							fun?fun->name:"unk");
					if (++count > 9) break;
				}
			}
		} else xrefs = NULL;
示例#3
0
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;
}
示例#4
0
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;
}