replace use of getMaxBranch1Insn() with
[dyninst.git] / paradynd / src / inst-sparc-sunos.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 "paradynd/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(pdFunction *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)
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           addr += 4;
72           originalInstruction.raw = owner->get_instruction(addr);
73           delaySlotInsn.raw = owner->get_instruction(addr+4);
74           size += 2*sizeof(instruction);
75
76           // If the second instruction is DCTI, we need to move the
77           // the instruction in the delayed slot.
78           if (IS_DELAYED_INST(delaySlotInsn)) {
79               isDelayed = true; 
80               isDelayedInsn.raw = owner->get_instruction(addr+8);
81               size += 1*sizeof(instruction);
82
83               // Life is hard. If the second instruction is actually
84               // an CALL instruction, we need to move the instruction
85               // after the instruction in the delayed slot if the 
86               // return value of this function is a aggregate value.
87               aggregateInsn.raw = owner->get_instruction(addr+12);
88               if (isCallInsn(delaySlotInsn)) {
89                   if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
90                       callAggregate = true;
91                       size += 1*sizeof(instruction);
92                   }
93               }
94           }
95
96       // The following are easier.        
97       } else if (ipType == callSite) {
98           delaySlotInsn.raw = owner->get_instruction(addr+4);
99           size += 2*sizeof(instruction);
100
101           aggregateInsn.raw = owner->get_instruction(addr+8);
102           if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
103               callAggregate = true;
104               size += 1*sizeof(instruction);
105           }
106       } else {
107           delaySlotInsn.raw = owner->get_instruction(addr+4);
108           size += 2*sizeof(instruction);
109       }
110   }
111
112   // When the function is a leaf function
113   else {
114
115       // For the leaf procedure, there are no function calls in
116       // this procdure. So we don't need to consider the 
117       // aggregate instuction.
118       if (ipType == functionEntry) {
119
120           otherInstruction.raw = owner->get_instruction(addr+4);
121           delaySlotInsn.raw = owner->get_instruction(addr+8);
122           size += 2*sizeof(instruction);
123
124           if (IS_DELAYED_INST(delaySlotInsn)) {
125               isDelayed = true;
126               isDelayedInsn.raw = owner->get_instruction(addr+12);
127               size += 1*sizeof(instruction);
128           }
129
130       } else if (ipType == functionExit) {
131           
132           addr -= 4;
133
134           if (owner->isValidAddress(addr-4)) {
135               instruction iplus1;
136               iplus1.raw = owner->get_instruction(addr-4);
137               if (IS_DELAYED_INST(iplus1) && !delayOK) {
138                   addr -= 4;
139                   inDelaySlot = true;
140                   size += 1*sizeof(instruction);
141               }
142           }
143
144           originalInstruction.raw = owner->get_instruction(addr);
145           otherInstruction.raw = owner->get_instruction(addr+4);
146           delaySlotInsn.raw = owner->get_instruction(addr+8);
147           size += 3*sizeof(instruction);
148
149           if (inDelaySlot) {
150               inDelaySlotInsn.raw = owner->get_instruction(addr+12);
151           }
152
153       } else {
154           // Of course, the leaf function could not have call sites. 
155           logLine("Internal Error: in inst-sparc.C.");
156           abort();
157       }
158   }
159
160   // return the address in the code segment after this instruction
161   // sequence. (there's a -1 here because one will be added up later in
162   // the function findInstPoints)  
163   adr = addr + (size - 1*sizeof(instruction));
164 }
165
166 // Determine if the called function is a "library" function or a "user" function
167 // This cannot be done until all of the functions have been seen, verified, and
168 // classified
169 //
170 void pdFunction::checkCallPoints() {
171   instPoint *p;
172   Address loc_addr;
173
174   vector<instPoint*> non_lib;
175
176   for (unsigned i=0; i<calls.size(); ++i) {
177     /* check to see where we are calling */
178     p = calls[i];
179     assert(p);
180
181     if (isInsnType(p->originalInstruction, CALLmask, CALLmatch)) {
182       // Direct call
183       loc_addr = p->addr + (p->originalInstruction.call.disp30 << 2);
184       pdFunction *pdf = (file_->exec())->findFunction(loc_addr);
185       if (pdf && !pdf->isLibTag()) {
186         p->callee = pdf;
187         non_lib += p;
188       } else {
189           delete p;
190       }
191     } else {
192       // Indirect call -- be conservative, assume it is a call to 
193       // an unnamed user function
194       assert(!p->callee); assert(p->callIndirect);
195       p->callee = NULL;
196       non_lib += p;
197     }
198   }
199   calls = non_lib;
200 }
201
202 // TODO we cannot find the called function by address at this point in time
203 // because the called function may not have been seen.
204 // reloc_info is 0 if the function is not currently being relocated
205 Address pdFunction::newCallPoint(Address &adr, const instruction instr,
206                                  const image *owner, bool &err, 
207                                  int &callId, Address &oldAddr,
208                                  relocatedFuncInfo *reloc_info,
209                                  const instPoint *&location)
210 {
211     Address ret=adr;
212     instPoint *point;
213
214     err = true;
215     if (isTrap) {
216         point = new instPoint(this, instr, owner, adr, false, callSite, oldAddr);
217     } else {
218         point = new instPoint(this, instr, owner, adr, false, false, callSite);
219     }
220
221     if (!isInsnType(instr, CALLmask, CALLmatch)) {
222       point->callIndirect = true;
223       point->callee = NULL;
224     } else{
225       point->callIndirect = false;
226     }
227
228     if (isTrap) {
229         if (!reloc_info) {
230             calls += point;
231             calls[callId] -> instId = callId++;
232         } else {
233             // calls to a location within the function are not
234             // kept in the calls vector
235             assert(callId >= 0);
236             assert(((u_int)callId) < calls.size());
237             point->relocated_ = true;
238             // if the location was this call site, then change its value
239             if(location && (calls[callId] == location)) { 
240                 assert(calls[callId]->instId  == location->instId);
241                 location = point; 
242             } 
243             point->instId = callId++;
244             reloc_info->addFuncCall(point);
245         }
246     } else {
247         if (!reloc_info) {
248             calls += point;
249         }
250         else {
251             point->relocated_ = true;
252             reloc_info->addFuncCall(point);
253         }
254     }
255     err = false;
256     return ret;
257 }
258
259 /*
260  * Given and instruction, relocate it to a new address, patching up
261  *   any relative addressing that is present.
262  *
263  */
264 void relocateInstruction(instruction *insn, u_int origAddr, u_int targetAddr,
265                          process *proc)
266 {
267     u_int newOffset;
268
269     // If the instruction is a CALL instruction, calculate the new
270     // offset
271     if (isInsnType(*insn, CALLmask, CALLmatch)) {
272         newOffset = origAddr  - targetAddr + (insn->call.disp30 << 2);
273         insn->call.disp30 = newOffset >> 2;
274     } else if (isInsnType(*insn, BRNCHmask, BRNCHmatch)||
275                isInsnType(*insn, FBRNCHmask, FBRNCHmatch)) {
276
277         // If the instruction is a Branch instruction, calculate the 
278         // new offset. If the new offset is out of reach after the 
279         // instruction is moved to the base Trampoline, we would do
280         // the following:
281         //    b  address  ......    address: save
282         //                                   call new_offset             
283         //                                   restore 
284         newOffset = origAddr - targetAddr + (insn->branch.disp22 << 2);
285         // if the branch is too far, then allocate more space in inferior
286         // heap for a call instruction to branch target.  The base tramp 
287         // will branch to this new inferior heap code, which will call the
288         // target of the branch
289         if (!offsetWithinRangeOfBranchInsn(newOffset)) {
290 //      if (ABS(newOffset) > getMaxBranch1Insn()) {
291             int ret = inferiorMalloc(proc,3*sizeof(instruction), textHeap);
292             u_int old_offset = insn->branch.disp22 << 2;
293             // TODO: this is the wrong branch offset
294             insn->branch.disp22  = (ret - targetAddr)>>2;
295             instruction insnPlus[3];
296             genImmInsn(insnPlus, SAVEop3, REG_SP, -112, REG_SP);
297             generateCallInsn(insnPlus+1, ret+sizeof(instruction), 
298                              origAddr+old_offset);
299             genSimpleInsn(insnPlus+2, RESTOREop3, 0, 0, 0); 
300             proc->writeDataSpace((caddr_t)ret, sizeof(insnPlus), 
301                          (caddr_t) insnPlus);
302         } else {
303             insn->branch.disp22 = newOffset >> 2;
304         }
305     } else if (isInsnType(*insn, TRAPmask, TRAPmatch)) {
306         // There should be no probelm for moving trap instruction
307         // logLine("attempt to relocate trap\n");
308     } 
309     /* The rest of the instructions should be fine as is */
310 }
311
312 /*
313  * Install a base tramp -- fill calls with nop's for now.
314  *
315  * This one install the base tramp for the regular functions.
316  *
317  */
318 trampTemplate *installBaseTramp(const instPoint *&location, process *proc)
319 {
320     unsigned baseAddr = inferiorMalloc(proc, baseTemplate.size, textHeap);
321
322     instruction *code = new instruction[baseTemplate.size];
323     assert(code);
324
325     memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
326
327     instruction *temp;
328     unsigned currAddr;
329     for (temp = code, currAddr = baseAddr; 
330         (currAddr - baseAddr) < (unsigned) baseTemplate.size;
331         temp++, currAddr += sizeof(instruction)) {
332
333         if (temp->raw == EMULATE_INSN) {
334
335             // Load the value of link register from stack 
336             // If it is a leaf function, genereate a RESTORE instruction
337             // since there's an instruction SAVE generated and put in the
338             // code segment.
339             if (location -> leaf) {
340                 genImmInsn(temp, RESTOREop3, 0, 0, 0);
341                 temp++;
342                 currAddr += sizeof(instruction);
343             } 
344
345             // Same for the leaf and nonleaf functions.
346             // First, relocate the "FIRST instruction" in the sequence;  
347             *temp = location->originalInstruction;
348             Address fromAddr = location->addr;
349             relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
350
351             // Again, for leaf function, one more is needed to move for one
352             // more spot;
353             if (location->leaf) {
354                 fromAddr += sizeof(instruction);
355                 currAddr += sizeof(instruction);
356                 *++temp = location->otherInstruction;
357                 relocateInstruction(temp, fromAddr, currAddr, 
358                                     (process *)proc);
359             }     
360             
361             // Second, relocate the "NEXT instruction";
362             fromAddr += sizeof(instruction);
363             currAddr += sizeof(instruction);
364             *++temp = location->delaySlotInsn;
365             relocateInstruction(temp, fromAddr, currAddr,
366                                 (process *)proc);
367             
368             // Third, if the "NEXT instruction" is a DCTI, 
369             if (location->isDelayed) {
370                 fromAddr += sizeof(instruction);
371                 currAddr += sizeof(instruction);
372                 *++temp = location->isDelayedInsn;
373                 relocateInstruction(temp, fromAddr, currAddr,
374                                     (process *)proc);
375                 
376                 // Then, possibly, there's an callAggregate instruction
377                 // after this. 
378                 if (location->callAggregate) {
379                     currAddr += sizeof(instruction);
380                     *++temp = location->aggregateInsn;
381                     continue;
382                 }       
383             }
384             
385             // If the "FIRST instruction" is a DCTI, then our so called 
386             // "NEXT instruction" is in the delayed Slot and this might
387             // happen. (actullay, it happened)
388             if (location->callAggregate) {
389                 currAddr += sizeof(instruction);
390                 *++temp = location->aggregateInsn;
391                 continue;
392             }   
393             
394             // For the leaf function, if there's an inDelaySlot instruction,
395             // move this one to the base Tramp.(i.e. at the function exit,
396             // if the first instruction is in the delayed slot the previous
397             // instruction, we have to move that one too, so we count from 
398             // that one and the last one is this sequence is called inDelaySlot
399             // instruction.)
400             // Well, after all these, another SAVE instruction is generated
401             // so we are prepared to handle the returning to our application's
402             // code segment. 
403             if (location->leaf) {
404                 if (location->inDelaySlot) {
405                     fromAddr += sizeof(instruction);
406                     currAddr += sizeof(instruction);
407                     *++temp = location->inDelaySlotInsn;
408                     relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
409                 } 
410                 
411                 genImmInsn(temp+1, SAVEop3, REG_SP, -112, REG_SP);
412             }
413             
414         } else if (temp->raw == RETURN_INSN) {
415             // Back to the code segement of the application.
416             // If the location is in the leaf procedure, generate an RESTORE
417             // instruction right after the CALL instruction to restore all
418             // the values in the registers.
419             if (location -> leaf) {
420                 generateCallInsn(temp, currAddr, location->addr+location->size);
421                 genImmInsn(temp+1, RESTOREop3, 0, 0, 0);
422             } else {
423                 generateCallInsn(temp, currAddr, location->addr+location->size);
424             }
425         } else if (temp->raw == SKIP_PRE_INSN) {
426             unsigned offset;
427             offset = baseAddr+baseTemplate.updateCostOffset-currAddr;
428             generateAnnulledBranchInsn(temp,offset);
429
430         } else if (temp->raw == SKIP_POST_INSN) {
431             unsigned offset;
432             offset = baseAddr+baseTemplate.returnInsOffset-currAddr;
433             generateAnnulledBranchInsn(temp,offset);
434
435         } else if (temp->raw == UPDATE_COST_INSN) {
436             
437             baseTemplate.costAddr = currAddr;
438             generateNOOP(temp);
439         } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
440                    (temp->raw == GLOBAL_PRE_BRANCH) ||
441                    (temp->raw == LOCAL_POST_BRANCH) ||
442                    (temp->raw == GLOBAL_POST_BRANCH)) {
443 #if defined(MT_THREAD)
444             if ((temp->raw == LOCAL_PRE_BRANCH) ||
445                 (temp->raw == LOCAL_POST_BRANCH)) {
446                 temp -= NUM_INSN_MT_PREAMBLE;
447                 unsigned numIns=0;
448                 generateMTpreamble((char *)temp, numIns, proc);
449                 temp += NUM_INSN_MT_PREAMBLE;
450             }
451 #endif
452             /* fill with no-op */
453             generateNOOP(temp);
454         }
455     }
456     // TODO cast
457     proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size,(caddr_t) code);
458
459     delete [] code;
460
461     trampTemplate *baseInst = new trampTemplate;
462     *baseInst = baseTemplate;
463     baseInst->baseAddr = baseAddr;
464     return baseInst;
465 }
466
467 /*
468  * Install the base Tramp for the function relocated.
469  * (it means the base tramp that don't need to bother with long jump and
470  *  is the one we used before for all the functions(since there's no
471  *  long jumps)
472  *  for system calls
473  */ 
474 trampTemplate *installBaseTrampSpecial(const instPoint *&location,
475                              process *proc,
476                              vector<instruction> &extra_instrs) 
477 {
478     unsigned currAddr;
479     instruction *code;
480     instruction *temp;
481
482     unsigned baseAddr = inferiorMalloc(proc, baseTemplate.size, textHeap);
483
484     if(!(location->func->isInstalled(proc))) {
485         location->func->relocateFunction(proc,location,extra_instrs);
486     }
487     else if(!location->relocated_){
488         // need to find new instPoint for location...it has the pre-relocated
489         // address of the instPoint
490         location->func->modifyInstPoint(location,proc);      
491     }
492
493     code = new instruction[baseTemplate.size];
494     memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
495
496     for (temp = code, currAddr = baseAddr; 
497         (currAddr - baseAddr) < (unsigned) baseTemplate.size;
498         temp++, currAddr += sizeof(instruction)) {
499
500         if (temp->raw == EMULATE_INSN) {
501             if (location->isBranchOut) {
502                 // the original instruction is a branch that goes out of a 
503                 // function.  We don't relocate the original instruction. We 
504                 // only get to the tramp is the branch is taken, so we generate
505                 // a unconditional branch to the target of the original 
506                 // instruction here 
507                 assert(location->branchTarget);
508                 int disp = location->branchTarget - currAddr;
509                 generateAnnulledBranchInsn(temp, disp);
510                 disp = temp->branch.disp22;
511                 continue;
512             }
513             else {
514                 *temp = location->originalInstruction;
515                 Address fromAddress = location->addr;
516                 relocateInstruction(temp, fromAddress, currAddr, proc);
517                 if (location->isDelayed) {
518                     /* copy delay slot instruction into tramp instance */
519                     currAddr += sizeof(instruction);  
520                     *++temp = location->delaySlotInsn;
521                 }
522                 if (location->callAggregate) {
523                     /* copy invalid insn with aggregate size in it */
524                     currAddr += sizeof(instruction);  
525                     *++temp = location->aggregateInsn;
526                 }
527             }
528         } else if (temp->raw == RETURN_INSN) {
529             generateAnnulledBranchInsn(temp, 
530                 (location->addr+ sizeof(instruction) - currAddr));
531             if (location->isDelayed) {
532                 /* skip the delay slot instruction */
533                 temp->branch.disp22 += 1;
534             }
535             if (location->callAggregate) {
536                 /* skip the aggregate size slot */
537                 temp->branch.disp22 += 1;
538             }
539         } else if (temp->raw == SKIP_PRE_INSN) {
540           unsigned offset;
541           offset = baseAddr+baseTemplate.updateCostOffset-currAddr;
542           generateAnnulledBranchInsn(temp,offset);
543         } else if (temp->raw == SKIP_POST_INSN) {
544           unsigned offset;
545           offset = baseAddr+baseTemplate.returnInsOffset-currAddr;
546           generateAnnulledBranchInsn(temp,offset);
547         } else if (temp->raw == UPDATE_COST_INSN) {
548             baseTemplate.costAddr = currAddr;
549             generateNOOP(temp);
550         } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
551                    (temp->raw == GLOBAL_PRE_BRANCH) ||
552                    (temp->raw == LOCAL_POST_BRANCH) ||
553                    (temp->raw == GLOBAL_POST_BRANCH)) {
554 #if defined(MT_THREAD)
555             if ((temp->raw == LOCAL_PRE_BRANCH) ||
556                 (temp->raw == LOCAL_POST_BRANCH)) {
557                 temp -= NUM_INSN_MT_PREAMBLE;
558                 unsigned numIns=0;
559                 generateMTpreamble((char *)temp, numIns, proc);
560                 temp += NUM_INSN_MT_PREAMBLE;
561             }
562 #endif
563             /* fill with no-op */
564             generateNOOP(temp);
565         }
566     }
567     // TODO cast
568     proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size,(caddr_t) code);
569
570     delete [] code;
571
572     trampTemplate *baseInst = new trampTemplate;
573     *baseInst = baseTemplate;
574     baseInst->baseAddr = baseAddr;
575     return baseInst;
576 }
577
578 /*
579  * Allocate the space for the base Trampoline, and generate the instruction
580  * we need for modifying the code segment
581  *
582  */
583 trampTemplate *findAndInstallBaseTramp(process *proc, 
584                                  const instPoint *&location,
585                                  returnInstance *&retInstance,
586                                  bool )
587 {
588     Address adr = location->addr;
589     trampTemplate *ret;
590     retInstance = NULL;
591     if (!proc->baseMap.defines((const instPoint *)location)) {
592         if (location->func->isTrapFunc()) {
593             // Install Base Tramp for the functions which are 
594             // relocated to the heap.
595             vector<instruction> extra_instrs;
596             ret = installBaseTrampSpecial(location,proc,extra_instrs);
597             if (location->isBranchOut){
598                 changeBranch(proc, location->addr, (int) ret->baseAddr, 
599                              location->originalInstruction);
600             } else {
601                 generateBranch(proc, location->addr, (int)ret->baseAddr);
602             }
603
604             // If for this process, a call to the relocated function has not
605             // yet be installed in its original location, then genterate the
606             // following instructions at the begining of the function:
607             //   SAVE;             CALL;         RESTORE.
608             // so that it would jump the start of the relocated function
609             // which is in heap.
610             if(!(location->func->isInstalled(proc))){
611                 location->func->setInstalled(proc);
612                 u_int e_size = extra_instrs.size();
613                 instruction *insn = new instruction[3 + e_size];
614                 Address adr = location-> func -> getAddress(0);
615                 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
616                 generateCallInsn(insn+1, adr+4, 
617                                  location->func->getAddress(proc));
618                 genSimpleInsn(insn+2, RESTOREop3, 0, 0, 0); 
619                 for(u_int i=0; i < e_size; i++){
620                     insn[3+i] = extra_instrs[i];
621                 }
622                 retInstance = new returnInstance((instructUnion *)insn, 
623                                          (3+e_size)*sizeof(instruction), 
624                                          adr, location->func->size());
625                 assert(retInstance);
626
627                 //cerr << "created a new return instance (relocated fn)!" << endl;
628             }
629
630         } else {
631             // Install base tramp for all the other regular functions. 
632             ret = installBaseTramp(location, proc);
633             if (location->leaf) {
634                 // if it is the leaf function, we need to generate
635                 // the following instruction sequence:
636                 //     SAVE;      CALL;      NOP.
637                 instruction *insn = new instruction[3];
638                 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
639                 generateCallInsn(insn+1, adr+4, (int) ret->baseAddr);
640                 generateNOOP(insn+2);
641                 retInstance = new returnInstance((instructUnion *)insn, 
642                                                  3*sizeof(instruction), adr, 
643                                                  3*sizeof(instruction));
644                 assert(retInstance);
645             } else {
646                 // Otherwise,
647                 // Generate branch instruction from the application to the
648                 // base trampoline and no SAVE instruction is needed
649                 instruction *insn = new instruction[2]; 
650                 assert(insn);
651
652                 generateCallInsn(insn, adr, (int) ret->baseAddr);
653                 generateNOOP(insn+1);
654
655                 retInstance = new returnInstance((instructUnion *)insn, 
656                                                  2*sizeof(instruction), adr, 
657                                                  2*sizeof(instruction));
658                 assert(retInstance);
659             }
660         }
661
662         proc->baseMap[(const instPoint *)location] = ret;
663
664     } else {
665         ret = proc->baseMap[(const instPoint *)location];
666     }
667       
668     return(ret);
669 }
670
671 /*
672  * Install a single tramp.
673  *
674  */
675 void installTramp(instInstance *inst, char *code, int codeSize)
676 {
677     totalMiniTramps++;
678     insnGenerated += codeSize/sizeof(int);
679
680     // TODO cast
681    (inst->proc)->writeDataSpace((caddr_t)inst->trampBase, codeSize, code);
682
683     unsigned atAddr;
684     if (inst->when == callPreInsn) {
685         if (inst->baseInstance->prevInstru == false) {
686             atAddr = inst->baseInstance->baseAddr+baseTemplate.skipPreInsOffset;
687             inst->baseInstance->cost += inst->baseInstance->prevBaseCost;
688             inst->baseInstance->prevInstru = true;
689             generateNoOp(inst->proc, atAddr);
690         }
691     } else {
692         if (inst->baseInstance->postInstru == false) {
693             atAddr = inst->baseInstance->baseAddr+baseTemplate.skipPostInsOffset
694             ;
695             inst->baseInstance->cost += inst->baseInstance->postBaseCost;
696             inst->baseInstance->postInstru = true;
697             generateNoOp(inst->proc, atAddr);
698         }
699     }
700     generateNoOp(inst->proc, atAddr);
701 }
702
703
704 unsigned emitFuncCall(opCode op, 
705                       registerSpace *rs,
706                       char *i, unsigned &base, 
707                       const vector<AstNode *> &operands, 
708                       const string &callee, process *proc,
709                       bool noCost)
710 {
711         assert(op == callOp);
712         unsigned addr;
713         bool err;
714         vector <reg> srcs;
715
716         addr = proc->findInternalAddress(callee, false, err);
717
718         if (err) {
719             pdFunction *func = proc->findOneFunction(callee);
720             if (!func) {
721                 ostrstream os(errorLine, 1024, ios::out);
722                 os << "Internal error: unable to find addr of " << callee << endl;
723                 logLine(errorLine);
724                 showErrorCallback(80, (const char *) errorLine);
725                 P_abort();
726             }
727             // TODO: is this correct or should we get relocated address?
728             addr = func->getAddress(0);
729         }
730         
731         for (unsigned u = 0; u < operands.size(); u++)
732             srcs += operands[u]->generateCode(proc, rs, i, base, noCost);
733
734         // TODO cast
735         instruction *insn = (instruction *) ((void*)&i[base]);
736
737         for (unsigned u=0; u<srcs.size(); u++){
738             if (u >= 5) {
739                  string msg = "Too many arguments to function call in instrumentation code: only 5 arguments can be passed on the sparc architecture.\n";
740                  fprintf(stderr, msg.string_of());
741                  showErrorCallback(94,msg);
742                  cleanUpAndExit(-1);
743             }
744             genSimpleInsn(insn, ORop3, 0, srcs[u], u+8); insn++;
745             base += sizeof(instruction);
746             rs->freeRegister(srcs[u]);
747         }
748
749         // As Ling pointed out to me, the following is rather inefficient.  It does:
750         //   sethi %hi(addr), %o5
751         //   jmpl %o5 + %lo(addr), %o7   ('call' pseudo-instr)
752         //   nop
753         // We can do better:
754         //   call <addr>    (but note that the call true-instr is pc-relative jump)
755         //   nop
756         generateSetHi(insn, addr, 13); insn++;
757         genImmInsn(insn, JMPLop3, 13, LOW10(addr), 15); insn++;
758         generateNOOP(insn);
759
760         base += 3 * sizeof(instruction);
761
762         // return value is the register with the return value from the
763         //   function.
764         // This needs to be %o0 since it is back in the callers scope.
765         return(8);
766 }
767  
768 unsigned emit(opCode op, reg src1, reg src2, reg dest, char *i, unsigned &base,
769               bool noCost)
770 {
771     // TODO cast
772     instruction *insn = (instruction *) ((void*)&i[base]);
773
774     if (op == loadConstOp) {
775       // dest = src1:imm    TODO
776       if (src1 > MAX_IMM13 || src1 < MIN_IMM13) {
777             // src1 is out of range of imm13, so we need an extra instruction
778             generateSetHi(insn, src1, dest);
779             base += sizeof(instruction);
780             insn++;
781
782             // or regd,imm,regd
783
784             // Chance for optimization: we should check for LOW10(src1)==0, and
785             // if so, don't generate the following bitwise-or instruction, since
786             // in that case nothing would be done.
787
788             genImmInsn(insn, ORop3, dest, LOW10(src1), dest);
789             base += sizeof(instruction);
790         } else {
791             // really or %g0,imm,regd
792             genImmInsn(insn, ORop3, 0, src1, dest);
793
794             base += sizeof(instruction);
795         }
796     } else if (op ==  loadOp) {
797         // dest = [src1]   TODO
798         generateSetHi(insn, src1, dest);
799         insn++;
800
801         generateLoad(insn, dest, LOW10(src1), dest);
802
803         base += sizeof(instruction)*2;
804     } else if (op ==  loadIndirOp) {
805         generateLoad(insn, src1, 0, dest);
806         base += sizeof(instruction);
807     } else if (op ==  storeOp) {
808         generateSetHi(insn, dest, src2);
809         insn++;
810
811         generateStore(insn, src1, src2, LOW10(dest));
812
813         base += sizeof(instruction)*2;
814     } else if (op ==  storeIndirOp) {
815         generateStore(insn, src1, dest, 0);
816         base += sizeof(instruction);
817     } else if (op ==  ifOp) {
818         // cmp src1,0
819         genSimpleInsn(insn, SUBop3cc, src1, 0, 0); insn++;
820         genBranch(insn, dest, BEcond, false); insn++;
821
822         generateNOOP(insn);
823         base += sizeof(instruction)*3;
824         return(base - 2*sizeof(instruction));
825     } else if (op ==  updateCostOp) {
826         // generate code to update the observed cost.
827         if (!noCost) {
828            // sethi %hi(dest), %l0
829            generateSetHi(insn, dest, REG_L0);
830            base += sizeof(instruction);
831            insn++;
832   
833            // ld [%l0+ lo(dest)], %l1
834            generateLoad(insn, REG_L0, LOW10(dest), REG_L1);
835            base += sizeof(instruction);
836            insn++;
837   
838            // update value (src1 holds the cost, in cycles; e.g. 19)
839            if (src1 <= MAX_IMM13) {
840               genImmInsn(insn, ADDop3, REG_L1, src1, REG_L1);
841               base += sizeof(instruction);
842               insn++;
843
844               generateNOOP(insn);
845               base += sizeof(instruction);
846               insn++;
847
848               generateNOOP(insn);
849               base += sizeof(instruction);
850               insn++;
851            } else {
852               // load in two parts
853               generateSetHi(insn, src1, REG_L2);
854               base += sizeof(instruction);
855               insn++;
856
857               // or regd,imm,regd
858               genImmInsn(insn, ORop3, REG_L2, LOW10(src1), REG_L2);
859               base += sizeof(instruction);
860               insn++;
861
862               // now add it
863               genSimpleInsn(insn, ADDop3, REG_L1, REG_L2, REG_L1);
864               base += sizeof(instruction);
865               insn++;
866            }
867   
868            // store result st %l1, [%l0+ lo(dest)];
869            generateStore(insn, REG_L1, REG_L0, LOW10(dest));
870            base += sizeof(instruction);
871            insn++;
872         } // if (!noCost)
873     } else if (op ==  trampPreamble) {
874     } else if (op ==  trampTrailer) {
875         // dest is in words of offset and generateBranchInsn is bytes offset
876         generateAnnulledBranchInsn(insn, dest << 2);
877         base += sizeof(instruction);
878         insn++;
879
880         // add no-op, SS-5 sometimes seems to try to decode this insn - jkh 2/14
881         generateNOOP(insn);
882         insn++;
883         base += sizeof(instruction);
884
885         return(base -  2 * sizeof(instruction));
886     } else if (op == noOp) {
887         generateNOOP(insn);
888         base += sizeof(instruction);
889     } else if (op == getParamOp) {
890 #if defined(MT_THREAD)
891         // saving CT/vector address on the stack
892         generateStore(insn, REG_MT, REG_FP, -40);
893         insn++;
894 #endif
895         // first 8 parameters are in register 24 ....
896         genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
897         insn++;
898
899         generateStore(insn, 24+src1, REG_SP, 68+4*src1); 
900         insn++;
901               
902         genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
903         insn++;
904
905         generateLoad(insn, REG_SP, 112+68+4*src1, 24+src1); 
906         insn++;
907
908 #if defined(MT_THREAD)
909         // restoring CT/vector address back in REG_MT
910         generateLoad(insn, REG_FP, -40, REG_MT);
911         insn++;
912 #endif
913
914 #if defined(MT_THREAD)
915         base += 6*sizeof(instruction);
916 #else
917         base += 4*sizeof(instruction);
918 #endif
919         
920         if (src1 <= 8) {
921             return(24+src1);
922         }
923         
924         abort();
925     } else if (op == getSysParamOp) {
926         
927         if (src1 <= 8) {
928             return(24+src1);
929         }       
930     } else if (op == getRetValOp) {
931         // return value is in register 24
932         genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
933         insn++;
934
935         generateStore(insn, 24, REG_SP, 68); 
936         insn++;
937               
938         genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
939         insn++;
940
941         generateLoad(insn, REG_SP, 112+68, 24); 
942         insn++;
943
944         base += 4*sizeof(instruction);
945
946         return(24);
947
948     } else if (op == getSysRetValOp) {
949         return(24);
950     } else if (op == saveRegOp) {
951         // should never be called for this platform.
952         abort();
953     } else {
954       int op3=-1;
955         switch (op) {
956             // integer ops
957             case plusOp:
958                 op3 = ADDop3;
959                 break;
960
961             case minusOp:
962                 op3 = SUBop3;
963                 break;
964
965             case timesOp:
966                 op3 = SMULop3;
967                 break;
968
969             case divOp:
970                 op3 = SDIVop3;
971                 break;
972
973             // Bool ops
974             case orOp:
975                 op3 = ORop3;
976                 break;
977
978             case andOp:
979                 op3 = ANDop3;
980                 break;
981
982             // rel ops
983             // For a particular condition (e.g. <=) we need to use the
984             // the opposite in order to get the right value (e.g. for >=
985             // we need BLTcond) - naim
986             case eqOp:
987                 genRelOp(insn, BNEcond, src1, src2, dest, base);
988                 return(0);
989                 break;
990
991             case neOp:
992                 genRelOp(insn, BEcond, src1, src2, dest, base);
993                 return(0);
994                 break;
995
996             case lessOp:
997                 genRelOp(insn, BGEcond, src1, src2, dest, base);
998                 return(0);
999                 break;
1000
1001             case leOp:
1002                 genRelOp(insn, BGTcond, src1, src2, dest, base);
1003                 return(0);
1004                 break;
1005
1006             case greaterOp:
1007                 genRelOp(insn, BLEcond, src1, src2, dest, base);
1008                 return(0);
1009                 break;
1010
1011             case geOp:
1012                 genRelOp(insn, BLTcond, src1, src2, dest, base);
1013                 return(0);
1014                 break;
1015
1016             default:
1017                 abort();
1018                 break;
1019         }
1020         genSimpleInsn(insn, op3, src1, src2, dest);
1021
1022         base += sizeof(instruction);
1023       }
1024     return(0);
1025 }
1026
1027 /*
1028  * Find the instPoints of this function.
1029  */
1030 bool pdFunction::findInstPoints(const image *owner) {
1031
1032    if (size() == 0) {
1033      return false;
1034    }
1035
1036    leaf = true;
1037    Address adr;
1038    Address adr1 = getAddress(0);
1039    instruction instr;
1040    instr.raw = owner->get_instruction(adr1);
1041    if (!IS_VALID_INSN(instr))
1042      return false;
1043
1044    // If it contains an instruction, I assume it would be s system call
1045    // which will be treat differently. 
1046    isTrap = false;
1047    bool func_entry_found = false;
1048
1049    for ( ; adr1 < getAddress(0) + size(); adr1 += 4) {
1050        instr.raw = owner->get_instruction(adr1);
1051
1052        // If there's an TRAP instruction in the function, we 
1053        // assume that it is an system call and will relocate it 
1054        // to the heap
1055        if (isInsnType(instr, TRAPmask, TRAPmatch)) {
1056            isTrap = true;
1057            return findInstPoints(owner, getAddress(0), 0);
1058        } 
1059
1060        // The function Entry is defined as the first SAVE instruction plus
1061        // the instructions after this.
1062        // ( The first instruction for the nonleaf function is not 
1063        //   necessarily a SAVE instruction. ) 
1064        if (isInsnType(instr, SAVEmask, SAVEmatch) && !func_entry_found) {
1065
1066            leaf = false;
1067            func_entry_found = true;
1068            funcEntry_ = new instPoint(this, instr, owner, adr1, true, leaf, 
1069                                       functionEntry);
1070            adr = adr1;
1071            assert(funcEntry_);
1072        }
1073    }
1074
1075    // If there's no SAVE instruction found, this is a leaf function and
1076    // and function Entry will be defined from the first instruction
1077    if (leaf) {
1078        adr = getAddress(0);
1079        instr.raw = owner->get_instruction(adr);
1080        funcEntry_ = new instPoint(this, instr, owner, adr, true, leaf,
1081                                   functionEntry);
1082        assert(funcEntry_);
1083    }
1084
1085    for ( ; adr < getAddress(0) + size(); adr += sizeof(instruction)) {
1086
1087      instr.raw = owner->get_instruction(adr);
1088
1089      bool done;
1090
1091      // check for return insn and as a side affect decide if we are at the
1092      //   end of the function.
1093      if (isReturnInsn(owner, adr, done)) {
1094        // define the return point
1095        funcReturns += new instPoint(this, instr, owner, adr, false, leaf, 
1096                                     functionExit);
1097
1098      } else if (instr.branch.op == 0 
1099                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6) 
1100                 && (instr.branch.cond == 0 ||instr.branch.cond == 8)) {
1101        // find if this branch is going out of the function
1102        int disp = instr.branch.disp22;
1103        Address target = adr +  (disp << 2);
1104        if ((target < (getAddress(0)))  
1105            || (target >= (getAddress(0) + size()))) {
1106          instPoint *point = new instPoint(this, instr, owner, adr, false, leaf, 
1107                                           functionExit);
1108          funcReturns += point;
1109        }
1110
1111      } else if (isCallInsn(instr)) {
1112
1113        // if the call target is the address of the call instruction
1114        // then this is not something that we can instrument...
1115        // this occurs in functions with code that is modifined when 
1116        // they are loaded by the run-time linker, or when the .init
1117        // section is executed.  In this case the instructions in the
1118        // parsed image file are different from the ones in the executable
1119        // process.
1120        if(instr.call.op == CALLop) { 
1121            Address call_target = adr + (instr.call.disp30 << 2);
1122            if(call_target == adr){ 
1123                 return false;
1124        }}
1125        // first, check for tail-call optimization: a call where the instruction 
1126        // in the delay slot write to register %o7(15), usually just moving
1127        // the caller's return address, or doing a restore
1128        // Tail calls are instrumented as return points, not call points.
1129
1130
1131        instruction nexti; 
1132        nexti.raw = owner->get_instruction(adr+4);
1133
1134        if (nexti.rest.op == 2 
1135            && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1136               || nexti.rest.op3 == RESTOREop3)) {
1137          funcReturns += new instPoint(this, instr, owner, adr, false, leaf, 
1138                                       functionExit);
1139
1140        } else {
1141          // define a call point
1142          // this may update address - sparc - aggregate return value
1143          // want to skip instructions
1144          bool err;
1145          int dummyId;
1146          instPoint *blah = 0;
1147          adr = newCallPoint(adr, instr, owner, err, dummyId, adr,0,blah);
1148        }
1149      }
1150
1151      else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
1152        /* A register indirect jump. Some jumps may exit the function 
1153           (e.g. read/write on SunOS). In general, the only way to 
1154           know if a jump is exiting the function is to instrument
1155           the jump to test if the target is outside the current 
1156           function. Instead of doing this, we just check the 
1157           previous two instructions, to see if they are loading
1158           an address that is out of the current function.
1159           This should catch the most common cases (e.g. read/write).
1160           For other cases, we would miss a return point.
1161
1162           This is the case considered:
1163
1164              sethi addr_hi, r
1165              or addr_lo, r, r
1166              jump r
1167         */
1168
1169        reg jumpreg = instr.rest.rs1;
1170        instruction prev1;
1171        instruction prev2;
1172
1173        prev1.raw = owner->get_instruction(adr-4);
1174        prev2.raw = owner->get_instruction(adr-8);
1175
1176        unsigned targetAddr;
1177
1178        if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
1179            && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2 
1180            && prev2.sethi.rd == (unsigned)jumpreg
1181            && prev1.rest.op == RESTop 
1182            && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
1183            && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg) {
1184
1185          targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
1186          targetAddr |= prev1.resti.simm13;
1187          if ((targetAddr<getAddress(0))||(targetAddr>=(getAddress(0)+size()))){
1188            instPoint *point = new instPoint(this, instr, owner, adr, false, 
1189                                             leaf, functionExit);
1190            funcReturns += point;
1191          }
1192        }
1193
1194      }
1195  }
1196
1197  return (checkInstPoints(owner)); 
1198 }
1199
1200 /*
1201  * Check all the instPoints within this function to see if there's 
1202  * any conficts happen.
1203  */
1204 bool pdFunction::checkInstPoints(const image *owner) {
1205
1206     // Our own library function, skip the test.
1207     if (prettyName_.prefixed_by("DYNINST")) 
1208         return true;
1209
1210     // The function is too small to be worthing instrumenting.
1211     if (size() <= 12)
1212         return false;
1213
1214     // No function return! return false;
1215     if (sizeof(funcReturns) == 0)
1216         return false;
1217
1218     instruction instr;
1219     Address adr = getAddress(0);
1220
1221     // Check if there's any branch instruction jump to the middle
1222     // of the instruction sequence in the function entry point
1223     // and function exit point.
1224     for ( ; adr < getAddress(0) + size(); adr += sizeof(instruction)) {
1225
1226         instr.raw = owner->get_instruction(adr);
1227
1228         if (isInsnType(instr, BRNCHmask, BRNCHmatch)||
1229             isInsnType(instr, FBRNCHmask, FBRNCHmatch)) {
1230
1231             int disp = instr.branch.disp22;
1232             Address target = adr + (disp << 2);
1233
1234             if ((target > funcEntry_->addr)&&
1235                 (target < (funcEntry_->addr + funcEntry_->size))) {
1236                 if (adr > (funcEntry_->addr+funcEntry_->size))
1237                     //cout << "Function " << prettyName_ <<" entry" << endl;
1238                     return false;
1239             }
1240
1241             for (u_int i = 0; i < funcReturns.size(); i++) {
1242                 if ((target > funcReturns[i]->addr)&&
1243                     (target < (funcReturns[i]->addr + funcReturns[i]->size))) {
1244                     if ((adr < funcReturns[i]->addr)||
1245                         (adr > (funcReturns[i]->addr + funcReturns[i]->size)))
1246                         return false;
1247                 }
1248             }
1249         }
1250     }
1251
1252     return true;        
1253 }
1254
1255 // This function is to find the inst Points for a function
1256 // that will be relocated if it is instrumented. 
1257 bool pdFunction::findInstPoints(const image *owner, Address newAdr, 
1258                                 process *proc){
1259
1260    int i;
1261    if (size() == 0) {
1262      return false;
1263    }
1264    relocatable_ = true;
1265
1266    Address adr = getAddress(0);
1267    instruction instr;
1268    instr.raw = owner->get_instruction(adr);
1269    if (!IS_VALID_INSN(instr))
1270      return false;
1271    
1272    if (size() <= 3*sizeof(instruction)) 
1273        return false;
1274
1275    instPoint *point = new instPoint(this, instr, owner, newAdr, true, 
1276                                     functionEntry, adr);
1277
1278    funcEntry_ = point;
1279
1280    // if the second instruction in a relocated function is a call instruction
1281    // or a branch instruction, then we can't deal with this 
1282    if(size() > sizeof(instruction)){
1283        Address second_adr = adr + sizeof(instruction);
1284        instruction second_instr;
1285        second_instr.raw =  owner->get_instruction(second_adr); 
1286        if ((isCallInsn(second_instr)) || 
1287                       (second_instr.branch.op == 0 && 
1288                       (second_instr.branch.op2 == 2 || 
1289                       second_instr.branch.op2 == 6))) {
1290            return false;
1291        }
1292    }
1293    
1294    assert(funcEntry_);
1295    int retId = 0;
1296    int callsId = 0; 
1297
1298    for (i = 0; adr < getAddress(0) + size(); adr += sizeof(instruction),  
1299         newAdr += sizeof(instruction), i++) {
1300
1301      instr.raw = owner->get_instruction(adr);
1302      newInstr[i] = instr;
1303      bool done;
1304
1305      // check for return insn and as a side affect decide if we are at the
1306      //   end of the function.
1307      if (isReturnInsn(owner, adr, done)) {
1308        // define the return point
1309        instPoint *point = new instPoint(this, instr, owner, newAdr, false, 
1310                                         functionExit, adr);
1311        funcReturns += point;
1312        funcReturns[retId] -> instId = retId++;
1313      } else if (instr.branch.op == 0 
1314                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) {
1315        // find if this branch is going out of the function
1316        int disp = instr.branch.disp22;
1317        Address target = adr + (disp << 2);
1318        if (target < getAddress(0) || target >= getAddress(0) + size()) {
1319            relocateInstruction(&newInstr[i], adr, newAdr, proc);
1320            instPoint *point = new instPoint(this, newInstr[i], owner, 
1321                                             newAdr, false, 
1322                                             functionExit, adr);
1323            if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {  
1324                point->isBranchOut = true;
1325                point->branchTarget = target;
1326            }
1327            funcReturns += point;
1328            funcReturns[retId] -> instId = retId++;
1329        }
1330
1331      } else if (isCallInsn(instr)) {
1332
1333        // first, check for tail-call optimization: a call where the instruction 
1334        // in the delay slot write to register %o7(15), usually just moving
1335        // the caller's return address, or doing a restore
1336        // Tail calls are instrumented as return points, not call points.
1337        instruction nexti; 
1338        nexti.raw = owner->get_instruction(adr+4);
1339
1340        if (nexti.rest.op == 2 
1341            && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1342               || nexti.rest.op3 == RESTOREop3)) {
1343
1344            instPoint *point = new instPoint(this, instr, owner, newAdr, false,
1345                                       functionExit, adr);
1346            funcReturns += point;
1347            funcReturns[retId] -> instId = retId++;
1348
1349        } else {
1350
1351          // define a call point
1352          // this may update address - sparc - aggregate return value
1353          // want to skip instructions
1354          bool err;
1355          instPoint *blah = 0;
1356          adr = newCallPoint(newAdr, instr, owner, err, callsId, adr,0,blah);
1357          if (err)
1358            return false;
1359        }
1360      }
1361
1362      else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
1363        /* A register indirect jump. Some jumps may exit the function 
1364           (e.g. read/write on SunOS). In general, the only way to 
1365           know if a jump is exiting the function is to instrument
1366           the jump to test if the target is outside the current 
1367           function. Instead of doing this, we just check the 
1368           previous two instructions, to see if they are loading
1369           an address that is out of the current function.
1370           This should catch the most common cases (e.g. read/write).
1371           For other cases, we would miss a return point.
1372
1373           This is the case considered:
1374
1375              sethi addr_hi, r
1376              or addr_lo, r, r
1377              jump r
1378         */
1379
1380          reg jumpreg = instr.rest.rs1;
1381          instruction prev1;
1382          instruction prev2;
1383          
1384          prev1.raw = owner->get_instruction(adr-4);
1385          prev2.raw = owner->get_instruction(adr-8);
1386
1387          unsigned targetAddr;
1388
1389          if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
1390              && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2 
1391              && prev2.sethi.rd == (unsigned)jumpreg
1392              && prev1.rest.op == RESTop 
1393              && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
1394              && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg){
1395              
1396              targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
1397              targetAddr |= prev1.resti.simm13;
1398              if ((targetAddr < getAddress(0)) 
1399                  || (targetAddr >= (getAddress(0)+size()))) {
1400                  instPoint *point = new instPoint(this, instr, owner, 
1401                                                   newAdr, false,
1402                                                   functionExit, adr);
1403                  funcReturns += point;
1404                  funcReturns[retId] -> instId = retId++;
1405              }
1406          }
1407      }
1408  }
1409  return true;
1410 }
1411
1412 // This function assigns new address to instrumentation points of  
1413 // a function that has been relocated
1414 bool pdFunction::findNewInstPoints(const image *owner, 
1415                                 const instPoint *&location,
1416                                 Address newAdr,
1417                                 process *proc,
1418                                 vector<instruction> &,
1419                                 relocatedFuncInfo *reloc_info) {
1420
1421    int i;
1422    if (size() == 0) {
1423      return false;
1424    }
1425    assert(reloc_info);
1426
1427    Address adr = getAddress(0);
1428    instruction instr;
1429    instr.raw = owner->get_instruction(adr);
1430    if (!IS_VALID_INSN(instr))
1431      return false;
1432
1433    instPoint *point = new instPoint(this, instr, owner, newAdr, true, 
1434                                     functionEntry, adr);
1435    point->relocated_ = true;
1436    // if location was the entry point then change location's value to new pt
1437    if(location == funcEntry_) { 
1438         location = point; 
1439    }
1440
1441    reloc_info->addFuncEntry(point);
1442    assert(reloc_info->funcEntry());
1443    int retId = 0;
1444    int callsId = 0; 
1445
1446    // get baseAddress if this is a shared object
1447    Address baseAddress = 0;
1448    if(!(proc->getBaseAddress(owner,baseAddress))){
1449        baseAddress =0;
1450    }
1451
1452    for (i = 0; adr < getAddress(0) + size(); adr += 4,  newAdr += 4, i++) {
1453     
1454      instr.raw = owner->get_instruction(adr);
1455      newInstr[i] = instr;
1456
1457      bool done;
1458
1459      // check for return insn and as a side affect decide if we are at the
1460      //   end of the function.
1461      if (isReturnInsn(owner, adr, done)) {
1462        // define the return point
1463        instPoint *point = new instPoint(this, instr, owner, newAdr, false, 
1464                                         functionExit, adr);
1465        point->relocated_ = true;
1466        // if location was this point, change it to new point
1467        if(location == funcReturns[retId]) { 
1468            location = point; 
1469        }
1470        retId++;
1471        reloc_info->addFuncReturn(point);
1472      } else if (instr.branch.op == 0 
1473                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) {
1474        // find if this branch is going out of the function
1475        int disp = instr.branch.disp22;
1476        Address target = adr + (disp << 2);
1477        if ((target < (getAddress(0))) 
1478            || (target >= (getAddress(0) + size()))) {
1479            relocateInstruction(&newInstr[i],adr,newAdr,proc);
1480            instPoint *point = new instPoint(this, newInstr[i], owner, 
1481                                             newAdr, false, 
1482                                             functionExit, adr);
1483            point->relocated_ = true;
1484            // TODO is this the correct displacement???
1485            disp = newInstr[i].branch.disp22;
1486            if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {  
1487                point->isBranchOut = true;
1488                // TODO is this the correct target???
1489                point->branchTarget = target;
1490            }
1491            // if location was this point, change it to new point
1492            if(location == funcReturns[retId]) { 
1493                location = point;
1494            }
1495            retId++;
1496            reloc_info->addFuncReturn(point);
1497        }
1498
1499      } else if (isCallInsn(instr)) {
1500
1501        // first, check for tail-call optimization: a call where the instruction 
1502        // in the delay slot write to register %o7(15), usually just moving
1503        // the caller's return address, or doing a restore
1504        // Tail calls are instrumented as return points, not call points.
1505        instruction nexti; 
1506        nexti.raw = owner->get_instruction(adr+4);
1507
1508        if (nexti.rest.op == 2 
1509            && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
1510               || nexti.rest.op3 == RESTOREop3)) {
1511
1512             // Undoing the tail-call optimazation when the function
1513             // is relocated. Here is an example:
1514             //   before:          --->             after
1515             // ---------------------------------------------------
1516             //   call  %g1                        restore    
1517             //   restore                          st  %i0, [ %fp + 0x44 ]
1518             //                                    mov %o7 %i0
1519             //                                    call %g1 
1520             //                                    nop
1521             //                                    mov %i0,%o7
1522             //                                    st  [ %fp + 0x44 ], %i0
1523             //                              retl
1524             //                                    nop
1525             // Q: Here the assumption that register i1 is available 
1526             //    might be an question, is it?
1527             // A: I think it is appropriate because:
1528             //      (in situation A calls B and B calls C)
1529             //      The procedure C called via tail call is a leaf 
1530             //      procedure, the value arguments and return value between
1531             //      A and C are passed by register (o1...o5, o7)
1532             //      So even If B mess up the value of i0, it won't affect the
1533             //      commnucation between A and C. Also, we saved the value of
1534             //      i0 on stack and when we return from B, the value of i0
1535             //      won't be affected.
1536             //      If C is not a leaf procedure, it should be fine
1537             //      as it is.
1538             //    ( If you could give an counter-example, please
1539             //      let me know.                         --ling )
1540
1541             genSimpleInsn(&newInstr[i++], RESTOREop3, 0, 0, 0);
1542             generateStore(&newInstr[i++], 24, REG_FP, 0x44); 
1543             genImmInsn(&newInstr[i++], ORop3, 15, 0, 24); 
1544             newInstr[i++].raw = owner->get_instruction(adr);
1545             generateNOOP(&newInstr[i++]);
1546             genImmInsn(&newInstr[i++], ORop3, 24, 0, 15);
1547             generateLoad(&newInstr[i++], REG_FP, 0x44, 24);         
1548             generateJmplInsn(&newInstr[i++], 15, 8 ,0);
1549             newAdr += 28;
1550             generateNOOP(&newInstr[i]);
1551             instPoint *point = new instPoint(this, instr, owner, newAdr, false,
1552                                       functionExit, adr);
1553             point-> originalInstruction = newInstr[i-1];
1554             point-> delaySlotInsn = newInstr[i];
1555             point-> isDelayed = true;
1556             point->relocated_ = true;
1557             // if location was this point, change it to new point
1558             if(location == funcReturns[retId]) { 
1559                 location = point;
1560             }
1561             retId++;
1562             reloc_info->addFuncReturn(point);
1563        } else {
1564
1565            // otherwise, this is a call instruction to a location
1566            // outside the function
1567            bool err;
1568            // relocateInstruction(&newInstr[i],adr+baseAddress,newAdr,proc);
1569            adr = newCallPoint(newAdr, newInstr[i], owner, err,
1570                                    callsId, adr,reloc_info,location);
1571            if (err) return false;
1572        }
1573      }
1574
1575      else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
1576        /* A register indirect jump. Some jumps may exit the function 
1577           (e.g. read/write on SunOS). In general, the only way to 
1578           know if a jump is exiting the function is to instrument
1579           the jump to test if the target is outside the current 
1580           function. Instead of doing this, we just check the 
1581           previous two instructions, to see if they are loading
1582           an address that is out of the current function.
1583           This should catch the most common cases (e.g. read/write).
1584           For other cases, we would miss a return point.
1585
1586           This is the case considered:
1587
1588              sethi addr_hi, r
1589              or addr_lo, r, r
1590              jump r
1591         */
1592
1593          reg jumpreg = instr.rest.rs1;
1594          instruction prev1;
1595          instruction prev2;
1596          
1597          prev1.raw = owner->get_instruction(adr-4);
1598          prev2.raw = owner->get_instruction(adr-8);
1599
1600          unsigned targetAddr;
1601
1602          if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
1603              && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2 
1604              && prev2.sethi.rd == (unsigned)jumpreg
1605              && prev1.rest.op == RESTop 
1606              && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
1607              && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg){
1608              
1609              targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
1610              targetAddr |= prev1.resti.simm13;
1611              if ((targetAddr < getAddress(0)) 
1612                  || (targetAddr >= (getAddress(0)+size()))) {
1613                  instPoint *point = new instPoint(this, instr, owner, 
1614                                                   newAdr, false,
1615                                                   functionExit, adr);
1616                  point->relocated_ = true;
1617                  // if location was this point, change it to new point
1618                  if(location == funcReturns[retId]) { 
1619                      location = point;
1620                  }
1621                  retId++;
1622                  reloc_info->addFuncReturn(point);
1623              }
1624          }
1625      }
1626  }
1627    
1628    return true;
1629 }