mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-14 08:49:50 +00:00
9b47635f0c
This was originally used to cause a seek to the next block prior to reading such that successive calls to r_core_block_read() would progress through memory one block at a time. This was broken, though, by commit452669d941
("more cleanup in r_core_block_read") when when it used `next' to directly calculate the offset rather than via a seek. Only one call site remains that attempts to read the next block instead of the current, and this probably was not even observable due to the "hacky fix" added in commit3bfa61946e
("Cleaner pvj, fix tinype load, and honor 'ao N's"). The current of semantics of `next' appear to be broken and there is very little dependence on it. If the original behavior should be restored anywhere, it would be much better to add a new function, or just do the seek explicitly, rather than parameterizing r_core_block_read() on it.
494 lines
12 KiB
C
494 lines
12 KiB
C
/* radare2 - LGPL - Copyright 2009-2015 - pancake */
|
|
|
|
#include "r_core.h"
|
|
|
|
R_API int r_core_setup_debugger (RCore *r, const char *debugbackend, bool attach) {
|
|
int pid, *p = NULL;
|
|
ut8 is_gdb = (strcmp (debugbackend, "gdb") == 0);
|
|
RIODesc * fd = r->file ? r->file->desc : NULL;
|
|
const char *prompt = NULL;
|
|
|
|
p = fd ? fd->data : NULL;
|
|
r_config_set_i (r->config, "cfg.debug", 1);
|
|
if (!p) {
|
|
eprintf ("Invalid debug io\n");
|
|
return false;
|
|
}
|
|
|
|
pid = *p; // 1st element in debugger's struct must be int
|
|
r_config_set (r->config, "io.ff", "true");
|
|
if (is_gdb)
|
|
r_core_cmd (r, "dh gdb", 0);
|
|
else
|
|
r_core_cmdf (r, "dh %s", debugbackend);
|
|
//this makes to attach twice showing warnings in the output
|
|
//we get "resource busy" so it seems isn't an issue
|
|
if (attach)
|
|
r_core_cmdf (r, "dpa %d", pid);
|
|
r_core_cmdf (r, "dp=%d", pid);
|
|
r_core_cmd (r, ".dr*", 0);
|
|
/* honor dbg.bep */
|
|
{
|
|
const char *bep = r_config_get (r->config, "dbg.bep");
|
|
if (bep) {
|
|
if (!strcmp (bep, "loader")) {
|
|
/* do nothing here */
|
|
} else if (!strcmp (bep, "entry")) {
|
|
r_core_cmd (r, "dcu entry0", 0);
|
|
} else {
|
|
r_core_cmdf (r, "dcu %s", bep);
|
|
}
|
|
}
|
|
}
|
|
r_core_cmd (r, "sr PC", 0);
|
|
|
|
/* set the prompt if it's not been set already by the callbacks */
|
|
prompt = r_config_get (r->config, "cmd.prompt");
|
|
if (prompt && !strcmp (prompt, "")) {
|
|
if (r_config_get_i (r->config, "dbg.status"))
|
|
r_config_set (r->config, "cmd.prompt", ".dr*;drd;sr PC;pi 1;s-");
|
|
else
|
|
r_config_set (r->config, "cmd.prompt", ".dr*");
|
|
}
|
|
r_config_set (r->config, "cmd.vprompt", ".dr*");
|
|
return true;
|
|
}
|
|
|
|
R_API int r_core_seek_base (RCore *core, const char *hex) {
|
|
ut64 addr = r_num_tail (core->num, core->offset, hex);
|
|
return r_core_seek (core, addr, 1);
|
|
}
|
|
|
|
R_API int r_core_dump(RCore *core, const char *file, ut64 addr, ut64 size, int append) {
|
|
ut64 i;
|
|
ut8 *buf;
|
|
int bs = core->blocksize;
|
|
FILE *fd;
|
|
if (append) {
|
|
fd = r_sandbox_fopen (file, "ab");
|
|
} else {
|
|
r_sys_truncate (file, 0);
|
|
fd = r_sandbox_fopen (file, "wb");
|
|
}
|
|
if (!fd) {
|
|
eprintf ("Cannot open '%s' for writing\n", file);
|
|
return false;
|
|
}
|
|
/* some io backends seems to be buggy in those cases */
|
|
if (bs > 4096)
|
|
bs = 4096;
|
|
buf = malloc (bs);
|
|
if (!buf) {
|
|
eprintf ("Cannot alloc %d bytes\n", bs);
|
|
fclose (fd);
|
|
return false;
|
|
}
|
|
r_cons_break (NULL, NULL);
|
|
for (i = 0; i<size; i += bs) {
|
|
if (r_cons_singleton ()->breaked)
|
|
break;
|
|
if ((i + bs) > size)
|
|
bs = size - i;
|
|
r_io_read_at (core->io, addr + i, buf, bs);
|
|
if (fwrite (buf, bs, 1, fd) < 1) {
|
|
eprintf ("write error\n");
|
|
break;
|
|
}
|
|
}
|
|
eprintf ("dumped 0x%"PFMT64x" bytes\n", i);
|
|
r_cons_break_end ();
|
|
fclose (fd);
|
|
free (buf);
|
|
return true;
|
|
}
|
|
|
|
R_API int r_core_write_op(RCore *core, const char *arg, char op) {
|
|
int i, j, len, ret = false;
|
|
char *str = NULL;
|
|
ut8 *buf;
|
|
|
|
// XXX we can work with config.block instead of dupping it
|
|
buf = (ut8 *)malloc (core->blocksize);
|
|
if (!buf)
|
|
goto beach;
|
|
memcpy (buf, core->block, core->blocksize);
|
|
|
|
if (op!='e') {
|
|
// fill key buffer either from arg or from clipboard
|
|
if (arg) { // parse arg for key
|
|
// r_hex_str2bin() is guaranteed to output maximum half the
|
|
// input size, or 1 byte if there is just a single nibble.
|
|
str = (char *)malloc (strlen (arg) / 2 + 1);
|
|
if (!str)
|
|
goto beach;
|
|
len = r_hex_str2bin (arg, (ut8 *)str);
|
|
// Output is invalid if there was just a single nibble,
|
|
// but in that case, len is negative (-1).
|
|
if (len <= 0) {
|
|
eprintf ("Invalid hexpair string\n");
|
|
goto beach;
|
|
}
|
|
} else { // use clipboard as key
|
|
len = core->yank_buf->length;
|
|
if (len <= 0) {
|
|
eprintf ("Clipboard is empty and no value argument(s) given\n");
|
|
goto beach;
|
|
}
|
|
str = r_mem_dup (core->yank_buf->buf, len);
|
|
if (!str)
|
|
goto beach;
|
|
}
|
|
} else len = 0;
|
|
|
|
// execute the operand
|
|
if (op=='e') {
|
|
int wordsize = 1;
|
|
char *os, *p, *s = strdup (arg);
|
|
int n, from = 0, to = 0, dif = 0, step = 1;
|
|
n = from = to;
|
|
os = s;
|
|
to = UT8_MAX;
|
|
//
|
|
p = strchr (s, ' ');
|
|
if (p) {
|
|
*p = 0;
|
|
from = r_num_math (core->num, s);
|
|
s = p+1;
|
|
}
|
|
p = strchr (s, ' ');
|
|
if (p) {
|
|
*p = 0;
|
|
to = r_num_math (core->num, s);
|
|
s = p+1;
|
|
}
|
|
p = strchr (s, ' ');
|
|
if (p) {
|
|
*p = 0;
|
|
step = r_num_math (core->num, s);
|
|
s = p+1;
|
|
wordsize = r_num_math (core->num, s);
|
|
} else {
|
|
step = r_num_math (core->num, s);
|
|
}
|
|
free (os);
|
|
eprintf ("from %d to %d step %d size %d\n", from, to, step, wordsize);
|
|
dif = (to<=from)? UT8_MAX: (to-from)+1;
|
|
if (wordsize==1) {
|
|
if (to<1 || to>UT8_MAX) to = UT8_MAX;
|
|
from %= (UT8_MAX+1);
|
|
}
|
|
if (dif<1) dif = UT8_MAX+1;
|
|
if (step<1) step = 1;
|
|
if (wordsize<1) wordsize = 1;
|
|
if (wordsize == 1) {
|
|
for (i=n=0; i<core->blocksize; i++, n+= step)
|
|
buf[i] = (ut8)(n % dif) + from;
|
|
} else if (wordsize == 2) {
|
|
ut16 num16 = from;
|
|
for (i = 0; i < core->blocksize; i += wordsize, num16 += step) {
|
|
r_write_le16 (buf + i, num16);
|
|
}
|
|
} else if (wordsize == 4) {
|
|
ut32 num32 = from;
|
|
for (i = 0; i < core->blocksize; i += wordsize, num32 += step) {
|
|
r_write_le32 (buf + i, num32);
|
|
}
|
|
} else if (wordsize == 8) {
|
|
ut64 num64 = from;
|
|
for (i = 0; i < core->blocksize; i += wordsize, num64 += step) {
|
|
r_write_le64 (buf + i, num64);
|
|
}
|
|
} else {
|
|
eprintf ("Invalid word size. Use 1, 2, 4 or 8\n");
|
|
}
|
|
} else
|
|
if (op=='2' || op=='4') {
|
|
op -= '0';
|
|
// if i < core->blocksize would pass the test but buf[i+3] goes beyond the buffer
|
|
if (core->blocksize > 3) {
|
|
for (i=0; i<core->blocksize-3; i+=op) {
|
|
/* endian swap */
|
|
ut8 tmp = buf[i];
|
|
buf[i] = buf[i+3];
|
|
buf[i+3] = tmp;
|
|
if (op==4) {
|
|
tmp = buf[i+1];
|
|
buf[i+1] = buf[i+2];
|
|
buf[i+2] = tmp;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for (i=j=0; i<core->blocksize; i++) {
|
|
switch (op) {
|
|
case 'x': buf[i] ^= str[j]; break;
|
|
case 'a': buf[i] += str[j]; break;
|
|
case 's': buf[i] -= str[j]; break;
|
|
case 'm': buf[i] *= str[j]; break;
|
|
case 'w': buf[i] = str[j]; break;
|
|
case 'd': buf[i] = (str[j])? buf[i] / str[j]: 0; break;
|
|
case 'r': buf[i] >>= str[j]; break;
|
|
case 'l': buf[i] <<= str[j]; break;
|
|
case 'o': buf[i] |= str[j]; break;
|
|
case 'A': buf[i] &= str[j]; break;
|
|
}
|
|
j++; if (j>=len) j=0; /* cyclic key */
|
|
}
|
|
}
|
|
|
|
ret = r_core_write_at (core, core->offset, buf, core->blocksize);
|
|
beach:
|
|
free (buf);
|
|
free (str);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void _set_bits(RCore *core, ut64 addr, int *bits) {
|
|
RAnalRange *range;
|
|
RListIter *iter;
|
|
|
|
r_list_foreach (core->anal->bits_ranges, iter, range) {
|
|
if (addr >= range->from && addr < range->to) {
|
|
*bits = range->bits;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
R_API int r_core_seek_archbits(RCore *core, ut64 addr) {
|
|
static char *oldarch = NULL;
|
|
static int oldbits = 0;
|
|
bool flag = false;
|
|
int bits = 0;
|
|
char *arch = (char *)r_io_section_get_archbits (core->io, addr, &bits);
|
|
if (!bits) {
|
|
_set_bits (core, addr, &bits);
|
|
}
|
|
if (!arch) {
|
|
arch = strdup (r_config_get (core->config, "asm.arch"));
|
|
flag = true;
|
|
} else {
|
|
arch = strdup (arch);
|
|
}
|
|
if (arch && bits) {
|
|
if (bits != oldbits) {
|
|
r_config_set_i (core->config, "asm.bits", bits);
|
|
oldbits = bits;
|
|
}
|
|
if (!oldarch) {
|
|
RBinInfo *info = r_bin_get_info (core->bin);
|
|
if (info && info->arch) {
|
|
oldarch = strdup (info->arch);
|
|
} else {
|
|
oldarch = strdup (r_config_get (core->config, "asm.arch"));
|
|
oldbits = r_config_get_i (core->config, "asm.bits");
|
|
}
|
|
if (strcmp (arch, oldarch)) {
|
|
r_config_set (core->config, "asm.arch", arch);
|
|
}
|
|
}
|
|
free (arch);
|
|
return 1;
|
|
}
|
|
if (oldarch) {
|
|
if (!(flag && !strcmp (oldarch, arch))) {
|
|
r_config_set (core->config, "asm.arch", oldarch);
|
|
}
|
|
free (oldarch);
|
|
oldarch = NULL;
|
|
}
|
|
if (oldbits) {
|
|
r_config_set_i (core->config, "asm.bits", oldbits);
|
|
}
|
|
free (arch);
|
|
return 0;
|
|
}
|
|
|
|
R_API bool r_core_seek(RCore *core, ut64 addr, bool rb) {
|
|
RIOSection *newsection;
|
|
ut64 ret, old = core->offset;
|
|
|
|
core->offset = addr;
|
|
core->io->section = core->section; // HACK
|
|
ret = r_io_seek (core->io, addr, R_IO_SEEK_SET);
|
|
newsection = core->io->section;
|
|
|
|
if (ret == UT64_MAX) {
|
|
if (!core->io->va)
|
|
return false;
|
|
} else {
|
|
core->offset = addr;
|
|
}
|
|
if (rb) {
|
|
ret = r_core_block_read (core);
|
|
if (core->io->ff) {
|
|
if (ret < 1 || ret > core->blocksize)
|
|
memset (core->block, core->io->Oxff, core->blocksize);
|
|
else
|
|
memset (core->block+ret, core->io->Oxff, core->blocksize-ret);
|
|
ret = core->blocksize;
|
|
core->offset = addr;
|
|
} else {
|
|
if (ret < 1)
|
|
core->offset = old;
|
|
}
|
|
}
|
|
if (core->section != newsection) {
|
|
r_core_seek_archbits (core, core->offset);
|
|
core->section = newsection;
|
|
}
|
|
return (ret == -1)? false: true;
|
|
}
|
|
|
|
R_API int r_core_seek_delta(RCore *core, st64 addr) {
|
|
ut64 tmp = core->offset;
|
|
int ret;
|
|
if (addr == 0)
|
|
return true;
|
|
if (addr>0LL) {
|
|
/* check end of file */
|
|
if (0) addr = 0;
|
|
else addr += tmp;
|
|
} else {
|
|
/* check < 0 */
|
|
if (-addr > tmp) addr = 0;
|
|
else addr += tmp;
|
|
}
|
|
core->offset = addr;
|
|
ret = r_core_seek (core, addr, 1);
|
|
//ret = r_core_block_read (core);
|
|
//if (ret == -1)
|
|
// memset (core->block, 0xff, core->blocksize);
|
|
// core->offset = tmp;
|
|
return ret;
|
|
}
|
|
|
|
R_API int r_core_write_at(RCore *core, ut64 addr, const ut8 *buf, int size) {
|
|
int ret;
|
|
if (!core->io || !core->file || size<1)
|
|
return false;
|
|
ret = r_io_use_desc (core->io, core->file->desc);
|
|
if (ret != -1) {
|
|
ret = r_io_write_at (core->io, addr, buf, size);
|
|
if (addr >= core->offset && addr <= core->offset+core->blocksize)
|
|
r_core_block_read (core);
|
|
}
|
|
return (ret==-1)? false: true;
|
|
}
|
|
|
|
R_API int r_core_extend_at(RCore *core, ut64 addr, int size) {
|
|
int ret;
|
|
if (!core->io || !core->file || size<1)
|
|
return false;
|
|
//ret = r_io_use_fd (core->io, core->file->desc->fd);
|
|
ret = r_io_use_desc (core->io, core->file->desc);
|
|
if (ret != -1) {
|
|
ret = r_io_extend_at (core->io, addr, size);
|
|
if (addr >= core->offset && addr <= core->offset+core->blocksize)
|
|
r_core_block_read (core);
|
|
}
|
|
return (ret==-1)? false: true;
|
|
}
|
|
|
|
R_API int r_core_shift_block(RCore *core, ut64 addr, ut64 b_size, st64 dist) {
|
|
// bstart - block start, fstart file start
|
|
ut64 fend = 0, fstart = 0, bstart = 0, file_sz = 0;
|
|
ut8 * shift_buf = NULL;
|
|
int res = false;
|
|
|
|
if (b_size == 0 || b_size == (ut64) -1) {
|
|
res = r_io_use_desc (core->io, core->file->desc);
|
|
file_sz = r_io_size (core->io);
|
|
bstart = r_io_seek (core->io, addr, R_IO_SEEK_SET);
|
|
fend = r_io_seek (core->io, 0, R_IO_SEEK_END);
|
|
fstart = file_sz - fend;
|
|
b_size = fend > bstart ? fend - bstart: 0;
|
|
}
|
|
|
|
|
|
if (!core->io || !core->file || b_size<1)
|
|
return false;
|
|
|
|
|
|
// XXX handling basic cases atm
|
|
shift_buf = malloc (b_size);
|
|
memset (shift_buf, 0, b_size);
|
|
|
|
// cases
|
|
// addr + b_size + dist > file_end
|
|
//if ( (addr+b_size) + dist > file_end ) {
|
|
// res = false;
|
|
//}
|
|
// addr + b_size + dist < file_start (should work since dist is signed)
|
|
//else if ( (addr+b_size) + dist < 0 ) {
|
|
// res = false;
|
|
//}
|
|
// addr + dist < file_start
|
|
if ( addr + dist < fstart ) {
|
|
res = false;
|
|
}
|
|
// addr + dist > file_end
|
|
else if ( (addr) + dist > fend) {
|
|
res = false;
|
|
} else {
|
|
res = r_io_use_desc (core->io, core->file->desc);
|
|
r_io_read_at (core->io, addr, shift_buf, b_size);
|
|
r_io_write_at (core->io, addr+dist, shift_buf, b_size);
|
|
res = true;
|
|
}
|
|
|
|
r_core_seek (core, addr, 1);
|
|
free (shift_buf);
|
|
return res;
|
|
}
|
|
|
|
static RCoreFile * r_core_file_set_first_valid(RCore *core) {
|
|
RListIter *iter;
|
|
RCoreFile *file = NULL;
|
|
|
|
r_list_foreach (core->files, iter, file) {
|
|
if (file && file->desc) {
|
|
core->io->raised = file->desc->fd;
|
|
core->switch_file_view = 1;
|
|
break;
|
|
}
|
|
}
|
|
return file;
|
|
}
|
|
|
|
R_API int r_core_block_read(RCore *core) {
|
|
if (core->file == NULL && r_core_file_set_first_valid(core) == NULL) {
|
|
memset (core->block, core->io->Oxff, core->blocksize);
|
|
return -1;
|
|
}
|
|
if (core->file && core->switch_file_view) {
|
|
r_io_use_desc (core->io, core->file->desc);
|
|
r_core_bin_set_by_fd (core, core->file->desc->fd); //needed?
|
|
core->switch_file_view = 0;
|
|
} else {
|
|
r_io_use_fd (core->io, core->io->raised); //possibly not needed
|
|
}
|
|
return r_io_read_at (core->io, core->offset, core->block, core->blocksize);
|
|
}
|
|
|
|
R_API int r_core_read_at(RCore *core, ut64 addr, ut8 *buf, int size) {
|
|
if (!core->io || !core->file || !core->file->desc || size<1) {
|
|
if (size > 0)
|
|
memset (buf, core->io->Oxff, size);
|
|
return false;
|
|
}
|
|
r_io_use_desc (core->io, core->file->desc);
|
|
return r_io_read_at (core->io, addr, buf, size);
|
|
}
|
|
|
|
R_API int r_core_is_valid_offset (RCore *core, ut64 offset) {
|
|
if (!core) {
|
|
eprintf ("r_core_is_valid_offset: core is NULL\n");
|
|
r_sys_backtrace ();
|
|
return R_FAIL;
|
|
}
|
|
return r_io_is_valid_offset (core->io, offset, 0);
|
|
}
|