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