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