/* * Interactive disassembler (IDA). * Copyright (c) 1990-2021 Hex-Rays * ALL RIGHTS RESERVED. * */ #ifndef _EXPR_H #define _EXPR_H #include #include /*! \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. NULL 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=NULL); /// 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 NULL. /// \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 NULL 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 NULL 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=NULL, 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 /// \returns 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 NULL /// \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=NULL); /// Find an existing IDC class by its name. /// \param name name of the class /// \return pointer to the class or NULL. /// 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 NULL, the definitions are removed. /// \return name of the old attribute function. NULL 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 NULL. /// If returns NULL, 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 NULL. /// 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 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)]; ///< internal housekeeping: 64-bit qstring is bigger than 12 bytes #ifndef SWIG }; #endif // SWIG /// Create a #VT_LONG value idc_value_t(sval_t n=0) : num(n) {} /// Create a $VT_LONG with an existing idc value idc_value_t(const idc_value_t &r) { 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 == NULL ? 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_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 NULL) //@{ /// 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 NULL, #EXTFUN_BASE is not checked. bool (idaapi *is_database_open)(void); /// Convert an address to a string. /// if this pointer is NULL, '%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 NULL, 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, NULL, 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_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 NULL /// \param ighlighter_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 have to create namespaces for _certain_ paths: /// - plugins, /// - loaders. /// /// For example, if compile_file() receives a hypothetical path: /// .../loaders/myloader.py, /// the namespace-aware extlang_t handling 'py' files will have to create /// a namespace derived from the loader file name (without its extension), /// i.e., '__loaders__myloader', into which the file will be compiled. /// /// Then, call_func() has to be prepared to receive a function name that /// is namespace-qualified: "__loaders__myloader.accept_file()". /// /// compile_file() must handle the following 'special' paths, and create /// the following namespaces to compile them into: /// .../loaders/ => '__loaders__' /// .../plugins/ => '__plugins__' /// /// Similarly, a namespace-aware extlang_t's load_procmod() /// will have to load the processor module in its own namespace: /// .../procs/ => '__procs__' /// /// \param file file name /// \param[out] errbuf error message if compilation fails bool (idaapi *compile_file)(const char *file, 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 NULL) /// \param attr attribute name. /// if NULL 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 NULL) /// \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 extlangs_t; ///< vector of external language descriptions typedef qrefcnt_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 NULL, 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 NULL 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=NULL); /// See eval_expr_long() inline bool idaapi eval_expr_long( uval_t *res, ea_t where, const char *line, qstring *errbuf=NULL) { 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=NULL); /// 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=NULL); /// Compile a text file with IDC function(s). /// \param file name of file to compile /// if NULL, 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=NULL, 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 NULL!) /// \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 NULL. /// \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=NULL, idc_resolver_t *resolver=NULL, 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 NULL. /// \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=NULL, idc_resolver_t *resolver=NULL, 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 NULL 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 NULL. /// \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=NULL, idc_resolver_t *resolver=NULL); /// 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 NULL 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=NULL) { 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 NULL 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 NULL. /// \return success /// \note see also eval_idc_expr() idaman bool ida_export eval_idc_snippet( idc_value_t *result, const char *line, qstring *errbuf=NULL, idc_resolver_t *resolver=NULL); //------------------------------------------------------------------------ /// 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 */