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