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 | |