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