/* radare - LGPL - Copyright 2008-2016 - pancake */ #include #include #include #include #include #include R_API int r_io_map_count (RIO *io) { return r_list_length (io->maps); } R_API RIOMap * r_io_map_new(RIO *io, int fd, int flags, ut64 delta, ut64 addr, ut64 size) { RIOMap *map = R_NEW0 (RIOMap); if (!map || ((UT64_MAX - size) < addr)) { //prevent interger-overflow free (map); return NULL; } map->fd = fd; map->flags = flags; map->delta = delta; map->from = addr; map->to = addr + size; r_list_append (io->maps, map); return map; } R_API void r_io_map_init(RIO *io) { io->maps = r_list_new (); } R_API int r_io_map_sort(void *_a, void *_b) { RIOMap *a = _a, *b = _b; if (a->from == b->from) { ut64 a_sz = a->to - a->from; ut64 b_sz = b->to - b->from; return a_sz < b_sz; } return a->from < b->from; } R_API int r_io_map_write_update(RIO *io, int fd, ut64 addr, ut64 len) { int res = false; RIOMap *map = NULL; RListIter *iter; r_list_foreach (io->maps, iter, map) { if (map->fd == fd) break; map = NULL; } if (map && map->to < addr+len) { res = true; map->to = addr+len; } return res; } R_API int r_io_map_truncate_update(RIO *io, int fd, ut64 sz) { int res = false; RIOMap *map = NULL; RListIter *iter; r_list_foreach (io->maps, iter, map) { if (map->fd == fd) break; map = NULL; } if (map) { res = true; map->to = map->from + sz; } return res; } R_API RIOMap *r_io_map_get(RIO *io, ut64 addr) { RIOMap *map; RListIter *iter; r_list_foreach (io->maps, iter, map) { if (map->from == map->to && addr >= map->from) { return map; } if (addr >= map->from && addr < map->to) { return map; } } return NULL; } R_API RIOMap *r_io_map_resolve(RIO *io, int fd) { RIOMap *map; RListIter *iter; if (io && io->maps) { r_list_foreach (io->maps, iter, map) { if (map->fd == fd) { return map; } } } return NULL; } R_API RIOMap *r_io_map_resolve_from_list (RList *maps, int fd) { RIOMap *map = NULL; RListIter *iter; if (maps) { r_list_foreach (maps, iter, map) { if (map->fd == fd) { return map; } } } return NULL; } static RList *r_io_map_get_maps_in_range_prepend(RIO *io, ut64 addr, ut64 endaddr) { RIOMap *map; RListIter *iter; RList *maps = r_list_new (); if (!maps) return NULL; maps->free = NULL; r_list_foreach (io->maps, iter, map) { if (map->from <= addr && addr < map->to) r_list_append(maps, map); //if (map->from == addr && endaddr == map->to) r_list_prepend(maps, map); if (map->from < endaddr && endaddr < map->to) r_list_prepend(maps, map); if (addr <= map->from && map->to <= endaddr) r_list_prepend(maps, map); } return maps; } R_API RIOMap *r_io_map_resolve_in_range (RIO *io, ut64 addr, ut64 endaddr, int fd) { RList *maps; RIOMap *map; if (!io || !io->maps) { return NULL; } maps = r_io_map_get_maps_in_range_prepend (io, addr, endaddr); map = r_io_map_resolve_from_list (maps, fd); r_list_free (maps); return map; } R_API RList *r_io_map_get_maps_in_range(RIO *io, ut64 addr, ut64 endaddr) { RIOMap *map; RListIter *iter; RList *maps = r_list_new (); if (!maps) return NULL; maps->free = NULL; r_list_foreach (io->maps, iter, map) { if (map->from <= addr && addr < map->to) r_list_append(maps, map); //if (map->from == addr && endaddr == map->to) r_list_append(maps, map); if (map->from < endaddr && endaddr < map->to) r_list_append(maps, map); if (addr <= map->from && map->to <= endaddr) r_list_append(maps, map); } return maps; } R_API RIOMap * r_io_map_get_first_map_in_range(RIO *io, ut64 addr, ut64 endaddr) { RIOMap *map = NULL; RListIter *iter; r_list_foreach (io->maps, iter, map) { if (map->from <= addr && addr < map->to) break; //if (map->from == addr && endaddr == map->to) r_list_append(maps, map); if (map->from < endaddr && endaddr < map->to) break; if (addr <= map->from && map->to <= endaddr) break; map = NULL; } return map; } R_API int r_io_map_del(RIO *io, int fd) { RIOMap *map; RListIter *iter, *tmp; ut8 deleted = false; if (io && io->maps) { r_list_foreach_safe (io->maps, iter, tmp, map) { if (fd==-1 || map->fd==fd) { r_list_delete (io->maps, iter); deleted = true; } } } return deleted; } R_API ut64 r_io_map_next(RIO *io, ut64 addr) { ut64 next = UT64_MAX; RIOMap *map; RListIter *iter; r_list_foreach (io->maps, iter, map) { if (map->from > addr) if (!next || map->from < next) next = map->from; } return next; } R_API int r_io_map_del_at(RIO *io, ut64 addr) { RIOMap *map; RListIter *iter; r_list_foreach (io->maps, iter, map) { if (map->from <= addr && addr < map->to) { r_list_delete (io->maps, iter); return true; } } return false; } R_API RIOMap *r_io_map_add_next_available(RIO *io, int fd, int flags, ut64 delta, ut64 addr, ut64 size, ut64 load_align) { RIOMap *map; RListIter *iter; ut64 next_addr = addr, end_addr = next_addr + size; r_list_foreach (io->maps, iter, map) { next_addr = R_MAX (next_addr, map->to+(load_align - (map->to % load_align))); // XXX - This does not handle when file overflow 0xFFFFFFFF000 -> 0x00000FFF // adding the check for the map's fd to see if this removes contention for // memory mapping with multiple files. if (map->fd == fd && ((map->from <= next_addr && next_addr < map->to) || (map->from <= end_addr && end_addr < map->to)) ) { //return r_io_map_add(io, fd, flags, delta, map->to, size); next_addr = map->to + (load_align - (map->to % load_align)); return r_io_map_add_next_available(io, fd, flags, delta, next_addr, size, load_align); } else break; } return r_io_map_new (io, fd, flags, delta, next_addr, size); } R_API RIOMap *r_io_map_add(RIO *io, int fd, int flags, ut64 delta, ut64 addr, ut64 size) { RIOMap *map; RListIter *iter; ut64 end_addr = addr + size; r_list_foreach (io->maps, iter, map) { // XXX - This does not handle when file overflow 0xFFFFFFFF000 -> 0x00000000 // keeping (fd, to, from) tuples as separate maps if ( map->fd == fd && ((map->from <= addr && addr < map->to) || (map->from <= end_addr && end_addr < map->to)) ) //return r_io_map_add(io, fd, flags, delta, map->to, size); return NULL; } return r_io_map_new (io, fd, flags, delta, addr, size); } R_API int r_io_map_exists_for_offset (RIO *io, ut64 off) { int res = false; RIOMap *im = NULL; RListIter *iter; r_list_foreach (io->maps, iter, im) { if (im->from <= off && off < im->to) { res = true; break; } } return res; } R_API ut64 r_io_map_select(RIO *io, ut64 off) { int done = 0; ut64 fd = -1; ut64 paddr = off; RIOMap *im = NULL; RListIter *iter; ut64 prevfrom = 0LL; r_list_foreach (io->maps, iter, im) { if (off >= im->from) { if (prevfrom) { if (im->from < prevfrom) { r_io_use_fd (io, im->fd); } } else { r_io_use_fd (io, im->fd); } prevfrom = im->from; } if (off >= im->from && off < im->to) { paddr = off - im->from + im->delta; //-im->from; fd = im->fd; done = 1; if (fd == io->raised) { break; } } } if (done == 0) { r_io_use_fd (io, fd); (void)r_io_seek (io, -1, R_IO_SEEK_SET); return paddr; } if (fd == -1) { (void)r_io_seek (io, off, R_IO_SEEK_SET); return off; } r_io_use_fd (io, fd); if (io->debug) { /* HACK */ (void)r_io_seek (io, off, R_IO_SEEK_SET); } else { r_io_seek (io, paddr, R_IO_SEEK_SET); } r_io_use_fd (io, fd); return paddr; } R_API ut64 r_io_map_select_current_fd(RIO *io, ut64 off, int fd) { int done = 0; ut64 paddr = off; RIOMap *im = NULL; RListIter *iter; r_list_foreach (io->maps, iter, im) { if (im->fd != fd) { continue; } if (off >= im->from && off < im->to) { paddr = off - im->from + im->delta; //-im->from; done = 1; } } if (done == 0) { (void) r_io_seek (io, -1, R_IO_SEEK_SET); return paddr; } if (fd == -1) { (void) r_io_seek (io, off, R_IO_SEEK_SET); return off; } if (io->debug) { /* HACK */ (void) r_io_seek (io, off, R_IO_SEEK_SET); } else { (void) r_io_seek (io, paddr, R_IO_SEEK_SET); } return paddr; } R_API bool r_io_map_overlaps (RIO *io, RIODesc *fd, RIOMap *map) { RListIter *iter; RIOMap *im = NULL; ut64 off = map->from; if (!fd) { return false; } r_list_foreach (io->maps, iter, im) { if (im == map) { continue; } if (off >= im->from && off < im->to) { return true; } } return false; } R_API void r_io_map_list(RIO *io, int mode) { RIOMap *map; RListIter *iter; if (io && io->maps && io->cb_printf) { r_list_foreach (io->maps, iter, map) { switch (mode) { case 1: case 'r': if (map->from) { io->cb_printf ("omr 0x0 0x%"PFMT64x"\n", map->from); } break; default: io->cb_printf ("%i +0x%"PFMT64x" 0x%"PFMT64x " - 0x%"PFMT64x" ; %s\n", map->fd, map->delta, map->from, map->to, r_str_rwx_i (map->flags)); break; } } } }