Update copyright to LGPL on all files
[dyninst.git] / instructionAPI / src / Operation.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 #include "Operation.h"
33 #include "arch-x86.h"
34 #include "entryIDs-IA32.h"
35 #include "../../common/h/Singleton.h"
36 #include "Register.h"
37 #include <map>
38 #include <boost/assign/list_of.hpp>
39 #include "../../common/h/singleton_object_pool.h"
40
41 using namespace boost::assign;
42
43 namespace Dyninst
44 {
45   namespace InstructionAPI
46   {
47     RegisterAST::Ptr makeRegFromID(IA32Regs regID)
48     {
49       return make_shared(singleton_object_pool<RegisterAST>::construct(regID));
50     }
51
52     Operation::Operation(ia32_entry* e, ia32_prefixes* p, ia32_locations* l) :
53       doneOtherSetup(false), doneFlagsSetup(false)
54     
55     {
56       operationID = e->getID(l);
57       if(p && p->getCount())
58       {
59         if (p->getPrefix(0) == PREFIX_REP || p->getPrefix(0) == PREFIX_REPNZ)
60         {
61             otherRead.insert(makeRegFromID(r_DF));
62         }
63         int segPrefix = p->getPrefix(1);
64         switch(segPrefix)
65         {
66             case PREFIX_SEGCS:
67                 otherRead.insert(makeRegFromID(r_CS));
68                 break;
69             case PREFIX_SEGDS:
70                 otherRead.insert(makeRegFromID(r_DS));
71                 break;
72             case PREFIX_SEGES:
73                 otherRead.insert(makeRegFromID(r_ES));
74                 break;
75             case PREFIX_SEGFS:
76                 otherRead.insert(makeRegFromID(r_FS));
77                 break;
78             case PREFIX_SEGGS:
79                 otherRead.insert(makeRegFromID(r_GS));
80                 break;
81             case PREFIX_SEGSS:
82                 otherRead.insert(makeRegFromID(r_SS));
83                 break;
84         }
85       }
86     }
87
88     Operation::Operation(const Operation& o)
89     {
90       otherRead = o.otherRead;
91       otherWritten = o.otherWritten;
92       otherEffAddrsRead = o.otherEffAddrsRead;
93       otherEffAddrsWritten = o.otherEffAddrsWritten;
94       operationID = o.operationID;
95       doneOtherSetup = o.doneOtherSetup;
96       doneFlagsSetup = o.doneFlagsSetup;
97       
98     }
99     const Operation& Operation::operator=(const Operation& o)
100     {
101       otherRead = o.otherRead;
102       otherWritten = o.otherWritten;
103       otherEffAddrsRead = o.otherEffAddrsRead;
104       otherEffAddrsWritten = o.otherEffAddrsWritten;
105       operationID = o.operationID;
106       doneOtherSetup = o.doneOtherSetup;
107       doneFlagsSetup = o.doneFlagsSetup;
108       return *this;
109     }
110     Operation::Operation()
111     {
112       operationID = e_No_Entry;
113     }
114     
115     const Operation::registerSet&  Operation::implicitReads() const
116     {
117       if(!doneOtherSetup) SetUpNonOperandData(true);
118       
119       return otherRead;
120     }
121     const Operation::registerSet&  Operation::implicitWrites() const
122     {
123       if(!doneOtherSetup) SetUpNonOperandData(true);
124
125       return otherWritten;
126     }
127     bool Operation::isRead(Expression::Ptr candidate) const
128     {
129       if(!doneOtherSetup)
130       {
131         SetUpNonOperandData(candidate->isFlag());
132       }
133       for(registerSet::const_iterator r = otherRead.begin();
134           r != otherRead.end();
135           ++r)
136       {
137         if(*candidate == *(*r))
138         {
139           return true;
140         }
141       }
142       for(VCSet::const_iterator e = otherEffAddrsRead.begin();
143           e != otherEffAddrsRead.end();
144           ++e)
145       {
146         if(*candidate == *(*e))
147         {
148           return true;
149         }
150       }
151       return false;
152     }
153     const Operation::VCSet& Operation::getImplicitMemReads() const
154     {
155       if(!doneOtherSetup) SetUpNonOperandData(true);
156       return otherEffAddrsRead;
157     }
158     const Operation::VCSet& Operation::getImplicitMemWrites() const
159     {
160       if(!doneOtherSetup) SetUpNonOperandData(true);
161       return otherEffAddrsWritten;
162     }
163
164     bool Operation::isWritten(Expression::Ptr candidate) const
165     {
166       if(!doneOtherSetup)
167       {
168         SetUpNonOperandData(candidate->isFlag());
169       }
170       for(registerSet::const_iterator r = otherWritten.begin();
171           r != otherWritten.end();
172           ++r)
173       {
174         if(*candidate == *(*r))
175         {
176           return true;
177         }
178       }
179       for(VCSet::const_iterator e = otherEffAddrsWritten.begin();
180           e != otherEffAddrsWritten.end();
181           ++e)
182       {
183         if(*candidate == *(*e))
184         {
185           return true;
186         }
187       }
188       return false;
189     }
190           
191     std::string Operation::format() const
192     {
193       dyn_hash_map<entryID, std::string>::const_iterator found = entryNames_IAPI.find(operationID);
194       if(found != entryNames_IAPI.end())
195         return found->second;
196       return "[INVALID]";
197     }
198
199     entryID Operation::getID() const
200     {
201       return operationID;
202     }
203
204     struct OperationMaps
205     {
206     public:
207       OperationMaps()
208       {
209         thePC.insert(RegisterAST::Ptr(new RegisterAST(RegisterAST::makePC())));
210         pcAndSP.insert(RegisterAST::Ptr(new RegisterAST(RegisterAST::makePC())));
211         pcAndSP.insert(RegisterAST::Ptr(new RegisterAST(r_eSP)));
212         
213         stackPointer.insert(RegisterAST::Ptr(new RegisterAST(r_eSP)));
214         stackPointerAsExpr.insert(Expression::Ptr(new RegisterAST(r_eSP)));
215         framePointer.insert(RegisterAST::Ptr(new RegisterAST(r_eBP)));
216         spAndBP.insert(RegisterAST::Ptr(new RegisterAST(r_eSP)));
217         spAndBP.insert(RegisterAST::Ptr(new RegisterAST(r_eBP)));
218         
219         nonOperandRegisterReads = 
220         map_list_of
221         (e_call, pcAndSP)
222         (e_ret_near, stackPointer)
223         (e_ret_far, stackPointer)
224         (e_leave, framePointer)
225         (e_enter, spAndBP);
226         
227         nonOperandRegisterWrites = 
228         map_list_of
229         (e_call, pcAndSP)
230         (e_ret_near, pcAndSP)
231         (e_ret_far, pcAndSP)
232         (e_leave, spAndBP)
233         (e_enter, spAndBP)
234         (e_loop, thePC)
235         (e_loope, thePC)
236         (e_loopn, thePC)
237         (e_jb, thePC)
238         (e_jb_jnaej_j, thePC)
239         (e_jbe, thePC)
240         (e_jcxz_jec, thePC)
241         (e_jl, thePC)
242         (e_jle, thePC)
243         (e_jmp, thePC)
244         (e_jnb, thePC)
245         (e_jnb_jae_j, thePC)
246         (e_jnbe, thePC)
247         (e_jnl, thePC)
248         (e_jnle, thePC)
249         (e_jno, thePC)
250         (e_jnp, thePC)
251         (e_jns, thePC)
252         (e_jnz, thePC)
253         (e_jo, thePC)
254         (e_jp, thePC)
255         (e_js, thePC)
256         (e_jz, thePC);
257         nonOperandMemoryReads[e_pop] = stackPointerAsExpr;
258         nonOperandMemoryWrites[e_push] = stackPointerAsExpr;
259         nonOperandMemoryWrites[e_call] = stackPointerAsExpr;
260         nonOperandMemoryReads[e_ret_near] = stackPointerAsExpr;
261         nonOperandMemoryReads[e_ret_far] = stackPointerAsExpr;
262         nonOperandMemoryReads[e_leave] = stackPointerAsExpr;
263       }
264       Operation::registerSet thePC;
265       Operation::registerSet pcAndSP;
266       Operation::registerSet stackPointer;
267       Operation::VCSet stackPointerAsExpr;
268       Operation::registerSet framePointer;
269       Operation::registerSet spAndBP;
270       dyn_hash_map<entryID, Operation::registerSet > nonOperandRegisterReads;
271       dyn_hash_map<entryID, Operation::registerSet > nonOperandRegisterWrites;
272
273       dyn_hash_map<entryID, Operation::VCSet > nonOperandMemoryReads;
274       dyn_hash_map<entryID, Operation::VCSet > nonOperandMemoryWrites;
275     };
276     OperationMaps op_data;
277     void Operation::SetUpNonOperandData(bool needFlags) const
278     {
279       
280       dyn_hash_map<entryID, registerSet >::const_iterator foundRegs;
281       foundRegs = op_data.nonOperandRegisterReads.find(operationID);
282       if(foundRegs != op_data.nonOperandRegisterReads.end())
283       {
284         otherRead = foundRegs->second;
285         //std::copy(foundRegs->second.begin(), foundRegs->second.end(),
286         //        inserter(otherRead, otherRead.begin()));
287       }
288       foundRegs = op_data.nonOperandRegisterWrites.find(operationID);
289       if(foundRegs != op_data.nonOperandRegisterWrites.end())
290       {
291         otherWritten = foundRegs->second;
292         //std::copy(foundRegs->second.begin(), foundRegs->second.end(),
293         //        inserter(otherWritten, otherWritten.begin()));
294       }
295       dyn_hash_map<entryID, VCSet >::const_iterator foundMem;
296       foundMem = op_data.nonOperandMemoryReads.find(operationID);
297       if(foundMem != op_data.nonOperandMemoryReads.end())
298       {
299         otherEffAddrsRead = foundMem->second;
300         //std::copy(foundMem->second.begin(), foundMem->second.end(),
301         //        inserter(otherEffAddrsRead, otherEffAddrsRead.begin()));
302       }
303       foundMem = op_data.nonOperandMemoryWrites.find(operationID);
304       if(foundMem != op_data.nonOperandMemoryWrites.end())
305       {
306         otherEffAddrsWritten = foundMem->second;
307         //std::copy(foundMem->second.begin(), foundMem->second.end(),
308         //        inserter(otherEffAddrsWritten, otherEffAddrsWritten.begin()));
309       }
310       
311       if(needFlags && !doneFlagsSetup)
312       {
313         
314         dyn_hash_map<entryID, flagInfo>::const_iterator found = ia32_instruction::getFlagTable().find(operationID);
315         if(found != ia32_instruction::getFlagTable().end())
316         {
317           for(unsigned i = 0; i < found->second.readFlags.size(); i++)
318           {
319             otherRead.insert(makeRegFromID(found->second.readFlags[i]));
320           }
321           for(unsigned j = 0; j < found->second.writtenFlags.size(); j++)
322           {
323             otherWritten.insert(makeRegFromID(found->second.writtenFlags[j]));
324           }
325         }
326         doneFlagsSetup = true;
327       }
328       doneOtherSetup = true;
329     }
330   };
331
332 };