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-solaris.C,v 1.87 2001/07/11 21:19:57 gurari Exp $
44 #include "dyninstAPI/src/inst-sparc.h"
45 #include "dyninstAPI/src/instPoint.h"
46 #include "common/h/debugOstream.h"
48 // Needed for function relocation
49 #include "dyninstAPI/src/func-reloc.h"
51 #include <sys/utsname.h>
54 extern bool relocateFunction(process *proc, instPoint *&location);
55 extern bool branchInsideRange(instruction insn, Address branchAddress,
56 Address firstAddress, Address lastAddress);
57 extern instPoint* find_overlap(vector<instPoint*> v, Address targetAddress);
58 extern void sorted_ips_vector(vector<instPoint*>&fill_in);
60 /****************************************************************************/
61 /****************************************************************************/
62 /****************************************************************************/
64 // static unsigned pfdp_to_pfdp_hash(pd_Function * const &f) {
65 // pd_Function *pdf = f;
66 // unsigned l = (unsigned)pdf;
67 // return addrHash4(l);
70 /****************************************************************************/
71 /****************************************************************************/
72 /****************************************************************************/
74 // Another constructor for the class instPoint. This one is called
75 // for the define the instPoints for regular functions which means
76 // multiple instructions is going to be moved to based trampoline.
77 // Since we will use the instruction CALL to branch to the base
78 // tramp(so it doesn't have any code size restriction), things are
79 // a little more complicated because instruction CALL changes the
80 // value in the link register.
81 instPoint::instPoint(pd_Function *f, const instruction &instr,
82 const image *owner, Address &adr,
84 instPointType pointType)
85 : insnAddr(adr), addr(adr), originalInstruction(instr),
86 inDelaySlot(false), isDelayed(false),
87 callIndirect(false), callAggregate(false), callee(NULL),
89 ipType(pointType), image_ptr(owner), firstIsConditional(false),
90 relocated_(false), isLongJump(false)
96 // When the function has a stack frame
97 if (!this->hasNoStackFrame()) {
99 // we will treat the first instruction after the SAVE instruction
100 // in the nonleaf procedure as the function entry.
101 if (ipType == functionEntry) {
103 assert(isInsnType(instr, SAVEmask, SAVEmatch));
104 saveInsn.raw = owner->get_instruction(addr);
106 originalInstruction.raw = owner->get_instruction(addr);
107 delaySlotInsn.raw = owner->get_instruction(addr+4);
108 size += 2*sizeof(instruction);
110 // If the second instruction is DCTI, we need to move the
111 // the instruction in the delayed slot.
112 if (IS_DELAYED_INST(delaySlotInsn)) {
114 isDelayedInsn.raw = owner->get_instruction(addr+8);
115 size += 1*sizeof(instruction);
117 // Life is Hard. If the second instruction is actually
118 // an CALL instruction, we need to move the instruction
119 // after the instruction in the delayed slot if the
120 // return value of this function is a aggregate value.
121 aggregateInsn.raw = owner->get_instruction(addr+12);
122 if (isCallInsn(delaySlotInsn)) {
123 if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
124 callAggregate = true;
125 size += 1*sizeof(instruction);
130 // The following are easier.
131 } else if (ipType == callSite) {
132 delaySlotInsn.raw = owner->get_instruction(addr+4);
133 size += 2*sizeof(instruction);
135 aggregateInsn.raw = owner->get_instruction(addr+8);
136 if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
137 callAggregate = true;
138 size += 1*sizeof(instruction);
141 delaySlotInsn.raw = owner->get_instruction(addr+4);
142 size += 2*sizeof(instruction);
146 // When the function is a leaf function
149 // For the leaf procedure, there are no function calls in
150 // this procdure. So we don't need to consider the
151 // aggregate instuction.
152 if (ipType == functionEntry) {
154 otherInstruction.raw = owner->get_instruction(addr+4);
155 delaySlotInsn.raw = owner->get_instruction(addr+8);
156 size += 2*sizeof(instruction);
158 if (IS_DELAYED_INST(delaySlotInsn)) {
160 isDelayedInsn.raw = owner->get_instruction(addr+12);
161 size += 2*sizeof(instruction);
164 } else if (ipType == functionExit) {
168 if (owner->isValidAddress(addr-4)) {
170 iplus1.raw = owner->get_instruction(addr-4);
171 if (IS_DELAYED_INST(iplus1) && !delayOK) {
174 size += 1*sizeof(instruction);
175 if(isCondBranch(iplus1)){
176 instruction previous_inst;
177 previous_inst.raw = owner->get_instruction(addr-4);
178 firstIsConditional = true;
179 addr -= sizeof(instruction);
180 size += 1*sizeof(instruction);
185 originalInstruction.raw = owner->get_instruction(addr);
186 otherInstruction.raw = owner->get_instruction(addr+4);
187 delaySlotInsn.raw = owner->get_instruction(addr+8);
188 size += 3*sizeof(instruction);
191 inDelaySlotInsn.raw = owner->get_instruction(addr+12);
192 if(firstIsConditional) {
193 extraInsn.raw = owner->get_instruction(addr+16);
196 } else if(ipType == otherPoint) {
197 delaySlotInsn.raw = owner->get_instruction(addr+4);
198 size += 2*sizeof(instruction);
200 assert(ipType == callSite);
201 // Usually, a function without a stack frame won't have any call sites
202 //cerr << "inst-sparc-solaris.C WARNING: found a leaf fn (no stack frame)"
203 // << "which makes a function call : " << func->prettyName()
204 // << " at address " << adr << endl;
206 // Actually - that is incorrect. It confuses a leaf function
207 // (one without a stack frame of its own) with a function which
208 // does not make any calls). It is possible for a function without
209 // a stack frae to make calls in the case of e.g. tail-call
210 // optimization (in this case, the function could end with
211 // e.g. jmp, nop)....
212 delaySlotInsn.raw = owner->get_instruction(addr+4);
213 size += 2*sizeof(instruction);
215 aggregateInsn.raw = owner->get_instruction(addr+8);
216 if (!IS_VALID_INSN(aggregateInsn) && aggregateInsn.raw != 0) {
217 callAggregate = true;
218 size += 1*sizeof(instruction);
223 // return the address in the code segment after this instruction
224 // sequence. (there's a -1 here because one will be added up later in
225 // the function findInstPoints)
226 adr = addr + (size - 1*sizeof(instruction));
229 /****************************************************************************/
230 /****************************************************************************/
231 /****************************************************************************/
233 // return the instruction after originalInstruction....
234 const instruction instPoint::insnAfterPoint() const {
235 if (this->hasNoStackFrame()) {
238 return otherInstruction;
241 return delaySlotInsn;
244 return otherInstruction;
252 return delaySlotInsn;
255 return delaySlotInsn;
258 return delaySlotInsn;
264 // should never be reached....
266 // prevent warning about lack of return value....
267 return delaySlotInsn;
270 /****************************************************************************/
271 /****************************************************************************/
272 /****************************************************************************/
274 void AstNode::sysFlag(instPoint *location)
276 if (location -> ipType == functionEntry) {
277 astFlag = (location -> isLongJump)? false:true;
278 } else if (location -> ipType == functionExit) {
279 astFlag = location -> hasNoStackFrame(); // formerly "isLeaf()"
284 loperand->sysFlag(location);
286 roperand->sysFlag(location);
288 for (unsigned u = 0; u < operands.size(); u++) {
289 operands[u]->sysFlag(location);
293 /****************************************************************************/
294 /****************************************************************************/
295 /****************************************************************************/
297 // Determine if the called function is a "library" function or a "user" function
298 // This cannot be done until all of the functions have been seen, verified, and
301 void pd_Function::checkCallPoints() {
305 //cerr << "pd_Function:: checkCallPoints called, *this = " << *this;
307 vector<instPoint*> non_lib;
309 for (unsigned i=0; i<calls.size(); ++i) {
310 /* check to see where we are calling */
314 if (isInsnType(p->originalInstruction, CALLmask, CALLmatch)) {
315 //cerr << " isIsinType TRUE" << endl;
317 loc_addr = p->addr + (p->originalInstruction.call.disp30 << 2);
318 pd_Function *pdf = (file_->exec())->findFunction(loc_addr);
321 non_lib.push_back(p);
322 //cerr << " pdf (called func?) non-NULL = " << *pdf;
324 //cerr << " pdf (called func) NULL" << endl;
325 // if this is a call outside the fuction, keep it
326 if((loc_addr < getAddress(0))||(loc_addr > (getAddress(0)+size()))){
327 //cerr << " apparent call outside function, adding p to non_lib"
329 p->callIndirect = true;
331 non_lib.push_back(p);
334 //cerr << " apparent call inside function, deleting p" << endl;
339 //cerr << " isIsinType FALSE, assuming call to unnamed user function" << endl;
340 // Indirect call -- be conservative, assume it is a call to
341 // an unnamed user function
342 assert(!p->callee); assert(p->callIndirect);
344 non_lib.push_back(p);
350 /****************************************************************************/
351 /****************************************************************************/
352 /****************************************************************************/
354 // TODO we cannot find the called function by address at this point in time
355 // because the called function may not have been seen.
356 // reloc_info is 0 if the function is not currently being relocated
357 // Note that this may be called even when instr is NOT a CAlL inst, e.g.
358 // in the case of a jmp instruction where paradynd/dyninstAPI knows
359 // (really guesses) that control flow will return to the point following
361 // to mark the jmp as a call to preserve its logical structure of
362 // synchronous call + return (which is violated by tail-call optimization -
363 // including a function (w/o stack frame) which ends w/ jmp, nop....
364 Address pd_Function::newCallPoint(Address &adr, const instruction instr,
365 const image *owner, bool &err,
366 unsigned &callId, Address &oldAddr,
367 relocatedFuncInfo *reloc_info,
368 const instPoint *&location)
373 #ifdef DEBUG_CALL_POINTS
374 cerr << "pd_Function::newCallPoint called " << endl;
375 cerr << " this " << *this << endl;
376 cerr << " adr = " << adr << endl;
377 cerr << " isTrap = " << isTrap << endl;
378 cerr << " reloc_info = " << reloc_info << endl;
384 point = new instPoint(this, instr, owner, adr, false, callSite, oldAddr);
386 point = new instPoint(this, instr, owner, adr, false, callSite);
388 //point = new instPoint(this, instr, owner, adr, false, callSite);
390 if (!isInsnType(instr, CALLmask, CALLmatch)) {
391 point->callIndirect = true;
392 point->callee = NULL;
394 point->callIndirect = false;
399 calls.push_back(point);
400 calls[callId] -> instId = callId; callId++;
402 // calls to a location within the function are not
403 // kept in the calls vector
405 #ifdef DEBUG_CALL_POINTS
406 cerr << " *this = " << *this;
407 cerr << " callId = " << callId;
408 cerr << " (u_int)callId = " << (u_int)callId;
409 cerr << " calls.size() = " << calls.size() << endl;
410 cerr << " calls = " << endl;
411 for(unsigned un=0;un<calls.size();un++) {
412 cerr << calls[un] << " , ";
417 point->relocated_ = true;
420 // cannot simply assert that this is true, because of the case
421 // where (as a hack), the call site in a tail-call optimization
422 // might not have been previously seen....
423 assert((callId) < calls.size());
425 if(location && (calls[callId] == location)) {
426 assert(calls[callId]->instId == location->instId);
430 point->instId = callId++;
431 reloc_info->addFuncCall(point);
435 calls.push_back(point);
438 point->relocated_ = true;
439 reloc_info->addFuncCall(point);
446 /****************************************************************************/
447 /****************************************************************************/
448 /****************************************************************************/
451 * Given an instruction, relocate it to a new address, patching up
452 * any relative addressing that is present.
455 void relocateInstruction(instruction*& insn,
456 Address origAddr, Address& targetAddr, process *proc)
460 // If the instruction is a CALL instruction, calculate the new
462 if (isInsnType(*insn, CALLmask, CALLmatch)) {
464 newOffset = origAddr - targetAddr + (insn->call.disp30 << 2);
465 insn->call.disp30 = newOffset >> 2;
467 } else if (isInsnType(*insn, BRNCHmask, BRNCHmatch)||
468 isInsnType(*insn, FBRNCHmask, FBRNCHmatch)) {
470 // If the instruction is a Branch instruction, calculate the
471 // new offset. If the new offset is out of reach after the
472 // instruction is moved to the base Trampoline, we would do
474 // b address ...... address: save
477 newOffset = origAddr - targetAddr + (insn->branch.disp22 << 2);
479 // if the branch is too far, then allocate more space in inferior
480 // heap for a call instruction to branch target. The base tramp
481 // will branch to this new inferior heap code, which will call the
482 // target of the branch
483 if (!offsetWithinRangeOfBranchInsn(newOffset)) {
484 // if (ABS(newOffset) > getMaxBranch1Insn()) {
485 int ret = inferiorMalloc(proc,3*sizeof(instruction), textHeap,targetAddr);
487 u_int old_offset = insn->branch.disp22 << 2;
488 insn->branch.disp22 = (ret - targetAddr)>>2;
489 instruction insnPlus[3];
490 genImmInsn(insnPlus, SAVEop3, REG_SPTR, -112, REG_SPTR);
491 generateCallInsn(insnPlus+1, ret+sizeof(instruction),
492 origAddr+old_offset);
493 genSimpleInsn(insnPlus+2, RESTOREop3, 0, 0, 0);
494 proc->writeDataSpace((caddr_t)ret, sizeof(insnPlus),
497 insn->branch.disp22 = newOffset >> 2;
499 } else if (isInsnType(*insn, TRAPmask, TRAPmatch)) {
500 // There should be no probelm for moving trap instruction
501 // logLine("attempt to relocate trap\n");
503 /* The rest of the instructions should be fine as is */
506 /****************************************************************************/
507 /****************************************************************************/
508 /****************************************************************************/
510 void generate_base_tramp_recursive_guard_code( process & p,
513 NonRecursiveTrampTemplate & templ )
515 /* prepare guard flag memory, if needed */
516 Address guard_flag_address = p.getTrampGuardFlagAddr();
517 if( guard_flag_address == 0 )
519 int initial_value = 1;
520 guard_flag_address = inferiorMalloc( & p, sizeof( int ), dataHeap );
521 /* initialize the new value */
522 p.writeDataSpace( ( void * )guard_flag_address, sizeof( int ), & initial_value );
524 p.setTrampGuardFlagAddr( guard_flag_address );
527 instruction * curr_instr;
530 /* fill the 'guard on' pre-instruction instrumentation */
531 curr_instr = code + templ.guardOnPre_beginOffset / sizeof( instruction );
532 curr_addr = base_addr + templ.guardOnPre_beginOffset;
533 generateSetHi( curr_instr, guard_flag_address, REG_L(0) );
534 curr_instr++; curr_addr += sizeof( instruction );
535 genSimpleInsn( curr_instr, ADDop3, REG_G(0), REG_G(0), REG_L(1) );
536 curr_instr++; curr_addr += sizeof( instruction );
537 generateLoad( curr_instr, REG_L(0), LOW10( guard_flag_address ), REG_L(2) );
538 curr_instr++; curr_addr += sizeof( instruction );
539 generateStore( curr_instr, REG_L(1), REG_L(0), LOW10( guard_flag_address ) );
540 curr_instr++; curr_addr += sizeof( instruction );
541 genSimpleInsn( curr_instr, SUBop3cc, REG_L(2), REG_G(0), REG_G(0) );
542 curr_instr++; curr_addr += sizeof( instruction );
543 int branch_offset_in_bytes =
544 ( base_addr + templ.guardOffPre_endOffset )
548 genBranch( curr_instr,
549 branch_offset_in_bytes,
552 curr_instr++; curr_addr += sizeof( instruction );
553 generateNOOP ( curr_instr );
555 /* fill the 'guard off' pre-instruction instrumentation */
556 curr_instr = code + templ.guardOffPre_beginOffset / sizeof( instruction );
557 curr_addr = base_addr + templ.guardOffPre_beginOffset;
558 generateSetHi( curr_instr, guard_flag_address, REG_L(0) );
559 curr_instr++; curr_addr += sizeof( instruction );
560 genImmInsn( curr_instr, ADDop3, REG_G(0), 1, REG_L(1) );
561 curr_instr++; curr_addr += sizeof( instruction );
562 generateStore( curr_instr, REG_L(1), REG_L(0), LOW10( guard_flag_address ) );
564 /* fill the 'guard on' post-instruction instrumentation */
565 curr_instr = code + templ.guardOnPost_beginOffset / sizeof( instruction );
566 curr_addr = base_addr + templ.guardOnPost_beginOffset;
567 generateSetHi( curr_instr, guard_flag_address, REG_L(0) );
568 curr_instr++; curr_addr += sizeof( instruction );
569 genSimpleInsn( curr_instr, ADDop3, REG_G(0), REG_G(0), REG_L(1) );
570 curr_instr++; curr_addr += sizeof( instruction );
571 generateLoad( curr_instr, REG_L(0), LOW10( guard_flag_address ), REG_L(2) );
572 curr_instr++; curr_addr += sizeof( instruction );
573 generateStore( curr_instr, REG_L(1), REG_L(0), LOW10( guard_flag_address ) );
574 curr_instr++; curr_addr += sizeof( instruction );
575 genSimpleInsn( curr_instr, SUBop3cc, REG_L(2), REG_G(0), REG_G(0) );
576 curr_instr++; curr_addr += sizeof( instruction );
577 branch_offset_in_bytes =
578 ( base_addr + templ.guardOffPost_endOffset )
582 genBranch( curr_instr,
583 branch_offset_in_bytes,
586 curr_instr++; curr_addr += sizeof( instruction );
587 generateNOOP ( curr_instr );
589 /* fill the 'guard off' post-instruction instrumentation */
590 curr_instr = code + templ.guardOffPost_beginOffset / sizeof( instruction );
591 curr_addr = base_addr + templ.guardOffPost_beginOffset;
592 generateSetHi( curr_instr, guard_flag_address, REG_L(0) );
593 curr_instr++; curr_addr += sizeof( instruction );
594 genImmInsn( curr_instr, ADDop3, REG_G(0), 1, REG_L(1) );
595 curr_instr++; curr_addr += sizeof( instruction );
596 generateStore( curr_instr, REG_L(1), REG_L(0), LOW10( guard_flag_address ) );
599 /****************************************************************************/
600 /****************************************************************************/
601 /****************************************************************************/
604 * Install a base tramp -- fill calls with nop's for now.
606 * This one install the base tramp for the regular functions.
609 trampTemplate * installBaseTramp( instPoint * & location,
611 bool trampRecursiveDesired = false )
613 trampTemplate* current_template = &nonRecursiveBaseTemplate;
615 if(location->ipType == otherPoint)
616 current_template = &nonRecursiveConservativeBaseTemplate;
618 if( trampRecursiveDesired )
620 current_template = &baseTemplate;
622 if(location->ipType == otherPoint)
623 current_template = &conservativeBaseTemplate;
627 proc->getBaseAddress( location->image_ptr, ipAddr );
628 ipAddr += location->addr;
630 Address baseAddr = inferiorMalloc( proc, current_template->size, textHeap, ipAddr );
633 /* very conservative installation as o7 can be live at
634 this arbitrary inst point */
635 if((location->ipType == otherPoint) &&
636 (in1BranchInsnRange(ipAddr, baseAddr) == false))
638 vector<addrVecType> pointsToCheck;
639 inferiorFree(proc,baseAddr,pointsToCheck);
643 instruction * code = new instruction[ current_template->size ];
646 memcpy( ( char * )code,
647 ( char * )current_template->trampTemp,
648 current_template->size );
652 for (temp = code, currAddr = baseAddr;
653 (currAddr - baseAddr) < (unsigned) current_template->size;
654 temp++, currAddr += sizeof(instruction)) {
656 if (temp->raw == EMULATE_INSN) {
658 // Load the value of link register from stack
659 // If no stack frame, genereate a RESTORE instruction
660 // since there's an instruction SAVE generated and put in the
662 if (location -> hasNoStackFrame()) {
664 Address baseAddress = 0;
665 proc->getBaseAddress(location->image_ptr,baseAddress);
666 baseAddress += location -> addr;
668 if (in1BranchInsnRange(baseAddress, baseAddr) == false) {
669 //cerr << "This happen very rarely, I suppose "<< endl;
670 //cerr << "Lets see if this is going to be executed..." << endl;
671 location -> isLongJump = true;
672 genImmInsn(temp, RESTOREop3, 0, 0, 0);
677 currAddr += sizeof(instruction);
679 // Same for the leaf and nonleaf functions.
680 // First, relocate the "FIRST instruction" in the sequence;
681 Address fromAddr = location->addr;
683 if (!(location -> hasNoStackFrame())) {
684 if (location -> ipType == functionEntry) {
685 *temp = location -> saveInsn;
687 currAddr += sizeof(instruction);
690 *temp = location->originalInstruction;
692 // compute the real from address if this instrumentation
693 // point is from a shared object image
694 Address baseAddress = 0;
695 if(proc->getBaseAddress(location->image_ptr,baseAddress)){
696 fromAddr += baseAddress;
699 // If the instruction is a call instruction to a location somewhere
700 // within the function, then the 07 regester must be saved and
701 // resored around the relocated call from the base tramp...the call
702 // instruction changes the value of 07 to be the PC value, and if
703 // we move the call instruction to the base tramp, its value will
704 // be incorrect when we use it in the function. We generate the
705 // following base tramp code:
706 // original delay slot instruction
708 // original call instruction
710 // This case should only occur for function entry points in
711 // functions from shared objects, and there should be no append
712 // trampolene code because the relocated call instruction will
713 // not return to the base tramp
714 if (isInsnType(*temp, CALLmask, CALLmatch)) {
715 Address offset = fromAddr + (temp->call.disp30 << 2);
716 if ((offset > (location->func->getAddress(0)+ baseAddress)) &&
717 (offset < ((location->func->getAddress(0)+ baseAddress)+
718 location->func->size()))) {
719 // offset > adr; "=" means recursive function which is allowed
720 // offset < adr + size; "=" does not apply to this case
722 // TODO: this assumes that the delay slot instruction is not
723 // a call instruction....is this okay?
725 // assume this situation only happens at function entry point
726 // for the shared library routine. And it is definately nees
728 assert(location -> ipType == functionEntry);
729 location -> isLongJump = true;
731 // In this situation, save instruction is discarded
733 assert(location->hasNoStackFrame() == false);
735 currAddr -= sizeof(instruction);
737 *temp = location->delaySlotInsn;
739 currAddr += sizeof(instruction);
740 genImmInsn(temp, SAVEop3, REG_SPTR, -112, REG_SPTR);
742 currAddr += sizeof(instruction);
743 *temp = location->originalInstruction;
744 relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
746 fromAddr += sizeof(instruction);
747 currAddr += sizeof(instruction);
748 genImmInsn(temp, RESTOREop3, 0, 0, 0);
753 relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
755 // Again, for leaf function, one more is needed to move for one
757 if (location->hasNoStackFrame()) {
758 // check to see if the otherInstruction is a call instruction
759 // to itself, if so then generate the following
760 // before after basetramp
761 // ------ ----- ---------
762 // mov originalInsn mov sethi
763 // call otherInsn call save
764 // sethi delaySlot nop call
766 // the idea is to not really relocate the originalInsn, and
767 // relocate only the call otherInsn and delaySlot instrn
768 // then do a save and restore around the relocated call to
769 // save the value of the o7 register from the call to base tramp
770 if (isInsnType(location->otherInstruction,CALLmask,CALLmatch)) {
771 *temp = location->otherInstruction;
772 fromAddr += sizeof(instruction);
773 Address offset = fromAddr + (temp->call.disp30 << 2);
774 if ((offset > (location->func->getAddress(0)+baseAddress)) &&
775 (offset < ((location->func->getAddress(0)+ baseAddress)+
776 location->func->size()))) {
777 location -> isLongJump = true;
778 // need to replace retore instr with nop
781 // relocate delaySlot instr
783 *temp = location->delaySlotInsn;
784 fromAddr += sizeof(instruction);
785 relocateInstruction(temp,fromAddr,currAddr,
788 currAddr += sizeof(instruction);
789 genImmInsn(temp, SAVEop3, REG_SPTR, -112, REG_SPTR);
791 // relocate the call instruction
793 currAddr += sizeof(instruction);
794 fromAddr -= sizeof(instruction);
795 *temp = location->otherInstruction;
796 relocateInstruction(temp,fromAddr,currAddr,
799 fromAddr += sizeof(instruction);
800 currAddr += sizeof(instruction);
801 genImmInsn(temp, RESTOREop3, 0, 0, 0);
806 // otherwise relocate the other instruction
807 fromAddr += sizeof(instruction);
808 currAddr += sizeof(instruction);
809 *++temp = location->otherInstruction;
810 relocateInstruction(temp, fromAddr, currAddr,
814 // Second, relocate the "NEXT instruction";
815 fromAddr += sizeof(instruction);
816 currAddr += sizeof(instruction);
817 *++temp = location->delaySlotInsn;
819 // if the NEXT instruction is a call instruction to a location
820 // within the function, then the 07 regester must be saved and
821 // resored around the relocated call from the base tramp...the call
822 // instruction changes the value of 07 to be the PC value, and if
823 // we move the call instruction to the base tramp, its value will
824 // be incorrect when we use it in the function. We generate:
826 // orignial relocated to base tramp
827 // -------- -----------------------
828 // save nop // SAVE added above, replace w/nop
829 // original insn original instruction // already relocated
830 // delaySlotInsn isDelayedInsn
831 // isDelayedInsn save
832 // delaySlotInsn (call with offset - 4)
834 // In the function, the call to the base tramp will have an
835 // additional add instruction to adjust the 07 register
836 // orignial relocated to base tramp
837 // -------- -----------------------
843 if (isInsnType(*temp, CALLmask, CALLmatch)) {
844 Address offset = fromAddr + (temp->call.disp30 << 2);
845 if ((offset > (location->func->getAddress(0)+ baseAddress)) &&
846 (offset < ((location->func->getAddress(0)+ baseAddress)+
847 location->func->size()))) {
854 location->isLongJump = true;
855 // assert(location->hasNoStackFrame() == false);
856 // assume that this is not a delayed instr.
857 *temp = location->isDelayedInsn;
859 currAddr += sizeof(instruction);
860 genImmInsn(temp, SAVEop3, REG_SPTR, -112, REG_SPTR);
862 currAddr += sizeof(instruction);
863 *temp = location->delaySlotInsn;
864 Address new_call_addr = fromAddr - sizeof(instruction);
865 relocateInstruction(temp,new_call_addr,currAddr,proc);
867 fromAddr += sizeof(instruction);
868 currAddr += sizeof(instruction);
869 genImmInsn(temp, RESTOREop3, 0, 0, 0);
874 // otherwise relocate the NEXT instruction
875 relocateInstruction(temp, fromAddr, currAddr,
878 // Third, if the "NEXT instruction" is a DCTI,
879 if (location->isDelayed) {
880 fromAddr += sizeof(instruction);
881 currAddr += sizeof(instruction);
882 *++temp = location->isDelayedInsn;
883 relocateInstruction(temp, fromAddr, currAddr,
886 // Then, possibly, there's an callAggregate instruction
888 if (location->callAggregate) {
889 currAddr += sizeof(instruction);
890 *++temp = location->aggregateInsn;
895 // If the "FIRST instruction" is a DCTI, then our so called
896 // "NEXT instruction" is in the delayed Slot and this might
897 // happen. (actullay, it happened)
898 if (location->callAggregate) {
899 currAddr += sizeof(instruction);
900 *++temp = location->aggregateInsn;
904 // For the leaf function, if there's an inDelaySlot instruction,
905 // move this one to the base Tramp.(i.e. at the function exit,
906 // if the first instruction is in the delayed slot the previous
907 // instruction, we have to move that one too, so we count from
908 // that one and the last one is this sequence is called inDelaySlot
910 // Well, after all these, another SAVE instruction is generated
911 // so we are prepared to handle the returning to our application's
913 if (location->hasNoStackFrame()) {
914 if (location->inDelaySlot) {
915 fromAddr += sizeof(instruction);
916 currAddr += sizeof(instruction);
917 *++temp = location->inDelaySlotInsn;
918 relocateInstruction(temp,fromAddr,currAddr,(process *)proc);
919 if(location->firstIsConditional){
920 fromAddr += sizeof(instruction);
921 currAddr += sizeof(instruction);
922 *++temp = location->extraInsn;
923 relocateInstruction(temp, fromAddr, currAddr, proc);
927 genImmInsn(temp+1, SAVEop3, REG_SPTR, -112, REG_SPTR);
930 } else if (temp->raw == RETURN_INSN) {
931 // compute the real from address if this instrumentation
932 // point is from a shared object image
933 Address baseAddress = 0;
934 if(proc->getBaseAddress(location->image_ptr,baseAddress)){
936 // Back to the code segement of the application.
937 // If the location is in the leaf procedure, generate an RESTORE
938 // instruction right after the CALL instruction to restore all
939 // the values in the registers.
940 if (location -> hasNoStackFrame()) {
941 generateCallInsn(temp, currAddr,
942 (baseAddress + location->addr)+location->size);
943 genImmInsn(temp+1, RESTOREop3, 0, 0, 0);
944 } else if(location->ipType == otherPoint){
945 /** to save the value of live o7 register we save and call*/
946 genImmInsn(temp, SAVEop3, REG_SPTR, -120, REG_SPTR);
947 generateCallInsn(temp+1, currAddr+sizeof(instruction),
948 (baseAddress + location->addr)+location->size);
949 genImmInsn(temp+2, RESTOREop3, 0, 0, 0);
951 generateCallInsn(temp, currAddr,
952 (baseAddress + location->addr)+location->size);
954 } else if (temp->raw == SKIP_PRE_INSN) {
956 offset = baseAddr+current_template->updateCostOffset-currAddr;
957 generateBranchInsn(temp,offset);
958 } else if (temp->raw == SKIP_POST_INSN) {
961 offset = baseAddr+current_template->returnInsOffset-currAddr;
962 generateBranchInsn(temp,offset);
964 } else if (temp->raw == UPDATE_COST_INSN) {
965 current_template->costAddr = currAddr;
967 } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
968 (temp->raw == GLOBAL_PRE_BRANCH) ||
969 (temp->raw == LOCAL_POST_BRANCH) ||
970 (temp->raw == GLOBAL_POST_BRANCH)) {
971 #if defined(MT_THREAD)
972 if ((temp->raw == LOCAL_PRE_BRANCH) ||
973 (temp->raw == LOCAL_POST_BRANCH))
975 temp -= NUM_INSN_MT_PREAMBLE;
977 generateMTpreamble((char *)temp, numIns, proc);
978 temp += NUM_INSN_MT_PREAMBLE;
981 /* fill with no-op */
984 else if( temp->raw == RECURSIVE_GUARD_ON_PRE_INSN )
986 generateNOOP( temp );
988 else if( temp->raw == RECURSIVE_GUARD_OFF_PRE_INSN )
990 generateNOOP( temp );
992 else if( temp->raw == RECURSIVE_GUARD_ON_POST_INSN )
994 generateNOOP( temp );
996 else if( temp->raw == RECURSIVE_GUARD_OFF_POST_INSN )
998 generateNOOP( temp );
1002 if( ! trampRecursiveDesired )
1004 generate_base_tramp_recursive_guard_code( * proc,
1007 ( NonRecursiveTrampTemplate & )*current_template );
1011 proc->writeDataSpace( ( caddr_t )baseAddr,
1012 current_template->size,
1016 trampTemplate * baseInst;
1017 if( trampRecursiveDesired )
1019 baseInst = new trampTemplate;
1023 baseInst = new NonRecursiveTrampTemplate;
1025 * baseInst = *current_template;
1026 baseInst->baseAddr = baseAddr;
1031 /****************************************************************************/
1032 /****************************************************************************/
1033 /****************************************************************************/
1036 * Install the base Tramp for the function relocated.
1037 * (it means the base tramp that don't need to bother with long jump and
1038 * is the one we used before for all the functions(since there's no
1042 trampTemplate *installBaseTrampSpecial(const instPoint *&location,
1043 process *proc, bool &deferred,
1044 bool trampRecursiveDesired = false)
1046 trampTemplate* current_template = &nonRecursiveBaseTemplate;
1048 if(location->ipType == otherPoint)
1049 current_template = &nonRecursiveConservativeBaseTemplate;
1051 if( trampRecursiveDesired )
1053 current_template = &baseTemplate;
1055 if(location->ipType == otherPoint)
1056 current_template = &conservativeBaseTemplate;
1065 if(!(location->func->isInstalled(proc))) {
1066 relocated = location->func->relocateFunction(proc, const_cast<instPoint *>(location), deferred);
1068 // Unable to relocate function
1069 if (relocated == false) {
1073 else if(!location->relocated_){
1074 // need to find new instPoint for location...it has the pre-relocated
1075 // address of the instPoint
1076 location->func->modifyInstPoint(location,proc);
1079 code = new instruction[current_template->size];
1080 memcpy((char *) code, (char*) current_template->trampTemp, current_template->size);
1082 Address baseAddr = inferiorMalloc(proc, current_template->size, textHeap, location->addr);
1085 for (temp = code, currAddr = baseAddr;
1086 (currAddr - baseAddr) < (unsigned) current_template->size;
1087 temp++, currAddr += sizeof(instruction)) {
1089 if (temp->raw == EMULATE_INSN) {
1090 if (location->isBranchOut) {
1091 // the original instruction is a branch that goes out of a
1092 // function. We don't relocate the original instruction. We
1093 // only get to the tramp if the branch is taken, so we generate
1094 // an unconditional branch to the target of the original
1096 assert(location->branchTarget);
1097 int disp = location->branchTarget - currAddr;
1099 if (in1BranchInsnRange(currAddr,location->branchTarget)) {
1100 generateBranchInsn(temp, disp);
1101 disp = temp->branch.disp22;
1103 generateCallInsn(temp, currAddr, disp);
1108 *temp = location->originalInstruction;
1109 Address fromAddress = location->addr;
1110 relocateInstruction(temp, fromAddress, currAddr, proc);
1111 if (location->isDelayed) {
1112 /* copy delay slot instruction into tramp instance */
1113 currAddr += sizeof(instruction);
1114 *++temp = location->delaySlotInsn;
1116 if (location->callAggregate) {
1117 /* copy invalid insn with aggregate size in it */
1118 currAddr += sizeof(instruction);
1119 *++temp = location->aggregateInsn;
1122 } else if (temp->raw == RETURN_INSN) {
1123 generateBranchInsn(temp,
1124 (location->addr+ sizeof(instruction) - currAddr));
1125 if (location->isDelayed) {
1126 /* skip the delay slot instruction */
1127 temp->branch.disp22 += 1;
1129 if (location->callAggregate) {
1130 /* skip the aggregate size slot */
1131 temp->branch.disp22 += 1;
1133 } else if (temp->raw == SKIP_PRE_INSN) {
1135 offset = baseAddr+current_template->updateCostOffset-currAddr;
1136 generateBranchInsn(temp,offset);
1137 } else if (temp->raw == SKIP_POST_INSN) {
1139 offset = baseAddr+current_template->returnInsOffset-currAddr;
1140 generateBranchInsn(temp,offset);
1141 } else if (temp->raw == UPDATE_COST_INSN) {
1143 current_template->costAddr = currAddr;
1145 } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
1146 (temp->raw == GLOBAL_PRE_BRANCH) ||
1147 (temp->raw == LOCAL_POST_BRANCH) ||
1148 (temp->raw == GLOBAL_POST_BRANCH)) {
1149 #if defined(MT_THREAD)
1150 if ((temp->raw == LOCAL_PRE_BRANCH) ||
1151 (temp->raw == LOCAL_POST_BRANCH))
1153 temp -= NUM_INSN_MT_PREAMBLE;
1155 generateMTpreamble((char *)temp, numIns, proc);
1156 temp += NUM_INSN_MT_PREAMBLE;
1159 /* fill with no-op */
1162 else if( temp->raw == RECURSIVE_GUARD_ON_PRE_INSN )
1164 generateNOOP( temp );
1166 else if( temp->raw == RECURSIVE_GUARD_OFF_PRE_INSN )
1168 generateNOOP( temp );
1170 else if( temp->raw == RECURSIVE_GUARD_ON_POST_INSN )
1172 generateNOOP( temp );
1174 else if( temp->raw == RECURSIVE_GUARD_OFF_POST_INSN )
1176 generateNOOP( temp );
1180 if( ! trampRecursiveDesired )
1182 generate_base_tramp_recursive_guard_code( * proc,
1185 ( NonRecursiveTrampTemplate & )*current_template );
1189 proc->writeDataSpace((caddr_t)baseAddr, current_template->size,(caddr_t) code);
1193 trampTemplate * baseInst;
1194 if( trampRecursiveDesired )
1196 baseInst = new trampTemplate;
1200 baseInst = new NonRecursiveTrampTemplate;
1202 * baseInst = *current_template;
1203 baseInst->baseAddr = baseAddr;
1208 /****************************************************************************/
1209 /****************************************************************************/
1210 /****************************************************************************/
1213 * Allocate the space for the base Trampoline, and generate the instruction
1214 * we need for modifying the code segment.
1216 * 'retInstance' tells you how to modify the code to jump to the base tramp
1219 trampTemplate *findAndInstallBaseTramp(process *proc,
1220 instPoint *&location,
1221 returnInstance *&retInstance,
1222 bool trampRecursionDesired,
1226 Address adr = location->addr;
1229 const instPoint *&cLocation = const_cast<const instPoint *&>(location);
1232 if (proc->baseMap.find(cLocation, ret)) // writes to ret if found
1233 // This base tramp already exists; nothing to do.
1236 if (location->func->isTrapFunc()) {
1237 // get the base Address of this function if it is a
1239 Address baseAddress = 0;
1240 if(!proc->getBaseAddress(location->image_ptr,baseAddress)){
1241 // TODO: what should be done here?
1242 logLine("Error:findAndInstallBaseTramp call getBaseAddress\n");
1244 // Install Base Tramp for the functions which are
1245 // relocated to the heap.
1246 // vector<instruction> extra_instrs; // not any more
1248 ret = installBaseTrampSpecial(cLocation, proc, deferred,
1249 trampRecursionDesired);
1250 if(!ret) return NULL;
1252 // add a branch from relocated function to the base tramp
1253 // if function was just relocated then location has old address
1254 // otherwise location will have address in already relocated func
1255 if (!location->func->isInstalled(proc)){
1256 if (location->isBranchOut){
1257 changeBranch(proc, location->addr,
1258 (int) ret->baseAddr, location->originalInstruction);
1260 generateBranch(proc, location->addr, (int)ret->baseAddr);
1263 else { // location's address is correct...it is in the heap
1264 if (location->isBranchOut){
1265 changeBranch(proc, location->addr,
1266 (int) ret->baseAddr, location->originalInstruction);
1268 generateBranch(proc, location->addr, (int)ret->baseAddr);
1272 // If for this process, a call to the relocated function has not
1273 // yet be installed in its original location, then genterate either
1276 // SAVE; CALL; RESTORE.
1277 // so that it would jump to the start of the relocated function
1278 // which is in heap.
1279 if (!location->func->isInstalled(proc)){
1280 location->func->setInstalled(proc);
1282 Address adr = location-> func -> getAddress(0);
1284 unsigned branchSize ;
1285 if (in1BranchInsnRange(adr+baseAddress, location->func->getAddress(proc))) {
1287 insn = new instruction[branchSize];
1288 generateBranchInsn(insn,(int)(location->func->getAddress(proc)-(adr+baseAddress)));
1291 insn = new instruction[branchSize];
1292 genImmInsn(insn, SAVEop3, REG_SPTR, -112, REG_SPTR);
1293 generateCallInsn(insn+1, adr+baseAddress+4, location->func->getAddress(proc));
1294 genSimpleInsn(insn+2, RESTOREop3, 0, 0, 0);
1297 // set unknown the number of instructions to be overwritten
1298 retInstance = new returnInstance(0/*branchSize*/, (instructUnion *)insn,
1299 branchSize*sizeof(instruction),
1301 location->func->size());
1302 assert(retInstance);
1304 //cerr << "created a new return instance (relocated fn)!" << endl;
1307 // It's not a trap-function; it's a "normal" function
1308 // compute the real from address if this instrumentation
1309 // point is from a shared object image
1310 Address baseAddress = 0;
1311 if (proc->getBaseAddress(location->image_ptr,baseAddress)){
1315 ret = installBaseTramp(location, proc, trampRecursionDesired);
1316 if(!ret) return NULL;
1317 // check to see if this is an entry point and if the delay
1318 // slot instruction is a call insn, if so, then if the
1319 // call is to a location within the function, then we need to
1320 // add an extra instruction after the restore to correctly
1321 // set the o7 register
1322 bool need_to_add = false;
1323 if (location->ipType==functionEntry &&
1324 isInsnType(location->delaySlotInsn,CALLmask,CALLmatch)) {
1325 Address call_offset = location->addr + 8 +
1326 (location->delaySlotInsn.call.disp30<<2);
1327 Address fun_addr = location->func->getAddress(0);
1328 u_int fun_size = location->func->size();
1329 if (call_offset>fun_addr && call_offset<(fun_addr+fun_size)) {
1330 assert(location->isLongJump);
1335 if (location->hasNoStackFrame()) {
1336 // if it is the leaf function, we need to generate
1337 // the following instruction sequence:
1340 if (location -> isLongJump == false) {
1341 instruction *insn = new instruction;
1342 generateBranchInsn(insn, (int)(ret->baseAddr-adr));
1343 retInstance = new returnInstance(1, (instructUnion *)insn,
1344 sizeof(instruction), adr,
1345 sizeof(instruction));
1346 } else if (need_to_add) {
1347 // generate original; call; add $o7 imm4
1348 instruction *insn = new instruction[2];
1349 generateCallInsn(insn, adr+4, (int) ret->baseAddr);
1350 genImmInsn(insn+1,ADDop3,REG_O(7),4,REG_O(7));
1351 retInstance = new returnInstance(2, (instructUnion *)insn,
1352 2*sizeof(instruction), adr+4,
1353 2*sizeof(instruction));
1355 bool already_done = false;
1356 // check to see if the otherInstruction is a call instruction
1357 // to itself, if so then generate the following
1358 // before after basetramp
1359 // ------ ----- ---------
1360 // mov originalInsn mov sethi
1361 // call otherInsn call save
1362 // sethi delaySlot nop call
1364 // only generate a call and nop...leave the originalInsn
1366 if (isInsnType(location->otherInstruction, CALLmask, CALLmatch)) {
1367 Address offset = location-> func -> getAddress(0)+4 +
1368 (location->otherInstruction.call.disp30 << 2);
1369 if ((offset > (location->func->getAddress(0))) &&
1370 (offset < ((location->func->getAddress(0))+
1371 location->func->size()))) {
1372 instruction *insn = new instruction[2];
1373 generateCallInsn(insn, adr+4, (int) ret->baseAddr);
1374 generateNOOP(insn+1);
1375 retInstance = new returnInstance(2, (instructUnion *)insn,
1376 2*sizeof(instruction), adr+4,
1377 2*sizeof(instruction));
1379 already_done = true;
1384 instruction *insn = new instruction[3];
1385 genImmInsn(insn, SAVEop3, REG_SPTR, -112, REG_SPTR);
1386 generateCallInsn(insn+1, adr+4, (int) ret->baseAddr);
1387 generateNOOP(insn+2);
1388 retInstance = new returnInstance(3, (instructUnion *)insn,
1389 3*sizeof(instruction), adr,
1390 3*sizeof(instruction));
1394 assert(retInstance);
1397 // Generate branch instruction from the application to the
1398 // base trampoline and no SAVE instruction is needed
1400 if (in1BranchInsnRange(adr, ret->baseAddr)) {
1401 // make sure that the isLongJump won't be true
1402 // which only is possible for shlib entry point
1403 //assert(location->isLongJump == false);
1404 if (location->isLongJump) {
1405 instruction *insn = new instruction[2];
1406 generateCallInsn(insn, adr, (int) ret->baseAddr);
1407 assert(location->ipType == functionEntry);
1408 generateNOOP(insn+1);
1409 retInstance = new returnInstance(2, (instructUnion *)insn,
1410 2*sizeof(instruction), adr,
1411 2*sizeof(instruction));
1412 assert(retInstance);
1414 instruction *insn = new instruction;
1415 if (location -> ipType == functionEntry) {
1416 generateBranchInsn(insn, (int)(ret->baseAddr-adr+sizeof(instruction)));
1417 retInstance = new returnInstance(1, (instructUnion *)insn,
1418 sizeof(instruction),
1419 adr - sizeof(instruction),
1420 sizeof(instruction));
1422 generateBranchInsn(insn,(int)(ret->baseAddr-adr));
1423 retInstance = new returnInstance(1, (instructUnion *)insn,
1424 sizeof(instruction),
1426 sizeof(instruction));
1429 } else if(need_to_add) {
1430 // the delay slot instruction is is a call to a location
1431 // within the same function, then need to generate 3 instrs
1433 // nop // delay slot (originally call insn)
1434 // add o7 imm4 // sets o7 register to correct value
1435 instruction *insn = new instruction[3];
1436 generateCallInsn(insn, adr, (int) ret->baseAddr);
1437 generateNOOP(insn+1);
1438 genImmInsn(insn+2,ADDop3,REG_O(7),4,REG_O(7));
1439 retInstance = new returnInstance(3, (instructUnion *)insn,
1440 3*sizeof(instruction), adr,
1441 3*sizeof(instruction));
1443 instruction *insn = new instruction[2];
1444 generateCallInsn(insn, adr, (int) ret->baseAddr);
1445 if (location -> ipType == functionEntry) {
1446 if (location -> isLongJump)
1447 generateNOOP(insn+1);
1449 genSimpleInsn(insn+1, RESTOREop3, 0, 0, 0);
1451 generateNOOP(insn+1);
1453 retInstance = new returnInstance(2, (instructUnion *)insn,
1454 2*sizeof(instruction), adr,
1455 2*sizeof(instruction));
1456 assert(retInstance);
1461 proc->baseMap[(const instPoint *)location] = ret;
1464 // remember, ret was the result of either installBaseTramp() or
1465 // installBaseTrampSpecial()
1468 /****************************************************************************/
1469 /****************************************************************************/
1470 /****************************************************************************/
1473 * Install a single tramp.
1476 void installTramp(instInstance *inst, char *code, int codeSize)
1478 //the default base trampoline template is the regular base trampoline.
1479 //However if the location iptype is randomPoint then we have to use
1480 //the conservatibve base trampoline which saves the condition codes
1482 trampTemplate* current_template = &baseTemplate;
1484 if(inst->location->ipType == otherPoint)
1485 current_template = &conservativeBaseTemplate;
1488 insnGenerated += codeSize/sizeof(int);
1491 (inst->proc)->writeDataSpace((caddr_t)inst->trampBase, codeSize, code);
1494 if (inst->when == callPreInsn) {
1495 if (inst->baseInstance->prevInstru == false) {
1496 atAddr = inst->baseInstance->baseAddr+current_template->skipPreInsOffset;
1497 inst->baseInstance->cost += inst->baseInstance->prevBaseCost;
1498 inst->baseInstance->prevInstru = true;
1499 generateNoOp(inst->proc, atAddr);
1502 if (inst->baseInstance->postInstru == false) {
1503 atAddr = inst->baseInstance->baseAddr+current_template->skipPostInsOffset;
1504 inst->baseInstance->cost += inst->baseInstance->postBaseCost;
1505 inst->baseInstance->postInstru = true;
1506 generateNoOp(inst->proc, atAddr);
1511 /****************************************************************************/
1512 /****************************************************************************/
1513 /****************************************************************************/
1515 //This function returns true if the processor on which the daemon is running
1516 //is an ultra SPARC, otherwise returns false.
1517 bool isUltraSparc(){
1520 cerr <<"Trouble in uname(), inst-sparc-solaris.C\n";
1523 if(!strcmp(u.machine, "sun4u")){
1529 /****************************************************************************/
1530 /****************************************************************************/
1531 /****************************************************************************/
1533 void emitLoadPreviousStackFrameRegister(Address register_num,
1539 if(register_num > 31)
1541 else if(register_num > 15){
1542 /*Need to find it on the stack*/
1543 unsigned frame_offset = (register_num-16) * 4;
1544 /*generate a FLUSHW instruction, in order to make sure that
1545 the registers from the caller are on the caller's stack
1547 instruction *in = (instruction *) ((void*)&insn[base]);
1551 generateTrapRegisterSpill(in);
1552 base+=sizeof(instruction);
1554 if(frame_offset == 0){
1555 emitV(loadIndirOp, 30, 0, dest, insn, base, noCost, size);
1558 emitImm(plusOp,(Register) 30,(RegValue)frame_offset,
1559 dest, insn, base, noCost);
1560 emitV(loadIndirOp, dest, 0, dest, insn, base, noCost, size);
1563 else if(register_num > 7) {
1564 //out registers become in registers, so we add 16 to the register
1565 //number to find it's value this stack frame. We move it's value
1566 //into the destination register
1567 emitV(orOp, (Register) register_num + 16, 0, dest, insn, base, false);
1569 else /* if(register_num >= 0) */ {
1571 if(register_num % 2 == 0)
1572 frame_offset = (register_num * -4) - 8;
1574 frame_offset = (register_num * -4);
1575 //read globals from the stack, they were saved in tramp-sparc.S
1576 emitImm(plusOp,(Register) 30,(RegValue)frame_offset,
1577 dest, insn, base, noCost);
1578 emitV(loadIndirOp, dest, 0, dest, insn, base, noCost, size);
1580 /* else assert(0); */
1584 /****************************************************************************/
1585 /****************************************************************************/
1586 /****************************************************************************/
1588 Register emitFuncCall(opCode op,
1590 char *i, Address &base,
1591 const vector<AstNode *> &operands,
1592 const string &callee, process *proc,
1593 bool noCost, const function_base *calleefunc)
1595 assert(op == callOp);
1598 vector <Register> srcs;
1599 void cleanUpAndExit(int status);
1602 addr = calleefunc->getEffectiveAddress(proc);
1604 addr = proc->findInternalAddress(callee, false, err);
1606 function_base *func = proc->findOneFunction(callee);
1608 ostrstream os(errorLine, 1024, ios::out);
1609 os << "Internal error: unable to find addr of " << callee << endl;
1610 showErrorCallback(80, (const char *) errorLine);
1613 // TODO: is this correct or should we get relocated address?
1614 addr = func->getAddress(0);
1617 for (unsigned u = 0; u < operands.size(); u++)
1618 srcs.push_back(operands[u]->generateCode(proc, rs, i, base, noCost, false));
1621 instruction *insn = (instruction *) ((void*)&i[base]);
1623 for (unsigned u=0; u<srcs.size(); u++){
1625 string msg = "Too many arguments to function call in instrumentation code: only 5 arguments can be passed on the sparc architecture.\n";
1626 fprintf(stderr, msg.string_of());
1627 showErrorCallback(94,msg);
1630 genSimpleInsn(insn, ORop3, 0, srcs[u], u+8); insn++;
1631 base += sizeof(instruction);
1632 rs->freeRegister(srcs[u]);
1635 // As Ling pointed out to me, the following is rather inefficient. It does:
1636 // sethi %hi(addr), %o5
1637 // jmpl %o5 + %lo(addr), %o7 ('call' pseudo-instr)
1639 // We can do better:
1640 // call <addr> (but note that the call true-instr is pc-relative jump)
1642 generateSetHi(insn, addr, 13); insn++;
1643 genImmInsn(insn, JMPLop3, 13, LOW10(addr), 15); insn++;
1646 base += 3 * sizeof(instruction);
1648 // return value is the register with the return value from the function.
1649 // This needs to be %o0 since it is back in the caller's scope.
1653 /****************************************************************************/
1654 /****************************************************************************/
1655 /****************************************************************************/
1657 Address emitA(opCode op, Register src1, Register /*src2*/, Register dest,
1658 char *i, Address &base, bool /*noCost*/)
1660 //fprintf(stderr,"emitA(op=%d,src1=%d,src2=XX,dest=%d)\n",op,src1,dest);
1662 instruction *insn = (instruction *) ((void*)&i[base]);
1667 genImmInsn(insn, SUBop3cc, src1, 0, 0); insn++;
1668 //genSimpleInsn(insn, SUBop3cc, src1, 0, 0); insn++;
1670 insn->branch.op = 0;
1671 insn->branch.cond = BEcond;
1672 insn->branch.op2 = BICCop2;
1673 insn->branch.anneal = false;
1674 insn->branch.disp22 = dest/4;
1678 base += sizeof(instruction)*3;
1679 return(base - 2*sizeof(instruction));
1682 // Unconditional branch
1683 generateBranchInsn(insn, dest); insn++;
1686 base += sizeof(instruction)*2;
1687 return(base - 2*sizeof(instruction));
1689 case trampPreamble: {
1691 // save and restore are done in the base tramp now
1692 genImmInsn(insn, SAVEop3, REG_SPTR, -112, REG_SPTR);
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_FPTR, - (8 + 8*u));
1699 base += sizeof(instruction);
1703 return(0); // let's hope this is expected!
1705 case trampTrailer: {
1707 // save and restore are done in the base tramp now
1708 // generate code to restore global registers
1709 for (unsigned u = 0; u < 4; u++) {
1710 genLoadD(insn, REG_FPTR, - (8 + 8*u), 2*u);
1711 base += sizeof(instruction);
1715 // sequence: restore; nop; b,a back to base tramp; nop
1716 // we can do better. How about putting the restore in
1717 // the delay slot of the branch instruction, as in:
1718 // b <back to base tramp>; restore
1719 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1720 base += sizeof(instruction);
1724 base += sizeof(instruction);
1727 // dest is in words of offset and generateBranchInsn is bytes offset
1728 generateBranchInsn(insn, dest << 2);
1729 base += sizeof(instruction);
1732 // add no-op, SS-5 sometimes seems to try to decode this insn - jkh 2/14
1735 base += sizeof(instruction);
1737 return(base - 2 * sizeof(instruction));
1740 abort(); // unexpected op for this emit!
1744 /****************************************************************************/
1745 /****************************************************************************/
1746 /****************************************************************************/
1748 Register emitR(opCode op, Register src1, Register /*src2*/, Register /*dest*/,
1749 char *i, Address &base, bool /*noCost*/)
1751 //fprintf(stderr,"emitR(op=%d,src1=%d,src2=XX,dest=XX)\n",op,src1);
1753 instruction *insn = (instruction *) ((void*)&i[base]);
1757 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1758 // saving CT/vector address on the stack
1759 generateStore(insn, REG_MT, REG_FPTR, -40);
1762 // first 8 parameters are in register bank I (24..31)
1763 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1766 generateStore(insn, REG_I(src1), REG_SPTR, 68+4*src1);
1769 genImmInsn(insn, SAVEop3, REG_SPTR, -112, REG_SPTR);
1772 generateLoad(insn, REG_SPTR, 112+68+4*src1, REG_I(src1));
1775 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1776 // restoring CT/vector address back in REG_MT
1777 generateLoad(insn, REG_FPTR, -40, REG_MT);
1779 base += 6*sizeof(instruction);
1781 base += 4*sizeof(instruction);
1785 return(REG_I(src1));
1789 case getSysParamOp: {
1791 return(REG_I(src1));
1796 // return value is in register REG_I(0)==24
1797 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1800 generateStore(insn, REG_I(0), REG_SPTR, 68);
1803 genImmInsn(insn, SAVEop3, REG_SPTR, -112, REG_SPTR);
1806 generateLoad(insn, REG_SPTR, 112+68, REG_I(0));
1809 base += 4*sizeof(instruction);
1813 case getSysRetValOp:
1816 abort(); // unexpected op for this emit!
1820 /****************************************************************************/
1821 /****************************************************************************/
1822 /****************************************************************************/
1825 // load the original FP (before the dyninst saves) into register dest
1827 int getFP(instruction *insn, Register dest)
1829 genSimpleInsn(insn, RESTOREop3, 0, 0, 0);
1832 generateStore(insn, REG_FPTR, REG_SPTR, 68);
1835 genImmInsn(insn, SAVEop3, REG_SPTR, -112, REG_SPTR);
1838 generateLoad(insn, REG_SPTR, 112+68, dest);
1841 return(4*sizeof(instruction));
1844 /****************************************************************************/
1845 /****************************************************************************/
1846 /****************************************************************************/
1848 void emitVload(opCode op, Address src1, Register src2, Register dest,
1849 char *i, Address &base, bool /*noCost*/, int /* size */)
1851 instruction *insn = (instruction *) ((void*)&i[base]);
1853 if (op == loadConstOp) {
1854 // dest = src1:imm TODO
1856 if ((src1) > ( unsigned )MAX_IMM13 || (src1) < ( unsigned )MIN_IMM13) {
1857 // src1 is out of range of imm13, so we need an extra instruction
1858 generateSetHi(insn, src1, dest);
1859 base += sizeof(instruction);
1864 // Chance for optimization: we should check for LOW10(src1)==0,
1865 // and if so, don't generate the following bitwise-or instruction,
1866 // since in that case nothing would be done.
1868 genImmInsn(insn, ORop3, dest, LOW10(src1), dest);
1869 base += sizeof(instruction);
1871 // really or %g0,imm,regd
1872 genImmInsn(insn, ORop3, 0, src1, dest);
1874 base += sizeof(instruction);
1876 } else if (op == loadOp) {
1877 // dest = [src1] TODO
1878 generateSetHi(insn, src1, dest);
1881 generateLoad(insn, dest, LOW10(src1), dest);
1883 base += sizeof(instruction)*2;
1884 } else if (op == loadFrameRelativeOp) {
1885 // return the value that is FP offset from the original fp
1886 // need to restore old fp and save it on the stack to get at it.
1888 base += getFP(insn, dest);
1889 insn = (instruction *) ((void*)&i[base]);
1890 if (((int) src1 < MIN_IMM13) || ((int) src1 > MAX_IMM13)) {
1891 // offsets are signed!
1892 int offset = (int) src1;
1894 // emit sethi src2, offset
1895 generateSetHi(insn, offset, src2);
1896 base += sizeof(instruction);
1899 // or src2, offset, src2
1900 genImmInsn(insn, ORop3, src2, LOW10(offset), src2);
1901 base += sizeof(instruction);
1904 // add dest, src2, dest
1905 genSimpleInsn(insn, ADDop3, dest, src2, src2);
1906 base += sizeof(instruction);
1909 generateLoad(insn, src2, 0, dest);
1911 base += sizeof(instruction);
1913 generateLoad(insn, dest, src1, dest);
1915 base += sizeof(instruction);
1917 } else if (op == loadFrameAddr) {
1918 // offsets are signed!
1919 int offset = (int) src1;
1921 base += getFP(insn, dest);
1922 insn = (instruction *) ((void*)&i[base]);
1924 if (((int) offset < MIN_IMM13) || ((int) offset > MAX_IMM13)) {
1925 // emit sethi src2, offset
1926 generateSetHi(insn, offset, src2);
1927 base += sizeof(instruction);
1930 // or src2, offset, src2
1931 genImmInsn(insn, ORop3, src2, LOW10(offset), src2);
1932 base += sizeof(instruction);
1935 // add dest, src2, dest
1936 genSimpleInsn(insn, ADDop3, dest, src2, dest);
1937 base += sizeof(instruction);
1940 // fp is in dest, just add the offset
1941 genImmInsn(insn, ADDop3, dest, offset, dest);
1943 base += sizeof(instruction);
1946 abort(); // unexpected op for this emit!
1950 /****************************************************************************/
1951 /****************************************************************************/
1952 /****************************************************************************/
1954 void emitVstore(opCode op, Register src1, Register src2, Address dest,
1955 char *i, Address &base, bool /*noCost*/, int /* size */)
1957 instruction *insn = (instruction *) ((void*)&i[base]);
1959 if (op == storeOp) {
1960 insn->sethi.op = FMT2op;
1961 insn->sethi.rd = src2;
1962 insn->sethi.op2 = SETHIop2;
1963 insn->sethi.imm22 = HIGH22(dest);
1966 generateStore(insn, src1, src2, LOW10(dest));
1968 base += sizeof(instruction)*2;
1969 } else if (op == storeFrameRelativeOp) {
1970 // offsets are signed!
1971 int offset = (int) dest;
1973 base += getFP(insn, src2);
1974 insn = (instruction *) ((void*)&i[base]);
1976 if ((offset < MIN_IMM13) || (offset > MAX_IMM13)) {
1977 // We are really one regsiter short here, so we put the
1978 // value to store onto the stack for part of the sequence
1979 generateStore(insn, src1, REG_SPTR, 112+68);
1980 base += sizeof(instruction);
1983 generateSetHi(insn, offset, src1);
1984 base += sizeof(instruction);
1987 genImmInsn(insn, ORop3, src1, LOW10(offset), src1);
1988 base += sizeof(instruction);
1991 genSimpleInsn(insn, ADDop3, src1, src2, src2);
1992 base += sizeof(instruction);
1995 generateLoad(insn, REG_SPTR, 112+68, src1);
1996 base += sizeof(instruction);
1999 generateStore(insn, src1, src2, 0);
2000 base += sizeof(instruction);
2003 generateStore(insn, src1, src2, offset);
2005 base += sizeof(instruction);
2008 abort(); // unexpected op for this emit!
2012 /****************************************************************************/
2013 /****************************************************************************/
2014 /****************************************************************************/
2016 void emitVupdate(opCode op, RegValue src1, Register /*src2*/, Address dest,
2017 char *i, Address &base, bool noCost)
2019 instruction *insn = (instruction *) ((void*)&i[base]);
2021 if (op == updateCostOp) {
2022 // generate code to update the observed cost.
2024 // sethi %hi(dest), %l0
2025 generateSetHi(insn, dest, REG_L(0));
2026 base += sizeof(instruction);
2029 // ld [%l0+ lo(dest)], %l1
2030 generateLoad(insn, REG_L(0), LOW10(dest), REG_L(1));
2031 base += sizeof(instruction);
2034 // update value (src1 holds the cost, in cycles; e.g. 19)
2035 if (src1 <= MAX_IMM13) {
2036 genImmInsn(insn, ADDop3, REG_L(1), src1, REG_L(1));
2037 base += sizeof(instruction);
2041 base += sizeof(instruction);
2045 base += sizeof(instruction);
2048 // load in two parts
2049 generateSetHi(insn, src1, REG_L(2));
2050 base += sizeof(instruction);
2054 genImmInsn(insn, ORop3, REG_L(2), LOW10(src1), REG_L(2));
2055 base += sizeof(instruction);
2059 genSimpleInsn(insn, ADDop3, REG_L(1), REG_L(2), REG_L(1));
2060 base += sizeof(instruction);
2064 // store result st %l1, [%l0+ lo(dest)];
2065 generateStore(insn, REG_L(1), REG_L(0), LOW10(dest));
2066 base += sizeof(instruction);
2070 abort(); // unexpected op for this emit!
2074 /****************************************************************************/
2075 /****************************************************************************/
2076 /****************************************************************************/
2078 void emitV(opCode op, Register src1, Register src2, Register dest,
2079 char *i, Address &base, bool /*noCost*/, int /* size */)
2081 //fprintf(stderr,"emitV(op=%d,src1=%d,src2=%d,dest=%d)\n",op,src1,src2,dest);
2083 assert ((op!=branchOp) && (op!=ifOp) &&
2084 (op!=trampTrailer) && (op!=trampPreamble)); // !emitA
2085 assert ((op!=getRetValOp) && (op!=getSysRetValOp) &&
2086 (op!=getParamOp) && (op!=getSysParamOp)); // !emitR
2087 assert ((op!=loadOp) && (op!=loadConstOp)); // !emitVload
2088 assert ((op!=storeOp)); // !emitVstore
2089 assert ((op!=updateCostOp)); // !emitVupdate
2091 instruction *insn = (instruction *) ((void*)&i[base]);
2093 if (op == loadIndirOp) {
2094 generateLoad(insn, src1, 0, dest);
2095 base += sizeof(instruction);
2096 } else if (op == storeIndirOp) {
2097 generateStore(insn, src1, dest, 0);
2098 base += sizeof(instruction);
2099 } else if (op == noOp) {
2101 base += sizeof(instruction);
2102 } else if (op == saveRegOp) {
2103 // should never be called for this platform.
2123 //need to set the Y register to Zero, Zhichen
2124 genImmInsn(insn, WRYop3, REG_G(0), 0, 0);
2125 base += sizeof(instruction);
2126 insn = (instruction *) ((void*)&i[base]);
2139 // For a particular condition (e.g. <=) we need to use the
2140 // the opposite in order to get the right value (e.g. for >=
2141 // we need BLTcond) - naim
2143 genRelOp(insn, BNEcond, src1, src2, dest, base);
2148 genRelOp(insn, BEcond, src1, src2, dest, base);
2153 genRelOp(insn, BGEcond, src1, src2, dest, base);
2158 genRelOp(insn, BGTcond, src1, src2, dest, base);
2163 genRelOp(insn, BLEcond, src1, src2, dest, base);
2168 genRelOp(insn, BLTcond, src1, src2, dest, base);
2176 genSimpleInsn(insn, op3, src1, src2, dest);
2178 base += sizeof(instruction);
2183 /****************************************************************************/
2184 /****************************************************************************/
2185 /****************************************************************************/
2187 static inline bool isRestoreInsn(instruction i) {
2188 return (i.rest.op == 2 \
2189 && ((i.rest.op3 == ORop3 && i.rest.rd == 15)
2190 || i.rest.op3 == RESTOREop3));
2193 /****************************************************************************/
2194 /****************************************************************************/
2195 /****************************************************************************/
2197 static inline bool CallRestoreTC(instruction instr, instruction nexti) {
2198 return (isCallInsn(instr) && isRestoreInsn(nexti));
2202 Return integer value indicating whether instruction sequence
2203 found signals tail call
2206 sequence. Note that this should NOT include jmpl nop, ret nop, retl
2208 Current heuristic to detect such sequences :
2209 look for jmp %reg, nop in function w/ no stack frame, if jmp, nop
2210 are last 2 instructions, return 1 (definate TC), at any other point,
2211 return 0 (not TC). Otherwise, return 0 (no TC).
2212 w/ no stack frame....
2213 instr is instruction being examioned.
2214 nexti is instruction after
2215 addr is address of <instr>
2216 func is pointer to function class object describing function
2217 instructions come from....
2219 static inline bool JmpNopTC(instruction instr, instruction nexti,
2220 Address addr, pd_Function *func) {
2222 if (!isInsnType(instr, JMPLmask, JMPLmatch)) {
2226 assert(instr.resti.op3 == 0x38);
2228 // only looking for jump instructions which don't overwrite a register
2229 // with the PC which the jump comes from (g0 is hardwired to 0, so a write
2230 // there has no effect?)....
2231 // instr should have gdb disass syntax :
2233 // NOT jmpl %reg1, %reg2
2234 if (instr.resti.rd != REG_G(0)) {
2238 // only looking for jump instructions in which the destination is
2239 // NOT %i7 + 8/12/16 or %o7 + 8/12/16 (ret and retl synthetic
2240 // instructions, respectively)
2241 if (instr.resti.i == 1) {
2242 if (instr.resti.rs1 == REG_I(7) || instr.resti.rs1 == REG_O(7)) {
2243 // NOTE : some return and retl instructions jump to {io}7 + 12,
2244 // or (io)7 + 16, not + 8, to have some extra space to store the size of a
2245 // return structure....
2246 if (instr.resti.simm13 == 0x8 || instr.resti.simm13 == 12 ||
2247 instr.resti.simm13 == 16) {
2253 // jmp, foloowed by NOP....
2254 if (!isNopInsn(nexti)) {
2258 // in function w/o stack frame....
2259 if (!func->hasNoStackFrame()) {
2263 // if sequence is detected, but not at end of fn
2264 // (last 2 instructions....), return value indicating possible TC.
2265 // This should (eventually) mark the fn as uninstrumenatble....
2266 if (addr != (func->getAddress(0) + func->size() - 8)) {
2273 /****************************************************************************/
2274 /****************************************************************************/
2275 /****************************************************************************/
2278 Is the specified call instruction one whose goal is to set the 07 register
2279 (the sequence of execution is as if the call instruction did not change the
2280 control flow, and the O7 register is set)?
2282 here, we define a call whose goal is to set the 07 regsiter
2283 as one where the target is the call address + 8, AND where that
2284 target is INSIDE the same function (need to make sure to check for that
2285 last case also, c.f. function DOW, which ends with):
2286 0xef601374 <DOW+56>: call 0xef60137c <adddays>
2287 0xef601378 <DOW+60>: restore
2289 instr - raw instruction....
2290 functionSize - size of function (in bytes, NOT # instructions)....
2291 instructionOffset - BYTE offset in function at which instr occurs....
2293 static inline bool is_set_O7_call(instruction instr, unsigned functionSize,
2294 unsigned instructionOffset) {
2295 // if the instruction is call %register, assume that it is NOT a
2296 // call designed purely to set %O7....
2297 if(instr.call.op != CALLop) {
2300 if (((instr.call.disp30 << 2) == 8) &&
2301 (instructionOffset < (functionSize - 2 * sizeof(instruction)))) {
2307 /****************************************************************************/
2308 /****************************************************************************/
2309 /****************************************************************************/
2312 Does the specified call instruction call to target inside function
2313 or outside - may be indeterminate if insn is call %reg instead of
2314 call <address> (really call PC + offset)
2315 Note: (recursive) calls back to the beginning of the function are OK
2316 since we really want to consider these as instrumentable call sites!
2318 enum fuzzyBoolean {eFalse = 0, eTrue = 1, eDontKnow = 2};
2320 static enum fuzzyBoolean is_call_outside_function(const instruction instr,
2321 const Address functionStarts, const Address instructionAddress,
2322 const unsigned int functionSize)
2324 // call %register - don't know if target inside function....
2325 if(instr.call.op != CALLop) {
2328 const Address call_target = instructionAddress + (instr.call.disp30 << 2);
2329 if ((call_target > functionStarts) &&
2330 (call_target < (functionStarts + functionSize))) {
2337 /****************************************************************************/
2338 /****************************************************************************/
2339 /****************************************************************************/
2342 * Find the instPoints of this function.
2344 bool pd_Function::findInstPoints(const image *owner) {
2346 Address firstAddress = getAddress(0);
2347 Address lastAddress = getAddress(0) + size();
2356 // For determining if function needs relocation to be instrumented
2358 relocatable_ = false;
2359 bool canBeRelocated = true;
2361 // Initially assume function has no stack frame
2362 noStackFrame = true;
2364 // variables for function parameters
2365 const instPoint *blah = 0;
2369 // Ids for instPoints
2371 unsigned callsId = 0;
2377 instr.raw = owner->get_instruction(firstAddress);
2378 if (!IS_VALID_INSN(instr)) {
2382 // Determine if function needs to be relocated when instrumented
2383 for ( adr = firstAddress; adr < lastAddress; adr += 4) {
2384 instr.raw = owner->get_instruction(adr);
2385 nexti.raw = owner->get_instruction(adr+4);
2387 // If there's an TRAP instruction in the function, we assume
2388 // that it is an system call and will relocate it to the heap
2389 if (isInsnType(instr, TRAPmask, TRAPmatch)) {
2391 relocatable_ = true;
2394 // TODO: This is a hacking for the solaris(solaris2.5 actually)
2395 // We will relocate that function if the function has been
2396 // tail-call optimazed.
2397 // (Actully, the reason of this is that the system calls like
2398 // read, write, etc have the tail-call optimazation to call
2399 // the _read, _write etc. which contain the TRAP instruction
2400 // This is only done if libc is statically linked...if the
2401 // libTag is set, otherwise we instrument read and _read
2402 // both for the dynamically linked case
2403 // New for Solaris 2.6 support - new form of tail-call opt-
2407 // as last 2 instructions in function which does not have
2408 // own register frame.
2409 if (CallRestoreTC(instr, nexti) || JmpNopTC(instr, nexti, adr, this)) {
2411 relocatable_ = true;
2414 // if call is directly to a retl, this is not a real call, but
2415 // is instead used to set the o7 register. Set the function to be
2416 // relocated when instrumented.
2417 if (isCallInsn(instr)) {
2419 // find target address of call
2420 disp = instr.call.disp30 << 2;
2421 target = adr + disp;
2423 // get target instruction of the call
2424 instruction tmpInsn;
2425 tmpInsn.raw = owner->get_instruction( target );
2427 if((tmpInsn.raw & 0xfffff000) == 0x81c3e000) {
2429 relocatable_ = true;
2435 /* FIND FUNCTION ENTRY */
2437 entry = firstAddress;
2438 for ( adr = firstAddress; adr < lastAddress; adr += 4) {
2440 // The function Entry is defined as the first SAVE instruction plus
2441 // the instructions after this.
2442 // ( The first instruction for the nonleaf function is not
2443 // necessarily a SAVE instruction. )
2444 instr.raw = owner->get_instruction(adr);
2446 if (isInsnType(instr, SAVEmask, SAVEmatch)) {
2448 noStackFrame = false;
2453 // If there's no SAVE instruction found, this is a leaf function
2454 // and function Entry will be defined from the first instruction
2457 // noStackFrame, apparently leaf function
2464 /* CHECK IF FUNCTION SHOULD NOT BE RELOCATED WHEN INSTRUMENTED */
2466 // FUNCTION TOO SMALL
2467 if (size() <= 3*sizeof(instruction)) {
2468 canBeRelocated = false;
2472 // if the second instruction in a function that needs relocation is a call
2473 // instruction or a branch instruction, then we can't deal with this.
2474 // New: only a problem if the call is to a location outside the function,
2475 // or is a jump to itself....
2477 // Grab second instruction
2478 Address addrSecondInstr = firstAddress + sizeof(instruction);
2479 instr.raw = owner->get_instruction(addrSecondInstr);
2481 if ( isCallInsn(instr) ) {
2484 target = addrSecondInstr + (instr.call.disp30 << 2);
2486 // if call dest. is outside of function, assume real
2487 // call site. Assuming cant deal with this case!!!!
2488 if ( !(target >= firstAddress && target <= lastAddress) ||
2489 (target == addrSecondInstr) ) {
2490 canBeRelocated = false;
2493 // Branch instruction
2494 if ( instr.branch.op == 0 &&
2495 (instr.branch.op2 == 2 || instr.branch.op2 == 6) ) {
2496 canBeRelocated = false;
2501 // Can't handle function
2502 if (canBeRelocated == false && isTrap == true) {
2507 #ifdef BPATCH_LIBRARY
2508 if (BPatch::bpatch->hasForcedRelocation_NP()) {
2509 if (canBeRelocated == true) {
2511 relocatable_ = true;
2517 /* CREATE ENTRY INSTPOINT */
2518 instr.raw = owner->get_instruction(entry);
2520 if (relocatable_ == true) {
2521 funcEntry_ = new instPoint(this, instr, owner, entry, true,
2522 functionEntry, entry);
2524 funcEntry_ = new instPoint(this, instr, owner, entry, true,
2531 // ITERATE OVER INSTRUCTIONS, locating instPoints
2534 for (int i=0; adr < lastAddress; adr += sizeof(instruction), i++) {
2536 instr.raw = owner->get_instruction(adr);
2537 newInstr[i] = instr;
2538 nexti.raw = owner->get_instruction(adr+4);
2540 // check for return insn and as a side affect decide if we are at the
2541 // end of the function.
2542 if (isReturnInsn(owner, adr, dummyParam, prettyName())) {
2543 // define the return point
2546 if (relocatable_ == true) {
2547 point = new instPoint(this, instr, owner, adr, false,
2550 point = new instPoint(this, instr, owner, adr, false,
2554 funcReturns.push_back(point);
2555 funcReturns[retId] -> instId = retId; retId++;
2558 else if (instr.branch.op == 0
2559 && (instr.branch.op2 == 2 || instr.branch.op2 == 6)
2560 && (instr.branch.cond == 0 || instr.branch.cond == 8)) {
2562 // find if this branch is going out of the function
2563 disp = instr.branch.disp22;
2564 Address target = adr + (disp << 2);
2566 if (target < firstAddress || target >= lastAddress) {
2569 if (relocatable_ == true) {
2570 point = new instPoint(this, newInstr[i], owner, adr,
2571 false, functionExit, adr);
2573 point = new instPoint(this, newInstr[i], owner, adr,
2574 false, functionExit);
2577 if ((instr.branch.cond != 0) && (instr.branch.cond != 8)) {
2579 point->isBranchOut = true;
2580 point->branchTarget = target;
2583 funcReturns.push_back(point);
2584 funcReturns[retId] -> instId = retId; retId++;
2589 else if (isCallInsn(instr)) {
2591 // if the call target is the address of the call instruction
2592 // then this is not something that we can instrument...
2593 // this occurs in functions with code that is modifined when
2594 // they are loaded by the run-time linker, or when the .init
2595 // section is executed. In this case the instructions in the
2596 // parsed image file are different from the ones in the executable
2598 Address call_target = adr + (instr.call.disp30 << 2);
2599 if(instr.call.op == CALLop) {
2600 if(call_target == adr){
2601 cerr << "WARN : function " << prettyName().string_of()
2602 << " has call to same location as call, NOT instrumenting"
2608 // first, check for tail-call optimization: a call where the
2609 // instruction in the delay slot write to register %o7(15), usually
2610 // just moving the caller's return address, or doing a restore
2611 // Tail calls are instrumented as return points, not call points.
2613 if (CallRestoreTC(instr, nexti)) {
2615 adr = newCallPoint(adr, instr, owner, err, callsId, adr, 0, blah);
2620 disp = adr + sizeof(instruction);
2621 instPoint *point = new instPoint(this, instr, owner, disp,
2622 false, functionExit, adr);
2623 funcReturns.push_back(point);
2624 funcReturns[retId] -> instId = retId; retId++;
2628 // check if the call is to inside the function - if definately
2629 // inside function (meaning that thew destination can be determined
2630 // statically because its a call to an address, not to a register
2631 // or register + offset) then don't instrument as call site,
2632 // otherwise (meaning that the call destination is known statically
2633 // to be outside the function, or is not known statically), then
2634 // instrument as a call site....
2635 enum fuzzyBoolean is_inst_point;
2636 is_inst_point = is_call_outside_function(instr, firstAddress,
2638 if (is_inst_point == eFalse) {
2640 // if this is a call instr to a location within the function,
2641 // and if the offest is not 8 then do not define this function
2642 if (!is_set_O7_call(instr, size(), adr - firstAddress)) {
2645 adr = newCallPoint(adr, instr, owner, err, callsId, adr, 0, blah);
2649 // get call target instruction
2650 Address call_target = adr + (instr.call.disp30 << 2);
2651 instruction tmpInsn;
2652 tmpInsn.raw = owner->get_instruction( call_target );
2654 // check that call is not directly to a retl instruction,
2655 // and thus a real call
2656 if((tmpInsn.raw & 0xfffff000) != 0x81c3e000) {
2657 adr = newCallPoint(adr, instr, owner, err, callsId,
2667 else if (JmpNopTC(instr, nexti, adr, this)) {
2669 adr = newCallPoint(adr, instr, owner, err, callsId, adr, 0, blah);
2674 disp = adr + sizeof(instruction);
2675 instPoint *point = new instPoint(this, instr, owner, disp, false,
2677 funcReturns.push_back(point);
2678 funcReturns[retId] -> instId = retId; retId++;
2681 else if (isInsnType(instr, JMPLmask, JMPLmatch)) {
2682 /* A register indirect jump. Some jumps may exit the function
2683 (e.g. read/write on SunOS). In general, the only way to
2684 know if a jump is exiting the function is to instrument
2685 the jump to test if the target is outside the current
2686 function. Instead of doing this, we just check the
2687 previous two instructions, to see if they are loading
2688 an address that is out of the current function.
2689 This should catch the most common cases (e.g. read/write).
2690 For other cases, we would miss a return point.
2692 This is the case considered:
2699 Register jumpreg = instr.rest.rs1;
2703 prev1.raw = owner->get_instruction(adr-4);
2704 prev2.raw = owner->get_instruction(adr-8);
2708 if (instr.rest.rd == 0 && (instr.rest.i == 1 || instr.rest.rs2 == 0)
2709 && prev2.sethi.op == FMT2op && prev2.sethi.op2 == SETHIop2
2710 && prev2.sethi.rd == (unsigned)jumpreg
2711 && prev1.rest.op == RESTop
2712 && prev1.rest.rd == (unsigned)jumpreg && prev1.rest.i == 1
2713 && prev1.rest.op3 == ORop3 && prev1.rest.rs1 == (unsigned)jumpreg) {
2715 targetAddr = (prev2.sethi.imm22 << 10) & 0xfffffc00;
2716 targetAddr |= prev1.resti.simm13;
2718 if ( (targetAddr < firstAddress) || (targetAddr >= lastAddress) ){
2721 if (relocatable_ == true) {
2722 point = new instPoint(this, instr, owner, adr, false,
2725 point = new instPoint(this, instr, owner, adr, false,
2729 funcReturns.push_back(point);
2730 funcReturns[retId] -> instId = retId; retId++;
2736 bool checkPoints = checkInstPoints(owner);
2738 if ( (checkPoints == false) || (!canBeRelocated && isTrap) ){
2745 /****************************************************************************/
2746 /****************************************************************************/
2747 /****************************************************************************/
2750 * Check all the instPoints within this function to see if there's
2751 * any conficts happen.
2753 bool pd_Function::checkInstPoints(const image *owner) {
2755 // Our own library function, skip the test.
2756 if (prettyName().prefixed_by("DYNINST"))
2759 #ifndef BPATCH_LIBRARY /* XXX Users of libdyninstAPI might not agree. */
2760 // The function is too small to be worthing instrumenting.
2762 //cerr << "WARN : function " << prettyName().string_of()
2763 // << " too small (size <= 12), can't instrument" << endl;
2768 // No function return! return false;
2769 if (sizeof(funcReturns) == 0) {
2770 //cerr << "WARN : function " << prettyName().string_of()
2771 // << " no return point found, can't instrument" << endl;
2776 Address adr = getAddress(0);
2778 bool retl_inst = false;
2779 bool restore_inst = false;
2780 // Check if there's any branch instruction jump to the middle
2781 // of the instruction sequence in the function entry point
2782 // and function exit point.
2783 for ( ; adr < getAddress(0) + size(); adr += sizeof(instruction)) {
2785 instr.raw = owner->get_instruction(adr);
2786 if(isInsnType(instr, RETLmask, RETLmatch)) retl_inst = true;
2787 if(isInsnType(instr, RESTOREmask, RESTOREmatch)) restore_inst = true;
2788 if (isInsnType(instr, BRNCHmask, BRNCHmatch)||
2789 isInsnType(instr, FBRNCHmask, FBRNCHmatch)) {
2791 int disp = instr.branch.disp22;
2792 Address target = adr + (disp << 2);
2794 if ((target > funcEntry_->addr)&&
2795 (target < (funcEntry_->addr + funcEntry_->size))) {
2796 if (adr > (funcEntry_->addr+funcEntry_->size)){
2797 //cerr << "WARN : function " << prettyName().string_of()
2798 // << " has branch target inside fn entry point, can't instrument" << endl;
2801 // function can be instrumented if we relocate it
2803 relocatable_ = true;
2806 for (u_int i = 0; i < funcReturns.size(); i++) {
2807 if ((target > funcReturns[i]->addr)&&
2808 (target < (funcReturns[i]->addr + funcReturns[i]->size))) {
2809 if ((adr < funcReturns[i]->addr)||
2810 (adr > (funcReturns[i]->addr + funcReturns[i]->size))){
2811 //cerr << "WARN : function " << prettyName().string_of()
2812 // << " has branch target inside fn return point, "
2813 // << "can't instrument" << endl;
2816 // function can be instrumented if we relocate it
2818 relocatable_ = true;
2824 // if there is a retl instruction and we don't think this is a leaf
2825 // function then this is a way messed up function...well, at least we
2826 // we can't deal with this...the only example I can find is _cerror
2827 // and _cerror64 in libc.so.1
2828 if(retl_inst && !noStackFrame && !restore_inst){
2829 //cerr << "WARN : function " << prettyName().string_of()
2830 // << " retl instruction in non-leaf function, can't instrument"
2835 // check that no instrumentation points could overlap
2836 Address func_entry = funcEntry_->addr + funcEntry_->size;
2837 for (u_int i = 0; i < funcReturns.size(); i++) {
2838 if(func_entry >= funcReturns[i]->addr){
2841 // function can be instrumented if we relocate it
2843 relocatable_ = true;
2845 if(i >= 1){ // check if return points overlap
2846 Address prev_exit = funcReturns[i-1]->addr+funcReturns[i-1]->size;
2847 if(funcReturns[i]->addr < prev_exit) {
2848 //cerr << "WARN : function " << prettyName().string_of()
2849 // << " overlapping instrumentation points, can't instrument"
2852 // function can be instrumented if we relocate it
2854 relocatable_ = true;
2862 /****************************************************************************/
2863 /****************************************************************************/
2864 /****************************************************************************/
2866 // used for sorting inst points - typecast void *s to instPoint **s, then
2867 // do {-1, 0, 1} comparison by address....
2868 int sort_inst_points_by_address(const void *arg1, const void *arg2) {
2869 instPoint * const *a = static_cast<instPoint* const *>(arg1);
2870 instPoint * const *b = static_cast<instPoint* const *>(arg2);
2871 if ((*a)->iPgetAddress() > (*b)->iPgetAddress()) {
2873 } else if ((*a)->iPgetAddress() < (*b)->iPgetAddress()) {
2879 /****************************************************************************/
2880 /****************************************************************************/
2881 /****************************************************************************/
2884 First pass, handle cases where general-purpose re-writing needs to be
2885 done to preserve paradynd/dyninstAPI's assumptions about function
2887 In current sparc-solaris version, this is ONLY the following cases:
2888 If a call site and return point overlap and are located directly
2889 next to eachother, and the return point is located on a
2890 restore operation, then a TailCallPA is applied whose footprint
2891 covers the call and the restore.
2892 The TailCallPA should rewrite the call; restore, and update the
2893 locations of both inst points as necessary.
2894 If the 2nd instruction in a function is a CALL, then a single nop
2895 is inserted before the call - to clear out the delay slot of the
2896 branch which is inserted at the first instruction (for entry point
2898 If the dyninstAPI is seperated from paradyn, or when converting this
2899 code to support instrumentation at arbitrary points (instead of assuming
2900 entry, exit, and call site instrumentation), then the check should be
2902 look at 2nd insn, see if its a call
2904 look at all inst points, see if any of them have a call in what
2905 corresponds to the delay slot of the instruction which is going to
2906 get stomped by a branch/call to tramp....
2907 If the code has any calls to address (of call) + 8, replace the call with
2908 a sequence which sets the 07 register to the (original) address....
2910 Attaches LocalAlterations related to general rewrites of function
2911 (by adding them to LocalAlterationSet p).
2912 returns boolean value indicating whether it was able to figure out
2913 sequence of LocalAlterations to apply to perform specified rewrites....
2915 bool pd_Function::PA_attachGeneralRewrites( const image *owner,
2916 LocalAlterationSet *p,
2917 Address baseAddress,
2918 Address firstAddress,
2919 instruction loadedCode[],
2920 unsigned /* numInstructions */,
2922 instruction instr, nexti;
2923 TailCallOptimization *tail_call;
2924 // previously referred to calls[i] directly, but gdb seems to be having
2925 // trouble with templated types with the new compiler - making debugging
2926 // difficult - so, directly assign calls[i] to the_call so can use gdb
2927 // to get at info about it....
2928 instPoint *the_call;
2930 #ifdef DEBUG_PA_INST
2931 cerr << "pd_Function::PA_attachGeneralRewrites called" <<endl;
2932 cerr << " prettyName = " << prettyName() << endl;
2935 // Look at the 2nd instruction in function. If its a call, then
2936 // stick a single nop before it....
2937 // The comment in the old inst-sparc-solaris.C version describing the rationale
2938 // for thw change is :
2939 // if the second instruction in the function is a call instruction
2940 // then this cannot go in the delay slot of the branch to the
2941 // base tramp, so add a noop between first and second instructions
2942 // in the relocated function (check out write in libc.so.1 for
2943 // and example of this):
2945 // save %sp, -96, %sp brach to base tramp
2948 // Note that if this call insn is a call to address + 8, it will actually
2949 // be replaced by a sequence which does NOT include a call, so don't need to
2950 // worry about inserting the extra nop....
2951 if (isCallInsn(loadedCode[1]) &&
2952 !is_set_O7_call(loadedCode[1], codeSize, sizeof(instruction))) {
2953 // Insert one no-op after the first instruction
2954 // (RewriteFootprint will copy the instruction at offset 0, and then
2955 // place the no-op after that instruction)
2956 InsertNops *nop = new InsertNops(this, 0, sizeof(instruction));
2957 p->AddAlteration(nop);
2958 #ifdef DEBUG_PA_INST
2959 cerr << " added single NOP in 2nd instruction" << endl;
2963 // Iterate over function instruction by instruction, looking for calls to
2965 assert((codeSize % sizeof(instruction)) == 0);
2966 for(unsigned i=0;i<(codeSize/sizeof(instruction));i++) {
2967 // want CALL %address, NOT CALL %register
2968 if (isTrueCallInsn(loadedCode[i])) {
2969 // figure out destination of call....
2970 if (is_set_O7_call(loadedCode[i], codeSize, i * sizeof(instruction))) {
2971 SetO7 *seto7 = new SetO7(this, i * sizeof(instruction));
2972 p->AddAlteration(seto7);
2973 #ifdef DEBUG_PA_INST
2974 cerr << " detected call pattern designed to set 07 register at offset "
2975 << i * sizeof(instruction) << endl;
2979 // Check for a call to a location outside of the function,
2980 // where the target of the call is a retl instruction. This
2981 // sequence is used to set the o7 register with the PC.
2983 // Get target of call instruction
2984 Address callAddress = firstAddress + i*sizeof(instruction);
2985 Address callTarget = callAddress +
2986 (loadedCode[i].call.disp30 << 2);
2988 // If call is to location outside of function
2989 if ( (callTarget < firstAddress) ||
2990 (callTarget > firstAddress + size()) ) {
2992 // get target instruction
2993 instruction tmpInsn;
2994 tmpInsn.raw = owner->get_instruction(callTarget - baseAddress);
2995 // If call target instruction is a retl instruction
2996 if((tmpInsn.raw & 0xfffff000) == 0x81c3e000) {
2998 // Retrieve the instruction in the delay slot of the retl,
2999 // so that it can be copied into the relocated function
3001 owner->get_instruction( (callTarget - baseAddress) + sizeof(instruction) );
3003 RetlSetO7 *retlSetO7 =
3004 new RetlSetO7(this, i * sizeof(instruction), tmpInsn);
3005 p->AddAlteration(retlSetO7);
3007 #ifdef DEBUG_PA_INST
3008 cerr << " detected call to retl instruction"
3009 << " designed to set 07 register at offset "
3010 << i * sizeof(instruction) << endl;
3018 // Look for an instPoint in funcCalls where the instruction is
3019 // a call instruction and the next instruction is a restore op
3020 // or where the instruction is a jmp (out of function?), and the next
3021 // instruction is a nop....
3022 // There is an unfortunate dependence on the method for detecting tail-call
3023 // optimizations in the code for detecting overlapping inst-points, below.
3024 // If change this code, may need to update that code correspondingly....
3025 for(unsigned i=0;i<calls.size();i++) {
3026 // this should return the offset at which the FIRST instruction which
3027 // is ACTUALLY OVEWRITTEN BY INST POINT is located....
3028 the_call = calls[i];
3029 int offset = (the_call->iPgetAddress() - getAddress(0));
3030 instr = the_call->insnAtPoint();
3031 nexti = the_call->insnAfterPoint();
3032 if (CallRestoreTC(instr, nexti)) {
3033 tail_call = new CallRestoreTailCallOptimization(this, offset,
3034 offset + 2 * sizeof(instruction), instr);
3035 p->AddAlteration(tail_call);
3036 #ifdef DEBUG_PA_INST
3037 cerr << " detected call, restore tail-call optimization at offset "
3041 if (JmpNopTC(instr, nexti, the_call->iPgetAddress(), this)) {
3042 tail_call = new JmpNopTailCallOptimization(this, offset,
3043 offset + 2 * sizeof(instruction));
3044 p->AddAlteration(tail_call);
3045 #ifdef DEBUG_PA_INST
3046 cerr << " detected jmp, nop tail-call optimization at offset "
3055 /****************************************************************************/
3056 /****************************************************************************/
3057 /****************************************************************************/
3060 Second pass, handle cases where inst points overlap eachother (and
3061 thus prevent the normal instrumentation technique from being used).
3062 In current sparc-solaris version, the following algorithm is used:
3063 Check all inst points. If any overlap, figure out the instruction
3064 that each is trying to get and insert nops so that they no longer
3067 bool pd_Function::PA_attachOverlappingInstPoints(
3068 LocalAlterationSet *p, Address /* baseAddress */,
3069 Address /* firstAddress */,
3070 instruction loadedCode[], int /* codeSize */) {
3072 instruction instr, nexti;
3074 #ifdef DEBUG_PA_INST
3075 cerr << "pd_Function::PA_attachOverlappingInstPoints called" <<endl;
3076 cerr << " prettyName = " << prettyName() << endl;
3079 // Make a list of all inst-points attached to function, and sort
3080 // by address. Then check for overlaps....
3081 vector<instPoint*> foo;
3082 //foo += funcEntry_;
3083 //foo += funcReturns;
3085 // define sort_inst_points_by_address as function with following
3087 // void sort (int (*)(const void *, const void *))
3088 // - takes 2 void *'s, typecasts to instPoint *'s, then does
3089 // {-1, 0, 1} comparison based on ip->addr....
3090 // foo.sort(sort_inst_points_by_address);
3091 // qsort((void *) data_, sz_, sizeof(T), cmpfunc);
3092 //qsort(foo.data(), foo.size(), sizeof(instPoint*), sort_inst_points_by_address);
3094 sorted_ips_vector(foo);
3096 // should hopefully have inst points for fn sorted by address....
3097 // check for overlaps....
3098 for (unsigned i=0;i<foo.size()-1;i++) {
3099 instPoint *this_inst_point = foo[i];
3100 instPoint *next_inst_point = foo[i+1];
3101 // This is kind of a hack - strictly speaking, the peephole alteration
3102 // abstraction for relocating inst points should be applied to the set of
3103 // inst points in the function after every independent set of alterations is
3104 // applied. This is nto done for performance reasons - rather all the inst
3105 // points in the function are relocated at once - based on the alteration sets.
3106 // As such, the peephole alterations are NOT implemented so as to be strictly
3107 // independent. An example of this is the interaction of the code for attaching
3108 // tail-call optimization PAs based on inst points (NOT function instructions),
3109 // above. Anyway, the net efffect is that by the time flow-of-control reaches
3110 // here, the tail-call optimization has (hopefully) been rewritten, but the
3111 // inst points pointing to it have not been updated. As such, check here to
3112 // make sure that the overalpping inst points aren't really part of a tail-call
3113 // optimization. This introduces some lack of locality of reference - sorry....
3115 if ((this_inst_point->ipType == callSite) &&
3116 (next_inst_point->ipType == functionExit)) {
3117 instr = this_inst_point->insnAtPoint();
3118 nexti = this_inst_point->insnAfterPoint();
3119 if (CallRestoreTC(instr, nexti) ||
3120 JmpNopTC(instr, nexti, this_inst_point->iPgetAddress(), this)) {
3122 // This tail call optimization will be rewritten, eliminating the
3123 // overlap, so we don't have to worry here about rewriting this
3124 // as overlapping instPoints.
3125 // Also, I added the i++ because we don't have to bother looking
3126 // for an overlap between the next_inst_point, and any instPoints
3127 // that may follow it (even one that is located at the very next
3128 // instruction). The reason for this is that when we relocate the
3129 // function, we will call installBaseTrampSpecial to generate the
3130 // base tramp. The distance between the base tramp and the
3131 // relocated function will then be within the range
3132 // of a branch insn, and only one instruction at the instPoint
3133 // will be relocated to the baseTramp (since the restore or nop
3134 // will not also have a delay slot insn) which means that there
3135 // will be no conflict with next_inst_point overlapping another
3143 // check if inst point overlaps with next inst point....
3144 int overlap = ((this_inst_point->iPgetAddress() +
3145 this_inst_point->Size()) - next_inst_point->iPgetAddress());
3147 // Inst point overlaps with next one. Insert
3148 // InsertNops into PA Set AFTER instruction pointed to
3149 // by inst point (Making sure that this does NOT break up
3150 // an insn and its delay slot).....
3151 // ALRT ALRT : This is NOT designed to handle the case where
3152 // 2 inst points are located at exactly the same place or
3153 // 1 is located in the delay slot of the other - it will NOT
3154 // break up the 2 inst points in that case....
3156 int offset = (this_inst_point->insnAddress() - getAddress(0));
3158 if (IS_DELAYED_INST(loadedCode[offset/sizeof(instruction)])) {
3159 offset += sizeof(instruction);
3161 InsertNops *nops = new InsertNops(this, offset, overlap);
3162 p->AddAlteration(nops);
3164 #ifdef DEBUG_PA_INST
3165 cerr << " detected overlapping inst points : offset " << offset <<
3166 " overlap " << overlap << endl;
3173 /****************************************************************************/
3174 /****************************************************************************/
3175 /****************************************************************************/
3178 Third pass, handle cases where inst points overlap branch/jump targets.
3179 In current sparc-solaris version, the following algorithm is used:
3180 Check all branch/jump operations. If they go into footprint of
3181 any inst points, then try to insert nops so that the branch targets
3182 move outside of the the footprint....
3183 Note that the algorithm given below should be attached AFTER alterations
3184 which unwind tail-call optimizations and seperate overlapping inst points
3185 have been BOTH attached and applied....
3187 bool pd_Function::PA_attachBranchOverlaps(
3188 LocalAlterationSet *p, Address /* baseAddress */,
3189 Address firstAddress, instruction loadedCode[],
3190 unsigned /* numberOfInstructions */,
3193 #ifdef DEBUG_PA_INST
3194 cerr << "pd_Function::PA_attachBranchOverlaps called" <<endl;
3195 cerr << " prettyName = " << prettyName() << endl;
3198 // Make a list of all inst-points attached to function, and sort
3199 // by address. Then check for overlaps....
3200 vector<instPoint*> foo;
3201 foo.push_back(funcEntry_);
3202 VECTOR_APPEND(foo,funcReturns);
3203 VECTOR_APPEND(foo,calls);
3205 // Sort inst points list by address....
3206 VECTOR_SORT(foo, sort_inst_points_by_address);
3208 // Iterate over function instruction by instruction....
3209 assert((codeSize % sizeof(instruction)) == 0);
3210 for(unsigned i=0;i<(codeSize/sizeof(instruction));i++) {
3211 // looking for branch instructions inside function....
3212 if (!branchInsideRange(loadedCode[i],
3213 firstAddress + (i * sizeof(instruction)),
3215 firstAddress + size())) {
3219 int disp = loadedCode[i].branch.disp22;
3220 Address target = firstAddress + (i * sizeof(instruction))
3223 // branch insn inside function. Check target versus known inst points....
3224 instPoint *overlap = find_overlap(foo, target);
3225 if (overlap == NULL) continue;
3228 // ALRT ALRT - What happens if you have multiple barcnhes to the same spot?
3229 // They will reuslt in multiple identical NOP expansions added here. Need
3230 // LocalAlterationSet to ignore multiple identical alterations (identical
3231 // in type, location, and all fields) beyond first....
3233 // branch target inside function and inside inst point footprint....
3234 // if target is before actual inst point target instruction, add
3235 // (target - 1st addres) nops, where 1st address is address of 1st
3236 // instruction actually inside the footprint....
3237 if (target <= overlap->iPgetAddress()) {
3238 InsertNops *nops = new InsertNops(this,
3239 (target - firstAddress) - sizeof(instruction),
3240 target - overlap->firstAddress());
3241 p->AddAlteration(nops);
3242 #ifdef DEBUG_PA_INST
3243 cerr << " detected overlap between branch target and inst point : offset "
3244 << target - firstAddress << " # bytes "
3245 << target - overlap->firstAddress() << endl;