bug fix to findAndInstallBaseTramp when checking for need_to_add
[dyninst.git] / dyninstAPI / src / inst-sparc-solaris.C
1 /*
2  * Copyright (c) 1996 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 #include "dyninstAPI/src/inst-sparc.h"
43
44 // Another constructor for the class instPoint. This one is called
45 // for the define the instPoints for regular functions which means
46 // multiple instructions is going to be moved to based trampoline.
47 // Since we will use the instruction CALL to branch to the base
48 // tramp(so it doesn't have any code size restriction), things are
49 // a little more complicated because instruction CALL changes the 
50 // value in the link register.
51 instPoint::instPoint(pd_Function *f, const instruction &instr, 
52                      const image *owner, Address &adr,
53                      bool delayOK, bool isLeaf, instPointType pointType)
54 : addr(adr), originalInstruction(instr), inDelaySlot(false), isDelayed(false),
55   callIndirect(false), callAggregate(false), callee(NULL), func(f),
56   leaf(isLeaf), ipType(pointType), image_ptr(owner), firstIsConditional(false),
57   relocated_(false), isLongJump(false)
58 {
59
60   isBranchOut = false;
61   size = 0;
62
63   // When the function is not a leaf function 
64   if (!leaf) {
65
66       // we will treat the first instruction after the SAVE instruction
67       // in the nonleaf procedure as the function entry.  
68       if (ipType == functionEntry) {
69
70           assert(isInsnType(instr, SAVEmask, SAVEmatch));
71           saveInsn.raw = owner->get_instruction(addr);
72           addr += 4;
73           originalInstruction.raw = owner->get_instruction(addr);
74           delaySlotInsn.raw = owner->get_instruction(addr+4);
75           size += 2*sizeof(instruction);
76
77           // If the second instruction is DCTI, we need to move the
78           // the instruction in the delayed slot.
79           if (IS_DELAYED_INST(delaySlotInsn)) {
80               isDelayed = true; 
81               isDelayedInsn.raw = owner->get_instruction(addr+8);
82               size += 1*sizeof(instruction);
83
84               // Life is hard. If the second instruction is actually
85               // an CALL instruction, we need to move the instruction
86               // after the instruction in the delayed slot if the 
87               // return value of this function is a aggregate value.
88               aggregateInsn.raw = owner->get_instruction(addr+12);
89               if (isCallInsn(delaySlotInsn)) {
90                   if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
91                       callAggregate = true;
92                       size += 1*sizeof(instruction);
93                   }
94               }
95           }
96
97       // The following are easier.        
98       } else if (ipType == callSite) {
99           delaySlotInsn.raw = owner->get_instruction(addr+4);
100           size += 2*sizeof(instruction);
101
102           aggregateInsn.raw = owner->get_instruction(addr+8);
103           if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
104               callAggregate = true;
105               size += 1*sizeof(instruction);
106           }
107       } else {
108           delaySlotInsn.raw = owner->get_instruction(addr+4);
109           size += 2*sizeof(instruction);
110       }
111   }
112
113   // When the function is a leaf function
114   else {
115
116       // For the leaf procedure, there are no function calls in
117       // this procdure. So we don't need to consider the 
118       // aggregate instuction.
119       if (ipType == functionEntry) {
120
121           otherInstruction.raw = owner->get_instruction(addr+4);
122           delaySlotInsn.raw = owner->get_instruction(addr+8);
123           size += 2*sizeof(instruction);
124
125           if (IS_DELAYED_INST(delaySlotInsn)) {
126               isDelayed = true;
127               isDelayedInsn.raw = owner->get_instruction(addr+12);
128               size += 2*sizeof(instruction);
129           }
130
131       } else if (ipType == functionExit) {
132           
133           addr -= 4;
134
135           if (owner->isValidAddress(addr-4)) {
136               instruction iplus1;
137               iplus1.raw = owner->get_instruction(addr-4);
138               if (IS_DELAYED_INST(iplus1) && !delayOK) {
139                   addr -= 4;
140                   inDelaySlot = true;
141                   size += 1*sizeof(instruction);
142                   if(isCondBranch(iplus1)){
143                       instruction previous_inst; 
144                       previous_inst.raw = owner->get_instruction(addr-4);
145                       firstIsConditional = true;
146                       addr -= sizeof(instruction);
147                       size += 1*sizeof(instruction);
148                   }
149               }
150           }
151
152           originalInstruction.raw = owner->get_instruction(addr);
153           otherInstruction.raw = owner->get_instruction(addr+4);
154           delaySlotInsn.raw = owner->get_instruction(addr+8);
155           size += 3*sizeof(instruction);
156
157           if (inDelaySlot) {
158               inDelaySlotInsn.raw = owner->get_instruction(addr+12);
159               if(firstIsConditional) {
160                   extraInsn.raw = owner->get_instruction(addr+16);
161               }
162           }
163
164       } else {
165           // Of course, the leaf function could not have call sites. 
166           logLine("Internal Error: in inst-sparc.C.");
167           abort();
168       }
169   }
170
171   // return the address in the code segment after this instruction
172   // sequence. (there's a -1 here because one will be added up later in
173   // the function findInstPoints)  
174   adr = addr + (size - 1*sizeof(instruction));
175 }
176
177
178 void AstNode::sysFlag(instPoint *location)
179 {
180     // astFlag = location->func->isTrapFunc();
181     if (location -> ipType == functionEntry) {
182         astFlag = (location -> isLongJump)? false:true; 
183     } else if (location -> ipType == functionExit) {
184         astFlag = location -> leaf;
185     } else
186         astFlag = false;
187
188     if (loperand)
189         loperand->sysFlag(location);
190     if (roperand)
191         roperand->sysFlag(location); 
192
193     for (unsigned u = 0; u < operands.size(); u++) {
194         operands[u]->sysFlag(location);
195     }
196 }
197
198 // Determine if the called function is a "library" function or a "user" function
199 // This cannot be done until all of the functions have been seen, verified, and
200 // classified
201 //
202 void pd_Function::checkCallPoints() {
203   instPoint *p;
204   Address loc_addr;
205
206   vector<instPoint*> non_lib;
207
208   for (unsigned i=0; i<calls.size(); ++i) {
209     /* check to see where we are calling */
210     p = calls[i];
211     assert(p);
212
213     if (isInsnType(p->originalInstruction, CALLmask, CALLmatch)) {
214       // Direct call
215       loc_addr = p->addr + (p->originalInstruction.call.disp30 << 2);
216       pd_Function *pdf = (file_->exec())->findFunction(loc_addr);
217       if (pdf && !pdf->isLibTag()) {
218         p->callee = pdf;
219         non_lib += p;
220       } else if(!pdf){
221            // if this is a call outside the fuction, keep it
222            if((loc_addr < getAddress(0))||(loc_addr > (getAddress(0)+size()))){
223                 p->callIndirect = true;
224                 p->callee = NULL;
225                 non_lib += p;
226            }
227            else {
228                delete p;
229            }
230       } else {
231           delete p;
232       }
233     } else {
234       // Indirect call -- be conservative, assume it is a call to 
235       // an unnamed user function
236       assert(!p->callee); assert(p->callIndirect);
237       p->callee = NULL;
238       non_lib += p;
239     }
240   }
241   calls = non_lib;
242 }
243
244 // TODO we cannot find the called function by address at this point in time
245 // because the called function may not have been seen.
246 // reloc_info is 0 if the function is not currently being relocated
247 Address pd_Function::newCallPoint(Address &adr, const instruction instr,
248                                  const image *owner, bool &err, 
249                                  int &callId, Address &oldAddr,
250                                  relocatedFuncInfo *reloc_info,
251                                  const instPoint *&location)
252 {
253     Address ret=adr;
254     instPoint *point;
255
256     err = true;
257     if (isTrap) {
258         point = new instPoint(this, instr, owner, adr, false, callSite, oldAddr);
259     } else {
260         point = new instPoint(this, instr, owner, adr, false, false, callSite);
261     }
262
263     if (!isInsnType(instr, CALLmask, CALLmatch)) {
264       point->callIndirect = true;
265       point->callee = NULL;
266     } else{
267       point->callIndirect = false;
268     }
269
270     if (isTrap) {
271         if (!reloc_info) {
272             calls += point;
273             calls[callId] -> instId = callId++;
274         } else {
275             // calls to a location within the function are not
276             // kept in the calls vector
277             assert(callId >= 0);
278             assert(((u_int)callId) < calls.size());
279             point->relocated_ = true;
280             // if the location was this call site, then change its value
281             if(location && (calls[callId] == location)) { 
282                 assert(calls[callId]->instId  == location->instId);
283                 location = point; 
284             } 
285             point->instId = callId++;
286             reloc_info->addFuncCall(point);
287         }
288     } else {
289         if (!reloc_info) {
290             calls += point;
291         }
292         else {
293             point->relocated_ = true;
294             reloc_info->addFuncCall(point);
295         }
296     }
297     err = false;
298     return ret;
299 }
300
301 /*
302  * Given and instruction, relocate it to a new address, patching up
303  *   any relative addressing that is present.
304  *
305  */
306 void relocateInstruction(instruction *insn, u_int origAddr, u_int targetAddr,
307                          process *proc)
308 {
309     int newOffset;
310
311     // If the instruction is a CALL instruction, calculate the new
312     // offset
313     if (isInsnType(*insn, CALLmask, CALLmatch)) {
314         newOffset = origAddr  - targetAddr + (insn->call.disp30 << 2);
315         insn->call.disp30 = newOffset >> 2;
316     } else if (isInsnType(*insn, BRNCHmask, BRNCHmatch)||
317                isInsnType(*insn, FBRNCHmask, FBRNCHmatch)) {
318
319         // If the instruction is a Branch instruction, calculate the 
320         // new offset. If the new offset is out of reach after the 
321         // instruction is moved to the base Trampoline, we would do
322         // the following:
323         //    b  address  ......    address: save
324         //                                   call new_offset             
325         //                                   restore 
326         newOffset = origAddr - targetAddr + (insn->branch.disp22 << 2);
327
328         // if the branch is too far, then allocate more space in inferior
329         // heap for a call instruction to branch target.  The base tramp 
330         // will branch to this new inferior heap code, which will call the
331         // target of the branch
332         if (!offsetWithinRangeOfBranchInsn(newOffset)) {
333 //      if (ABS(newOffset) > getMaxBranch1Insn()) {
334             int ret = inferiorMalloc(proc,3*sizeof(instruction), textHeap);
335             u_int old_offset = insn->branch.disp22 << 2;
336             insn->branch.disp22  = (ret - targetAddr)>>2;
337             instruction insnPlus[3];
338             genImmInsn(insnPlus, SAVEop3, REG_SP, -112, REG_SP);
339             generateCallInsn(insnPlus+1, ret+sizeof(instruction), 
340                              origAddr+old_offset);
341             genSimpleInsn(insnPlus+2, RESTOREop3, 0, 0, 0); 
342             proc->writeDataSpace((caddr_t)ret, sizeof(insnPlus), 
343                          (caddr_t) insnPlus);
344         } else {
345             insn->branch.disp22 = newOffset >> 2;
346         }
347     } else if (isInsnType(*insn, TRAPmask, TRAPmatch)) {
348         // There should be no probelm for moving trap instruction
349         // logLine("attempt to relocate trap\n");
350     } 
351     /* The rest of the instructions should be fine as is */
352 }
353
354 /*
355  * Install a base tramp -- fill calls with nop's for now.
356  *
357  * This one install the base tramp for the regular functions.
358  *
359  */
360 trampTemplate *installBaseTramp(instPoint *&location, process *proc)
361 {
362     // cerr << location->func->prettyName() << ":\t" << location->ipType << endl;
363     unsigned baseAddr = inferiorMalloc(proc, baseTemplate.size, textHeap);
364
365     instruction *code = new instruction[baseTemplate.size];
366     assert(code);
367
368     memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
369
370     instruction *temp;
371     unsigned currAddr;
372     for (temp = code, currAddr = baseAddr; 
373         (currAddr - baseAddr) < (unsigned) baseTemplate.size;
374         temp++, currAddr += sizeof(instruction)) {
375
376         if (temp->raw == EMULATE_INSN) {
377
378             // Load the value of link register from stack 
379             // If it is a leaf function, genereate a RESTORE instruction
380             // since there's an instruction SAVE generated and put in the
381             // code segment.
382             if (location -> leaf) {
383
384                 Address baseAddress = 0;
385                 proc->getBaseAddress(location->image_ptr,baseAddress);
386                 baseAddress += location -> addr;
387
388                 if (in1BranchInsnRange(baseAddress, baseAddr) == false) {
389                     //cerr << "This happen very rarely, I suppose "<< endl;
390                     //cerr << "Let's see if this is going to be executed..." << endl;
391                     location -> isLongJump = true;
392                     genImmInsn(temp, RESTOREop3, 0, 0, 0);
393                 } else {
394                     generateNOOP(temp);
395                 }
396                 temp++;
397                 currAddr += sizeof(instruction);
398             } 
399             // Same for the leaf and nonleaf functions.
400             // First, relocate the "FIRST instruction" in the sequence;  
401             Address fromAddr = location->addr;
402
403             if (!location -> leaf)
404                 if (location -> ipType == functionEntry) {
405                     *temp = location -> saveInsn;
406                     temp++;
407                     currAddr += sizeof(instruction);
408                 }
409
410             *temp = location->originalInstruction;
411
412             // compute the real from address if this instrumentation
413             // point is from a shared object image
414             Address baseAddress = 0;
415             if(proc->getBaseAddress(location->image_ptr,baseAddress)){
416                 fromAddr += baseAddress;                
417             }
418             // If the instruction is a call instruction to a location somewhere 
419             // within the function, then the 07 regester must be saved and 
420             // resored around the relocated call from the base tramp...the call
421             // instruction changes the value of 07 to be the PC value, and if
422             // we move the call instruction to the base tramp, its value will
423             // be incorrect when we use it in the function.  We generate the
424             // following base tramp code:
425             //          original delay slot instruction 
426             //          save
427             //          original call instruction
428             //          restore
429             // This case should only occur for function entry points in
430             // functions from shared objects, and there should be no append
431             // trampolene code because the relocated call instruction will
432             // not return to the base tramp
433             if (isInsnType(*temp, CALLmask, CALLmatch)) {
434                 Address offset = fromAddr + (temp->call.disp30 << 2);
435                 if ((offset > (location->func->getAddress(0)+ baseAddress)) && 
436                     (offset < ((location->func->getAddress(0)+ baseAddress)+
437                                  location->func->size()))) {
438                     // offset > adr; "=" means recursive function which is allowed
439                     // offset < adr + size; "=" does not apply to this case
440
441                     // TODO: this assumes that the delay slot instruction is not
442                     // a call instruction....is this okay?
443                     
444                     // assume this situation only happens at function entry point 
445                     // for the shared library routine. And it is definately nees
446                     // long jump support
447                     assert(location -> ipType == functionEntry); 
448                     location -> isLongJump = true;
449                     
450                     // In this situcation, save instruction is discarded
451                     // Rollback!! 
452                     assert(location->leaf == false);
453                     temp--;
454                     currAddr -= sizeof(instruction);
455                     
456                     *temp = location->delaySlotInsn;  
457                     temp++; 
458                     currAddr += sizeof(instruction);
459                     genImmInsn(temp, SAVEop3, REG_SP, -112, REG_SP); 
460                     temp++; 
461                     currAddr += sizeof(instruction);  
462                     *temp = location->originalInstruction;
463                     relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
464                     temp++; 
465                     fromAddr += sizeof(instruction); 
466                     currAddr += sizeof(instruction);
467                     genImmInsn(temp, RESTOREop3, 0, 0, 0);
468                     continue;
469                 }
470             }   
471
472             relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
473
474             // Again, for leaf function, one more is needed to move for one
475             // more spot;
476             if (location->leaf) {
477                 fromAddr += sizeof(instruction);
478                 currAddr += sizeof(instruction);
479                 *++temp = location->otherInstruction;
480                 relocateInstruction(temp, fromAddr, currAddr, 
481                                     (process *)proc);
482             }     
483             
484             // Second, relocate the "NEXT instruction";
485             fromAddr += sizeof(instruction);
486             currAddr += sizeof(instruction);
487             *++temp = location->delaySlotInsn;
488  
489             // if the NEXT instruction is a call instruction to a location
490             // within the function, then the 07 regester must be saved and 
491             // resored around the relocated call from the base tramp...the call
492             // instruction changes the value of 07 to be the PC value, and if
493             // we move the call instruction to the base tramp, its value will
494             // be incorrect when we use it in the function.  We generate:
495             //
496             //  orignial            relocated to base tramp
497             //  --------            -----------------------
498             //  save                nop  // SAVE added above, replace w/nop 
499             //  original insn       original instruction // already relocated
500             //  delaySlotInsn       isDelayedInsn
501             //  isDelayedInsn       save
502             //                      delaySlotInsn  (call with offset - 4)
503             //                      restore
504             //  In the function, the call to the base tramp will have an
505             //  additional add instruction to adjust the 07 register
506             //  orignial            relocated to base tramp
507             //  --------            -----------------------
508             //  save                 save       
509             //  mov                  call
510             //  call                 nop
511             //  sethi                add $o7 4   
512             //
513             if (isInsnType(*temp, CALLmask, CALLmatch)) {
514                 Address offset = fromAddr + (temp->call.disp30 << 2);
515                 if ((offset > (location->func->getAddress(0)+ baseAddress)) && 
516                     (offset < ((location->func->getAddress(0)+ baseAddress)+
517                                  location->func->size()))) {
518                     
519                     temp--;
520                     temp--;
521                     generateNOOP(temp);  
522                     temp++;
523                     temp++;
524                     location->isLongJump = true;
525                     // assert(location->leaf == false);
526                     // assume that this is not a delayed instr.
527                     *temp = location->isDelayedInsn;  
528                     temp++; 
529                     currAddr += sizeof(instruction);
530                     genImmInsn(temp, SAVEop3, REG_SP, -112, REG_SP); 
531                     temp++; 
532                     currAddr += sizeof(instruction);  
533                     *temp = location->delaySlotInsn;
534                     Address new_call_addr = fromAddr - sizeof(instruction);
535                     relocateInstruction(temp,new_call_addr,currAddr,proc);
536                     temp++; 
537                     fromAddr += sizeof(instruction); 
538                     currAddr += sizeof(instruction);
539                     genImmInsn(temp, RESTOREop3, 0, 0, 0);
540                     continue;
541                 }
542             }   
543
544             // otherwise relocate the NEXT instruction
545             relocateInstruction(temp, fromAddr, currAddr,
546                                 (process *)proc);
547             
548             // Third, if the "NEXT instruction" is a DCTI, 
549             if (location->isDelayed) {
550                 fromAddr += sizeof(instruction);
551                 currAddr += sizeof(instruction);
552                 *++temp = location->isDelayedInsn;
553                 relocateInstruction(temp, fromAddr, currAddr,
554                                     (process *)proc);
555                 
556                 // Then, possibly, there's an callAggregate instruction
557                 // after this. 
558                 if (location->callAggregate) {
559                     currAddr += sizeof(instruction);
560                     *++temp = location->aggregateInsn;
561                     continue;
562                 }       
563             }
564             
565             // If the "FIRST instruction" is a DCTI, then our so called 
566             // "NEXT instruction" is in the delayed Slot and this might
567             // happen. (actullay, it happened)
568             if (location->callAggregate) {
569                 currAddr += sizeof(instruction);
570                 *++temp = location->aggregateInsn;
571                 continue;
572             }   
573             
574             // For the leaf function, if there's an inDelaySlot instruction,
575             // move this one to the base Tramp.(i.e. at the function exit,
576             // if the first instruction is in the delayed slot the previous
577             // instruction, we have to move that one too, so we count from 
578             // that one and the last one is this sequence is called inDelaySlot
579             // instruction.)
580             // Well, after all these, another SAVE instruction is generated
581             // so we are prepared to handle the returning to our application's
582             // code segment. 
583             if (location->leaf) {
584                 if (location->inDelaySlot) {
585                     fromAddr += sizeof(instruction);
586                     currAddr += sizeof(instruction);
587                     *++temp = location->inDelaySlotInsn;
588                     relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
589                     if(location->firstIsConditional){
590                         fromAddr += sizeof(instruction);
591                         currAddr += sizeof(instruction);
592                         *++temp = location->extraInsn;
593                         relocateInstruction(temp, fromAddr, currAddr, proc);
594                     }
595                 } 
596                 
597                 genImmInsn(temp+1, SAVEop3, REG_SP, -112, REG_SP);
598             }
599             
600         } else if (temp->raw == RETURN_INSN) {
601             // compute the real from address if this instrumentation
602             // point is from a shared object image
603             Address baseAddress = 0;
604             if(proc->getBaseAddress(location->image_ptr,baseAddress)){
605             }
606             // Back to the code segement of the application.
607             // If the location is in the leaf procedure, generate an RESTORE
608             // instruction right after the CALL instruction to restore all
609             // the values in the registers.
610             if (location -> leaf) {
611                 generateCallInsn(temp, currAddr, 
612                                 (baseAddress + location->addr)+location->size);
613                 genImmInsn(temp+1, RESTOREop3, 0, 0, 0);
614             } else {
615                 generateCallInsn(temp, currAddr, 
616                                 (baseAddress + location->addr)+location->size);
617             }
618         } else if (temp->raw == SKIP_PRE_INSN) {
619             unsigned offset;
620             offset = baseAddr+baseTemplate.updateCostOffset-currAddr;
621             generateBranchInsn(temp,offset);
622
623         } else if (temp->raw == SKIP_POST_INSN) {
624             unsigned offset;
625             offset = baseAddr+baseTemplate.returnInsOffset-currAddr;
626             generateBranchInsn(temp,offset);
627
628         } else if (temp->raw == UPDATE_COST_INSN) {
629             
630             baseTemplate.costAddr = currAddr;
631             generateNOOP(temp);
632         } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
633                    (temp->raw == GLOBAL_PRE_BRANCH) ||
634                    (temp->raw == LOCAL_POST_BRANCH) ||
635                    (temp->raw == GLOBAL_POST_BRANCH)) {
636 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
637             if ((temp->raw == LOCAL_PRE_BRANCH) ||
638                 (temp->raw == LOCAL_POST_BRANCH)) {
639                 temp -= NUM_INSN_MT_PREAMBLE;
640                 unsigned numIns=0;
641                 generateMTpreamble((char *)temp, numIns, proc);
642                 temp += NUM_INSN_MT_PREAMBLE;
643             }
644 #endif
645             /* fill with no-op */
646             generateNOOP(temp);
647         }
648     }
649     // TODO cast
650     proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size,(caddr_t) code);
651
652     delete [] code;
653
654     trampTemplate *baseInst = new trampTemplate;
655     *baseInst = baseTemplate;
656     baseInst->baseAddr = baseAddr;
657     return baseInst;
658 }
659
660 /*
661  * Install the base Tramp for the function relocated.
662  * (it means the base tramp that don't need to bother with long jump and
663  *  is the one we used before for all the functions(since there's no
664  *  long jumps)
665  *  for system calls
666  */ 
667 trampTemplate *installBaseTrampSpecial(const instPoint *&location,
668                              process *proc,
669                              vector<instruction> &extra_instrs) 
670 {
671     unsigned currAddr;
672     instruction *code;
673     instruction *temp;
674
675     unsigned baseAddr = inferiorMalloc(proc, baseTemplate.size, textHeap);
676
677     if(!(location->func->isInstalled(proc))) {
678         location->func->relocateFunction(proc,location,extra_instrs);
679     }
680     else if(!location->relocated_){
681         // need to find new instPoint for location...it has the pre-relocated
682         // address of the instPoint
683         location->func->modifyInstPoint(location,proc);      
684     }
685
686     code = new instruction[baseTemplate.size];
687     memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
688
689     for (temp = code, currAddr = baseAddr; 
690         (currAddr - baseAddr) < (unsigned) baseTemplate.size;
691         temp++, currAddr += sizeof(instruction)) {
692
693         if (temp->raw == EMULATE_INSN) {
694             if (location->isBranchOut) {
695                 // the original instruction is a branch that goes out of a 
696                 // function.  We don't relocate the original instruction. We 
697                 // only get to the tramp is the branch is taken, so we generate
698                 // a unconditional branch to the target of the original 
699                 // instruction here 
700                 assert(location->branchTarget);
701                 int disp = location->branchTarget - currAddr;
702
703                 generateBranchInsn(temp, disp);
704                 disp = temp->branch.disp22;
705                 continue;
706             }
707             else {
708                 *temp = location->originalInstruction;
709                 Address fromAddress = location->addr;
710                 relocateInstruction(temp, fromAddress, currAddr, proc);
711                 if (location->isDelayed) {
712                     /* copy delay slot instruction into tramp instance */
713                     currAddr += sizeof(instruction);  
714                     *++temp = location->delaySlotInsn;
715                 }
716                 if (location->callAggregate) {
717                     /* copy invalid insn with aggregate size in it */
718                     currAddr += sizeof(instruction);  
719                     *++temp = location->aggregateInsn;
720                 }
721             }
722         } else if (temp->raw == RETURN_INSN) {
723             generateBranchInsn(temp, 
724                 (location->addr+ sizeof(instruction) - currAddr));
725             if (location->isDelayed) {
726                 /* skip the delay slot instruction */
727                 temp->branch.disp22 += 1;
728             }
729             if (location->callAggregate) {
730                 /* skip the aggregate size slot */
731                 temp->branch.disp22 += 1;
732             }
733         } else if (temp->raw == SKIP_PRE_INSN) {
734           unsigned offset;
735           offset = baseAddr+baseTemplate.updateCostOffset-currAddr;
736           generateBranchInsn(temp,offset);
737         } else if (temp->raw == SKIP_POST_INSN) {
738           unsigned offset;
739           offset = baseAddr+baseTemplate.returnInsOffset-currAddr;
740           generateBranchInsn(temp,offset);
741         } else if (temp->raw == UPDATE_COST_INSN) {
742             
743             baseTemplate.costAddr = currAddr;
744             generateNOOP(temp);
745         } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
746                    (temp->raw == GLOBAL_PRE_BRANCH) ||
747                    (temp->raw == LOCAL_POST_BRANCH) ||
748                    (temp->raw == GLOBAL_POST_BRANCH)) {
749 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
750             if ((temp->raw == LOCAL_PRE_BRANCH) ||
751                 (temp->raw == LOCAL_POST_BRANCH)) {
752                 temp -= NUM_INSN_MT_PREAMBLE;
753                 unsigned numIns=0;
754                 generateMTpreamble((char *)temp, numIns, proc);
755                 temp += NUM_INSN_MT_PREAMBLE;
756             }
757 #endif
758             /* fill with no-op */
759             generateNOOP(temp);
760         }
761     }
762     // TODO cast
763     proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size,(caddr_t) code);
764
765     delete [] code;
766
767     trampTemplate *baseInst = new trampTemplate;
768     *baseInst = baseTemplate;
769     baseInst->baseAddr = baseAddr;
770     return baseInst;
771 }
772
773 /*
774  * Allocate the space for the base Trampoline, and generate the instruction
775  * we need for modifying the code segment
776  *
777  */
778 trampTemplate *findAndInstallBaseTramp(process *proc, 
779                                  instPoint *&location,
780                                  returnInstance *&retInstance,
781                                  bool)
782 {
783     Address adr = location->addr;
784     trampTemplate *ret;
785     retInstance = NULL;
786     if (!proc->baseMap.defines((const instPoint *)location)) {
787
788         if (location->func->isTrapFunc()) {
789             // get the base Address of this function if it is a 
790             // shared object
791             Address baseAddress = 0;
792             if(!(proc->getBaseAddress(location->image_ptr,baseAddress))){
793                 // TODO: what should be done here?      
794                 logLine("Error:findAndInstallBaseTramp call getBaseAddress\n"); 
795             }
796             // Install Base Tramp for the functions which are 
797             // relocated to the heap.
798             vector<instruction> extra_instrs;
799
800             ret = installBaseTrampSpecial(location, proc,extra_instrs);
801
802             // add a branch from relocated function to the base tramp
803             // if function was just relocated than location has old address
804             // otherwise location will have address in already relocated func
805             if(!(location->func->isInstalled(proc))){
806                 if (location->isBranchOut){
807                     changeBranch(proc, location->addr, 
808                           (int) ret->baseAddr, location->originalInstruction);
809                 } else {
810                     generateBranch(proc, location->addr, (int)ret->baseAddr);
811                 }
812             }
813             else {  // location's address is correct...it is in the heap
814                 if (location->isBranchOut){
815                     changeBranch(proc, location->addr, 
816                           (int) ret->baseAddr, location->originalInstruction);
817                 } else {
818                     generateBranch(proc, location->addr, (int)ret->baseAddr);
819                 }
820             }
821
822             // If for this process, a call to the relocated function has not
823             // yet be installed in its original location, then genterate the
824             // following instructions at the begining of the function:
825             //   SAVE;             CALL;         RESTORE.
826             // so that it would jump the start of the relocated function
827             // which is in heap.
828             if(!(location->func->isInstalled(proc))){
829                 location->func->setInstalled(proc);
830                 u_int e_size = extra_instrs.size();
831                 instruction *insn = new instruction[3 + e_size];
832                 Address adr = location-> func -> getAddress(0);
833                 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
834                 generateCallInsn(insn+1, adr+baseAddress+4, 
835                                  location->func->getAddress(proc));
836                 genSimpleInsn(insn+2, RESTOREop3, 0, 0, 0); 
837                 for(u_int i=0; i < e_size; i++){
838                     insn[3+i] = extra_instrs[i];
839                 }
840                 retInstance = new returnInstance((instructUnion *)insn, 
841                                          (3+e_size)*sizeof(instruction), 
842                                          adr+baseAddress, 
843                                          location->func->size());
844                 assert(retInstance);
845
846                 //cerr << "created a new return instance (relocated fn)!" << endl;
847             }
848
849         } else {
850
851             // compute the real from address if this instrumentation
852             // point is from a shared object image
853             Address baseAddress = 0;
854             if(proc->getBaseAddress(location->image_ptr,baseAddress)){
855                 adr += baseAddress;             
856             }
857
858             // Install base tramp for all the other regular functions. 
859             ret = installBaseTramp(location, proc);
860             // check to see if this is an entry point and if the delay 
861             // slot instruction is a call insn, if so, then if the 
862             // call is to a location within the function we need to 
863             // add an extra instruction after the restore to correctly
864             // set the o7 register
865             bool need_to_add = false;
866             if((location->ipType==functionEntry) 
867                     &&(isInsnType(location->delaySlotInsn,CALLmask,CALLmatch))){
868                  Address call_offset = location->addr + 8 + 
869                                        (location->delaySlotInsn.call.disp30<<2);
870                  Address fun_addr = location->func->getAddress(0);
871                  u_int fun_size = location->func->size();
872                  if((call_offset>fun_addr)&&(call_offset<(fun_addr+fun_size))){
873                      assert(location->isLongJump);
874                      need_to_add = true;
875                 }
876             }   
877
878             if (location->leaf) {
879                 // if it is the leaf function, we need to generate
880                 // the following instruction sequence:
881                 //     SAVE;      CALL;      NOP.
882
883                 if (location -> isLongJump == false) {
884                     instruction *insn = new instruction;
885                     generateBranchInsn(insn, (int)(ret->baseAddr-location->addr));
886                     retInstance = new returnInstance((instructUnion *)insn,
887                                                      sizeof(instruction), adr, 
888                                                      sizeof(instruction));
889                 } else if(need_to_add) {
890                     // generate  origninal; call; add $o7 imm4 
891                     instruction *insn = new instruction[2];
892                     generateCallInsn(insn, adr+4, (int) ret->baseAddr);
893                     genImmInsn(insn+1,ADDop3,REG_O7,4,REG_O7);
894                     retInstance = new returnInstance((instructUnion *)insn,
895                                  2*sizeof(instruction), adr+4,
896                                  2*sizeof(instruction));
897
898                 } else {
899                     instruction *insn = new instruction[3];
900                     genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
901                     generateCallInsn(insn+1, adr+4, (int) ret->baseAddr);
902                     generateNOOP(insn+2);
903                     retInstance = new returnInstance((instructUnion *)insn, 
904                                                      3*sizeof(instruction), adr, 
905                                                      3*sizeof(instruction));
906                     
907                 }
908                 
909                 assert(retInstance);
910
911                 //cerr << "created a new return instance (leaf)!" << endl;
912             } else {
913                 // Otherwise,
914                 // Generate branch instruction from the application to the
915                 // base trampoline and no SAVE instruction is needed
916
917                 
918                 if (in1BranchInsnRange(adr, ret->baseAddr)) {
919                     // make sure that the isLongJump won't be true
920                     // which only is possible for shlib entry point 
921                     assert(location->isLongJump == false);
922                     instruction *insn = new instruction;
923                     if (location -> ipType == functionEntry) {
924                         generateBranchInsn(insn, (int)(ret->baseAddr 
925                                         - location->addr+sizeof(instruction))); 
926                         retInstance = new returnInstance((instructUnion *)insn,
927                                                          sizeof(instruction), 
928                                                          adr - sizeof(instruction), 
929                                                          sizeof(instruction));
930                     } else {
931                         generateBranchInsn(insn, (int)(ret->baseAddr-location->addr));
932                         retInstance = new returnInstance((instructUnion *)insn,
933                                                          sizeof(instruction), 
934                                                          adr, 
935                                                          sizeof(instruction));
936                     }
937  
938                 } else if(need_to_add) {
939                   // the delay slot instruction is is a call to a location
940                   // within the same function, then need to generate 3 instrs
941                   //    call
942                   //    nop          // delay slot (originally call insn)
943                   //    add o7 imm4  // sets o7 register to correct value
944                   instruction *insn = new instruction[3];       
945                   generateCallInsn(insn, adr, (int) ret->baseAddr);
946                   generateNOOP(insn+1);
947                   genImmInsn(insn+2,ADDop3,REG_O7,4,REG_O7);
948                   retInstance = new returnInstance((instructUnion *)insn, 
949                                              3*sizeof(instruction), adr, 
950                                              3*sizeof(instruction));
951                 } else {
952                     instruction *insn = new instruction[2];     
953                     generateCallInsn(insn, adr, (int) ret->baseAddr);
954                     if (location -> ipType == functionEntry) {
955                         if (location -> isLongJump)
956                             generateNOOP(insn+1);
957                         else
958                             genSimpleInsn(insn+1, RESTOREop3, 0, 0, 0);
959                     } else
960                         generateNOOP(insn+1);
961                     retInstance = new returnInstance((instructUnion *)insn, 
962                                                      2*sizeof(instruction), adr, 
963                                                      2*sizeof(instruction));
964                     assert(retInstance);
965                     
966                     //cerr << "created a new return instance (normal)!" << endl;
967                 }
968             }
969         }
970
971         proc->baseMap[(const instPoint *)location] = ret;
972         
973     } else {
974         ret = proc->baseMap[(const instPoint *)location];
975     }
976     
977     return(ret);
978 }
979
980 /*
981  * Install a single tramp.
982  *
983  */
984 void installTramp(instInstance *inst, char *code, int codeSize) 
985 {
986     totalMiniTramps++;
987     insnGenerated += codeSize/sizeof(int);
988     
989     // TODO cast
990     (inst->proc)->writeDataSpace((caddr_t)inst->trampBase, codeSize, code);
991
992     unsigned atAddr;
993     if (inst->when == callPreInsn) {
994         if (inst->baseInstance->prevInstru == false) {
995             atAddr = inst->baseInstance->baseAddr+baseTemplate.skipPreInsOffset;
996             inst->baseInstance->cost += inst->baseInstance->prevBaseCost;
997             inst->baseInstance->prevInstru = true;
998             generateNoOp(inst->proc, atAddr);
999         }
1000     } else {
1001         if (inst->baseInstance->postInstru == false) {
1002             atAddr = inst->baseInstance->baseAddr+baseTemplate.skipPostInsOffset; 
1003             inst->baseInstance->cost += inst->baseInstance->postBaseCost;
1004             inst->baseInstance->postInstru = true;
1005             generateNoOp(inst->proc, atAddr);
1006         }
1007     }
1008 }
1009
1010
1011 unsigned emitFuncCall(opCode op, 
1012                       registerSpace *rs,
1013                       char *i, unsigned &base, 
1014                       const vector<AstNode *> &operands, 
1015                       const string &callee, process *proc,
1016                       bool noCost)
1017 {
1018         assert(op == callOp);
1019         unsigned addr;
1020         bool err;
1021         vector <reg> srcs;
1022         void cleanUpAndExit(int status);
1023
1024         addr = proc->findInternalAddress(callee, false, err);
1025
1026         if (err) {
1027             function_base *func = proc->findOneFunction(callee);
1028             if (!func) {
1029                 ostrstream os(errorLine, 1024, ios::out);
1030                 os << "Internal error: unable to find addr of " << callee << endl;
1031                 logLine(errorLine);
1032                 showErrorCallback(80, (const char *) errorLine);
1033                 P_abort();
1034             }
1035             // TODO: is this correct or should we get relocated address?
1036             addr = func->getAddress(0);
1037         }
1038         
1039         for (unsigned u = 0; u < operands.size(); u++)
1040             srcs += operands[u]->generateCode(proc, rs, i, base, noCost);
1041
1042         // TODO cast
1043         instruction *insn = (instruction *) ((void*)&i[base]);
1044
1045         for (unsigned u=0; u<srcs.size(); u++){
1046             if (u >= 5) {
1047                  string msg = "Too many arguments to function call in instrumentation code: only 5 arguments can be passed on the sparc architecture.\n";
1048                  fprintf(stderr, msg.string_of());
1049                  showErrorCallback(94,msg);
1050                  cleanUpAndExit(-1);
1051             }
1052             genSimpleInsn(insn, ORop3, 0, srcs[u], u+8); insn++;
1053             base += sizeof(instruction);
1054             rs->freeRegister(srcs[u]);
1055         }
1056
1057         // As Ling pointed out to me, the following is rather inefficient.  It does:
1058         //   sethi %hi(addr), %o5
1059         //   jmpl %o5 + %lo(addr), %o7   ('call' pseudo-instr)
1060         //   nop
1061         // We can do better:
1062         //   call <addr>    (but note that the call true-instr is pc-relative jump)
1063         //   nop
1064         generateSetHi(insn, addr, 13); insn++;
1065         genImmInsn(insn, JMPLop3, 13, LOW10(addr), 15); insn++;
1066         generateNOOP(insn);
1067
1068         base += 3 * sizeof(instruction);
1069
1070         // return value is the register with the return value from the
1071         //   function.
1072         // This needs to be %o0 since it is back in the callers scope.
1073         return(8);
1074 }
1075  
1076 unsigned emit(opCode op, reg src1, reg src2, reg dest, char *i, unsigned &base,
1077               bool noCost)
1078 {
1079     // TODO cast
1080     instruction *insn = (instruction *) ((void*)&i[base]);
1081
1082     if (op == loadConstOp) {
1083       // dest = src1:imm    TODO
1084       if (src1 > MAX_IMM13 || src1 < MIN_IMM13) {
1085             // src1 is out of range of imm13, so we need an extra instruction
1086             generateSetHi(insn, src1, dest);
1087             base += sizeof(instruction);
1088             insn++;
1089
1090             // or regd,imm,regd
1091
1092             // Chance for optimization: we should check for LOW10(src1)==0, and
1093             // if so, don't generate the following bitwise-or instruction, since
1094             // in that case nothing would be done.
1095
1096             genImmInsn(insn, ORop3, dest, LOW10(src1), dest);
1097             base += sizeof(instruction);
1098         } else {
1099             // really or %g0,imm,regd
1100             genImmInsn(insn, ORop3, 0, src1, dest);
1101
1102             base += sizeof(instruction);
1103         }
1104     } else if (op ==  loadOp) {
1105         // dest = [src1]   TODO
1106         generateSetHi(insn, src1, dest);
1107         insn++;
1108
1109         generateLoad(insn, dest, LOW10(src1), dest);
1110
1111         base += sizeof(instruction)*2;
1112     } else if (op ==  loadIndirOp) {
1113         generateLoad(insn, src1, 0, dest);
1114         base += sizeof(instruction);
1115     } else if (op ==  storeOp) {
1116         insn->sethi.op = FMT2op;
1117         insn->sethi.rd = src2;
1118         insn->sethi.op2 = SETHIop2;
1119         insn->sethi.imm22 = HIGH22(dest);
1120         insn++;
1121
1122         generateStore(insn, src1, src2, LOW10(dest));
1123
1124         base += sizeof(instruction)*2;
1125     } else if (op ==  storeIndirOp) {
1126         generateStore(insn, src1, dest, 0);
1127         base += sizeof(instruction);
1128     } else if (op ==  ifOp) {
1129         // cmp src1,0
1130         genSimpleInsn(insn, SUBop3cc, src1, 0, 0); insn++;
1131
1132         insn->branch.op = 0;
1133         insn->branch.cond = BEcond;
1134         insn->branch.op2 = BICCop2;
1135         insn->branch.anneal = false;
1136         insn->branch.disp22 = dest/4;
1137         insn++;
1138
1139         generateNOOP(insn);
1140         base += sizeof(instruction)*3;
1141         return(base - 2*sizeof(instruction));
1142     } else if (op ==  updateCostOp) {
1143         // generate code to update the observed cost.
1144         if (!noCost) {
1145            // sethi %hi(dest), %l0
1146            generateSetHi(insn, dest, REG_L0);
1147            base += sizeof(instruction);
1148            insn++;
1149   
1150            // ld [%l0+ lo(dest)], %l1
1151            generateLoad(insn, REG_L0, LOW10(dest), REG_L1);
1152            base += sizeof(instruction);
1153            insn++;
1154   
1155            // update value (src1 holds the cost, in cycles; e.g. 19)
1156            if (src1 <= MAX_IMM13) {
1157               genImmInsn(insn, ADDop3, REG_L1, src1, REG_L1);
1158               base += sizeof(instruction);
1159               insn++;
1160
1161               generateNOOP(insn);
1162               base += sizeof(instruction);
1163               insn++;
1164
1165               generateNOOP(insn);
1166               base += sizeof(instruction);
1167               insn++;
1168            } else {
1169               // load in two parts
1170               generateSetHi(insn, src1, REG_L2);
1171               base += sizeof(instruction);
1172               insn++;
1173
1174               // or regd,imm,regd
1175               genImmInsn(insn, ORop3, REG_L2, LOW10(src1), REG_L2);
1176               base += sizeof(instruction);
1177               insn++;
1178
1179               // now add it
1180               genSimpleInsn(insn, ADDop3, REG_L1, REG_L2, REG_L1);
1181               base += sizeof(instruction);
1182               insn++;
1183            }
1184   
1185            // store result st %l1, [%l0+ lo(dest)];
1186            generateStore(insn, REG_L1, REG_L0, LOW10(dest));
1187            base += sizeof(instruction);
1188            insn++;
1189         } // if (!noCost)
1190     } else if (op ==  trampPreamble) {
1191 #ifdef ndef
1192         // save and restore are done inthe base tramp now
1193         genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1194         base += sizeof(instruction);
1195         insn++;
1196
1197         // generate code to save global registers
1198         for (unsigned u = 0; u < 4; u++) {
1199           genStoreD(insn, 2*u, REG_FP, - (8 + 8*u));
1200           base += sizeof(instruction);
1201           insn++;
1202         }
1203 #endif
1204     } else if (op ==  trampTrailer) {
1205 #ifdef ndef
1206         // save and restore are done inthe base tramp now
1207         // generate code to restore global registers
1208         for (unsigned u = 0; u < 4; u++) {
1209           genLoadD(insn, REG_FP, - (8 + 8*u), 2*u);
1210           base += sizeof(instruction);
1211           insn++;
1212         }
1213
1214         // sequence: restore; nop; b,a back to base tramp; nop
1215         // we can do better.  How about putting the restore in
1216         // the delay slot of the branch instruction, as in:
1217         // b <back to base tramp>; restore
1218         genSimpleInsn(insn, RESTOREop3, 0, 0, 0); 
1219         base += sizeof(instruction);
1220         insn++;
1221
1222         generateNOOP(insn);
1223         base += sizeof(instruction);
1224         insn++;
1225 #endif
1226         // dest is in words of offset and generateBranchInsn is bytes offset
1227         generateBranchInsn(insn, dest << 2);
1228         base += sizeof(instruction);
1229         insn++;
1230
1231         // add no-op, SS-5 sometimes seems to try to decode this insn - jkh 2/14
1232         generateNOOP(insn);
1233         insn++;
1234         base += sizeof(instruction);
1235
1236         return(base -  2 * sizeof(instruction));
1237     } else if (op == noOp) {
1238         generateNOOP(insn);
1239         base += sizeof(instruction);
1240     } else if (op == getParamOp) {
1241 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1242         // saving CT/vector address on the stack
1243         generateStore(insn, REG_MT, REG_FP, -40);
1244         insn++;
1245 #endif
1246         // first 8 parameters are in register 24 ....
1247         genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1248         insn++;
1249
1250         generateStore(insn, 24+src1, REG_SP, 68+4*src1); 
1251         insn++;
1252               
1253         genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1254         insn++;
1255
1256         generateLoad(insn, REG_SP, 112+68+4*src1, 24+src1); 
1257         insn++;
1258
1259 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1260         // restoring CT/vector address back in REG_MT
1261         generateLoad(insn, REG_FP, -40, REG_MT);
1262         insn++;
1263         base += 6*sizeof(instruction);
1264 #else
1265         base += 4*sizeof(instruction);
1266 #endif
1267         
1268         if (src1 <= 8) {
1269             return(24+src1);
1270         }
1271         
1272         abort();
1273     } else if (op == getSysParamOp) {
1274         
1275         if (src1 <= 8) {
1276             return(24+src1);
1277         }       
1278     } else if (op == getRetValOp) {
1279         // return value is in register 24
1280         genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1281         insn++;
1282
1283         generateStore(insn, 24, REG_SP, 68); 
1284         insn++;
1285               
1286         genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1287         insn++;
1288
1289         generateLoad(insn, REG_SP, 112+68, 24); 
1290         insn++;
1291
1292         base += 4*sizeof(instruction);
1293
1294         return(24);
1295
1296     } else if (op == getSysRetValOp) {
1297
1298         return(24);
1299     } else if (op == saveRegOp) {
1300         // should never be called for this platform.
1301         abort();
1302     } else {
1303       int op3=-1;
1304         switch (op) {
1305             // integer ops
1306             case plusOp:
1307                 op3 = ADDop3;
1308                 break;
1309
1310             case minusOp:
1311                 op3 = SUBop3;
1312                 break;
1313
1314             case timesOp:
1315                 op3 = SMULop3;
1316                 break;
1317
1318             case divOp:
1319                 op3 = SDIVop3;
1320                 break;
1321
1322             // Bool ops
1323             case orOp:
1324                 op3 = ORop3;
1325                 break;
1326
1327             case andOp:
1328                 op3 = ANDop3;
1329                 break;
1330
1331             // rel ops
1332             // For a particular condition (e.g. <=) we need to use the
1333             // the opposite in order to get the right value (e.g. for >=
1334             // we need BLTcond) - naim
1335             case eqOp:
1336                 genRelOp(insn, BNEcond, src1, src2, dest, base);
1337                 return(0);
1338                 break;
1339
1340             case neOp:
1341                 genRelOp(insn, BEcond, src1, src2, dest, base);
1342                 return(0);
1343                 break;
1344
1345             case lessOp:
1346                 genRelOp(insn, BGEcond, src1, src2, dest, base);
1347                 return(0);
1348                 break;
1349
1350             case leOp:
1351                 genRelOp(insn, BGTcond, src1, src2, dest, base);
1352                 return(0);
1353                 break;
1354
1355             case greaterOp:
1356                 genRelOp(insn, BLEcond, src1, src2, dest, base);
1357                 return(0);
1358                 break;
1359
1360             case geOp:
1361                 genRelOp(insn, BLTcond, src1, src2, dest, base);
1362                 return(0);
1363                 break;
1364
1365             default:
1366                 abort();
1367                 break;
1368         }
1369         genSimpleInsn(insn, op3, src1, src2, dest);
1370
1371         base += sizeof(instruction);
1372       }
1373     return(0);
1374 }
1375
1376 /*
1377  * Find the instPoints of this function.
1378  */
1379 bool pd_Function::findInstPoints(const image *owner) {
1380
1381    if (size() == 0) {
1382      return false;
1383    }
1384
1385    leaf = true;
1386    Address adr;
1387    Address adr1 = getAddress(0);
1388    instruction instr;
1389    instr.raw = owner->get_instruction(adr1);
1390    if (!IS_VALID_INSN(instr))
1391      return false;
1392
1393    // If it contains an instruction, I assume it would be s system call
1394    // which will be treat differently. 
1395    isTrap = false;
1396    bool func_entry_found = false;
1397
1398    for ( ; adr1 < getAddress(0) + size(); adr1 += 4) {
1399        instr.raw = owner->get_instruction(adr1);
1400
1401        // If there's an TRAP instruction in the function, we 
1402        // assume that it is an system call and will relocate it 
1403        // to the heap
1404        if (isInsnType(instr, TRAPmask, TRAPmatch)) {
1405            isTrap = true;
1406            return findInstPoints(owner, getAddress(0), 0);
1407        } 
1408
1409        // TODO: This is a hacking for the solaris(solaris2.5 actually)
1410        // We will relocate that function if the function has been 
1411        // tail-call optimazed.
1412        // (Actully, the reason of this is that the system calls like 
1413        //  read, write, etc have the tail-call optimazation to call
1414        //  the _read, _write etc. which contain the TRAP instruction 
1415        //  This is only done if libc is statically linked...if the
1416        //  libTag is set, otherwise we instrument read and _read
1417        //  both for the dynamically linked case
1418        if (isLibTag()) {
1419            if (isCallInsn(instr)) {
1420                instruction nexti; 
1421                nexti.raw = owner->get_instruction(adr1+4);
1422                
1423                if (nexti.rest.op == 2 
1424                    && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1425                        || nexti.rest.op3 == RESTOREop3)) {
1426                    isTrap = true;
1427                    return findInstPoints(owner, getAddress(0), 0);
1428                }
1429            }   
1430        }
1431
1432        // The function Entry is defined as the first SAVE instruction plus
1433        // the instructions after this.
1434        // ( The first instruction for the nonleaf function is not 
1435        //   necessarily a SAVE instruction. ) 
1436        if (isInsnType(instr, SAVEmask, SAVEmatch) && !func_entry_found) {
1437
1438            leaf = false;
1439            func_entry_found = true;
1440            funcEntry_ = new instPoint(this, instr, owner, adr1, true, leaf, 
1441                                       functionEntry);
1442            adr = adr1;
1443            assert(funcEntry_);
1444        }
1445    }
1446
1447    // If there's no SAVE instruction found, this is a leaf function and
1448    // and function Entry will be defined from the first instruction
1449    if (leaf) {
1450        adr = getAddress(0);
1451        instr.raw = owner->get_instruction(adr);
1452        funcEntry_ = new instPoint(this, instr, owner, adr, true, leaf, functionEntry);
1453        assert(funcEntry_);
1454    }
1455
1456    for ( ; adr < getAddress(0) + size(); adr += sizeof(instruction)) {
1457
1458      instr.raw = owner->get_instruction(adr);
1459
1460      bool done;
1461
1462      // check for return insn and as a side affect decide if we are at the
1463      //   end of the function.
1464      if (isReturnInsn(owner, adr, done)) {
1465        // define the return point
1466        funcReturns += new instPoint(this, instr, owner, adr, false, leaf, 
1467                                     functionExit);
1468
1469      } else if (instr.branch.op == 0 
1470                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6) 
1471                 && (instr.branch.cond == 0 ||instr.branch.cond == 8)) {
1472        // find if this branch is going out of the function
1473        int disp = instr.branch.disp22;
1474        Address target = adr +  (disp << 2);
1475        if ((target < (getAddress(0)))  
1476            || (target >= (getAddress(0) + size()))) {
1477          instPoint *point = new instPoint(this, instr, owner, adr, false, leaf, 
1478                                           functionExit);
1479          funcReturns += point;
1480        }
1481
1482      } else if (isCallInsn(instr)) {
1483
1484        // if the call target is the address of the call instruction
1485        // then this is not something that we can instrument...
1486        // this occurs in functions with code that is modifined when 
1487        // they are loaded by the run-time linker, or when the .init
1488        // section is executed.  In this case the instructions in the
1489        // parsed image file are different from the ones in the executable
1490        // process.
1491        if(instr.call.op == CALLop) { 
1492            Address call_target = adr + (instr.call.disp30 << 2);
1493            if(call_target == adr){ 
1494                 return false;
1495        }}
1496        // first, check for tail-call optimization: a call where the instruction 
1497        // in the delay slot write to register %o7(15), usually just moving
1498        // the caller's return address, or doing a restore
1499        // Tail calls are instrumented as return points, not call points.
1500
1501
1502        instruction nexti; 
1503        nexti.raw = owner->get_instruction(adr+4);
1504
1505        if (nexti.rest.op == 2 
1506            && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1507               || nexti.rest.op3 == RESTOREop3)) {
1508          //fprintf(stderr, "#### Tail-call optimization in function %s, addr %x\n",
1509          //     prettyName().string_of(), adr);
1510          funcReturns += new instPoint(this, instr, owner, adr, false, leaf, 
1511                                       functionExit);
1512
1513        } else {
1514          // define a call point
1515          // this may update address - sparc - aggregate return value
1516          // want to skip instructions
1517          bool err;
1518          int dummyId;
1519          instPoint *blah = 0;
1520          adr = newCallPoint(adr, instr, owner, err, dummyId, adr,0,blah);
1521        }
1522      }
1523
1524      else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
1525        /* A register indirect jump. Some jumps may exit the function 
1526           (e.g. read/write on SunOS). In general, the only way to 
1527           know if a jump is exiting the function is to instrument
1528           the jump to test if the target is outside the current 
1529           function. Instead of doing this, we just check the 
1530           previous two instructions, to see if they are loading
1531           an address that is out of the current function.
1532           This should catch the most common cases (e.g. read/write).
1533           For other cases, we would miss a return point.
1534
1535           This is the case considered:
1536
1537              sethi addr_hi, r
1538              or addr_lo, r, r
1539              jump r
1540         */
1541
1542        reg jumpreg = instr.rest.rs1;
1543        instruction prev1;
1544        instruction prev2;
1545
1546        prev1.raw = owner->get_instruction(adr-4);
1547        prev2.raw = owner->get_instruction(adr-8);
1548
1549        unsigned targetAddr;
1550
1551        if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
1552            && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2 
1553            && prev2.sethi.rd == (unsigned)jumpreg
1554            && prev1.rest.op == RESTop 
1555            && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
1556            && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg) {
1557
1558          targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
1559          targetAddr |= prev1.resti.simm13;
1560          if ((targetAddr<getAddress(0))||(targetAddr>=(getAddress(0)+size()))){
1561            instPoint *point = new instPoint(this, instr, owner, adr, false, 
1562                                             leaf, functionExit);
1563            funcReturns += point;
1564          }
1565        }
1566
1567      }
1568  }
1569
1570  return (checkInstPoints(owner)); 
1571 }
1572
1573 /*
1574  * Check all the instPoints within this function to see if there's 
1575  * any conficts happen.
1576  */
1577 bool pd_Function::checkInstPoints(const image *owner) {
1578
1579     // Our own library function, skip the test.
1580     if (prettyName().prefixed_by("DYNINST")) 
1581         return true;
1582
1583 #ifndef BPATCH_LIBRARY /* XXX Users of libdyninstAPI might not agree. */
1584     // The function is too small to be worthing instrumenting.
1585     if (size() <= 12){
1586         return false;
1587     }
1588 #endif
1589
1590     // No function return! return false;
1591     if (sizeof(funcReturns) == 0) {
1592         return false;
1593     }
1594
1595     instruction instr;
1596     Address adr = getAddress(0);
1597
1598     bool retl_inst = false;
1599     // Check if there's any branch instruction jump to the middle
1600     // of the instruction sequence in the function entry point
1601     // and function exit point.
1602     for ( ; adr < getAddress(0) + size(); adr += sizeof(instruction)) {
1603
1604         instr.raw = owner->get_instruction(adr);
1605         if(isInsnType(instr, RETLmask, RETLmatch)) retl_inst = true;
1606
1607         if (isInsnType(instr, BRNCHmask, BRNCHmatch)||
1608             isInsnType(instr, FBRNCHmask, FBRNCHmatch)) {
1609
1610             int disp = instr.branch.disp22;
1611             Address target = adr + (disp << 2);
1612
1613             if ((target > funcEntry_->addr)&&
1614                 (target < (funcEntry_->addr + funcEntry_->size))) {
1615                 if (adr > (funcEntry_->addr+funcEntry_->size)){
1616                     //cout << "Function " << prettyName().string_of() <<" entry" << endl;
1617                     return false;
1618             } }
1619
1620             for (u_int i = 0; i < funcReturns.size(); i++) {
1621                 if ((target > funcReturns[i]->addr)&&
1622                     (target < (funcReturns[i]->addr + funcReturns[i]->size))) {
1623                     if ((adr < funcReturns[i]->addr)||
1624                         (adr > (funcReturns[i]->addr + funcReturns[i]->size))){
1625                         return false;
1626                 } }
1627             }
1628         }
1629     }
1630
1631     // if there is a retl instruction and we don't think this is a leaf
1632     // function then this is a way messed up function...well, at least we
1633     // we can't deal with this...the only example I can find is _cerror
1634     // and _cerror64 in libc.so.1
1635     if(retl_inst && !leaf){
1636          return false;
1637     }
1638
1639     // check that no instrumentation points could overlap
1640     Address func_entry = funcEntry_->addr + funcEntry_->size; 
1641     for (u_int i = 0; i < funcReturns.size(); i++) {
1642         if(func_entry >= funcReturns[i]->addr){
1643            return false;
1644         }
1645         if(i >= 1){ // check if return points overlap
1646             Address prev_exit = funcReturns[i-1]->addr+funcReturns[i-1]->size;  
1647             if(funcReturns[i]->addr < prev_exit) {
1648                 return false;
1649             } 
1650         }
1651     }
1652
1653     return true;        
1654 }
1655
1656
1657 /* The maximum length of relocatable function is 1k instructions */  
1658 // This function is to find the inst Points for a function
1659 // that will be relocated if it is instrumented. 
1660 bool pd_Function::findInstPoints(const image *owner, Address newAdr, process*){
1661
1662    int i;
1663    if (size() == 0) {
1664      return false;
1665    }
1666    relocatable_ = true;
1667
1668    Address adr = getAddress(0);
1669    instruction instr;
1670    instr.raw = owner->get_instruction(adr);
1671    if (!IS_VALID_INSN(instr))
1672      return false;
1673    
1674    if (size() <= 3*sizeof(instruction)) 
1675        return false;
1676
1677    instPoint *point = new instPoint(this, instr, owner, newAdr, true, 
1678                                     functionEntry, adr);
1679
1680    funcEntry_ = point;
1681
1682    // if the second instruction in a relocated function is a call instruction
1683    // or a branch instruction, then we can't deal with this 
1684    if(size() > sizeof(instruction)){
1685        Address second_adr = adr + sizeof(instruction);
1686        instruction second_instr;
1687        second_instr.raw =  owner->get_instruction(second_adr); 
1688        if ((isCallInsn(second_instr)) || 
1689                       (second_instr.branch.op == 0 && 
1690                       (second_instr.branch.op2 == 2 || 
1691                       second_instr.branch.op2 == 6))) {
1692            return false;
1693        }
1694    }
1695    
1696    assert(funcEntry_);
1697    int retId = 0;
1698    int callsId = 0; 
1699
1700    for (i = 0; adr < getAddress(0) + size(); adr += sizeof(instruction),  
1701         newAdr += sizeof(instruction), i++) {
1702
1703      instr.raw = owner->get_instruction(adr);
1704      newInstr[i] = instr;
1705      bool done;
1706
1707      // check for return insn and as a side affect decide if we are at the
1708      //   end of the function.
1709      if (isReturnInsn(owner, adr, done)) {
1710        // define the return point
1711        instPoint *point = new instPoint(this, instr, owner, newAdr, false, 
1712                                         functionExit, adr);
1713        funcReturns += point;
1714        funcReturns[retId] -> instId = retId++;
1715      } else if (instr.branch.op == 0 
1716                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) {
1717        // find if this branch is going out of the function
1718        int disp = instr.branch.disp22;
1719        Address target = adr + (disp << 2);
1720        if (target < getAddress(0) || target >= getAddress(0) + size()) {
1721            instPoint *point = new instPoint(this, newInstr[i], owner, 
1722                                             newAdr, false, 
1723                                             functionExit, adr);
1724            if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {  
1725                point->isBranchOut = true;
1726                point->branchTarget = target;
1727            }
1728            funcReturns += point;
1729            funcReturns[retId] -> instId = retId++;
1730        }
1731
1732      } else if (isCallInsn(instr)) {
1733
1734        // first, check for tail-call optimization: a call where the instruction 
1735        // in the delay slot write to register %o7(15), usually just moving
1736        // the caller's return address, or doing a restore
1737        // Tail calls are instrumented as return points, not call points.
1738        instruction nexti; 
1739        nexti.raw = owner->get_instruction(adr+4);
1740
1741        if (nexti.rest.op == 2 
1742            && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1743               || nexti.rest.op3 == RESTOREop3)) {
1744
1745            instPoint *point = new instPoint(this, instr, owner, newAdr, false,
1746                                       functionExit, adr);
1747            funcReturns += point;
1748            funcReturns[retId] -> instId = retId++;
1749
1750        } else {
1751          // if this is a call instr to a location within the function, and if 
1752          // the offest is not 8 then do not define this function 
1753          if(instr.call.op == CALLop){ 
1754            Address call_target = adr + (instr.call.disp30 << 2);
1755            if((call_target >= getAddress(0)) 
1756               && (call_target <= (getAddress(0)+size()))){ 
1757               if((instr.call.disp30 << 2) != 2*sizeof(instruction)) {
1758                 return false;
1759               }
1760            }
1761          }
1762          // define a call point
1763          // this may update address - sparc - aggregate return value
1764          // want to skip instructions
1765          bool err;
1766          instPoint *blah = 0;
1767          adr = newCallPoint(newAdr, instr, owner, err, callsId, adr,0,blah);
1768          if (err)
1769            return false;
1770        }
1771      }
1772
1773      else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
1774        /* A register indirect jump. Some jumps may exit the function 
1775           (e.g. read/write on SunOS). In general, the only way to 
1776           know if a jump is exiting the function is to instrument
1777           the jump to test if the target is outside the current 
1778           function. Instead of doing this, we just check the 
1779           previous two instructions, to see if they are loading
1780           an address that is out of the current function.
1781           This should catch the most common cases (e.g. read/write).
1782           For other cases, we would miss a return point.
1783
1784           This is the case considered:
1785
1786              sethi addr_hi, r
1787              or addr_lo, r, r
1788              jump r
1789         */
1790
1791          reg jumpreg = instr.rest.rs1;
1792          instruction prev1;
1793          instruction prev2;
1794          
1795          prev1.raw = owner->get_instruction(adr-4);
1796          prev2.raw = owner->get_instruction(adr-8);
1797
1798          unsigned targetAddr;
1799
1800          if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
1801              && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2 
1802              && prev2.sethi.rd == (unsigned)jumpreg
1803              && prev1.rest.op == RESTop 
1804              && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
1805              && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg){
1806              
1807              targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
1808              targetAddr |= prev1.resti.simm13;
1809              if ((targetAddr < getAddress(0)) 
1810                  || (targetAddr >= (getAddress(0)+size()))) {
1811                  instPoint *point = new instPoint(this, instr, owner, 
1812                                                   newAdr, false,
1813                                                   functionExit, adr);
1814                  funcReturns += point;
1815                  funcReturns[retId] -> instId = retId++;
1816              }
1817          }
1818      }
1819  }
1820  return true;
1821 }
1822
1823 // This function assigns new address to instrumentation points of  
1824 // a function that has been relocated
1825 bool pd_Function::findNewInstPoints(const image *owner, 
1826                                 const instPoint *&location,
1827                                 Address newAdr,
1828                                 process *proc,
1829                                 vector<instruction> &callInstrs,
1830                                 relocatedFuncInfo *reloc_info) {
1831
1832    int i;
1833    if (size() == 0) {
1834      return false;
1835    }
1836    assert(reloc_info);
1837
1838    Address adr = getAddress(0);
1839    instruction instr;
1840    instr.raw = owner->get_instruction(adr);
1841    if (!IS_VALID_INSN(instr))
1842      return false;
1843
1844    instPoint *point = new instPoint(this, instr, owner, newAdr, true, 
1845                                     functionEntry, adr);
1846    point->relocated_ = true;
1847    // if location was the entry point then change location's value to new pt
1848    if(location == funcEntry_) { 
1849         location = point;
1850    }
1851
1852    reloc_info->addFuncEntry(point);
1853    assert(reloc_info->funcEntry());
1854    int retId = 0;
1855    int callsId = 0; 
1856
1857    // get baseAddress if this is a shared object
1858    Address baseAddress = 0;
1859    if(!(proc->getBaseAddress(owner,baseAddress))){
1860         baseAddress =0;
1861    }
1862
1863    // if we have call instructions that need to be added after the instrs
1864    // to call the relocated instruction, the first address we can use is
1865    // the address of the 4th instruction in the function
1866    Address call_start_addr = getAddress(0)+baseAddress + 3*sizeof(instruction);
1867
1868    for (i = 0; adr < getAddress(0) + size(); adr += 4,  newAdr += 4, i++) {
1869     
1870      instr.raw = owner->get_instruction(adr);
1871      newInstr[i] = instr;
1872
1873      bool done;
1874
1875      // check for return insn and as a side affect decide if we are at the
1876      //   end of the function.
1877      if (isReturnInsn(owner, adr, done)) {
1878        // define the return point
1879        instPoint *point = new instPoint(this, instr, owner, newAdr, false, 
1880                                         functionExit, adr);
1881        point->relocated_ = true;
1882        // if location was this point, change it to new point
1883        if(location == funcReturns[retId]) { 
1884            location = point;
1885        }
1886        retId++;
1887        reloc_info->addFuncReturn(point);
1888      } else if (instr.branch.op == 0 
1889                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) {
1890        // find if this branch is going out of the function
1891        int disp = instr.branch.disp22;
1892        Address target = adr + baseAddress + (disp << 2);
1893
1894        // getAddress(0) gives the addr of the fn before it's relocated
1895        if ((target < (getAddress(0) + baseAddress)) 
1896            || (target >= (getAddress(0) + baseAddress + size()))) {
1897            // the original branch went out of the function...
1898
1899            relocateInstruction(&newInstr[i],adr+baseAddress,newAdr,proc);
1900            instPoint *point = new instPoint(this, newInstr[i], owner, 
1901                                             newAdr, false, 
1902                                             functionExit, adr);
1903            point->relocated_ = true;
1904            disp = newInstr[i].branch.disp22;
1905            if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {  
1906                point->isBranchOut = true;
1907                point->branchTarget = adr + (disp<<2);
1908            }
1909            // if location was this point, change it to new point
1910            if(location == funcReturns[retId]) { 
1911                location = point;
1912            }
1913            retId++;
1914            reloc_info->addFuncReturn(point);
1915        }
1916
1917      } else if (isCallInsn(instr)) {
1918
1919        // first, check for tail-call optimization: a call where the instruction 
1920        // in the delay slot write to register %o7(15), usually just moving
1921        // the caller's return address, or doing a restore
1922        // Tail calls are instrumented as return points, not call points.
1923        instruction nexti; 
1924        nexti.raw = owner->get_instruction(adr+4);
1925
1926        if (nexti.rest.op == 2 
1927            && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1928               || nexti.rest.op3 == RESTOREop3)) {
1929
1930             // Undoing the tail-call optimazation when the function
1931             // is relocated. Here is an example:
1932             //   before:          --->             after
1933             // ---------------------------------------------------
1934             //   call  %g1                        restore    
1935             //   restore                          st  %i0, [ %fp + 0x44 ]
1936             //                                    mov %o7 %i0
1937             //                                    call %g1 
1938             //                                    nop
1939             //                                    mov %i0,%o7
1940             //                                    st  [ %fp + 0x44 ], %i0
1941             //                              retl
1942             //                                    nop
1943             // Q: Here the assumption that register i1 is available 
1944             //    might be an question, is it?
1945             // A: I think it is appropriate because:
1946             //      (in situation A calls B and B calls C)
1947             //      The procedure C called via tail call is a leaf 
1948             //      procedure, the value arguments and return value between
1949             //      A and C are passed by register (o1...o5, o7)
1950             //      So even If B mess up the value of i0, it won't affect the
1951             //      commnucation between A and C. Also, we saved the value of
1952             //      i0 on stack and when we return from B, the value of i0
1953             //      won't be affected.
1954             //      If C is not a leaf procedure, it should be fine
1955             //      as it is.
1956             //    ( If you could give an counter-example, please
1957             //      let me know.                         --ling )
1958
1959             genSimpleInsn(&newInstr[i++], RESTOREop3, 0, 0, 0);
1960             generateStore(&newInstr[i++], 24, REG_FP, 0x44); 
1961             genImmInsn(&newInstr[i++], ORop3, 15, 0, 24); 
1962             newInstr[i++].raw = owner->get_instruction(adr);
1963             generateNOOP(&newInstr[i++]);
1964             genImmInsn(&newInstr[i++], ORop3, 24, 0, 15);
1965             generateLoad(&newInstr[i++], REG_FP, 0x44, 24);         
1966             generateJmplInsn(&newInstr[i++], 15, 8 ,0);
1967             newAdr += 28;
1968             generateNOOP(&newInstr[i]);
1969             instPoint *point = new instPoint(this, instr, owner, newAdr, false,
1970                                       functionExit, adr);
1971             point-> originalInstruction = newInstr[i-1];
1972             point-> delaySlotInsn = newInstr[i];
1973             point-> isDelayed = true;
1974             point->relocated_ = true;
1975             // if location was this point, change it to new point
1976             if(location == funcReturns[retId]) { 
1977                 location = point;
1978             }
1979             retId++;
1980             reloc_info->addFuncReturn(point);
1981        } else {
1982          // if the second instruction in the function is a call instruction
1983          // then this cannot go in the delay slot of the branch to the
1984          // base tramp, so add a noop between first and second instructions
1985          // in the relocated function (check out write in libc.so.1 for
1986          // and example of this):
1987          //
1988          //     save  %sp, -96, %sp             brach to base tramp
1989          //     call  0x73b70                   nop
1990          //                                     call 0x73b70
1991          if(adr == (getAddress(0)+4)){
1992              newInstr[i+1] = instr;
1993              generateNOOP(&newInstr[i]);
1994              i++;
1995              newAdr += 4;
1996          }
1997
1998          // if this is a call to an address within the same function, then
1999          // we need to set the 07 register to have the same value as it
2000          // would before the function was relocated
2001          // to do this we generate a call instruction back to the original
2002          // function location, and then at this location we generate a call 
2003          // instruction back to the relocated instruction.  In the delay 
2004          // slot of the second instruction the value of 07 is changed by 
2005          // the difference between the origninal call instruction, and 
2006          // the location of the call instruction back to the relocated
2007          // function.  This way the 07 register will contain the address
2008          // of the original call instruction
2009          Address call_target = adr + (instr.call.disp30 << 2);
2010          if((call_target >= getAddress(0)) 
2011                 && (call_target <= (getAddress(0) + size()))){ 
2012             assert((newInstr[i].call.disp30 << 2) == 8);
2013
2014             // generating call instruction to orginal function address
2015             // after the SAVE call RESTORE instr.s that call the relocated
2016             // function 
2017             newInstr[i].call.disp30 = ((call_start_addr -newAdr) >> 2); 
2018
2019             // generate call to relocated function from original function 
2020             // (this will get almost correct value for register 07)
2021             instruction new_inst;
2022             generateCallInsn(&new_inst,call_start_addr,
2023                              newAdr+sizeof(instruction));
2024             callInstrs += new_inst;
2025            
2026             // generate add isntruction to get correct value for 07 register 
2027             // this will go in delay slot of previous call instr.
2028             genImmInsn(&new_inst,ADDop3,REG_O7,
2029                        (adr+baseAddress-call_start_addr),REG_O7);
2030             callInstrs += new_inst;
2031             call_start_addr += 2*sizeof(instruction);
2032          }
2033          else {
2034             // otherwise, this is a call instruction to a location
2035             // outside the function
2036             bool err;
2037             relocateInstruction(&newInstr[i],adr+baseAddress,newAdr,proc);
2038             (void)newCallPoint(newAdr, newInstr[i], owner, err, 
2039                                callsId, adr,reloc_info,location);
2040             if (err) return false;
2041          }
2042        }
2043      }
2044
2045      else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
2046        /* A register indirect jump. Some jumps may exit the function 
2047           (e.g. read/write on SunOS). In general, the only way to 
2048           know if a jump is exiting the function is to instrument
2049           the jump to test if the target is outside the current 
2050           function. Instead of doing this, we just check the 
2051           previous two instructions, to see if they are loading
2052           an address that is out of the current function.
2053           This should catch the most common cases (e.g. read/write).
2054           For other cases, we would miss a return point.
2055
2056           This is the case considered:
2057
2058              sethi addr_hi, r
2059              or addr_lo, r, r
2060              jump r
2061         */
2062
2063          reg jumpreg = instr.rest.rs1;
2064          instruction prev1;
2065          instruction prev2;
2066          
2067          prev1.raw = owner->get_instruction(adr-4);
2068          prev2.raw = owner->get_instruction(adr-8);
2069
2070          unsigned targetAddr;
2071
2072          if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
2073              && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2 
2074              && prev2.sethi.rd == (unsigned)jumpreg
2075              && prev1.rest.op == RESTop 
2076              && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
2077              && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg){
2078              
2079              targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
2080              targetAddr |= prev1.resti.simm13;
2081              if ((targetAddr < getAddress(0)) 
2082                  || (targetAddr >= (getAddress(0)+size()))) {
2083                  instPoint *point = new instPoint(this, instr, owner, 
2084                                                   newAdr, false,
2085                                                   functionExit, adr);
2086                  point->relocated_ = true;
2087                  // if location was this point, change it to new point
2088                  if(location == funcReturns[retId]) { 
2089                      location = point;
2090                  }
2091                  retId++;
2092                  reloc_info->addFuncReturn(point);
2093              }
2094          }
2095      }
2096  }
2097    
2098    return true;
2099 }