/* * See the dyninst/COPYRIGHT file for copyright information. * * We provide the Paradyn Tools (below described as "Paradyn") * on an AS IS basis, and do not warrant its validity or performance. * We reserve the right to update, modify, or discontinue this * software at any time. We shall have no obligation to supply such * updates or modifications or any other form of support to you. * * By your use of Paradyn, you understand and agree that we (or any * other person or entity with proprietary rights in Paradyn) are * under no obligation to provide either maintenance services, * update services, notices of latent defects, or correction of * defects for Paradyn. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define BPATCH_FILE #include "binaryEdit.h" #include "inst.h" #include "instP.h" #include "function.h" // Dyninst::PatchAPI::PatchFunction #include "codeRange.h" #include "addressSpace.h" #include "dynProcess.h" #include "debug.h" #include "mapped_module.h" #include "BPatch_libInfo.h" #include "BPatch.h" #include "BPatch_thread.h" #include "BPatch_function.h" #include "BPatch_point.h" #include "BPatch_private.h" #include "ast.h" #include "BPatch_addressSpace.h" #include "BPatch_instruction.h" #include "mapped_object.h" #include #include "Parsing.h" #include "Command.h" #include "Relocation/DynInstrumenter.h" #include "PatchMgr.h" using Dyninst::PatchAPI::Patcher; using Dyninst::PatchAPI::DynInsertSnipCommand; using Dyninst::PatchAPI::DynReplaceFuncCommand; using Dyninst::PatchAPI::DynModifyCallCommand; using Dyninst::PatchAPI::DynRemoveCallCommand; BPatch_addressSpace::BPatch_addressSpace() : pendingInsertions(NULL), image(NULL) { } BPatch_addressSpace::~BPatch_addressSpace() {} BPatch_function *BPatch_addressSpace::findOrCreateBPFunc(Dyninst::PatchAPI::PatchFunction* ifunc, BPatch_module *bpmod) { func_instance *fi = static_cast(ifunc); if (!bpmod) bpmod = image->findOrCreateModule(fi->mod()); assert(bpmod); if (bpmod->func_map.count(ifunc)) { BPatch_function *bpf = bpmod->func_map[ifunc]; assert(bpf); assert(bpf->func == ifunc); return bpf; } // check to see if the func_instance refers to a different // module, and that module contains a bpatch_func BPatch_module* containing = NULL; if (fi->mod() != NULL) { containing = getImage()->findModule(fi->mod()->fileName().c_str()); } // findModule has a tendency to make new function objects... so // check the map again if (containing->func_map.count(ifunc)) { BPatch_function *bpf = containing->func_map[ifunc]; assert(bpf); assert(bpf->func == ifunc); return bpf; } BPatch_function *ret = new BPatch_function(this, fi, bpmod); assert( ret != NULL ); assert(ret->func == ifunc); return ret; } BPatch_point *BPatch_addressSpace::findOrCreateBPPoint(BPatch_function *bpfunc, Dyninst::PatchAPI::Point *p, BPatch_procedureLocation pointType) { instPoint *ip = static_cast(p); assert(ip); func_instance *fi = static_cast(ip->func()); if (!fi) return NULL; // PatchAPI can create function-less points, but we can't represent them as BPatch_points BPatch_module *mod = image->findOrCreateModule(fi->mod()); assert(mod); if (mod->instp_map.count(ip)) return mod->instp_map[ip]; if (pointType == BPatch_locUnknownLocation) { cerr << "Error: point type not specified!" << endl; assert(0); return NULL; } AddressSpace *lladdrSpace = fi->proc(); if (!bpfunc) bpfunc = findOrCreateBPFunc(fi, mod); assert(bpfunc->func == ip->func()); std::pair pointsToUse = instPoint::getInstpointPair(ip); BPatch_point *pt = new BPatch_point(this, bpfunc, pointsToUse.first, pointsToUse.second, pointType, lladdrSpace); mod->instp_map[ip] = pt; return pt; } BPatch_variableExpr *BPatch_addressSpace::findOrCreateVariable(int_variable *v, BPatch_type *type) { BPatch_module *mod = image->findOrCreateModule(v->mod()); assert(mod); if (mod->var_map.count(v)) return mod->var_map[v]; if (!type) { SymtabAPI::Type *stype = v->ivar()->svar()->getType(); if (stype){ type = BPatch_type::findOrCreateType(stype); }else{ type = BPatch::bpatch->type_Untyped; } } BPatch_variableExpr *var = BPatch_variableExpr::makeVariableExpr(this, v, type); mod->var_map[v] = var; return var; } BPatch_function *BPatch_addressSpace::createBPFuncCB(AddressSpace *a, Dyninst::PatchAPI::PatchFunction *f) { BPatch_addressSpace *aS = (BPatch_addressSpace *)a->up_ptr(); assert(aS); return aS->findOrCreateBPFunc(f, NULL); } BPatch_point *BPatch_addressSpace::createBPPointCB(AddressSpace *a, Dyninst::PatchAPI::PatchFunction *pf, Dyninst::PatchAPI::Point *p, int type) { func_instance *fi = static_cast(pf); instPoint *ip = static_cast(p); BPatch_addressSpace *aS = (BPatch_addressSpace *)a->up_ptr(); assert(aS); BPatch_module *bpmod = aS->getImage()->findOrCreateModule(fi->mod()); assert(bpmod); BPatch_function *func = aS->findOrCreateBPFunc(fi, bpmod); assert(func); return aS->findOrCreateBPPoint(func, ip, (BPatch_procedureLocation) type); } /*************************************************************************** * Bpatch_snippetHandle ***************************************************************************/ /* * BPatchSnippetHandle::BPatchSnippetHandle * * Constructor for BPatchSnippetHandle. Delete the snippet instance(s) * associated with the BPatchSnippetHandle. */ BPatchSnippetHandle::BPatchSnippetHandle(BPatch_addressSpace * addSpace) : addSpace_(addSpace) { } /* * BPatchSnippetHandle::~BPatchSnippetHandle * * Destructor for BPatchSnippetHandle. Delete the snippet instance(s) * associated with the BPatchSnippetHandle. */ BPatchSnippetHandle::~BPatchSnippetHandle() { // don't delete inst instances since they are might have been copied } BPatch_addressSpace *BPatchSnippetHandle::getAddressSpace() { return addSpace_; } BPatch_process *BPatchSnippetHandle::getProcess() { return dynamic_cast(addSpace_); } BPatch_Vector &BPatchSnippetHandle::getCatchupThreads() { return catchup_threads; } BPatchSnippetHandle::thread_iter BPatchSnippetHandle::getCatchupThreads_begin() { return catchup_threads.begin(); } BPatchSnippetHandle::thread_iter BPatchSnippetHandle::getCatchupThreads_end() { return catchup_threads.end(); } // Return true if any sub-minitramp uses a trap? Other option // is "if all"... bool BPatchSnippetHandle::usesTrap() { return false; } BPatch_function * BPatchSnippetHandle::getFunc() { if (!instances_.empty()) { Dyninst::PatchAPI::PatchFunction *func = instances_.back()->point()->func(); BPatch_function *bpfunc = addSpace_->findOrCreateBPFunc(func,NULL); return bpfunc; } return NULL; } BPatch_image * BPatch_addressSpace::getImage() { return image; } /* * BPatch_addressSpace::deleteSnippet * * Deletes an instance of a snippet. * * handle The handle returned by insertSnippet when the instance to * deleted was created. */ bool BPatch_addressSpace::deleteSnippet(BPatchSnippetHandle *handle) { if (getTerminated()) return true; if (handle == NULL) { bperr("Request to delete NULL snippet handle, returning false\n"); return false; } if (handle->addSpace_ != this) { bperr("Error: wrong address space in deleteSnippet\n"); return false; } mal_printf("deleting snippet handle from func at %lx, point at %lx of type %d\n", (Address)handle->getFunc()->getBaseAddr(), handle->instances_.empty() ? 0 : handle->instances_[0]->point()->addr(), handle->instances_.empty() ? -1 : handle->instances_[0]->point()->type()); // if this is a process, check to see if the instrumentation is // executing on the call stack instPoint *ip = static_cast(handle->instances_[0]->point()); if ( handle->getProcess() && handle->instances_.size() > 0 && BPatch_normalMode != ip->func()->obj()->hybridMode()) { if (handle->instances_.size() > 1) { mal_printf("ERROR: Removing snippet that is installed in " "multiple miniTramps %s[%d]\n",FILE__,__LINE__); } } // uninstrument and remove snippet handle from point datastructures for (unsigned int i=0; i < handle->instances_.size(); i++) { uninstrument(handle->instances_[i]); Dyninst::PatchAPI::Point *iPoint = handle->instances_[i]->point(); BPatch_point *bPoint = findOrCreateBPPoint(NULL, iPoint, BPatch_point::convertInstPointType_t(iPoint->type())); assert(bPoint); bPoint->removeSnippet(handle); } handle->instances_.clear(); if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } //delete handle; return true; } /* * BPatch_addressSpace::replaceCode * * Replace a given instruction with a BPatch_snippet. * * point Represents the instruction to be replaced * snippet The replacing snippet */ bool BPatch_addressSpace::replaceCode(BPatch_point * /*point*/, BPatch_snippet * /*snippet*/) { // Need to reevaluate how this code works. I don't think it should be // point-based, though. assert(0); return false; } /* * BPatch_addressSpace::replaceFunctionCall * * Replace a function call with a call to a different function. Returns true * upon success, false upon failure. * * point The call site that is to be changed. * newFunc The function that the call site will now call. */ bool BPatch_addressSpace::replaceFunctionCall(BPatch_point &point, BPatch_function &newFunc) { char name[1024]; newFunc.getName(name, 1024); // Can't make changes to code when mutations are not active. if (!getMutationsActive()) return false; assert(point.point && newFunc.lowlevel_func()); /* PatchAPI stuffs */ AddressSpace* addr_space = point.getAS(); DynModifyCallCommand* rep_call = DynModifyCallCommand::create(addr_space, point.point->block(), newFunc.lowlevel_func(), point.point->func()); addr_space->patcher()->add(rep_call); /* End of PatchAPI */ if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; } /* * BPatch_addressSpace::removeFunctionCall * * Replace a function call with a NOOP. Returns true upon success, false upon * failure. * * point The call site that is to be NOOPed out. */ bool BPatch_addressSpace::removeFunctionCall(BPatch_point &point) { // Can't make changes to code when mutations are not active. if (!getMutationsActive()) return false; assert(point.point); /* PatchAPI stuffs */ AddressSpace* addr_space = point.getAS(); DynRemoveCallCommand* remove_call = DynRemoveCallCommand::create(addr_space, point.point->block(), point.point->func()); addr_space->patcher()->add(remove_call); /* End of PatchAPI */ if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; } /* * BPatch_addressSpace::replaceFunction * * Replace all calls to function OLDFUNC with calls to NEWFUNC. * Returns true upon success, false upon failure. * * oldFunc The function to replace * newFunc The replacement function */ bool BPatch_addressSpace::replaceFunction(BPatch_function &oldFunc, BPatch_function &newFunc) { assert(oldFunc.lowlevel_func() && newFunc.lowlevel_func()); if (!getMutationsActive()) return false; // Self replacement is a nop // We should just test direct equivalence here... if (oldFunc.lowlevel_func() == newFunc.lowlevel_func()) { return true; } /* PatchAPI stuffs */ AddressSpace* addr_space = oldFunc.lowlevel_func()->proc(); DynReplaceFuncCommand* rep_func = DynReplaceFuncCommand::create(addr_space, oldFunc.lowlevel_func(), newFunc.lowlevel_func()); addr_space->patcher()->add(rep_func); /* End of PatchAPI */ if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; } /* * BPatch_addressSpace::revertReplaceFunction * * Undoes a replaceFunction operation */ bool BPatch_addressSpace::revertReplaceFunction(BPatch_function &oldFunc) { assert(oldFunc.lowlevel_func()); if (!getMutationsActive()) return false; func_instance *func = oldFunc.lowlevel_func(); func->proc()->revertReplacedFunction(func); if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; } bool BPatch_addressSpace::wrapFunction(BPatch_function *original, BPatch_function *wrapper, Dyninst::SymtabAPI::Symbol *clone) { assert(original->lowlevel_func() && wrapper->lowlevel_func()); if (!getMutationsActive()) return false; // Self replacement is a nop // We should just test direct equivalence here... if (original->lowlevel_func() == wrapper->lowlevel_func()) { return true; } if (!original->lowlevel_func()->proc()->wrapFunction(original->lowlevel_func(), wrapper->lowlevel_func(), clone)) return false; if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; } bool BPatch_addressSpace::revertWrapFunction(BPatch_function *original) { assert(original->lowlevel_func()); func_instance *func = original->lowlevel_func(); assert(func); func->proc()->revertWrapFunction(func); if (pendingInsertions == NULL) { // Trigger it now bool tmp; finalizeInsertionSet(false, &tmp); } return true; } bool BPatch_addressSpace::getAddressRanges( const char * fileName, unsigned int lineNo, std::vector< SymtabAPI::AddressRange > & ranges ) { unsigned int originalSize = ranges.size(); image->getAddressRanges(fileName, lineNo, ranges); // BPatch_Vector< BPatch_module * > * modules = image->getModules(); /* Iteratate over the modules, looking for addr in each. */ //for ( unsigned int i = 0; i < modules->size(); i++ ) { // BPatch_module *m = (*modules)[i]; // m->getAddressRanges(fileName, lineNo, ranges); //} if ( ranges.size() != originalSize ) { return true; } return false; } /* end getAddressRanges() */ bool BPatch_addressSpace::getSourceLines( unsigned long addr, BPatch_Vector< BPatch_statement > & lines ) { return image->getSourceLines(addr, lines); } /* end getLineAndFile() */ /* * BPatch_process::malloc * * Allocate memory in the thread's address space. * * n The number of bytes to allocate. * * Returns: * A pointer to a BPatch_variableExpr representing the memory. * * If otherwise unspecified when binary rewriting, then the allocation * happens in the original object. */ BPatch_variableExpr *BPatch_addressSpace::malloc(int n, std::string name) { std::vector as; assert(BPatch::bpatch != NULL); getAS(as); assert(as.size()); void *ptr = (void *) as[0]->inferiorMalloc(n, dataHeap); if (!ptr) return NULL; if(name.empty()){ std::stringstream namestr; namestr << "dyn_malloc_0x" << std::hex << ptr << "_" << n << "_bytes"; name = namestr.str(); } BPatch_type *type = BPatch::bpatch->createScalar(name.c_str(), n); return BPatch_variableExpr::makeVariableExpr(this, as[0], name, ptr, type); } /* * BPatch_process::malloc * * Allocate memory in the thread's address space for a variable of the given * type. * * type The type of variable for which to allocate space. * * Returns: * A pointer to a BPatch_variableExpr representing the memory. * * XXX Should return NULL on failure, but the function which it calls, * inferiorMalloc, calls exit rather than returning an error, so this * is not currently possible. */ BPatch_variableExpr *BPatch_addressSpace::malloc(const BPatch_type &type, std::string name) { std::vector as; assert(BPatch::bpatch != NULL); getAS(as); assert(as.size()); BPatch_type &t = const_cast(type); void *mem = (void *) as[0]->inferiorMalloc(t.getSize(), dataHeap); if (!mem) return NULL; if(name.empty()){ std::stringstream namestr; namestr << "dyn_malloc_0x" << std::hex << mem << "_" << type.getName(); name = namestr.str(); } BPatch_variableExpr *varExpr = BPatch_variableExpr::makeVariableExpr(this, as[0], name, mem, &t); return varExpr; } /* * BPatch_process::free * * Free memory that was allocated with BPatch_process::malloc. * * ptr A BPatch_variableExpr representing the memory to free. */ bool BPatch_addressSpace::free(BPatch_variableExpr &ptr) { if(ptr.intvar) { // kill the symbols } ptr.getAS()->inferiorFree((Address)ptr.getBaseAddr()); return true; } BPatch_variableExpr *BPatch_addressSpace::createVariable(std::string name, Dyninst::Address addr, BPatch_type *type) { assert(BPatch::bpatch != NULL); std::vector as; getAS(as); assert(as.size()); //dynC added feature if(strstr(name.c_str(), "dynC") == name.c_str()){ void *mem = (void *) as[0]->inferiorMalloc(type->getSize(), dataHeap); if (!mem) return NULL; BPatch_variableExpr *varExpr = BPatch_variableExpr::makeVariableExpr(this, as[0], name, mem, type); BPatch_module *mod = image->findOrCreateModule(varExpr->intvar->mod()); assert(mod); mod->var_map[varExpr->intvar] = varExpr; return varExpr; } BPatch_variableExpr *varExpr = BPatch_variableExpr::makeVariableExpr(this, as[0], name, (void *)addr, type); return varExpr; } /* * BPatch_addressSpace::findFunctionByAddr * * Returns the function that contains the specified address, or NULL if the * address is not within a function. * * addr The address to use for the lookup. */ BPatch_function *BPatch_addressSpace::findFunctionByAddr(void *addr) { std::vector as; getAS(as); assert(as.size()); std::set funcs; if (!as[0]->findFuncsByAddr((Address) addr, funcs)) { // if it's a mapped_object that has yet to be analyzed, // trigger analysis and re-invoke this function mapped_object *obj = as[0]->findObject((Address) addr); if (obj && !obj->isAnalyzed()) { obj->analyze(); return findFunctionByAddr(addr); } return NULL; } if (funcs.empty()) return NULL; if (funcs.size() > 1) { bpwarn("Warning: deprecated function findFunctionByAddr found " "multiple functions sharing address 0x%lx, picking one at " "random. Use findFunctionByEntry or findFunctionsByAddr\n", addr); } return findOrCreateBPFunc((*(funcs.begin())), NULL); } /* * BPatch_addressSpace::findFunctionByEntry * * Returns the function starting at the given address, or NULL if the * address is not within a function. * * entry The address to use for the lookup. */ BPatch_function *BPatch_addressSpace::findFunctionByEntry(Address entry) { vector funcs; findFunctionsByAddr(entry, funcs); vector::iterator fit; for (fit = funcs.begin(); fit != funcs.end(); fit++) { if (entry == (Address)(*fit)->getBaseAddr()) { return *fit; } } return NULL; } bool BPatch_addressSpace::findFuncsByRange(Address startAddr, Address endAddr, std::set &bpFuncs) { std::vector as; getAS(as); assert(as.size()); // find the first code range in the region mapped_object* mobj = as[0]->findObject(startAddr); assert(mobj); set intFuncs; mobj->findFuncsByRange(startAddr,endAddr,intFuncs); set::iterator fIter = intFuncs.begin(); for (; fIter != intFuncs.end(); fIter++) { BPatch_function * bpfunc = findOrCreateBPFunc(*fIter,NULL); bpFuncs.insert(bpfunc); } return 0 != bpFuncs.size(); } /* * BPatch_addressSpace::findFunctionsByAddr * * Returns the functions that contain the specified address, or NULL if the * address is not within a function. (there could be multiple functions * because of the possibility of shared code) * * addr The address to use for the lookup. * returns false if there were no functions that matched the address */ bool BPatch_addressSpace::findFunctionsByAddr(Address addr, std::vector &funcs) { std::vector as; getAS(as); assert(as.size()); // grab the funcs, return false if there aren't any std::set intfuncs; if (!as[0]->findFuncsByAddr( addr, intfuncs )) { return false; } // convert to BPatch_functions for (std::set::iterator fiter=intfuncs.begin(); fiter != intfuncs.end(); fiter++) { funcs.push_back(findOrCreateBPFunc(*fiter, NULL)); } return 0 < funcs.size(); } /* * BPatch_addressSpace::findModuleByAddr * * Returns the module that contains the specified address, or NULL if the * address is not within a module. Does NOT trigger parsing * * addr The address to use for the lookup. */ BPatch_module *BPatch_addressSpace::findModuleByAddr(Address addr) { std::vector as; getAS(as); assert(as.size()); mapped_object *obj = as[0]->findObject(addr); if ( ! obj ) return NULL; const pdvector mods = obj->getModules(); if (mods.size()) { return getImage()->findOrCreateModule(mods[0]); } return NULL; } /* * BPatch_addressSpace::insertSnippet * * Insert a code snippet at a given instrumentation point. Upon success, * returns a handle to the created instance of the snippet, which can be used * to delete it. Otherwise returns NULL. * * expr The snippet to insert. * point The point at which to insert it. */ BPatchSnippetHandle *BPatch_addressSpace::insertSnippet(const BPatch_snippet &expr, BPatch_point &point, BPatch_snippetOrder order) { BPatch_callWhen when; if (point.getPointType() == BPatch_exit) when = BPatch_callAfter; else when = BPatch_callBefore; return insertSnippet(expr, point, when, order); } /* * BPatch_addressSpace::insertSnippet * * Insert a code snippet at a given instrumentation point. Upon succes, * returns a handle to the created instance of the snippet, which can be used * to delete it. Otherwise returns NULL. * * expr The snippet to insert. * point The point at which to insert it. */ // This handles conversion without requiring inst.h in a header file... extern bool BPatchToInternalArgs(BPatch_point *point, BPatch_callWhen when, BPatch_snippetOrder order, callWhen &ipWhen, callOrder &ipOrder); BPatchSnippetHandle *BPatch_addressSpace::insertSnippet(const BPatch_snippet &expr, BPatch_point &point, BPatch_callWhen when, BPatch_snippetOrder order) { BPatch_Vector points; points.push_back(&point); return insertSnippet(expr, points, when, order); } extern int dyn_debug_ast; /* * BPatch_addressSpace::insertSnippet * * Insert a code snippet at each of a list of instrumentation points. Upon * success, Returns a handle to the created instances of the snippet, which * can be used to delete them (as a unit). Otherwise returns NULL. * * expr The snippet to insert. * points The list of points at which to insert it. */ // A lot duplicated from the single-point version. This is unfortunate. BPatchSnippetHandle *BPatch_addressSpace::insertSnippet(const BPatch_snippet &expr, const BPatch_Vector &points, BPatch_callWhen when, BPatch_snippetOrder order) { BPatchSnippetHandle *retHandle = new BPatchSnippetHandle(this); if (dyn_debug_inst) { BPatch_function *f; for (unsigned i=0; igetFunction(); const string sname = f->func->prettyName(); inst_printf("[%s:%u] - %d. Insert instrumentation at function %s, " "address %p, when %d, order %d\n", FILE__, __LINE__, i, sname.c_str(), points[i]->getAddress(), (int) when, (int) order); } } if (BPatch::bpatch->isTypeChecked()) { if (expr.ast_wrapper->checkType() == BPatch::bpatch->type_Error) { fprintf(stderr, "[%s:%u] - Type error inserting instrumentation\n", FILE__, __LINE__); //expr.ast_wrapper->debugPrint(); return NULL; } } if (!points.size()) { inst_printf("%s[%d]: request to insert snippet at zero points!\n", FILE__, __LINE__); return NULL; } for (unsigned i = 0; i < points.size(); i++) { BPatch_point *bppoint = points[i]; if (bppoint->addSpace == NULL) { fprintf(stderr, "Error: attempt to use point with no process info\n"); continue; } if (dynamic_cast(bppoint->addSpace) != this) { fprintf(stderr, "Error: attempt to use point specific to a different process\n"); continue; } callWhen ipWhen; callOrder ipOrder; if (!BPatchToInternalArgs(bppoint, when, order, ipWhen, ipOrder)) { fprintf(stderr, "[%s:%u] - BPatchToInternalArgs failed for point %d\n", FILE__, __LINE__, i); return retHandle; } if(!expr.checkTypesAtPoint(bppoint)) { continue; } /* PatchAPI stuffs */ instPoint *ipoint = static_cast(bppoint->getPoint(when)); Dyninst::PatchAPI::InstancePtr instance = (ipOrder == orderFirstAtPoint) ? ipoint->pushFront(expr.ast_wrapper) : ipoint->pushBack(expr.ast_wrapper); /* End of PatchAPI stuffs */ if (instance) { if (BPatch::bpatch->isTrampRecursive()) { instance->disableRecursiveGuard(); } retHandle->addInstance(instance); bppoint->recordSnippet(when, order, retHandle); } } if (pendingInsertions == NULL) { // There's no insertion set, instrument now bool tmp; if (!finalizeInsertionSet(false, &tmp)) { return NULL; } } // If we inserted nothing successfully, NULL if(retHandle->isEmpty()) return NULL; return retHandle; } /* * BPatch_addressSpace::insertSnippet * * Insert a code snippet at each of a list of instrumentation points. Upon * success, Returns a handle to the created instances of the snippet, which * can be used to delete them (as a unit). Otherwise returns NULL. * * expr The snippet to insert. * points The list of points at which to insert it. */ BPatchSnippetHandle *BPatch_addressSpace::insertSnippet( const BPatch_snippet &expr, const BPatch_Vector &points, BPatch_snippetOrder order) { return insertSnippet(expr, points, BPatch_callUnset, order); } /* * BPatch_addressSpace::isStaticExecutable * * Returns true if the underlying image represents a statically-linked executable, false otherwise. */ bool BPatch_addressSpace::isStaticExecutable() { std::vector as; getAS(as); if( !as.size() ) return false; AddressSpace *aout = as[0]; return aout->getAOut()->isStaticExec(); } #include "registerSpace.h" #if defined(cap_registers) void BPatch_addressSpace::init_registers() { if(registers_.size()) return; std::vector as; getAS(as); assert(as.size()); registerSpace *rs = registerSpace::getRegisterSpace(as[0]); for (unsigned i = 0; i < rs->realRegs().size(); i++) { // Let's do just GPRs for now registerSlot *regslot = rs->realRegs()[i]; registers_.push_back(BPatch_register(regslot->name, regslot->number)); } // Temporary override: also return EFLAGS though it's certainly not a #if defined(arch_x86) || defined(arch_x86_64) for (unsigned i = 0; i < rs->SPRs().size(); ++i) { if (rs->SPRs()[i]->name == "eflags") { registers_.push_back(BPatch_register(rs->SPRs()[i]->name, rs->SPRs()[i]->number)); } } #endif } bool BPatch_addressSpace::getRegisters(std::vector ®s) { init_registers(); regs = registers_; return true; } BPatch_addressSpace::register_iter BPatch_addressSpace::getRegisters_begin() { init_registers(); return registers_.begin(); } BPatch_addressSpace::register_iter BPatch_addressSpace::getRegisters_end() { init_registers(); return registers_.end(); } #else void BPatch_addressSpace::init_registers() {} bool BPatch_addressSpace::getRegisters(std::vector &) { // Empty vector since we're not supporting register objects on // these platforms (yet) return false; } BPatch_addressSpace::register_iter BPatch_addressSpace::getRegisters_begin() { init_registers(); return registers_.begin(); } BPatch_addressSpace::register_iter BPatch_addressSpace::getRegisters_end() { init_registers(); return registers_.end(); } #endif #if defined(cap_registers) bool BPatch_addressSpace::createRegister_NP(std::string regName, BPatch_register ®) { // Build the register list. std::vector dontcare; getRegisters(dontcare); for (unsigned i = 0; i < registers_.size(); i++) { if (registers_[i].name() == regName) { reg = registers_[i]; return true; } } return false; } #else bool BPatch_addressSpace::createRegister_NP(std::string, BPatch_register &) { return false; } #endif void BPatch_addressSpace::allowTraps(bool allowtraps) { std::vector as; getAS(as); for (std::vector::iterator i = as.begin(); i != as.end(); i++) { (*i)->setUseTraps(allowtraps); } } BPatch_variableExpr *BPatch_addressSpace::createVariable( Dyninst::Address at_addr, BPatch_type *type, std::string var_name, BPatch_module *in_module) { BPatch_binaryEdit *binEdit = dynamic_cast(this); if (binEdit && !in_module) { //Address alone isn't unique when binary rewriting return NULL; } if (!type) { //Required for size information. return NULL; } AddressSpace *ll_addressSpace = NULL; std::vector as; getAS(as); if (binEdit) { std::vector::iterator as_i; for (as_i = as.begin(); as_i != as.end(); as_i++) { BinaryEdit *b = dynamic_cast(*as_i); assert(b); if (in_module->mod->obj() == b->getMappedObject()) { ll_addressSpace = *as_i; break; } } } else { assert(as.size() == 1); ll_addressSpace = as[0]; } if (!ll_addressSpace) { //in_module doesn't belong to 'this' return NULL; } if (!var_name.size()) { std::stringstream namestream; namestream << "dyninst_var_" << std::hex << at_addr; var_name = namestream.str(); } return BPatch_variableExpr::makeVariableExpr(this, ll_addressSpace, var_name, (void *) at_addr, type); } Dyninst::PatchAPI::PatchMgrPtr Dyninst::PatchAPI::convert(const BPatch_addressSpace *a) { const BPatch_binaryEdit *edit = dynamic_cast(a); if (edit) { return edit->lowlevel_edit()->mgr(); } else { const BPatch_process *proc = dynamic_cast(a); return proc->lowlevel_process()->mgr(); } }