R_API ut64 r_io_seek(RIO *io, ut64 offset, int whence) { int posix_whence = SEEK_SET; ut64 ret = UT64_MAX; if (io->buffer_enabled) { io->off = offset; return offset; } switch (whence) { case R_IO_SEEK_SET: posix_whence = SEEK_SET; ret = offset; break; case R_IO_SEEK_CUR: // offset += io->off; posix_whence = SEEK_CUR; ret = offset+io->off; break; case R_IO_SEEK_END: //offset = UT64_MAX; // XXX: depending on io bits? ret = UT64_MAX; posix_whence = SEEK_END; break; } if (io == NULL) return ret; // XXX: list_empty trick must be done in r_io_set_va(); //eprintf ("-(seek)-> 0x%08llx\n", offset); if (!io->debug && io->va && !r_list_empty (io->sections)) { ut64 o = r_io_section_vaddr_to_offset (io, offset); if (o != UT64_MAX) offset = o; // eprintf ("-(vadd)-> 0x%08llx\n", offset); } // if resolution fails... just return as invalid address if (offset==UT64_MAX) return UT64_MAX; if (io->fd != NULL) { if (io->plugin && io->plugin->lseek) ret = io->plugin->lseek (io, io->fd, offset, whence); // XXX can be problematic on w32..so no 64 bit offset? else ret = (ut64)lseek (io->fd->fd, offset, posix_whence); if (ret != UT64_MAX) { io->off = ret; // XXX this can be tricky.. better not to use this .. must be deprecated // r_io_sundo_push (io); ret = (!io->debug && io->va && !r_list_empty (io->sections))? r_io_section_offset_to_vaddr (io, io->off) : io->off; } //else eprintf ("r_io_seek: cannot seek to %"PFMT64x"\n", offset); } //else { eprintf ("r_io_seek: null fd\n"); } return ret; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr, *out; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; switch (*str) { case '[': { ut64 n = 0LL; int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = NULL; if (strlen (str)>5) p = strchr (str+5, ':'); // TODO: honor LE if (p) { refsz = atoi (str+1); str = p; } // push state { if (str[0] && str[1]) { const char *q; char *o = strdup (str+1); if (o) { q = r_num_calc_index (core->num, NULL); if (q) { if (r_str_replace_char (o, ']', 0)>0) { n = r_num_math (core->num, o); r_num_calc_index (core->num, q); } } free (o); } } } // pop state if (ok) *ok = 1; ut32 num = 0; switch (refsz) { case 8: case 4: case 2: case 1: (void)r_io_read_at (core->io, n, (ut8*)&num, refsz); r_mem_copyendian ((ut8*)&num, (ut8*)&num, refsz, !core->assembler->big_endian); return num; default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); return 0LL; } } break; case '$': if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case 'k': if (str[2]!='{') { eprintf ("Expected '{' after 'k'.\n"); break; } bptr = strdup (str+3); ptr = strchr (bptr, '}'); if (ptr == NULL) { // invalid json free (bptr); break; } *ptr = '\0'; ret = 0LL; out = sdb_querys (core->sdb, NULL, 0, bptr); if (out && *out) { if (strstr (out, "$k{")) { eprintf ("Recursivity is not permitted here\n"); } else { ret = r_num_math (core->num, out); } } free (bptr); free (out); return ret; break; case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } free (bptr); break; case 'c': return r_cons_get_size (NULL); case 'r': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return r_anal_op_is_eob (&op); case 'j': return op.jump; case 'p': return r_sys_getpid (); case 'P': return (core->dbg->pid>0)? core->dbg->pid: 0; case 'f': return op.fail; case 'm': return op.ptr; // memref case 'v': return op.val; // immediate value case 'l': return op.size; case 'b': return core->blocksize; case 's': if (core->file) { return r_io_desc_size (core->io, core->file->desc); } return 0LL; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_vget (core->io, core->offset); return s? (str[2]=='S'? s->size: s->vaddr): 3; case '?': return core->num->value; case '$': return core->offset; case 'o': return r_io_section_vaddr_to_offset (core->io, core->offset); case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_get_fcn_in (core->anal, core->offset, 0); return fcn? fcn->size: 0; } break; default: if (*str>'A') { // NOTE: functions override flags RAnalFunction *fcn = r_anal_fcn_find_name (core->anal, str); if (fcn) { if (ok) *ok = R_TRUE; return fcn->addr; } #if 0 ut64 addr = r_anal_fcn_label_get (core->anal, core->offset, str); if (addr != 0) { ret = addr; } else { ... } #endif if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } break; }
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 eprintf ("cfg.debug is false\n"); } 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': { 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_get (core->io, r_io_section_vaddr_to_offset (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_get (core->io, r_io_section_vaddr_to_offset (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 '?': r_cons_printf ( "|Usage: s[+-] [addr]\n" "| s print current address\n" "| s 0x320 seek to this address\n" "| s- undo seek\n" "| s+ redo seek\n" "| s* list undo seek history\n" "| s++ seek blocksize bytes forward\n" "| s-- seek blocksize bytes backward\n" "| s+ 512 seek 512 bytes forward\n" "| s- 512 seek 512 bytes backward\n" "| sg/sG seek begin (sg) or end (sG) of section or file\n" "| s.hexoff Seek honoring a base from core->offset\n" "| sa [[+-]a] [asz] seek asz (or bsize) aligned to addr\n" "| sn/sp seek next/prev scr.nkey\n" "| s/ DATA search for next occurrence of 'DATA'\n" "| s/x 9091 search for next occurrence of \\x90\\x91\n" "| sb seek aligned to bb start\n" //"| sp [page] seek page N (page = block)\n" "| so [num] seek to N next opcode(s)\n" "| sf seek to next function (f->addr+f->size)\n" "| sC str seek to comment matching given string\n" "| sr pc seek to register\n"); break; } } else r_cons_printf ("0x%"PFMT64x"\n", core->offset); return 0; }
static ut64 num_callback(RNum *userptr, const char *str, int *ok) { RCore *core = (RCore *)userptr; // XXX ? RAnalFunction *fcn; char *ptr, *bptr; RFlagItem *flag; RIOSection *s; RAnalOp op; ut64 ret = 0; if (ok) *ok = R_FALSE; if (*str=='[') { int refsz = (core->assembler->bits & R_SYS_BITS_64)? 8: 4; const char *p = strchr (str+5, ':'); ut64 n; // TODO: honor endian if (p) { refsz = atoi (str+1); str = p; } // push state { char *o = strdup (str+1); const char *q = r_num_calc_index (core->num, NULL); r_str_replace_char (o, ']', 0); n = r_num_math (core->num, o); r_num_calc_index (core->num, q); free (o); } // pop state switch (refsz) { case 8: { ut64 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 4: { ut32 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 2: { ut16 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } case 1: { ut8 num = 0; r_io_read_at (core->io, n, (ut8*)&num, sizeof (num)); return num; } default: eprintf ("Invalid reference size: %d (%s)\n", refsz, str); break; } } else if (str[0]=='$') { if (ok) *ok = 1; // TODO: group analop-dependant vars after a char, so i can filter r_anal_op (core->anal, &op, core->offset, core->block, core->blocksize); switch (str[1]) { case '.': // can use pc, sp, a0, a1, ... return r_debug_reg_get (core->dbg, str+2); case '{': bptr = strdup (str+2); ptr = strchr (bptr, '}'); if (ptr != NULL) { ut64 ret; ptr[0] = '\0'; ret = r_config_get_i (core->config, bptr); free (bptr); return ret; } break; case 'h': { int rows; r_cons_get_size (&rows); return rows; } case 'e': return op.eob; case 'j': return op.jump; case 'f': return op.fail; case 'r': return op.ref; case 'l': return op.length; case 'b': return core->blocksize; case 's': return core->file->size; case 'w': return r_config_get_i (core->config, "asm.bits") / 8; case 'S': s = r_io_section_get (core->io, r_io_section_vaddr_to_offset (core->io, core->offset)); return s? (str[2]=='S'? s->size: s->offset): 0; case '?': return core->num->value; case '$': return core->offset; case 'o': return core->io->off; case 'C': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CALL); case 'J': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_CODE); case 'D': return getref (core, atoi (str+2), 'r', R_ANAL_REF_TYPE_DATA); case 'X': return getref (core, atoi (str+2), 'x', R_ANAL_REF_TYPE_CALL); case 'I': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->ninstr: 0; case 'F': fcn = r_anal_fcn_find (core->anal, core->offset, 0); return fcn? fcn->size: 0; } } else if (*str>'A') { if ((flag = r_flag_get (core->flags, str))) { ret = flag->offset; if (ok) *ok = R_TRUE; } } return ret; }
R_API int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len) { ut64 paddr, last, last2; int ms, ret, l, olen = len, w = 0; io->off = addr; memset (buf, 0xff, len); // probably unnecessary if (io->buffer_enabled) return r_io_buffer_read (io, addr, buf, len); while (len>0) { last = r_io_section_next (io, addr+w); last2 = r_io_map_next (io, addr+w); // XXX: must use physical address if (last == (addr+w)) last = last2; //else if (last2<last) last = last2; l = (len > (last-addr+w))? (last-addr+w): len; if (l<1) l = len; { paddr = w? r_io_section_vaddr_to_offset (io, addr+w): addr; if (len>0 && l>len) l = len; addr = paddr-w; if (r_io_seek (io, paddr, R_IO_SEEK_SET)==UT64_MAX) { memset (buf+w, 0xff, l); } } #if 0 if (io->zeromap) if (!r_io_map_get (io, addr+w)) { if (addr==0||r_io_section_getv (io, addr+w)) { memset (buf+w, 0xff, l); eprintf ("RETRERET\n"); return -1; } } #endif // XXX is this necessary? ms = r_io_map_select (io, addr+w); ret = r_io_read_internal (io, buf+w, l); //eprintf ("READ %d = %02x %02x %02x\n", ret, buf[w], buf[w+1], buf[w+2]); if (ret<1) { memset (buf+w, 0xff, l); // reading out of file ret = 1; } else if (ret<l) { l = ret; } #if USE_CACHE if (io->cached) { r_io_cache_read (io, addr+w, buf+w, len-w); } else if (r_list_length (io->maps) >1) { if (!io->debug && ms>0) { //eprintf ("FAIL MS=%d l=%d d=%d\n", ms, l, d); /* check if address is vaddred in sections */ ut64 o = r_io_section_offset_to_vaddr (io, addr+w); if (o == UT64_MAX) { ut64 o = r_io_section_vaddr_to_offset (io, addr+w); if (o == UT64_MAX) memset (buf+w, 0xff, l); } break; } } #endif w += l; len -= l; } return olen; }
R_API int r_io_read_at(RIO *io, ut64 addr, ut8 *buf, int len) { int ret, l, olen = len; int w = 0; #if 0 // HACK?: if io->va == 0 -> call seek+read without checking sections ? if (!io->va) { // r_io_seek (io, addr, R_IO_SEEK_SET); r_io_map_select (io, addr); ret = r_io_read_internal (io, buf, len); if (io->cached) { r_io_cache_read (io, addr, buf, len); } return ret; } #endif // XXX: this is buggy! while (len>0) { int ms; ut64 last = r_io_section_next (io, addr); l = (len > (last-addr))? (last-addr): len; if (l<1) l = len; // ignore seek errors // eprintf ("0x%llx %llx\n", addr+w, //r_io_seek (io, addr+w, R_IO_SEEK_SET); if (r_io_seek (io, addr+w, R_IO_SEEK_SET)==UT64_MAX) { memset (buf+w, 0xff, l); return -1; } ms = r_io_map_select (io, addr+w); ret = r_io_read_internal (io, buf+w, l); if (ret<1) { memset (buf+w, 0xff, l); // reading out of file ret = 1; } else if (ret<l) { // eprintf ("FOUND EOF AT %llx\n", addr+ret); l = ret; } if (io->cached) { r_io_cache_read (io, addr+w, buf+w, l); /* * XXX: The 'else' below is fixing the io.cache * with resized files. That may be wrong */ } else // hide non-mapped files here // do not allow reading on real addresses if mapped != 0 if (!io->debug && ms>0) { //eprintf ("FAIL MS=%d l=%d d=%d\n", ms, l, d); /* check if address is vaddred in sections */ ut64 o = r_io_section_offset_to_vaddr (io, addr); if (o == UT64_MAX) { ut64 o = r_io_section_vaddr_to_offset (io, addr); if (o == UT64_MAX) memset (buf+w, 0xff, l); } break; } w += l; len -= l; } return olen; }