Adds support for ppc64_linux linker stubs (SecurePLT)
[dyninst.git] / parseAPI / src / IA_IAPI.C
1 /*
2  * Copyright (c) 1996-2009 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
32 #include "dyntypes.h"
33 #include "IA_IAPI.h"
34
35 #include "Register.h"
36 #include "Dereference.h"
37 #include "Immediate.h"
38 #include "BinaryFunction.h"
39 #include "debug_parse.h"
40
41 #include <deque>
42 #include <map>
43
44 using namespace Dyninst;
45 using namespace InstructionAPI;
46 using namespace Dyninst::InsnAdapter;
47 using namespace Dyninst::ParseAPI;
48
49 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::framePtr;
50 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::stackPtr;
51 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::thePC;
52
53 void IA_IAPI::initASTs()
54 {
55     if(framePtr.empty())
56     {
57         framePtr[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86)));
58         framePtr[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86_64)));
59         framePtr[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_ppc32)));
60         framePtr[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_ppc64)));
61     }
62     if(stackPtr.empty())
63     {
64         stackPtr[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86)));
65         stackPtr[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86_64)));
66         stackPtr[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_ppc32)));
67         stackPtr[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_ppc64)));
68     }
69     if(thePC.empty())
70     {
71         thePC[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_x86)));
72         thePC[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_x86_64)));
73         thePC[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_ppc32)));
74         thePC[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_ppc64)));
75     }
76 }
77
78 IA_IAPI::IA_IAPI(InstructionDecoder dec_, 
79         Address where_,
80         CodeObject * o,
81         CodeRegion * r,
82         InstructionSource *isrc) :
83     InstructionAdapter(where_, o, r, isrc), 
84     dec(dec_),
85     validCFT(false), 
86     cachedCFT(0),
87     validLinkerStubState(false)
88 {
89     hascftstatus.first = false;
90     tailCall.first = false;
91     boost::tuples::tie(curInsnIter, boost::tuples::ignore) = allInsns.insert(std::make_pair(current, dec.decode()));
92     initASTs();
93 }
94
95 void IA_IAPI::advance()
96 {
97     if(!curInsn()) {
98         parsing_printf("..... WARNING: failed to advance InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current,
99                        allInsns.size());
100         return;
101     }
102     InstructionAdapter::advance();
103     current += curInsn()->size();
104     boost::tuples::tie(curInsnIter, boost::tuples::ignore) = allInsns.insert(std::make_pair(current, dec.decode()));
105     if(!curInsn())
106     {
107         parsing_printf("......WARNING: after advance at 0x%lx, curInsn() NULL\n", current);
108     }
109     validCFT = false;
110     validLinkerStubState = false;
111     hascftstatus.first = false;
112     tailCall.first = false;
113 }
114
115 void IA_IAPI::retreat()
116 {
117     if(!curInsn()) {
118         parsing_printf("..... WARNING: failed to retreat InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current,
119                        allInsns.size());
120         return;
121     }
122     InstructionAdapter::retreat();
123     std::map<Address,Instruction::Ptr>::iterator remove = curInsnIter;
124     if(curInsnIter != allInsns.begin()) {
125         --curInsnIter;
126         allInsns.erase(remove);
127         current = curInsnIter->first;
128         if(curInsnIter != allInsns.begin()) {
129             std::map<Address,Instruction::Ptr>::iterator pit = curInsnIter;
130             --pit;
131             previous = curInsnIter->first;
132         } else {
133             previous = -1;
134         }
135     } else {
136         parsing_printf("..... WARNING: cowardly refusal to retreat past first instruction at 0x%lx\n", current);
137     }
138
139     /* blind duplication -- nate */
140     validCFT = false;
141     validLinkerStubState = false;
142     hascftstatus.first = false;
143     tailCall.first = false;
144
145     
146     
147
148 size_t IA_IAPI::getSize() const
149 {
150     Instruction::Ptr ci = curInsn();
151     assert(ci);
152     return ci->size();
153 }
154
155 bool IA_IAPI::hasCFT() const
156 {
157     if(hascftstatus.first) return hascftstatus.second;
158     InsnCategory c = curInsn()->getCategory();
159     hascftstatus.second = false;
160     if(c == c_BranchInsn ||
161        c == c_ReturnInsn)
162     {
163         hascftstatus.second = true;
164     }
165     if(c == c_CallInsn)
166     {
167         if(isRealCall()) {
168             hascftstatus.second = true;
169         }
170         if(isDynamicCall()) {
171             hascftstatus.second = true;
172         }
173         if(simulateJump()) {
174             hascftstatus.second = true;
175         }
176     }
177     hascftstatus.first = true;
178     return hascftstatus.second;
179 }
180
181 bool IA_IAPI::isAbortOrInvalidInsn() const
182 {
183     entryID e = curInsn()->getOperation().getID();
184     if(e == e_No_Entry)
185     {
186         parsing_printf("...WARNING: un-decoded instruction at 0x%x\n", current);
187     }
188     return e == e_No_Entry ||
189             e == e_int3 ||
190             e == e_hlt;
191 }
192
193 bool IA_IAPI::isFrameSetupInsn() const
194 {
195     return isFrameSetupInsn(curInsn());
196 }
197
198 bool IA_IAPI::isDynamicCall() const
199 {
200     Instruction::Ptr ci = curInsn();
201     if(ci && (ci->getCategory() == c_CallInsn))
202     {
203         if(getCFT() == 0)
204         {
205             parsing_printf("... Call 0x%lx is indirect\n", current);
206             return true;
207         }
208     }
209     return false;
210 }
211
212 bool IA_IAPI::isAbsoluteCall() const
213 {
214     Instruction::Ptr ci = curInsn();
215     if(ci->getCategory() == c_CallInsn)
216     {
217         Expression::Ptr cft = ci->getControlFlowTarget();
218         if(cft && dyn_detail::boost::dynamic_pointer_cast<Immediate>(cft))
219         {
220             return true;
221         }
222     }
223     return false;
224 }
225
226
227 bool IA_IAPI::isReturn() const
228 {
229     return curInsn()->getCategory() == c_ReturnInsn;
230 }
231 bool IA_IAPI::isBranch() const
232 {
233     return curInsn()->getCategory() == c_BranchInsn;
234 }
235 bool IA_IAPI::isCall() const
236 {
237     return curInsn()->getCategory() == c_CallInsn;
238 }
239
240 bool IA_IAPI::isInterruptOrSyscall() const
241 {
242     return (isInterrupt() && isSyscall());
243 }
244
245 bool IA_IAPI::isSyscall() const
246 {
247     static RegisterAST::Ptr gs(new RegisterAST(x86::gs));
248     
249     Instruction::Ptr ci = curInsn();
250
251     return (((ci->getOperation().getID() == e_call) &&
252             /*(curInsn()->getOperation().isRead(gs))) ||*/
253             (ci->getOperand(0).format() == "16")) ||
254             (ci->getOperation().getID() == e_syscall) || 
255             (ci->getOperation().getID() == e_int) || 
256             (ci->getOperation().getID() == power_op_sc));
257 }
258
259
260 bool IA_IAPI::isInterrupt() const
261 {
262     Instruction::Ptr ci = curInsn();
263     return ((ci->getOperation().getID() == e_int) ||
264             (ci->getOperation().getID() == e_int3));
265 }
266
267 void IA_IAPI::getNewEdges(
268         std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges,
269         Function* context,
270         Block* currBlk,
271         unsigned int num_insns,
272         dyn_hash_map<Address, std::string> *plt_entries) const
273 {
274     Instruction::Ptr ci = curInsn();
275
276     // Only call this on control flow instructions!
277     if(ci->getCategory() == c_CallInsn)
278     {
279         Address target = getCFT();
280         if(isRealCall() || isDynamicCall())
281         {
282             outEdges.push_back(std::make_pair(target, NOEDGE));
283         }
284         else
285         {
286             if(_isrc->isValidAddress(target))
287             {
288                 if(simulateJump())
289                 {
290                     parsing_printf("[%s:%u] call at 0x%lx simulated as "
291                             "jump to 0x%lx\n",
292                     FILE__,__LINE__,getAddr(),getCFT());
293                     outEdges.push_back(std::make_pair(target, DIRECT));
294                     return;
295                 }
296             }
297         }
298         outEdges.push_back(std::make_pair(getAddr() + getSize(),
299                            CALL_FT));
300         return;
301     }
302     else if(ci->getCategory() == c_BranchInsn)
303     {
304         Address target;
305         if(ci->allowsFallThrough())
306         {
307             outEdges.push_back(std::make_pair(getCFT(),
308                                COND_TAKEN));
309             outEdges.push_back(std::make_pair(getNextAddr(), COND_NOT_TAKEN));
310             return;
311         }
312         // Direct jump
313         else if((target = getCFT()) != 0)
314         {
315             Address catchStart;
316             if(_cr->findCatchBlock(getNextAddr(),catchStart))
317             {
318                 outEdges.push_back(std::make_pair(catchStart, CATCH));
319             }
320         
321
322             if(!isTailCall(context,num_insns))
323             {
324                 if(plt_entries->find(target) == plt_entries->end())
325                 {
326                     outEdges.push_back(std::make_pair(target,DIRECT));
327                 }
328                 else
329                 {
330                     parsing_printf("%s[%d]: PLT tail call to %x (%s)\n", 
331                         FILE__, __LINE__, target,
332                         (*plt_entries)[target].c_str());
333                     outEdges.push_back(std::make_pair(target, NOEDGE));
334                     tailCall.second = true;
335                 }
336             }
337             else
338             {
339                 parsing_printf("%s[%d]: tail call to %x\n", 
340                     FILE__, __LINE__, target);
341                 outEdges.push_back(std::make_pair(target, NOEDGE));
342             }
343             return;
344         }
345         else
346         {
347             parsing_printf("... indirect jump at 0x%x\n", current);
348             if( num_insns == 2 ) {
349                 parsing_printf("... uninstrumentable due to 0 size\n");
350                 return;
351             }
352             if(isTailCall(context,num_insns)) {
353                 parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__,
354                                ci->format().c_str(), current);
355                 return;
356             }
357             parsing_printf("%s[%d]: jump table candidate %s at 0x%lx\n", FILE__, __LINE__,
358                            ci->format().c_str(), current);
359             parsedJumpTable = true;
360             successfullyParsedJumpTable = parseJumpTable(currBlk, outEdges);
361
362             if(!successfullyParsedJumpTable || outEdges.empty()) {
363                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
364             }
365             return;
366         }
367     }
368     else if(ci->getCategory() == c_ReturnInsn)
369     {
370         if(ci->allowsFallThrough())
371         {
372             outEdges.push_back(std::make_pair(getNextAddr(), FALLTHROUGH));
373             return;
374         }
375         return;
376     }
377     fprintf(stderr, "Unhandled instruction %s\n", ci->format().c_str());
378     assert(0);
379 }
380
381 bool IA_IAPI::isIPRelativeBranch() const
382 {
383             // These don't exist on IA32...
384 #if !defined(arch_x86_64)
385     return false;
386 #endif
387     Instruction::Ptr ci = curInsn();
388
389     if(ci->getCategory() == c_BranchInsn &&
390         !getCFT())
391 {
392     Expression::Ptr cft = ci->getControlFlowTarget();
393     if(cft->isUsed(thePC[_isrc->getArch()]))
394     {
395         parsing_printf("\tIP-relative indirect jump to %s at 0x%lx\n",
396                        cft->format().c_str(), current);
397         return true;
398     }
399 }
400     return false;
401     
402 }
403
404 Instruction::Ptr IA_IAPI::curInsn() const
405 {
406     return curInsnIter->second;
407 }
408
409 bool IA_IAPI::isLeave() const
410 {
411     Instruction::Ptr ci = curInsn();
412     return ci && (ci->getOperation().getID() == e_leave);
413 }
414
415 bool IA_IAPI::isDelaySlot() const
416 {
417 #if defined(arch_sparc)
418     assert(!"Implement delay slots on SPARC!");
419 #endif
420     return false;
421 }
422
423 Instruction::Ptr IA_IAPI::getInstruction()
424 {
425     return curInsn();
426 }
427
428 bool IA_IAPI::isRealCall() const
429 {
430     if(getCFT() == getNextAddr())
431     {
432         parsing_printf("... getting PC\n");
433         return false;
434     }
435     if(!_isrc->isValidAddress(getCFT()))
436     {
437         CodeSource *_csrc = dynamic_cast<CodeSource *>(_isrc);
438         assert(_csrc);
439
440         if (_csrc->linkage().find(getCFT()) == _csrc->linkage().end()) {
441             parsing_printf(" isRealCall failed _isrc->isValidAddress(%lx)\n",
442                            getCFT());
443             return false;
444         }
445     }
446     if(isThunk()) {
447         return false;
448     }
449     return true;
450 }
451
452 std::map<Address, bool> IA_IAPI::thunkAtTarget;
453
454 bool IA_IAPI::isConditional() const
455 {
456     return curInsn()->allowsFallThrough();
457 }
458
459 bool IA_IAPI::simulateJump() const
460 {
461     // obfuscated programs simulate jumps by calling into a block that 
462     // discards the return address from the stack, we check for these
463     // fake calls in malware mode
464     if (_obj->defensiveMode()) {
465         return isFakeCall();
466     }
467     // TODO: we don't simulate jumps on x86 architectures; add logic as we need it.                
468     return false;
469 }
470
471 Address IA_IAPI::getCFT() const
472 {
473     if(validCFT) return cachedCFT;
474     Expression::Ptr callTarget = curInsn()->getControlFlowTarget();
475         // FIXME: templated bind(),dammit!
476     callTarget->bind(thePC[_isrc->getArch()].get(), Result(s64, current));
477     parsing_printf("%s[%d]: binding PC %s in %s to 0x%x...", FILE__, __LINE__,
478                    thePC[_isrc->getArch()]->format().c_str(), curInsn()->format().c_str(), current);
479     Result actualTarget = callTarget->eval();
480     if(actualTarget.defined)
481     {
482         cachedCFT = actualTarget.convert<Address>();
483         parsing_printf("SUCCESS (CFT=0x%x)\n", cachedCFT);
484     }
485     else
486     {
487         cachedCFT = 0;
488         parsing_printf("FAIL (CFT=0x%x), callTarget exp: %s\n",
489                        cachedCFT,callTarget->format().c_str());
490     }
491     validCFT = true;
492
493     if(isLinkerStub()) {
494         parsing_printf("Linker stub detected: Correcting CFT.  (CFT=0x%x)\n",
495                        cachedCFT);
496     }
497
498     return cachedCFT;
499 }
500
501 bool IA_IAPI::isRelocatable(InstrumentableLevel lvl) const
502 {
503     Instruction::Ptr ci = curInsn();
504     if(ci && (ci->getCategory() == c_CallInsn))
505     {
506         if(!isDynamicCall())
507         {
508             if(!_isrc->isValidAddress(getCFT()))
509             {
510                 parsing_printf("... Call to 0x%lx is invalid (outside code or data)\n",
511                                getCFT());
512                 return false;
513             }
514         }
515     }
516     if(lvl == HAS_BR_INDIR)
517     {
518         return false;
519     }
520     return true;
521 }
522
523 InstrumentableLevel IA_IAPI::getInstLevel(Function * context, unsigned int num_insns) const
524 {
525     InstrumentableLevel ret = InstructionAdapter::getInstLevel(context, num_insns);
526 /*    if(ret == HAS_BR_INDIR && isIPRelativeBranch())
527     {
528         return NORMAL;
529 }*/
530     return ret;
531 }