aboutsummaryrefslogtreecommitdiff
path: root/src/third_party/libdisasm/x86_operand_list.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/libdisasm/x86_operand_list.c')
-rw-r--r--src/third_party/libdisasm/x86_operand_list.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/src/third_party/libdisasm/x86_operand_list.c b/src/third_party/libdisasm/x86_operand_list.c
new file mode 100644
index 00000000..95409e06
--- /dev/null
+++ b/src/third_party/libdisasm/x86_operand_list.c
@@ -0,0 +1,191 @@
+#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);
+}