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