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