Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / BPatch_binaryEdit.C
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
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.
10  * 
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.
16  * 
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.
21  * 
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.
26  * 
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
30  */
31
32 #define BPATCH_FILE
33
34 #include "process.h"
35 #include "binaryEdit.h"
36 #include "addressSpace.h"
37 #include "EventHandler.h"
38 #include "mailbox.h"
39 #include "signalgenerator.h"
40 #include "inst.h"
41 #include "instP.h"
42 #include "instPoint.h"
43 #include "function.h" // int_function
44 #include "codeRange.h"
45 #include "dyn_thread.h"
46 #include "miniTramp.h"
47
48 #include "mapped_module.h"
49
50 #include "BPatch_libInfo.h"
51 #include "BPatch.h"
52 #include "BPatch_addressSpace.h"
53
54 #include "BPatch_binaryEdit.h"
55 #include "BPatch_image.h"
56 #include "BPatch_thread.h"
57 #include "BPatch_function.h"
58 #include "callbacks.h"
59
60 #include "BPatch_private.h"
61 #include <queue>
62
63
64 #include "ast.h"
65
66 #include "sys/stat.h"
67
68 /*
69  * BPatch_binaryEdit::BPatch_binaryEdit
70  *
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
73  * executing any code.
74  *
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.
81  */
82 BPatch_binaryEdit::BPatch_binaryEdit(const char *path, bool openDependencies) :
83    BPatch_addressSpace(),
84    creation_error(false)
85 {
86   pendingInsertions = new BPatch_Vector<batchInsertionRecord *>;
87  
88   pdvector<std::string> argv_vec;
89   pdvector<std::string> envp_vec;
90   
91   std::string directoryName = "";
92
93   startup_printf("[%s:%u] - Opening original file %s\n", 
94                  FILE__, __LINE__, path);
95   origBinEdit = BinaryEdit::openFile(std::string(path));
96   if (!origBinEdit){
97      startup_printf("[%s:%u] - Creation error opening %s\n", 
98                     FILE__, __LINE__, path);
99      creation_error = true;
100      return;
101   }
102   llBinEdits[path] = origBinEdit;
103   
104   if(openDependencies) {
105     origBinEdit->getAllDependencies(llBinEdits); 
106   }
107
108   origBinEdit->getDyninstRTLibName();
109   std::string rt_name = origBinEdit->dyninstRT_name;
110   rtLib = BinaryEdit::openFile(rt_name);
111   if (!rtLib) {
112      startup_printf("[%s:%u] - ERROR.  Could not open RT library\n",
113                     __FILE__, __LINE__);
114      creation_error = true;
115      return;
116   }
117
118   std::map<std::string, BinaryEdit*>::iterator i, j;
119   for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
120      (*i).second->setupRTLibrary(rtLib);
121   }
122
123   int_variable* masterTrampGuard = origBinEdit->createTrampGuard();
124   assert(masterTrampGuard);
125   
126   for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
127      BinaryEdit *llBinEdit = (*i).second;
128      llBinEdit->registerFunctionCallback(createBPFuncCB);
129      llBinEdit->registerInstPointCallback(createBPPointCB);
130      llBinEdit->set_up_ptr(this);
131      llBinEdit->setupRTLibrary(rtLib);
132      llBinEdit->setTrampGuard(masterTrampGuard);
133      llBinEdit->setMultiThreadCapable(isMultiThreadCapable());
134      for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) {
135         llBinEdit->addSibling((*j).second);
136      }
137   }
138
139   image = new BPatch_image(this);
140 }
141
142 bool BPatch_binaryEdit::isMultiThreadCapable() const
143 {
144   return origBinEdit->isMultiThreadCapable();
145 }
146
147 BPatch_image * BPatch_binaryEdit::getImageInt() {
148         return image;
149 }
150
151 void BPatch_binaryEdit::BPatch_binaryEdit_dtor()
152 {
153    if (image) 
154       delete image;
155    
156    image = NULL;
157
158    if (pendingInsertions) {
159      for (unsigned f = 0; f < pendingInsertions->size(); f++) {
160        delete (*pendingInsertions)[f];
161      }
162      delete pendingInsertions;
163      pendingInsertions = NULL;
164    }
165
166   std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
167   for(; i != llBinEdits.end(); i++) {
168      delete (*i).second;
169   }
170   llBinEdits.clear();
171   origBinEdit = NULL;
172   
173   assert(BPatch::bpatch != NULL);
174 }
175
176 bool BPatch_binaryEdit::writeFileInt(const char * outFile)
177 {
178     assert(pendingInsertions);
179
180     // This should be a parameter...
181     bool atomic = false;
182    
183     // Define up here so we don't have gotos causing issues
184     std::set<int_function *> instrumentedFunctions;
185     
186     // Two loops: first addInst, then generate/install/link
187     pdvector<miniTramp *> workDone;
188     bool err = false;
189
190     for (unsigned i = 0; i < pendingInsertions->size(); i++) {
191         batchInsertionRecord *&bir = (*pendingInsertions)[i];
192         assert(bir);
193
194         // Don't handle thread inst yet...
195         assert(!bir->thread_);
196
197         if (!bir->points_.size()) {
198           fprintf(stderr, "%s[%d]:  WARN:  zero points for insertion record\n", FILE__, __LINE__);
199           fprintf(stderr, "%s[%d]:  failing to addInst\n", FILE__, __LINE__);
200         }
201
202         for (unsigned j = 0; j < bir->points_.size(); j++) {
203             BPatch_point *bppoint = bir->points_[j];
204             instPoint *point = bppoint->point;
205             callWhen when = bir->when_[j];
206             
207             miniTramp *mini = point->addInst(bir->snip.ast_wrapper,
208                                              when,
209                                              bir->order_,
210                                              bir->trampRecursive_,
211                                              false);
212             if (mini) {
213                 workDone.push_back(mini);
214                 // Add to snippet handle
215                 bir->handle_->addMiniTramp(mini);
216             }
217             else {
218                 err = true;
219                 if (atomic) break;
220             }
221         }
222         if (atomic && err)
223             break;
224     }
225     
226    if (atomic && err) goto cleanup;
227
228    // Having inserted the requests, we hand things off to functions to 
229    // actually do work. First, develop a list of unique functions. 
230
231    for (unsigned i = 0; i < pendingInsertions->size(); i++) {
232        batchInsertionRecord *&bir = (*pendingInsertions)[i];
233        for (unsigned j = 0; j < bir->points_.size(); j++) {
234            BPatch_point *bppoint = bir->points_[j];
235            instPoint *point = bppoint->point;
236            point->optimizeBaseTramps(bir->when_[j]);
237
238            instrumentedFunctions.insert(point->func());
239        }
240    }
241
242    for (std::set<int_function *>::iterator funcIter = instrumentedFunctions.begin();
243         funcIter != instrumentedFunctions.end();
244         funcIter++) {
245
246        pdvector<instPoint *> failedInstPoints;
247        (*funcIter)->performInstrumentation(atomic,
248                                            failedInstPoints); 
249        if (failedInstPoints.size() && atomic) {
250            err = true;
251            goto cleanup;
252        }
253    }
254
255    
256    // Now that we've instrumented we can see if we need to replace the
257    // trap handler.
258    replaceTrapHandler();
259
260
261    if (atomic && err) 
262       goto cleanup;
263
264    for(std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
265        i != llBinEdits.end(); i++) 
266    {
267       (*i).second->trapMapping.flush();
268    }
269
270   cleanup:
271     bool ret = true;
272
273     if (atomic && err) {
274         // Something failed...   Cleanup...
275         for (unsigned k = 0; k < workDone.size(); k++) {
276             workDone[k]->uninstrument();
277         }
278         ret = false;
279     }
280
281     for (unsigned int i = 0; i < pendingInsertions->size(); i++) {
282         batchInsertionRecord *&bir = (*pendingInsertions)[i];
283         assert(bir);
284         delete(bir);
285     }
286
287     pendingInsertions->clear();
288
289     origBinEdit->writeFile(outFile);
290
291     std::map<std::string, BinaryEdit *>::iterator i;
292     for (i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
293        BinaryEdit *bin = (*i).second;
294        if (bin == origBinEdit)
295           continue;
296        if (!bin->isDirty())
297           continue;
298        
299        std::string newname = bin->getMappedObject()->fileName();
300        bin->writeFile(newname);
301     }
302
303
304     return ret;
305 }
306
307 bool BPatch_binaryEdit::getType()
308 {
309   return STATIC_EDITOR;
310 }
311
312 void BPatch_binaryEdit::getAS(std::vector<AddressSpace *> &as)
313 {
314    std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
315    as.push_back(origBinEdit);
316    for(; i != llBinEdits.end(); i++) {
317       if ((*i).second == origBinEdit)
318          continue;
319       as.push_back((*i).second);
320    }
321 }
322
323
324 /*
325  * BPatch_addressSpace::beginInsertionSet
326  * 
327  * Starts a batch insertion set; that is, all calls to insertSnippet until
328  * finalizeInsertionSet are delayed.
329  *
330  */
331
332 void BPatch_binaryEdit::beginInsertionSetInt() 
333 {
334     return;
335 }
336
337
338 bool BPatch_binaryEdit::finalizeInsertionSetInt(bool /*atomic*/, bool * /*modified*/) 
339 {
340     return true;
341 }
342
343 bool BPatch_binaryEdit::loadLibraryInt(const char *libname, bool deps)
344 {
345   std::pair<std::string, BinaryEdit*> lib = origBinEdit->openResolvedLibraryName(libname);
346   if(!lib.second)
347     return false;
348
349   llBinEdits.insert(lib);
350   
351   int_variable* masterTrampGuard = origBinEdit->createTrampGuard();
352   assert(masterTrampGuard);
353   
354   lib.second->registerFunctionCallback(createBPFuncCB);
355   lib.second->registerInstPointCallback(createBPPointCB);
356   lib.second->set_up_ptr(this);
357   lib.second->setupRTLibrary(rtLib);
358   lib.second->setTrampGuard(masterTrampGuard);
359   lib.second->setMultiThreadCapable(isMultiThreadCapable());
360   /* Do we need to do this? 
361   std::map<std::string, BinaryEdit*>::iterator j;
362   for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) {
363         lib.second->addSibling((*j).second);
364   }
365   */
366
367    
368   if (deps)
369     return lib.second->getAllDependencies(llBinEdits);
370   return true;
371   
372 }
373
374 // Here's the story. We may need to install a trap handler for instrumentation
375 // to work in the rewritten binary. This doesn't play nicely with trap handlers
376 // that the binary itself registers. So we're going to replace every call to
377 // sigaction in the binary with a call to our wrapper. This wrapper:
378 //   1) Ignores attempts to register a SIGTRAP
379 //   2) Passes everything else through to sigaction
380 // It's called "dyn_sigaction".
381 // This is just a multiplexing function over each child binaryEdit
382 // object because they're all individual.
383
384 bool BPatch_binaryEdit::replaceTrapHandler() {
385     // Did we use a trap?
386
387     bool usedATrap = false;
388
389     std::map<std::string, BinaryEdit *>::iterator iter = llBinEdits.begin();
390     for (; iter != llBinEdits.end(); iter++) {
391         if (iter->second == rtLib) continue;
392         if (iter->second->usedATrap()) {
393             usedATrap = true;
394         }
395     }
396
397     if (!usedATrap) return true;
398
399     // We used a trap, so go through and set up the replacement instrumentation.
400     // However, don't let this be the first piece of instrumentation put into
401     // a library.
402
403     bool success = true;
404     iter = llBinEdits.begin();
405     for (; iter != llBinEdits.end(); iter++) {
406         BinaryEdit *binEd = iter->second;
407         if (binEd == rtLib) {
408             continue;
409         }
410
411         // Did we instrument this already?
412         if (!binEd->isDirty()) {
413             continue;
414         }
415
416         // Okay, replace trap handler
417         if (!binEd->replaceTrapHandler()) {
418             success = false;
419         }
420     }
421     return success;
422 }
423     
424