Require c++11 thread_local support (#860)
[dyninst.git] / dyninstAPI / src / BPatch_memoryAccessAdapter.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 "BPatch_memoryAccessAdapter.h"
32 #include "BPatch_memoryAccess_NP.h"
33 #include "Instruction.h"
34 #include "Immediate.h"
35 #include "Register.h"
36 #include "Dereference.h"
37
38 #include "common/src/arch.h"
39
40 #include "legacy-instruction.h"
41
42 using namespace Dyninst;
43 using namespace InstructionAPI;
44
45
46 BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction insn,
47                                                          Address current, bool is64)
48 {
49 #if defined(arch_x86) || defined(arch_x86_64)
50     static unsigned int log2[] = { 0, 0, 1, 1, 2, 2, 2, 2, 3 };
51     
52   // TODO 16-bit registers
53     
54   int nac = 0;
55     
56   ia32_memacc mac[3];
57   ia32_condition cnd;
58   ia32_instruction i(mac, &cnd);
59     
60   const unsigned char* addr = reinterpret_cast<const unsigned char*>(insn.ptr());
61   BPatch_memoryAccess* bmap = BPatch_memoryAccess::none;
62
63
64     ia32_decode(IA32_DECODE_MEMACCESS | IA32_DECODE_CONDITION, addr, i, is64);
65   
66   bool first = true;
67
68   for(int j=0; j<3; ++j) {
69     ia32_memacc& mac = const_cast<ia32_memacc&>(i.getMac(j));
70     const ia32_condition& cond = i.getCond();
71     int bmapcond = cond.is ? cond.tttn : -1;
72     if(mac.is) {
73
74       // here, we can set the correct address for RIP-relative addressing
75       //
76       // Xiaozhu: This works for dynamic instrumentation in all cases,
77       // and binary rewriting on non-pic code. This will break for rewriting
78       // PIE and shared libraries
79       if (mac.regs[0] == mRIP) {
80         mac.imm = current + insn.size() + mac.imm;
81       }
82
83       if(first) {
84         if(mac.prefetch) {
85           if(mac.prefetchlvl > 0) // Intel
86             bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
87                                            false, false,
88                                            mac.imm, mac.regs[0], mac.regs[1], mac.scale,
89                                            0, -1, -1, 0,
90                                            bmapcond, false, mac.prefetchlvl);
91           else // AMD
92             bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
93                                            false, false,
94                                            mac.imm, mac.regs[0], mac.regs[1], mac.scale,
95                                            0, -1, -1, 0,
96                                            bmapcond, false, mac.prefetchstt + IA32AMDprefetch);
97         }
98         else switch(mac.sizehack) { // translation to pseudoregisters
99         case 0:
100           bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
101                                          mac.read, mac.write,
102                                          mac.size, mac.imm, mac.regs[0], mac.regs[1], mac.scale, 
103                                          bmapcond, mac.nt);
104           break;
105         case shREP: // use ECX register to compute final size as mac.size * ECX
106           bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
107                                          mac.read, mac.write,
108                                          mac.imm, mac.regs[0], mac.regs[1], mac.scale,
109                                          0, -1, 1 , log2[mac.size],
110                                          bmapcond, false);
111           break;
112         case shREPESCAS:
113           bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
114                                          mac.read, mac.write,
115                                          mac.imm, mac.regs[0], mac.regs[1], mac.scale,
116                                          0, -1, IA32_ESCAS, log2[mac.size],
117                                          bmapcond, false);
118           break;
119         case shREPNESCAS:
120           bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
121                                          mac.read, mac.write,
122                                          mac.imm, mac.regs[0], mac.regs[1], mac.scale,
123                                          0, -1, IA32_NESCAS, log2[mac.size],
124                                          bmapcond, false);
125           break;
126         case shREPECMPS:
127           bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
128                                          mac.read, mac.write,
129                                          mac.imm, mac.regs[0], mac.regs[1], mac.scale,
130                                          0, -1, IA32_ECMPS, log2[mac.size],
131                                          bmapcond, false);
132           break;
133         case shREPNECMPS:
134           bmap = new BPatch_memoryAccess(new internal_instruction(NULL), current,
135                                          mac.read, mac.write,
136                                          mac.imm, mac.regs[0], mac.regs[1], mac.scale,
137                                          0, -1, IA32_NECMPS, log2[mac.size],
138                                          bmapcond, false);
139           break;
140         default:
141           assert(!"Unknown size hack");
142         }
143         first = false;
144       }
145       else
146         switch(mac.sizehack) { // translation to pseudoregisters
147         case 0:
148           bmap->set2nd(mac.read, mac.write, mac.size, mac.imm,
149                        mac.regs[0], mac.regs[1], mac.scale);
150           break;
151         case shREP: // use ECX register to compute final size as mac.size * ECX
152           bmap->set2nd(mac.read, mac.write,
153                        mac.imm, mac.regs[0], mac.regs[1], mac.scale,
154                        0, -1, 1 , log2[mac.size],
155                        bmapcond, false);
156           break;
157         case shREPESCAS:
158         case shREPNESCAS:
159           assert(!"Cannot happen");
160           break;
161         case shREPECMPS:
162           bmap->set2nd(mac.read, mac.write,
163                        mac.imm, mac.regs[0], mac.regs[1], mac.scale,
164                        0, -1, IA32_ECMPS, log2[mac.size],
165                        bmapcond, false);
166           break;
167         case shREPNECMPS:
168           //fprintf(stderr, "In set2nd[shREPNECMPS]!!!\n");
169           bmap->set2nd(mac.read, mac.write,
170                        mac.imm, mac.regs[0], mac.regs[1], mac.scale,
171                        0, -1, IA32_NECMPS, log2[mac.size],
172                        bmapcond, false);
173           break;
174         default:
175           assert(!"Unknown size hack");
176         }
177       ++nac;
178     }
179   }
180   assert(nac < 3);
181   return bmap;
182 #elif defined(arch_ppc)||defined(arch_ppc64)
183         (void) is64; //Silence warnings
184     std::vector<Operand> operands;
185     insn.getOperands(operands);
186     for(std::vector<Operand>::iterator op = operands.begin();
187         op != operands.end();
188        ++op)
189     {
190         bool isLoad = op->readsMemory();
191         bool isStore = op->writesMemory();
192         if(isLoad || isStore)
193         {
194                         op->getValue()->apply(this);
195             if(insn.getOperation().getID() == power_op_lmw ||
196                insn.getOperation().getID() == power_op_stmw)
197             {
198                 RegisterAST::Ptr byteOverride =
199                         boost::dynamic_pointer_cast<RegisterAST>(insn.getOperand(0).getValue());
200                 assert(byteOverride);
201                 MachRegister base = byteOverride->getID().getBaseRegister();
202                 unsigned int converted = base.val() & 0xFFFF;
203                 bytes = (32 - converted) << 2;
204             }
205             if(insn.getOperation().getID() == power_op_lswi ||
206                insn.getOperation().getID() == power_op_stswi)
207             {
208                 Immediate::Ptr byteOverride =
209                         boost::dynamic_pointer_cast<Immediate>(insn.getOperand(2).getValue());
210                 assert(byteOverride);
211                 bytes = byteOverride->eval().convert<unsigned int>();
212                 if(bytes == 0) bytes = 32;
213             }
214             if(insn.getOperation().getID() == power_op_lswx ||
215                insn.getOperation().getID() == power_op_stswx)
216             {
217                 return new BPatch_memoryAccess(new internal_instruction(NULL), current, isLoad, isStore, (long)0, ra, rb, (long)0, 9999, -1);
218             }
219                         return new BPatch_memoryAccess(new internal_instruction(NULL), current, isLoad, isStore,
220                                        bytes, imm, ra, rb);
221         }
222     }
223     return NULL;
224 #elif defined(arch_aarch64) 
225         
226         (void) is64; //Silence warnings
227     std::vector<Operand> operands;
228     insn.getOperands(operands);
229     for(std::vector<Operand>::iterator op = operands.begin();
230         op != operands.end();
231        ++op)
232     {
233         bool isLoad = op->readsMemory();
234         bool isStore = op->writesMemory();
235         if(isLoad || isStore)
236         {
237                 
238                         op->getValue()->apply(this);
239       // Xiaozhu: This works for dynamic instrumentation in all cases,
240       // and binary rewriting on non-pic code. This will break for rewriting
241       // PIE and shared libraries
242                         if (ra == 32) {
243                             imm = imm + current;
244                         }
245                         //fprintf(stderr, "instruction: %s, operand %s\n", insn.format().c_str(),op->getValue()->format().c_str());
246                         //fprintf(stderr, "imm: %d, ra: %d, rb: %d, scale: %d\n", imm, ra, rb, sc);
247
248                         return new BPatch_memoryAccess(new internal_instruction(NULL), current, isLoad, isStore,
249                                        bytes, imm, ra, rb, sc);
250         }
251     }
252         return NULL;
253 #else 
254     assert(!"Unimplemented architecture");
255 #endif
256 }
257
258
259 void BPatch_memoryAccessAdapter::visit(Dereference* d)
260 {
261     bytes = d->size();
262 }
263
264 void BPatch_memoryAccessAdapter::visit(RegisterAST* r)
265 {
266     MachRegister base = r->getID().getBaseRegister();
267     //fprintf(stderr, "base: %d\n", base.val());
268             
269         unsigned int converted = base.val() & 0xFFFF;
270         #if defined(arch_ppc)||defined(arch_ppc64)
271     if((ra == -1) && !setImm) {
272         ra = converted;
273         return;
274     } else if(rb == -1) {
275         rb = converted;
276         if(ra == 0) ra = -1;
277         return;
278     }
279     else
280     {
281         fprintf(stderr, "ASSERT: only two registers used in a power load/store calc!\n");
282         assert(0);
283     }
284         #else
285         if(ra == -1) {
286                 ra = converted;
287                 return;
288         }
289         else if(rb == -1) {
290                 rb = converted;
291                 return;
292         }
293     else
294     {
295         fprintf(stderr, "ASSERT: only two registers used in a power load/store calc!\n");
296         assert(0);
297     }
298         #endif        
299 }
300
301 void BPatch_memoryAccessAdapter::visit(Immediate* i)
302 {
303     imm = i->eval().convert<long>();
304         setImm = true;
305 }
306
307 void BPatch_memoryAccessAdapter::visit(BinaryFunction* b)
308 {       
309         if(b->isLeftShift() == true) {
310                 sc = imm;
311                 imm = 0;
312         }
313 }
314