* Bugfix: InstrucIter no longer used for int_function iteration.
[dyninst.git] / dyninstAPI / src / multiTramp.h
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 // $Id: multiTramp.h,v 1.25 2007/12/11 20:22:07 bill Exp $
43
44 #if !defined(MULTI_TRAMP_H)
45 #define MULTI_TRAMP_H
46
47 #include "common/h/Dictionary.h"
48 #include "codeRange.h"
49 #include "arch.h"
50 #include "instP.h"
51 #include "mapped_object.h"
52 #include "ast.h"
53
54 // A chunk of code (instruction vector), a "do we care where it is",
55 // and a mechanism to update the code if it moves.
56
57 // Superclass of the baseTrampInstance, miniTrampInstance, and
58 // relocatedInsn classes... lets me play games with virtual functions.
59
60 class instPointInstance;
61 class baseTramp;
62 class miniTramp;
63 class codeRange;
64 class process;
65 class int_function;
66 class multiTramp;
67 class AddressSpace; // process superclass
68
69 #if defined( cap_unwind )
70 #include <libunwind.h>
71 #define UNW_INFO_TYPE unw_dyn_region_info_t
72 #else
73 #define UNW_INFO_TYPE void
74 #endif
75
76 class generatedCodeObject : public codeRange {
77  public:
78     // Do we need to regenerate this code? Used to determine
79     // whether a level of hierarchy needs to be replaced
80     virtual bool hasChanged() { return hasChanged_; }
81
82     // And how much space do you need? (worst case scenario)
83     virtual unsigned maxSizeRequired() = 0;
84     
85     // Prep everything
86     // This may be a noop if we've already generated and nothing
87     // changed. In that case, we bump offset and keep going.
88
89     virtual bool generateCode(codeGen &gen,
90                               Address baseInMutatee,
91                               UNW_INFO_TYPE * * unwindInformation) = 0;
92
93     // And some global setting up state
94     bool generateSetup(codeGen &gen, Address baseInMutatee);
95
96     // Collected code
97     bool alreadyGenerated(codeGen &gen, Address baseInMutatee);
98
99     // And actually write things in. This call is "recursive",
100     // in that it will call into subsidiary objects (e.g.,
101     // baseTramp->miniTramps) to write themselves. When the
102     // call completes all subsidiaries must also be written
103     // into the address space. However, they can do so however
104     // they feel is best. If there isn't anything to do (the 
105     // object is in-lined) no writing will occur, but sub-objects
106     // will be recursed into. On the other hand, some last-second
107     // overwrites can happen (jumps between things)
108
109     // Each level is guaranteed to be installed before the sublevels
110     // are called; any updates must be written into the addr space
111     // directly
112
113     // Any new code is not linked by this call; installCode can be
114     // safely run on multiple points without any new code actually being
115     // executed by the application.
116     virtual bool installCode() { installed_ = true; return true; }
117
118     // If we generated or installed, then decided something didn't work.
119     virtual void invalidateCode();
120     
121     // Link new code into the application
122     virtual bool linkCode() { linked_ = true; return true; } 
123
124     // Begin the deletion process; argument is the child that
125     // was just removed
126     // Default for those that don't care.
127     // Called from the bottom up or top down; check type of
128     // argument to figure out which. Defaults to "do nothing"
129     virtual void removeCode(generatedCodeObject *) { return; }
130
131     // If you want this to work, specialize it.
132     virtual bool safeToFree(codeRange *) { return true; }
133     
134     // Do the final freeing; let parent know we're gone if necessary.
135     // May call the destructor.
136     // Override if you allocate space.
137     virtual void freeCode() { assert(0); return; }
138
139     // Make a copy if necessary, or just return ourselves.
140     virtual generatedCodeObject *replaceCode(generatedCodeObject *newParent) = 0;
141
142     virtual bool shouldGenerate() { return true; }
143
144     // For stack unwinding: give us the "uninstrumented" address (AKA
145     // where we would have been) - since all instrumentation occurs at
146     // a 'single' point, we can do this.
147
148     virtual Address uninstrumentedAddr() const = 0;
149  protected:
150     // And modification times
151     bool generated_;
152     bool installed_;
153     bool linked_;
154     bool hasChanged_;
155  public:
156     bool generated() const { return generated_; }
157     bool installed() const { return installed_; }
158     bool linked() const { return linked_; }
159     void markChanged(bool newValue) { hasChanged_ = newValue; }
160     void markGenerated(bool newValue) { generated_ = newValue; }
161     void markInstalled(bool newValue) { installed_ = newValue; }
162     void markLinked(bool newValue) { linked_ = newValue; }
163
164     // Due to our one-pass generation structure, we might
165     // want to pin one of these at a particular offset from wherever
166     // we start.
167     Address pinnedOffset;
168
169     // Amount of space actually used.
170     unsigned size_;    
171
172     // And where we ended up
173     Address addrInMutatee_;
174
175     Address get_address_cr() const { return addrInMutatee_; }
176     unsigned get_size_cr() const { return size_; }
177
178     bool objIsChild(generatedCodeObject *obj);
179
180     generatedCodeObject() :
181         generated_(false),
182         installed_(false),
183         linked_(false),
184         hasChanged_(true),
185         pinnedOffset(0),
186         size_(0),
187         addrInMutatee_(0),
188         previous_(NULL),
189         fallthrough_(NULL),
190         target_(NULL) 
191         {}
192     generatedCodeObject(const generatedCodeObject *old,
193                         AddressSpace *) :
194         generated_(old->generated_),
195         installed_(old->installed_),
196         linked_(old->linked_),
197         hasChanged_(old->hasChanged_),
198         pinnedOffset(old->pinnedOffset),
199         size_(old->size_),
200         addrInMutatee_(old->addrInMutatee_),
201         previous_(NULL),
202         fallthrough_(NULL),
203         target_(NULL)// These must be set later
204         {}
205
206     // These form mini-CFGs. These pointers allow
207     // us to walk 'em safely.
208
209     generatedCodeObject *previous_;
210     generatedCodeObject *fallthrough_;
211     generatedCodeObject *target_;
212   
213     // And assignment methods. We do this so we can assign
214     // a node n to itself; for example, a shared baseTramp. 
215     // In this case, the assignment disappears.
216     // Returns the "next object to use".
217     // Virtual: relocatedInstruction might platform-override this.
218     virtual generatedCodeObject *setPrevious(generatedCodeObject *obj);
219     virtual generatedCodeObject *setFallthrough(generatedCodeObject *obj);
220     virtual generatedCodeObject *setTarget(generatedCodeObject *obj);
221 };
222
223 class multiTramp;
224
225 // Model the "we're at the end of the tramp, jump back" object
226 class trampEnd : public generatedCodeObject {
227  private: 
228     trampEnd() {};
229  public:
230     // Must always give target
231     trampEnd(multiTramp *multi, Address target);
232     trampEnd(const trampEnd *parEnd, multiTramp *cMT, process *child);
233
234     bool generateCode(codeGen &gen,
235                       Address baseInMutatee,
236                       UNW_INFO_TYPE * * unwindInformation);
237
238     unsigned maxSizeRequired();
239
240     generatedCodeObject *replaceCode(generatedCodeObject *newParent);
241
242     Address target() { return target_; }
243
244     virtual Address uninstrumentedAddr() const { return target_; }
245     
246     void *getPtrToInstruction(Address addr) const;
247     
248  private:
249     multiTramp *multi_;
250     Address target_;
251 };
252
253 class relocatedInstruction;
254
255 // Wrapper for "original code pieces" (or replacements),
256 // AKA not instrumentation.
257 // Things that have an original address
258 class relocatedCode : public generatedCodeObject {
259  public:
260     relocatedCode() :
261         generatedCodeObject() {};
262
263     relocatedCode(const relocatedCode *old,
264                   AddressSpace *proc) :
265         generatedCodeObject(old, proc) 
266         {};
267     
268     virtual Address relocAddr() const = 0;
269
270     virtual const relocatedInstruction *relocInsn() const = 0;
271 };
272
273 class relocatedInstruction : public relocatedCode {
274  private:
275     relocatedInstruction() {};
276  public:
277     relocatedInstruction(instruction *i,
278                          Address o, // The original location in the untouched mutatee
279                          Address f, // Where we're coming from (function relocation)
280                          Address t, // Target (if already set)
281                          multiTramp *m) :
282         relocatedCode(),
283         insn(i),
284 #if defined(arch_sparc)
285         ds_insn(NULL),
286         agg_insn(NULL),
287 #endif
288         origAddr_(o), fromAddr_(f), targetAddr_(t),
289         multiT(m), targetOverride_(0) {}
290     relocatedInstruction(relocatedInstruction *prev,
291                          multiTramp *m) :
292         relocatedCode(),
293         insn(prev->insn),
294 #if defined(arch_sparc)
295         ds_insn(prev->ds_insn),
296         agg_insn(prev->agg_insn),
297 #endif
298       origAddr_(prev->origAddr_), fromAddr_(prev->fromAddr_),
299       targetAddr_(prev->targetAddr_),
300       multiT(m),
301         targetOverride_(prev->targetOverride_) {}
302     
303     relocatedInstruction(const relocatedInstruction *parRI,
304                          multiTramp *cMT,
305                          process *child);
306     
307     ~relocatedInstruction();
308
309     instruction *insn;
310
311 #if defined(arch_sparc)
312     // We wrap delay slots; not going to allow instrumentation
313     // of them (as it's a pain)
314     instruction *ds_insn;
315     instruction *agg_insn;
316 #endif
317
318     Address origAddr_;
319     Address fromAddr_;
320     Address targetAddr_;
321     multiTramp *multiT;
322
323     Address relocAddr() const;
324
325     unsigned maxSizeRequired();
326
327     bool generateCode(codeGen &gen,
328                       Address baseInMutatee,
329                       UNW_INFO_TYPE * * unwindInformation);
330
331     // Change the target of a jump 
332     void overrideTarget(Address newTarget);
333
334     // And get the original target
335     Address originalTarget() const;
336
337     const relocatedInstruction *relocInsn() const { return this; }
338
339     generatedCodeObject *replaceCode(generatedCodeObject *newParent);
340     
341     virtual Address uninstrumentedAddr() const { return fromAddr_; }
342
343     void *getPtrToInstruction(Address addr) const;
344
345  private:
346     // TODO: move to vector of instructions
347     Address targetOverride_;
348 };
349
350 // Preliminary code to replace an instruction with an AST. 
351
352
353 // Good luck....
354 // Implemented in replacedInstruction.C ; header file is here
355 // so that we can build off generatedCodeObject.
356
357 class replacedInstruction : public relocatedCode {
358  private: 
359     replacedInstruction() {};
360  public:
361     // We take a relocatedInstruction in; first it's
362     // moved into the multiTramp, then it's replaced by
363     // something else.
364     replacedInstruction(const relocatedInstruction *i,
365                         AstNodePtr ast,
366                         instPoint *p, // Needed for memory instrumentation
367                         multiTramp *m) :
368         relocatedCode(),
369         oldInsn_(i),
370         ast_(ast),
371         point_(p),
372         multiT_(m) {}
373     
374     // Update constructor
375     replacedInstruction(replacedInstruction *prev,
376                         multiTramp *m) :
377         relocatedCode(),
378         oldInsn_(prev->oldInsn_),
379         ast_(prev->ast_),
380         point_(prev->point_),
381         multiT_(m) {
382     };
383
384     // Fork constructor
385     replacedInstruction(replacedInstruction *parRI,
386                         multiTramp *cMT,
387                         process *child);
388
389     ~replacedInstruction();
390
391     const relocatedInstruction *relocInsn() const { return oldInsn_; }
392     AstNodePtr ast() const { return ast_; }
393     instPoint *point() const { return point_; }
394     multiTramp *multi() const { return multiT_; }
395     AddressSpace *proc() const;
396
397     Address relocAddr() const { return get_address_cr(); }
398     Address uninstrumentedAddr() { return relocInsn()->uninstrumentedAddr(); }
399
400     // Overridden from generatedCodeObject
401     generatedCodeObject *replaceCode(generatedCodeObject *newParent);
402     bool generateCode(codeGen &gen,
403                       Address baseInMutatee,
404                       UNW_INFO_TYPE **unwindInformation);
405     unsigned maxSizeRequired();
406     Address uninstrumentedAddr() const { return oldInsn_->uninstrumentedAddr(); }
407     Address get_address_cr() const { return addrInMutatee_; };
408     unsigned get_size_cr() const { return size_; };
409
410     bool safeToFree(codeRange *range);
411
412
413     const relocatedInstruction *oldInsn_;
414     AstNodePtr ast_;
415     instPoint *point_;
416     multiTramp *multiT_;
417     
418     Address addr_;
419     unsigned size_;
420 };
421
422
423
424 // Code generation. Code generation is really just a special case
425 // of a baby control flow graph, and we treat it as such. This is
426 // going to look very similar to the various CFG classes, and it's not
427 // accidental.
428
429 class generatedCFG_t;
430
431 class generatedCFG_t {    
432     // See previous: STUPID WINDOWS COMPILER
433 #if defined(os_windows)
434  public:
435 #endif
436     generatedCodeObject *start_;
437     
438     generatedCodeObject *copy_int(generatedCodeObject *obj,
439                                   generatedCodeObject *par,
440                                   multiTramp *newMulti,
441                                   pdvector<generatedCodeObject *> &unused);
442     generatedCodeObject *fork_int(const generatedCodeObject *parObj,
443                                   generatedCodeObject *childPrev,
444                                   multiTramp *childMulti,
445                                   process *child);
446
447  public:
448     class iterator {
449         pdvector<generatedCodeObject *> stack_;
450         generatedCodeObject *cur_;
451     public:
452         iterator(const generatedCFG_t &cfg) : cur_(cfg.start_) {}
453         iterator() : cur_(NULL) {};
454         void initialize(generatedCFG_t &cfg);
455         // (int) : post-increment
456         void find(generatedCFG_t &cfg, generatedCodeObject *pointer);
457         generatedCodeObject *operator++(int);
458         generatedCodeObject *operator*();
459     };
460     
461  public:
462     generatedCFG_t() : start_(NULL) {};
463     // FORK!
464     generatedCFG_t(const generatedCFG_t &par, 
465                    multiTramp *cMT,
466                    process *child);
467
468     ~generatedCFG_t() {};
469
470     // Called by multiTramp::replaceCode
471     void replaceCode(generatedCFG_t &oldCFG,
472                      multiTramp *newMulti,
473                      pdvector<generatedCodeObject *> &unused);
474
475     void setStart(generatedCodeObject *s) {start_ = s; }
476     generatedCodeObject *start() { return start_; }
477
478     // Empty it out; assumes all nodes deleted elsewhere
479     void destroy();
480
481     // Get the last thing added; for construction.
482     generatedCodeObject *back();
483 };
484       
485 // Multipoint: represents the physical instruction(s) overwritten with
486 // a jump. There will be multiple instPoints to one multiTramp. It
487 // also now owns a lot of the classless utility functions (such as
488 // installBaseTramp and generateBranchToTramp).
489
490 // Note: there can also be multiple multiTramps to a single instPoint
491 // if a function has been relocated.
492
493 #if defined( cap_unwind )
494 #include <libunwind.h>
495 #endif /* defined( cap_unwind ) */
496
497 class instArea;
498
499 class multiTramp : public generatedCodeObject {
500     friend class instArea;
501   static unsigned id_ctr; // All hail the unique ID
502
503  public:
504   unsigned id() const { return id_; }
505
506  private:
507   unsigned id_;
508   // Blah blah private constructor.
509   multiTramp();
510   // First-time constructor
511   multiTramp(Address addr,
512              unsigned size,
513              int_function *func);
514   // If we're regenerating for some reason, 
515   // we use the old one for info rather than having to 
516   // redo everything.
517   multiTramp(multiTramp *ot);
518
519   // Keep a mapping so we can find multiTramps
520   //static dictionary_hash<multiTrampID, multiTramp *> multiTrampDict;
521   // Now in the process class so we can handle fork easily
522
523   // Replacement method. Used when the physical multiTramp
524   // doesn't agree with the abstract version. Since we re-allocate,
525   // we go ahead and make a new one.
526   // TODO: two-phase remove step.
527   static bool replaceMultiTramp(multiTramp *oldMulti, bool &deleteReplaced);
528
529  public:
530   // And a factory method. Creates a multiTramp that covers the point
531   // given, but may not be aligned with it (platform dependent). The
532   // tramp is not actually generated and installed until
533   // generateMultiTramp is called.
534   // Also registers the multiTramp with the process.
535   // Returns a handle that can be used to get the multiTramp; allows
536   // us to replace them "under the hood"
537
538   static int findOrCreateMultiTramp(Address pointAddr, 
539                                     AddressSpace *proc); 
540
541   // MultiTramps span several instructions. By default, they cover a
542   // basic block on non-IA64 platforms; due to the inefficiency of our
543   // relocation algorithm, only bundles are covered on that
544   // platform. The instPoint logic needs to know what will be covered
545   // by a multiTramp to properly decide who can share baseTramps.
546   // Returns startAddr and size
547   static bool getMultiTrampFootprint(Address instAddr,
548                                      AddressSpace *proc,
549                                      Address &startAddr,
550                                      unsigned &size,
551                                      bool &basicBlock);
552
553   static multiTramp *getMulti(int id, AddressSpace *proc);
554
555   // Fork constructor. Must copy over all sub-objects as well.
556   multiTramp(const multiTramp *parentMulti, process *child);
557
558   // Error codes!
559   typedef enum { mtSuccess, mtAllocFailed, mtTryRelocation, mtError } mtErrorCode_t;
560
561   // Entry point for code generation: from an instPointInstance
562   mtErrorCode_t generateMultiTramp();
563   mtErrorCode_t installMultiTramp();
564   mtErrorCode_t linkMultiTramp();
565
566   // Temporarily install or remove
567   bool disable();
568   bool enable();
569
570   ~multiTramp();
571
572   int_function *func() const;
573   
574   baseTrampInstance *getBaseTrampInstance(instPointInstance *point,
575                                           callWhen when) const;
576   // This has "byAddr" added because the Address and callWhen types
577   // overlap; no accidentally calling the wrong one.
578   baseTrampInstance *getBaseTrampInstanceByAddr(Address addr) const;
579
580   // codeRange stuff
581   Address get_address_cr() const { return trampAddr_; }
582   unsigned get_size_cr() const { return trampSize_; }
583   void *get_local_ptr() const { return generatedMultiT_.start_ptr(); }
584
585   void *getPtrToInstruction(Address addr) const;
586
587   Address getAddress() const { return trampAddr_; }
588
589   Address instAddr() const { return instAddr_; }
590   unsigned instSize() const { return instSize_; }
591   unsigned branchSize() const { return branchSize_; }
592
593   // Address in the multitramp -> equivalent in uninstrumented terms
594   // Kind of the reverse of base tramp instances...
595   Address instToUninstAddr(Address addr);
596   // Returns 0 if the addr isn't within the tramp
597   Address uninstToInstAddr(Address addr);
598
599   // Returns the closest instPoint that we're at
600   instPoint *findInstPointByAddr(Address addr);
601
602   // Can't call this on a multiTramp as it covers multiple
603   // instructions...
604   Address uninstrumentedAddr() const { assert(0); return 0; }
605
606   // Mmmm breaking logic up
607   // Returns true if the PC is in the multiTramp (or sub-areas)
608   // and after the given miniTramp. Returns false if it's before.
609   // Asserts if the PC is not "in" the multiTramp at all.
610   bool catchupRequired(Address pc, miniTramp *newMT, bool active, codeRange *range = NULL);
611
612   AddressSpace *proc() const;
613
614   ///////////////// Generation
615   bool generateCode(codeGen &gen,
616                     Address baseInMutatee,
617                     UNW_INFO_TYPE * * unwindInformation);
618
619   // The most that we can need to get to a multitramp...
620   unsigned maxSizeRequired();
621   // the space needed for a jump to this particular multitramp...
622   // (unsigned) -1: can't make it, so sorry.
623   unsigned sizeDesired() const { return branchSize_; };
624   bool usesTrap() const { return usedTrap_; };
625
626   bool hasChanged();
627   bool installCode();
628   void invalidateCode();
629   bool linkCode();
630   void removeCode(generatedCodeObject *subObject);
631     // STUPID WINDOWS COMPILER
632   generatedCodeObject *replaceCode(generatedCodeObject *newParent);
633   bool safeToFree(codeRange *range);
634   void freeCode();
635
636  private:
637   Address instAddr_; 
638   Address trampAddr_;  // Where we are
639   unsigned trampSize_; // Size of the generated multiTramp
640   unsigned instSize_; // Size of the original instrumented area
641   unsigned branchSize_; // Size of the branch instruction(s) used to get to
642                    // the multiTramp (in a perfect world). Also, MAXINT
643                    // means that due to architecture limitations we
644                    // can't put a branch in, and is a signal to either
645                    // relocate or trap (or, likely, both).
646   bool usedTrap_;
647
648   int_function *func_;
649   AddressSpace *proc_;
650   // A list of tramp structures we created a baseTramp stores
651   // offsets for various points. We keep it separate to avoid clogging
652   // up this structure.
653   pdvector<generatedCodeObject *> deletedObjs;
654
655   // A mini-CFG for code generation
656   generatedCFG_t generatedCFG_;
657   // And track all the instructions we cover.
658   dictionary_hash<Address, relocatedCode *> insns_;
659   void updateInsnDict();
660
661   // Insert jumps/traps/whatever from previous multiTramp to new multiTramp.
662   // Allows correct instrumentation semantics - "if you add to a later point,
663   // the new code will execute". We add to this vector from the previous 
664   // multiTramp and put traps in when linking the new one. Then we nuke the
665   // vector.
666   // Format: <uninst addr, addr in old multiTramp>
667   // We need to map old mT to new mT - however, the "new mT" isn't done until
668   // we generate. So instead we go "uninst, oldMT", as we can map uninst -> newMT
669   // via insns_
670   pdvector<pdpair<Address, Address> > *previousInsnAddrs_;
671   void constructPreviousInsnList(multiTramp *oldMulti);
672
673   codeGen generatedMultiT_;
674   codeGen jumpBuf_;
675
676   // And what was there before we copied it.
677   void *savedCodeBuf_;
678
679   friend class instPointInstance;
680   void addInstInstance(instPointInstance *instInstance);
681
682   // Go and check to see if there are any new instInstances...
683   void updateInstInstances();
684
685   bool generateBranchToTramp(codeGen &gen);
686   bool generateTrapToTramp(codeGen &gen);
687   bool fillJumpBuf(codeGen &gen);
688   
689 #if defined( cap_unwind )
690   unw_dyn_info_t * unwindInformation;
691 #endif /* defined( cap_unwind ) */
692
693   bool changedSinceLastGeneration_;
694   
695   void setFirstInsn(generatedCodeObject *obj) { generatedCFG_.setStart(obj); }
696 };
697
698 // Funfun... we need to look up multiTramps by both their instrumentation range and 
699 // the instrumented range; but current codeRange can only do one. So we make a wrapper.
700
701 // This reports the instAddr_ and instSize_ members
702
703 class instArea : public codeRange {
704  public:
705     instArea(multiTramp *m) : multi(m) {}
706     multiTramp *multi;
707     Address get_address_cr() const { assert(multi); return multi->instAddr(); }
708     unsigned get_size_cr() const { assert(multi); return multi->instSize(); }
709     void *get_local_ptr() const { assert(multi); return multi->jumpBuf_.start_ptr(); }
710 };
711
712
713
714 /////////////////
715 // Sticking this here for now
716 class replacedFunctionCall : public codeRange {
717  public:
718     Address get_address_cr() const { return callAddr; }
719     unsigned get_size_cr() const { return callSize; }
720     void *get_local_ptr() const { return newCall.start_ptr(); }
721     
722     Address callAddr;
723     unsigned callSize;
724     Address newTargetAddr;
725     codeGen newCall;
726     codeGen oldCall;
727 };
728
729 #endif