Add API to request function variables without arguments (#3597)
* Add Doxygen to variables API * Add Doxygen to function API * Improve arguments and variables API
This commit is contained in:
parent
c9ef508bf4
commit
33c056e4e3
3 changed files with 125 additions and 7 deletions
|
|
@ -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 /*<RzAnalysisVar *>*/ *rz_analysis_function_args(RzAnalysis *a, RzAnalysisFunction *fcn) {
|
||||
if (!a || !fcn) {
|
||||
|
|
@ -2467,12 +2493,69 @@ cleanup:
|
|||
return args;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns vector of all function variables without arguments
|
||||
*
|
||||
* \param a RzAnalysis instance
|
||||
* \param fcn Function
|
||||
*/
|
||||
RZ_API RZ_OWN RzPVector /*<RzAnalysisVar *>*/ *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 /*<RzType *>*/ *rz_analysis_types_from_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn) {
|
||||
RzList *type_used = rz_list_new();
|
||||
void **it;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -2145,6 +2145,8 @@ RZ_API RzAnalysisClassErr rz_analysis_class_vtable_delete(RzAnalysis *analysis,
|
|||
RZ_API RzGraph /*<RzGraphNodeInfo *>*/ *rz_analysis_class_get_inheritance_graph(RzAnalysis *analysis);
|
||||
|
||||
RZ_API RZ_OWN RzPVector /*<RzAnalysisVar *>*/ *rz_analysis_function_args(RzAnalysis *a, RzAnalysisFunction *fcn);
|
||||
RZ_API RZ_OWN RzPVector /*<RzAnalysisVar *>*/ *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 /*<RzType *>*/ *rz_analysis_types_from_fcn(RzAnalysis *analysis, RzAnalysisFunction *fcn);
|
||||
RZ_API RZ_OWN RzCallable *rz_analysis_function_derive_type(RzAnalysis *analysis, RzAnalysisFunction *f);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue