Added code to suppress "functions" that have aninvalid instruction
[dyninst.git] / paradynd / src / inst-sparc.C
1 /*
2  * Copyright (c) 1993, 1994 Barton P. Miller, Jeff Hollingsworth,
3  *     Bruce Irvin, Jon Cargille, Krishna Kunchithapadam, Karen
4  *     Karavanic, Tia Newhall, Mark Callaghan.  All rights reserved.
5  * 
6  * This software is furnished under the condition that it may not be
7  * provided or otherwise made available to, or used by, any other
8  * person, except as provided for by the terms of applicable license
9  * agreements.  No title to or ownership of the software is hereby
10  * transferred.  The name of the principals may not be used in any
11  * advertising or publicity related to this software without specific,
12  * written prior authorization.  Any use of this software must include
13  * the above copyright notice.
14  *
15  */
16
17 #ifndef lint
18 static char Copyright[] = "@(#) Copyright (c) 1993, 1994 Barton P. Miller, \
19   Jeff Hollingsworth, Jon Cargille, Krishna Kunchithapadam, Karen Karavanic,\
20   Tia Newhall, Mark Callaghan.  All rights reserved.";
21
22 static char rcsid[] = "@(#) $Header: /home/jaw/CVSROOT_20081103/CVSROOT/core/paradynd/src/Attic/inst-sparc.C,v 1.17 1994/10/25 22:20:38 hollings Exp $";
23 #endif
24
25 /*
26  * inst-sparc.C - Identify instrumentation points for a SPARC processors.
27  *
28  * $Log: inst-sparc.C,v $
29  * Revision 1.17  1994/10/25 22:20:38  hollings
30  * Added code to suppress "functions" that have aninvalid instruction
31  * as their first instruction.  These are really read-only data that has
32  * been placed in the text segment to protect it from writing.
33  *
34  * Revision 1.16  1994/10/13  07:24:42  krisna
35  * solaris porting and updates
36  *
37  * Revision 1.15  1994/09/22  01:58:17  markc
38  * made getStrOp() return const char*
39  * changed *allocs to news
40  * enter funcFrequencyTable handles into stringPool
41  * cast args to ptrace, PCptrace
42  *
43  * Revision 1.14  1994/08/08  20:13:37  hollings
44  * Added suppress instrumentation command.
45  *
46  * Revision 1.13  1994/07/28  22:40:38  krisna
47  * changed definitions/declarations of xalloc functions to conform to alloc.
48  *
49  * Revision 1.12  1994/07/26  19:57:31  hollings
50  * moved instruction definitions to seperate header file.
51  *
52  * Revision 1.11  1994/07/20  23:23:35  hollings
53  * added insn generated metric.
54  *
55  * Revision 1.10  1994/07/14  23:30:24  hollings
56  * Hybrid cost model added.
57  *
58  * Revision 1.9  1994/07/12  20:09:06  jcargill
59  * Added warning if a function's code appears to be a valid insn.
60  *
61  * Revision 1.8  1994/07/06  00:35:44  hollings
62  * Added code to handle SPARC ABI aggregate return type calling convention
63  * of using the instruction after the call's delay slot to indicate aggregate
64  * size.  We treat this as an extra delay slot and relocate it to the
65  * base tramp as needed.
66  *
67  * Revision 1.7  1994/07/05  03:26:03  hollings
68  * observed cost model
69  *
70  * Revision 1.6  1994/06/30  18:01:35  jcargill
71  * Fixed MAX_BRANCH definition (offset is in words, not bytes).
72  *
73  * Revision 1.5  1994/06/29  22:37:19  hollings
74  * Changed heap bound brack error to warning if we can reach some of the inst
75  * heap.  The firewall will catch if this is a real error.
76  *
77  * Revision 1.4  1994/06/29  02:52:28  hollings
78  * Added metricDefs-common.{C,h}
79  * Added module level performance data
80  * cleanedup types of inferrior addresses instrumentation defintions
81  * added firewalls for large branch displacements due to text+data over 2meg.
82  * assorted bug fixes.
83  *
84  * Revision 1.3  1994/06/27  18:56:47  hollings
85  * removed printfs.  Now use logLine so it works in the remote case.
86  * added internalMetric class.
87  * added extra paramter to metric info for aggregation.
88  *
89  * Revision 1.2  1994/06/22  01:43:15  markc
90  * Removed warnings.  Changed bcopy in inst-sparc.C to memcpy.  Changed process.C
91  * reference to proc->status to use proc->heap->status.
92  *
93  * Revision 1.1  1994/01/27  20:31:22  hollings
94  * Iinital version of paradynd speaking dynRPC igend protocol.
95  *
96  * Revision 1.11  1993/12/15  21:02:42  hollings
97  * added PVM support.
98  *
99  * Revision 1.10  1993/12/13  19:54:03  hollings
100  * count internal operations and recognize invalid instructions.
101  *
102  * Revision 1.9  1993/10/19  15:27:54  hollings
103  * AST based mini-tramp code generator.
104  *
105  * Revision 1.9  1993/10/19  15:27:54  hollings
106  * AST based mini-tramp code generator.
107  *
108  * Revision 1.8  1993/08/20  21:59:32  hollings
109  * added generateNoOp.
110  *
111  * Revision 1.7  1993/08/17  22:29:59  hollings
112  * corrected definition of call indirect to not include jmp %x (used in case).
113  *
114  * Revision 1.6  1993/08/11  01:54:12  hollings
115  * added predicated cost model
116  *
117  * Revision 1.5  1993/07/13  18:27:37  hollings
118  * changed return insn pattern to check consider any jmp through %i7 as a
119  * return insn.
120  *
121  * Revision 1.4  1993/06/24  16:18:06  hollings
122  * global fixes.
123  *
124  * Revision 1.3  1993/06/22  19:00:01  hollings
125  * global inst state.
126  *
127  * Revision 1.2  1993/06/08  20:14:34  hollings
128  * state prior to bc net ptrace replacement.
129  *
130  * Revision 1.1  1993/03/19  22:45:45  hollings
131  * Initial revision
132  *
133  *
134  */
135
136 extern "C" {
137 #include <stdio.h>
138 #include <sys/ptrace.h>
139 #include <stdlib.h>
140 #include <sys/unistd.h>
141 #include <memory.h>
142 }
143
144 #include "rtinst/h/rtinst.h"
145 #include "symtab.h"
146 #include "process.h"
147 #include "inst.h"
148 #include "instP.h"
149 #include "inst-sparc.h"
150 #include "arch-sparc.h"
151 #include "ast.h"
152 #include "util.h"
153 #include "internalMetrics.h"
154
155 #define perror(a) abort();
156
157 #define FALSE   0
158 #define TRUE    1
159
160 #define ABS(x)          ((x) > 0 ? x : -x)
161 #define MAX_BRANCH      0x1<<23
162 #define MAX_IMM         0x1<<12         /* 11 plus shign == 12 bits */
163
164 extern int errno;
165 extern int insnGenerated;
166 extern int totalMiniTramps;
167
168 #define REG_G5          5
169 #define REG_G6          6
170 #define REG_G7          7
171
172 const char *registerNames[] = { "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
173                                 "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
174                                 "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
175                                 "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7" };
176
177 const char *getStrOp(int op)
178 {
179     switch (op) {
180         case SetCC:     return("set");
181         case ADDop3:    return("add");
182         case ANDop3:    return("and");
183         case ORop3:     return("or");
184         case SUBop3:    return("sub");
185         case SUBop3cc:  return("subcc");
186         case SMULop3:   return("smul");
187         case SDIVop3:   return("sdiv");
188         case XNORop3:   return("xnor");
189         case SAVEop3:   return("save");
190         case RESTOREop3:        return("restore");
191         case JMPLop3:   return("jmpl");
192         default:        return("???");
193     }
194 }
195
196 inline void generateNOOP(instruction *insn)
197 {
198     insn->raw = 0;
199     insn->branch.op = 0;
200     insn->branch.op2 = NOOPop2;
201
202     // logLine("nop\n");
203 }
204
205 inline void generateBranchInsn(instruction *insn, int offset)
206 {
207     if (ABS(offset) > MAX_BRANCH) {
208         logLine("a branch too far\n");
209         abort();
210     }
211
212     insn->raw = 0;
213     insn->branch.op = 0;
214     insn->branch.cond = BAcond;
215     insn->branch.op2 = BICCop2;
216     insn->branch.anneal = TRUE;
217     insn->branch.disp22 = offset >> 2;
218
219     // logLine("ba,a %x\n", offset);
220 }
221
222 inline void genSimpleInsn(instruction *insn, int op, reg rs1, reg rs2, reg rd)
223 {
224     insn->raw = 0;
225     insn->rest.op = RESTop;
226     insn->rest.rd = rd;
227     insn->rest.op3 = op;
228     insn->rest.rs1 = rs1;
229     insn->rest.rs2 = rs2;
230
231     // logLine("%s %%%s,%%%s,%%%s\n", getStrOp(op), registerNames[rs1], 
232     //  registerNames[rs2], registerNames[rd]);
233 }
234
235 inline void genImmInsn(instruction *insn, int op, reg rs1, int immd, reg rd)
236 {
237     insn->raw = 0;
238     insn->resti.op = RESTop;
239     insn->resti.rd = rd;
240     insn->resti.op3 = op;
241     insn->resti.rs1 = rs1;
242     insn->resti.i = 1;
243     insn->resti.simm13 = immd;
244
245     // logLine("%s %%%s,%d,%%%s\n", getStrOp(op), registerNames[rs1], immd,
246     //  registerNames[rd]);
247 }
248
249 inline void genRelOp(instruction *insn, int cond, reg rs1,
250                      reg rs2, reg rd, caddr_t *base)
251 {
252     // cmp rs1, rs2
253     genSimpleInsn(insn, SUBop3cc, rs1, rs2, 0); insn++;
254     // mov 1, rd
255     genImmInsn(insn, ORop3, 0, 1, rd); insn++;
256
257     // b??,a +2
258     insn->branch.op = 0;
259     insn->branch.cond = cond;
260     insn->branch.op2 = BICCop2;
261     insn->branch.anneal = TRUE;
262     insn->branch.disp22 = 2;
263     insn++;
264
265     // clr rd
266     genSimpleInsn(insn, ORop3, 0, 0, rd); insn++;
267     *base += 4 * sizeof(instruction);
268 }
269
270 inline void generateSetHi(instruction *insn, int src1, int dest)
271 {
272     insn->raw = 0;
273     insn->sethi.op = FMT2op;
274     insn->sethi.rd = dest;
275     insn->sethi.op2 = SETHIop2;
276     insn->sethi.imm22 = HIGH(src1);
277
278     // logLine("sethi  %%hi(0x%x), %%%s\n", HIGH(src1)*1024, 
279     //  registerNames[dest]);
280 }
281
282 void defineInstPoint(pdFunction *func, instPoint *point, instruction *code, 
283     int codeIndex, int offset, int delayOK)
284 {
285     point->func = func;
286     point->addr = (codeIndex+offset)<<2;
287     point->originalInstruction = code[codeIndex];
288     point->delaySlotInsn = code[codeIndex+1];
289     point->aggregateInsn = code[codeIndex+2];
290     point->isDelayed = 0;
291     if (IS_DELAYED_INST(code[codeIndex])) {
292          point->isDelayed = 1;
293     }
294     point->inDelaySlot = 0;
295     if (IS_DELAYED_INST(code[codeIndex-1]) && !delayOK) {
296          sprintf(errorLine,"**** inst point %s %s at addr %x in a dely slot\n", 
297              (char*) func->file->fullName, (char*)func->prettyName, point->addr);
298          logLine(errorLine);
299          point->inDelaySlot = 1;
300     }
301 }
302
303 void newCallPoint(pdFunction *func, instruction *code, int codeIndex, int offset)
304 {
305     caddr_t addr;
306     instPoint *point;
307     
308     if (!func->calls) {
309       func->callLimit = 10;
310       func->calls = new instPoint*[func->callLimit];
311     } else if (func->callCount == func->callLimit) {
312       instPoint **newCalls;
313       int i;
314       newCalls = new instPoint*[func->callLimit + 10];
315       for (i=0; i<func->callLimit; i++) {
316         newCalls[i] = func->calls[i];
317       }
318       func->callLimit += 10;
319       func->calls = newCalls;
320     }
321
322     point = new instPoint;
323     defineInstPoint(func, point, code, codeIndex, offset, FALSE);
324
325     /* check to see where we are calling */
326     if (isInsn(code[codeIndex], CALLmask, CALLmatch)) {
327         point->callIndirect = 0;
328         addr = (caddr_t) point->addr + (code[codeIndex].call.disp30 << 2);
329         point->callee = findFunctionByAddr(func->file->exec, addr);
330     } else {
331         point->callIndirect = 1;
332         point->callee = NULL;
333     }
334
335     // check for aggregate type being returned 
336     // this is marked by insn after call's delay solt being an
337     //   invalid insn.  We treat this as an extra delay slot and
338     //   relocate it to base tramps as needed.
339     if (!IS_VALID_INSN(code[codeIndex+2])) {
340         point->callAggregate = 1;
341     }
342
343     func->calls[func->callCount++] = point;
344 }
345
346 StringList<int> funcFrequencyTable;
347
348 void initDefaultPointFrequencyTable()
349 {
350     funcFrequencyTable.add(1, pool.findAndAdd("main"));
351     funcFrequencyTable.add(1, pool.findAndAdd("exit"));
352 }
353
354 /*
355  * Get an etimate of the frequency for the passed instPoint.  
356  *    This is not (always) the same as the function that contains the point.
357  * 
358  *  The function is selected as follows:
359  *
360  *  If the point is an entry or an exit return the function name.
361  *  If the point is a call and the callee can be determined, return the called
362  *     function.
363  *  else return the funcation containing the point.
364  *
365  *  WARNING: This code contins arbitray values for func frequency (both user 
366  *     and system).  This should be refined over time.
367  *
368  * Using 1000 calls sec to be one SD from the mean for most FPSPEC apps.
369  *      -- jkh 6/24/94
370  *
371  */
372 float getPointFrequency(instPoint *point)
373 {
374     int val;
375     pdFunction *func;
376
377     if (point->callee)
378         func = point->callee;
379     else
380         func = point->func;
381
382     val = funcFrequencyTable.find(func->prettyName);
383     if (!val) {
384         if (func->tag & TAG_LIB_FUNC) {
385             return(100);
386         } else {
387             return(250);
388         }
389     }
390     return(val);
391 }
392
393 /*
394  * Given the definition of a function and a pointer to the code for that
395  *   function, find the standard entry/exit points from the function.
396  *
397  * WARNING: This code is highly machine dependent it looks as SPARC executables
398  *   and finds selected instructions!
399  *
400  */
401 void locateInstPoints(pdFunction *func, void *codeV, int offset, int calls)
402 {
403     int done;
404     int codeIndex;
405     instruction *code = (instruction *) codeV;
406
407     codeIndex = ((unsigned int) (func->addr-offset))/sizeof(instruction);
408     offset /= sizeof(instruction);
409     if (!IS_VALID_INSN(code[codeIndex])) {
410         func->tag |= TAG_NON_FUNC;
411         // comment out warning since all gobal const have this property.
412         // jkh 10/17/94
413         // sprintf (errorLine, "Func '%s', code %x is not a valid insn\n", 
414                  // (char*)func->prettyName, (code[codeIndex]).raw);
415         // logLine (errorLine);
416         func->funcEntry = NULL;
417         func->funcReturn = NULL;
418         return;
419     }
420     func->funcEntry = new instPoint;
421     defineInstPoint(func, func->funcEntry, code,codeIndex,offset,TRUE);
422     done = 0;
423     while (!done) {
424         if (isInsn(code[codeIndex],RETmask, RETmatch) || 
425             isInsn(code[codeIndex],RETLmask, RETLmatch)) {
426             done = 1;
427             func->funcReturn = new instPoint;
428             defineInstPoint(func, func->funcReturn, code, codeIndex, 
429                 offset,FALSE);
430             if ((code[codeIndex].resti.simm13 != 8) &&
431                 (code[codeIndex].resti.simm13 != 12)) {
432                 logLine("*** FATAL Error:");
433                 sprintf(errorLine, " unsupported return at %x\n", 
434                     func->funcReturn->addr);
435                 logLine(errorLine);
436                 abort();
437             }
438         } else if (isInsn(code[codeIndex], CALLmask, CALLmatch) ||
439                    isInsn(code[codeIndex], CALLImask, CALLImatch)) {
440             if (calls) {
441                 newCallPoint(func, code, codeIndex, offset);
442
443             }
444         }
445         codeIndex++;
446     }
447 }
448
449 Boolean locateAllInstPoints(image *i)
450 {
451     int curr;
452     pdFunction *func;
453     int instHeapEnd;
454
455
456     instHeapEnd = (int) findInternalAddress(i, GLOBAL_HEAP_BASE, True);
457     
458     curr = (int) findInternalAddress(i, INFERRIOR_HEAP_BASE, True);
459     if (curr > instHeapEnd) instHeapEnd = curr;
460
461     // check that we can get to our heap.
462     if (instHeapEnd > MAX_BRANCH) {
463         logLine("*** FATAL ERROR: Program text + data too big for dyninst\n");
464         sprintf(errorLine, "    heap ends at %x\n", instHeapEnd);
465         logLine(errorLine);
466         return(FALSE);
467     } else if (instHeapEnd + SYN_INST_BUF_SIZE > MAX_BRANCH) {
468         logLine("WARNING: Program text + data could be too big for dyninst\n");
469     }
470
471 //
472 // always scan ALL functions, library or not to identify
473 // valid code points and stuff
474 //
475 // these functions may not be reported to paradyn nor instrumented
476 // otherwise
477 //
478
479     for (func=i->funcs; func; func=func->next) {
480 //      if (!(func->tag & TAG_LIB_FUNC)) {
481 //          if (func->line) {
482 //              sprintf(errorLine, "inst %s line %d:%s\n", func->file->fileName, 
483 //                     func->line, func->prettyName);
484 //              logLine (errorLine);
485 //          }
486             locateInstPoints(func, (instruction *) i->code, i->textOffset,TRUE);
487 #ifdef notdef
488             if (!func->funcEntry && !func->funcReturn) {
489                 sprintf(errorLine, "could not find entry and exit for this function\n");
490                 logLine(errorLine);
491             }
492 #endif
493 //      }
494 //      else {
495 //          sprintf(errorLine, "ignoring library function: %s %d %s\n",
496 //              func->file->fileName, func->line, func->prettyName);
497 //          logLine(errorLine);
498 //      }
499     }
500     return(TRUE);
501 }
502
503
504
505 /*
506  * Given and instruction, relocate it to a new address, patching up
507  *   any relitive addressing that is present.
508  *
509  */
510 void relocateInstruction(instruction *insn, int origAddr, int targetAddr)
511 {
512     int newOffset;
513
514     if (isInsn(*insn, CALLmask, CALLmatch)) {
515         newOffset = origAddr  - targetAddr + (insn->call.disp30 << 2);
516         insn->call.disp30 = newOffset >> 2;
517     } else if isInsn(*insn, BRNCHmask, BRNCHmatch) {
518         newOffset = origAddr - targetAddr + (insn->branch.disp22 << 2);
519         if (ABS(newOffset) > MAX_BRANCH) {
520             logLine("a branch too far\n");
521             abort();
522         } else {
523             insn->branch.disp22 = newOffset >> 2;
524         }
525     } else if isInsn(*insn, TRAPmask, TRAPmatch) {
526         logLine("attempt to relocate trap\n");
527         abort();
528     } 
529     /* The rest of the instructions should be fine as is */
530 }
531
532 trampTemplate baseTemplate;
533 trampTemplate noArgsTemplate;
534 trampTemplate withArgsTemplate;
535
536 extern "C" void baseTramp();
537 extern "C" void noArgsTramp();
538 extern "C" void withArgsTramp();
539
540 void initATramp(trampTemplate *thisTemp, instruction *tramp)
541 {
542     instruction *temp;
543
544     thisTemp->trampTemp = (void *) tramp;
545     for (temp = tramp; temp->raw != END_TRAMP; temp++) {
546         switch (temp->raw) {
547             case LOCAL_PRE_BRANCH:
548                 thisTemp->localPreOffset = ((void *)temp - (void *)tramp);
549                 break;
550             case GLOBAL_PRE_BRANCH:
551                 thisTemp->globalPreOffset = ((void *)temp - (void *)tramp);
552                 break;
553             case LOCAL_POST_BRANCH:
554                 thisTemp->localPostOffset = ((void *)temp - (void *)tramp);
555                 break;
556             case GLOBAL_POST_BRANCH:
557                 thisTemp->globalPostOffset = ((void *)temp - (void *)tramp);
558                 break;
559         }       
560     }
561     thisTemp->size = (int) temp - (int) tramp;
562 }
563
564 registerSpace *regSpace;
565 int regList[] = {16, 17, 18, 19, 20, 21, 22, 23 };
566
567 void initTramps()
568 {
569     static Boolean inited;
570
571     if (inited) return;
572     inited = True;
573
574     initATramp(&baseTemplate, (instruction *) baseTramp);
575
576     regSpace = new registerSpace(sizeof(regList)/sizeof(int), regList);
577 }
578
579 /*
580  * Install a base tramp -- fill calls with nop's for now.
581  *
582  */
583 void installBaseTramp(int baseAddr, 
584                       instPoint *location,
585                       process *proc) 
586 {
587     int currAddr;
588     extern int errno;
589     instruction *code;
590     instruction *temp;
591
592     code = (instruction *) xmalloc(baseTemplate.size);
593     memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
594     // bcopy(baseTemplate.trampTemp, code, baseTemplate.size);
595
596     for (temp = code, currAddr = baseAddr; 
597         (currAddr - baseAddr) < baseTemplate.size;
598         temp++, currAddr += sizeof(instruction)) {
599         if (temp->raw == EMULATE_INSN) {
600             *temp = location->originalInstruction;
601             relocateInstruction(temp, location->addr, currAddr);
602             if (location->isDelayed) {
603                 /* copy delay slot instruction into tramp instance */
604                 *(temp+1) = location->delaySlotInsn;
605             }
606             if (location->callAggregate) {
607                 /* copy invalid insn with aggregate size in it */
608                 *(temp+2) = location->aggregateInsn;
609             }
610         } else if (temp->raw == RETURN_INSN) {
611             generateBranchInsn(temp, 
612                 (location->addr+sizeof(instruction) - currAddr));
613             if (location->isDelayed) {
614                 /* skip the delay slot instruction */
615                 temp->branch.disp22 += 1;
616             }
617             if (location->callAggregate) {
618                 /* skip the aggregate size slot */
619                 temp->branch.disp22 += 1;
620             }
621         } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
622                    (temp->raw == GLOBAL_PRE_BRANCH) ||
623                    (temp->raw == LOCAL_POST_BRANCH) ||
624                    (temp->raw == GLOBAL_POST_BRANCH)) {
625             /* fill with no-op */
626             generateNOOP(temp);
627         }
628     }
629
630     errno = 0;
631     (void) PCptrace(PTRACE_WRITEDATA, proc, (void*)baseAddr, 
632         baseTemplate.size, (void*) code);
633     if (errno) {
634         perror("data PCptrace");
635     }
636
637     free(code);
638 }
639
640 void generateNoOp(process *proc, int addr)
641 {
642     instruction insn;
643
644     /* fill with no-op */
645     insn.raw = 0;
646     insn.branch.op = 0;
647     insn.branch.op2 = NOOPop2;
648
649     (void) PCptrace(PTRACE_POKETEXT, proc, (void*) addr, insn.raw, NULL);
650 }
651
652
653 void *findAndInstallBaseTramp(process *proc, instPoint *location)
654 {
655     void *ret;
656     process *globalProc;
657     extern process *nodePseudoProcess;
658
659     if (nodePseudoProcess && (proc->symbols == nodePseudoProcess->symbols)){
660         globalProc = nodePseudoProcess;
661         // logLine("findAndInstallBaseTramp global\n");
662     } else {
663         globalProc = proc;
664     }
665     ret = globalProc->baseMap.find((void *) location);
666     if (!ret) {
667         ret = (void *) inferriorMalloc(globalProc, baseTemplate.size);
668         installBaseTramp((int) ret, location, globalProc);
669         generateBranch(globalProc, location->addr, (int) ret);
670         globalProc->baseMap.add(ret, location);
671     }
672     return(ret);
673 }
674
675 /*
676  * Install a single tramp.
677  *
678  */
679 void installTramp(instInstance *inst, char *code, int codeSize) 
680 {
681     totalMiniTramps++;
682     insnGenerated += codeSize/sizeof(int);
683
684     errno = 0;
685     (void) PCptrace(PTRACE_WRITEDATA, inst->proc, (void*)inst->trampBase, 
686         codeSize, (char *) code);
687     if (errno) {
688         perror("data PCptrace");
689     }
690 }
691
692 /*
693  * change the insn at addr to be a branch to newAddr.
694  *   Used to add multiple tramps to a point.
695  */
696 void generateBranch(process *proc, int fromAddr, int newAddr)
697 {
698     int disp;
699     instruction insn;
700
701     disp = newAddr-fromAddr;
702     generateBranchInsn(&insn, disp);
703
704     errno = 0;
705     (void) PCptrace(PTRACE_POKETEXT, proc, (void*) fromAddr, 
706         insn.raw, NULL);
707     if (errno) {
708         perror("PCptrace");
709     }
710 }
711
712 int callsTrackedFuncP(instPoint *point)
713 {
714     if (point->callIndirect) {
715 #ifdef notdef
716         // it's rare to call a library function as a parameter.
717         sprintf(errorLine, "*** Warning call indirect\n from %s %s (addr %d)\n",
718             point->func->file->fullName, point->func->prettyName, point->addr);
719         logLine(errorLine);
720 #endif
721         return(TRUE);
722     } else {
723         if (point->callee && !(point->callee->tag & TAG_LIB_FUNC)) {
724             return(TRUE);
725         } else {
726             return(FALSE);
727         }
728     }
729 }
730
731 /*
732  * return the function asociated with a point.
733  *
734  *     If the point is a funcation call, and we know the function being called,
735  *          then we use that.  Otherwise it is the function that contains the
736  *          point.
737  *  
738  *   This is done to return a better idea of which function we are using.
739  */
740 pdFunction *getFunction(instPoint *point)
741 {
742     return(point->callee ? point->callee : point->func);
743 }
744
745 caddr_t emit(opCode op, reg src1, reg src2, reg dest, char *i, caddr_t *base)
746 {
747     instruction *insn = (instruction *) &i[(unsigned) *base];
748
749     if (op == loadConstOp) {
750         if (ABS(src1) > MAX_IMM) {
751             generateSetHi(insn, src1, dest);
752             *base += sizeof(instruction);
753             insn++;
754
755             // or regd,imm,regd
756             genImmInsn(insn, ORop3, dest, LOW(src1), dest);
757             *base += sizeof(instruction);
758         } else {
759             // really or %g0,imm,regd
760             genImmInsn(insn, ORop3, 0, LOW(src1), dest);
761             *base += sizeof(instruction);
762         }
763     } else if (op ==  loadOp) {
764         generateSetHi(insn, src1, dest);
765         insn++;
766
767         insn->resti.op = LOADop;
768         insn->resti.op3 = LDop3;
769         insn->resti.rd = dest;
770         insn->resti.rs1 = dest;
771         insn->resti.i = 1;
772         insn->resti.simm13 = LOW(src1);
773
774         *base += sizeof(instruction)*2;
775     } else if (op ==  storeOp) {
776         insn->sethi.op = FMT2op;
777         insn->sethi.rd = src2;
778         insn->sethi.op2 = SETHIop2;
779         insn->sethi.imm22 = HIGH(dest);
780         insn++;
781
782         insn->resti.op = STop;
783         insn->resti.rd = src1;
784         insn->resti.op3 = STop3;
785         insn->resti.rs1 = src2;
786         insn->resti.i = 1;
787         insn->resti.simm13 = LOW(dest);
788
789         *base += sizeof(instruction)*2;
790     } else if (op ==  ifOp) {
791         // cmp src1,0
792         genSimpleInsn(insn, SUBop3cc, src1, 0, 0); insn++;
793
794         insn->branch.op = 0;
795         insn->branch.cond = BEcond;
796         insn->branch.op2 = BICCop2;
797         insn->branch.anneal = FALSE;
798         insn->branch.disp22 = dest/4;
799         insn++;
800
801         generateNOOP(insn);
802         *base += sizeof(instruction)*3;
803         return(*base - 2*sizeof(instruction));
804     } else if (op ==  callOp) {
805         if (src1 > 0) {
806             genSimpleInsn(insn, ORop3, 0, src1, 8); insn++;
807             *base += sizeof(instruction);
808         }
809         if (src2 > 0) {
810             genSimpleInsn(insn, ORop3, 0, src2, 9); insn++;
811             *base += sizeof(instruction);
812         }
813         /* ??? - should really set up correct # of args */
814         // clr i2
815         genSimpleInsn(insn, ORop3, 0, 0, 10); insn++;
816         *base += sizeof(instruction);
817
818         // clr i3
819         genSimpleInsn(insn, ORop3, 0, 0, 11); insn++;
820         *base += sizeof(instruction);
821
822
823         generateSetHi(insn, dest, 13); insn++;
824         genImmInsn(insn, JMPLop3, 13, LOW(dest), 15); insn++;
825         generateNOOP(insn);
826
827         *base += 3 * sizeof(instruction);
828     } else if (op ==  trampPreamble) {
829         genImmInsn(insn, SAVEop3, 14, -112, 14);
830         insn++;
831
832         // generate code to update the observed cost register.
833         // SPARC ABI reserved register %g7
834         // add %g7, <cost>, %g7
835         genImmInsn(insn, ADDop3, REG_G7, src1, REG_G7);
836
837         *base += 2 * sizeof(instruction);
838     } else if (op ==  trampTrailer) {
839         genSimpleInsn(insn, RESTOREop3, 0, 0, 0); insn++;
840
841         generateNOOP(insn);
842         insn++;
843
844         // dest is in words of offset and generateBranchInsn is bytes offset
845         generateBranchInsn(insn, dest << 2);
846
847         *base += sizeof(instruction) * 3;
848         return(*base -  sizeof(instruction));
849     } else if (op == noOp) {
850         generateNOOP(insn);
851         *base += sizeof(instruction);
852     } else {
853       int op3;
854         switch (op) {
855             // integer ops
856             case plusOp:
857                 op3 = ADDop3;
858                 break;
859
860             case minusOp:
861                 op3 = SUBop3;
862                 break;
863
864             case timesOp:
865                 op3 = SMULop3;
866                 break;
867
868             case divOp:
869                 op3 = SDIVop3;
870                 break;
871
872             // Bool ops
873             case orOp:
874                 op3 = ORop3;
875                 break;
876
877             case andOp:
878                 op3 = ANDop3;
879                 break;
880
881             // rel ops
882             case eqOp:
883                 genRelOp(insn, BNEcond, src1, src2, dest, base);
884                 return(0);
885                 break;
886
887             case neOp:
888                 genRelOp(insn, BEcond, src1, src2, dest, base);
889                 return(0);
890                 break;
891
892             case lessOp:
893             case greaterOp:
894             case leOp:
895             case geOp:
896                 abort();
897                 break;
898             
899             default:
900                 abort();
901                 break;
902         }
903         genSimpleInsn(insn, op3, src1, src2, dest);
904
905         *base += sizeof(instruction);
906       }
907     return(0);
908 }
909
910 //
911 // move the passed parameter into the passed register, or if it is already
912 //    in a register return the register number.
913 //
914 reg getParameter(reg dest, int param)
915 {
916     if (param <= 8) {
917         return(24+param);
918     }
919     abort();
920     return(-1);
921 }
922
923 //
924 // All values based on Cypress0 && Cypress1 implementations as documented in
925 //   SPARC v.8 manual p. 291
926 //
927 int getInsnCost(opCode op)
928 {
929     if (op == loadConstOp) {
930         return(2);
931     } else if (op ==  loadOp) {
932         // sethi + load single
933         return(1+2);
934     } else if (op ==  storeOp) {
935         // sethi + store single
936         return(1+3);
937     } else if (op ==  ifOp) {
938         // subcc
939         // be
940         // nop
941         return(1+1+1);
942     } else if (op ==  callOp) {
943         int count = 0;
944
945         // mov src1, %o0
946         count += 1;
947
948         // mov src2, %o1
949         count += 1;
950
951         // clr i2
952         count += 1;
953
954         // clr i3
955         count += 1;
956
957         // sethi
958         count += 1;
959
960         // jmpl
961         count += 2;
962
963         // noop
964         count += 1;
965
966         return(count);
967     } else if (op ==  trampPreamble) {
968         // save %o6, -112, %o6
969         // add %g7, <cost>, %g7
970         return(2);
971     } else if (op ==  trampTrailer) {
972         // restore
973         // noop
974         // retl
975         return(1+1+2);
976     } else if (op == noOp) {
977         // noop
978         return(1);
979     } else {
980         switch (op) {
981             // rel ops
982             case eqOp:
983             case neOp:
984                 // bne -- assume taken
985                 return(3);
986                 break;
987
988             case lessOp:
989             case greaterOp:
990             case leOp:
991             case geOp:
992                 abort();
993                 return(-1);
994                 break;
995             
996             default:
997                 return(1);
998                 break;
999         }
1000     }
1001 }
1002
1003
1004
1005 /************************************************************************
1006  * void restore_original_instructions(process* p, instPoint* ip)
1007 ************************************************************************/
1008
1009 void
1010 restore_original_instructions(process* p, instPoint* ip) {
1011     int addr = ip->addr;
1012
1013     PCptrace(PTRACE_POKETEXT, p, (void*) addr,
1014         ip->originalInstruction.raw, 0);
1015     addr += sizeof(instruction);
1016
1017     if (ip->isDelayed) {
1018         PCptrace(PTRACE_POKETEXT, p, (void*) addr,
1019             ip->delaySlotInsn.raw, 0);
1020         addr += sizeof(instruction);
1021     }
1022
1023     if (ip->callAggregate) {
1024         PCptrace(PTRACE_POKETEXT, p, (void*) addr,
1025             ip->aggregateInsn.raw, 0);
1026         addr += sizeof(instruction);
1027     }
1028
1029     return;
1030 }