Experimental: support parsing of indirect tail calls when they appear as a function...
[dyninst.git] / parseAPI / src / IA_IAPI.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 "dyntypes.h"
32 #include "dyn_regs.h"
33 #include "IA_IAPI.h"
34 #include "util.h"
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 #include "common/src/Types.h"
43 #include "dyntypes.h"
44
45 #include <deque>
46 #include <map>
47
48 #if defined(os_vxworks)
49 #include "common/src/wtxKludges.h"
50 #endif
51
52 using namespace Dyninst;
53 using namespace InstructionAPI;
54 using namespace Dyninst::InsnAdapter;
55 using namespace Dyninst::ParseAPI;
56
57 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::framePtr;
58 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::stackPtr;
59 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::thePC;
60
61 IA_IAPI::IA_IAPI(const IA_IAPI &rhs) 
62    : InstructionAdapter(rhs),
63      dec(rhs.dec),
64      allInsns(rhs.allInsns),
65      validCFT(rhs.validCFT),
66      cachedCFT(rhs.cachedCFT),
67      validLinkerStubState(rhs.validLinkerStubState),
68      cachedLinkerStubState(rhs.cachedLinkerStubState),
69      hascftstatus(rhs.hascftstatus),
70      tailCalls(rhs.tailCalls) {
71    //curInsnIter = allInsns.find(rhs.curInsnIter->first);
72     curInsnIter = allInsns.end()-1;
73 }
74
75 IA_IAPI &IA_IAPI::operator=(const IA_IAPI &rhs) {
76    dec = rhs.dec;
77    allInsns = rhs.allInsns;
78    //curInsnIter = allInsns.find(rhs.curInsnIter->first);
79    curInsnIter = allInsns.end()-1;
80    validCFT = rhs.validCFT;
81    cachedCFT = rhs.cachedCFT;
82    validLinkerStubState = rhs.validLinkerStubState;
83    cachedLinkerStubState = rhs.cachedLinkerStubState;
84    hascftstatus = rhs.hascftstatus;
85    tailCalls = rhs.tailCalls;
86
87    // InstructionAdapter members
88    current = rhs.current;
89    previous = rhs.previous;
90    parsedJumpTable = rhs.parsedJumpTable;
91    successfullyParsedJumpTable = rhs.successfullyParsedJumpTable;
92    isDynamicCall_ = rhs.isDynamicCall_;
93    checkedDynamicCall_ = rhs.checkedDynamicCall_;
94    isInvalidCallTarget_ = rhs.isInvalidCallTarget_;
95    checkedInvalidCallTarget_ = rhs.checkedInvalidCallTarget_;
96    _obj = rhs._obj;
97    _cr = rhs._cr;
98    _isrc = rhs._isrc;
99    _curBlk = rhs._curBlk;
100
101    return *this;
102 }
103
104 void IA_IAPI::initASTs()
105 {
106     if(framePtr.empty())
107     {
108         framePtr[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86)));
109         framePtr[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86_64)));
110         framePtr[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_ppc32)));
111         framePtr[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_ppc64)));
112     }
113     if(stackPtr.empty())
114     {
115         stackPtr[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86)));
116         stackPtr[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86_64)));
117         stackPtr[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_ppc32)));
118         stackPtr[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_ppc64)));
119     }
120     if(thePC.empty())
121     {
122         thePC[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_x86)));
123         thePC[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_x86_64)));
124         thePC[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_ppc32)));
125         thePC[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_ppc64)));
126     }
127 }
128
129 IA_IAPI::IA_IAPI(InstructionDecoder dec_, 
130         Address where_,
131         CodeObject * o,
132         CodeRegion * r,
133         InstructionSource *isrc,
134         Block * curBlk_) :
135     InstructionAdapter(where_, o, r, isrc, curBlk_), 
136     dec(dec_),
137     validCFT(false), 
138     cachedCFT(std::make_pair(false, 0)),
139     validLinkerStubState(false)
140 {
141     hascftstatus.first = false;
142     tailCalls.clear();
143
144     //boost::tuples::tie(curInsnIter, boost::tuples::ignore) = allInsns.insert(std::make_pair(current, dec.decode()));
145     curInsnIter =
146         allInsns.insert(
147             allInsns.end(),
148             std::make_pair(current, dec.decode()));
149
150     initASTs();
151 }
152
153 void
154 IA_IAPI::reset(
155     InstructionDecoder dec_,
156     Address start,
157     CodeObject *o,
158     CodeRegion *r,
159     InstructionSource *isrc,
160     Block * curBlk_)
161 {
162     // reset the base
163     InstructionAdapter::reset(start,o,r,isrc,curBlk_);
164
165     dec = dec_;
166     validCFT = false;
167     cachedCFT = make_pair(false, 0);
168     validLinkerStubState = false; 
169     hascftstatus.first = false;
170     tailCalls.clear();
171
172     allInsns.clear();
173
174     curInsnIter =
175         allInsns.insert(
176             allInsns.end(),
177             std::make_pair(current, dec.decode()));
178
179     initASTs();
180 }
181
182
183 void IA_IAPI::advance()
184 {
185     if(!curInsn()) {
186         parsing_printf("..... WARNING: failed to advance InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current,
187                        allInsns.size());
188         return;
189     }
190     InstructionAdapter::advance();
191     current += curInsn()->size();
192
193     curInsnIter =
194         allInsns.insert(
195             allInsns.end(),
196             std::make_pair(current, dec.decode()));
197
198     if(!curInsn())
199     {
200         parsing_printf("......WARNING: after advance at 0x%lx, curInsn() NULL\n", current);
201     }
202     validCFT = false;
203     validLinkerStubState = false;
204     hascftstatus.first = false;
205     tailCalls.clear();
206 }
207
208 bool IA_IAPI::retreat()
209 {
210     if(!curInsn()) {
211         parsing_printf("..... WARNING: failed to retreat InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current,
212                        allInsns.size());
213         return false;
214     }
215     InstructionAdapter::retreat();
216     allInsns_t::iterator remove = curInsnIter;
217     if(curInsnIter != allInsns.begin()) {
218         --curInsnIter;
219         allInsns.erase(remove);
220         current = curInsnIter->first;
221         if(curInsnIter != allInsns.begin()) {
222             allInsns_t::iterator pit = curInsnIter;
223             --pit;
224             previous = curInsnIter->first;
225         } else {
226             previous = -1;
227         }
228     } else {
229         parsing_printf("..... WARNING: cowardly refusal to retreat past first instruction at 0x%lx\n", current);
230         return false;
231     }
232
233     /* blind duplication -- nate */
234     validCFT = false;
235     validLinkerStubState = false;
236     hascftstatus.first = false;
237     tailCalls.clear();
238     return true;
239
240     
241     
242
243 size_t IA_IAPI::getSize() const
244 {
245     Instruction::Ptr ci = curInsn();
246     assert(ci);
247     return ci->size();
248 }
249
250 bool IA_IAPI::hasCFT() const
251 {
252     parsing_cerr << "hasCFT called" << endl;
253   if(hascftstatus.first) {
254     parsing_cerr << "\t Returning cached entry: " << hascftstatus.second << endl;
255     return hascftstatus.second;
256   }
257   InsnCategory c = curInsn()->getCategory();
258   hascftstatus.second = false;
259   if(c == c_BranchInsn ||
260      c == c_ReturnInsn) {
261      if ( likely ( ! (_obj->defensiveMode() && isNopJump()) ) ) {
262         parsing_cerr << "\t branch or return, ret true" << endl;
263         hascftstatus.second = true;
264      }
265   }
266   else if(c == c_CallInsn) {
267      if(isRealCall()) {
268         hascftstatus.second = true;
269      }
270      else if(isDynamicCall()) {
271         hascftstatus.second = true;
272      }
273      else if(simulateJump()) {
274         hascftstatus.second = true;
275      }
276   }
277   else if(c == c_SysEnterInsn) 
278   {
279     hascftstatus.second = true;
280   }
281   
282   hascftstatus.first = true;
283   return hascftstatus.second;
284 }
285
286 bool IA_IAPI::isAbort() const
287 {
288     entryID e = curInsn()->getOperation().getID();
289     return e == e_int3 ||
290        e == e_hlt;
291 }
292
293 bool IA_IAPI::isInvalidInsn() const
294 {
295     entryID e = curInsn()->getOperation().getID();
296     if(e == e_No_Entry)
297     {
298        parsing_printf("...WARNING: un-decoded instruction at 0x%x\n", current);
299        return true;
300     }
301     return false;
302 }
303
304 /* This function determines if a given instruction is weird enough that we've
305  * probably veered into non-code bytes and are parsing garbage.  
306  * note: yes, some of the code in here is does low-level things like 
307  *       grab instruction bytes directly instead of relying on the parseAPI,
308  *       but since this code executes for every parsed instruction, it needs
309  *       to be efficient.  
310  */
311 bool IA_IAPI::isGarbageInsn() const
312 {
313     bool ret = false;
314     // GARBAGE PARSING HEURISTIC
315     if (unlikely(_obj->defensiveMode())) {
316         entryID e = curInsn()->getOperation().getID();
317         switch (e) {
318         case e_arpl:
319             cerr << "REACHED AN ARPL AT "<< std::hex << current 
320                  << std::dec <<" COUNTING AS INVALID" << endl;
321             ret = true;
322             break;
323         case e_fisub:
324             cerr << "REACHED A FISUB AT "<< std::hex << current 
325                  << std::dec <<" COUNTING AS INVALID" << endl;
326             ret = true;
327             break;
328         case e_into:
329             cerr << "REACHED AN INTO AT "<< std::hex << current 
330                  << std::dec <<" COUNTING AS INVALID" << endl;
331             ret = true;
332             break;
333         case e_mov: {
334             set<RegisterAST::Ptr> regs;
335             curInsn()->getWriteSet(regs);
336             for (set<RegisterAST::Ptr>::iterator rit = regs.begin();
337                  rit != regs.end(); rit++) 
338             {
339                 if (Dyninst::isSegmentRegister((*rit)->getID().regClass())) {
340                     cerr << "REACHED A MOV SEGMENT INSN AT "<< std::hex 
341                         << current << std::dec <<" COUNTING AS INVALID" << endl;
342                     ret = true;
343                     break;
344                 }
345             }
346             break;
347         }
348         case e_add:
349             if (2 == curInsn()->size() && 
350                 0 == curInsn()->rawByte(0) && 
351                 0 == curInsn()->rawByte(1)) 
352             {
353                 cerr << "REACHED A 0x0000 INSTRUCTION "<< std::hex << current 
354                      << std::dec <<" COUNTING AS INVALID" << endl;
355                 ret = true;
356             }
357             break;
358         case e_push: // pushes of segment registers do not occur frequently in real code (and crash Rose)
359 #if 0 // instructionAPI implementation
360             set<RegisterAST::Ptr> regs;
361             curInsn()->getWriteSet(regs);
362             for (set<RegisterAST::Ptr>::iterator rit = regs.begin();
363                  rit != regs.end(); rit++) 
364             {
365                 if (Dyninst::isSegmentRegister((*rit)->getID().regClass())) {
366                     cerr << "REACHED A PUSH OF A SEGMENT REGISTER AT "<< std::hex 
367                         << current << std::dec <<" COUNTING AS INVALID" << endl;
368                     ret = true;
369                     break;
370                 }
371             }
372 #else // faster raw-byte implementation 
373             switch (curInsn()->rawByte(0)) {
374                 case 0x06:
375                 case 0x0e:
376                 case 0x16:
377                 case 0x1e:
378                     ret = true;
379                     cerr << "REACHED A PUSH OF A SEGMENT REGISTER "<< std::hex << current 
380                          << std::dec <<" COUNTING AS INVALID" << endl;
381                     break;
382                 case 0x0f:
383                     if (2 == curInsn()->size() && 
384                         ((0xa0 == curInsn()->rawByte(1)) || (0xa8 == curInsn()->rawByte(1))))
385                     {
386                         ret = true;
387                         cerr << "REACHED A 2-BYTE PUSH OF A SEGMENT REGISTER "<< std::hex << current 
388                              << std::dec <<" COUNTING AS INVALID" << endl;
389                     }
390                     break;
391                 default:
392                     break;
393             }
394 #endif
395         default:
396             break;
397         }
398     }
399     return ret;
400 }       
401 bool IA_IAPI::isFrameSetupInsn() const
402 {
403     return isFrameSetupInsn(curInsn());
404 }
405
406 bool IA_IAPI::isDynamicCall() const
407 {
408     Instruction::Ptr ci = curInsn();
409     if(ci && (ci->getCategory() == c_CallInsn))
410     {
411        Address addr;
412        bool success;
413        boost::tie(success, addr) = getCFT();
414        if (!success) {
415           parsing_printf("... Call 0x%lx is indirect\n", current);
416           return true;
417        }
418     }
419     return false;
420 }
421
422 bool IA_IAPI::isAbsoluteCall() const
423 {
424     Instruction::Ptr ci = curInsn();
425     if(ci->getCategory() == c_CallInsn)
426     {
427         Expression::Ptr cft = ci->getControlFlowTarget();
428         if(cft && boost::dynamic_pointer_cast<Immediate>(cft))
429         {
430             return true;
431         }
432         if (isDynamicCall()) {
433             return true; // indirect call targets are absolute 
434                          // (though unknown for now)
435         }
436     }
437     return false;
438 }
439
440 bool IA_IAPI::isBranch() const
441 {
442     return curInsn()->getCategory() == c_BranchInsn;
443 }
444 bool IA_IAPI::isCall() const
445 {
446     return curInsn()->getCategory() == c_CallInsn;
447 }
448
449 bool IA_IAPI::isInterruptOrSyscall() const
450 {
451     return (isInterrupt() && isSyscall());
452 }
453
454 bool IA_IAPI::isSyscall() const
455 {
456     static RegisterAST::Ptr gs(new RegisterAST(x86::gs));
457     
458     Instruction::Ptr ci = curInsn();
459
460     return (((ci->getOperation().getID() == e_call) &&
461             /*(curInsn()->getOperation().isRead(gs))) ||*/
462             (ci->getOperand(0).format(ci->getArch()) == "16")) ||
463             (ci->getOperation().getID() == e_syscall) || 
464             (ci->getOperation().getID() == e_int) || 
465             (ci->getOperation().getID() == power_op_sc));
466 }
467
468
469 bool IA_IAPI::isInterrupt() const
470 {
471     Instruction::Ptr ci = curInsn();
472     return ((ci->getOperation().getID() == e_int) ||
473             (ci->getOperation().getID() == e_int3));
474 }
475
476 bool IA_IAPI::isSysEnter() const
477 {
478   Instruction::Ptr ci = curInsn();
479   return (ci->getOperation().getID() == e_sysenter);
480 }
481
482 void IA_IAPI::parseSysEnter(std::vector<std::pair<Address, EdgeTypeEnum> >& outEdges) const
483 {
484   IA_IAPI scratch(*this);
485   
486   do {
487     scratch.advance();
488   } while(scratch.isNop());
489   if(scratch.curInsn()->getCategory() == c_BranchInsn)
490   {
491     parsing_printf("[%s:%d] Detected Linux-ish sysenter idiom at 0x%lx\n",
492                    FILE__, __LINE__, getAddr());
493     outEdges.push_back(std::make_pair(scratch.getAddr(), COND_NOT_TAKEN));
494     scratch.advance();
495     outEdges.push_back(std::make_pair(scratch.getAddr(), CALL_FT));
496   }
497   else
498   {
499     parsing_printf("[%s:%d] Treating sysenter as call to kernel w/normal return to next insn at 0x%lx\n",
500                    FILE__, __LINE__, getAddr());
501     outEdges.push_back(std::make_pair(getNextAddr(), CALL_FT));
502   }
503 }
504
505
506
507 void IA_IAPI::getNewEdges(std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges,
508                           Function* context,
509                           Block* currBlk,
510                           unsigned int num_insns,
511                           dyn_hash_map<Address, std::string> *plt_entries) const
512 {
513     Instruction::Ptr ci = curInsn();
514
515     // Only call this on control flow instructions!
516     if(ci->getCategory() == c_CallInsn)
517     {
518        bool success; 
519        Address target;
520        boost::tie(success, target) = getCFT();
521         bool callEdge = true;
522         bool ftEdge = true;
523         if( success && !isDynamicCall() )
524         {
525             if ( ! isRealCall() )
526                 callEdge = false;
527
528             if ( simulateJump() ) 
529             {
530                 outEdges.push_back(std::make_pair(target, DIRECT));
531                 callEdge = false;
532                 ftEdge = false;
533             }
534         }
535
536         if ( unlikely(_obj->defensiveMode()) )
537         {
538             if (!success || isDynamicCall()) 
539             {
540                 std::string empty;
541                if ( ! isIATcall(empty) )
542                     ftEdge = false;
543             }
544             else if ( ! _isrc->isValidAddress(target) )
545             {
546                 ftEdge = false;
547             }
548         }
549  
550         if (callEdge)
551             outEdges.push_back(std::make_pair(target, NOEDGE));
552         if (ftEdge)
553             outEdges.push_back(std::make_pair(getAddr() + getSize(), CALL_FT));
554         return;
555     }
556     else if(ci->getCategory() == c_BranchInsn)
557     {
558         if(ci->allowsFallThrough())
559         {
560             outEdges.push_back(std::make_pair(getCFT().second,
561                                               COND_TAKEN));
562             outEdges.push_back(std::make_pair(getNextAddr(), COND_NOT_TAKEN));
563             return;
564         }
565         bool valid;
566         Address target;
567         boost::tie(valid, target) = getCFT(); 
568         // Direct jump
569         if (valid) 
570         {
571             Address catchStart;
572             if(_cr->findCatchBlock(getNextAddr(),catchStart))
573             {
574                 outEdges.push_back(std::make_pair(catchStart, CATCH));
575             }
576
577             if(!isTailCall(context, DIRECT, num_insns))
578             {
579                 if(plt_entries->find(target) == plt_entries->end())
580                 {
581                     outEdges.push_back(std::make_pair(target,DIRECT));
582                 }
583                 else
584                 {
585                     parsing_printf("%s[%d]: PLT tail call to %x (%s)\n", 
586                         FILE__, __LINE__, target,
587                         (*plt_entries)[target].c_str());
588                     outEdges.push_back(std::make_pair(target, NOEDGE));
589                     tailCalls[DIRECT] = true;
590                 }
591             }
592             else
593             {
594                 parsing_printf("%s[%d]: tail call to %x\n", 
595                     FILE__, __LINE__, target);
596                 outEdges.push_back(std::make_pair(target, DIRECT));
597             }
598             return;
599         }
600         else
601         {
602             parsing_printf("... indirect jump at 0x%x\n", current);
603             if( num_insns == 2 ) {
604               // Handle a pernicious indirect tail call idiom here
605               // What we've seen is mov (%rdi), %rax; jmp *%rax
606               // Anything that tries to go enum->jump table *should* need more than two
607               // instructions and has not been seen in the wild....
608               if(currBlk == context->entry()) 
609               {
610                 parsing_printf("\tIndirect branch as 2nd insn of entry block, treating as tail call\n");
611                 parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__,
612                                ci->format().c_str(), current);
613                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
614                 tailCalls[INDIRECT]=true;
615                 return;
616               }
617               else
618               {
619                 parsing_printf("... uninstrumentable due to 0 size\n");
620                 return;
621               }
622             }
623             if(isTailCall(context, INDIRECT, num_insns)) {
624                 parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__,
625                                ci->format().c_str(), current);
626                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
627                 tailCalls[INDIRECT] = true;
628                 return;
629             }
630             parsing_printf("%s[%d]: jump table candidate %s at 0x%lx\n", FILE__, __LINE__,
631                            ci->format().c_str(), current);
632             parsedJumpTable = true;
633             successfullyParsedJumpTable = parseJumpTable(currBlk, outEdges);
634             parsing_printf("Parsed jump table 2\n");
635             if(!successfullyParsedJumpTable || outEdges.empty()) {
636                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
637                 parsing_printf("%s[%d]: BCTR unparsed jump table %s at 0x%lx in function %s UNINSTRUMENTABLE\n", FILE__, __LINE__,
638                            ci->format().c_str(), current, context->name().c_str());
639             }
640             return;
641         }
642     }
643     else if(ci->getCategory() == c_ReturnInsn)
644     {
645         parsing_printf("%s[%d]: BLR %s at 0x%lx\n", FILE__, __LINE__,
646                            ci->format().c_str(), current);
647         if(ci->allowsFallThrough())
648         {
649             outEdges.push_back(std::make_pair(getNextAddr(), FALLTHROUGH));
650         }
651         else if (!isReturn(context, currBlk)) {
652             // If BLR is not a return, then it is a jump table
653             parsedJumpTable = true;
654             parsing_printf("%s[%d]: BLR jump table candidate %s at 0x%lx\n", FILE__, __LINE__,
655                            ci->format().c_str(), current);
656             successfullyParsedJumpTable = parseJumpTable(currBlk, outEdges);
657             parsing_printf("Parsed BLR jump table\n");
658             if(!successfullyParsedJumpTable || outEdges.empty()) {
659                 parsing_printf("%s[%d]: BLR unparsed jump table %s at 0x%lx in function %s UNINSTRUMENTABLE\n", 
660                                FILE__, __LINE__, ci->format().c_str(), current, context->name().c_str());
661                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
662             }
663         }
664         parsing_printf("Returning from parse out edges\n");
665         return;
666     }
667     else if(isSysEnter())
668     {
669       parseSysEnter(outEdges);
670       return;
671     }
672     
673     fprintf(stderr, "Unhandled instruction %s\n", ci->format().c_str());
674     assert(0);
675 }
676
677 bool IA_IAPI::isIPRelativeBranch() const
678 {
679             // These don't exist on IA32...
680 #if !defined(arch_x86_64)
681     return false;
682 #endif
683     Instruction::Ptr ci = curInsn();
684
685     bool valid;
686     Address target;
687     boost::tie(valid, target) = getCFT();
688     
689     if(ci->getCategory() == c_BranchInsn &&
690        !valid) {
691        Expression::Ptr cft = ci->getControlFlowTarget();
692        if(cft->isUsed(thePC[_isrc->getArch()]))
693        {
694           parsing_printf("\tIP-relative indirect jump to %s at 0x%lx\n",
695                          cft->format().c_str(), current);
696           return true;
697        }
698     }
699     return false;
700     
701 }
702
703 Instruction::Ptr IA_IAPI::curInsn() const
704 {
705     return curInsnIter->second;
706 }
707
708 bool IA_IAPI::isLeave() const
709 {
710     Instruction::Ptr ci = curInsn();
711     return ci && (ci->getOperation().getID() == e_leave);
712 }
713
714 bool IA_IAPI::isDelaySlot() const
715 {
716     return false;
717 }
718
719 Instruction::Ptr IA_IAPI::getInstruction() const
720 {
721     return curInsn();
722 }
723
724 bool IA_IAPI::isRealCall() const
725 {
726   // Obviated by simulateJump
727    bool success;
728    Address addr;
729    boost::tie(success, addr) = getCFT();
730    if (success &&
731        (addr == getNextAddr())) {
732       parsing_printf("... getting PC\n");
733       return false;
734    }
735    if(isThunk()) {
736       return false;
737    }
738    return true;
739 }
740
741 std::map<Address, bool> IA_IAPI::thunkAtTarget;
742
743
744 bool IA_IAPI::isConditional() const
745 {
746     return curInsn()->allowsFallThrough();
747 }
748
749 bool IA_IAPI::simulateJump() const
750 {
751     // obfuscated programs simulate jumps by calling into a block that 
752     // discards the return address from the stack, we check for these
753     // fake calls in malware mode
754     if (_obj->defensiveMode() && !isDynamicCall()) {
755         return isFakeCall();
756     }
757     // TODO: we don't simulate jumps on x86 architectures; add logic as we need it.                
758     return false;
759 }
760
761 std::pair<bool, Address> IA_IAPI::getFallthrough() const 
762 {
763    return make_pair(true, curInsnIter->first + curInsnIter->second->size());
764 }
765
766 std::pair<bool, Address> IA_IAPI::getCFT() const
767 {
768    if(validCFT) return cachedCFT;
769     Expression::Ptr callTarget = curInsn()->getControlFlowTarget();
770         if (!callTarget) return make_pair(false, 0);
771        // FIXME: templated bind(),dammit!
772     callTarget->bind(thePC[_isrc->getArch()].get(), Result(s64, current));
773     parsing_printf("%s[%d]: binding PC %s in %s to 0x%x...", FILE__, __LINE__,
774                    thePC[_isrc->getArch()]->format().c_str(), curInsn()->format().c_str(), current);
775
776     Result actualTarget = callTarget->eval();
777 #if defined(os_vxworks)
778
779     int reloc_target = current;
780 #if defined(arch_x86)
781     ++reloc_target;
782 #endif
783
784     if (actualTarget.convert<Address>() == reloc_target) {
785         // We have a zero offset branch.  Consider relocation information.
786         SymtabCodeRegion *scr = dynamic_cast<SymtabCodeRegion *>(_cr);
787         SymtabCodeSource *scs = dynamic_cast<SymtabCodeSource *>(_obj->cs());
788
789         if (!scr && scs) {
790             set<CodeRegion *> regions;
791             assert( scs->findRegions(reloc_target, regions) == 1 );
792             scr = dynamic_cast<SymtabCodeRegion *>(*regions.begin());
793         }
794
795         SymtabAPI::Symbol *sym = NULL;
796         if (scr) {
797             std::vector<SymtabAPI::relocationEntry> relocs =
798                 scr->symRegion()->getRelocations();
799
800             for (unsigned i = 0; i < relocs.size(); ++i) {
801                 if (relocs[i].rel_addr() == reloc_target) {
802                     sym = relocs[i].getDynSym();
803                     if (sym && sym->getOffset()) {
804                         parsing_printf(" <reloc hit> ");
805                         actualTarget = Result(s64, sym->getOffset());
806                     }
807                     break;
808                 }
809             }
810         }
811
812         if (sym && sym->getOffset() == 0) {
813             // VxWorks external call.
814             // Need some external means to find the target.
815             Address found;
816             const std::string &sym_name = sym->getMangledName();
817             if (wtxFindFunction(sym_name.c_str(), 0x0, found)) {
818                 parsing_printf(" <wtx search hit> ");
819                 actualTarget = Result(s64, found);
820
821                 // We've effectively found a plt call.  Update linkage table.
822                 _obj->cs()->linkage()[found] = sym_name;
823
824             } else {
825                 parsing_printf(" <wtx fail %s> ", sym_name.c_str());
826                 actualTarget.defined = false;
827             }
828         }
829     }
830 #endif
831
832     if(actualTarget.defined)
833     {
834        cachedCFT = std::make_pair(true, actualTarget.convert<Address>());
835        parsing_printf("SUCCESS (CFT=0x%x)\n", cachedCFT.second);
836     }
837     else
838     {
839        cachedCFT = std::make_pair(false, 0); 
840         parsing_printf("FAIL (CFT=0x%x), callTarget exp: %s\n",
841                        cachedCFT.second,callTarget->format().c_str());
842     }
843     validCFT = true;
844
845     if(isLinkerStub()) {
846         parsing_printf("Linker stub detected: Correcting CFT.  (CFT=0x%x)\n",
847                        cachedCFT.second);
848     }
849
850     return cachedCFT;
851 }
852
853 bool IA_IAPI::isRelocatable(InstrumentableLevel lvl) const
854 {
855     Instruction::Ptr ci = curInsn();
856     if(ci && (ci->getCategory() == c_CallInsn))
857     {
858         if(!isDynamicCall())
859         {
860            bool valid; Address addr;
861            boost::tie(valid, addr) = getCFT();
862            assert(valid);
863            if(!_isrc->isValidAddress(addr))
864            {
865               parsing_printf("... Call to 0x%lx is invalid (outside code or data)\n",
866                              addr);
867                 return false;
868             }
869         }
870     }
871     if(lvl == HAS_BR_INDIR)
872     {
873         return false;
874     }
875     return true;
876 }
877
878 bool IA_IAPI::parseJumpTable(Dyninst::ParseAPI::Block* currBlk,
879                     std::vector<std::pair< Address, Dyninst::ParseAPI::EdgeTypeEnum > >& outEdges) const
880 {
881     IA_platformDetails* jumpTableParser = makePlatformDetails(_isrc->getArch(), this);
882     bool ret = jumpTableParser->parseJumpTable(currBlk, outEdges);
883     parsing_printf("Jump table parser returned %d, %d edges\n", ret, outEdges.size());
884     // Update statistics 
885     currBlk->obj()->cs()->incrementCounter(PARSE_JUMPTABLE_COUNT);
886     if (!ret) currBlk->obj()->cs()->incrementCounter(PARSE_JUMPTABLE_FAIL);
887
888     delete jumpTableParser;
889     return ret;
890 }
891
892
893
894 InstrumentableLevel IA_IAPI::getInstLevel(Function * context, unsigned int num_insns) const
895 {
896     InstrumentableLevel ret = InstructionAdapter::getInstLevel(context, num_insns);
897 /*    if(ret == HAS_BR_INDIR && isIPRelativeBranch())
898     {
899         return NORMAL;
900 }*/
901     return ret;
902 }