Redesign the REvent API ##api

This commit is contained in:
pancake 2024-11-21 19:08:23 +01:00 committed by GitHub
parent face0fc5df
commit 89faa9a7a2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 315 additions and 132 deletions

View File

@ -1,8 +1,6 @@
/* radare - LGPL - Copyright 2018 - thestr4ng3r */
/* radare - LGPL - Copyright 2018-2024 - thestr4ng3r */
#include <r_anal.h>
#include <r_vector.h>
#include <r_util.h>
static void r_anal_class_base_delete_class(RAnal *anal, const char *class_name);
static void r_anal_class_method_delete_class(RAnal *anal, const char *class_name);

View File

@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2018 - pancake */
/* radare - LGPL - Copyright 2018-2024 - pancake */
#ifndef R_EVENT_H
#define R_EVENT_H
@ -8,37 +8,181 @@ extern "C" {
#endif
#include <sdb/ht_up.h>
#include <r_vector.h>
typedef struct r_event_t {
void *user;
bool incall;
HtUP *callbacks;
RVector all_callbacks;
int next_handle;
} REvent;
typedef struct r_event_callback_handle_t {
int handle;
int type;
} REventCallbackHandle;
typedef void (*REventCallback)(REvent *ev, int type, void *user, void *data);
#include <r_vec.h>
typedef enum {
R_EVENT_ALL = 0,
R_EVENT_META_SET, // REventMeta
R_EVENT_META_DEL, // REventMeta
R_EVENT_META_CLEAR, // REventMeta
R_EVENT_CLASS_NEW, // REventClass
R_EVENT_CLASS_DEL, // REventClass
R_EVENT_CLASS_RENAME, // REventClassRename
R_EVENT_CLASS_ATTR_SET, // REventClassAttr
R_EVENT_CLASS_ATTR_DEL, // REventClassAttrSet
R_EVENT_CLASS_ATTR_RENAME, // REventClassAttrRename
R_EVENT_DEBUG_PROCESS_FINISHED, // REventDebugProcessFinished
R_EVENT_IO_WRITE, // REventIOWrite
R_EVENT_MAX,
R_EVENT_META_SET,
R_EVENT_META_DEL,
R_EVENT_META_CLEAR,
R_EVENT_CLASS_NEW,
R_EVENT_CLASS_DEL,
R_EVENT_CLASS_RENAME,
R_EVENT_CLASS_ATTR_SET,
R_EVENT_CLASS_ATTR_DEL,
R_EVENT_CLASS_ATTR_RENAME,
R_EVENT_DEBUG_PROCESS_FINISHED,
R_EVENT_ANALYSIS_START,
R_EVENT_ANALYSIS_END,
R_EVENT_ANALYSIS_FUNCTION_ADDED,
R_EVENT_ANALYSIS_BLOCK_ADDED,
R_EVENT_ANALYSIS_BLOCK_REMOVED,
R_EVENT_DEBUG_START,
R_EVENT_DEBUG_STOP,
R_EVENT_DEBUG_STEP,
R_EVENT_DEBUG_BREAKPOINT_HIT,
R_EVENT_DEBUG_EXCEPTION,
R_EVENT_IO_READ,
R_EVENT_IO_WRITE,
R_EVENT_IO_OPEN,
R_EVENT_IO_CLOSE,
R_EVENT_PLUGIN_LOAD,
R_EVENT_PLUGIN_UNLOAD,
R_EVENT_SEARCH_START,
R_EVENT_SEARCH_END,
R_EVENT_SEARCH_HIT,
R_EVENT_CHILD_SYSCALL,
R_EVENT_CHILD_SIGNAL_RECEIVED,
R_EVENT_BINARY_START,
R_EVENT_BINARY_LOADED,
R_EVENT_IO_MAP_ADDED,
R_EVENT_IO_MAP_REMOVED,
R_EVENT_MEMORY_ACCESS_VIOLATION,
R_EVENT_CHILD_REGISTERS_UPDATED,
R_EVENT_DEBUG_REGISTER_READ,
R_EVENT_DEBUG_REGISTER_WRITE,
R_EVENT_FLAGS_ADDED,
R_EVENT_FLAGS_REMOVED,
R_EVENT_ANALYSIS_VARIABLE_ADD,
R_EVENT_ANALYSIS_VARIABLE_DELETE,
R_EVENT_TRACE_START,
R_EVENT_TRACE_END,
R_EVENT_TRACE_POINT_HIT,
R_EVENT_BREAKPOINT_ADDED,
R_EVENT_BREAKPOINT_REMOVED,
R_EVENT_WATCHPOINT_ADDED,
R_EVENT_WATCHPOINT_REMOVED,
R_EVENT_STEP_OVER,
R_EVENT_STEP_IN,
R_EVENT_STEP_OUT,
R_EVENT_DISASSEMBLY_STARTED,
R_EVENT_DISASSEMBLY_ENDED,
R_EVENT_INSTRUCTION_DECODED,
R_EVENT_EXECUTION_PAUSED,
R_EVENT_EXECUTION_RESUMED,
R_EVENT_MEMORY_READ,
R_EVENT_MEMORY_WRITE,
R_EVENT_MEMORY_ALLOCATED,
R_EVENT_MEMORY_FREED,
R_EVENT_FILE_OPEN,
R_EVENT_FILE_CLOSE,
R_EVENT_NETWORK_CONNECTION_OPEN,
R_EVENT_NETWORK_CONNECTION_CLOSE,
R_EVENT_NETWORK_DATA_RECEIVED,
R_EVENT_NETWORK_DATA_SENT,
R_EVENT_PLUGIN_INITIALIZED,
R_EVENT_PLUGIN_FINALIZED,
R_EVENT_BINARY_ANALYZED,
R_EVENT_SIGNATURE_MATCH_FOUND,
R_EVENT_CRC_CHECKSUM_COMPUTED,
R_EVENT_PROCESS_START,
R_EVENT_PROCESS_EXIT,
R_EVENT_THREAD_START,
R_EVENT_THREAD_STOP,
R_EVENT_MODULE_LOADED,
R_EVENT_MODULE_UNLOADED,
R_EVENT_SYMBOL_ADDED,
R_EVENT_SYMBOL_REMOVED,
R_EVENT_RELOCATIONS_PROCESSED,
R_EVENT_SECTION_ADDED,
R_EVENT_BINARY_DUMP_STARTED,
R_EVENT_BINARY_DUMP_FINISHED,
R_EVENT_EMULATION_STARTED,
R_EVENT_EMULATION_STOPPED,
R_EVENT_BINARY_HASH_COMPUTED,
R_EVENT_STRING_DETECTED,
R_EVENT_HEX_PATTERN_MATCHED,
R_EVENT_DECOMPILATION_STARTED,
R_EVENT_DECOMPILATION_ENDED,
R_EVENT_INLINE_PATCH_ADDED,
R_EVENT_INLINE_PATCH_REMOVED,
R_EVENT_SYMBOL_RESOLVED,
R_EVENT_SYMBOL_UNRESOLVED,
R_EVENT_SECTION_MAPPED,
R_EVENT_SECTION_UNMAPPED,
R_EVENT_CACHE_HIT,
R_EVENT_CACHE_MISS,
R_EVENT_CODE_SIGNATURE_VERIFIED,
R_EVENT_CODE_SIGNATURE_INVALID,
R_EVENT_EXCEPTION_RAISED,
R_EVENT_EXCEPTION_HANDLED,
R_EVENT_HARDWARE_BREAKPOINT_SET,
R_EVENT_HARDWARE_BREAKPOINT_REMOVED,
R_EVENT_WATCHPOINT_HIT,
R_EVENT_WATCHPOINT_IGNORED,
R_EVENT_INTERRUPT_RAISED,
R_EVENT_INTERRUPT_HANDLED,
R_EVENT_PLUGIN_CONFIGURATION_UPDATED,
R_EVENT_BINARY_RELOCATED,
R_EVENT_ANALYSIS_RESTART,
R_EVENT_ANALYSIS_ABORTED,
R_EVENT_GADGET_FOUND,
R_EVENT_GADGET_EXECUTED,
R_EVENT_REGISTER_STATE_SAVED,
R_EVENT_REGISTER_STATE_RESTORED,
R_EVENT_FILE_RELOCATED,
R_EVENT_BINARY_CHECKSUM_VERIFIED,
R_EVENT_FUNCTION_CALLED,
R_EVENT_FUNCTION_RETURNED,
R_EVENT_LAST,
} REventType;
typedef struct r_event_meta_t {
@ -82,11 +226,41 @@ typedef struct r_event_io_write_t {
int len;
} REventIOWrite;
typedef struct r_event_msg_t {
ut32 type;
void *data;
size_t data_len;
} REventMessage;
typedef struct r_event_t REvent;
typedef void (*REventCallback)(REvent *ev, int type, void *user, void *data);
typedef struct r_event_hook_t {
ut32 event_type;
REventCallback cb;
void *user;
} REventHook;
// R_VEC_TYPE(RVecREventCallback, REventCallback);
R_VEC_TYPE(RVecREventHook, REventHook);
typedef struct r_event_t {
void *user;
RVecREventHook all_events;
RVecREventHook known_events[R_EVENT_LAST];
HtUP *other_events; // when event id > R_EVENT_LAST
RThreadLock *lock;
} REvent;
typedef struct r_event_callback_handle_t {
int handle;
int type;
} REventCallbackHandle;
R_API REvent *r_event_new(void *user);
R_API void r_event_free(REvent *ev);
R_API REventCallbackHandle r_event_hook(REvent *ev, int type, REventCallback cb, void *user);
R_API void r_event_unhook(REvent *ev, REventCallbackHandle handle);
R_API void r_event_send(REvent *ev, int type, void *data);
R_API void r_event_hook(REvent *ev, ut32 type, REventCallback cb, void *data);
R_API bool r_event_unhook(R_NULLABLE REvent *ev, ut32 event_hook, REventCallback cb);
R_API void r_event_send(REvent *ev, ut32 type, void *data);
#ifdef __cplusplus
}

View File

@ -1,16 +1,10 @@
/* radare2 - MIT - Copyright 2018 - pancake */
/* radare2 - MIT - Copyright 2018-2024 - pancake */
#include <r_util.h>
#include <r_vector.h>
typedef struct r_event_callback_hook_t {
REventCallback cb;
void *user;
int handle;
} REventCallbackHook;
static void ht_callback_free(HtUPKv *kv) {
r_vector_free ((RVector *)kv->value);
RVecREventHook_fini (kv->value);
}
R_API REvent *r_event_new(void *user) {
@ -18,109 +12,124 @@ R_API REvent *r_event_new(void *user) {
if (!ev) {
return NULL;
}
ev->user = user;
ev->next_handle = 0;
ev->callbacks = ht_up_new (NULL, ht_callback_free, NULL);
if (!ev->callbacks) {
goto err;
ut32 i;
for (i = 0; i < R_EVENT_LAST; i++) {
RVecREventHook_init (&ev->known_events[i]);
}
ev->lock = r_th_lock_new (false);
ev->other_events = ht_up_new (NULL, ht_callback_free, NULL);
if (R_UNLIKELY (!ev->other_events)) {
r_event_free (ev);
ev = NULL;
}
r_vector_init (&ev->all_callbacks, sizeof (REventCallbackHook), NULL, NULL);
return ev;
err:
r_event_free (ev);
return NULL;
}
R_API void r_event_free(REvent *ev) {
if (!ev) {
return;
}
ht_up_free (ev->callbacks);
r_vector_clear (&ev->all_callbacks);
r_th_lock_enter (ev->lock);
ht_up_free (ev->other_events);
RVecREventHook_fini (&ev->all_events);
ut32 i;
for (i = 0; i < R_EVENT_LAST; i++) {
RVecREventHook_fini (&ev->known_events[i]);
}
r_th_lock_leave (ev->lock);
r_th_lock_free (ev->lock);
free (ev);
}
static RVector *get_cbs(REvent *ev, int type) {
RVector *cbs = ht_up_find (ev->callbacks, (ut64)type, NULL);
static RVecREventHook *get_cbs(REvent *ev, int type) {
RVecREventHook *cbs = ht_up_find (ev->other_events, (ut64)type, NULL);
if (!cbs) {
cbs = r_vector_new (sizeof (REventCallbackHook), NULL, NULL);
if (cbs) {
ht_up_insert (ev->callbacks, (ut64)type, cbs);
cbs = R_NEW0 (RVecREventHook);
RVecREventHook_init (cbs);
if (R_LIKELY (cbs)) {
ht_up_insert (ev->other_events, (ut64)type, cbs);
}
}
return cbs;
}
R_API REventCallbackHandle r_event_hook(REvent *ev, int type, REventCallback cb, void *user) {
REventCallbackHandle handle = {0};
REventCallbackHook hook;
R_RETURN_VAL_IF_FAIL (ev, handle);
hook.cb = cb;
hook.user = user;
hook.handle = ev->next_handle++;
if (type == R_EVENT_ALL) {
r_vector_push (&ev->all_callbacks, &hook);
} else {
RVector *cbs = get_cbs (ev, type);
if (!cbs) {
return handle;
}
r_vector_push (cbs, &hook);
}
handle.handle = hook.handle;
handle.type = type;
return handle;
}
static bool del_hook(void *user, const ut64 k, const void *v) {
int handle = *(int *)user;
RVector *cbs = (RVector *)v;
REventCallbackHook *hook;
size_t i;
R_RETURN_VAL_IF_FAIL (cbs, false);
r_vector_enumerate (cbs, hook, i) {
if (hook->handle == handle) {
r_vector_remove_at (cbs, i, NULL);
break;
}
}
return true;
}
R_API void r_event_unhook(REvent *ev, REventCallbackHandle handle) {
R_RETURN_IF_FAIL (ev);
if (handle.type == R_EVENT_ALL) {
// try to delete it both from each list of callbacks and from
// the "all_callbacks" vector
ht_up_foreach (ev->callbacks, del_hook, &handle.handle);
del_hook (&handle.handle, 0, &ev->all_callbacks);
} else {
RVector *cbs = ht_up_find (ev->callbacks, (ut64)handle.type, NULL);
R_RETURN_IF_FAIL (cbs);
del_hook (&handle.handle, 0, cbs);
}
}
R_API void r_event_send(REvent *ev, int type, void *data) {
REventCallbackHook *hook;
R_RETURN_IF_FAIL (ev && !ev->incall);
// send to both the per-type callbacks and to the all_callbacks
ev->incall = true;
r_vector_foreach (&ev->all_callbacks, hook) {
hook->cb (ev, type, hook->user, data);
}
ev->incall = false;
RVector *cbs = ht_up_find (ev->callbacks, (ut64)type, NULL);
if (!cbs) {
R_API void r_event_hook(R_NULLABLE REvent *ev, ut32 type, REventCallback cb, void *user) {
if (!ev) {
return;
}
ev->incall = true;
r_vector_foreach (cbs, hook) {
hook->cb (ev, type, hook->user, data);
r_th_lock_enter (ev->lock);
REventHook hook = { type, cb, user };
if (type == R_EVENT_ALL) {
RVecREventHook_push_back (&ev->all_events, &hook);
} else {
if (type < R_EVENT_LAST) {
RVecREventHook_push_back (&ev->known_events[type], &hook);
} else {
RVecREventHook *cbs = get_cbs (ev, type);
if (R_LIKELY (cbs)) {
RVecREventHook_push_back (cbs, &hook);
}
}
}
ev->incall = false;
r_th_lock_leave (ev->lock);
}
static inline bool del_hook(RVecREventHook *hooks, const ut64 k, REventCallback cb) {
REventHook *hook;
size_t n = 0;
R_VEC_FOREACH (hooks, hook) {
if (hook->cb == cb) {
RVecREventHook_remove (hooks, n);
return true;
}
n++;
}
return false;
}
R_API bool r_event_unhook(R_NULLABLE REvent *ev, ut32 event_type, REventCallback cb) {
bool res = false;
if (!ev) {
return res;
}
r_th_lock_enter (ev->lock);
if (event_type == R_EVENT_ALL) {
res = del_hook (&ev->all_events, 0, cb);
} else if (event_type < R_EVENT_LAST) {
res = del_hook (&ev->known_events[event_type], 0, cb);
} else {
RVecREventHook *hooks = ht_up_find (ev->other_events, (ut64)event_type, NULL);
if (hooks != NULL) {
res = del_hook (hooks, 0, cb);
}
}
r_th_lock_leave (ev->lock);
return res;
}
// r_event_send (core->ev, R_EVENT_ANALYSIS_START, "");
R_API void r_event_send(R_NULLABLE REvent *ev, ut32 event_type, void *data) {
if (!ev || event_type == R_EVENT_ALL) {
return;
}
REventHook *hook;
r_th_lock_enter (ev->lock);
R_VEC_FOREACH (&ev->all_events, hook) {
hook->cb (ev, event_type, hook->user, data);
}
RVecREventHook *eh = NULL;
if (R_LIKELY (event_type < R_EVENT_LAST)) {
eh = &ev->known_events[event_type];
} else {
eh = ht_up_find (ev->other_events, (ut64)event_type, NULL);
}
if (R_LIKELY (eh)) {
R_VEC_FOREACH (eh, hook) {
hook->cb (ev, event_type, hook->user, data);
}
}
r_th_lock_leave (ev->lock);
}

View File

@ -23,8 +23,10 @@ bool test_r_event(void) {
EventTestAcc acc_all = {0};
EventTestAcc acc_specific = {0};
REventCallbackHandle handle_all = r_event_hook (ev, R_EVENT_ALL, callback_test, &acc_all);
REventCallbackHandle handle_specific = r_event_hook (ev, R_EVENT_META_SET, callback_test, &acc_specific);
// REventCallbackHandle handle_all =
r_event_hook (ev, R_EVENT_ALL, callback_test, &acc_all);
// REventCallbackHandle handle_specific =
r_event_hook (ev, R_EVENT_META_SET, callback_test, &acc_specific);
r_event_send (ev, R_EVENT_META_DEL, (void *)0x4242);
@ -35,7 +37,7 @@ bool test_r_event(void) {
r_event_send (ev, R_EVENT_META_SET, (void *)0xdeadbeef);
mu_assert_eq (acc_all.count, 2, "all count after event");
mu_assert_eq (acc_all.count, 2, "all count after event second metaset");
mu_assert_eq (acc_all.last_type, R_EVENT_META_SET, "all type after event");
mu_assert_ptreq (acc_all.last_data, (void *)0xdeadbeef, "all type after event");
@ -43,7 +45,7 @@ bool test_r_event(void) {
mu_assert_eq (acc_specific.last_type, R_EVENT_META_SET, "specific type after event");
mu_assert_ptreq (acc_specific.last_data, (void *)0xdeadbeef, "specific type after event");
r_event_unhook (ev, handle_all);
r_event_unhook (ev, R_EVENT_ALL, callback_test); // handle_all);
r_event_send (ev, R_EVENT_META_SET, (void *)0xc0ffee);
mu_assert_eq (acc_all.count, 2, "all count after event after being removed");
@ -54,7 +56,7 @@ bool test_r_event(void) {
mu_assert_eq (acc_specific.last_type, R_EVENT_META_SET, "specific type after event");
mu_assert_ptreq (acc_specific.last_data, (void *)0xc0ffee, "specific type after event");
r_event_unhook (ev, handle_specific);
r_event_unhook (ev, R_EVENT_META_SET, callback_test);
r_event_send (ev, R_EVENT_META_SET, (void *)0xc0ffee);
mu_assert_eq (acc_specific.count, 2, "specific count after event after being removed");