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