2 * Copyright (c) 1996-2009 Barton P. Miller
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.
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.
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.
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.
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
36 #include "Dereference.h"
37 #include "Immediate.h"
38 #include "BinaryFunction.h"
39 #include "debug_parse.h"
40 #include "IA_platformDetails.h"
45 using namespace Dyninst;
46 using namespace InstructionAPI;
47 using namespace Dyninst::InsnAdapter;
48 using namespace Dyninst::ParseAPI;
50 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::framePtr;
51 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::stackPtr;
52 std::map<Architecture, RegisterAST::Ptr> IA_IAPI::thePC;
54 void IA_IAPI::initASTs()
58 framePtr[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86)));
59 framePtr[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86_64)));
60 framePtr[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_ppc32)));
61 framePtr[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_ppc64)));
65 stackPtr[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86)));
66 stackPtr[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86_64)));
67 stackPtr[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_ppc32)));
68 stackPtr[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_ppc64)));
72 thePC[Arch_x86] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_x86)));
73 thePC[Arch_x86_64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_x86_64)));
74 thePC[Arch_ppc32] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_ppc32)));
75 thePC[Arch_ppc64] = RegisterAST::Ptr(new RegisterAST(MachRegister::getPC(Arch_ppc64)));
79 IA_IAPI::IA_IAPI(InstructionDecoder dec_,
83 InstructionSource *isrc) :
84 InstructionAdapter(where_, o, r, isrc),
88 validLinkerStubState(false)
90 hascftstatus.first = false;
91 tailCall.first = false;
92 boost::tuples::tie(curInsnIter, boost::tuples::ignore) = allInsns.insert(std::make_pair(current, dec.decode()));
96 void IA_IAPI::advance()
99 parsing_printf("..... WARNING: failed to advance InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current,
103 InstructionAdapter::advance();
104 current += curInsn()->size();
105 boost::tuples::tie(curInsnIter, boost::tuples::ignore) = allInsns.insert(std::make_pair(current, dec.decode()));
108 parsing_printf("......WARNING: after advance at 0x%lx, curInsn() NULL\n", current);
111 validLinkerStubState = false;
112 hascftstatus.first = false;
113 tailCall.first = false;
116 void IA_IAPI::retreat()
119 parsing_printf("..... WARNING: failed to retreat InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current,
123 InstructionAdapter::retreat();
124 std::map<Address,Instruction::Ptr>::iterator remove = curInsnIter;
125 if(curInsnIter != allInsns.begin()) {
127 allInsns.erase(remove);
128 current = curInsnIter->first;
129 if(curInsnIter != allInsns.begin()) {
130 std::map<Address,Instruction::Ptr>::iterator pit = curInsnIter;
132 previous = curInsnIter->first;
137 parsing_printf("..... WARNING: cowardly refusal to retreat past first instruction at 0x%lx\n", current);
140 /* blind duplication -- nate */
142 validLinkerStubState = false;
143 hascftstatus.first = false;
144 tailCall.first = false;
149 size_t IA_IAPI::getSize() const
151 Instruction::Ptr ci = curInsn();
156 bool IA_IAPI::hasCFT() const
158 if(hascftstatus.first) return hascftstatus.second;
159 InsnCategory c = curInsn()->getCategory();
160 hascftstatus.second = false;
161 if(c == c_BranchInsn ||
164 hascftstatus.second = true;
169 hascftstatus.second = true;
171 if(isDynamicCall()) {
172 hascftstatus.second = true;
175 hascftstatus.second = true;
178 hascftstatus.first = true;
179 return hascftstatus.second;
182 bool IA_IAPI::isAbortOrInvalidInsn() const
184 entryID e = curInsn()->getOperation().getID();
187 parsing_printf("...WARNING: un-decoded instruction at 0x%x\n", current);
189 return e == e_No_Entry ||
194 bool IA_IAPI::isFrameSetupInsn() const
196 return isFrameSetupInsn(curInsn());
199 bool IA_IAPI::isDynamicCall() const
201 Instruction::Ptr ci = curInsn();
202 if(ci && (ci->getCategory() == c_CallInsn))
206 parsing_printf("... Call 0x%lx is indirect\n", current);
213 bool IA_IAPI::isAbsoluteCall() const
215 Instruction::Ptr ci = curInsn();
216 if(ci->getCategory() == c_CallInsn)
218 Expression::Ptr cft = ci->getControlFlowTarget();
219 if(cft && dyn_detail::boost::dynamic_pointer_cast<Immediate>(cft))
228 bool IA_IAPI::isReturn() const
230 return curInsn()->getCategory() == c_ReturnInsn;
232 bool IA_IAPI::isBranch() const
234 return curInsn()->getCategory() == c_BranchInsn;
236 bool IA_IAPI::isCall() const
238 return curInsn()->getCategory() == c_CallInsn;
241 bool IA_IAPI::isInterruptOrSyscall() const
243 return (isInterrupt() && isSyscall());
246 bool IA_IAPI::isSyscall() const
248 static RegisterAST::Ptr gs(new RegisterAST(x86::gs));
250 Instruction::Ptr ci = curInsn();
252 return (((ci->getOperation().getID() == e_call) &&
253 /*(curInsn()->getOperation().isRead(gs))) ||*/
254 (ci->getOperand(0).format() == "16")) ||
255 (ci->getOperation().getID() == e_syscall) ||
256 (ci->getOperation().getID() == e_int) ||
257 (ci->getOperation().getID() == power_op_sc));
261 bool IA_IAPI::isInterrupt() const
263 Instruction::Ptr ci = curInsn();
264 return ((ci->getOperation().getID() == e_int) ||
265 (ci->getOperation().getID() == e_int3));
268 void IA_IAPI::getNewEdges(
269 std::vector<std::pair< Address, EdgeTypeEnum> >& outEdges,
272 unsigned int num_insns,
273 dyn_hash_map<Address, std::string> *plt_entries) const
275 Instruction::Ptr ci = curInsn();
277 // Only call this on control flow instructions!
278 if(ci->getCategory() == c_CallInsn)
280 Address target = getCFT();
281 if(isRealCall() || isDynamicCall())
283 outEdges.push_back(std::make_pair(target, NOEDGE));
287 if(_isrc->isValidAddress(target))
291 parsing_printf("[%s:%u] call at 0x%lx simulated as "
293 FILE__,__LINE__,getAddr(),getCFT());
294 outEdges.push_back(std::make_pair(target, DIRECT));
299 outEdges.push_back(std::make_pair(getAddr() + getSize(),
303 else if(ci->getCategory() == c_BranchInsn)
306 if(ci->allowsFallThrough())
308 outEdges.push_back(std::make_pair(getCFT(),
310 outEdges.push_back(std::make_pair(getNextAddr(), COND_NOT_TAKEN));
314 else if((target = getCFT()) != 0)
317 if(_cr->findCatchBlock(getNextAddr(),catchStart))
319 outEdges.push_back(std::make_pair(catchStart, CATCH));
323 if(!isTailCall(context,num_insns))
325 if(plt_entries->find(target) == plt_entries->end())
327 outEdges.push_back(std::make_pair(target,DIRECT));
331 parsing_printf("%s[%d]: PLT tail call to %x (%s)\n",
332 FILE__, __LINE__, target,
333 (*plt_entries)[target].c_str());
334 outEdges.push_back(std::make_pair(target, NOEDGE));
335 tailCall.second = true;
340 parsing_printf("%s[%d]: tail call to %x\n",
341 FILE__, __LINE__, target);
342 outEdges.push_back(std::make_pair(target, NOEDGE));
348 parsing_printf("... indirect jump at 0x%x\n", current);
349 if( num_insns == 2 ) {
350 parsing_printf("... uninstrumentable due to 0 size\n");
353 if(isTailCall(context,num_insns)) {
354 parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__,
355 ci->format().c_str(), current);
358 parsing_printf("%s[%d]: jump table candidate %s at 0x%lx\n", FILE__, __LINE__,
359 ci->format().c_str(), current);
360 parsedJumpTable = true;
361 successfullyParsedJumpTable = parseJumpTable(currBlk, outEdges);
363 if(!successfullyParsedJumpTable || outEdges.empty()) {
364 outEdges.push_back(std::make_pair((Address)-1,INDIRECT));
369 else if(ci->getCategory() == c_ReturnInsn)
371 if(ci->allowsFallThrough())
373 outEdges.push_back(std::make_pair(getNextAddr(), FALLTHROUGH));
378 fprintf(stderr, "Unhandled instruction %s\n", ci->format().c_str());
382 bool IA_IAPI::isIPRelativeBranch() const
384 // These don't exist on IA32...
385 #if !defined(arch_x86_64)
388 Instruction::Ptr ci = curInsn();
390 if(ci->getCategory() == c_BranchInsn &&
393 Expression::Ptr cft = ci->getControlFlowTarget();
394 if(cft->isUsed(thePC[_isrc->getArch()]))
396 parsing_printf("\tIP-relative indirect jump to %s at 0x%lx\n",
397 cft->format().c_str(), current);
405 Instruction::Ptr IA_IAPI::curInsn() const
407 return curInsnIter->second;
410 bool IA_IAPI::isLeave() const
412 Instruction::Ptr ci = curInsn();
413 return ci && (ci->getOperation().getID() == e_leave);
416 bool IA_IAPI::isDelaySlot() const
418 #if defined(arch_sparc)
419 assert(!"Implement delay slots on SPARC!");
424 Instruction::Ptr IA_IAPI::getInstruction()
429 bool IA_IAPI::isRealCall() const
431 if(getCFT() == getNextAddr())
433 parsing_printf("... getting PC\n");
436 if(!_isrc->isValidAddress(getCFT()))
438 CodeSource *_csrc = dynamic_cast<CodeSource *>(_isrc);
440 _csrc->linkage().find(getCFT()) == _csrc->linkage().end()) {
441 parsing_printf(" isRealCall failed _isrc->isValidAddress(%lx)\n",
452 std::map<Address, bool> IA_IAPI::thunkAtTarget;
454 bool IA_IAPI::isConditional() const
456 return curInsn()->allowsFallThrough();
459 bool IA_IAPI::simulateJump() const
461 // obfuscated programs simulate jumps by calling into a block that
462 // discards the return address from the stack, we check for these
463 // fake calls in malware mode
464 if (_obj->defensiveMode()) {
467 // TODO: we don't simulate jumps on x86 architectures; add logic as we need it.
471 Address IA_IAPI::getCFT() const
473 if(validCFT) return cachedCFT;
474 Expression::Ptr callTarget = curInsn()->getControlFlowTarget();
475 // FIXME: templated bind(),dammit!
476 callTarget->bind(thePC[_isrc->getArch()].get(), Result(s64, current));
477 parsing_printf("%s[%d]: binding PC %s in %s to 0x%x...", FILE__, __LINE__,
478 thePC[_isrc->getArch()]->format().c_str(), curInsn()->format().c_str(), current);
479 Result actualTarget = callTarget->eval();
480 if(actualTarget.defined)
482 cachedCFT = actualTarget.convert<Address>();
483 parsing_printf("SUCCESS (CFT=0x%x)\n", cachedCFT);
488 parsing_printf("FAIL (CFT=0x%x), callTarget exp: %s\n",
489 cachedCFT,callTarget->format().c_str());
494 parsing_printf("Linker stub detected: Correcting CFT. (CFT=0x%x)\n",
501 bool IA_IAPI::isRelocatable(InstrumentableLevel lvl) const
503 Instruction::Ptr ci = curInsn();
504 if(ci && (ci->getCategory() == c_CallInsn))
508 if(!_isrc->isValidAddress(getCFT()))
510 parsing_printf("... Call to 0x%lx is invalid (outside code or data)\n",
516 if(lvl == HAS_BR_INDIR)
523 bool IA_IAPI::parseJumpTable(Dyninst::ParseAPI::Block* currBlk,
524 std::vector<std::pair< Address, Dyninst::ParseAPI::EdgeTypeEnum > >& outEdges) const
526 IA_platformDetails* jumpTableParser = makePlatformDetails(_isrc->getArch(), this);
527 bool ret = jumpTableParser->parseJumpTable(currBlk, outEdges);
528 delete jumpTableParser;
534 InstrumentableLevel IA_IAPI::getInstLevel(Function * context, unsigned int num_insns) const
536 InstrumentableLevel ret = InstructionAdapter::getInstLevel(context, num_insns);
537 /* if(ret == HAS_BR_INDIR && isIPRelativeBranch())