Add RzBaseFindOpt for custom thread status callback (#2768)

This commit is contained in:
Giovanni 2022-07-06 11:34:00 +02:00 committed by GitHub
parent dda9c1e7a4
commit 2e0d490d2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 341 additions and 120 deletions

View file

@ -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);

View file

@ -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;
}

View file

@ -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");

View file

@ -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
}

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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',

View 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)