Changes to work towards compatability with IBM's version of dyninst.
[dyninst.git] / dyninstAPI / src / inst-sparc.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 // $Id: inst-sparc.C,v 1.105 2001/08/29 23:25:28 hollings Exp $
43
44 #include "dyninstAPI/src/inst-sparc.h"
45 #include "dyninstAPI/src/instPoint.h"
46
47 #include "dyninstAPI/src/FunctionExpansionRecord.h"
48
49 /****************************************************************************/
50 /****************************************************************************/
51 /****************************************************************************/
52
53 static dictionary_hash<string, unsigned> funcFrequencyTable(string::hash);
54
55 trampTemplate baseTemplate;
56 NonRecursiveTrampTemplate nonRecursiveBaseTemplate;
57
58 //declaration of conservative base trampoline template
59
60 trampTemplate conservativeBaseTemplate;
61 NonRecursiveTrampTemplate nonRecursiveConservativeBaseTemplate;
62
63
64
65 registerSpace *regSpace;
66
67 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
68 // registers 8 to 15: out registers 
69 // registers 16 to 22: local registers
70 Register deadList[] = {16, 17, 18, 19, 20, 21, 22 };
71 #else
72 Register deadList[] = {16, 17, 18, 19, 20, 21, 22, 23 };
73 #endif
74
75 int deadListSize = sizeof(deadList);
76
77 /****************************************************************************/
78 /****************************************************************************/
79 /****************************************************************************/
80
81 // Constructor for the class instPoint. This one defines the 
82 // instPoints for the relocated function. Since the function reloated
83 // to the heap don't need to worry about that jump could be out of
84 // reach, the instructions to be moved are the one instruction at that
85 // point plus others if necessary(i.e. instruction in the delayed
86 // slot and maybe the aggregate instuction ).    
87 //
88 // Unfortunately, this constructor does NOT set several internal fields
89 //  e.g. size, isDelayedInsn, aggregateInsn, delaySlotInsn
90 instPoint::instPoint(pd_Function *f, const instruction &instr, 
91                      const image *owner, Address &adr, bool delayOK, 
92                      instPointType pointType, Address &oldAddr)
93 : insnAddr(adr), addr(adr), originalInstruction(instr), 
94   inDelaySlot(false), isDelayed(false),
95   callIndirect(false), callAggregate(false), callee(NULL), func(f), 
96   ipType(pointType), image_ptr(owner), firstIsConditional(false), 
97   relocated_(false), isLongJump(false)
98 {
99   assert(f->isTrapFunc() == true);  
100
101   isBranchOut = false;
102   delaySlotInsn.raw = owner->get_instruction(oldAddr+4);
103   aggregateInsn.raw = owner->get_instruction(oldAddr+8);
104
105   // If the instruction is a DCTI, the instruction in the delayed 
106   // slot is to be moved.
107   if (IS_DELAYED_INST(instr))
108     isDelayed = true;
109
110   // If this function call another function which return an aggregate
111   // value, move the aggregate instruction, too. 
112   if (ipType == callSite) {
113       if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
114           callAggregate = true;
115           adr += 8;
116           oldAddr += 8;
117       }
118   }
119
120   if (owner->isValidAddress(oldAddr-4)) {
121     instruction iplus1;
122     iplus1.raw = owner->get_instruction(oldAddr-4);
123     if (IS_DELAYED_INST(iplus1) && !delayOK) {
124       // ostrstream os(errorLine, 1024, ios::out);
125       // os << "** inst point " << func->file->fullName << "/"
126       //  << func->prettyName() << " at addr " << addr <<
127       //        " in a delay slot\n";
128       // logLine(errorLine);
129       inDelaySlot = true;
130     }
131   }
132
133   // set size at least....
134   size = 0;
135   if (ipType == functionEntry) {
136       if (hasNoStackFrame()) {
137           size = 4 * sizeof(instruction);
138       } else {
139           size = 5 * sizeof(instruction);
140       }
141   } else if (ipType == callSite) {
142       size = 3 * sizeof(instruction);
143   } else if (ipType == functionExit) {
144       if (hasNoStackFrame()) {
145           size = 5 * sizeof(instruction);
146       } else {
147           size = 2 * sizeof(instruction);
148       }
149   } else if (ipType == otherPoint){
150           size = 2 * sizeof(instruction);
151   } else {
152       assert(false);  
153   }
154 }
155
156 /****************************************************************************/
157 /****************************************************************************/
158 /****************************************************************************/
159
160 // Add the astNode opt to generate one instruction to get the 
161 // return value for the compiler optimazed case
162 void
163 AstNode::optRetVal(AstNode *opt) {
164
165     if (oType == ReturnVal) {
166         cout << "Optimazed Return." << endl;
167         if (loperand == 0) {
168             loperand = opt;
169             return;
170         } else if (opt == 0) {
171             delete loperand;
172             loperand = NULL;
173             return; 
174         }
175     }
176     if (loperand) loperand->optRetVal(opt);
177     if (roperand) roperand->optRetVal(opt);
178     for (unsigned i = 0; i < operands.size(); i++) 
179         operands[i] -> optRetVal(opt);
180 }
181
182 /****************************************************************************/
183 /****************************************************************************/
184 /****************************************************************************/
185
186 bool 
187 processOptimaRet(instPoint *location, AstNode *&ast) {
188
189     // For optimazed return code
190     if (location -> ipType == functionExit) {
191         if ((isInsnType(location -> originalInstruction, RETmask, RETmatch)) ||
192             (isInsnType(location -> originalInstruction, RETLmask, RETLmatch)))
193         {
194             if (isInsnType(location -> delaySlotInsn, 
195                            RESTOREmask, RESTOREmatch)&&
196                 ((location->delaySlotInsn.raw | 0xc1e82000) != 0xc1e82000)) 
197             {
198                 /* cout << "Optimazed Retrun Value:  Addr " << hex << 
199                     location->addr << " in "
200                         << location -> func -> prettyName() << endl; */
201                 AstNode *opt = new AstNode(AstNode::Constant,
202                                            (void *)location->delaySlotInsn.raw);
203                 ast -> optRetVal(opt);
204                 return true;
205             }
206         }
207     }
208     return false;
209 }
210
211 /****************************************************************************/
212 /****************************************************************************/
213 /****************************************************************************/
214
215 Register
216 emitOptReturn(instruction i, Register src, char *insn, Address &base, bool noCost) {
217     
218     unsigned instr = i.raw;
219
220     cout << "Handling a special case for optimized return value." << endl;
221
222     assert(((instr&0x3e000000)>>25) <= 16);
223
224     if ((instr&0x02000)>>13)
225         emitImm(plusOp, (instr&0x07c000)>>14, instr&0x01fff,
226                 ((instr&0x3e000000)>>25)+16, insn, base, noCost);
227     else
228         (void) emitV(plusOp, (instr&0x07c000)>>14, instr&0x01fff,
229              ((instr&0x3e000000)>>25)+16, insn, base, noCost);
230     
231     return emitR(getSysRetValOp, 0, 0, src, insn, base, noCost);
232 }
233
234 /****************************************************************************/
235 /****************************************************************************/
236 /****************************************************************************/
237
238 //
239 // initDefaultPointFrequencyTable - define the expected call frequency of
240 //    procedures.  Currently we just define several one shots with a
241 //    frequency of one, and provide a hook to read a file with more accurate
242 //    information.
243 //
244 void initDefaultPointFrequencyTable()
245 {
246     FILE *fp;
247     float value;
248     char name[512];
249
250     funcFrequencyTable["main"] = 1;
251     funcFrequencyTable["DYNINSTsampleValues"] = 1;
252     funcFrequencyTable[EXIT_NAME] = 1;
253
254     // try to read file.
255     fp = fopen("freq.input", "r");
256     if (!fp) {
257         return;
258     } else {
259         printf("found freq.input file\n");
260     }
261     while (!feof(fp)) {
262         fscanf(fp, "%s %f\n", name, &value);
263         funcFrequencyTable[name] = (int) value;
264         printf("adding %s %f\n", name, value);
265     }
266     fclose(fp);
267 }
268
269 /****************************************************************************/
270 /****************************************************************************/
271 /****************************************************************************/
272
273 /*
274  * Get an estimate of the frequency for the passed instPoint.  
275  *    This is not (always) the same as the function that contains the point.
276  * 
277  *  The function is selected as follows:
278  *
279  *  If the point is an entry or an exit return the function name.
280  *  If the point is a call and the callee can be determined, return the called
281  *     function.
282  *  else return the funcation containing the point.
283  *
284  *  WARNING: This code contins arbitray values for func frequency (both user 
285  *     and system).  This should be refined over time.
286  *
287  * Using 1000 calls sec to be one SD from the mean for most FPSPEC apps.
288  *      -- jkh 6/24/94
289  *
290  */
291 float getPointFrequency(instPoint *point)
292 {
293
294     pd_Function *func;
295
296     if (point->callee)
297         func = point->callee;
298     else
299         func = point->func;
300
301     if (!funcFrequencyTable.defines(func->prettyName())) {
302       // Changing this value from 250 to 100 because predictedCost was
303       // too high - naim 07/18/96
304       return(100); 
305       
306     } else {
307       return (funcFrequencyTable[func->prettyName()]);
308     }
309 }
310
311 /****************************************************************************/
312 /****************************************************************************/
313 /****************************************************************************/
314
315 //
316 // return cost in cycles of executing at this point.  This is the cost
317 //   of the base tramp if it is the first at this point or 0 otherwise.
318 //
319 int getPointCost(process *proc, const instPoint *point)
320 {
321     if (proc->baseMap.defines(point)) {
322         return(0);
323     } else {
324         // 70 cycles for base tramp (worst case)
325         return(70);
326     }
327 }
328
329 /****************************************************************************/
330 /****************************************************************************/
331 /****************************************************************************/
332
333 void initATramp (trampTemplate *thisTemp, Address tramp,
334                  bool isConservative=false)
335 {
336     instruction *temp;
337
338     if(!isConservative){
339
340         thisTemp->savePreInsOffset = 
341                         ((Address)baseTramp_savePreInsn - tramp);
342         thisTemp->restorePreInsOffset = 
343                         ((Address)baseTramp_restorePreInsn - tramp);
344         thisTemp->savePostInsOffset = 
345                         ((Address)baseTramp_savePostInsn - tramp);
346         thisTemp->restorePostInsOffset = 
347                         ((Address)baseTramp_restorePostInsn - tramp);
348     }else{
349         thisTemp->savePreInsOffset =
350                 ((Address)conservativeBaseTramp_savePreInsn - tramp);
351         thisTemp->restorePreInsOffset =
352                 ((Address)conservativeBaseTramp_restorePreInsn - tramp);
353         thisTemp->savePostInsOffset =
354                 ((Address)conservativeBaseTramp_savePostInsn - tramp);
355         thisTemp->restorePostInsOffset =
356                 ((Address)conservativeBaseTramp_restorePostInsn - tramp);
357     }
358
359     // TODO - are these offsets always positive?
360     thisTemp->trampTemp = (void *) tramp;
361     for (temp = (instruction*)tramp; temp->raw != END_TRAMP; temp++) {
362         const Address offset = (Address)temp - tramp;
363         switch (temp->raw) {
364             case LOCAL_PRE_BRANCH:
365                 thisTemp->localPreOffset = offset;
366                 thisTemp->localPreReturnOffset = thisTemp->localPreOffset 
367                                                 + sizeof(temp->raw);
368                 break;
369             case GLOBAL_PRE_BRANCH:
370                 thisTemp->globalPreOffset = offset;
371                 break;
372             case LOCAL_POST_BRANCH:
373                 thisTemp->localPostOffset = offset;
374                 thisTemp->localPostReturnOffset = thisTemp->localPostOffset
375                                                 + sizeof(temp->raw);
376                 break;
377             case GLOBAL_POST_BRANCH:
378                 thisTemp->globalPostOffset = offset;
379                 break;
380             case SKIP_PRE_INSN:
381                 thisTemp->skipPreInsOffset = offset;
382                 break;
383             case UPDATE_COST_INSN:
384                 thisTemp->updateCostOffset = offset;
385                 break;
386             case SKIP_POST_INSN:
387                 thisTemp->skipPostInsOffset = offset;
388                 break;
389             case RETURN_INSN:
390                 thisTemp->returnInsOffset = offset;
391                 break;
392             case EMULATE_INSN:
393                 thisTemp->emulateInsOffset = offset;
394                 break;
395             case CONSERVATIVE_TRAMP_READ_CONDITION:
396                 if(isConservative)
397                         temp->raw = 0x83408000; /*read condition codes to g1*/
398                 break;
399             case CONSERVATIVE_TRAMP_WRITE_CONDITION:
400                 if(isConservative)
401                         temp->raw = 0x85806000; /*write condition codes fromg1*/
402                 break;
403         }       
404     }
405
406     // Cost with the skip branches.
407     thisTemp->cost = 14;  
408     thisTemp->prevBaseCost = 20 +
409       RECURSIVE_GUARD_ON_CODE_SIZE + RECURSIVE_GUARD_OFF_CODE_SIZE;
410     thisTemp->postBaseCost = 22 +
411       RECURSIVE_GUARD_ON_CODE_SIZE + RECURSIVE_GUARD_OFF_CODE_SIZE;
412     thisTemp->prevInstru = thisTemp->postInstru = false;
413     thisTemp->size = (int) temp - (int) tramp;
414 }
415
416 /****************************************************************************/
417 /****************************************************************************/
418 /****************************************************************************/
419
420 void initATramp(NonRecursiveTrampTemplate *thisTemp, Address tramp,
421                 bool isConservative=false)
422 {
423   initATramp((trampTemplate *)thisTemp, tramp,isConservative);
424
425   instruction *temp;
426
427   for (temp = (instruction*)tramp; temp->raw != END_TRAMP; temp++) {
428     const Address offset = (Address)temp - tramp;
429     switch (temp->raw)
430       {
431
432       case RECURSIVE_GUARD_ON_PRE_INSN:
433         thisTemp->guardOnPre_beginOffset = offset;
434         thisTemp->guardOnPre_endOffset = thisTemp->guardOnPre_beginOffset
435                 + RECURSIVE_GUARD_ON_CODE_SIZE * INSN_SIZE;
436         break;
437
438       case RECURSIVE_GUARD_OFF_PRE_INSN:
439         thisTemp->guardOffPre_beginOffset = offset;
440         thisTemp->guardOffPre_endOffset = thisTemp->guardOffPre_beginOffset
441                 + RECURSIVE_GUARD_OFF_CODE_SIZE * INSN_SIZE;
442         break;
443
444       case RECURSIVE_GUARD_ON_POST_INSN:
445         thisTemp->guardOnPost_beginOffset = offset;
446         thisTemp->guardOnPost_endOffset = thisTemp->guardOnPost_beginOffset
447                 + RECURSIVE_GUARD_ON_CODE_SIZE * INSN_SIZE;
448         break;
449
450       case RECURSIVE_GUARD_OFF_POST_INSN:
451         thisTemp->guardOffPost_beginOffset = offset;
452         thisTemp->guardOffPost_endOffset = thisTemp->guardOffPost_beginOffset
453                 + RECURSIVE_GUARD_OFF_CODE_SIZE * INSN_SIZE;
454         break;
455
456       }
457   }
458 }
459
460 /****************************************************************************/
461 /****************************************************************************/
462 /****************************************************************************/
463
464 void initTramps()
465 {
466     static bool inited=false;
467
468     if (inited) return;
469     inited = true;
470
471     initATramp(&baseTemplate, (Address) baseTramp);
472     initATramp(&nonRecursiveBaseTemplate, (Address)baseTramp);
473
474
475     initATramp(&conservativeBaseTemplate,
476                (Address)conservativeBaseTramp,true);
477     initATramp(&nonRecursiveConservativeBaseTemplate,
478                (Address)conservativeBaseTramp,true);
479
480     regSpace = new registerSpace(sizeof(deadList)/sizeof(Register), deadList,
481                                          0, NULL);
482     assert(regSpace);
483 }
484
485 /****************************************************************************/
486 /****************************************************************************/
487 /****************************************************************************/
488
489 #if defined(MT_THREAD)
490 //
491 // For multithreaded applications and shared memory sampling, this routine 
492 // will compute the address where the corresponding counter/timer vector for
493 // level 0 is (by default). In the mini-tramp, if the counter/timer is at a
494 // different level, we will add the corresponding offset - naim 4/18/97
495 //
496 // NUM_INSN_MT_PREAMBLE
497 void generateMTpreamble(char *insn, Address &base, process *proc)
498 {
499   AstNode *t1 ;
500   Address tableAddr;
501   int value; 
502   bool err;
503   unsigned offset = 19*sizeof(instruction);
504   Register src = Null_Register;
505
506   vector<AstNode *> dummy;
507
508   t1 = new AstNode("DYNINSTthreadPos", dummy);
509
510   // t2=DYNINSTthreadPos()*sizeof(unsigned)
511   value = sizeof(unsigned);
512   AstNode* t4 = new AstNode(AstNode::Constant,(void *)value);
513   AstNode* t2 = new AstNode(timesOp, t1, t4);
514   removeAst(t1) ;
515   removeAst(t4) ;
516
517   // t3=DYNINSTthreadTable+t2
518   //
519   tableAddr = proc->findInternalAddress("DYNINSTthreadTable",true,err);
520   assert(!err);
521   AstNode* t5 = new AstNode(AstNode::Constant, (void *)tableAddr);
522   AstNode* t3 = new AstNode(plusOp, t2, t5);
523   removeAst(t2);
524   removeAst(t5);
525
526   AstNode* t7 = new AstNode(AstNode::Constant,(void *)-2);
527   AstNode* t8 = new AstNode(eqOp, t1, t7);
528   removeAst(t7);
529   AstNode* t9 = new AstNode(AstNode::Constant, (void *)(offset));
530   //goto offset
531   AstNode* t10 = new AstNode(branchOp, t9);
532   removeAst(t9);
533   //t11 = "if(t1 ==-2) goto offset"
534   AstNode* t11 = new AstNode(ifOp, t8, t10);
535   removeAst(t8);
536   removeAst(t10) ;
537
538   //t6 = " if (t1 == -2) goto Offset; t3=DYNINSTthreadTable+t2"
539   AstNode *t6= new AstNode(t11, t3);
540   removeAst(t11);
541   removeAst(t3);
542   src = t6->generateCode(proc, regSpace, insn, base, false, true);
543   removeAst(t6);
544   (void) emitV(orOp, src, 0, REG_MT, insn, base, false);
545   regSpace->freeRegister(src);
546 }
547
548 /****************************************************************************/
549 /****************************************************************************/
550 /****************************************************************************/
551
552 void generateRPCpreamble(char *insn, Address &base, process *proc, unsigned offset, int tid, unsigned pos)
553 {
554   AstNode *t1 ;
555   Address tableAddr;
556   int value; 
557   bool err;
558   Register src = Null_Register;
559
560   if (tid != -1)  {
561     vector<AstNode *> param;
562     param += new AstNode(AstNode::Constant,(void *)tid);
563     param += new AstNode(AstNode::Constant,(void *)pos);
564     t1 = new AstNode("DYNINSTthreadPosTID", param);
565     for (unsigned i=0; i<param.size(); i++) 
566       removeAst(param[i]) ;
567
568     value = sizeof(unsigned);
569     AstNode* t4 = new AstNode(AstNode::Constant,(void *)value);
570     AstNode* t2 = new AstNode(timesOp, t1, t4);
571     removeAst(t1) ;
572     removeAst(t4) ;
573
574     // t3=DYNINSTthreadTable[thr_self()]
575     //
576     tableAddr = proc->findInternalAddress("DYNINSTthreadTable",true,err);
577     assert(!err);
578     AstNode* t5 = new AstNode(AstNode::Constant, (void *)tableAddr);
579     AstNode* t3 = new AstNode(plusOp, t2, t5);
580     removeAst(t2);
581     removeAst(t5);
582
583     AstNode* t7 = new AstNode(AstNode::Constant,(void *)-2);
584     AstNode* t8 = new AstNode(eqOp, t1, t7);
585     removeAst(t7);
586     AstNode* t9 = new AstNode(AstNode::Constant, (void *)(offset));
587     AstNode* t10 = new AstNode(branchOp, t9);
588     removeAst(t9);
589     AstNode* t11 = new AstNode(ifOp, t8, t10);
590     removeAst(t8);
591     removeAst(t10);
592
593     AstNode *t6= new AstNode(t11, t3);
594     removeAst(t11);
595     removeAst(t3);
596     src = t6->generateCode(proc, regSpace, insn, base, false, true);
597     removeAst(t6);
598     unsigned first_insn=base;
599     (void) emitV(orOp, src, 0, REG_MT, insn, base, false);
600     regSpace->freeRegister(src);
601   }
602 }
603 #endif
604
605 /****************************************************************************/
606 /****************************************************************************/
607 /****************************************************************************/
608
609 void generateNoOp(process *proc, Address addr)
610 {
611     instruction insn;
612
613     /* fill with no-op */
614     insn.raw = 0;
615     insn.branch.op = 0;
616     insn.branch.op2 = NOOPop2;
617
618     proc->writeTextWord((caddr_t)addr, insn.raw);
619 }
620
621
622 /****************************************************************************/
623 /****************************************************************************/
624 /****************************************************************************/
625
626 /*
627  * change the insn at addr to be a branch to newAddr.
628  *   Used to add multiple tramps to a point.
629  */
630 void generateBranch(process *proc, Address fromAddr, Address newAddr)
631 {
632     int disp;
633     instruction insn;
634
635     disp = newAddr-fromAddr;
636     generateBranchInsn(&insn, disp);
637
638     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
639 }
640
641 /****************************************************************************/
642 /****************************************************************************/
643 /****************************************************************************/
644
645 void generateCall(process *proc, Address fromAddr, Address newAddr)
646 {
647     instruction insn; 
648     generateCallInsn(&insn, fromAddr, newAddr);
649
650     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
651
652 }
653
654 /****************************************************************************/
655 /****************************************************************************/
656 /****************************************************************************/
657
658 void genImm(process *proc, Address fromAddr, int op, 
659                         Register rs1, int immd, Register rd)
660 {
661     instruction insn;
662     genImmInsn(&insn, op, rs1, immd, rd);
663
664     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
665 }
666
667 /****************************************************************************/
668 /****************************************************************************/
669 /****************************************************************************/
670
671 /*
672  *  change the target of the branch at fromAddr, to be newAddr.
673  */
674 void changeBranch(process *proc, Address fromAddr, Address newAddr, 
675                   instruction originalBranch) {
676     int disp = newAddr-fromAddr;
677     instruction insn;
678     insn.raw = originalBranch.raw;
679     insn.branch.disp22 = disp >> 2;
680     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
681 }
682
683 /****************************************************************************/
684 /****************************************************************************/
685 /****************************************************************************/
686
687 int callsTrackedFuncP(instPoint *point)
688 {
689     if (point->callIndirect) {
690         return(true);
691     } else {
692         if (point->callee) {
693             return(true);
694         } else {
695             return(false);
696         }
697     }
698 }
699
700 /****************************************************************************/
701 /****************************************************************************/
702 /****************************************************************************/
703
704 /*
705  * return the function asociated with a point.
706  *
707  *     If the point is a funcation call, and we know the function being called,
708  *          then we use that.  Otherwise it is the function that contains the
709  *          point.
710  *  
711  *   This is done to return a better idea of which function we are using.
712  */
713 pd_Function *getFunction(instPoint *point)
714 {
715     return(point->callee ? point->callee : point->func);
716 }
717
718 /****************************************************************************/
719 /****************************************************************************/
720 /****************************************************************************/
721
722 bool process::emitInferiorRPCheader(void *insnPtr, Address &baseBytes) {
723    instruction *insn = (instruction *)insnPtr;
724    Address baseInstruc = baseBytes / sizeof(instruction);
725
726    genImmInsn(&insn[baseInstruc++], SAVEop3, 14, -112, 14);
727
728    baseBytes = baseInstruc * sizeof(instruction); // convert back
729    return true;
730 }
731
732
733 /****************************************************************************/
734 /****************************************************************************/
735 /****************************************************************************/
736
737 bool process::emitInferiorRPCtrailer(void *insnPtr, Address &baseBytes,
738                                      unsigned &breakOffset,
739                                      bool stopForResult,
740                                      unsigned &stopForResultOffset,
741 #if defined(MT_THREAD)
742                                      unsigned &justAfter_stopForResultOffset,
743                                      bool isSafeRPC) {
744 #else
745                                      unsigned &justAfter_stopForResultOffset) {
746 #endif
747    // Sequence: restore, trap, illegal
748
749    instruction *insn = (instruction *)insnPtr;
750    Address baseInstruc = baseBytes / sizeof(instruction);
751
752    if (stopForResult) {
753       // trap insn:
754       genBreakpointTrap(&insn[baseInstruc]);
755       stopForResultOffset = baseInstruc * sizeof(instruction);
756       baseInstruc++;
757       justAfter_stopForResultOffset = baseInstruc * sizeof(instruction);
758    }
759
760 #if defined(MT_THREAD)
761    if (isSafeRPC) //ret instruction
762      genImmInsn(&insn[baseInstruc++], JMPLop3, REG_I(7), 0x08, REG_G(0)) ;
763 #endif
764    genSimpleInsn(&insn[baseInstruc++], RESTOREop3, 0, 0, 0);
765
766    // Now that the inferior has executed the 'restore' instruction, the %in and
767    // %local registers have been restored.  We mustn't modify them after this point!!
768    // (reminder: the %in and %local registers aren't saved and set with ptrace
769    //  GETREGS/SETREGS call)
770
771 #if defined(MT_THREAD)
772    if (!isSafeRPC) {
773 #endif
774      // Trap instruction:
775      genBreakpointTrap(&insn[baseInstruc]); // ta 1
776      breakOffset = baseInstruc * sizeof(instruction);
777      baseInstruc++;
778
779      // And just to make sure that we don't continue from the trap:
780      genUnimplementedInsn(&insn[baseInstruc++]); // UNIMP 0
781 #if defined(MT_THREAD)
782    }
783 #endif
784    baseBytes = baseInstruc * sizeof(instruction); // convert back
785
786    return true; // success
787 }
788
789 /****************************************************************************/
790 /****************************************************************************/
791 /****************************************************************************/
792
793 void emitImm(opCode op, Register src1, RegValue src2imm, Register dest, 
794              char *i, Address &base, bool noCost)
795 {
796         instruction *insn = (instruction *) ((void*)&i[base]);
797         RegValue op3 = -1;
798         int result = -1;
799         switch (op) {
800             // integer ops
801             case plusOp:
802                 op3 = ADDop3;
803                 genImmInsn(insn, op3, src1, src2imm, dest);
804                 break;
805
806             case minusOp:
807                 op3 = SUBop3;
808                 genImmInsn(insn, op3, src1, src2imm, dest);
809                 break;
810
811             case timesOp:
812                 op3 = SMULop3;
813                 if (isPowerOf2(src2imm,result) && (result<32))
814                   generateLShift(insn, src1, (Register)result, dest);           
815                 else 
816                   genImmInsn(insn, op3, src1, src2imm, dest);
817                 break;
818
819             case divOp:
820                 op3 = SDIVop3;
821                 if (isPowerOf2(src2imm,result) && (result<32))
822                   generateRShift(insn, src1, (Register)result, dest);           
823                 else { // needs to set the Y register to zero first
824                   // Set the Y register to zero: Zhichen
825                   genImmInsn(insn, WRYop3, REG_G(0), 0, 0);
826                   base += sizeof(instruction);
827                   insn = (instruction *) ((void*)&i[base]);
828                   genImmInsn(insn, op3, src1, src2imm, dest);
829                 }
830
831                 break;
832
833             // Bool ops
834             case orOp:
835                 op3 = ORop3;
836                 genImmInsn(insn, op3, src1, src2imm, dest);
837                 break;
838
839             case andOp:
840                 op3 = ANDop3;
841                 genImmInsn(insn, op3, src1, src2imm, dest);
842                 break;
843
844             // rel ops
845             // For a particular condition (e.g. <=) we need to use the
846             // the opposite in order to get the right value (e.g. for >=
847             // we need BLTcond) - naim
848             case eqOp:
849                 genImmRelOp(insn, BNEcond, src1, src2imm, dest, base);
850                 return;
851                 break;
852
853             case neOp:
854                 genImmRelOp(insn, BEcond, src1, src2imm, dest, base);
855                 return;
856                 break;
857
858             case lessOp:
859                 genImmRelOp(insn, BGEcond, src1, src2imm, dest, base);
860                 return;
861                 break;
862
863             case leOp:
864                 genImmRelOp(insn, BGTcond, src1, src2imm, dest, base);
865                 return;
866                 break;
867
868             case greaterOp:
869                 genImmRelOp(insn, BLEcond, src1, src2imm, dest, base);
870                 return;
871                 break;
872
873             case geOp:
874                 genImmRelOp(insn, BLTcond, src1, src2imm, dest, base);
875                 return;
876                 break;
877
878             default:
879                 Register dest2 = regSpace->allocateRegister(i, base, noCost);
880                 (void) emitV(loadConstOp, src2imm, dest2, dest2, i, base, noCost);
881                 (void) emitV(op, src1, dest2, dest, i, base, noCost);
882                 regSpace->freeRegister(dest2);
883                 return;
884                 break;
885         }
886         base += sizeof(instruction);
887         return;
888 }
889
890 /****************************************************************************/
891 /****************************************************************************/
892 /****************************************************************************/
893
894 //
895 // All values based on Cypress0 && Cypress1 implementations as documented in
896 //   SPARC v.8 manual p. 291
897 //
898 int getInsnCost(opCode op)
899 {
900     /* XXX Need to add branchOp */
901     if (op == loadConstOp) {
902         return(1);
903     } else if (op ==  loadOp) {
904         // sethi + load single
905         return(1+1);
906     } else if (op ==  loadIndirOp) {
907         return(1);
908     } else if (op ==  storeOp) {
909         // sethi + store single
910         // return(1+3); 
911         // for SS-5 ?
912         return(1+2); 
913     } else if (op ==  storeIndirOp) {
914         return(2); 
915     } else if (op ==  ifOp) {
916         // subcc
917         // be
918         // nop
919         return(1+1+1);
920     } else if (op ==  callOp) {
921         int count = 0;
922
923         // mov src1, %o0
924         count += 1;
925
926         // mov src2, %o1
927         count += 1;
928
929         // clr i2
930         count += 1;
931
932         // clr i3
933         count += 1;
934
935         // sethi
936         count += 1;
937
938         // jmpl
939         count += 1;
940
941         // noop
942         count += 1;
943
944         return(count);
945     } else if (op ==  updateCostOp) {
946         // sethi %hi(obsCost), %l0
947         // ld [%lo + %lo(obsCost)], %l1
948         // add %l1, <cost>, %l1
949         // st %l1, [%lo + %lo(obsCost)]
950         return(1+2+1+3);
951     } else if (op ==  trampPreamble) {
952         return(0);
953     } else if (op ==  trampTrailer) {
954         // retl
955         return(2);
956     } else if (op == noOp) {
957         // noop
958         return(1);
959     } else if (op == getParamOp) {
960         return(0);
961     } else {
962         switch (op) {
963             // rel ops
964             case eqOp:
965             case neOp:
966             case lessOp:
967             case leOp:
968             case greaterOp:
969             case geOp:
970                 // bne -- assume taken
971                 return(2);
972                 break;
973             default:
974                 return(1);
975                 break;
976         }
977     }
978 }
979
980 /****************************************************************************/
981 /****************************************************************************/
982 /****************************************************************************/
983
984 bool isReturnInsn(instruction instr, Address addr, string name) {
985     if (isInsnType(instr, RETmask, RETmatch) ||
986         isInsnType(instr, RETLmask, RETLmatch)) {
987         //  Why 8 or 12?
988         //  According to the sparc arch manual (289), ret or retl are
989         //   synthetic instructions for jmpl %i7+8, %g0 or jmpl %o7+8, %go.
990         //  Apparently, the +8 is not really a hard limit though, as 
991         //   sometimes some extra space is allocated after the jump 
992         //   instruction for various reasons.
993         //  1 possible reason is to include information on the size of
994         //   returned structure (4 bytes).
995         //  So, 8 or 12 here is a heuristic, but doesn't seem to 
996         //   absolutely have to be true.
997         //  -matt
998         if ((instr.resti.simm13 != 8) && (instr.resti.simm13 != 12) 
999                     && (instr.resti.simm13 != 16)) {
1000           sprintf(errorLine,"WARNING: unsupported return at address 0x%lx"
1001                         " in function %s - appears to be return to PC + %i", 
1002                   addr, name.string_of(), (int)instr.resti.simm13);
1003           showErrorCallback(55, errorLine);
1004         } else { 
1005           return true;
1006         }
1007     }
1008     return false;
1009 }
1010
1011 /****************************************************************************/
1012 /****************************************************************************/
1013 /****************************************************************************/
1014
1015 bool isReturnInsn(const image *owner, Address adr, bool &lastOne, string name)
1016 {
1017     instruction instr;
1018
1019     instr.raw = owner->get_instruction(adr);
1020     lastOne = false;
1021
1022     return isReturnInsn(instr, adr, name);
1023 }
1024
1025 /****************************************************************************/
1026 /****************************************************************************/
1027 /****************************************************************************/
1028
1029 bool isBranchInsn(instruction instr) {
1030     if (instr.branch.op == 0 
1031                 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) 
1032           return true;
1033     return false;
1034 }
1035
1036 /****************************************************************************/
1037 /****************************************************************************/
1038 /****************************************************************************/
1039
1040 // modifyInstPoint: if the function associated with the process was 
1041 // recently relocated, then the instPoint may have the old pre-relocated
1042 // address (this can occur because we are getting instPoints in mdl routines 
1043 // and passing these to routines that do the instrumentation, it would
1044 // be better to let the routines that do the instrumenting find the points)
1045 void pd_Function::modifyInstPoint(const instPoint *&location,process *proc)
1046 {
1047
1048     if(relocatable_ && !(location->relocated_)){
1049         for(u_int i=0; i < relocatedByProcess.size(); i++){
1050             if((relocatedByProcess[i])->getProcess() == proc){
1051                 if(location->ipType == functionEntry){
1052                     const instPoint *new_entry = 
1053                                 (relocatedByProcess[i])->funcEntry();
1054                     location = new_entry;
1055                 } 
1056                 else if(location->ipType == functionExit){
1057                     const vector<instPoint *> new_returns = 
1058                         (relocatedByProcess[i])->funcReturns(); 
1059                     if(funcReturns.size() != new_returns.size()){
1060                         printf("funcReturns = %d new_returns = %d\n",
1061                                 funcReturns.size(),new_returns.size());
1062                         fflush(stdout);
1063                     }
1064                     assert(funcReturns.size() == new_returns.size());
1065                     for(u_int j=0; j < new_returns.size(); j++){
1066                         if(funcReturns[j] == location){
1067                             location = (new_returns[j]);
1068                             break;
1069                         }
1070                     }
1071                 }
1072                 else if(location->ipType == otherPoint) {
1073                     const vector<instPoint *> new_arbitrary = 
1074                         (relocatedByProcess[i])->funcArbitraryPoints(); 
1075
1076                     assert(arbitraryPoints.size() == new_arbitrary.size());
1077                     for(u_int j=0; j < new_arbitrary.size(); j++){
1078                         if(arbitraryPoints[j] == location){
1079                             location = (new_arbitrary[j]);
1080                             break;
1081                         }
1082                     }
1083                 }
1084                 else {
1085                     const vector<instPoint *> new_calls = 
1086                                 (relocatedByProcess[i])->funcCallSites(); 
1087                     assert(calls.size() == new_calls.size());
1088                     for(u_int j=0; j < new_calls.size(); j++){
1089                         if(calls[j] == location){
1090                             location = (new_calls[j]);
1091                             break;
1092                         }
1093                     }
1094
1095                 }
1096                 break;
1097     } } }
1098 }
1099
1100 /****************************************************************************/
1101 /****************************************************************************/
1102 /****************************************************************************/
1103
1104 // The exact semantics of the heap are processor specific.
1105 //
1106 // find all DYNINST symbols that are data symbols
1107 //
1108 bool process::heapIsOk(const vector<sym_data> &find_us) {
1109   Symbol sym;
1110   Address baseAddr;
1111
1112   // find the main function
1113   // first look for main or _main
1114   if (!((mainFunction = findOneFunction("main")) 
1115         || (mainFunction = findOneFunction("_main")))) {
1116      string msg = "Cannot find main. Exiting.";
1117      statusLine(msg.string_of());
1118 #if defined(BPATCH_LIBRARY)
1119      BPatch_reportError(BPatchWarning, 50, msg.string_of());
1120 #else
1121      showErrorCallback(50, msg);
1122 #endif
1123      return false;
1124   }
1125
1126   for (unsigned i=0; i<find_us.size(); i++) {
1127     const string &str = find_us[i].name;
1128     if (!getSymbolInfo(str, sym, baseAddr)) {
1129       string str1 = string("_") + str.string_of();
1130       if (!getSymbolInfo(str1, sym, baseAddr) && find_us[i].must_find) {
1131         string msg;
1132         msg = string("Cannot find ") + str + string(". Exiting");
1133         statusLine(msg.string_of());
1134         showErrorCallback(50, msg);
1135         return false;
1136       }
1137     }
1138   }
1139
1140 //  string ghb = GLOBAL_HEAP_BASE;
1141 //  if (!getSymbolInfo(ghb, sym, baseAddr)) {
1142 //    ghb = U_GLOBAL_HEAP_BASE;
1143 //    if (!linkedFile.get_symbol(ghb, sym)) {
1144 //      string msg;
1145 //      msg = string("Cannot find ") + ghb + string(". Exiting");
1146 //      statusLine(msg.string_of());
1147 //      showErrorCallback(50, msg);
1148 //      return false;
1149 //    }
1150 //  }
1151 //  Address instHeapEnd = sym.addr()+baseAddr;
1152 //  addInternalSymbol(ghb, instHeapEnd);
1153
1154
1155 #ifdef ndef
1156   /* Not needed with the new heap type system */
1157
1158   string ihb = INFERIOR_HEAP_BASE;
1159   if (!getSymbolInfo(ihb, sym, baseAddr)) {
1160     ihb = UINFERIOR_HEAP_BASE;
1161     if (!getSymbolInfo(ihb, sym, baseAddr)) {
1162       string msg;
1163       msg = string("Cannot find ") + ihb + string(". Cannot use this application");
1164       statusLine(msg.string_of());
1165       showErrorCallback(50, msg);
1166       return false;
1167     }
1168   }
1169
1170   Address curr = sym.addr()+baseAddr;
1171   // Check that we can patch up user code to jump to our base trampolines
1172   // (Perhaps this code is no longer needed for sparc platforms, since we use full
1173   // 32-bit jumps)
1174   const Address instHeapStart = curr;
1175   const Address instHeapEnd = instHeapStart + SYN_INST_BUF_SIZE - 1;
1176
1177   if (instHeapEnd > getMaxBranch3Insn()) {
1178     logLine("*** FATAL ERROR: Program text + data too big for dyninst\n");
1179     sprintf(errorLine, "    heap starts at %x and ends at %x; maxbranch=%x\n",
1180             instHeapStart, instHeapEnd, getMaxBranch3Insn());
1181     logLine(errorLine);
1182     return false;
1183   }
1184 #endif
1185
1186   return true;
1187 }
1188
1189 /****************************************************************************/
1190 /****************************************************************************/
1191 /****************************************************************************/
1192
1193 // Certain registers (i0-i7 on a SPARC) may be available to be read
1194 // as an operand, but cannot be written.
1195 bool registerSpace::readOnlyRegister(Register /*reg_number*/) {
1196 // -- this code removed, since it seems incorrect
1197 //if ((reg_number < REG_L(0)) || (reg_number > REG_L(7)))
1198 //    return true;
1199 //else
1200       return false;
1201 }
1202
1203 /****************************************************************************/
1204 /****************************************************************************/
1205 /****************************************************************************/
1206
1207 bool returnInstance::checkReturnInstance(const vector<Address> &stack, u_int &index) {
1208     // If false (unsafe) is returned, then 'index' is set to the first unsafe call stack
1209     // index.
1210
1211   //    cout << "checkReturnInstance: addr_=" << (void*)addr_ << "; size_=" <<
1212   //            (void*)size_ << endl;
1213   //    cout << "instruction sequence is:" << endl;
1214   //    for (unsigned i=0; i < instSeqSize/4; i ++)
1215   //       cout << (void*)instructionSeq[i].raw << endl;
1216   //    cout << endl;
1217   //    
1218   //    for (unsigned i=0; i < stack.size(); i++)
1219   //       cout << (void*)stack[i] << endl;
1220
1221     for (u_int i=0; i < stack.size(); i++) {
1222         index = i;
1223
1224         // Is the following check correct?  Shouldn't the ">" be changed to ">=",
1225         // and the "<=" be changed to "<" ??? --ari 6/11/97
1226         if (stack[i] > addr_ && stack[i] <= addr_+size_)
1227             return false;
1228     }
1229
1230     return true;
1231 }
1232
1233 /****************************************************************************/
1234 /****************************************************************************/
1235 /****************************************************************************/
1236
1237 void returnInstance::installReturnInstance(process *proc) {
1238     proc->writeTextSpace((caddr_t)addr_, instSeqSize, 
1239                          (caddr_t) instructionSeq); 
1240         installed = true;
1241 }
1242
1243 /****************************************************************************/
1244 /****************************************************************************/
1245 /****************************************************************************/
1246
1247 void generateBreakPoint(instruction &insn) {
1248     insn.raw = BREAK_POINT_INSN;
1249 }
1250
1251 /****************************************************************************/
1252 /****************************************************************************/
1253 /****************************************************************************/
1254
1255 void returnInstance::addToReturnWaitingList(Address pc, process *proc) {
1256     // if there already is a TRAP set at this pc for this process don't
1257     // generate a trap instruction again...you will get the wrong original
1258     // instruction if you do a readDataSpace
1259     bool found = false;
1260     instruction insn;
1261     for (u_int i=0; i < instWList.size(); i++) {
1262          if (instWList[i]->pc_ == pc && instWList[i]->which_proc == proc) {
1263              found = true;
1264              insn = instWList[i]->relocatedInstruction;
1265              break;
1266          }
1267     }
1268     if(!found) {
1269         instruction insnTrap;
1270         generateBreakPoint(insnTrap);
1271         proc->readDataSpace((caddr_t)pc, sizeof(insn), (char *)&insn, true);
1272         proc->writeTextSpace((caddr_t)pc, sizeof(insnTrap), (caddr_t)&insnTrap);
1273     }
1274     else {
1275     }
1276
1277     instWaitingList *instW = new instWaitingList(instructionSeq,instSeqSize,
1278                                                  addr_,pc,insn,pc,proc);
1279     instWList.push_back(instW);
1280 }
1281
1282 /****************************************************************************/
1283 /****************************************************************************/
1284 /****************************************************************************/
1285
1286 bool doNotOverflow(int value)
1287 {
1288   // we are assuming that we have 13 bits to store the immediate operand.
1289   //if ( (value <= 16383) && (value >= -16384) ) return(true);
1290   if ( (value <= MAX_IMM13) && (value >= MIN_IMM13) ) return(true);
1291   else return(false);
1292 }
1293
1294 /****************************************************************************/
1295 /****************************************************************************/
1296 /****************************************************************************/
1297
1298 void instWaitingList::cleanUp(process *proc, Address pc) {
1299     proc->writeTextSpace((caddr_t)pc, sizeof(relocatedInstruction),
1300                     (caddr_t)&relocatedInstruction);
1301     proc->writeTextSpace((caddr_t)addr_, instSeqSize, (caddr_t)instructionSeq);
1302 }
1303
1304 /****************************************************************************/
1305 /****************************************************************************/
1306 /****************************************************************************/
1307
1308 // process::replaceFunctionCall
1309 //
1310 // Replace the function call at the given instrumentation point with a call to
1311 // a different function, or with a NOOP.  In order to replace the call with a
1312 // NOOP, pass NULL as the parameter "func."
1313 // Returns true if sucessful, false if not.  Fails if the site is not a call
1314 // site, or if the site has already been instrumented using a base tramp.
1315 bool process::replaceFunctionCall(const instPoint *point,
1316                                   const function_base *func) {
1317     // Must be a call site
1318     if (point->ipType != callSite)
1319         return false;
1320
1321     // Cannot already be instrumented with a base tramp
1322     if (baseMap.defines(point))
1323         return false;
1324
1325     // Replace the call
1326     if (func == NULL)
1327         generateNoOp(this, point->addr);
1328     else
1329         generateCall(this, point->addr,
1330                      func->getEffectiveAddress(this));
1331
1332     return true;
1333 }
1334
1335 /****************************************************************************/
1336 /****************************************************************************/
1337 /****************************************************************************/
1338
1339 #ifndef BPATCH_LIBRARY
1340 bool process::isDynamicCallSite(instPoint *callSite){
1341   function_base *temp;
1342   if(!findCallee(*(callSite),temp)){
1343     //True call instructions are not dynamic on sparc,
1344     //they are always to a pc relative offset
1345     if(!isTrueCallInsn(callSite->originalInstruction))
1346       return true;
1347   }
1348   return false;
1349 }
1350
1351 /****************************************************************************/
1352 /****************************************************************************/
1353 /****************************************************************************/
1354
1355 bool process::MonitorCallSite(instPoint *callSite){
1356  
1357   if(isJmplInsn(callSite->originalInstruction)){
1358     vector<AstNode *> the_args(2);
1359     
1360     //this instruction is a jmpl with i == 1, meaning it
1361     //calling function register rs1+simm13
1362     if(callSite->originalInstruction.rest.i == 1){
1363       
1364       AstNode *base =  new AstNode(AstNode::PreviousStackFrameDataReg,
1365                           (void *) callSite->originalInstruction.rest.rs1);
1366       AstNode *offset = new AstNode(AstNode::Constant, 
1367                         (void *) callSite->originalInstruction.resti.simm13);
1368       the_args[0] = new AstNode(plusOp, base, offset);
1369     } 
1370     
1371     //This instruction is a jmpl with i == 0, meaning its
1372     //two operands are registers
1373     else if(callSite->originalInstruction.rest.i == 0){
1374       //Calculate the byte offset from the contents of the %fp reg
1375       //that the registers from the previous stack frame 
1376       //specified by rs1 and rs2 are stored on the stack
1377       AstNode *callee_addr1 = 
1378         new AstNode(AstNode::PreviousStackFrameDataReg,
1379                     (void *) callSite->originalInstruction.rest.rs1);
1380       AstNode *callee_addr2 = 
1381         new AstNode(AstNode::PreviousStackFrameDataReg, 
1382                     (void *) callSite->originalInstruction.rest.rs2);
1383       the_args[0] = new AstNode(plusOp, callee_addr1, callee_addr2);
1384     }
1385     else assert(0);
1386     
1387     the_args[1] = new AstNode(AstNode::Constant,
1388                               (void *) callSite->iPgetAddress());
1389     AstNode *func = new AstNode("DYNINSTRegisterCallee", 
1390                                 the_args);
1391     addInstFunc(this, callSite, func, callPreInsn,
1392                 orderFirstAtPoint,
1393                 true,
1394                 false);
1395   }
1396   else if(isTrueCallInsn(callSite->originalInstruction)){
1397     //True call destinations are always statically determinable.
1398     return true;
1399   }
1400   else return false;
1401
1402   return true;
1403 }
1404 #endif
1405
1406 /****************************************************************************/
1407 /****************************************************************************/
1408 /****************************************************************************/
1409
1410 // Emit code to jump to function CALLEE without linking.  (I.e., when
1411 // CALLEE returns, it returns to the current caller.)  On SPARC, we do
1412 // this by ensuring that the register context upon entry to CALLEE is
1413 // the register context of function we are instrumenting, popped once.
1414 void emitFuncJump(opCode op, 
1415                   char *i, Address &base, 
1416                   const function_base *callee,
1417                   process *proc)
1418 {
1419         assert(op == funcJumpOp);
1420         Address addr;
1421         void cleanUpAndExit(int status);
1422
1423         addr = callee->getEffectiveAddress(proc);
1424         // TODO cast
1425         instruction *insn = (instruction *) ((void*)&i[base]);
1426
1427         generateSetHi(insn, addr, 13); insn++;
1428         // don't want the return address to be used
1429         genImmInsn(insn, JMPLop3, 13, LOW10(addr), 0); insn++;
1430         genSimpleInsn(insn, RESTOREop3, 0, 0, 0); insn++;
1431         base += 3 * sizeof(instruction);
1432 }
1433
1434 #ifdef BPATCH_LIBRARY
1435
1436 #include "BPatch_flowGraph.h"
1437 #include "BPatch_function.h"
1438
1439 #include <sys/systeminfo.h>
1440
1441 /*
1442  * function which check whether the architecture is 
1443  * sparcv8plus or not. For the earlier architectures 
1444  * it is not possible to support random instrumentation 
1445  */
1446 bool isV8plusISA()
1447 {
1448     char isaOptions[256];
1449
1450     if (sysinfo(SI_ISALIST, isaOptions, 256) < 0)
1451         return false;
1452     if (strstr(isaOptions, "sparcv8plus"))
1453         return true;
1454     return false;
1455 }
1456
1457 /*
1458  * createInstructionInstPoint
1459  *
1460  * Create a BPatch_point instrumentation point at the given address, which
1461  * is guaranteed not be one of the "standard" inst points.
1462  *
1463  * proc         The process in which to create the inst point.
1464  * address      The address for which to create the point.
1465  */
1466 BPatch_point *createInstructionInstPoint(process *proc, void *address)
1467 {
1468     unsigned i;
1469     Address begin_addr,end_addr,curr_addr;
1470
1471     //the method to check whether conservative base tramp can be installed
1472     //or not since it contains condition code instructions which is
1473     //available after version8plus of sparc
1474
1475     if(!isV8plusISA()){
1476         cerr << "BPatch_image::createInstPointAtAddr : is not supported for";
1477         cerr << " sparc architecture earlier than v8plus\n";
1478         return NULL;
1479     }
1480
1481     curr_addr = (Address)address;
1482
1483     //if the address is not aligned then there is a problem
1484     if(!isAligned(curr_addr))   
1485         return NULL;
1486
1487     function_base *func = proc->findFuncByAddr(curr_addr);
1488
1489     pd_Function* pointFunction = (pd_Function*)func;
1490     Address pointImageBase = 0;
1491     image* pointImage = pointFunction->file()->exec();
1492     proc->getBaseAddress((const image*)pointImage,pointImageBase);
1493     curr_addr -= pointImageBase;
1494
1495     if (func != NULL) {
1496         instPoint *entry = const_cast<instPoint *>(func->funcEntry(NULL));
1497         assert(entry);
1498
1499         begin_addr = entry->iPgetAddress();
1500         end_addr = begin_addr + entry->Size();
1501
1502         if(((begin_addr - INSN_SIZE) <= curr_addr) && 
1503            (curr_addr < end_addr)){ 
1504             BPatch_reportError(BPatchSerious, 117,
1505                                "instrumentation point conflict");
1506             return NULL;
1507         }
1508
1509         const vector<instPoint*> &exits = func->funcExits(NULL);
1510         for (i = 0; i < exits.size(); i++) {
1511             assert(exits[i]);
1512
1513             begin_addr = exits[i]->iPgetAddress();
1514             end_addr = begin_addr + exits[i]->Size();
1515
1516             if (((begin_addr - INSN_SIZE) <= curr_addr) &&
1517                 (curr_addr < end_addr)){
1518                 BPatch_reportError(BPatchSerious, 117,
1519                                    "instrumentation point conflict");
1520                 return NULL;
1521             }
1522         }
1523
1524         const vector<instPoint*> &calls = func->funcCalls(NULL);
1525         for (i = 0; i < calls.size(); i++) {
1526             assert(calls[i]);
1527
1528             begin_addr = calls[i]->iPgetAddress();
1529             end_addr = begin_addr + calls[i]->Size();
1530
1531             if (((begin_addr - INSN_SIZE) <= curr_addr) &&
1532                 (curr_addr < end_addr)){
1533                 BPatch_reportError(BPatchSerious, 117,
1534                                    "instrumentation point conflict");
1535                 return NULL;
1536             }
1537         }
1538     }
1539
1540     curr_addr += pointImageBase;
1541     /* Check for conflict with a previously created inst point. */
1542     if (proc->instPointMap.defines(curr_addr - INSN_SIZE)) {
1543         BPatch_reportError(BPatchSerious,117,"instrumentation point conflict");
1544         return NULL;
1545     } else if (proc->instPointMap.defines(curr_addr + INSN_SIZE)) {
1546         BPatch_reportError(BPatchSerious,117,"instrumentation point conflict");
1547         return NULL;
1548     }
1549
1550     /* Check for instrumentation where the delay slot of the jump to the
1551        base tramp would be a branch target from elsewhere in the function. */
1552
1553     BPatch_function *bpfunc = proc->PDFuncToBPFuncMap[func];
1554     /* XXX Should create here with correct module, but we don't know it. */
1555     if (bpfunc == NULL) bpfunc = new BPatch_function(proc, func, NULL);
1556
1557     BPatch_flowGraph *cfg = bpfunc->getCFG();
1558     BPatch_basicBlock** belements =
1559                 new BPatch_basicBlock*[cfg->getAllBasicBlocks()->size()];
1560     cfg->getAllBasicBlocks()->elements(belements);
1561
1562     for(i=0; i< (unsigned)cfg->getAllBasicBlocks()->size(); i++) {
1563         void *bbsa, *bbea;
1564         if (belements[i]->getAddressRange(bbsa,bbea)) {
1565             begin_addr = (Address)bbsa;
1566             if ((begin_addr - INSN_SIZE) == curr_addr) {
1567                 delete[] belements;
1568                 BPatch_reportError(BPatchSerious, 118,
1569                                    "point uninstrumentable");
1570                 return NULL;
1571             }
1572         }
1573     }
1574     delete[] belements;
1575
1576     /* Check for instrumenting just before or after a branch. */
1577
1578     if ((Address)address > func->getEffectiveAddress(proc)) {
1579         instruction prevInstr;
1580         proc->readTextSpace((char *)address - INSN_SIZE,
1581                             sizeof(instruction),
1582                             &prevInstr.raw);
1583         if (IS_DELAYED_INST(prevInstr)){
1584             BPatch_reportError(BPatchSerious, 118, "point uninstrumentable");
1585             return NULL;
1586         }
1587     }
1588
1589     if ((Address)address + INSN_SIZE <
1590         func->getEffectiveAddress(proc) + func->size()) {
1591         instruction nextInstr;
1592         proc->readTextSpace((char *)address + INSN_SIZE,
1593                             sizeof(instruction),
1594                             &nextInstr.raw);
1595         if (IS_DELAYED_INST(nextInstr)){
1596             BPatch_reportError(BPatchSerious, 118, "point uninstrumentable");
1597             return NULL;
1598         }
1599     }
1600
1601     instruction instr;
1602     proc->readTextSpace(address, sizeof(instruction), &instr.raw);
1603         
1604     curr_addr -= pointImageBase;
1605     //then create the instrumentation point object for the address
1606     instPoint *newpt = new instPoint(pointFunction,
1607                                      (const instructUnion &)instr,
1608                                      (const image*)pointImage,
1609                                      (Address &)curr_addr,
1610                                      false, // bool delayOk - ignored,
1611                                      otherPoint);
1612
1613     pointFunction->addArbitraryPoint(newpt,proc);
1614
1615     return proc->findOrCreateBPPoint(bpfunc, newpt, BPatch_instruction);
1616
1617 }
1618
1619 /*
1620  * BPatch_point::getDisplacedInstructions
1621  *
1622  * Returns the instructions to be relocated when instrumentation is inserted
1623  * at this point.  Returns the number of bytes taken up by these instructions.
1624  *
1625  * maxSize      The maximum number of bytes of instructions to return.
1626  * insns        A pointer to a buffer in which to return the instructions.
1627  */
1628 int BPatch_point::getDisplacedInstructions(int maxSize, void* insns)
1629 {
1630     int count = 0;
1631     instruction copyOut[10];    // I think 7 is the max - jkh 8/3/00
1632
1633     //
1634     // This function is based on what is contained in the instPoint 
1635     //    constructor in the file inst-sparc-solaris.C
1636     //
1637     if (!point->hasNoStackFrame()) {
1638         if (point->ipType == functionEntry) {
1639             copyOut[count++].raw = point->saveInsn.raw;
1640             copyOut[count++].raw = point->originalInstruction.raw;
1641             copyOut[count++].raw = point->delaySlotInsn.raw;
1642             if (point->isDelayed) {
1643                 copyOut[count++].raw = point->isDelayedInsn.raw;
1644                 if (point->callAggregate) {
1645                     copyOut[count++].raw = point->aggregateInsn.raw;
1646                 }
1647             }
1648         } else if (point->ipType == callSite) {
1649             copyOut[count++].raw = point->originalInstruction.raw;
1650             copyOut[count++].raw = point->delaySlotInsn.raw;
1651             if (point->callAggregate) {
1652                 copyOut[count++].raw = point->aggregateInsn.raw;
1653             }
1654         } else {
1655             copyOut[count++].raw = point->originalInstruction.raw;
1656             copyOut[count++].raw = point->delaySlotInsn.raw;
1657         }
1658     } else {
1659         if (point->ipType == functionEntry) {
1660             copyOut[count++].raw = point->originalInstruction.raw;
1661             copyOut[count++].raw = point->otherInstruction.raw;
1662             copyOut[count++].raw = point->delaySlotInsn.raw;
1663             if (point->isDelayed) {
1664                 copyOut[count++].raw = point->isDelayedInsn.raw;
1665             }
1666         } else if (point->ipType == functionExit) {
1667             copyOut[count++].raw = point->originalInstruction.raw;
1668             copyOut[count++].raw = point->otherInstruction.raw;
1669             copyOut[count++].raw = point->delaySlotInsn.raw;
1670             if (point->inDelaySlot) {
1671                 copyOut[count++].raw = point->inDelaySlotInsn.raw;
1672                 if (point->firstIsConditional) {
1673                     copyOut[count++].raw = point->extraInsn.raw;
1674                 }
1675             }
1676         } else if(point->ipType == otherPoint) {
1677            copyOut[count++].raw = point->originalInstruction.raw;
1678            copyOut[count++].raw = point->otherInstruction.raw;
1679         } else {
1680            assert(point->ipType == callSite);
1681            copyOut[count++].raw = point->originalInstruction.raw;
1682            copyOut[count++].raw = point->delaySlotInsn.raw;
1683            if (point->callAggregate) {
1684                copyOut[count++].raw = point->aggregateInsn.raw;
1685            }
1686         }
1687     }
1688
1689     if (count * sizeof(instruction) > (unsigned) maxSize) {
1690         return -1;
1691     } else {
1692         memcpy(insns, copyOut, count * sizeof(instruction));
1693         return count * sizeof(instruction);
1694     }
1695 }
1696
1697 #endif
1698
1699 // needed in metric.C
1700 bool instPoint::match(instPoint *p)
1701 {
1702   if (this == p)
1703     return true;
1704   
1705   // should we check anything else?
1706   if (addr == p->addr)
1707     return true;
1708   
1709   return false;
1710 }