*** empty log message ***
[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 #include "dyninstAPI/src/inst-sparc.h"
43 #include "dyninstAPI/src/instPoint.h"
44
45 instruction newInstr[1024];
46 static dictionary_hash<string, unsigned> funcFrequencyTable(string::hash);
47
48 trampTemplate baseTemplate;
49 registerSpace *regSpace;
50
51 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
52 // registers 8 to 15: out registers 
53 // registers 16 to 22: local registers
54 int deadList[] = {16, 17, 18, 19, 20, 21, 22 };
55 #else
56 int deadList[] = {16, 17, 18, 19, 20, 21, 22, 23 };
57 #endif
58
59 int deadListSize = sizeof(deadList);
60
61 // Constructor for the class instPoint. This one defines the 
62 // instPoints for the relocated function. Since the function reloated
63 // to the heap don't need to worry about that jump could be out of
64 // reach, the instructions to be moved are the one instruction at that
65 // point plus others if necessary(i.e. instruction in the delayed
66 // slot and maybe the aggregate instuction ).    
67 instPoint::instPoint(pd_Function *f, const instruction &instr, 
68                      const image *owner, Address &adr, bool delayOK, 
69                      instPointType pointType, Address &oldAddr)
70 : addr(adr), originalInstruction(instr), inDelaySlot(false), isDelayed(false),
71   callIndirect(false), callAggregate(false), callee(NULL), func(f), 
72   ipType(pointType), image_ptr(owner), firstIsConditional(false), 
73   relocated_(false), isLongJump(false)
74 {
75   assert(f->isTrapFunc() == true);  
76
77   isBranchOut = false;
78   delaySlotInsn.raw = owner->get_instruction(oldAddr+4);
79   aggregateInsn.raw = owner->get_instruction(oldAddr+8);
80
81   // If the instruction is a DCTI, the instruction in the delayed 
82   // slot is to be moved.
83   if (IS_DELAYED_INST(instr))
84     isDelayed = true;
85
86   // If this function call another function which return an aggregate
87   // value, move the aggregate instruction, too. 
88   if (ipType == callSite) {
89       if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
90           callAggregate = true;
91           adr += 8;
92           oldAddr += 8;
93       }
94   }
95
96   if (owner->isValidAddress(oldAddr-4)) {
97     instruction iplus1;
98     iplus1.raw = owner->get_instruction(oldAddr-4);
99     if (IS_DELAYED_INST(iplus1) && !delayOK) {
100       // ostrstream os(errorLine, 1024, ios::out);
101       // os << "** inst point " << func->file->fullName << "/"
102       //  << func->prettyName() << " at addr " << addr <<
103       //        " in a delay slot\n";
104       // logLine(errorLine);
105       inDelaySlot = true;
106     }
107   }
108 }
109
110 // Add the astNode opt to generate one instruction to get the 
111 // return value for the compiler optimazed case
112 void
113 AstNode::optRetVal(AstNode *opt) {
114
115     if (oType == ReturnVal) {
116         cout << "Optimazed Return." << endl;
117         if (loperand == 0) {
118             loperand = opt;
119             return;
120         } else if (opt == 0) {
121             delete loperand;
122             loperand = NULL;
123             return; 
124         }
125     }
126     if (loperand) loperand->optRetVal(opt);
127     if (roperand) roperand->optRetVal(opt);
128     for (unsigned i = 0; i < operands.size(); i++) 
129         operands[i] -> optRetVal(opt);
130 }
131
132 bool 
133 processOptimaRet(instPoint *location, AstNode *&ast) {
134
135     // For optimazed return code
136     if (location -> ipType == functionExit) {
137         if ((isInsnType(location -> originalInstruction, RETmask, RETmatch)) ||
138             (isInsnType(location -> originalInstruction, RETLmask, RETLmatch)))
139         {
140             if (isInsnType(location -> delaySlotInsn, 
141                            RESTOREmask, RESTOREmatch)&&
142                 ((location->delaySlotInsn.raw | 0xc1e82000) != 0xc1e82000)) 
143             {
144                 /* cout << "Optimazed Retrun Value:  Addr " << hex << 
145                     location->addr << " in "
146                         << location -> func -> prettyName() << endl; */
147                 AstNode *opt = new AstNode(AstNode::Constant,
148                                            (void *)location->delaySlotInsn.raw);
149                 ast -> optRetVal(opt);
150                 return true;
151             }
152         }
153     }
154     return false;
155 }
156
157 unsigned 
158 emitOptReturn(unsigned instr, reg src, char *insn, unsigned &base, bool noCost) {
159     
160     cout << "Handling a special case for optimazed return value." << endl;
161
162     assert((((instr&0x3e000000)>>25) >= 0) ||
163            (((instr&0x3e000000)>>25) <= 16));
164
165     if ((instr&0x02000)>>13)
166         emitImm(plusOp, (instr&0x07c000)>>14, instr&0x01fff,
167                 ((instr&0x3e000000)>>25)+16, insn, base, noCost);
168     else
169         emit(plusOp, (instr&0x07c000)>>14, instr&0x01fff,
170              ((instr&0x3e000000)>>25)+16, insn, base, noCost);
171     
172     return emit(getSysRetValOp, 0, 0, src, insn, base, noCost);
173 }
174
175
176 //
177 // initDefaultPointFrequencyTable - define the expected call frequency of
178 //    procedures.  Currently we just define several one shots with a
179 //    frequency of one, and provide a hook to read a file with more accurate
180 //    information.
181 //
182 void initDefaultPointFrequencyTable()
183 {
184     FILE *fp;
185     float value;
186     char name[512];
187
188     funcFrequencyTable["main"] = 1;
189     funcFrequencyTable["DYNINSTsampleValues"] = 1;
190     funcFrequencyTable[EXIT_NAME] = 1;
191
192     // try to read file.
193     fp = fopen("freq.input", "r");
194     if (!fp) {
195         return;
196     } else {
197         printf("found freq.input file\n");
198     }
199     while (!feof(fp)) {
200         fscanf(fp, "%s %f\n", name, &value);
201         funcFrequencyTable[name] = (int) value;
202         printf("adding %s %f\n", name, value);
203     }
204     fclose(fp);
205 }
206
207 /*
208  * Get an etimate of the frequency for the passed instPoint.  
209  *    This is not (always) the same as the function that contains the point.
210  * 
211  *  The function is selected as follows:
212  *
213  *  If the point is an entry or an exit return the function name.
214  *  If the point is a call and the callee can be determined, return the called
215  *     function.
216  *  else return the funcation containing the point.
217  *
218  *  WARNING: This code contins arbitray values for func frequency (both user 
219  *     and system).  This should be refined over time.
220  *
221  * Using 1000 calls sec to be one SD from the mean for most FPSPEC apps.
222  *      -- jkh 6/24/94
223  *
224  */
225 float getPointFrequency(instPoint *point)
226 {
227
228     pd_Function *func;
229
230     if (point->callee)
231         func = point->callee;
232     else
233         func = point->func;
234
235     if (!funcFrequencyTable.defines(func->prettyName())) {
236       // Changing this value from 250 to 100 because predictedCost was
237       // too high - naim 07/18/96
238       return(100); 
239       
240     } else {
241       return (funcFrequencyTable[func->prettyName()]);
242     }
243 }
244
245 //
246 // return cost in cycles of executing at this point.  This is the cost
247 //   of the base tramp if it is the first at this point or 0 otherwise.
248 //
249 int getPointCost(process *proc, const instPoint *point)
250 {
251     if (proc->baseMap.defines(point)) {
252         return(0);
253     } else {
254         // 70 cycles for base tramp (worst case)
255         return(70);
256     }
257 }
258
259
260 void initATramp(trampTemplate *thisTemp, instruction *tramp)
261 {
262     instruction *temp;
263
264     // TODO - are these offset always positive?
265     thisTemp->trampTemp = (void *) tramp;
266     for (temp = tramp; temp->raw != END_TRAMP; temp++) {
267         switch (temp->raw) {
268             case LOCAL_PRE_BRANCH:
269                 thisTemp->localPreOffset = ((void*)temp - (void*)tramp);
270                 thisTemp->localPreReturnOffset = thisTemp->localPreOffset 
271                                                  + sizeof(temp->raw);
272                 break;
273             case GLOBAL_PRE_BRANCH:
274                 thisTemp->globalPreOffset = ((void*)temp - (void*)tramp);
275                 break;
276             case LOCAL_POST_BRANCH:
277                 thisTemp->localPostOffset = ((void*)temp - (void*)tramp);
278                 thisTemp->localPostReturnOffset = thisTemp->localPostOffset
279                                                   + sizeof(temp->raw);
280                 break;
281             case GLOBAL_POST_BRANCH:
282                 thisTemp->globalPostOffset = ((void*)temp - (void*)tramp);
283                 break;
284             case SKIP_PRE_INSN:
285                 thisTemp->skipPreInsOffset = ((void*)temp - (void*)tramp);
286                 break;
287             case UPDATE_COST_INSN:
288                 thisTemp->updateCostOffset = ((void*)temp - (void*)tramp);
289                 break;
290             case SKIP_POST_INSN:
291                 thisTemp->skipPostInsOffset = ((void*)temp - (void*)tramp);
292                 break;
293             case RETURN_INSN:
294                 thisTemp->returnInsOffset = ((void*)temp - (void*)tramp);
295                 break;
296             case EMULATE_INSN:
297                 thisTemp->emulateInsOffset = ((void*)temp - (void*)tramp);
298                 break;
299         }       
300     }
301
302     // Cost with the skip branchs.
303     thisTemp->cost = 14;  
304     thisTemp->prevBaseCost = 20;
305     thisTemp->postBaseCost = 22;
306     thisTemp->prevInstru = thisTemp->postInstru = false;
307     thisTemp->size = (int) temp - (int) tramp;
308 }
309
310
311 void initTramps()
312 {
313     static bool inited=false;
314
315     if (inited) return;
316     inited = true;
317
318     initATramp(&baseTemplate, (instruction *) baseTramp);
319
320     regSpace = new registerSpace(sizeof(deadList)/sizeof(int), deadList,                                         0, NULL);
321     assert(regSpace);
322 }
323
324 //
325 // For multithreaded applications and shared memory sampling, this routine 
326 // will compute the address where the corresponding counter/timer vector for
327 // level 0 is (by default). In the mini-tramp, if the counter/timer is at a
328 // different level, we will add the corresponding offset - naim 4/18/97
329 //
330 void generateMTpreamble(char *insn, unsigned &base, process *proc)
331 {
332   AstNode *t1,*t2,*t3,*t4,*t5;;
333   vector<AstNode *> dummy;
334   unsigned tableAddr;
335   int value; 
336   bool err;
337   reg src = -1;
338
339   /* t3=DYNINSTthreadTable[thr_self()] */
340   t1 = new AstNode("DYNINSTthreadPos", dummy);
341   value = sizeof(unsigned);
342   t4 = new AstNode(AstNode::Constant,(void *)value);
343   t2 = new AstNode(timesOp, t1, t4);
344   removeAst(t1);
345   removeAst(t4);
346
347   tableAddr = proc->findInternalAddress("DYNINSTthreadTable",true,err);
348   assert(!err);
349   t5 = new AstNode(AstNode::Constant, (void *)tableAddr);
350   t3 = new AstNode(plusOp, t2, t5);
351   removeAst(t2);
352   removeAst(t5);
353   src = t3->generateCode(proc, regSpace, insn, base, false);
354   removeAst(t3);
355   (void) emit(orOp, src, 0, REG_MT, insn, base, false);
356   regSpace->freeRegister(src);
357 }
358
359 void generateNoOp(process *proc, int addr)
360 {
361     instruction insn;
362
363     /* fill with no-op */
364     insn.raw = 0;
365     insn.branch.op = 0;
366     insn.branch.op2 = NOOPop2;
367
368     // TODO cast
369     proc->writeTextWord((caddr_t)addr, insn.raw);
370 }
371
372
373 /*
374  * change the insn at addr to be a branch to newAddr.
375  *   Used to add multiple tramps to a point.
376  */
377 void generateBranch(process *proc, unsigned fromAddr, unsigned newAddr)
378 {
379     int disp;
380     instruction insn;
381
382     disp = newAddr-fromAddr;
383     generateBranchInsn(&insn, disp);
384
385     // TODO cast
386     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
387 }
388
389 void generateCall(process *proc, unsigned fromAddr,unsigned newAddr)
390 {
391     instruction insn; 
392     generateCallInsn(&insn, fromAddr, newAddr);
393
394     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
395
396 }
397
398 void genImm(process *proc, Address fromAddr,int op, reg rs1, int immd, reg rd)
399 {
400     instruction insn;
401     genImmInsn(&insn, op, rs1, immd, rd);
402
403     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
404 }
405
406 /*
407  *  change the target of the branch at fromAddr, to be newAddr.
408  */
409 void changeBranch(process *proc, unsigned fromAddr, unsigned newAddr, 
410                   instruction originalBranch) {
411     int disp = newAddr-fromAddr;
412     instruction insn;
413     insn.raw = originalBranch.raw;
414     insn.branch.disp22 = disp >> 2;
415     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
416 }
417
418 int callsTrackedFuncP(instPoint *point)
419 {
420     if (point->callIndirect) {
421         return(true);
422     } else {
423         if (point->callee) {
424             return(true);
425         } else {
426             return(false);
427         }
428     }
429 }
430
431 /*
432  * return the function asociated with a point.
433  *
434  *     If the point is a funcation call, and we know the function being called,
435  *          then we use that.  Otherwise it is the function that contains the
436  *          point.
437  *  
438  *   This is done to return a better idea of which function we are using.
439  */
440 pd_Function *getFunction(instPoint *point)
441 {
442     return(point->callee ? point->callee : point->func);
443 }
444
445 bool process::emitInferiorRPCheader(void *insnPtr, unsigned &baseBytes) {
446    instruction *insn = (instruction *)insnPtr;
447    unsigned baseInstruc = baseBytes / sizeof(instruction);
448
449    genImmInsn(&insn[baseInstruc++], SAVEop3, 14, -112, 14);
450
451    baseBytes = baseInstruc * sizeof(instruction); // convert back
452    return true;
453 }
454
455
456 bool process::emitInferiorRPCtrailer(void *insnPtr, unsigned &baseBytes,
457                                      unsigned &breakOffset,
458                                      bool stopForResult,
459                                      unsigned &stopForResultOffset,
460                                      unsigned &justAfter_stopForResultOffset) {
461    // Sequence: restore, trap, illegal
462
463    instruction *insn = (instruction *)insnPtr;
464    unsigned baseInstruc = baseBytes / sizeof(instruction);
465
466    if (stopForResult) {
467       // trap insn:
468       genBreakpointTrap(&insn[baseInstruc]);
469       stopForResultOffset = baseInstruc * sizeof(instruction);
470       baseInstruc++;
471       justAfter_stopForResultOffset = baseInstruc * sizeof(instruction);
472    }
473
474    genSimpleInsn(&insn[baseInstruc++], RESTOREop3, 0, 0, 0);
475
476    // Now that the inferior has executed the 'restore' instruction, the %in and
477    // %local registers have been restored.  We mustn't modify them after this point!!
478    // (reminder: the %in and %local registers aren't saved and set with ptrace
479    //  GETREGS/SETREGS call)
480
481    // Trap instruction:
482    genBreakpointTrap(&insn[baseInstruc]); // ta 1
483    breakOffset = baseInstruc * sizeof(instruction);
484    baseInstruc++;
485
486    // And just to make sure that we don't continue from the trap:
487    genUnimplementedInsn(&insn[baseInstruc++]); // UNIMP 0
488
489    baseBytes = baseInstruc * sizeof(instruction); // convert back
490
491    return true; // success
492 }
493
494 unsigned emitImm(opCode op, reg src1, reg src2, reg dest, char *i, 
495                  unsigned &base, bool noCost)
496 {
497         instruction *insn = (instruction *) ((void*)&i[base]);
498         int op3=-1;
499         int result;
500         switch (op) {
501             // integer ops
502             case plusOp:
503                 op3 = ADDop3;
504                 genImmInsn(insn, op3, src1, src2, dest);
505                 break;
506
507             case minusOp:
508                 op3 = SUBop3;
509                 genImmInsn(insn, op3, src1, src2, dest);
510                 break;
511
512             case timesOp:
513                 op3 = SMULop3;
514                 if (isPowerOf2(src2,result) && (result<32))
515                   generateLShift(insn, src1, (reg)result, dest);           
516                 else 
517                   genImmInsn(insn, op3, src1, src2, dest);
518                 break;
519
520             case divOp:
521                 op3 = SDIVop3;
522                 if (isPowerOf2(src2,result) && (result<32))
523                   generateRShift(insn, src1, (reg)result, dest);           
524                 else { // needs to set the Y register to zero first
525                   // Set the Y register to zero: Zhichen
526                   genImmInsn(insn, WRYop3, REG_G0, 0, 0);
527                   base += sizeof(instruction);
528                   insn = (instruction *) ((void*)&i[base]);
529                   genImmInsn(insn, op3, src1, src2, dest);
530                 }
531
532                 break;
533
534             // Bool ops
535             case orOp:
536                 op3 = ORop3;
537                 genImmInsn(insn, op3, src1, src2, dest);
538                 break;
539
540             case andOp:
541                 op3 = ANDop3;
542                 genImmInsn(insn, op3, src1, src2, dest);
543                 break;
544
545             // rel ops
546             // For a particular condition (e.g. <=) we need to use the
547             // the opposite in order to get the right value (e.g. for >=
548             // we need BLTcond) - naim
549             case eqOp:
550                 genImmRelOp(insn, BNEcond, src1, src2, dest, base);
551                 return(0);
552                 break;
553
554             case neOp:
555                 genImmRelOp(insn, BEcond, src1, src2, dest, base);
556                 return(0);
557                 break;
558
559             case lessOp:
560                 genImmRelOp(insn, BGEcond, src1, src2, dest, base);
561                 return(0);
562                 break;
563
564             case leOp:
565                 genImmRelOp(insn, BGTcond, src1, src2, dest, base);
566                 return(0);
567                 break;
568
569             case greaterOp:
570                 genImmRelOp(insn, BLEcond, src1, src2, dest, base);
571                 return(0);
572                 break;
573
574             case geOp:
575                 genImmRelOp(insn, BLTcond, src1, src2, dest, base);
576                 return(0);
577                 break;
578
579             default:
580                 reg dest2 = regSpace->allocateRegister(i, base, noCost);
581                 (void) emit(loadConstOp, src2, dest2, dest2, i, base, noCost);
582                 (void) emit(op, src1, dest2, dest, i, base, noCost);
583                 regSpace->freeRegister(dest2);
584                 return(0);
585                 break;
586         }
587         base += sizeof(instruction);
588         return(0);
589 }
590
591 //
592 // All values based on Cypress0 && Cypress1 implementations as documented in
593 //   SPARC v.8 manual p. 291
594 //
595 int getInsnCost(opCode op)
596 {
597     /* XXX Need to add branchOp */
598     if (op == loadConstOp) {
599         return(1);
600     } else if (op ==  loadOp) {
601         // sethi + load single
602         return(1+1);
603     } else if (op ==  loadIndirOp) {
604         return(1);
605     } else if (op ==  storeOp) {
606         // sethi + store single
607         // return(1+3); 
608         // for SS-5 ?
609         return(1+2); 
610     } else if (op ==  storeIndirOp) {
611         return(2); 
612     } else if (op ==  ifOp) {
613         // subcc
614         // be
615         // nop
616         return(1+1+1);
617     } else if (op ==  callOp) {
618         int count = 0;
619
620         // mov src1, %o0
621         count += 1;
622
623         // mov src2, %o1
624         count += 1;
625
626         // clr i2
627         count += 1;
628
629         // clr i3
630         count += 1;
631
632         // sethi
633         count += 1;
634
635         // jmpl
636         count += 1;
637
638         // noop
639         count += 1;
640
641         return(count);
642     } else if (op ==  updateCostOp) {
643         // sethi %hi(obsCost), %l0
644         // ld [%lo + %lo(obsCost)], %l1
645         // add %l1, <cost>, %l1
646         // st %l1, [%lo + %lo(obsCost)]
647         return(1+2+1+3);
648     } else if (op ==  trampPreamble) {
649         return(0);
650     } else if (op ==  trampTrailer) {
651         // retl
652         return(2);
653     } else if (op == noOp) {
654         // noop
655         return(1);
656     } else if (op == getParamOp) {
657         return(0);
658     } else {
659         switch (op) {
660             // rel ops
661             case eqOp:
662             case neOp:
663             case lessOp:
664             case leOp:
665             case greaterOp:
666             case geOp:
667                 // bne -- assume taken
668                 return(2);
669                 break;
670             default:
671                 return(1);
672                 break;
673         }
674     }
675 }
676
677 bool isReturnInsn(const image *owner, Address adr, bool &lastOne)
678 {
679     instruction instr;
680     
681     instr.raw = owner->get_instruction(adr);
682     lastOne = false;
683
684     if (isInsnType(instr, RETmask, RETmatch) ||
685         isInsnType(instr, RETLmask, RETLmatch)) {
686         if ((instr.resti.simm13 != 8) && (instr.resti.simm13 != 12)) {
687             logLine("*** FATAL Error:");
688             sprintf(errorLine, " unsupported return\n");
689             logLine(errorLine);
690             showErrorCallback(55, "");
691             P_abort();
692         }
693         return true;
694     }
695     return false;
696 }
697
698
699 //
700 // called to relocate a function: when a request is made to instrument
701 // a system call we relocate the entire function into the heap
702 //
703 bool pd_Function::relocateFunction(process *proc, 
704                                  const instPoint *&location,
705                                  vector<instruction> &extra_instrs) {
706
707     relocatedFuncInfo *reloc_info = 0;
708     // check to see if this process already has a relocation record 
709     // for this function
710     for(u_int i=0; i < relocatedByProcess.size(); i++){
711         if((relocatedByProcess[i])->getProcess() == proc){
712             reloc_info = relocatedByProcess[i];
713         }
714     }
715     u_int ret = 0;
716     if(!reloc_info){
717         //Allocate the heap for the function to be relocated
718         ret = inferiorMalloc(proc, size()+RELOCATED_FUNC_EXTRA_SPACE, \
719                              textHeap);
720         if(!ret)  return false;
721         reloc_info = new relocatedFuncInfo(proc,ret);
722         relocatedByProcess += reloc_info;
723     }
724     if(!(findNewInstPoints(location->image_ptr, location, ret, proc, 
725                            extra_instrs, reloc_info))){
726     }
727     proc->writeDataSpace((caddr_t)ret, size()+RELOCATED_FUNC_EXTRA_SPACE \
728                          ,(caddr_t) newInstr);
729     return true;
730 }
731
732 // modifyInstPoint: if the function associated with the process was 
733 // recently relocated, then the instPoint may have the old pre-relocated
734 // address (this can occur because we are getting instPoints in mdl routines 
735 // and passing these to routines that do the instrumentation, it would
736 // be better to let the routines that do the instrumenting find the points)
737 void pd_Function::modifyInstPoint(const instPoint *&location,process *proc)
738 {
739
740     if(relocatable_ && !(location->relocated_)){
741         for(u_int i=0; i < relocatedByProcess.size(); i++){
742             if((relocatedByProcess[i])->getProcess() == proc){
743                 if(location->ipType == functionEntry){
744                     const instPoint *new_entry = 
745                                 (relocatedByProcess[i])->funcEntry();
746                     location = new_entry;
747                 } 
748                 else if(location->ipType == functionExit){
749                     const vector<instPoint *> new_returns = 
750                         (relocatedByProcess[i])->funcReturns(); 
751                     if(funcReturns.size() != new_returns.size()){
752                         printf("funcReturns = %d new_returns = %d\n",
753                                 funcReturns.size(),new_returns.size());
754                         fflush(stdout);
755                     }
756                     assert(funcReturns.size() == new_returns.size());
757                     for(u_int j=0; j < new_returns.size(); j++){
758                         if(funcReturns[j] == location){
759                             location = (new_returns[j]);
760                             break;
761                         }
762                     }
763                 }
764                 else {
765                     const vector<instPoint *> new_calls = 
766                                 (relocatedByProcess[i])->funcCallSites(); 
767                     assert(calls.size() == new_calls.size());
768                     for(u_int j=0; j < new_calls.size(); j++){
769                         if(calls[j] == location){
770                             location = (new_calls[j]);
771                             break;
772                         }
773                     }
774
775                 }
776                 break;
777     } } }
778 }
779
780
781 // The exact semantics of the heap are processor specific.
782 //
783 // find all DYNINST symbols that are data symbols
784 //
785 bool process::heapIsOk(const vector<sym_data> &find_us) {
786   Symbol sym;
787   Address baseAddr;
788
789   // find the main function
790   // first look for main or _main
791   if (!((mainFunction = findOneFunction("main")) 
792         || (mainFunction = findOneFunction("_main")))) {
793      string msg = "Cannot find main. Exiting.";
794      statusLine(msg.string_of());
795      showErrorCallback(50, msg);
796      return false;
797   }
798
799   for (unsigned i=0; i<find_us.size(); i++) {
800     const string &str = find_us[i].name;
801     if (!getSymbolInfo(str, sym, baseAddr)) {
802       string str1 = string("_") + str.string_of();
803       if (!getSymbolInfo(str1, sym, baseAddr) && find_us[i].must_find) {
804         string msg;
805         msg = string("Cannot find ") + str + string(". Exiting");
806         statusLine(msg.string_of());
807         showErrorCallback(50, msg);
808         return false;
809       }
810     }
811   }
812
813 //  string ghb = GLOBAL_HEAP_BASE;
814 //  if (!getSymbolInfo(ghb, sym, baseAddr)) {
815 //    ghb = U_GLOBAL_HEAP_BASE;
816 //    if (!linkedFile.get_symbol(ghb, sym)) {
817 //      string msg;
818 //      msg = string("Cannot find ") + ghb + string(". Exiting");
819 //      statusLine(msg.string_of());
820 //      showErrorCallback(50, msg);
821 //      return false;
822 //    }
823 //  }
824 //  Address instHeapEnd = sym.addr()+baseAddr;
825 //  addInternalSymbol(ghb, instHeapEnd);
826
827   string ihb = INFERIOR_HEAP_BASE;
828   if (!getSymbolInfo(ihb, sym, baseAddr)) {
829     ihb = UINFERIOR_HEAP_BASE;
830     if (!getSymbolInfo(ihb, sym, baseAddr)) {
831       string msg;
832       msg = string("Cannot find ") + ihb + string(". Cannot use this application");
833       statusLine(msg.string_of());
834       showErrorCallback(50, msg);
835       return false;
836     }
837   }
838   Address curr = sym.addr()+baseAddr;
839
840 #ifdef ndef
841   // Check that we can patch up user code to jump to our base trampolines
842   // (Perhaps this code is no longer needed for sparc platforms, since we use full
843   // 32-bit jumps)
844   const Address instHeapStart = curr;
845   const Address instHeapEnd = instHeapStart + SYN_INST_BUF_SIZE - 1;
846
847   if (instHeapEnd > getMaxBranch3Insn()) {
848     logLine("*** FATAL ERROR: Program text + data too big for dyninst\n");
849     sprintf(errorLine, "    heap starts at %x and ends at %x; maxbranch=%x\n",
850             instHeapStart, instHeapEnd, getMaxBranch3Insn());
851     logLine(errorLine);
852     return false;
853   }
854 #endif
855
856   return true;
857 }
858
859
860
861 // Certain registers (i0-i7 on a SPARC) may be available to be read
862 // as an operand, but cannot be written.
863 bool registerSpace::readOnlyRegister(reg reg_number) {
864   if ((reg_number < 16) || (reg_number > 23))
865       return true;
866   else
867       return false;
868 }
869
870 bool returnInstance::checkReturnInstance(const vector<Address> &stack, u_int &index) {
871     // If false (unsafe) is returned, then 'index' is set to the first unsafe call stack
872     // index.
873
874   //    cout << "checkReturnInstance: addr_=" << (void*)addr_ << "; size_=" <<
875   //            (void*)size_ << endl;
876   //    cout << "instruction sequence is:" << endl;
877   //    for (unsigned i=0; i < instSeqSize/4; i ++)
878   //       cout << (void*)instructionSeq[i].raw << endl;
879   //    cout << endl;
880   //    
881   //    for (unsigned i=0; i < stack.size(); i++)
882   //       cout << (void*)stack[i] << endl;
883
884     for (u_int i=0; i < stack.size(); i++) {
885         index = i;
886
887         // Is the following check correct?  Shouldn't the ">" be changed to ">=",
888         // and the "<=" be changed to "<" ??? --ari 6/11/97
889         if (stack[i] > addr_ && stack[i] <= addr_+size_)
890             return false;
891     }
892
893     return true;
894 }
895
896 void returnInstance::installReturnInstance(process *proc) {
897     proc->writeTextSpace((caddr_t)addr_, instSeqSize, 
898                          (caddr_t) instructionSeq); 
899 }
900
901 void generateBreakPoint(instruction &insn) {
902     insn.raw = BREAK_POINT_INSN;
903 }
904
905 void returnInstance::addToReturnWaitingList(Address pc, process *proc) {
906     // if there already is a TRAP set at this pc for this process don't
907     // generate a trap instruction again...you will get the wrong original
908     // instruction if you do a readDataSpace
909     bool found = false;
910     instruction insn;
911     for (u_int i=0; i < instWList.size(); i++) {
912          if (instWList[i]->pc_ == pc && instWList[i]->which_proc == proc) {
913              found = true;
914              insn = instWList[i]->relocatedInstruction;
915              break;
916          }
917     }
918     if(!found) {
919         instruction insnTrap;
920         generateBreakPoint(insnTrap);
921         proc->readDataSpace((caddr_t)pc, sizeof(insn), (char *)&insn, true);
922         proc->writeTextSpace((caddr_t)pc, sizeof(insnTrap), (caddr_t)&insnTrap);
923     }
924     else {
925     }
926
927     instWaitingList *instW = new instWaitingList(instructionSeq,instSeqSize,
928                                                  addr_,pc,insn,pc,proc);
929     instWList += instW;
930 }
931
932
933 bool doNotOverflow(int value)
934 {
935   // we are assuming that we have 13 bits to store the immediate operand.
936   if ( (value <= 16383) && (value >= -16384) ) return(true);
937   else return(false);
938 }
939
940 void instWaitingList::cleanUp(process *proc, Address pc) {
941     proc->writeTextSpace((caddr_t)pc, sizeof(relocatedInstruction),
942                     (caddr_t)&relocatedInstruction);
943     proc->writeTextSpace((caddr_t)addr_, instSeqSize, (caddr_t)instructionSeq);
944 }
945
946
947 // process::replaceFunctionCall
948 //
949 // Replace the function call at the given instrumentation point with a call to
950 // a different function, or with a NOOP.  In order to replace the call with a
951 // NOOP, pass NULL as the parameter "func."
952 // Returns true if sucessful, false if not.  Fails if the site is not a call
953 // site, or if the site has already been instrumented using a base tramp.
954 bool process::replaceFunctionCall(const instPoint *point,
955                                   const function_base *func) {
956     // Must be a call site
957     if (point->ipType != callSite)
958         return false;
959
960     // Cannot already be instrumented with a base tramp
961     if (baseMap.defines(point))
962         return false;
963
964     // Replace the call
965     if (func == NULL)
966         generateNoOp(this, point->addr);
967     else
968         generateCall(this, point->addr,
969                      ((function_base *)func)->getAddress(this));
970
971     return true;
972 }