radare2/libr/io/ioutils.c
2018-07-08 02:11:01 +02:00

314 lines
7.5 KiB
C

/* radare - LGPL - Copyright 2017-2018 - condret */
#include <r_io.h>
#include <r_util.h>
#include <r_types.h>
// TODO: we may probably take care of this when the binfiles have an associated list of fds
#define REUSE_NULL_MAPS 1
static int __access_log_e_cmp (const void *a, const void *b) {
RIOAccessLogElement *A = (RIOAccessLogElement *)a;
RIOAccessLogElement *B = (RIOAccessLogElement *)b;
return (A->buf_idx > B->buf_idx);
}
typedef struct {
const char *uri;
int flags;
RIODesc *desc;
} FindFile;
#if REUSE_NULL_MAPS
static bool findFile(void *user, void *data, ut32 id) {
FindFile *res = (FindFile*)user;
RIODesc *desc = (RIODesc*)data;
if (desc->flags && res->flags && !strcmp (desc->uri, res->uri)) {
res->desc = desc;
return false;
}
return true;
}
static RIODesc *findReusableFile(RIO *io, const char *uri, int flags) {
FindFile arg = {
.uri = uri,
.flags = flags,
.desc = NULL,
};
r_id_storage_foreach (io->files, findFile, &arg);
return arg.desc;
}
#else
static RIODesc *findReusableFile(RIO *io, const char *uri, int flags) {
return NULL;
}
#endif
R_API bool r_io_create_mem_map(RIO *io, RIOSection *sec, ut64 at, bool null, bool do_skyline) {
RIODesc *desc = NULL;
char *uri = NULL;
bool reused = false;
if (!io || !sec) {
return false;
}
ut64 gap = sec->vsize - sec->size;
if (null) {
uri = r_str_newf ("null://%"PFMT64u, gap);
desc = findReusableFile (io, uri, sec->flags);
if (desc) {
RIOMap *map = r_io_map_get (io, at);
if (!map) {
r_io_map_new (io, desc->fd, desc->flags, 0LL, at, gap, false);
}
reused = true;
}
} else {
uri = r_str_newf ("malloc://%"PFMT64u, gap);
}
if (!desc) {
desc = r_io_open_at (io, uri, sec->flags, 664, at);
}
free (uri);
if (!desc) {
return false;
}
if (do_skyline) {
r_io_map_calculate_skyline (io);
}
// this works, because new maps are allways born on the top
RIOMap *map = r_io_map_get (io, at);
// check if the mapping failed
if (!map) {
if (!reused) {
r_io_desc_close (desc);
}
return false;
}
// let the section refere to the map as a memory-map
sec->memmap = map->id;
map->name = r_str_newf ("mmap.%s", sec->name);
return true;
}
R_API bool r_io_create_file_map(RIO *io, RIOSection *sec, ut64 size, bool patch, bool do_skyline) {
RIOMap *map = NULL;
int flags = 0;
RIODesc *desc;
if (!io || !sec) {
return false;
}
desc = r_io_desc_get (io, sec->fd);
if (!desc) {
return false;
}
flags = sec->flags;
//create file map for patching
if (patch) {
//add -w to the map for patching if needed
//if the file was not opened with -w desc->flags won't have that bit active
flags = flags | desc->flags;
}
map = r_io_map_add (io, sec->fd, flags, sec->paddr, sec->vaddr, size, do_skyline);
if (map) {
sec->filemap = map->id;
map->name = r_str_newf ("fmap.%s", sec->name);
return true;
}
return false;
}
R_API bool r_io_create_mem_for_section(RIO *io, RIOSection *sec) {
if (!io || !sec) {
return false;
}
if (sec->vsize - sec->size > 0) {
ut64 at = sec->vaddr + sec->size;
if (!r_io_create_mem_map (io, sec, at, false, true)) {
return false;
}
RIOMap *map = r_io_map_get (io, at);
r_io_map_set_name (map, sdb_fmt ("mem.%s", sec->name));
}
if (sec->size) {
if (!r_io_create_file_map (io, sec, sec->size, false, true)) {
return false;
}
RIOMap *map = r_io_map_get (io, sec->vaddr);
r_io_map_set_name (map, sdb_fmt ("fmap.%s", sec->name));
}
return true;
}
//This helper function only check if the given vaddr is mapped, it does not account
//for map perms
R_API bool r_io_addr_is_mapped(RIO *io, ut64 vaddr) {
if (io) {
if (io->va && r_io_map_get (io, vaddr)) {
return true;
}
}
return false;
}
// when io.va is true this checks if the highest priorized map at this
// offset has the same or high permissions set. When there is no map it
// check for the current desc permissions and size.
// when io.va is false it only checks for the desc
R_API bool r_io_is_valid_offset(RIO* io, ut64 offset, int hasperm) {
RIOMap* map;
if (!io) {
return false;
}
if (io->va) {
if ((map = r_io_map_get (io, offset))) {
return ((map->flags & hasperm) == hasperm);
}
return false;
}
if (!io->desc) {
return false;
}
if (r_io_desc_size (io->desc) <= offset) {
return false;
}
return ((io->desc->flags & hasperm) == hasperm);
}
// this is wrong, there is more than big and little endian
R_API bool r_io_read_i(RIO* io, ut64 addr, ut64 *val, int size, bool endian) {
ut8 buf[8];
if (!val) {
return false;
}
size = R_DIM (size, 1, 8);
if (!r_io_read_at (io, addr, buf, size)) {
return false;
}
//size says the number of bytes to read transform to bits for r_read_ble
*val = r_read_ble (buf, endian, size * 8);
return true;
}
R_API bool r_io_write_i(RIO* io, ut64 addr, ut64 *val, int size, bool endian) {
ut8 buf[8];
if (!val) {
return false;
}
size = R_DIM (size, 1, 8);
//size says the number of bytes to read transform to bits for r_read_ble
r_write_ble (buf, *val, endian, size * 8);
if (!r_io_write_at (io, addr, buf, size)) {
return false;
}
return true;
}
R_API RIOAccessLog *r_io_accesslog_new() {
RIOAccessLog *log = R_NEW0 (RIOAccessLog);
if (!log) {
return NULL;
}
if (!(log->log = r_list_newf (free))) {
free (log);
return NULL;
}
return log;
}
R_API void r_io_accesslog_free(RIOAccessLog *log) {
if (log) {
r_list_free (log->log);
}
free (log);
}
R_API void r_io_accesslog_sort(RIOAccessLog *log) {
if (!log || !log->log) {
return;
}
r_list_sort (log->log, __access_log_e_cmp);
}
R_API void r_io_accesslog_sqash_ignore_gaps(RIOAccessLog *log) {
RListIter *iter, *ator;
RIOAccessLogElement *ale, *ela;
if (!log || !log->log || !log->log->length) {
return;
}
if (!log->log->sorted) {
r_list_sort (log->log, __access_log_e_cmp);
}
r_list_foreach_safe (log->log, iter, ator, ale) {
if (iter->p) {
ela = (RIOAccessLogElement *)iter->p->data;
if ((ale->len == ale->expect_len) && (ela->len == ela->expect_len)) {
if (ela->mapid != ale->mapid) {
ela->mapid = 0; //what to do with fd?
}
ela->flags &= ale->flags;
ela->len += (ale->buf_idx - ela->buf_idx) + ale->len;
r_list_delete (log->log, iter);
}
}
}
}
R_API void r_io_accesslog_sqash_byflags(RIOAccessLog *log, int flags) {
RListIter *iter, *ator;
RIOAccessLogElement *ale, *ela;
if (!log || !log->log || !log->log->length) {
return;
}
if (!log->log->sorted) {
r_list_sort (log->log, __access_log_e_cmp);
}
r_list_foreach_safe (log->log, iter, ator, ale) {
if (iter->p) {
ela = (RIOAccessLogElement *)iter->p->data;
if (((ale->flags & flags) == (ela->flags & flags)) &&
((ale->flags & flags) == flags) &&
(ale->len == ale->expect_len) && //only sqash on succes
(ela->len == ela->expect_len) &&
((ela->buf_idx + ela->len) == ale->buf_idx)) {
if (ela->mapid != ale->mapid) {
ela->mapid = 0; //what to do with fd?
}
ela->flags &= (ale->flags & flags);
ela->len += ale->len;
r_list_delete (log->log, iter);
}
}
}
}
//gets first buffer that matches with the flags and frees the element
R_API ut8 *r_io_accesslog_getf_buf_byflags(RIOAccessLog *log, int flags, ut64 *addr, int *len) {
RListIter *iter;
RIOAccessLogElement *ale;
ut8 *ret;
if (!log || !log->log || !log->log->length) {
return NULL;
}
if (!log->log->sorted) {
r_list_sort (log->log, __access_log_e_cmp);
}
r_list_foreach (log->log, iter, ale) {
if (((ale->flags & flags) == flags) && (ale->len == ale->expect_len)) {
ret = &log->buf[ale->buf_idx];
*len = ale->len;
*addr = ale->vaddr; //what about pa?
r_list_delete (log->log, iter);
return ret;
}
}
return NULL;
}