mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-03 19:01:31 +00:00
314 lines
7.5 KiB
C
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;
|
|
}
|