Added instruction iterator
[dyninst.git] / dyninstAPI / src / InstrucIter-x86.C
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <string.h>
5
6 #include "common/h/Types.h"
7 #include "common/h/Vector.h"
8 #include "common/h/Dictionary.h"
9
10 #include "arch.h"
11 #include "util.h"
12 #include "process.h"
13 #include "symtab.h"
14 #include "instPoint.h"
15 #include "InstrucIter.h"
16
17 #include "BPatch_Set.h"
18
19 //some more function used to identify the properties of the instruction
20 /** is the instruction used to return from the functions
21   * @param i the instruction value 
22   */
23 bool InstrucIter::isAReturnInstruction()
24 {
25   const instruction i = getInstruction();
26         return i.isReturn();
27 }
28
29 extern const unsigned char*
30 skip_headers(const unsigned char*,bool&,bool&);
31 extern bool insn_hasSIB(unsigned,unsigned&,unsigned&,unsigned&);
32
33 /** is the instruction an indirect jump instruction 
34   * @param i the instruction value 
35   */
36 bool InstrucIter::isAIndirectJumpInstruction()
37 {
38   const instruction i = getInstruction();
39         if((i.type() & IS_JUMP) &&
40            (i.type() & INDIR))
41         {
42                 /* since there are two is_jump and indirect instructions
43                    we are looking for the one with the indirect register
44                    addressing mode one of which ModR/M contains 4 in its
45                    reg/opcode field */
46                 bool isWordAddr,isWordOp;
47                 const unsigned char* ptr =
48                         skip_headers(i.ptr(),isWordAddr,isWordOp);
49                 assert(*ptr == 0xff);
50                 ptr++;
51                 if((*ptr & 0x38) == 0x20) 
52                         return true;
53         }
54         return false;
55 }
56
57 /** is the instruction a conditional branch instruction 
58   * @param i the instruction value 
59   */ 
60 bool InstrucIter::isACondBranchInstruction()
61 {
62   const instruction i = getInstruction();
63         if(i.type() & IS_JCC)
64                 return true;
65         return false;
66 }
67
68 /** is the instruction an unconditional branch instruction 
69   * @param i the instruction value 
70   */
71 bool InstrucIter::isAJumpInstruction()
72 {
73   const instruction i = getInstruction();
74         if((i.type() & IS_JUMP) &&
75            !(i.type() & INDIR) && 
76            !(i.type() & PTR_WX))
77                 return true;
78         return false;
79 }
80
81 /** is the instruction a call instruction 
82   * @param i the instruction value 
83   */
84 bool InstrucIter::isACallInstruction()
85 {
86   const instruction i = getInstruction();
87         return i.isCall();
88 }
89
90 bool InstrucIter::isAnneal()
91 {
92         return true;
93 }
94
95 /** function which returns the offset of control transfer instructions
96   * @param i the instruction value 
97   */
98 Address InstrucIter::getBranchTargetAddress(Address pos)
99 {
100     const instruction i = getInstruction();
101         return i.getTarget(pos);
102 }
103
104 void initOpCodeInfo()
105 {
106 }
107
108 /* NOT yet implemented. */
109 BPatch_memoryAccess InstrucIter::isLoadOrStore()
110 {
111   return BPatch_memoryAccess::none;
112 }
113
114
115 //Address Handle used by flowGraph which wraps the instructions
116 //and supply enough operation to iterate over the instrcution sequence.
117
118 void InstrucIter::init()
119 {
120   if(!instructionPointers) {
121         unsigned i,t,j;
122         instructionPointers = new InstrucPos[range];
123         const unsigned char* ptr = addressImage->getPtrToInstruction(baseAddress);
124         for(i=0,t;i<range;t++){
125                 instructionPointers[i++] = ptr;
126                 unsigned instructionType;
127                 unsigned instructionSize = get_instruction(ptr,instructionType);
128                 for(j=1;j<instructionSize;j++){
129                         if(i < range)
130                                 instructionPointers[i++] = NULL;
131                         else{
132                                 range -= j;
133                                 instructionSize = 0;
134                                 break;
135                         }
136                 }
137                 ptr += instructionSize;
138         }
139   }
140 }
141
142 void InstrucIter::copy(const InstrucIter& ah)
143 {
144         instructionPointers = new InstrucPos[range];
145         for(unsigned i=0;i<range;i++)
146                 instructionPointers[i] = ah.instructionPointers[i];
147 }
148
149 void InstrucIter::kill()
150 {
151   delete[] instructionPointers;
152 }
153
154 void InstrucIter::getMultipleJumpTargets(BPatch_Set<Address>& result,
155                                            InstrucIter& mayUpdate)
156 {
157         Address backupAddress = currentAddress;
158         (*this)--;
159
160         /* check whether register indirect or memory indirect */
161         instruction tableInsn = getInstruction();
162         bool isAddressInJmp = true;
163         bool isWordAddr,isWordOp;
164         const unsigned char* ptr =
165                 skip_headers(tableInsn.ptr(),isWordAddr,isWordOp);
166         assert(*ptr == 0xff);
167         ptr++;
168         /* if register indirect then table address will be taken from
169            previous ins */
170         if((*ptr & 0xc7) != 0x04){
171                 isAddressInJmp = false;
172                 (*this)--;
173                 while(hasMore()){
174                         tableInsn = getInstruction();
175                         ptr = skip_headers(tableInsn.ptr(),isWordAddr,isWordOp);
176                         if(*ptr == 0x8b)
177                                 break;
178                         (*this)--;
179                 }
180         }
181         (*this)--;
182         /* now get the instruction to find the maximum switch value */
183         instruction maxSwitchInsn;
184         while(hasMore()){
185                 instruction check = getInstruction();
186                 if(check.type() & IS_JCC){
187                         (*this)--;
188                         maxSwitchInsn = getInstruction();
189                         break;
190                 }
191                 (*this)--;
192         }
193
194         unsigned maxSwitch = 0;
195         ptr = skip_headers(maxSwitchInsn.ptr(),isWordAddr,isWordOp);
196         if(*ptr == 0x3d){
197                 ptr++;
198                 if(isWordOp){
199                         maxSwitch |= *(ptr+1);
200                         maxSwitch <<= 8;
201                         maxSwitch |= *ptr;
202                 }
203                 else
204                         maxSwitch = *(const unsigned*)ptr;
205                 maxSwitch++;
206         }
207         else if(*ptr == 0x83){
208                 ptr++;
209                 if((*ptr & 0x38) == 0x38){
210                         unsigned Mod,Reg,RM;
211                         bool hasSIB = insn_hasSIB(*ptr,Mod,Reg,RM);
212                         ptr++;
213                         if(hasSIB)
214                                 ptr++;
215                         maxSwitch = *ptr;
216                         maxSwitch++;
217                 }
218         }
219         if(!maxSwitch){
220                 result += backupAddress;        
221                 return;
222         }
223
224         Address jumpTable = 0;
225         ptr = skip_headers(tableInsn.ptr(),isWordAddr,isWordOp);
226         if(isAddressInJmp || (!isAddressInJmp && (*ptr == 0x8b))){
227                 ptr++;
228                 if(((*ptr & 0xc7) == 0x04) &&
229                    ((*(ptr+1) & 0xc7) == 0x85))
230                 {
231                         ptr += 2;
232                         if(isWordAddr){
233                                 jumpTable |= *(ptr+1);
234                                 jumpTable <<= 8;
235                                 jumpTable |= *ptr;
236                         }
237                         else
238                                 jumpTable = *(const Address*)ptr;
239                 }
240         }
241
242         if(!jumpTable){
243                 result += backupAddress;        
244                 return;
245         }
246
247         for(unsigned int i=0;i<maxSwitch;i++){
248                 Address tableEntry = jumpTable + (i * sizeof(Address));
249                 if(containsAddress(tableEntry)){
250                         for(unsigned j=0;j<sizeof(Address);j++)
251                                 mayUpdate.instructionPointers[(tableEntry+j)-baseAddress] = NULL;
252                         if(mayUpdate.currentAddress == tableEntry)
253                                 mayUpdate.currentAddress += sizeof(Address);
254                 }
255                 int jumpAddress = 0;
256                 addressProc->readTextSpace((const void*)tableEntry,
257                                            sizeof(Address),
258                                            (const void*)&jumpAddress);
259                 result += jumpAddress;
260         }
261 }
262
263 bool InstrucIter::delayInstructionSupported()
264 {
265   return false;
266 }
267
268 bool InstrucIter::hasMore()
269 {
270         if((currentAddress < (baseAddress + range )) &&
271            (currentAddress >= baseAddress))
272                 return true;
273         return false;
274 }
275
276 bool InstrucIter::hasPrev()
277 {
278     if((currentAddress < (baseAddress + range )) &&
279        (currentAddress > baseAddress))
280         return true;
281     return false;
282 }
283
284 Address InstrucIter::prevAddress()
285 {
286         Address i = currentAddress-1;
287         for(;i>=baseAddress;i--)
288                 if(instructionPointers[i-baseAddress])
289                         break;
290         return i;
291 }
292
293 Address InstrucIter::nextAddress()
294 {
295         Address i = currentAddress+1;
296         for(;i<(baseAddress+range);i++)
297                 if(instructionPointers[i-baseAddress])
298                         break;
299         return i;
300 }
301
302 void InstrucIter::setCurrentAddress(Address addr)
303 {
304         currentAddress = addr;
305 }
306
307 instruction InstrucIter::getInstruction()
308 {
309         const unsigned char* ptr = 
310                         instructionPointers[currentAddress-baseAddress];
311         unsigned instructionType;
312         unsigned instructionSize = get_instruction(ptr,instructionType);
313         return instruction(ptr,instructionType,instructionSize);
314 }
315
316 instruction InstrucIter::getNextInstruction()
317 {
318         Address addr = nextAddress();
319         const unsigned char* ptr = instructionPointers[addr-baseAddress];
320         unsigned instructionType;
321         unsigned instructionSize = get_instruction(ptr,instructionType);
322         return instruction(ptr,instructionType,instructionSize);
323 }
324
325 instruction InstrucIter::getPrevInstruction()
326 {
327         Address addr = prevAddress();
328         const unsigned char* ptr = instructionPointers[addr-baseAddress];
329         unsigned instructionType;
330         unsigned instructionSize = get_instruction(ptr,instructionType);
331         return instruction(ptr,instructionType,instructionSize);
332 }
333
334 Address InstrucIter::operator++()
335 {
336         currentAddress = nextAddress();
337         return currentAddress;
338 }
339
340 Address InstrucIter::operator--()
341 {
342         currentAddress = prevAddress();
343         return currentAddress;
344 }
345
346 Address InstrucIter::operator++(int)
347 {
348         Address ret = currentAddress;
349         currentAddress = nextAddress();
350         return ret;
351 }
352
353 Address InstrucIter::operator--(int)
354 {
355         Address ret = currentAddress;
356         currentAddress = prevAddress();
357         return ret;
358 }
359
360 Address InstrucIter::operator*()
361 {
362         return currentAddress;
363 }