1 #include <stdlib.h>
2 #include "libdis.h"
3
4
x86_oplist_append(x86_insn_t * insn,x86_oplist_t * op)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
x86_operand_new(x86_insn_t * insn)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
x86_oplist_free(x86_insn_t * insn)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 */
x86_operand_foreach(x86_insn_t * insn,x86_operand_fn func,void * arg,enum x86_op_foreach_type type)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
count_operand(x86_op_t * op,x86_insn_t * insn,void * arg)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
x86_operand_count(x86_insn_t * insn,enum x86_op_foreach_type type)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 */
x86_operand_1st(x86_insn_t * insn)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
x86_operand_2nd(x86_insn_t * insn)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
x86_operand_3rd(x86_insn_t * insn)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