Added hybrid analysis modes, not fully functional.
[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
249        // if this is a process, check to see if the instrumentation is
250        // executing on the call stack
251        if ( handle->getProcess() ) {
252            handle->getProcess()->lowlevel_process()->updateActiveMultis();
253            if (handle->mtHandles_.size() > 1) {
254                mal_printf("ERROR: Removing snippet that is installed in "
255                           "multiple miniTramps %s[%d]\n",FILE__,__LINE__);
256            }
257        }
258
259        // uninstrument and remove snippet handle from point datastructures
260        for (unsigned int i=0; i < handle->mtHandles_.size(); i++)
261        {
262            instPoint *iPoint = handle->mtHandles_[i]->instP();
263            handle->mtHandles_[i]->uninstrument();
264            BPatch_point *bPoint = findOrCreateBPPoint(NULL, iPoint);
265            assert(bPoint);
266            bPoint->deleteSnippet(handle);
267        }
268
269        delete handle;
270        return true;
271    } 
272
273    // Handle isn't to a snippet instance in this process
274    bperr("Error: wrong address space in deleteSnippet\n");
275    return false;
276 }
277
278 /*
279  * BPatch_addressSpace::replaceCode
280  *
281  * Replace a given instruction with a BPatch_snippet.
282  *
283  * point       Represents the instruction to be replaced
284  * snippet     The replacing snippet
285  */
286
287 bool BPatch_addressSpace::replaceCodeInt(BPatch_point *point,
288       BPatch_snippet *snippet) 
289 {
290    if (!getMutationsActive())
291       return false;
292
293    if (!point) {
294       return false;
295    }
296    if (getTerminated()) {
297       return true;
298    }
299
300    if (point->edge_) {
301       return false;
302    }
303
304
305    return point->point->replaceCode(snippet->ast_wrapper);
306 }
307
308
309
310 /*
311  * BPatch_addressSpace::replaceFunctionCall
312  *
313  * Replace a function call with a call to a different function.  Returns true
314  * upon success, false upon failure.
315  * 
316  * point        The call site that is to be changed.
317  * newFunc      The function that the call site will now call.
318  */
319 bool BPatch_addressSpace::replaceFunctionCallInt(BPatch_point &point,
320       BPatch_function &newFunc)
321 {
322    char name[1024];
323    newFunc.getName(name, 1024);
324
325    // Can't make changes to code when mutations are not active.
326    if (!getMutationsActive())
327       return false;
328
329    assert(point.point && newFunc.lowlevel_func());
330
331 #if defined(arch_x86) || defined(arch_x86_64)
332    bool old_recursion_flag = BPatch::bpatch->isTrampRecursive();
333    BPatch::bpatch->setTrampRecursive( true );
334
335    BPatch_funcJumpExpr fjmp(newFunc, true);
336    insertSnippet(fjmp, point, BPatch_lastSnippet);
337    
338    BPatch::bpatch->setTrampRecursive( old_recursion_flag );
339    return true;
340 #else
341    return point.getAS()->replaceFunctionCall(point.point, 
342                                              newFunc.lowlevel_func());
343 #endif
344 }
345
346 /*
347  * BPatch_addressSpace::removeFunctionCall
348  *
349  * Replace a function call with a NOOP.  Returns true upon success, false upon
350  * failure.
351  * 
352  * point        The call site that is to be NOOPed out.
353  */
354 bool BPatch_addressSpace::removeFunctionCallInt(BPatch_point &point)
355 {
356    // Can't make changes to code when mutations are not active.
357    if (!getMutationsActive())
358       return false;   
359
360    assert(point.point);
361
362    return point.getAS()->replaceFunctionCall(point.point, NULL);
363 }
364
365
366 /*
367  * BPatch_addressSpace::replaceFunction
368  *
369  * Replace all calls to function OLDFUNC with calls to NEWFUNC.
370  * Returns true upon success, false upon failure.
371  * 
372  * oldFunc      The function to replace
373  * newFunc      The replacement function
374  */
375 bool BPatch_addressSpace::replaceFunctionInt(BPatch_function &oldFunc,
376       BPatch_function &newFunc)
377 {
378   char oldname[1024];
379   char newname[1024];
380   oldFunc.getName(oldname, 1024);
381   newFunc.getName(newname, 1024);
382    assert(oldFunc.lowlevel_func() && newFunc.lowlevel_func());
383    if (!getMutationsActive())
384       return false;
385
386    // Self replacement is a nop
387    // We should just test direct equivalence here...
388    if (oldFunc.lowlevel_func() == newFunc.lowlevel_func()) {
389       return true;
390    }
391
392    BPatch_Vector<BPatch_point *> *pts = oldFunc.findPoint(BPatch_entry);
393
394    if (! pts || ! pts->size()) {
395       return false;
396    }
397
398    BPatch_funcJumpExpr fje(newFunc);
399 //#if defined(cap_instruction_replacement) && defined(arch_power)
400 #if 0
401    // Replace the first instruction with fje
402    for (unsigned i = 0; i < pts->size(); i++) {
403        BPatch_point *point = (*pts)[i];
404        point->getPoint()->replaceCode(fje.ast_wrapper);
405    }
406
407    return true;
408 #else
409
410    bool old_recursion_flag = BPatch::bpatch->isTrampRecursive();
411    BPatch::bpatch->setTrampRecursive( true );
412
413    // We replace functions by instrumenting the entry of OLDFUNC with
414    // a non-linking jump to NEWFUNC.  Calls to OLDFUNC do actually
415    // transfer to OLDFUNC, but then our jump shunts them to NEWFUNC.
416    // The non-linking jump ensures that when NEWFUNC returns, it
417    // returns directly to the caller of OLDFUNC.
418
419
420    BPatchSnippetHandle * result = insertSnippet(fje, *pts, BPatch_callBefore);
421
422    BPatch::bpatch->setTrampRecursive( old_recursion_flag );
423
424    return (NULL != result);
425 #endif
426 }
427
428
429 bool BPatch_addressSpace::getAddressRangesInt( const char * fileName, 
430       unsigned int lineNo, 
431       std::vector< std::pair< unsigned long, unsigned long > > & ranges ) 
432 {
433    unsigned int originalSize = ranges.size();
434    BPatch_Vector< BPatch_module * > * modules = image->getModules();
435
436    /* Iteratate over the modules, looking for addr in each. */
437    for ( unsigned int i = 0; i < modules->size(); i++ ) {
438       BPatch_module *m = (*modules)[i];
439       m->getAddressRanges(fileName, lineNo, ranges);
440    }
441
442    if ( ranges.size() != originalSize ) { return true; }
443
444    return false;
445 } /* end getAddressRangesInt() */
446
447 bool BPatch_addressSpace::getSourceLinesInt( unsigned long addr, 
448       BPatch_Vector< BPatch_statement > & lines ) 
449 {
450    return image->getSourceLinesInt(addr, lines);
451 } /* end getLineAndFile() */
452
453
454 /*
455  * BPatch_process::malloc
456  *
457  * Allocate memory in the thread's address space.
458  *
459  * n    The number of bytes to allocate.
460  *
461  * Returns:
462  *      A pointer to a BPatch_variableExpr representing the memory.
463  *
464  * If otherwise unspecified when binary rewriting, then the allocation
465  * happens in the original object.
466  */
467
468 BPatch_variableExpr *BPatch_addressSpace::mallocInt(int n)
469 {
470    std::vector<AddressSpace *> as;
471    assert(BPatch::bpatch != NULL);
472    getAS(as);
473    assert(as.size());
474    void *ptr = (void *) as[0]->inferiorMalloc(n, dataHeap);
475    if (!ptr) return NULL;
476    std::stringstream namestr;
477    namestr << "dyn_malloc_0x" << std::hex << ptr << "_" << n << "_bytes";
478    std::string name = namestr.str();
479    
480    BPatch_type *type = BPatch::bpatch->createScalar(name.c_str(), n);
481
482    return BPatch_variableExpr::makeVariableExpr(this, as[0], name, ptr,
483                                                 type);
484 }
485
486
487 /*
488  * BPatch_process::malloc
489  *
490  * Allocate memory in the thread's address space for a variable of the given
491  * type.
492  *
493  * type         The type of variable for which to allocate space.
494  *
495  * Returns:
496  *      A pointer to a BPatch_variableExpr representing the memory.
497  *
498  * XXX Should return NULL on failure, but the function which it calls,
499  *     inferiorMalloc, calls exit rather than returning an error, so this
500  *     is not currently possible.
501  */
502
503 BPatch_variableExpr *BPatch_addressSpace::mallocByType(const BPatch_type &type)
504 {
505    std::vector<AddressSpace *> as;
506    assert(BPatch::bpatch != NULL);
507    getAS(as);
508    assert(as.size());
509    BPatch_type &t = const_cast<BPatch_type &>(type);
510    void *mem = (void *) as[0]->inferiorMalloc(t.getSize(), dataHeap);
511    if (!mem) return NULL;
512    std::stringstream namestr;
513    namestr << "dyn_malloc_0x" << std::hex << mem << "_" << type.getName();
514    std::string name = namestr.str();
515    return BPatch_variableExpr::makeVariableExpr(this, as[0], name, mem, &t);
516 }
517
518
519 /*
520  * BPatch_process::free
521  *
522  * Free memory that was allocated with BPatch_process::malloc.
523  *
524  * ptr          A BPatch_variableExpr representing the memory to free.
525  */
526
527 bool BPatch_addressSpace::freeInt(BPatch_variableExpr &ptr)
528 {
529   if(ptr.intvar)
530   {
531     // kill the symbols
532     
533   }
534   
535    ptr.getAS()->inferiorFree((Address)ptr.getBaseAddr());
536    return true;
537 }
538
539 BPatch_variableExpr *BPatch_addressSpace::createVariableInt(std::string name,
540                                                             Dyninst::Address addr,
541                                                             BPatch_type *type) {
542     assert(BPatch::bpatch != NULL);
543     std::vector<AddressSpace *> as;
544     getAS(as);
545     assert(as.size());
546
547     return BPatch_variableExpr::makeVariableExpr(this, 
548                                                  as[0],
549                                                  name,
550                                                  (void *)addr, 
551                                                  type);
552 }
553
554
555 /*
556  * BPatch_addressSpace::findFunctionByAddr
557  *
558  * Returns the function that contains the specified address, or NULL if the
559  * address is not within a function.
560  *
561  * addr         The address to use for the lookup.
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    return findOrCreateBPFunc(func, NULL);
589 }
590
591 bool BPatch_addressSpace::findFuncsByRange(Address startAddr,
592                                            Address endAddr,
593                                            std::set<BPatch_function*> &bpFuncs)
594 {
595     std::vector<AddressSpace *> as;
596     getAS(as);
597     assert(as.size());
598
599     // find the first code range in the region
600     mapped_object* mobj = as[0]->findObject(startAddr);
601     assert(mobj);
602     set<int_function*> intFuncs;
603     mobj->findFuncsByRange(startAddr,endAddr,intFuncs);
604     set<int_function*>::iterator fIter = intFuncs.begin();
605     for (; fIter != intFuncs.end(); fIter++) {
606         BPatch_function * bpfunc = findOrCreateBPFunc(*fIter,NULL);
607         bpFuncs.insert(bpfunc);
608     }
609     return 0 != bpFuncs.size();
610 }
611
612
613 /*
614  * BPatch_addressSpace::findFunctionsByAddr
615  *
616  * Returns the functions that contain the specified address, or NULL if the
617  * address is not within a function. (there could be multiple functions 
618  * because of the possibility of shared code)
619  *
620  * addr         The address to use for the lookup.
621  * returns false if there were no functions that matched the address
622  */
623 bool BPatch_addressSpace::findFunctionsByAddrInt
624     (Address addr, std::vector<BPatch_function*> &funcs)
625 {
626     std::vector<AddressSpace *> as;
627     getAS(as);
628     assert(as.size());
629
630     // grab the funcs, return false if there aren't any
631     std::vector<int_function*> intfuncs;
632     if (!as[0]->findFuncsByAddr( addr, intfuncs )) {
633         return false;
634     }
635     // convert to BPatch_functions
636     for (std::vector<int_function*>::iterator fiter=intfuncs.begin(); 
637          fiter != intfuncs.end(); fiter++) 
638     {
639         funcs.push_back(findOrCreateBPFunc(*fiter, NULL));
640     }
641     return 0 < funcs.size();
642 }
643
644
645 /*
646  * BPatch_addressSpace::findModuleByAddr
647  *
648  * Returns the module that contains the specified address, or NULL if the
649  * address is not within a module.  Does NOT trigger parsing
650  *
651  * addr         The address to use for the lookup.
652  */
653 BPatch_module *BPatch_addressSpace::findModuleByAddr(Address addr)
654 {
655    std::vector<AddressSpace *> as;
656    getAS(as);
657    assert(as.size());
658
659    mapped_object *obj = as[0]->findObject(addr);
660    if ( ! obj ) 
661        return NULL;
662
663    const pdvector<mapped_module*> mods = obj->getModules();
664    if (mods.size()) {
665        return getImage()->findOrCreateModule(mods[0]);
666    }
667    return NULL;
668 }
669
670
671 /*
672  * BPatch_addressSpace::insertSnippet
673  *
674  * Insert a code snippet at a given instrumentation point.  Upon success,
675  * returns a handle to the created instance of the snippet, which can be used
676  * to delete it.  Otherwise returns NULL.
677  *
678  * expr         The snippet to insert.
679  * point        The point at which to insert it.
680  */
681
682 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetInt(const BPatch_snippet &expr, 
683       BPatch_point &point, 
684       BPatch_snippetOrder order)
685 {
686    BPatch_callWhen when;
687    if (point.getPointType() == BPatch_exit)
688       when = BPatch_callAfter;
689    else
690       when = BPatch_callBefore;
691
692    return insertSnippetWhen(expr, point, when, order);
693 }
694
695 /*
696  * BPatch_addressSpace::insertSnippet
697  *
698  * Insert a code snippet at a given instrumentation point.  Upon succes,
699  * returns a handle to the created instance of the snippet, which can be used
700  * to delete it.  Otherwise returns NULL.
701  *
702  * expr         The snippet to insert.
703  * point        The point at which to insert it.
704  */
705
706 // This handles conversion without requiring inst.h in a header file...
707 extern bool BPatchToInternalArgs(BPatch_point *point,
708       BPatch_callWhen when,
709       BPatch_snippetOrder order,
710       callWhen &ipWhen,
711       callOrder &ipOrder);
712
713
714 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetWhen(const BPatch_snippet &expr,
715       BPatch_point &point,
716       BPatch_callWhen when,
717       BPatch_snippetOrder order)
718 {
719    BPatch_Vector<BPatch_point *> points;
720    points.push_back(&point);
721
722    return insertSnippetAtPointsWhen(expr,
723          points,
724          when,
725          order);
726 }
727
728
729 /*
730  * BPatch_addressSpace::insertSnippet
731  *
732  * Insert a code snippet at each of a list of instrumentation points.  Upon
733  * success, Returns a handle to the created instances of the snippet, which
734  * can be used to delete them (as a unit).  Otherwise returns NULL.
735  *
736  * expr         The snippet to insert.
737  * points       The list of points at which to insert it.
738  */
739
740 // A lot duplicated from the single-point version. This is unfortunate.
741 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetAtPointsWhen(const BPatch_snippet &expr,
742       const BPatch_Vector<BPatch_point *> &points,
743       BPatch_callWhen when,
744       BPatch_snippetOrder order)
745 {
746
747    if (dyn_debug_inst) {
748       BPatch_function *f;
749       for (unsigned i=0; i<points.size(); i++) {
750          f = points[i]->getFunction();
751          const char *sname = f->func->prettyName().c_str();
752          inst_printf("[%s:%u] - %d. Insert instrumentation at function %s, "
753                "address %p, when %d, order %d\n",
754                FILE__, __LINE__, i,
755                sname, points[i]->getAddress(), (int) when, (int) order);
756
757       }
758    }
759
760    if (BPatch::bpatch->isTypeChecked()) {
761       if (expr.ast_wrapper->checkType() == BPatch::bpatch->type_Error) {
762          inst_printf("[%s:%u] - Type error inserting instrumentation\n",
763                FILE__, __LINE__);
764          expr.ast_wrapper->debugPrint();
765          return false;
766       }
767    }
768
769    if (!points.size()) {
770       inst_printf("%s[%d]:  request to insert snippet at zero points!\n", FILE__, __LINE__);
771       return false;
772    }
773
774
775    batchInsertionRecord *rec = new batchInsertionRecord;
776    rec->thread_ = NULL;
777    rec->snip = expr;
778    rec->trampRecursive_ = BPatch::bpatch->isTrampRecursive();
779
780    BPatchSnippetHandle *ret = new BPatchSnippetHandle(this);
781    rec->handle_ = ret;
782
783    for (unsigned i = 0; i < points.size(); i++) {
784       BPatch_point *point = points[i];
785
786       if (point->addSpace == NULL) {
787          fprintf(stderr, "Error: attempt to use point with no process info\n");
788          continue;
789       }
790
791       if (dynamic_cast<BPatch_addressSpace *>(point->addSpace) != this) {
792          fprintf(stderr, "Error: attempt to use point specific to a different process\n");
793          continue;
794       }        
795
796       callWhen ipWhen;
797       callOrder ipOrder;
798
799       if (!BPatchToInternalArgs(point, when, order, ipWhen, ipOrder)) {
800          inst_printf("[%s:%u] - BPatchToInternalArgs failed for point %d\n",
801                FILE__, __LINE__, i);
802          return NULL;
803       }
804
805       rec->points_.push_back(point);
806       rec->when_.push_back(ipWhen);
807       rec->order_ = ipOrder;
808
809       point->recordSnippet(when, order, ret);
810    }
811
812    assert(rec->points_.size() == rec->when_.size());
813
814    // Okey dokey... now see if we just tack it on, or insert now.
815    if (pendingInsertions) {
816       pendingInsertions->push_back(rec);
817    }
818    else {
819       BPatch_process *proc = dynamic_cast<BPatch_process *>(this);
820       assert(proc);
821       proc->beginInsertionSetInt();
822       pendingInsertions->push_back(rec);
823       // All the insertion work was moved here...
824       proc->finalizeInsertionSetInt(false);
825    }
826    return ret;
827 }
828
829
830 /*
831  * BPatch_addressSpace::insertSnippet
832  *
833  * Insert a code snippet at each of a list of instrumentation points.  Upon
834  * success, Returns a handle to the created instances of the snippet, which
835  * can be used to delete them (as a unit).  Otherwise returns NULL.
836  *
837  * expr         The snippet to insert.
838  * points       The list of points at which to insert it.
839  */
840
841 BPatchSnippetHandle *BPatch_addressSpace::insertSnippetAtPoints(
842       const BPatch_snippet &expr,
843       const BPatch_Vector<BPatch_point *> &points,
844       BPatch_snippetOrder order)
845 {
846    return insertSnippetAtPointsWhen(expr,
847          points,
848          BPatch_callUnset,
849          order);
850 }
851
852 #include "registerSpace.h"
853
854 #if defined(cap_registers)
855 bool BPatch_addressSpace::getRegistersInt(std::vector<BPatch_register> &regs) {
856    if (registers_.size()) {
857        regs = registers_;
858        return true;
859    }
860
861    std::vector<AddressSpace *> as;
862
863    getAS(as);
864    assert(as.size());
865           
866    registerSpace *rs = registerSpace::getRegisterSpace(as[0]);
867    
868    for (unsigned i = 0; i < rs->realRegs().size(); i++) {
869        // Let's do just GPRs for now
870        registerSlot *regslot = rs->realRegs()[i];
871        registers_.push_back(BPatch_register(regslot->name, regslot->number));
872    }
873    regs = registers_;
874    return true;
875 }
876 #else
877 bool BPatch_addressSpace::getRegistersInt(std::vector<BPatch_register> &) {
878     // Empty vector since we're not supporting register objects on
879     // these platforms (yet)
880    return false;
881 }
882 #endif
883
884 #if defined(cap_registers)
885 bool BPatch_addressSpace::createRegister_NPInt(std::string regName,
886                                                BPatch_register &reg) {
887     // Build the register list.
888     std::vector<BPatch_register> dontcare;
889     getRegisters(dontcare);
890
891     for (unsigned i = 0; i < registers_.size(); i++) {
892         if (registers_[i].name() == regName) {
893             reg = registers_[i];
894             return true;
895         }
896     }
897     return false;
898 }
899 #else
900 bool BPatch_addressSpace::createRegister_NPInt(std::string,
901                                                BPatch_register &) 
902 {
903    return false;
904 }
905 #endif
906
907 bool BPatch_addressSpace::loadLibraryInt(const char * /*libname*/, bool /*reload*/)
908 {
909         return false;
910 }
911
912 void BPatch_addressSpace::allowTrapsInt(bool allowtraps)
913 {
914    std::vector<AddressSpace *> as;
915    getAS(as);
916    
917    for (std::vector<AddressSpace *>::iterator i = as.begin(); i != as.end(); i++)
918    {
919       (*i)->setUseTraps(allowtraps);
920    }
921 }
922
923 BPatch_variableExpr *BPatch_addressSpace::createVariableInt(
924                         Dyninst::Address at_addr,
925                         BPatch_type *type, std::string var_name,
926                         BPatch_module *in_module)
927 {
928    BPatch_binaryEdit *binEdit = dynamic_cast<BPatch_binaryEdit *>(this);
929    if (binEdit && !in_module) {
930       //Address alone isn't unique when binary rewriting
931       return NULL;
932    }
933    if (!type) {
934       //Required for size information.  
935       return NULL;
936    }
937    AddressSpace *ll_addressSpace = NULL;
938    
939    std::vector<AddressSpace *> as;
940    getAS(as);
941    if (binEdit) {
942       std::vector<AddressSpace *>::iterator as_i;      
943       for (as_i = as.begin(); as_i != as.end(); as_i++)
944       {
945          BinaryEdit *b = dynamic_cast<BinaryEdit *>(*as_i);
946          assert(b);
947          if (in_module->mod->obj() == b->getMappedObject()) {
948             ll_addressSpace = *as_i;
949             break;
950          }
951       }
952    }
953    else {
954       assert(as.size() == 1);
955       ll_addressSpace = as[0];
956    }
957
958    if (!ll_addressSpace) {
959       //in_module doesn't belong to 'this'
960       return NULL;
961    }
962
963    if (!var_name.size()) {
964       std::stringstream namestream;
965       namestream << "dyninst_var_" << std::hex << at_addr;
966       var_name = namestream.str();
967    }
968    
969    return BPatch_variableExpr::makeVariableExpr(this, ll_addressSpace, var_name,
970                                                 (void *) at_addr, type);
971 }
972