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