Move architecture dependent code in PCWidget.C to three separate architecture specifi...
[dyninst.git] / dyninstAPI / src / Relocation / Widgets / PCWidget-ppc.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
31 #include "PCWidget.h"
32 #include "instructionAPI/h/Instruction.h"
33 #include "../dyninstAPI/src/debug.h"
34 #include "../CFG/RelocBlock.h"
35 #include "../CodeBuffer.h"
36 #include "../CodeTracker.h"
37 #include "dyninstAPI/src/function.h"
38
39 #include "dyninstAPI/src/addressSpace.h" // For determining which type of getPC to emit
40 #include "dyninstAPI/src/RegisterConversion.h"
41 #include "dyninstAPI/src/registerSpace.h"
42
43 #include "dyninstAPI/src/emitter.h"
44
45 using namespace Dyninst;
46 using namespace Relocation;
47 using namespace InstructionAPI;
48
49 bool PCWidget::PCtoReturnAddr(const codeGen &templ, const RelocBlock *t, CodeBuffer &buffer) {
50   if(templ.addrSpace()->proc()) {
51     std::vector<unsigned char> newInsn;
52     // We want to get a value into LR, which is the return address.
53     // Fun for the whole family... we need a spare register. Argh!
54     codeGen gen(64);
55     gen.applyTemplate(templ);
56     // Must be in LR
57     instPoint *point = templ.point();
58     
59     // If we do not have a point then we have to invent one
60     if (!point || (point->type() != instPoint::PreInsn && point->insnAddr() != addr())) {
61       point = instPoint::preInsn(t->func(), t->block(), addr(), insn_, true);
62     }
63     assert(point);  
64     
65     registerSpace *rs = registerSpace::actualRegSpace(point);
66     gen.setRegisterSpace(rs);
67     int stackSize = 0;
68     pdvector<Register> freeReg;
69     pdvector<Register> excludeReg;  
70     
71     Address origRet = addr() + insn_.size();
72     Register scratch = gen.rs()->getScratchRegister(gen, true);
73     bool createFrame = false;
74     if (scratch == REG_NULL) {
75       stackSize = insnCodeGen::createStackFrame(gen, 1, freeReg, excludeReg);
76       assert(stackSize == 1);
77       scratch = freeReg[0];
78       createFrame = true;
79     }
80     insnCodeGen::loadImmIntoReg(gen, scratch, origRet);
81     insnCodeGen::generateMoveToLR(gen, scratch);
82     if (createFrame) {
83       insnCodeGen::removeStackFrame(gen);
84     }
85     buffer.addPIC(gen, tracker(t));
86   }
87   else {
88     IPPatch *newPatch = new IPPatch(IPPatch::Push, addr_, insn_, t->block(), t->func());
89     buffer.addPatch(newPatch, tracker(t));
90   }     
91   return true;
92 }
93
94 bool PCWidget::PCtoReg(const codeGen &templ, const RelocBlock *t, CodeBuffer &buffer) {
95   bool ignored;
96   Register reg = convertRegID(a_.reg(), ignored);
97
98   if(templ.addrSpace()->proc()) {
99     // Move immediate to register?
100     codeGen gen(16);
101     insnCodeGen::loadImmIntoReg(gen, reg, addr_);
102     buffer.addPIC(gen, tracker(t));
103   }
104   else {
105     IPPatch *newPatch = new IPPatch(IPPatch::Reg, addr_, reg, thunkAddr_, insn_, t->block(), t->func());
106     buffer.addPatch(newPatch, tracker(t));
107   }
108   return true;
109 }
110
111 #include "dyninstAPI/src/registerSpace.h"
112 bool IPPatch::apply(codeGen &gen, CodeBuffer *) {
113   relocation_cerr << "\t\t IPPatch::apply" << endl;
114   relocation_cerr << "\t\t\t Generating IPPatch for target address " << std::hex << addr << ", CodeGen current address " << std::hex << gen.currAddr() << " and register number " << reg << endl;
115
116   // For dynamic we can do this in-line
117   assert(gen.addrSpace()->edit());
118
119   instPoint *point = gen.point();
120   // If we do not have a point then we have to invent one
121   if (!point || (point->type() != instPoint::PreInsn && point->insnAddr() != addr)) {
122     point = instPoint::preInsn(func, block, addr, insn, true);
123   }
124   assert(point);
125     
126   registerSpace *rs = registerSpace::actualRegSpace(point);
127   gen.setRegisterSpace(rs);
128
129   // Must be in LR
130   if (reg == (Register) -1) reg = registerSpace::lr;
131   assert(reg == registerSpace::lr);
132     
133   int stackSize = 0;
134   pdvector<Register> freeReg;
135   pdvector<Register> excludeReg;
136     
137   Register scratchPCReg = gen.rs()->getScratchRegister(gen, true);
138   excludeReg.push_back(scratchPCReg);
139   Register scratchReg = gen.rs()->getScratchRegister(gen, excludeReg, true);
140     
141   if ((scratchPCReg == REG_NULL) && (scratchReg == REG_NULL)) {
142     excludeReg.clear();
143     stackSize = insnCodeGen::createStackFrame(gen, 2, freeReg, excludeReg);
144     assert(stackSize == 2);
145     scratchPCReg = freeReg[0];
146     scratchReg = freeReg[1];
147       
148   } else if (scratchReg == REG_NULL && scratchPCReg != REG_NULL) {
149     stackSize = insnCodeGen::createStackFrame(gen, 1, freeReg, excludeReg);
150     assert(stackSize == 1);
151     scratchReg = freeReg[0];
152   } 
153     
154   //scratchPCReg == NULL && scratchReg != NULL - not a valid case 
155   //since getScratchRegister works in order
156     
157   // relocaAddr may have moved if we added instructions to setup a new stack frame
158   Address newRelocAddr = gen.currAddr();
159     
160   insnCodeGen::generateBranch(gen, gen.currAddr(),  gen.currAddr()+4, true); // blrl
161   insnCodeGen::generateMoveFromLR(gen, scratchPCReg); // mflr
162     
163   Address varOffset = addr - newRelocAddr;
164   gen.emitter()->emitCallRelative(scratchReg, varOffset, scratchPCReg, gen);
165   insnCodeGen::generateMoveToLR(gen, scratchReg);
166
167   if( stackSize > 0) {
168     insnCodeGen::removeStackFrame(gen); 
169   }
170   return true;
171 }