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