Fixed tail call instrumentation, removed calls to deprecated interfaces
[dyninst.git] / dyninstAPI / src / BPatch_addressSpace.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 "EventHandler.h"
37 #include "mailbox.h"
38 #include "signalgenerator.h"
39 #include "inst.h"
40 #include "instP.h"
41 #include "instPoint.h"
42 #include "function.h" // int_function
43 #include "codeRange.h"
44 #include "dyn_thread.h"
45 #include "miniTramp.h"
46 #include "addressSpace.h"
47
48 #include "mapped_module.h"
49
50 #include "BPatch_libInfo.h"
51 #include "BPatch_asyncEventHandler.h"
52 #include "BPatch.h"
53 #include "BPatch_thread.h"
54 #include "BPatch_function.h"
55 #include "callbacks.h"
56
57 #include "BPatch_private.h"
58
59 #include "ast.h"
60
61 #include "BPatch_addressSpace.h"
62
63 #include "BPatch_instruction.h"
64
65 #include <sstream>
66
67 BPatch_addressSpace::BPatch_addressSpace() :
68    image(NULL)
69 {
70 }
71
72 BPatch_addressSpace::~BPatch_addressSpace()
73 {}
74
75
76 BPatch_function *BPatch_addressSpace::findOrCreateBPFunc(int_function* ifunc,
77                                                          BPatch_module *bpmod)
78 {
79    if (!bpmod)
80       bpmod = image->findOrCreateModule(ifunc->mod());
81    assert(bpmod);
82    if (bpmod->func_map.count(ifunc)) {
83       BPatch_function *bpf = bpmod->func_map[ifunc];
84       assert(bpf);
85       return bpf;
86    }
87
88    // Find the module that contains the function
89    if (bpmod == NULL && ifunc->mod() != NULL) {
90       bpmod = getImage()->findModule(ifunc->mod()->fileName().c_str());
91    }
92
93    // findModule has a tendency to make new function objects... so
94    // check the map again
95    if (bpmod->func_map.count(ifunc)) {
96       BPatch_function *bpf = bpmod->func_map[ifunc];
97       assert(bpf);
98       return bpf;
99    }
100
101    BPatch_function *ret = new BPatch_function(this, ifunc, bpmod);
102    assert( ret != NULL );
103    return ret;
104 }
105
106
107
108
109 BPatch_point *BPatch_addressSpace::findOrCreateBPPoint(BPatch_function *bpfunc,
110                               instPoint *ip, BPatch_procedureLocation pointType)
111 {
112    assert(ip);
113    
114    BPatch_module *mod = image->findOrCreateModule(ip->func()->mod());
115    assert(mod);
116    
117    if (mod->instp_map.count(ip)) 
118       return mod->instp_map[ip];
119
120    if (pointType == BPatch_locUnknownLocation)
121       return NULL;
122
123    AddressSpace *lladdrSpace = ip->func()->proc();
124    if (!bpfunc) 
125       bpfunc = findOrCreateBPFunc(ip->func(), mod);
126
127    BPatch_point *pt = new BPatch_point(this, bpfunc, ip, pointType, lladdrSpace);
128    mod->instp_map[ip] = pt;
129
130    return pt;
131 }
132
133 BPatch_variableExpr *BPatch_addressSpace::findOrCreateVariable(int_variable *v,
134                                                                BPatch_type *type)
135 {
136    BPatch_module *mod = image->findOrCreateModule(v->mod());
137    assert(mod);
138    if (mod->var_map.count(v))
139       return mod->var_map[v];
140
141    if (!type) {
142       SymtabAPI::Type *stype = v->ivar()->svar()->getType();
143       if (stype)
144          type = BPatch_type::findOrCreateType(stype);
145       else
146          type = BPatch::bpatch->type_Untyped;
147    }
148    
149    BPatch_variableExpr *var = BPatch_variableExpr::makeVariableExpr(this, v, type);
150    mod->var_map[v] = var;
151    return var;
152 }
153                                                                
154
155
156 BPatch_function *BPatch_addressSpace::createBPFuncCB(AddressSpace *a, int_function *f)
157 {
158    BPatch_addressSpace *aS = (BPatch_addressSpace *)a->up_ptr();
159    assert(aS);
160    return aS->findOrCreateBPFunc(f, NULL);
161 }
162
163 BPatch_point *BPatch_addressSpace::createBPPointCB(AddressSpace *a, 
164                                                    int_function *f, 
165                                                    instPoint *ip, int type)
166 {
167    BPatch_addressSpace *aS = (BPatch_addressSpace *)a->up_ptr();
168    assert(aS);
169
170    BPatch_module *bpmod = aS->getImageInt()->findOrCreateModule(f->mod());
171    assert(bpmod);
172
173    BPatch_function *func = aS->findOrCreateBPFunc(f, bpmod);
174    assert(func);
175    
176    return aS->findOrCreateBPPoint(func, ip, (BPatch_procedureLocation) type);
177 }
178
179
180
181 /***************************************************************************
182  * Bpatch_snippetHandle
183  ***************************************************************************/
184
185 /*
186  * BPatchSnippetHandle::BPatchSnippetHandle
187  *
188  * Constructor for BPatchSnippetHandle.  Delete the snippet instance(s)
189  * associated with the BPatchSnippetHandle.
190  */
191 BPatchSnippetHandle::BPatchSnippetHandle(BPatch_addressSpace * addSpace) :
192    addSpace_(addSpace)
193 {
194 }
195
196 /*
197  * BPatchSnippetHandle::~BPatchSnippetHandle
198  *
199  * Destructor for BPatchSnippetHandle.  Delete the snippet instance(s)
200  * associated with the BPatchSnippetHandle.
201  */
202 void BPatchSnippetHandle::BPatchSnippetHandle_dtor()
203 {
204    // don't delete inst instances since they are might have been copied
205 }
206
207 BPatch_addressSpace *BPatchSnippetHandle::getAddressSpaceInt()
208 {
209    return addSpace_;
210 }
211
212 BPatch_process *BPatchSnippetHandle::getProcessInt()
213 {
214    return dynamic_cast<BPatch_process *>(addSpace_);
215 }
216
217 BPatch_Vector<BPatch_thread *> &BPatchSnippetHandle::getCatchupThreadsInt()
218 {
219    return catchup_threads;
220 }
221
222
223 BPatch_image * BPatch_addressSpace::getImageInt()
224 {
225    return image;
226 }
227
228
229 /*
230  * BPatch_addressSpace::deleteSnippet
231  * 
232  * Deletes an instance of a snippet.
233  *
234  * handle       The handle returned by insertSnippet when the instance to
235  *              deleted was created.
236  */
237
238 bool BPatch_addressSpace::deleteSnippetInt(BPatchSnippetHandle *handle)
239 {   
240    if (getTerminated()) return true;
241
242    if (handle == NULL) {
243        bperr("Request to delete NULL snippet handle, returning false\n");
244        return false;
245    }
246
247    if (handle->addSpace_ != this) {
248      bperr("Error: wrong address space in deleteSnippet\n");
249      return false;
250    }
251
252    // if this is a process, check to see if the instrumentation is
253    // executing on the call stack
254    if ( handle->getProcess() ) {
255      //handle->getProcess()->lowlevel_process()->updateActiveMultis();
256      if (handle->mtHandles_.size() > 1) {
257        mal_printf("ERROR: Removing snippet that is installed in "
258                   "multiple miniTramps %s[%d]\n",FILE__,__LINE__);
259      }
260    }
261    
262    // uninstrument and remove snippet handle from point datastructures
263    for (unsigned int i=0; i < handle->mtHandles_.size(); i++)
264      {
265        instPoint *iPoint = handle->mtHandles_[i]->instP();
266        handle->mtHandles_[i]->uninstrument();
267        BPatch_point *bPoint = findOrCreateBPPoint(NULL, iPoint);
268        assert(bPoint);
269        bPoint->removeSnippet(handle);
270      }
271    
272    delete handle;
273    
274    if (pendingInsertions == NULL) {
275      // Trigger it now
276      bool tmp;
277      finalizeInsertionSet(false, &tmp);
278    }
279
280    return true;
281 }
282
283 /*
284  * BPatch_addressSpace::replaceCode
285  *
286  * Replace a given instruction with a BPatch_snippet.
287  *
288  * point       Represents the instruction to be replaced
289  * snippet     The replacing snippet
290  */
291
292 bool BPatch_addressSpace::replaceCodeInt(BPatch_point *point,
293       BPatch_snippet *snippet) 
294 {
295    if (!getMutationsActive())
296       return false;
297
298    if (!point) {
299       return false;
300    }
301    if (getTerminated()) {
302       return true;
303    }
304
305    if (point->edge_) {
306       return false;
307    }
308
309    if (!point->point->replaceCode(snippet->ast_wrapper)) return false;
310
311    if (pendingInsertions == NULL) {
312      // Trigger it now
313      bool tmp;
314      finalizeInsertionSet(false, &tmp);
315    }   
316    return true;
317 }
318
319 /*
320  * BPatch_addressSpace::replaceFunctionCall
321  *
322  * Replace a function call with a call to a different function.  Returns true
323  * upon success, false upon failure.
324  * 
325  * point        The call site that is to be changed.
326  * newFunc      The function that the call site will now call.
327  */
328 bool BPatch_addressSpace::replaceFunctionCallInt(BPatch_point &point,
329       BPatch_function &newFunc)
330 {
331    char name[1024];
332    newFunc.getName(name, 1024);
333
334    // Can't make changes to code when mutations are not active.
335    if (!getMutationsActive())
336       return false;
337
338    assert(point.point && newFunc.lowlevel_func());
339
340    point.getAS()->replaceFunctionCall(point.point, 
341                                       newFunc.lowlevel_func());
342
343    if (pendingInsertions == NULL) {
344      // Trigger it now
345      bool tmp;
346      finalizeInsertionSet(false, &tmp);
347    }
348    return true;
349 }
350
351 /*
352  * BPatch_addressSpace::removeFunctionCall
353  *
354  * Replace a function call with a NOOP.  Returns true upon success, false upon
355  * failure.
356  * 
357  * point        The call site that is to be NOOPed out.
358  */
359 bool BPatch_addressSpace::removeFunctionCallInt(BPatch_point &point)
360 {
361    // Can't make changes to code when mutations are not active.
362    if (!getMutationsActive())
363       return false;   
364
365    assert(point.point);
366
367    point.getAS()->removeFunctionCall(point.point);
368
369    if (pendingInsertions == NULL) {
370      // Trigger it now
371      bool tmp;
372      finalizeInsertionSet(false, &tmp);
373    }
374    
375    return true;
376 }
377
378
379 /*
380  * BPatch_addressSpace::replaceFunction
381  *
382  * Replace all calls to function OLDFUNC with calls to NEWFUNC.
383  * Returns true upon success, false upon failure.
384  * 
385  * oldFunc      The function to replace
386  * newFunc      The replacement function
387  */
388 bool BPatch_addressSpace::replaceFunctionInt(BPatch_function &oldFunc,
389       BPatch_function &newFunc)
390 {
391   assert(oldFunc.lowlevel_func() && newFunc.lowlevel_func());
392   if (!getMutationsActive())
393     return false;
394   
395   // Self replacement is a nop
396   // We should just test direct equivalence here...
397   if (oldFunc.lowlevel_func() == newFunc.lowlevel_func()) {
398     return true;
399   }
400   
401   oldFunc.lowlevel_func()->proc()->replaceFunction(oldFunc.lowlevel_func(), newFunc.lowlevel_func());
402
403   if (pendingInsertions == NULL) {
404     // Trigger it now
405     bool tmp;
406     finalizeInsertionSet(false, &tmp);
407   }
408   return true;
409 #if 0
410
411   BPatch_Vector<BPatch_point *> *pts = oldFunc.findPoint(BPatch_entry);
412   
413   if (! pts || ! pts->size()) {
414     return false;
415   }
416
417   
418   
419    BPatch_funcJumpExpr fje(newFunc);
420    bool old_recursion_flag = BPatch::bpatch->isTrampRecursive();
421    BPatch::bpatch->setTrampRecursive( true );
422
423    // We replace functions by instrumenting the entry of OLDFUNC with
424    // a non-linking jump to NEWFUNC.  Calls to OLDFUNC do actually
425    // transfer to OLDFUNC, but then our jump shunts them to NEWFUNC.
426    // The non-linking jump ensures that when NEWFUNC returns, it
427    // returns directly to the caller of OLDFUNC.
428
429
430    BPatchSnippetHandle * result = insertSnippet(fje, *pts, BPatch_callBefore);
431
432    BPatch::bpatch->setTrampRecursive( old_recursion_flag );
433
434    return (NULL != result);
435 #endif
436 }
437
438
439 bool BPatch_addressSpace::getAddressRangesInt( const char * fileName, 
440       unsigned int lineNo, 
441       std::vector< std::pair< unsigned long, unsigned long > > & ranges ) 
442 {
443    unsigned int originalSize = ranges.size();
444    BPatch_Vector< BPatch_module * > * modules = image->getModules();
445
446    /* Iteratate over the modules, looking for addr in each. */
447    for ( unsigned int i = 0; i < modules->size(); i++ ) {
448       BPatch_module *m = (*modules)[i];
449       m->getAddressRanges(fileName, lineNo, ranges);
450    }
451
452    if ( ranges.size() != originalSize ) { return true; }
453
454    return false;
455 } /* end getAddressRangesInt() */
456
457 bool BPatch_addressSpace::getSourceLinesInt( unsigned long addr, 
458       BPatch_Vector< BPatch_statement > & lines ) 
459 {
460    return image->getSourceLinesInt(addr, lines);
461 } /* end getLineAndFile() */
462
463
464 /*
465  * BPatch_process::malloc
466  *
467  * Allocate memory in the thread's address space.
468  *
469  * n    The number of bytes to allocate.
470  *
471  * Returns:
472  *      A pointer to a BPatch_variableExpr representing the memory.
473  *
474  * If otherwise unspecified when binary rewriting, then the allocation
475  * happens in the original object.
476  */
477
478 BPatch_variableExpr *BPatch_addressSpace::mallocInt(int n)
479 {
480    std::vector<AddressSpace *> as;
481    assert(BPatch::bpatch != NULL);
482    getAS(as);
483    assert(as.size());
484    void *ptr = (void *) as[0]->inferiorMalloc(n, dataHeap);
485    if (!ptr) return NULL;
486    std::stringstream namestr;
487    namestr << "dyn_malloc_0x" << std::hex << ptr << "_" << n << "_bytes";
488    std::string name = namestr.str();
489    
490    BPatch_type *type = BPatch::bpatch->createScalar(name.c_str(), n);
491
492    return BPatch_variableExpr::makeVariableExpr(this, as[0], name, ptr,
493                                                 type);
494 }
495
496
497 /*
498  * BPatch_process::malloc
499  *
500  * Allocate memory in the thread's address space for a variable of the given
501  * type.
502  *
503  * type         The type of variable for which to allocate space.
504  *
505  * Returns:
506  *      A pointer to a BPatch_variableExpr representing the memory.
507  *
508  * XXX Should return NULL on failure, but the function which it calls,
509  *     inferiorMalloc, calls exit rather than returning an error, so this
510  *     is not currently possible.
511  */
512
513 BPatch_variableExpr *BPatch_addressSpace::mallocByType(const BPatch_type &type)
514 {
515    std::vector<AddressSpace *> as;
516    assert(BPatch::bpatch != NULL);
517    getAS(as);
518    assert(as.size());
519    BPatch_type &t = const_cast<BPatch_type &>(type);
520    void *mem = (void *) as[0]->inferiorMalloc(t.getSize(), dataHeap);
521    if (!mem) return NULL;
522    std::stringstream namestr;
523    namestr << "dyn_malloc_0x" << std::hex << mem << "_" << type.getName();
524    std::string name = namestr.str();
525    return BPatch_variableExpr::makeVariableExpr(this, as[0], name, mem, &t);
526 }
527
528
529 /*
530  * BPatch_process::free
531  *
532  * Free memory that was allocated with BPatch_process::malloc.
533  *
534  * ptr          A BPatch_variableExpr representing the memory to free.
535  */
536
537 bool BPatch_addressSpace::freeInt(BPatch_variableExpr &ptr)
538 {
539   if(ptr.intvar)
540   {
541     // kill the symbols
542     
543   }
544   
545    ptr.getAS()->inferiorFree((Address)ptr.getBaseAddr());
546    return true;
547 }
548
549 BPatch_variableExpr *BPatch_addressSpace::createVariableInt(std::string name,
550                                                             Dyninst::Address addr,
551                                                             BPatch_type *type) {
552     assert(BPatch::bpatch != NULL);
553     std::vector<AddressSpace *> as;
554     getAS(as);
555     assert(as.size());
556
557     return BPatch_variableExpr::makeVariableExpr(this, 
558                                                  as[0],
559                                                  name,
560                                                  (void *)addr, 
561                                                  type);
562 }
563
564 BPatch_function *BPatch_addressSpace::findFunctionByAddrInt(void *addr)
565 {
566    int_function *func;   
567    std::vector<AddressSpace *> as;
568
569    getAS(as);
570    assert(as.size());
571    codeRange *range = as[0]->findOrigByAddr((Address) addr);
572    if (!range)
573       return NULL;
574
575    func = range->is_function();
576
577    if (!func) {
578       // if it's a mapped_object that has yet to be analyzed, 
579       // trigger analysis and re-invoke this function
580       if ( range->is_mapped_object() && 
581           ! ((mapped_object*)range)->isAnalyzed() ) {
582          ((mapped_object*)range)->analyze();
583          return findFunctionByAddrInt(addr);
584       }
585       return NULL;
586    }
587
588    if (func->findBlockByAddr((Address)addr)->llb()->isShared()) {
589        bpwarn("Warning: deprecated function findFunctionByAddr found "
590               "multiple functions sharing address 0x%lx, picking one at "
591               "random.  Use findFunctionByEntry or findFunctionsByAddr\n",
592               addr);
593    }
594
595    return findOrCreateBPFunc(func, NULL);
596 }
597
598 /*
599  *  BPatch_addressSpace::findFunctionByEntry
600  *  
601  *  Returns the function starting at the given address, or NULL if the
602  *  address is not within a function.
603  *
604  *  entry       The address to use for the lookup.
605  */
606 BPatch_function *BPatch_addressSpace::findFunctionByEntryInt(Address entry)
607 {
608     vector<BPatch_function*> funcs;
609     findFunctionsByAddr(entry, funcs);
610     vector<BPatch_function*>::iterator fit;
611     for (fit = funcs.begin(); fit != funcs.end(); fit++) {
612         if (entry == (Address)(*fit)->getBaseAddrInt()) {
613             return *fit;
614         }
615     }
616     return NULL;
617 }
618
619 bool BPatch_addressSpace::findFuncsByRange(Address startAddr,
620                                            Address endAddr,
621                                            std::set<BPatch_function*> &bpFuncs)
622 {
623     std::vector<AddressSpace *> as;
624     getAS(as);
625     assert(as.size());
626
627     // find the first code range in the region
628     mapped_object* mobj = as[0]->findObject(startAddr);
629     assert(mobj);
630     set<int_function*> intFuncs;
631     mobj->findFuncsByRange(startAddr,endAddr,intFuncs);
632     set<int_function*>::iterator fIter = intFuncs.begin();
633     for (; fIter != intFuncs.end(); fIter++) {
634         BPatch_function * bpfunc = findOrCreateBPFunc(*fIter,NULL);
635         bpFuncs.insert(bpfunc);
636     }
637     return 0 != bpFuncs.size();
638 }
639
640
641 /*
642  * BPatch_addressSpace::findFunctionsByAddr
643  *
644  * Returns the functions that contain the specified address, or NULL if the
645  * address is not within a function. (there could be multiple functions 
646  * because of the possibility of shared code)
647  *
648  * addr         The address to use for the lookup.
649  * returns false if there were no functions that matched the address
650  */
651 bool BPatch_addressSpace::findFunctionsByAddrInt
652     (Address addr, std::vector<BPatch_function*> &funcs)
653 {
654     std::vector<AddressSpace *> as;
655     getAS(as);
656     assert(as.size());
657
658     // grab the funcs, return false if there aren't any
659     std::vector<int_function*> intfuncs;
660     if (!as[0]->findFuncsByAddr( addr, intfuncs )) {
661         return false;
662     }
663     // convert to BPatch_functions
664     for (std::vector<int_function*>::iterator fiter=intfuncs.begin(); 
665          fiter != intfuncs.end(); fiter++) 
666     {
667         funcs.push_back(findOrCreateBPFunc(*fiter, NULL));
668     }
669     return 0 < funcs.size();
670 }
671
672
673 /*
674  * BPatch_addressSpace::findModuleByAddr
675  *
676  * Returns the module that contains the specified address, or NULL if the
677  * address is not within a module.  Does NOT trigger parsing
678  *
679  * addr         The address to use for the lookup.
680  */
681 BPatch_module *BPatch_addressSpace::findModuleByAddr(Address addr)
682 {
683    std::vector<AddressSpace *> as;
684    getAS(as);
685    assert(as.size());
686
687    mapped_object *obj = as[0]->findObject(addr);
688    if ( ! obj ) 
689        return NULL;
690
691    const pdvector<mapped_module*> mods = obj->getModules();
692    if (mods.size()) {
693        return getImage()->findOrCreateModule(mods[0]);
694    }
695    return NULL;
696 }
697
698
699 /*
700  * BPatch_addressSpace::insertSnippet
701  *
702  * Insert a code snippet at a given instrumentation point.  Upon success,
703  * returns a handle to the created instance of the snippet, which can be used
704  * to delete it.  Otherwise returns NULL.
705  *
706  * expr         The snippet to insert.
707  * point        The point at which to insert it.
708  */
709
710 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetInt(const BPatch_snippet &expr, 
711       BPatch_point &point, 
712       BPatch_snippetOrder order)
713 {
714    BPatch_callWhen when;
715    if (point.getPointType() == BPatch_exit)
716       when = BPatch_callAfter;
717    else
718       when = BPatch_callBefore;
719
720    return insertSnippetWhen(expr, point, when, order);
721 }
722
723 /*
724  * BPatch_addressSpace::insertSnippet
725  *
726  * Insert a code snippet at a given instrumentation point.  Upon succes,
727  * returns a handle to the created instance of the snippet, which can be used
728  * to delete it.  Otherwise returns NULL.
729  *
730  * expr         The snippet to insert.
731  * point        The point at which to insert it.
732  */
733
734 // This handles conversion without requiring inst.h in a header file...
735 extern bool BPatchToInternalArgs(BPatch_point *point,
736       BPatch_callWhen when,
737       BPatch_snippetOrder order,
738       callWhen &ipWhen,
739       callOrder &ipOrder);
740
741
742 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetWhen(const BPatch_snippet &expr,
743       BPatch_point &point,
744       BPatch_callWhen when,
745       BPatch_snippetOrder order)
746 {
747    BPatch_Vector<BPatch_point *> points;
748    points.push_back(&point);
749
750    return insertSnippetAtPointsWhen(expr,
751          points,
752          when,
753          order);
754 }
755
756
757 /*
758  * BPatch_addressSpace::insertSnippet
759  *
760  * Insert a code snippet at each of a list of instrumentation points.  Upon
761  * success, Returns a handle to the created instances of the snippet, which
762  * can be used to delete them (as a unit).  Otherwise returns NULL.
763  *
764  * expr         The snippet to insert.
765  * points       The list of points at which to insert it.
766  */
767
768 // A lot duplicated from the single-point version. This is unfortunate.
769 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetAtPointsWhen(const BPatch_snippet &expr,
770                                                                     const BPatch_Vector<BPatch_point *> &points,
771                                                                     BPatch_callWhen when,
772                                                                     BPatch_snippetOrder order)
773 {
774
775    if (dyn_debug_inst) {
776       BPatch_function *f;
777       for (unsigned i=0; i<points.size(); i++) {
778          f = points[i]->getFunction();
779          const char *sname = f->func->prettyName().c_str();
780          inst_printf("[%s:%u] - %d. Insert instrumentation at function %s, "
781                "address %p, when %d, order %d\n",
782                FILE__, __LINE__, i,
783                sname, points[i]->getAddress(), (int) when, (int) order);
784
785       }
786    }
787
788    if (BPatch::bpatch->isTypeChecked()) {
789       if (expr.ast_wrapper->checkType() == BPatch::bpatch->type_Error) {
790         fprintf(stderr, "[%s:%u] - Type error inserting instrumentation\n",
791                 FILE__, __LINE__);
792          expr.ast_wrapper->debugPrint();
793          return false;
794       }
795    }
796
797    if (!points.size()) {
798      fprintf(stderr, "%s[%d]:  request to insert snippet at zero points!\n", FILE__, __LINE__);
799       return false;
800    }
801
802    BPatchSnippetHandle *ret = new BPatchSnippetHandle(this);
803
804    for (unsigned i = 0; i < points.size(); i++) {
805       BPatch_point *bppoint = points[i];
806
807       if (bppoint->addSpace == NULL) {
808          fprintf(stderr, "Error: attempt to use point with no process info\n");
809          continue;
810       }
811
812       if (dynamic_cast<BPatch_addressSpace *>(bppoint->addSpace) != this) {
813          fprintf(stderr, "Error: attempt to use point specific to a different process\n");
814          continue;
815       }        
816
817       callWhen ipWhen;
818       callOrder ipOrder;
819
820       if (!BPatchToInternalArgs(bppoint, when, order, ipWhen, ipOrder)) {
821         fprintf(stderr, "[%s:%u] - BPatchToInternalArgs failed for point %d\n",
822                FILE__, __LINE__, i);
823          return NULL;
824       }
825
826       miniTramp *mini = bppoint->point->addInst(expr.ast_wrapper,
827                                                 ipWhen,
828                                                 ipOrder,
829                                                 BPatch::bpatch->isTrampRecursive(), 
830                                                 false);
831
832       if (mini) {
833         ret->mtHandles_.push_back(mini);
834         bppoint->recordSnippet(when, order, ret);
835       }
836    }
837
838    if (pendingInsertions == NULL) {
839      // Trigger it now
840      bool tmp;
841      finalizeInsertionSet(false, &tmp);
842    }   
843    return ret;
844 }
845
846
847 /*
848  * BPatch_addressSpace::insertSnippet
849  *
850  * Insert a code snippet at each of a list of instrumentation points.  Upon
851  * success, Returns a handle to the created instances of the snippet, which
852  * can be used to delete them (as a unit).  Otherwise returns NULL.
853  *
854  * expr         The snippet to insert.
855  * points       The list of points at which to insert it.
856  */
857
858 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetAtPoints(
859       const BPatch_snippet &expr,
860       const BPatch_Vector<BPatch_point *> &points,
861       BPatch_snippetOrder order)
862 {
863    return insertSnippetAtPointsWhen(expr,
864          points,
865          BPatch_callUnset,
866          order);
867 }
868
869 /*
870  * BPatch_addressSpace::isStaticExecutable
871  *
872  * Returns true if the underlying image represents a statically-linked executable, false otherwise.
873  */
874 bool BPatch_addressSpace::isStaticExecutableInt() {
875    std::vector<AddressSpace *> as;
876    getAS(as);
877
878    if( !as.size() ) return false;
879
880    AddressSpace *aout = as[0];
881    return aout->getAOut()->isStaticExec();
882 }
883
884 #include "registerSpace.h"
885
886 #if defined(cap_registers)
887 bool BPatch_addressSpace::getRegistersInt(std::vector<BPatch_register> &regs) {
888    if (registers_.size()) {
889        regs = registers_;
890        return true;
891    }
892
893    std::vector<AddressSpace *> as;
894
895    getAS(as);
896    assert(as.size());
897           
898    registerSpace *rs = registerSpace::getRegisterSpace(as[0]);
899    
900    for (unsigned i = 0; i < rs->realRegs().size(); i++) {
901        // Let's do just GPRs for now
902        registerSlot *regslot = rs->realRegs()[i];
903        registers_.push_back(BPatch_register(regslot->name, regslot->number));
904    }
905    regs = registers_;
906    return true;
907 }
908 #else
909 bool BPatch_addressSpace::getRegistersInt(std::vector<BPatch_register> &) {
910     // Empty vector since we're not supporting register objects on
911     // these platforms (yet)
912    return false;
913 }
914 #endif
915
916 #if defined(cap_registers)
917 bool BPatch_addressSpace::createRegister_NPInt(std::string regName,
918                                                BPatch_register &reg) {
919     // Build the register list.
920     std::vector<BPatch_register> dontcare;
921     getRegisters(dontcare);
922
923     for (unsigned i = 0; i < registers_.size(); i++) {
924         if (registers_[i].name() == regName) {
925             reg = registers_[i];
926             return true;
927         }
928     }
929     return false;
930 }
931 #else
932 bool BPatch_addressSpace::createRegister_NPInt(std::string,
933                                                BPatch_register &) 
934 {
935    return false;
936 }
937 #endif
938
939 bool BPatch_addressSpace::loadLibraryInt(const char * /*libname*/, bool /*reload*/)
940 {
941         return false;
942 }
943
944 void BPatch_addressSpace::allowTrapsInt(bool allowtraps)
945 {
946    std::vector<AddressSpace *> as;
947    getAS(as);
948    
949    for (std::vector<AddressSpace *>::iterator i = as.begin(); i != as.end(); i++)
950    {
951       (*i)->setUseTraps(allowtraps);
952    }
953 }
954
955 BPatch_variableExpr *BPatch_addressSpace::createVariableInt(
956                         Dyninst::Address at_addr,
957                         BPatch_type *type, std::string var_name,
958                         BPatch_module *in_module)
959 {
960    BPatch_binaryEdit *binEdit = dynamic_cast<BPatch_binaryEdit *>(this);
961    if (binEdit && !in_module) {
962       //Address alone isn't unique when binary rewriting
963       return NULL;
964    }
965    if (!type) {
966       //Required for size information.  
967       return NULL;
968    }
969    AddressSpace *ll_addressSpace = NULL;
970    
971    std::vector<AddressSpace *> as;
972    getAS(as);
973    if (binEdit) {
974       std::vector<AddressSpace *>::iterator as_i;      
975       for (as_i = as.begin(); as_i != as.end(); as_i++)
976       {
977          BinaryEdit *b = dynamic_cast<BinaryEdit *>(*as_i);
978          assert(b);
979          if (in_module->mod->obj() == b->getMappedObject()) {
980             ll_addressSpace = *as_i;
981             break;
982          }
983       }
984    }
985    else {
986       assert(as.size() == 1);
987       ll_addressSpace = as[0];
988    }
989
990    if (!ll_addressSpace) {
991       //in_module doesn't belong to 'this'
992       return NULL;
993    }
994
995    if (!var_name.size()) {
996       std::stringstream namestream;
997       namestream << "dyninst_var_" << std::hex << at_addr;
998       var_name = namestream.str();
999    }
1000    
1001    return BPatch_variableExpr::makeVariableExpr(this, ll_addressSpace, var_name,
1002                                                 (void *) at_addr, type);
1003 }
1004