Files
2024-02-21 14:22:30 +01:00

2.8 KiB

This is an FAQ-style repository of SWiG incantations that are regularly needed.

Remove an argument from a prototype (because it doesn't make sense in the context of IDAPython)

%typemap(in,numinputs=0) int length
{
    $1 = -1; // always -1 in IDAPython
}

Add a parameter to a C++ notification

Assume a notification named struc_renamed, to which you just added a bool success parameter (to carry along information about the operation's success so far):

struc_renamed,          ///< A structure type has been renamed.
                        ///< \param sptr (::struc_t *)
                        ///< \param success (bool)  // <--------- new

That new parameter will be picked up by the hooks-producing code automatically (great!), which means existing hooks are now broken (bad.)

We need to add support for calling into "old-style" hooks. That's done through the patch_codegen.py mechanism, and in particular the director_method_call_arity_cap rule. Something like this should do:

"SwigDirector_IDB_Hooks::struc_renamed" : [
    ("director_method_call_arity_cap", (
        False, # add GIL lock
        "struc_renamed",
        "(method ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)",
        "(swig_get_self(), (PyObject *) swig_method_name ,(PyObject *)obj0,(__argcnt < 3 ? nullptr : (PyObject *)obj1), nullptr)")
    )),
],

Handle a virtual method's "output" parameter in a director

Assume you have a virtual method taking an 'output' argument:

void merge_node_helper_t::get_column_headers(qstrvec_t *out, ...)

The neat thing to do here is to let Python implementations do the following:

def get_column_headers(self, ...):
    # ...
    return ["Name", "Address"]

To achieve that, you want to use the directorargout typemap:

%typemap(directorargout) qstrvec_t * (qstrvec_t tmp)
{ // %typemap(directorargout) qstrvec_t *
  if ( PyW_PySeqToStrVec(&tmp, $result) >= 0 )
  {
    $1->swap(tmp);
  }
  else
  {
    Swig::DirectorTypeMismatchException::raise(
            SWIG_ErrorType(SWIG_TypeError),
            "in output value of type 'qstrvec_t' in method '$symname'");
  }
}

"intercept" access to a structure/class field, in order to perform extra work

For example, idainfo.lflags bits should be set using proper setters, because they can have side-effects.

. tell swig to consider the member as unreachable:

%ignore idainfo::lflags;

. extend the type to "manually" provide the field:

%extend idainfo
{
  // ...
  uint32 _get_lflags() const { return $self->lflags; }
  void _set_lflags(uint32 _f)
  {
    // do the job here
  }

  %pythoncode {
    lflags = property(_get_lflags, _set_lflags)