initial dyninstAPI commit for code coverage
[dyninst.git] / dyninstAPI / src / inst-mips.C
1 /*
2  * Copyright (c) 1998 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include <iostream.h>
43 #include <iomanip.h>
44 #include <stdio.h>
45 #include <assert.h>
46 #include "dyninstAPI/src/arch-mips.h"
47 #include "dyninstAPI/src/inst-mips.h"
48 #include "dyninstAPI/src/symtab.h"    // pd_Function, image
49 #include "dyninstAPI/src/instPoint.h" // instPoint
50 #include "dyninstAPI/src/process.h"   // process
51 #include "dyninstAPI/src/instP.h"     // instWaitingList
52 #include "dyninstAPI/src/stats.h"     // accounting
53 #include "common/h/debugOstream.h"
54 #ifndef mips_unknown_ce2_11 //ccw 28 mar 2001
55 #include <disassembler.h>
56 #endif
57
58 #ifdef BPATCH_LIBRARY
59 #include "BPatch_basicBlock.h"
60 #include "BPatch_flowGraph.h"
61 #else
62 //#include "rtinst/h/trace.h"
63 //#include "paradynd/src/metric.h"
64 //#include "paradynd/src/main.h"
65 #include "paradynd/src/perfStream.h" // firstRecordTime
66 //#include "dyninstAPI/src/showerror.h"
67 #include "dyninstAPI/src/dyninstP.h"  // isApplicationPaused()
68 #endif
69
70 /****************************************************************************/
71 /****************************************************************************/
72 /****************************************************************************/
73
74 typedef signed short       SignedImm;
75 typedef unsigned short     UnsignedImm;
76
77 class NonRecursiveTrampTemplate : public trampTemplate
78 {
79
80 public:
81
82   int guardOnPre_beginOffset;
83   int guardOnPre_endOffset;
84
85   int guardOffPre_beginOffset;
86   int guardOffPre_endOffset;
87
88   int guardOnPost_beginOffset;
89   int guardOnPost_endOffset;
90
91   int guardOffPost_beginOffset;
92   int guardOffPost_endOffset;
93
94 };
95
96 /****************************************************************************/
97 /****************************************************************************/
98 /****************************************************************************/
99
100 // external prototypes
101 extern bool isPowerOf2(int value, int &result);
102
103 /****************************************************************************/
104 /****************************************************************************/
105 /****************************************************************************/
106
107 // global variables
108 trampTemplate baseTemplate;
109 registerSpace *regSpace;
110
111 trampTemplate conservativeTemplate;
112 registerSpace *conservativeRegSpace;
113
114 /* excluded registers: 
115    0(zero)
116    1($at)
117    2-3(return)
118    4-11(args)
119    25($t9)
120    31($ra)
121 */
122 Register Dead[] = 
123 {
124   /* 0,*/ /* 1,*/ /* 2,*/ /* 3,*/ /* 4,*/ /* 5,*/ /* 6,*/ /* 7,*/ 
125   /* 8,*/ /* 9,*/ /*10,*/ /*11,*/   12,     13,     14,     15,  
126     16,     17,     18,     19,     20,     21,     22,     23,  
127     24,   /*25,*/   26,     27,     28,     29,     30,   /*31,*/
128 };
129 const unsigned int nDead = sizeof(Dead) / sizeof(Dead[0]);
130
131 /* mihai Mon Feb 21 14:34:06 CST 2000
132  * This template is an extension of the trampTemplate,
133  * with several public member variables added. These
134  * public member variables store the offsets of the
135  * recursive guard code.
136  */
137 NonRecursiveTrampTemplate nonRecursiveBaseTemplate;
138
139 /****************************************************************************/
140 /****************************************************************************/
141 /****************************************************************************/
142
143 #define MAX_IMM16 ((SignedImm)0x7fff)
144 #define MIN_IMM16 ((SignedImm)0x8000)
145
146 #undef M_TRACE_DEBUG
147 #undef M_INFO_DEBUG
148
149 /*
150  * mihai Thu Feb 17 17:51:16 CST 2000
151  *
152  * These are trace and debug macros:
153  *
154  * TRACE_B( string ) should be used at the beginning of a function
155  * TRACE_E( string ) should be used at the end (exit points) of a function
156  * TRACE_B and TRACE_E print the strings they are given indented, and
157  * the indentation level is controlled by the number of TRACE_B and TRACE_E
158  * calls. TRACE_B and TRACE_E will output the strings, only the strings
159  * are found in the selected_for_trace array. The usual usage is to call
160  * TRACE_? with the function name in which TRACE_? is found, and to
161  * include that function name as an element in selected_for_trace.
162  *
163  * DEBUG takes a sequence of C++ stream parameters and writes them to
164  * the DEBUG_STREAM. For example:
165  * DEBUG( "Value of x = " << x << ", y = " << y );
166  * generates:
167  * { DEBUG_STREAM << "DEBUG: " << "Value of x = " << x << ", y = " << y << endl; };
168  *
169  * DEBUG_STREAM controls the output stream to which the macros write the
170  * strings.
171  *
172  * TRACE_B and TRACE_E are enabled if M_TRACE_DEBUG is defined.
173  * DEBUG is enabled if M_INFO_DEBUG is defined.
174  *
175  */
176
177 #define DEBUG_STREAM cout
178
179 #ifdef M_TRACE_DEBUG /* mihai's trace macros */
180
181 int level = 0;
182
183 char * selected_for_trace[] = { "",
184                                 "addIfNew",
185                                 "branchWithinRange",
186                                 // "cmpByAddr",
187                                 "computePauseTimeMetric",
188                                 // "contains",
189                                 "dis",
190                                 "disDataSpace",
191                                 "doNotOverflow",
192                                 // "emitA",
193                                 // "emitFuncCall",
194                                 // "emitFuncJump",
195                                 // "emitImm",
196                                 // "emitLoadPreviousStackFrameRegister",
197                                 // "emitR",
198                                 // "emitV",
199                                 // "emitVload",
200                                 // "emitVstore",
201                                 // "emitVupdate",
202                                 "findAndInstallBaseTramp",
203                                 "findFunctionLikeRld",
204                                 "generate_base_tramp_recursive_guard_code",
205                                 // "genBranch",
206                                 // "genIll",
207                                 // "genItype",
208                                 // "genJtype",
209                                 // "genJump",
210                                 // "genLoadConst",
211                                 // "genLoadNegConst",
212                                 // "genMove",
213                                 // "genNop",
214                                 // "genRtype",
215                                 // "genTrap",
216                                 // "generateBranch",
217                                 // "generateNoOp",
218                                 // "getImmField",
219                                 // "getInsnCost",
220                                 // "getPointCost",
221                                 // "getPointFrequency",
222                                 // "get_dword",
223                                 "got_ld_off",
224                                 "initDefaultPointFrequencyTable",
225                                 "initLibraryFunctions",
226                                 "initPrimitiveCost",
227                                 "initTramps",
228                                 "instWaitingList::cleanUp",
229                                 "installBaseTramp",
230                                 "installTramp",
231                                 // "lookup_fn",
232                                 "mips_dis_init",
233                                 // "pd_Function::checkCallPoints",
234                                 // "pd_Function::checkInstPoints",
235                                 // "pd_Function::findBranchTarget",
236                                 // "pd_Function::findIndirectJumpTarget",
237                                 // "pd_Function::findInstPoints",
238                                 // "pd_Function::findJumpTarget",
239                                 // "pd_Function::findStackFrame",
240                                 // "pd_Function::findTarget",
241                                 // "pd_Function::setVectorIds",
242                                 "pdcmp_got_name",
243                                 "print_function",
244                                 "print_inst_pts",
245                                 "print_saved_registers",
246                                 "print_sequence",
247                                 "process::MonitorCallSite",
248                                 "process::emitInferiorRPCheader",
249                                 "process::emitInferiorRPCtrailer",
250                                 // "process::findCallee",
251                                 "process::getProcessStatus",
252                                 // "process::isDynamicCallSite",
253                                 "process::replaceFunctionCall",
254                                 "readAddressInMemory",
255                                 "relocateInstruction",
256                                 "returnInstance::addToReturnWaitingList",
257                                 "returnInstance::checkReturnInstance",
258                                 "returnInstance::installReturnInstance",
259                                 ""
260                               };
261
262 bool is_in_string_set( char * needle )
263 {
264   for( int i = 0; i < sizeof( selected_for_trace ) / sizeof( char * ); i++ )
265     if( strcmp( needle, selected_for_trace[ i ] ) == 0 )
266       return true;
267   return false;
268 }
269
270 #define TRACE_B(msg) \
271         { \
272           if( is_in_string_set( msg ) ) \
273             { \
274               level++; \
275               for( int i = 0; i < level ; i++ ) DEBUG_STREAM << "  "; \
276               DEBUG_STREAM << ">" << __FILE__ << "[" << __LINE__ << "]: " << ( msg ) << endl; \
277             } \
278         }
279 #define TRACE_E(msg) \
280         { \
281           if( is_in_string_set( msg ) ) \
282             { \
283               for( int i = 0; i < level; i++ ) DEBUG_STREAM << "  "; \
284               DEBUG_STREAM << "<" << __FILE__ << "[" << __LINE__ << "]: " << ( msg ) << endl; \
285               level--; \
286             } \
287         }
288
289 #else
290
291 #define TRACE_B(msg)
292 #define TRACE_E(msg)
293
294 #endif
295
296 #ifdef M_INFO_DEBUG /* mihai's debug macros */
297
298 #define DEBUG(a) { DEBUG_STREAM << "DEBUG: " << a << endl; }
299
300 #else
301
302 #define DEBUG(a)
303
304 #endif
305
306 /****************************************************************************/
307 /****************************************************************************/
308 /****************************************************************************/
309
310 // local variables
311 static dictionary_hash<string, unsigned> funcFrequencyTable(string::hash);
312
313 FILE *Stderr = stderr; // hack for debugging
314
315 /****************************************************************************/
316 /****************************************************************************/
317 /****************************************************************************/
318
319 #ifdef mips_unknown_ce2_11 //ccw 2 aug 2000 : 28 mar 2001
320 //in order to get the mips assembly code on the NT box 
321 //where it needs to be to produce the trampolines,
322 //the assembly is loaded by the CE client, and passed back
323 //up to the NT box.  In that case, the assembly functions are
324 //just defined as Addresses, set when the system initializes.
325 //
326 //these values are set by remoteDevice::remoteDevice in file remoteDevice.C
327 //
328 //baseTrampTemplate.h defines the externs for these so that the rest
329 //of the world can see them.
330 //baseTrampTemplate.h defines externs for the actual assembly functions
331 //for non-CE platforms, since the assembly can be linked w/libdyninst.[lib|a]
332 char *baseTrampMem; //where the allocated memory will go.
333 char *baseNonRecursiveTrampMem;//the the NonRecursive code goes.
334
335 Address baseTramp;
336
337 Address baseTemplate_savePreInsOffset;
338 Address baseTemplate_skipPreInsOffset;
339 Address baseTemplate_globalPreOffset;
340 Address baseTemplate_localPreOffset;
341 Address baseTemplate_localPreReturnOffset;
342 Address baseTemplate_updateCostOffset;
343 Address baseTemplate_restorePreInsOffset;
344 Address baseTemplate_emulateInsOffset;
345 Address baseTemplate_skipPostInsOffset;
346 Address baseTemplate_savePostInsOffset;
347 Address baseTemplate_globalPostOffset;
348 Address baseTemplate_localPostOffset;
349 Address baseTemplate_localPostReturnOffset;
350 Address baseTemplate_restorePostInsOffset;
351 Address baseTemplate_returnInsOffset;
352
353 Address baseTemplate_trampTemp;
354 Address baseTemplate_size;
355 Address baseTemplate_cost;
356 Address baseTemplate_prevBaseCost;
357 Address baseTemplate_postBaseCost;
358 Address baseTemplate_prevInstru;
359 Address baseTemplate_postInstru;
360 Address baseTramp_endTramp;
361
362
363 /////nonRecursive!
364 Address baseNonRecursiveTramp;
365
366 Address nonRecursiveBaseTemplate_savePreInsOffset;
367 Address nonRecursiveBaseTemplate_skipPreInsOffset;
368 Address nonRecursiveBaseTemplate_globalPreOffset ;
369 Address nonRecursiveBaseTemplate_localPreOffset;
370 Address nonRecursiveBaseTemplate_localPreReturnOffset;
371 Address nonRecursiveBaseTemplate_updateCostOffset;
372 Address nonRecursiveBaseTemplate_restorePreInsOffset;
373 Address nonRecursiveBaseTemplate_emulateInsOffset;
374 Address nonRecursiveBaseTemplate_skipPostInsOffset;
375 Address nonRecursiveBaseTemplate_savePostInsOffset;
376 Address nonRecursiveBaseTemplate_globalPostOffset;
377 Address nonRecursiveBaseTemplate_localPostOffset;
378 Address nonRecursiveBaseTemplate_localPostReturnOffset;
379 Address nonRecursiveBaseTemplate_restorePostInsOffset;
380 Address nonRecursiveBaseTemplate_returnInsOffset;
381 Address nonRecursiveBaseTemplate_guardOnPre_beginOffset;
382 Address nonRecursiveBaseTemplate_guardOffPre_beginOffset;
383 Address nonRecursiveBaseTemplate_guardOnPost_beginOffset;
384 Address nonRecursiveBaseTemplate_guardOffPost_beginOffset;
385 Address nonRecursiveBaseTemplate_guardOnPre_endOffset;
386 Address nonRecursiveBaseTemplate_guardOffPre_endOffset;
387 Address nonRecursiveBaseTemplate_guardOnPost_endOffset;
388 Address nonRecursiveBaseTemplate_guardOffPost_endOffset;
389 Address nonRecursiveBaseTemplate_trampTemp;
390 Address nonRecursiveBaseTemplate_size;
391 Address nonRecursiveBaseTemplate_cost;
392 Address nonRecursiveBaseTemplate_prevBaseCost;
393 Address nonRecursiveBaseTemplate_postBaseCost;
394 Address nonRecursiveBaseTemplate_prevInstru;
395 Address nonRecursiveBaseTemplate_postInstru;
396 #endif
397
398
399 void print_inst_pts(const vector<instPoint*> &pts, pd_Function *fn) 
400 {
401   TRACE_B( "print_inst_pts" );
402
403   for (unsigned i = 0; i < pts.size(); i++) {
404     fprintf(stderr, "  0x%p: ", (void *)(pts[i]->offset() + fn->getAddress(0)));
405     switch(pts[i]->type()) {
406     case IPT_ENTRY:
407       fprintf(stderr, "entry\n"); break;
408     case IPT_EXIT:
409       fprintf(stderr, "exit\n"); break;
410     case IPT_CALL:
411       fprintf(stderr, "call\n"); break;
412     case IPT_NONE:      
413     default:
414       fprintf(stderr, "??? (%i)\n", pts[i]->type()); break;
415     }
416   }
417
418   TRACE_E( "print_inst_pts" );
419 }
420
421 /****************************************************************************/
422 /****************************************************************************/
423 /****************************************************************************/
424
425 void print_function(pd_Function *f)
426 {
427   TRACE_B( "print_function" );
428
429   fprintf(stderr, "0x%016lx: %s (%i insns):\n", 
430           f->getAddress(0), 
431           f->prettyName().string_of(), 
432           f->size() / (int)INSN_SIZE);
433
434   vector<instPoint*> t;
435   t.push_back(const_cast<instPoint*>(f->funcEntry(0)));
436   print_inst_pts(t, f);
437
438   print_inst_pts(f->funcCalls(0), f);
439
440   print_inst_pts(f->funcExits(0), f);
441
442   TRACE_E( "print_function" );
443 }
444
445 /****************************************************************************/
446 /****************************************************************************/
447 /****************************************************************************/
448
449 static void mips_dis_init()
450 {
451   TRACE_B( "mips_dis_init" );
452
453   static bool init = true;
454   if (init) {
455     //dis_init32("0x%016lx\t", 0, reg_names, 1);
456     //dis_init64("0x%016lx\t", 0, reg_names, 1);
457     init = false;
458   }
459
460   TRACE_E( "mips_dis_init" );
461 }
462
463 /****************************************************************************/
464 /****************************************************************************/
465 /****************************************************************************/
466
467 void disDataSpace(process *p, void *addr_, int ninsns, 
468                   const char *pre, FILE *stream)
469 {
470   TRACE_B( "disDataSpace" );
471
472   mips_dis_init();
473   
474   instruction *addr = (instruction *)addr_;
475   assert(isAligned((Address)addr));
476   instruction insn;
477   char buf[64];
478   static bool is_elf64 =
479 #if !defined(mips_unknown_ce2_11) //ccw 20 july 2000 : 28 mar 2001
480   p->getImage()->getObject().is_elf64();
481 #else
482   false;
483 #endif
484
485   for (int i = 0; i < ninsns; i++) {
486     void *inTraced = addr + i;
487     p->readDataSpace(inTraced, INSN_SIZE, &insn, true);
488     // Elf32_Addr regmask, lsreg; /* commented out by Mihai. Unused variables. */
489     if (is_elf64) {
490
491       // Elf64_Addr value; /* commented out by Mihai. Unused variables. */
492       //disasm64(buf, (Elf64_Addr)inTraced, *(Elf32_Addr *)&insn, &regmask, &value, &lsreg);
493
494     } else { // 32-bit app
495
496       // Elf32_Addr value; /* commented out by Mihai. Unused variables. */
497       //disasm32(buf, (Elf32_Addr)(Address)inTraced, *(Elf32_Addr *)&insn, &regmask, &value, &lsreg);
498
499     }
500     if (pre) fprintf(stream, "%s", pre);
501     fprintf(stream, "%s\n", buf);
502   }
503
504   TRACE_E( "disDataSpace" );
505 }
506
507 /****************************************************************************/
508 /****************************************************************************/
509 /****************************************************************************/
510
511 void dis(void *actual_, void *addr_, int ninsns, 
512          const char *pre, FILE *stream)
513 {
514   TRACE_B( "dis" );
515
516   mips_dis_init();
517
518   instruction *actual = (instruction *)actual_;
519   instruction *addr = (instruction *)addr_;
520   if (addr == NULL) addr = actual;
521   char buf[64];
522
523 #if 0 /* Unifdef and link with -lelfutil for debugging. */
524   Elf32_Addr regmask, value, lsreg;
525   for (int i = 0; i < ninsns; i++) {
526     Elf32_Addr inSelf = (Elf32_Addr)(Address)(addr + i);
527     Elf32_Addr insn = *(Elf32_Addr *)(actual + i);
528     disasm32(buf, inSelf, insn, &regmask, &value, &lsreg);
529     fprintf(stream, "%s%s\n", (pre) ? (pre) : (""), buf);
530   }
531 #endif
532
533   TRACE_E( "dis" );
534 }
535
536 /****************************************************************************/
537 /****************************************************************************/
538 /****************************************************************************/
539
540 Address readAddressInMemory(process *p, Address ptr, bool is_elf64)
541 {
542   TRACE_B( "readAddressInMemory" );
543
544   void *ret = NULL;
545   char *local_addr = (char *)&ret;
546   unsigned nbytes = sizeof(void *);
547
548   if (!is_elf64 && sizeof(void *) == sizeof(uint64_t)) {
549     // 64-bit paradynd, 32-bit application
550     local_addr += sizeof(uint32_t);
551     nbytes -= sizeof(uint32_t);
552   }
553
554   // read pointer from memory
555   bool ret2 = p->readDataSpace((void *)ptr, nbytes, local_addr, true);
556   assert(ret2);
557
558   TRACE_E( "readAddressInMemory" );
559
560   return (Address)ret;
561 }
562
563 /****************************************************************************/
564 /****************************************************************************/
565 /****************************************************************************/
566
567 Address lookup_fn(process *p, const string &f)
568 {
569   TRACE_B( "lookup_fn" );
570
571   //fprintf(stderr, ">>> lookup_fn(%s)\n", f.string_of());
572   Address ret = 0;
573
574   // findInternalSymbol()
575   /*
576   if (ret == 0 ) {
577     internalSym sym;
578     if (p->findInternalSymbol(f, false, sym)) {
579       ret = sym.getAddr();
580       //fprintf(stderr, "  findInternalSymbol: 0x%08x\n", ret);
581     }
582   }
583   */
584
585   // findInternalAddress()
586   if (ret == 0) {
587     bool err;
588     ret = p->findInternalAddress(f, false, err);
589     //if (ret) fprintf(stderr, "  findInternalAddress: 0x%08x\n", ret);
590   }
591   
592   // findOneFunction()
593   if (ret == 0) {
594     pd_Function *pdf = (pd_Function *)p->findOneFunction(f);
595     if (pdf) {
596       Address obj_base;
597       p->getBaseAddress(pdf->file()->exec(), obj_base);
598       ret = obj_base + pdf->getAddress(p);
599       //fprintf(stderr, "  findOneFunction: 0x%08x\n", ret);
600     }
601   }
602
603   TRACE_E( "lookup_fn" );
604
605   return ret;
606 }
607
608 /****************************************************************************/
609 /****************************************************************************/
610 /****************************************************************************/
611
612 /*
613  * findInstPoints(): EXPORTED
614  *
615  * pd_Function members populated:
616  *   funcEntry_
617  *   funcReturns
618  *   calls
619  *   relocatable_
620  *   noStackFrame
621  *   isTrap
622  *
623  */
624
625 #ifdef CSS_DEBUG_INST
626 #define UNINSTR(str) \
627   fprintf(stderr, "uninstrumentable: %s (%0#10x: %i insns) - %s\n", \
628           prettyName().string_of(), \
629           file_->exec()->getObject().get_base_addr() + getAddress(0), \
630           size() / INSN_SIZE, \
631           str)
632 #else
633 #define UNINSTR(str)
634 #endif
635
636 bool pd_Function::findInstPoints(const image *owner) {
637     TRACE_B( "pd_Function::findInstPoints" );
638
639   //fprintf(stderr, "\n>>> pd_Function::findInstPoints()\n");
640   //fprintf(stderr, "%0#10x: %s(%u insns):\n", 
641   //getAddress(0), prettyName().string_of(), size() / INSN_SIZE);
642   if (size() == 0) {
643     UNINSTR("zero length");
644
645     TRACE_E( "pd_Function::findInstPoints" );
646
647     return false;
648   }
649
650   // default values
651   isTrap = false;
652   relocatable_ = false;
653   noStackFrame = true;
654
655   // parse instPoints
656   Address start = getAddress(0);
657   Address end = start + size();
658   Offset off;
659   instruction insn;
660
661   /* stack frame info */
662   /* check if function has a stack frame:
663    *  - yes: entry point is "save" instruction ([d]addiu sp,sp,-XX)
664    *  - no: entry point is start of function
665    */
666   Address entry = findStackFrame(owner);
667   
668   /* ENTRY point */
669   funcEntry_ = new entryPoint(this, entry); 
670   assert(funcEntry_);
671
672
673   /* CALL and EXIT points */
674   for (off = 0; off < end - start; off += INSN_SIZE) {
675     insn.raw = owner->get_instruction(start + off);
676       
677     /* CALL points */
678     if (isCallInsn(insn)) {
679       /* simple call */
680       //cerr << "  found call pt" << endl;
681       calls.push_back(new callPoint(this, off));
682     } else if (isInsnType(insn, BGEZALLmask, BGEZALLmatch)) {
683       /* optimized recursive call: branch to start of function */
684       //cerr << "  found optimized recursive call pt" << endl;
685       signed branchOff = insn.regimm.simm16 << 2;
686       Offset targetOff = off + INSN_SIZE + branchOff;
687       if (targetOff == 0) {
688         calls.push_back(new callPoint(this, off, IP_RecursiveBranch));
689       }
690     } else if (isInsnType(insn, SYSCALLmask, SYSCALLmatch)) {
691       isTrap = true;
692       // TODO: system call handling
693     }
694
695       
696     /* EXIT points */
697     // TODO - distinguish between return and switch? (maybe "jr ra" vs "jr v1")
698     if (isReturnInsn(insn)) {
699       //cerr << "  found return pt" << endl;
700       funcReturns.push_back(new exitPoint(this, off));
701     }
702   }
703
704   setVectorIds(); // set CALL and EXIT vectorIds
705
706   TRACE_E( "pd_Function::findInstPoints" );
707
708   return checkInstPoints();
709 }
710
711 /****************************************************************************/
712 /****************************************************************************/
713 /****************************************************************************/
714
715 static bool contains(vector<int> &V, int val)
716 {
717   TRACE_B( "contains" );
718
719   for (unsigned i = 0; i < V.size(); i++) {
720     if (V[i] == val)
721       {
722 //      TRACE_E( "contains" );
723
724         return true;
725       }
726   }
727
728   TRACE_E( "contains" );
729
730   return false;
731 }
732
733 /****************************************************************************/
734 /****************************************************************************/
735 /****************************************************************************/
736
737 static void addIfNew(vector<int> &V, int val)
738 {
739   TRACE_B( "addIfNew" );
740
741   if (contains(V, val))
742     {
743       TRACE_E( "addIfNew" );
744
745       return;
746     }
747
748   V.push_back(val);
749
750   TRACE_E( "addIfNew" );
751 }
752
753 /****************************************************************************/
754 /****************************************************************************/
755 /****************************************************************************/
756
757 static void print_saved_registers(pd_Function *fn, const vector<vector<int> > &slots)
758 {
759   TRACE_B( "print_saved_registers" );
760
761   /*
762   vector<vector<int> > slots2(slots.size());
763   vector<int> locals;
764   for (unsigned i = 0; i < slots.size(); i++) {
765     for (int j = 0; j < slots[i].size(); j++) {
766       int slot = slots[i][j];
767       bool dup = false;
768       if (contains(locals, slot)) dup = true;
769       for (int k = 0; k < slots.size() && !dup; k++) {
770         if (k == i) continue;
771         if (contains(slots[k], slot)) dup = true;
772       }
773       if (!dup) addIfNew(slots2[i], slot);
774       else addIfNew(locals, slot);
775     }
776   }
777   */  
778   
779   bool mult = false;
780   for (unsigned i = 0; i < slots.size(); i++) {
781     if (slots[i].size() > 1) {
782       mult = true;
783       break;
784     }
785   }
786
787
788   if (mult) {
789     fprintf(stderr, "*** %s (0x%016lx: %i insns): stack frame\n",
790             fn->prettyName().string_of(), 
791             fn->getAddress(0), 
792             fn->size() / (int)INSN_SIZE);
793     vector<int> locals;
794     for (unsigned i = 0; i < slots.size(); i++) {
795       if (slots[i].size() > 0) {
796         fprintf(stderr, "  $%-4s:", reg_names[i]);
797         for (unsigned j = 0; j < slots[i].size(); j++) {
798           int slot = slots[i][j];
799           bool dup = false;
800           for (unsigned k = 0; k < slots.size() && !dup; k++) {
801             if (k == i) continue;
802             for (unsigned l = 0; l < slots[k].size() && !dup; l++) {
803               if (slots[k][l] == slot) {
804                 addIfNew(locals, slot);
805                 dup = true;
806               }
807             }
808           }
809           if (contains(locals, slot)) continue;
810           fprintf(stderr, " %3i", slot);
811           if (dup) fprintf(stderr, "*");
812           //if (contains(locals, slot)) fprintf(stderr, "&");
813         }       
814         fprintf(stderr, "\n");
815       }
816     }
817     fprintf(stderr, "  vars :");
818     for (
819 #if !defined(mips_unknown_ce2_11)  //ccw 20 july 2000 : 28 mar 2001
820                 unsigned
821 #endif 
822         i = 0; i < locals.size(); i++) {
823       fprintf(stderr, " %3i", locals[i]);
824     }
825     fprintf(stderr, "\n");
826   }
827
828   TRACE_E( "print_saved_registers" );
829 }
830
831 /****************************************************************************/
832 /****************************************************************************/
833 /****************************************************************************/
834
835 Address pd_Function::findStackFrame(const image *owner)
836 {
837   TRACE_B( "pd_Function::findStackFrame" );
838
839   bool foundRest;
840   int lastRestore;
841   InactiveFrameRange ifr;
842   
843   /*
844     fprintf(stderr, ">>> findStackFrame(): <0x%016lx:\"%s\"> %i insns\n",
845     owner->getObject().get_base_addr() + getAddress(0), 
846     prettyName().string_of(), size() / INSN_SIZE);
847   */
848  
849   // initialize stack frame info
850   for (int i = 0; i < NUM_REGS; i++) {
851     reg_saves[i].slot = -1;
852   }
853   sp_mod = (Address)-1;
854   frame_size = 0;
855   fp_mod = (Address)-1;
856   uses_fp = false;
857
858   // register aliasing
859   int aliases[NUM_REGS];
860   for (
861 #ifndef mips_unknown_ce2_11 //ccw 17 july 2001
862 int
863 #endif
864  i = 0; i < NUM_REGS; i++) {
865     aliases[i] = i;
866   }
867
868   // parse insns relevant to stack frame
869   Address start = getAddress(0);
870   Address end = start + size();
871   Offset off;
872   instruction insn;
873   Address fn_addr = owner->getObject().get_base_addr() + getAddress(0);
874   for (off = 0; off < end - start; off += INSN_SIZE) {
875     insn.raw = owner->get_instruction(start + off);
876     struct fmt_itype &itype = insn.itype;
877     struct fmt_rtype &rtype = insn.rtype;
878     //Address iaddr = fn_addr + off; // debug
879
880     /* TODO: This stack frame parsing does not handle cases where the
881        stack frame is adjusted multiple times in the same function.
882        Dataflow analysis is required to handle this scenario
883        correctly. */
884
885     // stack frame (save): "[d]addiu sp,sp,-XX" insn
886     if ((itype.op == ADDIUop || itype.op == DADDIUop) && 
887         itype.rs == REG_SP &&
888         itype.rt == REG_SP &&
889         itype.simm16 < 0 &&
890         noStackFrame == true)
891     {
892       noStackFrame = false;
893       sp_mod = off;
894       frame_size = -itype.simm16;
895     }
896     // stack frame (save, large): "[d]subu sp,sp,at" insn,
897     //  which usually follows an "ori at, 0, XX" insn,
898     //  with possibly a lui preceeding the ori
899     else if ((rtype.ops == SUBUops || rtype.ops == DSUBUops) &&
900              rtype.rd == REG_SP &&
901              rtype.rs == REG_SP &&
902              noStackFrame == true)
903     {
904       instruction tempInsn;
905       tempInsn.raw = owner->get_instruction(start + off - INSN_SIZE);
906       struct fmt_itype &tempItype = tempInsn.itype;
907
908       if ( tempItype.op == ORIop && 
909            rtype.rt == tempItype.rt )
910       {
911         int totFrameSize = tempItype.simm16 & 0xffff;
912
913         noStackFrame = false;
914         sp_mod = off;
915
916         tempInsn.raw = owner->get_instruction(start + off - (2*INSN_SIZE));
917         if ( tempItype.op == LUIop && 
918              rtype.rt == tempItype.rt )
919         {
920           totFrameSize |= (tempItype.simm16 << 16);
921         }
922
923         frame_size = totFrameSize;
924       }
925     }
926     // stack frame (restore): "[d]addiu sp,sp,<frame_size>" insn
927     else if ((itype.op == ADDIUop || itype.op == DADDIUop) && 
928              itype.rs == REG_SP &&
929              itype.rt == REG_SP &&
930              itype.simm16 == frame_size &&
931              noStackFrame == false)
932     {
933       lastRestore = off;
934       foundRest = true;
935     }
936     // stack frame (restore from $fp): "move sp,s8" insn
937     else if (rtype.op == SPECIALop &&
938              rtype.ops == ORops &&
939              rtype.rt == REG_ZERO &&
940              rtype.rs == REG_S8 &&
941              rtype.rd == REG_SP &&
942              uses_fp == true)
943     {
944       lastRestore = off;
945       foundRest = true;
946     }
947
948     // frame pointer #1: "[d]addiu s8,sp,<frame_size>" insn
949     else if ((itype.op == ADDIUop || itype.op == DADDIUop) &&
950              itype.rs == REG_SP &&
951              itype.rt == REG_S8 &&
952              itype.simm16 == frame_size)
953     {
954       fp_mod = off;
955       uses_fp = true;
956     }
957     // frame pointer #2: "move s8,sp" insn
958     else if (rtype.op == SPECIALop &&
959              rtype.ops == ORops &&
960              rtype.rt == REG_ZERO &&
961              rtype.rs == REG_SP &&
962              rtype.rd == REG_S8 &&
963              frame_size == 0)
964     {
965       fp_mod = off;
966       uses_fp = true;
967     }
968
969     // frame pointer #3: "daddu s8,sp, at" insn
970     else if (rtype.op == SPECIALop &&
971              rtype.ops == DADDUops &&
972              rtype.rs == REG_SP &&
973              rtype.rd == REG_S8)
974     {
975       fp_mod = off;
976       uses_fp = true;
977     }
978
979     // register aliasing: "move R2,R1" insn
980     else if (rtype.op  == SPECIALop &&
981              rtype.ops == ORops &&
982              rtype.rt  == REG_ZERO &&
983              rtype.rs  != REG_ZERO)
984     {
985       int r_src = aliases[rtype.rs];
986       // check if register has been saved yet
987       if (reg_saves[r_src].slot == -1) {
988         int r_dst = rtype.rd;
989         /*
990           if (aliases[r_dst] != r_dst) {
991           fprintf(stderr, "!!! <0x%016lx:\"%s\" multiple aliasing\n",
992           iaddr, prettyName().string_of());
993           } */
994         aliases[r_dst] = r_src;
995       }
996     }
997
998     // register save #1: "sd/sw RR,XX(sp)" insn
999     else if ((itype.op == SDop || itype.op == SWop) &&
1000              itype.rs == REG_SP &&
1001              itype.simm16 >= 0)
1002     {
1003       assert(isAligned(itype.simm16));
1004       int r = aliases[itype.rt];
1005       regSave_t &save = reg_saves[r];
1006       // check if register has been saved yet
1007       if (save.slot == -1) {
1008         // convert positive $sp offset to negative $fp offset
1009         save.slot = itype.simm16 - frame_size;
1010         save.dword = (itype.op == SDop);
1011         save.insn = off;
1012       }
1013     }
1014     // register save #2: "sd/sw RR,-XX(s8)" insn
1015     else if ((itype.op == SDop || itype.op == SWop) &&
1016              uses_fp && itype.rs == REG_S8 &&
1017              itype.simm16 < 0)
1018     {
1019       int r = aliases[itype.rt];
1020       regSave_t &save = reg_saves[r];
1021       // check if register has been saved yet
1022       if (save.slot == -1) {
1023         save.slot = itype.simm16; // negative $fp offset
1024         save.dword = (itype.op == SDop);
1025         save.insn = off;
1026       }
1027     }
1028     //  return : "jr ra" insn
1029     else if ( rtype.op == SPECIALop && rtype.ops == JRops ) 
1030     {
1031       if ( frame_size > 0 )
1032       {
1033         instruction tempInsn;
1034         struct fmt_itype &itype = tempInsn.itype;
1035         struct fmt_rtype &rtype = tempInsn.rtype;
1036         Address fn_addr = owner->getObject().get_base_addr() + getAddress(0);
1037         tempInsn.raw = owner->get_instruction(start + off + INSN_SIZE);
1038
1039         //  check if frame pop is in delay slot
1040         //  if so, don't save pop/return offsets to
1041         //  identify inactive frame range
1042
1043         if ( ((itype.op == ADDIUop || itype.op == DADDIUop) && 
1044               itype.rs == REG_SP &&
1045               itype.rt == REG_SP &&
1046               itype.simm16 == frame_size &&
1047               noStackFrame == false) || 
1048
1049              (rtype.op == SPECIALop &&
1050               rtype.ops == ORops &&
1051               rtype.rt == REG_ZERO &&
1052               rtype.rs == REG_S8 &&
1053               rtype.rd == REG_SP &&
1054               uses_fp == true) )
1055         {
1056           off += INSN_SIZE;
1057         }
1058         else
1059         {
1060           if ( foundRest )
1061           {
1062             //fprintf(stderr, "\n\n  in function %s, saving pop %d and ret %d\n", prettyName().string_of(), lastRestore, off);
1063             ifr.popOffset = lastRestore;
1064             ifr.retOffset = off;
1065             inactiveRanges.push_back(ifr);
1066           }
1067         }
1068
1069         foundRest = false;
1070       }
1071     }
1072   }
1073   
1074   TRACE_E( "pd_Function::findStackFrame" );
1075
1076   // default return value (entry point = first insn of fn)
1077   return (noStackFrame) ? (0) : (sp_mod);
1078 }
1079
1080 /****************************************************************************/
1081 /****************************************************************************/
1082 /****************************************************************************/
1083
1084 void pd_Function::setVectorIds()
1085 {
1086   TRACE_B( "pd_Function::setVectorIds" );
1087   //fprintf(stderr, ">>> pd_Function::setIDS()\n");
1088   for (unsigned i = 0; i < calls.size(); i++) 
1089     calls[i]->vectorId = i;
1090   for (
1091 #ifndef mips_unknown_ce2_11 //ccw 17 july 2001
1092 unsigned
1093 #endif
1094  i = 0; i < funcReturns.size(); i++) 
1095     funcReturns[i]->vectorId = i;
1096
1097   TRACE_E( "pd_Function::setVectorIds" );
1098 }
1099
1100 /****************************************************************************/
1101 /****************************************************************************/
1102 /****************************************************************************/
1103
1104 /* compare instPoints by Address: used in checkInstPoints() */
1105 static int cmpByAddr(const void *A, const void *B)
1106 {
1107   TRACE_B( "cmpByAddr" );
1108
1109   instPoint *ptA = *(instPoint **)const_cast<void*>(A);
1110   instPoint *ptB = *(instPoint **)const_cast<void*>(B);
1111   Offset offA = ptA->offset();
1112   Offset offB = ptB->offset();
1113   if (offA < offB)
1114     {
1115       TRACE_E( "cmpByAddr" );
1116
1117       return -1;
1118     }
1119   if (offA > offB)
1120     {
1121       TRACE_E( "cmpByAddr" );
1122
1123       return 1;
1124     }
1125
1126   TRACE_E( "cmpByAddr" );
1127
1128   return 0;
1129 }
1130
1131 /****************************************************************************/
1132 /****************************************************************************/
1133 /****************************************************************************/
1134
1135 /* checkInstPoints(): check for special instPoint conditions...
1136  * - overlapping instPoints
1137  * - first instPoint is not an entry point
1138  */
1139 bool pd_Function::checkInstPoints()
1140 {
1141   TRACE_B( "pd_Function::checkInstPoints" );
1142
1143   //fprintf(stderr, ">>> pd_Function::checkInstPoints()\n");
1144   bool ret = true;
1145
1146   // resolve call targets of "_start"
1147   // (looking for calls to "main")
1148   if (symTabName() == "_start" ||
1149       symTabName() == "__start") 
1150   {
1151     for (unsigned i = 0; i < calls.size(); i++) {
1152       findTarget(calls[i]);
1153     }
1154   }
1155
1156   /* no entry point */
1157   if (!funcEntry_) {
1158     UNINSTR("no entry point");
1159     ret = false;
1160   } 
1161
1162   /* no exit points */
1163   if (funcReturns.size() == 0 && symTabName() != "main") {
1164     UNINSTR("no exit points");
1165     ret = false;
1166   }
1167
1168   /* sort all instPoints by address */
1169   vector<instPoint*> pts;
1170   if (funcEntry_) pts.push_back(funcEntry_);
1171   for(unsigned  i = 0; i < funcReturns.size(); i++) {
1172     pts.push_back(funcReturns[i]);
1173   }
1174   for (
1175 #ifndef mips_unknown_ce2_11 //ccw 17 july 2001
1176 unsigned
1177 #endif
1178     i = 0; i < calls.size(); i++) {
1179     pts.push_back(calls[i]);
1180   }
1181   VECTOR_SORT(pts, cmpByAddr);
1182
1183   /* first instPoint not an entry point */
1184   if (pts[0]->type() != IPT_ENTRY) {
1185     UNINSTR("1st inst pt not entry");
1186     //print_inst_pts(pts, this);
1187     ret = false;
1188   }
1189
1190   /* check for overlapping instPoints */
1191   for (
1192 #ifndef mips_unknown_ce2_11 //ccw 17 july 2001
1193 unsigned
1194 #endif
1195          i = 0; i < pts.size() - 1; i++) {
1196     instPoint *p = pts[i];
1197     instPoint *p2 = pts[i+1];
1198     if (p2->offset() < p->offset() + p->size()) {
1199       relocatable_ = true;
1200       isTrap = true; // alias for relocatable_ (TODO)
1201       p2->flags |= IP_Overlap;
1202     }
1203   }
1204   // TODO: function relocation not yet implemented
1205   if (relocatable_) {
1206     ret = false;
1207   }
1208   
1209   TRACE_E( "pd_Function::checkInstPoints" );
1210
1211   //if (!ret) fprintf(stderr, ">>> uninstrumentable: \"%s\"\n", prettyName().string_of());
1212   return ret;
1213 }
1214
1215 /****************************************************************************/
1216 /****************************************************************************/
1217 /****************************************************************************/
1218
1219 /* checkCallPoints():
1220  * Determine if callee is a "library" or "user" function.  
1221  * This cannot be done until all functions have been seen.  
1222  */
1223 void pd_Function::checkCallPoints() 
1224 {
1225   TRACE_B( "pd_Function::checkCallPoints" );
1226
1227   //fprintf(stderr, ">>> pd_Function::checkCallPoints()\n");
1228 #ifdef CSS_DEBUG_INST
1229   fprintf(stderr, ">>> %s(%0#10x: %u insns)\n", 
1230           prettyName().string_of(), getAddress(0), size() / INSN_SIZE);
1231 #endif
1232   //fprintf(stderr, "%0#10x: %s(%u insns)\n", 
1233   //file()->exec()->getObject().get_base_addr() + getAddress(0), 
1234   //prettyName().string_of(), 
1235   //size() / INSN_SIZE);
1236   
1237   Address fnStart = getAddress(0);
1238   vector<instPoint*> calls2;
1239   for (unsigned i = 0; i < calls.size(); i++) {
1240     instPoint *ip = calls[i];
1241     assert(ip);
1242     
1243     Address tgt_addr = findTarget(ip);
1244     if (tgt_addr) {
1245       pd_Function *tgt_fn = file_->exec()->findFuncByAddr(tgt_addr);
1246       ip->setCallee(tgt_fn); // possibly NULL
1247       // NOTE: (target == fnStart) => optimized recursive call
1248       if (!tgt_fn && tgt_addr > fnStart && tgt_addr < fnStart + size()) {
1249         // target is inside same function (i.e. branch)
1250         delete ip;
1251         continue;
1252       }
1253     }
1254      
1255     /* fallthrough cases (call sites are kept):
1256      * - target is unknown (trap)
1257      * - target is external, but callee function cannot be found
1258      */
1259     calls2.push_back(ip);
1260   }
1261   calls = calls2;
1262   setVectorIds();
1263
1264   TRACE_E( "pd_Function::checkCallPoints" );
1265 }
1266
1267 /****************************************************************************/
1268 /****************************************************************************/
1269 /****************************************************************************/
1270
1271 /* findTarget(): calculate target of call point
1272  * return of 0 means unknown 
1273  */
1274 Address pd_Function::findTarget(instPoint *p)
1275 {
1276   TRACE_B( "pd_Function::findTarget" );
1277
1278   //fprintf(stderr, ">>> pd_Function::findTarget()\n");
1279   assert(p->type() == IPT_CALL);
1280   Address ret = 0;
1281   instruction i;
1282   i.raw = p->code();
1283
1284   if (isBranchInsn(i)) {
1285     ret = findBranchTarget(p, i);
1286   } else if (isJumpInsn(i)) {
1287     ret = findJumpTarget(p, i);
1288   } else if (isTrapInsn(i)) {
1289     fprintf(stderr, "!!! pd_Function::findTarget(): trap insn\n");
1290     assert(0); // not seen yet
1291   } else {
1292     fprintf(stderr, "!!! pd_Function::findTarget(): unknown call insn (0x%08x)\n", i.raw);
1293     assert(0); // hopefully not reached
1294   }
1295
1296   TRACE_E( "pd_Function::findTarget" );
1297
1298   return ret;
1299 }
1300
1301 /****************************************************************************/
1302 /****************************************************************************/
1303 /****************************************************************************/
1304
1305 Address pd_Function::findBranchTarget(instPoint *p, instruction i)
1306 {
1307   TRACE_B( "pd_Function::findBranchTarget" );
1308
1309   // PC-relative branch
1310   Address base = p->address() + INSN_SIZE;
1311   signed off = i.itype.simm16 << 2;
1312   Address ret = base + off;
1313   //fprintf(stderr, ">>> pd_Function::findBranchTarget() => 0x%08x\n", ret);
1314
1315   TRACE_E( "pd_Function::findBranchTarget" );
1316
1317   return ret;
1318 }
1319
1320 /****************************************************************************/
1321 /****************************************************************************/
1322 /****************************************************************************/
1323
1324 Address pd_Function::findJumpTarget(instPoint *p, instruction i)
1325 {
1326   TRACE_B( "pd_Function::findJumpTarget" );
1327
1328   Address ret = 0;
1329   //fprintf(stderr, ">>> pd_Function::findJumpTarget():");
1330   unsigned opcode = i.decode.op;
1331   switch (opcode) {
1332   case Jop:
1333   case JALop:
1334     { // PC-region branch
1335       Address hi = (p->address() + INSN_SIZE) & (REGION_NUM_MASK);
1336       Address lo = (i.jtype.imm26 << 2) & REGION_OFF_MASK;
1337       ret = hi | lo;
1338     } break;
1339   case SPECIALop: 
1340     // indirect (register) jump
1341     ret = findIndirectJumpTarget(p, i);
1342     break;
1343   default:
1344     fprintf(stderr, "pd_Function::findJumpTarget(): bogus instruction %0#10x\n", i.raw);
1345     assert(0);
1346   }
1347
1348   TRACE_E( "pd_Function::findJumpTarget" );
1349
1350   return ret;
1351 }
1352
1353 /****************************************************************************/
1354 /****************************************************************************/
1355 /****************************************************************************/
1356
1357 void print_sequence(int targetReg, vector<int> &baseAdjusts,
1358                     vector<int> &adjusts, int n, char * /*pre*/ = NULL)
1359 {
1360   TRACE_B( "print_sequence" );
1361
1362   if ((unsigned)n == baseAdjusts.size()) {
1363     fprintf(stderr, "%s", reg_names[targetReg]);
1364
1365     TRACE_E( "print_sequence" );
1366
1367     return;
1368   }
1369
1370   fprintf(stderr, "[");
1371   print_sequence(targetReg, baseAdjusts, adjusts, n+1);
1372   if (baseAdjusts[n] != 0) fprintf(stderr, "%+i", baseAdjusts[n]);
1373   fprintf(stderr, "]");
1374   if (adjusts[n] != 0) fprintf(stderr, "%+i", adjusts[n]);
1375
1376   TRACE_E( "print_sequence" );
1377 }
1378
1379 /****************************************************************************/
1380 /****************************************************************************/
1381 /****************************************************************************/
1382
1383 uint32_t get_word(const Object &elf, Address addr)
1384 {
1385   TRACE_E( "get_word" );
1386
1387   uint32_t ret = 0;
1388   if (addr >= elf.code_off() && addr < elf.code_off() + (elf.code_len() << 2)) {
1389     char *base = (char *)const_cast<Word*>(elf.code_ptr());
1390     char *ptr = base + (addr - elf.code_off());
1391     ret = *(uint32_t *)ptr;
1392   } else if (addr >= elf.data_off() && addr < elf.data_off() + (elf.data_len() << 2)) {
1393     char *base = (char *)const_cast<Word*>(elf.data_ptr());
1394     char *ptr = base + (addr - elf.data_off());
1395     ret = *(uint32_t *)ptr;
1396   }
1397
1398   TRACE_E( "get_word" );
1399
1400   return ret;
1401 }
1402
1403 /****************************************************************************/
1404 /****************************************************************************/
1405 /****************************************************************************/
1406
1407 uint64_t get_dword(const Object &elf, Address addr)
1408 {
1409   TRACE_B( "get_dword" );
1410
1411   uint64_t ret = 0;
1412   if (addr >= elf.code_off() && addr < elf.code_off() + (elf.code_len() << 2)) {
1413     char *base = (char *)const_cast<Word*>(elf.code_ptr());
1414     char *ptr = base + (addr - elf.code_off());
1415     uint64_t hi = *(uint32_t *)ptr;
1416     uint64_t lo = *(uint32_t *)(ptr + sizeof(uint32_t));
1417     ret = (hi << 32) | lo;
1418   } else if (addr >= elf.data_off() && addr < elf.data_off() + (elf.data_len() << 2)) {
1419     char *base = (char *)const_cast<Word*>(elf.data_ptr());
1420     char *ptr = base + (addr - elf.data_off());
1421     uint64_t hi = *(uint32_t *)ptr;
1422     uint64_t lo = *(uint32_t *)(ptr + sizeof(uint32_t));
1423     ret = (hi << 32) | lo;
1424   }
1425
1426   TRACE_E( "get_dword" );
1427
1428   return ret;
1429 }
1430
1431 /****************************************************************************/
1432 /****************************************************************************/
1433 /****************************************************************************/
1434
1435 Address pd_Function::findIndirectJumpTarget(instPoint *ip, instruction i)
1436 {
1437   TRACE_B( "pd_Function::findIndirectJumpTarget" );
1438
1439   /*
1440   fprintf(stderr, ">>> pd_Function::findIndirectJumpTarget <0x%016lx: %s>\n", 
1441           file_->exec()->getObject().get_base_addr() + ip->address(), 
1442           prettyName().string_of());
1443   */
1444
1445   assert(i.rtype.op == SPECIALop);
1446   assert(i.rtype.ops == JALRops || i.rtype.ops == JRops);
1447   
1448   // look for the following instruction sequence(s):
1449   // lw          R1,XX(gp)
1450   // [[d]addiu]  R1,R1,XX
1451   // j[al]r      R2,R1
1452
1453   // TODO: need control flow info
1454   // TODO: internal indirect jump (switch)
1455
1456   // indirect jump sequence
1457   Register targetReg = i.rtype.rs;
1458   vector<int> baseRegs;
1459   vector<int> baseAdjusts;
1460   vector<int> adjusts;
1461   vector<unsigned int> insns;
1462   vector<Address> insnAddrs;
1463
1464   // parse code
1465   Address start = getAddress(0);
1466   image *owner = file_->exec();
1467   int adjust = 0;
1468   instruction i2;
1469   // indirect jump insn (debug)
1470   insns.push_back(i.raw);
1471   insnAddrs.push_back(ip->offset() + start);
1472   int off; // must be signed
1473   // start at "ip+4" to parse delay slot insn
1474   for (off = ip->offset() + INSN_SIZE; off >= 0; off -= INSN_SIZE) {
1475     // analysis stops when $gp or $sp encountered
1476     // TODO: decode $sp sequences using stack frame info
1477     if (targetReg == REG_GP) break;
1478     if (targetReg == REG_SP) break;
1479
1480     i2.raw = owner->get_instruction(start+off);
1481
1482     // parse indirect jump sequence
1483  
1484     // daddu t9,t9,gp
1485     if (isInsnType(i2, DADDUmask, DADDUmatch) &&
1486         i2.rtype.rs == REG_T9 &&
1487         i2.rtype.rt == REG_GP &&
1488         i2.rtype.rd == REG_T9)
1489     {
1490       targetReg = REG_GP;
1491       // debug
1492       insns.push_back(i2.raw);
1493       insnAddrs.push_back(start+off);
1494     }
1495     // move R2,R1
1496     if (isInsnType(i2, ORmask, ORmatch) &&
1497         i2.rtype.rt == REG_ZERO &&
1498         i2.rtype.rd == targetReg) 
1499     {
1500       targetReg = i2.rtype.rs;
1501       // debug
1502       insns.push_back(i2.raw);
1503       insnAddrs.push_back(start+off);
1504     }
1505     // addiu  R1,R1,X
1506     // daddiu R1,R1,X
1507     if ((isInsnType(i2, ADDIUmask, ADDIUmatch) || 
1508          isInsnType(i2, DADDIUmask, DADDIUmatch)) &&
1509         i2.itype.rs == targetReg &&
1510         i2.itype.rt == targetReg) 
1511     {
1512       adjust += i2.itype.simm16;
1513       // debug
1514       insns.push_back(i2.raw);
1515       insnAddrs.push_back(start+off);
1516     }
1517     // lw R2,X(R1)
1518     // ld R2,X(R1)
1519     if ((isInsnType(i2, LWmask, LWmatch) || 
1520          isInsnType(i2, LDmask, LDmatch)) &&
1521         i2.itype.rt == targetReg) 
1522     {
1523       baseRegs.push_back((int)i2.itype.rs);
1524       baseAdjusts.push_back((int)i2.itype.simm16);
1525       adjusts.push_back(adjust);
1526       adjust = 0;
1527       targetReg = i2.itype.rs;
1528       // debug
1529       insns.push_back(i2.raw);
1530       insnAddrs.push_back(start+off);
1531     }
1532   }
1533
1534   // sanity check
1535   unsigned int n_loads = baseRegs.size();
1536   if (n_loads < 1) return 0;
1537   assert(baseAdjusts.size() == n_loads);
1538   assert(adjusts.size() == n_loads);
1539   //assert(n_loads > 0); // jump to $a1
1540   //assert(adjust == 0);
1541   
1542   // debug: target arithmetic
1543   /*
1544   fprintf(stderr, ">>> <0x%016lx:%s>", 
1545           owner->getObject().get_base_addr() + ip->address(),
1546           prettyName().string_of());
1547   fprintf(stderr, ": ");
1548   print_sequence(targetReg, baseAdjusts, adjusts, 0, NULL);
1549   fprintf(stderr, "\n");
1550   */
1551
1552   // debug: insn sequence
1553   /*
1554   instruction i3;
1555   for (int i = insns.size()-1; i >= 0; i--) {
1556     i3.raw = insns[i];
1557     dis(&i3, (void *)insnAddrs[i], 1, "  ");
1558   }
1559   */
1560
1561   // check base register
1562   Address target;
1563   const Object &elf = owner->getObject();
1564   switch(targetReg) {
1565   case REG_GP:
1566     target = elf.get_gp_value();
1567     break;
1568   case REG_T9:
1569   default:
1570     // base register is dynamic
1571     //fprintf(stderr, "!!! bogus base register $%s (%s,%0#10x)\n",
1572     //reg_names[targetReg], prettyName().string_of(), ip->address());
1573     return 0;
1574   }
1575
1576   Address obj_base = elf.get_base_addr();
1577   bool is_elf64= 
1578 #ifndef mips_unknown_ce2_11 //ccw 26 july 2000 : 28 mar 2001
1579           elf.is_elf64();
1580 #else
1581   false;
1582 #endif
1583
1584   // special case: function call via GOT entry
1585   if (baseRegs.size() == 1 && 
1586       targetReg == REG_GP &&
1587       adjusts[0] == 0) 
1588   {
1589     /* NOTE: We do not resolve the GOT entry yet.  While the static
1590        entry may appear to resolve to a local symbol, it can be
1591        preempted at runtime.  The Fortran function "MAIN__" is one
1592        such case. */
1593 #ifndef mips_unknown_ce2_11 //ccw 26 july 2000 : 28 mar 2001
1594
1595     Address got_entry_off = target + baseAdjusts[0] - obj_base;    
1596
1597     // check for calls to "main"
1598     const char *callee_name = elf.got_entry_name(got_entry_off);
1599     if (callee_name && !strcmp("main", callee_name)) {
1600       owner->main_call_addr_ = ip->address();
1601     }
1602     
1603     // wait for runtime value of GOT entry
1604     ip->hint_got_ = got_entry_off;
1605     return 0;
1606 #else
1607         cerr << "FAILURE: pd_Function::findIndirectJumpTarget(instPoint *ip, instruction i) wants GOT"<<endl;
1608         exit(-1);
1609 #endif 
1610
1611   }
1612   
1613   // debug: target arithmetic
1614   /*
1615   fprintf(stderr, ">>> findIndirectJumpTarget <0x%016lx: %s>\n", 
1616           ip->address() + obj_base, prettyName().string_of());
1617   fprintf(stderr, "  => ");
1618   print_sequence(targetReg, baseAdjusts, adjusts, 0, NULL);
1619   fprintf(stderr, "\n");
1620   */
1621
1622   // calculate jump target
1623  for(int ii = baseRegs.size()-1; ii >= 0; ii--) {
1624     Address vaddr = target + baseAdjusts[ii];
1625     Address vaddr_rel = vaddr - obj_base;
1626     // address-in-memory
1627     Address addr_in_mem = (is_elf64)
1628       ? (get_dword(elf, vaddr_rel))
1629       : (get_word(elf, vaddr_rel));
1630     if (addr_in_mem == 0) return 0;
1631     target = addr_in_mem + adjusts[ii];
1632   }
1633   target -= obj_base; // relative addressing
1634
1635   TRACE_E( "pd_Function::findIndirectJumpTarget" );
1636
1637   return target;
1638 }
1639
1640 /****************************************************************************/
1641 /****************************************************************************/
1642 /****************************************************************************/
1643
1644 bool doNotOverflow(int value)
1645 {
1646   TRACE_B( "doNotOverflow" );
1647
1648   //fprintf(stderr, ">>> doNotOverflow()\n");
1649   if (value >= MIN_IMM16 && value <= MAX_IMM16)
1650     {
1651       TRACE_E( "doNotOverflow" );
1652
1653       return true;
1654     }
1655
1656   TRACE_E( "doNotOverflow" );
1657
1658   return false;
1659 }
1660
1661 /****************************************************************************/
1662 /****************************************************************************/
1663 /****************************************************************************/
1664
1665 void generateNoOp(process *proc, Address addr) {
1666   TRACE_B( "generateNoOp" );
1667
1668   //fprintf(stderr, ">>> generateNoOp()\n");
1669   proc->writeTextWord((caddr_t)addr, NOP_INSN);
1670
1671   TRACE_E( "generateNoOp" );
1672 }
1673
1674 /****************************************************************************/
1675 /****************************************************************************/
1676 /****************************************************************************/
1677
1678 bool branchWithinRange(Address branch, Address target)
1679 {
1680   TRACE_B( "branchWithinRange" );
1681
1682   //fprintf(stderr, ">>> branchWithinRange(0x%08x,0x%08x)\n", branch, target);
1683   Address slot = branch + INSN_SIZE; // delay slot insn
1684
1685   // PC-region jump
1686   if (region_num(slot) == region_num(target))
1687     {
1688       TRACE_E( "branchWithinRange" );
1689
1690       return true;  
1691     }
1692
1693   // PC-relative branch
1694   RegValue offset = target - slot;
1695   if (offset >= BRANCH_MIN && offset <= BRANCH_MAX)
1696     {
1697       TRACE_E( "branchWithinRange" );
1698
1699       return true;
1700     }
1701
1702   TRACE_E( "branchWithinRange" );
1703
1704   return false;
1705 }
1706
1707 /****************************************************************************/
1708 /****************************************************************************/
1709 /****************************************************************************/
1710
1711 /* generateBranch():
1712    called by inst.C for instrumentation jumps
1713    - instPoint to basetramp
1714    - basetramp to minitramp
1715    - minitramp to minitramp
1716    - minitramp to basetramp
1717    - basetramp to instPoint
1718 */
1719 void generateBranch(process *p, Address branch, Address target)
1720 {
1721   TRACE_B( "generateBranch" );
1722
1723   //fprintf(stderr, "!!! generateBranch(): %0#10x to %0#10x", branch, target);
1724   assert(isAligned(branch));
1725   assert(isAligned(target));
1726
1727   instruction i;
1728
1729   Address slot = branch + INSN_SIZE; // address of delay slot insn
1730   if (region_num(slot) == region_num(target)) {
1731     // same 256MB region: direct jump
1732     //fprintf(stderr, " (PC-region branch)\n");
1733     i.jtype.op = Jop;
1734     i.jtype.imm26 = (target & REGION_OFF_MASK) >> 2;
1735   } else {
1736     RegValue offset = target - slot;
1737     if (offset >= BRANCH_MIN && offset <= BRANCH_MAX) {
1738       // within 18-bit offset: branch
1739       //fprintf(stderr, " (PC-relative branch)\n");
1740       genItype(&i, BEQop, REG_ZERO, REG_ZERO, offset >> 2);
1741     } else {
1742       // out of range: indirect jump (yuck)
1743       fprintf(stderr, " (indirect branch: out of range)\n");
1744       assert(0); // TODO: implement
1745     }
1746   }
1747  
1748   // TODO: delay slot insn?
1749   p->writeTextWord((caddr_t)branch, i.raw);
1750   //fprintf(stderr, ">>> generateBranch(): 0x%016lx to 0x%016lx\n", branch, target);
1751   //disDataSpace(p, (void *)branch, 1, "  ");
1752
1753   TRACE_E( "generateBranch" );
1754 }
1755
1756
1757 /****************************************************************************/
1758 /****************************************************************************/
1759 /****************************************************************************/
1760
1761 void genRtype(instruction *insn, int ops, reg rs, reg rt, 
1762               reg rd, int sa) 
1763 {
1764   TRACE_B( "genRtype" );
1765
1766   struct fmt_rtype *i = &insn->rtype;
1767   i->op = SPECIALop;
1768   i->rs = rs;
1769   i->rt = rt;
1770   i->rd = rd;
1771   i->sa = sa;
1772   i->ops = ops;
1773
1774   TRACE_E( "genRtype" );
1775 }
1776
1777 /****************************************************************************/
1778 /****************************************************************************/
1779 /****************************************************************************/
1780
1781 void genItype(instruction *insn, int op, reg rs, reg rt, signed short imm)
1782 {
1783   TRACE_B( "genItype" );
1784
1785   struct fmt_itype *i = &insn->itype;
1786   i->op = op;
1787   i->rs = rs;
1788   i->rt = rt;
1789   i->simm16 = imm;
1790
1791   TRACE_E( "genItype" );
1792 }
1793
1794 /****************************************************************************/
1795 /****************************************************************************/
1796 /****************************************************************************/
1797
1798 void genJtype(instruction *insn, int op, unsigned imm)
1799 {
1800   TRACE_B( "genJtype" );
1801
1802   struct fmt_jtype *i = &insn->jtype;
1803   i->op = op;
1804   i->imm26 = imm;
1805
1806   TRACE_E( "genJtype" );
1807 }
1808
1809 /****************************************************************************/
1810 /****************************************************************************/
1811 /****************************************************************************/
1812
1813 void genBranch(instruction *insn, Address branch, Address target) {
1814   TRACE_B( "genBranch" );
1815
1816   Address slot = branch + INSN_SIZE;
1817   RegValue disp_ = (target - slot) >> 2;
1818   assert(disp_ <= MAX_IMM16 && disp_ >= MIN_IMM16);
1819   signed short disp = (signed short)disp_;
1820   genItype(insn, BEQop, REG_ZERO, REG_ZERO, disp);
1821
1822   TRACE_E( "genBranch" );
1823 }
1824
1825 /****************************************************************************/
1826 /****************************************************************************/
1827 /****************************************************************************/
1828
1829 bool genJump(instruction *insn, Address branch, Address target) {
1830   TRACE_B( "genJump" );
1831
1832   Address slot = branch + INSN_SIZE;
1833   // try PC-region branch
1834   if (region_num(slot) == region_num(target)) {
1835     genJtype(insn, Jop, (target & REGION_OFF_MASK) >> 2);
1836
1837     TRACE_E( "genJump" );
1838
1839     return true;
1840   }
1841   // try PC-relative branch
1842   RegValue disp_ = (target - slot) >> 2;
1843   if (disp_ <= MAX_IMM16 && disp_ >= MIN_IMM16) {
1844     genBranch(insn, branch, target);
1845
1846     TRACE_E( "genJump" );
1847
1848     return true;
1849   }
1850   // one-insn branch failed
1851   assert(false); // TODO
1852
1853   TRACE_E( "genJump" );
1854
1855   return false;
1856 }
1857
1858 /****************************************************************************/
1859 /****************************************************************************/
1860 /****************************************************************************/
1861
1862 void genNop(instruction *insn) {
1863   TRACE_B( "genNop" );
1864
1865   insn->raw = NOP_INSN;
1866
1867   TRACE_E( "genNop" );
1868 }
1869
1870 /****************************************************************************/
1871 /****************************************************************************/
1872 /****************************************************************************/
1873
1874 void genTrap(instruction *insn) {
1875   TRACE_B( "genTrap" );
1876
1877   insn->raw = TRAP_INSN;
1878
1879   TRACE_E( "genTrap" );
1880 }
1881
1882 /****************************************************************************/
1883 /****************************************************************************/
1884 /****************************************************************************/
1885
1886 void genIll(instruction *insn) {
1887   TRACE_B( "genIll" );
1888
1889   insn->raw = ILLEGAL_INSN;
1890
1891   TRACE_E( "genIll" );
1892 }
1893 // "mov rd,rs" emitted as "or rd,rs,r0"
1894
1895 /****************************************************************************/
1896 /****************************************************************************/
1897 /****************************************************************************/
1898
1899 void genMove(instruction *insn, reg rs, reg rd) {
1900   TRACE_B( "genMove" );
1901
1902   genRtype(insn, ORops, rs, REG_ZERO, rd);
1903
1904   TRACE_E( "genMove" );
1905 }
1906
1907 /****************************************************************************/
1908 /****************************************************************************/
1909 /****************************************************************************/
1910
1911 #define IMM_NBITS ((Address)0x10)
1912 #define IMM_MASK  ((Address)0xffff)
1913 // next two must be same type as getImmField() return
1914 #define IMM_ZERO  ((UnsignedImm)0)
1915 #define IMM_ONES  ((UnsignedImm)~(UnsignedImm)0)
1916 #define bit(n,v) ((v >> n) & 0x1)
1917
1918 UnsignedImm getImmField(Address val, int n)
1919 {
1920   TRACE_B( "getImmField" );
1921
1922   Address offset = n * IMM_NBITS;
1923   Address mask = IMM_MASK << offset;
1924   UnsignedImm ret = (val & mask) >> offset;
1925
1926   TRACE_E( "getImmField" );
1927
1928   return ret;
1929 }
1930
1931 /****************************************************************************/
1932 /****************************************************************************/
1933 /****************************************************************************/
1934
1935 void genLoadNegConst(reg dst, Address imm, char *code, Address &base, bool /*noCost*/)
1936 {
1937   TRACE_B( "genLoadNegConst" );
1938
1939   //fprintf(stderr, ">>> genLoadNegConst(0x%016lx)\n", imm);
1940   //Address base_orig = base; // debug
1941
1942   int i;
1943   int nbits = sizeof(Address) * 8; // N-bit registers
1944   int nimm = (nbits/IMM_NBITS); // # of immediate (16-bit) fields
1945
1946   int zerobit; // highest significance zero bit (field #)
1947   for (zerobit = nimm - 1; zerobit > 0; zerobit--) {
1948     if (getImmField(imm, zerobit) != IMM_ONES) break;
1949   }
1950   int signbit = zerobit; // lowest significance sign bit (field #)
1951   // check if zero bit occurred in highest bit of a 16-bit field
1952   // if so, the previous field is the one with the last sign bit
1953   UnsignedImm zerofield = getImmField(imm, zerobit);
1954   if (!bit(IMM_NBITS-1, zerofield)) signbit++;
1955   assert(signbit < nimm);
1956   
1957   instruction *insn = (instruction *)(code + base);
1958   switch (signbit) {
1959   case 0:
1960 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
1961     genItype(insn, ADDIUop, REG_ZERO, dst, imm); //ccw 5 nov 2000
1962 #else
1963     genItype(insn, DADDIUop, REG_ZERO, dst, imm);
1964 #endif
1965     base += INSN_SIZE;
1966     break;
1967   default:
1968     genItype(insn, LUIop, 0, dst, getImmField(imm, signbit));
1969     base += INSN_SIZE;
1970     if (getImmField(imm, signbit-1) != 0) {
1971       genItype(insn+1, ORIop, dst, dst, getImmField(imm, signbit-1));
1972       base += INSN_SIZE;
1973     }
1974     for (i = signbit-2; i >= 0; i--) {
1975       insn = (instruction *)(code + base);
1976 #ifdef mips_unknown_ce2_11 //ccw 12 jan 2001 : 28 mar 2001
1977       genRtype(insn, SLLops, 0, dst, dst, IMM_NBITS);
1978 #else
1979       genRtype(insn, DSLLops, 0, dst, dst, IMM_NBITS);
1980 #endif
1981       base += INSN_SIZE;
1982       if (getImmField(imm, i) != 0) {
1983         genItype(insn+1, ORIop, dst, dst, getImmField(imm, i));
1984         base += INSN_SIZE;
1985       }
1986     }
1987   }
1988
1989   // debug
1990   /*
1991   for (Address i = base_orig; i < base; i += INSN_SIZE) {
1992     dis((instruction *)(code + i), NULL, 1, "  ");
1993   }
1994   */
1995
1996   TRACE_E( "genLoadNegConst" );
1997 }
1998
1999 /****************************************************************************/
2000 /****************************************************************************/
2001 /****************************************************************************/
2002
2003 void genLoadConst(reg dst, RegValue imm, char *code, Address &base, bool noCost)
2004 {
2005   TRACE_B( "genLoadConst" );
2006
2007   // if negative, use genLoadNegConst()
2008   if (imm < 0) {
2009     genLoadNegConst(dst, (Address)imm, code, base, noCost);
2010
2011     TRACE_E( "genLoadConst" );
2012
2013     return;
2014   }
2015
2016   //fprintf(stderr, ">>> genLoadConst(0x%lx)\n", imm);
2017   //Address base_orig = base; // debug
2018
2019   int nbits = sizeof(RegValue) * 8; // N-bit addresses
2020   int nimm = (nbits/IMM_NBITS); // # of immediate (16-bit) fields
2021   int nonzero = 0; // most significant nonzero field
2022   for (nonzero = nimm - 1; nonzero > 0; nonzero--) {
2023     if (getImmField(imm, nonzero) != IMM_ZERO) break;
2024   }
2025
2026   instruction *insn = (instruction *)(code + base);
2027   switch (nonzero) {
2028   case 0: 
2029     {
2030       genItype(insn, ORIop, REG_ZERO, dst, getImmField(imm, 0));
2031       base += INSN_SIZE;
2032     } break;
2033   default:
2034     {
2035       // load most significant nonzero field
2036       UnsignedImm field = getImmField(imm, nonzero);
2037       if (bit(IMM_NBITS-1, field)) {
2038         // MSB of first nonzero field is one 
2039         // (i.e. sign-extending would be bad)
2040         // => ori, dsll
2041         genItype(insn, ORIop, REG_ZERO, dst, field);
2042         base += INSN_SIZE;
2043 #ifdef mips_unknown_ce2_11 //ccw 12 jan 2001 : 28 mar 2001
2044         genRtype(insn+1, SLLops, 0, dst, dst, IMM_NBITS);
2045 #else
2046         genRtype(insn+1, DSLLops, 0, dst, dst, IMM_NBITS);
2047 #endif
2048         base += INSN_SIZE;
2049       } else {
2050         // MSB of first nonzero field is zero
2051         // => lui
2052         genItype(insn, LUIop, 0, dst, field);
2053         base += INSN_SIZE;
2054       }
2055       // load next field
2056       if (getImmField(imm, nonzero-1) != IMM_ZERO) {
2057         genItype(insn+1, ORIop, dst, dst, getImmField(imm, nonzero-1));
2058         base += INSN_SIZE;
2059       }
2060       // load remaining fields
2061       for (int i = nonzero-2; i >= 0; i--) {
2062         insn = (instruction *)(code + base);
2063 #ifdef mips_unknown_ce2_11 //ccw 12 jan 2001 : 28 mar 2001
2064         genRtype(insn, SLLops, 0, dst, dst, IMM_NBITS);
2065 #else
2066         genRtype(insn, DSLLops, 0, dst, dst, IMM_NBITS);
2067 #endif
2068         base += INSN_SIZE;
2069         if (getImmField(imm, i) != IMM_ZERO) {
2070           genItype(insn+1, ORIop, dst, dst, getImmField(imm, i));
2071           base += INSN_SIZE;
2072         }
2073       }
2074     }
2075   }
2076
2077   // debug
2078   /*
2079   for (Address i = base_orig; i < base; i += INSN_SIZE) {
2080     dis((instruction *)(code + i), NULL, 1, "  ");
2081   }
2082   */
2083
2084   TRACE_E( "genLoadConst" );
2085 }
2086
2087 /****************************************************************************/
2088 /****************************************************************************/
2089 /****************************************************************************/
2090
2091 // HERE BE DRAGONS
2092
2093 // return Address
2094 // [ifOp, branchOp, trampPreamble, trampTrailer]
2095 // TODO: "dst" is a Register, should be RegValue (holds branch offset)
2096 Address emitA(opCode op, Register src1, Register /*src2*/, Register dst, 
2097               char *code, Address &base, bool /*noCost*/)
2098 {
2099   TRACE_B( "emitA" );
2100
2101   Address ret = 0;
2102   instruction *insn = (instruction *)(code + base);
2103   RegValue word_off_;
2104   SignedImm word_off;
2105         int i;//ccw 10 apr 2001
2106
2107   switch (op) {
2108
2109   case ifOp:
2110     // "src1"     : condition register
2111     // "dst"      : branch target offset (bytes)
2112     // return val : branch insn offset (bytes)
2113     // TODO: nonzero conditon is true?
2114     //fprintf(stderr, ">>> emit(ifOp)\n"); 
2115     // BEQ offset is relative to delay slot and has word units
2116     // zero offsets are often used for dummy calls (padding)
2117     word_off_ = (dst) ? ((dst - INSN_SIZE) >> 2) : (0);
2118     assert(word_off_ <= MAX_IMM16);
2119     word_off = (SignedImm)word_off_;
2120     ret = base;
2121     genItype(insn, BEQop, src1, REG_ZERO, word_off);
2122     genNop(insn+1);
2123     base += 2*INSN_SIZE;
2124     break;
2125
2126   case branchOp:
2127     // "dst"      : branch target offset (bytes)
2128     // return val : branch insn offset (bytes)
2129     //fprintf(stderr, ">>> emit(branchOp)\n");
2130     // BEQ offset is relative to delay slot and has word units
2131     // zero offsets are often used for dummy calls (padding)
2132     word_off_ = (dst) ? ((dst - INSN_SIZE) >> 2) : (0);
2133     assert(word_off_ <= MAX_IMM16);
2134     word_off = (SignedImm)word_off_;
2135     ret = base;
2136     genItype(insn, BEQop, REG_ZERO, REG_ZERO, word_off);
2137     genNop(insn+1);
2138     base += 2*INSN_SIZE;
2139     break;
2140
2141   case trampPreamble:
2142     //fprintf(stderr, ">>> emit(trampPreamble)\n"); 
2143     // no trampoline preamble for this platform
2144     break;
2145
2146   case trampTrailer:
2147     // return = offset (in bytes) of branch insn
2148     // TODO: instInstance::returnAddr stores return value
2149     //       offset of branch insn could change (nops padded in front)
2150     //fprintf(stderr, ">>> emit(trampTrailer)\n");
2151     // allocate enough space for indirect jump (just in case)
2152     ret = base;
2153     for ( i = 0; i < 8; i++) genNop(insn+i);
2154     base += 8*INSN_SIZE;
2155     break;
2156
2157   default:
2158     assert(0);
2159   }
2160
2161   TRACE_E( "emitA" );
2162
2163   return ret;
2164 }
2165
2166 /****************************************************************************/
2167 /****************************************************************************/
2168 /****************************************************************************/
2169
2170 // return Register
2171 // [getParamOp, getSysParamOp, getRetValOp, getSysRetValOp]
2172 Register emitR(opCode op, Register src1, Register /*src2*/, Register dst, 
2173                char *code, Address &base, bool /*noCost*/)
2174 {
2175   TRACE_B( "emitR" );
2176
2177   Register ret = REG_ZERO;
2178   int frame_off = 0;
2179
2180   switch (op) {
2181
2182   case getParamOp:
2183     // "src1"     : argument number [0,7]
2184     // "dst"      : allocated return register
2185     // return val : argument register
2186     // TODO: extract >8 parameters from stack (need to know stack frame size)
2187     //fprintf(stderr, ">>> emit(getParamOp): %i\n", src1);
2188         if ( src1 <  //ccw 28 mar 2001
2189 #ifdef mips_unknown_ce2_11 //ccw 22 jan 2001 : ce only passes 4 args on the registers
2190                 4
2191 #else
2192                 8 
2193 #endif
2194     ){
2195       ret = dst;
2196 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2197           frame_off = 108 - (BYTES_PER_ARG * src1); // see tramp-mips.S
2198           // 108 comes from the position in the stack where register 4 is stored!
2199 #else
2200           frame_off = 216 - (BYTES_PER_ARG * src1); // see tramp-mips.S
2201 #endif
2202
2203 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2204       genItype((instruction *)(code + base), LWop, REG_SP, ret, frame_off);
2205 #else
2206       genItype((instruction *)(code + base), LDop, REG_SP, ret, frame_off);
2207 #endif
2208      base += INSN_SIZE;
2209     }
2210     else
2211     {
2212       ret = dst;
2213 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2214           frame_off = 128 ;//ccw 24 jan 2001 + (BYTES_PER_ARG * (src1-4)); 
2215           //128 is 32 registers * 4 bytes each
2216 #else
2217       frame_off = 512 + (BYTES_PER_ARG * (src1-8)); 
2218 #endif
2219
2220 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2221       genItype((instruction *)(code + base), LWop, REG_SP, ret, frame_off);
2222 #else
2223       genItype((instruction *)(code + base), LDop, REG_SP, ret, frame_off);
2224 #endif
2225      base += INSN_SIZE;
2226     }
2227     break;
2228
2229   case getSysParamOp:
2230     // "src1"     : argument number [0,7]
2231     // "dst"      : allocated return register
2232     // return val : argument register
2233     // TODO: extract >8 parameters from stack (need to know stack frame size)
2234     //fprintf(stderr, ">>> emit(getSysParamOp)\n");
2235     assert(src1 < 8);
2236     ret = dst;
2237 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2238           frame_off = 108 - (BYTES_PER_ARG * src1); // see tramp-mips.S
2239           //see above comment
2240 #else
2241           frame_off = 216 - (BYTES_PER_ARG * src1); // see tramp-mips.S
2242 #endif
2243
2244 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2245         //DebugBreak();
2246       genItype((instruction *)(code + base), LWop, REG_SP, ret, frame_off);
2247 #else
2248       genItype((instruction *)(code + base), LDop, REG_SP, ret, frame_off);
2249 #endif
2250    base += INSN_SIZE;
2251     break;
2252
2253   case getRetValOp:
2254     // "dst"      : allocated return register
2255     // return val : return value register
2256     //fprintf(stderr, ">>> emit(getRetValOp)\n");
2257     ret = dst;
2258 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : ccw 28 mar 2001
2259     frame_off = 116; // see tramp-mips.S
2260         // position of register 2
2261 #else
2262     frame_off = 232; // see tramp-mips.S
2263 #endif
2264
2265 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2266 //      DebugBreak();
2267       genItype((instruction *)(code + base), LWop, REG_SP, ret, frame_off);
2268 #else
2269       genItype((instruction *)(code + base), LDop, REG_SP, ret, frame_off);
2270 #endif
2271    base += INSN_SIZE;
2272     break;
2273
2274   case getSysRetValOp:
2275     // "dst"      : allocated return register
2276     // return val : return value register
2277     //fprintf(stderr, ">>> emit(getSysRetValOp)\n");
2278     ret = dst;
2279 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2280     frame_off = 116; // see tramp-mips.S
2281         // position of register 2
2282 #else
2283     frame_off = 232; // see tramp-mips.S
2284 #endif
2285
2286 #ifdef mips_unknown_ce2_11 //ccw 15 jan 2001 : 28 mar 2001
2287       genItype((instruction *)(code + base), LWop, REG_SP, ret, frame_off);
2288 #else
2289       genItype((instruction *)(code + base), LDop, REG_SP, ret, frame_off);
2290 #endif
2291    base += INSN_SIZE;
2292     break;
2293
2294   default:
2295     assert(0);
2296   }
2297
2298   TRACE_E( "emitR" );
2299
2300   return ret;
2301 }
2302
2303 /****************************************************************************/
2304 /****************************************************************************/
2305 /****************************************************************************/
2306
2307 // return void
2308 // [loadIndirOp, storeIndirOp, noOp, saveRegOp,
2309 //  plusOp, minusOp, timesOp, divOp,
2310 //  orOp, andOp, eqOp, neOp, lessOp, leOp, greaterOp, geOp]
2311 void emitV(opCode op, Register src1, Register src2, Register dst, 
2312            char *code, Address &base, bool /*noCost*/, int /* size */)
2313 {
2314   TRACE_B( "emitV" );
2315
2316   instruction *insn = (instruction *)(code + base);
2317
2318   switch (op) {
2319
2320   case noOp:
2321     //fprintf(stderr, ">>> emit(noOp)\n");
2322     genNop(insn);
2323     base += INSN_SIZE;
2324     break;
2325
2326   case saveRegOp:
2327     // not used on this platform
2328     fprintf(stderr, "!!! emit(saveRegOp): should never be called\n");
2329     assert(0);
2330
2331     /* memory operators */
2332
2333   case loadIndirOp:
2334     // TODO: 32/64-bit value
2335     // "src1"     : address register (from)
2336     // "dst"      : value register (to)
2337     genItype(insn, LWop, src1, dst, 0);
2338     base += INSN_SIZE;
2339     break;
2340   case storeIndirOp:
2341     // TODO: 32/64-bit value
2342     // "src1"     : value register (from)
2343     // "dst"      : address register (to)
2344     //fprintf(stderr, ">>> emit(storeIndirOp)\n"); 
2345     genItype(insn, SWop, dst, src1, 0);
2346     base += INSN_SIZE;
2347     break;
2348
2349     /* arithmetic operators */
2350
2351   case plusOp:
2352     //fprintf(stderr, ">>> emit(plusOp)\n");
2353 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2354     genRtype(insn, ADDUops, src1, src2, dst); //ccw 5 nov 2000
2355 #else
2356         genRtype(insn, DADDUops, src1, src2, dst);
2357 #endif
2358     base += INSN_SIZE;
2359     break;
2360   case minusOp:
2361     //fprintf(stderr, ">>> emit(minusOp)\n");
2362 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2363         genRtype(insn, SUBUops, src1, src2, dst);
2364 #else
2365         genRtype(insn, DSUBUops, src1, src2, dst);
2366 #endif
2367     base += INSN_SIZE;
2368     break;
2369   case timesOp:
2370     /* multiply ("mul rd,rs,imm") = four instructions
2371        mult  rs,rd   # (HI,LO) <- rs * rd
2372        mflo  rd      # rd <- LO
2373        nop           # padding for "mflo"
2374        nop           # padding for "mflo"
2375     */
2376     //fprintf(stderr, ">>> emit(timesOp)\n");
2377 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2378     genRtype(insn, MULTUops, src1, src2, 0);
2379 #else
2380     genRtype(insn, DMULTUops, src1, src2, 0);
2381 #endif
2382     genRtype(insn+1, MFLOops, 0, 0, dst);
2383     genNop(insn+2);
2384     genNop(insn+3);
2385     base += 4 * INSN_SIZE;
2386     break;
2387   case divOp:
2388     /* divide ("div rd,rs,imm") = four instructions
2389        div   rs,rd   # (HI,LO) <- rs / rd
2390        mflo  rd      # rd <- LO
2391        nop           # padding for "mflo"
2392        nop           # padding for "mflo"
2393     */
2394     //fprintf(stderr, ">>> emit(divOp)\n");
2395 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2396         genRtype(insn, DIVUops, src1, src2, 0);
2397 #else
2398         genRtype(insn, DDIVUops, src1, src2, 0);
2399 #endif
2400     genRtype(insn+1, MFLOops, 0, 0, dst);
2401     genNop(insn+2);
2402     genNop(insn+3);
2403     base += 4 * INSN_SIZE;
2404     break;
2405
2406     /* relational operators */
2407
2408   case lessOp:
2409     //fprintf(stderr, ">>> emit(lessOp)\n");
2410     genRtype(insn, SLTUops, src1, src2, dst);
2411     base += INSN_SIZE;
2412     break;
2413   case greaterOp:
2414     //fprintf(stderr, ">>> emit(greaterOp)\n");
2415     genRtype(insn, SLTUops, src2, src1, dst);
2416     base += INSN_SIZE;
2417     break;    
2418   case leOp:
2419     //fprintf(stderr, ">>> emit(leOp)\n");
2420     genItype(insn, BEQLop, src1, src2, 0x2);
2421     genItype(insn+1, ORIop, REG_ZERO, dst, 0x1);
2422     genRtype(insn+2, SLTUops, src1, src2, dst);
2423     base += 3 * INSN_SIZE;
2424     break;
2425   case geOp:
2426     //fprintf(stderr, ">>> emit(geOp)\n");
2427     genItype(insn, BEQLop, src1, src2, 0x2);
2428     genItype(insn+1, ORIop, REG_ZERO, dst, 0x1);
2429     genRtype(insn+2, SLTUops, src2, src1, dst);
2430     base += 3 * INSN_SIZE;
2431     break;
2432   case eqOp:
2433     //fprintf(stderr, ">>> emit(eqOp)\n");
2434     genItype(insn, BEQLop, src1, src2, 0x2);
2435     genItype(insn+1, ORIop, REG_ZERO, dst, 0x1);
2436     genItype(insn+2, ORIop, REG_ZERO, dst, 0x0);
2437     base += 3 * INSN_SIZE;
2438     break;
2439   case neOp:
2440     //fprintf(stderr, ">>> emit(neOp)\n");
2441     genItype(insn, BNELop, src1, src2, 0x2);
2442     genItype(insn+1, ORIop, REG_ZERO, dst, 0x1);
2443     genItype(insn+2, ORIop, REG_ZERO, dst, 0x0);
2444     base += 3 * INSN_SIZE;
2445     break;
2446
2447     /* boolean operators */
2448
2449   case orOp:
2450     //fprintf(stderr, ">>> emit(orOp)\n");
2451     genRtype(insn, ORops, src1, src2, dst);
2452     base += INSN_SIZE;
2453     break;
2454   case andOp:
2455     //fprintf(stderr, ">>> emit(andOp)\n");
2456     genRtype(insn, ANDops, src1, src2, dst);
2457     base += INSN_SIZE;
2458     break;
2459
2460
2461   default:
2462     fprintf(stderr, "!!! illegal operator %i emitted\n", op);
2463     assert(0);
2464   }
2465
2466   TRACE_E( "emitV" );
2467 }
2468
2469 /****************************************************************************/
2470 /****************************************************************************/
2471 /****************************************************************************/
2472
2473 // [loadConstOp, loadOp]
2474 void emitVload(opCode op, Address src1, Register /*src2*/, Register dst, 
2475                char *code, Address &base, bool noCost, int size)
2476 {
2477   TRACE_B( "emitVload" );
2478
2479   switch (op) {
2480
2481   case loadConstOp:
2482     // "src1" : constant value to load
2483     //fprintf(stderr, ">>> emit(loadConstOp)\n");
2484     genLoadConst(dst, src1, code, base, noCost);
2485     break;
2486
2487   case loadOp:
2488     // TODO: 32/64-bit value
2489     // "src1" : address value (from)
2490     // "dst"  : value register (to)
2491     //fprintf(stderr, ">>> emit(loadOp)\n");
2492     genLoadConst(dst, src1, code, base, noCost);
2493     if (size == sizeof(uint32_t)) {
2494       // 32-bit load (use "loadIndirOp")
2495       emitV(loadIndirOp, dst, 0, dst, code, base, noCost);
2496     } else if (size == sizeof(uint64_t)) {
2497       // 64-bit load
2498                 //ccw 15 jan 2001 : 28 mar 2001
2499                 // this is a 64 bit load. when is it used? 
2500                 // it will need to be split...
2501                 // TODO
2502       genItype((instruction *)(code + base), LDop, dst, dst, 0);
2503       base += INSN_SIZE;
2504     } else {
2505       // bogus pointer size
2506       assert(0);
2507     }
2508     break;
2509
2510   default: 
2511     assert(0);
2512   }
2513
2514   TRACE_E( "emitVload" );
2515 }
2516
2517 /****************************************************************************/
2518 /****************************************************************************/
2519 /****************************************************************************/
2520
2521 // [storeOp]
2522 void emitVstore(opCode op, Register src1, Register src2, Address dst, 
2523                 char *code, Address &base, bool noCost, int size)
2524 {
2525   TRACE_B( "emitVstore" );
2526
2527   assert(op == storeOp);
2528   // "src1" : value register (from)
2529   // "src2" : scratch address register (to)
2530   // "dst"  : address value (to)
2531   //fprintf(stderr, ">>> emit(storeOp)\n");
2532   genLoadConst(src2, dst, code, base, noCost);
2533   if (size == sizeof(uint32_t)) {
2534     // 32-bit store (use "storeIndirOp")
2535     emitV(storeIndirOp, src1, 0, src2, code, base, noCost);
2536   } else if (size == sizeof(uint64_t)) {
2537     // 64-bit store
2538     genItype((instruction *)(code + base), SDop, src2, src1, 0);
2539     base += INSN_SIZE;
2540   } else {
2541     // bogus pointer size
2542     assert(0);
2543   }
2544
2545   TRACE_E( "emitVstore" );
2546 }
2547
2548 /****************************************************************************/
2549 /****************************************************************************/
2550 /****************************************************************************/
2551
2552 // [updateCostOp]
2553 void emitVupdate(opCode op, RegValue src1, Register /*src2*/, Address dst, 
2554                  char *code, Address &base, bool noCost)
2555 {
2556   TRACE_B( "emitVupdate" );
2557
2558   //fprintf(stderr, ">>> emit(updateCostOp)\n");
2559   //Address base_orig = base; // debug
2560   assert(op == updateCostOp);
2561
2562   if (!noCost) {
2563     Address cost_addr = dst;
2564     Address cost_update = src1;
2565     /* (15 insns max)
2566        set     r1,cost_addr (6 insns max)
2567        lw      r3,r1
2568        set     r2,cost_update (6 insns max)
2569        daddu   r2,r2,r3
2570        sw      r2,r1
2571        (stomps three registers)
2572     */
2573     Register r1 = regSpace->allocateRegister(code, base, noCost); // cost address
2574     Register r3 = regSpace->allocateRegister(code, base, noCost); // cost
2575     genLoadConst(r1, cost_addr, code, base, noCost);
2576     // NOTE: 32-bit value, see obsCostLow and processCost()
2577     genItype((instruction *)(code + base), LWop, r1, r3, 0);
2578     base += INSN_SIZE;
2579     if (doNotOverflow(cost_update)) {
2580       emitImm(plusOp, r3, cost_update, r3, code, base, noCost);
2581     } else {
2582       Register r2 = regSpace->allocateRegister(code, base, noCost); // cost update
2583       genLoadConst(r2, cost_update, code, base, noCost);
2584       emitV(plusOp, r2, r3, r3, code, base, noCost);
2585       regSpace->freeRegister(r2);
2586     }
2587     genItype((instruction *)(code + base), SWop, r1, r3, 0);
2588     base += INSN_SIZE;
2589     regSpace->freeRegister(r3);
2590     regSpace->freeRegister(r1);
2591   }
2592
2593   // debug
2594   //int ninsns = (base - base_orig) / INSN_SIZE;
2595   //fprintf(stderr, "  updateCostOp code (%i insns):\n", ninsns);
2596   //dis(code + base_orig, NULL, ninsns, "  ");
2597
2598   TRACE_E( "emitVupdate" );
2599 }
2600
2601
2602 /****************************************************************************/
2603 /****************************************************************************/
2604 /****************************************************************************/
2605
2606 /* emitImm(): This function is complicated because of the MIPS RISC
2607    architecture.  Specifically, the only immediate instruction
2608    primitives are "add" and "set less than". 
2609 */
2610 // TODO - signed operations
2611 // TODO - immediate insns use 32- or 64-bit operands?
2612 void emitImm(opCode op, Register src, RegValue imm, Register dst, 
2613              char *code, Address &base, bool noCost)
2614 {
2615   TRACE_B( "emitImm" );
2616
2617   //fprintf(stderr, ">>> emitImm(): op %s,%s,%i\n", reg_names[dst], reg_names[src], imm);
2618   instruction *insn = (instruction *)(code + base);
2619   int n;
2620
2621   // immediate value should fit in immediate field
2622   switch (op) {
2623     
2624     /* arithmetic operands */
2625     
2626   case plusOp:
2627     if (!doNotOverflow(imm)) break;
2628 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2629     genItype(insn, ADDIUop, src, dst, imm); //ccw 5 nov 2000
2630 #else
2631     genItype(insn, DADDIUop, src, dst, imm);
2632 #endif
2633     base += INSN_SIZE;
2634
2635     TRACE_E( "emitImm" );
2636
2637     return;
2638   case minusOp:
2639     if (!doNotOverflow(-imm)) break;
2640 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2641         genItype(insn, ADDIUop, src, dst, -imm); //ccw 5 nov 2000
2642 #else
2643         genItype(insn, DADDIUop, src, dst, -imm);
2644 #endif
2645     base += INSN_SIZE;
2646
2647     TRACE_E( "emitImm" );
2648
2649     return;
2650   case timesOp:
2651     if (!isPowerOf2(imm, n) || (n >= 64)) break;
2652     // use left shift for powers of 2
2653      if (n < 32){
2654
2655 #ifdef mips_unknown_ce2_11 //ccw 12 jan 2001 : 28 mar 2001
2656                 //ce does not support DSLL!
2657                 genRtype(insn, SLLops, 0, src, dst, n);
2658 #else
2659                 genRtype(insn, DSLLops, 0, src, dst, n);
2660 #endif
2661
2662         }else{
2663
2664 #ifdef mips_unknown_ce2_11 //ccw 12 jan 2001
2665                 exit(-1);               
2666 #else
2667                 genRtype(insn, DSLL32ops, 0, src, dst, n-32);
2668 #endif
2669         }
2670     base += INSN_SIZE;
2671
2672     TRACE_E( "emitImm" );
2673
2674     return;
2675   case divOp:
2676     if (!isPowerOf2(imm, n) || n >= 64) break;
2677     // use right shift for powers of 2
2678     if (n < 32) genRtype(insn, DSRAops, 0, src, dst, n);
2679     else genRtype(insn, DSRA32ops, 0, src, dst, n-32);
2680     base += INSN_SIZE;
2681
2682     TRACE_E( "emitImm" );
2683
2684     return;
2685     
2686     /* relational operands */
2687     
2688   case lessOp:
2689     if (!doNotOverflow(imm)) break;
2690     genItype(insn, SLTIUop, src, dst, imm);
2691     base += INSN_SIZE;
2692
2693     TRACE_E( "emitImm" );
2694
2695     return; 
2696   case eqOp:
2697     if (!doNotOverflow(-imm)) break;
2698     // saves one register over emitV()
2699 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2700     genItype(insn, ADDIUop, src, dst, -imm); //ccw 5 nov 2000
2701 #else
2702     genItype(insn, DADDIUop, src, dst, -imm);
2703 #endif
2704     genItype(insn+1, BEQLop, dst, REG_ZERO, 0x2);
2705     genItype(insn+2, ORIop, REG_ZERO, dst, 0x1);
2706     genItype(insn+3, ORIop, REG_ZERO, dst, 0x0);
2707     base += 4 * INSN_SIZE;
2708
2709     TRACE_E( "emitImm" );
2710
2711     return;
2712   case neOp:
2713     if (!doNotOverflow(-imm)) break;
2714     // saves one register over emitV()
2715 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2716     genItype(insn, ADDIUop, src, dst, -imm); //ccw 5 nov 2000
2717 #else
2718     genItype(insn, DADDIUop, src, dst, -imm);
2719 #endif
2720     genItype(insn+1, BNELop, dst, REG_ZERO, 0x2);
2721     genItype(insn+2, ORIop, REG_ZERO, dst, 0x1);
2722     genItype(insn+3, ORIop, REG_ZERO, dst, 0x0);
2723     base += 4 * INSN_SIZE;
2724
2725     TRACE_E( "emitImm" );
2726
2727     return;
2728   case greaterOp:
2729   case leOp:
2730   case geOp:
2731     // unsafe as immediate insns
2732     break;
2733     
2734     /* boolean operands */
2735     
2736   case orOp:
2737     if (!doNotOverflow(imm)) break;
2738     genItype(insn, ORIop, src, dst, imm);
2739     base += INSN_SIZE;
2740
2741     TRACE_E( "emitImm" );
2742
2743     return;
2744   case andOp:
2745     if (!doNotOverflow(imm)) break;
2746     genItype(insn, ANDIop, src, dst, imm);
2747     base += INSN_SIZE;
2748
2749     TRACE_E( "emitImm" );
2750
2751     return;
2752       
2753   default:
2754     assert(0);
2755   }
2756
2757   // default: use the general-purpose code generator "emitV()"
2758   // load the "immediate" value into a register and call emitV()
2759   Register src2 = regSpace->allocateRegister(code, base, noCost);
2760   genLoadConst(src2, imm, code, base, noCost);
2761   emitV(op, src, src2, dst, code, base, noCost);
2762   regSpace->freeRegister(src2);
2763
2764   TRACE_E( "emitImm" );
2765
2766   return;
2767 }
2768
2769 /****************************************************************************/
2770 /****************************************************************************/
2771 /****************************************************************************/
2772
2773 bool process::emitInferiorRPCheader(void *code_, Address &base)
2774 {
2775   TRACE_B( "process::emitInferiorRPCheader" );
2776
2777   //fprintf(stderr, ">>> process::emitInferiorRPCheader()\n");
2778   char *code = (char *)code_;
2779   instruction *insn = (instruction *)(code + base);
2780
2781   // TODO: why 512 bytes? not using basetramp code, right?
2782 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2783         //DebugBreak(); //ccw 16 jan 2001
2784         genItype(insn, ADDIUop, REG_SP, REG_SP, -512); //ccw 5 nov 2000 : was 512
2785 #else
2786         genItype(insn, DADDIUop, REG_SP, REG_SP, -512); // daddiu sp,sp,-512
2787 #endif
2788   base += INSN_SIZE;
2789
2790   TRACE_E( "process::emitInferiorRPCheader" );
2791
2792   return true;
2793 }
2794
2795 /****************************************************************************/
2796 /****************************************************************************/
2797 /****************************************************************************/
2798
2799 // TODO: should offset parameters be Address's?
2800 bool process::emitInferiorRPCtrailer(void *code_, Address &base,
2801                                      unsigned &breakOffset,
2802                                      bool stopForResult,
2803                                      unsigned &stopForResultOffset,
2804                                      unsigned &justAfter_stopForResultOffset)
2805 {
2806   TRACE_B( "process::emitInferiorRPCtrailer" );
2807
2808   //fprintf(stderr, ">>> process::emitInferiorRPCtrailer()\n");
2809   char *code = (char *)code_;
2810
2811   // optional code for grabbing RPC result
2812   if (stopForResult) {
2813     instruction *insn = (instruction *)(code + base);
2814     genTrap(insn); // trap to grab result
2815     stopForResultOffset = base;
2816     base += INSN_SIZE;
2817     justAfter_stopForResultOffset = base;
2818   }
2819
2820   // mandatory RPC trailer: restore, trap, illegal
2821   instruction *insn = (instruction *)(code + base);
2822   // daddiu sp,sp,512
2823 #ifdef mips_unknown_ce2_11 //ccw 5 nov 2000 : 28 mar 2001
2824         genItype(insn, ADDIUop, REG_SP, REG_SP, 512); //ccw 5 nov 2000 : was 512
2825 #else
2826         genItype(insn, DADDIUop, REG_SP, REG_SP, 512);
2827 #endif
2828   base += INSN_SIZE;
2829   // trap insn
2830   genTrap(insn+1);
2831   breakOffset = base;
2832   base += INSN_SIZE;
2833   // illegal insn
2834   genIll(insn+2);
2835   base += INSN_SIZE;
2836
2837   TRACE_E( "process::emitInferiorRPCtrailer" );
2838
2839   return true;
2840 }
2841
2842 /****************************************************************************/
2843 /****************************************************************************/
2844 /****************************************************************************/
2845
2846 int getInsnCost(opCode op)
2847 {
2848   TRACE_B( "getInsnCost" );
2849
2850   //fprintf(stderr, ">>> getInsnCost()\n");
2851   switch(op) {
2852
2853   case plusOp:
2854   case minusOp: 
2855   case timesOp:
2856   case divOp:
2857   case orOp:
2858   case andOp:
2859
2860     TRACE_E( "getInsnCost" );
2861
2862     return 1;
2863
2864   case lessOp:
2865   case greaterOp:
2866
2867     TRACE_E( "getInsnCost" );
2868
2869     return 1;
2870
2871   case leOp:
2872   case geOp:
2873   case eqOp:
2874   case neOp:
2875
2876     TRACE_E( "getInsnCost" );
2877
2878     return 3;
2879
2880   case noOp:
2881
2882     TRACE_E( "getInsnCost" );
2883
2884     return 1;
2885
2886   case loadConstOp:
2887
2888     TRACE_E( "getInsnCost" );
2889
2890     return 3; // average = 3.0625
2891
2892   case getAddrOp:
2893     // usually generates "loadConstOp" above
2894
2895     TRACE_E( "getInsnCost" );
2896
2897     return 3;
2898
2899   case loadOp:
2900   case storeOp:
2901
2902     TRACE_E( "getInsnCost" );
2903
2904     return 4; // average = 4.0625
2905
2906   case ifOp:
2907   case branchOp:
2908
2909     TRACE_E( "getInsnCost" );
2910
2911     return 2;
2912
2913   case callOp:
2914     // assume 2 parameters
2915     // mov, mov, lui, ori, jalr, nop
2916
2917     TRACE_E( "getInsnCost" );
2918
2919     return 6;
2920
2921   case trampPreamble:
2922
2923     TRACE_E( "getInsnCost" );
2924
2925     return 0;
2926
2927   case trampTrailer:
2928     // padded in case indirect jump needed
2929
2930     TRACE_E( "getInsnCost" );
2931
2932     return 8;
2933
2934   case getRetValOp:
2935   case getSysRetValOp: 
2936   case getParamOp:
2937   case getSysParamOp:      
2938
2939     TRACE_E( "getInsnCost" );
2940
2941     return 1;
2942
2943   case loadIndirOp:
2944   case storeIndirOp:
2945
2946     TRACE_E( "getInsnCost" );
2947
2948     return 1;
2949
2950   case updateCostOp:
2951     // padded for two constant loads (cost value and address)
2952
2953     TRACE_E( "getInsnCost" );
2954
2955     return 15;
2956
2957   case saveRegOp:
2958     // not used on this platform
2959
2960     TRACE_E( "getInsnCost" );
2961
2962     assert(0);
2963     
2964   case loadFrameAddr:
2965   case storeFrameRelativeOp:
2966     // TODO: not implemented on this platform
2967     assert(0);
2968
2969   default:
2970     assert(0);
2971   }
2972
2973   TRACE_E( "getInsnCost" );
2974
2975   return 0;
2976 }
2977
2978 /****************************************************************************/
2979 /****************************************************************************/
2980 /****************************************************************************/
2981 #ifndef mips_unknown_ce2_11 //ccw 13 apr 2001
2982
2983 // baseTramp assembly code symbols
2984 extern "C" void baseTramp();
2985 extern "C" void baseTramp_savePreInsn();
2986 extern "C" void baseTramp_skipPreInsn();
2987 extern "C" void baseTramp_globalPreBranch();
2988 extern "C" void baseTramp_localPreBranch();
2989 extern "C" void baseTramp_localPreReturn();
2990 extern "C" void baseTramp_updateCostInsn();
2991 extern "C" void baseTramp_restorePreInsn();
2992 extern "C" void baseTramp_emulateInsn();
2993 extern "C" void baseTramp_skipPostInsn();
2994 extern "C" void baseTramp_savePostInsn();
2995 extern "C" void baseTramp_globalPostBranch();
2996 extern "C" void baseTramp_localPostBranch();
2997 extern "C" void baseTramp_localPostReturn();
2998 extern "C" void baseTramp_restorePostInsn();
2999 extern "C" void baseTramp_returnInsn();
3000 extern "C" void baseTramp_endTramp();
3001
3002 extern "C" void baseNonRecursiveTramp();
3003 extern "C" void baseNonRecursiveTramp_savePreInsn();
3004 extern "C" void baseNonRecursiveTramp_skipPreInsn();
3005 extern "C" void baseNonRecursiveTramp_guardOnPre_begin();
3006 extern "C" void baseNonRecursiveTramp_guardOnPre_end();
3007 extern "C" void baseNonRecursiveTramp_globalPreBranch();
3008 extern "C" void baseNonRecursiveTramp_localPreBranch();
3009 extern "C" void baseNonRecursiveTramp_localPreReturn();
3010 extern "C" void baseNonRecursiveTramp_guardOffPre_begin();
3011 extern "C" void baseNonRecursiveTramp_guardOffPre_end();
3012 extern "C" void baseNonRecursiveTramp_updateCostInsn();
3013 extern "C" void baseNonRecursiveTramp_restorePreInsn();
3014 extern "C" void baseNonRecursiveTramp_emulateInsn();
3015 extern "C" void baseNonRecursiveTramp_skipPostInsn();
3016 extern "C" void baseNonRecursiveTramp_savePostInsn();
3017 extern "C" void baseNonRecursiveTramp_guardOnPost_begin();
3018 extern "C" void baseNonRecursiveTramp_guardOnPost_end();
3019 extern "C" void baseNonRecursiveTramp_globalPostBranch();
3020 extern "C" void baseNonRecursiveTramp_localPostBranch();
3021 extern "C" void baseNonRecursiveTramp_localPostReturn();
3022 extern "C" void baseNonRecursiveTramp_guardOffPost_begin();
3023 extern "C" void baseNonRecursiveTramp_guardOffPost_end();
3024 extern "C" void baseNonRecursiveTramp_restorePostInsn();
3025 extern "C" void baseNonRecursiveTramp_returnInsn();
3026 extern "C" void baseNonRecursiveTramp_endTramp();
3027
3028 extern "C" void conservativeTramp();
3029 extern "C" void conservativeTramp_savePreInsn();
3030 extern "C" void conservativeTramp_skipPreInsn();
3031 extern "C" void conservativeTramp_globalPreBranch();
3032 extern "C" void conservativeTramp_localPreBranch();
3033 extern "C" void conservativeTramp_localPreReturn();
3034 extern "C" void conservativeTramp_updateCostInsn();
3035 extern "C" void conservativeTramp_restorePreInsn();
3036 extern "C" void conservativeTramp_emulateInsn();
3037 extern "C" void conservativeTramp_skipPostInsn();
3038 extern "C" void conservativeTramp_savePostInsn();
3039 extern "C" void conservativeTramp_globalPostBranch();
3040 extern "C" void conservativeTramp_localPostBranch();
3041 extern "C" void conservativeTramp_localPostReturn();
3042 extern "C" void conservativeTramp_restorePostInsn();
3043 extern "C" void conservativeTramp_returnInsn();
3044 extern "C" void conservativeTramp_endTramp();
3045 #endif
3046
3047 /****************************************************************************/
3048 /****************************************************************************/
3049 /****************************************************************************/
3050
3051 void initTramps()
3052 {
3053   TRACE_B( "initTramps" );
3054
3055   static bool inited = false;
3056   if (inited)
3057     {
3058       TRACE_E( "initTramps" );
3059
3060       return;
3061     }
3062   inited = true;
3063
3064   // register space
3065   regSpace = new registerSpace(nDead, Dead, 0, NULL);
3066   assert(regSpace);
3067 #ifdef mips_unknown_ce2_11 //ccw 3 aug 2000 : 28 mar 2001
3068         baseTemplate.savePreInsOffset = baseTemplate_savePreInsOffset;
3069         baseTemplate.skipPreInsOffset = baseTemplate_skipPreInsOffset;
3070         baseTemplate.globalPreOffset = baseTemplate_globalPreOffset;
3071         baseTemplate.localPreOffset = baseTemplate_localPreOffset;
3072         baseTemplate.localPreReturnOffset = baseTemplate_localPreReturnOffset;
3073         baseTemplate.updateCostOffset = baseTemplate_updateCostOffset;
3074         baseTemplate.restorePreInsOffset = baseTemplate_restorePreInsOffset;
3075         baseTemplate.emulateInsOffset = baseTemplate_emulateInsOffset;
3076         baseTemplate.skipPostInsOffset = baseTemplate_skipPostInsOffset;
3077         baseTemplate.savePostInsOffset = baseTemplate_savePostInsOffset;
3078         baseTemplate.globalPostOffset = baseTemplate_globalPostOffset;
3079         baseTemplate.localPostOffset = baseTemplate_localPostOffset;
3080         baseTemplate.localPostReturnOffset = baseTemplate_localPostReturnOffset;
3081         baseTemplate.restorePostInsOffset = baseTemplate_restorePostInsOffset;
3082         baseTemplate.returnInsOffset = baseTemplate_returnInsOffset;
3083
3084         baseTemplate.trampTemp = (void*)baseTemplate_trampTemp;
3085         baseTemplate.size = baseTemplate_size;
3086         baseTemplate.cost = baseTemplate_cost;
3087         baseTemplate.prevBaseCost = baseTemplate_prevBaseCost;
3088         baseTemplate.postBaseCost = baseTemplate_postBaseCost;
3089         baseTemplate.prevInstru = baseTemplate_prevInstru;
3090         baseTemplate.postInstru = baseTemplate_postInstru;
3091         //baseTemplate.endTramp = baseTemplate_endTramp;
3092
3093         nonRecursiveBaseTemplate.guardOffPost_beginOffset = nonRecursiveBaseTemplate_guardOffPost_beginOffset;
3094         nonRecursiveBaseTemplate.savePreInsOffset = nonRecursiveBaseTemplate_savePreInsOffset;
3095         nonRecursiveBaseTemplate.skipPreInsOffset = nonRecursiveBaseTemplate_skipPreInsOffset;
3096         nonRecursiveBaseTemplate.globalPreOffset  = nonRecursiveBaseTemplate_globalPreOffset;
3097         nonRecursiveBaseTemplate.localPreOffset = nonRecursiveBaseTemplate_localPreOffset;
3098         nonRecursiveBaseTemplate.localPreReturnOffset = nonRecursiveBaseTemplate_localPreReturnOffset;
3099         nonRecursiveBaseTemplate.updateCostOffset = nonRecursiveBaseTemplate_updateCostOffset;
3100         nonRecursiveBaseTemplate.restorePreInsOffset = nonRecursiveBaseTemplate_restorePreInsOffset;
3101         nonRecursiveBaseTemplate.emulateInsOffset = nonRecursiveBaseTemplate_emulateInsOffset;
3102         nonRecursiveBaseTemplate.skipPostInsOffset = nonRecursiveBaseTemplate_skipPostInsOffset;
3103         nonRecursiveBaseTemplate.savePostInsOffset = nonRecursiveBaseTemplate_savePostInsOffset;
3104         nonRecursiveBaseTemplate.globalPostOffset = nonRecursiveBaseTemplate_globalPostOffset;
3105         nonRecursiveBaseTemplate.localPostOffset = nonRecursiveBaseTemplate_localPostOffset;
3106         nonRecursiveBaseTemplate.localPostReturnOffset = nonRecursiveBaseTemplate_localPostReturnOffset;
3107         nonRecursiveBaseTemplate.restorePostInsOffset = nonRecursiveBaseTemplate_restorePostInsOffset;
3108         nonRecursiveBaseTemplate.returnInsOffset = nonRecursiveBaseTemplate_returnInsOffset;
3109         nonRecursiveBaseTemplate.guardOnPre_beginOffset = nonRecursiveBaseTemplate_guardOnPre_beginOffset;
3110         nonRecursiveBaseTemplate.guardOffPre_beginOffset = nonRecursiveBaseTemplate_guardOffPre_beginOffset;
3111         nonRecursiveBaseTemplate.guardOnPost_beginOffset = nonRecursiveBaseTemplate_guardOnPost_beginOffset;
3112         nonRecursiveBaseTemplate.guardOffPost_beginOffset = nonRecursiveBaseTemplate_guardOffPost_beginOffset;
3113         nonRecursiveBaseTemplate.guardOnPre_endOffset = nonRecursiveBaseTemplate_guardOnPre_endOffset;
3114         nonRecursiveBaseTemplate.guardOffPre_endOffset = nonRecursiveBaseTemplate_guardOffPre_endOffset;
3115         nonRecursiveBaseTemplate.guardOnPost_endOffset = nonRecursiveBaseTemplate_guardOnPost_endOffset;
3116         nonRecursiveBaseTemplate.guardOffPost_endOffset = nonRecursiveBaseTemplate_guardOffPost_endOffset;
3117         //ccw 20 aug 2000 added the &
3118         nonRecursiveBaseTemplate.trampTemp =  (void*) baseNonRecursiveTramp; //ccw 17 oct 2000
3119
3120         nonRecursiveBaseTemplate.size = nonRecursiveBaseTemplate_size;
3121         nonRecursiveBaseTemplate.cost = nonRecursiveBaseTemplate_cost;
3122         nonRecursiveBaseTemplate.prevBaseCost = nonRecursiveBaseTemplate_prevBaseCost;
3123         nonRecursiveBaseTemplate.postBaseCost = nonRecursiveBaseTemplate_postBaseCost;
3124         nonRecursiveBaseTemplate.prevInstru = nonRecursiveBaseTemplate_prevInstru;
3125         nonRecursiveBaseTemplate.postInstru = nonRecursiveBaseTemplate_postInstru;
3126
3127 #else
3128
3129   // base trampoline template
3130   Address i, base = (Address)baseTramp;
3131   for (i = base; i < (Address)baseTramp_endTramp; i += INSN_SIZE) {
3132     Address off = i - base;
3133     // note: these should not be made into if..else blocks
3134     // (some of the label values are the same)
3135
3136     if (i == (Address)baseTramp_savePreInsn)
3137       baseTemplate.savePreInsOffset = off;
3138
3139     if (i == (Address)baseTramp_skipPreInsn)
3140       baseTemplate.skipPreInsOffset = off;
3141
3142     if (i == (Address)baseTramp_globalPreBranch)
3143       baseTemplate.globalPreOffset = off;
3144
3145     if (i == (Address)baseTramp_localPreBranch)
3146       baseTemplate.localPreOffset = off;
3147     if (i == (Address)baseTramp_localPreReturn)
3148       baseTemplate.localPreReturnOffset = off;
3149
3150     if (i == (Address)baseTramp_updateCostInsn)
3151       baseTemplate.updateCostOffset = off;
3152
3153     if (i == (Address)baseTramp_restorePreInsn)
3154       baseTemplate.restorePreInsOffset = off;
3155
3156     if (i == (Address)baseTramp_emulateInsn)
3157       baseTemplate.emulateInsOffset = off;
3158
3159     if (i == (Address)baseTramp_skipPostInsn)
3160       baseTemplate.skipPostInsOffset = off;
3161
3162     if (i == (Address)baseTramp_savePostInsn)
3163       baseTemplate.savePostInsOffset = off;
3164
3165     if (i == (Address)baseTramp_globalPostBranch)
3166       baseTemplate.globalPostOffset = off;
3167
3168     if (i == (Address)baseTramp_localPostBranch)
3169       baseTemplate.localPostOffset = off;
3170     if (i == (Address)baseTramp_localPostReturn)
3171       baseTemplate.localPostReturnOffset = off;
3172
3173     if (i == (Address)baseTramp_restorePostInsn)
3174       baseTemplate.restorePostInsOffset = off;
3175
3176     if (i == (Address)baseTramp_returnInsn)
3177       baseTemplate.returnInsOffset = off;
3178   }
3179   baseTemplate.trampTemp = (void *)baseTramp;
3180   // TODO: include endTramp insns? (2 nops)
3181   baseTemplate.size = (Address)baseTramp_endTramp - (Address)baseTramp;
3182   baseTemplate.cost = 8;           // cost if both pre- and post- skipped
3183   baseTemplate.prevBaseCost = 135; // cost of [global_pre_branch, update_cost)
3184   baseTemplate.postBaseCost = 134; // cost of [global_post_branch, return_insn)
3185   baseTemplate.prevInstru = false;
3186   baseTemplate.postInstru = false;
3187
3188   // base non recursive trampoline template
3189   base = ( Address )baseNonRecursiveTramp;
3190   for( i = base;
3191        i < ( Address )baseNonRecursiveTramp_endTramp;
3192        i += INSN_SIZE )
3193     {
3194       Address off = i - base;
3195       // note: these should not be made into if..else blocks
3196       // (some of the label values are the same)
3197
3198       if( i == ( Address )baseNonRecursiveTramp_savePreInsn )
3199         nonRecursiveBaseTemplate.savePreInsOffset = off;
3200
3201       if( i == ( Address )baseNonRecursiveTramp_skipPreInsn )
3202         nonRecursiveBaseTemplate.skipPreInsOffset = off;
3203
3204       if( i == ( Address )baseNonRecursiveTramp_globalPreBranch )
3205         nonRecursiveBaseTemplate.globalPreOffset = off;
3206
3207       if( i == ( Address )baseNonRecursiveTramp_localPreBranch )
3208         nonRecursiveBaseTemplate.localPreOffset = off;
3209       if( i == ( Address )baseNonRecursiveTramp_localPreReturn )
3210         nonRecursiveBaseTemplate.localPreReturnOffset = off;
3211
3212       if( i == ( Address )baseNonRecursiveTramp_updateCostInsn )
3213         nonRecursiveBaseTemplate.updateCostOffset = off;
3214
3215       if( i == ( Address )baseNonRecursiveTramp_restorePreInsn )
3216         nonRecursiveBaseTemplate.restorePreInsOffset = off;
3217
3218       if( i == ( Address )baseNonRecursiveTramp_emulateInsn )
3219         nonRecursiveBaseTemplate.emulateInsOffset = off;
3220
3221       if( i == ( Address )baseNonRecursiveTramp_skipPostInsn )
3222         nonRecursiveBaseTemplate.skipPostInsOffset = off;
3223
3224       if( i == ( Address )baseNonRecursiveTramp_savePostInsn )
3225         nonRecursiveBaseTemplate.savePostInsOffset = off;
3226
3227       if( i == ( Address )baseNonRecursiveTramp_globalPostBranch )
3228         nonRecursiveBaseTemplate.globalPostOffset = off;
3229
3230       if( i == ( Address )baseNonRecursiveTramp_localPostBranch )
3231         nonRecursiveBaseTemplate.localPostOffset = off;
3232       if( i == ( Address )baseNonRecursiveTramp_localPostReturn )
3233         nonRecursiveBaseTemplate.localPostReturnOffset = off;
3234
3235       if( i == ( Address )baseNonRecursiveTramp_restorePostInsn )
3236         nonRecursiveBaseTemplate.restorePostInsOffset = off;
3237
3238       if( i == ( Address )baseNonRecursiveTramp_returnInsn )
3239         nonRecursiveBaseTemplate.returnInsOffset = off;
3240
3241       if( i == ( Address )baseNonRecursiveTramp_guardOnPre_begin )
3242         {
3243           DEBUG( "baseNonRecursiveTramp_guardOnPre_begin offset initialized." );
3244           nonRecursiveBaseTemplate.guardOnPre_beginOffset = off;
3245         }
3246       if( i == ( Address )baseNonRecursiveTramp_guardOffPre_begin )
3247         {
3248           DEBUG( "baseNonRecursiveTramp_guardOffPre_begin offset initialized." );
3249           nonRecursiveBaseTemplate.guardOffPre_beginOffset = off;
3250         }
3251       if( i == ( Address )baseNonRecursiveTramp_guardOnPost_begin )
3252         {
3253           DEBUG( "baseNonRecursiveTramp_guardOnPost_begin offset initialized." );
3254           nonRecursiveBaseTemplate.guardOnPost_beginOffset = off;
3255         }
3256       if( i == ( Address )baseNonRecursiveTramp_guardOffPost_begin )
3257         {
3258           DEBUG( "baseNonRecursiveTramp_guardOffPost_begin offset initialized." );
3259           nonRecursiveBaseTemplate.guardOffPost_beginOffset = off;
3260         }
3261       if( i == ( Address )baseNonRecursiveTramp_guardOnPre_end )
3262         {
3263           DEBUG( "baseNonRecursiveTramp_guardOnPre_end offset initialized." );
3264           nonRecursiveBaseTemplate.guardOnPre_endOffset = off;
3265         }
3266       if( i == ( Address )baseNonRecursiveTramp_guardOffPre_end )
3267         {
3268           DEBUG( "baseNonRecursiveTramp_guardOffPre_end offset initialized." );
3269           nonRecursiveBaseTemplate.guardOffPre_endOffset = off;
3270         }
3271       if( i == ( Address )baseNonRecursiveTramp_guardOnPost_end )
3272         {
3273           DEBUG( "baseNonRecursiveTramp_guardOnPost_end offset initialized." );
3274           nonRecursiveBaseTemplate.guardOnPost_endOffset = off;
3275         }
3276       if( i == ( Address )baseNonRecursiveTramp_guardOffPost_end )
3277         {
3278           DEBUG( "baseNonRecursiveTramp_guardOffPost_end offset initialized." );
3279           nonRecursiveBaseTemplate.guardOffPost_endOffset = off;
3280         }
3281     }
3282   nonRecursiveBaseTemplate.trampTemp = ( void * )baseNonRecursiveTramp;
3283   // TODO: include endTramp insns? (2 nops)
3284   nonRecursiveBaseTemplate.size =
3285     ( Address )baseNonRecursiveTramp_endTramp - ( Address )baseNonRecursiveTramp;
3286   nonRecursiveBaseTemplate.cost = 8;           // cost if both pre- and post- skipped
3287   nonRecursiveBaseTemplate.prevBaseCost = 135; // cost of [global_pre_branch, update_cost)
3288   nonRecursiveBaseTemplate.postBaseCost = 134; // cost of [global_post_branch, return_insn)
3289   nonRecursiveBaseTemplate.prevInstru = false;
3290   nonRecursiveBaseTemplate.postInstru = false;
3291
3292   /* For the conservative version of the base tramp. */
3293   // register space
3294   conservativeRegSpace = new registerSpace(nDead, Dead, 0, NULL);
3295   assert(conservativeRegSpace);
3296
3297   // conservative base trampoline template
3298   base = (Address)conservativeTramp;
3299   for (i = base; i < (Address)conservativeTramp_endTramp; i += INSN_SIZE) {
3300     Address off = i - base;
3301     // note: these should not be made into if..else blocks
3302     // (some of the label values are the same)
3303     if (i == (Address)conservativeTramp_savePreInsn)
3304       conservativeTemplate.savePreInsOffset = off;
3305     if (i == (Address)conservativeTramp_skipPreInsn)
3306       conservativeTemplate.skipPreInsOffset = off;
3307     if (i == (Address)conservativeTramp_globalPreBranch)
3308       conservativeTemplate.globalPreOffset = off;
3309     if (i == (Address)conservativeTramp_localPreBranch)
3310       conservativeTemplate.localPreOffset = off;
3311     if (i == (Address)conservativeTramp_localPreReturn)
3312       conservativeTemplate.localPreReturnOffset = off;
3313     if (i == (Address)conservativeTramp_updateCostInsn)
3314       conservativeTemplate.updateCostOffset = off;
3315     if (i == (Address)conservativeTramp_restorePreInsn)
3316       conservativeTemplate.restorePreInsOffset = off;
3317     if (i == (Address)conservativeTramp_emulateInsn)
3318       conservativeTemplate.emulateInsOffset = off;
3319     if (i == (Address)conservativeTramp_skipPostInsn)
3320       conservativeTemplate.skipPostInsOffset = off;
3321     if (i == (Address)conservativeTramp_savePostInsn)
3322       conservativeTemplate.savePostInsOffset = off;
3323     if (i == (Address)conservativeTramp_globalPostBranch)
3324       conservativeTemplate.globalPostOffset = off;
3325     if (i == (Address)conservativeTramp_localPostBranch)
3326       conservativeTemplate.localPostOffset = off;
3327     if (i == (Address)conservativeTramp_localPostReturn)
3328       conservativeTemplate.localPostReturnOffset = off;
3329     if (i == (Address)conservativeTramp_restorePostInsn)
3330       conservativeTemplate.restorePostInsOffset = off;
3331     if (i == (Address)conservativeTramp_returnInsn)
3332       conservativeTemplate.returnInsOffset = off;
3333   }
3334   conservativeTemplate.trampTemp = (void *)conservativeTramp;
3335   // TODO: include endTramp insns? (2 nops)
3336   conservativeTemplate.size = (Address)conservativeTramp_endTramp -
3337                               (Address)conservativeTramp;
3338   // XXX These costs are copied from the normal base tramp, they
3339   //     probably need to be increased.
3340   // cost if both pre- and post- skipped
3341   conservativeTemplate.cost = 8;
3342   // cost of [global_pre_branch, update_cost)
3343   conservativeTemplate.prevBaseCost = 135;
3344   // cost of [global_post_branch, return_insn)
3345   conservativeTemplate.postBaseCost = 134;
3346   conservativeTemplate.prevInstru = false;
3347   conservativeTemplate.postInstru = false;
3348 #endif
3349   TRACE_E( "initTramps" );
3350 }
3351
3352 /****************************************************************************/
3353 /****************************************************************************/
3354 /****************************************************************************/
3355
3356 Register emitFuncCall(opCode op, registerSpace *rs, char *code, Address &base, 
3357                       const vector<AstNode *> &params, const string &calleeName,
3358                       process *p, bool noCost, const function_base *callee)
3359 {
3360   TRACE_B( "emitFuncCall" );
3361
3362   //fprintf(stderr, ">>> emitFuncCall(%s)\n", calleeName.string_of());
3363   assert(op == callOp);  
3364   instruction *insn;
3365   Address calleeAddr = (callee) 
3366     ? (callee->getEffectiveAddress(p))
3367     : (lookup_fn(p, calleeName));
3368   //Address base_orig = base; // debug
3369   //fprintf(stderr, "  <0x%08x:%s>\n", calleeAddr, calleeName.string_of());
3370   
3371   // generate argument values
3372   vector<reg> args;
3373 #ifdef mips_unknown_ce2_11 //ccw 22 jan 2001 : 28 mar 2001
3374   
3375         //add to the stack HACK
3376         //Windows CE forces you to have already allocated space
3377         //on the stack for the called function to use to store
3378         //parameters from the registers (a0-a3) to memory.
3379
3380         //ccw 18 jan 2001 : RIGHT HERE generate stack grow!
3381         int argSize=24; //ccw 18 jan 2001
3382         for (unsigned ii = 0; ii < params.size(); ii++) {
3383                 argSize += params[ii]->getSize(); //ccw 18 jan 2001
3384         }
3385         //ccw 18 jan 2001
3386         //allocate extra room on the stack for the args!
3387
3388         insn = (instruction *)(code + base);
3389         genItype(insn, ADDIUop, REG_SP, REG_SP, -1*argSize); 
3390         base += INSN_SIZE;
3391
3392         unsigned int offsetMask= 0x0000FFFF;
3393         unsigned int newInsn = 0x00000000;
3394         unsigned int newOffset = 0;
3395 #endif
3396
3397   for (unsigned i = 0; i < params.size(); i++) {
3398     args.push_back(params[i]->generateCode(p, rs, code, base, noCost, false));
3399 #ifdef mips_unknown_ce2_11 //ccw 22 jan 2001 : 28 mar 2001
3400                 //since we allocted extra memory on the stack for the
3401                 //parameters, we need to fix up the 'lw XX, XX(sp)' that is
3402                 //generated above to add the amount of stack space we
3403                 //just generated to the offset.
3404                 //ONLY do this when the instruction is a 'lw XX, XX(sp)'
3405                 //sometimes a constant is loaded or something is loaded
3406                 //from another memory location
3407                 newInsn = *((unsigned int*) (code + (base - INSN_SIZE)));
3408                 struct fmt_itype *tmpInsn = (struct fmt_itype*) ((code + (base - INSN_SIZE)));
3409                 if( (tmpInsn->op == 35) && // ls
3410                         (tmpInsn->rs == 29) ) { // XX(sp) 
3411
3412                         newOffset = (offsetMask & *((unsigned int*) (code + (base - INSN_SIZE))))+ argSize;
3413                         if(i>3) { //5th parameter, not in register.
3414                                 newOffset +=  (i*4) ;
3415                         }
3416                         newInsn = newInsn & 0xFFFF0000;
3417                         newInsn = newInsn | newOffset;
3418                         *((unsigned int*) (code + (base - INSN_SIZE)))= newInsn;
3419
3420                 }
3421 #endif
3422   }
3423   
3424   unsigned nargs = args.size();
3425   bool stackArgs = (nargs > NUM_ARG_REGS) ? (true) : (false);
3426   int stackBytes = 0;
3427
3428   // put parameters 0-7 in argument registers
3429   // ccw  10 jan 2001 mips on the CE devices
3430   // uses the o32 calling convention, only allowing 
3431   // 4 arguments to be passed in registers.
3432   for (
3433 #ifndef mips_unknown_ce2_11 //ccw 17 july 2001
3434 unsigned
3435 #endif
3436         i = 0; i < nargs && i < NUM_ARG_REGS; i++) {
3437     insn = (instruction *)(code + base);
3438     genMove(insn, args[i], REG_A0 + i);
3439     base += INSN_SIZE;
3440     rs->freeRegister(args[i]);
3441   }
3442
3443   // put parameters 8+ on the stack
3444   if (stackArgs) {
3445 #ifndef mips_unknown_ce2_11 //ccw 10 jan 2001 : 28 mar 2001
3446         //dont grow the stack if you are on mips, use o32
3447         // also removes the addiu sp,sp,stackBytes below
3448
3449     // grow stack frame
3450     stackBytes = (nargs - NUM_ARG_REGS) * BYTES_PER_ARG; // 8 bytes per parameter
3451     insn = (instruction *)(code + base);
3452
3453     genItype (insn, DADDIUop, REG_SP, REG_SP, -stackBytes);
3454     base += INSN_SIZE;
3455 #endif
3456
3457     /* NOTE: the size of the stack frame has been temporarily
3458        increased; its size is restored by the "addiu sp,sp,stackBytes"
3459        generated below */
3460     // store parameters in stack frame
3461     for (unsigned i = NUM_ARG_REGS; i < nargs; i++) {
3462 #ifdef mips_unknown_ce2_11 //ccw 10 jan 2001 : 28 mar 2001
3463       int stackOff = (i - NUM_ARG_REGS) * BYTES_PER_ARG + 16; //ccw 10 jan 2001 added + 16
3464 #else
3465       int stackOff = (i - NUM_ARG_REGS) * BYTES_PER_ARG;
3466 #endif
3467       insn = (instruction *)(code + base);
3468 #ifdef mips_unknown_ce2_11 //ccw 10 jan 2001 : 28 mar 2001
3469           // ce does not have SDop 
3470       genItype(insn, SWop, REG_SP, args[i], stackOff);
3471 #else
3472       genItype(insn, SDop, REG_SP, args[i], stackOff);
3473 #endif
3474       base += INSN_SIZE;
3475       rs->freeRegister(args[i]);
3476     }
3477
3478   }
3479
3480   // call function
3481   genLoadConst(REG_T9, calleeAddr, code, base, noCost);
3482   insn = (instruction *)(code + base);
3483   genRtype(insn, JALRops, REG_T9, 0, REG_RA);
3484   genNop(insn+1);
3485   base += 2*INSN_SIZE;
3486
3487   // restore stack frame (if necessary)
3488 #ifndef mips_unknown_ce2_11 //ccw 18 jan 2001 : 28 mar 2001
3489
3490   if (stackArgs) {
3491     insn = (instruction *)(code + base);
3492     genItype(insn, DADDIUop, REG_SP, REG_SP, stackBytes);
3493     base += INSN_SIZE;
3494   }
3495 #else
3496  //ccw 18 jan 2001 : RIGHT HERE generate stack shrink!
3497
3498   //ccw 18 jan 2001
3499   //de-allocate extra room on the stack for the args!
3500
3501   insn = (instruction *)(code + base);
3502   genItype(insn, ADDIUop, REG_SP, REG_SP, argSize); 
3503   base += INSN_SIZE;
3504
3505 #endif
3506
3507   // debug
3508   //fprintf(stderr, "  emitFuncCall code:\n");
3509   //dis(code+base_orig, NULL, (base-base_orig)/INSN_SIZE);
3510
3511   TRACE_E( "emitFuncCall" );
3512
3513   return REG_V0;
3514 }
3515
3516 /****************************************************************************/
3517 /****************************************************************************/
3518 /****************************************************************************/
3519
3520 void returnInstance::installReturnInstance(process *p)
3521 {
3522   TRACE_B( "returnInstance::installReturnInstance" );
3523
3524   //fprintf(stderr, ">>> returnInstance::installReturnInstance(%0#10x, %i bytes)\n", addr_, instSeqSize);
3525   p->writeTextSpace((void *)addr_, instSeqSize, instructionSeq);
3526   //disDataSpace(p, (void *)addr_, 4, "!!! jump to basetramp: ");
3527   installed = true;
3528
3529   TRACE_E( "returnInstance::installReturnInstance" );
3530 }
3531
3532 /****************************************************************************/
3533 /****************************************************************************/
3534 /****************************************************************************/
3535
3536 /***********************/
3537 /*** HERE BE DRAGONS ***/
3538 /***********************/
3539
3540 int relocateInstruction(instruction *insn, Address origAddr, 
3541                          Address relocAddr, int numInsns, process *p)
3542 {
3543   TRACE_B( "relocateInstruction" );
3544
3545   //fprintf(stderr, "!!! relocateInstruction(0x%08x): ", relocAddr);
3546   //dis(insn, (void *)origAddr, 1, ">>> reloc ");
3547
3548   if (isBranchInsn(*insn)) {
3549     Address target = (origAddr + INSN_SIZE) + (insn->itype.simm16 << 2);
3550     RegValue newOffset = target - (relocAddr + INSN_SIZE);
3551
3552     if (newOffset >= BRANCH_MIN && newOffset <= BRANCH_MAX) {
3553       insn->itype.simm16 = newOffset >> 2;
3554     } else {
3555       /*
3556        * The branch is too far, so we need to branch to another location
3557        * and hopefully we can use a jump from there.
3558        */
3559       Address extra = inferiorMalloc(p, 2 * INSN_SIZE, anyHeap, relocAddr);
3560       if (!extra) {
3561         TRACE_E("relocateInstruction");
3562         return -1;
3563       }
3564
3565       if (region_num(extra + INSN_SIZE) != region_num(target)) {
3566         TRACE_E("relocateInstruction");
3567         return -1;
3568       }
3569
3570       /* Fix up the branch to go to our jump. */
3571       newOffset = extra - (relocAddr + INSN_SIZE);
3572
3573       if (newOffset >= BRANCH_MIN && newOffset <= BRANCH_MAX) {
3574           /* We can just redirect the branch to a jump. */
3575           insn->itype.simm16 = newOffset >> 2;
3576
3577           /* Generate the jump. */
3578           instruction jumpCode[2];
3579           genJump(jumpCode, extra, target);
3580           genNop(&jumpCode[1]);
3581
3582           /* Write the jump into the inferior. */
3583           p->writeDataSpace((caddr_t)extra, sizeof(jumpCode),
3584                             (caddr_t)jumpCode);
3585         } else {
3586           /*
3587            * The extra space is too far away to redirect the branch, so
3588            * we need to replace it with a jump and move the branch and it's
3589            * delay slot to the extra space.  We'll need more space for this,
3590            * so we'll reallocate extra.
3591            */
3592
3593           /* We'll need to move the delay slot, too. */
3594           assert(numInsns > 1);
3595
3596           vector<addrVecType> pointsToCheck;
3597           inferiorFree(p, extra, pointsToCheck);
3598           Address extra = inferiorMalloc(p, 6 * INSN_SIZE, anyHeap, relocAddr);
3599           if (!extra) {
3600             TRACE_E("relocateInstruction");
3601             return -1;
3602           }
3603
3604           assert(region_num(extra + (5*INSN_SIZE)) == region_num(target));
3605           assert(region_num(relocAddr + INSN_SIZE) == region_num(extra));
3606           assert(!isBranchInsn(insn[1]) && !isJumpInsn(insn[1]));
3607
3608           instruction extraCode[6];
3609           extraCode[0].raw = insn[0].raw;
3610           extraCode[0].itype.simm16 = 3;
3611           extraCode[1].raw = insn[1].raw;
3612           genJump(&extraCode[2],
3613                   extra + (2*INSN_SIZE), relocAddr + (2*INSN_SIZE));
3614           genNop(&extraCode[3]);
3615           genJump(&extraCode[4],
3616                   extra + (4*INSN_SIZE), target);
3617           genNop(&extraCode[5]);
3618
3619           /* Write the jump into the inferior. */
3620           p->writeDataSpace((caddr_t)extra, sizeof(extraCode),
3621                             (caddr_t)extraCode);
3622           /* Change the instructions back in the base tramp to a jump
3623              to our new code. */
3624           genJump(&insn[0], relocAddr, extra);
3625           genNop(&insn[1]);
3626
3627           TRACE_E( "relocateInstruction" );
3628
3629           return 2;
3630         }
3631       }
3632     } else if (isJumpInsn(*insn)) {
3633       switch (insn->decode.op) {
3634         case Jop:
3635         case JALop: { // PC-region branch
3636           /* To calculate the address, uncomment this:
3637           Address hi = (origAddr + INSN_SIZE) & (REGION_NUM_MASK);
3638           Address lo = (insn->jtype.imm26 << 2) & REGION_OFF_MASK;
3639           Address target = hi | lo;
3640           */
3641           /* XXX Is there any way to get around this restriction? */
3642           assert(region_num(origAddr + INSN_SIZE) ==
3643                  region_num(relocAddr + INSN_SIZE));
3644           } break;
3645         case SPECIALop: // indirect (register) jump - don't have to do anything
3646           break;
3647         default:
3648           fprintf(stderr, "relocateInstruction: bogus instruction %0#10x\n",
3649                   insn->raw);
3650           assert(0);
3651       }
3652   }
3653
3654   TRACE_E( "relocateInstruction" );
3655
3656   return 1;
3657 }
3658
3659 /****************************************************************************/
3660 /****************************************************************************/
3661 /****************************************************************************/
3662
3663 void generate_base_tramp_recursive_guard_code( process * p,
3664                                                char * code,
3665                                                NonRecursiveTrampTemplate * templ )
3666 {
3667   TRACE_B( "generate_base_tramp_recursive_guard_code" );
3668   int offset = 0;//ccw 24 oct 2000 : 28 mar 2001 used to calculate offset of BEQ
3669
3670
3671   /* prepare guard flag memory, if needed */
3672   Address guardFlagAddress = p->getTrampGuardFlagAddr();
3673   if( guardFlagAddress == 0 )
3674     {
3675         int initial_value = 1;
3676         DEBUG( "Attempting to allocate guard space." );
3677         guardFlagAddress = inferiorMalloc( p, sizeof( int ), dataHeap );
3678         DEBUG( "Address of guard is 0x" << setw( 16 ) << setfill( '0' ) << setbase(16)
3679                << guardFlagAddress << dec << "." );
3680         // Zero out the new value
3681         p->writeDataSpace( ( void * )guardFlagAddress, sizeof( int ), & initial_value );
3682         DEBUG( "Initialized guardFlagAddress." );
3683
3684         p->setTrampGuardFlagAddr( guardFlagAddress );
3685     }
3686
3687   /* The 64-bit address is split into 4 16-bit chunks: A, B, C, D */
3688   /* A is the most significant chunk, D the least significant.    */
3689 #ifndef mips_unknown_ce2_11 //ccw 24 oct 2000 : 28 mar 2001
3690   //if we are not on CE then use a 64 bit address
3691   //if we are on CE use a 32 bit address
3692
3693   unsigned short int chunk_A = ( guardFlagAddress >> 48 ) & 0x000000000000FFFF;
3694   unsigned short int chunk_B = ( guardFlagAddress >> 32 ) & 0x000000000000FFFF;
3695   unsigned short int chunk_C = ( guardFlagAddress >> 16 ) & 0x000000000000FFFF;
3696   unsigned short int chunk_D = ( guardFlagAddress       ) & 0x000000000000FFFF;
3697
3698   DEBUG( "Using flag address 0x"
3699          << setfill('0') << setw(16) << setbase(16) << guardFlagAddress );
3700   DEBUG( "split into 16-bit chunks: "
3701          << "0x" << setfill('0') << setw(4) << setbase(16) << chunk_A << " "
3702          << "0x" << setfill('0') << setw(4) << setbase(16) << chunk_B << " "
3703          << "0x" << setfill('0') << setw(4) << setbase(16) << chunk_C << " "
3704          << "0x" << setfill('0') << setw(4) << setbase(16) << chunk_D
3705          << dec << "." );
3706 #else
3707
3708   unsigned short int chunk_A = ( guardFlagAddress >> 16 ) & 0x0000FFFF;
3709   unsigned short int chunk_B = ( guardFlagAddress       ) & 0x0000FFFF;
3710
3711 #endif
3712
3713   /* populate guardOnPre section */
3714   instruction * guardOnInsn = ( instruction * )( code + templ->guardOnPre_beginOffset );
3715   offset = 7;//ccw 24 oct 2000 : 28 mar 2001
3716
3717 #ifndef mips_unknown_ce2_11 //ccw 24 oct 2000 : 28 mar 2001
3718   genItype ( guardOnInsn     , LUIop,  0, 12, chunk_A );
3719   genItype ( guardOnInsn + 1 , ORIop, 12, 12, chunk_B );
3720   genItype ( guardOnInsn + 2 , LUIop,  0, 13, chunk_C );
3721   genItype ( guardOnInsn + 3 , ORIop, 13, 13, chunk_D );
3722   //offset -=2;//ccw 24 oct 2000
3723 #else
3724   genItype ( guardOnInsn     , LUIop,  0, 13, chunk_A );
3725   genItype ( guardOnInsn + 1 , ORIop, 13, 13, chunk_B );
3726
3727 #endif
3728
3729   genItype ( guardOnInsn + offset , BEQop, 12, 0, //ccw 24 oct 2000 : offset was 7 : 28 mar 2001
3730              ( templ->guardOffPre_endOffset -
3731                ( templ->guardOnPre_beginOffset + ( 7 + 1 ) * INSN_SIZE ) ) / INSN_SIZE );
3732
3733   /* populate guardOffPre section */
3734   instruction * guardOffInsn = ( instruction * )( code + templ->guardOffPre_beginOffset );
3735 #ifndef mips_unknown_ce2_11 //ccw 24 oct 2000 : 28 mar 2001
3736   genItype ( guardOffInsn     , LUIop,  0, 12, chunk_A );
3737   genItype ( guardOffInsn + 1 , ORIop, 12, 12, chunk_B );
3738   genItype ( guardOffInsn + 2 , LUIop,  0, 13, chunk_C );
3739   genItype ( guardOffInsn + 3 , ORIop, 13, 13, chunk_D );
3740 #else
3741   genItype ( guardOffInsn     , LUIop,  0, 13, chunk_A );
3742   genItype ( guardOffInsn + 1 , ORIop, 13, 13, chunk_B );