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