Repository URL to install this package:
|
Version:
9.1~250226-4.fc43 ▾
|
/*
* Interactive disassembler (IDA).
* Copyright (c) 1990-2025 Hex-Rays
* ALL RIGHTS RESERVED.
*
*/
#ifndef _EXPR_H
#define _EXPR_H
#include <ieee.h>
#include <idp.hpp>
/*! \file expr.hpp
\brief Functions that deal with C-like expressions and built-in IDC language.
Functions marked #THREAD_SAFE may be called from any thread.
No simultaneous calls should be made for the same variable.
We protect only global structures, individual variables must
be protected manually.
*/
//------------------------------------------------------------------------
// Forward declarations
class idc_value_t;
class idc_class_t;
class idc_object_t;
/// IDC script extension
#define IDC_LANG_EXT "idc"
/// Convert IDC variable to a long (32/64bit) number.
/// \return v = 0 if impossible to convert to long
idaman THREAD_SAFE error_t ida_export idcv_long(idc_value_t *v);
/// Convert IDC variable to a 64bit number.
/// \return v = 0 if impossible to convert to int64
idaman THREAD_SAFE error_t ida_export idcv_int64(idc_value_t *v);
/// Convert IDC variable to a long number.
/// \return
/// - v = 0 if IDC variable = "false" string
/// - v = 1 if IDC variable = "true" string
/// - v = number if IDC variable is number or string containing a number
/// - eTypeConflict if IDC variable = empty string
idaman THREAD_SAFE error_t ida_export idcv_num(idc_value_t *v);
/// Convert IDC variable to a text string
idaman THREAD_SAFE error_t ida_export idcv_string(idc_value_t *v);
/// Convert IDC variable to a floating point
idaman THREAD_SAFE error_t ida_export idcv_float(idc_value_t *v);
/// Create an IDC object. The original value of 'v' is discarded (freed).
/// \param v variable to hold the object. any previous value will be cleaned
/// \param icls ptr to the desired class. nullptr means "object" class
/// this ptr must be returned by add_idc_class() or find_idc_class()
/// \return always eOk
idaman THREAD_SAFE error_t ida_export idcv_object(
idc_value_t *v,
const idc_class_t *icls=nullptr);
/// Move 'src' to 'dst'.
/// This function is more effective than copy_idcv since it never copies big
/// amounts of data.
idaman THREAD_SAFE error_t ida_export move_idcv(
idc_value_t *dst,
idc_value_t *src);
/// Copy 'src' to 'dst'.
/// For idc objects only a reference is copied.
idaman THREAD_SAFE error_t ida_export copy_idcv(
idc_value_t *dst,
const idc_value_t &src);
/// Deep copy an IDC object.
/// This function performs deep copy of idc objects.
/// If 'src' is not an object, copy_idcv() will be called
idaman THREAD_SAFE error_t ida_export deep_copy_idcv(
idc_value_t *dst,
const idc_value_t &src);
/// Free storage used by #VT_STR/#VT_OBJ IDC variables.
/// After this call the variable has a numeric value 0
idaman THREAD_SAFE void ida_export free_idcv(idc_value_t *v);
/// Swap 2 variables
idaman THREAD_SAFE void ida_export swap_idcvs(
idc_value_t *v1,
idc_value_t *v2);
/// Retrieves the IDC object class name.
/// \param out qstring ptr for the class name. Can be nullptr.
/// \param obj class instance variable
/// \return error code, eOk on success
idaman THREAD_SAFE error_t ida_export get_idcv_class_name(
qstring *out,
const idc_value_t *obj);
/// Get an object attribute.
/// \param res buffer for the attribute value
/// \param obj variable that holds an object reference.
/// if obj is nullptr it searches global variables, then user functions
/// \param attr attribute name
/// \param may_use_getattr may call getattr functions to calculate the attribute if it does not exist
/// \return error code, eOk on success
idaman THREAD_SAFE error_t ida_export get_idcv_attr(
idc_value_t *res,
const idc_value_t *obj,
const char *attr,
bool may_use_getattr=false);
/// Set an object attribute.
/// \param obj variable that holds an object reference.
/// if obj is nullptr then it tries to modify a global variable with the attribute name
/// \param attr attribute name
/// \param value new attribute value
/// \param may_use_setattr may call setattr functions for the class
/// \return error code, eOk on success
idaman THREAD_SAFE error_t ida_export set_idcv_attr(
idc_value_t *obj,
const char *attr,
const idc_value_t &value,
bool may_use_setattr=false);
/// Delete an object attribute.
/// \param obj variable that holds an object reference
/// \param attr attribute name
/// \return error code, eOk on success
idaman THREAD_SAFE error_t ida_export del_idcv_attr(
idc_value_t *obj,
const char *attr);
/// \name Enumerate object attributes
///@{
idaman THREAD_SAFE const char *ida_export first_idcv_attr(const idc_value_t *obj);
idaman THREAD_SAFE const char *ida_export last_idcv_attr(const idc_value_t *obj);
idaman THREAD_SAFE const char *ida_export next_idcv_attr(const idc_value_t *obj, const char *attr);
idaman THREAD_SAFE const char *ida_export prev_idcv_attr(const idc_value_t *obj, const char *attr);
///@}
/// Get text representation of idc_value_t
idaman bool ida_export print_idcv(
qstring *out,
const idc_value_t &v,
const char *name=nullptr,
int indent=0);
/// Get slice.
/// \param res output variable that will contain the slice
/// \param v input variable (string or object)
/// \param i1 slice start index
/// \param i2 slice end index (excluded)
/// \param flags \ref VARSLICE_ or 0
/// \return eOk if success
idaman THREAD_SAFE error_t ida_export get_idcv_slice(
idc_value_t *res,
const idc_value_t *v,
uval_t i1,
uval_t i2,
int flags=0);
/// \defgroup VARSLICE_ IDC variable slice flags
/// Passed as 'flags' parameter to get_idcv_slice() and set_idcv_slice()
///@{
#define VARSLICE_SINGLE 0x0001 ///< return single index (i2 is ignored)
///@}
/// Set slice.
/// \param v variable to modify (string or object)
/// \param i1 slice start index
/// \param i2 slice end index (excluded)
/// \param in new value for the slice
/// \param flags \ref VARSLICE_ or 0
/// \return eOk on success
idaman THREAD_SAFE error_t ida_export set_idcv_slice(
idc_value_t *v,
uval_t i1,
uval_t i2,
const idc_value_t &in,
int flags=0);
//-------------------------------------------------------------------------
// IDC class related functions
/// Create a new IDC class.
/// \param name name of the new class
/// \param super the base class for the new class. if the new class is not based
/// on any other class, pass nullptr
/// \return pointer to the created class. If such a class already exists, a pointer
/// to it will be returned.
/// Pointers to other existing classes may be invalidated by this call.
idaman THREAD_SAFE idc_class_t *ida_export add_idc_class(
const char *name,
const idc_class_t *super=nullptr);
/// Find an existing IDC class by its name.
/// \param name name of the class
/// \return pointer to the class or nullptr.
/// The returned pointer is valid until a new call to add_idc_class()
idaman THREAD_SAFE idc_class_t *ida_export find_idc_class(const char *name);
/// Set an IDC class method.
/// \param icls pointer to the class
/// \param fullfuncname name of the function to call. use full method name: classname.funcname
/// \retval true success
/// \retval false the function could not be found
idaman THREAD_SAFE bool ida_export set_idc_method(idc_class_t *icls, const char *fullfuncname);
/// \name Set user-defined functions to work with object attributes.
/// If the function name is nullptr, the definitions are removed.
/// \return name of the old attribute function. nullptr means error, "" means no previous attr func
///@{
idaman THREAD_SAFE const char *ida_export set_idc_getattr(idc_class_t *icls, const char *fullfuncname);
idaman THREAD_SAFE const char *ida_export set_idc_setattr(idc_class_t *icls, const char *fullfuncname);
///@}
/// Set a destructor for an idc class.
/// The destructor is called before deleting any object of the specified class.
/// Exceptions that escape the destructor are silently ignored, runtime errors too.
idaman THREAD_SAFE const char *ida_export set_idc_dtor(idc_class_t *icls, const char *fullfuncname);
/// Dereference a #VT_REF variable.
/// \param v variable to dereference
/// \param vref_flags \ref VREF_
/// \return pointer to the dereference result or nullptr.
/// If returns nullptr, qerrno is set to eExecBadRef "Illegal variable reference"
idaman THREAD_SAFE idc_value_t *ida_export deref_idcv(idc_value_t *v, int vref_flags);
/// \defgroup VREF_ Dereference IDC variable flags
/// Passed as 'vref_flags' parameter to deref_idcv()
///@{
#define VREF_LOOP 0x0000 ///< dereference until we get a non #VT_REF
#define VREF_ONCE 0x0001 ///< dereference only once, do not loop
#define VREF_COPY 0x0002 ///< copy the result to the input var (v)
///@}
/// Create a variable reference.
/// Currently only references to global variables can be created.
/// \param ref ptr to the result
/// \param v variable to reference
/// \return success
idaman THREAD_SAFE bool ida_export create_idcv_ref(idc_value_t *ref, const idc_value_t *v);
/// Add global IDC variable.
/// \param name name of the global variable
/// \return pointer to the created variable or existing variable.
/// NB: the returned pointer is valid until a new global var is added.
idaman THREAD_SAFE idc_value_t *ida_export add_idc_gvar(const char *name);
/// Find an existing global IDC variable by its name.
/// \param name name of the global variable
/// \return pointer to the variable or nullptr.
/// NB: the returned pointer is valid until a new global var is added.
/// FIXME: it is difficult to use this function in a thread safe manner
idaman THREAD_SAFE idc_value_t *ida_export find_idc_gvar(const char *name);
//-------------------------------------------------------------------------
/// Class to hold idc values
class idc_value_t
{
public:
/// \defgroup VT_ IDC value types
/// Used by idc_value_t::vtype
///@{
#define VT_LONG 2 ///< Integer (see idc_value_t::num)
#define VT_FLOAT 3 ///< Floating point (see idc_value_t::e)
#define VT_WILD 4 ///< Function with arbitrary number of arguments.
///< The actual number of arguments will be passed in idc_value_t::num.
///< This value should not be used for ::idc_value_t.
#define VT_OBJ 5 ///< Object (see idc_value_t::obj)
#define VT_FUNC 6 ///< Function (see idc_value_t::funcidx)
#define VT_STR 7 ///< String (see qstr() and similar functions)
#define VT_PVOID 8 ///< void *
#define VT_INT64 9 ///< i64
#define VT_REF 10 ///< Reference
///@}
char vtype = VT_LONG; ///< \ref VT_
#ifndef SWIG
// this union must be the last member (see memset below)
union
{
#endif // SWIG
sval_t num; ///< #VT_LONG
fpvalue_t e; ///< #VT_FLOAT
idc_object_t *obj;
int funcidx; ///< #VT_FUNC
void *pvoid; ///< #VT_PVOID
int64 i64; ///< #VT_INT64
uchar reserve[sizeof(qstring)]; ///< VT_STR
#ifndef SWIG
};
#endif // SWIG
/// Create a #VT_LONG value
idc_value_t(sval_t n=0)
{
memset(reserve, 0, sizeof(idc_value_t) - qoffsetof(idc_value_t, reserve));
num = n;
}
/// Create a $VT_LONG with an existing idc value
idc_value_t(const idc_value_t &r)
{
memset(reserve, 0, sizeof(idc_value_t) - qoffsetof(idc_value_t, reserve));
copy_idcv(this, r);
}
/// Create a #VT_STR value
idc_value_t(const char *_str) : vtype(VT_STR) { new(&qstr()) qstring(_str); }
/// Create a #VT_STR value
idc_value_t(const qstring &_str) : vtype(VT_STR) { new(&qstr()) qstring(_str); }
/// Destructor
~idc_value_t(void) { clear(); }
/// See free_idcv()
void clear(void) { free_idcv(this); } // put num 0
/// Assign this value to an existing value
idc_value_t &operator = (const idc_value_t &r)
{
copy_idcv(this, r);
return *this;
}
qstring &qstr(void) { return *(qstring *)# } ///< #VT_STR
const qstring &qstr(void) const { return *(qstring *)# } ///< #VT_STR
const char *c_str(void) const { return qstr().c_str(); } ///< #VT_STR
const uchar *u_str(void) const { return (const uchar *)c_str(); } ///< #VT_STR
void swap(idc_value_t &v) { swap_idcvs(this, &v); } ///< Set this = r and v = this
bool is_zero(void) const { return vtype == VT_LONG && num == 0; } ///< Does value represent the integer 0?
bool is_integral(void) { return vtype == VT_LONG || vtype == VT_INT64; } ///< Does value represent a whole number?
/// Convertible types are #VT_LONG, #VT_FLOAT, #VT_INT64, and #VT_STR
bool is_convertible(void) const { return (vtype >= 1 && vtype <= VT_FLOAT) || vtype == VT_STR || vtype == VT_INT64; }
/// \name Warning
/// The following functions do not free the existing data!
/// When the contents are unknown, use the functions without a leading underscore.
///@{
void _create_empty_string(void) { vtype = VT_STR; new (&qstr()) qstring; }
void _set_string(const qstring &_str)
{
vtype = VT_STR;
new (&qstr()) qstring(_str);
}
void _set_string(const char *_str, size_t len)
{
vtype = VT_STR;
new (&qstr()) qstring(_str, len);
}
void _set_string(const char *_str)
{
size_t len = _str == nullptr ? 0 : strlen(_str);
_set_string(_str, len);
}
void _set_long(sval_t v) { vtype = VT_LONG; num = v; }
void _set_pvoid(void *p) { vtype = VT_PVOID; pvoid = p; }
void _set_int64(int64 v) { vtype = VT_INT64; i64 = v; }
void _set_float(const fpvalue_t &f) { vtype = VT_FLOAT; e = f; }
///@}
/// \name Setters
/// These functions ensure the previous value is cleared
///@{
void create_empty_string(void) { clear(); _create_empty_string(); }
void set_string(const char *_str, size_t len) { clear(); _set_string(_str, len); }
void set_string(const char *_str) { clear(); _set_string(_str); }
void set_string(const qstring &_str) { clear(); _set_string(_str); }
void set_long(sval_t v) { clear(); _set_long(v); }
void set_pvoid(void *p) { clear(); vtype = VT_PVOID; pvoid = p; }
void set_int64(int64 v) { clear(); vtype = VT_INT64; i64 = v; }
void set_float(const fpvalue_t &f) { clear(); vtype = VT_FLOAT; e = f; }
///@}
};
/// Global idc variable
struct idc_global_t
{
qstring name;
idc_value_t value;
idc_global_t(void) {}
idc_global_t(const char *n) : name(n) {}
};
typedef qvector<idc_global_t> idc_vars_t; ///< vector of global idc variables
/// Prototype of an external IDC function (implemented in C).
/// \param argv vector of input arguments. IDA will convert all arguments
/// to types specified by ext_idcfunc_t::args, except for #VT_WILD
/// \param r return value of the function or exception
/// \return 0 if ok, all other values indicate error.
/// the error code must be set with set_qerrno():
/// - #eExecThrow - a new exception has been generated, see 'r'
/// - other values - runtime error has occurred
typedef error_t idaapi idc_func_t(idc_value_t *argv, idc_value_t *r);
#define eExecThrow 90 ///< See return value of ::idc_func_t
/// Element of functions table. See idcfuncs_t::funcs
struct ext_idcfunc_t
{
const char *name; ///< Name of function
idc_func_t *fptr; ///< Pointer to the Function
const char *args; ///< Type of arguments. Terminated with 0.
///< #VT_WILD at the end means a variadic function.
///< Actual number of arguments will be passed
///< in res->num in this case.
const idc_value_t *defvals; ///< Default argument values.
///< Only the rightmost arguments may have
///< default values.
int ndefvals; ///< Number of default values.
int flags; ///< \ref EXTFUN_
/// \defgroup EXTFUN_ Function description flags
/// Used by ext_idcfunc_t::flags
///@{
#define EXTFUN_BASE 0x0001 ///< requires open database.
#define EXTFUN_NORET 0x0002 ///< does not return. the interpreter may
///< clean up its state before calling it.
#define EXTFUN_SAFE 0x0004 ///< thread safe function. may be called
///< from any thread.
///@}
};
/// Describes an array of IDC functions
struct idcfuncs_t
{
size_t qnty; ///< Number of functions
ext_idcfunc_t *funcs; ///< Function table
/// \name IDC Engine
/// IDC engine requires the following functions (all of them may be nullptr)
///@{
/// Start IDC engine. Called before executing any IDC code.
error_t (idaapi *startup)(void);
/// Stop IDC engine. Called when all IDC engines finish.
/// In other words, nested IDC engines do not call startup/shutdown.
error_t (idaapi *shutdown)(void);
/// Initialize IDC engine. Called once at the very beginning of work.
/// This callback may create additional IDC classes, methods, etc.
void (idaapi *init_idc)(void);
/// Terminate IDC engine. Called once at the very end of work.
void (idaapi *term_idc)(void);
/// Is the database open? (used for #EXTFUN_BASE functions).
/// if this pointer is nullptr, #EXTFUN_BASE is not checked.
bool (idaapi *is_database_open)(void);
/// Convert an address to a string.
/// if this pointer is nullptr, '%a' will be used.
size_t (idaapi *ea2str)(char *buf, size_t bufsize, ea_t ea);
/// Should a variable name be accepted without declaration?.
/// When the parser encounters an unrecognized variable, this callback is called.
/// If it returns false, the parser generates the 'undefined variable' error
/// else the parser generates code to call to a set or get function,
/// depending on the current context.
/// If this pointer is nullptr, undeclared variables won't be supported.
/// However, if 'resolver' object is provided to the parser, it will be used
/// to resolve such names to constants at the compilation time.
/// This callback is used by IDA to handle processor register names.
bool (idaapi *undeclared_variable_ok)(const char *name);
///@}
/// \name Indexes
/// Indexes into the 'f' array. non-positive values mean that the function does not exist
///@{
/// Retrieve value of an undeclared variable.
/// Expected prototype: get(#VT_STR varname)
int get_unkvar;
/// Store a value to an undeclared variable.
/// Expected prototype: set(#VT_WILD new_value, #VT_STR varname)
int set_unkvar;
/// Execute resolved function.
/// If 'resolver' was used to resolve an unknown name to a constant in a function
/// call context, such a call will be redirected here.
/// Expected prototype: exec_resolved_func(#VT_LONG func, #VT_WILD typeinfo, ...)
/// This callback is used in IDA for Appcall.
int exec_resolved_func;
/// Calculate sizeof(type).
/// This function is used by the interpreter to calculate sizeof() expressions.
/// Please note that the 'type' argument is an IDC object of typeinfo class.
/// Expected prototype: calc_sizeof(#VT_OBJ typeinfo)
/// This callback requires support of the type system (available only in IDA kernel)
/// It should not be used by standalone IDC interpreters.
int calc_sizeof;
/// Get address of the specified field using the type information from the idb.
/// This function is used to resolve expressions like 'mystr.field' where
/// mystr does not represent an IDC object but just a plain number.
/// The number is interpreted as an address in the current idb.
/// This function retrieves type information at this address and tried to find
/// the specified 'field'. It returns the address of the 'field' in the idb.
/// This callback should not be used by standalone IDC interpreters.
int get_field_ea;
///@}
};
// Our idc_value_t and idc_global_t classes are freely movable with memcpy()
DECLARE_TYPE_AS_MOVABLE(idc_value_t);
DECLARE_TYPE_AS_MOVABLE(idc_global_t);
//------------------------------------------------------------------------
/// Add an IDC function.
/// This function does not modify the predefined kernel functions.
/// Example:
/// \code
/// static error_t idaapi myfunc5(idc_value_t *argv, idc_value_t *res)
/// {
/// msg("myfunc is called with arg0=%a and arg1=%s\n", argv[0].num, argv[1].str);
/// res->num = 5; // let's return 5
/// return eOk;
/// }
/// static const char myfunc5_args[] = { VT_LONG, VT_STR, 0 };
/// static const ext_idcfunc_t myfunc_desc = { "MyFunc5", myfunc5, myfunc5_args, nullptr, 0, EXTFUN_BASE };
///
/// // after this:
/// add_idc_func(myfunc_desc);
///
/// // there is a new IDC function which can be called like this:
/// MyFunc5(0x123, "test");
///
/// \endcode
/// \param func function description block.
/// \note If the function already exists, it will be replaced by the new function
/// \return success
idaman THREAD_SAFE bool ida_export add_idc_func(const ext_idcfunc_t &func);
/// Delete an IDC function
///
idaman THREAD_SAFE bool ida_export del_idc_func(const char *name);
// Find an idc function that starts with the given prefix.
// \param out buffer for the output name
// \param prefix prefix to search for
// \param n how many matches to skip
// Returns: success
idaman THREAD_SAFE bool ida_export find_idc_func(
qstring *out,
const char *prefix,
int n=0);
/// Possible syntax element highlighting style names
enum syntax_highlight_style
{
HF_DEFAULT = 0,
HF_KEYWORD1 = 1,
HF_KEYWORD2 = 2,
HF_KEYWORD3 = 3,
HF_STRING = 4,
HF_COMMENT = 5,
HF_PREPROC = 6,
HF_NUMBER = 7,
HF_USER1 = 8,
HF_USER2 = 9,
HF_USER3 = 10,
HF_USER4 = 11,
HF_MAX,
};
#define HF_FIRST HF_KEYWORD1
struct highlighter_cbs_t
{
virtual ~highlighter_cbs_t() {}
virtual void idaapi set_style(int32 /*start*/, int32 /*len*/, syntax_highlight_style /*style*/) {}
virtual int32 idaapi prev_block_state() { return 0; }
virtual int32 idaapi cur_block_state() { return 0; }
virtual void idaapi set_block_state(int32 /*state*/) {}
};
/// Base class for syntax highligters
struct syntax_highlighter_t
{
/// Function for extlang syntax highlighting
/// \param context implementation specific context. can be nullptr
/// \param highlighter_cbs structure with set of callbacks
/// \param text part of text to colorize
typedef void idaapi block_highlighter_t(
void *context,
highlighter_cbs_t *highlighter_cbs,
const qstring &text);
syntax_highlighter_t(block_highlighter_t *bh=nullptr) : highlight_block(bh) {}
virtual ~syntax_highlighter_t() {}
block_highlighter_t *highlight_block;
};
//------------------------------------------------------------------------
/// External language (to support third party language interpreters)
struct extlang_t
{
size_t size; ///< Size of this structure
uint32 flags; ///< Language features
#define EXTLANG_IDC 0x01
#define EXTLANG_NS_AWARE 0x02 ///< Namespace-aware (see above.)
int32 refcnt; ///< Reference count
const char *name; ///< Language name
const char *fileext; ///< File name extension for the language
syntax_highlighter_t *highlighter; // Language syntax highlighter
/// Compile an expression.
/// \param name name of the function which will
/// hold the compiled expression
/// \param current_ea current address. if unknown then #BADADDR
/// \param expr expression to compile
/// \param[out] errbuf error message if compilation fails
/// \return success
bool (idaapi *compile_expr)(
const char *name,
ea_t current_ea,
const char *expr,
qstring *errbuf);
/// Compile (load) a file.
///
/// If an extlang_t object claims to be namespace-aware, it means its
/// 'compile_file()' will receive a requested namespace to compile a file
/// under.
///
/// For example, compile_file() might receive a file
/// '.../loaders/myloader.py', with the corresponding namespace:
/// '__loaders__myloader'
///
/// Accordingly, call_func() has to be prepared to receive a function name that
/// is namespace-qualified: "__loaders__myloader.accept_file()".
///
/// \param file file name
/// \param requested_namespace requested namespace, may be ignored if not namespace-aware
/// \param[out] errbuf error message if compilation fails
bool (idaapi *compile_file)(const char *file, const char *requested_namespace, qstring *errbuf);
/// Evaluate a previously compiled expression.
/// \param[out] result function result or exception
/// \param name function to call
/// \param nargs number of input arguments
/// \param args input arguments
/// \param[out] errbuf error message if evaluation fails
/// \return success
bool (idaapi *call_func)(
idc_value_t *result,
const char *name,
const idc_value_t args[],
size_t nargs,
qstring *errbuf);
/// Compile and evaluate an expression.
/// \param[out] rv expression value or exception
/// \param current_ea current address. if unknown then BADADDR
/// \param expr expression to evaluate
/// \param[out] errbuf error message if evaluation fails
/// \return success
bool (idaapi *eval_expr)(
idc_value_t *rv,
ea_t current_ea,
const char *expr,
qstring *errbuf);
/// Compile and execute a string with statements.
/// (see also: eval_expr() which works with expressions)
/// \param str input string to execute
/// \param[out] errbuf error message
/// \return success
bool (idaapi *eval_snippet)(
const char *str,
qstring *errbuf);
/// Create an object instance.
/// \param result created object or exception
/// \param name object class name
/// \param args input arguments
/// \param nargs number of input arguments
/// \param errbuf error message if evaluation fails
/// \return success
bool (idaapi *create_object)(
idc_value_t *result,
const char *name,
const idc_value_t args[],
size_t nargs,
qstring *errbuf);
/// Returns the attribute value of a given object from the global scope.
/// \param[out] result attribute value
/// \param obj object (may be nullptr)
/// \param attr attribute name.
/// if nullptr or empty string then the object instance name
/// (i.e. class name) should be returned.
/// \return success
bool (idaapi *get_attr)(
idc_value_t *result,
const idc_value_t *obj,
const char *attr);
/// Sets the attribute value of a given object in the global scope.
/// \param obj object (may be nullptr)
/// \param attr attribute name
/// \param value attribute value
/// \return success
bool (idaapi *set_attr)(
idc_value_t *obj,
const char *attr,
const idc_value_t &value);
/// Calls a member function.
/// \param[out] result function result or exception
/// \param obj object instance
/// \param name method name to call
/// \param args input arguments
/// \param nargs number of input arguments
/// \param[out] errbuf error message if evaluation fails
/// \return success
bool (idaapi *call_method)(
idc_value_t *result,
const idc_value_t *obj,
const char *name,
const idc_value_t args[],
size_t nargs,
qstring *errbuf);
/// Compile (load) a file with processor module.
///
/// See the note about namespace-awareness in compile_file()
///
/// \param[out] procobj created object or exception
/// \param path processor module file name
/// \param[out] errbuf error message if compilation fails
/// \retval true success
/// \retval false if errbuf is empty then file has been
/// loaded (compiled) successfully but
/// it doesn't contain processor module
bool (idaapi *load_procmod)(
idc_value_t *procobj,
const char *path,
qstring *errbuf);
/// Unload previously loaded processor module.
/// \param path processor module file name
/// \param[out] errbuff error message if compilation fails
/// \return success
bool (idaapi *unload_procmod)(
const char *path,
qstring *errbuf);
bool is_idc(void) const { return (flags & EXTLANG_IDC) != 0; }
bool is_namespace_aware(void) const { return (flags & EXTLANG_NS_AWARE) != 0; }
void release(void) {}
};
typedef qvector<extlang_t *> extlangs_t; ///< vector of external language descriptions
typedef qrefcnt_t<extlang_t> extlang_object_t;
/// Get current active external language.
idaman void *ida_export get_current_extlang(void); // do not use
inline const extlang_object_t get_extlang(void) // use this function
{
return extlang_object_t((extlang_t *)get_current_extlang());
}
/// Install an external language interpreter.
/// Any previously registered interpreter will be automatically unregistered.
/// The installed extlang can be used in select_extlang().
/// \param el description of the new language. must point to static storage.
/// \return extlang id; -1 means failure and will happen if the extlang has
/// already been installed
idaman ssize_t ida_export install_extlang(extlang_t *el);
/// Uninstall an external language interpreter.
/// \return success
idaman bool ida_export remove_extlang(extlang_t *el);
/// Selects the external language interpreter.
/// The specified extlang must be registered before selecting it.
/// It will be used to evaluate expressions entered in dialog boxes.
/// It will also replace the eval_expr() and eval_expr_long() functions.
/// \return success
idaman bool ida_export select_extlang(extlang_t *el);
struct extlang_visitor_t
{
virtual ssize_t idaapi visit_extlang(extlang_t *extlang) = 0;
};
/// Process all registered extlangs
// \param ev visitor object
// \param select temporarily select extlang for the duration of the visit
// \return 0 or the first non-zero value returned by visit_extlang()
idaman ssize_t ida_export for_all_extlangs(extlang_visitor_t &ev, bool select=false);
// Helper function to search for extlang
enum find_extlang_kind_t
{
FIND_EXTLANG_BY_EXT,
FIND_EXTLANG_BY_NAME,
FIND_EXTLANG_BY_IDX,
};
// do not use
idaman void *ida_export find_extlang(const void *str, find_extlang_kind_t kind);
/// Get the extlang that can handle the given file extension
inline extlang_object_t find_extlang_by_ext(const char *ext)
{
return extlang_object_t((extlang_t *)find_extlang(ext, FIND_EXTLANG_BY_EXT));
}
/// Find an extlang by name
inline extlang_object_t find_extlang_by_name(const char *name)
{
return extlang_object_t((extlang_t *)find_extlang(name, FIND_EXTLANG_BY_NAME));
}
/// Find an extlang by index
inline extlang_object_t find_extlang_by_index(size_t idx)
{
return extlang_object_t((extlang_t *)find_extlang(&idx, FIND_EXTLANG_BY_IDX));
}
//------------------------------------------------------------------------
/// Set or append a header path.
/// IDA looks for the include files in the appended header paths,
/// then in the ida executable directory.
/// \param path list of directories to add (separated by ';')
/// may be nullptr, in this case nothing is added
/// \param add true: append.
/// false: remove old paths.
/// \retval true success
/// \retval false no memory
idaman THREAD_SAFE bool ida_export set_header_path(const char *path, bool add);
/// Get full name of IDC file name.
/// Search for file in list of include directories, IDCPATH directory
/// and system directories.
/// \param buf buffer for the answer
/// \param bufsize size of buffer
/// \param file file name without full path
/// \return nullptr is file not found.
/// otherwise returns pointer to buf
idaman THREAD_SAFE char *ida_export get_idc_filename(
char *buf,
size_t bufsize,
const char *file);
/// Compile and execute "main" function from system file.
/// \param file file name with IDC function(s).
/// The file will be searched using get_idc_filename().
/// \param complain_if_no_file
/// - 1: display warning if the file is not found
/// - 0: don't complain if file doesn't exist
/// \retval 1 ok, file is compiled and executed
/// \retval 0 failure, compilation or execution error, warning is displayed
idaman THREAD_SAFE bool ida_export exec_system_script(
const char *file,
bool complain_if_no_file=true);
/// Compile and calculate an expression.
/// \param res pointer to result. The result will be converted
/// to 32/64bit number. Use eval_expr() if you
/// need the result of another type.
/// \param where the current linear address in the addressing space of the
/// program being disassembled. it will be used to resolve
/// names of local variables, etc.
/// if not applicable, then should be #BADADDR
/// \param line a text line with IDC expression
/// \param[out] errbuf buffer for the error message
/// \retval true ok
/// \retval false error, see errbuf
idaman bool ida_export eval_expr_long(
sval_t *res,
ea_t where,
const char *line,
qstring *errbuf=nullptr);
/// See eval_expr_long()
inline bool idaapi eval_expr_long(
uval_t *res,
ea_t where,
const char *line,
qstring *errbuf=nullptr)
{
return eval_expr_long((sval_t *)res, where, line, errbuf);
}
/// Compile and calculate an expression.
/// \param rv pointer to the result
/// \param where the current linear address in the addressing space of the
/// program being disassembled. If will be used to resolve
/// names of local variables etc.
/// if not applicable, then should be #BADADDR.
/// \param line the expression to evaluate
/// \param[out] errbuf buffer for the error message
/// \retval true ok
/// \retval false error, see errbuf
idaman bool ida_export eval_expr(
idc_value_t *rv,
ea_t where,
const char *line,
qstring *errbuf=nullptr);
/// Same as eval_expr(), but will always use the IDC interpreter regardless of the
/// currently installed extlang.
idaman bool ida_export eval_idc_expr(
idc_value_t *rv,
ea_t where,
const char *buf,
qstring *errbuf=nullptr);
/// Compile a text file with IDC function(s).
/// \param file name of file to compile
/// if nullptr, then "File not found" is returned.
/// \param[out] errbuf buffer for the error message
/// \param cpl_flags \ref CPL_ or 0
/// \retval true ok
/// \retval false error, see errbuf
/// \defgroup CPL_ Flags for compile_idc_file()
///@{
#define CPL_DEL_MACROS 0x0001 ///< delete macros at the end of compilation
#define CPL_USE_LABELS 0x0002 ///< allow program labels in the script
#define CPL_ONLY_SAFE 0x0004 ///< allow calls of only thread-safe functions
///@}
idaman THREAD_SAFE bool ida_export compile_idc_file(
const char *file,
qstring *errbuf=nullptr,
int cpl_flags = CPL_DEL_MACROS|CPL_USE_LABELS);
/// Compile text with IDC function(s).
/// \param line line with IDC function(s) (can't be nullptr!)
/// \param[out] errbuf buffer for the error message
/// \param resolver callback object to get values of undefined variables
/// This object will be called if IDC function contains
/// references to undefined variables. May be nullptr.
/// \param only_safe_funcs if true, any calls to functions without #EXTFUN_SAFE flag
/// will lead to a compilation error.
/// \retval true ok
/// \retval false error, see errbuf
struct idc_resolver_t
{
virtual uval_t idaapi resolve_name(const char *name) = 0;
};
idaman THREAD_SAFE bool ida_export compile_idc_text(
const char *line,
qstring *errbuf=nullptr,
idc_resolver_t *resolver=nullptr,
bool only_safe_funcs=false);
/// Compile text with IDC statements.
/// \param func name of the function to create out of the snippet
/// \param text text to compile
/// \param[out] errbuf buffer for the error message
/// \param resolver callback object to get values of undefined variables
/// This object will be called if IDC function contains
/// references to undefined variables. May be nullptr.
/// \param only_safe_funcs if true, any calls to functions without #EXTFUN_SAFE flag
/// will lead to a compilation error.
/// \retval true ok
/// \retval false error, see errbuf
idaman bool ida_export compile_idc_snippet(
const char *func,
const char *text,
qstring *errbuf=nullptr,
idc_resolver_t *resolver=nullptr,
bool only_safe_funcs=false);
// Execution of IDC code can generate exceptions. Exception objects
// will have the following attributes:
// file - the source file name
// line - the line number that was executing when the exception occurred
// func - the function name
// pc - bytecode program counter
// For runtime errors, the following additional attributes exist:
// qerrno - runtime error code
// description - text description of the runtime error
/// Execute an IDC function.
/// \param[out] result pointer to idc_value_t to hold the return value of the function.
/// If execution fails, this variable will contain
/// the exception information.
/// Can be nullptr if return value is not required.
/// \param fname function name. User-defined functions, built-in functions,
/// and plugin-defined functions are accepted.
/// \param args array of parameters
/// \param argsnum number of parameters to pass to 'fname'.
/// This number should be equal to number of parameters
/// the function expects.
/// \param[out] errbuf buffer for the error message
/// \param resolver callback object to get values of undefined variables
/// This object will be called if IDC function contains
/// references to undefined variables. May be nullptr.
/// \retval true ok
/// \retval false error, see errbuf
idaman bool ida_export call_idc_func(
idc_value_t *result,
const char *fname,
const idc_value_t args[],
size_t argsnum,
qstring *errbuf=nullptr,
idc_resolver_t *resolver=nullptr);
/// Compile and execute IDC function(s) from file.
/// \param result ptr to idc_value_t to hold result of the function.
/// If execution fails, this variable will contain
/// the exception information.
/// You may pass nullptr if you are not interested in the returned
/// value.
/// \param path text file containing text of IDC functions
/// \param func function name to execute
/// \param args array of parameters
/// \param argsnum number of parameters to pass to 'fname'
/// This number should be equal to number of parameters
/// the function expects.
/// \param[out] errbuf buffer for the error message
/// \retval true ok
/// \retval false error, see errbuf
THREAD_SAFE inline bool exec_idc_script(
idc_value_t *result,
const char *path,
const char *func,
const idc_value_t args[],
size_t argsnum,
qstring *errbuf=nullptr)
{
if ( !compile_idc_file(path, errbuf) )
return false;
return call_idc_func(result, func, args, argsnum, errbuf);
}
/// Compile and execute IDC statements or expressions.
/// \param result ptr to idc_value_t to hold result of the function.
/// If execution fails, this variable will contain
/// the exception information.
/// You may pass nullptr if you are not interested in the returned
/// value.
/// \param line body of IDC the function
/// \param[out] errbuf buffer for the error message
/// \param resolver callback object to get values of undefined variables
/// This object will be called if IDC function contains
/// references to undefined variables. May be nullptr.
/// \return success
/// \note see also eval_idc_expr()
idaman bool ida_export eval_idc_snippet(
idc_value_t *result,
const char *line,
qstring *errbuf=nullptr,
idc_resolver_t *resolver=nullptr);
//------------------------------------------------------------------------
/// Setup lowcnd callbacks to read/write registers.
/// These callbacks will be used by the idc engine to read/write registers
/// while calculating low level breakpoint conditions for local debuggers.
idaman void ida_export setup_lowcnd_regfuncs(idc_func_t *getreg, idc_func_t *setreg);
//------------------------------------------------------------------------
/// Extract type & data from the idc_value_t instance that
/// was passed to parse_config_value().
///
/// \param vtype pointer to storage that will hold the type (\ref IDPOPT_T)
/// \param vdata pointer to storage that contains the value (see \ref IDPOPT_T
/// for what type of data is pointed to.)
/// \param v the value holder
/// \return true in case of success, false if 'v' is of unexpected type
inline THREAD_SAFE bool get_idptype_and_data(int *vtype, const void **vdata, const idc_value_t &v)
{
switch ( v.vtype )
{
case VT_STR: *vtype = IDPOPT_STR, *vdata = v.c_str(); break;
case VT_LONG: *vtype = IDPOPT_NUM; *vdata = &v.num; break;
case VT_WILD: *vtype = IDPOPT_BIT; *vdata = &v.num; break;
case VT_INT64: *vtype = IDPOPT_I64; *vdata = &v.i64; break;
case VT_PVOID: *vtype = IDPOPT_CST; *vdata = v.pvoid; break;
default: return false;
}
return true;
}
/// Create an idc execution exception object.
/// This helper function can be used to return an exception from C++ code to IDC.
/// In other words this function can be called from idc_func_t() callbacks.
/// Sample usage: if ( !ok ) return throw_idc_exception(r, "detailed error msg");
/// \param r object to hold the exception object
/// \param desc exception description
/// \return eExecThrow
idaman error_t ida_export throw_idc_exception(idc_value_t *r, const char *desc);
#endif /* _EXPR_H */