Home | History | Annotate | Download | only in libdisasm
      1 #include <stdlib.h>
      2 #include "libdis.h"
      3 
      4 
      5 static void x86_oplist_append( x86_insn_t *insn, x86_oplist_t *op ) {
      6 	x86_oplist_t *list;
      7 
      8 	if (! insn ) {
      9 		return;
     10 	}
     11 
     12 	list = insn->operands;
     13 	if (! list ) {
     14 		insn->operand_count = 1;
     15 		/* Note that we have no way of knowing if this is an
     16 		 * exlicit operand or not, since the caller fills
     17 		 * the x86_op_t after we return. We increase the
     18 		 * explicit count automatically, and ia32_insn_implicit_ops
     19 		 * decrements it */
     20 		insn->explicit_count = 1;
     21 		insn->operands = op;
     22 		return;
     23 	}
     24 
     25 	/* get to end of list */
     26 	for ( ; list->next; list = list->next )
     27 		;
     28 
     29 	insn->operand_count = insn->operand_count + 1;
     30 	insn->explicit_count = insn->explicit_count + 1;
     31 	list->next = op;
     32 
     33 	return;
     34 }
     35 
     36 x86_op_t * x86_operand_new( x86_insn_t *insn ) {
     37 	x86_oplist_t *op;
     38 
     39 	if (! insn ) {
     40 		return(NULL);
     41 	}
     42 	op = calloc( sizeof(x86_oplist_t), 1 );
     43 	op->op.insn = insn;
     44 	x86_oplist_append( insn, op );
     45 	return( &(op->op) );
     46 }
     47 
     48 void x86_oplist_free( x86_insn_t *insn ) {
     49 	x86_oplist_t *op, *list;
     50 
     51 	if (! insn ) {
     52 		return;
     53 	}
     54 
     55 	for ( list = insn->operands; list; ) {
     56 		op = list;
     57 		list = list->next;
     58 		free(op);
     59 	}
     60 
     61 	insn->operands = NULL;
     62 	insn->operand_count = 0;
     63 	insn->explicit_count = 0;
     64 
     65 	return;
     66 }
     67 
     68 /* ================================================== LIBDISASM API */
     69 /* these could probably just be #defines, but that means exposing the
     70    enum... yet one more confusing thing in the API */
     71 int x86_operand_foreach( x86_insn_t *insn, x86_operand_fn func, void *arg,
     72 	       		enum x86_op_foreach_type type ){
     73 	x86_oplist_t *list;
     74 	char explicit = 1, implicit = 1;
     75 
     76 	if (! insn || ! func ) {
     77 		return 0;
     78 	}
     79 
     80 	/* note: explicit and implicit can be ORed together to
     81 	 * allow an "all" limited by access type, even though the
     82 	 * user is stupid to do this since it is default behavior :) */
     83 	if ( (type & op_explicit) && ! (type & op_implicit) ) {
     84 		implicit = 0;
     85 	}
     86 	if ( (type & op_implicit) && ! (type & op_explicit) ) {
     87 		explicit = 0;
     88 	}
     89 
     90 	type = type & 0x0F; /* mask out explicit/implicit operands */
     91 
     92 	for ( list = insn->operands; list; list = list->next ) {
     93 		if (! implicit && (list->op.flags & op_implied) ) {
     94 			/* operand is implicit */
     95 			continue;
     96 		}
     97 
     98 		if (! explicit && ! (list->op.flags & op_implied) ) {
     99 			/* operand is not implicit */
    100 			continue;
    101 		}
    102 
    103 		switch ( type ) {
    104 			case op_any:
    105 				break;
    106 			case op_dest:
    107 				if (! (list->op.access & op_write) ) {
    108 					continue;
    109 				}
    110 				break;
    111 			case op_src:
    112 				if (! (list->op.access & op_read) ) {
    113 					continue;
    114 				}
    115 				break;
    116 			case op_ro:
    117 				if (! (list->op.access & op_read) ||
    118 				      (list->op.access & op_write ) ) {
    119 					continue;
    120 				}
    121 				break;
    122 			case op_wo:
    123 				if (! (list->op.access & op_write) ||
    124 				      (list->op.access & op_read ) ) {
    125 					continue;
    126 				}
    127 				break;
    128 			case op_xo:
    129 				if (! (list->op.access & op_execute) ) {
    130 					continue;
    131 				}
    132 				break;
    133 			case op_rw:
    134 				if (! (list->op.access & op_write) ||
    135 				    ! (list->op.access & op_read ) ) {
    136 					continue;
    137 				}
    138 				break;
    139 			case op_implicit: case op_explicit: /* make gcc happy */
    140 					  break;
    141 		}
    142 		/* any non-continue ends up here: invoke the callback */
    143 		(*func)( &list->op, insn, arg );
    144 	}
    145 
    146 	return 1;
    147 }
    148 
    149 static void count_operand( x86_op_t *op, x86_insn_t *insn, void *arg ) {
    150 	size_t * count = (size_t *) arg;
    151 	*count = *count + 1;
    152 }
    153 
    154 size_t x86_operand_count( x86_insn_t *insn, enum x86_op_foreach_type type ) {
    155 	size_t count = 0;
    156 
    157 	/* save us a list traversal for common counts... */
    158 	if ( type == op_any ) {
    159 		return insn->operand_count;
    160 	} else if ( type == op_explicit ) {
    161 		return insn->explicit_count;
    162 	}
    163 
    164 	x86_operand_foreach( insn, count_operand, &count, type );
    165 	return count;
    166 }
    167 
    168 /* accessor functions */
    169 x86_op_t * x86_operand_1st( x86_insn_t *insn ) {
    170 	if (! insn->explicit_count ) {
    171 		return NULL;
    172 	}
    173 
    174 	return &(insn->operands->op);
    175 }
    176 
    177 x86_op_t * x86_operand_2nd( x86_insn_t *insn ) {
    178 	if ( insn->explicit_count < 2 ) {
    179 		return NULL;
    180 	}
    181 
    182 	return &(insn->operands->next->op);
    183 }
    184 
    185 x86_op_t * x86_operand_3rd( x86_insn_t *insn ) {
    186 	if ( insn->explicit_count < 3 ) {
    187 		return NULL;
    188 	}
    189 
    190 	return &(insn->operands->next->next->op);
    191 }
    192