Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / src / 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 // $Id: binaryEdit.C,v 1.26 2008/10/28 18:42:44 bernat Exp $
33
34 #include "binaryEdit.h"
35 #include "common/h/headers.h"
36 #include "mapped_object.h"
37 #include "mapped_module.h"
38 #include "multiTramp.h"
39 #include "debug.h"
40 #include "os.h"
41 #include "instPoint.h"
42
43 // #define USE_ADDRESS_MAPS
44
45 // Reading and writing get somewhat interesting. We are building
46 // a false address space - that of the "inferior" binary we're editing. 
47 // However, that address space doesn't exist - and so we must overlay
48 // it on ours. In the dynamic case this is easy, of course. So what
49 // we have is a mapping. An "Address" that we get (inOther), can
50 // map to one of the following:
51 //  1) An area created with inferiorMalloc
52 //  2) A section of the binary that is original
53 //  3) A section of the binary that was modified
54
55 bool BinaryEdit::readTextSpace(const void *inOther,
56                                u_int size,
57                                const void *inSelf) {
58     Address addr = (Address) inOther;
59     
60     // Look up this address in the code range tree of memory
61     codeRange *range = NULL;
62     if (!memoryTracker_->find(addr, range))
63         return false;
64     assert(addr >= range->get_address());
65
66     Address offset = addr - range->get_address();
67     assert(offset < range->get_size());
68
69     void *local_ptr = ((void *) (offset + (Address)range->get_local_ptr()));
70     memcpy(const_cast<void *>(inSelf), local_ptr, size);
71
72     return true;
73 }
74
75 bool BinaryEdit::writeTextSpace(void *inOther,
76                             u_int size,
77                             const void *inSelf) {
78     // This assumes we already have a memory tracker; inefficient, but
79     // it works. 
80     Address addr = (Address) inOther;
81     unsigned int to_do = size;
82     Address local = (Address) inSelf;
83     markDirty();
84
85     while (to_do) {
86        // Look up this address in the code range tree of memory
87        codeRange *range = NULL;
88        if (!memoryTracker_->find(addr, range)) {
89           return false;
90        }
91        
92        // We might (due to fragmentation) be overlapping multiple backing
93        // store "chunks", so this has to be iterative rather than a one-shot.
94        
95        Address chunk_start = range->get_address();
96        Address chunk_end = range->get_address() + range->get_size();
97        
98        assert (addr >= chunk_start);
99        
100        unsigned chunk_size = 0;
101        if ((addr + to_do) <= chunk_end) {
102           chunk_size = to_do;
103        }
104        else {
105           chunk_size = chunk_end - addr;
106        }
107        
108        Address offset = addr - range->get_address();
109        assert(offset < range->get_size());
110        
111        void *local_ptr = ((void *) (offset + (Address)range->get_local_ptr()));
112        inst_printf("Copying to 0x%lx [base=0x%lx] from 0x%lx (%d bytes)  target=0x%lx  offset=0x%lx\n", 
113               local_ptr, range->get_local_ptr(), local, chunk_size, addr, offset);
114        //range->print_range();
115        memcpy(local_ptr, (void *)local, chunk_size);
116        memoryTracker* mt = dynamic_cast<memoryTracker*>(range);
117        assert(mt);
118        mt->dirty = true;
119        
120        to_do -= chunk_size;
121        addr += chunk_size;
122        local += chunk_size;
123     }
124
125     return true;
126 }    
127
128 bool BinaryEdit::readDataSpace(const void *inOther,
129                            u_int amount,
130                            void *inSelf,
131                            bool) {
132     return readTextSpace(inOther, amount, inSelf);
133 }
134
135 bool BinaryEdit::writeDataSpace(void *inOther,
136                             u_int amount,
137                             const void *inSelf) {
138     return writeTextSpace(inOther, amount, inSelf);
139 }
140
141 const Address ADDRESS_LO = (Address)0;
142 const Address ADDRESS_HI = (Address)(~(Address)0);
143 const unsigned HEAP_STAT_BUF_SIZE = (0x100000);
144
145 Address BinaryEdit::inferiorMalloc(unsigned size,
146                                inferiorHeapType /*ignored*/,
147                                Address /*near*/,
148                                bool *err) {
149     // It looks like we're ignoring near...
150     Address ret = 0;
151
152     Address lo = ADDRESS_LO;
153     Address hi = ADDRESS_HI;
154
155     if (err) *err = false;
156    
157     inferiorMallocAlign(size); // align size
158
159     int freeIndex = -1;
160     int ntry = 0;
161     for (ntry = 0; freeIndex == -1; ntry++) {
162         switch(ntry) {
163         case 0: 
164             // See if we have available memory
165             break;
166         case 1:
167             inferiorFreeCompact();
168             break;
169         case 2:
170             inferiorMallocStatic(size);
171             break;
172         default:
173             return 0;
174         }
175         ret = inferiorMallocInternal(size, lo, hi, anyHeap);
176         if (ret) {
177           memoryTracker *newTracker = new memoryTracker(ret, size);
178           newTracker->alloced = true;
179           if (!memoryTracker_)
180             memoryTracker_ = new codeRangeTree();
181           memoryTracker_->insert(newTracker);
182
183           break;
184         }
185     }
186
187     return ret;
188 }
189
190 void BinaryEdit::inferiorFree(Address item)
191 {
192   inferiorFreeInternal(item);
193
194   codeRange *obj;
195   memoryTracker_->find(item, obj);
196   
197   delete obj;
198
199   memoryTracker_->remove(item);
200 }
201
202 bool BinaryEdit::inferiorRealloc(Address item, unsigned newsize)
203 {
204   bool result = inferiorReallocInternal(item, newsize);
205   if (!result)
206     return false;
207
208   codeRange *obj;
209   result = memoryTracker_->find(item, obj);
210   assert(result);
211
212   memoryTracker_->remove(item);
213
214   memoryTracker *mem_track = dynamic_cast<memoryTracker *>(obj);
215   assert(mem_track);
216   mem_track->realloc(newsize);
217
218   memoryTracker_->insert(obj);
219   return true;
220 }
221
222 unsigned BinaryEdit::getAddressWidth() const {
223     assert(mapped_objects.size());
224     
225     return mapped_objects[0]->parse_img()->getObject()->getAddressWidth();
226 }
227
228 bool BinaryEdit::multithread_capable(bool) {
229    return multithread_capable_;
230 }
231
232 bool BinaryEdit::multithread_ready(bool) {
233     return multithread_capable();
234 }
235
236 void BinaryEdit::deleteGeneratedCode(generatedCodeObject *del) {
237   // This can happen - say that someone writes a file (which generates), 
238   // then goes around uninstrumenting... yeah, it can happen.
239
240   // Or a failed atomic insert.
241
242     // No reason to delay deletion.
243     delete del;
244 }
245
246 BinaryEdit::BinaryEdit() : 
247    highWaterMark_(0),
248    lowWaterMark_(0),
249    isDirty_(false),
250    memoryTracker_(NULL),
251    multithread_capable_(false)
252 {
253    trapMapping.shouldBlockFlushes(true);
254 }
255
256 BinaryEdit::~BinaryEdit() 
257 {
258 }
259
260 void BinaryEdit::deleteBinaryEdit() {
261     deleteAddressSpace();
262     highWaterMark_ = 0;
263     lowWaterMark_ = 0;
264
265     // TODO: is this cleanup necessary?
266     depRelocation *rel;
267     while (dependentRelocations.size() > 0) {
268         rel = dependentRelocations[0];
269         dependentRelocations.erase(dependentRelocations.begin());
270         delete rel;
271     }
272 }
273
274 BinaryEdit *BinaryEdit::openFile(const std::string &file) {
275     if (!OS::executableExists(file)) {
276         startup_printf("%s[%d]:  failed to read file %s\n", FILE__, __LINE__, file.c_str());
277         std::string msg = std::string("Can't read executable file ") + file + (": ") + strerror(errno);
278         showErrorCallback(68, msg.c_str());
279         return NULL;
280     }
281     
282     fileDescriptor desc;
283     if (!getStatFileDescriptor(file, desc)) {
284         startup_printf("%s[%d]: failed to create file descriptor for %s!\n",
285                        FILE__, __LINE__, file.c_str());
286         return NULL;
287     }
288
289     BinaryEdit *newBinaryEdit = new BinaryEdit();
290     if (!newBinaryEdit) {
291         startup_printf("%s[%d]: failed to create binary representation for %s!\n",
292                        FILE__, __LINE__, file.c_str());
293     }
294
295     newBinaryEdit->mobj = mapped_object::createMappedObject(desc, newBinaryEdit);
296     if (!newBinaryEdit->mobj) {
297         startup_printf("%s[%d]: failed to create mapped object for %s\n",
298                        FILE__, __LINE__, file.c_str());
299         return NULL;
300     }
301
302     newBinaryEdit->mapped_objects.push_back(newBinaryEdit->mobj);
303     newBinaryEdit->addOrigRange(newBinaryEdit->mobj);
304
305     // We now need to access the start of the new section we're creating.
306
307     // I'm going through the mapped_object interface for now - 
308     // I assume we'll pass it to DynSymtab, then add our base
309     // address to it at the mapped_ level. 
310     Symtab* linkedFile = newBinaryEdit->getAOut()->parse_img()->getObject();
311     newBinaryEdit->highWaterMark_ = linkedFile->getFreeOffset(50*1024*1024);
312     newBinaryEdit->lowWaterMark_ = newBinaryEdit->highWaterMark_;
313
314     newBinaryEdit->makeInitAndFiniIfNeeded();
315
316     newBinaryEdit->createMemoryBackingStore(newBinaryEdit->getAOut());
317     newBinaryEdit->initialize();
318
319     //Don't count initialization in determining dirty
320     newBinaryEdit->isDirty_ = false; //!(foundInit && foundFini);
321     return newBinaryEdit;
322 }
323
324 #if !defined(os_linux)
325 void BinaryEdit::makeInitAndFiniIfNeeded()
326 {
327 }
328 #endif
329
330 bool BinaryEdit::getStatFileDescriptor(const std::string &name, fileDescriptor &desc) {
331    desc = fileDescriptor(name.c_str(),
332                          0, // code base address
333                          0); // data base address
334    return true;
335 }
336
337 #if !defined(cap_binary_rewriter)
338 std::pair<std::string, BinaryEdit*> BinaryEdit::openResolvedLibraryName(std::string filename)
339 {
340   assert(!"Not implemented");
341   return std::make_pair("", static_cast<BinaryEdit*>(NULL));
342 }
343
344 #endif
345
346 bool BinaryEdit::isMultiThreadCapable()
347 {
348    Symtab *symtab = mobj->parse_img()->getObject();
349    std::vector<std::string> depends = symtab->getDependencies();
350    for (std::vector<std::string>::iterator curDep = depends.begin();
351         curDep != depends.end(); curDep++) {
352      if((curDep->find("libpthread") != std::string::npos) || (curDep->find("libthread") != std::string::npos))
353        return true;
354    }
355    return false;
356 }
357
358 bool BinaryEdit::getAllDependencies(std::map<std::string, BinaryEdit*>& deps)
359 {
360    Symtab *symtab = mobj->parse_img()->getObject();
361    std::deque<std::string> depends;
362    std::copy(symtab->getDependencies().begin(), symtab->getDependencies().end(), std::back_inserter(depends));
363    while(!depends.empty())
364    {
365      std::string lib = depends.front();
366      if(deps.find(lib) == deps.end()) {
367        std::pair<std::string, BinaryEdit*> res = openResolvedLibraryName(lib);
368        if (res.second) {
369          deps.insert(res);
370          if(!res.second->getAllDependencies(deps))
371          {
372            return false;
373          }
374        } else {
375          return false;
376        }
377      }
378      depends.pop_front();
379    }
380    return true;
381 }
382
383 bool BinaryEdit::writeFile(const std::string &newFileName) 
384 {
385    // We've made a bunch of changes and additions to the
386    // mapped object.
387    //   Changes: modifiedRanges_
388    //   Additions: textRanges_, excepting the file itself. 
389    // 
390    // Although, since we're creating a new file name we want
391    // textRanges. Basically, we want to serialize the contents
392    // of textRanges_, dataRanges_, and modifiedRanges_.
393
394    // A _lot_ of this method will depend on how the new file
395    // generation ends up working. Do we provide buffers? I'm guessing
396    // so.
397
398    // Step 1: changes. 
399
400       inst_printf(" writing %s ... \n", newFileName.c_str());
401
402       Symtab *symObj = mobj->parse_img()->getObject();
403
404       vector<Region*> oldSegs;
405       symObj->getAllRegions(oldSegs);
406
407       //vector<Region*> newSegs = oldSegs;
408
409       //Write any traps to the mutatee
410       trapMapping.shouldBlockFlushes(false);
411       trapMapping.flush();
412
413       // Now, we need to copy in the memory of the new segments
414       for (unsigned i = 0; i < oldSegs.size(); i++) {
415          codeRange *segRange = NULL;
416          if (!memoryTracker_->find(oldSegs[i]->getRegionAddr(), segRange)) {
417 #if 0
418             // Looks like BSS
419             if (newSegs[i].name == ".bss")
420 #endif
421                continue;
422             //inst_printf (" segment name: %s\n", newSegs[i].name.c_str());
423             //assert(0);
424          }
425          //inst_printf(" ==> memtracker: Copying to 0x%lx from 0x%lx\n", 
426          //newSegs[i].loadaddr, segRange->get_local_ptr());
427          memoryTracker* mt = dynamic_cast<memoryTracker*>(segRange);
428          assert(mt);
429          if(mt->dirty) {
430            oldSegs[i]->setPtrToRawData(segRange->get_local_ptr(), oldSegs[i]->getRegionSize());
431          }
432          
433          //newSegs[i].data = segRange->get_local_ptr();
434       }
435
436       // Okay, that does it for the old stuff.
437
438       // Now we need to get the new stuff. That's all the allocated memory. First, big
439       // buffer to hold it.
440
441       void *newSectionPtr = malloc(highWaterMark_ - lowWaterMark_);
442
443       pdvector<codeRange *> writes;
444       memoryTracker_->elements(writes);
445
446       for (unsigned i = 0; i < writes.size(); i++) {
447          memoryTracker *tracker = dynamic_cast<memoryTracker *>(writes[i]);
448          assert(tracker);
449          //inst_printf("memory tracker: 0x%lx  load=0x%lx  size=%d  %s\n", 
450          //tracker->get_local_ptr(), tracker->get_address(), tracker->get_size(),
451          //tracker->alloced ? "[A]" : "");
452          if (!tracker->alloced) continue;
453
454          // Copy whatever is in there into the big buffer, at the appropriate address
455          assert(tracker->get_address() >= lowWaterMark_);
456          Address offset = tracker->get_address() - lowWaterMark_;
457          assert((offset + tracker->get_size()) < highWaterMark_);
458          void *ptr = (void *)(offset + (Address)newSectionPtr);
459          memcpy(ptr, tracker->get_local_ptr(), tracker->get_size());
460       }
461             
462       // Righto. Now, that includes the old binary - by design - 
463       // so skip it and see what we're talking about size-wise. Which should
464       // be less than the highWaterMark, so we can double-check.
465
466       // Next, make a new section. We have the following parameters:
467       // Offset vaddr: we get this from Symtab - "first free address with sufficient space"
468       // std::string name: without reflection, ".dyninstInst"
469       // unsigned long flags: these are a SymtabAPI abstraction. We're going with text|data because
470       //    we might have both.
471       // bool loadable: heck yeah...
472         
473       Region *newSec = NULL;
474       symObj->findRegion(newSec, ".dyninstInst");
475       if (newSec) {
476          // We're re-instrumenting - will fail for now
477          fprintf(stderr, "ERROR:  unable to reinstrument previously instrumented binary!\n");
478          return false;
479       }
480         
481       symObj->addRegion(lowWaterMark_,
482                         newSectionPtr,
483                         highWaterMark_ - lowWaterMark_,
484                         ".dyninstInst",
485                         Region::RT_TEXTDATA,
486                         true);
487         
488       symObj->findRegion(newSec, ".dyninstInst");
489       assert(newSec);
490
491       if (mobj == getAOut()) {
492          // Add dynamic symbol relocations
493          Symbol *referring, *newSymbol;
494          for (unsigned i=0; i < dependentRelocations.size(); i++) {
495             Address to = dependentRelocations[i]->getAddress();
496             referring = dependentRelocations[i]->getReferring();
497             if (!symObj->hasReldyn() && !symObj->hasReladyn()) {
498               Address addr = referring->getOffset();
499               bool result = writeDataSpace((void *) to, getAddressWidth(), &addr);
500               assert(result);
501               continue;
502             }
503             
504             newSymbol = new Symbol(referring->getName(), 
505                                    Symbol::ST_FUNCTION, 
506                                    Symbol::SL_GLOBAL,
507                                    Symbol::SV_DEFAULT, 
508                                    (Address)0, 
509                                    symObj->getDefaultModule(),
510                                    NULL, 
511                                    8,
512                                    true, 
513                                    false);
514             symObj->addSymbol(newSymbol, referring);
515             if (!symObj->hasReldyn() && symObj->hasReladyn()) {
516                newSec->addRelocationEntry(to, newSymbol, relocationEntry::dynrel, Region::RT_RELA);
517             } else {
518                if (mobj->isSharedLib()) {
519                   //inst_printf("  ::: shared lib jump slot - 0x%lx [base=0x%lx]\n", 
520                   //to - obj->imageOffset(), obj->imageOffset());
521                   newSec->addRelocationEntry(
522                                              to - mobj->imageOffset(), newSymbol, relocationEntry::dynrel);
523                }
524                else {
525                   //inst_printf("  ::: regular jump slot - 0x%lx\n", to);
526                   newSec->addRelocationEntry(to, newSymbol, relocationEntry::dynrel);
527                }
528             }
529          }
530       }
531
532       pdvector<Symbol *> newSyms;
533       buildDyninstSymbols(newSyms, newSec, symObj->getOrCreateModule("dyninstInst",
534                                                                      lowWaterMark_));
535       for (unsigned i = 0; i < newSyms.size(); i++) {
536          symObj->addSymbol(newSyms[i]);
537       }
538         
539       // Okay, now...
540       // Hand textSection and newSection to DynSymtab.
541         
542       // First, textSection.
543         
544       // From the SymtabAPI documentation: we have the following methods we want to use.
545       // Symtab::addSection(Offset vaddr, void *data, unsigned int dataSize, std::string name, 
546       //                    unsigned long flags, bool loadable)
547       // Symtab::updateCode(void *buffer, unsigned size)
548       // Symtab::emit(std::string filename)
549         
550       // First, text
551       assert(symObj);
552         
553 #if 0
554       for (unsigned i = 0; i < oldSegs.size(); i++) {
555          if (oldSegs[i].data != newSegs[i].data) {
556             inst_printf("Data not equivalent, %d, %s  load=0x%lx\n", 
557                         i, oldSegs[i].name.c_str(), oldSegs[i].loadaddr);
558             
559             if (oldSegs[i].name == ".text" || 
560                 memcmp(oldSegs[i].data, newSegs[i].data, oldSegs[i].size < newSegs[i].size ? oldSegs[i].size : newSegs[i].size)) {
561             //if ((oldSegs[i].name == ".text") 
562              //|| (oldSegs[i].name == ".data")) {
563                //inst_printf("  TEXT SEGMENT: old-base=0x%lx  old-size=%d  new-base=0x%lx  new-size=%d\n",
564                //oldSegs[i].data, oldSegs[i].size, newSegs[i].data, newSegs[i].size);
565                symObj->updateRegion(oldSegs[i].name.c_str(), newSegs[i].data,
566                                   newSegs[i].size);
567             }
568          }
569       }
570 #endif        
571
572       // And now we generate the new binary
573       //if (!symObj->emit(newFileName.c_str())) {
574       if (!symObj->emit(newFileName.c_str())) {
575          return false;
576       }
577    return true;
578 }
579
580 bool BinaryEdit::inferiorMallocStatic(unsigned size) {
581     // Should be set by now
582     assert(highWaterMark_ != 0);
583
584 #if defined(USE_ADDRESS_MAPS)
585     void *buf = malloc(size);
586     if (!buf) return false;
587 #endif
588     
589     Address newStart = highWaterMark_;
590
591     // If there is a free heap that _ends_ at the highWaterMark,
592     // just extend it. This is a special case of inferiorFreeCompact;
593     // when we make that function faster, we can just call it. 
594     bool found = false;
595     for (unsigned i = 0; i < heap_.heapFree.size(); i++) {
596         heapItem *h = heap_.heapFree[i];
597         assert(h);
598         Address end = h->addr + h->length;
599         if (end == newStart) {
600             found = true;
601             h->length += size;
602             break;
603         }
604     }
605     if (!found) {
606         // Build tracking objects for it
607         heapItem *h = new heapItem(highWaterMark_, 
608                                    size,
609                                    anyHeap,
610                                    true,
611                                    HEAPfree);
612         addHeap(h);
613     }
614
615     highWaterMark_ += size;
616
617     return true;
618 }
619
620
621 bool BinaryEdit::createMemoryBackingStore(mapped_object *obj) {
622     // We want to create a buffer for every section in the
623     // binary so that we can store updates.
624
625     Symtab *symObj = obj->parse_img()->getObject();
626     vector<Region*> regs;
627     symObj->getAllRegions(regs);
628
629    for (unsigned i = 0; i < regs.size(); i++) {
630       memoryTracker *newTracker = NULL;
631       if (regs[i]->getRegionType() == Region::RT_BSS) {
632          continue;
633       }
634       else {
635          newTracker = new memoryTracker(regs[i]->getRegionAddr(),
636                                         regs[i]->getDiskSize(),
637                                         regs[i]->getPtrToRawData());
638          
639       }
640       newTracker->alloced = false;
641       if (!memoryTracker_)
642          memoryTracker_ = new codeRangeTree();
643       memoryTracker_->insert(newTracker);
644    }
645
646     
647    return true;
648 }
649
650
651 bool BinaryEdit::initialize() {
652    //Load the RT library
653    
654    // Create the tramp guard
655    
656    // Initialization. For now we're skipping threads, since we can't
657    // get the functions we need. However, we kinda need the recursion
658    // guard. This is an integer (one per thread, for now - 1) that 
659    // begins initialized to 1.
660
661     return true;
662 }
663
664 void BinaryEdit::addDependentRelocation(Address to, Symbol *referring) {
665     // prevent duplicate relocations
666     std::vector<depRelocation *>::iterator it;
667     for (it = dependentRelocations.begin(); it != dependentRelocations.end(); it++)
668         if ((*it)->getAddress() == to && (*it)->getReferring() == referring)
669             return;
670     // create a new relocation and add it to the collection
671         depRelocation *reloc = new depRelocation(to, referring);
672         dependentRelocations.push_back(reloc);
673 }
674
675 Address BinaryEdit::getDependentRelocationAddr(Symbol *referring) {
676         Address retAddr = 0x0;
677         for (unsigned i=0; i < dependentRelocations.size(); i++) {
678                 if (dependentRelocations[i]->getReferring() == referring) {
679                         retAddr = dependentRelocations[i]->getAddress();
680                         break;
681                 }
682         }
683         return retAddr;
684 }
685
686
687 // Build a list of symbols describing instrumentation and relocated functions. 
688 // To keep this list (somewhat) short, we're doing one symbol per extent of 
689 // instrumentation + relocation for a particular function. 
690 // New: do this for one mapped object. 
691
692
693 void BinaryEdit::buildDyninstSymbols(pdvector<Symbol *> &newSyms, 
694                                      Region *newSec,
695                                      Module *newMod) {
696     pdvector<codeRange *> ranges;
697     textRanges_.elements(ranges);
698
699     int_function *currFunc = NULL;
700     codeRange *startRange = NULL;
701
702     Address startAddr = 0;
703     unsigned size = 0;
704
705     for (unsigned i = 0; i < ranges.size(); i++) {
706         multiTramp *multi = ranges[i]->is_multitramp();
707         bblInstance *bbl = ranges[i]->is_basicBlockInstance();
708
709         bool finishCurrentRegion = false;
710         bool startNewRegion = false;
711         bool extendCurrentRegion = false;
712
713         if (multi) {
714             if (multi->func() != currFunc) {
715                 finishCurrentRegion = true;
716                 startNewRegion = true;
717             }
718             else {
719                 extendCurrentRegion = true;
720             }
721         }
722         if (bbl) {
723             if (bbl->func() != currFunc) {
724                 finishCurrentRegion = true;
725                 startNewRegion = true;
726             }
727             else {
728                 extendCurrentRegion = true;
729             }
730         }
731         else
732             continue;
733
734         
735         if (finishCurrentRegion && (currFunc != NULL)) {
736             std::string name = currFunc->prettyName();
737             name.append("_dyninst");
738
739             Symbol *newSym = new Symbol(name.c_str(),
740                                         Symbol::ST_FUNCTION,
741                                         Symbol::SL_GLOBAL,
742                                         Symbol::SV_DEFAULT,
743                                         startAddr,
744                                         newMod,
745                                         newSec,
746                                         size,
747                                         (void *)startRange);
748             newSyms.push_back(newSym);
749
750             currFunc = NULL;
751             startAddr = 0;
752             size = 0;
753             startRange = NULL;
754         }
755         if (startNewRegion) {
756             assert(currFunc == NULL);
757             
758             currFunc = (multi != NULL) ? (multi->func()) : (bbl->func());
759             assert(currFunc != NULL);
760             startRange = ranges[i];
761             startAddr = ranges[i]->get_address();
762             size = ranges[i]->get_size();
763         }
764         if (extendCurrentRegion) {
765             size += ranges[i]->get_size() + (ranges[i]->get_address() - (startAddr + size));
766         }
767     }
768 }
769     
770 void BinaryEdit::markDirty()
771 {
772    isDirty_ = true;
773 }
774
775 bool BinaryEdit::isDirty()
776 {
777    return isDirty_;
778 }
779
780 mapped_object *BinaryEdit::getMappedObject()
781 {
782    return mobj;
783 }
784
785 void BinaryEdit::setupRTLibrary(BinaryEdit *r)
786 {
787    rtlib = r;
788    runtime_lib = rtlib->getMappedObject();
789    assert(rtlib);
790 }
791
792 void BinaryEdit::setTrampGuard(int_variable* tg)
793 {
794   trampGuardBase_ = tg;
795 }
796
797
798 int_variable* BinaryEdit::createTrampGuard()
799 {
800   // If we have one, just return it
801   if(trampGuardBase_) return trampGuardBase_;
802   assert(rtlib);
803
804   mapped_object *mobj = rtlib->getMappedObject();
805   const int_variable *var = mobj->getVariable("DYNINST_default_tramp_guards");
806   assert(var);
807   trampGuardBase_ = const_cast<int_variable *>(var);
808   
809   return trampGuardBase_;
810 }
811
812 BinaryEdit *BinaryEdit::rtLibrary()
813 {
814    return rtlib;
815 }
816
817 int_function *BinaryEdit::findOnlyOneFunction(const std::string &name,
818                                               const std::string &libname,
819                                               bool search_rt_lib)
820 {
821    int_function *f = AddressSpace::findOnlyOneFunction(name, libname, search_rt_lib);
822    if (!f && search_rt_lib) {
823       f = rtLibrary()->findOnlyOneFunction(name, libname, false);
824    }
825    return f;
826 }
827
828 void BinaryEdit::setMultiThreadCapable(bool b)
829 {
830    multithread_capable_ = b;
831 }
832
833 void BinaryEdit::addSibling(BinaryEdit *be)
834 {
835    if (this != be) {
836       siblings.push_back(be);
837    }
838 }
839
840 std::vector<BinaryEdit *> &BinaryEdit::getSiblings()
841 {
842    return siblings;
843 }
844
845
846
847 // Here's the story. We may need to install a trap handler for instrumentation
848 // to work in the rewritten binary. This doesn't play nicely with trap handlers
849 // that the binary itself registers. So we're going to replace every call to
850 // sigaction in the binary with a call to our wrapper. This wrapper:
851 //   1) Ignores attempts to register a SIGTRAP
852 //   2) Passes everything else through to sigaction
853 // It's called "dyn_sigaction".
854
855 bool BinaryEdit::usedATrap() {
856     return (!trapMapping.empty());
857 }
858
859 bool BinaryEdit::replaceTrapHandler() {
860     // Find all calls to sigaction and replace with
861     // calls to dyn_sigaction. 
862
863     // We haven't code generated yet, so we're working 
864     // with addInst.
865
866     int_function *dyn_sigaction = findOnlyOneFunction("dyn_sigaction");
867     assert(dyn_sigaction);
868
869     int_function *dyn_signal = findOnlyOneFunction("dyn_signal");
870     assert(dyn_signal);
871
872     bool success = true;
873     
874     pdvector<int_function *> allFuncs;
875     getAllFunctions(allFuncs);
876
877     for (unsigned i = 0; i < allFuncs.size(); i++) {
878         int_function *func = allFuncs[i];
879         
880         assert(func);
881         const pdvector<instPoint *> &calls = func->funcCalls();
882
883         for (unsigned j = 0; j < calls.size(); j++) {
884             instPoint *point = calls[j];
885             
886             std::string calleeName = point->getCalleeName();
887
888             if ((calleeName == "sigaction") ||
889                 (calleeName == "_sigaction") ||
890                 (calleeName == "__sigaction")) {
891                 if (!replaceFunctionCall(point, dyn_sigaction)) {
892                     success = false;
893                 }
894             }
895             else if ((calleeName == "signal") ||
896                      (calleeName == "_signal") ||
897                      (calleeName == "__signal"))
898             {
899                if (!replaceFunctionCall(point, dyn_signal)) {
900                   success = false;
901                }
902             }
903         }
904     }
905     
906     return success;
907 }
908
909 bool BinaryEdit::needsPIC()
910 {
911    Symtab *symtab = getMappedObject()->parse_img()->getObject();
912    assert(symtab);
913
914    //If there is a fixed load address, then we can calculate 
915    // absolute addresses.
916    return (symtab->getLoadAddress() == 0);  
917 }