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