Logo Search packages:      
Sourcecode: libdisasm version File versions  Download package

x86_operand_list.c

#include <stdlib.h>
#include "libdis.h"


static void x86_oplist_append( x86_insn_t *insn, x86_oplist_t *op ) {
      x86_oplist_t *list;

      if (! insn ) {    
            return;
      }

      list = insn->operands;
      if (! list ) {
            insn->operand_count = 1;
            /* Note that we have no way of knowing if this is an
             * exlicit operand or not, since the caller fills 
             * the x86_op_t after we return. We increase the
             * explicit count automatically, and ia32_insn_implicit_ops
             * decrements it */
            insn->explicit_count = 1;
            insn->operands = op;
            return;
      }

      /* get to end of list */
      for ( ; list->next; list = list->next ) 
            ;

      insn->operand_count = insn->operand_count + 1;
      insn->explicit_count = insn->explicit_count + 1;
      list->next = op;

      return;
}
      
x86_op_t * x86_operand_new( x86_insn_t *insn ) {
      x86_oplist_t *op;

      if (! insn ) {    
            return(NULL);
      }
      op = calloc( sizeof(x86_oplist_t), 1 );
      op->op.insn = insn;
      x86_oplist_append( insn, op );
      return( &(op->op) );
}

void x86_oplist_free( x86_insn_t *insn ) {
      x86_oplist_t *op, *list;

      if (! insn ) {
            return;
      }

      for ( list = insn->operands; list; ) {
            op = list;
            list = list->next;
            free(op);
      }

      insn->operands = NULL;
      insn->operand_count = 0;
      insn->explicit_count = 0;

      return;
}

/* ================================================== LIBDISASM API */
/* these could probably just be #defines, but that means exposing the
   enum... yet one more confusing thing in the API */
int x86_operand_foreach( x86_insn_t *insn, x86_operand_fn func, void *arg, 
                        enum x86_op_foreach_type type ){
      x86_oplist_t *list;
      char explicit = 1, implicit = 1;

      if (! insn || ! func ) {
            return 0;
      }
      
      /* note: explicit and implicit can be ORed together to
       * allow an "all" limited by access type, even though the
       * user is stupid to do this since it is default behavior :) */
      if ( (type & op_explicit) && ! (type & op_implicit) ) {
            implicit = 0;
      }
      if ( (type & op_implicit) && ! (type & op_explicit) ) {
            explicit = 0;
      }

      type = type & 0x0F; /* mask out explicit/implicit operands */

      for ( list = insn->operands; list; list = list->next ) {
            if (! implicit && (list->op.flags & op_implied) ) {
                  /* operand is implicit */
                  continue;
            }

            if (! explicit && ! (list->op.flags & op_implied) ) {
                  /* operand is not implicit */
                  continue;
            }

            switch ( type ) {
                  case op_any:
                        break;
                  case op_dest:
                        if (! (list->op.access & op_write) ) {
                              continue;
                        }
                        break;
                  case op_src:
                        if (! (list->op.access & op_read) ) {
                              continue;
                        }
                        break;
                  case op_ro:
                        if (! (list->op.access & op_read) ||
                              (list->op.access & op_write ) ) {
                              continue;
                        }
                        break;
                  case op_wo:
                        if (! (list->op.access & op_write) ||
                              (list->op.access & op_read ) ) {
                              continue;
                        }
                        break;
                  case op_xo:
                        if (! (list->op.access & op_execute) ) {
                              continue;
                        }
                        break;
                  case op_rw:
                        if (! (list->op.access & op_write) ||
                            ! (list->op.access & op_read ) ) {
                              continue;
                        }
                        break;
                  case op_implicit: case op_explicit: /* make gcc happy */
                                break;
            }
            /* any non-continue ends up here: invoke the callback */
            (*func)( &list->op, insn, arg );
      }

      return 1;
}

static void count_operand( x86_op_t *op, x86_insn_t *insn, void *arg ) {
      size_t * count = (size_t *) arg;
      *count = *count + 1;
}

size_t x86_operand_count( x86_insn_t *insn, enum x86_op_foreach_type type ) {
      size_t count = 0;
      
      /* save us a list traversal for common counts... */
      if ( type == op_any ) {
            return insn->operand_count;
      } else if ( type == op_explicit ) {
            return insn->explicit_count;
      }

      x86_operand_foreach( insn, count_operand, &count, type );
      return count;
}

/* accessor functions */
x86_op_t * x86_operand_1st( x86_insn_t *insn ) {
      if (! insn->explicit_count ) {
            return NULL;
      }

      return &(insn->operands->op);
}

x86_op_t * x86_operand_2nd( x86_insn_t *insn ) {
      if ( insn->explicit_count < 2 ) {
            return NULL;
      }

      return &(insn->operands->next->op);
}

x86_op_t * x86_operand_3rd( x86_insn_t *insn ) {
      if ( insn->explicit_count < 3 ) {
            return NULL;
      }

      return &(insn->operands->next->next->op);
}

Generated by  Doxygen 1.6.0   Back to index