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