2 * Copyright (c) 1996 Barton P. Miller
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.
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.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
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.
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.
42 // $Id: inst-sparc.C,v 1.105 2001/08/29 23:25:28 hollings Exp $
44 #include "dyninstAPI/src/inst-sparc.h"
45 #include "dyninstAPI/src/instPoint.h"
47 #include "dyninstAPI/src/FunctionExpansionRecord.h"
49 /****************************************************************************/
50 /****************************************************************************/
51 /****************************************************************************/
53 static dictionary_hash<string, unsigned> funcFrequencyTable(string::hash);
55 trampTemplate baseTemplate;
56 NonRecursiveTrampTemplate nonRecursiveBaseTemplate;
58 //declaration of conservative base trampoline template
60 trampTemplate conservativeBaseTemplate;
61 NonRecursiveTrampTemplate nonRecursiveConservativeBaseTemplate;
65 registerSpace *regSpace;
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 };
72 Register deadList[] = {16, 17, 18, 19, 20, 21, 22, 23 };
75 int deadListSize = sizeof(deadList);
77 /****************************************************************************/
78 /****************************************************************************/
79 /****************************************************************************/
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 ).
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)
99 assert(f->isTrapFunc() == true);
102 delaySlotInsn.raw = owner->get_instruction(oldAddr+4);
103 aggregateInsn.raw = owner->get_instruction(oldAddr+8);
105 // If the instruction is a DCTI, the instruction in the delayed
106 // slot is to be moved.
107 if (IS_DELAYED_INST(instr))
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;
120 if (owner->isValidAddress(oldAddr-4)) {
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);
133 // set size at least....
135 if (ipType == functionEntry) {
136 if (hasNoStackFrame()) {
137 size = 4 * sizeof(instruction);
139 size = 5 * sizeof(instruction);
141 } else if (ipType == callSite) {
142 size = 3 * sizeof(instruction);
143 } else if (ipType == functionExit) {
144 if (hasNoStackFrame()) {
145 size = 5 * sizeof(instruction);
147 size = 2 * sizeof(instruction);
149 } else if (ipType == otherPoint){
150 size = 2 * sizeof(instruction);
156 /****************************************************************************/
157 /****************************************************************************/
158 /****************************************************************************/
160 // Add the astNode opt to generate one instruction to get the
161 // return value for the compiler optimazed case
163 AstNode::optRetVal(AstNode *opt) {
165 if (oType == ReturnVal) {
166 cout << "Optimazed Return." << endl;
170 } else if (opt == 0) {
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);
182 /****************************************************************************/
183 /****************************************************************************/
184 /****************************************************************************/
187 processOptimaRet(instPoint *location, AstNode *&ast) {
189 // For optimazed return code
190 if (location -> ipType == functionExit) {
191 if ((isInsnType(location -> originalInstruction, RETmask, RETmatch)) ||
192 (isInsnType(location -> originalInstruction, RETLmask, RETLmatch)))
194 if (isInsnType(location -> delaySlotInsn,
195 RESTOREmask, RESTOREmatch)&&
196 ((location->delaySlotInsn.raw | 0xc1e82000) != 0xc1e82000))
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);
211 /****************************************************************************/
212 /****************************************************************************/
213 /****************************************************************************/
216 emitOptReturn(instruction i, Register src, char *insn, Address &base, bool noCost) {
218 unsigned instr = i.raw;
220 cout << "Handling a special case for optimized return value." << endl;
222 assert(((instr&0x3e000000)>>25) <= 16);
224 if ((instr&0x02000)>>13)
225 emitImm(plusOp, (instr&0x07c000)>>14, instr&0x01fff,
226 ((instr&0x3e000000)>>25)+16, insn, base, noCost);
228 (void) emitV(plusOp, (instr&0x07c000)>>14, instr&0x01fff,
229 ((instr&0x3e000000)>>25)+16, insn, base, noCost);
231 return emitR(getSysRetValOp, 0, 0, src, insn, base, noCost);
234 /****************************************************************************/
235 /****************************************************************************/
236 /****************************************************************************/
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
244 void initDefaultPointFrequencyTable()
250 funcFrequencyTable["main"] = 1;
251 funcFrequencyTable["DYNINSTsampleValues"] = 1;
252 funcFrequencyTable[EXIT_NAME] = 1;
255 fp = fopen("freq.input", "r");
259 printf("found freq.input file\n");
262 fscanf(fp, "%s %f\n", name, &value);
263 funcFrequencyTable[name] = (int) value;
264 printf("adding %s %f\n", name, value);
269 /****************************************************************************/
270 /****************************************************************************/
271 /****************************************************************************/
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.
277 * The function is selected as follows:
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
282 * else return the funcation containing the point.
284 * WARNING: This code contins arbitray values for func frequency (both user
285 * and system). This should be refined over time.
287 * Using 1000 calls sec to be one SD from the mean for most FPSPEC apps.
291 float getPointFrequency(instPoint *point)
297 func = point->callee;
301 if (!funcFrequencyTable.defines(func->prettyName())) {
302 // Changing this value from 250 to 100 because predictedCost was
303 // too high - naim 07/18/96
307 return (funcFrequencyTable[func->prettyName()]);
311 /****************************************************************************/
312 /****************************************************************************/
313 /****************************************************************************/
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.
319 int getPointCost(process *proc, const instPoint *point)
321 if (proc->baseMap.defines(point)) {
324 // 70 cycles for base tramp (worst case)
329 /****************************************************************************/
330 /****************************************************************************/
331 /****************************************************************************/
333 void initATramp (trampTemplate *thisTemp, Address tramp,
334 bool isConservative=false)
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);
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);
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;
364 case LOCAL_PRE_BRANCH:
365 thisTemp->localPreOffset = offset;
366 thisTemp->localPreReturnOffset = thisTemp->localPreOffset
369 case GLOBAL_PRE_BRANCH:
370 thisTemp->globalPreOffset = offset;
372 case LOCAL_POST_BRANCH:
373 thisTemp->localPostOffset = offset;
374 thisTemp->localPostReturnOffset = thisTemp->localPostOffset
377 case GLOBAL_POST_BRANCH:
378 thisTemp->globalPostOffset = offset;
381 thisTemp->skipPreInsOffset = offset;
383 case UPDATE_COST_INSN:
384 thisTemp->updateCostOffset = offset;
387 thisTemp->skipPostInsOffset = offset;
390 thisTemp->returnInsOffset = offset;
393 thisTemp->emulateInsOffset = offset;
395 case CONSERVATIVE_TRAMP_READ_CONDITION:
397 temp->raw = 0x83408000; /*read condition codes to g1*/
399 case CONSERVATIVE_TRAMP_WRITE_CONDITION:
401 temp->raw = 0x85806000; /*write condition codes fromg1*/
406 // Cost with the skip branches.
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;
416 /****************************************************************************/
417 /****************************************************************************/
418 /****************************************************************************/
420 void initATramp(NonRecursiveTrampTemplate *thisTemp, Address tramp,
421 bool isConservative=false)
423 initATramp((trampTemplate *)thisTemp, tramp,isConservative);
427 for (temp = (instruction*)tramp; temp->raw != END_TRAMP; temp++) {
428 const Address offset = (Address)temp - tramp;
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;
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;
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;
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;
460 /****************************************************************************/
461 /****************************************************************************/
462 /****************************************************************************/
466 static bool inited=false;
471 initATramp(&baseTemplate, (Address) baseTramp);
472 initATramp(&nonRecursiveBaseTemplate, (Address)baseTramp);
475 initATramp(&conservativeBaseTemplate,
476 (Address)conservativeBaseTramp,true);
477 initATramp(&nonRecursiveConservativeBaseTemplate,
478 (Address)conservativeBaseTramp,true);
480 regSpace = new registerSpace(sizeof(deadList)/sizeof(Register), deadList,
485 /****************************************************************************/
486 /****************************************************************************/
487 /****************************************************************************/
489 #if defined(MT_THREAD)
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
496 // NUM_INSN_MT_PREAMBLE
497 void generateMTpreamble(char *insn, Address &base, process *proc)
503 unsigned offset = 19*sizeof(instruction);
504 Register src = Null_Register;
506 vector<AstNode *> dummy;
508 t1 = new AstNode("DYNINSTthreadPos", dummy);
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);
517 // t3=DYNINSTthreadTable+t2
519 tableAddr = proc->findInternalAddress("DYNINSTthreadTable",true,err);
521 AstNode* t5 = new AstNode(AstNode::Constant, (void *)tableAddr);
522 AstNode* t3 = new AstNode(plusOp, t2, t5);
526 AstNode* t7 = new AstNode(AstNode::Constant,(void *)-2);
527 AstNode* t8 = new AstNode(eqOp, t1, t7);
529 AstNode* t9 = new AstNode(AstNode::Constant, (void *)(offset));
531 AstNode* t10 = new AstNode(branchOp, t9);
533 //t11 = "if(t1 ==-2) goto offset"
534 AstNode* t11 = new AstNode(ifOp, t8, t10);
538 //t6 = " if (t1 == -2) goto Offset; t3=DYNINSTthreadTable+t2"
539 AstNode *t6= new AstNode(t11, t3);
542 src = t6->generateCode(proc, regSpace, insn, base, false, true);
544 (void) emitV(orOp, src, 0, REG_MT, insn, base, false);
545 regSpace->freeRegister(src);
548 /****************************************************************************/
549 /****************************************************************************/
550 /****************************************************************************/
552 void generateRPCpreamble(char *insn, Address &base, process *proc, unsigned offset, int tid, unsigned pos)
558 Register src = Null_Register;
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]) ;
568 value = sizeof(unsigned);
569 AstNode* t4 = new AstNode(AstNode::Constant,(void *)value);
570 AstNode* t2 = new AstNode(timesOp, t1, t4);
574 // t3=DYNINSTthreadTable[thr_self()]
576 tableAddr = proc->findInternalAddress("DYNINSTthreadTable",true,err);
578 AstNode* t5 = new AstNode(AstNode::Constant, (void *)tableAddr);
579 AstNode* t3 = new AstNode(plusOp, t2, t5);
583 AstNode* t7 = new AstNode(AstNode::Constant,(void *)-2);
584 AstNode* t8 = new AstNode(eqOp, t1, t7);
586 AstNode* t9 = new AstNode(AstNode::Constant, (void *)(offset));
587 AstNode* t10 = new AstNode(branchOp, t9);
589 AstNode* t11 = new AstNode(ifOp, t8, t10);
593 AstNode *t6= new AstNode(t11, t3);
596 src = t6->generateCode(proc, regSpace, insn, base, false, true);
598 unsigned first_insn=base;
599 (void) emitV(orOp, src, 0, REG_MT, insn, base, false);
600 regSpace->freeRegister(src);
605 /****************************************************************************/
606 /****************************************************************************/
607 /****************************************************************************/
609 void generateNoOp(process *proc, Address addr)
613 /* fill with no-op */
616 insn.branch.op2 = NOOPop2;
618 proc->writeTextWord((caddr_t)addr, insn.raw);
622 /****************************************************************************/
623 /****************************************************************************/
624 /****************************************************************************/
627 * change the insn at addr to be a branch to newAddr.
628 * Used to add multiple tramps to a point.
630 void generateBranch(process *proc, Address fromAddr, Address newAddr)
635 disp = newAddr-fromAddr;
636 generateBranchInsn(&insn, disp);
638 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
641 /****************************************************************************/
642 /****************************************************************************/
643 /****************************************************************************/
645 void generateCall(process *proc, Address fromAddr, Address newAddr)
648 generateCallInsn(&insn, fromAddr, newAddr);
650 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
654 /****************************************************************************/
655 /****************************************************************************/
656 /****************************************************************************/
658 void genImm(process *proc, Address fromAddr, int op,
659 Register rs1, int immd, Register rd)
662 genImmInsn(&insn, op, rs1, immd, rd);
664 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
667 /****************************************************************************/
668 /****************************************************************************/
669 /****************************************************************************/
672 * change the target of the branch at fromAddr, to be newAddr.
674 void changeBranch(process *proc, Address fromAddr, Address newAddr,
675 instruction originalBranch) {
676 int disp = newAddr-fromAddr;
678 insn.raw = originalBranch.raw;
679 insn.branch.disp22 = disp >> 2;
680 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
683 /****************************************************************************/
684 /****************************************************************************/
685 /****************************************************************************/
687 int callsTrackedFuncP(instPoint *point)
689 if (point->callIndirect) {
700 /****************************************************************************/
701 /****************************************************************************/
702 /****************************************************************************/
705 * return the function asociated with a point.
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
711 * This is done to return a better idea of which function we are using.
713 pd_Function *getFunction(instPoint *point)
715 return(point->callee ? point->callee : point->func);
718 /****************************************************************************/
719 /****************************************************************************/
720 /****************************************************************************/
722 bool process::emitInferiorRPCheader(void *insnPtr, Address &baseBytes) {
723 instruction *insn = (instruction *)insnPtr;
724 Address baseInstruc = baseBytes / sizeof(instruction);
726 genImmInsn(&insn[baseInstruc++], SAVEop3, 14, -112, 14);
728 baseBytes = baseInstruc * sizeof(instruction); // convert back
733 /****************************************************************************/
734 /****************************************************************************/
735 /****************************************************************************/
737 bool process::emitInferiorRPCtrailer(void *insnPtr, Address &baseBytes,
738 unsigned &breakOffset,
740 unsigned &stopForResultOffset,
741 #if defined(MT_THREAD)
742 unsigned &justAfter_stopForResultOffset,
745 unsigned &justAfter_stopForResultOffset) {
747 // Sequence: restore, trap, illegal
749 instruction *insn = (instruction *)insnPtr;
750 Address baseInstruc = baseBytes / sizeof(instruction);
754 genBreakpointTrap(&insn[baseInstruc]);
755 stopForResultOffset = baseInstruc * sizeof(instruction);
757 justAfter_stopForResultOffset = baseInstruc * sizeof(instruction);
760 #if defined(MT_THREAD)
761 if (isSafeRPC) //ret instruction
762 genImmInsn(&insn[baseInstruc++], JMPLop3, REG_I(7), 0x08, REG_G(0)) ;
764 genSimpleInsn(&insn[baseInstruc++], RESTOREop3, 0, 0, 0);
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)
771 #if defined(MT_THREAD)
775 genBreakpointTrap(&insn[baseInstruc]); // ta 1
776 breakOffset = baseInstruc * sizeof(instruction);
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)
784 baseBytes = baseInstruc * sizeof(instruction); // convert back
786 return true; // success
789 /****************************************************************************/
790 /****************************************************************************/
791 /****************************************************************************/
793 void emitImm(opCode op, Register src1, RegValue src2imm, Register dest,
794 char *i, Address &base, bool noCost)
796 instruction *insn = (instruction *) ((void*)&i[base]);
803 genImmInsn(insn, op3, src1, src2imm, dest);
808 genImmInsn(insn, op3, src1, src2imm, dest);
813 if (isPowerOf2(src2imm,result) && (result<32))
814 generateLShift(insn, src1, (Register)result, dest);
816 genImmInsn(insn, op3, src1, src2imm, dest);
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);
836 genImmInsn(insn, op3, src1, src2imm, dest);
841 genImmInsn(insn, op3, src1, src2imm, dest);
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
849 genImmRelOp(insn, BNEcond, src1, src2imm, dest, base);
854 genImmRelOp(insn, BEcond, src1, src2imm, dest, base);
859 genImmRelOp(insn, BGEcond, src1, src2imm, dest, base);
864 genImmRelOp(insn, BGTcond, src1, src2imm, dest, base);
869 genImmRelOp(insn, BLEcond, src1, src2imm, dest, base);
874 genImmRelOp(insn, BLTcond, src1, src2imm, dest, base);
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);
886 base += sizeof(instruction);
890 /****************************************************************************/
891 /****************************************************************************/
892 /****************************************************************************/
895 // All values based on Cypress0 && Cypress1 implementations as documented in
896 // SPARC v.8 manual p. 291
898 int getInsnCost(opCode op)
900 /* XXX Need to add branchOp */
901 if (op == loadConstOp) {
903 } else if (op == loadOp) {
904 // sethi + load single
906 } else if (op == loadIndirOp) {
908 } else if (op == storeOp) {
909 // sethi + store single
913 } else if (op == storeIndirOp) {
915 } else if (op == ifOp) {
920 } else if (op == callOp) {
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)]
951 } else if (op == trampPreamble) {
953 } else if (op == trampTrailer) {
956 } else if (op == noOp) {
959 } else if (op == getParamOp) {
970 // bne -- assume taken
980 /****************************************************************************/
981 /****************************************************************************/
982 /****************************************************************************/
984 bool isReturnInsn(instruction instr, Address addr, string name) {
985 if (isInsnType(instr, RETmask, RETmatch) ||
986 isInsnType(instr, RETLmask, RETLmatch)) {
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.
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);
1011 /****************************************************************************/
1012 /****************************************************************************/
1013 /****************************************************************************/
1015 bool isReturnInsn(const image *owner, Address adr, bool &lastOne, string name)
1019 instr.raw = owner->get_instruction(adr);
1022 return isReturnInsn(instr, adr, name);
1025 /****************************************************************************/
1026 /****************************************************************************/
1027 /****************************************************************************/
1029 bool isBranchInsn(instruction instr) {
1030 if (instr.branch.op == 0
1031 && (instr.branch.op2 == 2 || instr.branch.op2 == 6))
1036 /****************************************************************************/
1037 /****************************************************************************/
1038 /****************************************************************************/
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)
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;
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());
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]);
1072 else if(location->ipType == otherPoint) {
1073 const vector<instPoint *> new_arbitrary =
1074 (relocatedByProcess[i])->funcArbitraryPoints();
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]);
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]);
1100 /****************************************************************************/
1101 /****************************************************************************/
1102 /****************************************************************************/
1104 // The exact semantics of the heap are processor specific.
1106 // find all DYNINST symbols that are data symbols
1108 bool process::heapIsOk(const vector<sym_data> &find_us) {
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());
1121 showErrorCallback(50, msg);
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) {
1132 msg = string("Cannot find ") + str + string(". Exiting");
1133 statusLine(msg.string_of());
1134 showErrorCallback(50, msg);
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)) {
1145 // msg = string("Cannot find ") + ghb + string(". Exiting");
1146 // statusLine(msg.string_of());
1147 // showErrorCallback(50, msg);
1151 // Address instHeapEnd = sym.addr()+baseAddr;
1152 // addInternalSymbol(ghb, instHeapEnd);
1156 /* Not needed with the new heap type system */
1158 string ihb = INFERIOR_HEAP_BASE;
1159 if (!getSymbolInfo(ihb, sym, baseAddr)) {
1160 ihb = UINFERIOR_HEAP_BASE;
1161 if (!getSymbolInfo(ihb, sym, baseAddr)) {
1163 msg = string("Cannot find ") + ihb + string(". Cannot use this application");
1164 statusLine(msg.string_of());
1165 showErrorCallback(50, msg);
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
1174 const Address instHeapStart = curr;
1175 const Address instHeapEnd = instHeapStart + SYN_INST_BUF_SIZE - 1;
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());
1189 /****************************************************************************/
1190 /****************************************************************************/
1191 /****************************************************************************/
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)))
1203 /****************************************************************************/
1204 /****************************************************************************/
1205 /****************************************************************************/
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
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;
1218 // for (unsigned i=0; i < stack.size(); i++)
1219 // cout << (void*)stack[i] << endl;
1221 for (u_int i=0; i < stack.size(); i++) {
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_)
1233 /****************************************************************************/
1234 /****************************************************************************/
1235 /****************************************************************************/
1237 void returnInstance::installReturnInstance(process *proc) {
1238 proc->writeTextSpace((caddr_t)addr_, instSeqSize,
1239 (caddr_t) instructionSeq);
1243 /****************************************************************************/
1244 /****************************************************************************/
1245 /****************************************************************************/
1247 void generateBreakPoint(instruction &insn) {
1248 insn.raw = BREAK_POINT_INSN;
1251 /****************************************************************************/
1252 /****************************************************************************/
1253 /****************************************************************************/
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
1261 for (u_int i=0; i < instWList.size(); i++) {
1262 if (instWList[i]->pc_ == pc && instWList[i]->which_proc == proc) {
1264 insn = instWList[i]->relocatedInstruction;
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);
1277 instWaitingList *instW = new instWaitingList(instructionSeq,instSeqSize,
1278 addr_,pc,insn,pc,proc);
1279 instWList.push_back(instW);
1282 /****************************************************************************/
1283 /****************************************************************************/
1284 /****************************************************************************/
1286 bool doNotOverflow(int value)
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);
1294 /****************************************************************************/
1295 /****************************************************************************/
1296 /****************************************************************************/
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);
1304 /****************************************************************************/
1305 /****************************************************************************/
1306 /****************************************************************************/
1308 // process::replaceFunctionCall
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)
1321 // Cannot already be instrumented with a base tramp
1322 if (baseMap.defines(point))
1327 generateNoOp(this, point->addr);
1329 generateCall(this, point->addr,
1330 func->getEffectiveAddress(this));
1335 /****************************************************************************/
1336 /****************************************************************************/
1337 /****************************************************************************/
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))
1351 /****************************************************************************/
1352 /****************************************************************************/
1353 /****************************************************************************/
1355 bool process::MonitorCallSite(instPoint *callSite){
1357 if(isJmplInsn(callSite->originalInstruction)){
1358 vector<AstNode *> the_args(2);
1360 //this instruction is a jmpl with i == 1, meaning it
1361 //calling function register rs1+simm13
1362 if(callSite->originalInstruction.rest.i == 1){
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);
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);
1387 the_args[1] = new AstNode(AstNode::Constant,
1388 (void *) callSite->iPgetAddress());
1389 AstNode *func = new AstNode("DYNINSTRegisterCallee",
1391 addInstFunc(this, callSite, func, callPreInsn,
1396 else if(isTrueCallInsn(callSite->originalInstruction)){
1397 //True call destinations are always statically determinable.
1406 /****************************************************************************/
1407 /****************************************************************************/
1408 /****************************************************************************/
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,
1419 assert(op == funcJumpOp);
1421 void cleanUpAndExit(int status);
1423 addr = callee->getEffectiveAddress(proc);
1425 instruction *insn = (instruction *) ((void*)&i[base]);
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);
1434 #ifdef BPATCH_LIBRARY
1436 #include "BPatch_flowGraph.h"
1437 #include "BPatch_function.h"
1439 #include <sys/systeminfo.h>
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
1448 char isaOptions[256];
1450 if (sysinfo(SI_ISALIST, isaOptions, 256) < 0)
1452 if (strstr(isaOptions, "sparcv8plus"))
1458 * createInstructionInstPoint
1460 * Create a BPatch_point instrumentation point at the given address, which
1461 * is guaranteed not be one of the "standard" inst points.
1463 * proc The process in which to create the inst point.
1464 * address The address for which to create the point.
1466 BPatch_point *createInstructionInstPoint(process *proc, void *address)
1469 Address begin_addr,end_addr,curr_addr;
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
1476 cerr << "BPatch_image::createInstPointAtAddr : is not supported for";
1477 cerr << " sparc architecture earlier than v8plus\n";
1481 curr_addr = (Address)address;
1483 //if the address is not aligned then there is a problem
1484 if(!isAligned(curr_addr))
1487 function_base *func = proc->findFuncByAddr(curr_addr);
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;
1496 instPoint *entry = const_cast<instPoint *>(func->funcEntry(NULL));
1499 begin_addr = entry->iPgetAddress();
1500 end_addr = begin_addr + entry->Size();
1502 if(((begin_addr - INSN_SIZE) <= curr_addr) &&
1503 (curr_addr < end_addr)){
1504 BPatch_reportError(BPatchSerious, 117,
1505 "instrumentation point conflict");
1509 const vector<instPoint*> &exits = func->funcExits(NULL);
1510 for (i = 0; i < exits.size(); i++) {
1513 begin_addr = exits[i]->iPgetAddress();
1514 end_addr = begin_addr + exits[i]->Size();
1516 if (((begin_addr - INSN_SIZE) <= curr_addr) &&
1517 (curr_addr < end_addr)){
1518 BPatch_reportError(BPatchSerious, 117,
1519 "instrumentation point conflict");
1524 const vector<instPoint*> &calls = func->funcCalls(NULL);
1525 for (i = 0; i < calls.size(); i++) {
1528 begin_addr = calls[i]->iPgetAddress();
1529 end_addr = begin_addr + calls[i]->Size();
1531 if (((begin_addr - INSN_SIZE) <= curr_addr) &&
1532 (curr_addr < end_addr)){
1533 BPatch_reportError(BPatchSerious, 117,
1534 "instrumentation point conflict");
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");
1545 } else if (proc->instPointMap.defines(curr_addr + INSN_SIZE)) {
1546 BPatch_reportError(BPatchSerious,117,"instrumentation point conflict");
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. */
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);
1557 BPatch_flowGraph *cfg = bpfunc->getCFG();
1558 BPatch_basicBlock** belements =
1559 new BPatch_basicBlock*[cfg->getAllBasicBlocks()->size()];
1560 cfg->getAllBasicBlocks()->elements(belements);
1562 for(i=0; i< (unsigned)cfg->getAllBasicBlocks()->size(); i++) {
1564 if (belements[i]->getAddressRange(bbsa,bbea)) {
1565 begin_addr = (Address)bbsa;
1566 if ((begin_addr - INSN_SIZE) == curr_addr) {
1568 BPatch_reportError(BPatchSerious, 118,
1569 "point uninstrumentable");
1576 /* Check for instrumenting just before or after a branch. */
1578 if ((Address)address > func->getEffectiveAddress(proc)) {
1579 instruction prevInstr;
1580 proc->readTextSpace((char *)address - INSN_SIZE,
1581 sizeof(instruction),
1583 if (IS_DELAYED_INST(prevInstr)){
1584 BPatch_reportError(BPatchSerious, 118, "point uninstrumentable");
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),
1595 if (IS_DELAYED_INST(nextInstr)){
1596 BPatch_reportError(BPatchSerious, 118, "point uninstrumentable");
1602 proc->readTextSpace(address, sizeof(instruction), &instr.raw);
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,
1613 pointFunction->addArbitraryPoint(newpt,proc);
1615 return proc->findOrCreateBPPoint(bpfunc, newpt, BPatch_instruction);
1620 * BPatch_point::getDisplacedInstructions
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.
1625 * maxSize The maximum number of bytes of instructions to return.
1626 * insns A pointer to a buffer in which to return the instructions.
1628 int BPatch_point::getDisplacedInstructions(int maxSize, void* insns)
1631 instruction copyOut[10]; // I think 7 is the max - jkh 8/3/00
1634 // This function is based on what is contained in the instPoint
1635 // constructor in the file inst-sparc-solaris.C
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;
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;
1655 copyOut[count++].raw = point->originalInstruction.raw;
1656 copyOut[count++].raw = point->delaySlotInsn.raw;
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;
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;
1676 } else if(point->ipType == otherPoint) {
1677 copyOut[count++].raw = point->originalInstruction.raw;
1678 copyOut[count++].raw = point->otherInstruction.raw;
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;
1689 if (count * sizeof(instruction) > (unsigned) maxSize) {
1692 memcpy(insns, copyOut, count * sizeof(instruction));
1693 return count * sizeof(instruction);
1699 // needed in metric.C
1700 bool instPoint::match(instPoint *p)
1705 // should we check anything else?
1706 if (addr == p->addr)