Add initial code for power 32 semantics and symbolic expansion for power 64
[dyninst.git] / dataflowAPI / src / RoseInsnFactory.C
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 #include "RoseInsnFactory.h"
31
32 #include "Instruction.h"
33 #include "Dereference.h"
34 #include "Immediate.h"
35
36 #include "../rose/SgAsmInstruction.h"
37 #include "../rose/SgAsmPowerpcInstruction.h"
38 #include "../rose/SgAsmArmv8Instruction.h"
39 #include "../rose/SgAsmx86Instruction.h"
40 #include "../rose/SgAsmExpression.h"
41
42 #include "ExpressionConversionVisitor.h"
43
44 // Assume Windows/MSVC is little-endian
45
46 #if defined(_MSC_VER)
47 #define htobe _byteswap_ulong
48 #endif
49
50 using namespace Dyninst;
51 using namespace InstructionAPI;
52 using namespace DataflowAPI;
53
54 SgAsmInstruction *RoseInsnFactory::convert(const InstructionAPI::Instruction::Ptr &insn, uint64_t addr) {
55   SgAsmInstruction *rinsn = createInsn();
56   
57   rinsn->set_address(addr);
58   rinsn->set_mnemonic(insn->format());
59   setOpcode(rinsn, insn->getOperation().getID(), insn->getOperation().getPrefixID(), insn->getOperation().format());
60
61   // semantics don't support 64-bit code
62   setSizes(rinsn);
63
64   //rinsn->set_operandSize(x86_insnsize_32);
65   //rinsn->set_addressSize(x86_insnsize_32);
66   
67   std::vector<unsigned char> rawBytes;
68   for (unsigned i = 0; i < insn->size(); ++i) rawBytes.push_back(insn->rawByte(i));
69   rinsn->set_raw_bytes(rawBytes);
70   
71   // operand list
72   SgAsmOperandList *roperands = new SgAsmOperandList;
73   
74 //   std::cerr << "Converting " << insn->format(addr) << " @" << std::hex << addr << std::dec << std::endl;
75   
76 //   std::cerr << "checking instruction: " << insn->format(addr) << " for special handling" << std::endl;
77   if (handleSpecialCases(insn->getOperation().getID(), rinsn, roperands)) {
78       rinsn->set_operandList(roperands);
79       return rinsn;
80   }
81
82 //   std::cerr << "no special handling by opcode, checking if we should mangle operands..." << std::endl;
83   std::vector<InstructionAPI::Operand> operands;
84   insn->getOperands(operands);
85 //   std::cerr << "\t " << operands.size() << " operands" << std::endl;
86   massageOperands(insn, operands);
87   int i = 0;
88 //   std::cerr << "converting insn " << insn->format(addr) << std::endl;
89   for (std::vector<InstructionAPI::Operand>::iterator opi = operands.begin();
90        opi != operands.end();
91        ++opi, ++i) {
92       InstructionAPI::Operand &currOperand = *opi;
93 //       std::cerr << "Converting operand " << currOperand.format(arch(), addr) << std::endl;
94       roperands->append_operand(convertOperand(currOperand.getValue(), addr, insn->size()));
95   }  
96   rinsn->set_operandList(roperands);
97   return rinsn;
98 }
99
100 SgAsmExpression *RoseInsnFactory::convertOperand(const Expression::Ptr expression, int64_t addr, size_t insnSize) {
101   if(!expression) return NULL;
102   ExpressionConversionVisitor visitor(arch(), addr, insnSize);
103   expression->apply(&visitor);
104   return visitor.getRoseExpression();
105 }
106
107 ///////////// X86 //////////////////
108
109 SgAsmInstruction *RoseInsnX86Factory::createInsn() {
110   return new SgAsmx86Instruction;
111 }
112
113 // Note: convertKind is defined in convertOpcodes.C
114
115 void RoseInsnX86Factory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID prefix, std::string) {
116   SgAsmx86Instruction *tmp = static_cast<SgAsmx86Instruction *>(insn);
117   
118   tmp->set_kind(convertKind(opcode, prefix));
119 }
120
121 void RoseInsnX86Factory::setSizes(SgAsmInstruction *insn) {
122   SgAsmx86Instruction *tmp = static_cast<SgAsmx86Instruction *>(insn);
123   if (a == Arch_x86_64) {
124       tmp->set_operandSize(x86_insnsize_64);
125       tmp->set_addressSize(x86_insnsize_64);
126   } else {
127       tmp->set_operandSize(x86_insnsize_32);
128       tmp->set_addressSize(x86_insnsize_32);
129   }
130 }
131
132 bool RoseInsnX86Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsmOperandList *) {
133   // Does nothing?
134
135   return false;
136 }
137
138 void RoseInsnX86Factory::massageOperands(const InstructionAPI::Instruction::Ptr &insn, 
139                                          std::vector<InstructionAPI::Operand> &operands) {
140   switch (insn->getOperation().getID()) {
141   case e_lea: {
142     // ROSE expects there to be a "memory reference" statement wrapping the
143     // address calculation. It then unwraps it. 
144     Dereference::Ptr tmp = Dereference::Ptr(new Dereference(operands[1].getValue(), u32));
145     operands[1] = Operand(tmp, operands[1].isRead(), operands[1].isWritten());
146     operands.resize(2);
147     break;  
148   }
149   case e_push:
150   case e_pop:
151     operands.resize(1);
152     break;
153   case e_cmpxch:
154     operands.resize(2);
155     break;
156   case e_movsb:
157   case e_movsd:
158   case e_movsw:
159     // No operands
160     operands.clear();
161     break;
162   case e_cmpsb:
163   case e_cmpsw:
164   case e_cmpsd:
165     // No operands
166     operands.clear();
167     break;
168   case e_scasb:
169   case e_scasd:
170   case e_scasw:
171     // Same here
172     operands.clear();
173     break;
174   case e_stosb:
175   case e_stosd:
176   case e_stosw:
177     // Also, no operands
178     operands.clear();
179     break;
180   case e_jcxz_jec:
181     operands.resize(1);
182     break;
183   case e_cbw:
184   case e_cwde:
185   case e_cdq:
186     // Nada
187     operands.clear();
188     break;
189   case e_popad:
190   case e_pushfd:
191     operands.clear();
192     break;
193   case e_lodsd:
194   case e_lodsb:
195   case e_lodsw:
196       operands.clear();
197       break;
198   case e_pushad:
199       operands.clear();
200       break;
201   case e_loop:
202   case e_loope:
203   case e_loopn:
204       operands.resize(1);
205       break;
206   case e_ret_far:
207   case e_ret_near:
208           if (operands.size() == 2) {
209                   operands[0]=operands[1];
210           }
211           operands.resize(1);
212           break;
213   case e_aaa:
214   case e_aas: 
215           // ROSE does not expect implicit operand rax/eax to be treated as an operand
216           operands.clear();
217           break;
218   case e_aad:
219   case e_aam: {
220           // ROSE does not expect implicit operand rax/eax to be treated as an operand
221           std::set<RegisterAST::Ptr> regs;
222           operands[0].getReadSet(regs);
223           operands[0].getWriteSet(regs);                  
224           if (!regs.empty()) {        
225                       operands[0] = operands[1];
226           }
227           operands.resize(1);
228           break;
229   }
230   case e_div:
231   case e_idiv:
232   case e_imul:
233   case e_mul:
234     // remove implicit operands.
235     if (operands.size() == 3) {
236       operands[0] = operands[2];
237       operands.resize(1);
238     }
239     break;
240   default:
241     break;
242   }
243 }
244
245
246 //////////// PPC ///////////////////
247 // Note: convertKind is defined in convertOpcodes.C
248
249 SgAsmInstruction *RoseInsnPPCFactory::createInsn() {
250   return new SgAsmPowerpcInstruction;
251 }
252
253 void RoseInsnPPCFactory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID /*prefix*/, std::string mnem) {
254   SgAsmPowerpcInstruction *tmp = static_cast<SgAsmPowerpcInstruction *>(insn);
255   kind = convertKind(opcode, mnem);
256   tmp->set_kind(kind);
257 }
258
259
260 void RoseInsnPPCFactory::setSizes(SgAsmInstruction *) {
261 }
262
263 bool RoseInsnPPCFactory::handleSpecialCases(entryID iapi_opcode,
264                                             SgAsmInstruction *insn,
265                                             SgAsmOperandList *rose_operands) {
266   SgAsmPowerpcInstruction *rose_insn = static_cast<SgAsmPowerpcInstruction *>(insn);
267
268   switch(iapi_opcode) {
269   case power_op_b:
270   case power_op_bc:
271   case power_op_bcctr:
272   case power_op_bclr: {
273     unsigned int raw = 0;
274     int branch_target = 0;
275     unsigned int bo = 0, bi = 0;
276     std::vector<unsigned char> bytes = rose_insn->get_raw_bytes();
277     for(unsigned i = 0; i < bytes.size(); i++) {
278       raw = raw << 8;
279       raw |= bytes[i];
280     }
281 #ifdef os_windows
282     // Visual Studio doensn't define htobe32, so we assume that Windows is always little endian.
283     raw = _byteswap_ulong(raw);
284 #else
285     raw = htobe32(raw);
286 #endif
287     bool isAbsolute = (bool)(raw & 0x00000002);
288     bool isLink = (bool)(raw & 0x00000001);
289     rose_insn->set_kind(makeRoseBranchOpcode(iapi_opcode, isAbsolute, isLink));
290     if(power_op_b == iapi_opcode) {
291       branch_target = ((raw >> 2) & 0x00FFFFFF) << 2;
292       branch_target = (branch_target << 8) >> 8;
293     } else {
294       if(power_op_bc == iapi_opcode) {
295         branch_target = ((raw >> 2) & 0x00003FFF) << 2;
296         branch_target = (branch_target << 18) >> 18;
297         //cerr << "14-bit branch target: " << branch_target << endl;
298       }
299       bo = ((raw >> 21) & 0x0000001F);
300       bi = ((raw >> 16) & 0x0000001F);
301       rose_operands->append_operand(new SgAsmByteValueExpression(bo));
302       rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_cr, bi,
303                                                                                 powerpc_condreggranularity_bit));
304     }
305     if(branch_target) {
306       rose_operands->append_operand(new SgAsmDoubleWordValueExpression(branch_target));
307     } else if(power_op_bcctr == iapi_opcode) {
308       rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_spr, powerpc_spr_ctr));
309     } else {
310       assert(power_op_bclr == iapi_opcode);
311       rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_spr, powerpc_spr_lr));
312     }
313     return true;
314   }
315     break;
316   case power_op_sc:
317   case power_op_svcs: {
318     //cerr << "special-casing syscall insn" << endl;
319     unsigned int raw = 0;
320     std::vector<unsigned char> bytes = rose_insn->get_raw_bytes();
321     for(unsigned i = 0; i < bytes.size(); i++) {
322       raw = raw << 8;
323       raw |= bytes[i];
324     }
325     unsigned int lev = (raw >> 5) & 0x7F;
326     rose_operands->append_operand(new SgAsmByteValueExpression(lev));
327     //cerr << "LEV = " << lev << endl;
328     return true;
329   }
330   default:
331     return false;
332   }
333   
334 }  
335
336 void RoseInsnPPCFactory::massageOperands(const InstructionAPI::Instruction::Ptr &insn, 
337                                          std::vector<InstructionAPI::Operand> &operands) {
338   /*
339   if(insn->writesMemory())
340     std::swap(operands[0], operands[1]);
341   */
342   entryID opcode = insn->getOperation().getID();
343   // Anything that's writing RA, ROSE expects in RA, RS, RB/immediates form.
344   // Any store, however, ROSE expects in RS, RA, RB/displacement form.  Very confusing,
345   // but we handle it cleanly here.
346   if(!operands[0].isWritten() && operands.size() >= 2 &&
347      operands[1].isWritten() && !operands[1].writesMemory()) {
348     //std::cerr << "swapping RS and RA in " << insn->format() << std::endl;
349     std::swap(operands[0], operands[1]);
350   }
351   if(opcode == power_op_cmp ||
352      opcode == power_op_cmpl ||
353      opcode == power_op_cmpi ||
354      opcode == power_op_cmpli) {
355     operands.push_back(Operand(Immediate::makeImmediate(Result(u8, 1)), false, false));
356     std::swap(operands[2], operands[3]);
357     std::swap(operands[1], operands[2]);
358   }
359   if(insn->getOperation().format().find(".") != std::string::npos &&
360      insn->getOperation().getID() != power_op_stwcx_rc) {
361     operands.pop_back();
362   }
363
364   // Convert to ROSE so we can use numeric greater than/less than
365
366   if(kind >= powerpc_lbz && kind <= powerpc_lwzx) {
367     operands.resize(2);
368   }
369   if(kind >= powerpc_stb && kind <= powerpc_stwx) {
370     operands.resize(2);
371   }
372
373   return;
374 }
375
376 void RoseInsnArmv8Factory::setSizes(SgAsmInstruction */*insn*/) {
377
378 }
379
380 SgAsmInstruction *RoseInsnArmv8Factory::createInsn() {
381   return new SgAsmArmv8Instruction;
382 }
383
384 void RoseInsnArmv8Factory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID, std::string) {
385   SgAsmArmv8Instruction *tmp = static_cast<SgAsmArmv8Instruction *>(insn);
386   tmp->set_kind(convertKind(opcode));
387 }
388
389 bool RoseInsnArmv8Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsmOperandList *) {
390   return false;
391 }
392
393 void RoseInsnArmv8Factory::massageOperands(const InstructionAPI::Instruction::Ptr &,
394                                            std::vector <InstructionAPI::Operand> &) {
395   return;
396 }