Add RzBaseFindOpt for custom thread status callback (#2768)
This commit is contained in:
parent
dda9c1e7a4
commit
2e0d490d2f
11 changed files with 341 additions and 120 deletions
|
|
@ -28,7 +28,7 @@ typedef struct basefind_thread_data_t {
|
|||
ut64 current;
|
||||
ut64 base_start;
|
||||
ut64 base_end;
|
||||
ut64 base_inc;
|
||||
ut64 alignment;
|
||||
ut64 io_size;
|
||||
ut32 score_min;
|
||||
RzThreadLock *lock;
|
||||
|
|
@ -37,10 +37,11 @@ typedef struct basefind_thread_data_t {
|
|||
BaseFindArray *array;
|
||||
} BaseFindThreadData;
|
||||
|
||||
typedef struct basefind_thread_cons_t {
|
||||
bool progress;
|
||||
typedef struct basefind_ui_info_t {
|
||||
RzThreadPool *pool;
|
||||
} BaseFindThreadCons;
|
||||
void *user;
|
||||
RzBaseFindThreadInfoCb callback;
|
||||
} BaseFindUIInfo;
|
||||
|
||||
static RzBinFile *basefind_new_bin_file(RzCore *core) {
|
||||
// Copied from cbin.c -> rz_core_bin_whole_strings_print
|
||||
|
|
@ -91,7 +92,7 @@ static bool basefind_array_has(const BaseFindArray *array, ut64 value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
static BaseFindArray *basefind_create_array_of_addresses(RzCore *core) {
|
||||
static BaseFindArray *basefind_create_array_of_addresses(RzCore *core, ut32 min_string_len) {
|
||||
RzList *strings = NULL;
|
||||
BaseFindArray *array = NULL;
|
||||
RzBinFile *alloc = NULL;
|
||||
|
|
@ -103,16 +104,10 @@ static BaseFindArray *basefind_create_array_of_addresses(RzCore *core) {
|
|||
}
|
||||
}
|
||||
|
||||
ut32 string_min_size = rz_config_get_i(core->config, "basefind.string.min");
|
||||
if (string_min_size < 1) {
|
||||
RZ_LOG_ERROR("basefind: cannot find strings when 'basefind.string.min' is zero.\n");
|
||||
rz_goto_if_reached(error);
|
||||
}
|
||||
|
||||
// if this list is sorted we can improve speed via half-interval search
|
||||
strings = rz_bin_file_strings(current, string_min_size, true);
|
||||
strings = rz_bin_file_strings(current, min_string_len, true);
|
||||
if (!strings || rz_list_empty(strings)) {
|
||||
RZ_LOG_ERROR("basefind: cannot find strings in binary with a minimum size of %u.\n", string_min_size);
|
||||
RZ_LOG_ERROR("basefind: cannot find strings in binary with a minimum size of %u.\n", min_string_len);
|
||||
rz_list_free(strings);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -211,7 +206,7 @@ static void *basefind_thread_runner(BaseFindThreadData *bftd) {
|
|||
ut64 base;
|
||||
|
||||
bfd.array = bftd->array;
|
||||
for (base = bftd->base_start; base < bftd->base_end; base += bftd->base_inc) {
|
||||
for (base = bftd->base_start; base < bftd->base_end; base += bftd->alignment) {
|
||||
if (rz_cons_is_breaked()) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -249,38 +244,45 @@ static void *basefind_thread_runner(BaseFindThreadData *bftd) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void basefind_set_thread_info(BaseFindThreadData *bftd, RzBaseFindThreadInfo *th_info, ut32 thread_idx) {
|
||||
ut32 percentage = ((bftd->current - bftd->base_start) * 100) / (bftd->base_end - bftd->base_start);
|
||||
if (percentage > 100) {
|
||||
percentage = 100;
|
||||
}
|
||||
|
||||
th_info->thread_idx = thread_idx;
|
||||
th_info->begin_address = bftd->base_start;
|
||||
th_info->current_address = bftd->current;
|
||||
th_info->end_address = bftd->base_end;
|
||||
th_info->percentage = percentage;
|
||||
}
|
||||
|
||||
// this thread does not care about thread-safety since it only prints
|
||||
// data that will always be available during its lifetime.
|
||||
static void *basefind_thread_cons(BaseFindThreadCons *th_cons) {
|
||||
bool progress = th_cons->progress;
|
||||
RzThreadPool *pool = th_cons->pool;
|
||||
size_t pool_size = rz_th_pool_size(pool);
|
||||
rz_cons_flush();
|
||||
int begin_line = rz_cons_get_cur_line();
|
||||
static void *basefind_thread_ui(BaseFindUIInfo *ui_info) {
|
||||
RzThreadPool *pool = ui_info->pool;
|
||||
ut32 pool_size = rz_th_pool_size(pool);
|
||||
RzBaseFindThreadInfoCb callback = ui_info->callback;
|
||||
void *user = ui_info->user;
|
||||
RzBaseFindThreadInfo th_info;
|
||||
th_info.n_threads = pool_size;
|
||||
|
||||
do {
|
||||
if (progress) {
|
||||
rz_cons_gotoxy(1, begin_line);
|
||||
for (ut32 i = 0; i < pool_size; ++i) {
|
||||
RzThread *th = rz_th_pool_get_thread(pool, i);
|
||||
if (!th) {
|
||||
continue;
|
||||
}
|
||||
BaseFindThreadData *bftd = rz_th_get_user(th);
|
||||
ut32 perc = ((bftd->current - bftd->base_start) * 100) / (bftd->base_end - bftd->base_start);
|
||||
if (perc > 100) {
|
||||
perc = 100;
|
||||
}
|
||||
rz_cons_printf("basefind: thread %u: 0x%08" PFMT64x " / 0x%08" PFMT64x " %u%%\n", i, bftd->current, bftd->base_end, perc);
|
||||
for (ut32 i = 0; i < pool_size; ++i) {
|
||||
RzThread *th = rz_th_pool_get_thread(pool, i);
|
||||
if (!th) {
|
||||
continue;
|
||||
}
|
||||
BaseFindThreadData *bftd = rz_th_get_user(th);
|
||||
basefind_set_thread_info(bftd, &th_info, i);
|
||||
if (!callback(&th_info, user)) {
|
||||
rz_th_pool_kill(pool);
|
||||
goto end;
|
||||
}
|
||||
rz_cons_flush();
|
||||
begin_line = rz_cons_get_cur_line() - pool_size;
|
||||
}
|
||||
rz_sys_usleep(100000);
|
||||
if (rz_cons_is_breaked()) {
|
||||
rz_th_pool_kill(pool);
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
end:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -300,68 +302,68 @@ static inline bool create_thread_interval(RzThreadPool *pool, BaseFindThreadData
|
|||
/**
|
||||
* \brief Calculates a list of possible base addresses candidates using the strings position
|
||||
*
|
||||
* The code finds all the strings in memory with a minimum acceptable size (via basefind.string.min)
|
||||
* The code finds all the strings in memory with a minimum acceptable size (via opt.min_string_len)
|
||||
* and calculates all possible words 32 or 64 bit large sizes (endianness via cfg.bigendian) in the
|
||||
* given binary.
|
||||
* These addresses are then compared with the strings and a variable base address (see basefind.base.start
|
||||
* and basefind.base.end) which is increased over time (see basefind.base.increase).
|
||||
* The scores are ignored if below basefind.score.min otherwise they are added to the list with the
|
||||
* associated base address.
|
||||
* These addresses are then compared with the strings and a variable base address which is increased
|
||||
* over time by opt.alignment.
|
||||
*
|
||||
* \param core RzCore struct to use.
|
||||
* \param pointer_size Pointer size in bits.
|
||||
* \return RzList Sorted list of pairs (score, address) from highest score to lowest.
|
||||
* The scores are added to the result list with the associated base address if their score are higher
|
||||
* than opt.min_score, otherwise they are ignored.
|
||||
*
|
||||
* It is possible via opt.callback to set a callback function that can stop the search (when returning
|
||||
* false) or display the thread statuses (the callback will be called N-times for N spawned threads.
|
||||
*
|
||||
* \param core RzCore struct to use.
|
||||
* \param options Pointer to the RzBaseFindOpt structure.
|
||||
*/
|
||||
RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, ut32 pointer_size) {
|
||||
rz_return_val_if_fail(core, NULL);
|
||||
RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, RZ_NONNULL RzBaseFindOpt *options) {
|
||||
rz_return_val_if_fail(core && options, NULL);
|
||||
RzList *scores = NULL;
|
||||
BaseFindArray *array = NULL;
|
||||
HtUU *pointers = NULL;
|
||||
ut64 base_start = 0, base_end = 0, base_inc = 0;
|
||||
ut32 score_min = 0;
|
||||
size_t max_threads = 0, pool_size = 1;
|
||||
size_t pool_size = 1;
|
||||
RzThreadPool *pool = NULL;
|
||||
RzThreadLock *lock = NULL;
|
||||
bool progress = false;
|
||||
RzThread *user_thread = NULL;
|
||||
BaseFindUIInfo ui_info = { 0 };
|
||||
|
||||
if (pointer_size != 32 && pointer_size != 64) {
|
||||
ut64 base_start = options->start_address;
|
||||
ut64 base_end = options->end_address;
|
||||
ut64 alignment = options->alignment;
|
||||
|
||||
if (options->pointer_size != 32 && options->pointer_size != 64) {
|
||||
RZ_LOG_ERROR("basefind: supported pointer sizes are 32 and 64 bits.\n");
|
||||
return NULL;
|
||||
}
|
||||
pointer_size /= 8;
|
||||
|
||||
if (!core->file) {
|
||||
RZ_LOG_ERROR("basefind: not file was opened via RzCore.\n");
|
||||
} else if (!core->file) {
|
||||
RZ_LOG_ERROR("basefind: the file was not opened via RzCore.\n");
|
||||
return NULL;
|
||||
} else if (base_start >= base_end) {
|
||||
RZ_LOG_ERROR("basefind: start address is greater or equal to end address.\n");
|
||||
return NULL;
|
||||
} else if (alignment < 1) {
|
||||
RZ_LOG_ERROR("basefind: the alignment is set to zero bytes.\n");
|
||||
return NULL;
|
||||
} else if (options->min_score < 1) {
|
||||
RZ_LOG_ERROR("basefind: the minimum score is set to zero.\n");
|
||||
return NULL;
|
||||
} else if (options->min_string_len < 1) {
|
||||
RZ_LOG_ERROR("basefind: the minimum string length is set to zero.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base_start = rz_config_get_i(core->config, "basefind.base.start");
|
||||
base_end = rz_config_get_i(core->config, "basefind.base.end");
|
||||
base_inc = rz_config_get_i(core->config, "basefind.base.increase");
|
||||
score_min = rz_config_get_i(core->config, "basefind.score.min");
|
||||
max_threads = rz_config_get_i(core->config, "basefind.threads.max");
|
||||
progress = rz_config_get_b(core->config, "basefind.progress");
|
||||
|
||||
if (base_start >= base_end) {
|
||||
RZ_LOG_ERROR("basefind: option 'basefind.base.start' is greater or equal to 'basefind.base.end'.\n");
|
||||
return NULL;
|
||||
} else if (base_inc < 1) {
|
||||
RZ_LOG_ERROR("basefind: option 'basefind.base.increase' is zero.\n");
|
||||
return NULL;
|
||||
} else if (base_inc < RZ_BASEFIND_BASE_INCREASE) {
|
||||
RZ_LOG_WARN("basefind: option 'basefind.base.increase' is less than 0x%x, which may result in a very slow search.\n", RZ_BASEFIND_BASE_INCREASE);
|
||||
if (alignment < RZ_BASEFIND_BASE_ALIGNMENT) {
|
||||
RZ_LOG_WARN("basefind: the alignment is less than 0x%x bytes, "
|
||||
"which may result in a very slow search.\n",
|
||||
RZ_BASEFIND_BASE_ALIGNMENT);
|
||||
}
|
||||
|
||||
if (score_min < 1) {
|
||||
RZ_LOG_WARN("basefind: option 'basefind.score.min' zero, which may result in a long list of results.\n");
|
||||
}
|
||||
|
||||
array = basefind_create_array_of_addresses(core);
|
||||
array = basefind_create_array_of_addresses(core, options->min_string_len);
|
||||
if (!array) {
|
||||
goto rz_basefind_end;
|
||||
}
|
||||
|
||||
pointers = basefind_create_pointer_map(core, pointer_size);
|
||||
pointers = basefind_create_pointer_map(core, options->pointer_size / 8);
|
||||
if (!pointers) {
|
||||
goto rz_basefind_end;
|
||||
}
|
||||
|
|
@ -372,7 +374,7 @@ RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, ut32 pointer_size) {
|
|||
goto rz_basefind_end;
|
||||
}
|
||||
|
||||
pool = rz_th_pool_new(max_threads);
|
||||
pool = rz_th_pool_new(options->max_threads);
|
||||
if (!pool) {
|
||||
RZ_LOG_ERROR("basefind: cannot allocate thread pool.\n");
|
||||
goto rz_basefind_end;
|
||||
|
|
@ -396,11 +398,11 @@ RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, ut32 pointer_size) {
|
|||
rz_th_pool_kill(pool);
|
||||
goto rz_basefind_end;
|
||||
}
|
||||
bftd->base_inc = base_inc;
|
||||
bftd->alignment = alignment;
|
||||
bftd->base_start = base_start + (sector_size * i);
|
||||
bftd->current = bftd->base_start;
|
||||
bftd->base_end = bftd->base_start + sector_size;
|
||||
bftd->score_min = score_min;
|
||||
bftd->score_min = options->min_score;
|
||||
bftd->io_size = io_size;
|
||||
bftd->lock = lock;
|
||||
bftd->scores = scores;
|
||||
|
|
@ -413,22 +415,32 @@ RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, ut32 pointer_size) {
|
|||
}
|
||||
}
|
||||
|
||||
BaseFindThreadCons th_cons;
|
||||
th_cons.progress = progress;
|
||||
th_cons.pool = pool;
|
||||
|
||||
RzThread *cons_thread = rz_th_new((RzThreadFunction)basefind_thread_cons, &th_cons);
|
||||
if (!cons_thread) {
|
||||
rz_th_pool_kill(pool);
|
||||
goto rz_basefind_end;
|
||||
if (options->callback) {
|
||||
ui_info.pool = pool;
|
||||
ui_info.user = options->user;
|
||||
ui_info.callback = options->callback;
|
||||
user_thread = rz_th_new((RzThreadFunction)basefind_thread_ui, &ui_info);
|
||||
if (!user_thread) {
|
||||
rz_th_pool_kill(pool);
|
||||
goto rz_basefind_end;
|
||||
}
|
||||
}
|
||||
rz_th_pool_wait(pool);
|
||||
if (progress) {
|
||||
// ensure to print the 100%
|
||||
rz_sys_usleep(100000);
|
||||
if (options->callback) {
|
||||
RzBaseFindThreadInfo th_info;
|
||||
th_info.n_threads = pool_size;
|
||||
for (ut32 i = 0; i < pool_size; ++i) {
|
||||
RzThread *th = rz_th_pool_get_thread(pool, i);
|
||||
if (!th) {
|
||||
continue;
|
||||
}
|
||||
BaseFindThreadData *bftd = rz_th_get_user(th);
|
||||
basefind_set_thread_info(bftd, &th_info, i);
|
||||
options->callback(&th_info, options->user);
|
||||
}
|
||||
rz_th_kill(user_thread);
|
||||
rz_th_free(user_thread);
|
||||
}
|
||||
rz_th_kill(cons_thread);
|
||||
rz_th_free(cons_thread);
|
||||
|
||||
rz_list_sort(scores, (RzListComparator)basefind_score_compare);
|
||||
|
||||
|
|
|
|||
|
|
@ -2554,12 +2554,50 @@ RZ_API bool rz_core_bin_cur_segment_print(RzCore *core, RzBinFile *bf, RzCmdStat
|
|||
return rz_core_bin_segments_print(core, bf, state, &filter, hashes);
|
||||
}
|
||||
|
||||
static bool core_basefind_progess_status(const RzBaseFindThreadInfo *th_info, void *user) {
|
||||
rz_cons_flush();
|
||||
rz_cons_printf("basefind: thread %u: 0x%08" PFMT64x " / 0x%08" PFMT64x " %u%%\n",
|
||||
th_info->thread_idx, th_info->current_address,
|
||||
th_info->end_address, th_info->percentage);
|
||||
rz_cons_flush();
|
||||
if ((th_info->thread_idx + 1) >= th_info->n_threads) {
|
||||
rz_cons_gotoxy(1, rz_cons_get_cur_line() - th_info->n_threads);
|
||||
}
|
||||
return !rz_cons_is_breaked();
|
||||
}
|
||||
|
||||
static bool core_basefind_check_ctrl_c(const RzBaseFindThreadInfo *th_info, void *user) {
|
||||
return !rz_cons_is_breaked();
|
||||
}
|
||||
|
||||
RZ_API bool rz_core_bin_basefind_print(RzCore *core, ut32 pointer_size, RzCmdStateOutput *state) {
|
||||
rz_return_val_if_fail(core && state, false);
|
||||
RzListIter *it = NULL;
|
||||
RzBaseFindScore *pair = NULL;
|
||||
RzBaseFindOpt options;
|
||||
bool progress = rz_config_get_b(core->config, "basefind.progress");
|
||||
int begin_line = rz_cons_get_cur_line();
|
||||
|
||||
options.pointer_size = pointer_size;
|
||||
options.start_address = rz_config_get_i(core->config, "basefind.search.start");
|
||||
options.end_address = rz_config_get_i(core->config, "basefind.search.end");
|
||||
options.alignment = rz_config_get_i(core->config, "basefind.alignment");
|
||||
options.max_threads = rz_config_get_i(core->config, "basefind.max.threads");
|
||||
options.min_score = rz_config_get_i(core->config, "basefind.min.score");
|
||||
options.min_string_len = rz_config_get_i(core->config, "basefind.min.string");
|
||||
options.callback = progress ? core_basefind_progess_status : core_basefind_check_ctrl_c;
|
||||
options.user = NULL;
|
||||
|
||||
RzList *scores = rz_basefind(core, &options);
|
||||
|
||||
if (progress) {
|
||||
// ensure the last printed line is actually the last expected line
|
||||
// this depends on the number of the threads requested and available
|
||||
// this requires to be called before checking the results
|
||||
int n_cores = (int)rz_th_request_physical_cores(options.max_threads);
|
||||
rz_cons_gotoxy(1, begin_line + n_cores);
|
||||
}
|
||||
|
||||
RzList *scores = rz_basefind(core, pointer_size);
|
||||
if (!scores) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3647,12 +3647,12 @@ RZ_API int rz_core_config_init(RzCore *core) {
|
|||
|
||||
/* basefind */
|
||||
SETB("basefind.progress", false, "Basefind threads progress (true: enable, false: disable)");
|
||||
SETI("basefind.base.start", RZ_BASEFIND_BASE_MIN_ADDRESS, "Basefind start address value");
|
||||
SETI("basefind.base.end", RZ_BASEFIND_BASE_MAX_ADDRESS, "Basefind end address value");
|
||||
SETI("basefind.base.increase", RZ_BASEFIND_BASE_INCREASE, "Basefind increase address by");
|
||||
SETI("basefind.score.min", RZ_BASEFIND_SCORE_MIN_VALUE, "Basefind min score value to consider it valid");
|
||||
SETI("basefind.string.min", RZ_BASEFIND_STRING_MIN_LENGTH, "Basefind min string size to find to consider it valid");
|
||||
SETI("basefind.threads.max", RZ_THREAD_POOL_ALL_CORES, "Basefind max threads number (when 0 uses all available cores)");
|
||||
SETI("basefind.search.start", RZ_BASEFIND_BASE_MIN_ADDRESS, "Basefind start search address");
|
||||
SETI("basefind.search.end", RZ_BASEFIND_BASE_MAX_ADDRESS, "Basefind end search address");
|
||||
SETI("basefind.alignment", RZ_BASEFIND_BASE_ALIGNMENT, "Basefind alignment in bytes");
|
||||
SETI("basefind.min.score", RZ_BASEFIND_SCORE_MIN_VALUE, "Basefind min score value to consider it valid");
|
||||
SETI("basefind.min.string", RZ_BASEFIND_STRING_MIN_LENGTH, "Basefind min string size to find to consider it valid");
|
||||
SETI("basefind.max.threads", RZ_THREAD_POOL_ALL_CORES, "Basefind max threads number (when 0 uses all available cores)");
|
||||
|
||||
/* nkeys */
|
||||
SETPREF("key.s", "", "override step into action");
|
||||
|
|
|
|||
|
|
@ -13,15 +13,39 @@ extern "C" {
|
|||
#define RZ_BASEFIND_STRING_MIN_LENGTH (10)
|
||||
#define RZ_BASEFIND_BASE_MIN_ADDRESS (0ull)
|
||||
#define RZ_BASEFIND_BASE_MAX_ADDRESS (0xf0000000ull)
|
||||
#define RZ_BASEFIND_BASE_INCREASE (0x1000)
|
||||
#define RZ_BASEFIND_BASE_ALIGNMENT (0x1000)
|
||||
#define RZ_BASEFIND_SCORE_MIN_VALUE (1)
|
||||
|
||||
typedef struct rz_basefind_t {
|
||||
ut64 candidate;
|
||||
ut32 score;
|
||||
ut64 candidate; ///< Candidate physical base address
|
||||
ut32 score; ///< Score of the candidate address
|
||||
} RzBaseFindScore;
|
||||
|
||||
RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, ut32 pointer_size);
|
||||
typedef struct rz_basefind_info_t {
|
||||
ut32 n_threads; ///< Total number of search threads.
|
||||
ut32 thread_idx; ///< Sesarch thread number.
|
||||
ut64 begin_address; ///< Thread related search address (start).
|
||||
ut64 current_address; ///< Thread related search address (current).
|
||||
ut64 end_address; ///< Thread related search address (end).
|
||||
ut32 percentage; ///< Progress made by the search thread.
|
||||
} RzBaseFindThreadInfo;
|
||||
|
||||
// Used to provide user information regarding the running threads and to stop the execution when needed.
|
||||
typedef bool (*RzBaseFindThreadInfoCb)(const RzBaseFindThreadInfo *th_info, void *user);
|
||||
|
||||
typedef struct rz_basefind_options_t {
|
||||
size_t max_threads; ///< Max requested number of threads (not guaranteed).
|
||||
ut32 pointer_size; ///< Pointer size in bits (32 or 64)
|
||||
ut64 start_address; ///< Start search address
|
||||
ut64 end_address; ///< End search address
|
||||
ut64 alignment; ///< Memory alignment in bytes (suggested to set it to RZ_BASEFIND_BASE_ALIGNMENT)
|
||||
ut32 min_score; ///< Minimum score to reach to be part of the list of possible addresses
|
||||
ut32 min_string_len; ///< Min string length to search for
|
||||
RzBaseFindThreadInfoCb callback; ///< When set allows to get the thread information
|
||||
void *user; ///< User pointer to pass to the callback function for the thread info
|
||||
} RzBaseFindOpt;
|
||||
|
||||
RZ_API RZ_OWN RzList *rz_basefind(RZ_NONNULL RzCore *core, RZ_NONNULL RzBaseFindOpt *options);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ RZ_API bool rz_io_read_at_mapped(RzIO *io, ut64 addr, ut8 *buf, int len);
|
|||
RZ_API int rz_io_nread_at(RzIO *io, ut64 addr, ut8 *buf, int len);
|
||||
RZ_API bool rz_io_write_at(RzIO *io, ut64 addr, const ut8 *buf, int len);
|
||||
RZ_API bool rz_io_read(RzIO *io, ut8 *buf, int len);
|
||||
RZ_API bool rz_io_write(RzIO *io, ut8 *buf, int len);
|
||||
RZ_API bool rz_io_write(RzIO *io, const ut8 *buf, int len);
|
||||
RZ_API ut64 rz_io_size(RzIO *io);
|
||||
RZ_API bool rz_io_is_listener(RzIO *io);
|
||||
RZ_API char *rz_io_system(RzIO *io, const char *cmd);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ RZ_API void rz_th_cond_wait(RZ_NONNULL RzThreadCond *cond, RZ_NONNULL RzThreadLo
|
|||
RZ_API void rz_th_cond_free(RZ_NULLABLE RzThreadCond *cond);
|
||||
|
||||
RZ_API size_t rz_th_physical_core_number();
|
||||
RZ_API size_t rz_th_request_physical_cores(size_t max_cores);
|
||||
RZ_API RZ_OWN RzThreadPool *rz_th_pool_new(size_t max_threads);
|
||||
RZ_API void rz_th_pool_free(RZ_NULLABLE RzThreadPool *pool);
|
||||
RZ_API bool rz_th_pool_add_thread(RZ_NONNULL RzThreadPool *pool, RZ_NONNULL RzThread *thread);
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ RZ_API bool rz_io_read(RzIO *io, ut8 *buf, int len) {
|
|||
return false;
|
||||
}
|
||||
|
||||
RZ_API bool rz_io_write(RzIO *io, ut8 *buf, int len) {
|
||||
RZ_API bool rz_io_write(RzIO *io, const ut8 *buf, int len) {
|
||||
if (io && buf && len > 0 && rz_io_write_at(io, io->off, buf, len)) {
|
||||
io->off += len;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -67,6 +67,22 @@ RZ_API size_t rz_th_physical_core_number() {
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the maximum number of cores available regardless of the number of cores requested.
|
||||
* When set to 0, it will be the max number of physical cores.
|
||||
*
|
||||
* \param[in] max_cores The maximum number of physical cores to request
|
||||
*
|
||||
* \return The actual max number of cores available
|
||||
*/
|
||||
RZ_API size_t rz_th_request_physical_cores(size_t max_cores) {
|
||||
size_t n_cores = rz_th_physical_core_number();
|
||||
if (!max_cores) {
|
||||
return n_cores;
|
||||
}
|
||||
return RZ_MIN(n_cores, max_cores);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief returns a new RzThreadPool structure with a pool of thread
|
||||
*
|
||||
|
|
@ -83,13 +99,8 @@ RZ_API RZ_OWN RzThreadPool *rz_th_pool_new(size_t max_threads) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
size_t cores = rz_th_physical_core_number();
|
||||
if (max_threads) {
|
||||
cores = RZ_MIN(cores, max_threads);
|
||||
}
|
||||
|
||||
pool->size = cores;
|
||||
pool->threads = RZ_NEWS0(RzThread *, cores);
|
||||
pool->size = rz_th_request_physical_cores(max_threads);
|
||||
pool->threads = RZ_NEWS0(RzThread *, pool->size);
|
||||
if (!pool->threads) {
|
||||
free(pool);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
NAME=basefind via rizin
|
||||
FILE=bins/firmware/stm32f103-dapboot-v1.20-bluepill.bin
|
||||
CMDS=<<EOF
|
||||
e basefind.threads.max=1
|
||||
e basefind.base.end=0x10000000
|
||||
e basefind.base.start=0x6000000
|
||||
e basefind.max.threads=1
|
||||
e basefind.search.start=0x06000000
|
||||
e basefind.search.end=0x10000000
|
||||
e log.level=3
|
||||
Bj
|
||||
Bq
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ if get_option('enable_tests')
|
|||
)
|
||||
|
||||
tests = [
|
||||
'analysis_il',
|
||||
'analysis_global_var',
|
||||
'analysis_il',
|
||||
'autocmplt',
|
||||
'basefind',
|
||||
'bin',
|
||||
'bin_vfiles',
|
||||
'cpu_platform_profiles',
|
||||
|
|
|
|||
134
test/integration/test_basefind.c
Normal file
134
test/integration/test_basefind.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// SPDX-FileCopyrightText: 2015 Jeffrey Crowell <crowell@bu.edu>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_core.h>
|
||||
#include <rz_basefind.h>
|
||||
#include "../unit/minunit.h"
|
||||
|
||||
static void basefind_options_set_valid(RzBaseFindOpt *options) {
|
||||
options->start_address = 0;
|
||||
options->end_address = 4096;
|
||||
options->pointer_size = 32;
|
||||
options->min_score = 1;
|
||||
options->min_string_len = 10;
|
||||
options->alignment = RZ_BASEFIND_BASE_ALIGNMENT;
|
||||
options->max_threads = 1;
|
||||
options->callback = NULL;
|
||||
options->user = NULL;
|
||||
}
|
||||
|
||||
static bool test_basefind_callback_false(const RzBaseFindThreadInfo *th_info, void *user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool test_basefind_callback_true(const RzBaseFindThreadInfo *th_info, void *user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int test_rz_basefind_with_callbacks(void) {
|
||||
RzBaseFindOpt options;
|
||||
RzList *result = NULL;
|
||||
RzCore *core = rz_core_new();
|
||||
rz_core_file_open_load(core, "bins/firmware/stm32f103-dapboot-v1.20-bluepill.bin", 0, RZ_PERM_R, false);
|
||||
|
||||
// test_basefind_callback_true
|
||||
basefind_options_set_valid(&options);
|
||||
options.callback = test_basefind_callback_true;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_notnull(result, "valid callback (true)");
|
||||
rz_list_free(result);
|
||||
|
||||
// test_basefind_callback_false
|
||||
basefind_options_set_valid(&options);
|
||||
options.callback = test_basefind_callback_false;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_notnull(result, "valid callback (false)");
|
||||
rz_list_free(result);
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
int test_rz_basefind_no_callback(void) {
|
||||
RzBaseFindOpt options;
|
||||
RzList *result = NULL;
|
||||
RzCore *core = rz_core_new();
|
||||
rz_core_file_open_load(core, "bins/firmware/stm32f103-dapboot-v1.20-bluepill.bin", 0, RZ_PERM_R, false);
|
||||
|
||||
// valid configuration
|
||||
basefind_options_set_valid(&options);
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_notnull(result, "valid pointer_size 32");
|
||||
rz_list_free(result);
|
||||
|
||||
// valid configuration
|
||||
basefind_options_set_valid(&options);
|
||||
options.pointer_size = 64;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_notnull(result, "valid pointer_size 64");
|
||||
rz_list_free(result);
|
||||
|
||||
// pointer_size
|
||||
basefind_options_set_valid(&options);
|
||||
options.pointer_size = 77;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "invalid pointer_size");
|
||||
|
||||
// min_score
|
||||
basefind_options_set_valid(&options);
|
||||
options.min_score = 0;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "invalid min_score");
|
||||
|
||||
// min_string_len
|
||||
basefind_options_set_valid(&options);
|
||||
options.min_string_len = 0;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "invalid min_string_len");
|
||||
|
||||
// alignment
|
||||
basefind_options_set_valid(&options);
|
||||
options.alignment = 0;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "invalid alignment");
|
||||
|
||||
// start == end
|
||||
basefind_options_set_valid(&options);
|
||||
options.start_address = 0x1111;
|
||||
options.end_address = 0x1111;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "invalid address (start == end).");
|
||||
|
||||
// start > end
|
||||
basefind_options_set_valid(&options);
|
||||
options.start_address = 0x1111;
|
||||
options.end_address = 0x77;
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "invalid address (start > end).");
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
int test_rz_basefind_no_core_load(void) {
|
||||
RzBaseFindOpt options;
|
||||
RzList *result = NULL;
|
||||
RzCore *core = rz_core_new();
|
||||
|
||||
rz_io_open(core->io, "bins/firmware/stm32f103-dapboot-v1.20-bluepill.bin", RZ_PERM_R, 0);
|
||||
basefind_options_set_valid(&options);
|
||||
result = rz_basefind(core, &options);
|
||||
mu_assert_null(result, "file not loaded via core");
|
||||
|
||||
rz_core_free(core);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
int all_tests() {
|
||||
mu_run_test(test_rz_basefind_no_core_load);
|
||||
mu_run_test(test_rz_basefind_no_callback);
|
||||
mu_run_test(test_rz_basefind_with_callbacks);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
mu_main(all_tests)
|
||||
Loading…
Reference in a new issue