OLD | NEW |
| (Empty) |
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 } | |
OLD | NEW |