Remove old testsuite
[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 <dyn_detail/boost/assign/list_of.hpp>
49 //#include <dyn_detail/boost/iterator/indirect_iterator.hpp>
50 #include <boost/assign/list_of.hpp>
51 #include <boost/iterator/indirect_iterator.hpp>
52
53 using namespace Dyninst;
54 using namespace InstructionAPI;
55 using namespace boost;
56 using namespace boost::assign;
57
58 using namespace std;
59
60 class test_instruction_read_write_Mutator : public InstructionMutator {
61 public:
62    test_instruction_read_write_Mutator() { };
63    virtual test_results_t executeTest();
64 };
65
66 extern "C" DLLEXPORT TestMutator* test_instruction_read_write_factory()
67 {
68    return new test_instruction_read_write_Mutator();
69 }
70
71 template <typename T>
72 struct shared_ptr_lt
73 {
74   bool operator()(const T& lhs, const T& rhs)
75   {
76     // Non-nulls precede nulls
77     if(rhs.get() == NULL)
78     {
79       return lhs.get() != NULL;
80     }
81     if(lhs.get() == NULL)
82       return false;
83     // Otherwise, dereference and compare
84     return *lhs < *rhs;
85   }
86   
87 };
88
89
90 typedef std::set<RegisterAST::Ptr, shared_ptr_lt<RegisterAST::Ptr> > registerSet;
91
92 test_results_t failure_accumulator(test_results_t lhs, test_results_t rhs)
93 {
94   if(lhs == FAILED || rhs == FAILED)
95   {
96     return FAILED;
97   }
98   return PASSED;
99 }
100
101 test_results_t verify_read_write_sets(const Instruction& i, const registerSet& expectedRead,
102                                       const registerSet& expectedWritten)
103 {
104   set<RegisterAST::Ptr> actualRead_uo;
105   set<RegisterAST::Ptr> actualWritten_uo;
106   i.getWriteSet(actualWritten_uo);
107   i.getReadSet(actualRead_uo);
108   registerSet actualRead, actualWritten;
109   copy(actualRead_uo.begin(), actualRead_uo.end(), inserter(actualRead, actualRead.begin()));
110   copy(actualWritten_uo.begin(), actualWritten_uo.end(), inserter(actualWritten, actualWritten.begin()));
111   
112   if(actualRead.size() != expectedRead.size() ||
113      actualWritten.size() != expectedWritten.size())
114   {
115     logerror("FAILED: instruction %s, expected %d regs read, %d regs written, actual %d read, %d written\n",
116              i.format().c_str(), expectedRead.size(), expectedWritten.size(), actualRead.size(), actualWritten.size());
117     logerror("Expected read:\n");
118     for (registerSet::iterator iter = expectedRead.begin(); iter != expectedRead.end(); iter++) {
119         logerror("\t%s\n", (*iter)->format().c_str());
120     }
121     logerror("Expected written:\n");
122     for (registerSet::iterator iter = expectedWritten.begin(); iter != expectedWritten.end(); iter++) {
123         logerror("\t%s\n", (*iter)->format().c_str());
124     }
125     logerror("Actual read:\n");
126     for (registerSet::iterator iter = actualRead.begin(); iter != actualRead.end(); iter++) {
127         logerror("\t%s\n", (*iter)->format().c_str());
128     }
129     logerror("Actual written:\n");
130     for (registerSet::iterator iter = actualWritten.begin(); iter != actualWritten.end(); iter++) {
131         logerror("\t%s\n", (*iter)->format().c_str());
132     }
133
134     return FAILED;
135   }
136   registerSet::const_iterator safety;
137   for(safety = expectedRead.begin();
138       safety != expectedRead.end();
139       ++safety)
140   {
141     if(!(*safety))
142     {
143       logerror("ERROR: null shared pointer in expectedRead for instruction %s\n", i.format().c_str());
144       return FAILED;
145     }
146     
147   }
148   for(safety = actualRead.begin();
149       safety != actualRead.end();
150       ++safety)
151   {
152     if(!(*safety))
153     {
154       logerror("ERROR: null shared pointer in actualRead for instruction %s\n", i.format().c_str());
155       return FAILED;
156     }
157     
158   }
159   
160   if(equal(make_indirect_iterator(actualRead.begin()), 
161            make_indirect_iterator(actualRead.end()), 
162            make_indirect_iterator(expectedRead.begin())))
163   {
164     for(registerSet::const_iterator it = expectedRead.begin();
165         it != expectedRead.end();
166         ++it)
167     {
168       if(!i.isRead(*it))
169       {
170         logerror("%s was in read set, but isRead(%s) was false\n", (*it)->format().c_str(), (*it)->format().c_str());
171         return FAILED;
172       }
173     }
174   }
175   else
176   {
177     logerror("Read set for instruction %s not as expected\n", i.format().c_str());
178     return FAILED;
179   }
180   
181   for(safety = expectedWritten.begin();
182       safety != expectedWritten.end();
183       ++safety)
184   {
185     if(!(*safety))
186     {
187       logerror("ERROR: null shared pointer in expectedWritten for instruction %s\n", i.format().c_str());
188       return FAILED;
189     }
190     
191   }
192   for(safety = actualWritten.begin();
193       safety != actualWritten.end();
194       ++safety)
195   {
196     if(!(*safety))
197     {
198       logerror("ERROR: null shared pointer in actualWritten for instruction %s\n", i.format().c_str());
199       return FAILED;
200     }
201     
202   }
203   if(equal(make_indirect_iterator(actualWritten.begin()), 
204            make_indirect_iterator(actualWritten.end()), 
205            make_indirect_iterator(expectedWritten.begin())))
206   {
207     for(registerSet::const_iterator it = expectedWritten.begin();
208         it != expectedWritten.end();
209         ++it)
210     {
211       if(!i.isWritten(*it))
212       {
213         logerror("%s was in write set, but isWritten(%s) was false\n", (*it)->format().c_str(), (*it)->format().c_str());
214         return FAILED;
215       }
216     }
217   }
218   else
219   {
220     logerror("Write set for instruction %s not as expected\n", i.format().c_str());
221     return FAILED;
222   }
223   logerror("PASSED: Instruction %s had read, write sets as expected\n", i.format().c_str());
224   return PASSED;
225 }
226
227
228 test_results_t test_instruction_read_write_Mutator::executeTest()
229 {
230   const unsigned char buffer[] = 
231   {
232     0x05, 0xef, 0xbe, 0xad, 0xde, // ADD eAX, 0xDEADBEEF
233     0x50, // PUSH rAX
234     0x74, 0x10, // JZ +0x10(8)
235     0xE8, 0x20, 0x00, 0x00, 0x00, // CALL +0x20(32)
236     0xF8, // CLC
237     0x04, 0x30, // ADD AL, 0x30(8)
238     0xc7, 0x45, 0xfc, 0x01, 0x00, 0x00, 0x00, // MOVL 0x01, -0x4(EBP)
239     0x88, 0x55, 0xcc, // MOVB DL, -0x34(EBP)
240     0xF2, 0x0F, 0x12, 0xC0, // MOVDDUP XMM0, XMM1
241     0x66, 0x0F, 0x7C, 0xC9  // HADDPD XMM1, XMM1
242   };
243   unsigned int size = 34;
244   unsigned int expectedInsns = 11;
245   InstructionDecoder d(buffer, size);
246 #if defined(arch_x86_64_test)
247   d.setMode(true);
248 #endif
249   std::vector<Instruction> decodedInsns;
250   Instruction i;
251   do
252   {
253     i = d.decode();
254     decodedInsns.push_back(i);
255   }
256   while(i.isValid());
257   if(decodedInsns.size() != expectedInsns)
258   {
259     logerror("FAILED: Expected %d instructions, decoded %d\n", expectedInsns, decodedInsns.size());
260     for(std::vector<Instruction>::iterator curInsn = decodedInsns.begin();
261         curInsn != decodedInsns.end();
262         ++curInsn)
263     {
264       logerror("\t%s\n", curInsn->format().c_str());
265     }
266     
267     return FAILED;
268   }
269   if(decodedInsns.back().isValid())
270   {
271     logerror("FAILED: Expected instructions to end with an invalid instruction, but they didn't");
272     return FAILED;
273   }
274   RegisterAST::Ptr eax(new RegisterAST(r_eAX));
275   RegisterAST::Ptr adjust(new RegisterAST(r_AF));
276   RegisterAST::Ptr zero(new RegisterAST(r_ZF));
277   RegisterAST::Ptr overflow(new RegisterAST(r_OF));
278   RegisterAST::Ptr parity(new RegisterAST(r_PF));
279   RegisterAST::Ptr sign(new RegisterAST(r_SF));
280   RegisterAST::Ptr carry(new RegisterAST(r_CF));
281   registerSet expectedRead, expectedWritten;
282   expectedRead.insert(expectedRead.begin(), eax);
283   expectedWritten = list_of(eax)(adjust)(zero)(overflow)(parity)(sign)(carry);
284   
285   test_results_t retVal = PASSED;
286   
287   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[0], expectedRead, expectedWritten));
288
289   RegisterAST::Ptr rax(new RegisterAST(r_rAX));
290   RegisterAST::Ptr esp(new RegisterAST(r_eSP));
291   expectedRead.clear();
292   expectedWritten.clear();
293   expectedRead = list_of(esp)(rax);
294   expectedWritten = list_of(esp);
295   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[1], expectedRead, expectedWritten));
296
297   expectedRead.clear();
298   expectedWritten.clear();
299   RegisterAST::Ptr ip(new RegisterAST(r_EIP));
300   // Jccs are all documented as "may read zero, sign, carry, parity, overflow", so a JZ comes back as reading all
301   // of these flags
302   expectedRead = list_of(zero)(sign)(carry)(parity)(overflow)(ip);
303   expectedWritten = list_of(ip);
304   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[2], expectedRead, expectedWritten));
305   
306   expectedRead.clear();
307   expectedWritten.clear();
308   expectedRead = list_of(esp)(ip);
309   expectedWritten = list_of(esp)(ip);
310   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[3], expectedRead, expectedWritten));
311
312   expectedRead.clear();
313   expectedWritten.clear();
314   expectedWritten = list_of(carry);
315   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[4], expectedRead, expectedWritten));
316
317   expectedRead.clear();
318   expectedWritten.clear();
319   RegisterAST::Ptr al(new RegisterAST(r_AL));
320   expectedRead = list_of(al);
321   expectedWritten = list_of(al)(zero)(carry)(sign)(overflow)(parity)(adjust);
322   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[5], expectedRead, expectedWritten));
323
324 #if defined(arch_x86_64_test)
325   RegisterAST::Ptr bp(new RegisterAST(r_RBP));
326 #else
327   RegisterAST::Ptr bp(new RegisterAST(r_EBP));
328 #endif
329   expectedRead.clear();
330   expectedWritten.clear();
331   expectedRead = list_of(bp);
332   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[6], expectedRead, expectedWritten));
333   
334   RegisterAST::Ptr dl(new RegisterAST(r_DL));
335   expectedRead.clear();
336   expectedWritten.clear();
337   expectedRead = list_of(bp)(dl);
338   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[7], expectedRead, expectedWritten));
339
340   RegisterAST::Ptr xmm0(new RegisterAST(r_XMM0));
341   RegisterAST::Ptr xmm1(new RegisterAST(r_XMM1));
342   expectedRead.clear();
343   expectedWritten.clear();
344   expectedRead = list_of(xmm0);
345   expectedWritten = list_of(xmm0);
346   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[8], expectedRead, expectedWritten));
347   if(decodedInsns[8].size() != 4) {
348     logerror("FAILURE: movddup expected size 4, decoded to %s, had size %d\n", decodedInsns[8].format().c_str(), decodedInsns[8].size());
349     retVal = FAILED;
350   }
351   expectedRead.clear();
352   expectedWritten.clear();
353   expectedRead = list_of(xmm1);
354   expectedWritten = list_of(xmm1);
355   retVal = failure_accumulator(retVal, verify_read_write_sets(decodedInsns[9], expectedRead, expectedWritten));
356   if(decodedInsns[9].size() != 4) {
357     logerror("FAILURE: haddpd expected size 4, decoded to %s, had size %d\n", decodedInsns[9].format().c_str(), decodedInsns[9].size());
358     retVal = FAILED;
359   }  
360 #if defined(arch_x86_64_test)
361   const unsigned char amd64_specific[] = 
362   {
363     0x44, 0x89, 0x45, 0xc4
364   };
365   unsigned int amd64_size = 4;
366   unsigned int amd64_num_valid_insns = 1;
367   vector<Instruction> amd64Insns;
368   
369   InstructionDecoder amd64_decoder(amd64_specific, amd64_size);
370   amd64_decoder.setMode(true);
371   
372   Instruction tmp;
373   do
374   {
375     tmp = amd64_decoder.decode();
376     amd64Insns.push_back(tmp);
377   } while(tmp.isValid());
378   amd64Insns.pop_back();
379   if(amd64Insns.size() != amd64_num_valid_insns) 
380   {
381     logerror("FAILED: expected %d instructions in AMD64-specific part, got %d\n", amd64_num_valid_insns,
382              amd64Insns.size());
383     return FAILED;
384   }
385   RegisterAST::Ptr r8(new RegisterAST(r_R8));
386   
387   expectedRead = list_of(bp)(r8);
388   expectedWritten.clear();
389   
390   retVal = failure_accumulator(retVal, verify_read_write_sets(amd64Insns[0], expectedRead, expectedWritten));
391 #endif
392
393   Expression::Ptr cft = decodedInsns[3].getControlFlowTarget();
394   if(!cft) {
395     logerror("FAILED: call had no control flow target\n");
396     return FAILED;
397   }
398   RegisterAST* the_ip = new RegisterAST(r_EIP);
399   
400   if(!cft->bind(the_ip, Result(u32, 0))) {
401     logerror("FAILED: bind found no IP in call Jz CFT\n");
402     return FAILED;
403   }
404   
405   Result theTarget = cft->eval();
406   if(!theTarget.defined) {
407     logerror("FAILED: bind of IP on a Jz operand did not resolve all dependencies\n");
408     return FAILED;
409   }
410   if(theTarget.type != u32) {
411     logerror("FAILED: CFT was not address type\n");
412     logerror("   %s\n", theTarget.format().c_str());
413     return FAILED;
414   }
415   // Call target should be to IP + displacement + size
416   if(theTarget.val.u32val != 0x25) {
417     logerror("FAILED: expected call to %x, got call to %x\n", 0x20, theTarget.val.u32val);
418     logerror("   %s\n", theTarget.format().c_str());
419     return FAILED;
420   }
421   logerror("PASSED call CFT subtest\n");
422   delete the_ip;
423   
424   return retVal;
425 }
426