Calculation of immediate operand in logical immediate instructions was done wrong...
[dyninst.git] / instructionAPI / h / BinaryFunction.h
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #if !defined(BINARYFUNCTION_H)
32 #define BINARYFUNCTION_H
33
34 #include "Expression.h"
35 #include "Register.h"
36 #include "Result.h"
37 #include <sstream>
38
39 #if defined(_MSC_VER)
40 #pragma warning(disable:4251)
41 #endif
42
43 namespace Dyninst
44 {
45   namespace InstructionAPI
46   {
47     using std::vector;
48
49     /// A %BinaryFunction object represents a function that can combine two %Expressions and produce another %ValueComputation.
50     ///
51     /// For the purposes of representing a single operand of an instruction, the %BinaryFunctions of interest are addition and multiplication of
52     /// integer values; this allows a %Expression to represent all addressing modes on the architectures currently
53     /// supported by the %Instruction API.
54     class INSTRUCTION_EXPORT BinaryFunction : public Expression
55     {
56                 public:
57                         class INSTRUCTION_EXPORT funcT
58                         {
59                                 public:
60                                         funcT(std::string name) : m_name(name) 
61                                         {
62                                         }
63                                         
64                                         virtual ~funcT()
65                                         {
66                                         }
67         
68                                         virtual Result operator()(const Result& arg1, const Result& arg2) const = 0;
69                                         
70                                         std::string format() const 
71                                         {
72                                                 return m_name;
73                                         }
74                                         
75                                         typedef boost::shared_ptr<funcT> Ptr;
76         
77                                         private:
78                                                 std::string m_name;
79                         };
80       
81       
82                         class INSTRUCTION_EXPORT addResult : public funcT
83                         {
84                                 public:
85                                         addResult() : funcT("+") 
86                                         {
87                                         }
88         
89                                         virtual ~addResult()
90                                         {
91                                         }
92                                         
93                                         Result operator()(const Result& arg1, const Result& arg2) const
94                                         {
95                                                 return arg1 + arg2;
96                                         }
97                         };
98                         
99                         class INSTRUCTION_EXPORT multResult : public funcT
100                         {
101                                 public:
102                                         multResult() : funcT("*")
103                                         {
104                                         }
105                                         
106                                         virtual ~multResult()
107                                         {
108                                         }
109         
110                                         Result operator()(const Result& arg1, const Result& arg2) const
111                                         {
112                                                 return arg1 * arg2;
113                                         }
114                         };
115       
116                         class INSTRUCTION_EXPORT leftShiftResult : public funcT
117                         {
118                                 public:
119                                         leftShiftResult() : funcT("<<")
120                                         {
121                                         }
122         
123                                         virtual ~leftShiftResult()
124                                         {
125                                         }
126         
127                                         Result operator()(const Result& arg1, const Result& arg2) const
128                                         {
129                                                 return arg1 << arg2;
130                                         }
131                         };
132                         
133                         class INSTRUCTION_EXPORT rightArithmeticShiftResult : public funcT
134                         {
135                                 public:
136                                         rightArithmeticShiftResult() : funcT("ASR")
137                                         {
138                                         }
139         
140                                         virtual ~rightArithmeticShiftResult()
141                                         {
142                                         }
143         
144                                         Result operator()(const Result& arg1, const Result& arg2) const
145                                         {
146                                                 return arg1 >> arg2;
147                                         }
148                         };
149                         
150                         class INSTRUCTION_EXPORT andResult : public funcT
151                         {
152                                 public:
153                                         andResult() : funcT("&")
154                                         {
155                                         }
156         
157                                         virtual ~andResult()
158                                         {
159                                         }
160         
161                                         Result operator()(const Result& arg1, const Result& arg2) const
162                                         {
163                                                 return arg1 & arg2;
164                                         }
165                         };
166                         
167                         class INSTRUCTION_EXPORT orResult : public funcT
168                         {
169                                 public:
170                                         orResult() : funcT("|")
171                                         {
172                                         }
173         
174                                         virtual ~orResult()
175                                         {
176                                         }
177         
178                                         Result operator()(const Result& arg1, const Result& arg2) const
179                                         {
180                                                 return arg1 | arg2;
181                                         }
182                         };
183                         
184                         class INSTRUCTION_EXPORT rightLogicalShiftResult : public funcT
185                         {
186                                 public:
187                                         rightLogicalShiftResult() : funcT("LSR")
188                                         {
189                                         }
190         
191                                         virtual ~rightLogicalShiftResult()
192                                         {
193                                         }
194         
195                                         Result operator()(const Result& arg1, const Result& arg2) const
196                                         {
197                                                 Result mask;
198                                                 switch(arg1.type)
199                                                 {
200                                                         case s8:
201                                                         case u8:mask = Result(u8, ~0);
202                                                                         break;
203                                                         case s16:
204                                                         case u16:mask = Result(u16, ~0);
205                                                                         break;
206                                                         case s32:
207                                                         case u32:mask = Result(u32, ~0);
208                                                                         break;
209                                                         case s48:
210                                                         case u48:mask = Result(u48, ~0);
211                                                                         break;
212                                                         case s64:
213                                                         case u64:mask = Result(u64, ~0);
214                                                                         break;
215                                                         default: assert(!"not valid");
216                                                         
217                                                 }
218                                                 
219                                                 return (arg1 >> arg2) & (mask >> arg2);
220                                         }
221                         };
222                         
223                         class INSTRUCTION_EXPORT rightRotateResult : public funcT
224                         {
225                                 public:
226                                         rightRotateResult() : funcT("ROR")
227                                         {
228                                         }
229         
230                                         virtual ~rightRotateResult()
231                                         {
232                                         }
233         
234                                         Result operator()(const Result& arg1, const Result& arg2) const
235                                         {
236                                                 Result leftShiftAmount;
237                                                 uint64_t arg2val = arg2.convert<Result_type2type<u64>::type >();
238                                                                                 
239                                                 switch(arg1.type)
240                                                 {
241                                                         case s8:
242                                                         case u8:arg2val %= 8;
243                                                                         leftShiftAmount = Result(arg2.type, 8 - arg2val);
244                                                                         break;
245                                                         case s16:
246                                                         case u16:arg2val %= 16;
247                                                                          leftShiftAmount = Result(arg2.type, 16- arg2val);
248                                                                          break;
249                                                         case s32:
250                                                         case u32:arg2val %= 32;
251                                                                          leftShiftAmount = Result(arg2.type, 32- arg2val);
252                                                                          break;
253                                                         case s48:
254                                                         case u48:arg2val %= 48;
255                                                                          leftShiftAmount = Result(arg2.type, 48- arg2val);
256                                                                          break;
257                                                         case s64:
258                                                         case u64:arg2val %= 64;
259                                                                          leftShiftAmount = Result(arg2.type, 64- arg2val);
260                                                                          break;
261                                                         default: assert(!"not valid");
262                                                 }
263                                                 
264                                                 Result one(u64, 1);
265                                                 Result rot = arg1 & (Result(u64, (1<<arg2val) - 1));
266                                                 
267                                                 rightLogicalShiftResult lhsRightShift;
268                                                 Result arg2mod = Result(arg2.type, arg2val);
269                                                 return lhsRightShift(arg1, arg2mod) | (rot << leftShiftAmount);
270                                         }
271                         };
272                         
273                         /// \param arg1 first input to function
274                         /// \param arg2 second input to function
275                         /// \param result_type type of the function's result
276                         /// \param func implementation of the function
277                         ///
278                         /// The constructor for a %BinaryFunction may take a reference-counted pointer or a plain C++ pointer to each of the
279                         /// child Expressions that represent its arguments.  Since the reference-counted implementation requires explicit construction,
280                         /// we provide overloads for all four combinations of plain and reference-counted pointers.  Note that regardless of which constructor
281                         /// is used, the pointers \c arg1 and \c arg2 become owned by the %BinaryFunction being constructed, and should not be deleted.
282                         /// They will be cleaned up when the %BinaryFunction object is destroyed.
283                         ///
284                         /// The \c func parameter is a binary functor on two Results.  It should be derived from \c %funcT.  \c addResult and
285                         /// \c multResult, which respectively add and multiply two %Results, are provided as part of the InstructionAPI, 
286                         /// as they are necessary for representing address calculations.  Other \c %funcTs may be implemented by the user if desired.
287                         /// %funcTs have names associated with them for output and debugging purposes.  The addition and multiplication functors
288                         /// provided with the %Instruction API are named "+" and "*", respectively.
289                         BinaryFunction(Expression::Ptr arg1, Expression::Ptr arg2, Result_Type result_type,
290                      funcT::Ptr func) : 
291                           Expression(result_type), m_arg1(arg1), m_arg2(arg2), m_funcPtr(func)
292                         {
293                         }
294               
295                         virtual ~BinaryFunction() 
296                         {
297                         }
298
299                         /// The %BinaryFunction version of \c eval allows the \c eval mechanism to handle complex addressing modes.  Like all of the %ValueComputation
300                         /// implementations, a %BinaryFunction's \c eval will return the result of evaluating the expression it represents
301                         /// if possible, or an empty %Result otherwise.
302                         /// A %BinaryFunction may have arguments that can be evaluated, or arguments that cannot.
303                         /// Additionally, it may have a real function pointer, or it may have a null function pointer.
304                         /// If the arguments can be evaluated and the function pointer is real, a result other than an empty %Result is guaranteed to be
305                         /// returned.  This result is cached after its initial calculation; the caching mechanism also allows
306                         /// outside information to override the results of the %BinaryFunction's internal computation.
307                         /// If the cached result exists, it is guaranteed to be returned even if the arguments or the function
308                         /// are not evaluable.
309                         virtual const Result& eval() const;
310     
311                         /// The children of a %BinaryFunction are its two arguments.
312                         /// \param children Appends the children of this %BinaryFunction to \c children.
313                         virtual void getChildren(vector<InstructionAST::Ptr>& children) const
314                         {
315                                 children.push_back(m_arg1);
316                                 children.push_back(m_arg2);
317                                 
318                                 return;
319                         }
320       
321                         virtual void getChildren(vector<Expression::Ptr>& children) const
322                         {
323                                 children.push_back(m_arg1);
324                                 children.push_back(m_arg2);
325                                 
326                                 return;
327                         }
328       
329                     /// The use set of a %BinaryFunction is the union of the use sets of its children.
330                     /// \param uses Appends the use set of this %BinaryFunction to \c uses.
331                     virtual void getUses(set<InstructionAST::Ptr>& uses)
332                     {
333                                 m_arg1->getUses(uses);
334                                 m_arg2->getUses(uses);
335                                 
336                                 return;
337                         }
338                         
339                         /// \c isUsed returns true if \c findMe is an argument of this %BinaryFunction,
340                         /// or if it is in the use set of either argument.
341                         virtual bool isUsed(InstructionAST::Ptr findMe) const
342                         {
343                                 return m_arg1->isUsed(findMe) || m_arg2->isUsed(findMe) 
344                                                                         || (*m_arg1 == *findMe) || (*m_arg2 == *findMe) || (*findMe == *this);
345                         }
346                         
347                         virtual std::string format(formatStyle how) const
348                         {
349                                 std::stringstream retVal;
350                                 if(how == memoryAccessStyle)
351                                 {
352                                         retVal << m_arg2->format() << "(" << m_arg1->format() << ")";
353                                 }
354                                 else
355                                 {
356                                         retVal << m_arg1->format() << " " << m_funcPtr->format() << " " << m_arg2->format();
357                                 }
358                                 
359                                 return retVal.str();
360                         }
361                     
362                     virtual bool bind(Expression* expr, const Result& value);
363                         virtual void apply(Visitor* v);
364                         
365                         bool isAdd() const;
366                         bool isMultiply() const;
367                         bool isLeftShift() const;
368                         bool isRightArithmeticShift() const;
369                         bool isAndResult() const;
370                         bool isOrResult() const;
371                         bool isRightLogicalShift() const;
372                         bool isRightRotate() const;
373                         
374                 protected:
375                         virtual bool isStrictEqual(const InstructionAST& rhs) const
376                         {
377                                 const BinaryFunction& other(dynamic_cast<const BinaryFunction&>(rhs));
378                                 if(*(other.m_arg1) == *m_arg1 &&
379                     (*other.m_arg2) == *m_arg2)
380                     return true;
381                     
382                                 if(*(other.m_arg1) == *m_arg2 &&
383                                         (*other.m_arg2) == *m_arg1) return true;
384                                 
385                                 return false;
386                         }
387   
388                 private:
389                   Expression::Ptr m_arg1;
390                   Expression::Ptr m_arg2;
391                   funcT::Ptr m_funcPtr;
392       
393                 };
394         };
395 };
396
397
398 #endif // !defined(BINARYFUNCTION_H)