INSTRUCTION_EXPORT std::string Operand::format(Architecture arch, Address addr) const { if(!op_value) return "ERROR: format() called on empty operand!"; if (addr) { Expression::Ptr thePC = Expression::Ptr(new RegisterAST(MachRegister::getPC(arch))); op_value->bind(thePC.get(), Result(u32, addr)); Result res = op_value->eval(); if (res.defined) { stringstream ret; ret << hex << res.convert<unsigned>() << dec; return ret.str(); } } return op_value->format(); }
AbsRegion AbsRegionConverter::convert(Expression::Ptr exp, Address addr, ParseAPI::Function *func, ParseAPI::Block *block) { // We want to simplify the expression as much as possible given // currently known state, and then quantify it as one of the following: // // Stack: a memory access based off the current frame pointer (FP) or // stack pointer (SP). If we can determine an offset from the "top" // of the stack we create a stack slot location. Otherwise we create // a "stack" location that represents all stack locations. // // Heap: a memory access to a generic pointer. // // Memory: a memory access to a known address. // // TODO: aliasing relations. Aliasing SUCKS. // Since we have an Expression as input, we don't have the dereference // operator. // Here's the logic: // If no registers are used: // If only immediates are used: // Evaluate and create a MemLoc. // If a dereference exists: // WTF??? // If registers are used: // If the only register is the FP AND the function has a stack frame: // Set FP to 0, eval, and create a specific StackLoc. // If the only register is the SP: // If we know the contents of SP: // Eval and create a specific StackLoc // Else create a generic StackLoc. // If a non-stack register is used: // Create a generic MemLoc. long spHeight = 0; bool stackDefined = getCurrentStackHeight(func, block, addr, spHeight); long fpHeight = 0; bool frameDefined = getCurrentFrameHeight(func, block, addr, fpHeight); bool isStack = false; bool isFrame = false; static Expression::Ptr theStackPtr(new RegisterAST(MachRegister::getStackPointer(Arch_x86))); static Expression::Ptr theStackPtr64(new RegisterAST(MachRegister::getStackPointer(Arch_x86_64))); static Expression::Ptr theStackPtrPPC(new RegisterAST(MachRegister::getStackPointer(Arch_ppc32))); static Expression::Ptr theFramePtr(new RegisterAST(MachRegister::getFramePointer(Arch_x86))); static Expression::Ptr theFramePtr64(new RegisterAST(MachRegister::getFramePointer(Arch_x86_64))); static Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(Arch_x86))); static Expression::Ptr thePC64(new RegisterAST(MachRegister::getPC(Arch_x86_64))); static Expression::Ptr thePCPPC(new RegisterAST(MachRegister::getPC(Arch_ppc32))); // We currently have to try and bind _every_ _single_ _alias_ // of the stack pointer... if (stackDefined) { if (exp->bind(theStackPtr.get(), Result(s32, spHeight)) || exp->bind(theStackPtr64.get(), Result(s64, spHeight)) || exp->bind(theStackPtrPPC.get(), Result(s32, spHeight))) { isStack = true; } } if (frameDefined) { if (exp->bind(theFramePtr.get(), Result(s32, fpHeight)) || exp->bind(theFramePtr64.get(), Result(s64, fpHeight))) { isFrame = true; } } // Bind the IP, why not... exp->bind(thePC.get(), Result(u32, addr)); exp->bind(thePC64.get(), Result(u64, addr)); exp->bind(thePCPPC.get(), Result(u32, addr)); Result res = exp->eval(); if (isFrame && stackAnalysisEnabled_) { if (res.defined && frameDefined) { return AbsRegion(Absloc(res.convert<Address>(), 0, func)); } else { return AbsRegion(Absloc::Stack); } } if (isStack && stackAnalysisEnabled_) { if (res.defined && stackDefined) { return AbsRegion(Absloc(res.convert<Address>(), 0, func)); } else if (func->obj()->defensiveMode()) { // SP could point to the heap, we make the worst-case // assumption and will emulate this stack access return AbsRegion(Absloc::Heap); } else { return AbsRegion(Absloc::Stack); } } // Otherwise we're on the heap if (res.defined) { return AbsRegion(Absloc(res.convert<Address>())); } else { return AbsRegion(Absloc::Heap); } }
func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHandler) { using namespace Dyninst::InstructionAPI; const pdvector<func_instance *> *funcs = findFuncVectorByMangled(dtorHandler); if( funcs != NULL ) { return funcs->at(0); } /* * If the symbol isn't found, try looking for it in a call in the * .fini section. It is the last call in .fini. * * The pattern is: * * _fini: * * ... some code ... * * call dtor_handler * * ... prologue ... */ Symtab *linkedFile = parse_img()->getObject(); Region *finiRegion = NULL; if( !linkedFile->findRegion(finiRegion, ".fini") ) { vector<Dyninst::SymtabAPI::Function *> symFuncs; if( linkedFile->findFunctionsByName(symFuncs, "_fini") ) { finiRegion = symFuncs[0]->getRegion(); }else{ logLine("failed to locate .fini Region or _fini function\n"); return NULL; } } if( finiRegion == NULL ) { logLine("failed to locate .fini Region or _fini function\n"); return NULL; } // Search for last call in the function Address dtorAddress = 0; unsigned bytesSeen = 0; const unsigned char *p = reinterpret_cast<const unsigned char *>(finiRegion->getPtrToRawData()); InstructionDecoder decoder(p, finiRegion->getDiskSize(), parse_img()->codeObject()->cs()->getArch()); Instruction::Ptr lastCall; Instruction::Ptr curInsn = decoder.decode(); while(curInsn && curInsn->isValid() && bytesSeen < finiRegion->getDiskSize()) { InsnCategory category = curInsn->getCategory(); if( category == c_CallInsn ) { lastCall = curInsn; break; } bytesSeen += curInsn->size(); curInsn = decoder.decode(); } if( !lastCall.get() || !lastCall->isValid() ) { logLine("heuristic for finding global destructor function failed\n"); return NULL; } Address callAddress = finiRegion->getMemOffset() + bytesSeen; RegisterAST thePC = RegisterAST( Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch())); Expression::Ptr callTarget = lastCall->getControlFlowTarget(); if( !callTarget.get() ) { logLine("failed to find global destructor function\n"); return NULL; } callTarget->bind(&thePC, Result(s64, callAddress)); Result actualTarget = callTarget->eval(); if( actualTarget.defined ) { dtorAddress = actualTarget.convert<Address>(); }else{ logLine("failed to find global destructor function\n"); return NULL; } if( !dtorAddress || !parse_img()->codeObject()->cs()->isValidAddress(dtorAddress) ) { logLine("invalid address for global destructor function\n"); return NULL; } // A targ stub should have been created at the address func_instance *ret = NULL; if( (ret = findFuncByEntry(dtorAddress)) == NULL ) { logLine("unable to find global destructor function\n"); return NULL; } inst_printf("%s[%d]: set global destructor address to 0x%lx\n", FILE__, __LINE__, dtorAddress); return ret; }
func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorHandler) { using namespace Dyninst::InstructionAPI; const pdvector<func_instance *> *funcs = findFuncVectorByMangled(ctorHandler); if( funcs != NULL ) { return funcs->at(0); } /* If the symbol isn't found, try looking for it in a call instruction in * the .init section * * On Linux, the instruction sequence is: * ... * some instructions * ... * call call_gmon_start * call frame_dummy * call ctor_handler * * On FreeBSD, the instruction sequence is: * ... * some instructions * ... * call frame_dummy * call ctor_handler */ Symtab *linkedFile = parse_img()->getObject(); Region *initRegion = NULL; if( !linkedFile->findRegion(initRegion, ".init") ) { vector<Dyninst::SymtabAPI::Function *> symFuncs; if( linkedFile->findFunctionsByName(symFuncs, "_init") ) { initRegion = symFuncs[0]->getRegion(); }else{ logLine("failed to locate .init Region or _init function\n"); return NULL; } } if( initRegion == NULL ) { logLine("failed to locate .init Region or _init function\n"); return NULL; } // Search for last of a fixed number of calls #if defined(os_freebsd) const unsigned CTOR_NUM_CALLS = 2; #else const unsigned CTOR_NUM_CALLS = 3; #endif Address ctorAddress = 0; unsigned bytesSeen = 0; unsigned numCalls = 0; const unsigned char *p = reinterpret_cast<const unsigned char *>(initRegion->getPtrToRawData()); InstructionDecoder decoder(p, initRegion->getDiskSize(), parse_img()->codeObject()->cs()->getArch()); Instruction::Ptr curInsn = decoder.decode(); while(numCalls < CTOR_NUM_CALLS && curInsn && curInsn->isValid() && bytesSeen < initRegion->getDiskSize()) { InsnCategory category = curInsn->getCategory(); if( category == c_CallInsn ) { numCalls++; } if( numCalls < CTOR_NUM_CALLS ) { bytesSeen += curInsn->size(); curInsn = decoder.decode(); } } if( numCalls != CTOR_NUM_CALLS ) { logLine("heuristic for finding global constructor function failed\n"); return NULL; } Address callAddress = initRegion->getMemOffset() + bytesSeen; RegisterAST thePC = RegisterAST( Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch())); Expression::Ptr callTarget = curInsn->getControlFlowTarget(); if( !callTarget.get() ) { logLine("failed to find global constructor function\n"); return NULL; } callTarget->bind(&thePC, Result(s64, callAddress)); Result actualTarget = callTarget->eval(); if( actualTarget.defined ) { ctorAddress = actualTarget.convert<Address>(); }else{ logLine("failed to find global constructor function\n"); return NULL; } if( !ctorAddress || !parse_img()->codeObject()->cs()->isValidAddress(ctorAddress) ) { logLine("invalid address for global constructor function\n"); return NULL; } func_instance *ret; if( (ret = findFuncByEntry(ctorAddress)) == NULL ) { logLine("unable to create representation for global constructor function\n"); return NULL; } inst_printf("%s[%d]: set global constructor address to 0x%lx\n", FILE__, __LINE__, ctorAddress); return ret; }