rizin/librz/io/io_desc.c
Giovanni 6131a0e187
Fix RZ_IPI usage on public headers & fix memory leak in the ROP code. (#6171)
* Fix RZ_IPI declaration on public api for rz_pdb

* Fix RZ_IPI declaration on public api for jemalloc/glibc

* Fix RZ_IPI declaration on public api for rz_io

* Remove functions from public header for rz_panels

* Fix public functions not following rizin nomenclature in rz_graph

* Fix public functions not following rizin nomenclature in rz_rop

* move resolve_fcn_name into rz_analysis

* Fix public functions not following rizin nomenclature in rz_ascii_table

* Fix leak in rop code

* Rewrite parser for rop

* Add doxygen comment
2026-04-08 13:37:17 +08:00

402 lines
10 KiB
C

// SPDX-FileCopyrightText: 2017-2020 condret <condr3t@protonmail.com>
// SPDX-FileCopyrightText: 2017-2020 pancake <pancake@nopcode.org>
// SPDX-FileCopyrightText: 2017-2020 alvaro <alvaro.felipe91@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_io.h>
#include <sdb.h>
#include <string.h>
// shall be used by plugins for creating descs
RZ_API RzIODesc *rz_io_desc_new(RzIO *io, RzIOPlugin *plugin, const char *uri, int perm, void *data) {
ut32 fd32 = 0;
// this is required for emscripten builds to work, but should assert
if (!io || !plugin || !uri) {
return NULL;
}
if (io->files) {
if (!rz_id_pool_grab_id(io->files->pool, &fd32)) {
return NULL;
}
}
RzIODesc *desc = RZ_NEW0(RzIODesc);
if (desc) {
desc->fd = fd32;
desc->io = io;
desc->plugin = plugin;
desc->data = data;
desc->perm = perm;
// because the uri-arg may live on the stack
desc->uri = rz_str_dup(uri);
}
return desc;
}
RZ_API void rz_io_desc_free(RzIODesc *desc) {
if (desc) {
free(desc->uri);
free(desc->referer);
free(desc->name);
rz_io_desc_cache_fini(desc);
if (desc->io && desc->io->files) {
rz_id_storage_delete(desc->io->files, desc->fd);
}
// free (desc->plugin);
}
free(desc);
}
RZ_API bool rz_io_desc_add(RzIO *io, RzIODesc *desc) {
rz_return_val_if_fail(io && desc && desc->io, false);
if (!rz_id_storage_set(io->files, desc, desc->fd)) {
// TODO: use assert here
eprintf("You are using this API incorrectly\n");
eprintf("fd %d was probably not generated by this RzIO-instance\n", desc->fd);
rz_sys_backtrace();
return false;
}
return true;
}
RZ_API bool rz_io_desc_del(RzIO *io, int fd) { // can we pass this a riodesc and check if it belongs to the desc->io ?
rz_return_val_if_fail(io && io->files, false);
RzIODesc *desc = rz_id_storage_get(io->files, fd);
rz_io_desc_free(desc);
if (desc == io->desc) {
io->desc = NULL;
}
// remove all dead maps
rz_io_map_cleanup(io);
return true;
}
RZ_API RzIODesc *rz_io_desc_get(RzIO *io, int fd) {
rz_return_val_if_fail(io && io->files, NULL);
return (RzIODesc *)rz_id_storage_get(io->files, fd);
}
RZ_API RzIODesc *rz_io_desc_get_next(RzIO *io, RzIODesc *desc) {
rz_return_val_if_fail(desc && io && io->files, NULL);
const int next_fd = rz_io_fd_get_next(io, desc->fd);
if (next_fd == -1) {
return NULL;
}
return (RzIODesc *)rz_id_storage_get(io->files, next_fd);
}
RZ_API RzIODesc *rz_io_desc_get_prev(RzIO *io, RzIODesc *desc) {
rz_return_val_if_fail(desc && io && io->files, NULL);
const int prev_fd = rz_io_fd_get_prev(io, desc->fd);
if (prev_fd == -1) {
return NULL;
}
return (RzIODesc *)rz_id_storage_get(io->files, prev_fd);
}
RZ_API RzIODesc *rz_io_desc_get_highest(RzIO *io) {
int fd = rz_io_fd_get_highest(io);
if (fd == -1) {
return NULL;
}
return rz_io_desc_get(io, fd);
}
RZ_API RzIODesc *rz_io_desc_get_lowest(RzIO *io) {
int fd = rz_io_fd_get_lowest(io);
if (fd == -1) {
return NULL;
}
return rz_io_desc_get(io, fd);
}
RZ_API RzIODesc *rz_io_desc_open(RzIO *io, const char *uri, int perm, int mode) {
rz_return_val_if_fail(io && uri, NULL);
RzIOPlugin *plugin = rz_io_plugin_resolve(io, uri, 0);
if (!plugin || !plugin->open) {
return NULL;
}
RzIODesc *desc = plugin->open(io, uri, perm, mode);
if (!desc) {
return NULL;
}
// for none static callbacks, those that cannot use rz_io_desc_new
if (!desc->name) {
desc->name = rz_str_dup(uri);
}
if (!desc->uri) {
desc->uri = rz_str_dup(uri);
}
if (!desc->plugin) {
desc->plugin = plugin;
}
if (!rz_io_desc_add(io, desc)) {
rz_io_desc_free(desc);
return NULL;
}
return desc;
}
RZ_API RzIODesc *rz_io_desc_open_plugin(RzIO *io, RzIOPlugin *plugin, const char *uri, int perm, int mode) {
rz_return_val_if_fail(io && io->files && uri, NULL);
if (!plugin || !plugin->open || !plugin->check || !plugin->check(io, uri, false)) {
return NULL;
}
RzIODesc *desc = plugin->open(io, uri, perm, mode);
if (!desc) {
return NULL;
}
// for none static callbacks, those that cannot use rz_io_desc_new
if (!desc->plugin) {
desc->plugin = plugin;
}
if (!desc->uri) {
desc->uri = rz_str_dup(uri);
}
if (!desc->name) {
desc->name = rz_str_dup(uri);
}
if (!rz_io_desc_add(io, desc)) {
rz_io_desc_free(desc);
return NULL;
}
return desc;
}
RZ_API bool rz_io_desc_close(RzIODesc *desc) {
if (!desc || !desc->io || !desc->plugin) {
return false;
}
RzIO *io = desc->io;
RzEventIODescClose ev = { desc };
rz_event_send(io->event, RZ_EVENT_IO_DESC_CLOSE, &ev);
if (desc->plugin->close && desc->plugin->close(desc)) {
return false;
}
// remove entry from idstorage and free the desc-struct
rz_io_desc_del(io, desc->fd);
// remove all dead maps
rz_io_map_cleanup(io);
return true;
}
// returns length of written bytes
RZ_API int rz_io_desc_write(RzIODesc *desc, const ut8 *buf, size_t len) {
rz_return_val_if_fail(desc && buf, -1);
if (len < 0) {
return -1;
}
// check pointers and pcache
if (desc->io && (desc->io->p_cache & 2)) {
return rz_io_desc_cache_write(desc,
rz_io_desc_seek(desc, 0LL, RZ_IO_SEEK_CUR), buf, len);
}
return rz_io_plugin_write(desc, buf, len);
}
// returns length of read bytes
RZ_API int rz_io_desc_read(RzIODesc *desc, ut8 *buf, size_t len) {
// check pointers and permissions
if (!buf || !desc || !desc->plugin || !(desc->perm & RZ_PERM_R)) {
return -1;
}
ut64 seek = rz_io_desc_seek(desc, 0LL, RZ_IO_SEEK_CUR);
if (desc->io->cachemode) {
if (seek != UT64_MAX && rz_io_cache_at(desc->io, seek)) {
return rz_io_cache_read(desc->io, seek, buf, len, NULL);
}
}
int ret = rz_io_plugin_read(desc, buf, len);
if (ret > 0 && desc->io->cachemode) {
rz_io_cache_write(desc->io, seek, buf, len);
} else if ((ret > 0) && desc->io && (desc->io->p_cache & 1)) {
ret = rz_io_desc_cache_read(desc, seek, buf, ret);
}
return ret;
}
RZ_API ut64 rz_io_desc_seek(RzIODesc *desc, ut64 offset, int whence) {
if (!desc || !desc->plugin || !desc->plugin->lseek) {
return (ut64)-1;
}
return desc->plugin->lseek(desc->io, desc, offset, whence);
}
RZ_API ut64 rz_io_desc_size(RzIODesc *desc) {
if (!desc || !desc->plugin || !desc->plugin->lseek) {
return 0LL;
}
ut64 off = rz_io_desc_seek(desc, 0LL, RZ_IO_SEEK_CUR);
ut64 ret = rz_io_desc_seek(desc, 0LL, RZ_IO_SEEK_END);
// what to do if that seek fails?
rz_io_desc_seek(desc, off, RZ_IO_SEEK_SET);
return ret;
}
/**
* \brief Returns the underlying buffer of the io descriptor
* \param[in] desc The io descriptor
* \param[out] size Size of buffer returned
* \return The buffer or NULL if the buffer is not available
*/
RZ_API ut8 *rz_io_desc_get_buf(RzIODesc *desc, RZ_OUT RZ_NONNULL ut64 *size) {
rz_return_val_if_fail(size, NULL);
if (!desc || !desc->plugin || !desc->plugin->get_buf) {
*size = 0;
return NULL;
}
return desc->plugin->get_buf(desc, size);
}
RZ_API bool rz_io_desc_resize(RzIODesc *desc, ut64 newsize) {
if (desc && desc->plugin && desc->plugin->resize) {
bool ret = desc->plugin->resize(desc->io, desc, newsize);
if (desc->io && desc->io->p_cache) {
rz_io_desc_cache_cleanup(desc);
}
return ret;
}
return false;
}
RZ_API bool rz_io_desc_is_blockdevice(RzIODesc *desc) {
if (!desc || !desc->plugin || !desc->plugin->is_blockdevice) {
return false;
}
return desc->plugin->is_blockdevice(desc);
}
RZ_API bool rz_io_desc_is_chardevice(RzIODesc *desc) {
if (!desc || !desc->plugin || !desc->plugin->is_chardevice) {
return false;
}
return desc->plugin->is_chardevice(desc);
}
RZ_API bool rz_io_desc_exchange(RzIO *io, int fd, int fdx) {
RzIODesc *desc, *descx;
if (!(desc = rz_io_desc_get(io, fd)) || !(descx = rz_io_desc_get(io, fdx))) {
return false;
}
desc->fd = fdx;
descx->fd = fd;
rz_id_storage_set(io->files, desc, fdx);
rz_id_storage_set(io->files, descx, fd);
if (io->p_cache) {
HtUP *cache = desc->cache;
desc->cache = descx->cache;
descx->cache = cache;
rz_io_desc_cache_cleanup(desc);
rz_io_desc_cache_cleanup(descx);
}
void **it;
rz_pvector_foreach (&io->maps, it) {
RzIOMap *map = *it;
if (map->fd == fdx) {
map->perm &= (desc->perm | RZ_PERM_X);
} else if (map->fd == fd) {
map->perm &= (descx->perm | RZ_PERM_X);
}
}
return true;
}
RZ_API bool rz_io_desc_is_dbg(RzIODesc *desc) {
if (desc && desc->plugin) {
return desc->plugin->isdbg;
}
return false;
}
RZ_API int rz_io_desc_get_pid(RzIODesc *desc) {
//-1 and -2 are reserved
if (!desc) {
return -3;
}
if (!desc->plugin) {
return -4;
}
if (!desc->plugin->isdbg) {
return -5;
}
if (!desc->plugin->getpid) {
return -6;
}
return desc->plugin->getpid(desc);
}
RZ_API int rz_io_desc_get_tid(RzIODesc *desc) {
//-1 and -2 are reserved
if (!desc) {
return -3;
}
if (!desc->plugin) {
return -4;
}
if (!desc->plugin->isdbg) {
return -5;
}
if (!desc->plugin->gettid) {
return -6;
}
return desc->plugin->gettid(desc);
}
RZ_API bool rz_io_desc_get_base(RzIODesc *desc, ut64 *base) {
if (!base || !desc || !desc->plugin || !desc->plugin->isdbg || !desc->plugin->getbase) {
return false;
}
return desc->plugin->getbase(desc, base);
}
RZ_API int rz_io_desc_read_at(RzIODesc *desc, ut64 addr, ut8 *buf, size_t len) {
ut64 val = rz_io_desc_seek(desc, addr, RZ_IO_SEEK_SET);
if (desc && buf && val != UT64_MAX && val == addr) {
return rz_io_desc_read(desc, buf, len);
}
return 0;
}
RZ_API int rz_io_desc_write_at(RzIODesc *desc, ut64 addr, const ut8 *buf, size_t len) {
ut64 val = rz_io_desc_seek(desc, addr, RZ_IO_SEEK_SET);
if (desc && buf && val != UT64_MAX && val == addr) {
return rz_io_desc_write(desc, buf, len);
}
return 0;
}
/* lifecycle */
// TODO: move into io.c : rz_io_init
RZ_API bool rz_io_desc_init(RzIO *io) {
rz_return_val_if_fail(io, false);
rz_io_desc_fini(io);
// TODO: it leaks if called twice
// fd is signed
io->files = rz_id_storage_new(3, 0x80000000);
if (!io->files) {
return false;
}
return true;
}
static bool desc_fini_cb(void *user, void *data, ut32 id) {
RzIODesc *desc = (RzIODesc *)data;
if (desc->plugin && desc->plugin->close) {
desc->plugin->close(desc);
}
rz_io_desc_free(desc);
return true;
}
// closes all descs and frees all descs and io->files
RZ_API bool rz_io_desc_fini(RzIO *io) {
rz_return_val_if_fail(io, false);
if (io->files) {
rz_id_storage_foreach(io->files, desc_fini_cb, io);
rz_id_storage_free(io->files);
io->files = NULL;
}
// no map-cleanup here, to keep it modular useable
io->desc = NULL;
return true;
}