mods/additions largely under the USE_STL_VECTOR and IBM_BPATCH_COMPAT flags
[dyninst.git] / dyninstAPI / src / process.C
1 /*
2  * Copyright (c) 1996-2002 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 // $Id: process.C,v 1.312 2002/03/19 22:57:21 jaw Exp $
43
44 extern "C" {
45 #ifdef PARADYND_PVM
46 int pvmputenv (const char *);
47 int pvmendtask();
48 #endif
49 }
50
51 #include <ctype.h>
52
53 #if defined(i386_unknown_solaris2_5)
54 #include <sys/procfs.h>
55 #endif
56 #include "common/h/headers.h"
57 #include "dyninstAPI/src/symtab.h"
58 #ifndef BPATCH_LIBRARY
59 #include "dyninstAPI/src/pdThread.h"
60 #endif
61 #include "dyninstAPI/src/process.h"
62 #include "dyninstAPI/src/util.h"
63 #include "dyninstAPI/src/inst.h"
64 #include "dyninstAPI/src/instP.h"
65 #include "dyninstAPI/src/instPoint.h"
66 #include "dyninstAPI/src/dyninstP.h"
67 #include "dyninstAPI/src/os.h"
68 #include "dyninstAPI/src/showerror.h"
69 #include "dyninstAPI/src/dynamiclinking.h"
70 // #include "paradynd/src/mdld.h"
71 #include "common/h/Timer.h"
72 #include "common/h/Time.h"
73 #include "common/h/timing.h"
74
75 #ifdef BPATCH_LIBRARY
76 #include "dyninstAPI/h/BPatch.h"
77 #else
78 #include "rtinst/h/rtinst.h"
79 #include "rtinst/h/trace.h"
80 #include "paradynd/src/perfStream.h"
81 #include "paradynd/src/costmetrics.h"
82 #include "paradynd/src/mdld.h"
83 #include "paradynd/src/main.h"
84 #include "paradynd/src/init.h"
85 #include "pdutil/h/pdDebugOstream.h"
86 #include "common/h/int64iostream.h"
87 #endif
88
89 #ifndef BPATCH_LIBRARY
90 extern void generateRPCpreamble(char *insn, Address &base, process *proc, 
91                                 unsigned offset, int tid, unsigned pos);
92 #endif
93
94 #include "common/h/debugOstream.h"
95
96 #ifdef ATTACH_DETACH_DEBUG
97 debug_ostream attach_cerr(cerr, true);
98 #else
99 debug_ostream attach_cerr(cerr, false);
100 #endif
101
102
103 #ifdef INFERIOR_RPC_DEBUG
104 debug_ostream inferiorrpc_cerr(cerr, true);
105 #else
106 debug_ostream inferiorrpc_cerr(cerr, false);
107 #endif
108
109 #ifdef SHM_SAMPLING_DEBUG
110 debug_ostream shmsample_cerr(cerr, true);
111 #else
112 debug_ostream shmsample_cerr(cerr, false);
113 #endif
114
115 #ifdef FORK_EXEC_DEBUG
116 debug_ostream forkexec_cerr(cerr, true);
117 #else
118 debug_ostream forkexec_cerr(cerr, false);
119 #endif
120
121 #ifdef SIGNAL_DEBUG
122 debug_ostream signal_cerr(cerr, true);
123 #else
124 debug_ostream signal_cerr(cerr, false);
125 #endif
126
127 #ifdef SHAREDOBJ_DEBUG
128 debug_ostream sharedobj_cerr(cerr, true);
129 #else
130 debug_ostream sharedobj_cerr(cerr, false);
131 #endif
132
133 #ifndef BPATCH_LIBRARY
134 #ifdef METRIC_DEBUG
135 pdDebug_ostream metric_cerr(cerr, true);
136 #else
137 pdDebug_ostream metric_cerr(cerr, false);
138 #endif
139
140 #ifdef SAMPLEVALUE_DEBUG
141 pdDebug_ostream sampleVal_cerr(cerr, true);
142 #else
143 pdDebug_ostream sampleVal_cerr(cerr, false);
144 #endif
145
146 #ifdef AGGREGATE_DEBUG
147 pdDebug_ostream agg_cerr(cerr, true);
148 #else
149 pdDebug_ostream agg_cerr(cerr, false);
150 #endif
151 #endif
152
153 #define FREE_WATERMARK (hp->totalFreeMemAvailable/2)
154 #define SIZE_WATERMARK 100
155 static const timeLength MaxWaitingTime(10, timeUnit::sec());
156 static const timeLength MaxDeletingTime(2, timeUnit::sec());
157 unsigned inferiorMemAvailable=0;
158
159 unsigned activeProcesses; // number of active processes
160 vector<process*> processVec;
161 string process::programName;
162 string process::dyninstName;
163 string process::pdFlavor;
164 vector<string> process::arg_list;
165
166 #ifndef BPATCH_LIBRARY
167 extern string osName;
168 #endif
169
170 // PARADYND_DEBUG_XXX
171 int pd_debug_infrpc=0;
172 int pd_debug_catchup=0;
173 //
174
175 process *findProcess(int pid) { // make a public static member fn of class process
176   unsigned size=processVec.size();
177   for (unsigned u=0; u<size; u++)
178     if (processVec[u] && processVec[u]->getPid() == pid)
179       return processVec[u];
180   return NULL;
181 }
182
183 bool waitingPeriodIsOver()
184 {
185   static timeStamp initPrevious = timeStamp::ts1970();
186   static timeStamp previous = initPrevious;
187   bool waiting=false;
188
189   if (previous == initPrevious) {
190     previous=getCurrentTime();
191     waiting=true;
192   }
193   else {
194     timeStamp current=getCurrentTime();
195     if ( (current-previous) > MaxWaitingTime ) {
196       previous=getCurrentTime();
197       waiting=true;
198     }
199   }
200   return(waiting);
201 }
202 // Frame(process *): return toplevel (active) stack frame
203 // (platform-independent wrapper)
204 Frame::Frame(process *p)
205   : uppermost_(true), pc_(0), fp_(0), lwp_id_(0), thread_(NULL)
206 {
207   if (p->curr_lwp) lwp_id_ = p->curr_lwp;
208   getActiveFrame(p);
209 }
210
211 #if defined(USE_STL_VECTOR)
212 // need to use dumber vector alloc method w/stl, I think -JAW 1/2002
213 disabledItem::disabledItem(heapItem *h, const vector<addrVecType> &preds) :
214   block(h) 
215 {
216   for (unsigned int i = 0; i < preds.size(); ++i) {
217     pointsToCheck.push_back(preds[i]);
218   }
219 }
220
221 disabledItem::disabledItem(const disabledItem &src) : 
222   block(src.block) 
223 {
224   for (unsigned int i = 0; i < src.pointsToCheck.size(); ++i) {
225     pointsToCheck.push_back(src.pointsToCheck[i]);
226   }
227 }
228
229 #endif
230
231 /* AIX method defined in aix.C */
232 #if !defined(rs6000_ibm_aix4_1)
233 Address process::getTOCoffsetInfo(Address /*dest */)
234 {
235   Address tmp;
236   assert(0);
237   return tmp; // this is to make the nt compiler happy! - naim
238 }
239 #endif
240
241 #if defined(mips_unknown_ce2_11) //ccw 6 feb 2001 : 29 mar 2001
242 //ccw 6 feb 2001 : windows CE does not have the NT walkStack function
243 //so we use this one.
244
245 void process::walkStack(Frame currentFrame, vector<Address>&pcs, 
246                         vector<Address>& /* fps*/, bool noPause)
247 {
248   bool needToCont = noPause ? false : (status() == running);
249
250   if (pause()) {
251     Address spOld = 0xffffffff;
252
253     while (!currentFrame.isLastFrame()) {
254       Address spNew = currentFrame.getSP(); // ccw 6 feb 2001 : should get SP?
255
256       // successive frame pointers might be the same (e.g. leaf functions)
257       if (spOld < spNew) {
258
259         // not moving up stack
260         if (!noPause && needToCont && !continueProc()) {
261           cerr << "walkStack: continueProc failed" << endl;
262         }
263
264         vector<Address> ev; // empty vector
265         pcs = ev;
266
267         return;
268       }
269
270       spOld = spNew;
271
272       Address next_pc = currentFrame.getPC();
273       // printf("currentFrame pc = %p\n",next_pc);
274       pcs.push_back(next_pc);
275
276           //ccw 6 feb 2001 : at this point, i need to use the 
277           //list of functions parsed from the debug symbols to
278           //determine the frame size for each function and find the 
279           //return value for each (which is the previous fir value)
280       currentFrame = currentFrame.getCallerFrame(this); 
281
282     }
283
284     pcs.push_back(currentFrame.getPC());
285   }
286
287   if (!noPause && needToCont) {
288      if (!continueProc()){
289         cerr << "walkStack: continueProc failed" << endl;
290      }
291   }  
292
293   return;
294 }
295
296 #elif !defined(i386_unknown_nt4_0)
297 // Windows NT has its own version of the walkStack function in pdwinnt.C
298 // Note: it may not always be possible to do a correct stack walk.
299 // If it can't do a complete walk, the function should return an empty
300 // vector, which means that there was an error, and we can't walk the stack.
301 //
302 // Multithreaded AIX addition: in the case when we have a multithreaded program
303 // but are only using the standard daemon, use the cached kernel thread ID to
304 // do the ptracing. This is contained in the frame class, but bears mentioning
305 // because of the main-search behavior.
306 void process::walkStack(Frame currentFrame, vector<Address> &pcs,
307                         vector<Address> &fps, bool noPause) 
308 {
309   u_int sig_size   = 0;
310   Address sig_addr = 0;
311
312   pcs.resize(0);
313   fps.resize(0);
314
315   Address next_pc = 0;
316   Address leaf_pc = 0;
317   Address fpOld   = 0;
318   Address fpNew   = 0;
319
320   bool needToCont = noPause ? false : (status() == running);
321
322 #ifndef BPATCH_LIBRARY
323   startTimingStackwalk();
324 #endif
325
326   if (!noPause && !pause()) {
327       cerr << "walkStack: pause failed" << endl;
328
329 #ifndef BPATCH_LIBRARY
330       stopTimingStackwalk();
331 #endif
332       return;
333   }
334
335
336
337   if(signal_handler){
338       const image *sig_image = (signal_handler->file())->exec();
339
340       if(getBaseAddress(sig_image, sig_addr)){
341           sig_addr += signal_handler->getAddress(this);
342       } else {
343           sig_addr = signal_handler->getAddress(this);
344       }
345
346       sig_size = signal_handler->size();
347   }
348
349
350   // Make sure application is paused
351   if ( pause() ) {
352
353     // Step through the stack frames
354     while (!currentFrame.isLastFrame()) {
355
356       // grab the frame pointer
357       fpNew = currentFrame.getFP();
358
359       // Check that we are not moving up the stack
360       // successive frame pointers might be the same (e.g. leaf functions)
361       if (fpOld > fpNew) {
362
363
364         if (!noPause && needToCont && !continueProc()) {
365             cerr << "walkStack: continueProc failed" << endl;
366         }
367
368         // AIX:
369         // There's a signal function in the MPI library that we're not
370         // handling properly. Instead of returning an empty stack,
371         // return what we have.
372         // One thing that makes me feel better: gdb is getting royally
373         // confused as well. This sucks for catchup.
374
375         // empty vector
376         vector<Address> ev;
377
378 #ifndef BPATCH_LIBRARY
379         stopTimingStackwalk();
380 #endif
381 #ifndef rs6000_ibm_aix4_1
382         pcs = ev;
383 #endif
384         return;
385       }
386
387       fpOld = fpNew;
388
389       next_pc = currentFrame.getPC();
390       pcs.push_back(next_pc);
391       fps.push_back(fpOld);
392       //fprintf(stderr, "   0x%x/0x%x\n", fpOld, next_pc);
393
394       // is this pc in the signal_handler function?
395       if(signal_handler && (next_pc >= sig_addr)
396           && (next_pc < (sig_addr+sig_size))){
397
398           // check to see if a leaf function was executing when the signal
399           // handler was called.  If so, then an extra frame should be added
400           // for the leaf function...the call to getCallerFrame
401           // will get the function that called the leaf function
402           leaf_pc = 0;
403
404           if(this->needToAddALeafFrame(currentFrame,leaf_pc)){
405               pcs.push_back(leaf_pc);
406               fps.push_back(fpOld);
407           }
408       }
409
410       currentFrame = currentFrame.getCallerFrame(this); 
411     }
412
413     pcs.push_back(currentFrame.getPC());
414     fps.push_back(fpOld);
415   }
416
417   if (!noPause && needToCont) {
418      if (!continueProc()){
419         cerr << "walkStack: continueProc failed" << endl;
420      }
421   }  
422
423 #ifndef BPATCH_LIBRARY
424   stopTimingStackwalk();
425 #endif
426 }
427
428
429 #if defined(MT_THREAD)
430 /*
431  * On AIX there is a pthread debugging library which allows us to 
432  * access most of the internal data for a pthread. This is much
433  * preferable to the situation on Solaris, where we use magic offsets
434  * gotten from examining header files. However, their mechanism uses
435  * callbacks, which we have to define and initialize. 
436  */
437 #ifdef rs6000_ibm_aix4_1
438 // Prototypes, oh boy.
439
440 int PTHDB_read_data(pthdb_user_t user,
441                     void *buf,
442                     pthdb_addr_t addr,
443                     size_t len);
444 int PTHDB_write_data(pthdb_user_t user,
445                     void *buf,
446                     pthdb_addr_t addr,
447                     size_t len);
448 int PTHDB_read_regs(pthdb_user_t user,
449                     tid_t tid,
450                     unsigned long long flags,
451                     pthdb_context_t *context);
452 int PTHDB_write_regs(pthdb_user_t user,
453                     tid_t tid,
454                     unsigned long long flags,
455                     pthdb_context_t *context);
456 int PTHDB_alloc(pthdb_user_t user,
457                 size_t len,
458                 void **bufp);
459 int PTHDB_realloc(pthdb_user_t user,
460                   void *buf,
461                   size_t len,
462                   void **bufp);
463 int PTHDB_dealloc(pthdb_user_t user,
464                   void *buf);
465 int PTHDB_print(pthdb_user_t user, char *str);
466
467
468 bool process::init_pthdb_library()
469 {
470   static int initialized = 0;
471
472   if (initialized) return false;
473   
474   // Use our address as the unique user value
475   pthdb_user_t user = (pthdb_user_t) this;
476   pthdb_callbacks_t callbacks;
477   callbacks.symbol_addrs = NULL;
478   callbacks.read_data = PTHDB_read_data;
479   callbacks.write_data = PTHDB_write_data;
480   callbacks.read_regs = NULL;
481   callbacks.write_regs = NULL;
482   callbacks.alloc = PTHDB_alloc;
483   callbacks.realloc = PTHDB_realloc;
484   callbacks.dealloc = PTHDB_dealloc;
485   callbacks.print = PTHDB_print;
486   int ret;
487   ret = pthdb_session_init(user, PEM_32BIT, 
488                            PTHDB_FLAG_GPRS | PTHDB_FLAG_SPRS | PTHDB_FLAG_FPRS | PTHDB_FLAG_SUSPEND,
489                            &callbacks, &pthdb_session_);
490   if (ret) {
491     fprintf(stderr, "Initializing pthread debug library returned %d\n", ret);
492     return false;
493   }
494   initialized = true;
495   return true;
496 }
497     
498 #endif
499
500
501 vector<vector<Address> > process::walkAllStack(bool noPause) {
502
503   vector<vector<Address> > result;
504   vector<vector<Address> > stack_buffer;
505   vector<Address> pcs;
506   vector<Address> fps;
507   bool needToCont = noPause ? false : (status() == running);
508
509   if (!noPause && !pause()) {
510      cerr << "walkAllStack: pause failed" << endl;
511      return result;
512   }
513  
514 #ifndef BPATCH_LIBRARY
515   startTimingStackwalk();
516 #endif
517
518
519   if (pause()) {
520
521 #ifdef rs6000_ibm_aix4_1
522     // AIX: initialize the pthread debug library
523     init_pthdb_library();
524 #endif
525
526     // Walk the lwp stack first, walk a thread stack only if it is not active
527     // If we walk an active thread stack, information may be incorrect. 
528     int i=0;
529     vector<Address> lwp_stack_lo;
530     vector<Address> lwp_stack_hi;
531     vector<unsigned> lwpIDs;
532
533     if (getLWPIDs(lwpIDs)) {
534
535       for (unsigned iter = 0; iter < lwpIDs.size(); iter++){
536         int lwp_id = lwpIDs[i] ;
537         Address fp, pc;
538
539         if (getLWPFrame(lwp_id, &fp, &pc)) {
540           Frame currentFrame(lwp_id, fp, pc, true);
541
542           cerr << "Walking stack, lwp_id " << lwp_id << endl;
543           walkStack(currentFrame, pcs, fps, noPause);
544
545           stack_buffer.push_back(pcs);
546           lwp_stack_hi.push_back(fps[fps.size()-1]);
547           lwp_stack_lo.push_back(fps[0]);
548         }
549
550         i++ ;
551       }
552     }
553
554     for (unsigned j=0; j< lwp_stack_lo.size(); j++) {
555       sprintf(errorLine, "lwp[%d], stack_lo=0x%lx, stack_hi=0x%lx\n", 
556               j, lwp_stack_lo[j], lwp_stack_hi[j]);
557       logLine(errorLine);
558     }
559
560     //Walk thread stacks
561     for (unsigned i=0; i<threads.size(); i++) {
562         Frame currentFrame(threads[i]);
563         Address stack_lo = currentFrame.getFP();
564
565         //sprintf(errorLine, "stack_lo[%d]=0x%lx\n", i, stack_lo);
566         //logLine(errorLine);
567
568         bool active = false;
569
570         // If we find a match in the non-running list (stack_buffer), 
571         // add it to result. This basically sorts the resulting buffer
572         // by lwp id. The sorting is assumed in the catchup code. 
573         // Alternative: use a structure which is a (thread id, vector) pair.
574         for (unsigned j=0; j< lwp_stack_lo.size(); j++) {
575           if (stack_lo >= lwp_stack_lo[j] && stack_lo <= lwp_stack_hi[j]){
576             active = true;
577             result.push_back(stack_buffer[j]);
578             break;
579           }
580         }
581         
582         if (!active) {
583           walkStack(currentFrame, pcs, fps, noPause);
584           result.push_back(pcs);
585         }
586     }
587   }
588
589   if (!noPause && needToCont) {
590      if (!continueProc()){
591         cerr << "walkAllStack: continueProc failed" << endl;
592      }
593   }
594     
595 #ifndef BPATCH_LIBRARY
596   stopTimingStackwalk();
597 #endif
598
599   return result;
600 }
601 #endif //MT_THREAD
602 #endif
603
604 void process::correctStackFuncsForTramps(vector<Address> &pcs, 
605                                          vector<pd_Function *> &funcs)
606 {
607   instPoint *ip;
608   function_base *fn;
609
610   for(unsigned i=0; i < pcs.size(); i++) {
611
612     ip = findInstPointFromAddress(this, pcs[i]);
613     if( ip ) {
614
615       fn = const_cast<function_base*>( ip->iPgetFunction() );
616       if( fn ) {
617         funcs[i] = (pd_Function *) fn;
618       }
619     }
620   }
621 }
622
623
624 vector<pd_Function *> process::convertPCsToFuncs(vector<Address> pcs) {
625     vector <pd_Function *> ret;
626     unsigned i;
627         pd_Function *fn;
628     for(i=0;i<pcs.size();i++) {
629                 fn = (pd_Function *)findFuncByAddr(pcs[i]);
630         ret.push_back(fn);
631     }
632     return ret;
633 }
634
635
636 // triggeredInStackFrame is used to determine whether instrumentation
637 //   added at the specified instPoint/callWhen/callOrder would have been
638 //   executed based on the supplied pc.
639 //
640 // If the pc is within instrumentation for the instPoint, the callWhen
641 //   and callOrder must be examined.  triggeredInStackFrame will return
642 //   true if the pc is located after the identified point of
643 //   instrumentation.
644 //   
645 // If the pc is not in instrumentation for the supplied instPoint, and
646 //   the instPoint is located at the function entry or if the instPoint
647 //   is for preInsn at a function call and the pc is located at the
648 //   return address of the callsite (indicating that the call is
649 //   currently executing), triggeredInStackFrame will return true.
650
651 bool process::triggeredInStackFrame(instPoint* point, pd_Function* stack_fn,
652                                     Address pc, callWhen when, callOrder order)
653 {
654   //this->print(stderr, ">>> triggeredInStackFrame(): ");
655   trampTemplate *tempTramp;
656   bool retVal = false;
657
658   if (stack_fn != point->iPgetFunction()) return false;
659
660   if ( pd_debug_catchup )
661       cerr << "In triggeredInStackFrame : stack function matches function containing instPoint" << endl;
662   
663   //  Is the pc within the instPoint instrumentation?
664   instPoint* currentIp = findInstPointFromAddress(this, pc);
665
666   if ( currentIp && currentIp == point )
667   {
668     tempTramp = findBaseTramp(currentIp, this);
669
670     if ( tempTramp )
671     {
672       //  Check if pc in basetramp
673       if ( tempTramp->inBasetramp(pc) )
674       {
675         if ( pd_debug_catchup )
676         {
677           cerr << "  Found pc in BaseTramp" << endl;
678           fprintf(stderr, "    baseTramp range is (%lx - %lx)\n",
679                   tempTramp->baseAddr,
680                   (tempTramp->baseAddr + tempTramp->size));
681           fprintf(stderr, "    localPreReturnOffset is %lx\n",
682                   tempTramp->baseAddr+tempTramp->localPreReturnOffset);
683           fprintf(stderr, "    localPostReturnOffset is %lx\n",
684                   tempTramp->baseAddr+tempTramp->localPostReturnOffset);
685         }
686         
687         if ( (when == callPreInsn && 
688             pc >= tempTramp->baseAddr+tempTramp->localPreReturnOffset) ||
689           (when == callPostInsn &&
690             pc >= tempTramp->baseAddr+tempTramp->localPostReturnOffset) )
691         {
692           if ( pd_debug_catchup )
693             cerr << "  pc is after requested instrumentation point, returning true." << endl;
694           retVal = true;
695         }
696         else
697         {
698           if ( pd_debug_catchup )
699             cerr << "  pc is before requested instrumentation point, returning false." << endl;
700         }
701       }
702       else //  pc is in a mini-tramp
703       {
704         instInstance* currInstance = findMiniTramps(currentIp);
705         bool pcInTramp = false;
706
707         while ( currInstance != NULL && !pcInTramp )
708         {
709           if ( pd_debug_catchup )
710           {
711             fprintf(stderr, "  Checking for pc in mini-tramp (%lx - %lx)\n",
712                     currInstance->trampBase, currInstance->returnAddr);
713           }
714           
715           if ( pc >= currInstance->trampBase &&
716                 pc <= currInstance->returnAddr )
717           {
718             // We have found the mini-tramp that is currently being executed
719             pcInTramp = true;
720
721             if ( pd_debug_catchup )
722             {
723               cerr << "  Found pc in mini-tramp" << endl;
724               cerr << "    Requested instrumentation is for ";
725               switch(when) {
726                 case callPreInsn:
727                   cerr << "PreInsn ";
728                   break;
729                 case callPostInsn:
730                   cerr << "PostInsn ";
731                   break;
732               }
733               switch(order) {
734                 case orderFirstAtPoint:
735                   cerr << "prepend ";
736                   break;
737                 case orderLastAtPoint:
738                   cerr << "append ";
739                   break;
740               }
741               cerr << endl;
742
743               cerr << "    The pc is in ";
744               switch(currInstance->when) {
745                 case callPreInsn:
746                   cerr << "PreInsn ";
747                   break;
748                 case callPostInsn:
749                   cerr << "PostInsn ";
750                   break;
751               }
752               cerr << "instrumentation." << endl;
753             }
754             
755             // The request should be triggered if it is for:
756             //   1)  pre-instruction instrumentation to prepend
757             //   2)  pre-instruction instrumentation to append
758             //         and the pc is in PostInsn instrumentation
759             //   3)  post-instruction instrumentation to prepend
760             //         and the pc is in PostInsn instrumentation
761             if ( (when == callPreInsn && (order == orderFirstAtPoint || 
762                   (order == orderLastAtPoint &&
763                     currInstance->when == callPostInsn))) ||
764                  (when == callPostInsn && order == orderFirstAtPoint &&
765                     currInstance->when == callPostInsn) )
766             {
767               if ( pd_debug_catchup )
768                 cerr << "  pc is after requested instrumentation point, returning true." << endl;
769               retVal = true;
770             }
771             else
772             {
773               if ( pd_debug_catchup )
774                 cerr << "  pc is before requested instrumentation point, returning false." << endl;
775             }
776           }
777   
778           currInstance = currInstance->next;
779         }
780       }
781     } 
782   }
783   else  // pc not in instrumentation
784   {
785     //  If the instrumentation point is located at the entry of the
786     //    function, it would be triggered.
787     //  If the instrumentation point is a call site, the instrumentation
788     //    is preInsn and the pc points to the return address of the call,
789     //    the instrumentation should be triggered as any postInsn instrumentation
790     //    will be executed.
791 #if defined(mips_sgi_irix6_4) || defined(mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
792     if (point->ipType_ == IPT_ENTRY) {
793       if ( pd_debug_catchup )
794         cerr << "  pc not in instrumentation, requested instrumentation for function entry, returning true." << endl;
795       retVal = true;
796     } else if (point->ipType_ == IPT_CALL && when == callPreInsn) {
797       // check if the $pc corresponds to the native call insn
798       Address base;
799       getBaseAddress(stack_fn->file()->exec(), base);
800       Address native_ra = base + stack_fn->getAddress(0) + point->offset_ + point->size_;
801       if (pc == native_ra)
802       {
803         if ( pd_debug_catchup )
804           cerr << "  Requested instrumentation is preInsn for callsite being executed.  Returning true." << endl;
805         retVal = true;
806       }
807       else
808       {
809         if ( pd_debug_catchup )
810           cerr << "  Function at requested preInsn callsite is not being executed.  Returning false." << endl;
811       }
812     }
813     else
814     {
815       if ( pd_debug_catchup )
816         cerr << "  Requested instrumentation point is not appropriate for catchup, returning false." << endl;
817     }      
818 #elif defined(sparc_sun_solaris2_4) || defined(alpha_dec_osf4_0)
819     if (point->ipType == functionEntry) {
820       if ( pd_debug_catchup )
821         cerr << "  pc not in instrumentation, requested instrumentation for function entry, returning true." << endl;
822       retVal = true;
823     } else if (point->ipType == callSite && when == callPreInsn) {
824       // looking at gdb, sparc-solaris seems to record PC of the 
825       //  call site + 8, as opposed to the PC of the call site.
826       Address base, target;
827       getBaseAddress( stack_fn->file()->exec(), base );
828       target = base + point->addr + 2 * sizeof(instruction);
829       if (pc == target) {
830         if ( pd_debug_catchup )
831           cerr << "  Requested instrumentation is preInsn for callsite being executed.  Returning true." << endl;
832         retVal = true;
833       } else {
834         trampTemplate *bt = findBaseTramp( point, this );
835         Address target = bt->baseAddr + bt->emulateInsOffset + 2 * sizeof(instruction);
836         if( pc == target )
837         {
838           if ( pd_debug_catchup )
839             cerr << "  Requested instrumentation is preInsn for callsite being executed.  Returning true." << endl;
840           retVal = true;
841         }
842         else
843         {
844           if ( pd_debug_catchup )
845             cerr << "  Function at requested preInsn callsite is not being executed.  Returning false." << endl;
846         }
847       }
848     }
849     else
850     {
851       if ( pd_debug_catchup )
852         cerr << "  Requested instrumentation point is not appropriate for catchup, returning false." << endl;
853     }      
854 #elif defined(rs6000_ibm_aix4_1)
855     if ( point->ipLoc == ipFuncEntry ) {
856       if ( pd_debug_catchup )
857         cerr << "  pc not in instrumentation, requested instrumentation for function entry, returning true." << endl;
858       retVal = true;
859     } else if ( point->ipLoc == ipFuncCallPoint && when == callPreInsn ) {
860       // check if the stack_pc points to the instruction after the call site
861       Address base, target;
862       getBaseAddress( stack_fn->file()->exec(), base );
863       target = base + point->addr + sizeof(instruction);
864       //cerr << " stack_pc should be " << (void*)target;
865       if ( pc == target ) {
866         if ( pd_debug_catchup )
867           cerr << "  Requested instrumentation is preInsn for callsite being executed.  Returning true." << endl;
868         retVal = true;
869       }
870       else
871       {
872         if ( pd_debug_catchup )
873           cerr << "  Function at requested preInsn callsite is not being executed.  Returning false." << endl;
874       }
875       //cerr << endl;
876     }
877     else
878     {
879       //if ( pd_debug_catchup )
880         //cerr << "  Requested instrumentation point is not appropriate for catchup, returning false." << endl;
881     }      
882 #elif defined(i386_unknown_nt4_0) || defined(i386_unknown_solaris2_5) \
883 || defined(i386_unknown_linux2_0) || defined(ia64_unknown_linux2_4)
884     if ( point->address() == point->func()->getAddress( this ) ) {
885       if ( pd_debug_catchup )
886         cerr << "  pc not in instrumentation, requested instrumentation for function entry, returning true." << endl;
887       retVal = true;
888     } else if ( point->insnAtPoint().isCall() && when == callPreInsn ) {
889       // check if the pc points to the instruction after the call site
890       Address base, target;
891       getBaseAddress( stack_fn->file()->exec(), base );
892       target = base + point->address() + point->insnAtPoint().size();
893       //cerr << " pc should be " << (void*)target;
894       if ( pc == target ) {
895         if ( pd_debug_catchup )
896           cerr << "  Requested instrumentation is preInsn for callsite being executed." << endl;
897         //cerr << " -- HIT";
898         retVal = true;
899       }
900       else
901       {
902         if ( pd_debug_catchup )
903           cerr << "  Function at requested preInsn callsite is not being executed.  Returning false." << endl;
904       }
905       //cerr << endl;
906     }
907     else
908     {
909       if ( pd_debug_catchup )
910         cerr << "  Requested instrumentation point is not appropriate for catchup, returning false." << endl;
911     }      
912 #endif
913   }
914
915   return retVal;
916 }
917
918
919 static Address alignAddress(Address addr, unsigned align) {
920   Address skew = addr % align;
921   return (skew) ? (((addr/align)+1)*align) : addr;
922 }
923
924 // disItem was previously declared const, but heap management
925 // occasionally deletes such items
926 bool isFreeOK(process *proc, disabledItem &dis, vector<Address> &pcs)
927 {
928   Address disPointer = dis.block.addr;
929   inferiorHeap *hp = &proc->heap;
930
931 #if defined(hppa1_1_hp_hpux)
932   if (proc->freeNotOK) return false;
933 #endif
934
935   heapItem *ptr = NULL;
936   if (!hp->heapActive.find(disPointer, ptr)) {
937     sprintf(errorLine,"Warning: attempt to free undefined heap entry "
938             "0x%p (pid=%d, heapActive.size()=%d)\n", 
939             (void*)disPointer, proc->getPid(), 
940             hp->heapActive.size());
941     logLine(errorLine);
942     return false;
943   }
944   assert(ptr);
945
946   vector<addrVecType> &points = dis.pointsToCheck; 
947   for (unsigned pci = 0; pci < pcs.size(); pci++) {
948     Address pc = pcs[pci];
949     // Condition 1: PC is inside current block
950     if ((pc >= ptr->addr) && (pc <= ptr->addr + ptr->length)) {
951       return false;
952     }
953     
954     for (unsigned j = 0; j < points.size(); j++) {
955       for (unsigned k = 0; k < points[j].size(); k++) {
956         Address predStart = points[j][k]; // start of predecessor code block
957         heapItem *pred = NULL;
958         if (!hp->heapActive.find(predStart, pred)) {
959           // predecessor code already freed: remove from list
960           int size = points[j].size();
961           points[j][k] = points[j][size-1];
962           points[j].resize(size-1);
963           k--; // move index back to account for resize()
964           continue;
965         }
966         assert(pred);
967
968         // Condition 2: current block is subset of predecessor block ???
969         if ((ptr->addr >= pred->addr) && (ptr->addr <= pred->addr + pred->length)) {
970           return false;
971         }
972         // Condition 3: PC is inside predecessor block
973         if ((pc >= pred->addr) && (pc <= pred->addr + pred->length)) {
974           return false;     
975         }
976       }
977     }
978   }
979   return true;
980 }
981
982 int heapItemCmpByAddr(const heapItem **A, const heapItem **B)
983 {
984   heapItem *a = *(heapItem **)const_cast<heapItem **>(A);
985   heapItem *b = *(heapItem **)const_cast<heapItem **>(B);
986
987   if (a->addr < b->addr) {
988       return -1;
989   } else if (a->addr > b->addr) {
990       return 1;
991   } else {
992       return 0;
993   }
994 }
995
996 void inferiorFreeCompact(inferiorHeap *hp)
997 {
998   vector<heapItem *> &freeList = hp->heapFree;
999   unsigned i, nbuf = freeList.size();
1000
1001   /* sort buffers by address */
1002   VECTOR_SORT(freeList, heapItemCmpByAddr);
1003
1004   /* combine adjacent buffers */
1005   bool needToCompact = false;
1006   for (i = 1; i < freeList.size(); i++) {
1007     heapItem *h1 = freeList[i-1];
1008     heapItem *h2 = freeList[i];
1009     assert(h1->length != 0);
1010     assert(h1->addr + h1->length <= h2->addr);
1011     if (h1->addr + h1->length == h2->addr
1012         && h1->type == h2->type) {
1013       h2->addr = h1->addr;
1014       h2->length = h1->length + h2->length;
1015       h1->length = 0;
1016       nbuf--;
1017       needToCompact = true;
1018     }
1019   }
1020
1021   /* remove any absorbed (empty) buffers */ 
1022   if (needToCompact) {
1023     vector<heapItem *> cleanList;
1024     unsigned end = freeList.size();
1025     for (i = 0; i < end; i++) {
1026       heapItem *h1 = freeList[i];
1027       if (h1->length != 0) {
1028         cleanList.push_back(h1);
1029       } else {
1030         delete h1;
1031       }
1032     }
1033     assert(cleanList.size() == nbuf);
1034     for (i = 0; i < nbuf; i++) {
1035       freeList[i] = cleanList[i];
1036     }
1037     freeList.resize(nbuf);
1038     assert(freeList.size() == nbuf);
1039   }
1040 }
1041
1042 void inferiorFreeDeferred(process *proc, inferiorHeap *hp, bool runOutOfMem)
1043 {
1044   // The curr_lwp parameter is IGNORED on non-AIX platforms.
1045   Frame currentFrame(proc);
1046   vector<Address> pcs;
1047   vector<Address> fps;
1048   proc->walkStack(currentFrame, pcs, fps);
1049
1050 #if defined(i386_unknown_nt4_0) || (defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
1051   // if walkStack() fails, assume not safe to delete anything
1052   if (pcs.size() == 0) return;
1053 #endif
1054
1055   // set allowed deletion time
1056   timeLength maxDelTime = MaxDeletingTime;
1057   if (runOutOfMem) {
1058     maxDelTime += MaxDeletingTime; // double allowed deletion time
1059     sprintf(errorLine, "Emergency attempt to free memory (pid=%d)\n", proc->getPid());
1060     logLine(errorLine);
1061   }
1062   timeStamp initTime = getCurrentTime();
1063
1064   vector<disabledItem> &disabled = hp->disabledList;
1065   for (unsigned i = 0; i < disabled.size(); i++) {
1066     // exit if over allowed deletion time
1067     if (getCurrentTime() - initTime >= maxDelTime) {
1068       sprintf(errorLine, "inferiorFreeDeferred(): out of time\n");
1069       logLine(errorLine);
1070       return;
1071     }
1072
1073     disabledItem &item = disabled[i];
1074     if (isFreeOK(proc, item, pcs)) {
1075       heapItem *np = NULL;
1076       Address pointer = item.block.addr;
1077       if (!hp->heapActive.find(pointer, np)) {
1078         showErrorCallback(96,"Internal error: "
1079                 "attempt to free non-defined heap entry.");
1080         return;
1081       }
1082       assert(np);
1083
1084       if (np->status != HEAPallocated) {
1085         sprintf(errorLine,"Attempt to re-free heap entry 0x%lx\n", pointer);
1086         logLine(errorLine);
1087         showErrorCallback(67, (const char *)errorLine); 
1088         return;
1089       }
1090
1091       // remove from active list
1092       hp->heapActive.undef(pointer);
1093       // remove from disabled list
1094       disabled[i] = disabled[disabled.size()-1];
1095       disabled.resize(disabled.size()-1);
1096       hp->disabledListTotalMem -= np->length;
1097       // add to free list
1098       np->status = HEAPfree;      
1099       hp->heapFree.push_back(np);
1100       hp->totalFreeMemAvailable += np->length;
1101       // bookkeeping
1102       hp->freed += np->length;
1103       inferiorMemAvailable = hp->totalFreeMemAvailable;
1104       i--; // move index back to account for resize()
1105     }
1106   }
1107 }
1108
1109 // Get inferior heaps from every library currently loaded.
1110 // This is done at startup by initInferiorHeap().
1111 // There's also another one which takes a shared library and
1112 // only looks in there for the heaps
1113
1114 bool process::getInfHeapList(vector<heapDescriptor> &infHeaps)
1115 {
1116   bool foundHeap = false;
1117   // First check the program (without shared libs)
1118   foundHeap = getInfHeapList(symbols, infHeaps);
1119
1120   // Now iterate through shared libs
1121   if (shared_objects)
1122     for(u_int j=0; j < shared_objects->size(); j++)
1123       {
1124         if(((*shared_objects)[j]->getImage())){
1125                 if (getInfHeapList(((*shared_objects)[j])->getImage(), infHeaps))
1126                   foundHeap = true;
1127               }
1128         }
1129
1130   return foundHeap;
1131 }
1132
1133 bool process::getInfHeapList(const image *theImage, // okay, boring name
1134                              vector<heapDescriptor> &infHeaps)
1135 {
1136
1137   // First we get the list of symbols we're interested in, then
1138   // we go through and add them to the heap list. This is done
1139   // for two reasons: first, the symbol address might be off (depends
1140   // on the image), and this lets us do some post-processing.
1141   bool foundHeap = false;
1142   vector<Symbol> heapSymbols;
1143   Address baseAddr = 0;
1144
1145   // For maximum flexibility the findInternalByPrefix function
1146   // returns a list of symbols
1147
1148   foundHeap = theImage->findInternalByPrefix(string("DYNINSTstaticHeap"),
1149                                              heapSymbols);
1150   if (!foundHeap)
1151     // Some platforms preface with an underscore
1152     foundHeap = theImage->findInternalByPrefix(string("_DYNINSTstaticHeap"),
1153                                                heapSymbols);
1154
1155   // The address in the symbol isn't necessarily absolute
1156   getBaseAddress(theImage, baseAddr);
1157   for (u_int j = 0; j < heapSymbols.size(); j++)
1158     {
1159       // The string layout is: DYNINSTstaticHeap_size_type_unique
1160       // Can't allocate a variable-size array on NT, so malloc
1161       // that sucker
1162       char *temp_str = (char *)malloc(strlen(heapSymbols[j].name().string_of())+1);
1163       strcpy(temp_str, heapSymbols[j].name().string_of());
1164       char *garbage_str = strtok(temp_str, "_"); // Don't care about beginning
1165       assert(!strcmp("DYNINSTstaticHeap", garbage_str));
1166       // Name is as is.
1167       // If address is zero, then skip (error condition)
1168       if (heapSymbols[j].addr() == 0)
1169         {
1170           cerr << "Skipping heap " << heapSymbols[j].name().string_of()
1171                << "with address 0" << endl;
1172           continue;
1173         }
1174       // Size needs to be parsed out (second item)
1175       // Just to make life difficult, the heap can have an optional
1176       // trailing letter (k,K,m,M,g,G) which indicates that it's in
1177       // kilobytes, megabytes, or gigabytes. Why gigs? I was bored.
1178       char *heap_size_str = strtok(NULL, "_"); // Second element, null-terminated
1179       unsigned heap_size = (unsigned) atol(heap_size_str);
1180       if (heap_size == 0)
1181         /* Zero size or error, either way this makes no sense for a heap */
1182         {
1183           free(temp_str);
1184           continue;
1185         }
1186       switch (heap_size_str[strlen(heap_size_str)-1])
1187         {
1188         case 'g':
1189         case 'G':
1190           heap_size *= 1024;
1191         case 'm':
1192         case 'M':
1193           heap_size *= 1024;
1194         case 'k':
1195         case 'K':
1196           heap_size *= 1024;
1197         default:
1198           break;
1199         }
1200
1201       // Type needs to be parsed out. Can someone clean this up?
1202       inferiorHeapType heap_type;
1203       char *heap_type_str = strtok(NULL, "_");
1204
1205       if (!strcmp(heap_type_str, "anyHeap"))
1206         heap_type = anyHeap;
1207       else if (!strcmp(heap_type_str, "lowmemHeap"))
1208         heap_type = lowmemHeap;
1209       else if (!strcmp(heap_type_str, "dataHeap"))
1210         heap_type = dataHeap;
1211       else if (!strcmp(heap_type_str, "textHeap"))
1212         heap_type = textHeap;
1213       else
1214         {
1215           cerr << "Unknown heap string " << heap_type_str << " read from file!" << endl;
1216           free(temp_str);
1217           continue;
1218         }
1219
1220       infHeaps.push_back(heapDescriptor(heapSymbols[j].name(),
1221 #ifdef mips_unknown_ce2_11 //ccw 13 apr 2001
1222                                  heapSymbols[j].addr(), 
1223 #else
1224                                  heapSymbols[j].addr()+baseAddr, 
1225 #endif
1226                                  heap_size, heap_type));
1227 #ifdef DEBUG
1228       fprintf(stderr, "Added heap %s at %x to %x\n",
1229               heapSymbols[j].name().string_of(), 
1230               heapSymbols[j].addr()+baseAddr,
1231               heapSymbols[j].addr()+baseAddr+heap_size);
1232 #endif /* DEBUG */
1233       free(temp_str);
1234     }
1235   return foundHeap;
1236 }
1237
1238 /*
1239  * This function adds an item to the dataUpdates vector
1240  * which is used to maintain a list of variables that have
1241  * been written by the mutator //ccw 26 nov 2001
1242  */
1243 void process::saveWorldData(Address address, int size, const void* src){
1244 #ifdef BPATCH_LIBRARY
1245 #ifdef sparc_sun_solaris2_4
1246         dataUpdate *newData = new dataUpdate;
1247         newData->address= address;
1248         newData->size = size;
1249         newData->value = new char[size];
1250         memcpy(newData->value, src, size);
1251         dataUpdates.push_back(newData);
1252 #else /* Get rid of annoying warnings */
1253 #if !defined(i386_unknown_linux2_0) && !defined(rs6000_ibm_aix4_1)
1254         Address tempaddr = address;
1255         int tempsize = size;
1256         const void *bob = src;
1257 #endif
1258 #endif
1259 #endif
1260 }
1261
1262 /*
1263  * Given an image, add all static heaps inside it
1264  * (DYNINSTstaticHeap...) to the buffer pool.
1265  */
1266
1267 void process::addInferiorHeap(const image *theImage)
1268 {
1269   vector<heapDescriptor> infHeaps;
1270
1271   /* Get a list of inferior heaps in the new image */
1272   if (getInfHeapList(theImage, infHeaps))
1273     {
1274       /* Add the vector to the inferior heap structure */
1275       for (u_int j=0; j < infHeaps.size(); j++)
1276         {
1277           heapItem *h = new heapItem (infHeaps[j].addr(), infHeaps[j].size(),
1278                                       infHeaps[j].type(), false);
1279           heap.bufferPool.push_back(h);
1280           heapItem *h2 = new heapItem(h);
1281           heap.heapFree.push_back(h2);
1282         }
1283     }
1284 }
1285
1286
1287 /*
1288  * Called to (re)initialize the static inferior heap structure.
1289  * To incrementally add a static inferior heap (in a dlopen()d module,
1290  * for example), use addInferiorHeap(image *)
1291  */
1292 void process::initInferiorHeap()
1293 {
1294   assert(this->symbols);
1295   inferiorHeap *hp = &heap;
1296   vector<heapDescriptor> infHeaps;
1297
1298   // first initialization: add static heaps to pool
1299   if (hp->bufferPool.size() == 0) {
1300     bool err;
1301     Address heapAddr=0;
1302     int staticHeapSize = alignAddress(SYN_INST_BUF_SIZE, 32);
1303
1304     // Get the inferior heap list
1305     getInfHeapList(infHeaps);
1306     
1307     bool lowmemHeapAdded = false;
1308     bool heapAdded = false;
1309     
1310     for (u_int j=0; j < infHeaps.size(); j++)
1311       {
1312         hp->bufferPool.push_back(new heapItem (infHeaps[j].addr(), infHeaps[j].size(),
1313                                         infHeaps[j].type(), false));
1314         heapAdded = true;
1315         if (infHeaps[j].type() == lowmemHeap)
1316           lowmemHeapAdded = true;
1317       }
1318     if (!heapAdded)
1319       {
1320         // No heap added. Check for the old DYNINSTdata heap
1321         unsigned LOWMEM_HEAP_SIZE=(32*1024);
1322         cerr << "No heap found of the form DYNINSTstaticHeap_<size>_<type>_<unique>." << endl;
1323         cerr << "Attempting to use old DYNINSTdata inferior heap..." << endl;
1324         heapAddr = findInternalAddress(string("DYNINSTdata"), true, err);
1325         assert(heapAddr);
1326         hp->bufferPool.push_back(new heapItem(heapAddr, staticHeapSize - LOWMEM_HEAP_SIZE,
1327                                        anyHeap, false));
1328         hp->bufferPool.push_back(new heapItem(heapAddr + staticHeapSize - LOWMEM_HEAP_SIZE,
1329                                        LOWMEM_HEAP_SIZE, lowmemHeap, false));
1330         heapAdded = true; 
1331         lowmemHeapAdded = true;
1332       }
1333     if (!lowmemHeapAdded)
1334       {
1335         // Didn't find the low memory heap. 
1336         // Handle better?
1337         // Yeah, gripe like hell
1338         cerr << "No lowmem heap found (DYNINSTstaticHeap_*_lowmem), inferior RPCs" << endl;
1339         cerr << "will probably fail" << endl;
1340       }
1341     
1342   }
1343
1344   // (re)initialize everything 
1345   hp->heapActive.clear();
1346   hp->heapFree.resize(0);
1347   hp->disabledList.resize(0);
1348   hp->disabledListTotalMem = 0;
1349   hp->freed = 0;
1350   hp->totalFreeMemAvailable = 0;
1351   
1352   /* add dynamic heap segments to free list */
1353   for (unsigned i = 0; i < hp->bufferPool.size(); i++) {
1354     heapItem *hi = new heapItem(hp->bufferPool[i]);
1355     hi->status = HEAPfree;
1356     hp->heapFree.push_back(hi);
1357     hp->totalFreeMemAvailable += hi->length;     
1358   }
1359   inferiorMemAvailable = hp->totalFreeMemAvailable;
1360 }
1361
1362 bool process::initTrampGuard()
1363 {
1364   // The runtime lib has a variable called DYNINST_tramp_guard
1365   // that acts as a flag determining whether or not it is safe
1366   // to enter instrumentation code. Basically, when we enter 
1367   // a base tramp first check to see if the flag is set. If
1368   // so, we skip instrumentation. If not, we set the flag and 
1369   // continue.
1370   // MT_THREAD: addr points to a vector, one per POS
1371   // Set after this is called: trampGuardAddr_
1372   // Returns: true on success, false on failure (can be asserted against).
1373   
1374   const string vrbleName = "DYNINST_tramp_guard";
1375   internalSym sym;
1376   bool flag = findInternalSymbol(vrbleName, true, sym);
1377   assert(flag);
1378   trampGuardAddr_ = sym.getAddr();
1379   //fprintf(stderr, "Found tramp guard at addr %x\n", (unsigned) trampGuardAddr_);
1380   return true;
1381 }
1382   
1383
1384 // create a new inferior heap that is a copy of src. This is used when a process
1385 // we are tracing forks.
1386 inferiorHeap::inferiorHeap(const inferiorHeap &src):
1387     heapActive(addrHash16)
1388 {
1389     for (unsigned u1 = 0; u1 < src.heapFree.size(); u1++) {
1390       heapFree.push_back(new heapItem(src.heapFree[u1]));
1391     }
1392
1393     vector<heapItem *> items = src.heapActive.values();
1394     for (unsigned u2 = 0; u2 < items.size(); u2++) {
1395       heapActive[items[u2]->addr] = new heapItem(items[u2]);
1396     }
1397     
1398     for (unsigned u3 = 0; u3 < src.disabledList.size(); u3++) {
1399       disabledList.push_back(src.disabledList[u3]);
1400     }
1401
1402     for (unsigned u4 = 0; u4 < src.bufferPool.size(); u4++) {
1403       bufferPool.push_back(new heapItem(src.bufferPool[u4]));
1404     }
1405
1406     disabledListTotalMem = src.disabledListTotalMem;
1407     totalFreeMemAvailable = src.totalFreeMemAvailable;
1408     inferiorMemAvailable = totalFreeMemAvailable;
1409     freed = 0;
1410 }
1411
1412 //
1413 // This function will return the index corresponding to the next position
1414 // available in heapFree.
1415 //
1416 int findFreeIndex(process *p, unsigned size, int type, Address lo, Address hi)
1417 {
1418   vector<heapItem *> &freeList = p->heap.heapFree;
1419
1420   int best = -1;
1421   for (unsigned i = 0; i < freeList.size(); i++) {
1422     heapItem *h = freeList[i];
1423     // check if free block matches allocation constraints
1424     if (h->type & type &&
1425         h->addr >= lo &&
1426         h->addr + size - 1 <= hi &&
1427         h->length >= size) 
1428       {
1429         if (best == -1) best = i;
1430         // check for better match
1431         if (h->length < freeList[best]->length) best = i;
1432       } 
1433   }
1434   return best;
1435 }  
1436
1437 //
1438 // dynamic inferior heap stuff
1439 //
1440 #if defined(USES_DYNAMIC_INF_HEAP)
1441 #define HEAP_DYN_BUF_SIZE (0x100000)
1442 // "imd_rpc_ret" = Inferior Malloc Dynamic RPC RETurn structure
1443 typedef struct {
1444   bool ready;
1445   void *result;
1446 } imd_rpc_ret;
1447 void inferiorMallocCallback(process * /*p*/, void *data, void *result)
1448 {
1449   imd_rpc_ret *ret = (imd_rpc_ret *)data;
1450   ret->result = result;
1451   ret->ready = true;
1452 }
1453 void alignUp(int &val, int align)
1454 {
1455   assert(val >= 0);
1456   assert(align >= 0);
1457
1458   if (val % align != 0) {
1459     val = ((val / align) + 1) * align;
1460   }
1461 }
1462 // dynamically allocate a new inferior heap segment using inferiorRPC
1463 void inferiorMallocDynamic(process *p, int size, Address lo, Address hi)
1464 {
1465 /* 03/07/2001 - Jeffrey Shergalis
1466  * TODO: This code was placed to prevent the infinite recursion on the
1467  * call to inferiorMallocDynamic, unfortunately it makes paradyn break
1468  * on Irix, temporarily fixed by the #if !defined(mips..., but should be properly fixed
1469  * in the future, just no time now
1470  */
1471 #if !defined(mips_sgi_irix6_4)
1472   // Fun (not) case: there's no space for the RPC to execute.
1473   // It'll call inferiorMalloc, which will call inferiorMallocDynamic...
1474   // Avoid this with a static bool.
1475   static bool inInferiorMallocDynamic = false;
1476
1477   if (inInferiorMallocDynamic) return;
1478   inInferiorMallocDynamic = true;
1479 #endif
1480
1481   // word-align buffer size 
1482   // (see "DYNINSTheap_align" in rtinst/src/RTheap-<os>.c)
1483   alignUp(size, 4);
1484
1485   // build AstNode for "DYNINSTos_malloc" call
1486   string callee = "DYNINSTos_malloc";
1487   vector<AstNode*> args(3);
1488   args[0] = new AstNode(AstNode::Constant, (void *)size);
1489   args[1] = new AstNode(AstNode::Constant, (void *)lo);
1490   args[2] = new AstNode(AstNode::Constant, (void *)hi);
1491   AstNode *code = new AstNode(callee, args);
1492   removeAst(args[0]);
1493   removeAst(args[1]);
1494   removeAst(args[2]);
1495
1496   // issue RPC and wait for result
1497   imd_rpc_ret ret = { false, NULL };
1498
1499   /* set lowmem to ensure there is space for inferior malloc */
1500   p->postRPCtoDo(code, true, &inferiorMallocCallback, &ret, -1, -1, 
1501                                                       false, true);
1502
1503   extern void checkProcStatus();
1504   do {
1505 #ifdef DETACH_ON_THE_FLY
1506     p->launchRPCifAppropriate((p->status()==running || p->juststopped), false);
1507 #else
1508     p->launchRPCifAppropriate((p->status()==running), false);
1509 #endif
1510     checkProcStatus();
1511   } while (!ret.ready);
1512   switch ((int)(Address)ret.result) {
1513   case 0:
1514 #ifdef DEBUG
1515     sprintf(errorLine, "DYNINSTos_malloc() failed\n");
1516     logLine(errorLine);
1517 #endif
1518     break;
1519   case -1:
1520     // TODO: assert?
1521     sprintf(errorLine, "DYNINSTos_malloc(): unaligned buffer size\n");
1522     logLine(errorLine);
1523     break;
1524   default:
1525     // add new segment to buffer pool
1526     heapItem *h = new heapItem((Address)ret.result, size, anyHeap, true, HEAPfree);
1527     p->heap.bufferPool.push_back(h);
1528     // add new segment to free list
1529     heapItem *h2 = new heapItem(h);
1530     p->heap.heapFree.push_back(h2);
1531     break;
1532   }
1533
1534 /* 03/07/2001 - Jeffrey Shergalis
1535  * Part of the above #if !defined(mips... patch for the recursion problem
1536  * TODO: Need a better solution
1537  */
1538 #if !defined(mips_sgi_irix6_4)
1539   inInferiorMallocDynamic = false;
1540 #endif
1541 }
1542 #endif /* USES_DYNAMIC_INF_HEAP */
1543
1544 const Address ADDRESS_LO = ((Address)0);
1545 const Address ADDRESS_HI = ((Address)~((Address)0));
1546
1547 Address inferiorMalloc(process *p, unsigned size, inferiorHeapType type, 
1548                        Address near_, bool *err)
1549 {
1550   inferiorHeap *hp = &p->heap;
1551   if (err) *err = false;
1552   assert(size > 0);
1553
1554   // allocation range
1555   Address lo = ADDRESS_LO; // Should get reset to a more reasonable value
1556   Address hi = ADDRESS_HI; // Should get reset to a more reasonable value
1557  
1558 #if defined(USES_DYNAMIC_INF_HEAP)
1559   inferiorMallocAlign(size); // align size
1560   // Set the lo/hi constraints (if necessary)
1561   inferiorMallocConstraints(near_, lo, hi, type);
1562
1563 #else
1564   /* align to cache line size (32 bytes on SPARC) */
1565   size = (size + 0x1f) & ~0x1f; 
1566 #endif /* USES_DYNAMIC_INF_HEAP */
1567   // find free memory block (7 attempts)
1568   // attempt 0: as is
1569   // attempt 1: deferred free, compact free blocks
1570   // attempt 2: allocate new segment (1 MB, constrained)
1571   // attempt 3: allocate new segment (sized, constrained)
1572   // attempt 4: remove range constraints
1573   // attempt 5: allocate new segment (1 MB, unconstrained)
1574   // attempt 6: allocate new segment (sized, unconstrained)
1575   // attempt 7: deferred free, compact free blocks (why again?)
1576   int freeIndex = -1;
1577   int ntry = 0;
1578   for (ntry = 0; freeIndex == -1; ntry++) {
1579     switch(ntry) {
1580     case 0: // as is
1581       break;
1582 #if defined(USES_DYNAMIC_INF_HEAP)
1583     case 1: // deferred free, compact free blocks
1584       inferiorFreeDeferred(p, hp, false);
1585       inferiorFreeCompact(hp);
1586       break;
1587     case 2: // allocate new segment (1MB, constrained)
1588       inferiorMallocDynamic(p, HEAP_DYN_BUF_SIZE, lo, hi);
1589       break;
1590     case 3: // allocate new segment (sized, constrained)
1591       inferiorMallocDynamic(p, size, lo, hi);
1592       break;
1593     case 4: // remove range constraints
1594       fprintf(stderr, "Removing address limits: looking for 0x%x near 0x%x. Old constraints: 0x%x - 0x%x\n", 
1595               (unsigned int) size, (unsigned int) near_, (unsigned int)lo, (unsigned int)hi);
1596       lo = ADDRESS_LO;
1597       hi = ADDRESS_HI;
1598       if (err) {
1599         *err = true;
1600       }
1601       break;
1602     case 5: // allocate new segment (1MB, unconstrained)
1603       inferiorMallocDynamic(p, HEAP_DYN_BUF_SIZE, lo, hi);
1604       break;
1605     case 6: // allocate new segment (sized, unconstrained)
1606       inferiorMallocDynamic(p, size, lo, hi);
1607       break;
1608     case 7: // deferred free, compact free blocks
1609       inferiorFreeDeferred(p, hp, true);
1610       inferiorFreeCompact(hp);
1611       break;
1612 #else /* !(USES_DYNAMIC_INF_HEAP) */
1613     case 1: // deferred free, compact free blocks
1614       inferiorFreeDeferred(p, hp, true);
1615       inferiorFreeCompact(hp);
1616       break;
1617 #endif /* USES_DYNAMIC_INF_HEAP */
1618       
1619     default: // error - out of memory
1620       sprintf(errorLine, "***** Inferior heap overflow: %d bytes "
1621               "freed, %d bytes requested\n", hp->freed, size);
1622       logLine(errorLine);
1623       showErrorCallback(66, (const char *) errorLine);    
1624 #if defined(BPATCH_LIBRARY)
1625       return(0);
1626 #else
1627       P__exit(-1);
1628 #endif
1629     }
1630     freeIndex = findFreeIndex(p, size, type, lo, hi);
1631   }
1632
1633   // adjust active and free lists
1634   heapItem *h = hp->heapFree[freeIndex];
1635   assert(h);
1636   // remove allocated buffer from free list
1637   if (h->length != size) {
1638     // size mismatch: put remainder of block on free list
1639     heapItem *rem = new heapItem(h);
1640     rem->addr += size;
1641     rem->length -= size;
1642     hp->heapFree[freeIndex] = rem;
1643   } else {
1644     // size match: remove entire block from free list
1645     unsigned last = hp->heapFree.size();
1646     hp->heapFree[freeIndex] = hp->heapFree[last-1];
1647     hp->heapFree.resize(last-1);
1648   }
1649   // add allocated block to active list
1650   h->length = size;
1651   h->status = HEAPallocated;
1652   hp->heapActive[h->addr] = h;
1653   // bookkeeping
1654   hp->totalFreeMemAvailable -= size;
1655   inferiorMemAvailable = hp->totalFreeMemAvailable;
1656   assert(h->addr);
1657
1658         // ccw: 28 oct 2001
1659         // create imageUpdate here:
1660         // imageUpdate(h->addr,size)
1661
1662 #ifdef BPATCH_LIBRARY
1663 #if defined(sparc_sun_solaris2_4 ) || defined(i386_unknown_linux2_0)
1664         if(p->collectSaveWorldData){
1665
1666 #if defined(sparc_sun_solaris2_4)
1667                 if(h->addr < 0xF0000000){
1668 #elif defined(i386_unknown_linux2_0)
1669                 if(h->addr < 0x40000000){
1670 #endif  
1671                         imageUpdate *imagePatch=new imageUpdate; 
1672                         imagePatch->address = h->addr;
1673                         imagePatch->size = size;
1674                         p->imageUpdates.push_back(imagePatch);
1675                         //printf(" PUSHBACK %x %x\n", imagePatch->address, imagePatch->size); 
1676                 }else{
1677                         //printf(" HIGHMEM UPDATE %x %x\n", h->addr, size);
1678                         imageUpdate *imagePatch=new imageUpdate;
1679                         imagePatch->address = h->addr;
1680                         imagePatch->size = size;
1681                         p->highmemUpdates.push_back(imagePatch);
1682                         //printf(" PUSHBACK %x %x\n", imagePatch->address, imagePatch->size);
1683
1684                 }
1685                 //fflush(stdout);
1686         }
1687 #endif
1688 #endif
1689
1690   return(h->addr);
1691 }
1692
1693 void inferiorFree(process *p, Address block, 
1694                   const vector<addrVecType> &pointsToCheck)
1695 {
1696   inferiorHeap *hp = &p->heap;
1697
1698   // find block on active list
1699   heapItem *h = NULL;  
1700   if (!hp->heapActive.find(block, h)) {
1701     showErrorCallback(96,"Internal error: "
1702         "attempt to free non-defined heap entry.");
1703     return;
1704   }
1705   assert(h);
1706
1707   // add block to disabled list
1708   hp->disabledList.push_back(disabledItem(h, pointsToCheck));
1709   hp->disabledListTotalMem += h->length;
1710   
1711   // perform deferred freeing if above watermark
1712   if (((hp->disabledListTotalMem > FREE_WATERMARK) ||
1713        (hp->disabledList.size() > SIZE_WATERMARK)) && waitingPeriodIsOver()) 
1714     {
1715       inferiorFreeDeferred(p, hp, false);
1716     }
1717 }
1718
1719
1720 #ifdef DETACH_ON_THE_FLY
1721 extern void initDetachOnTheFly();
1722 #endif
1723
1724 // initializes all DYNINST lib stuff: init the inferior heap and check for 
1725 // required symbols.
1726 // This is only called after we get the first breakpoint (SIGTRAP), because
1727 // the DYNINST lib can be dynamically linked (currently it is only dynamically
1728 // linked on Windows NT)
1729 bool process::initDyninstLib() {
1730 #if defined(i386_unknown_nt4_0)  || (defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
1731    /***
1732      Kludge for Windows NT: we need to call waitProcs here so that
1733      we can load libdyninstRT when we attach to an already running
1734      process. The solution to avoid this kludge is to divide 
1735      attachProcess in two parts: first we attach to a process,
1736      and later, after libdyninstRT has been loaded,
1737      we install the call to DYNINSTinit.
1738     ***/
1739
1740    // libDyninstRT should already be loaded when we get here,
1741    // except if the process was created via attach
1742    if (createdViaAttach) {
1743      // need to set reachedFirstBreak to false here, so that
1744      // libdyninstRT gets loaded in waitProcs.
1745      reachedFirstBreak = false;
1746      while (!hasLoadedDyninstLib) {
1747        int status;
1748        waitProcs(&status);
1749      }
1750    }
1751    assert(hasLoadedDyninstLib);
1752 #endif
1753
1754   initInferiorHeap();
1755   initTrampGuard();
1756   extern vector<sym_data> syms_to_find;
1757   if (!heapIsOk(syms_to_find))
1758     return false;
1759
1760   return true;
1761 }
1762
1763 //
1764 // cleanup when a process is deleted
1765 //
1766 #ifdef BPATCH_LIBRARY
1767 process::~process()
1768 {
1769     detach(false);
1770
1771     // remove inst points for this process
1772     cleanInstFromActivePoints(this);
1773
1774     // remove it from the processVec
1775     unsigned int size = processVec.size();
1776     bool found = false;
1777
1778     for (unsigned lcv=0; lcv < size; lcv++) {
1779         if (processVec[lcv] == this) {
1780             assert(!found);
1781             found = true;
1782             processVec[lcv] = processVec[processVec.size()-1];
1783             processVec.resize(size-1);
1784         }
1785     }
1786 }
1787 #else
1788 process::~process() {
1789   cpuTimeMgr->destroyMechTimers(this);
1790 }
1791 #endif
1792
1793 unsigned hash_bp(function_base * const &bp ) { return(addrHash4((Address) bp)); }
1794
1795 //
1796 // Process "normal" (non-attach, non-fork) ctor, for when a new process
1797 // is fired up by paradynd itself.
1798 // This ctor. is also used in the case that the application has been fired up
1799 // by another process and stopped just after executing the execv() system call.
1800 // In the "normal" case, the parameter iTraceLink will be a non-negative value which
1801 // corresponds to the pipe descriptor of the trace pipe used between the paradynd
1802 // and the application. In the later case, iTraceLink will be -1. This will be 
1803 // posteriorly used to properly initialize the createdViaAttachToCreated flag. - Ana
1804 //
1805
1806 //removed all ioLink related code for output redirection
1807 process::process(int iPid, image *iImage, int iTraceLink 
1808 #ifdef SHM_SAMPLING
1809                  , key_t theShmKey,
1810                  const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
1811 #endif
1812 ) :
1813   curr_lwp(0),
1814   collectSaveWorldData(true),
1815 #ifndef BPATCH_LIBRARY
1816   cpuTimeMgr(NULL),
1817 #ifdef HRTIME
1818   hr_cpu_link(NULL),
1819 #endif
1820 #endif
1821   baseMap(ipHash), 
1822 #ifdef BPATCH_LIBRARY
1823   PDFuncToBPFuncMap(hash_bp),
1824   instPointMap(hash_address),
1825 #endif
1826   savedRegs(NULL),
1827   pid(iPid), // needed in fastInferiorHeap ctors below
1828 #if !defined(BPATCH_LIBRARY)
1829   previous(0),
1830   inferiorHeapMgr(theShmKey, iShmHeapStats, iPid),
1831   theSuperTable(this,
1832                 iShmHeapStats[0].maxNumElems,
1833                 iShmHeapStats[1].maxNumElems,
1834 #if defined(MT_THREAD)  
1835                 iShmHeapStats[2].maxNumElems,
1836                 MAX_NUMBER_OF_THREADS/4
1837 #else
1838                 iShmHeapStats[2].maxNumElems
1839 #endif
1840                 ),
1841 #endif
1842   callBeforeContinue(NULL)
1843 {
1844 #ifdef DETACH_ON_THE_FLY
1845   haveDetached = 0;
1846   juststopped = 0;
1847   needsDetach = 0;
1848   pendingSig = 0;
1849 #endif /* DETACH_ON_THE_FLY */
1850
1851 #if defined(MT_THREAD)
1852     preambleForDYNINSTinit=true;
1853     inThreadCreation=false;
1854     DYNINSTthreadRPC = 0 ;      //for safe inferiorRPC
1855     DYNINSTthreadRPC_mp = NULL ;
1856     DYNINSTthreadRPC_cvp = NULL;
1857     DYNINSTthreadRPC_pending_p =  NULL;
1858     DYNINST_allthreads_p = 0 ;  //for look into the thread package
1859     allthreads = 0 ;            // and the live threads
1860 #endif
1861     hasBootstrapped = false;
1862     save_exitset_ptr = NULL;
1863
1864     // the next two variables are used only if libdyninstRT is dynamically linked
1865     hasLoadedDyninstLib = false;
1866     isLoadingDyninstLib = false;
1867
1868 #if !defined(i386_unknown_nt4_0)  && !(defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
1869     dyninstlib_brk_addr = 0;
1870     main_brk_addr = 0;
1871 #endif
1872
1873     reachedFirstBreak = false; // haven't yet seen first trap
1874     wasRunningWhenAttached = false;
1875     reachedVeryFirstTrap = false;
1876     createdViaAttach = false;
1877     createdViaFork = false;
1878     createdViaAttachToCreated = false; 
1879
1880 #ifndef BPATCH_LIBRARY
1881       if (iTraceLink == -1 ) createdViaAttachToCreated = true;
1882                          // indicates the unique case where paradynd is attached to
1883                          // a stopped application just after executing the execv() --Ana
1884 #endif
1885     needToContinueAfterDYNINSTinit = false;  //Wait for press of "RUN" button
1886
1887     symbols = iImage;
1888     mainFunction = NULL; // set in platform dependent function heapIsOk
1889
1890     status_ = neonatal;
1891     exitCode_ = -1;
1892     continueAfterNextStop_ = 0;
1893     deferredContinueProc = false;
1894
1895 #ifndef BPATCH_LIBRARY
1896     initCpuTimeMgr();
1897
1898     string buff = string(pid); // + string("_") + getHostName();
1899     rid = resource::newResource(machineResource, // parent
1900                                 (void*)this, // handle
1901                                 nullString, // abstraction
1902                                 iImage->name(), // process name
1903                                 timeStamp::ts1970(), // creation time
1904                                 buff, // unique name (?)
1905                                 MDL_T_STRING, // mdl type (?)
1906                                 true
1907                                 );
1908 #endif
1909
1910     parent = NULL;
1911     bufStart = 0;
1912     bufEnd = 0;
1913     inExec = false;
1914
1915     cumObsCost = 0;
1916     lastObsCostLow = 0;
1917
1918     proc_fd = -1;
1919
1920 #if defined(i386_unknown_solaris2_5) || defined(i386_unknown_linux2_0) \
1921  || defined(i386_unknown_nt4_0) || defined(ia64_unknown_linux2_4)
1922     trampTableItems = 0;
1923     memset(trampTable, 0, sizeof(trampTable));
1924 #endif
1925     currentPC_ = 0;
1926     hasNewPC = false;
1927     
1928     dynamiclinking = false;
1929     dyn = new dynamic_linking;
1930     shared_objects = 0;
1931     runtime_lib = 0;
1932     all_functions = 0;
1933     all_modules = 0;
1934     some_modules = 0;
1935     some_functions = 0;
1936     waiting_for_resources = false;
1937     signal_handler = 0;
1938     execed_ = false;
1939
1940 #ifdef SHM_SAMPLING
1941 #ifdef sparc_sun_sunos4_1_3
1942    kvmHandle = kvm_open(0, 0, 0, O_RDONLY, 0);
1943    if (kvmHandle == NULL) {
1944       perror("could not map child's uarea; kvm_open");
1945       exit(5);
1946    }
1947
1948 //   childUareaPtr = tryToMapChildUarea(iPid);
1949    childUareaPtr = NULL;
1950 #endif
1951 #endif
1952
1953    splitHeaps = false;
1954
1955 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1) || defined(alpha_dec_osf4_0)
1956         // XXXX - move this to a machine dependant place.
1957
1958         // create a seperate text heap.
1959         //initInferiorHeap(true);
1960         splitHeaps = true;
1961 #endif
1962 #if defined(alpha_dec_osf4_0)
1963    changedPCvalue = 0;
1964 #endif
1965
1966           traceLink = iTraceLink; // notice that tracelink will be -1 in the unique
1967                                   // case called "AttachToCreated" - Ana
1968           
1969    //removed for output redirection
1970    //ioLink = iIoLink;
1971
1972    RPCs_waiting_for_syscall_to_complete = false;
1973    stoppedInSyscall = false;
1974
1975    // attach to the child process (machine-specific implementation)
1976    if (!attach()) { // error check?
1977       string msg = string("Warning: unable to attach to specified process :")
1978                    + string(pid);
1979       showErrorCallback(26, msg.string_of());
1980    }
1981 /*
1982 // A test. Let's see if my symbol-print-out works
1983    fprintf(stderr, "Attempting to find DYNINST internal symbols\n");
1984    vector<heapDescriptor*> inferiorHeaps;
1985    symbols->getDYNINSTHeaps(inferiorHeaps);
1986    fprintf(stderr, "Done\n");
1987 */
1988 } // end of normal constructor
1989
1990
1991 //
1992 // Process "attach" ctor, for when paradynd is attaching to an already-existing
1993 // process. 
1994 //
1995 process::process(int iPid, image *iSymbols,
1996                  int afterAttach, // 1 --> pause, 2 --> run, 0 --> leave as is
1997                  bool &success
1998 #if !defined(BPATCH_LIBRARY)
1999                  , key_t theShmKey,
2000                  const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
2001 #endif
2002                  ) :
2003   curr_lwp(0),
2004   collectSaveWorldData(true),
2005 #if !defined(BPATCH_LIBRARY)
2006   cpuTimeMgr(NULL),
2007 #ifdef HRTIME
2008   hr_cpu_link(NULL),
2009 #endif // HRTIME
2010 #endif // BPATCH
2011   baseMap(ipHash),
2012 #if defined(BPATCH_LIBRARY)
2013   PDFuncToBPFuncMap(hash_bp),
2014   instPointMap(hash_address),
2015 #endif
2016   savedRegs(NULL),
2017   pid(iPid),
2018 #if !defined(BPATCH_LIBRARY)
2019   previous(0),
2020   inferiorHeapMgr(theShmKey, iShmHeapStats, iPid),
2021   theSuperTable(this,
2022                 iShmHeapStats[0].maxNumElems,
2023                 iShmHeapStats[1].maxNumElems,
2024 #if defined(MT_THREAD)
2025                 iShmHeapStats[2].maxNumElems,
2026                 MAX_NUMBER_OF_THREADS/4
2027 #else
2028   iShmHeapStats[2].maxNumElems
2029 #endif
2030                 ),
2031 #endif
2032   callBeforeContinue(NULL)
2033 {
2034
2035 #ifdef DETACH_ON_THE_FLY
2036   haveDetached = 0;
2037   juststopped = 0;
2038   needsDetach = 0;
2039   pendingSig = 0;
2040 #endif /* DETACH_ON_THE_FLY */
2041
2042
2043 #if defined(MT_THREAD)
2044    inThreadCreation=false;
2045    preambleForDYNINSTinit=true;
2046    DYNINSTthreadRPC = 0 ;
2047    DYNINSTthreadRPC_mp = NULL ;
2048    DYNINSTthreadRPC_cvp = NULL;
2049    DYNINSTthreadRPC_pending_p = NULL;
2050    DYNINST_allthreads_p = 0 ;
2051    allthreads = 0 ;
2052 #endif
2053    RPCs_waiting_for_syscall_to_complete = false;
2054    save_exitset_ptr = NULL;
2055    stoppedInSyscall = false;
2056
2057 #if !defined(i386_unknown_nt4_0)  && !(defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
2058     dyninstlib_brk_addr = 0;
2059     main_brk_addr = 0;
2060 #endif
2061
2062 #if !defined(BPATCH_LIBRARY)
2063    //  When running an IRIX MPI program, the IRIX MPI job launcher
2064    //  "mpirun" creates all the processes.  When we create process
2065    //  objects for these processes we aren't actually "attaching" to
2066    //  the program, but we use most of this constructor since we
2067    //  don't actually create the processes.
2068
2069     if ( process::pdFlavor == "mpi" && osName.prefixed_by("IRIX") )
2070       {
2071         needToContinueAfterDYNINSTinit = false;  //Wait for press of "RUN" button         
2072         reachedFirstBreak = false; // haven't yet seen first trap
2073         createdViaAttach = false;
2074       }
2075     else
2076 #endif
2077       {
2078         reachedFirstBreak = true;
2079         createdViaAttach = true;
2080       }
2081     
2082     hasBootstrapped = false;
2083     reachedVeryFirstTrap = true;
2084     createdViaFork = false;
2085     createdViaAttachToCreated = false; 
2086     
2087     // the next two variables are used only if libdyninstRT is dynamically linked
2088     hasLoadedDyninstLib = false;
2089     isLoadingDyninstLib = false;
2090     
2091     symbols = iSymbols;
2092     mainFunction = NULL; // set in platform dependent function heapIsOk
2093     
2094     status_ = neonatal;
2095     exitCode_ = -1;
2096     continueAfterNextStop_ = 0;
2097     deferredContinueProc = false;
2098     
2099 #ifndef BPATCH_LIBRARY
2100     initCpuTimeMgr();
2101     
2102     string buff = string(pid); // + string("_") + getHostName();
2103     rid = resource::newResource(machineResource, // parent
2104                                 (void*)this, // handle
2105                                 nullString, // abstraction
2106                                 symbols->name(),
2107                                 timeStamp::ts1970(), // creation time
2108                                 buff, // unique name (?)
2109                                 MDL_T_STRING, // mdl type (?)
2110                                 true
2111                                 );
2112 #endif
2113
2114     parent = NULL;
2115     bufStart = 0;
2116     bufEnd = 0;
2117     inExec = false;
2118
2119     cumObsCost = 0;
2120     lastObsCostLow = 0;
2121
2122     proc_fd = -1;
2123
2124 #if defined(i386_unknown_solaris2_5) || defined(i386_unknown_linux2_0) \
2125  || defined(i386_unknown_nt4_0) || defined(ia64_unknown_linux2_4)
2126     trampTableItems = 0;
2127     memset(trampTable, 0, sizeof(trampTable));
2128 #endif
2129     currentPC_ = 0;
2130     hasNewPC = false;
2131     
2132     dynamiclinking = false;
2133     dyn = new dynamic_linking;
2134     shared_objects = 0;
2135     runtime_lib = 0;
2136     all_functions = 0;
2137     all_modules = 0;
2138     some_modules = 0;
2139     some_functions = 0;
2140     waiting_for_resources = false;
2141     signal_handler = 0;
2142     execed_ = false;
2143
2144     splitHeaps = false;
2145
2146 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1) || defined(alpha_dec_osf4_0)
2147         // XXXX - move this to a machine dependant place.
2148
2149         // create a seperate text heap.
2150         //initInferiorHeap(true);
2151         splitHeaps = true;
2152 #endif
2153
2154 #if defined(alpha_dec_osf4_0)
2155    changedPCvalue = 0;
2156 #endif
2157
2158    traceLink = -1; // will be set later, when the appl runs DYNINSTinit
2159
2160    //removed for output redirection
2161    //ioLink = -1; // (ARGUABLY) NOT YET IMPLEMENTED...MAYBE WHEN WE ATTACH WE DON'T WANT
2162                 // TO REDIRECT STDIO SO WE CAN LEAVE IT AT -1.
2163
2164    // Now the actual attach...the moment we've all been waiting for
2165
2166    attach_cerr << "process attach ctor: about to attach to pid " << getPid() << endl;
2167
2168    // It is assumed that a call to attach() doesn't affect the running status
2169    // of the process.  But, unfortunately, some platforms may barf if the
2170    // running status is anything except paused. (How to deal with this?)
2171    // Note that solaris in particular seems able to attach even if the process
2172    // is running.
2173
2174    if (!attach()) {
2175       string msg = string("Warning: unable to attach to specified process: ")
2176                    + string(pid);
2177       showErrorCallback(26, msg.string_of());
2178       success = false;
2179       return;
2180    }
2181
2182 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
2183    // Now that we're attached, we can reparse the image with correct
2184    // settings.
2185    // Process is paused 
2186    int status = pid;
2187    fileDescriptor *desc = getExecFileDescriptor(symbols->pathname(), status, false);
2188    if (!desc) {
2189       string msg = string("Warning: unable to parse to specified process: ")
2190                    + string(pid);
2191       showErrorCallback(26, msg.string_of());
2192       success = false;
2193       return;
2194    }
2195    image *theImage = image::parseImage(desc);
2196    if (theImage == NULL) {
2197       string msg = string("Warning: unable to parse to specified process: ")
2198                    + string(pid);
2199       showErrorCallback(26, msg.string_of());
2200       success = false;
2201       return;
2202    }
2203    // this doesn't leak, since the old theImage was deleted. 
2204    symbols = theImage;
2205 #endif
2206
2207 #if defined(mips_sgi_irix6_4) && !defined(BPATCH_LIBRARY)
2208    if ( process::pdFlavor == "mpi" && osName.prefixed_by("IRIX") )
2209    {
2210       pause_();
2211       insertTrapAtEntryPointOfMain();
2212       continueProc();
2213    }
2214 #endif
2215
2216 #if defined(rs6000_ibm_aix4_1)
2217    wasRunningWhenAttached = false; /* XXX Or should the default be true? */
2218    // We use ptrace of AIX, which stops the process on attach.
2219    status_ = stopped;
2220 #else
2221    wasRunningWhenAttached = isRunning_();
2222    status_ = running;
2223 #endif
2224
2225 #if defined(i386_unknown_nt4_0)  || (defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
2226 // Except we still pause on NT.
2227     if (!pause())
2228         assert(false);
2229 #endif
2230
2231    if (afterAttach == 0)
2232       needToContinueAfterDYNINSTinit = wasRunningWhenAttached;
2233    else if (afterAttach == 1)
2234       needToContinueAfterDYNINSTinit = false;
2235    else if (afterAttach == 2)
2236       needToContinueAfterDYNINSTinit = true;
2237    else
2238       assert(false);
2239
2240    // Does attach() send a SIGTRAP, a la the initial SIGTRAP sent at the
2241    // end of exec?  It seems that on some platforms it does; on others
2242    // it doesn't.  Ick.  On solaris, it doesn't.
2243
2244    // note: we don't call getSharedObjects() yet; that happens once DYNINSTinit
2245    //       finishes (handleStartProcess)
2246
2247    // Everything worked
2248    success = true;
2249 }
2250
2251 // #if !defined(BPATCH_LIBRARY)
2252
2253 //
2254 // Process "fork" ctor, for when a process which is already being monitored by
2255 // paradynd executes the fork syscall.
2256 //
2257
2258 process::process(const process &parentProc, int iPid, int iTrace_fd
2259 #ifdef SHM_SAMPLING
2260                  ,key_t theShmKey,
2261                  void *applShmSegPtr,
2262                  const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
2263 #endif
2264                  ) :
2265   curr_lwp(0),
2266   collectSaveWorldData(true),
2267 #ifndef BPATCH_LIBRARY
2268   cpuTimeMgr(NULL),
2269 #ifdef HRTIME
2270   hr_cpu_link(NULL),
2271 #endif
2272 #endif
2273   baseMap(ipHash), // could change to baseMap(parentProc.baseMap)
2274 #ifdef BPATCH_LIBRARY
2275   PDFuncToBPFuncMap(hash_bp),
2276   instPointMap(hash_address),
2277 #endif
2278   savedRegs(NULL)
2279 #ifdef SHM_SAMPLING
2280   ,previous(0),
2281   inferiorHeapMgr(parentProc.inferiorHeapMgr, applShmSegPtr, 
2282                   theShmKey, iShmHeapStats, iPid),
2283   theSuperTable(parentProc.getTable(), this)
2284 #endif
2285   ,callBeforeContinue(parentProc.callBeforeContinue)
2286
2287 {
2288
2289 #ifdef DETACH_ON_THE_FLY
2290   haveDetached = 0;
2291   juststopped = 0;
2292   needsDetach = 0;
2293   pendingSig = 0;
2294 #endif /* DETACH_ON_THE_FLY */
2295
2296     // This is the "fork" ctor
2297 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
2298     inThreadCreation=false;
2299     preambleForDYNINSTinit=true;
2300     DYNINSTthreadRPC = 0 ;
2301     DYNINSTthreadRPC_mp = NULL ;
2302     DYNINSTthreadRPC_cvp = NULL;
2303     DYNINSTthreadRPC_pending_p = NULL;
2304     DYNINST_allthreads_p = 0 ;
2305     allthreads = 0 ;
2306 #endif
2307     RPCs_waiting_for_syscall_to_complete = false;
2308     save_exitset_ptr = NULL;
2309     stoppedInSyscall = false;
2310
2311
2312     hasBootstrapped = false;
2313        // The child of fork ("this") has yet to run DYNINSTinit.
2314
2315     // the next two variables are used only if libdyninstRT is dynamically linked
2316     hasLoadedDyninstLib = false; // TODO: is this the right value?
2317     isLoadingDyninstLib = false;
2318
2319     createdViaAttachToCreated = false;
2320         createdViaFork = true;
2321     createdViaAttach = parentProc.createdViaAttach;
2322     wasRunningWhenAttached = true;
2323     needToContinueAfterDYNINSTinit = true;
2324
2325     symbols = parentProc.symbols; // shouldn't a reference count also be bumped?
2326     mainFunction = parentProc.mainFunction;
2327
2328     traceLink = iTrace_fd;
2329
2330     //removed for output redireciton
2331     //ioLink = -1; // when does this get set?
2332
2333     status_ = neonatal; // is neonatal right?
2334     exitCode_ = -1;
2335     continueAfterNextStop_ = 0;
2336     deferredContinueProc = false;
2337
2338     pid = iPid; 
2339
2340 #ifndef BPATCH_LIBRARY
2341     initCpuTimeMgr();
2342
2343     string buff = string(pid); // + string("_") + getHostName();
2344     rid = resource::newResource(machineResource, // parent
2345                                 (void*)this, // handle
2346                                 nullString, // abstraction
2347                                 parentProc.symbols->name(),
2348                                 timeStamp::ts1970(), // creation time
2349                                 buff, // unique name (?)
2350                                 MDL_T_STRING, // mdl type (?)
2351                                 true
2352                                 );
2353 #endif
2354
2355     parent = &parentProc;
2356     
2357     bufStart = 0;
2358     bufEnd = 0;
2359
2360 #if !defined(i386_unknown_nt4_0) && !(defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
2361     dyninstlib_brk_addr = 0;
2362     main_brk_addr = 0;
2363 #endif
2364 #if defined(alpha_dec_osf4_0)
2365    changedPCvalue = 0;
2366 #endif
2367
2368     reachedFirstBreak = true; // initial TRAP has (long since) been reached
2369     reachedVeryFirstTrap = true;
2370
2371     splitHeaps = parentProc.splitHeaps;
2372
2373     heap = inferiorHeap(parentProc.heap);
2374
2375     inExec = false;
2376
2377     cumObsCost = 0;
2378     lastObsCostLow = 0;
2379
2380     proc_fd = -1;
2381
2382 #if defined(i386_unknown_solaris2_5) || defined(i386_unknown_linux2_0) \
2383  || defined(i386_unknown_nt4_0) || defined(ia64_unknown_linux2_4)
2384     trampTableItems = 0;
2385     memset(trampTable, 0, sizeof(trampTable));
2386 #endif
2387     currentPC_ = 0;
2388     hasNewPC = false;
2389
2390     dynamiclinking = parentProc.dynamiclinking;
2391     dyn = new dynamic_linking;
2392     *dyn = *parentProc.dyn;
2393     runtime_lib = parentProc.runtime_lib;
2394
2395     shared_objects = 0;
2396
2397     // make copy of parent's shared_objects vector
2398     if (parentProc.shared_objects) {
2399       shared_objects = new vector<shared_object*>;
2400       for (unsigned u1 = 0; u1 < parentProc.shared_objects->size(); u1++){
2401         (*shared_objects).push_back(
2402             new shared_object(*(*parentProc.shared_objects)[u1]));
2403       }
2404     }
2405
2406     all_functions = 0;
2407     if (parentProc.all_functions) {
2408       all_functions = new vector<function_base *>;
2409       for (unsigned u2 = 0; u2 < parentProc.all_functions->size(); u2++)
2410         (*all_functions).push_back((*parentProc.all_functions)[u2]);
2411     }
2412
2413     all_modules = 0;
2414     if (parentProc.all_modules) {
2415       all_modules = new vector<module *>;
2416       for (unsigned u3 = 0; u3 < parentProc.all_modules->size(); u3++)
2417         (*all_modules).push_back((*parentProc.all_modules)[u3]);
2418     }
2419
2420     some_modules = 0;
2421     if (parentProc.some_modules) {
2422       some_modules = new vector<module *>;
2423       for (unsigned u4 = 0; u4 < parentProc.some_modules->size(); u4++)
2424         (*some_modules).push_back((*parentProc.some_modules)[u4]);
2425     }
2426     
2427     some_functions = 0;
2428     if (parentProc.some_functions) {
2429       some_functions = new vector<function_base *>;
2430       for (unsigned u5 = 0; u5 < parentProc.some_functions->size(); u5++)
2431         (*some_functions).push_back((*parentProc.some_functions)[u5]);
2432     }
2433
2434     waiting_for_resources = false;
2435     signal_handler = parentProc.signal_handler;
2436     execed_ = false;
2437
2438 #if !defined(BPATCH_LIBRARY)
2439    // threads... // 6/2/99 zhichen
2440    for (unsigned i=0; i<parentProc.threads.size(); i++) {
2441      threads += new pdThread(this,parentProc.threads[i]);
2442 #if defined(MT_THREAD)
2443      pdThread *thr = threads[i] ;
2444      string buffer;
2445      string pretty_name=string(thr->get_start_func()->prettyName().string_of());
2446      buffer = string("thr_")+string(thr->get_tid())+string("{")+pretty_name+string("}");
2447      resource *rid;
2448      rid = resource::newResource(this->rid, (void *)thr, nullString, buffer, 
2449                                  timeStamp::ts1970(), "", MDL_T_STRING, true);
2450      thr->update_rid(rid);
2451 #endif
2452    }
2453 #endif
2454
2455 #if defined(SHM_SAMPLING) && defined(sparc_sun_sunos4_1_3)
2456    childUareaPtr = NULL;
2457 #endif
2458
2459    if (!attach()) {     // moved from ::forkProcess
2460       showErrorCallback(69, "Error in fork: cannot attach to child process");
2461       status_ = exited;
2462       return;
2463    }
2464
2465    if( isRunning_() )
2466            status_ = running;
2467    else
2468            status_ = stopped;
2469    // would neonatal be more appropriate?  Nah, we've reached the first trap
2470 }
2471
2472 // #endif
2473
2474 #ifdef SHM_SAMPLING
2475 void process::registerInferiorAttachedSegs(void *inferiorAttachedAtPtr) {
2476    shmsample_cerr << "process pid " << getPid() << ": welcome to register with inferiorAttachedAtPtr=" << inferiorAttachedAtPtr << endl;
2477
2478    inferiorHeapMgr.registerInferiorAttachedAt(inferiorAttachedAtPtr);
2479    theSuperTable.setBaseAddrInApplic(0,(intCounter*) inferiorHeapMgr.getSubHeapInApplic(0));
2480    theSuperTable.setBaseAddrInApplic(1,(tTimer*) inferiorHeapMgr.getSubHeapInApplic(1));
2481    theSuperTable.setBaseAddrInApplic(2,(tTimer*) inferiorHeapMgr.getSubHeapInApplic(2));
2482 #if defined(MT_THREAD)
2483    // we are now ready to update the thread table for thread 0 - naim
2484    assert(threads.size()==1 && threads[0]!=NULL);
2485    getTable().addThread(threads[0]);
2486 #endif
2487 }
2488 #endif
2489
2490
2491 extern bool forkNewProcess(string &file, string dir, vector<string> argv, 
2492                     vector<string> envp, string inputFile, string outputFile,
2493                     int &traceLink, 
2494                     int &pid, int &tid, 
2495                     int &procHandle, int &thrHandle,
2496                     int stdin_fd, int stdout_fd, int stderr_fd);
2497
2498 /*
2499  * Create a new instance of the named process.  Read the symbols and start
2500  *   the program
2501  */
2502 process *createProcess(const string File, vector<string> argv, 
2503                         vector<string> envp, const string dir = "", 
2504                         int stdin_fd=0, int stdout_fd=1, int stderr_fd=2)
2505 {
2506
2507         // prepend the directory (if any) to the filename,
2508         // unless the filename is an absolute pathname
2509         // 
2510         // The filename is an absolute pathname if it starts with a '/' on UNIX,
2511         // or a letter and colon pair on Windows.
2512     string file = File;
2513         if( dir.length() > 0 )
2514         {
2515 #if !defined(i386_unknown_nt4_0)
2516                 if( !file.prefixed_by("/") )
2517                 {
2518                         // file does not start  with a '/', so it is a relative pathname
2519                         // we modify it to prepend the given directory
2520                         if( dir.suffixed_by("/") )
2521                         {
2522                                 // the dir already has a trailing '/', so we can
2523                                 // just concatenate them to get an absolute path
2524                                 file = dir + file;
2525                         }
2526                         else
2527                         {
2528                                 // the dir does not have a trailing '/', so we must
2529                                 // add a '/' to get the absolute path
2530                                 file = dir + "/" + file;
2531                         }
2532                 }
2533                 else
2534                 {
2535                         // file starts with a '/', so it is an absolute pathname
2536                         // DO NOT prepend the directory, regardless of what the
2537                         // directory variable holds.
2538                         // nothing to do in this case
2539                 }
2540
2541 #else // !defined(i386_unknown_nt4_0)
2542                 if( (file.length() < 2) ||      // file is too short to be a drive specifier
2543                         !isalpha( file[0] ) ||  // first character in file is not a letter
2544                         (file[1] != ':') )              // second character in file is not a colon
2545                 {
2546                         file = dir + "\\" + file;
2547                 }
2548 #endif // !defined(i386_unknown_nt4_0)
2549         }
2550
2551 #if defined(BPATCH_LIBRARY) && !defined(BPATCH_REDIRECT_IO)
2552     string inputFile;
2553     string outputFile;
2554 #else
2555     // check for I/O redirection in arg list.
2556     string inputFile;
2557     for (unsigned i1=0; i1<argv.size(); i1++) {
2558       if (argv[i1] == "<") {
2559         inputFile = argv[i1+1];
2560         for (unsigned j=i1+2, k=i1; j<argv.size(); j++, k++)
2561           argv[k] = argv[j];
2562         argv.resize(argv.size()-2);
2563       }
2564     }
2565     // TODO -- this assumes no more than 1 of each "<", ">"
2566     string outputFile;
2567     for (unsigned i2=0; i2<argv.size(); i2++) {
2568       if (argv[i2] == ">") {
2569         outputFile = argv[i2+1];
2570         for (unsigned j=i2+2, k=i2; j<argv.size(); j++, k++)
2571           argv[k] = argv[j];
2572         argv.resize(argv.size()-2);
2573       }
2574     }
2575
2576
2577 #endif /* BPATCH_LIBRARY */
2578
2579     int traceLink = -1;
2580     //remove all ioLink related code for output redirection
2581     //int ioLink = stdout_fd;
2582
2583     int pid;
2584     int tid;
2585     int procHandle;
2586     int thrHandle;
2587
2588     if (!forkNewProcess(file, dir, argv, envp, inputFile, outputFile,
2589                    traceLink, pid, tid, procHandle, thrHandle,
2590                    stdin_fd, stdout_fd, stderr_fd)) {
2591       // forkNewProcess is responsible for displaying error messages
2592       return NULL;
2593     }
2594
2595 #ifdef BPATCH_LIBRARY
2596     // Register the pid with the BPatch library (not yet associated with a
2597     // BPatch_thread object).
2598     assert(BPatch::bpatch != NULL);
2599     BPatch::bpatch->registerProvisionalThread(pid);
2600 #endif
2601
2602     int status = pid;
2603     
2604     // Get the file descriptor for the executable file
2605     // "true" value is for AIX -- waiting for an initial trap
2606     // it's ignored on other platforms
2607     fileDescriptor *desc = getExecFileDescriptor(file, status, true);
2608     if (!desc)
2609       return NULL;
2610
2611 #ifndef BPATCH_LIBRARY
2612 // NEW: We bump up batch mode here; the matching bump-down occurs after shared objects
2613 //      are processed (after receiving the SIGSTOP indicating the end of running
2614 //      DYNINSTinit; more specifically, procStopFromDYNINSTinit().
2615 //      Prevents a diabolical w/w deadlock on solaris --ari
2616 tp->resourceBatchMode(true);
2617 #endif /* BPATCH_LIBRARY */
2618
2619         image *img = image::parseImage(desc);
2620         if (!img) {
2621             // For better error reporting, two failure return values would be
2622             // useful.  One for simple error like because-file-not-because.
2623             // Another for serious errors like found-but-parsing-failed 
2624             //    (internal error; please report to paradyn@cs.wisc.edu)
2625
2626             string msg = string("Unable to parse image: ") + file;
2627             showErrorCallback(68, msg.string_of());
2628             // destroy child process
2629             OS::osKill(pid);
2630             return(NULL);
2631         }
2632
2633         /* parent */
2634         statusLine("initializing process data structures");
2635
2636 #ifdef SHM_SAMPLING
2637         vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
2638         theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
2639         theShmHeapStats[0].maxNumElems  = numIntCounters;
2640
2641         theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
2642         theShmHeapStats[1].maxNumElems  = numWallTimers;
2643
2644         theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
2645         theShmHeapStats[2].maxNumElems  = numProcTimers;
2646 #endif
2647
2648         process *ret = new process(pid, img, traceLink
2649 #ifdef SHM_SAMPLING
2650                                    , 7000, // shm seg key to try first
2651                                    theShmHeapStats
2652 #endif
2653                                    );
2654            // change this to a ctor that takes in more args
2655
2656         assert(ret);
2657 #ifdef mips_unknown_ce2_11 //ccw 27 july 2000 : 29 mar 2001
2658                 //the MIPS instruction generator needs the Gp register value to
2659                 //correctly calculate the jumps.  In order to get it there it needs
2660                 //to be visible in Object-nt, and must be taken from process.
2661                 void *cont;
2662                 //DebugBreak();
2663                 cont = ret->GetRegisters(thrHandle); //ccw 10 aug 2000 : ADD thrHandle HERE!
2664                 img->getObjectNC().set_gp_value(((w32CONTEXT*) cont)->IntGp);
2665 #endif
2666
2667         processVec.push_back(ret);
2668         activeProcesses++;
2669
2670 #ifndef BPATCH_LIBRARY
2671         if (!costMetric::addProcessToAll(ret))
2672            assert(false);
2673 #endif
2674         // find the signal handler function
2675         ret->findSignalHandler(); // should this be in the ctor?
2676
2677         // initializing vector of threads - thread[0] is really the 
2678         // same process
2679
2680 #ifndef BPATCH_LIBRARY
2681 #if defined(i386_unknown_nt4_0) || (defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
2682         ret->threads += new pdThread(ret, tid, (handleT)thrHandle);
2683 #else
2684         ret->threads += new pdThread(ret);
2685 #endif
2686 #endif
2687         // initializing hash table for threads. This table maps threads to
2688         // positions in the superTable - naim 4/14/97
2689
2690         // we use this flag to solve race condition between inferiorRPC and 
2691         // continueProc message from paradyn - naim
2692         ret->deferredContinueProc = false;
2693
2694         ret->numOfActCounters_is=0;
2695         ret->numOfActProcTimers_is=0;
2696         ret->numOfActWallTimers_is=0;
2697
2698 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
2699         // XXXX - this is a hack since getExecFileDescriptor needed to wait for
2700         //    the TRAP signal.
2701         // We really need to move most of the above code (esp parse image)
2702         //    to the TRAP signal handler.  The problem is that we don't
2703         //    know the base addresses until we get the load info via ptrace.
2704         //    In general it is even harder, since dynamic libs can be loaded
2705         //    at any time.
2706         extern int handleSigChild(int pid, int status);
2707
2708         (void) handleSigChild(pid, status);
2709 #endif
2710     return ret;
2711
2712 }
2713
2714
2715 void process::DYNINSTinitCompletionCallback(process* theProc,
2716                                             void* userData, // user data
2717                                             void* /*ret*/ // return value from DYNINSTinit
2718                                             ) {
2719    attach_cerr << "Welcome to DYNINSTinitCompletionCallback" << endl;
2720    if (NULL != userData && 0==strcmp((char*)userData, "viaCreateProcess"))
2721      theProc->handleCompletionOfDYNINSTinit(false);
2722    else
2723      theProc->handleCompletionOfDYNINSTinit(true);
2724 }
2725
2726
2727 bool attachProcess(const string &progpath, int pid, int afterAttach
2728 #ifdef BPATCH_LIBRARY
2729                    , process *&newProcess
2730 #endif
2731                    ) {
2732    // implementation of dynRPC::attach() (the igen call)
2733    // This is meant to be "the other way" to start a process (competes w/ createProcess)
2734
2735    // progpath gives the full path name of the executable, which we use ONLY to
2736    // read the symbol table.
2737
2738    // We try to make progpath optional, since given pid, we should be able to
2739    // calculate it with a clever enough search of the process' PATH, examining
2740    // its argv[0], examining its current directory, etc.  /proc gives us this
2741    // information on solaris...not sure about other platforms...
2742
2743    // possible values for afterAttach: 1 --> pause, 2 --> run, 0 --> leave as is
2744
2745    attach_cerr << "welcome to attachProcess for pid " << pid << endl;
2746
2747    // QUESTION: When we attach to a process, do we want to redirect its stdout/stderr
2748    //           (like we do when we fork off a new process the 'usual' way)?
2749    //           My first guess would be no.  -ari
2750    //           But although we may ignore the io, we still need the trace stream.
2751
2752    // When we attach to a process, we don't fork...so this routine is much simpler
2753    // than its "competitor", createProcess() (above).
2754
2755    string fullPathToExecutable = process::tryToFindExecutable(progpath, pid);
2756    if (!fullPathToExecutable.length())
2757       return false;
2758
2759 #ifndef BPATCH_LIBRARY
2760    tp->resourceBatchMode(true);
2761       // matching bump-down occurs in procStopFromDYNINSTinit().
2762 #endif
2763
2764
2765    int status = pid;
2766    fileDescriptor *desc = getExecFileDescriptor(fullPathToExecutable,
2767                                                 status, false);
2768    if (!desc)
2769      return false;
2770
2771    image *theImage = image::parseImage(desc);
2772    if (theImage == NULL) {
2773       // two failure return values would be useful here, to differentiate
2774       // file-not-found vs. catastrophic-parse-error.
2775       string msg = string("Unable to parse image: ") + fullPathToExecutable;
2776       showErrorCallback(68, msg.string_of());
2777       return false; // failure
2778    }
2779
2780 #ifdef SHM_SAMPLING
2781    vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
2782    theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
2783    theShmHeapStats[0].maxNumElems  = numIntCounters;
2784
2785    theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
2786    theShmHeapStats[1].maxNumElems  = numWallTimers;
2787
2788    theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
2789    theShmHeapStats[2].maxNumElems  = numProcTimers;
2790 #endif
2791
2792    // NOTE: the actual attach happens in the process "attach" constructor:
2793    bool success=false;
2794    process *theProc = new process(pid, theImage, afterAttach, success
2795 #ifdef SHM_SAMPLING
2796                                   ,7000, // shm seg key to try first
2797                                   theShmHeapStats
2798 #endif                            
2799                                   );
2800    assert(theProc);
2801    if (!success) {
2802        // XXX Do we need to do something to get rid of theImage, too?
2803        delete theProc;
2804        return false;
2805    }
2806
2807    // Note: it used to be that the attach ctor called pause()...not anymore...so
2808    // the process is probably running even as we speak.
2809
2810    processVec.push_back(theProc);
2811    activeProcesses++;
2812
2813 #ifndef BPATCH_LIBRARY
2814    theProc->threads += new pdThread(theProc);
2815    theProc->setCallbackBeforeContinue(mdnContinueCallback);
2816 #endif
2817
2818 #if !(defined i386_unknown_nt4_0)  && !(defined mips_unknown_ce2_11) //ccw 20 july 2000 : 29 mar 2001
2819    // we now need to dynamically load libdyninstRT.so.1 - naim
2820    if (!theProc->pause()) {
2821      logLine("WARNING: pause failed\n");
2822      assert(0);
2823    }
2824
2825    theProc->handleStartProcess();
2826
2827    if (!theProc->dyninstLibAlreadyLoaded()) {
2828      /* Ordinarily, dyninstlib has not been loaded yet.  But sometimes
2829         a zany user links it into their application, leaving no need
2830         to load it again (in fact, we will probably hang if we try to
2831         load it again).  This is checked in the call to
2832         handleStartProcess */
2833
2834      if (!theProc->dlopenDYNINSTlib()) {
2835         return false;
2836      }
2837
2838      // this will set isLoadingDyninstLib to true - naim
2839      if (!theProc->continueProc()) {
2840        logLine("WARNING: continueProc failed\n");
2841        assert(0);
2842      }
2843      int status;
2844      while (!theProc->dyninstLibAlreadyLoaded()) {
2845        theProc->waitProcs(&status);
2846      }
2847    }
2848 #endif
2849
2850    theProc->initDyninstLib();
2851
2852 #ifndef BPATCH_LIBRARY
2853    if (!costMetric::addProcessToAll(theProc))
2854       assert(false);
2855 #endif
2856
2857    // find the signal handler function
2858    theProc->findSignalHandler(); // shouldn't this be in the ctor?
2859
2860    // Now force DYNINSTinit() to be invoked, via inferiorRPC.
2861    string buffer = string("PID=") + string(pid) + ", running DYNINSTinit()...";
2862    statusLine(buffer.string_of());
2863
2864 #ifdef BPATCH_LIBRARY
2865    newProcess = theProc;
2866
2867 #ifdef USE_STL_VECTOR
2868    vector<AstNode*> the_args;
2869    the_args.push_back(new AstNode(AstNode::Constant, (void*)3));
2870    the_args.push_back(new AstNode(AstNode::Constant, (void*)getpid()));
2871 #else
2872    vector<AstNode*> the_args(2);
2873    the_args[0] = new AstNode(AstNode::Constant, (void*)3);
2874    the_args[1] = new AstNode(AstNode::Constant, (void*)getpid());
2875 #endif
2876
2877 #else /* BPATCH_LIBRARY */
2878    attach_cerr << "calling DYNINSTinit with args:" << endl;
2879
2880 #ifndef USE_STL_VECTOR
2881    vector<AstNode*> the_args(3);
2882 #else
2883    vector<AstNode*> the_args;
2884 #endif
2885
2886 #ifdef SHM_SAMPLING
2887    AstNode *an1 = new AstNode(AstNode::Constant,
2888                               (void*)(theProc->getShmKeyUsed()));
2889    attach_cerr << theProc->getShmKeyUsed() << endl;
2890    const unsigned shmHeapTotalNumBytes = theProc->getShmHeapTotalNumBytes();
2891    AstNode *an2 = new AstNode(AstNode::Constant,
2892                               (void*)shmHeapTotalNumBytes);
2893    attach_cerr << shmHeapTotalNumBytes << endl;;
2894
2895 #else
2896    // 2 dummy args when not shm sampling -- just make sure they're not both -1, which
2897    // would indicate that we're called from fork
2898    
2899  AstNode an1 = new AstNode(AstNode::Constant, (void*)0);
2900  AstNode an2 = new AstNode(AstNode::Constant, (void*)0);
2901 #endif
2902
2903
2904    /*
2905       The third argument to DYNINSTinit is our (paradynd's) pid. It is used
2906       by DYNINSTinit to build the socket path to which it connects to in order
2907       to get the trace-stream connection.  We make it negative to indicate
2908       to DYNINSTinit that it's being called from attach (sorry for that little
2909       kludge...if we didn't have it, we'd probably need to boost DYNINSTinit
2910       from 3 to 4 parameters).
2911       
2912       This socket is set up in controllerMainLoop (perfStream.C).
2913    */
2914    AstNode *an3 =  new AstNode(AstNode::Constant, (void*)(-1 * traceConnectInfo));
2915    attach_cerr << (-1* getpid()) << endl;
2916
2917 #ifndef USE_STL_VECTOR   
2918    the_args[0] = an1; 
2919    the_args[1] = an2;
2920    the_args[2] = an3;
2921 #else
2922    the_args.push_back(an1);
2923    the_args.push_back(an2);
2924    the_args.push_back(an3);
2925 #endif
2926   
2927 #endif /* BPATCH_LIBRARY */
2928
2929    AstNode *the_ast = new AstNode("DYNINSTinit", the_args);
2930
2931    //  Do not call removeAst if Irix MPI, as the initialRequests vector 
2932    //  is being used more than once.
2933 #ifndef BPATCH_LIBRARY
2934    if ( !(process::pdFlavor == "mpi" && osName.prefixed_by("IRIX")) )
2935 #endif
2936       for (unsigned j=0;j<the_args.size();j++) removeAst(the_args[j]);
2937
2938    theProc->postRPCtoDo(the_ast,
2939                         true, // true --> don't try to update cost yet
2940                         process::DYNINSTinitCompletionCallback, // callback
2941                         NULL, // user data
2942                         -1,   // we use -1 if this is not metric definition
2943                         -1,
2944                         false);
2945
2946       // the rpc will be launched with a call to launchRPCifAppropriate()
2947       // in the main loop (perfStream.C).
2948       // DYNINSTinit() ends with a DYNINSTbreakPoint(), so we pick up
2949       // where we left off in the processing of the forwarded SIGSTOP signal.
2950       // In other words, there's lots more work to do, but since we can't do it until
2951       // DYNINSTinit has run, we wait until the SIGSTOP is forwarded.
2952
2953    // Note: we used to pause() the process while attaching.  Not anymore.
2954    // The attached process is running even as we speak.  (Though we'll interrupt
2955    // it pretty soon when the inferior RPC of DYNINSTinit gets launched).
2956
2957 #if defined(alpha_dec_osf4_0)
2958    // need to perform this after dyninst Heap is present and happy
2959    theProc->getDyn()->setMappingHooks(theProc);
2960 #endif
2961
2962    return true; // successful
2963 }
2964
2965
2966
2967 /*
2968  * This function is needed in the unique case where we want to 
2969  * attach to an application which has been previously stopped
2970  * in the exec() system call as in the normal case (createProcess).
2971  * In this particular case, the SIGTRAP due to the exec() has been 
2972  * previously caught by another process, therefore we should taking into
2973  * account this issue in the necessary platforms. 
2974  * Basically, is an hybrid case between addprocess() and attachProcess().
2975  * 
2976  */
2977
2978 bool AttachToCreatedProcess(int pid,const string &progpath)
2979 {
2980
2981
2982     int traceLink = -1;
2983
2984     string fullPathToExecutable = process::tryToFindExecutable(progpath, pid);
2985     
2986     if (!fullPathToExecutable.length()) {
2987       return false;
2988     }  
2989
2990
2991 #if defined(i386_unknown_nt4_0) || (defined mips_unknown_ce2_11)
2992     int tid;
2993     int procHandle;
2994     int thrHandle;
2995 #endif    
2996
2997
2998 #ifdef BPATCH_LIBRARY
2999     // Register the pid with the BPatch library (not yet associated with a
3000     // BPatch_thread object).
3001     assert(BPatch::bpatch != NULL);
3002     BPatch::bpatch->registerProvisionalThread(pid);
3003 #endif
3004
3005     int status = pid;
3006     
3007     // Get the file descriptor for the executable file
3008     // "true" value is for AIX -- waiting for an initial trap
3009     // it's ignored on other platforms
3010     fileDescriptor *desc = 
3011         getExecFileDescriptor(fullPathToExecutable, status, true);
3012
3013     if (!desc) {
3014       return false;
3015     }
3016
3017 #ifndef BPATCH_LIBRARY
3018
3019 // We bump up batch mode here; the matching bump-down occurs after 
3020 // shared objects are processed (after receiving the SIGSTOP indicating
3021 // the end of running DYNINSTinit; more specifically, 
3022 // procStopFromDYNINSTinit(). Prevents a diabolical w/w deadlock on 
3023 // solaris --ari
3024     tp->resourceBatchMode(true);
3025
3026 #endif
3027
3028     image *img = image::parseImage(desc);
3029
3030     if (img==NULL) {
3031
3032         // For better error reporting, two failure return values would be
3033         // useful.  One for simple error like because-file-not-because.
3034         // Another for serious errors like found-but-parsing-failed 
3035         //    (internal error; please report to paradyn@cs.wisc.edu)
3036
3037         string msg = string("Unable to parse image: ") + fullPathToExecutable;
3038         showErrorCallback(68, msg.string_of());
3039         // destroy child process
3040         OS::osKill(pid);
3041         return(false);
3042     }
3043
3044     /* parent */
3045     statusLine("initializing process data structures");
3046
3047 #ifdef SHM_SAMPLING
3048     vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
3049     theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
3050     theShmHeapStats[0].maxNumElems  = numIntCounters;
3051
3052     theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
3053     theShmHeapStats[1].maxNumElems  = numWallTimers;
3054
3055     theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
3056     theShmHeapStats[2].maxNumElems  = numProcTimers;
3057 #endif
3058
3059     // The same process ctro. is used as in the "normal" case but
3060     // here, traceLink is -1 instead of a positive value.
3061     process *ret = new process(pid, img, traceLink
3062
3063 #ifdef SHM_SAMPLING
3064                                    , 7000, // shm seg key to try first
3065                                    theShmHeapStats
3066 #endif
3067                                    );
3068
3069     assert(ret);
3070
3071 #ifdef mips_unknown_ce2_11 //ccw 27 july 2000 : 29 mar 2001
3072
3073     //the MIPS instruction generator needs the Gp register value to
3074     //correctly calculate the jumps.  In order to get it there it needs
3075     //to be visible in Object-nt, and must be taken from process.
3076     void *cont;
3077     //DebugBreak();
3078     //ccw 10 aug 2000 : ADD thrHandle HERE
3079     
3080     cont = ret->GetRegisters(thrHandle);
3081
3082     img->getObjectNC().set_gp_value(((w32CONTEXT*) cont)->IntGp);
3083 #endif
3084
3085     processVec.push_back(ret);
3086     activeProcesses++;
3087
3088 #ifndef BPATCH_LIBRARY
3089     if (!costMetric::addProcessToAll(ret)) {
3090         assert(false);
3091     }
3092 #endif
3093
3094     // find the signal handler function
3095     ret->findSignalHandler(); // should this be in the ctor?
3096
3097     // initializing vector of threads - thread[0] is really the 
3098     // same process
3099
3100 #ifndef BPATCH_LIBRARY
3101 #if defined(i386_unknown_nt4_0) || (defined mips_unknown_ce2_11)
3102     //ccw 20 july 2000 : 29 mar 2001
3103     ret->threads += new pdThread(ret, tid, (handleT)thrHandle);
3104 #else
3105     ret->threads += new pdThread(ret);     
3106 #endif
3107 #endif
3108
3109     // initializing hash table for threads. This table maps threads to
3110     // positions in the superTable - naim 4/14/97
3111
3112     // we use this flag to solve race condition between inferiorRPC and 
3113     // continueProc message from paradyn - naim
3114     ret->deferredContinueProc  = false;
3115     ret->numOfActCounters_is   = 0;
3116     ret->numOfActProcTimers_is = 0;
3117     ret->numOfActWallTimers_is = 0;
3118
3119 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
3120     // XXXX - this is a hack since getExecFileDescriptor needed to wait for
3121     //        the TRAP signal.
3122     // We really need to move most of the above code (esp parse image)
3123     // to the TRAP signal handler.  The problem is that we don't
3124     // know the base addresses until we get the load info via ptrace.
3125     // In general it is even harder, since dynamic libs can be loaded
3126     // at any time.
3127     extern int handleSigChild(int pid, int status);
3128
3129     (void) handleSigChild(pid, status);
3130 #endif
3131
3132 #ifndef BPATCH_LIBRARY
3133     if (ret) {
3134       ret->setCallbackBeforeContinue(mdnContinueCallback); 
3135     }
3136 #endif
3137     
3138     return(true);
3139
3140 } // end of AttachToCreatedProcess
3141
3142
3143
3144 #ifndef BPATCH_LIBRARY
3145 bool attachToIrixMPIprocess(const string &progpath, int pid, int afterAttach) {
3146
3147    //  This function has been cannibalized from attachProcess.
3148    //  IRIX MPI applications appear to present a unique attaching
3149    //  scenario: We technically "attach" to processes forked by
3150    //  the master MPI app process/daemon (which is started by
3151    //  mpirun), but since we haven't passed main yet, we want to
3152    //  add a breakpoint at main and call DYNINSTinit then.
3153         
3154    string fullPathToExecutable = process::tryToFindExecutable(progpath, pid);
3155    if (!fullPathToExecutable.length())
3156       return false;
3157
3158    tp->resourceBatchMode(true);
3159       // matching bump-down occurs in procStopFromDYNINSTinit().
3160
3161    int status = pid;
3162    fileDescriptor *desc = getExecFileDescriptor(fullPathToExecutable,
3163                                                 status,
3164                                                 false);
3165
3166    image *theImage = image::parseImage(desc);
3167    if (theImage == NULL) {
3168       // two failure return values would be useful here, to differentiate
3169       // file-not-found vs. catastrophic-parse-error.
3170       string msg = string("Unable to parse image: ") + fullPathToExecutable;
3171       showErrorCallback(68, msg.string_of());
3172       return false; // failure
3173    }
3174
3175 #ifdef SHM_SAMPLING
3176    vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
3177    theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
3178    theShmHeapStats[0].maxNumElems  = numIntCounters;
3179
3180    theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
3181    theShmHeapStats[1].maxNumElems  = numWallTimers;
3182
3183    theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
3184    theShmHeapStats[2].maxNumElems  = numProcTimers;
3185 #endif
3186
3187    // NOTE: the actual attach happens in the process "attach" constructor:
3188    bool success=false;
3189    process *theProc = new process(pid, theImage, afterAttach, success
3190 #ifdef SHM_SAMPLING
3191                                   ,7000, // shm seg key to try first
3192                                   theShmHeapStats
3193 #endif                            
3194                                   );
3195    assert(theProc);
3196    if (!success) {
3197        delete theProc;
3198        return false;
3199    }
3200
3201    processVec += theProc;
3202    activeProcesses++;
3203
3204    theProc->threads += new pdThread(theProc);
3205
3206    if (!costMetric::addProcessToAll(theProc))
3207       assert(false);
3208
3209    // find the signal handler function
3210    theProc->findSignalHandler(); // shouldn't this be in the ctor?
3211
3212    return true; // successful
3213 }
3214 #endif  // #ifndef BPATCH_LIBRARY
3215
3216
3217 #ifdef SHM_SAMPLING
3218 bool process::doMajorShmSample() {
3219    bool result = true; // will be set to false if any processAll() doesn't complete
3220                        // successfully.
3221    if (!theSuperTable.doMajorSample())
3222       result = false;
3223       // inferiorProcessTimers used to take in a non-dummy process time as the
3224       // 2d arg, but it looks like that we need to re-read the process time for
3225       // each proc timer, at the time of sampling the timer's value, to avoid
3226       // ugly jagged spikes in histogram (i.e. to avoid incorrect sampled 
3227       // values).  Come to think of it: the same may have to be done for the 
3228       // wall time too!!!
3229
3230    const timeStamp theProcTime = getCpuTime();
3231    const timeStamp curWallTime = getWallTime();
3232    // Now sample the observed cost.
3233    unsigned *costAddr = (unsigned *)this->getObsCostLowAddrInParadyndSpace();
3234    const unsigned theCost = *costAddr; // WARNING: shouldn't we be using a mutex?!
3235    this->processCost(theCost, curWallTime, theProcTime);
3236
3237    return result;
3238 }
3239
3240 bool process::doMinorShmSample() {
3241    // Returns true if the minor sample has successfully completed all outstanding
3242    // samplings.
3243    bool result = true; // so far...
3244
3245    if (!theSuperTable.doMinorSample())
3246       result = false;
3247
3248    return result;
3249 }
3250 #endif
3251
3252 extern void removeFromMetricInstances(process *);
3253 extern void disableAllInternalMetrics();
3254
3255 void handleProcessExit(process *proc, int exitStatus) {
3256
3257   proc->exitCode_ = exitStatus;
3258
3259   if (proc->status() == exited)
3260     return;
3261
3262   --activeProcesses;
3263
3264   proc->Exited(); // updates status line
3265
3266 #ifndef BPATCH_LIBRARY
3267   if (activeProcesses == 0)
3268     disableAllInternalMetrics();
3269 #endif
3270
3271 #ifdef PARADYND_PVM
3272   if (pvm_running) {
3273     PDYN_reportSIGCHLD(proc->getPid(), exitStatus);
3274   }
3275 #endif
3276
3277   // Perhaps these lines can be un-commented out in the future, but since
3278   // cleanUpAndExit() does the same thing, and it always gets called
3279   // (when paradynd detects that paradyn died), it's not really necessary
3280   // here.  -ari
3281 //  for (unsigned lcv=0; lcv < processVec.size(); lcv++)
3282 //     if (processVec[lcv] == proc) {
3283 //        delete proc; // destructor removes shm segments...
3284 //      processVec[lcv] = NULL;
3285 //     }
3286 }
3287
3288
3289 #ifndef BPATCH_LIBRARY
3290 /*
3291    process::forkProcess: called when a process forks, to initialize a new
3292    process object for the child.
3293
3294    the variable childHasInstrumentation is true if the child process has the 
3295    instrumentation of the parent. This is the common case.
3296    On some platforms (AIX) the child does not have any instrumentation because
3297    the text segment of the child is not a copy of the parent text segment at
3298    the time of the fork, but a copy of the original text segment of the parent,
3299    without any instrumentation.
3300    (actually, childHasInstr is obsoleted by aix's completeTheFork() routine)
3301 */
3302 process *process::forkProcess(const process *theParent, pid_t childPid,
3303                       dictionary_hash<instInstance*,instInstance*> &map, // gets filled in
3304                       int iTrace_fd
3305 #ifdef SHM_SAMPLING
3306                               ,key_t theKey,
3307                               void *applAttachedPtr
3308 #endif
3309                               ) {
3310 #ifdef SHM_SAMPLING
3311     vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
3312     theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
3313     theShmHeapStats[0].maxNumElems  = numIntCounters;
3314     
3315     theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
3316     theShmHeapStats[1].maxNumElems  = numWallTimers;
3317
3318     theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
3319     theShmHeapStats[2].maxNumElems  = numProcTimers;
3320 #endif
3321
3322     forkexec_cerr << "paradynd welcome to process::forkProcess; parent pid=" << theParent->getPid() << "; calling fork ctor now" << endl;
3323
3324     // Call the "fork" ctor:
3325     process *ret = new process(*theParent, (int)childPid, iTrace_fd
3326 #ifdef SHM_SAMPLING
3327                                , theKey,
3328                                applAttachedPtr,
3329                                theShmHeapStats
3330 #endif
3331                                );
3332     assert(ret);
3333
3334     forkexec_cerr << "paradynd fork ctor has completed ok...child pid is " << ret->getPid() << endl;
3335
3336     processVec += ret;
3337     activeProcesses++;
3338
3339     if (!costMetric::addProcessToAll(ret))
3340        assert(false);
3341
3342     // We used to do a ret->attach() here...it was moved to the fork ctor, so it's
3343     // been done already.
3344
3345     /* all instrumentation on the parent is active on the child */
3346     /* TODO: what about instrumentation inserted near the fork time??? */
3347     ret->baseMap = theParent->baseMap; // WHY IS THIS HERE?
3348
3349 #ifdef BPATCH_LIBRARY
3350     /* XXX Not sure if this is the right thing to do. */
3351     ret->instPointMap = theParent->instPointMap;
3352 #endif
3353
3354     // the following writes to "map", s.t. for each instInstance in the parent
3355     // process, we have a map to the corresponding one in the child process.
3356     // that's all this routine does -- it doesn't actually touch
3357     // any instrumentation (because it doesn't need to -- fork() syscall copied
3358     // all of the actual instrumentation [but what about AIX and its weird load
3359     // behavior?])
3360     copyInstInstances(theParent, ret, map);
3361          // doesn't copy anything; just writes to "map"
3362
3363     return ret;
3364 }
3365 #endif
3366
3367 #ifdef SHM_SAMPLING
3368 void process::processCost(unsigned obsCostLow,
3369                           timeStamp wallTime,
3370                           timeStamp processTime) {
3371   // wallTime and processTime should compare to DYNINSTgetWallTime() and
3372   // DYNINSTgetCPUtime().
3373
3374   // check for overflow, add to running total, convert cycles to seconds, and
3375   // report.  Member vrbles of class process: lastObsCostLow and cumObsCost
3376   // (the latter a 64-bit value).
3377
3378   // code to handle overflow used to be in rtinst; we borrow it pretty much
3379   // verbatim. (see rtinst/RTposix.c)
3380   if (obsCostLow < lastObsCostLow) {
3381     // we have a wraparound
3382     cumObsCost += ((unsigned)0xffffffff - lastObsCostLow) + obsCostLow + 1;
3383   }
3384   else
3385     cumObsCost += (obsCostLow - lastObsCostLow);
3386   
3387   lastObsCostLow = obsCostLow;
3388   sampleVal_cerr << "processCost- cumObsCost: " << cumObsCost << "\n"; 
3389   timeLength observedCost(cumObsCost, getCyclesPerSecond());
3390   timeUnit tu = getCyclesPerSecond(); // just used to print out
3391   sampleVal_cerr << "processCost: cyclesPerSecond=" << tu
3392                  << "; cum obs cost=" << observedCost << "\n";
3393   
3394   // Notice how most of the rest of this is copied from processCost() of
3395   // metric.C.  Be sure to keep the two "in sync"!
3396
3397   extern costMetric *totalPredictedCost; // init.C
3398   extern costMetric *observed_cost;      // init.C
3399   
3400   const timeStamp lastProcessTime = 
3401     totalPredictedCost->getLastSampleProcessTime(this);
3402   sampleVal_cerr << "processCost- lastProcessTime: " <<lastProcessTime << "\n";
3403   // find the portion of uninstrumented time for this interval
3404   timeLength userPredCost = timeLength::sec() + getCurrentPredictedCost();
3405   sampleVal_cerr << "processCost- userPredCost: " << userPredCost << "\n";
3406   const double unInstTime = (processTime - lastProcessTime) / userPredCost; 
3407   sampleVal_cerr << "processCost- unInstTime: " << unInstTime << "\n";
3408   // update predicted cost
3409   // note: currentPredictedCost is the same for all processes
3410   //       this should be changed to be computed on a per process basis
3411   pdSample newPredCost = totalPredictedCost->getCumulativeValue(this);
3412   sampleVal_cerr << "processCost- newPredCost: " << newPredCost << "\n";
3413   timeLength tempPredCost = getCurrentPredictedCost() * unInstTime;
3414   sampleVal_cerr << "processCost- tempPredCost: " << tempPredCost << "\n";
3415   newPredCost += pdSample(tempPredCost.getI(timeUnit::ns()));
3416   sampleVal_cerr << "processCost- tempPredCost: " << newPredCost << "\n";
3417   totalPredictedCost->updateValue(this, wallTime, newPredCost, processTime);
3418   // update observed cost
3419   pdSample sObsCost(observedCost);
3420   observed_cost->updateValue(this, wallTime, sObsCost, processTime);
3421 }
3422 #endif
3423
3424 /*
3425  * Copy data from controller process to the named process.
3426  */
3427 bool process::writeDataSpace(void *inTracedProcess, unsigned size,
3428                              const void *inSelf) {
3429   bool needToCont = false;
3430 #ifdef DETACH_ON_THE_FLY
3431   bool needToDetach = false;
3432 #endif
3433
3434   if (status_ == exited)
3435     return false;
3436
3437   if (status_ == running) {
3438     needToCont = true;
3439 #ifdef DETACH_ON_THE_FLY
3440     if (this->haveDetached) {
3441          needToDetach = true;
3442          this->reattach();
3443     }
3444 #endif /* DETACH_ON_THE_FLY */
3445     if (! pause())
3446       return false;
3447   }
3448
3449   if (status_ != stopped && status_ != neonatal) {
3450     sprintf(errorLine, "Internal error: "
3451                 "Unexpected process state %d in process::writeDataSpace",
3452                 (int)status_);
3453     logLine(errorLine);
3454     showErrorCallback(39, errorLine);
3455     return false;
3456   }
3457
3458   bool res = writeDataSpace_(inTracedProcess, size, inSelf);
3459   if (!res) {
3460     string msg = string("System error: unable to write to process data space:")
3461                    + string(sys_errlist[errno]);
3462     showErrorCallback(38, msg);
3463     return false;
3464   }
3465
3466   if (needToCont) {
3467 #ifdef DETACH_ON_THE_FLY
3468     if (needToDetach)
3469          return this->detachAndContinue();
3470     else
3471          return this->continueProc();
3472 #else
3473     return this->continueProc();
3474 #endif /* DETACH_ON_THE_FLY */
3475   }
3476   return true;
3477 }
3478
3479 bool process::readDataSpace(const void *inTracedProcess, unsigned size,
3480                             void *inSelf, bool displayErrMsg) {
3481   bool needToCont = false;
3482 #ifdef DETACH_ON_THE_FLY
3483   bool needToDetach = false;
3484 #endif
3485
3486   if (status_ == exited)
3487     return false;
3488
3489   if (status_ == running) {
3490     needToCont = true;
3491 #ifdef DETACH_ON_THE_FLY
3492     if (this->haveDetached) {
3493          needToDetach = true;
3494          this->reattach();
3495     }
3496 #endif /* DETACH_ON_THE_FLY */
3497     if (! pause()) {
3498       sprintf(errorLine, "in readDataSpace, status_ = running, but unable to pause()\n");
3499       logLine(errorLine);
3500       return false;
3501     }
3502   }
3503   if (status_ != stopped && status_ != neonatal) {
3504     sprintf(errorLine, "Internal error: "
3505                 "Unexpected process state %d in process::readDataSpace",
3506                 (int)status_);
3507     logLine(errorLine);
3508     showErrorCallback(39, errorLine);
3509     return false;
3510   }
3511
3512   bool res = readDataSpace_(inTracedProcess, size, inSelf);
3513   if (!res) {
3514     if (displayErrMsg) {
3515       sprintf(errorLine, "System error: "
3516           "unable to read %d@%s from process data space: %s (pid=%d)",
3517           size, Address_str((Address)inTracedProcess), 
3518           sys_errlist[errno], getPid());
3519       string msg(errorLine);
3520       showErrorCallback(38, msg);
3521     }
3522     return false;
3523  }
3524
3525   if (needToCont) {
3526 #ifdef DETACH_ON_THE_FLY
3527     if (needToDetach)
3528          needToCont = this->detachAndContinue();
3529     else
3530          needToCont = this->continueProc();
3531 #else
3532     needToCont = this->continueProc();
3533 #endif /* DETACH_ON_THE_FLY */
3534     if (!needToCont) {
3535         sprintf(errorLine, "warning : readDataSpace, needToCont FALSE, returning FALSE\n");
3536         logLine(errorLine);
3537     }
3538     return needToCont;
3539   }
3540   return true;
3541
3542 }
3543
3544 bool process::writeTextWord(caddr_t inTracedProcess, int data) {
3545   bool needToCont = false;
3546 #ifdef DETACH_ON_THE_FLY
3547   bool needToDetach = false;
3548 #endif /* DETACH_ON_THE_FLY */
3549
3550   if (status_ == exited)
3551     return false;
3552
3553   if (status_ == running) {
3554     needToCont = true;
3555 #ifdef DETACH_ON_THE_FLY
3556     if (this->haveDetached) {
3557          needToDetach = true;
3558          this->reattach();
3559     }
3560 #endif /* DETACH_ON_THE_FLY */
3561     if (! pause())
3562       return false;
3563   }
3564
3565   if (status_ != stopped && status_ != neonatal) {
3566     sprintf(errorLine, "Internal error: "
3567                 "Unexpected process state %d in process::writeTextWord",
3568                 (int)status_);
3569     showErrorCallback(39, errorLine);
3570     return false;
3571   }
3572
3573 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
3574   if (!isAddrInHeap((Address)inTracedProcess)) {
3575     if (!saveOriginalInstructions((Address)inTracedProcess, sizeof(int)))
3576         return false;
3577     afterMutationList.insertTail((Address)inTracedProcess, sizeof(int), &data);
3578   }
3579 #endif
3580
3581   bool res = writeTextWord_(inTracedProcess, data);
3582   if (!res) {
3583     string msg = string("System error: unable to write to process text word:")
3584                    + string(sys_errlist[errno]);
3585     showErrorCallback(38, msg);
3586     return false;
3587   }
3588
3589   if (needToCont) {
3590 #ifdef DETACH_ON_THE_FLY
3591     if (needToDetach)
3592          return this->detachAndContinue();
3593     else
3594          return this->continueProc();
3595 #else
3596     return this->continueProc();
3597 #endif /* DETACH_ON_THE_FLY */
3598   }
3599   return true;
3600
3601 }
3602
3603 bool process::writeTextSpace(void *inTracedProcess, u_int amount, 
3604                              const void *inSelf) {
3605   bool needToCont = false;
3606 #ifdef DETACH_ON_THE_FLY
3607   bool needToDetach = false;
3608 #endif /* DETACH_ON_THE_FLY */
3609
3610   if (status_ == exited)
3611     return false;
3612
3613   if (status_ == running) {
3614     needToCont = true;
3615 #ifdef DETACH_ON_THE_FLY
3616     if (this->haveDetached) {
3617          needToDetach = true;
3618          this->reattach();
3619     }
3620 #endif /* DETACH_ON_THE_FLY */
3621     if (! pause())
3622       return false;
3623   }
3624
3625   if (status_ != stopped && status_ != neonatal) {
3626     sprintf(errorLine, "Internal error: "
3627                 "Unexpected process state %d in process::writeTextSpace",
3628                 (int)status_);
3629     showErrorCallback(39, errorLine);
3630     return false;
3631   }
3632
3633 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
3634   if (!isAddrInHeap((Address)inTracedProcess)) {
3635     if (!saveOriginalInstructions((Address)inTracedProcess, amount))
3636         return false;
3637     afterMutationList.insertTail((Address)inTracedProcess, amount, inSelf);
3638   }
3639 #endif
3640
3641   bool res = writeTextSpace_(inTracedProcess, amount, inSelf);
3642   if (!res) {
3643     string msg = string("System error: unable to write to process text space:")
3644                    + string(sys_errlist[errno]);
3645     showErrorCallback(38, msg);
3646     return false;
3647   }
3648
3649   if (needToCont) {
3650 #ifdef DETACH_ON_THE_FLY
3651     if (needToDetach) 
3652          return this->detachAndContinue();
3653     else
3654          return this->continueProc();
3655 #else
3656     return this->continueProc();
3657 #endif /* DETACH_ON_THE_FLY */
3658   }
3659   return true;
3660 }
3661
3662 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
3663 bool process::readTextSpace(const void *inTracedProcess, u_int amount,
3664                             const void *inSelf)
3665 {
3666   bool needToCont = false;
3667 #ifdef DETACH_ON_THE_FLY
3668   bool needToDetach = false;
3669 #endif /* DETACH_ON_THE_FLY */
3670
3671   if (status_ == exited){
3672         printf(" STATUS == EXITED");
3673     return false;
3674         }
3675   if (status_ == running) {
3676     needToCont = true;
3677 #ifdef DETACH_ON_THE_FLY
3678     if (this->haveDetached) {
3679          needToDetach = true;
3680          this->reattach();
3681     }
3682 #endif
3683     if (! pause())
3684       return false;
3685   }
3686
3687   if (status_ != stopped && status_ != neonatal) {
3688     sprintf(errorLine, "Internal error: "
3689                 "Unexpected process state %d in process::readTextSpace",
3690                 (int)status_);
3691     showErrorCallback(39, errorLine);
3692     return false;
3693   }
3694
3695   bool res = readTextSpace_(const_cast<void*>(inTracedProcess), amount, inSelf);
3696   if (!res) {
3697     sprintf(errorLine, "System error: "
3698           "unable to read %d@%s from process text space: %s (pid=%d)",
3699           amount, Address_str((Address)inTracedProcess),
3700           sys_errlist[errno], getPid());
3701     string msg(errorLine);
3702     showErrorCallback(38, msg);
3703     return false;
3704   }
3705
3706   if (needToCont) {
3707 #ifdef DETACH_ON_THE_FLY
3708     if (needToDetach)
3709          return this->detachAndContinue();
3710     else
3711          return this->continueProc();
3712 #else
3713     return this->continueProc();
3714 #endif /* DETACH_ON_THE_FLY */
3715   }
3716   return true;
3717
3718 }
3719 #endif /* BPATCH_SET_MUTATIONS_ACTIVE */
3720
3721 bool process::pause() {
3722   if (status_ == stopped || status_ == neonatal) {
3723     return true;
3724   }