2 * See the dyninst/COPYRIGHT file for copyright information.
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.
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.
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.
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.
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
30 #include "RoseInsnFactory.h"
32 #include "Instruction.h"
33 #include "Dereference.h"
34 #include "Immediate.h"
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"
42 #include "ExpressionConversionVisitor.h"
44 // Assume Windows/MSVC is little-endian
47 #define htobe _byteswap_ulong
50 using namespace Dyninst;
51 using namespace InstructionAPI;
52 using namespace DataflowAPI;
54 SgAsmInstruction *RoseInsnFactory::convert(const Instruction &insn, uint64_t addr) {
55 SgAsmInstruction *rinsn = createInsn();
57 rinsn->set_address(addr);
58 rinsn->set_mnemonic(insn.format());
59 setOpcode(rinsn, insn.getOperation().getID(), insn.getOperation().getPrefixID(), insn.getOperation().format());
61 // semantics don't support 64-bit code
64 //rinsn->set_operandSize(x86_insnsize_32);
65 //rinsn->set_addressSize(x86_insnsize_32);
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);
72 SgAsmOperandList *roperands = new SgAsmOperandList;
74 //std::cerr << "Converting " << insn.format(addr) << " @" << std::hex << addr << std::dec << std::endl;
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);
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);
88 // std::cerr << "converting insn " << insn.format(addr) << std::endl;
89 for (std::vector<InstructionAPI::Operand>::iterator opi = operands.begin();
90 opi != operands.end();
92 InstructionAPI::Operand &currOperand = *opi;
93 // std::cerr << "Converting operand " << currOperand.format(arch(), addr) << std::endl;
94 SgAsmExpression *converted = convertOperand(currOperand.getValue(), addr, insn.size());
95 if (converted == NULL) return NULL;
96 roperands->append_operand(converted);
98 rinsn->set_operandList(roperands);
102 SgAsmExpression *RoseInsnFactory::convertOperand(const Expression::Ptr expression, int64_t addr, size_t insnSize) {
103 if(!expression) return NULL;
104 ExpressionConversionVisitor visitor(arch(), addr, insnSize);
105 expression->apply(&visitor);
106 return visitor.getRoseExpression();
109 ///////////// X86 //////////////////
111 SgAsmInstruction *RoseInsnX86Factory::createInsn() {
112 return new SgAsmx86Instruction;
115 // Note: convertKind is defined in convertOpcodes.C
117 void RoseInsnX86Factory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID prefix, std::string) {
118 SgAsmx86Instruction *tmp = static_cast<SgAsmx86Instruction *>(insn);
120 tmp->set_kind(convertKind(opcode, prefix));
123 void RoseInsnX86Factory::setSizes(SgAsmInstruction *insn) {
124 SgAsmx86Instruction *tmp = static_cast<SgAsmx86Instruction *>(insn);
125 if (a == Arch_x86_64) {
126 tmp->set_operandSize(x86_insnsize_64);
127 tmp->set_addressSize(x86_insnsize_64);
129 tmp->set_operandSize(x86_insnsize_32);
130 tmp->set_addressSize(x86_insnsize_32);
134 bool RoseInsnX86Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsmOperandList *) {
140 void RoseInsnX86Factory::massageOperands(const Instruction &insn,
141 std::vector<InstructionAPI::Operand> &operands) {
142 switch (insn.getOperation().getID()) {
144 // ROSE expects there to be a "memory reference" statement wrapping the
145 // address calculation. It then unwraps it.
146 Dereference::Ptr tmp = Dereference::Ptr(new Dereference(operands[1].getValue(), u32));
147 operands[1] = Operand(tmp, operands[1].isRead(), operands[1].isWritten());
210 if (operands.size() == 2) {
211 operands[0]=operands[1];
217 // ROSE does not expect implicit operand rax/eax to be treated as an operand
222 // ROSE does not expect implicit operand rax/eax to be treated as an operand
223 std::set<RegisterAST::Ptr> regs;
224 operands[0].getReadSet(regs);
225 operands[0].getWriteSet(regs);
227 operands[0] = operands[1];
236 // remove implicit operands.
237 if (operands.size() == 3) {
238 operands[0] = operands[2];
248 //////////// PPC ///////////////////
249 // Note: convertKind is defined in convertOpcodes.C
251 SgAsmInstruction *RoseInsnPPCFactory::createInsn() {
252 return new SgAsmPowerpcInstruction;
255 void RoseInsnPPCFactory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID /*prefix*/, std::string mnem) {
256 SgAsmPowerpcInstruction *tmp = static_cast<SgAsmPowerpcInstruction *>(insn);
257 kind = convertKind(opcode, mnem);
262 void RoseInsnPPCFactory::setSizes(SgAsmInstruction *) {
265 bool RoseInsnPPCFactory::handleSpecialCases(entryID iapi_opcode,
266 SgAsmInstruction *insn,
267 SgAsmOperandList *rose_operands) {
268 SgAsmPowerpcInstruction *rose_insn = static_cast<SgAsmPowerpcInstruction *>(insn);
270 switch(iapi_opcode) {
274 case power_op_bclr: {
275 unsigned int raw = 0;
276 int branch_target = 0;
277 unsigned int bo = 0, bi = 0;
278 std::vector<unsigned char> bytes = rose_insn->get_raw_bytes();
279 for(unsigned i = 0; i < bytes.size(); i++) {
284 // Visual Studio doensn't define htobe32, so we assume that Windows is always little endian.
285 raw = _byteswap_ulong(raw);
289 bool isAbsolute = (bool)(raw & 0x00000002);
290 bool isLink = (bool)(raw & 0x00000001);
291 rose_insn->set_kind(makeRoseBranchOpcode(iapi_opcode, isAbsolute, isLink));
292 if(power_op_b == iapi_opcode) {
293 branch_target = ((raw >> 2) & 0x00FFFFFF) << 2;
294 branch_target = (branch_target << 8) >> 8;
296 if(power_op_bc == iapi_opcode) {
297 branch_target = ((raw >> 2) & 0x00003FFF) << 2;
298 branch_target = (branch_target << 18) >> 18;
299 //cerr << "14-bit branch target: " << branch_target << endl;
301 bo = ((raw >> 21) & 0x0000001F);
302 // bi field specifies which condition register bit to test.
303 // bi has a 5-bit value. The top 3 bit specifies which condition register to use
304 // The bottom 2 bit specifies which bit within the given condition register
305 bi = ((raw >> 16) & 0x0000001F);
306 rose_operands->append_operand(new SgAsmIntegerValueExpression(bo, new SgAsmIntegerType(ByteOrder::ORDER_LSB, 8, false)));
308 SgAsmDirectRegisterExpression *dre = new SgAsmDirectRegisterExpression(RegisterDescriptor(powerpc_regclass_cr, 0, bi , 1));
309 dre->set_type(new SgAsmIntegerType(ByteOrder::ORDER_LSB, 1, false));
310 rose_operands->append_operand(dre);
313 // It looks like the ROSE semantics code will infer the target from
314 // the bo field. So, what is passed in as the third operands does not matter
316 rose_operands->append_operand(new SgAsmDoubleWordValueExpression(branch_target));
317 } else if(power_op_bcctr == iapi_opcode) {
318 rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_spr, powerpc_spr_ctr));
320 assert(power_op_bclr == iapi_opcode);
321 rose_operands->append_operand(new SgAsmPowerpcRegisterReferenceExpression(powerpc_regclass_spr, powerpc_spr_lr));
327 case power_op_svcs: {
328 //cerr << "special-casing syscall insn" << endl;
329 unsigned int raw = 0;
330 std::vector<unsigned char> bytes = rose_insn->get_raw_bytes();
331 for(unsigned i = 0; i < bytes.size(); i++) {
335 unsigned int lev = (raw >> 5) & 0x7F;
336 rose_operands->append_operand(new SgAsmIntegerValueExpression(lev, new SgAsmIntegerType(ByteOrder::ORDER_LSB, 8, false)));
337 //cerr << "LEV = " << lev << endl;
346 void RoseInsnPPCFactory::massageOperands(const Instruction &insn,
347 std::vector<InstructionAPI::Operand> &operands) {
349 if(insn.writesMemory())
350 std::swap(operands[0], operands[1]);
352 entryID opcode = insn.getOperation().getID();
353 // Anything that's writing RA, ROSE sometimes expects in RA, RS, RB/immediates form.
354 // Any store, however, Dyninst expects in RS, RA, RB/displacement form. Very confusing,
355 // but we handle it cleanly here.
356 if( opcode != power_op_rldicr &&
357 opcode != power_op_rldic &&
358 !operands[0].isWritten() && operands.size() >= 2 &&
359 operands[1].isWritten() && !operands[1].writesMemory()) {
360 //std::cerr << "swapping RS and RA in " << insn.format() << std::endl;
361 std::swap(operands[0], operands[1]);
363 if(opcode == power_op_cmp ||
364 opcode == power_op_cmpl ||
365 opcode == power_op_cmpi ||
366 opcode == power_op_cmpli) {
367 operands.push_back(Operand(Immediate::makeImmediate(Result(u8, 1)), false, false));
368 std::swap(operands[2], operands[3]);
369 std::swap(operands[1], operands[2]);
371 if(insn.getOperation().format().find(".") != std::string::npos &&
372 insn.getOperation().getID() != power_op_stwcx_rc) {
376 // Convert to ROSE so we can use numeric greater than/less than
378 if(kind >= powerpc_lbz && kind <= powerpc_lwzx) {
381 if(kind >= powerpc_stb && kind <= powerpc_stwx) {
388 void RoseInsnArmv8Factory::setSizes(SgAsmInstruction */*insn*/) {
392 SgAsmInstruction *RoseInsnArmv8Factory::createInsn() {
393 return new SgAsmArmv8Instruction;
396 void RoseInsnArmv8Factory::setOpcode(SgAsmInstruction *insn, entryID opcode, prefixEntryID, std::string) {
397 SgAsmArmv8Instruction *tmp = static_cast<SgAsmArmv8Instruction *>(insn);
398 tmp->set_kind(convertKind(opcode));
401 bool RoseInsnArmv8Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsmOperandList *) {
405 void RoseInsnArmv8Factory::massageOperands(const Instruction &,
406 std::vector<InstructionAPI::Operand> &) {