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
35 #include "binaryEdit.h"
36 #include "addressSpace.h"
37 #include "EventHandler.h"
39 #include "signalgenerator.h"
42 #include "instPoint.h"
43 #include "function.h" // int_function
44 #include "codeRange.h"
45 #include "dyn_thread.h"
46 #include "miniTramp.h"
48 #include "mapped_module.h"
50 #include "BPatch_libInfo.h"
52 #include "BPatch_addressSpace.h"
54 #include "BPatch_binaryEdit.h"
55 #include "BPatch_image.h"
56 #include "BPatch_thread.h"
57 #include "BPatch_function.h"
58 #include "callbacks.h"
60 #include "BPatch_private.h"
69 * BPatch_binaryEdit::BPatch_binaryEdit
71 * Starts a new process and associates it with the BPatch_binaryEdit being
72 * constructed. The new process is placed into a stopped state before
75 * path Pathname of the executable to start.
76 * argv A list of pointers to character strings which are the
77 * arguments for the new process, terminated by a NULL pointer.
78 * envp A list of pointers to character strings which are the
79 * environment variables for the new process, terminated by a
80 * NULL pointer. If NULL, the default environment will be used.
82 BPatch_binaryEdit::BPatch_binaryEdit(const char *path, bool openDependencies) :
83 BPatch_addressSpace(),
86 pendingInsertions = new BPatch_Vector<batchInsertionRecord *>;
88 pdvector<std::string> argv_vec;
89 pdvector<std::string> envp_vec;
91 std::string directoryName = "";
93 startup_printf("[%s:%u] - Opening original file %s\n",
94 FILE__, __LINE__, path);
95 origBinEdit = BinaryEdit::openFile(std::string(path));
97 startup_printf("[%s:%u] - Creation error opening %s\n",
98 FILE__, __LINE__, path);
99 creation_error = true;
102 llBinEdits[path] = origBinEdit;
104 if(openDependencies) {
105 origBinEdit->getAllDependencies(llBinEdits);
108 origBinEdit->getDyninstRTLibName();
109 std::string rt_name = origBinEdit->dyninstRT_name;
111 // Load the RT library and create the collection of BinaryEdits that represent it
112 std::map<std::string, BinaryEdit *> rtlibs = origBinEdit->openResolvedLibraryName(rt_name);
113 std::map<std::string, BinaryEdit *>::iterator rtlibs_it;
114 for(rtlibs_it = rtlibs.begin(); rtlibs_it != rtlibs.end(); ++rtlibs_it) {
115 if( !rtlibs_it->second ) {
116 std::string msg("Failed to load Dyninst runtime library, check the environment variable DYNINSTAPI_RT_LIB");
117 showErrorCallback(70, msg.c_str());
118 creation_error = true;
122 rtLib.push_back(rtlibs_it->second);
123 // Ensure that the correct type of library is loaded
124 if( rtlibs_it->second->getMappedObject()->isSharedLib()
125 && origBinEdit->getMappedObject()->isStaticExec() )
127 std::string msg = std::string("RT Library is a shared library ") +
128 std::string("when it should be a static library");
129 showErrorCallback(70, msg.c_str());
130 creation_error = true;
132 }else if( !rtlibs_it->second->getMappedObject()->isSharedLib()
133 && !origBinEdit->getMappedObject()->isStaticExec() )
135 std::string msg = std::string("RT Library is a static library ") +
136 std::string("when it should be a shared library");
137 showErrorCallback(70, msg.c_str());
138 creation_error = true;
143 std::map<std::string, BinaryEdit*>::iterator i, j;
144 for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
145 (*i).second->setupRTLibrary(rtLib);
148 int_variable* masterTrampGuard = origBinEdit->createTrampGuard();
149 assert(masterTrampGuard);
151 for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
152 BinaryEdit *llBinEdit = (*i).second;
153 llBinEdit->registerFunctionCallback(createBPFuncCB);
154 llBinEdit->registerInstPointCallback(createBPPointCB);
155 llBinEdit->set_up_ptr(this);
156 llBinEdit->setupRTLibrary(rtLib);
157 llBinEdit->setTrampGuard(masterTrampGuard);
158 llBinEdit->setMultiThreadCapable(isMultiThreadCapable());
159 for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) {
160 llBinEdit->addSibling((*j).second);
164 image = new BPatch_image(this);
167 bool BPatch_binaryEdit::isMultiThreadCapable() const
169 return origBinEdit->isMultiThreadCapable();
172 BPatch_image * BPatch_binaryEdit::getImageInt() {
176 void BPatch_binaryEdit::BPatch_binaryEdit_dtor()
183 if (pendingInsertions) {
184 for (unsigned f = 0; f < pendingInsertions->size(); f++) {
185 delete (*pendingInsertions)[f];
187 delete pendingInsertions;
188 pendingInsertions = NULL;
191 std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
192 for(; i != llBinEdits.end(); i++) {
198 assert(BPatch::bpatch != NULL);
201 bool BPatch_binaryEdit::writeFileInt(const char * outFile)
203 assert(pendingInsertions);
205 // This should be a parameter...
208 // Define up here so we don't have gotos causing issues
209 std::set<int_function *> instrumentedFunctions;
211 // Two loops: first addInst, then generate/install/link
212 pdvector<miniTramp *> workDone;
215 for (unsigned i = 0; i < pendingInsertions->size(); i++) {
216 batchInsertionRecord *&bir = (*pendingInsertions)[i];
219 // Don't handle thread inst yet...
220 assert(!bir->thread_);
222 if (!bir->points_.size()) {
223 fprintf(stderr, "%s[%d]: WARN: zero points for insertion record\n", FILE__, __LINE__);
224 fprintf(stderr, "%s[%d]: failing to addInst\n", FILE__, __LINE__);
227 for (unsigned j = 0; j < bir->points_.size(); j++) {
228 BPatch_point *bppoint = bir->points_[j];
229 instPoint *point = bppoint->point;
230 callWhen when = bir->when_[j];
232 miniTramp *mini = point->addInst(bir->snip.ast_wrapper,
235 bir->trampRecursive_,
238 workDone.push_back(mini);
239 // Add to snippet handle
240 bir->handle_->addMiniTramp(mini);
251 if (atomic && err) goto cleanup;
253 // Having inserted the requests, we hand things off to functions to
254 // actually do work. First, develop a list of unique functions.
256 for (unsigned i = 0; i < pendingInsertions->size(); i++) {
257 batchInsertionRecord *&bir = (*pendingInsertions)[i];
258 for (unsigned j = 0; j < bir->points_.size(); j++) {
259 BPatch_point *bppoint = bir->points_[j];
260 instPoint *point = bppoint->point;
261 point->optimizeBaseTramps(bir->when_[j]);
263 instrumentedFunctions.insert(point->func());
267 for (std::set<int_function *>::iterator funcIter = instrumentedFunctions.begin();
268 funcIter != instrumentedFunctions.end();
271 pdvector<instPoint *> failedInstPoints;
272 (*funcIter)->performInstrumentation(atomic,
274 if (failedInstPoints.size() && atomic) {
281 // Now that we've instrumented we can see if we need to replace the
283 replaceTrapHandler();
289 for(std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
290 i != llBinEdits.end(); i++)
292 (*i).second->trapMapping.flush();
299 // Something failed... Cleanup...
300 for (unsigned k = 0; k < workDone.size(); k++) {
301 workDone[k]->uninstrument();
306 for (unsigned int i = 0; i < pendingInsertions->size(); i++) {
307 batchInsertionRecord *&bir = (*pendingInsertions)[i];
312 pendingInsertions->clear();
314 if( !origBinEdit->writeFile(outFile) ) return false;
316 std::map<std::string, BinaryEdit *>::iterator i;
317 for (i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
318 BinaryEdit *bin = (*i).second;
319 if (bin == origBinEdit)
324 std::string newname = bin->getMappedObject()->fileName();
325 if( !bin->writeFile(newname) ) return false;
332 bool BPatch_binaryEdit::getType()
334 return STATIC_EDITOR;
337 void BPatch_binaryEdit::getAS(std::vector<AddressSpace *> &as)
339 std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
340 as.push_back(origBinEdit);
341 for(; i != llBinEdits.end(); i++) {
342 if ((*i).second == origBinEdit)
344 as.push_back((*i).second);
350 * BPatch_addressSpace::beginInsertionSet
352 * Starts a batch insertion set; that is, all calls to insertSnippet until
353 * finalizeInsertionSet are delayed.
357 void BPatch_binaryEdit::beginInsertionSetInt()
363 bool BPatch_binaryEdit::finalizeInsertionSetInt(bool /*atomic*/, bool * /*modified*/)
368 bool BPatch_binaryEdit::loadLibraryInt(const char *libname, bool deps)
370 std::map<std::string, BinaryEdit*> libs = origBinEdit->openResolvedLibraryName(libname);
371 std::map<std::string, BinaryEdit*>::iterator lib_it;
372 for(lib_it = libs.begin(); lib_it != libs.end(); ++lib_it) {
373 std::pair<std::string, BinaryEdit*> lib = *lib_it;
378 llBinEdits.insert(lib);
380 int_variable* masterTrampGuard = origBinEdit->createTrampGuard();
381 assert(masterTrampGuard);
383 lib.second->registerFunctionCallback(createBPFuncCB);
384 lib.second->registerInstPointCallback(createBPPointCB);
385 lib.second->set_up_ptr(this);
386 lib.second->setupRTLibrary(rtLib);
387 lib.second->setTrampGuard(masterTrampGuard);
388 lib.second->setMultiThreadCapable(isMultiThreadCapable());
389 /* Do we need to do this?
390 std::map<std::string, BinaryEdit*>::iterator j;
391 for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) {
392 lib.second->addSibling((*j).second);
396 if( !lib.second->getAllDependencies(llBinEdits) ) return false;
402 bool BPatch_binaryEdit::isStaticExecutableInt() {
403 return origBinEdit->getMappedObject()->isStaticExec();
406 // Here's the story. We may need to install a trap handler for instrumentation
407 // to work in the rewritten binary. This doesn't play nicely with trap handlers
408 // that the binary itself registers. So we're going to replace every call to
409 // sigaction in the binary with a call to our wrapper. This wrapper:
410 // 1) Ignores attempts to register a SIGTRAP
411 // 2) Passes everything else through to sigaction
412 // It's called "dyn_sigaction".
413 // This is just a multiplexing function over each child binaryEdit
414 // object because they're all individual.
416 bool BPatch_binaryEdit::replaceTrapHandler() {
417 // Did we use a trap?
419 bool usedATrap = false;
421 std::map<std::string, BinaryEdit *>::iterator iter = llBinEdits.begin();
422 for (; iter != llBinEdits.end(); iter++) {
423 if (iter->second->usedATrap()) {
428 if (!usedATrap) return true;
430 // We used a trap, so go through and set up the replacement instrumentation.
431 // However, don't let this be the first piece of instrumentation put into
435 iter = llBinEdits.begin();
436 for (; iter != llBinEdits.end(); iter++) {
437 BinaryEdit *binEd = iter->second;
439 // Did we instrument this already?
440 if (!binEd->isDirty()) {
444 // Okay, replace trap handler
445 if (!binEd->replaceTrapHandler()) {