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