Defer constructing blocksByRange to function finalizing, and removing the use blocksB...
[dyninst.git] / parseAPI / src / IA_x86.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
32 #include "IA_x86.h"
33 #include "Register.h"
34 #include "Dereference.h"
35 #include "Immediate.h"
36 #include "BinaryFunction.h"
37 #include "debug_parse.h"
38 #include "dataflowAPI/h/slicing.h"
39 #include "dataflowAPI/h/SymEval.h"
40 //#include "StackTamperVisitor.h"
41 #include "instructionAPI/h/Visitor.h"
42
43 #include <deque>
44
45 using namespace Dyninst;
46 using namespace InstructionAPI;
47 using namespace Dyninst::InsnAdapter;
48 using namespace Dyninst::ParseAPI;
49
50 IA_x86::IA_x86(Dyninst::InstructionAPI::InstructionDecoder dec_,
51                Address start_,
52                Dyninst::ParseAPI::CodeObject* o,
53                Dyninst::ParseAPI::CodeRegion* r,
54                Dyninst::InstructionSource *isrc,
55                Dyninst::ParseAPI::Block * curBlk_):
56                    IA_IAPI(dec_, start_, o, r, isrc, curBlk_) {
57 }
58
59 IA_x86::IA_x86(const IA_x86& rhs): IA_IAPI(rhs) {}
60
61 IA_x86* IA_x86::clone() const {
62     return new IA_x86(*this);
63 }
64
65 bool IA_x86::isFrameSetupInsn(Instruction i) const
66 {
67     if(i.getOperation().getID() == e_mov)
68     {
69         if(i.readsMemory() || i.writesMemory())
70         {
71             parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, not a reg-reg move\n",
72                            FILE__, __LINE__, i.format().c_str());
73             //return false;
74         }
75         if(i.isRead(stackPtr[_isrc->getArch()]) &&
76            i.isWritten(framePtr[_isrc->getArch()]))
77         {
78             if((unsigned) i.getOperand(0).getValue()->size() == _isrc->getAddressWidth())
79             {
80                 return true;
81             }
82             else
83             {
84                 parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, size mismatch for %d-byte addr width\n",
85                                FILE__, __LINE__, i.format().c_str(), _isrc->getAddressWidth());
86             }
87         }
88     }
89     return false;
90 }
91
92 class nopVisitor : public InstructionAPI::Visitor
93 {
94     public:
95         nopVisitor() : foundReg(false), foundImm(false), foundBin(false), isNop(true) {}
96         virtual ~nopVisitor() {}
97
98         bool foundReg;
99         bool foundImm;
100         bool foundBin;
101         bool isNop;
102
103         virtual void visit(BinaryFunction*)
104         {
105             if (foundBin) isNop = false;
106             if (!foundImm) isNop = false;
107             if (!foundReg) isNop = false;
108             foundBin = true;
109         }
110         virtual void visit(Immediate *imm)
111         {
112             if (imm != 0) isNop = false;
113             foundImm = true;
114         }
115         virtual void visit(RegisterAST *)
116         {
117             foundReg = true;
118         }
119         virtual void visit(Dereference *)
120         {
121             isNop = false;
122         }
123 };
124
125 bool isNopInsn(Instruction insn)
126 {
127     // TODO: add LEA no-ops
128     if(insn.getOperation().getID() == e_nop)
129         return true;
130     if(insn.getOperation().getID() == e_lea)
131     {
132         std::set<Expression::Ptr> memReadAddr;
133         insn.getMemoryReadOperands(memReadAddr);
134         std::set<RegisterAST::Ptr> writtenRegs;
135         insn.getWriteSet(writtenRegs);
136
137         if(memReadAddr.size() == 1 && writtenRegs.size() == 1)
138         {
139             if(**(memReadAddr.begin()) == **(writtenRegs.begin()))
140             {
141                 return true;
142             }
143         }
144         // Check for zero displacement
145         nopVisitor visitor;
146
147         // We need to get the src operand
148         insn.getOperand(1).getValue()->apply(&visitor);
149         if (visitor.isNop) return true; 
150     }
151     return false;
152 }
153
154 bool IA_x86::isNop() const
155 {
156     Instruction ci = curInsn();
157
158
159     return isNopInsn(ci);
160
161 }
162
163 /*
164  * A `thunk' is a function composed of the following pair of instructions:
165  
166  thunk:
167     mov (%esp), <some register>
168     ret
169  
170  * It has the effect of putting the address following a call to `thunk' into
171  * the register, and is used in position independent code.
172  */
173 namespace {
174     class ThunkVisitor : public InstructionAPI::Visitor {
175      public:
176         ThunkVisitor() : offset_(0) { }
177         virtual void visit(BinaryFunction *) {
178             return;
179         }
180         virtual void visit(Immediate *i) {
181             offset_ = i->eval().convert<Address>();
182         }
183         virtual void visit(RegisterAST*) {
184             return;
185         }
186         virtual void visit(Dereference*) {
187             return;
188         }
189         Address offset() const { return offset_; }
190
191      private:
192         Address offset_;
193     };
194 }
195 bool IA_x86::isThunk() const {
196   // Before we go a-wandering, check the target
197    bool valid; Address addr;
198    boost::tie(valid, addr) = getCFT();
199    if (!valid ||
200        !_isrc->isValidAddress(addr)) {
201         parsing_printf("... Call to 0x%lx is invalid (outside code or data)\n",
202                        addr);
203         return false;
204     }
205
206     const unsigned char *target =
207        (const unsigned char *)_isrc->getPtrToInstruction(addr);
208     InstructionDecoder targetChecker(target,
209             2*InstructionDecoder::maxInstructionLength, _isrc->getArch());
210     Instruction thunkFirst = targetChecker.decode();
211     Instruction thunkSecond = targetChecker.decode();
212     if((thunkFirst.getOperation().getID() == e_mov) &&
213         (thunkSecond.getCategory() == c_ReturnInsn))
214     {
215         if(thunkFirst.isRead(stackPtr[_isrc->getArch()]))
216         {
217             // it is not enough that the stack pointer is read; it must
218             // be a zero-offset read from the stack pointer
219             ThunkVisitor tv;
220             Operand op = thunkFirst.getOperand(1);
221             op.getValue()->apply(&tv); 
222     
223             return tv.offset() == 0; 
224         }
225     }
226     return false;
227 }
228
229 bool IA_x86::isTailCall(const Function *context, EdgeTypeEnum type, unsigned int,
230                         const set<Address> &knownTargets) const
231 {
232    // Collapse down to "branch" or "fallthrough"
233     switch(type) {
234        case COND_TAKEN:
235        case DIRECT:
236        case INDIRECT:
237           type = DIRECT;
238           break;
239        case CALL:
240        case RET:
241        case COND_NOT_TAKEN:
242        case FALLTHROUGH:
243        case CALL_FT:
244        default:
245           return false;
246     }
247
248     parsing_printf("Checking for Tail Call for x86\n");
249     context->obj()->cs()->incrementCounter(PARSE_TAILCALL_COUNT); 
250     if (tailCalls.find(type) != tailCalls.end()) {
251         parsing_printf("\tReturning cached tail call check result: %d\n", tailCalls[type]);
252         if (tailCalls[type]) {
253             context->obj()->cs()->incrementCounter(PARSE_TAILCALL_FAIL);
254             return true;
255         }
256         return false;
257     }
258     
259     bool valid; Address addr;
260     boost::tie(valid, addr) = getCFT();
261
262     Function* callee = _obj->findFuncByEntry(_cr, addr);
263     Block* target = _obj->findBlockByEntry(_cr, addr);
264     if(curInsn().getCategory() == c_BranchInsn &&
265        valid &&
266        callee && 
267        callee != context &&
268        /* the target can either be not parsed or not within the current context */
269        ((target == NULL) || (target && !context->contains(target)))
270        )
271     {
272       parsing_printf("\tjump to 0x%lx, TAIL CALL\n", addr);
273       tailCalls[type] = true;
274       return true;
275     }
276
277     if (curInsn().getCategory() == c_BranchInsn &&
278             valid &&
279             !callee) {
280         if (target) {
281             parsing_printf("\tjump to 0x%lx is known block, but not func entry, NOT TAIL CALL\n", addr);
282             tailCalls[type] = false;
283             return false;
284         } else if (knownTargets.find(addr) != knownTargets.end()) {
285             parsing_printf("\tjump to 0x%lx is known target in this function, NOT TAIL CALL\n", addr);
286             tailCalls[type] = false;
287             return false;
288         }
289     }
290
291     if(allInsns.size() < 2) {
292       if(context->addr() == _curBlk->start() && curInsn().getCategory() == c_BranchInsn)
293       {
294         parsing_printf("\tjump as only insn in entry block, TAIL CALL\n");
295         tailCalls[type] = true;
296         return true;
297       }
298       else
299       {
300         parsing_printf("\ttoo few insns to detect tail call\n");
301         context->obj()->cs()->incrementCounter(PARSE_TAILCALL_FAIL);
302         tailCalls[type] = false;
303         return false;
304       }
305     }
306
307     if ((curInsn().getCategory() == c_BranchInsn))
308     {
309         //std::map<Address, Instruction::Ptr>::const_iterator prevIter =
310                 //allInsns.find(current);
311         
312         // Updated: there may be zero or more nops between leave->jmp
313        
314         allInsns_t::const_iterator prevIter = curInsnIter;
315         --prevIter;
316         Instruction prevInsn = prevIter->second;
317     
318         while ( isNopInsn(prevInsn) && (prevIter != allInsns.begin()) ) {
319            --prevIter;
320            prevInsn = prevIter->second;
321         }
322         prevInsn = prevIter->second;
323         if(prevInsn.getOperation().getID() == e_leave)
324         {
325            parsing_printf("\tprev insn was leave, TAIL CALL\n");
326            tailCalls[type] = true;
327            return true;
328         }
329         else if(prevInsn.getOperation().getID() == e_pop)
330         {
331             if(prevInsn.isWritten(framePtr[_isrc->getArch()]))
332             {
333                 parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn.format().c_str());
334                 tailCalls[type] = true;
335                 return true;
336             }
337         }
338         else if(prevInsn.getOperation().getID() == e_add)
339         {                       
340             if(prevInsn.isWritten(stackPtr[_isrc->getArch()]))
341             {
342                                 bool call_fallthrough = false;
343                 boost::lock_guard<Block> g(*_curBlk);
344
345                                 if (_curBlk->start() == prevIter->first) {
346                                         for (auto eit = _curBlk->sources().begin(); eit != _curBlk->sources().end(); ++eit) {                                           
347                                                 if ((*eit)->type() == CALL_FT) {
348                                                         call_fallthrough = true;
349                                                         break;
350                                                 }
351                                         }
352                                 }
353                                 if (call_fallthrough) {
354                                         parsing_printf("\tprev insn was %s, but it is the next instruction of a function call, not a tail call %x %x\n",
355                                    prevInsn.format().c_str());
356                                 }       else {
357                                         parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn.format().c_str());
358                                         tailCalls[type] = true;
359                                         return true;
360                                 }
361                         } else
362                                 parsing_printf("\tprev insn was %s, not tail call\n", prevInsn.format().c_str());
363         }
364     }
365
366     tailCalls[type] = false;
367     context->obj()->cs()->incrementCounter(PARSE_TAILCALL_FAIL);
368     return false;
369 }
370
371 bool IA_x86::savesFP() const
372 {
373         std::vector<Instruction> insns;
374         insns.push_back(curInsn());
375 #if defined(os_windows)
376         // Windows functions can start with a noop...
377         InstructionDecoder tmp(dec);
378         insns.push_back(tmp.decode());
379 #endif
380         for (unsigned i = 0; i < insns.size(); ++i) {
381                 InstructionAPI::Instruction ci = insns[i];
382             if(ci.getOperation().getID() == e_push)
383                 {
384                         if (ci.isRead(framePtr[_isrc->getArch()])) {
385                                 return true;
386                         }
387                         else return false;
388                 }
389         }       
390         return false;
391 }
392
393 bool IA_x86::isStackFramePreamble() const
394 {
395 #if defined(os_windows)
396         // Windows pads with a noop
397         const int limit = 3;
398 #else 
399         const int limit = 2;
400 #endif
401         if (!savesFP()) return false;
402     InstructionDecoder tmp(dec);
403     std::vector<Instruction::Ptr> nextTwoInsns;
404     for (int i = 0; i < limit; ++i) {
405        Instruction insn = tmp.decode();
406        if (isFrameSetupInsn(insn)) {
407           return true;
408        }
409     }
410         return false;
411 }
412
413 bool IA_x86::cleansStack() const
414 {
415     Instruction ci = curInsn();
416         if (ci.getCategory() != c_ReturnInsn) return false;
417     std::vector<Operand> ops;
418         ci.getOperands(ops);
419         return (ops.size() > 1);
420 }
421
422 bool IA_x86::isReturn(Dyninst::ParseAPI::Function * /*context*/,
423                         Dyninst::ParseAPI::Block* /*currBlk*/) const
424 {
425     // For x86, we check if an instruction is return based on the category. 
426     // However, for powerpc, the return instruction BLR can be a return or
427     // an indirect jump used for jump tables etc. Hence, we need to function and block
428     // to determine if an instruction is a return. But these parameters are unused for x86. 
429     return curInsn().getCategory() == c_ReturnInsn;
430 }
431
432 bool IA_x86::isReturnAddrSave(Dyninst::Address&) const
433 {
434     // not implemented on non-power
435     return false;
436 }
437
438 bool IA_x86::sliceReturn(ParseAPI::Block* /*bit*/, Address /*ret_addr*/, ParseAPI::Function * /*func*/) const {
439    return true;
440 }
441
442 //class ST_Predicates : public Slicer::Predicates {};
443
444
445 /* returns true if the call leads to:
446  * -an invalid instruction (or immediately branches/calls to an invalid insn)
447  * -a block not ending in a return instruction that pops the return address 
448  *  off of the stack
449  */
450 bool IA_x86::isFakeCall() const
451 {
452     assert(_obj->defensiveMode());
453
454     if (isDynamicCall()) {
455         return false;
456     }
457
458     // get func entry
459     bool tampers = false;
460     bool valid; Address entry;
461     boost::tie(valid, entry) = getCFT();
462
463     if (!valid) return false;
464
465     if (! _cr->contains(entry) ) {
466        return false;
467     }
468
469     if ( ! _isrc->isCode(entry) ) {
470         mal_printf("WARNING: found function call at %lx "
471                    "to invalid address %lx %s[%d]\n", current, 
472                    entry, FILE__,__LINE__);
473         return false;
474     }
475
476     // get instruction at func entry
477     const unsigned char* bufPtr =
478      (const unsigned char *)(_cr->getPtrToInstruction(entry));
479     Offset entryOff = entry - _cr->offset();
480     InstructionDecoder newdec( bufPtr,
481                               _cr->length() - entryOff,
482                               _cr->getArch() );
483     IA_x86 *ah = new IA_x86(newdec, entry, _obj, _cr, _isrc, _curBlk);
484     Instruction insn = ah->curInsn();
485
486     // follow ctrl transfers until you get a block containing non-ctrl 
487     // transfer instructions, or hit a return instruction
488     while (insn.getCategory() == c_CallInsn ||
489            insn.getCategory() == c_BranchInsn)
490     {
491        boost::tie(valid, entry) = ah->getCFT();
492        if ( !valid || ! _cr->contains(entry) || ! _isrc->isCode(entry) ) {
493           mal_printf("WARNING: found call to function at %lx that "
494                      "leaves to %lx, out of the code region %s[%d]\n", 
495                      current, entry, FILE__,__LINE__);
496           return false;
497        }
498         bufPtr = (const unsigned char *)(_cr->getPtrToInstruction(entry));
499         entryOff = entry - _cr->offset();
500         delete(ah);
501         newdec = InstructionDecoder(bufPtr, 
502                                     _cr->length() - entryOff, 
503                                     _cr->getArch());
504         ah = new IA_x86(newdec, entry, _obj, _cr, _isrc, _curBlk);
505         insn = ah->curInsn();
506     }
507
508     // calculate instruction stack deltas for the block, leaving the iterator
509     // at the last ins'n if it's a control transfer, or after calculating the 
510     // last instruction's delta if we run off the end of initialized memory
511     int stackDelta = 0;
512     int addrWidth = _isrc->getAddressWidth();
513     static Expression::Ptr theStackPtr
514         (new RegisterAST(MachRegister::getStackPointer(_isrc->getArch())));
515     Address curAddr = entry;
516
517     while(true) {
518
519         // exit condition 1
520         if (insn.getCategory() == c_CallInsn ||
521             insn.getCategory() == c_ReturnInsn ||
522             insn.getCategory() == c_BranchInsn)
523         {
524             break;
525         }
526
527         // calculate instruction delta
528         if(insn.isWritten(theStackPtr)) {
529             entryID what = insn.getOperation().getID();
530             int sign = 1;
531             switch(what) 
532             {
533             case e_push:
534                 sign = -1;
535                 //FALLTHROUGH
536             case e_pop: {
537                 int size = insn.getOperand(0).getValue()->size();
538                 stackDelta += sign * size;
539                 break;
540             }
541             case e_pusha:
542             case e_pushad:
543                 sign = -1;
544                 //FALLTHROUGH
545             case e_popa:
546             case e_popad:
547                 if (1 == sign) {
548                     mal_printf("popad ins'n at %lx in func at %lx changes sp "
549                                "by %d. %s[%d]\n", ah->getAddr(), 
550                                entry, 8 * sign * addrWidth, FILE__, __LINE__);
551                 }
552                 stackDelta += sign * 8 * addrWidth;
553                 break;
554             case e_pushf:
555             case e_pushfd:
556                 sign = -1;
557                 //FALLTHROUGH
558             case e_popf:
559             case e_popfd:
560                 stackDelta += sign * 4;
561                 if (1 == sign) {
562                     mal_printf("popf ins'n at %lx in func at %lx changes sp "
563                                "by %d. %s[%d]\n", ah->getAddr(), entry, 
564                                sign * 4, FILE__, __LINE__);
565                 }
566                 break;
567             case e_enter:
568                 //mal_printf("Saw enter instruction at %lx in isFakeCall, "
569                 //           "quitting early, assuming not fake "
570                 //           "%s[%d]\n",curAddr, FILE__,__LINE__);
571                 // unhandled case, but not essential for correct analysis
572                 delete ah;
573                 return false;
574                 break;
575             case e_leave:
576                 mal_printf("WARNING: saw leave instruction "
577                            "at %lx that is not handled by isFakeCall %s[%d]\n",
578                            curAddr, FILE__,__LINE__);
579                 // unhandled, not essential for correct analysis, would
580                 // be a red flag if there wasn't an enter ins'n first and 
581                 // we didn't end in a return instruction
582                 break;
583                         case e_and:
584                                 // Rounding off the stack pointer. 
585                                 mal_printf("WARNING: saw and instruction at %lx that is not handled by isFakeCall %s[%d]\n",
586                                         curAddr, FILE__, __LINE__);
587                                 delete ah;
588                                 return false;
589                                 break;
590
591             case e_sub:
592                 sign = -1;
593                 //FALLTHROUGH
594             case e_add: {
595                 Operand arg = insn.getOperand(1);
596                 Result delta = arg.getValue()->eval();
597                 if(delta.defined) {
598                     int delta_int = sign;
599                     switch (delta.type) {
600                     case u8:
601                     case s8:
602                         delta_int *= (int)delta.convert<char>();
603                         break;
604                     case u16:
605                     case s16:
606                         delta_int *= (int)delta.convert<short>();
607                         break;
608                     case u32:
609                     case s32:
610                         delta_int *= delta.convert<int>();
611                         break;
612                     default:
613                         assert(0 && "got add/sub operand of unusual size");
614                         break;
615                     }
616                     stackDelta += delta_int;
617                 } else if (sign == -1) {
618                     delete ah;
619                     return false;
620                 } else {
621                     mal_printf("ERROR: in isFakeCall, add ins'n "
622                                "at %lx (in first block of function at "
623                                "%lx) modifies the sp but failed to evaluate "
624                                "its arguments %s[%d]\n", 
625                                ah->getAddr(), entry, FILE__, __LINE__);
626                     delete ah;
627                     return true;
628                 }
629                 break;
630             }
631             default: {
632                 fprintf(stderr,"WARNING: in isFakeCall non-push/pop "
633                         "ins'n at %lx (in first block of function at "
634                         "%lx) modifies the sp by an unknown amount. "
635                         "%s[%d]\n", ah->getAddr(), entry, 
636                         FILE__, __LINE__);
637                 break;
638             } // end default block
639             } // end switch
640         }
641
642         if (stackDelta > 0) {
643             tampers=true;
644         }
645
646         // exit condition 2
647         ah->advance();
648         Instruction next = ah->curInsn();
649         if (!next.isValid()) {
650             break;
651         }
652         curAddr += insn.size();
653         insn = next;
654     } 
655
656     // not a fake call if it ends w/ a return instruction
657     if (insn.getCategory() == c_ReturnInsn) {
658         delete ah;
659         return false;
660     }
661
662     // if the stack delta is positive or the return address has been replaced
663     // with an absolute value, it's a fake call, since in both cases 
664     // the return address is gone and we cannot return to the caller
665     if ( 0 < stackDelta || tampers ) {
666
667         delete ah;
668         return true;
669     }
670
671     delete ah;
672     return false;
673 }
674
675 bool IA_x86::isIATcall(std::string &calleeName) const
676 {
677     if (!isDynamicCall()) {
678         return false;
679     }
680
681     if (!curInsn().readsMemory()) {
682         return false;
683     }
684
685     std::set<Expression::Ptr> memReads;
686     curInsn().getMemoryReadOperands(memReads);
687     if (memReads.size() != 1) {
688         return false;
689     }
690
691     Result memref = (*memReads.begin())->eval();
692     if (!memref.defined) {
693         return false;
694     }
695     Address entryAddr = memref.convert<Address>();
696
697     // convert to a relative address
698     if (_obj->cs()->loadAddress() < entryAddr) {
699         entryAddr -= _obj->cs()->loadAddress();
700     }
701     
702     if (!_obj->cs()->isValidAddress(entryAddr)) {
703         return false;
704     }
705
706     // calculate the address of the ASCII string pointer, 
707     // skip over the IAT entry's two-byte hint
708     void * asciiPtr = _obj->cs()->getPtrToInstruction(entryAddr);
709     if (!asciiPtr) {
710         return false;
711     }
712     Address funcAsciiAddr = 2 + *(Address*) asciiPtr;
713     if (!_obj->cs()->isValidAddress(funcAsciiAddr)) {
714         return false;
715     }
716
717     // see if it's really a string that could be a function name
718     char *funcAsciiPtr = (char*) _obj->cs()->getPtrToData(funcAsciiAddr);
719     if (!funcAsciiPtr) {
720         return false;
721     }
722     char cur = 'a';
723     int count=0;
724     do {
725         cur = funcAsciiPtr[count];
726         count++;
727     }while (count < 100 && 
728             _obj->cs()->isValidAddress(funcAsciiAddr+count) &&
729             ((cur >= 'A' && cur <= 'z') ||
730              (cur >= '0' && cur <= '9')));
731     if (cur != 0 || count <= 1) 
732         return false;
733
734     mal_printf("found IAT call at %lx to %s\n", current, funcAsciiPtr);
735     calleeName = string(funcAsciiPtr);
736     return true;
737 }
738
739 bool IA_x86::isNopJump() const
740 {
741     InsnCategory cat = curInsn().getCategory();
742     if (c_BranchInsn != cat) {
743         return false;
744     }
745     bool valid; Address addr;
746     boost::tie(valid, addr) = getCFT();
747     if(valid && current+1 == addr) {
748         return true;
749     }
750     return false;
751 }
752
753 bool IA_x86::isLinkerStub() const
754 {
755     // No need for linker stubs on x86 platforms.
756     return false;
757 }