Attempts to fix legacy test failures in Dyninst test suite (#549)
[dyninst.git] / dyninstAPI / src / BPatch_binaryEdit.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  * 
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  * 
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  * 
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  * 
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  * 
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #define BPATCH_FILE
32
33 #include "binaryEdit.h"
34 #include "addressSpace.h"
35 #include "inst.h"
36 #include "instP.h"
37 #include "instPoint.h"
38 #include "function.h" // func_instance
39 #include "codeRange.h"
40
41 #include "mapped_module.h"
42
43 #include "BPatch_libInfo.h"
44 #include "BPatch.h"
45 #include "BPatch_addressSpace.h"
46
47 #include "BPatch_binaryEdit.h"
48 #include "BPatch_image.h"
49 #include "BPatch_thread.h"
50 #include "BPatch_function.h"
51 #include "debug.h"
52
53 #include "BPatch_private.h"
54 #include <queue>
55
56
57 #include "ast.h"
58
59 #include "sys/stat.h"
60 #include "mapped_object.h"
61 #include "Relocation/DynAddrSpace.h"
62
63 #include "boost/filesystem.hpp"
64 using Dyninst::PatchAPI::DynAddrSpacePtr;
65 using Dyninst::PatchAPI::DynAddrSpace;
66
67 /*
68  * BPatch_binaryEdit::BPatch_binaryEdit
69  *
70  * Creates a new BinaryEdit and associates it with the BPatch_binaryEdit
71  * being created. Additionally, if specified, the dependencies of the
72  * original BinaryEdit are opened and associated with the BPatch_binaryEdit
73  *
74  * path              Pathname of the executable
75  * openDependencies  if true, the dependencies of the original BinaryEdit are
76  *                   also opened
77  */
78 BPatch_binaryEdit::BPatch_binaryEdit(const char *path, bool openDependencies) :
79    BPatch_addressSpace(),
80    creation_error(false)
81 {
82   pendingInsertions = new BPatch_Vector<batchInsertionRecord *>;
83
84   pdvector<std::string> argv_vec;
85   pdvector<std::string> envp_vec;
86
87   std::string directoryName = "";
88
89   startup_printf("[%s:%u] - Opening original file %s\n",
90                  FILE__, __LINE__, path);
91   origBinEdit = BinaryEdit::openFile(std::string(path));
92
93   if (!origBinEdit){
94      startup_printf("[%s:%u] - Creation error opening %s\n",
95                     FILE__, __LINE__, path);
96      creation_error = true;
97      return;
98   }
99   llBinEdits[path] = origBinEdit;
100
101   if(openDependencies) {
102     origBinEdit->getAllDependencies(llBinEdits);
103   }
104   std::map<std::string, BinaryEdit*>::iterator i, j;
105
106   origBinEdit->getDyninstRTLibName();
107   std::string rt_name = origBinEdit->dyninstRT_name;
108
109   // Load the RT library and create the collection of BinaryEdits that represent it
110   std::map<std::string, BinaryEdit *> rtlibs;
111   origBinEdit->openResolvedLibraryName(rt_name, rtlibs);
112   std::map<std::string, BinaryEdit *>::iterator rtlibs_it;
113   for(rtlibs_it = rtlibs.begin(); rtlibs_it != rtlibs.end(); ++rtlibs_it) {
114       if( !rtlibs_it->second ) {
115           std::string msg("Failed to load Dyninst runtime library, check the environment variable DYNINSTAPI_RT_LIB");
116           showErrorCallback(70, msg.c_str());
117           creation_error = true;
118           return;
119       }
120       rtLib.push_back(rtlibs_it->second);
121       // Ensure that the correct type of library is loaded
122       if(    rtlibs_it->second->getMappedObject()->isSharedLib()
123           && origBinEdit->getMappedObject()->isStaticExec() )
124       {
125           std::string msg = std::string("RT Library is a shared library ") +
126               std::string("when it should be a static library");
127           showErrorCallback(70, msg.c_str());
128           creation_error = true;
129           return;
130       }else if(     !rtlibs_it->second->getMappedObject()->isSharedLib()
131                 &&  !origBinEdit->getMappedObject()->isStaticExec() )
132       {
133           std::string msg = std::string("RT Library is a static library ") +
134               std::string("when it should be a shared library");
135           showErrorCallback(70, msg.c_str());
136           creation_error = true;
137           return;
138       }
139   }
140
141   for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
142      (*i).second->setupRTLibrary(rtLib);
143   }
144
145   for(i = llBinEdits.begin(); i != llBinEdits.end(); i++) {
146      BinaryEdit *llBinEdit = (*i).second;
147      llBinEdit->registerFunctionCallback(createBPFuncCB);
148      llBinEdit->registerInstPointCallback(createBPPointCB);
149      llBinEdit->set_up_ptr(this);
150      llBinEdit->setupRTLibrary(rtLib);
151      llBinEdit->setMultiThreadCapable(isMultiThreadCapable());
152      for (j = llBinEdits.begin(); j != llBinEdits.end(); j++) {
153         llBinEdit->addSibling((*j).second);
154      }
155   }
156
157   image = new BPatch_image(this);
158 }
159
160 bool BPatch_binaryEdit::isMultiThreadCapable() const
161 {
162   return origBinEdit->isMultiThreadCapable();
163 }
164
165 BPatch_image * BPatch_binaryEdit::getImage() {
166         return image;
167 }
168
169 BPatch_binaryEdit::~BPatch_binaryEdit()
170 {
171    if (image)
172       delete image;
173
174    image = NULL;
175
176    if (pendingInsertions) {
177      for (unsigned f = 0; f < pendingInsertions->size(); f++) {
178        delete (*pendingInsertions)[f];
179      }
180      delete pendingInsertions;
181      pendingInsertions = NULL;
182    }
183
184   std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
185   for(; i != llBinEdits.end(); i++) {
186      delete (*i).second;
187   }
188   llBinEdits.clear();
189   origBinEdit = NULL;
190
191   assert(BPatch::bpatch != NULL);
192 }
193
194 bool BPatch_binaryEdit::writeFile(const char * outFile)
195 {
196     assert(pendingInsertions);
197
198     // This should be a parameter...
199     //bool atomic = false;
200
201     // Define up here so we don't have gotos causing issues
202     std::set<func_instance *> instrumentedFunctions;
203
204     // Two loops: first addInst, then generate/install/link
205     pdvector<miniTramp *> workDone;
206     //bool err = false;
207
208     // Iterate over our AddressSpaces, triggering relocation
209     // in each one.
210     std::vector<AddressSpace *> as;
211     getAS(as);
212     bool ret = true;
213
214     /* PatchAPI stuffs */
215     if (as.size() > 0) {
216           ret = AddressSpace::patch(as[0]);
217     }
218     /* end of PatchAPI stuffs */
219
220
221    // Now that we've instrumented we can see if we need to replace the
222    // trap handler.
223    replaceTrapHandler();
224
225    for(std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
226        i != llBinEdits.end(); i++)
227    {
228       (*i).second->trapMapping.flush();
229    }
230
231
232    if( !origBinEdit->writeFile(outFile) ) return false;
233
234    std::map<std::string, BinaryEdit *>::iterator curBinEdit;
235    for (curBinEdit = llBinEdits.begin(); curBinEdit != llBinEdits.end(); curBinEdit++) {
236      BinaryEdit *bin = (*curBinEdit).second;
237      if (bin == origBinEdit)
238        continue;
239      if (!bin->isDirty())
240        continue;
241
242      std::string newname = bin->getMappedObject()->fileName();
243      if( !bin->writeFile(newname) ) return false;
244    }
245    return ret;
246 }
247
248 processType BPatch_binaryEdit::getType()
249 {
250   return STATIC_EDITOR;
251 }
252
253 void BPatch_binaryEdit::getAS(std::vector<AddressSpace *> &as)
254 {
255    std::map<std::string, BinaryEdit*>::iterator i = llBinEdits.begin();
256    as.push_back(origBinEdit);
257    for(; i != llBinEdits.end(); i++) {
258       if ((*i).second == origBinEdit)
259          continue;
260       as.push_back((*i).second);
261    }
262 }
263
264
265 /*
266  * BPatch_addressSpace::beginInsertionSet
267  *
268  * Starts a batch insertion set; that is, all calls to insertSnippet until
269  * finalizeInsertionSet are delayed.
270  *
271  */
272
273 void BPatch_binaryEdit::beginInsertionSet()
274 {
275     return;
276 }
277
278
279 bool BPatch_binaryEdit::finalizeInsertionSet(bool /*atomic*/, bool * /*modified*/)
280 {
281     return true;
282 }
283
284 BPatch_object *BPatch_binaryEdit::loadLibrary(const char *libname, bool deps)
285 {
286    boost::filesystem::path p(libname);
287    string filename = p.filename().string();
288    auto loaded = loadedLibrary.find(filename); 
289    if (loaded != loadedLibrary.end()) {
290        return loaded->second; 
291    }
292    std::map<std::string, BinaryEdit*> libs;
293    mapped_object *obj = origBinEdit->openResolvedLibraryName(libname, libs);
294    if (!obj) return NULL;
295
296    std::map<std::string, BinaryEdit*>::iterator lib_it;
297    for(lib_it = libs.begin(); lib_it != libs.end(); ++lib_it) {
298       std::pair<std::string, BinaryEdit*> lib = *lib_it;
299       
300       if(!lib.second)
301          return NULL;
302       
303       llBinEdits.insert(lib);
304       /* PatchAPI stuffs */
305       mapped_object* plib = lib.second->getAOut();
306       assert(plib);
307       dynamic_cast<DynAddrSpace*>(origBinEdit->mgr()->as())->loadLibrary(plib);
308       lib.second->setMgr(origBinEdit->mgr());
309       lib.second->setPatcher(origBinEdit->patcher());
310       /* End of PatchAPi stuffs */
311
312
313     lib.second->registerFunctionCallback(createBPFuncCB);
314     lib.second->registerInstPointCallback(createBPPointCB);
315     lib.second->set_up_ptr(this);
316     lib.second->setupRTLibrary(rtLib);
317     lib.second->setMultiThreadCapable(isMultiThreadCapable());
318
319     if (deps)
320       if( !lib.second->getAllDependencies(llBinEdits) ) return NULL;
321
322    }
323    origBinEdit->addLibraryPrereq(libname);
324    BPatch_object * bpatch_obj = getImage()->findOrCreateObject(obj);
325    loadedLibrary[filename] = bpatch_obj;
326    return bpatch_obj;
327 }
328
329 // Here's the story. We may need to install a trap handler for instrumentation
330 // to work in the rewritten binary. This doesn't play nicely with trap handlers
331 // that the binary itself registers. So we're going to replace every call to
332 // sigaction in the binary with a call to our wrapper. This wrapper:
333 //   1) Ignores attempts to register a SIGTRAP
334 //   2) Passes everything else through to sigaction
335 // It's called "dyn_sigaction".
336 // This is just a multiplexing function over each child binaryEdit
337 // object because they're all individual.
338
339 bool BPatch_binaryEdit::replaceTrapHandler() {
340     // Did we use a trap?
341
342     bool usedATrap = false;
343
344     std::map<std::string, BinaryEdit *>::iterator iter = llBinEdits.begin();
345     for (; iter != llBinEdits.end(); iter++) {
346         if (iter->second->usedATrap()) {
347             usedATrap = true;
348             break;
349         }
350     }
351
352     if (!usedATrap) return true;
353
354     // We used a trap, so go through and set up the replacement instrumentation.
355     // However, don't let this be the first piece of instrumentation put into
356     // a library.
357
358     bool success = true;
359     iter = llBinEdits.begin();
360     for (; iter != llBinEdits.end(); iter++) {
361         BinaryEdit *binEd = iter->second;
362
363         // Did we instrument this already?
364         if (!binEd->isDirty()) {
365             continue;
366         }
367
368         // Okay, replace trap handler
369         if (!binEd->replaceTrapHandler()) {
370             success = false;
371         }
372     }
373     return success;
374 }
375
376