Added AMD64 support to test for dereferences.
[dyninst.git] / newtestsuite / src / instruction / test_instruction_read_write.C
1 /*
2  * Copyright (c) 1996-2008 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include "instruction_comp.h"
43 #include "test_lib.h"
44
45 #include "Instruction.h"
46 #include "InstructionDecoder.h"
47
48 #include <boost/assign.hpp>
49 #include <boost/iterator/indirect_iterator.hpp>
50
51 using namespace Dyninst;
52 using namespace InstructionAPI;
53 using namespace boost;
54 using namespace std;
55
56 class test_instruction_read_write_Mutator : public InstructionMutator {
57 public:
58    test_instruction_read_write_Mutator() { };
59    virtual test_results_t executeTest();
60 };
61
62 extern "C" DLLEXPORT TestMutator* test_instruction_read_write_factory()
63 {
64    return new test_instruction_read_write_Mutator();
65 }
66
67 template <typename T>
68 struct shared_ptr_lt
69 {
70   bool operator()(const T& lhs, const T& rhs)
71   {
72     // Non-nulls precede nulls
73     if(rhs.get() == NULL)
74     {
75       return lhs.get() != NULL;
76     }
77     if(lhs.get() == NULL)
78       return false;
79     // Otherwise, dereference and compare
80     return *lhs < *rhs;
81   }
82   
83 };
84
85
86 typedef std::set<RegisterAST::Ptr, shared_ptr_lt<RegisterAST::Ptr> > registerSet;
87
88 test_results_t failure_accumulator(test_results_t lhs, test_results_t rhs)
89 {
90   if(lhs == FAILED || rhs == FAILED)
91   {
92     return FAILED;
93   }
94   return PASSED;
95 }
96
97 test_results_t verify_read_write_sets(const Instruction& i, const registerSet& expectedRead,
98                                       const registerSet& expectedWritten)
99 {
100   set<RegisterAST::Ptr> actualRead_uo;
101   set<RegisterAST::Ptr> actualWritten_uo;
102   i.getWriteSet(actualWritten_uo);
103   i.getReadSet(actualRead_uo);
104   registerSet actualRead, actualWritten;
105   copy(actualRead_uo.begin(), actualRead_uo.end(), inserter(actualRead, actualRead.begin()));
106   copy(actualWritten_uo.begin(), actualWritten_uo.end(), inserter(actualWritten, actualWritten.begin()));
107   
108   if(actualRead.size() != expectedRead.size() ||
109      actualWritten.size() != expectedWritten.size())
110   {
111     logerror("FAILED: instruction %s, expected %d regs read, %d regs written, actual %d read, %d written\n",
112              i.format().c_str(), expectedRead.size(), expectedWritten.size(), actualRead.size(), actualWritten.size());
113     return FAILED;
114   }
115   registerSet::const_iterator safety;
116   for(safety = expectedRead.begin();
117       safety != expectedRead.end();
118       ++safety)
119   {
120     if(!(*safety))
121     {
122       logerror("ERROR: null shared pointer in expectedRead for instruction %s\n", i.format().c_str());
123       return FAILED;
124     }
125     
126   }
127   for(safety = actualRead.begin();
128       safety != actualRead.end();
129       ++safety)
130   {
131     if(!(*safety))
132     {
133       logerror("ERROR: null shared pointer in actualRead for instruction %s\n", i.format().c_str());
134       return FAILED;
135     }
136     
137   }
138   
139   if(equal(make_indirect_iterator(actualRead.begin()), 
140            make_indirect_iterator(actualRead.end()), 
141            make_indirect_iterator(expectedRead.begin())))
142   {
143     for(registerSet::const_iterator it = expectedRead.begin();
144         it != expectedRead.end();
145         ++it)
146     {
147       if(!i.isRead(*it))
148       {
149         logerror("%s was in read set, but isRead(%s) was false\n", (*it)->format().c_str(), (*it)->format().c_str());
150         return FAILED;
151       }
152     }
153   }
154   else
155   {
156     logerror("Read set for instruction %s not as expected\n", i.format().c_str());
157     return FAILED;
158   }
159   
160   for(safety = expectedWritten.begin();
161       safety != expectedWritten.end();
162       ++safety)
163   {
164     if(!(*safety))
165     {
166       logerror("ERROR: null shared pointer in expectedWritten for instruction %s\n", i.format().c_str());
167       return FAILED;
168     }
169     
170   }
171   for(safety = actualWritten.begin();
172       safety != actualWritten.end();
173       ++safety)
174   {
175     if(!(*safety))
176     {
177       logerror("ERROR: null shared pointer in actualWritten for instruction %s\n", i.format().c_str());
178       return FAILED;
179     }
180     
181   }
182   if(equal(make_indirect_iterator(actualWritten.begin()), 
183            make_indirect_iterator(actualWritten.end()), 
184            make_indirect_iterator(expectedWritten.begin())))
185   {
186     for(registerSet::const_iterator it = expectedWritten.begin();
187         it != expectedWritten.end();
188         ++it)
189     {
190       if(!i.isWritten(*it))
191       {
192         logerror("%s was in write set, but isWritten(%s) was false\n", (*it)->format().c_str(), (*it)->format().c_str());
193         return FAILED;
194       }
195     }
196   }
197   else
198   {
199     logerror("Write set for instruction %s not as expected\n", i.format().c_str());
200     return FAILED;
201   }
202   return PASSED;
203 }
204
205
206 test_results_t test_instruction_read_write_Mutator::executeTest()
207 {
208   const unsigned char buffer[] = 
209   {
210     0x05, 0xef, 0xbe, 0xad, 0xde, // INC eAX
211     0x50, // PUSH rAX
212     0x74, 0x10, // JZ +0x10(8)
213     0xE8, 0x20, 0x00, 0x00, 0x00, // CALL +0x20(32)
214     0xF8, // CLC
215     0x04, 0x30, // ADD AL, 0x30(8)
216     0xc7, 0x45, 0xfc, 0x01, 0x00, 0x00, 0x00, // MOVL 0x01, -0x4(EBP)
217         0x88, 0x55, 0xcc // MOVB DL, -0x34(EBP)
218   };
219   unsigned int size = 26;
220   unsigned int expectedInsns = 9;
221   InstructionDecoder d(buffer, size);
222   std::vector<Instruction> decodedInsns;
223   Instruction i;
224   do
225   {
226     i = d.decode();
227     decodedInsns.push_back(i);
228   }
229   while(i.isValid());
230   if(decodedInsns.size() != expectedInsns) // six valid, one invalid
231   {
232     logerror("FAILED: Expected %d instructions, decoded %d\n", expectedInsns, decodedInsns.size());
233     for(std::vector<Instruction>::iterator curInsn = decodedInsns.begin();
234         curInsn != decodedInsns.end();
235         ++curInsn)
236     {
237       logerror("\t%s\n", curInsn->format().c_str());
238     }
239     
240     return FAILED;
241   }
242   if(decodedInsns.back().isValid())
243   {
244     logerror("FAILED: Expected instructions to end with an invalid instruction, but they didn't");
245     return FAILED;
246   }
247   RegisterAST::Ptr eax(new RegisterAST(r_eAX));
248   RegisterAST::Ptr adjust(new RegisterAST(r_AF));
249   RegisterAST::Ptr zero(new RegisterAST(r_ZF));
250   RegisterAST::Ptr overflow(new RegisterAST(r_OF));
251   RegisterAST::Ptr parity(new RegisterAST(r_PF));
252   RegisterAST::Ptr sign(new RegisterAST(r_SF));
253   RegisterAST::Ptr carry(new RegisterAST(r_CF));
254   registerSet expectedRead, expectedWritten;
255   expectedRead.insert(expectedRead.begin(), eax);
256   expectedWritten = list_of(eax)(adjust)(zero)(overflow)(parity)(sign)(carry);
257   
258   test_results_t retVal = PASSED;
259   
260   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[0], expectedRead, expectedWritten));
261
262   RegisterAST::Ptr rax(new RegisterAST(r_rAX));
263   RegisterAST::Ptr esp(new RegisterAST(r_eSP));
264   expectedRead.clear();
265   expectedWritten.clear();
266   expectedRead = list_of(esp)(rax);
267   expectedWritten = list_of(esp);
268   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[1], expectedRead, expectedWritten));
269
270   expectedRead.clear();
271   expectedWritten.clear();
272   RegisterAST::Ptr ip(new RegisterAST(r_EIP));
273   // Jccs are all documented as "may read zero, sign, carry, parity, overflow", so a JZ comes back as reading all
274   // of these flags
275   expectedRead = list_of(zero)(sign)(carry)(parity)(overflow)(ip);
276   expectedWritten = list_of(ip);
277   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[2], expectedRead, expectedWritten));
278   
279   expectedRead.clear();
280   expectedWritten.clear();
281   expectedRead = list_of(ip);
282   expectedWritten = list_of(esp)(ip);
283   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[3], expectedRead, expectedWritten));
284
285   expectedRead.clear();
286   expectedWritten.clear();
287   expectedWritten = list_of(carry);
288   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[4], expectedRead, expectedWritten));
289
290   expectedRead.clear();
291   expectedWritten.clear();
292   RegisterAST::Ptr al(new RegisterAST(r_AL));
293   expectedRead = list_of(al);
294   expectedWritten = list_of(al)(zero)(carry)(sign)(overflow)(parity)(adjust);
295   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[5], expectedRead, expectedWritten));
296
297   RegisterAST::Ptr ebp(new RegisterAST(r_EBP));
298   expectedRead.clear();
299   expectedWritten.clear();
300   expectedRead = list_of(ebp);
301   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[6], expectedRead, expectedWritten));
302   
303   RegisterAST::Ptr dl(new RegisterAST(r_DL));
304   expectedRead.clear();
305   expectedWritten.clear();
306 #if defined(arch_x86_64_test)
307   RegisterAST::Ptr rbp(new RegisterAST(r_RBP));
308   expectedRead = list_of(rbp)(dl);
309 #else
310   expectedRead = list_of(ebp)(dl);
311 #endif
312   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[7], expectedRead, expectedWritten));
313   return retVal;
314 }
315