2 * Copyright (c) 1996-2004 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 * This license is for research uses. For such uses, there is no
12 * charge. We define "research use" to mean you may freely use it
13 * inside your organization for whatever purposes you see fit. But you
14 * may not re-distribute Paradyn or parts of Paradyn, in any form
15 * source or binary (including derivatives), electronic or otherwise,
16 * to any other organization or entity without our permission.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
24 * By your use of Paradyn, you understand and agree that we (or any
25 * other person or entity with proprietary rights in Paradyn) are
26 * under no obligation to provide either maintenance services,
27 * update services, notices of latent defects, or correction of
28 * defects for Paradyn.
30 * Even if advised of the possibility of such damages, under no
31 * circumstances shall we (or any other person or entity with
32 * proprietary rights in the software licensed hereunder) be liable
33 * to you or any third party for direct, indirect, or consequential
34 * damages of any character regardless of type of action, including,
35 * without limitation, loss of profits, loss of use, loss of good
36 * will, or computer failure or malfunction. You agree to indemnify
37 * us (and any other person or entity with proprietary rights in the
38 * software licensed hereunder) for any and all liability it may
39 * incur to third parties resulting from your use of Paradyn.
45 #include "binaryEdit.h"
46 #include "addressSpace.h"
47 #include "EventHandler.h"
49 #include "signalgenerator.h"
52 #include "instPoint.h"
53 #include "function.h" // int_function
54 #include "codeRange.h"
55 #include "dyn_thread.h"
56 #include "miniTramp.h"
58 #include "mapped_module.h"
60 #include "BPatch_libInfo.h"
62 #include "BPatch_addressSpace.h"
64 #include "BPatch_binaryEdit.h"
65 #include "BPatch_image.h"
66 #include "BPatch_thread.h"
67 #include "BPatch_function.h"
68 #include "callbacks.h"
70 #include "BPatch_private.h"
79 * BPatch_binaryEdit::BPatch_binaryEdit
81 * Starts a new process and associates it with the BPatch_binaryEdit being
82 * constructed. The new process is placed into a stopped state before
85 * path Pathname of the executable to start.
86 * argv A list of pointers to character strings which are the
87 * arguments for the new process, terminated by a NULL pointer.
88 * envp A list of pointers to character strings which are the
89 * environment variables for the new process, terminated by a
90 * NULL pointer. If NULL, the default environment will be used.
92 BPatch_binaryEdit::BPatch_binaryEdit(const char *path, bool openDependencies) :
93 BPatch_addressSpace(),
96 pendingInsertions = new BPatch_Vector<batchInsertionRecord *>;
98 pdvector<std::string> argv_vec;
99 pdvector<std::string> envp_vec;
101 std::string directoryName = "";
103 startup_printf("[%s:%u] - Opening original file %s\n",
104 FILE__, __LINE__, path);
105 origBinEdit = BinaryEdit::openFile(std::string(path));
107 startup_printf("[%s:%u] - Creation error opening %s\n",
108 FILE__, __LINE__, path);
109 creation_error = true;
112 llBinEdits[path] = origBinEdit;
114 if(openDependencies) {
115 origBinEdit->getAllDependencies(llBinEdits);
118 origBinEdit->getDyninstRTLibName();
119 std::string rt_name = origBinEdit->dyninstRT_name;
120 rtLib = BinaryEdit::openFile(rt_name);
122 startup_printf("[%s:%u] - ERROR. Could not open RT library\n",
124 creation_error = true;
128 std::map<std::string, BinaryEdit*>::iterator i, j;
129 for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
130 (*i).second->setupRTLibrary(rtLib);
133 int_variable* masterTrampGuard = origBinEdit->createTrampGuard();
134 assert(masterTrampGuard);
136 for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
137 BinaryEdit *llBinEdit = (*i).second;
138 llBinEdit->registerFunctionCallback(createBPFuncCB);
139 llBinEdit->registerInstPointCallback(createBPPointCB);
140 llBinEdit->set_up_ptr(this);
141 llBinEdit->setupRTLibrary(rtLib);
142 llBinEdit->setTrampGuard(masterTrampGuard);
143 llBinEdit->setMultiThreadCapable(isMultiThreadCapable());
144 for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) {
145 llBinEdit->addSibling((*j).second);
149 image = new BPatch_image(this);
152 bool BPatch_binaryEdit::isMultiThreadCapable() const
154 return origBinEdit->isMultiThreadCapable();
157 BPatch_image * BPatch_binaryEdit::getImageInt() {
161 void BPatch_binaryEdit::BPatch_binaryEdit_dtor()
168 if (pendingInsertions) {
169 for (unsigned f = 0; f < pendingInsertions->size(); f++) {
170 delete (*pendingInsertions)[f];
172 delete pendingInsertions;
173 pendingInsertions = NULL;
176 std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
177 for(; i != llBinEdits.end(); i++) {
183 assert(BPatch::bpatch != NULL);
186 bool BPatch_binaryEdit::writeFileInt(const char * outFile)
188 assert(pendingInsertions);
190 // This should be a parameter...
193 // Define up here so we don't have gotos causing issues
194 std::set<int_function *> instrumentedFunctions;
196 // Two loops: first addInst, then generate/install/link
197 pdvector<miniTramp *> workDone;
200 for (unsigned i = 0; i < pendingInsertions->size(); i++) {
201 batchInsertionRecord *&bir = (*pendingInsertions)[i];
204 // Don't handle thread inst yet...
205 assert(!bir->thread_);
207 if (!bir->points_.size()) {
208 fprintf(stderr, "%s[%d]: WARN: zero points for insertion record\n", FILE__, __LINE__);
209 fprintf(stderr, "%s[%d]: failing to addInst\n", FILE__, __LINE__);
212 for (unsigned j = 0; j < bir->points_.size(); j++) {
213 BPatch_point *bppoint = bir->points_[j];
214 instPoint *point = bppoint->point;
215 callWhen when = bir->when_[j];
217 miniTramp *mini = point->addInst(bir->snip.ast_wrapper,
220 bir->trampRecursive_,
223 workDone.push_back(mini);
224 // Add to snippet handle
225 bir->handle_->addMiniTramp(mini);
236 if (atomic && err) goto cleanup;
238 // Having inserted the requests, we hand things off to functions to
239 // actually do work. First, develop a list of unique functions.
241 for (unsigned i = 0; i < pendingInsertions->size(); i++) {
242 batchInsertionRecord *&bir = (*pendingInsertions)[i];
243 for (unsigned j = 0; j < bir->points_.size(); j++) {
244 BPatch_point *bppoint = bir->points_[j];
245 instPoint *point = bppoint->point;
246 point->optimizeBaseTramps(bir->when_[j]);
248 instrumentedFunctions.insert(point->func());
252 for (std::set<int_function *>::iterator funcIter = instrumentedFunctions.begin();
253 funcIter != instrumentedFunctions.end();
256 pdvector<instPoint *> failedInstPoints;
257 (*funcIter)->performInstrumentation(atomic,
259 if (failedInstPoints.size() && atomic) {
266 // Now that we've instrumented we can see if we need to replace the
268 replaceTrapHandler();
274 for(std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
275 i != llBinEdits.end(); i++)
277 (*i).second->trapMapping.flush();
284 // Something failed... Cleanup...
285 for (unsigned k = 0; k < workDone.size(); k++) {
286 workDone[k]->uninstrument();
291 for (unsigned int i = 0; i < pendingInsertions->size(); i++) {
292 batchInsertionRecord *&bir = (*pendingInsertions)[i];
297 pendingInsertions->clear();
299 origBinEdit->writeFile(outFile);
301 std::map<std::string, BinaryEdit *>::iterator i;
302 for (i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
303 BinaryEdit *bin = (*i).second;
304 if (bin == origBinEdit)
309 std::string newname = bin->getMappedObject()->fileName();
310 bin->writeFile(newname);
317 bool BPatch_binaryEdit::getType()
319 return STATIC_EDITOR;
322 void BPatch_binaryEdit::getAS(std::vector<AddressSpace *> &as)
324 std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
325 as.push_back(origBinEdit);
326 for(; i != llBinEdits.end(); i++) {
327 if ((*i).second == origBinEdit)
329 as.push_back((*i).second);
334 * BPatch_addressSpace::beginInsertionSet
336 * Starts a batch insertion set; that is, all calls to insertSnippet until
337 * finalizeInsertionSet are delayed.
341 void BPatch_binaryEdit::beginInsertionSetInt()
347 bool BPatch_binaryEdit::finalizeInsertionSetInt(bool /*atomic*/, bool * /*modified*/)
352 bool BPatch_binaryEdit::loadLibraryInt(const char *libname, bool deps)
354 std::pair<std::string, BinaryEdit*> lib = origBinEdit->openResolvedLibraryName(libname);
358 llBinEdits.insert(lib);
361 return lib.second->getAllDependencies(llBinEdits);
366 // Here's the story. We may need to install a trap handler for instrumentation
367 // to work in the rewritten binary. This doesn't play nicely with trap handlers
368 // that the binary itself registers. So we're going to replace every call to
369 // sigaction in the binary with a call to our wrapper. This wrapper:
370 // 1) Ignores attempts to register a SIGTRAP
371 // 2) Passes everything else through to sigaction
372 // It's called "dyn_sigaction".
373 // This is just a multiplexing function over each child binaryEdit
374 // object because they're all individual.
376 bool BPatch_binaryEdit::replaceTrapHandler() {
377 // Did we use a trap?
379 bool usedATrap = false;
381 std::map<std::string, BinaryEdit *>::iterator iter = llBinEdits.begin();
382 for (; iter != llBinEdits.end(); iter++) {
383 if (iter->second == rtLib) continue;
384 if (iter->second->usedATrap()) {
389 if (!usedATrap) return true;
391 // We used a trap, so go through and set up the replacement instrumentation.
392 // However, don't let this be the first piece of instrumentation put into
396 iter = llBinEdits.begin();
397 for (; iter != llBinEdits.end(); iter++) {
398 BinaryEdit *binEd = iter->second;
399 if (binEd == rtLib) {
403 // Did we instrument this already?
404 if (!binEd->isDirty()) {
408 // Okay, replace trap handler
409 if (!binEd->replaceTrapHandler()) {