Implementing rel operators <,<=,>,>= for the hp - naim
[dyninst.git] / dyninstAPI / src / inst-hppa.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/Attic/inst-hppa.C,v 1.4 1995/12/21 16:43:09 naim Exp $";
23 #endif
24
25 /*
26  * inst-hppa.C - Identify instrumentation points for PA-RISC processors.
27  *
28  * $Log: inst-hppa.C,v $
29  * Revision 1.4  1995/12/21 16:43:09  naim
30  * Implementing rel operators <,<=,>,>= for the hp - naim
31  *
32  * Revision 1.3  1995/12/19  01:04:46  hollings
33  * Moved the implementation of registerSpace::readOnlyRegister to processor
34  *   specific files (since it is).
35  * Fixed a bug in Power relOps cases.
36  *
37  * Revision 1.2  1995/11/30  15:13:40  krisna
38  * added call to matherr in main.C
39  * added code templates for callOp in inst-hppa.C
40  *
41  * Revision 1.1  1995/11/29 18:47:46  krisna
42  * hpux/hppa instrumentation code
43  *
44  */
45
46 #include "util/h/headers.h"
47
48 #include "rtinst/h/rtinst.h"
49 #include "symtab.h"
50 #include "process.h"
51 #include "inst.h"
52 #include "instP.h"
53 #include "inst-hppa.h"
54 #include "arch-hppa.h"
55 #include "ast.h"
56 #include "util.h"
57 #include "internalMetrics.h"
58 #include "stats.h"
59 #include "os.h"
60 #include "showerror.h"
61
62 #define perror(a) P_abort();
63
64 #define ABS(x)          ((x) > 0 ? x : -x)
65 #define MAX_BRANCH      ((0x1<<18)+8) /* 17-signed bits, lshift by 2, +8 */
66
67 unsigned getMaxBranch() {
68   return MAX_BRANCH;
69 }
70
71 const char *registerNames[] =
72     { "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
73       "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
74       "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
75       "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" };
76
77 dictionary_hash<string, unsigned> funcFrequencyTable(string::hash);
78
79 /* not called at all, why is this here
80 string getStrOp(int op)
81 {
82     switch (op) {
83         case ADDop:     return("add");
84         case ANDop:     return("and");
85         case BLop:      return("bl");
86         case COMBTop:   return("combt");
87         case LDILop:    return("ldil");
88         case LDOop:     return("ldo");
89         case LDWop:     return("ldw");
90         case ORop:      return("or");
91         case STWop:     return("stw");
92         case SUBop:     return("sub");
93
94         default:        return("???");
95     }
96 }
97 */
98
99 inline int w_w1_w2_to_offset(unsigned w, unsigned w1, unsigned w2) {
100     assemble_w_w1_w2 x;
101     x.raw = (w == 0) ? (0) : (~0); // sign extend the offset
102
103     x.w_w1_w2.w = w;
104     x.w_w1_w2.w1 = w1;
105     x.w_w1_w2.w2 = w2;
106
107     return ((x.raw << 2) + 8);
108 }
109
110 inline assemble_w_w1_w2 offset_to_w_w1_w2(int offset) {
111     if (ABS(offset) > MAX_BRANCH) {
112         logLine("a branch too far\n");
113         showErrorCallback(52, "");
114         abort();
115     }
116
117     offset -= 8;  /* 8 always added to branch */
118     offset >>= 2; /* undo lshift */
119
120     assemble_w_w1_w2 ret;
121     ret.raw = offset;
122     return ret;
123 }
124
125 inline void generateBranchInsn(instruction *insn, int offset, reg lr = 0)
126 {
127     assemble_w_w1_w2 x = offset_to_w_w1_w2(offset);
128
129     insn->raw = 0;
130     insn->bi.op = BLop;
131     insn->bi.r2_p_b_t = lr;
132     insn->bi.r1_im5_w1_x = x.w_w1_w2.w1;
133     insn->bi.c_s_ext3 = BLext;
134     insn->bi.w1_w2 = x.w_w1_w2.w2;
135     insn->bi.n = 1;
136     insn->bi.w = x.w_w1_w2.w;
137
138     // logLine("ba,a %x\n", offset);
139 }
140
141 inline void generateCompareBranch(instruction* insn, reg rs1, reg rs2,
142   int offset) {
143     offset -= 8; /* 8 always added to branch */
144     offset >>= 2; /* undo the lshift of assembly */
145     unsigned w = (offset % 2); /* pull out the w1,w bits */
146     unsigned w1 = offset >> 1;
147
148     insn->raw = 0;
149     insn->bi.op = COMBTop;
150     insn->bi.r2_p_b_t = rs2;
151     insn->bi.r1_im5_w1_x = rs1;
152     insn->bi.c_s_ext3 = COMCLR_EQ_C;
153     insn->bi.w1_w2 = w1;
154     insn->bi.n = 0;
155     insn->bi.w = w;
156 }
157
158 inline void genArithLogInsn(instruction *insn, unsigned op, unsigned ext7,
159     reg rs1, reg rs2, reg rd)
160 {
161     insn->raw = 0;
162     insn->ci.al.op = op;
163     insn->ci.al.r2 = rs2;
164     insn->ci.al.r1 = rs1;
165     insn->ci.al.ext7 = ext7;
166     insn->ci.al.t = rd;
167
168     // logLine("%s %%%s,%%%s,%%%s\n", getStrOp(op), registerNames[rs1],
169     //  registerNames[rs2], registerNames[rd]);
170 }
171
172 inline void generateNOOP(instruction *insn)
173 {
174     // or 0,0,0
175     genArithLogInsn(insn, ORop, ORext7, 0, 0, 0);
176
177     // logLine("nop\n");
178 }
179
180 inline void genCmpOp(instruction *insn, unsigned cond, unsigned flow,
181     reg rs1, reg rs2, reg rd)
182 {
183     insn->raw = 0;
184     insn->ci.al.op = COMCLRop;
185     insn->ci.al.r2 = rs2;
186     insn->ci.al.r1 = rs1;
187     insn->ci.al.c = cond;
188     insn->ci.al.f = flow;
189     insn->ci.al.ext7 = COMCLRext7;
190     insn->ci.al.t = rd;
191 }
192
193 inline void generateLoadConst(instruction *insn, int src1, int dest,
194   unsigned& base) {
195       const unsigned MAX_IMM21 = 0x1fffff;
196       if (ABS(src1) > MAX_IMM21) {
197         insn->raw = 0;
198         insn->li.op = LDILop;
199         insn->li.tr = dest;
200         insn->li.im21 = ((src1 >> 11) & 0x1fffff);
201         insn++;
202
203         insn->raw = 0;
204         insn->mr.ls.op = LDOop;
205         insn->mr.ls.b = dest;
206         insn->mr.ls.tr = dest;
207         insn->mr.ls.s = 0;
208         insn->mr.ls.im14 = src1 & 0x7ff;
209
210         base += 2*sizeof(instruction);
211       }
212       else {
213         insn->raw = 0;
214         insn->mr.ls.op = LDOop;
215         insn->mr.ls.b = 0;
216         insn->mr.ls.tr = dest;
217         insn->mr.ls.s = 0;
218         insn->mr.ls.im14 = src1 & 0x7ff;
219
220         base += sizeof(instruction);
221       }
222 }
223
224 inline void generateLoad(instruction *insn, reg src, reg dest)
225 {
226     insn->raw = 0;
227     insn->mr.ls.op = LDWop;
228     insn->mr.ls.b = src;
229     insn->mr.ls.tr = dest;
230     insn->mr.ls.s = 0;
231     insn->mr.ls.im14 = 0;
232 }
233
234 inline void generateStore(instruction *insn, int rd, int rs1, int im14 = 0)
235 {
236     insn->raw = 0;
237     insn->mr.ls.op = STWop;
238     insn->mr.ls.b = rs1;
239     insn->mr.ls.tr = rd;
240     insn->mr.ls.s = 0;
241     insn->mr.ls.im14 = im14;
242 }
243
244 instPoint::instPoint(pdFunction *f, const instruction &instr,
245                      const image *owner, Address adr,
246                      bool delayOK)
247 : addr(adr), originalInstruction(instr), inDelaySlot(false), isDelayed(false),
248   callIndirect(false), callAggregate(false), callee(NULL), func(f)
249 {
250   // why is the following code not in power
251
252   delaySlotInsn.raw = owner->get_instruction(adr+4);
253   aggregateInsn.raw = owner->get_instruction(adr+8);
254
255   if (IS_DELAYED_INST(instr))
256     isDelayed = true;
257
258   if (owner->isValidAddress(adr-4)) {
259     instruction iplus1;
260     iplus1.raw = owner->get_instruction(adr-4);
261     if (IS_DELAYED_INST(iplus1) && !delayOK) {
262       // ostrstream os(errorLine, 1024, ios::out);
263       // os << "** inst point " << func->file->fullName << "/"
264       //  << func->prettyName() << " at addr " << addr <<
265       //        " in a delay slot\n";
266       // logLine(errorLine);
267       inDelaySlot = true;
268     }
269   }
270 }
271
272 // Determine if the called function is a "library" function or a "user" function
273 // This cannot be done until all of the functions have been seen, verified, and
274 // classified
275 //
276 void pdFunction::checkCallPoints() {
277   int i;
278   instPoint *p;
279   Address loc_addr;
280
281   vector<instPoint*> non_lib;
282
283   for (i=0; i<calls.size(); ++i) {
284     /* check to see where we are calling */
285     p = calls[i];
286     assert(p);
287
288     if (!isCallInsn(p->originalInstruction)) {
289         logLine("what is a non-call (jump) doing in set of calls\n");
290         continue;
291     }
292
293     if (isInsnType(p->originalInstruction, CALLmask, CALLmatch)) {
294       // Direct call
295       int offset = w_w1_w2_to_offset(p->originalInstruction.bi.w,
296                 p->originalInstruction.bi.r1_im5_w1_x,
297                 p->originalInstruction.bi.w1_w2);
298       loc_addr = p->addr + offset;
299       pdFunction *pdf = (file_->exec())->findFunction(loc_addr);
300       if (pdf && !pdf->isLibTag()) {
301         p->callee = pdf;
302         non_lib += p;
303       } else {
304         delete p;
305       }
306     } else {
307       // Indirect call -- be conservative, assume it is a call to
308       // an unnamed user function
309       assert(!p->callee); assert(p->callIndirect);
310       p->callee = NULL;
311       non_lib += p;
312     }
313   }
314   calls = non_lib;
315 }
316
317 // TODO we cannot find the called function by address at this point in time
318 // because the called function may not have been seen.
319 //
320 Address pdFunction::newCallPoint(const Address adr, const instruction instr,
321                                  const image *owner, bool &err)
322 {
323     Address ret=adr;
324     instPoint *point;
325     bool err = true;
326
327     point = new instPoint(this, instr, owner, adr, false);
328
329     if (!isCallInsn(instr)) {
330         logLine("what is a non-call (jump) doing in newCallPoint\n");
331         assert(0);
332     }
333
334     if (!isInsnType(instr, CALLmask, CALLmatch)) {
335       point->callIndirect = true;
336       point->callee = NULL;
337     } else
338       point->callIndirect = false;
339
340     point->callAggregate = false;
341
342     calls += point;
343     err = false;
344     return ret;
345 }
346
347 void initDefaultPointFrequencyTable()
348 {
349     funcFrequencyTable[EXIT_NAME] = 1;
350
351 #ifdef notdef
352     FILE *fp;
353     float value;
354     char name[512];
355
356     funcFrequencyTable["main"] = 1;
357     funcFrequencyTable["DYNINSTsampleValues"] = 1;
358     // try to read file.
359     fp = fopen("freq.input", "r");
360     if (!fp) {
361         return;
362     } else {
363         printf("found freq.input file\n");
364     }
365     while (!feof(fp)) {
366         fscanf(fp, "%s %f\n", name, &value);
367         funcFrequencyTable[name] = (int) value;
368         printf("adding %s %f\n", name, value);
369     }
370     fclose(fp);
371 #endif
372 }
373
374 /*
375  * Get an etimate of the frequency for the passed instPoint.
376  *    This is not (always) the same as the function that contains the point.
377  *
378  *  The function is selected as follows:
379  *
380  *  If the point is an entry or an exit return the function name.
381  *  If the point is a call and the callee can be determined, return the called
382  *     function.
383  *  else return the funcation containing the point.
384  *
385  *  WARNING: This code contins arbitray values for func frequency (both user
386  *     and system).  This should be refined over time.
387  *
388  * Using 1000 calls sec to be one SD from the mean for most FPSPEC apps.
389  *      -- jkh 6/24/94
390  *
391  */
392 float getPointFrequency(instPoint *point)
393 {
394
395     pdFunction *func;
396
397     if (point->callee)
398         func = point->callee;
399     else
400         func = point->func;
401
402     if (!funcFrequencyTable.defines(func->prettyName())) {
403       if (func->isLibTag()) {
404         return(100);
405       } else {
406         return(250);
407       }
408     } else {
409       return (funcFrequencyTable[func->prettyName()]);
410     }
411 }
412
413 //
414 // return cost in cycles of executing at this point.  This is the cost
415 //   of the base tramp if it is the first at this point or 0 otherwise.
416 //
417 int getPointCost(process *proc, instPoint *point)
418 {
419     if (proc->baseMap.defines(point)) {
420         return(0);
421     } else {
422         // 8 cycles for base tramp
423         return(8);
424     }
425 }
426
427 /*
428  * Given and instruction, relocate it to a new address, patching up
429  *   any relative addressing that is present.
430  *
431  * There are 6 types of unconditional branches
432  * and 8 types of conditional branches on the PA-RISC.
433  *
434  * Most of the unconditional branches are base/index relative
435  * and cannot (need not?) be relocated.  However, most of the
436  * conditional branches can be relocated since they are PC relative.
437  *
438  * The simple solution is that for the instrumentation points we
439  * can handle (procedure entry, procedure exit, and procedure
440  * call), only certain types of branches can occur.  If anything
441  * else occurs in these places, the compiler is screwed.
442  *
443  */
444 void relocateInstruction(instruction *insn, int origAddr, int targetAddr)
445 {
446     int newOffset;
447
448     // make sure that GATE, BE, BLE are not allowed
449     if ((isInsnType(*insn, GATEmask, GATEmatch))
450         || (isInsnType(*insn, BEmask, BEmatch))
451         || (isInsnType(*insn, BLEmask, BLEmatch))) {
452         logLine("one of GATE, BE, BLE instruction called\n");
453         abort();
454     }
455     else if (isInsnType(*insn, CALLmask, CALLmatch)) {
456       int oldOffset = w_w1_w2_to_offset(insn->bi.w,
457                         insn->bi.r1_im5_w1_x,
458                         insn->bi.w1_w2);
459       newOffset = origAddr  - targetAddr + oldOffset;
460       assemble_w_w1_w2 x = offset_to_w_w1_w2(newOffset);
461       insn->bi.w = x.w_w1_w2.w;
462       insn->bi.r1_im5_w1_x = x.w_w1_w2.w1;
463       insn->bi.w1_w2 = x.w_w1_w2.w2;
464     }
465
466     /* The rest of the instructions should be fine as is */
467 }
468
469 trampTemplate baseTemplate;
470
471 extern "C" void baseTramp();
472
473 void initATramp(trampTemplate *thisTemp, instruction *tramp)
474 {
475     instruction *temp;
476
477     // TODO - are these offset always positive?
478     thisTemp->trampTemp = (void *) tramp;
479     for (temp = tramp; temp->raw != END_TRAMP; temp++) {
480         switch (temp->raw) {
481             case LOCAL_PRE_BRANCH:
482                 thisTemp->localPreOffset = ((void*)temp - (void*)tramp);
483                 break;
484             case GLOBAL_PRE_BRANCH:
485                 thisTemp->globalPreOffset = ((void*)temp - (void*)tramp);
486                 break;
487             case LOCAL_POST_BRANCH:
488                 thisTemp->localPostOffset = ((void*)temp - (void*)tramp);
489                 break;
490             case GLOBAL_POST_BRANCH:
491                 thisTemp->globalPostOffset = ((void*)temp - (void*)tramp);
492                 break;
493         }
494     }
495     thisTemp->size = (int) temp - (int) tramp;
496 }
497
498 registerSpace *regSpace;
499
500 // return values come via r28, r29; these should be dead at call point
501 int deadRegList[] = { 28, 29 };
502
503 // r26, r25, r24, r23 are call arguments (in that order)
504 int liveRegList[] = { 1, 19, 20, 21, 22, 23, 24, 31, 26, 25 };
505     // all are caller save registers
506
507 void initTramps()
508 {
509     static bool inited=false;
510
511     if (inited) return;
512     inited = true;
513
514     initATramp(&baseTemplate, (instruction *) baseTramp);
515
516     regSpace = new registerSpace(sizeof(deadRegList)/sizeof(int), deadRegList,
517         sizeof(liveRegList)/sizeof(int), liveRegList);
518 }
519
520 /*
521  * Install a base tramp -- fill calls with nop's for now.
522  *
523  */
524 void installBaseTramp(unsigned baseAddr,
525                       instPoint *location,
526                       process *proc)
527 {
528     unsigned currAddr;
529     instruction *code;
530     instruction *temp;
531
532     code = new instruction[baseTemplate.size];
533     memcpy((char *) code, (char*) baseTemplate.trampTemp, baseTemplate.size);
534     // bcopy(baseTemplate.trampTemp, code, baseTemplate.size);
535
536     for (temp = code, currAddr = baseAddr;
537         (currAddr - baseAddr) < baseTemplate.size;
538         temp++, currAddr += sizeof(instruction)) {
539         if (temp->raw == EMULATE_INSN) {
540             *temp = location->originalInstruction;
541             relocateInstruction(temp, location->addr, currAddr);
542             if (location->isDelayed) {
543                 /* copy delay slot instruction into tramp instance */
544                 *(temp+1) = location->delaySlotInsn;
545             }
546         } else if (temp->raw == RETURN_INSN) {
547             int disp = location->addr + sizeof(instruction) - currAddr;
548             if (location->isDelayed) {
549                 disp += sizeof(instruction);
550             }
551             generateBranchInsn(temp, disp);
552         } else if ((temp->raw == LOCAL_PRE_BRANCH) ||
553                    (temp->raw == GLOBAL_PRE_BRANCH) ||
554                    (temp->raw == LOCAL_POST_BRANCH) ||
555                    (temp->raw == GLOBAL_POST_BRANCH)) {
556             /* fill with no-op */
557             generateNOOP(temp);
558         }
559     }
560     // TODO cast
561     proc->writeDataSpace((caddr_t)baseAddr, baseTemplate.size, (caddr_t) code);
562
563     free(code);
564 }
565
566 void generateNoOp(process *proc, int addr)
567 {
568     instruction insn;
569
570     generateNOOP(&insn);
571     proc->writeTextWord((caddr_t)addr, insn.raw);
572 }
573
574
575 unsigned findAndInstallBaseTramp(process *proc,
576                                  instPoint *location)
577 {
578     unsigned ret;
579     process *globalProc;
580
581     globalProc = proc;
582     if (!globalProc->baseMap.defines(location)) {
583         ret = inferiorMalloc(globalProc, baseTemplate.size, textHeap);
584         installBaseTramp(ret, location, globalProc);
585         generateBranch(globalProc, location->addr, (int) ret);
586         globalProc->baseMap[location] = ret;
587     } else {
588         ret = globalProc->baseMap[location];
589     }
590
591     return(ret);
592 }
593
594 /*
595  * Install a single tramp.
596  *
597  */
598 void installTramp(instInstance *inst, char *code, int codeSize)
599 {
600     totalMiniTramps++;
601     insnGenerated += codeSize/sizeof(int);
602
603     // TODO cast
604     (inst->proc)->writeDataSpace((caddr_t)inst->trampBase, codeSize, code);
605 }
606
607 /*
608  * change the insn at addr to be a branch to newAddr.
609  *   Used to add multiple tramps to a point.
610  */
611 void generateBranch(process *proc, unsigned fromAddr, unsigned newAddr)
612 {
613     int disp;
614     instruction insn;
615
616     disp = newAddr-fromAddr;
617     generateBranchInsn(&insn, disp);
618
619     // TODO cast
620     proc->writeTextWord((caddr_t)fromAddr, insn.raw);
621 }
622
623 int callsTrackedFuncP(instPoint *point)
624 {
625     if (point->callIndirect) {
626 #ifdef notdef
627         // TODO this won't compile now
628         // it's rare to call a library function as a parameter.
629         sprintf(errorLine, "*** Warning call indirect\n from %s %s (addr %d)\n",
630             point->func->file->fullName, point->func->prettyName, point->addr);
631         logLine(errorLine);
632 #endif
633         return(true);
634     } else {
635         if (point->callee && !(point->callee->isLibTag())) {
636             return(true);
637         } else {
638             return(false);
639         }
640     }
641 }
642
643 /*
644  * return the function asociated with a point.
645  *
646  *     If the point is a funcation call, and we know the function being called,
647  *          then we use that.  Otherwise it is the function that contains the
648  *          point.
649  *
650  *   This is done to return a better idea of which function we are using.
651  */
652 pdFunction *getFunction(instPoint *point)
653 {
654     return(point->callee ? point->callee : point->func);
655 }
656
657 unsigned emit(opCode op, reg src1, reg src2, reg dest, char *i, unsigned &base)
658 {
659     // TODO cast
660     instruction *insn = (instruction *) ((void*)&i[base]);
661
662     if (op == loadConstOp) {
663       generateLoadConst(insn, src1, dest, base);
664     } else if (op ==  loadOp) {
665         generateLoadConst(insn, src1, dest, base);
666         insn = (instruction *) ((void*)&i[base]);
667
668         generateLoad(insn, dest, dest);
669         base += sizeof(instruction);
670     } else if (op ==  storeOp) {
671         generateLoadConst(insn, dest, src2, base);
672         insn = (instruction *) ((void*)&i[base]);
673
674         generateStore(insn, src1, dest);
675         base += sizeof(instruction);
676     } else if (op ==  ifOp) {
677         generateCompareBranch(insn, src1, 0, dest); insn++;
678         generateNOOP(insn);
679         base += sizeof(instruction)*2;
680         return(base - sizeof(instruction)); // whatever this means??
681     } else if (op ==  callOp) {
682         // printf("callOp: src1=%d, src2=%d, dest=%d\n", src1, src2, dest);
683         logLine("cannot generate callOp for now\n");
684         return(28); // return register is %r28
685
686         //
687         // the following assumes that no one has screwed around
688         // with the stack.  if not, chaos.
689         //
690         // stw %r2,  -20(0,%r30)                ; save RP
691         // stw %r26, -??(0,%r30)                ; save r26 (but where)
692         // stw %r25, -??(0,%r30)                ; save r25 (but where)
693         // stw %r22, -??(0,%r30)                ; save r22 (but where)
694         //
695         generateStore(insn, 2, 30, -20); insn++;
696         base += sizeof(instruction);
697
698         // set up %r26 and %r25, arguments
699         if (src1 > 0) {
700             genArithLogInsn(insn, ORop, ORext7, src1, 0, 26); insn++;
701             base += sizeof(instruction);
702         }
703         if (src2 > 0) {
704             genArithLogInsn(insn, ORop, ORext7, src2, 0, 25); insn++;
705             base += sizeof(instruction);
706         }
707
708         // need absolute location of current instruction
709         // to compute offsets
710         //
711         // int offset = dest - currentAddress;
712         // generateBranchLinkInsn(insn, offset, 2); insn++;
713         // generateNOOP(insn); insn++;
714         // base += 2*sizeof(instruction);
715
716         // return value is the register with the return value from the
717         // function. i.e. %r28
718         // return(28);
719
720     } else if (op ==  trampPreamble) {
721         // generate code to update observed cost, but we have no cost model
722
723     } else if (op ==  trampTrailer) {
724         // restore any saved registers, but we never save them
725         // dest is in words of offset and generateBranchInsn is bytes offset
726         generateBranchInsn(insn, dest << 2);
727         base += sizeof(instruction);
728         insn++;
729
730         generateNOOP(insn);
731         insn++;
732         base += sizeof(instruction);
733
734         return(base -  2 * sizeof(instruction));
735
736     } else if (op == noOp) {
737         generateNOOP(insn);
738         base += sizeof(instruction);
739
740     } else if (op == getParamOp) {
741         // first 4 params are in reg r23, r24, r25, r26
742         if (src1 <= 4) {
743             return (src1+23);
744         }
745         abort();
746     } else if (op == saveRegOp) {
747         // should never be called for this platform.
748         abort();
749     } else {
750       unsigned aop = 0;
751       unsigned ext7 = 0;
752         switch (op) {
753             // integer ops
754             case plusOp:
755                 aop = ADDop;
756                 ext7 = ADDext7;
757                 break;
758
759             case minusOp:
760                 aop = SUBop;
761                 ext7 = SUBext7;
762                 break;
763
764             // Bool ops
765             case orOp:
766                 aop = ORop;
767                 ext7 = ORext7;
768                 break;
769
770             case andOp:
771                 aop = ANDop;
772                 ext7 = ANDext7;
773                 break;
774
775             // rel ops
776             case eqOp:
777                 genCmpOp(insn, COMCLR_EQ_C, COMCLR_EQ_F, src1, src2, dest);
778                 base += sizeof(instruction);
779                 return(0);
780                 break;
781
782             case neOp:
783                 genCmpOp(insn, COMCLR_NE_C, COMCLR_NE_F, src1, src2, dest);
784                 base += sizeof(instruction);
785                 return(0);
786                 break;
787
788             case lessOp:
789                 genCmpOp(insn, COMCLR_LT_C, COMCLR_LT_F, src1, src2, dest);
790                 base += sizeof(instruction);
791                 return(0);
792                 break;
793
794             case greaterOp:
795                 genCmpOp(insn, COMCLR_LE_C, COMCLR_LE_T, src1, src2, dest);
796                 base += sizeof(instruction);
797                 return(0);
798                 break;
799
800             case leOp:
801                 genCmpOp(insn, COMCLR_LE_C, COMCLR_LE_F, src1, src2, dest);
802                 base += sizeof(instruction);
803                 return(0);
804                 break;
805
806             case geOp:
807                 genCmpOp(insn, COMCLR_LT_C, COMCLR_LT_T, src1, src2, dest);
808                 base += sizeof(instruction);
809                 return(0);
810                 break;
811
812             case timesOp:
813                 // emulated via "floating point!" multiply
814             case divOp:
815                 // emulated via millicode
816                 abort();
817                 break;
818
819             default:
820                 abort();
821                 break;
822         }
823         genArithLogInsn(insn, aop, ext7, src1, src2, dest);
824         base += sizeof(instruction);
825       }
826     return(0);
827 }
828
829 //
830 // someone needs to work out the cost model for pa-risc
831 //
832 int getInsnCost(opCode op)
833 {
834     return 0; // simple cost model
835 }
836
837 bool isReturnInsn(const instruction instr)
838 {
839     // all returns are of the form
840     //   bv,n 0(%r2)
841     //   bv   0(%r2)
842     // inter-space jumps/returns are ignored
843     if (isInsnType(instr, RETmask, RETmatch)) {
844         return true;
845     }
846     return false;
847 }
848
849
850 // The exact semantics of the heap are processor specific.
851 //
852 // find all DYNINST symbols that are data symbols
853 //
854 bool image::heapIsOk(const vector<sym_data> &find_us) {
855   Address curr, instHeapEnd;
856   Symbol sym;
857   string str;
858
859   for (unsigned i=0; i<find_us.size(); i++) {
860     str = find_us[i].name;
861     if (!linkedFile.get_symbol(str, sym)) {
862       string str1 = string("_") + str.string_of();
863       if (!linkedFile.get_symbol(str1, sym) && find_us[i].must_find) {
864         string msg;
865         msg = string("Cannot find ") + str + string(". Exiting");
866         statusLine(msg.string_of());
867         showErrorCallback(50, msg);
868         return false;
869       }
870     }
871     addInternalSymbol(str, sym.addr());
872   }
873
874   string ghb = GLOBAL_HEAP_BASE;
875   if (!linkedFile.get_symbol(ghb, sym)) {
876     ghb = U_GLOBAL_HEAP_BASE;
877     if (!linkedFile.get_symbol(ghb, sym)) {
878       string msg;
879       msg = string("Cannot find ") + str + string(". Exiting");
880       statusLine(msg.string_of());
881       showErrorCallback(50, msg);
882       return false;
883     }
884   }
885   instHeapEnd = sym.addr();
886   addInternalSymbol(ghb, instHeapEnd);
887   ghb = INFERIOR_HEAP_BASE;
888
889   if (!linkedFile.get_symbol(ghb, sym)) {
890     ghb = UINFERIOR_HEAP_BASE;
891     if (!linkedFile.get_symbol(ghb, sym)) {
892       string msg;
893       msg = string("Cannot find ") + str + string(". Cannot use this application");
894       statusLine(msg.string_of());
895       showErrorCallback(50, msg);
896       return false;
897     }
898   }
899   curr = sym.addr();
900   addInternalSymbol(ghb, curr);
901   if (curr > instHeapEnd) instHeapEnd = curr;
902
903   // check that we can get to our heap.
904   if (instHeapEnd > getMaxBranch()) {
905     logLine("*** FATAL ERROR: Program text + data too big for dyninst\n");
906     sprintf(errorLine, "    heap ends at %x\n", instHeapEnd);
907     logLine(errorLine);
908     return false;
909   } else if (instHeapEnd + SYN_INST_BUF_SIZE > getMaxBranch()) {
910     logLine("WARNING: Program text + data could be too big for dyninst\n");
911     showErrorCallback(54, "");
912     return false;
913   }
914   return true;
915 }
916
917 //
918 // This is specific to some processors that have info in registers that we
919 //   can read, but should not write.
920 //   HPPA has no such registers.
921 //
922 bool registerSpace::readOnlyRegister(reg reg_number) {
923   return false;
924 }