diff --git a/librz/analysis/fcn.c b/librz/analysis/fcn.c index b63394942e4..0c944a27d59 100644 --- a/librz/analysis/fcn.c +++ b/librz/analysis/fcn.c @@ -1718,6 +1718,9 @@ RZ_DEPRECATE RZ_API RzAnalysisFunction *rz_analysis_get_fcn_in_bounds(RzAnalysis return ret; } +/** + * \brief Returns function if exists given the \p name + */ RZ_API RzAnalysisFunction *rz_analysis_get_function_byname(RzAnalysis *a, const char *name) { bool found = false; RzAnalysisFunction *f = ht_pp_find(a->ht_name_fun, name, &found); @@ -1760,6 +1763,9 @@ RZ_API bool rz_analysis_fcn_add_bb(RzAnalysis *a, RzAnalysisFunction *fcn, ut64 return true; } +/** + * \brief Returns the amount of loops located in the \p fcn function + */ RZ_API int rz_analysis_function_loops(RzAnalysisFunction *fcn) { RzListIter *iter; RzAnalysisBlock *bb; @@ -1775,13 +1781,19 @@ RZ_API int rz_analysis_function_loops(RzAnalysisFunction *fcn) { return loops; } -RZ_API int rz_analysis_function_complexity(RzAnalysisFunction *fcn) { - /* - CC = E - N + 2P - E = the number of edges of the graph. - N = the number of nodes of the graph. - P = the number of connected components (exit nodes). +/** + * \brief Returns cyclomatic complexity of the function + * + * It calculated using this formula: + * + * CC = E - N + 2P + * where + * E is the number of edges of the graph. + * N is the number of nodes of the graph. + * P is the number of connected components (exit nodes). + * */ +RZ_API int rz_analysis_function_complexity(RzAnalysisFunction *fcn) { RzAnalysis *analysis = fcn->analysis; int E = 0, N = 0, P = 0; RzListIter *iter; @@ -1874,6 +1886,12 @@ RZ_API char *rz_analysis_function_get_json(RzAnalysisFunction *function) { return pj_drain(pj); } +/** + * \brief Returns type signature (prototype) of the function + * + * If the type is presented in the type database it uses it, + * otherwise it tries to derive the type from the analysis data + */ RZ_API RZ_OWN char *rz_analysis_function_get_signature(RZ_NONNULL RzAnalysisFunction *function) { rz_return_val_if_fail(function, NULL); RzAnalysis *a = function->analysis; @@ -2099,6 +2117,9 @@ RZ_API int rz_analysis_function_count_edges(const RzAnalysisFunction *fcn, RZ_NU return edges; } +/** + * \brief Returns if the function pure - accesses any external resources or not + */ RZ_API bool rz_analysis_function_purity(RzAnalysisFunction *fcn) { if (fcn->has_changed) { HtUP *ht = ht_up_new(NULL, NULL, NULL); @@ -2190,6 +2211,11 @@ static void __analysis_fcn_check_bp_use(RzAnalysis *analysis, RzAnalysisFunction } } +/** + * \brief This function checks whether any operation in a given function may change BP + * + * Excludes pattern like "mov bp, sp" and "pop sp, bp" for saving stack pointer value + */ RZ_API void rz_analysis_function_check_bp_use(RzAnalysisFunction *fcn) { rz_return_if_fail(fcn); __analysis_fcn_check_bp_use(fcn->analysis, fcn); @@ -2407,7 +2433,7 @@ RZ_API void rz_analysis_function_update_analysis(RzAnalysisFunction *fcn) { * \brief Returns vector of all function arguments * * \param a RzAnalysis instance - * \param f Function + * \param fcn Function */ RZ_API RZ_OWN RzPVector /**/ *rz_analysis_function_args(RzAnalysis *a, RzAnalysisFunction *fcn) { if (!a || !fcn) { @@ -2467,12 +2493,69 @@ RZ_API RZ_OWN RzPVector /**/ *rz_analysis_function_args(RzAnaly return args; } +/** + * \brief Returns vector of all function variables without arguments + * + * \param a RzAnalysis instance + * \param fcn Function + */ +RZ_API RZ_OWN RzPVector /**/ *rz_analysis_function_vars(RZ_NONNULL RzAnalysis *a, RZ_NONNULL RzAnalysisFunction *fcn) { + rz_return_val_if_fail(a && fcn, NULL); + RzAnalysisVar *var; + void **it; + RzPVector *vars = rz_pvector_new(NULL); + if (!vars) { + return NULL; + } + rz_pvector_foreach (&fcn->vars, it) { + var = *it; + if (!rz_analysis_var_is_arg(var)) { + rz_pvector_push(vars, var); + } + } + return vars; +} + +/** + * \brief Gets the argument given its index + * + * \param analysis RzAnalysis instance + * \param f Function to update + */ +RZ_API RZ_BORROW RzAnalysisVar *rz_analysis_function_get_arg_idx(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *f, size_t index) { + rz_return_val_if_fail(analysis && f, NULL); + int argnum = rz_analysis_function_get_arg_count(analysis, f); + if (argnum < 1) { + return NULL; + } + if (index >= argnum) { + RZ_LOG_VERBOSE("Function %s has less arguments (%d) than requested (%zu)\n", + f->name, argnum, index); + } + RzPVector *args = rz_analysis_function_args(analysis, f); + if (!args) { + RZ_LOG_VERBOSE("Function %s has no arguments\n", f->name); + return NULL; + } + if (rz_pvector_len(args) < index) { + RZ_LOG_VERBOSE("Function %s has less arguments (%zu) than requested (%zu)\n", + f->name, rz_pvector_len(args), index); + return NULL; + } + return rz_pvector_at(args, index); +} + static int typecmp(const void *a, const void *b) { const RzType *t1 = a; const RzType *t2 = b; return !rz_types_equal(t1, t2); } +/** + * \brief Returns vector of all unique types used in a function + * + * Accounts for all types used in both arguments and variables, excluding return value type + */ RZ_API RZ_OWN RzList /**/ *rz_analysis_types_from_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn) { RzList *type_used = rz_list_new(); void **it; diff --git a/librz/analysis/var.c b/librz/analysis/var.c index 2c1f1756fa0..e4dc352f218 100644 --- a/librz/analysis/var.c +++ b/librz/analysis/var.c @@ -204,6 +204,17 @@ RZ_IPI RZ_BORROW RzAnalysisVar *rz_analysis_function_add_var_dwarf(RzAnalysisFun return out; } +/** + * \brief Updates the type of the variable + * + * Frees the old type of the variable and sets a new one. + * After that it checks if the size of the variable has changed + * and tries to resolve overlaps if \p resolve_overlaps is set + * + * \param var variable to check + * \param type new type of the variable + * \param resolve_overlaps resolves overlaps if set + */ RZ_API void rz_analysis_var_set_type(RzAnalysisVar *var, RZ_OWN RzType *type, bool resolve_overlaps) { rz_return_if_fail(var && type); rz_type_free(var->type); @@ -283,11 +294,17 @@ RZ_API void rz_analysis_function_delete_arg_vars(RzAnalysisFunction *fcn) { } } +/** + * Delete all variables from \p fcn function - both arguments and local variables + */ RZ_API void rz_analysis_function_delete_all_vars(RzAnalysisFunction *fcn) { rz_pvector_fini(&fcn->vars); fcn->argnum = 0; } +/** + * Delete all unused (without any read or write access) variables from \p fcn function + */ RZ_API void rz_analysis_function_delete_unused_vars(RzAnalysisFunction *fcn) { void **v; RzPVector *vars_clone = rz_pvector_clone(&fcn->vars); @@ -300,12 +317,18 @@ RZ_API void rz_analysis_function_delete_unused_vars(RzAnalysisFunction *fcn) { rz_pvector_free(vars_clone); } +/** + * Delete variable \p var from \p fcn + */ RZ_API void rz_analysis_function_delete_var(RzAnalysisFunction *fcn, RzAnalysisVar *var) { rz_return_if_fail(fcn && var); rz_pvector_remove_data(&fcn->vars, var); rz_analysis_var_free(var); } +/** + * Search variable by \p name in \p fcn, return first match + */ RZ_API RZ_BORROW RzAnalysisVar *rz_analysis_function_get_var_byname(RzAnalysisFunction *fcn, const char *name) { rz_return_val_if_fail(fcn && name, NULL); void **it; @@ -529,6 +552,10 @@ RZ_API bool rz_analysis_var_rename(RzAnalysisVar *var, const char *new_name, boo return true; } +/** + * Returns the argument number if the variable \p is argument of some function + * and matches the calling convention + */ RZ_API int rz_analysis_var_get_argnum(RzAnalysisVar *var) { rz_return_val_if_fail(var, -1); RzAnalysis *analysis = var->fcn->analysis; @@ -681,10 +708,16 @@ RZ_API RzAnalysisVarAccess *rz_analysis_var_get_access_at(RzAnalysisVar *var, ut return NULL; } +/** + * \brief Adds a type constraint \p constraint to a \p var variables + */ RZ_API void rz_analysis_var_add_constraint(RzAnalysisVar *var, RZ_BORROW RzTypeConstraint *constraint) { rz_vector_push(&var->constraints, constraint); } +/** + * \brief Get all type constraints of a \p var variable in the text form + */ RZ_API char *rz_analysis_var_get_constraints_readable(RzAnalysisVar *var) { size_t n = var->constraints.len; if (!n) { diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 9c51854f999..7f063103218 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -2145,6 +2145,8 @@ RZ_API RzAnalysisClassErr rz_analysis_class_vtable_delete(RzAnalysis *analysis, RZ_API RzGraph /**/ *rz_analysis_class_get_inheritance_graph(RzAnalysis *analysis); RZ_API RZ_OWN RzPVector /**/ *rz_analysis_function_args(RzAnalysis *a, RzAnalysisFunction *fcn); +RZ_API RZ_OWN RzPVector /**/ *rz_analysis_function_vars(RZ_NONNULL RzAnalysis *a, RZ_NONNULL RzAnalysisFunction *fcn); +RZ_API RZ_BORROW RzAnalysisVar *rz_analysis_function_get_arg_idx(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisFunction *f, size_t index); RZ_API RZ_OWN RzList /**/ *rz_analysis_types_from_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn); RZ_API RZ_OWN RzCallable *rz_analysis_function_derive_type(RzAnalysis *analysis, RzAnalysisFunction *f);