Update copyright
[dyninst.git] / dataflowAPI / src / RoseInsnFactory.C
1 /*
2  * Copyright (c) 1996-2011 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 #include "RoseInsnFactory.h"
32 //#include "../rose/x86InstructionSemantics.h"
33 //#include "../rose/powerpcInstructionSemantics.h"
34
35 #include "Instruction.h"
36 #include "Operand.h"
37 #include "Expression.h"
38 #include "Dereference.h"
39 #include "Immediate.h"
40 #include <vector>
41
42 #include "../rose/SgAsmInstruction.h"
43 #include "../rose/SgAsmPowerpcInstruction.h"
44 #include "../rose/SgAsmx86Instruction.h"
45 #include "../rose/SgAsmExpression.h"
46
47 #include "ExpressionConversionVisitor.h"
48
49 using namespace Dyninst;
50 using namespace InstructionAPI;
51 using namespace DataflowAPI;
52
53 SgAsmInstruction *RoseInsnFactory::convert(const InstructionAPI::Instruction::Ptr &insn, uint64_t addr) {
54   SgAsmInstruction *rinsn = createInsn();
55   
56   rinsn->set_address(addr);
57   rinsn->set_mnemonic(insn->format());
58   setOpcode(rinsn, insn->getOperation().getID(), insn->getOperation().getPrefixID(), insn->getOperation().format());
59
60   // semantics don't support 64-bit code
61   setSizes(rinsn);
62
63   //rinsn->set_operandSize(x86_insnsize_32);
64   //rinsn->set_addressSize(x86_insnsize_32);
65   
66   std::vector<unsigned char> rawBytes;
67   for (unsigned i = 0; i < insn->size(); ++i) rawBytes.push_back(insn->rawByte(i));
68   rinsn->set_raw_bytes(rawBytes);
69   
70   // operand list
71   SgAsmOperandList *roperands = new SgAsmOperandList;
72   
73   //cerr << "Converting " << insn->format() << " @" << hex << addr << dec << endl;
74   
75   //cerr << "checking instruction: " << insn->format() << " for special handling" << endl;
76   if (handleSpecialCases(insn->getOperation().getID(), rinsn, roperands)) {
77     rinsn->set_operandList(roperands);
78     return rinsn;
79   }
80
81   //cerr << "no special handling by opcode, checking if we should mangle operands..." << endl;
82   std::vector<InstructionAPI::Operand> operands;
83   insn->getOperands(operands);
84   //cerr << "\t " << operands.size() << " operands" << endl;
85   massageOperands(insn, operands);
86   int i = 0;
87   //cerr << "converting insn " << insn->format() << endl;
88   for (std::vector<InstructionAPI::Operand>::iterator opi = operands.begin();
89        opi != operands.end();
90        ++opi, ++i) {
91     InstructionAPI::Operand &currOperand = *opi;
92     //cerr << "Converting operand " << currOperand.format() << endl;
93     roperands->append_operand(convertOperand(currOperand.getValue(), addr));
94   }  
95   rinsn->set_operandList(roperands);
96   return rinsn;
97 }
98
99 SgAsmExpression *RoseInsnFactory::convertOperand(const Expression::Ptr expression, uint64_t addr) {
100   if(!expression) return NULL;
101   ExpressionConversionVisitor visitor(arch(), addr);
102   expression->apply(&visitor);
103   return visitor.getRoseExpression();
104 }
105
106 ///////////// X86 //////////////////
107
108 SgAsmInstruction *RoseInsnX86Factory::createInsn() {
109   return new SgAsmx86Instruction;
110 }
111
112 // Note: convertKind is defined in convertOpcodes.C
113
114 void RoseInsnX86Factory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID prefix, std::string) {
115   SgAsmx86Instruction *tmp = static_cast<SgAsmx86Instruction *>(insn);
116   
117   tmp->set_kind(convertKind(opcode, prefix));
118 }
119
120 void RoseInsnX86Factory::setSizes(SgAsmInstruction *insn) {
121   // FIXME when we go 64-bit...
122   SgAsmx86Instruction *tmp = static_cast<SgAsmx86Instruction *>(insn);
123   tmp->set_operandSize(x86_insnsize_32);
124   tmp->set_addressSize(x86_insnsize_32);
125 }
126
127 bool RoseInsnX86Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsmOperandList *) {
128   // Does nothing?
129   return false;
130 }
131
132 void RoseInsnX86Factory::massageOperands(const InstructionAPI::Instruction::Ptr &insn, 
133                                          std::vector<InstructionAPI::Operand> &operands) {
134   switch (insn->getOperation().getID()) {
135   case e_lea: {
136                   // ROSE expects there to be a "memory reference" statement wrapping the 
137                   // address calculation. It then unwraps it.
138                   Dereference::Ptr tmp = Dereference::Ptr(new Dereference(operands[1].getValue(), u32));
139                   operands[1] = Operand(tmp, operands[1].isRead(), operands[1].isWritten());
140                   operands.resize(2);
141                   break;
142               }
143   case e_push:
144   case e_pop:
145     operands.resize(1);
146     break;
147   case e_cmpxch:
148     operands.resize(2);
149     break;
150   case e_movsb:
151   case e_movsd:
152   case e_movsw:
153     // No operands
154     operands.clear();
155     break;
156   case e_cmpsb:
157   case e_cmpsw:
158   case e_cmpsd:
159     // No operands
160     operands.clear();
161     break;
162   case e_scasb:
163   case e_scasd:
164   case e_scasw:
165     // Same here
166     operands.clear();
167     break;
168   case e_stosb:
169   case e_stosd:
170   case e_stosw:
171     // Also, no operands
172     operands.clear();
173     break;
174   case e_jcxz_jec:
175     operands.resize(1);
176     break;
177   case e_cbw:
178   case e_cwde:
179   case e_cdq:
180     // Nada
181     operands.clear();
182     break;
183   case e_popad:
184     operands.clear();
185     break;
186   default:
187     break;
188   }
189 }
190
191
192 //////////// PPC ///////////////////
193 // Note: convertKind is defined in convertOpcodes.C
194
195 SgAsmInstruction *RoseInsnPPCFactory::createInsn() {
196   return new SgAsmPowerpcInstruction;
197 }
198
199 void RoseInsnPPCFactory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID /*prefix*/, std::string mnem) {
200   SgAsmPowerpcInstruction *tmp = static_cast<SgAsmPowerpcInstruction *>(insn);
201   kind = convertKind(opcode, mnem);
202   tmp->set_kind(kind);
203 }
204
205
206 void RoseInsnPPCFactory::setSizes(SgAsmInstruction *) {
207 }
208
209
210 bool RoseInsnPPCFactory::handleSpecialCases(entryID iapi_opcode, 
211                                             SgAsmInstruction *insn, 
212                                             SgAsmOperandList *rose_operands) {
213   SgAsmPowerpcInstruction *rose_insn = static_cast<SgAsmPowerpcInstruction *>(insn);
214
215   switch(iapi_opcode) {
216   case power_op_b:
217   case power_op_bc:
218   case power_op_bcctr:
219   case power_op_bclr: {
220     unsigned int raw = 0;
221     int branch_target = 0;
222     unsigned int bo = 0, bi = 0;
223     std::vector<unsigned char> bytes = rose_insn->get_raw_bytes();
224     for(unsigned i = 0; i < bytes.size(); i++) {
225       raw = raw << 8;
226       raw |= bytes[i];
227     }
228     bool isAbsolute = (bool)(raw & 0x00000002);
229     bool isLink = (bool)(raw & 0x00000001);
230     rose_insn->set_kind(makeRoseBranchOpcode(iapi_opcode, isAbsolute, isLink));
231     if(power_op_b == iapi_opcode) {
232       branch_target = ((raw >> 2) & 0x00FFFFFF) << 2;
233       branch_target = (branch_target << 8) >> 8;
234     } else {
235       if(power_op_bc == iapi_opcode) {
236         branch_target = ((raw >> 2) & 0x00003FFF) << 2;
237         branch_target = (branch_target << 18) >> 18;
238         //cerr << "14-bit branch target: " << branch_target << endl;
239       }
240       bo = ((raw >> 21) & 0x0000001F);
241       bi = ((raw >> 16) & 0x0000001F);
242       rose_operands->append_operand(new SgAsmByteValueExpression(bo));
243       rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_cr, bi,
244                                                                                 powerpc_condreggranularity_bit));
245     }
246     if(branch_target) {
247       rose_operands->append_operand(new SgAsmDoubleWordValueExpression(branch_target));
248     } else if(power_op_bcctr == iapi_opcode) {
249       rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_spr, powerpc_spr_ctr));
250     } else {
251       assert(power_op_bclr == iapi_opcode);
252       rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_spr, powerpc_spr_lr));
253     }
254     return true;
255   }
256     break;
257   case power_op_sc:
258   case power_op_svcs: {
259     //cerr << "special-casing syscall insn" << endl;
260     unsigned int raw = 0;
261     std::vector<unsigned char> bytes = rose_insn->get_raw_bytes();
262     for(unsigned i = 0; i < bytes.size(); i++) {
263       raw = raw << 8;
264       raw |= bytes[i];
265     }
266     unsigned int lev = (raw >> 5) & 0x7F;
267     rose_operands->append_operand(new SgAsmByteValueExpression(lev));
268     //cerr << "LEV = " << lev << endl;
269     return true;
270   }
271   default:
272     return false;
273   }
274   
275 }  
276
277 void RoseInsnPPCFactory::massageOperands(const InstructionAPI::Instruction::Ptr &insn, 
278                                          std::vector<InstructionAPI::Operand> &operands) {
279   /*
280   if(insn->writesMemory())
281     std::swap(operands[0], operands[1]);
282   */
283   entryID opcode = insn->getOperation().getID();
284   // Anything that's writing RA, ROSE expects in RA, RS, RB/immediates form.
285   // Any store, however, ROSE expects in RS, RA, RB/displacement form.  Very confusing,
286   // but we handle it cleanly here.
287   if(!operands[0].isWritten() && operands.size() >= 2 &&
288      operands[1].isWritten() && !operands[1].writesMemory()) {
289     //std::cerr << "swapping RS and RA in " << insn->format() << std::endl;
290     std::swap(operands[0], operands[1]);
291   }
292   if(opcode == power_op_cmp ||
293      opcode == power_op_cmpl ||
294      opcode == power_op_cmpi ||
295      opcode == power_op_cmpli) {
296     operands.push_back(Operand(Immediate::makeImmediate(Result(u8, 1)), false, false));
297     std::swap(operands[2], operands[3]);
298     std::swap(operands[1], operands[2]);
299   }
300   if(insn->getOperation().format().find(".") != std::string::npos &&
301      insn->getOperation().getID() != power_op_stwcx_rc) {
302     operands.pop_back();
303   }
304
305   // Convert to ROSE so we can use numeric greater than/less than
306
307   if(kind >= powerpc_lbz && kind <= powerpc_lwzx) {
308     operands.resize(2);
309   }
310   if(kind >= powerpc_stb && kind <= powerpc_stwx) {
311     operands.resize(2);
312   }
313
314   return;
315 }
316