#ifndef __HEADER_I__ #define __HEADER_I__ %{ #ifndef USE_DANGEROUS_FUNCTIONS #define USE_DANGEROUS_FUNCTIONS 1 #endif #include #undef DEPRECATED #define DEPRECATED %} %{ #include "../../../idapy.hpp" %} #define SWIG_PYTHON_LEGACY_BOOL 1 %{ class plugin_t; #ifdef __NT__ idaman __declspec(dllimport) plugin_t PLUGIN; #else extern plugin_t PLUGIN; #endif %} // Auto-inserted header // generate directors for all classes that have virtual methods %feature("director"); // exceptions %feature("nodirector") enumplace_t; %feature("nodirector") generic_linput64_t; %feature("nodirector") generic_linput_t; %feature("nodirector") place_t; %feature("nodirector") idaplace_t; %feature("nodirector") qrefcnt_obj_t; %feature("nodirector") qstring_printer_t; %feature("nodirector") simpleline_place_t; %feature("nodirector") structplace_t; %feature("nodirector") qflow_chart_t; %feature("nodirector") lowertype_helper_t; %feature("nodirector") ida_lowertype_helper_t; %warnfilter(473) user_lvar_visitor_t::get_info_mapping_for_saving; // Returning a pointer or reference in a director method is not recommended // * http://swig.10945.n7.nabble.com/How-to-release-Python-GIL-td5027.html // * http://stackoverflow.com/questions/1576737/releasing-python-gil-in-c-code // * http://matt.eifelle.com/2007/11/23/enabling-thread-support-in-swig-and-python/ %nothread; // We don't want SWIG to release the GIL for *every* IDA API call. // Suppress 'previous definition of XX' warnings #pragma SWIG nowarn=302 // and others... #pragma SWIG nowarn=312 #pragma SWIG nowarn=325 #pragma SWIG nowarn=314 #pragma SWIG nowarn=362 #pragma SWIG nowarn=383 #pragma SWIG nowarn=389 #pragma SWIG nowarn=401 #pragma SWIG nowarn=451 #pragma SWIG nowarn=454 // Setting a pointer/reference variable may leak memory #pragma SWIG nowarn=514 // Director base class 'x' has no virtual destructor. // Do not create separate wrappers for default arguments %feature("compactdefaultargs"); %ignore qvector::at(size_t); %ignore qvector::front; %ignore qvector::back; %ignore qlist::iterator::operator--; %ignore qlist::const_iterator::operator--; %ignore qlist::reverse_iterator::operator--; %ignore qlist::const_reverse_iterator::operator--; // To be used e.g., when a '#define' in the source code // defines a uint32 value with the highest bit set, so that // SWiG knows it's not a negative integer. %define %predefine_uint32_macro(NAME, VALUE) %rename (NAME) PY_##NAME; %constant uint32 PY_##NAME = uint32(VALUE); %ignore NAME; %enddef %define %uncomparable_elements_qvector(ELEMENT_TYPE, VECTOR_TYPE) %ignore qvector::operator==; %ignore qvector::operator!=; %ignore qvector::find; %ignore qvector::has; %ignore qvector::del; %ignore qvector::add_unique; %template(VECTOR_TYPE) qvector; %enddef %ignore wchar2char; %ignore hit_counter_t; %ignore reg_hit_counter; %ignore create_hit_counter; %ignore hit_counter_timer; %ignore print_all_counters; %ignore incrementer_t; %ignore reloc_info_t; // swig under mac chokes on this %ignore qmutex_create; %ignore qiterator; %ignore qmutex_free; %ignore qmutex_lock; %ignore qmutex_t; %ignore qmutex_unlock; %ignore qsem_create; %ignore qsem_free; %ignore qsem_post; %ignore qsem_wait; %ignore qsemaphore_t; %ignore qthread_cb_t; %ignore qthread_create; %ignore qthread_free; %ignore qthread_join; %ignore qthread_kill; %ignore qthread_self; %ignore qthread_same; %ignore qthread_t; %ignore qhandle_t; %ignore qpipe_create; %ignore qpipe_read; %ignore qpipe_write; %ignore qpipe_close; %ignore qstrlen; %ignore qstrcmp; %ignore qstrstr; %ignore qstrchr; %ignore qstrrchr; %ignore bytevec_t; %ignore qstrvec_t; %ignore reloc_info_t; %ignore relobj_t; %ignore wchar2char; %ignore u2cstr; %ignore c2ustr; %ignore base64_encode; %ignore base64_decode; %ignore replace_tabs; %ignore utf8_unicode; %ignore unicode_utf8; %ignore win_utf2idb; %ignore char2oem; %ignore oem2char; %ignore set_codepages; %ignore get_codepages; %ignore convert_codepage; %ignore test_bit; %ignore set_bit; %ignore clear_bit; %ignore set_all_bits; %ignore clear_all_bits; %ignore interval::last; %ignore interval::overlap; %ignore interval::includes; %ignore interval::contains; %ignore qrotl; %ignore qrotr; %ignore setflag; %ignore read2bytes; %ignore rotate_left; //%ignore qswap; %ignore swap32; %ignore swap16; %ignore swap_value; %ignore qalloc_or_throw; %ignore qrealloc_or_throw; %ignore get_buffer_for_sysdir; %ignore get_buffer_for_winerr; %ignore call_atexits; %ignore launch_process_params_t; %ignore launch_process; %ignore term_process; %ignore get_process_exit_code; %ignore BELOW_NORMAL_PRIORITY_CLASS; %ignore parse_command_line; %ignore parse_command_line2; %ignore parse_command_line3; %rename (parse_command_line3) py_parse_command_line; %ignore qgetenv; %ignore qsetenv; %ignore qctime; %ignore qlocaltime; %ignore qstrftime; %ignore qstrftime64; %ignore qstrtok; %ignore qstrlwr; %ignore qstrupr; // Do not move this. We need to override the define from pro.h #define CASSERT(type) %pythoncode { import ida_idaapi } #ifdef BC695 %pythoncode { import sys _BC695 = sys.modules["__main__"].IDAPYTHON_COMPAT_695_API if _BC695: ## This is a helper for replacing an existing function, with a wrapper ## providing backwards-compatibility for API 6.95 -- typically because ## the number/types of arguments changed, while the function name itself ## remained the same in 7.0. ## (Note that this shouldn't be used for functions that don't exist ## in the vanilla 7.0 API, such as 'choose_named_type2'.) def bc695redef(func): ida_idaapi._BC695.replace_fun(func) return func } #endif // BC695 //--------------------------------------------------------------------- %extend qvector { inline size_t __len__() const { return $self->size(); } // The fact that we are returning a const version of a reference to the // type is what allows SWIG to generate a wrapper for this method, that // will build an proper object (int, unsigned int, ...) instead // of a pointer. Remove the 'const', and you'll see that, in // SWIGINTERN PyObject *_wrap_uvalvec_t___getitem__(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { // it will produce this: // resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_unsigned_int, 0 | 0 ); // instead of that: // resultobj = SWIG_From_unsigned_SS_int(static_cast< unsigned int >(*result)); inline const T &__getitem__(size_t i) const { if ( i >= $self->size() ) throw std::out_of_range("out of bounds access"); return $self->at(i); } inline void __setitem__(size_t i, const T &v) { if ( i >= $self->size() ) throw std::out_of_range("out of bounds access"); $self->at(i) = v; } %pythoncode { front = ida_idaapi._qvector_front back = ida_idaapi._qvector_back __iter__ = ida_idaapi._bounded_getitem_iterator } } //--------------------------------------------------------------------- %extend qlist { inline size_t __len__() const { return $self->size(); } inline const T &__getitem__(size_t i) const { if ( i >= $self->size() ) throw std::out_of_range("out of bounds access"); qlist::const_iterator it = $self->begin(); for ( size_t _i = 0; _i < i; ++_i ) ++it; return *it; } inline void __setitem__(size_t i, const T &v) { if ( i >= $self->size() ) throw std::out_of_range("out of bounds access"); qlist::iterator it = $self->begin(); for ( size_t _i = 0; _i < i; ++_i ) ++it; *it = v; } inline void insert(size_t i, const T &v) { if ( i > $self->size() ) throw std::out_of_range("out of bounds access"); qlist::iterator it = $self->begin(); for ( size_t _i = 0; _i < i; ++_i ) ++it; $self->insert(it, v); } inline bool remove(const T &v) { qlist::iterator it = $self->begin(); for ( ; it != $self->end(); ++it ) { if ( *it == v ) { $self->erase(it); return true; } } return false; } %pythoncode { front = ida_idaapi._qvector_front back = ida_idaapi._qvector_back __iter__ = ida_idaapi._bounded_getitem_iterator def find(self, item): it = self.begin() for i in range(self.size()): if it.cur == item: return it next(it) def index(self, item): it = self.begin() for i in range(self.size()): if it.cur == item: return i next(it) def at(self, index): it = self.begin() for i in range(self.size()): if i == index: return it.cur next(it) } } #if IDAPYTHON_MODULE_hexrays %define %ida_hexrays_wrapper_exception_catch() catch ( const vd_failure_t &e ) { __raise_vdf(e); SWIG_fail; } %enddef #else %define %ida_hexrays_wrapper_exception_catch()%enddef #endif %define %exception_set_default_handlers() %exception { try { $action } catch ( const std::bad_alloc &ba ) { __raise_ba(ba); SWIG_fail; } catch ( const std::out_of_range &e ) { __raise_oor(e); SWIG_fail; } catch ( const interr_exc_t &e ) { __raise_ie(e); SWIG_fail; }%ida_hexrays_wrapper_exception_catch() catch ( const Swig::DirectorException &e ) { __raise_de(e); SWIG_fail; } catch ( const std::exception &e ) { __raise_e(e); SWIG_fail; } catch ( ... ) { __raise_u(); SWIG_fail; } } %enddef %exception_set_default_handlers(); // Enable automatic docstring generation %feature(autodoc,2); %{ /* strnlen() arrived on OSX at v10.7. Provide it ourselves if needed. */ #ifdef __MAC__ #ifndef MAC_OS_X_VERSION_10_7 #define MAC_OS_X_VERSION_10_7 1070 #endif #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) inline size_t strnlen(const char *s, size_t maxlen) { const char *found = (const char *) memchr(s, 0, maxlen); return found != NULL ? size_t(found - s) : maxlen; } #endif #endif %} %define SWIG_DECLARE_PY_CLINKED_OBJECT(type) %inline %{ static PyObject *type##_create() { PYW_GIL_CHECK_LOCKED_SCOPE(); return PyCapsule_New(new type(), VALID_CAPSULE_NAME, NULL); } static bool type##_destroy(PyObject *py_obj) { PYW_GIL_CHECK_LOCKED_SCOPE(); if ( !PyCapsule_IsValid(py_obj, VALID_CAPSULE_NAME) ) return false; delete (type *)PyCapsule_GetPointer(py_obj, VALID_CAPSULE_NAME); return true; } static type *type##_get_clink(PyObject *self) { PYW_GIL_CHECK_LOCKED_SCOPE(); return (type *)pyobj_get_clink(self); } static PyObject *type##_get_clink_ptr(PyObject *self) { PYW_GIL_CHECK_LOCKED_SCOPE(); return PyLong_FromUnsignedLongLong( PTR2U64(pyobj_get_clink(self))); } %} %enddef // We use those special maps because SWIG wraps passed PyObject* with 'SwigPtr_PyObject' and 'SwigVar_PyObject' // They act like autoptr and decrement the reference of the object when the scope ends // We need to keep a reference outside SWIG and let the caller manage its references %typemap(directorin) PyObject * "/*%din%*/Py_XINCREF($1_name);$input = $1_name;" %typemap(directorout) PyObject * "/*%dout%*/$result = result;Py_XINCREF($result);" //--------------------------------------------------------------------- #ifdef PY3 %define %treat_serialized_tinfo_raw_pointer_as_bytes_1(_TYPE) %typemap(in) _TYPE * { // %treat_serialized_tinfo_raw_pointer_as_bytes_1 %typemap(in) _TYPE * if ( $input == Py_None ) $1 = ($1_ltype) NULL; else if ( PyBytes_Check($input) ) $1 = ($1_ltype) PyBytes_AsString($input); else SWIG_exception_fail( SWIG_ValueError, "Expected bytes " "in method '" "$symname" "', argument " "$argnum"" of type 'bytes'"); } %typemap(directorin) _TYPE * { // %treat_serialized_tinfo_raw_pointer_as_bytes_1 %typemap(directorin) _TYPE * $input = PyBytes_FromString($1 != NULL ? (const char *) $1 : ""); } %typemap(out) _TYPE * { // %treat_serialized_tinfo_raw_pointer_as_bytes_1 %typemap(out) _TYPE * $result = PyBytes_FromString($1 != NULL ? (const char *) $1 : ""); } // 'typecheck' typemaps are used for polymorphism. We want to favor // tinfo_t wrappers at the expense of 'type_t *' ones, so we want the // precedence for this to be very low. %typemap(typecheck, precedence=SWIG_TYPECHECK_STRING_ARRAY) _TYPE * { // %treat_serialized_tinfo_raw_pointer_as_bytes_1 %typemap(typecheck) _TYPE * $1 = ($input == Py_None || PyBytes_Check($input)) ? 1 : 0; } %enddef %define %treat_serialized_tinfo_raw_pointer_as_bytes(TYPE) %treat_serialized_tinfo_raw_pointer_as_bytes_1(TYPE); %treat_serialized_tinfo_raw_pointer_as_bytes_1(const TYPE); %enddef #else %define %treat_serialized_tinfo_raw_pointer_as_bytes(TYPE) %apply char * { TYPE * } %apply const char * { const TYPE * } %enddef #endif %treat_serialized_tinfo_raw_pointer_as_bytes(type_t); %treat_serialized_tinfo_raw_pointer_as_bytes(p_list); //------------------------------------------------------------------------- // For some reason, SWIG converts char arrays by computing the size // from the end of the array, and stops when it encounters a '\0'. // That doesn't work for us, as our API doesn't guarantee that // bytes past the length we are interested in will be zeroed-out. // In other words, the following code should *never* be present // in idaapi_include.cpp: // ------------------------- // while (size && ([size - 1] == '\0')) --size; // ------------------------- // %typemap(out) char [ANY], const char[ANY] { %set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0))); } %typemap(varout) char [ANY], const char[ANY] { %set_output(SWIG_FromCharPtrAndSize($1, strnlen($1, $1_dim0))); } %apply unsigned long long { size_t } %apply long long { ssize_t } //--------------------------------------------------------------------- // Convert an incoming Python list to a tid_t[] array %typemap(in) tid_t[ANY](tid_t temp[$1_dim0]) { int i, len; if (!PySequence_Check($input)) { PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); return NULL; } /* Cap the number of elements to copy */ len = PySequence_Length($input) < $1_dim0 ? PySequence_Length($input) : $1_dim0; for (i =0; i < len; i++) { newref_t item(PySequence_GetItem($input,i)); if (!PyLong_Check(item.o)) { PyErr_SetString(PyExc_ValueError,"Expecting a sequence of long integers"); return NULL; } temp[i] = PyLong_AsUnsignedLong(item.o); } $1 = &temp[0]; } //------------------------------------------------------------------------- // Same, but with non-fixed sized arrays. %typemap(in) (const tid_t *path, int plen) (qvector temp) { if (!PySequence_Check($input)) { PyErr_SetString(PyExc_TypeError,"Expecting a sequence"); return NULL; } int plen = PySequence_Length($input); if ( plen <= 0 ) { PyErr_SetString(PyExc_TypeError, "Sequence must have at least 1 item"); return NULL; } temp.resize(plen); for ( int i =0; i < plen; ++i ) { newref_t item(PySequence_GetItem($input,i)); if (!PyLong_Check(item.o)) { PyErr_SetString(PyExc_ValueError,"Expecting a sequence of long integers"); return NULL; } temp[i] = PyLong_AsUnsignedLong(item.o); } $1 = temp.begin(); $2 = int(temp.size()); } %{ SWIGINTERN PyObject *_maybe_cstring_result( PyObject *resultobj, const char *cstr, int result) { Py_XDECREF(resultobj); if ( result <= 0 ) Py_RETURN_NONE; return IDAPyStr_FromUTF8(cstr); } SWIGINTERN PyObject *_sized_cstring_result( PyObject *resultobj, const char *cstr, size_t cstrsz) { Py_XDECREF(resultobj); return IDAPyStr_FromUTF8AndSize(cstr, cstrsz); } SWIGINTERN PyObject *_maybe_sized_cstring_result( PyObject *resultobj, const char *cstr, size_t cstrsz, int result) { Py_XDECREF(resultobj); if ( result <= 0 ) Py_RETURN_NONE; return IDAPyStr_FromUTF8AndSize(cstr, cstrsz); } SWIGINTERN PyObject *_maybe_cstring_result_on_charptr_using_allocated_buf( PyObject *resultobj, const char *result, char *buf) { Py_XDECREF(resultobj); PyObject *out = NULL; if ( result != NULL ) { out = IDAPyStr_FromUTF8(buf); } else { Py_INCREF(Py_None); out = Py_None; } qfree(buf); return out; } SWIGINTERN PyObject *_maybe_cstring_result_on_charptr_using_qbuf( PyObject *resultobj, const char *result, const qstring &buf) { Py_XDECREF(resultobj); if ( result == NULL ) Py_RETURN_NONE; return IDAPyStr_FromUTF8AndSize(buf.begin(), buf.length()); } SWIGINTERN PyObject *_maybe_binary_result( PyObject *resultobj, void *buf, ssize_t result) { Py_XDECREF(resultobj); if ( result <= 0 ) Py_RETURN_NONE; #ifdef PY3 return PyBytes_FromStringAndSize((const char *) buf, result); #else return PyString_FromStringAndSize((const char *) buf, result); #endif } SWIGINTERN PyObject *_sized_binary_result( PyObject *resultobj, const char *cstr, size_t cstrsz) { Py_XDECREF(resultobj); return IDAPyBytes_FromMemAndSize(cstr, cstrsz); } SWIGINTERN PyObject *_maybe_sized_binary_result( PyObject *resultobj, const char *cstr, size_t cstrsz, int result) { Py_XDECREF(resultobj); if ( result <= 0 ) Py_RETURN_NONE; return IDAPyBytes_FromMemAndSize(cstr, cstrsz); } %} #if defined(IDA_MODULE_NALT) %{ #include #ifdef PY3 SWIGINTERN PyObject *_maybe_byte_array_or_none_result( PyObject *resultobj, bool result, const uchar *bytes, size_t nbytes) { Py_XDECREF(resultobj); if ( !result ) Py_RETURN_NONE; return IDAPyBytes_FromMemAndSize((const char *) bytes, nbytes); } #else SWIGINTERN PyObject *_maybe_byte_array_as_hex_or_none_result( PyObject *resultobj, bool result, const uchar *bytes, size_t nbytes) { Py_XDECREF(resultobj); if ( !result ) Py_RETURN_NONE; qstring buf; buf.resize(2*nbytes); get_hex_string(buf.begin(), buf.size(), bytes, nbytes); return IDAPyBytes_FromMemAndSize(buf.c_str(), buf.length()); } #endif %} #endif //--------------------------------------------------------------------- %define %cstring_output_maxstr_none(BUFFER_ARG, SIZE_ARG) %typemap(default) (BUFFER_ARG, SIZE_ARG) { // %cstring_output_maxstr_none(BUFFER_ARG, SIZE_ARG) %typemap(default) (BUFFER_ARG, SIZE_ARG) $2 = MAXSTR; } %typemap(in,numinputs=0) (BUFFER_ARG, SIZE_ARG) { // %cstring_output_maxstr_none(BUFFER_ARG, SIZE_ARG) %typemap(in,numinputs=0) (BUFFER_ARG, SIZE_ARG) $1 = ($1_ltype) qalloc(MAXSTR+1); } %typemap(argout) (BUFFER_ARG, SIZE_ARG) { // %cstring_output_maxstr_none(BUFFER_ARG, SIZE_ARG) %typemap(argout) (BUFFER_ARG, SIZE_ARG) resultobj = _maybe_cstring_result(resultobj, $1, int(result)); qfree($1); } %enddef //--------------------------------------------------------------------- %define %binary_output_or_none(BUFFER_ARG, SIZE_ARG) %typemap(default) (BUFFER_ARG, SIZE_ARG) { // %binary_output_or_none(BUFFER_ARG, SIZE_ARG) %typemap(default) (BUFFER_ARG, SIZE_ARG) $2 = MAXSPECSIZE; } %typemap(in,numinputs=0) (BUFFER_ARG, SIZE_ARG) { // %binary_output_or_none(BUFFER_ARG, SIZE_ARG) %typemap(in,numinputs=0) (BUFFER_ARG, SIZE_ARG) $1 = (char *) qalloc(MAXSPECSIZE+1); } %typemap(argout) (BUFFER_ARG, SIZE_ARG) { // %binary_output_or_none(BUFFER_ARG, SIZE_ARG) %typemap(argout) (BUFFER_ARG, SIZE_ARG) resultobj = _maybe_binary_result(resultobj, $1, ssize_t(result)); qfree((void *)$1); } %enddef //------------------------------------------------------------------------- // and a helper for overriding the 'argout' of some of those functions, // that return the input char* as return code; those build on recent // versions of Xcode (>= 9.0), and need special care %define %cstring_output_buf_and_size_returning_charptr(BUFIDX, ...) %typemap(argout) (__VA_ARGS__) { // cstring_output_buf_and_size_returning_charptr's argout resultobj = _maybe_cstring_result_on_charptr_using_allocated_buf(resultobj, (const char *) result, $BUFIDX); } %enddef //------------------------------------------------------------------------- // see %cstring_output_buf_and_size_returning_charptr above %define %cstring_output_qstring_returning_charptr(BUFIDX, ...) %typemap(argout) (__VA_ARGS__) { // %cstring_output_qstring_returning_charptr typemap(argout) __VA_ARGS__ resultobj = _maybe_cstring_result_on_charptr_using_qbuf(resultobj, (const char *) result, *$BUFIDX); } %enddef //------------------------------------------------------------------------- // OUT qstrvec_t //------------------------------------------------------------------------- %typemap(in,numinputs=0) qstrvec_t *out (qstrvec_t temp) { // %typemap(in,numinputs=0) qstrvec_t *out (qstrvec_t temp) $1 = &temp; } %typemap(argout) qstrvec_t *out { // %typemap(argout) qstrvec_t *out Py_XDECREF(resultobj); resultobj = qstrvec2pylist(*($1)); } %typemap(freearg) qstrvec_t* out { // %typemap(freearg) qstrvec_t* out // Nothing. We certainly don't want 'temp' to be deleted. } //------------------------------------------------------------------------- // md5/sha256 hash retrieval (as hex representation) //------------------------------------------------------------------------- #ifdef PY3 %define %byte_array_or_none(PARAM_NAME) %typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) { // byte_array_or_none typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) $1 = temp; } %typemap(argout) uchar PARAM_NAME[ANY] { // byte_array_or_none typemap(argout) uchar PARAM_NAME[ANY] resultobj = _maybe_byte_array_or_none_result(resultobj, result, $1, $1_dim0); } %enddef %byte_array_or_none(hash); #else %define %byte_array_as_hex_or_none(PARAM_NAME) %typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) { // byte_array_as_hex_or_none typemap(in, numinputs=0) uchar PARAM_NAME[ANY] (uchar temp[$1_dim0]) $1 = temp; } %typemap(argout) uchar PARAM_NAME[ANY] { // byte_array_as_hex_or_none typemap(argout) uchar PARAM_NAME[ANY] resultobj = _maybe_byte_array_as_hex_or_none_result(resultobj, result, $1, $1_dim0); } %enddef %byte_array_as_hex_or_none(hash); #endif // Check that the argument is a callable Python object //--------------------------------------------------------------------- %typemap(in) PyObject *pyfunc { if (!PyCallable_Check($input)) { PyErr_SetString(PyExc_TypeError, "Expected a callable object"); return NULL; } $1 = $input; } // Check that the argument is None or a callable Python object //--------------------------------------------------------------------- %typemap(in) PyObject *pyfunc_or_none { if ($input != Py_None && !PyCallable_Check($input)) { PyErr_SetString(PyExc_TypeError, "Expected None or a callable object"); return NULL; } $1 = $input; } // Check that the argument is None or a tuple //--------------------------------------------------------------------- %typemap(in) PyObject *tuple_or_none { if ($input != Py_None && !PyTuple_Check($input)) { PyErr_SetString(PyExc_TypeError, "Expected None or a tuple"); return NULL; } $1 = $input; } %typemap(in) ea_t { // %typemap(in) ea_t uint64 $1_temp; if ( !PyW_GetNumber($input, &$1_temp) ) SWIG_exception_fail( SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum"" of type 'ea_t'"); $1 = ea_t($1_temp); } %typemap(in) sval_t { // %typemap(in) sval_t uint64 $1_temp; if ( !PyW_GetNumber($input, &$1_temp) ) SWIG_exception_fail( SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum"" of type 'sval_t'"); $1 = sval_t($1_temp); } // Use PyLong_FromUnsignedLongLong, because 'long' is 4 bytes on // windows, and thus the ea_t would be truncated at the // PyLong_FromUnsignedLong(unsigned int) call time. %typemap(out) ea_t "$result = PyLong_FromUnsignedLongLong($1);" %typemap(in) qtime64_t "$1 = PyLong_AsUnsignedLongLong($input);" %typemap(out) qtime64_t "$result = PyLong_FromUnsignedLongLong($1);" %typemap(typecheck, precedence=SWIG_TYPECHECK_STRING_ARRAY) ea_t { // %typemap(typecheck, precedence=SWIG_TYPECHECK_STRING_ARRAY) ea_t uint64 $1_temp; $1 = PyW_GetNumber($input, &$1_temp); } //--------------------------------------------------------------------- // IN/OUT qstring/bytevec_t //--------------------------------------------------------------------- %define %bytes_container( REFTYPE, CONTAINER_TYPE, START_ACCESSOR, SIZE_ACCESSOR, INSTANCE_CAST, CHECKER, IN_CONVERTER, OUT_CONVERTER, ARGOUT_CONVERTER, ARGOUT_MAYBE_CONVERTER, ELTYPE_TO_REPORT1, ELTYPE_TO_REPORT2) %typemap(typecheck) REFTYPE { // bytes_container REFTYPE typemap(typecheck) $1 = CHECKER($input) ? 1 : 0; } %fragment("outarg_cvt_" #CONTAINER_TYPE, "header") { bool outarg_cvt_##CONTAINER_TYPE( CONTAINER_TYPE *out, PyObject *obj, bool can_be_none=false) { bool ok = can_be_none && obj == Py_None; if ( !ok ) { ok = CHECKER(obj); if ( ok ) IN_CONVERTER(out, obj); } return ok; } } %fragment("cvt_" #CONTAINER_TYPE, "header") { CONTAINER_TYPE *cvt_##CONTAINER_TYPE(PyObject *obj, bool can_be_none=false) { CONTAINER_TYPE *out = NULL; if ( can_be_none && obj == Py_None ) { out = new CONTAINER_TYPE; } else if ( CHECKER(obj) ) { // init properly, so ctor can't crash out = new CONTAINER_TYPE; IN_CONVERTER(out, obj); } return out; } } %typemap(in, fragment="cvt_" #CONTAINER_TYPE) REFTYPE { // bytes_container REFTYPE, CONTAINER_TYPE typemap(in) $1 = cvt_ ## CONTAINER_TYPE($input); if ( $1 == NULL ) SWIG_exception_fail( SWIG_ValueError, "Expected " ELTYPE_TO_REPORT1 " " "in method '" "$symname" "', argument " "$argnum"" of type '" ELTYPE_TO_REPORT2 "'"); } %typemap(in) const REFTYPE _type_or_none { // bytes_container REFTYPE _type_or_none, CONTAINER_TYPE typemap(in) $1 = cvt_ ## CONTAINER_TYPE($input, /*can_be_none=*/ true); if ( $1 == NULL ) SWIG_exception_fail( SWIG_ValueError, "Expected " ELTYPE_TO_REPORT1 " " "in method '" "$symname" "', argument " "$argnum"" of type '" ELTYPE_TO_REPORT2 "'"); } %typemap(in) const REFTYPE _fields { // bytes_container REFTYPE _fields, CONTAINER_TYPE typemap(in) $1 = cvt_ ## CONTAINER_TYPE($input, /*can_be_none=*/ true); if ( $1 == NULL ) SWIG_exception_fail( SWIG_ValueError, "Expected " ELTYPE_TO_REPORT1 " " "in method '" "$symname" "', argument " "$argnum"" of type '" ELTYPE_TO_REPORT2 "'"); } %typemap(freearg) REFTYPE { // bytes_container REFTYPE typemap(freearg) delete $1; } %typemap(out) REFTYPE // e.g., %typemap(out) qstring* { // bytes_container typemap(out) REFTYPE $result = OUT_CONVERTER((const char *) $1->START_ACCESSOR(), $1->SIZE_ACCESSOR()); } %typemap(out) CONTAINER_TYPE // e.g., %typemap(out) qstring { // bytes_container typemap(out) CONTAINER_TYPE $result = OUT_CONVERTER((const char *) $1.START_ACCESSOR(), $1.SIZE_ACCESSOR()); } %typemap(varout) CONTAINER_TYPE // e.g., %typemap(varout) qstring { // bytes_container typemap(varout) CONTAINER_TYPE $result = OUT_CONVERTER((const char *) $1.START_ACCESSOR(), $1.SIZE_ACCESSOR()); } // the following is used to turn a '... *result' output parameter, // into an actual return value. %typemap(in,numinputs=0) CONTAINER_TYPE *result (CONTAINER_TYPE temp) { // bytes_container typemap(in,numinputs=0) CONTAINER_TYPE *result (CONTAINER_TYPE temp) $1 = &temp; } %typemap(in,numinputs=0) CONTAINER_TYPE &result (CONTAINER_TYPE temp) { // bytes_container typemap(in,numinputs=0) CONTAINER_TYPE &result (CONTAINER_TYPE temp) $1 = &temp; } %typemap(argout) CONTAINER_TYPE *result { // bytes_container typemap(argout) CONTAINER_TYPE *result resultobj = ARGOUT_MAYBE_CONVERTER(resultobj, $1->START_ACCESSOR(), $1->SIZE_ACCESSOR(), int(result)); } %typemap(argout) CONTAINER_TYPE &result { // bytes_container typemap(argout) CONTAINER_TYPE &result resultobj = ARGOUT_MAYBE_CONVERTER(resultobj, $1->START_ACCESSOR(), $1->SIZE_ACCESSOR(), int(result)); } %typemap(freearg) CONTAINER_TYPE* result { // bytes_container typemap(freearg) CONTAINER_TYPE *result // Nothing. We certainly don't want 'temp' to be deleted. } %typemap(freearg) CONTAINER_TYPE& result { // bytes_container typemap(freearg) CONTAINER_TYPE &result // Nothing. We certainly don't want 'temp' to be deleted. } // We determine that the following parameter: "CONTAINER_TYPE *vout" has the // following characteristics: // - the C function being called returns void // - other than that, it's the same as for the "CONTAINER_TYPE *result" parameter // (i.e., requires a temporary 'qstring', etc...) // // Re-use the 'CONTAINER_TYPE *result' typemaps, ... %apply CONTAINER_TYPE *result { CONTAINER_TYPE *vout }; %apply CONTAINER_TYPE &result { CONTAINER_TYPE &vout }; // ...but override the argout one, so that it doesn't rely on a 'result' %typemap(argout) (CONTAINER_TYPE *vout) { // bytes_container typemap(argout) (CONTAINER_TYPE *vout) resultobj = ARGOUT_CONVERTER(resultobj, (const char *) $1->START_ACCESSOR(), $1->SIZE_ACCESSOR()); } %typemap(argout) (CONTAINER_TYPE &vout) { // bytes_container typemap(argout) (CONTAINER_TYPE &vout) resultobj = ARGOUT_CONVERTER(resultobj, (const char *) $1->START_ACCESSOR(), $1->SIZE_ACCESSOR()); } %typemap(directorin) CONTAINER_TYPE * { // bytes_container typemap(directorin) CONTAINER_TYPE * if ( $1 != NULL ) { $input = OUT_CONVERTER($1->START_ACCESSOR(), $1->SIZE_ACCESSOR()); } else { Py_INCREF(Py_None); $input = Py_None; } } %typemap(directorin) REFTYPE { // bytes_container typemap(directorin) REFTYPE $input = OUT_CONVERTER($1.START_ACCESSOR(), $1.SIZE_ACCESSOR()); } %typemap(directorout) CONTAINER_TYPE { // bytes_container typemap(directorout) CONTAINER_TYPE if ( CHECKER($1) ) IN_CONVERTER(&$result, $1); else Swig::DirectorTypeMismatchException::raise( SWIG_ErrorType(SWIG_TypeError), "in output value of type '" ELTYPE_TO_REPORT2 "' in method '$symname'"); } %typemap(directorargout) CONTAINER_TYPE *vout { // bytes_container typemap(directorargout) CONTAINER_TYPE *vout if ( CHECKER($result) ) { CONTAINER_TYPE _buf; if ( IN_CONVERTER(&_buf, $result) ) vout->insert(vout->SIZE_ACCESSOR(), _buf.START_ACCESSOR(), _buf.SIZE_ACCESSOR()); } } %enddef %define %bytes_container_ptr_and_ref( CONTAINER_TYPE, START_ACCESSOR, SIZE_ACCESSOR, INSTANCE_CAST, CHECKER, IN_CONVERTER, OUT_CONVERTER, ARGOUT_CONVERTER, ARGOUT_MAYBE_CONVERTER, ELTYPE_TO_REPORT1, ELTYPE_TO_REPORT2) %bytes_container( CONTAINER_TYPE *, CONTAINER_TYPE, START_ACCESSOR, SIZE_ACCESSOR, INSTANCE_CAST, CHECKER, IN_CONVERTER, OUT_CONVERTER, ARGOUT_CONVERTER, ARGOUT_MAYBE_CONVERTER, ELTYPE_TO_REPORT1, ELTYPE_TO_REPORT2); %bytes_container( CONTAINER_TYPE &, CONTAINER_TYPE, START_ACCESSOR, SIZE_ACCESSOR, INSTANCE_CAST, CHECKER, IN_CONVERTER, OUT_CONVERTER, ARGOUT_CONVERTER, ARGOUT_MAYBE_CONVERTER, ELTYPE_TO_REPORT1, ELTYPE_TO_REPORT2); %enddef #ifdef PY3 %bytes_container_ptr_and_ref( qstring, c_str, length, , IDAPyStr_Check, IDAPyStr_AsUTF8, IDAPyStr_FromUTF8AndSize, _sized_cstring_result, _maybe_sized_cstring_result, "string", "str"); %bytes_container_ptr_and_ref( bytevec_t, begin, size, , IDAPyBytes_Check, IDAPyBytes_AsBytes, IDAPyBytes_FromMemAndSize, _sized_binary_result, _maybe_sized_binary_result, "bytes", "bytes"); %bytes_container_ptr_and_ref( qtype, begin, length, (const uchar *), IDAPyBytes_Check, IDAPyBytes_as_qtype, IDAPyBytes_FromMemAndSize, _sized_binary_result, _maybe_sized_binary_result, "bytes", "bytes"); #else %bytes_container_ptr_and_ref( qstring, c_str, length, , IDAPyStr_Check, IDAPyStr_AsUTF8, IDAPyStr_FromUTF8AndSize, _sized_cstring_result, _maybe_sized_cstring_result, "string", "str"); %bytes_container_ptr_and_ref( bytevec_t, begin, size, , IDAPyBytes_Check, IDAPyBytes_AsBytes, IDAPyBytes_FromMemAndSize, _sized_binary_result, _maybe_sized_binary_result, "string", "str"); %bytes_container_ptr_and_ref( qtype, begin, length, (const uchar *), IDAPyBytes_Check, IDAPyBytes_as_qtype, IDAPyBytes_FromMemAndSize, _sized_binary_result, _maybe_sized_binary_result, "string", "str"); #endif //------------------------------------------------------------------------- // insn_t //------------------------------------------------------------------------- %fragment("cvt_const_insn_t_ref", "header") { bool convert_const_insn_t_ref(insn_t *out, PyObject *in) { uint64 ea; bool ok = PyW_GetNumber(in, &ea); if ( ok ) { insn_t tmp; ok = decode_insn(&tmp, ea_t(ea)); if ( ok ) *out = tmp; } else { insn_t *p_insn = nullptr; ok = SWIG_ConvertPtr(in, (void **) &p_insn, SWIGTYPE_p_insn_t, 0) >= 0 && p_insn != nullptr; if ( ok ) *out = *p_insn; } return ok; } } //------------------------------------------------------------------------- %typemap(in, fragment="cvt_const_insn_t_ref") (const insn_t &) (insn_t lins) { // %typemap(in) (const insn_t &) if ( !convert_const_insn_t_ref(&lins, $input) ) SWIG_exception_fail(SWIG_ValueError, "Expected either an address, or a non-null ida_ua.insn_t instance"); $1 = &lins; } %typemap(doc) (const insn_t &) "$1_name: an ida_ua.insn_t, or an address (C++: const insn_t &)" //--------------------------------------------------------------------- // varargs (mostly kernwin.hpp) //--------------------------------------------------------------------- // This is used for functions like warning(), info() and so on %typemap(in) (const char *format, ...) (qstring buf) { $1 = "%s"; /* Fix format string to %s */ IDAPyStr_AsUTF8(&buf, $input); /* Get string argument */ $2 = (void *) buf.begin(); /* Note: we cannot rely on 'nonnul_argument_prototype' for */ /* these, since we fiddle with the arguments number */ if ( $2 == NULL ) SWIG_exception_fail( SWIG_ValueError, "invalid null pointer " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); }; //------------------------------------------------------------------------- // for use with insn_t, op_t wrappers %typemap(in) (size_t ptrval) { $1 = size_t(PyLong_AsUnsignedLongLong($input)); } // Help SWIG to figure out the ulonglong type #ifdef SWIGWIN typedef unsigned __int64 ulonglong; typedef __int64 longlong; #else typedef unsigned long long ulonglong; typedef long long longlong; #endif #ifdef __EA64__ %apply longlong *INOUT { sval_t *value }; %apply longlong *INOUT { adiff_t *disp }; %apply ulonglong *INOUT { ea_t *addr }; %apply ulonglong *INPUT { ea_t *ea_ptr }; // get_debug_name %apply ulonglong *INOUT { sel_t *sel }; %apply ulonglong *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_range_selection() %apply ulonglong *OUTPUT { ea_t *from, ea_t *to, asize_t *size }; // get_mapping() %apply ulonglong *OUTPUT { uval_t *value }; // get_name_value #else %apply int *INOUT { sval_t *value }; %apply int *INOUT { adiff_t *disp }; %apply unsigned int *INOUT { ea_t *addr }; %apply unsigned int *INPUT { ea_t *ea_ptr }; // get_debug_name %apply unsigned int *INOUT { sel_t *sel }; %apply unsigned int *OUTPUT { ea_t *ea1, ea_t *ea2 }; // read_range_selection() %apply unsigned int *OUTPUT { ea_t *from, ea_t *to, asize_t *size }; // get_mapping() %apply unsigned int *OUTPUT { uval_t *value }; // get_name_value #endif %apply long long { qoff64_t }; %apply qstring *result { qstring *out }; %apply qstring *result { qstring *buf }; %apply qstring *result { qstring *errbuf }; %apply int *OUTPUT { int *icon }; %apply int *OUTPUT { action_state_t *state }; %apply bool *OUTPUT { bool *checkable }; %apply bool *OUTPUT { bool *checked }; %apply bool *OUTPUT { bool *visibility }; //------------------------------------------------------------------------- // 'errbuf' output handling can go many ways. Let's provide common helpers. %define %make_argout_errbuf_raise_exception_when_non_empty() %typemap(argout) (qstring *errbuf) { // %typemap(argout) qstring *errbuf (from: %make_argout_errbuf_raise_exception_when_non_empty) if ( !$1->empty() ) { if ( $result != NULL ) Py_XDECREF($result); SWIG_exception_fail(SWIG_RuntimeError, $1->c_str()); } } %enddef %define %make_argout_errbuf_raise_when_null_result() %typemap(argout) (qstring *errbuf) { // %typemap(argout) qstring *errbuf (from: %make_argout_errbuf_raise_when_null_result) if ( result == NULL ) { if ( $result != NULL ) Py_XDECREF($result); SWIG_exception_fail(SWIG_RuntimeError, $1->c_str()); } } %enddef //------------------------------------------------------------------------- // The following is to be used to expose an array of items // to IDAPython. This will not make a copy (on purpose!). //------------------------------------------------------------------------- // // (Very) heavily inspired by: // http://stackoverflow.com/questions/7713318/nested-structure-array-access-in-python-using-swig?rq=1 // // NOTE: This should probably hold a (weak?) reference // to the parent PyObject, because it is technically possible // to end up with dangling pointers otherwise // See also dynamic_wrapped_array_t %immutable; %inline %{ template struct wrapped_array_t { Type (&data)[N]; wrapped_array_t(Type (&data)[N]) : data(data) { } }; %} %mutable; %extend wrapped_array_t { inline size_t __len__() const { qnotused($self); return N; } inline const Type& __getitem__(size_t i) const { if ( i >= N ) throw std::out_of_range("out of bounds access"); return $self->data[i]; } inline void __setitem__(size_t i, const Type& v) { if ( i >= N ) throw std::out_of_range("out of bounds access"); $self->data[i] = v; } inline bytevec_t _get_bytes() const { bytevec_t bts; bts.resize(N * sizeof(Type)); memmove(bts.begin(), $self->data, bts.size()); return bts; } inline void _set_bytes(const bytevec_t &bts) { if ( bts.size() > N * sizeof(Type) ) throw std::out_of_range("out of bounds access"); memset($self->data, 0, sizeof($self->data)); memmove($self->data, bts.begin(), bts.size()); } %pythoncode { __iter__ = ida_idaapi._bounded_getitem_iterator bytes = property(_get_bytes, _set_bytes) } } //------------------------------------------------------------------------- // NOTE: see note for wrapped_array_t %immutable; %inline %{ template struct dynamic_wrapped_array_t { Type *data; size_t count; dynamic_wrapped_array_t(Type *_data, size_t _count) : data(_data), count(_count) { } }; %} %mutable; %extend dynamic_wrapped_array_t { inline size_t __len__() const { return $self->count; } inline const Type& __getitem__(size_t i) const { if ( i >= $self->count ) throw std::out_of_range("out of bounds access"); return $self->data[i]; } inline void __setitem__(size_t i, const Type& v) { if ( i >= $self->count ) throw std::out_of_range("out of bounds access"); $self->data[i] = v; } %pythoncode { __iter__ = ida_idaapi._bounded_getitem_iterator } } //------------------------------------------------------------------------- #if SWIG_VERSION == 0x40000 || SWIG_VERSION == 0x40001 %typemap(out) tinfo_t {} %typemap(ret) tinfo_t { // %typemap(ret) tinfo_t tinfo_t *ni = new tinfo_t($1); til_register_python_tinfo_t_instance(ni); $result = SWIG_NewPointerObj(ni, $&1_descriptor, SWIG_POINTER_OWN | 0); } %typemap(check) tinfo_t * { // %typemap(check) tinfo_t * if ( $1 == NULL ) SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); } %typemap(out) tinfo_t * { // %typemap(out) tinfo_t * tinfo_t *ni = new tinfo_t(*$1); til_register_python_tinfo_t_instance(ni); $result = SWIG_NewPointerObj(ni, $1_descriptor, SWIG_POINTER_OWN | 0); } %typemap(newfree) tinfo_t * { // %typemap(newfree) tinfo_t * delete $1; } #else #error Ensure tinfo_t wrapping is compatible with this version of SWIG #endif // Convert all of these %cstring_output_maxstr_none(char *buf, size_t bufsize); %cstring_output_maxstr_none(char *buf, int bufsize); %binary_output_or_none(void *buf, size_t bufsize); // Accept single Python string for const void * + size input arguments // For example: put_many_bytes() and patch_many_bytes() %apply (char *STRING, int LENGTH) { (const void *buf, size_t size) }; %apply (char *STRING, int LENGTH) { (const void *buf, size_t bufsize) }; %apply (char *STRING, int LENGTH) { (const void *buf, size_t len) }; %apply (char *STRING, int LENGTH) { (const void *value, size_t length) }; %apply (char *STRING, int LENGTH) { (const void *dataptr,size_t len) }; #ifdef PY3 %define %const_pointer_and_size(PTRTYPE, BUFNAME, SIZENAME, STORAGE_TYPE, CONVERTER, LENGTH_GETTER) %typemap(in) (const PTRTYPE *BUFNAME, size_t SIZENAME) (STORAGE_TYPE tmp) { // typemap(in) (const PTRTYPE *BUFNAME, size_t SIZENAME) if ( !CONVERTER(&tmp, $input) ) { %argument_fail(SWIG_ERROR, "$type", $symname, $argnum); } $1 = %reinterpret_cast(tmp.begin(), $1_ltype); $2 = %numeric_cast(tmp.LENGTH_GETTER(), $2_ltype); } %typemap(freearg) (const PTRTYPE *BUFNAME, size_t SIZENAME) { // typemap(freearg) (const PTRTYPE *BUFNAME, size_t SIZENAME) } %enddef %define %const_void_pointer_and_size(PTRTYPE, BUFNAME, SIZENAME) %typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) (const PTRTYPE *BUFNAME, size_t SIZENAME) { // %typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER) (const PTRTYPE *BUFNAME, size_t SIZENAME) $1 = PyBytes_Check($input) ? 1 : 0; } %const_pointer_and_size(PTRTYPE, BUFNAME, SIZENAME, bytevec_t, IDAPyBytes_AsBytes, size) %enddef %define %const_char_pointer_and_size(PTRTYPE, BUFNAME, SIZENAME) %const_pointer_and_size(PTRTYPE, BUFNAME, SIZENAME, qstring, IDAPyStr_AsUTF8, length) %enddef %const_void_pointer_and_size(void, buf, size); %const_void_pointer_and_size(void, buf, bufsize); %const_void_pointer_and_size(void, buf, len); %const_void_pointer_and_size(void, value, length); %const_void_pointer_and_size(void, dataptr, len); %const_char_pointer_and_size(char, value, length); #endif // Create wrapper classes for basic type arrays %array_class(uchar, uchar_array); %array_class(tid_t, tid_array); %array_class(ea_t, ea_array); %array_class(sel_t, sel_array); %array_class(uval_t, uval_array); %pointer_class(int, int_pointer); %pointer_class(ea_t, ea_pointer); %pointer_class(sval_t, sval_pointer); %pointer_class(sel_t, sel_pointer); %{ SWIGINTERN PyObject *qstrvec2pylist(const qstrvec_t &vec) { size_t n = vec.size(); PyObject *py_list = PyList_New(n); for ( size_t i=0; i < n; ++i ) PyList_SetItem(py_list, i, IDAPyStr_FromUTF8AndSize(vec[i].c_str(), vec[i].length())); return py_list; } %} //------------------------------------------------------------------------- // When it comes to uint64, we have been typically very tolerant and // accept negative values as if were logical to perform C-like numbers // 'wrapping' in Python. It's not, but bw-compat imposes that we do. %fragment("cvt_uint64", "header") { int cvt_uint64(uint64 *out, PyObject *obj) { unsigned long long ull = PyLong_AsUnsignedLongLong(obj); if ( PyErr_Occurred() ) { PyErr_Clear(); long long ll = PyLong_AsLongLong(obj); if ( PyErr_Occurred() ) { PyErr_Clear(); return SWIG_OverflowError; } ull = (unsigned long long) ll; } *out = uint64(ull); return SWIG_OK; } } %typemap(in, fragment="cvt_uint64") uint64 (int ecode) { // %typemap(in) uint64 ecode = cvt_uint64(&$1, $input); if ( !SWIG_IsOK(ecode) ) SWIG_exception_fail(SWIG_ArgError(ecode), "in method '$symname', argument $argnum of type $1_type"); } //------------------------------------------------------------------------- %define %_uint_result_as_output(TYPE, CONVFUNC, CHECK_EXPR) %typemap(in,numinputs=0) TYPE *result (TYPE temp = 0) { // %_uint_result_as_output(TYPE, CONVFUNC, CHECK_EXPR) %typemap(in,numinputs=0) TYPE *result $1 = &temp; } %typemap(argout) TYPE *result { // %_uint_result_as_output(TYPE, CONVFUNC) %typemap(argout) TYPE *result Py_XDECREF(resultobj); if ( CHECK_EXPR ) { resultobj = CONVFUNC(*(TYPE *) $1); } else { Py_INCREF(Py_None); resultobj = Py_None; } } %enddef //------------------------------------------------------------------------- %define %uint_result_as_output(TYPE, CONVFUNC) %_uint_result_as_output(TYPE, CONVFUNC, int(result) > 0); %enddef %uint_result_as_output(uint32, PyLong_FromUnsignedLong); %uint_result_as_output(uint64, PyLong_FromUnsignedLongLong); %uint_result_as_output(int64, PyLong_FromLongLong); %apply uint32 *result { uint32 *out }; %apply uint64 *result { uint64 *out }; %apply int64 *result { int64 *out }; #ifdef __EA64__ %apply uint64 *result { ea_t *result }; #else %apply uint32 *result { ea_t *result }; #endif // helpers to turn result into multiple values (just %apply, renaming 'appended_ea') %typemap(argout) ea_t *appended_ea { // %typemap(argout) ea_t *appended_ea #ifdef __EA64__ $result = SWIG_Python_AppendOutput($result, PyLong_FromUnsignedLongLong(*($1))); #else $result = SWIG_Python_AppendOutput($result, PyLong_FromUnsignedLong(*($1))); #endif } //------------------------------------------------------------------------- // Make get_any_cmt() work %apply unsigned char *OUTPUT { color_t *cmttype }; // For get_enum_id() %apply unsigned char *OUTPUT { uchar *serial }; // get_[first|last]_serial_enum_member() won't take serials as input; it'll be present as output %apply unsigned char *OUTPUT { uchar *out_serial }; // get_[next|prev]_serial_enum_member() take serials as input, and have the result present as output %apply unsigned char *INOUT { uchar *in_out_serial }; // This is meant only for the code that is defined in IDAPython, // as SDK non-null pointers should be marked by NONNULL and handled // automatically. %define %pywraps_nonnul_argument_prototype(PROTO, ARGSIG) /* first, define the typemap */ %typemap(check) (ARGSIG) { if ( $1 == NULL ) SWIG_exception_fail(SWIG_ValueError, "invalid null pointer " "in method '" "$symname" "', argument " "$argnum"" of type '" "$1_type""'"); } /* Then, redeclare prototype. Note that we want this prototype _only_ seen */ /* by SWiG, but not by the later compile phase: because of the defines */ /* in pro.h, 'idaapi', 'ida_export', etc... will disappear, causing */ /* VisualStudio to exit with a "same prototype, different modifiers" error. */ %inline %{ #ifndef _MSC_VER PROTO; #endif %} %enddef %define %numbers_list_to_values_vec_helper(VECTYPE, SWIGTYPE, PYLIST_CONVERTOR, REFTYPE) %typemap(arginit) VECTYPE REFTYPE "VECTYPE $1_local_storage; // %numbers_list_to_values_vec(VECTYPE) %typemap(arginit) VECTYPE REFTYPE" // *MUST NOT* be within '{}'s %typemap(in) VECTYPE REFTYPE { // %numbers_list_to_values_vec(VECTYPE) %typemap(in) VECTYPE REFTYPE if ( PySequence_Check($input) ) { if ( PYLIST_CONVERTOR(&$1_local_storage, $input) < 0 ) SWIG_fail; $1 = &$1_local_storage; } else { void *$1_vptr = 0; int res$argnum = SWIG_ConvertPtr($input, &$1_vptr, SWIGTYPE, 0 | 0); if ( !SWIG_IsOK(res$argnum) ) SWIG_exception_fail(SWIG_ArgError(res$argnum), "in method '$symname', argument $argnum of type $1_type"); $1 = reinterpret_cast($1_vptr); } } %typecheck(SWIG_TYPECHECK_POINTER) VECTYPE REFTYPE { // %numbers_list_to_values_vec(VECTYPE) %typecheck(SWIG_TYPECHECK_POINTER) VECTYPE REFTYPE if ( PySequence_Check($input) > 0 ) { $1 = 1; } else { int res = SWIG_ConvertPtr($input, 0, SWIGTYPE, 0); $1 = SWIG_CheckState(res); } } %enddef //------------------------------------------------------------------------- // For e.g., get_idainfo_by_type() %apply uint32 * OUTPUT { flags_t *out_flags }; %apply size_t * OUTPUT { size_t *out_size }; %apply size_t * OUTPUT { size_t *out_alsize }; %typemap(check) size_t *out_size "*($1) = 0; // %typemap(check) size_t *out_size"; %typemap(check) size_t *out_alsize "*($1) = 0; // %typemap(check) size_t *out_alsize"; %typemap(check) flags_t *out_flags "*($1) = 0; // %typemap(check) flags_t *out_flags"; %typemap(in,numinputs=0) opinfo_t *out_mt (opinfo_t temp) { // typemap(in,numinputs=0) opinfo_t *out_mt $1 = &temp; } %typemap(argout) opinfo_t *out_mt { // typemap(argout) opinfo_t *out_mt if ( result ) { PyObject *py_opinfo = SWIG_NewPointerObj(SWIG_as_voidptr(new opinfo_t(*($1))), SWIGTYPE_p_opinfo_t, SWIG_POINTER_NEW ); $result = SWIG_Python_AppendOutput($result, py_opinfo); } else { Py_INCREF(Py_None); $result = SWIG_Python_AppendOutput($result, Py_None); } } %typemap(freearg) opinfo_t *out_mt { // typemap(freearg) opinfo_t *out_mt // Nothing. We certainly don't want 'temp' to be deleted. } //------------------------------------------------------------------------- %define %numbers_list_to_values_vec(VECTYPE, SWIGTYPE, PYLIST_CONVERTOR) %numbers_list_to_values_vec_helper(VECTYPE, SWIGTYPE, PYLIST_CONVERTOR, *); %numbers_list_to_values_vec_helper(VECTYPE, SWIGTYPE, PYLIST_CONVERTOR, &); %enddef #ifdef __EA64__ %numbers_list_to_values_vec(eavec_t, SWIGTYPE_p_qvectorT_unsigned_long_long_t, PyW_PyListToEaVec); #else %numbers_list_to_values_vec(eavec_t, SWIGTYPE_p_qvectorT_unsigned_int_t, PyW_PyListToEaVec); #endif //------------------------------------------------------------------------- // Make sure the GIL is released, in case 'NAME' is calling execute_sync // either directly, or indirectly %define %calls_execute_sync(NAME) %thread NAME; %enddef #ifdef TESTABLE_BUILD # define HOOKS_DUMP_STATE() %ignore NAME##_Hooks::dump_state; #else # define HOOKS_DUMP_STATE() #endif %define %define_Hooks_class(NAME) %ignore NAME##_Callback; %ignore NAME##_Hooks::dispatch; %ignore NAME##_Hooks::mappings; %ignore NAME##_Hooks::mappings_size; HOOKS_DUMP_STATE(); %enddef %{ #include #include #include "../../../pywraps.hpp" %} %{ #ifdef __EA64__ # define ea_t_SWIGTYPE_name SWIGTYPE_p_unsigned_long_long #else # define ea_t_SWIGTYPE_name SWIGTYPE_p_unsigned_int #endif SWIGINTERN void __raise_ba(const std::bad_alloc &SWIGUNUSEDPARM(ba)) { PyErr_SetString(PyExc_MemoryError, "Out of memory (bad_alloc)"); } SWIGINTERN void __raise_u() { PyErr_SetString(PyExc_RuntimeError, "Unknown exception"); } SWIGINTERN void __raise_e(const std::exception &e) { const char *what = e.what(); if ( what == NULL || what[0] == '\0' ) { __raise_u(); } else { PyErr_SetString(PyExc_RuntimeError, what); } } SWIGINTERN void __raise_ie(const interr_exc_t &ie) { qstring emsg; emsg.sprnt(INTERR_EXC_FMT, ie.code); PyErr_SetString(PyExc_RuntimeError, emsg.begin()); } SWIGINTERN void __raise_de(const Swig::DirectorException &e) { bool handled = false; if ( PyErr_Occurred() != NULL ) { // Add the new bits of info to the error PyObject *exception, *v, *tb; PyErr_Fetch(&exception, &v, &tb); if ( exception != NULL ) { PyErr_NormalizeException(&exception, &v, &tb); if ( exception != NULL ) { // FIXME: We retrieve the message, but not the context (i.e., the // stack trace.) Ideally we should perhaps swoop in our own // 'sys.stderr', call PyErr_Print(), retrieve the result, and // append that to the new exception message. newref_t as_str(PyObject_Str(v)); if ( as_str != NULL ) { qstring buf; IDAPyStr_AsUTF8(&buf, as_str.o); buf.insert(" : "); buf.insert(e.getMessage()); PyErr_SetString(PyExc_RuntimeError, buf.c_str()); handled = true; } } } } if ( !handled ) PyErr_SetString(PyExc_RuntimeError, e.getMessage()); } SWIGINTERN void __raise_oor(const std::out_of_range &e) { PyErr_SetString(PyExc_IndexError, e.what()); } SWIGINTERN bool __chkthr() { bool ok = is_main_thread(); if ( !ok ) PyErr_SetString(PyExc_RuntimeError, "Function can be called from the main thread only"); return ok; } SWIGINTERN bool __chkreqidb() { bool ok = netnode::inited(); if ( !ok ) PyErr_SetString(PyExc_RuntimeError, "Function requires a database"); return ok; } %} %define %force_declare_SWiG_type(NAME) // KLUDGE: I have no idea how to force SWiG to declare a type for a module, // unless that type is indeed used. That's why this wrapper exists.. %inline %{ inline void _kludge_force_declare_##NAME(const NAME *) {} %} %enddef %define %modal_dialog_triggering_function(NAME) %thread NAME; %pythonprepend NAME %{ import ida_kernwin # kludge: we can't use %feature("shadow") for top-level # functions (see https://github.com/swig/swig/issues/980) # Thus we'll %pythonprepend some code, and return from it, # making the original code unreachable. Not pretty, but I # don't have anything better at the moment. with ida_kernwin.disabled_script_timeout_t(): return _ida_kernwin.NAME(*args) %} %enddef %include // If the module is 'pro', don't import pro.h, or the %include // at the beginning of pro.i won't have any effect. Same for all // modules. ${ALL_IMPORTS} // This is where all the collected NONNULL information coming // from the SDK, will be injected in the form of 'check' // typemaps. ${NONNULL_TYPEMAPS} // gdl_graph_t & subclasses %cstring_output_maxstr_none(char *iobuf, int iobufsize); %typemap(argout) (char *iobuf, int iobufsize) { // %typemap(argout) (char *iobuf, int iobufsize) qfree($1); } %typemap(directorout) char *get_node_label (qstring tmp) { // %typemap(directorout) char *get_node_label (qstring tmp) if ( IDAPyStr_AsUTF8(&tmp, result) ) ::qstrncpy(iobuf, tmp.c_str(), iobufsize); else Swig::DirectorTypeMismatchException::raise( SWIG_ErrorType(SWIG_TypeError), "in output value of type 'char *' in method '$symname'"); $result = iobuf; } %fragment("call_py_testf_t", "header") { bool call_py_testf_t(flags_t flags, void *ud) { PYW_GIL_CHECK_LOCKED_SCOPE(); PyObject *py_callable = (PyObject *) ud; QASSERT(0, PyCallable_Check(py_callable)); newref_t py_flags(PyLong_FromUnsignedLong(flags)); newref_t result(PyObject_CallFunctionObjArgs(py_callable, py_flags.o, nullptr)); return result != nullptr && PyObject_IsTrue(result.o); } } %typemap(in, fragment="call_py_testf_t") (testf_t *func, void *ud) { // %typemap(in, fragment="call_py_testf_t") (testf_t *func, void *ud) if ( !PyCallable_Check($input) ) SWIG_exception_fail( SWIG_TypeError, "in method '" "$symname" "', argument " "$argnum"" of type 'callable'"); $1 = call_py_testf_t; $2 = $input; } #endif // __HEADER_I__ // END: auto-inserted header