bool BPatch_binaryEdit::writeFile(const char * outFile) { assert(pendingInsertions); // This should be a parameter... //bool atomic = false; // Define up here so we don't have gotos causing issues std::set<func_instance *> instrumentedFunctions; // Two loops: first addInst, then generate/install/link pdvector<miniTramp *> workDone; //bool err = false; // Iterate over our AddressSpaces, triggering relocation // in each one. std::vector<AddressSpace *> as; getAS(as); bool ret = true; /* PatchAPI stuffs */ if (as.size() > 0) { ret = AddressSpace::patch(as[0]); } /* end of PatchAPI stuffs */ // Now that we've instrumented we can see if we need to replace the // trap handler. replaceTrapHandler(); for(std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin(); i != llBinEdits.end(); i++) { (*i).second->trapMapping.flush(); } if( !origBinEdit->writeFile(outFile) ) return false; std::map<std::string, BinaryEdit *>::iterator curBinEdit; for (curBinEdit = llBinEdits.begin(); curBinEdit != llBinEdits.end(); curBinEdit++) { BinaryEdit *bin = (*curBinEdit).second; if (bin == origBinEdit) continue; if (!bin->isDirty()) continue; std::string newname = bin->getMappedObject()->fileName(); if( !bin->writeFile(newname) ) return false; } return ret; }
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<BPatch_binaryEdit *>(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<AddressSpace *> as; getAS(as); if (binEdit) { std::vector<AddressSpace *>::iterator as_i; for (as_i = as.begin(); as_i != as.end(); as_i++) { BinaryEdit *b = dynamic_cast<BinaryEdit *>(*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); }
mapped_object *BinaryEdit::openResolvedLibraryName(std::string filename, std::map<std::string, BinaryEdit *> &allOpened) { /* * Note: this does not actually do any library name resolution, as that is OS-dependent * If resolution is required, it should be implemented in an OS-dependent file * (see linux.C for an example) * * However, this version allows the RT library to be opened with this function regardless * if library name resolution has been implemented on a platform. */ std::map<std::string, BinaryEdit *> retMap; assert(mgr()); BinaryEdit *temp = BinaryEdit::openFile(filename, mgr(), patcher()); if( temp && temp->getAddressWidth() == getAddressWidth() ) { allOpened.insert(std::make_pair(filename, temp)); return temp->getMappedObject(); } return NULL; }
bool BPatch_binaryEdit::replaceTrapHandler() { // Did we use a trap? bool usedATrap = false; std::map<std::string, BinaryEdit *>::iterator iter = llBinEdits.begin(); for (; iter != llBinEdits.end(); iter++) { if (iter->second->usedATrap()) { usedATrap = true; break; } } if (!usedATrap) return true; // We used a trap, so go through and set up the replacement instrumentation. // However, don't let this be the first piece of instrumentation put into // a library. bool success = true; iter = llBinEdits.begin(); for (; iter != llBinEdits.end(); iter++) { BinaryEdit *binEd = iter->second; // Did we instrument this already? if (!binEd->isDirty()) { continue; } // Okay, replace trap handler if (!binEd->replaceTrapHandler()) { success = false; } } return success; }
// findCallee: finds the function called by the instruction corresponding // to the instPoint "instr". If the function call has been bound to an // address, then the callee function is returned in "target" and the // instPoint "callee" data member is set to pt to callee's func_instance. // If the function has not yet been bound, then "target" is set to the // func_instance associated with the name of the target function (this is // obtained by the PLT and relocation entries in the image), and the instPoint // callee is not set. If the callee function cannot be found, (ex. function // pointers, or other indirect calls), it returns false. // Returns false on error (ex. process doesn't contain this instPoint). // // HACK: made an func_instance method to remove from instPoint class... // FURTHER HACK: made a block_instance method so we can share blocks func_instance *block_instance::callee() { // Check 1: pre-computed callee via PLT func_instance *ret = obj()->getCallee(this); if (ret) return ret; // See if we've already done this edge_instance *tEdge = getTarget(); if (!tEdge) { return NULL; } if (!tEdge->sinkEdge()) { func_instance *tmp = obj()->findFuncByEntry(tEdge->trg()); if (tmp && !(tmp->ifunc()->isPLTFunction())) { return tmp; } } // Do this the hard way - an inter-module jump // get the target address of this function Address target_addr; bool success; boost::tie(success, target_addr) = llb()->callTarget(); if(!success) { // this is either not a call instruction or an indirect call instr // that we can't get the target address //fprintf(stderr, "%s[%d]: returning NULL\n", FILE__, __LINE__); return NULL; } // get the relocation information for this image Symtab *sym = obj()->parse_img()->getObject(); pdvector<relocationEntry> fbt; vector <relocationEntry> fbtvector; if (!sym->getFuncBindingTable(fbtvector)) { //fprintf(stderr, "%s[%d]: returning NULL\n", FILE__, __LINE__); return NULL; } /** * Object files and static binaries will not have a function binding table * because the function binding table holds relocations used by the dynamic * linker */ if (!fbtvector.size() && !sym->isStaticBinary() && sym->getObjectType() != obj_RelocatableFile ) { fprintf(stderr, "%s[%d]: WARN: zero func bindings\n", FILE__, __LINE__); } for (unsigned index=0; index< fbtvector.size();index++) fbt.push_back(fbtvector[index]); Address base_addr = obj()->codeBase(); std::map<Address, std::string> pltFuncs; obj()->parse_img()->getPltFuncs(pltFuncs); // find the target address in the list of relocationEntries if (pltFuncs.find(target_addr) != pltFuncs.end()) { for (u_int i=0; i < fbt.size(); i++) { if (fbt[i].target_addr() == target_addr) { // check to see if this function has been bound yet...if the // PLT entry for this function has been modified by the runtime // linker func_instance *target_pdf = 0; if (proc()->hasBeenBound(fbt[i], target_pdf, base_addr)) { updateCallTarget(target_pdf); obj()->setCalleeName(this, target_pdf->symTabName()); obj()->setCallee(this, target_pdf); return target_pdf; } } } const char *target_name = pltFuncs[target_addr].c_str(); PCProcess *dproc = dynamic_cast<PCProcess *>(proc()); BinaryEdit *bedit = dynamic_cast<BinaryEdit *>(proc()); obj()->setCalleeName(this, std::string(target_name)); pdvector<func_instance *> pdfv; // See if we can name lookup if (dproc) { if (proc()->findFuncsByMangled(target_name, pdfv)) { obj()->setCallee(this, pdfv[0]); updateCallTarget(pdfv[0]); return pdfv[0]; } } else if (bedit) { std::vector<BinaryEdit *>::iterator i; for (i = bedit->getSiblings().begin(); i != bedit->getSiblings().end(); i++) { if ((*i)->findFuncsByMangled(target_name, pdfv)) { obj()->setCallee(this, pdfv[0]); updateCallTarget(pdfv[0]); return pdfv[0]; } } } else assert(0); } //fprintf(stderr, "%s[%d]: returning NULL: target addr = %p\n", FILE__, __LINE__, (void *)target_addr); return NULL; }
mapped_object *BinaryEdit::openResolvedLibraryName(std::string filename, std::map<std::string, BinaryEdit*> &retMap) { std::vector<std::string> paths; std::vector<std::string>::iterator pathIter; // First, find the specified library file bool resolved = getResolvedLibraryPath(filename, paths); // Second, create a set of BinaryEdits for the found library if ( resolved ) { startup_printf("[%s:%u] - Opening dependent file %s\n", FILE__, __LINE__, filename.c_str()); Symtab *origSymtab = getMappedObject()->parse_img()->getObject(); assert(mgr()); // Dynamic case if ( !origSymtab->isStaticBinary() ) { for(pathIter = paths.begin(); pathIter != paths.end(); ++pathIter) { BinaryEdit *temp = BinaryEdit::openFile(*pathIter, mgr(), patcher()); if (temp && temp->getAddressWidth() == getAddressWidth()) { retMap.insert(std::make_pair(*pathIter, temp)); return temp->getMappedObject(); } delete temp; } } else { // Static executable case /* * Alright, this is a kludge, but even though the Archive is opened * twice (once here and once by the image class later on), it is * only parsed once because the Archive class keeps track of all * open Archives. * * This is partly due to the fact that Archives are collections of * Symtab objects and their is one Symtab for each BinaryEdit. In * some sense, an Archive is a collection of BinaryEdits. */ for(pathIter = paths.begin(); pathIter != paths.end(); ++pathIter) { Archive *library; Symtab *singleObject; if (Archive::openArchive(library, *pathIter)) { std::vector<Symtab *> members; if (library->getAllMembers(members)) { std::vector <Symtab *>::iterator member_it; for (member_it = members.begin(); member_it != members.end(); ++member_it) { BinaryEdit *temp = BinaryEdit::openFile(*pathIter, mgr(), patcher(), (*member_it)->memberName()); if (temp && temp->getAddressWidth() == getAddressWidth()) { std::string mapName = *pathIter + string(":") + (*member_it)->memberName(); retMap.insert(std::make_pair(mapName, temp)); }else{ if(temp) delete temp; retMap.clear(); break; } } if (retMap.size() > 0) { origSymtab->addLinkingResource(library); // So we tried loading "libc.a", and got back a swarm of individual members. // Lovely. // Just return the first thing... return retMap.begin()->second->getMappedObject(); } //if( library ) delete library; } } else if (Symtab::openFile(singleObject, *pathIter)) { BinaryEdit *temp = BinaryEdit::openFile(*pathIter, mgr(), patcher()); if (temp && temp->getAddressWidth() == getAddressWidth()) { if( singleObject->getObjectType() == obj_SharedLib || singleObject->getObjectType() == obj_Executable ) { startup_printf("%s[%d]: cannot load dynamic object(%s) when rewriting a static binary\n", FILE__, __LINE__, pathIter->c_str()); std::string msg = std::string("Cannot load a dynamic object when rewriting a static binary"); showErrorCallback(71, msg.c_str()); delete singleObject; }else{ retMap.insert(std::make_pair(*pathIter, temp)); return temp->getMappedObject(); } } if(temp) delete temp; } } } } startup_printf("[%s:%u] - Creation error opening %s\n", FILE__, __LINE__, filename.c_str()); // If the only thing we could find was a dynamic lib for a static executable, we can reach here; caller should handle this. return NULL; }
/* * BPatch_binaryEdit::BPatch_binaryEdit * * Creates a new BinaryEdit and associates it with the BPatch_binaryEdit * being created. Additionally, if specified, the dependencies of the * original BinaryEdit are opened and associated with the BPatch_binaryEdit * * path Pathname of the executable * openDependencies if true, the dependencies of the original BinaryEdit are * also opened */ BPatch_binaryEdit::BPatch_binaryEdit(const char *path, bool openDependencies) : BPatch_addressSpace(), creation_error(false) { pendingInsertions = new BPatch_Vector<batchInsertionRecord *>; pdvector<std::string> argv_vec; pdvector<std::string> envp_vec; std::string directoryName = ""; startup_printf("[%s:%u] - Opening original file %s\n", FILE__, __LINE__, path); origBinEdit = BinaryEdit::openFile(std::string(path)); if (!origBinEdit){ startup_printf("[%s:%u] - Creation error opening %s\n", FILE__, __LINE__, path); creation_error = true; return; } llBinEdits[path] = origBinEdit; if(openDependencies) { origBinEdit->getAllDependencies(llBinEdits); } std::map<std::string, BinaryEdit*>::iterator i, j; origBinEdit->getDyninstRTLibName(); std::string rt_name = origBinEdit->dyninstRT_name; // Load the RT library and create the collection of BinaryEdits that represent it std::map<std::string, BinaryEdit *> rtlibs; origBinEdit->openResolvedLibraryName(rt_name, rtlibs); std::map<std::string, BinaryEdit *>::iterator rtlibs_it; for(rtlibs_it = rtlibs.begin(); rtlibs_it != rtlibs.end(); ++rtlibs_it) { if( !rtlibs_it->second ) { std::string msg("Failed to load Dyninst runtime library, check the environment variable DYNINSTAPI_RT_LIB"); showErrorCallback(70, msg.c_str()); creation_error = true; return; } rtLib.push_back(rtlibs_it->second); // Ensure that the correct type of library is loaded if( rtlibs_it->second->getMappedObject()->isSharedLib() && origBinEdit->getMappedObject()->isStaticExec() ) { std::string msg = std::string("RT Library is a shared library ") + std::string("when it should be a static library"); showErrorCallback(70, msg.c_str()); creation_error = true; return; }else if( !rtlibs_it->second->getMappedObject()->isSharedLib() && !origBinEdit->getMappedObject()->isStaticExec() ) { std::string msg = std::string("RT Library is a static library ") + std::string("when it should be a shared library"); showErrorCallback(70, msg.c_str()); creation_error = true; return; } } for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) { (*i).second->setupRTLibrary(rtLib); } int_variable* masterTrampGuard = origBinEdit->createTrampGuard(); assert(masterTrampGuard); for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) { BinaryEdit *llBinEdit = (*i).second; llBinEdit->registerFunctionCallback(createBPFuncCB); llBinEdit->registerInstPointCallback(createBPPointCB); llBinEdit->set_up_ptr(this); llBinEdit->setupRTLibrary(rtLib); llBinEdit->setTrampGuard(masterTrampGuard); llBinEdit->setMultiThreadCapable(isMultiThreadCapable()); for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) { llBinEdit->addSibling((*j).second); } } image = new BPatch_image(this); }
BinaryEdit *BinaryEdit::openFile(const std::string &file, PatchMgrPtr mgr, Dyninst::PatchAPI::Patcher *patch, const std::string &member) { if (!OS::executableExists(file)) { startup_printf("%s[%d]: failed to read file %s\n", FILE__, __LINE__, file.c_str()); std::string msg = std::string("Can't read executable file ") + file + (": ") + strerror(errno); showErrorCallback(68, msg.c_str()); return NULL; } fileDescriptor desc; if (!getStatFileDescriptor(file, desc)) { startup_printf("%s[%d]: failed to create file descriptor for %s!\n", FILE__, __LINE__, file.c_str()); return NULL; } // Open the mapped object as an archive member if( !member.empty() ) { desc.setMember(member); } BinaryEdit *newBinaryEdit = new BinaryEdit(); if (!newBinaryEdit) { startup_printf("%s[%d]: failed to create binary representation for %s!\n", FILE__, __LINE__, file.c_str()); } newBinaryEdit->mobj = mapped_object::createMappedObject(desc, newBinaryEdit); if (!newBinaryEdit->mobj) { startup_printf("%s[%d]: failed to create mapped object for %s\n", FILE__, __LINE__, file.c_str()); return NULL; } /* PatchAPI stuffs */ if (!mgr) { newBinaryEdit->initPatchAPI(); } else { newBinaryEdit->setMgr(mgr); assert(patch); newBinaryEdit->setPatcher(patch); } newBinaryEdit->addMappedObject(newBinaryEdit->mobj); /* End of PatchAPI stuffs */ // We now need to access the start of the new section we're creating. // I'm going through the mapped_object interface for now - // I assume we'll pass it to DynSymtab, then add our base // address to it at the mapped_ level. Symtab* linkedFile = newBinaryEdit->getAOut()->parse_img()->getObject(); Region *newSec = NULL; linkedFile->findRegion(newSec, ".dyninstInst"); if (newSec) { // We're re-instrumenting - will fail for now fprintf(stderr, "ERROR: unable to open/reinstrument previously instrumented binary %s!\n", file.c_str()); return NULL; } Address base = linkedFile->getFreeOffset(50*1024*1024); base += (1024*1024); base -= (base & (1024*1024-1)); newBinaryEdit->highWaterMark_ = base; newBinaryEdit->lowWaterMark_ = newBinaryEdit->highWaterMark_; //CHEN MODIFIED, this can reserve space for plt table, or even for inline code region //newBinaryEdit->highWaterMark_ += 0x100000; // Testing newBinaryEdit->makeInitAndFiniIfNeeded(); newBinaryEdit->createMemoryBackingStore(newBinaryEdit->getAOut()); newBinaryEdit->initialize(); //Don't count initialization in determining dirty newBinaryEdit->isDirty_ = false; //!(foundInit && foundFini); return newBinaryEdit; }