sysenter parsing improvements: if idiom not found, fall through rather than terminati...
[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/h/Types.h"
43 #include "dyntypes.h"
44
45 #include <deque>
46 #include <map>
47
48 #if defined(os_vxworks)
49 #include "common/h/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      tailCall(rhs.tailCall) {
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    tailCall = rhs.tailCall;
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     tailCall.first = false;
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     tailCall.first = false;
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     tailCall.first = false;
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     tailCall.first = false;
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::isAbortOrInvalidInsn() const
287 {
288     entryID e = curInsn()->getOperation().getID();
289     if(e == e_No_Entry)
290     {
291         parsing_printf("...WARNING: un-decoded instruction at 0x%x\n", current);
292         }
293         return e == e_No_Entry ||
294             e == e_int3 ||
295             e == e_hlt;
296 }
297
298 /* This function determines if a given instruction is weird enough that we've
299  * probably veered into non-code bytes and are parsing garbage.  
300  * note: yes, some of the code in here is does low-level things like 
301  *       grab instruction bytes directly instead of relying on the parseAPI,
302  *       but since this code executes for every parsed instruction, it needs
303  *       to be efficient.  
304  */
305 bool IA_IAPI::isGarbageInsn() const
306 {
307     bool ret = false;
308     // GARBAGE PARSING HEURISTIC
309     if (unlikely(_obj->defensiveMode())) {
310         entryID e = curInsn()->getOperation().getID();
311         switch (e) {
312         case e_arpl:
313             cerr << "REACHED AN ARPL AT "<< std::hex << current 
314                  << std::dec <<" COUNTING AS INVALID" << endl;
315             ret = true;
316             break;
317         case e_fisub:
318             cerr << "REACHED A FISUB AT "<< std::hex << current 
319                  << std::dec <<" COUNTING AS INVALID" << endl;
320             ret = true;
321             break;
322         case e_into:
323             cerr << "REACHED AN INTO AT "<< std::hex << current 
324                  << std::dec <<" COUNTING AS INVALID" << endl;
325             ret = true;
326             break;
327         case e_mov: {
328             set<RegisterAST::Ptr> regs;
329             curInsn()->getWriteSet(regs);
330             for (set<RegisterAST::Ptr>::iterator rit = regs.begin();
331                  rit != regs.end(); rit++) 
332             {
333                 if (Dyninst::isSegmentRegister((*rit)->getID().regClass())) {
334                     cerr << "REACHED A MOV SEGMENT INSN AT "<< std::hex 
335                         << current << std::dec <<" COUNTING AS INVALID" << endl;
336                     ret = true;
337                     break;
338                 }
339             }
340             break;
341         }
342         case e_add:
343             if (2 == curInsn()->size() && 
344                 0 == ((char*)curInsn()->ptr())[0] && 
345                 0 == ((char*)curInsn()->ptr())[1]) 
346             {
347                 cerr << "REACHED A 0x0000 INSTRUCTION "<< std::hex << current 
348                      << std::dec <<" COUNTING AS INVALID" << endl;
349                 ret = true;
350             }
351             break;
352         case e_push: // pushes of segment registers do not occur frequently in real code (and crash Rose)
353 #if 0 // instructionAPI implementation
354             set<RegisterAST::Ptr> regs;
355             curInsn()->getWriteSet(regs);
356             for (set<RegisterAST::Ptr>::iterator rit = regs.begin();
357                  rit != regs.end(); rit++) 
358             {
359                 if (Dyninst::isSegmentRegister((*rit)->getID().regClass())) {
360                     cerr << "REACHED A PUSH OF A SEGMENT REGISTER AT "<< std::hex 
361                         << current << std::dec <<" COUNTING AS INVALID" << endl;
362                     ret = true;
363                     break;
364                 }
365             }
366 #else // faster raw-byte implementation 
367             switch (((char*)curInsn()->ptr())[0]) {
368                 case 0x06:
369                 case 0x0e:
370                 case 0x16:
371                 case 0x1e:
372                     ret = true;
373                     cerr << "REACHED A PUSH OF A SEGMENT REGISTER "<< std::hex << current 
374                          << std::dec <<" COUNTING AS INVALID" << endl;
375                     break;
376                 case 0x0f:
377                     if (2 == curInsn()->size() && 
378                         ((0xa0 == ((unsigned char*)curInsn()->ptr())[1]) || (0xa8 == ((unsigned char*)curInsn()->ptr())[1])))
379                     {
380                         ret = true;
381                         cerr << "REACHED A 2-BYTE PUSH OF A SEGMENT REGISTER "<< std::hex << current 
382                              << std::dec <<" COUNTING AS INVALID" << endl;
383                     }
384                     break;
385                 default:
386                     break;
387             }
388 #endif
389         default:
390             break;
391         }
392     }
393     return ret;
394 }       
395 bool IA_IAPI::isFrameSetupInsn() const
396 {
397     return isFrameSetupInsn(curInsn());
398 }
399
400 bool IA_IAPI::isDynamicCall() const
401 {
402     Instruction::Ptr ci = curInsn();
403     if(ci && (ci->getCategory() == c_CallInsn))
404     {
405        Address addr;
406        bool success;
407        boost::tie(success, addr) = getCFT();
408        if (!success) {
409           parsing_printf("... Call 0x%lx is indirect\n", current);
410           return true;
411        }
412     }
413     return false;
414 }
415
416 bool IA_IAPI::isAbsoluteCall() const
417 {
418     Instruction::Ptr ci = curInsn();
419     if(ci->getCategory() == c_CallInsn)
420     {
421         Expression::Ptr cft = ci->getControlFlowTarget();
422         if(cft && boost::dynamic_pointer_cast<Immediate>(cft))
423         {
424             return true;
425         }
426         if (isDynamicCall()) {
427             return true; // indirect call targets are absolute 
428                          // (though unknown for now)
429         }
430     }
431     return false;
432 }
433
434 bool IA_IAPI::isBranch() const
435 {
436     return curInsn()->getCategory() == c_BranchInsn;
437 }
438 bool IA_IAPI::isCall() const
439 {
440     return curInsn()->getCategory() == c_CallInsn;
441 }
442
443 bool IA_IAPI::isInterruptOrSyscall() const
444 {
445     return (isInterrupt() && isSyscall());
446 }
447
448 bool IA_IAPI::isSyscall() const
449 {
450     static RegisterAST::Ptr gs(new RegisterAST(x86::gs));
451     
452     Instruction::Ptr ci = curInsn();
453
454     return (((ci->getOperation().getID() == e_call) &&
455             /*(curInsn()->getOperation().isRead(gs))) ||*/
456             (ci->getOperand(0).format(ci->getArch()) == "16")) ||
457             (ci->getOperation().getID() == e_syscall) || 
458             (ci->getOperation().getID() == e_int) || 
459             (ci->getOperation().getID() == power_op_sc));
460 }
461
462
463 bool IA_IAPI::isInterrupt() const
464 {
465     Instruction::Ptr ci = curInsn();
466     return ((ci->getOperation().getID() == e_int) ||
467             (ci->getOperation().getID() == e_int3));
468 }
469
470 bool IA_IAPI::isSysEnter() const
471 {
472   Instruction::Ptr ci = curInsn();
473   return (ci->getOperation().getID() == e_sysenter);
474 }
475
476 void IA_IAPI::parseSysEnter(std::vector<std::pair<Address, EdgeTypeEnum> >& outEdges) const
477 {
478   IA_IAPI scratch(*this);
479   
480   do {
481     scratch.advance();
482   } while(scratch.isNop());
483   if(scratch.curInsn()->getCategory() == c_BranchInsn)
484   {
485     parsing_printf("[%s:%d] Detected Linux-ish sysenter idiom at 0x%lx\n",
486                    FILE__, __LINE__, getAddr());
487     outEdges.push_back(std::make_pair(scratch.getAddr(), COND_NOT_TAKEN));
488     scratch.advance();
489     outEdges.push_back(std::make_pair(scratch.getAddr(), CALL_FT));
490   }
491   else
492   {
493     parsing_printf("[%s:%d] Treating sysenter as call to kernel w/normal return to next insn at 0x%lx\n",
494                    FILE__, __LINE__, getAddr());
495     outEdges.push_back(std::make_pair(getNextAddr(), CALL_FT));
496   }
497 }
498
499
500
501 void IA_IAPI::getNewEdges(std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges,
502                           Function* context,
503                           Block* currBlk,
504                           unsigned int num_insns,
505                           dyn_hash_map<Address, std::string> *plt_entries) const
506 {
507     Instruction::Ptr ci = curInsn();
508
509     // Only call this on control flow instructions!
510     if(ci->getCategory() == c_CallInsn)
511     {
512        bool success; 
513        Address target;
514        boost::tie(success, target) = getCFT();
515         bool callEdge = true;
516         bool ftEdge = true;
517         if( success && !isDynamicCall() )
518         {
519             if ( ! isRealCall() )
520                 callEdge = false;
521
522             if ( simulateJump() ) 
523             {
524                 outEdges.push_back(std::make_pair(target, DIRECT));
525                 callEdge = false;
526                 ftEdge = false;
527             }
528         }
529
530         if ( unlikely(_obj->defensiveMode()) )
531         {
532             if (!success || isDynamicCall()) 
533             {
534                 std::string empty;
535                if ( ! isIATcall(empty) )
536                     ftEdge = false;
537             }
538             else if ( ! _isrc->isValidAddress(target) )
539             {
540                 ftEdge = false;
541             }
542         }
543  
544         if (callEdge)
545             outEdges.push_back(std::make_pair(target, NOEDGE));
546         if (ftEdge)
547             outEdges.push_back(std::make_pair(getAddr() + getSize(), CALL_FT));
548         return;
549     }
550     else if(ci->getCategory() == c_BranchInsn)
551     {
552         if(ci->allowsFallThrough())
553         {
554             outEdges.push_back(std::make_pair(getCFT().second,
555                                               COND_TAKEN));
556             outEdges.push_back(std::make_pair(getNextAddr(), COND_NOT_TAKEN));
557             return;
558         }
559         bool valid;
560         Address target;
561         boost::tie(valid, target) = getCFT(); 
562         // Direct jump
563         if (valid) 
564         {
565             Address catchStart;
566             if(_cr->findCatchBlock(getNextAddr(),catchStart))
567             {
568                 outEdges.push_back(std::make_pair(catchStart, CATCH));
569             }
570
571             if(!isTailCall(context,num_insns))
572             {
573                 if(plt_entries->find(target) == plt_entries->end())
574                 {
575                     outEdges.push_back(std::make_pair(target,DIRECT));
576                 }
577                 else
578                 {
579                     parsing_printf("%s[%d]: PLT tail call to %x (%s)\n", 
580                         FILE__, __LINE__, target,
581                         (*plt_entries)[target].c_str());
582                     outEdges.push_back(std::make_pair(target, NOEDGE));
583                     tailCall.second = true;
584                 }
585             }
586             else
587             {
588                 parsing_printf("%s[%d]: tail call to %x\n", 
589                     FILE__, __LINE__, target);
590                 outEdges.push_back(std::make_pair(target, NOEDGE));
591             }
592             return;
593         }
594         else
595         {
596             parsing_printf("... indirect jump at 0x%x\n", current);
597             if( num_insns == 2 ) {
598                 parsing_printf("... uninstrumentable due to 0 size\n");
599                 return;
600             }
601             if(isTailCall(context,num_insns)) {
602                 parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__,
603                                ci->format().c_str(), current);
604                 return;
605             }
606             parsing_printf("%s[%d]: jump table candidate %s at 0x%lx\n", FILE__, __LINE__,
607                            ci->format().c_str(), current);
608             parsedJumpTable = true;
609             successfullyParsedJumpTable = parseJumpTable(currBlk, outEdges);
610             parsing_printf("Parsed jump table 2\n");
611             if(!successfullyParsedJumpTable || outEdges.empty()) {
612                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
613                 parsing_printf("%s[%d]: BCTR unparsed jump table %s at 0x%lx in function %s UNINSTRUMENTABLE\n", FILE__, __LINE__,
614                            ci->format().c_str(), current, context->name().c_str());
615             }
616             return;
617         }
618     }
619     else if(ci->getCategory() == c_ReturnInsn)
620     {
621         parsing_printf("%s[%d]: BLR %s at 0x%lx\n", FILE__, __LINE__,
622                            ci->format().c_str(), current);
623         if(ci->allowsFallThrough())
624         {
625             outEdges.push_back(std::make_pair(getNextAddr(), FALLTHROUGH));
626         }
627         else if (!isReturn(context, currBlk)) {
628             // If BLR is not a return, then it is a jump table
629             parsedJumpTable = true;
630             parsing_printf("%s[%d]: BLR jump table candidate %s at 0x%lx\n", FILE__, __LINE__,
631                            ci->format().c_str(), current);
632             successfullyParsedJumpTable = parseJumpTable(currBlk, outEdges);
633             parsing_printf("Parsed BLR jump table\n");
634             if(!successfullyParsedJumpTable || outEdges.empty()) {
635                 parsing_printf("%s[%d]: BLR unparsed jump table %s at 0x%lx in function %s UNINSTRUMENTABLE\n", 
636                                FILE__, __LINE__, ci->format().c_str(), current, context->name().c_str());
637                 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
638             }
639         }
640         parsing_printf("Returning from parse out edges\n");
641         return;
642     }
643     else if(isSysEnter())
644     {
645       parseSysEnter(outEdges);
646       return;
647     }
648     
649     fprintf(stderr, "Unhandled instruction %s\n", ci->format().c_str());
650     assert(0);
651 }
652
653 bool IA_IAPI::isIPRelativeBranch() const
654 {
655             // These don't exist on IA32...
656 #if !defined(arch_x86_64)
657     return false;
658 #endif
659     Instruction::Ptr ci = curInsn();
660
661     bool valid;
662     Address target;
663     boost::tie(valid, target) = getCFT();
664     
665     if(ci->getCategory() == c_BranchInsn &&
666        !valid) {
667        Expression::Ptr cft = ci->getControlFlowTarget();
668        if(cft->isUsed(thePC[_isrc->getArch()]))
669        {
670           parsing_printf("\tIP-relative indirect jump to %s at 0x%lx\n",
671                          cft->format().c_str(), current);
672           return true;
673        }
674     }
675     return false;
676     
677 }
678
679 Instruction::Ptr IA_IAPI::curInsn() const
680 {
681     return curInsnIter->second;
682 }
683
684 bool IA_IAPI::isLeave() const
685 {
686     Instruction::Ptr ci = curInsn();
687     return ci && (ci->getOperation().getID() == e_leave);
688 }
689
690 bool IA_IAPI::isDelaySlot() const
691 {
692     return false;
693 }
694
695 Instruction::Ptr IA_IAPI::getInstruction() const
696 {
697     return curInsn();
698 }
699
700 bool IA_IAPI::isRealCall() const
701 {
702   // Obviated by simulateJump
703    bool success;
704    Address addr;
705    boost::tie(success, addr) = getCFT();
706    if (success &&
707        (addr == getNextAddr())) {
708       parsing_printf("... getting PC\n");
709       return false;
710    }
711    if(isThunk()) {
712       return false;
713    }
714    return true;
715 }
716
717 std::map<Address, bool> IA_IAPI::thunkAtTarget;
718
719
720 bool IA_IAPI::isConditional() const
721 {
722     return curInsn()->allowsFallThrough();
723 }
724
725 bool IA_IAPI::simulateJump() const
726 {
727     // obfuscated programs simulate jumps by calling into a block that 
728     // discards the return address from the stack, we check for these
729     // fake calls in malware mode
730     if (_obj->defensiveMode() && !isDynamicCall()) {
731         return isFakeCall();
732     }
733     // TODO: we don't simulate jumps on x86 architectures; add logic as we need it.                
734     return false;
735 }
736
737 std::pair<bool, Address> IA_IAPI::getCFT() const
738 {
739    if(validCFT) return cachedCFT;
740     Expression::Ptr callTarget = curInsn()->getControlFlowTarget();
741         // FIXME: templated bind(),dammit!
742     callTarget->bind(thePC[_isrc->getArch()].get(), Result(s64, current));
743     parsing_printf("%s[%d]: binding PC %s in %s to 0x%x...", FILE__, __LINE__,
744                    thePC[_isrc->getArch()]->format().c_str(), curInsn()->format().c_str(), current);
745
746     Result actualTarget = callTarget->eval();
747 #if defined(os_vxworks)
748
749     int reloc_target = current;
750 #if defined(arch_x86)
751     ++reloc_target;
752 #endif
753
754     if (actualTarget.convert<Address>() == reloc_target) {
755         // We have a zero offset branch.  Consider relocation information.
756         SymtabCodeRegion *scr = dynamic_cast<SymtabCodeRegion *>(_cr);
757         SymtabCodeSource *scs = dynamic_cast<SymtabCodeSource *>(_obj->cs());
758
759         if (!scr && scs) {
760             set<CodeRegion *> regions;
761             assert( scs->findRegions(reloc_target, regions) == 1 );
762             scr = dynamic_cast<SymtabCodeRegion *>(*regions.begin());
763         }
764
765         SymtabAPI::Symbol *sym = NULL;
766         if (scr) {
767             std::vector<SymtabAPI::relocationEntry> relocs =
768                 scr->symRegion()->getRelocations();
769
770             for (unsigned i = 0; i < relocs.size(); ++i) {
771                 if (relocs[i].rel_addr() == reloc_target) {
772                     sym = relocs[i].getDynSym();
773                     if (sym && sym->getOffset()) {
774                         parsing_printf(" <reloc hit> ");
775                         actualTarget = Result(s64, sym->getOffset());
776                     }
777                     break;
778                 }
779             }
780         }
781
782         if (sym && sym->getOffset() == 0) {
783             // VxWorks external call.
784             // Need some external means to find the target.
785             Address found;
786             const std::string &sym_name = sym->getMangledName();
787             if (wtxFindFunction(sym_name.c_str(), 0x0, found)) {
788                 parsing_printf(" <wtx search hit> ");
789                 actualTarget = Result(s64, found);
790
791                 // We've effectively found a plt call.  Update linkage table.
792                 _obj->cs()->linkage()[found] = sym_name;
793
794             } else {
795                 parsing_printf(" <wtx fail %s> ", sym_name.c_str());
796                 actualTarget.defined = false;
797             }
798         }
799     }
800 #endif
801
802     if(actualTarget.defined)
803     {
804        cachedCFT = std::make_pair(true, actualTarget.convert<Address>());
805        parsing_printf("SUCCESS (CFT=0x%x)\n", cachedCFT.second);
806     }
807     else
808     {
809        cachedCFT = std::make_pair(false, 0); 
810         parsing_printf("FAIL (CFT=0x%x), callTarget exp: %s\n",
811                        cachedCFT.second,callTarget->format().c_str());
812     }
813     validCFT = true;
814
815     if(isLinkerStub()) {
816         parsing_printf("Linker stub detected: Correcting CFT.  (CFT=0x%x)\n",
817                        cachedCFT.second);
818     }
819
820     return cachedCFT;
821 }
822
823 bool IA_IAPI::isRelocatable(InstrumentableLevel lvl) const
824 {
825     Instruction::Ptr ci = curInsn();
826     if(ci && (ci->getCategory() == c_CallInsn))
827     {
828         if(!isDynamicCall())
829         {
830            bool valid; Address addr;
831            boost::tie(valid, addr) = getCFT();
832            assert(valid);
833            if(!_isrc->isValidAddress(addr))
834            {
835               parsing_printf("... Call to 0x%lx is invalid (outside code or data)\n",
836                              addr);
837                 return false;
838             }
839         }
840     }
841     if(lvl == HAS_BR_INDIR)
842     {
843         return false;
844     }
845     return true;
846 }
847
848 bool IA_IAPI::parseJumpTable(Dyninst::ParseAPI::Block* currBlk,
849                     std::vector<std::pair< Address, Dyninst::ParseAPI::EdgeTypeEnum > >& outEdges) const
850 {
851     IA_platformDetails* jumpTableParser = makePlatformDetails(_isrc->getArch(), this);
852     bool ret = jumpTableParser->parseJumpTable(currBlk, outEdges);
853     parsing_printf("Jump table parser returned %d, %d edges\n", ret, outEdges.size());
854     // Update statistics 
855     currBlk->obj()->cs()->incrementCounter(PARSE_JUMPTABLE_COUNT);
856     if (!ret) currBlk->obj()->cs()->incrementCounter(PARSE_JUMPTABLE_FAIL);
857
858     delete jumpTableParser;
859     return ret;
860 }
861
862
863
864 InstrumentableLevel IA_IAPI::getInstLevel(Function * context, unsigned int num_insns) const
865 {
866     InstrumentableLevel ret = InstructionAdapter::getInstLevel(context, num_insns);
867 /*    if(ret == HAS_BR_INDIR && isIPRelativeBranch())
868     {
869         return NORMAL;
870 }*/
871     return ret;
872 }