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.
43 * inst-sparc.C - Identify instrumentation points for a SPARC processors.
45 * $Log: inst-sparc-solaris.C,v $
46 * Revision 1.6 1996/10/15 20:11:05 newhall
47 * fix to relocating functions with a call instruction immediately following
48 * the save instruction, don't instrument functions with retl instruction and
49 * a call instruction, fix to get io and sync metrics to work correctly
51 * Revision 1.5 1996/10/04 16:12:40 naim
52 * Optimization for code generation (use of immediate operations whenever
53 * possible). This first commit is only for the sparc platform. Other platforms
54 * should follow soon - naim
56 * Revision 1.4 1996/10/04 04:19:52 newhall
57 * bug fix to pdFunction::checkCallPoints
59 * Revision 1.3 1996/10/03 22:12:12 mjrg
60 * Removed multiple stop/continues when inserting instrumentation
61 * Fixed bug on process termination
62 * Removed machine dependent code from metric.C and process.C
64 * Revision 1.2 1996/10/01 18:25:30 newhall
65 * bug fix to instPoint::instPoint when relocating a function
67 * Revision 1.1 1996/09/26 18:58:36 newhall
68 * added support for instrumenting dynamic executables on sparc-solaris
71 * Revision 1.47 1996/09/13 21:41:51 mjrg
72 * Implemented opcode ReturnVal for ast's to get the return value of functions.
73 * Added missing calls to free registers in Ast.generateCode and emitFuncCall.
74 * Removed architecture dependencies from inst.C.
75 * Changed code to allow base tramps of variable size.
77 * Revision 1.46 1996/09/12 18:25:14 naim
78 * Another minor fix to my previous commit! - naim
80 * Revision 1.44 1996/09/12 15:08:21 naim
81 * This commit move all saves and restores from the mini-tramps to the base
82 * tramp. It also add jumps to skip instrumentation in the base-tramp when
83 * it isn't required - naim
85 * Revision 1.43 1996/09/05 16:40:07 lzheng
86 * Moved the architecture dependent definations to the architecture
87 * dependent files; Added some comments
89 * Revision 1.42 1996/08/23 16:59:23 lzheng
90 * Another minor change related to the undoing of tail-call optimaztion
92 * Revision 1.41 1996/08/23 03:44:57 lzheng
93 * Changes made for the previous commit and also minor bug fix for the
94 * undoing of tail-call optimaztion
96 * Revision 1.40 1996/08/20 19:21:57 lzheng
97 * Implementation of moving multiple instructions sequence and
98 * splitting the instrumentation into two phases
99 * (For solaris2.5, ndo the tail-call optimaztion for the system call
100 * so we could get the correct value for calculating the time of system call.)
102 * Revision 1.39 1996/08/16 21:18:59 tamches
103 * updated copyright for release 1.1
105 * Revision 1.38 1996/07/18 19:37:46 naim
106 * Changing the "frequency" value from 250 to 100 - naim
108 * Revision 1.37 1996/05/08 23:51:41 mjrg
109 * included instructions to save registers in cost
111 * Revision 1.36 1996/04/29 22:18:46 mjrg
112 * Added size to functions (get size from symbol table)
113 * Use size to define function boundary
114 * Find multiple return points for sparc
115 * Instrument branches and jumps out of a function as return points (sparc)
116 * Recognize tail-call optimizations and instrument them as return points (sparc)
117 * Move instPoint to machine dependent files
119 * Revision 1.35 1996/04/26 20:43:07 lzheng
120 * Changes to the procedure emitFuncCall. (move all the code dealing with
121 * function Call in the miniTrampoline here)
123 * Revision 1.34 1996/03/25 22:58:05 hollings
124 * Support functions that have multiple exit points.
126 * Revision 1.33 1996/03/20 17:02:46 mjrg
127 * Added multiple arguments to calls.
128 * Instrument pvm_send instead of pvm_recv to get tags.
132 #include "util/h/headers.h"
134 #include "rtinst/h/rtinst.h"
139 #include "inst-sparc.h"
140 #include "arch-sparc.h"
143 #include "internalMetrics.h"
146 #include "showerror.h"
148 #define perror(a) P_abort();
150 extern bool isPowerOf2(int value, int &result);
154 instPoint(pdFunction *f, const instruction &instr, const image *owner,
155 Address &adr, const bool delayOK, bool isLeaf,
157 instPoint(pdFunction *f, const instruction &instr, const image *owner,
158 Address &adr, const bool delayOK, instPointType ipt,
160 ~instPoint() { /* TODO */ }
162 // can't set this in the constructor because call points can't be classified until
163 // all functions have been seen -- this might be cleaned up
164 void set_callee(pdFunction *to) { callee = to; }
167 Address addr; /* address of inst point */
168 instruction originalInstruction; /* original instruction */
169 instruction delaySlotInsn; /* original instruction */
170 instruction aggregateInsn; /* aggregate insn */
171 instruction otherInstruction;
172 instruction isDelayedInsn;
173 instruction inDelaySlotInsn;
174 instruction extraInsn; /* if 1st instr is conditional branch this is
175 previous instruction */
177 bool inDelaySlot; /* Is the instruction in a delay slot */
178 bool isDelayed; /* is the instruction a delayed instruction */
179 bool callIndirect; /* is it a call whose target is rt computed ? */
180 bool callAggregate; /* calling a func that returns an aggregate
181 we need to reolcate three insns in this case
183 pdFunction *callee; /* what function is called */
184 pdFunction *func; /* what function we are inst */
186 bool isBranchOut; /* true if this point is a conditional branch,
187 that may branch out of the function */
188 int branchTarget; /* the original target of the branch */
189 bool leaf; /* true if the procedure is a leaf */
190 instPointType ipType;
191 int instId; /* id of inst in this function */
192 int size; /* size of multiple instruction sequences */
193 const image *image_ptr; // for finding correct image in process
194 bool firstIsConditional; /* 1st instruction is conditional branch */
199 #define ABS(x) ((x) > 0 ? x : -x)
200 #define MAX_BRANCH 0x1<<23
201 //#define MAX_IMM 0x1<<12 /* 11 plus shign == 12 bits */
202 #define MAX_IMM13 (4095)
203 #define MIN_IMM13 (-4096)
205 unsigned getMaxBranch() {
222 const char *registerNames[] = { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
223 "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
224 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
225 "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7" };
227 dictionary_hash<string, unsigned> funcFrequencyTable(string::hash);
229 string getStrOp(int op)
232 case SetCC: return("set");
233 case ADDop3: return("add");
234 case ANDop3: return("and");
235 case ORop3: return("or");
236 case SUBop3: return("sub");
237 case SUBop3cc: return("subcc");
238 case SMULop3: return("smul");
239 case SDIVop3: return("sdiv");
240 case XNORop3: return("xnor");
241 case SAVEop3: return("save");
242 case RESTOREop3: return("restore");
243 case JMPLop3: return("jmpl");
244 default: return("???");
248 inline void generateNOOP(instruction *insn)
252 insn->branch.op2 = NOOPop2;
257 inline void generateBranchInsn(instruction *insn, int offset)
259 if (ABS(offset) > MAX_BRANCH) {
260 logLine("a Ranch too far\n");
261 //showErrorCallback(52, "");
268 insn->branch.cond = BAcond;
269 insn->branch.op2 = BICCop2;
270 insn->branch.anneal = true;
271 insn->branch.disp22 = offset >> 2;
273 // logLine("ba,a %x\n", offset);
276 inline void generateCallInsn(instruction *insn, int fromAddr, int toAddr)
278 int offset = toAddr - fromAddr;
280 insn->call.disp30 = offset >> 2;
283 inline void generateJmplInsn(instruction *insn, int rs1, int offset, int rd)
287 insn->resti.op3 = JMPLop3;
288 insn->resti.rs1 = rs1;
290 insn->resti.simm13 = LOW(offset);
293 inline void genBranch(instruction *insn, int offset, unsigned condition, bool annul)
295 if (ABS(offset) > MAX_BRANCH) {
296 logLine("a branch too far\n");
297 showErrorCallback(52, "");
303 insn->branch.cond = condition;
304 insn->branch.op2 = BICCop2;
305 insn->branch.anneal = annul;
306 insn->branch.disp22 = offset >> 2;
309 inline void genSimpleInsn(instruction *insn, int op, reg rs1, reg rs2, reg rd)
312 insn->rest.op = RESTop;
315 insn->rest.rs1 = rs1;
316 insn->rest.rs2 = rs2;
318 // logLine("%s %%%s,%%%s,%%%s\n", getStrOp(op), registerNames[rs1],
319 // registerNames[rs2], registerNames[rd]);
322 inline void genImmInsn(instruction *insn, int op, reg rs1, int immd, reg rd)
325 insn->resti.op = RESTop;
327 insn->resti.op3 = op;
328 insn->resti.rs1 = rs1;
330 insn->resti.simm13 = immd;
332 // logLine("%s %%%s,%d,%%%s\n", getStrOp(op), registerNames[rs1], immd,
333 // registerNames[rd]);
336 inline void genImmRelOp(instruction *insn, int cond, reg rs1,
337 int immd, reg rd, unsigned &base)
340 genImmInsn(insn, SUBop3cc, rs1, immd, 0); insn++;
342 genImmInsn(insn, ORop3, 0, 1, rd); insn++;
346 insn->branch.cond = cond;
347 insn->branch.op2 = BICCop2;
348 insn->branch.anneal = true;
349 insn->branch.disp22 = 2;
353 genSimpleInsn(insn, ORop3, 0, 0, rd); insn++;
354 base += 4 * sizeof(instruction);
357 inline void genRelOp(instruction *insn, int cond, reg rs1,
358 reg rs2, reg rd, unsigned &base)
361 genSimpleInsn(insn, SUBop3cc, rs1, rs2, 0); insn++;
363 genImmInsn(insn, ORop3, 0, 1, rd); insn++;
367 insn->branch.cond = cond;
368 insn->branch.op2 = BICCop2;
369 insn->branch.anneal = true;
370 insn->branch.disp22 = 2;
374 genSimpleInsn(insn, ORop3, 0, 0, rd); insn++;
375 base += 4 * sizeof(instruction);
378 inline void generateSetHi(instruction *insn, int src1, int dest)
381 insn->sethi.op = FMT2op;
382 insn->sethi.rd = dest;
383 insn->sethi.op2 = SETHIop2;
384 insn->sethi.imm22 = HIGH(src1);
386 // logLine("sethi %%hi(0x%x), %%%s\n", HIGH(src1)*1024,
387 // registerNames[dest]);
390 // st rd, [rs1 + offset]
391 inline void generateStore(instruction *insn, int rd, int rs1, int offset)
393 insn->resti.op = STop;
395 insn->resti.op3 = STop3;
396 insn->resti.rs1 = rs1;
398 insn->resti.simm13 = LOW(offset);
402 inline void generateLShift(instruction *insn, int rs1, int offset, int rd)
404 insn->restix.op = SLLop;
405 insn->restix.op3 = SLLop3;
406 insn->restix.rd = rd;
407 insn->restix.rs1 = rs1;
410 insn->restix.rs2 = offset;
414 inline void generateRShift(instruction *insn, int rs1, int offset, int rd)
416 insn->restix.op = SRLop;
417 insn->restix.op3 = SRLop3;
418 insn->restix.rd = rd;
419 insn->restix.rs1 = rs1;
422 insn->restix.rs2 = offset;
425 // load [rs1 + offset], rd
426 inline void generateLoad(instruction *insn, int rs1, int offset, int rd)
428 insn->resti.op = LOADop;
429 insn->resti.op3 = LDop3;
431 insn->resti.rs1 = rs1;
433 insn->resti.simm13 = LOW(offset);
436 // swap [rs1 + offset], rd
437 inline void generateSwap(instruction *insn, int rs1, int offset, int rd)
439 insn->resti.op = SWAPop;
441 insn->resti.op3 = SWAPop3;
442 insn->resti.rs1 = rs1;
444 insn->resti.simm13 = LOW(offset);
447 // std rd, [rs1 + offset]
448 inline void genStoreD(instruction *insn, int rd, int rs1, int offset)
450 insn->resti.op = STop;
452 insn->resti.op3 = STDop3;
453 insn->resti.rs1 = rs1;
455 insn->resti.simm13 = LOW(offset);
458 // ldd [rs1 + offset], rd
459 inline void genLoadD(instruction *insn, int rs1, int offset, int rd)
461 insn->resti.op = LOADop;
462 insn->resti.op3 = LDDop3;
464 insn->resti.rs1 = rs1;
466 insn->resti.simm13 = LOW(offset);
470 // Constructor for the class instPoint. This one defines the
471 // instPoints for the relocated function. Since the function reloated
472 // to the heap don't need to worry about that jump could be out of
473 // reach, the instructions to be moved are the one instruction at that
474 // point plus others if necessary(i.e. instruction in the delayed
475 // slot and maybe the aggregate instuction ).
476 instPoint::instPoint(pdFunction *f, const instruction &instr,
477 const image *owner, Address &adr, bool delayOK,
478 instPointType pointType, Address &oldAddr)
479 : addr(adr), originalInstruction(instr), inDelaySlot(false), isDelayed(false),
480 callIndirect(false), callAggregate(false), callee(NULL), func(f), ipType(pointType), image_ptr(owner), firstIsConditional(false)
482 assert(f->isTrap == true);
485 delaySlotInsn.raw = owner->get_instruction(oldAddr+4);
486 aggregateInsn.raw = owner->get_instruction(oldAddr+8);
488 // If the instruction is a DCTI, the instruction in the delayed
489 // slot is to be moved.
490 if (IS_DELAYED_INST(instr))
493 // If this function call another function which return an aggregate
494 // value, move the aggregate instruction, too.
495 if (ipType == callSite) {
496 if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
497 callAggregate = true;
503 if (owner->isValidAddress(oldAddr-4)) {
505 iplus1.raw = owner->get_instruction(oldAddr-4);
506 if (IS_DELAYED_INST(iplus1) && !delayOK) {
507 // ostrstream os(errorLine, 1024, ios::out);
508 // os << "** inst point " << func->file->fullName << "/"
509 // << func->prettyName() << " at addr " << addr <<
510 // " in a delay slot\n";
511 // logLine(errorLine);
517 // Another constructor for the class instPoint. This one is called
518 // for the define the instPoints for regular functions which means
519 // multiple instructions is going to be moved to based trampoline.
520 // Since we will use the instruction CALL to branch to the base
521 // tramp(so it doesn't have any code size restriction), things are
522 // a little more complicated because instruction CALL changes the
523 // value in the link register.
524 instPoint::instPoint(pdFunction *f, const instruction &instr,
525 const image *owner, Address &adr,
526 bool delayOK, bool isLeaf, instPointType pointType)
527 : addr(adr), originalInstruction(instr), inDelaySlot(false), isDelayed(false),
528 callIndirect(false), callAggregate(false), callee(NULL), func(f),
529 leaf(isLeaf), ipType(pointType), image_ptr(owner), firstIsConditional(false)
535 // When the function is not a leaf function
538 // we will treat the first instruction after the SAVE instruction
539 // in the nonleaf procedure as the function entry.
540 if (ipType == functionEntry) {
542 assert(isInsnType(instr, SAVEmask, SAVEmatch));
544 originalInstruction.raw = owner->get_instruction(addr);
545 delaySlotInsn.raw = owner->get_instruction(addr+4);
546 size += 2*sizeof(instruction);
548 // If the second instruction is DCTI, we need to move the
549 // the instruction in the delayed slot.
550 if (IS_DELAYED_INST(delaySlotInsn)) {
552 isDelayedInsn.raw = owner->get_instruction(addr+8);
553 size += 1*sizeof(instruction);
555 // Life is hard. If the second instruction is actually
556 // an CALL instruction, we need to move the instruction
557 // after the instruction in the delayed slot if the
558 // return value of this function is a aggregate value.
559 aggregateInsn.raw = owner->get_instruction(addr+12);
560 if (isCallInsn(delaySlotInsn)) {
561 if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
562 callAggregate = true;
563 size += 1*sizeof(instruction);
568 // The following are easier.
569 } else if (ipType == callSite) {
570 delaySlotInsn.raw = owner->get_instruction(addr+4);
571 size += 2*sizeof(instruction);
573 aggregateInsn.raw = owner->get_instruction(addr+8);
574 if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
575 callAggregate = true;
576 size += 1*sizeof(instruction);
579 delaySlotInsn.raw = owner->get_instruction(addr+4);
580 size += 2*sizeof(instruction);
584 // When the function is a leaf function
587 // For the leaf procedure, there are no function calls in
588 // this procdure. So we don't need to consider the
589 // aggregate instuction.
590 if (ipType == functionEntry) {
592 otherInstruction.raw = owner->get_instruction(addr+4);
593 delaySlotInsn.raw = owner->get_instruction(addr+8);
594 size += 2*sizeof(instruction);
596 if (IS_DELAYED_INST(delaySlotInsn)) {
598 isDelayedInsn.raw = owner->get_instruction(addr+12);
599 size += 2*sizeof(instruction);
602 } else if (ipType == functionExit) {
606 if (owner->isValidAddress(addr-4)) {
608 iplus1.raw = owner->get_instruction(addr-4);
609 if (IS_DELAYED_INST(iplus1) && !delayOK) {
612 size += 1*sizeof(instruction);
613 if(isCondBranch(iplus1)){
614 instruction previous_inst;
615 previous_inst.raw = owner->get_instruction(addr-4);
616 firstIsConditional = true;
617 addr -= sizeof(instruction);
618 size += 1*sizeof(instruction);
623 originalInstruction.raw = owner->get_instruction(addr);
624 otherInstruction.raw = owner->get_instruction(addr+4);
625 delaySlotInsn.raw = owner->get_instruction(addr+8);
626 size += 3*sizeof(instruction);
629 inDelaySlotInsn.raw = owner->get_instruction(addr+12);
630 if(firstIsConditional) {
631 extraInsn.raw = owner->get_instruction(addr+16);
636 // Of course, the leaf function could not have call sites.
637 logLine("Internal Error: in inst-sparc.C.");
642 // return the address in the code segment after this instruction
643 // sequence. (there's a -1 here because one will be added up later in
644 // the function findInstPoints)
645 adr = addr + (size - 1*sizeof(instruction));
648 // Determine if the called function is a "library" function or a "user" function
649 // This cannot be done until all of the functions have been seen, verified, and
652 void pdFunction::checkCallPoints() {
656 vector<instPoint*> non_lib;
658 for (unsigned i=0; i<calls.size(); ++i) {
659 /* check to see where we are calling */
663 if (isInsnType(p->originalInstruction, CALLmask, CALLmatch)) {
665 loc_addr = p->addr + (p->originalInstruction.call.disp30 << 2);
666 pdFunction *pdf = (file_->exec())->findFunction(loc_addr);
667 if (pdf && !pdf->isLibTag()) {
671 // if this is a call outside the fuction, keep it
672 if((loc_addr < addr()) || (loc_addr > (addr() + size()))){
673 p->callIndirect = true;
684 // Indirect call -- be conservative, assume it is a call to
685 // an unnamed user function
686 assert(!p->callee); assert(p->callIndirect);
694 // TODO we cannot find the called function by address at this point in time
695 // because the called function may not have been seen.
697 Address pdFunction::newCallPoint(Address &adr, const instruction instr,
698 const image *owner, bool &err,
699 int &callId, Address &oldAddr)
706 point = new instPoint(this, instr, owner, adr, false, callSite, oldAddr);
708 point = new instPoint(this, instr, owner, adr, false, false, callSite);
711 if (!isInsnType(instr, CALLmask, CALLmatch)) {
712 point->callIndirect = true;
713 point->callee = NULL;
715 point->callIndirect = false;
719 if (not_relocating) {
721 calls[callId] -> instId = callId++;
723 // calls to a location within the function are not
724 // kept in the calls vector
726 assert(((u_int)callId) < calls.size());
727 *(calls[callId++]) = *point;
737 // initDefaultPointFrequencyTable - define the expected call frequency of
738 // procedures. Currently we just define several one shots with a
739 // frequency of one, and provide a hook to read a file with more accurate
742 void initDefaultPointFrequencyTable()
748 funcFrequencyTable["main"] = 1;
749 funcFrequencyTable["DYNINSTsampleValues"] = 1;
750 funcFrequencyTable[EXIT_NAME] = 1;
753 fp = fopen("freq.input", "r");
757 printf("found freq.input file\n");
760 fscanf(fp, "%s %f\n", name, &value);
761 funcFrequencyTable[name] = (int) value;
762 printf("adding %s %f\n", name, value);
768 * Get an etimate of the frequency for the passed instPoint.
769 * This is not (always) the same as the function that contains the point.
771 * The function is selected as follows:
773 * If the point is an entry or an exit return the function name.
774 * If the point is a call and the callee can be determined, return the called
776 * else return the funcation containing the point.
778 * WARNING: This code contins arbitray values for func frequency (both user
779 * and system). This should be refined over time.
781 * Using 1000 calls sec to be one SD from the mean for most FPSPEC apps.
785 float getPointFrequency(instPoint *point)
791 func = point->callee;
795 if (!funcFrequencyTable.defines(func->prettyName())) {
796 if (func->isLibTag()) {
799 // Changing this value from 250 to 100 because predictedCost was
800 // too high - naim 07/18/96
804 return (funcFrequencyTable[func->prettyName()]);
809 // return cost in cycles of executing at this point. This is the cost
810 // of the base tramp if it is the first at this point or 0 otherwise.
812 int getPointCost(process *proc, instPoint *point)
814 if (proc->baseMap.defines(point)) {
817 // 70 cycles for base tramp (worst case)
823 * Given and instruction, relocate it to a new address, patching up
824 * any relative addressing that is present.
827 void relocateInstruction(instruction *insn, u_int origAddr, u_int targetAddr,
832 // If the instruction is a CALL instruction, calculate the new
834 if (isInsnType(*insn, CALLmask, CALLmatch)) {
835 newOffset = origAddr - targetAddr + (insn->call.disp30 << 2);
836 insn->call.disp30 = newOffset >> 2;
837 } else if (isInsnType(*insn, BRNCHmask, BRNCHmatch)||
838 isInsnType(*insn, FBRNCHmask, FBRNCHmatch)) {
840 // If the instruction is a Branch instruction, calculate the
841 // new offset. If the new offset is out of reach after the
842 // instruction is moved to the base Trampoline, we would do
844 // b address ...... address: save
847 newOffset = origAddr - targetAddr + (insn->branch.disp22 << 2);
849 // if the branch is too far, then allocate more space in inferior
850 // heap for a call instruction to branch target. The base tramp
851 // will branch to this new inferior heap code, which will call the
852 // target of the branch
853 if (ABS(newOffset) > MAX_BRANCH) {
854 int ret = inferiorMalloc(proc, 3*sizeof(instruction), textHeap);
855 u_int old_offset = insn->branch.disp22 << 2;
856 insn->branch.disp22 = (ret - targetAddr)>>2;
857 // printf("ret = %d origAddr = %d targetAddr = %d disp22 = %d oldoff = %d\n",
858 // ret ,origAddr, targetAddr,insn->branch.disp22,old_offset);
860 instruction insnPlus[3];
861 genImmInsn(insnPlus, SAVEop3, REG_SP, -112, REG_SP);
862 generateCallInsn(insnPlus+1, ret+sizeof(instruction),
863 origAddr+old_offset);
864 genSimpleInsn(insnPlus+2, RESTOREop3, 0, 0, 0);
865 proc->writeDataSpace((caddr_t)ret, sizeof(insnPlus),
868 insn->branch.disp22 = newOffset >> 2;
870 } else if (isInsnType(*insn, TRAPmask, TRAPmatch)) {
871 // There should be no probelm for moving trap instruction
872 // logLine("attempt to relocate trap\n");
874 /* The rest of the instructions should be fine as is */
877 trampTemplate baseTemplate;
879 extern "C" void baseTramp();
881 void initATramp(trampTemplate *thisTemp, instruction *tramp)
885 // TODO - are these offset always positive?
886 thisTemp->trampTemp = (void *) tramp;
887 for (temp = tramp; temp->raw != END_TRAMP; temp++) {
889 case LOCAL_PRE_BRANCH:
890 thisTemp->localPreOffset = ((void*)temp - (void*)tramp);
891 thisTemp->localPreReturnOffset = thisTemp->localPreOffset
894 case GLOBAL_PRE_BRANCH:
895 thisTemp->globalPreOffset = ((void*)temp - (void*)tramp);
897 case LOCAL_POST_BRANCH:
898 thisTemp->localPostOffset = ((void*)temp - (void*)tramp);
899 thisTemp->localPostReturnOffset = thisTemp->localPostOffset
902 case GLOBAL_POST_BRANCH:
903 thisTemp->globalPostOffset = ((void*)temp - (void*)tramp);
906 thisTemp->skipPreInsOffset = ((void*)temp - (void*)tramp);
909 thisTemp->skipPostInsOffset = ((void*)temp - (void*)tramp);
912 thisTemp->returnInsOffset = ((void*)temp - (void*)tramp);
915 thisTemp->emulateInsOffset = ((void*)temp - (void*)tramp);
919 thisTemp->size = (int) temp - (int) tramp;
922 registerSpace *regSpace;
924 int deadList[] = {16, 17, 18, 19, 20, 21, 22, 23 };
928 static bool inited=false;
933 initATramp(&baseTemplate, (instruction *) baseTramp);
935 regSpace = new registerSpace(sizeof(deadList)/sizeof(int), deadList, 0, NULL);
939 * Install a base tramp -- fill calls with nop's for now.
941 * This one install the base tramp for the regular functions.
944 trampTemplate *installBaseTramp(instPoint *location, process *proc)
950 unsigned baseAddr = inferiorMalloc(proc, baseTemplate.size, textHeap);
951 code = new instruction[baseTemplate.size];
952 memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
954 for (temp = code, currAddr = baseAddr;
955 (currAddr - baseAddr) < (unsigned) baseTemplate.size;
956 temp++, currAddr += sizeof(instruction)) {
958 if (temp->raw == EMULATE_INSN) {
960 // Load the value of link register from stack
961 // If it is a leaf function, genereate a RESTORE instruction
962 // since there's an instruction SAVE generated and put in the
964 if (location -> leaf) {
965 genImmInsn(temp, RESTOREop3, 0, 0, 0);
967 currAddr += sizeof(instruction);
970 // Same for the leaf and nonleaf functions.
971 // First, relocate the "FIRST instruction" in the sequence;
972 *temp = location->originalInstruction;
973 Address fromAddr = location->addr;
975 // compute the real from address if this instrumentation
976 // point is from a shared object image
977 Address baseAddress = 0;
978 if(proc->getBaseAddress(location->image_ptr,baseAddress)){
979 // printf("in installBaseTramp: currAddr = %x fromAddr = %x baseAddr = %x"
980 // ,currAddr, fromAddr,baseAddress);
981 fromAddr += baseAddress;
982 // printf(" newAddr = %x\n",fromAddr);
985 // If the instruction is a call instruction to a location somewhere
986 // within the function, then the 07 regester must be saved and
987 // resored around the relocated call from the base tramp...the call
988 // instruction changes the value of 07 to be the PC value, and if
989 // we move the call instruction to the base tramp, its value will
990 // be incorrect when we use it in the function. We generate the
991 // following base tramp code:
992 // original delay slot instruction
994 // original call instruction
996 // This case should only occur for function entry points in
997 // functions from shared objects, and there should be no append
998 // trampolene code because the relocated call instruction will
999 // not return to the base tramp
1000 if (isInsnType(*temp, CALLmask, CALLmatch)) {
1001 Address offset = fromAddr + (temp->call.disp30 << 2);
1002 if ((offset >= (location->func->addr()+ baseAddress)) &&
1003 (offset <= ((location->func->addr()+ baseAddress)+
1004 location->func->size()))) {
1005 // TODO: this assumes that the delay slot instruction is not
1006 // a call instruction....is this okay?
1007 *temp = location->delaySlotInsn;
1009 currAddr += sizeof(instruction);
1010 genImmInsn(temp, SAVEop3, REG_SP, -112, REG_SP);
1012 currAddr += sizeof(instruction);
1013 *temp = location->originalInstruction;
1014 relocateInstruction(temp, fromAddr, currAddr, proc);
1016 fromAddr += sizeof(instruction);
1017 currAddr += sizeof(instruction);
1018 genImmInsn(temp, RESTOREop3, 0, 0, 0);
1023 relocateInstruction(temp, fromAddr, currAddr, proc);
1025 // Again, for leaf function, one more is needed to move for one
1027 if (location->leaf) {
1028 fromAddr += sizeof(instruction);
1029 currAddr += sizeof(instruction);
1030 *++temp = location->otherInstruction;
1031 relocateInstruction(temp, fromAddr, currAddr,
1035 // Second, relocate the "NEXT instruction";
1036 fromAddr += sizeof(instruction);
1037 currAddr += sizeof(instruction);
1038 *++temp = location->delaySlotInsn;
1039 relocateInstruction(temp, fromAddr, currAddr,
1042 // Third, if the "NEXT instruction" is a DCTI,
1043 if (location->isDelayed) {
1044 fromAddr += sizeof(instruction);
1045 currAddr += sizeof(instruction);
1046 *++temp = location->isDelayedInsn;
1047 relocateInstruction(temp, fromAddr, currAddr,
1050 // Then, possibly, there's an callAggregate instruction
1052 if (location->callAggregate) {
1053 currAddr += sizeof(instruction);
1054 *++temp = location->aggregateInsn;
1059 // If the "FIRST instruction" is a DCTI, then our so called
1060 // "NEXT instruction" is in the delayed Slot and this might
1061 // happen. (actullay, it happened)
1062 if (location->callAggregate) {
1063 currAddr += sizeof(instruction);
1064 *++temp = location->aggregateInsn;
1068 // For the leaf function, if there's an inDelaySlot instruction,
1069 // move this one to the base Tramp.(i.e. at the function exit,
1070 // if the first instruction is in the delayed slot the previous
1071 // instruction, we have to move that one too, so we count from
1072 // that one and the last one is this sequence is called inDelaySlot
1074 // Well, after all these, another SAVE instruction is generated
1075 // so we are prepared to handle the returning to our application's
1077 if (location->leaf) {
1078 if (location->inDelaySlot) {
1079 fromAddr += sizeof(instruction);
1080 currAddr += sizeof(instruction);
1081 *++temp = location->inDelaySlotInsn;
1082 relocateInstruction(temp, fromAddr, currAddr, proc);
1083 if(location->firstIsConditional){
1084 fromAddr += sizeof(instruction);
1085 currAddr += sizeof(instruction);
1086 *++temp = location->extraInsn;
1087 relocateInstruction(temp, fromAddr, currAddr, proc);
1091 genImmInsn(temp+1, SAVEop3, REG_SP, -112, REG_SP);
1094 } else if (temp->raw == RETURN_INSN) {
1095 // compute the real from address if this instrumentation
1096 // point is from a shared object image
1097 Address baseAddress = 0;
1098 if(proc->getBaseAddress(location->image_ptr,baseAddress)){
1099 // printf("in installBaseTramp: RETURN_INSN: baseAddr = %x currAddr = %x size = %x\n",baseAddress,currAddr,location->size);
1101 // Back to the code segement of the application.
1102 // If the location is in the leaf procedure, generate an RESTORE
1103 // instruction right after the CALL instruction to restore all
1104 // the values in the registers.
1105 if (location -> leaf) {
1106 generateCallInsn(temp, currAddr,
1107 (baseAddress + location->addr)+location->size);
1108 genImmInsn(temp+1, RESTOREop3, 0, 0, 0);
1110 generateCallInsn(temp, currAddr,
1111 (baseAddress + location->addr)+location->size);
1113 } else if (temp->raw == SKIP_PRE_INSN) {
1115 offset = baseAddr+baseTemplate.emulateInsOffset-currAddr;
1116 generateBranchInsn(temp,offset);
1117 } else if (temp->raw == SKIP_POST_INSN) {
1119 offset = baseAddr+baseTemplate.returnInsOffset-currAddr;
1120 generateBranchInsn(temp,offset);
1121 } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
1122 (temp->raw == GLOBAL_PRE_BRANCH) ||
1123 (temp->raw == LOCAL_POST_BRANCH) ||
1124 (temp->raw == GLOBAL_POST_BRANCH)) {
1125 /* fill with no-op */
1130 proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size,(caddr_t) code);
1133 trampTemplate *baseInst = new trampTemplate;
1134 *baseInst = baseTemplate;
1135 baseInst->baseAddr = baseAddr;
1140 * Install the base Tramp for the function relocated.
1141 * (it means the base tramp that don't need to bother with long jump and
1142 * is the one we used before for all the functions(since there's no
1146 trampTemplate *installBaseTrampSpecial(instPoint *location,
1148 vector<instruction> &extra_instrs)
1154 unsigned baseAddr = inferiorMalloc(proc, baseTemplate.size, textHeap);
1155 if (location->func->not_relocating) {
1156 location->func->not_relocating = false;
1157 location->func->relocateFunction(proc,location,extra_instrs);
1160 code = new instruction[baseTemplate.size];
1161 memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
1163 for (temp = code, currAddr = baseAddr;
1164 (currAddr - baseAddr) < (unsigned) baseTemplate.size;
1165 temp++, currAddr += sizeof(instruction)) {
1167 // get the base address if this is a shared object
1168 Address baseAddress = 0;
1169 if(!(proc->getBaseAddress(location->image_ptr,baseAddress))){
1172 if (temp->raw == EMULATE_INSN) {
1174 if (location->isBranchOut) {
1175 // the original instruction is a branch that goes out of a
1176 // function. We don't relocate the original instruction. We
1177 // only get to the tramp is the branch is taken, so we generate
1178 // a unconditional branch to the target of the original
1180 assert(location->branchTarget);
1181 // int disp = location->branchTarget + baseAddress - currAddr;
1182 int disp = location->branchTarget - currAddr;
1183 //printf("A disp = %x\n",disp);
1184 generateBranchInsn(temp, disp);
1185 disp = temp->branch.disp22;
1189 *temp = location->originalInstruction;
1190 // compute the real from address if this instrumentation
1191 // point is from a shared object image
1192 Address fromAddress = location->addr;
1193 //if(proc->getBaseAddress(location->image_ptr,baseAddress)){
1194 // fromAddress += baseAddress;
1196 relocateInstruction(temp, fromAddress, currAddr, proc);
1197 if (location->isDelayed) {
1198 /* copy delay slot instruction into tramp instance */
1199 currAddr += sizeof(instruction);
1200 *++temp = location->delaySlotInsn;
1202 if (location->callAggregate) {
1203 /* copy invalid insn with aggregate size in it */
1204 currAddr += sizeof(instruction);
1205 *++temp = location->aggregateInsn;
1208 } else if (temp->raw == RETURN_INSN) {
1209 generateBranchInsn(temp,
1210 (location->addr+ sizeof(instruction) - currAddr));
1211 if (location->isDelayed) {
1212 /* skip the delay slot instruction */
1213 temp->branch.disp22 += 1;
1215 if (location->callAggregate) {
1216 /* skip the aggregate size slot */
1217 temp->branch.disp22 += 1;
1219 } else if (temp->raw == SKIP_PRE_INSN) {
1221 offset = baseAddr+baseTemplate.emulateInsOffset-currAddr;
1222 generateBranchInsn(temp,offset);
1223 } else if (temp->raw == SKIP_POST_INSN) {
1225 offset = baseAddr+baseTemplate.returnInsOffset-currAddr;
1226 generateBranchInsn(temp,offset);
1227 } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
1228 (temp->raw == GLOBAL_PRE_BRANCH) ||
1229 (temp->raw == LOCAL_POST_BRANCH) ||
1230 (temp->raw == GLOBAL_POST_BRANCH)) {
1231 /* fill with no-op */
1236 proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size,(caddr_t) code);
1238 trampTemplate *baseInst = new trampTemplate;
1239 *baseInst = baseTemplate;
1240 baseInst->baseAddr = baseAddr;
1244 void generateNoOp(process *proc, int addr)
1248 /* fill with no-op */
1251 insn.branch.op2 = NOOPop2;
1254 proc->writeTextWord((caddr_t)addr, insn.raw);
1255 // (void) PCptrace(PTRACE_POKETEXT, proc, (char*)addr, insn.raw, NULL);
1258 void changeBranch(process *proc, unsigned fromAddr, unsigned newAddr,
1259 instruction originalBranch);
1261 void generateCall(process *proc, unsigned fromAddr, unsigned newAddr);
1262 void genImm(process *proc, unsigned fromAddr, int op, reg rs1, int immd,reg rd);
1265 void AstNode::sysFlag(instPoint *location)
1267 astFlag = location->func->isTrap;
1269 loperand->sysFlag(location);
1271 roperand->sysFlag(location);
1273 for (unsigned u = 0; u < operands.size(); u++)
1274 operands[u].sysFlag(location);
1279 * Allocate the space for the base Trampoline, and generate the instruction
1280 * we need for modifying the code segment
1283 trampTemplate *findAndInstallBaseTramp(process *proc,
1284 instPoint *location,
1285 returnInstance *&retInstance)
1287 Address adr = location->addr;
1289 process *globalProc;
1291 if (nodePseudoProcess && (proc->symbols == nodePseudoProcess->symbols)){
1292 globalProc = nodePseudoProcess;
1298 if (!globalProc->baseMap.defines(location)) {
1299 if (location->func->isTrap) {
1300 // get the base Address of this function if it is a
1302 Address baseAddress = 0;
1303 if(!(proc->getBaseAddress(location->image_ptr,baseAddress))){
1304 // TODO: what should be done here?
1305 logLine("Error:findAndInstallBaseTramp call getBaseAddress\n");
1307 // Install Base Tramp for the functions which are
1308 // relocated to the heap.
1309 vector<instruction> extra_instrs;
1310 ret = installBaseTrampSpecial(location, globalProc,extra_instrs);
1311 if (location->isBranchOut){
1312 changeBranch(globalProc, location->addr,
1313 (int) ret->baseAddr, location->originalInstruction);
1315 generateBranch(globalProc, location->addr,
1316 (int)ret->baseAddr);
1319 // If the function has not been installed to the base Tramp yet,
1320 // generate the following instruction sequece at the right
1321 // beginning of this function:
1322 // SAVE; CALL; RESTORE.
1323 // so that it would jump the start of the relocated function
1324 // which is in heap.
1325 if (location->func->notInstalled) {
1326 location->func->notInstalled = false;
1327 u_int e_size = extra_instrs.size();
1328 instruction *insn = new instruction[3 + e_size];
1329 Address adr = location-> func -> addr();
1330 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1331 generateCallInsn(insn+1, adr+baseAddress+4,
1332 location->func->newAddr);
1333 genSimpleInsn(insn+2, RESTOREop3, 0, 0, 0);
1334 for(u_int i=0; i < e_size; i++){
1335 insn[3+i] = extra_instrs[i];
1337 retInstance = new returnInstance((instructUnion *)insn,
1338 (3+e_size)*sizeof(instruction),
1340 location->func->size());
1344 // Install base tramp for all the other regular functions.
1345 ret = installBaseTramp(location, globalProc);
1346 // compute the real from address if this instrumentation
1347 // point is from a shared object image
1348 Address baseAddress = 0;
1349 if(proc->getBaseAddress(location->image_ptr,baseAddress)){
1352 if (location->leaf) {
1353 // if it is the leaf function, we need to generate
1354 // the following instruction sequence:
1356 instruction *insn = new instruction[3];
1357 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1358 generateCallInsn(insn+1, adr+4, (int) ret->baseAddr);
1359 generateNOOP(insn+2);
1360 retInstance = new returnInstance((instructUnion *)insn,
1361 3*sizeof(instruction), adr,
1362 3*sizeof(instruction));
1365 // Generate branch instruction from the application to the
1366 // base trampoline and no SAVE instruction is needed
1367 instruction *insn = new instruction[2];
1368 generateCallInsn(insn, adr, (int) ret->baseAddr);
1369 generateNOOP(insn+1);
1370 retInstance = new returnInstance((instructUnion *)insn,
1371 2*sizeof(instruction), adr,
1372 2*sizeof(instruction));
1376 globalProc->baseMap[location] = ret;
1379 ret = globalProc->baseMap[location];
1386 * Install a single tramp.
1389 void installTramp(instInstance *inst, char *code, int codeSize)
1392 insnGenerated += codeSize/sizeof(int);
1395 (inst->proc)->writeDataSpace((caddr_t)inst->trampBase, codeSize, code);
1398 if (inst->when == callPreInsn) {
1399 atAddr = inst->baseInstance->baseAddr+baseTemplate.skipPreInsOffset;
1402 atAddr = inst->baseInstance->baseAddr+baseTemplate.skipPostInsOffset;
1404 generateNoOp(inst->proc, atAddr);
1408 * change the insn at addr to be a branch to newAddr.
1409 * Used to add multiple tramps to a point.
1411 void generateBranch(process *proc, unsigned fromAddr, unsigned newAddr)
1416 disp = newAddr-fromAddr;
1417 generateBranchInsn(&insn, disp);
1420 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
1421 // (void) PCptrace(PTRACE_POKETEXT, proc, (char*)fromAddr, insn.raw, NULL);
1424 void generateCall(process *proc, unsigned fromAddr,unsigned newAddr)
1427 generateCallInsn(&insn, fromAddr, newAddr);
1429 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
1433 void genImm(process *proc, Address fromAddr,int op, reg rs1, int immd, reg rd)
1436 genImmInsn(&insn, op, rs1, immd, rd);
1438 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
1442 * change the target of the branch at fromAddr, to be newAddr.
1444 void changeBranch(process *proc, unsigned fromAddr, unsigned newAddr,
1445 instruction originalBranch) {
1446 int disp = newAddr-fromAddr;
1448 insn.raw = originalBranch.raw;
1449 insn.branch.disp22 = disp >> 2;
1450 proc->writeTextWord((caddr_t)fromAddr, insn.raw);
1453 int callsTrackedFuncP(instPoint *point)
1455 if (point->callIndirect) {
1457 // TODO this won't compile now
1458 // it's rare to call a library function as a parameter.
1459 sprintf(errorLine, "*** Warning call indirect\n from %s %s (addr %d)\n",
1460 point->func->file->fullName, point->func->prettyName, point->addr);
1465 if (point->callee && !(point->callee->isLibTag())) {
1474 * return the function asociated with a point.
1476 * If the point is a funcation call, and we know the function being called,
1477 * then we use that. Otherwise it is the function that contains the
1480 * This is done to return a better idea of which function we are using.
1482 pdFunction *getFunction(instPoint *point)
1484 return(point->callee ? point->callee : point->func);
1487 unsigned emitFuncCall(opCode op,
1489 char *i, unsigned &base,
1490 vector<AstNode> operands,
1491 string callee, process *proc)
1493 assert(op == callOp);
1498 addr = (proc->symbols)->findInternalAddress(callee, false, err);
1500 pdFunction *func = (proc->symbols)->findOneFunction(callee);
1502 ostrstream os(errorLine, 1024, ios::out);
1503 os << "Internal error: unable to find addr of " << callee << endl;
1505 showErrorCallback(80, (const char *) errorLine);
1508 addr = func->addr();
1511 for (unsigned u = 0; u < operands.size(); u++)
1512 srcs += operands[u].generateCode(proc, rs, i, base);
1515 instruction *insn = (instruction *) ((void*)&i[base]);
1517 for (unsigned u=0; u<srcs.size(); u++){
1519 string msg = "Too many arguments to function call in instrumentation code: only 5 arguments can be passed on the sparc architecture.\n";
1520 fprintf(stderr, msg.string_of());
1521 showErrorCallback(94,msg);
1524 genSimpleInsn(insn, ORop3, 0, srcs[u], u+8); insn++;
1525 base += sizeof(instruction);
1526 rs->freeRegister(srcs[u]);
1529 generateSetHi(insn, addr, 13); insn++;
1530 genImmInsn(insn, JMPLop3, 13, LOW(addr), 15); insn++;
1533 base += 3 * sizeof(instruction);
1535 // return value is the register with the return value from the
1537 // This needs to be %o0 since it is back in the callers scope.
1541 unsigned emitImm(opCode op, reg src1, reg src2, reg dest, char *i,
1544 instruction *insn = (instruction *) ((void*)&i[base]);
1551 genImmInsn(insn, op3, src1, src2, dest);
1556 genImmInsn(insn, op3, src1, src2, dest);
1561 if (isPowerOf2(src2,result))
1562 generateLShift(insn, src1, (reg)result, dest);
1564 genImmInsn(insn, op3, src1, src2, dest);
1569 generateLShift(insn, src1, src2, dest);
1574 if (isPowerOf2(src2,result))
1575 generateRShift(insn, src1, (reg)result, dest);
1577 genImmInsn(insn, op3, src1, src2, dest);
1583 genImmInsn(insn, op3, src1, src2, dest);
1588 genImmInsn(insn, op3, src1, src2, dest);
1592 // For a particular condition (e.g. <=) we need to use the
1593 // the opposite in order to get the right value (e.g. for >=
1594 // we need BLTcond) - naim
1596 genImmRelOp(insn, BNEcond, src1, src2, dest, base);
1601 genImmRelOp(insn, BEcond, src1, src2, dest, base);
1606 genImmRelOp(insn, BGEcond, src1, src2, dest, base);
1611 genImmRelOp(insn, BGTcond, src1, src2, dest, base);
1616 genImmRelOp(insn, BLEcond, src1, src2, dest, base);
1621 genImmRelOp(insn, BLTcond, src1, src2, dest, base);
1629 base += sizeof(instruction);
1633 unsigned emit(opCode op, reg src1, reg src2, reg dest, char *i, unsigned &base)
1636 instruction *insn = (instruction *) ((void*)&i[base]);
1638 if (op == loadConstOp) {
1639 // dest = src1:imm TODO
1640 if (src1 > MAX_IMM13 || src1 < MIN_IMM13) {
1641 generateSetHi(insn, src1, dest);
1642 base += sizeof(instruction);
1646 genImmInsn(insn, ORop3, dest, LOW(src1), dest);
1647 base += sizeof(instruction);
1649 // really or %g0,imm,regd
1650 genImmInsn(insn, ORop3, 0, src1, dest);
1652 base += sizeof(instruction);
1654 } else if (op == loadOp) {
1655 // dest = [src1] TODO
1656 generateSetHi(insn, src1, dest);
1659 generateLoad(insn, dest, src1, dest);
1661 base += sizeof(instruction)*2;
1662 } else if (op == shiftOp) {
1663 generateLShift(insn, src1, src2, dest);
1664 base += sizeof(instruction);
1665 } else if (op == storeOp) {
1666 insn->sethi.op = FMT2op;
1667 insn->sethi.rd = src2;
1668 insn->sethi.op2 = SETHIop2;
1669 insn->sethi.imm22 = HIGH(dest);
1672 generateStore(insn, src1, src2, dest);
1674 base += sizeof(instruction)*2;
1675 } else if (op == ifOp) {
1677 genSimpleInsn(insn, SUBop3cc, src1, 0, 0); insn++;
1679 insn->branch.op = 0;
1680 insn->branch.cond = BEcond;
1681 insn->branch.op2 = BICCop2;
1682 insn->branch.anneal = false;
1683 insn->branch.disp22 = dest/4;
1687 base += sizeof(instruction)*3;
1688 return(base - 2*sizeof(instruction));
1689 } else if (op == trampPreamble) {
1691 // save and restore are done inthe base tramp now
1692 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1693 base += sizeof(instruction);
1696 // generate code to save global registers
1697 for (unsigned u = 0; u < 4; u++) {
1698 genStoreD(insn, 2*u, REG_FP, - (8 + 8*u));
1699 base += sizeof(instruction);
1703 // generate code to update the observed cost.
1704 // sethi %hi(dest), %l0
1705 generateSetHi(insn, dest, REG_L0);
1706 base += sizeof(instruction);
1709 // ld [%l0+ lo(dest)], %l1
1710 generateLoad(insn, REG_L0, dest, REG_L1);
1711 base += sizeof(instruction);
1715 if (src1 <= MAX_IMM13) {
1716 genImmInsn(insn, ADDop3, REG_L1, src1, REG_L1);
1717 base += sizeof(instruction);
1720 // load in two parts
1721 generateSetHi(insn, src1, REG_L2);
1722 base += sizeof(instruction);
1726 genImmInsn(insn, ORop3, REG_L2, LOW(src1), REG_L2);
1727 base += sizeof(instruction);
1731 genSimpleInsn(insn, ADDop3, REG_L1, REG_L2, REG_L1);
1732 base += sizeof(instruction);
1736 // store result st %l1, [%l0+ lo(dest)];
1737 generateStore(insn, REG_L1, REG_L0, dest);
1738 base += sizeof(instruction);
1740 } else if (op == trampTrailer) {
1742 // save and restore are done inthe base tramp now
1743 // generate code to restore global registers
1744 for (unsigned u = 0; u < 4; u++) {
1745 genLoadD(insn, REG_FP, - (8 + 8*u), 2*u);
1746 base += sizeof(instruction);
1750 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1751 base += sizeof(instruction);
1755 base += sizeof(instruction);
1758 // dest is in words of offset and generateBranchInsn is bytes offset
1759 generateBranchInsn(insn, dest << 2);
1760 base += sizeof(instruction);
1763 // add no-op, SS-5 sometimes seems to try to decode this insn - jkh 2/14
1766 base += sizeof(instruction);
1768 return(base - 2 * sizeof(instruction));
1769 } else if (op == noOp) {
1771 base += sizeof(instruction);
1772 } else if (op == getParamOp) {
1773 // first 8 parameters are in register 24 ....
1774 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1777 generateStore(insn, 24+src1, REG_SP, 68+4*src1);
1780 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1783 generateLoad(insn, REG_SP, 112+68+4*src1, 24+src1);
1786 base += 4*sizeof(instruction);
1793 } else if (op == getSysParamOp) {
1798 } else if (op == getRetValOp) {
1799 // return value is in register 24
1800 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1803 generateStore(insn, 24, REG_SP, 68);
1806 genImmInsn(insn, SAVEop3, REG_SP, -112, REG_SP);
1809 generateLoad(insn, REG_SP, 112+68, 24);
1812 base += 4*sizeof(instruction);
1816 } else if (op == getSysRetValOp) {
1818 } else if (op == saveRegOp) {
1819 // should never be called for this platform.
1851 // For a particular condition (e.g. <=) we need to use the
1852 // the opposite in order to get the right value (e.g. for >=
1853 // we need BLTcond) - naim
1855 genRelOp(insn, BNEcond, src1, src2, dest, base);
1860 genRelOp(insn, BEcond, src1, src2, dest, base);
1865 genRelOp(insn, BGEcond, src1, src2, dest, base);
1870 genRelOp(insn, BGTcond, src1, src2, dest, base);
1875 genRelOp(insn, BLEcond, src1, src2, dest, base);
1880 genRelOp(insn, BLTcond, src1, src2, dest, base);
1888 genSimpleInsn(insn, op3, src1, src2, dest);
1890 base += sizeof(instruction);
1896 // All values based on Cypress0 && Cypress1 implementations as documented in
1897 // SPARC v.8 manual p. 291
1899 int getInsnCost(opCode op)
1901 if (op == loadConstOp) {
1903 } else if (op == loadOp) {
1904 // sethi + load single
1906 } else if (op == shiftOp) {
1908 } else if (op == storeOp) {
1909 // sethi + store single
1913 } else if (op == ifOp) {
1918 } else if (op == callOp) {
1943 } else if (op == trampPreamble) {
1945 // sethi %hi(obsCost), %l0
1946 // ld [%lo + %lo(obsCost)], %l1
1947 // add %l1, <cost>, %l1
1948 // st %l1, [%lo + %lo(obsCost)]
1949 // return(1+1+2+1+3);
1950 return(1+1+1+1+2 + 4);
1951 } else if (op == trampTrailer) {
1956 } else if (op == noOp) {
1959 } else if (op == getParamOp) {
1970 // bne -- assume taken
1980 bool isReturnInsn(const image *owner, Address adr, bool &lastOne)
1984 instr.raw = owner->get_instruction(adr);
1987 if (isInsnType(instr, RETmask, RETmatch) ||
1988 isInsnType(instr, RETLmask, RETLmatch)) {
1989 if ((instr.resti.simm13 != 8) && (instr.resti.simm13 != 12)) {
1990 logLine("*** FATAL Error:");
1991 sprintf(errorLine, " unsupported return\n");
1993 showErrorCallback(55, "");
2002 * Find the instPoints of this function.
2004 bool pdFunction::findInstPoints(const image *owner) {
2012 Address adr1 = addr();
2014 instr.raw = owner->get_instruction(adr1);
2015 if (!IS_VALID_INSN(instr))
2018 // If it contains an instruction, I assume it would be s system call
2019 // which will be treat differently.
2021 not_relocating = false;
2022 bool func_entry_found = false;
2024 for ( ; adr1 < addr() + size(); adr1 += 4) {
2025 instr.raw = owner->get_instruction(adr1);
2027 // If there's an TRAP instruction in the function, we
2028 // assume that it is an system call and will relocate it
2030 if (isInsnType(instr, TRAPmask, TRAPmatch)) {
2032 not_relocating = true;
2033 notInstalled = true;
2034 return findInstPoints(owner, addr(), 0);
2037 // TODO: This is a hacking for the solaris(solaris2.5 actually)
2038 // We will relocate that function if the function has been
2039 // tail-call optimazed.
2040 // (Actully, the reason of this is that the system calls like
2041 // read, write, etc have the tail-call optimazation to call
2042 // the _read, _write etc. which contain the TRAP instruction
2043 // This is only done if libc is statically linked...if the
2044 // libTag is set, otherwise we instrument read and _read
2045 // both for the dynamically linked case
2047 if (isCallInsn(instr)) {
2049 nexti.raw = owner->get_instruction(adr1+4);
2051 if (nexti.rest.op == 2
2052 && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
2053 || nexti.rest.op3 == RESTOREop3)) {
2055 not_relocating = true;
2056 notInstalled = true;
2057 return findInstPoints(owner, addr(), 0);
2062 // The function Entry is defined as the first SAVE instruction plus
2063 // the instructions after this.
2064 // ( The first instruction for the nonleaf function is not
2065 // necessarily a SAVE instruction. )
2066 if (isInsnType(instr, SAVEmask, SAVEmatch) && !func_entry_found) {
2069 func_entry_found = true;
2070 funcEntry_ = new instPoint(this, instr, owner, adr1, true, leaf,
2077 // If there's no SAVE instruction found, this is a leaf function and
2078 // and function Entry will be defined from the first instruction
2081 instr.raw = owner->get_instruction(adr);
2082 funcEntry_ = new instPoint(this, instr, owner, adr, true, leaf, functionEntry);
2086 for ( ; adr < addr() + size(); adr += sizeof(instruction)) {
2088 instr.raw = owner->get_instruction(adr);
2092 // check for return insn and as a side affect decide if we are at the
2093 // end of the function.
2094 if (isReturnInsn(owner, adr, done)) {
2095 // define the return point
2096 funcReturns += new instPoint(this, instr, owner, adr, false, leaf,
2099 } else if (instr.branch.op == 0
2100 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)
2101 && (instr.branch.cond == 0 ||instr.branch.cond == 8)) {
2102 // find if this branch is going out of the function
2103 int disp = instr.branch.disp22;
2104 Address target = adr + (disp << 2);
2105 if ((target < (addr()))
2106 || (target >= (addr() + size()))) {
2107 instPoint *point = new instPoint(this, instr, owner, adr, false, leaf,
2109 funcReturns += point;
2112 } else if (isCallInsn(instr)) {
2114 // if the call target is the address of the call instruction
2115 // then this is not something that we can instrument...
2116 // this occurs in functions with code that is modifined when
2117 // they are loaded by the run-time linker, or when the .init
2118 // section is executed. In this case the instructions in the
2119 // parsed image file are different from the ones in the executable
2121 if(instr.call.op == CALLop) {
2122 Address call_target = adr + (instr.call.disp30 << 2);
2123 if(call_target == adr){
2126 // first, check for tail-call optimization: a call where the instruction
2127 // in the delay slot write to register %o7(15), usually just moving
2128 // the caller's return address, or doing a restore
2129 // Tail calls are instrumented as return points, not call points.
2133 nexti.raw = owner->get_instruction(adr+4);
2135 if (nexti.rest.op == 2
2136 && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
2137 || nexti.rest.op3 == RESTOREop3)) {
2138 //fprintf(stderr, "#### Tail-call optimization in function %s, addr %x\n",
2139 // prettyName().string_of(), adr);
2140 funcReturns += new instPoint(this, instr, owner, adr, false, leaf,
2144 // define a call point
2145 // this may update address - sparc - aggregate return value
2146 // want to skip instructions
2149 adr = newCallPoint(adr, instr, owner, err, dummyId, adr);
2153 else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
2154 /* A register indirect jump. Some jumps may exit the function
2155 (e.g. read/write on SunOS). In general, the only way to
2156 know if a jump is exiting the function is to instrument
2157 the jump to test if the target is outside the current
2158 function. Instead of doing this, we just check the
2159 previous two instructions, to see if they are loading
2160 an address that is out of the current function.
2161 This should catch the most common cases (e.g. read/write).
2162 For other cases, we would miss a return point.
2164 This is the case considered:
2171 reg jumpreg = instr.rest.rs1;
2175 prev1.raw = owner->get_instruction(adr-4);
2176 prev2.raw = owner->get_instruction(adr-8);
2178 unsigned targetAddr;
2180 if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
2181 && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2
2182 && prev2.sethi.rd == (unsigned)jumpreg
2183 && prev1.rest.op == RESTop
2184 && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
2185 && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg) {
2187 targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
2188 targetAddr |= prev1.resti.simm13;
2189 if (targetAddr < addr() || targetAddr >= addr() + size()) {
2190 //fprintf(stderr, "Jump out of function %s at addr = %x, target = %x\n",
2191 // prettyName().string_of(), adr, targetAddr);
2192 instPoint *point = new instPoint(this, instr, owner, adr, false, leaf,
2194 funcReturns += point;
2201 return (checkInstPoints(owner));
2205 * Check all the instPoints within this function to see if there's
2206 * any conficts happen.
2208 bool pdFunction::checkInstPoints(const image *owner) {
2210 // Our own library function, skip the test.
2211 if (prettyName_.prefixed_by("DYNINST"))
2214 // The function is too small to be worthing instrumenting.
2218 // No function return! return false;
2219 if (sizeof(funcReturns) == 0)
2223 Address adr = addr();
2225 bool retl_inst = false;
2226 // Check if there's any branch instruction jump to the middle
2227 // of the instruction sequence in the function entry point
2228 // and function exit point.
2229 for ( ; adr < addr() + size(); adr += sizeof(instruction)) {
2231 instr.raw = owner->get_instruction(adr);
2232 if(isInsnType(instr, RETLmask, RETLmatch)) retl_inst = true;
2234 if (isInsnType(instr, BRNCHmask, BRNCHmatch)||
2235 isInsnType(instr, FBRNCHmask, FBRNCHmatch)) {
2237 int disp = instr.branch.disp22;
2238 Address target = adr + (disp << 2);
2240 if ((target > funcEntry_->addr)&&
2241 (target < (funcEntry_->addr + funcEntry_->size))) {
2242 if (adr > (funcEntry_->addr+funcEntry_->size))
2243 //cout << "Function " << prettyName_ <<" entry" << endl;
2247 for (u_int i = 0; i < funcReturns.size(); i++) {
2248 if ((target > funcReturns[i]->addr)&&
2249 (target < (funcReturns[i]->addr + funcReturns[i]->size))) {
2250 if ((adr < funcReturns[i]->addr)||
2251 (adr > (funcReturns[i]->addr + funcReturns[i]->size)))
2252 // cout << "Function (at " << adr << ") " << prettyName_ <<" exit " << i << " ( adr: " << funcReturns[i]->addr << " size:" << funcReturns[i]->size<< ")" <<endl;
2259 // if there is a retl instruction and we don't think this is a leaf
2260 // function then this is a way messed up function...well, at least we
2261 // we can't deal with this...the only example I can find is _cerror
2262 // and _cerror64 in libc.so.1
2263 if(retl_inst && !leaf){
2267 // check that no instrumentation points could overlap
2268 Address func_entry = funcEntry_->addr + funcEntry_->size;
2269 for (u_int i = 0; i < funcReturns.size(); i++) {
2270 if(func_entry >= funcReturns[i]->addr){
2273 if(i > 1){ // check if return points overlap
2274 Address prev_exit = funcReturns[i-1]->addr+funcReturns[i-1]->size;
2275 if(funcReturns[i]->addr >= prev_exit) {
2285 /* The maximum length of relocatable function is 1k instructions */
2286 static instruction newInstr[1024];
2288 // This function is to find the inst Points for a function
2289 // that will be relocated if it is instrumented.
2290 bool pdFunction::findInstPoints(const image *owner, Address newAdr, process*){
2297 Address adr = addr();
2299 instr.raw = owner->get_instruction(adr);
2300 if (!IS_VALID_INSN(instr))
2303 if (size() <= 3*sizeof(instruction))
2306 instPoint *point = new instPoint(this, instr, owner, newAdr, true,
2307 functionEntry, adr);
2311 // if the second instruction in a relocated function is a call instruction
2312 // or a branch instruction, then we can't deal with this
2313 if(size() > sizeof(instruction)){
2314 Address second_adr = adr + sizeof(instruction);
2315 instruction second_instr;
2316 second_instr.raw = owner->get_instruction(second_adr);
2317 if ((isCallInsn(second_instr)) ||
2318 (second_instr.branch.op == 0 &&
2319 (second_instr.branch.op2 == 2 ||
2320 second_instr.branch.op2 == 6))) {
2329 for (i = 0; adr < addr() + size(); adr += sizeof(instruction),
2330 newAdr += sizeof(instruction), i++) {
2332 instr.raw = owner->get_instruction(adr);
2333 newInstr[i] = instr;
2336 // check for return insn and as a side affect decide if we are at the
2337 // end of the function.
2338 if (isReturnInsn(owner, adr, done)) {
2339 // define the return point
2340 instPoint *point = new instPoint(this, instr, owner, newAdr, false,
2342 funcReturns += point;
2343 funcReturns[retId] -> instId = retId++;
2344 } else if (instr.branch.op == 0
2345 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) {
2346 // find if this branch is going out of the function
2347 int disp = instr.branch.disp22;
2348 Address target = adr + (disp << 2);
2349 if (target < addr() || target >= addr() + size()) {
2350 instPoint *point = new instPoint(this, newInstr[i], owner,
2353 if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {
2354 point->isBranchOut = true;
2355 point->branchTarget = target;
2357 funcReturns += point;
2358 funcReturns[retId] -> instId = retId++;
2361 } else if (isCallInsn(instr)) {
2363 // first, check for tail-call optimization: a call where the instruction
2364 // in the delay slot write to register %o7(15), usually just moving
2365 // the caller's return address, or doing a restore
2366 // Tail calls are instrumented as return points, not call points.
2368 nexti.raw = owner->get_instruction(adr+4);
2370 if (nexti.rest.op == 2
2371 && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
2372 || nexti.rest.op3 == RESTOREop3)) {
2374 instPoint *point = new instPoint(this, instr, owner, newAdr, false,
2376 funcReturns += point;
2377 funcReturns[retId] -> instId = retId++;
2380 // if this is a call instr to a location within the function, and if
2381 // the offest is not 8 then do not define this function
2382 if(instr.call.op == CALLop){
2383 Address call_target = adr + (instr.call.disp30 << 2);
2384 if((call_target >= addr()) && (call_target <= (addr() + size()))){
2385 if((instr.call.disp30 << 2) != 2*sizeof(instruction)) {
2390 // define a call point
2391 // this may update address - sparc - aggregate return value
2392 // want to skip instructions
2394 adr = newCallPoint(newAdr, instr, owner, err, callsId, adr);
2400 else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
2401 /* A register indirect jump. Some jumps may exit the function
2402 (e.g. read/write on SunOS). In general, the only way to
2403 know if a jump is exiting the function is to instrument
2404 the jump to test if the target is outside the current
2405 function. Instead of doing this, we just check the
2406 previous two instructions, to see if they are loading
2407 an address that is out of the current function.
2408 This should catch the most common cases (e.g. read/write).
2409 For other cases, we would miss a return point.
2411 This is the case considered:
2418 reg jumpreg = instr.rest.rs1;
2422 prev1.raw = owner->get_instruction(adr-4);
2423 prev2.raw = owner->get_instruction(adr-8);
2425 unsigned targetAddr;
2427 if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
2428 && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2
2429 && prev2.sethi.rd == (unsigned)jumpreg
2430 && prev1.rest.op == RESTop
2431 && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
2432 && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg){
2434 targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
2435 targetAddr |= prev1.resti.simm13;
2436 if (targetAddr < addr() || targetAddr >= addr() + size()) {
2437 instPoint *point = new instPoint(this, instr, owner,
2440 funcReturns += point;
2441 funcReturns[retId] -> instId = retId++;
2449 // This function assigns new address to instrumentation points of
2450 // a function that has been relocated
2451 bool pdFunction::findNewInstPoints(const image *owner,
2454 vector<instruction> &callInstrs) {
2461 Address adr = addr();
2463 instr.raw = owner->get_instruction(adr);
2464 if (!IS_VALID_INSN(instr))
2467 instPoint *point = new instPoint(this, instr, owner, newAdr, true,
2468 functionEntry, adr);
2470 *funcEntry_ = *point;
2475 // get baseAddress if this is a shared object
2476 Address baseAddress = 0;
2477 if(!(proc->getBaseAddress(owner,baseAddress))){
2481 // if we have call instructions that need to be added after the instrs
2482 // to call the relocated instruction, the first address we can use is
2483 // the address of the 4th instruction in the function
2484 Address call_start_addr = addr() + baseAddress + 3*sizeof(instruction);
2486 for (i = 0; adr < addr() + size(); adr += 4, newAdr += 4, i++) {
2490 instr.raw = owner->get_instruction(adr);
2491 newInstr[i] = instr;
2493 // printf("next address = %x next instr = %x\n",adr,instr.raw);
2497 // check for return insn and as a side affect decide if we are at the
2498 // end of the function.
2499 if (isReturnInsn(owner, adr, done)) {
2500 // define the return point
2501 instPoint *point = new instPoint(this, instr, owner, newAdr, false,
2503 *funcReturns[retId++] = *point;
2504 } else if (instr.branch.op == 0
2505 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)) {
2506 // find if this branch is going out of the function
2507 int disp = instr.branch.disp22;
2508 Address target = adr + baseAddress + (disp << 2);
2509 if ((target < (addr() + baseAddress))
2510 || (target >= (addr() + baseAddress + size()))) {
2511 relocateInstruction(&newInstr[i],adr+baseAddress,newAdr,proc);
2512 instPoint *point = new instPoint(this, newInstr[i], owner,
2515 disp = newInstr[i].branch.disp22;
2516 if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {
2517 point->isBranchOut = true;
2518 point->branchTarget = adr + (disp<<2);
2520 *funcReturns[retId++] = *point;
2523 } else if (isCallInsn(instr)) {
2525 // first, check for tail-call optimization: a call where the instruction
2526 // in the delay slot write to register %o7(15), usually just moving
2527 // the caller's return address, or doing a restore
2528 // Tail calls are instrumented as return points, not call points.
2530 nexti.raw = owner->get_instruction(adr+4);
2532 if (nexti.rest.op == 2
2533 && ((nexti.rest.op3 == ORop3 && nexti.rest.rd == 15)
2534 || nexti.rest.op3 == RESTOREop3)) {
2536 // Undoing the tail-call optimazation when the function
2537 // is relocated. Here is an example:
2538 // before: ---> after
2539 // ---------------------------------------------------
2541 // restore st %i0, [ %fp + 0x44 ]
2546 // st [ %fp + 0x44 ], %i0
2549 // Q: Here the assumption that register i1 is available
2550 // might be an question, is it?
2551 // A: I think it is appropriate because:
2552 // (in situation A calls B and B calls C)
2553 // The procedure C called via tail call is a leaf
2554 // procedure, the value arguments and return value between
2555 // A and C are passed by register (o1...o5, o7)
2556 // So even If B mess up the value of i0, it won't affect the
2557 // commnucation between A and C. Also, we saved the value of
2558 // i0 on stack and when we return from B, the value of i0
2559 // won't be affected.
2560 // If C is not a leaf procedure, it should be fine
2562 // ( If you could give an counter-example, please
2563 // let me know. --ling )
2565 genSimpleInsn(&newInstr[i++], RESTOREop3, 0, 0, 0);
2566 generateStore(&newInstr[i++], 24, REG_FP, 0x44);
2567 genImmInsn(&newInstr[i++], ORop3, 15, 0, 24);
2568 newInstr[i++].raw = owner->get_instruction(adr);
2569 generateNOOP(&newInstr[i++]);
2570 genImmInsn(&newInstr[i++], ORop3, 24, 0, 15);
2571 generateLoad(&newInstr[i++], REG_FP, 0x44, 24);
2572 generateJmplInsn(&newInstr[i++], 15, 8 ,0);
2574 generateNOOP(&newInstr[i]);
2575 instPoint *point = new instPoint(this, instr, owner, newAdr, false,
2577 point-> originalInstruction = newInstr[i-1];
2578 point-> delaySlotInsn = newInstr[i];
2579 point-> isDelayed = true;
2580 *funcReturns[retId++] = *point;
2582 // if the second instruction in the function is a call instruction
2583 // then this cannot go in the delay slot of the branch to the
2584 // base tramp, so add a noop between first and second instructions
2585 // in the relocated function (check out write in libc.so.1 for
2586 // and example of this):
2588 // save %sp, -96, %sp brach to base tramp
2591 if(adr == (addr()+4)){
2592 newInstr[i+1] = instr;
2593 generateNOOP(&newInstr[i]);
2598 // if this is a call to an address within the same function, then
2599 // we need to set the 07 register to have the same value as it
2600 // would before the function was relocated
2601 // to do this we generate a call instruction back to the original
2602 // function location, and then at this location we generate a call
2603 // instruction back to the relocated instruction. In the delay
2604 // slot of the second instruction the value of 07 is changed by
2605 // the difference between the origninal call instruction, and
2606 // the location of the call instruction back to the relocated
2607 // function. This way the 07 register will contain the address
2608 // of the original call instruction
2609 Address call_target = adr + (instr.call.disp30 << 2);
2610 if((call_target >= addr())
2611 && (call_target <= (addr() + size()))){
2612 assert((newInstr[i].call.disp30 << 2) == 8);
2614 // generating call instruction to orginal function address
2615 // after the SAVE call RESTORE instr.s that call the relocated
2617 newInstr[i].call.disp30 = ((call_start_addr -newAdr) >> 2);
2619 // generate call to relocated function from original function
2620 // (this will get almost correct value for register 07)
2621 instruction new_inst;
2622 generateCallInsn(&new_inst,call_start_addr,
2623 newAdr+sizeof(instruction));
2624 callInstrs += new_inst;
2626 // printf("adr = %x baseAddress = %x call_sart = %x offset = %x addr() = %x\n",adr,baseAddress,call_start_addr,adr+baseAddress-call_start_addr,addr());
2627 // generate add isntruction to get correct value for 07 register
2628 // this will go in delay slot of previous call instr.
2629 genImmInsn(&new_inst,ADDop3,REG_O7,
2630 (adr+baseAddress-call_start_addr),REG_O7);
2631 callInstrs += new_inst;
2632 call_start_addr += 2*sizeof(instruction);
2635 // otherwise, this is a call instruction to a location
2636 // outside the function
2638 relocateInstruction(&newInstr[i],adr+baseAddress,newAdr,proc);
2639 Address temp = newCallPoint(newAdr, newInstr[i], owner, err,
2641 if (err) return false;
2646 else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
2647 /* A register indirect jump. Some jumps may exit the function
2648 (e.g. read/write on SunOS). In general, the only way to
2649 know if a jump is exiting the function is to instrument
2650 the jump to test if the target is outside the current
2651 function. Instead of doing this, we just check the
2652 previous two instructions, to see if they are loading
2653 an address that is out of the current function.
2654 This should catch the most common cases (e.g. read/write).
2655 For other cases, we would miss a return point.
2657 This is the case considered:
2664 reg jumpreg = instr.rest.rs1;
2668 prev1.raw = owner->get_instruction(adr-4);
2669 prev2.raw = owner->get_instruction(adr-8);
2671 unsigned targetAddr;
2673 if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
2674 && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2
2675 && prev2.sethi.rd == (unsigned)jumpreg
2676 && prev1.rest.op == RESTop
2677 && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
2678 && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg){
2680 targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
2681 targetAddr |= prev1.resti.simm13;
2682 if (targetAddr < addr() || targetAddr >= addr() + size()) {
2683 instPoint *point = new instPoint(this, instr, owner,
2686 *funcReturns[retId++] = *point;
2696 // called to relocate a function: when a request is made to instrument
2697 // a system call we relocate the entire function into the heap
2699 bool pdFunction::relocateFunction(process *proc, instPoint *location,
2700 vector<instruction> &extra_instrs) {
2703 process *globalProc;
2705 if (nodePseudoProcess && (proc->symbols == nodePseudoProcess->symbols)){
2706 globalProc = nodePseudoProcess;
2711 //Allocate the heap for the function to be relocated
2712 ret = inferiorMalloc(globalProc, size()+32, textHeap);
2715 findNewInstPoints(location->image_ptr, ret, proc, extra_instrs);
2716 proc->writeDataSpace((caddr_t)ret, size()+32,(caddr_t) newInstr);
2721 // The exact semantics of the heap are processor specific.
2723 // find all DYNINST symbols that are data symbols
2725 bool image::heapIsOk(const vector<sym_data> &find_us) {
2726 Address curr, instHeapEnd;
2730 for (unsigned i=0; i<find_us.size(); i++) {
2731 str = find_us[i].name;
2732 if (!linkedFile.get_symbol(str, sym)) {
2733 string str1 = string("_") + str.string_of();
2734 if (!linkedFile.get_symbol(str1, sym) && find_us[i].must_find) {
2736 msg = string("Cannot find ") + str + string(". Exiting");
2737 statusLine(msg.string_of());
2738 showErrorCallback(50, msg);
2742 addInternalSymbol(str, sym.addr());
2745 string ghb = GLOBAL_HEAP_BASE;
2746 if (!linkedFile.get_symbol(ghb, sym)) {
2747 ghb = U_GLOBAL_HEAP_BASE;
2748 if (!linkedFile.get_symbol(ghb, sym)) {
2750 msg = string("Cannot find ") + str + string(". Exiting");
2751 statusLine(msg.string_of());
2752 showErrorCallback(50, msg);
2756 instHeapEnd = sym.addr();
2757 addInternalSymbol(ghb, instHeapEnd);
2758 ghb = INFERIOR_HEAP_BASE;
2760 if (!linkedFile.get_symbol(ghb, sym)) {
2761 ghb = UINFERIOR_HEAP_BASE;
2762 if (!linkedFile.get_symbol(ghb, sym)) {
2764 msg = string("Cannot find ") + str + string(". Cannot use this application");
2765 statusLine(msg.string_of());
2766 showErrorCallback(50, msg);
2771 addInternalSymbol(ghb, curr);
2772 if (curr > instHeapEnd) instHeapEnd = curr;
2774 // check that we can get to our heap.
2775 //if (instHeapEnd > getMaxBranch()) {
2776 // logLine("*** FATAL ERROR: Program text + data too big for dyninst\n");
2777 // sprintf(errorLine, " heap ends at %x\n", instHeapEnd);
2778 // logLine(errorLine);
2780 //} else if (instHeapEnd + SYN_INST_BUF_SIZE > getMaxBranch()) {
2781 // logLine("WARNING: Program text + data could be too big for dyninst\n");
2782 // showErrorCallback(54, "");
2788 // Certain registers (i0-i7 on a SPARC) may be available to be read
2789 // as an operand, but cannot be written.
2790 bool registerSpace::readOnlyRegister(reg reg_number) {
2791 if ((reg_number < 16) || (reg_number > 23))
2797 bool returnInstance::checkReturnInstance(const Address adr) {
2798 if ((adr > addr_) && ( adr <= addr_+size_))
2804 void returnInstance::installReturnInstance(process *proc) {
2805 proc->writeTextSpace((caddr_t)addr_, instSeqSize,
2806 (caddr_t) instructionSeq);
2809 void returnInstance::addToReturnWaitingList(Address pc, process *proc) {
2811 instruction insnTrap;
2812 generateBreakPoint(insnTrap);
2813 proc->readDataSpace((caddr_t)pc, sizeof(insn), (char *)&insn, true);
2814 proc->writeTextSpace((caddr_t)pc, sizeof(insnTrap), (caddr_t)&insnTrap);
2816 instWaitingList *instW = new instWaitingList;
2818 instW->instructionSeq = instructionSeq;
2819 instW->instSeqSize = instSeqSize;
2820 instW->addr_ = addr_;
2822 instW->relocatedInstruction = insn;
2823 instW->relocatedInsnAddr = pc;
2825 instWList.add(instW, (void *)pc);
2828 void generateBreakPoint(instruction &insn) {
2829 insn.raw = BREAK_POINT_INSN;
2832 bool doNotOverflow(int value)
2834 if ( (value <= 16383) && (value >= -16384) ) return(true);
2838 void instWaitingList::cleanUp(process *proc, Address pc) {
2839 proc->writeTextSpace((caddr_t)pc, sizeof(relocatedInstruction),
2840 (caddr_t)&relocatedInstruction);
2841 proc->writeTextSpace((caddr_t)addr_, instSeqSize, (caddr_t)instructionSeq);