changed the way we are getting shared objects on Solaris platforms. We are no
[dyninst.git] / paradynd / src / process.C
1
2 /*
3  * Copyright (c) 1996 Barton P. Miller
4  * 
5  * We provide the Paradyn Parallel Performance Tools (below
6  * described as Paradyn") on an AS IS basis, and do not warrant its
7  * validity or performance.  We reserve the right to update, modify,
8  * or discontinue this software at any time.  We shall have no
9  * obligation to supply such updates or modifications or any other
10  * form of support to you.
11  * 
12  * This license is for research uses.  For such uses, there is no
13  * charge. We define "research use" to mean you may freely use it
14  * inside your organization for whatever purposes you see fit. But you
15  * may not re-distribute Paradyn or parts of Paradyn, in any form
16  * source or binary (including derivatives), electronic or otherwise,
17  * to any other organization or entity without our permission.
18  * 
19  * (for other uses, please contact us at paradyn@cs.wisc.edu)
20  * 
21  * All warranties, including without limitation, any warranty of
22  * merchantability or fitness for a particular purpose, are hereby
23  * excluded.
24  * 
25  * By your use of Paradyn, you understand and agree that we (or any
26  * other person or entity with proprietary rights in Paradyn) are
27  * under no obligation to provide either maintenance services,
28  * update services, notices of latent defects, or correction of
29  * defects for Paradyn.
30  * 
31  * Even if advised of the possibility of such damages, under no
32  * circumstances shall we (or any other person or entity with
33  * proprietary rights in the software licensed hereunder) be liable
34  * to you or any third party for direct, indirect, or consequential
35  * damages of any character regardless of type of action, including,
36  * without limitation, loss of profits, loss of use, loss of good
37  * will, or computer failure or malfunction.  You agree to indemnify
38  * us (and any other person or entity with proprietary rights in the
39  * software licensed hereunder) for any and all liability it may
40  * incur to third parties resulting from your use of Paradyn.
41  */
42
43 extern "C" {
44 #ifdef PARADYND_PVM
45 int pvmputenv (const char *);
46 int pvmendtask();
47 #endif
48 }
49
50 #include "util/h/headers.h"
51 #include "rtinst/h/rtinst.h"
52 #include "rtinst/h/trace.h"
53 #include "symtab.h"
54 #include "process.h"
55 #include "util.h"
56 #include "inst.h"
57 #include "instP.h"
58 #include "dyninstP.h"
59 #include "os.h"
60 #include "showerror.h"
61 #include "costmetrics.h"
62 #include "perfStream.h"
63 #include "dynamiclinking.h"
64 #include "paradynd/src/mdld.h"
65
66 #define FREE_WATERMARK (hp->totalFreeMemAvailable/2)
67 #define SIZE_WATERMARK 100
68 static const timeStamp MAX_WAITING_TIME=10.0;
69 static const timeStamp MAX_DELETING_TIME=2.0;
70
71 unsigned activeProcesses; // number of active processes
72 vector<process*> processVec;
73 string process::programName;
74 vector<string> process::arg_list;
75
76 #ifdef SHM_SAMPLING
77 static unsigned numIntCounters=10000; // rather arbitrary; can we do better?
78 static unsigned numWallTimers =10000; // rather arbitrary; can we do better?
79 static unsigned numProcTimers =10000; // rather arbitrary; can we do better?
80 #endif
81
82 bool waitingPeriodIsOver()
83 {
84 static timeStamp previous=0;
85 timeStamp current;
86 bool waiting=false;
87
88   if (!previous) {
89     previous=getCurrentTime(false);
90     waiting=true;
91   }
92   else {
93     current=getCurrentTime(false);
94     if ( (current-previous) > MAX_WAITING_TIME ) {
95       previous=getCurrentTime(false);
96       waiting=true;
97     }
98   }
99   return(waiting);
100 }
101
102 Frame::Frame(process *proc) {
103
104     frame_ = pc_ = 0;
105     proc->getActiveFrame(&frame_, &pc_);
106
107     uppermostFrame = true;
108 }
109
110 Frame Frame::getPreviousStackFrameInfo(process *proc) const {
111    if (frame_ == 0){
112       // no prev frame exists; must return frame with 0 pc value otherwise
113       // will never break out of loop in walkStack()
114       Frame fake_frame(0,0,false);
115       return fake_frame; 
116    }
117
118    int fp = frame_;
119    int rtn = pc_;
120
121    Frame result(0, 0, false);
122    if (proc->readDataFromFrame(frame_, &fp, &rtn, uppermostFrame)) {
123       result.frame_ = fp;
124       result.pc_    = rtn;
125    }
126
127    return result;
128 }
129
130 vector<Address> process::walkStack(bool noPause)
131 {
132   vector<Address> pcs;
133   bool needToCont = noPause ? false : (status() == running);
134
135   if (!noPause && !pause()) {
136      // pause failed...give up
137      cerr << "walkStack: pause failed" << endl;
138      return pcs;
139   }
140
141   Address sig_addr = 0;
142   u_int sig_size = 0;
143   if(signal_handler){
144       const image *sig_image = (signal_handler->file())->exec();
145       if(getBaseAddress(sig_image, sig_addr)){
146           sig_addr += signal_handler->getAddress(this);
147       } else {
148           sig_addr = signal_handler->getAddress(this);
149       }
150       sig_size = signal_handler->size();
151       // printf("signal_handler = %s size = %d addr = 0x%x\n",
152       //     (signal_handler->prettyName()).string_of(),sig_size,sig_addr);
153   }
154
155   if (pause()) {
156     Frame currentFrame(this);
157     while (!currentFrame.isLastFrame()) {
158       Address next_pc = currentFrame.getPC();
159       // printf("currentFrame pc = %d\n",next_pc);
160       pcs += next_pc;
161       // is this pc in the signal_handler function?
162       if(signal_handler && (next_pc >= sig_addr)
163           && (next_pc < (sig_addr+sig_size))){
164           // check to see if a leaf function was executing when the signal
165           // handler was called.  If so, then an extra frame should be added
166           // for the leaf function...the call to getPreviousStackFrameInfo
167           // will get the function that called the leaf function
168           Address leaf_pc = 0;
169           if(this->needToAddALeafFrame(currentFrame,leaf_pc)){
170               pcs += leaf_pc;
171           }
172       }
173       currentFrame = currentFrame.getPreviousStackFrameInfo(this); 
174     }
175     pcs += currentFrame.getPC();
176   }
177   if (!noPause && needToCont) {
178      if (!continueProc()){
179         cerr << "walkStack: continueProc failed" << endl;
180      }
181   }  
182   return(pcs);
183 }
184
185 bool isFreeOK(process *proc, const disabledItem &disItem, vector<Address> &pcs) {
186   const unsigned disItemPointer = disItem.getPointer();
187   const inferiorHeapType disItemHeap = disItem.getHeapType();
188
189 #if defined(hppa1_1_hp_hpux)
190   if (proc->freeNotOK) return(false);
191 #endif
192
193   heapItem *ptr=NULL;
194   if (!proc->heaps[disItemHeap].heapActive.find(disItemPointer, ptr)) {
195     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());
196     logLine(errorLine);
197     //showErrorCallback(67, (const char *)errorLine);
198     return(false);
199   }
200   assert(ptr);
201
202 #ifdef FREEDEBUG1
203   sprintf(errorLine, "isFreeOK  called on 0x%x\n", ptr->addr);
204   logLine(errorLine);
205 #endif
206
207   const vector<unsigVecType> &disItemPoints = disItem.getPointsToCheck();
208   const unsigned disItemNumPoints = disItemPoints.size();
209
210   for (unsigned int j=0;j<disItemNumPoints;j++) {
211     for (unsigned int k=0;k<disItemPoints[j].size();k++) {
212       unsigned pointer = disItemPoints[j][k];
213 #ifdef FREEDEBUG_ON
214       if (disItemHeap == dataHeap)
215         sprintf(errorLine, "checking DATA pointer 0x%x\n", pointer);
216       else
217         sprintf(errorLine, "checking TEXT pointer 0x%x\n", pointer);
218       logLine(errorLine);
219 #endif
220
221       const dictionary_hash<unsigned, heapItem*> &heapActivePart =
222               proc->splitHeaps ? proc->heaps[textHeap].heapActive :
223                                  proc->heaps[dataHeap].heapActive;
224
225       heapItem *np=NULL;
226       if (!heapActivePart.find(pointer, np)) { // fills in "np" if found
227 #ifdef FREEDEBUG1
228             sprintf(errorLine, "something freed addr 0x%x from us\n", pointer);
229             logLine(errorLine);
230 #endif
231         
232         // 
233         // This point was deleted already and we don't need it anymore in
234         // pointsToCheck
235         // 
236         const int size=disItemPoints[j].size();
237         disItemPoints[j][k] = disItemPoints[j][size-1];
238         disItemPoints[j].resize(size-1);
239
240         // need to make sure we check the next item too 
241         k--;
242       } else {
243         // Condition 1
244         assert(np);
245         if ( (ptr->addr >= np->addr) && 
246              (ptr->addr <= (np->addr + np->length)) )
247         {
248
249 #ifdef FREEDEBUG_ON
250           sprintf(errorLine,"*** TEST *** (pid=%d) IN isFreeOK: (1) we found 0x%x in our inst. range!\n",proc->pid,ptr->addr);
251           logLine(errorLine);
252 #endif
253
254           return(false);     
255         }
256
257         for (unsigned int l=0;l<pcs.size();l++) {
258           // Condition 2
259           if ((pcs[l] >= ptr->addr) && 
260               (pcs[l] <= (ptr->addr + ptr->length))) 
261           {
262
263 #ifdef FREEDEBUG_ON
264     sprintf(errorLine,"*** TEST *** (pid=%d) IN isFreeOK: (2) we found 0x%x in our inst. range!\n",proc->pid,ptr->addr);
265     logLine(errorLine);
266 #endif
267
268             return(false);
269           }
270           // Condition 3
271           if ( ((pcs[l] >= np->addr) && (pcs[l] <= (np->addr + np->length))) )
272           {
273
274 #ifdef FREEDEBUG_ON
275     sprintf(errorLine,"*** TEST *** (pid=%d) IN isFreeOK: (3) we found PC in our inst. range!\n",proc->pid);
276     logLine(errorLine);
277 #endif
278
279             return(false);     
280           }
281         }
282       }
283     }
284   }
285   return(true);
286 }
287
288 //
289 // This procedure will try to compact the framented memory available in 
290 // heapFree. This is an emergency procedure that will be called if we
291 // are running out of memory to insert instrumentation - naim
292 //
293 void inferiorFreeCompact(inferiorHeap *hp)
294 {
295   unsigned size;
296   heapItem *np;
297   size = hp->heapFree.size();
298   unsigned j,i=0;
299
300 #ifdef FREEDEBUG
301   logLine("***** Trying to compact freed memory...\n");
302 #endif
303
304   while (i < size) {
305     np = hp->heapFree[i];
306 #ifdef FREEDEBUG1
307     sprintf(errorLine,"***** Checking address=%d\n",ALIGN_TO_WORDSIZE(np->addr+np->length));
308     logLine(errorLine);
309 #endif
310     for (j=0; j < size; j++) {
311       if (i != j) {
312         if ( (np->addr+np->length)==(hp->heapFree[j])->addr )
313         {
314           np->length += (hp->heapFree[j])->length;
315           hp->heapFree[j] = hp->heapFree[size-1];
316           hp->heapFree.resize(size-1);
317           size = hp->heapFree.size();
318 #ifdef FREEDEBUG1
319           sprintf(errorLine,"***** Compacting free memory (%d bytes, i=%d, j=%d, heapFree.size=%d)\n",np->length,i,j,size);
320           logLine(errorLine);
321 #endif
322           break;
323         }
324       }
325     }
326     if (j == size) i++;
327   }
328
329 #ifdef FREEDEBUG
330   for (i=0;i<hp->disabledList.size();i++) {
331     for (j=i+1;j<hp->disabledList.size();j++) {
332       if ( (hp->disabledList[i]).getPointer() == 
333            (hp->disabledList[j]).getPointer() ) {
334         sprintf(errorLine,"***** ERROR: address 0x%x appears more than once\n",(hp->disabledList[j]).getPointer());
335         logLine(errorLine);
336       }
337     }
338   }
339 #endif
340
341 #ifdef FREEDEBUG
342   logLine("***** Compact memory procedure END...\n");
343 #endif
344 }
345
346 void inferiorFreeDefered(process *proc, inferiorHeap *hp, bool runOutOfMem)
347 {
348   unsigned int i=0;
349   vector<Address> pcs;
350   vector<disabledItem> *disList;
351   timeStamp initTime, maxDelTime;
352
353   pcs = proc->walkStack();
354
355   // this is a while loop since we don't update i if an item is deleted.
356   disList = &hp->disabledList;
357   if (runOutOfMem) {
358     maxDelTime = MAX_DELETING_TIME*2.0;
359     sprintf(errorLine,"Emergency attempt to free memory (pid=%d). Please, wait...\n",proc->getPid());
360     logLine(errorLine);
361 #ifdef FREEDEBUG1
362     sprintf(errorLine,"***** disList.size() = %d\n",disList->size());
363     logLine(errorLine);
364 #endif
365   }
366   else
367     maxDelTime = MAX_DELETING_TIME;
368   initTime=getCurrentTime(false);
369   while ( (i < disList->size()) && 
370           ((getCurrentTime(false)-initTime) < maxDelTime) )
371   {
372     disabledItem &item = (*disList)[i];
373     if (isFreeOK(proc,item,pcs)) {
374       heapItem *np=NULL;
375       unsigned pointer = item.getPointer();
376       if (!hp->heapActive.find(pointer,np)) {
377         showErrorCallback(96,"");
378         return;
379       }
380       assert(np);
381
382       if (np->status != HEAPallocated) {
383         sprintf(errorLine,"Attempt to free already freed heap entry %x\n", pointer);
384         logLine(errorLine);
385         showErrorCallback(67, (const char *)errorLine); 
386         return;
387       }
388       np->status = HEAPfree;      
389
390       // remove from active list.
391       hp->heapActive.undef(pointer);
392
393 #ifdef FREEDEBUG_ON
394    sprintf(errorLine,"inferiorFreeDefered: deleting 0x%x from heap\n",pointer);
395    logLine(errorLine);
396 #endif
397
398       hp->heapFree += np;
399       hp->freed += np->length;
400
401       // updating disabledList
402       hp->disabledList[i]=hp->disabledList[hp->disabledList.size()-1];
403       hp->disabledList.resize(hp->disabledList.size()-1);
404       hp->disabledListTotalMem -= np->length;
405       hp->totalFreeMemAvailable += np->length;
406     } else {
407       i++;
408     }
409   }
410 }
411
412 void process::initInferiorHeap(bool initTextHeap)
413 {
414     assert(this->symbols);
415
416     inferiorHeap *hp;
417     if (initTextHeap) {
418         hp = &this->heaps[textHeap];
419     } else {
420         hp = &this->heaps[dataHeap];
421     }
422
423     heapItem *np = new heapItem;
424     if (initTextHeap) {
425         bool err;
426         np->addr = symbols->findInternalAddress("DYNINSTtext", true,err);
427         if (err)
428           abort();
429     } else {
430         bool err;
431         np->addr = symbols->findInternalAddress(INFERIOR_HEAP_BASE, true, err);
432         if (err)
433           abort();
434     }
435     np->length = SYN_INST_BUF_SIZE;
436     np->status = HEAPfree;
437
438     // make the heap double-word aligned
439     Address base = np->addr & ~0x1f;
440     Address diff = np->addr - base;
441     if (diff) {
442       np->addr = base + 32;
443       np->length -= (32 - diff);
444     }
445
446     hp->totalFreeMemAvailable = np->length;
447     // need to clear everything here, since this function may be called to re-init a heap
448     hp->heapActive.clear();
449     hp->heapFree.resize(0);
450     hp->heapFree += np;
451     hp->disabledList.resize(0);
452     hp->disabledListTotalMem = 0;
453     hp->freed = 0;
454 }
455
456 // create a new inferior heap that is a copy of src. This is used when a process
457 // we are tracing forks.
458 inferiorHeap::inferiorHeap(const inferiorHeap &src):
459     heapActive(addrHash16)
460 {
461     for (unsigned u1 = 0; u1 < src.heapFree.size(); u1++) {
462       heapFree += new heapItem(src.heapFree[u1]);
463     }
464
465     vector<heapItem *> items = src.heapActive.values();
466     for (unsigned u2 = 0; u2 < items.size(); u2++) {
467       heapActive[items[u2]->addr] = new heapItem(items[u2]);
468     }
469     
470     for (unsigned u3 = 0; u3 < src.disabledList.size(); u3++) {
471       disabledList += src.disabledList[u3];
472     }
473     disabledListTotalMem = src.disabledListTotalMem;
474     totalFreeMemAvailable = src.totalFreeMemAvailable;
475     freed = 0;
476 }
477
478 #ifdef FREEDEBUG
479 void printHeapFree(process *proc, inferiorHeap *hp, int size)
480 {
481   for (unsigned i=0; i < hp->heapFree.size(); i++) {
482     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); 
483     logLine(errorLine);
484   }
485 }
486 #endif
487
488 //
489 // This function will return the index corresponding to the next position
490 // available in heapFree.
491 //
492 bool findFreeIndex(inferiorHeap *hp, int size, unsigned *index)
493 {
494   bool foundFree=false;
495   unsigned best=0;
496   int length=0;
497   for (unsigned i=0; i < hp->heapFree.size(); i++) {
498     length = (hp->heapFree[i])->length;
499     if (length >= size) {
500       foundFree = true;
501       best=i;
502       break;
503     }
504   }
505   if (index) 
506     *index = best;
507   else
508     foundFree=false;
509   return(foundFree);
510 }  
511
512 unsigned inferiorMalloc(process *proc, int size, inferiorHeapType type)
513 {
514     inferiorHeap *hp;
515     heapItem *np=NULL, *newEntry = NULL;
516     
517     assert(size > 0);
518     /* round to next cache line size */
519     /* 32 bytes on a SPARC */
520     size = (size + 0x1f) & ~0x1f; 
521
522     if ((type == textHeap) && (proc->splitHeaps)) {
523         hp = &proc->heaps[textHeap];
524     } else {
525         hp = &proc->heaps[dataHeap];
526     }
527
528     bool secondChance=false;
529     unsigned foundIndex;
530     if (!findFreeIndex(hp,size,&foundIndex)) {
531
532 #ifdef FREEDEBUG
533       sprintf(errorLine,"==> TEST <== In inferiorMalloc: heap overflow, calling inferiorFreeDefered for a second chance...\n");
534       logLine(errorLine);
535 #endif
536
537 #if !defined(sparc_tmc_cmost7_3)
538       inferiorFreeDefered(proc, hp, true);
539       inferiorFreeCompact(hp);
540       secondChance=true;
541 #endif
542     }
543
544     if (secondChance && !findFreeIndex(hp,size,&foundIndex)) {
545
546 #ifdef FREEDEBUG
547       printHeapFree(proc,hp,size);
548 #endif
549
550       sprintf(errorLine, "***** Inferior heap overflow: %d bytes freed, %d bytes requested\n", hp->freed, size);
551       logLine(errorLine);
552       showErrorCallback(66, (const char *) errorLine);
553       P__exit(-1);
554       //return(0);
555     }
556
557     //
558     // We must have found a free position in heapFree
559     //
560
561     np = hp->heapFree[foundIndex];
562     assert(np);
563     if (np->length != size) {
564         // divide it up.
565         newEntry = new heapItem;
566         newEntry->length = np->length - size;
567         newEntry->addr = np->addr + size;
568         hp->totalFreeMemAvailable -= size;
569         // overwrite the old entry
570         hp->heapFree[foundIndex] = newEntry;
571
572         /* now split curr */
573         np->length = size;
574     } else {
575       unsigned i = hp->heapFree.size();
576       // copy the last element over this element
577       hp->heapFree[foundIndex] = hp->heapFree[i-1];
578       hp->heapFree.resize(i-1);
579     }
580
581     // mark it used
582     np->status = HEAPallocated;
583
584     // onto in use list
585     hp->heapActive[np->addr] = np;
586
587     // make sure its a valid pointer.
588     assert(np->addr);
589
590     return(np->addr);
591 }
592
593 void inferiorFree(process *proc, unsigned pointer, inferiorHeapType type,
594                   const vector<unsigVecType> &pointsToCheck)
595 {
596     inferiorHeapType which = (type == textHeap && proc->splitHeaps) ? textHeap : dataHeap;
597     inferiorHeap *hp = &proc->heaps[which];
598     heapItem *np=NULL;
599
600     if (!hp->heapActive.find(pointer, np)) {
601       showErrorCallback(96,"");
602       return;
603     }
604     assert(np);
605
606 #ifndef sparc_tmc_cmost7_3
607     //
608     // Note: This code will be executed on every platform except for the CM-5.
609     // We are not going to delete instrumentation on the CM-5 for the time
610     // being - naim 03/26/96
611     //
612     disabledItem newItem(pointer, which, pointsToCheck);
613
614 #ifdef FREEDEBUG
615     for (unsigned i=0;i<hp->disabledList.size();i++) {
616       if (hp->disabledList[i].getPointer() == pointer) {
617         sprintf(errorLine,"***** ERROR, pointer 0x%x already defined in disabledList\n",pointer);
618         logLine(errorLine);
619       }
620     }
621 #endif
622
623     hp->disabledList += newItem;
624     hp->disabledListTotalMem += np->length;
625
626 #ifdef FREEDEBUG1
627     sprintf(errorLine,"==> TEST <== In inferiorFree: disabledList has %d items, %d bytes, and FREE_WATERMARK is %d\n",hp->disabledList.size(),hp->disabledListTotalMem,FREE_WATERMARK);
628     logLine(errorLine);
629     for (unsigned i=0; i < hp->disabledList.size(); i++) {
630         sprintf(errorLine, "   %x is on list\n", hp->disabledList[i].pointer);
631         logLine(errorLine);
632     }
633 #endif
634
635     //
636     // If the size of the disabled instrumentation list is greater than
637     // half of the size of the heapFree list, then we attempt to free
638     // all the defered requests. In my opinion, this seems to be a good
639     // time to proceed with the defered delete since this is an expensive
640     // procedure and should not be executed often - naim 03/19/96
641     //
642     if (((hp->disabledListTotalMem > FREE_WATERMARK) ||
643          (hp->disabledList.size() > SIZE_WATERMARK)) && waitingPeriodIsOver()) 
644     {
645
646 #ifdef FREEDEBUG
647 timeStamp t1,t2;
648 static timeStamp t3=0.0;
649 static timeStamp totalTime=0.0;
650 static timeStamp worst=0.0;
651 static int counter=0;
652 t1=getCurrentTime(false);
653 #endif
654
655       inferiorFreeDefered(proc, hp, false);
656
657 #ifdef FREEDEBUG
658 t2=getCurrentTime(false);
659 if (!t3) t3=t1;
660 counter++;
661 totalTime += t2-t1;
662 if ((t2-t1) > worst) worst=t2-t1;
663 if ((float)(t2-t1) > 1.0) {
664   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));
665   logLine(errorLine);
666 }
667 t3=t1;
668 #endif
669
670     }
671 #endif
672 }
673
674 process::process(int iPid, image *iImage, int iTraceLink, int iIoLink
675 #ifdef SHM_SAMPLING
676                  , key_t theShmKey,
677                  const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
678 #endif
679 ) :
680              baseMap(ipHash), 
681              instInstanceMapping(instInstanceHash),
682              pid(iPid), // needed in fastInferiorHeap ctors below
683 #ifdef SHM_SAMPLING
684              inferiorHeapMgr(theShmKey, iShmHeapStats, iPid),
685              inferiorIntCounters((intCounter*)inferiorHeapMgr.getSubHeapInParadynd(0),
686                                  this, iShmHeapStats[0].maxNumElems),
687              inferiorWallTimers ((tTimer*)inferiorHeapMgr.getSubHeapInParadynd(1),
688                                  this, iShmHeapStats[1].maxNumElems),
689              inferiorProcessTimers((tTimer*)inferiorHeapMgr.getSubHeapInParadynd(2),
690                                    this, iShmHeapStats[2].maxNumElems),
691 #endif
692                      firstRecordTime(0)
693 {
694
695     hasBootstrapped = false;
696
697     // this is the 'normal' ctor, when a proc is started fresh as opposed
698     // to via a fork().
699     symbols = iImage;
700
701     status_ = neonatal;
702
703     struct utsname un;
704     P_uname(&un);
705     string buffer = string(pid) + string("_") + string(un.nodename);
706     rid = resource::newResource(processResource, // parent
707                                 (void*)this, // handle
708                                 nullString, // abstraction
709                                 iImage->name(),
710                                 0.0, // creation time
711                                 buffer, // unique name (?)
712                                 MDL_T_STRING // mdl type (?)
713                                 );
714
715     parent = NULL;
716     bufStart = 0;
717     bufEnd = 0;
718     reachedFirstBreak = false; // process won't be paused until this is set
719     inExec = false;
720
721     cumObsCost = 0;
722     lastObsCostLow = 0;
723
724     proc_fd = -1;
725
726     trampTableItems = 0;
727     memset(trampTable, 0, sizeof(trampTable));
728     currentPC_ = 0;
729     hasNewPC = false;
730     
731     inhandlestart = false;
732     dynamiclinking = false;
733     dyn = new dynamic_linking;
734     shared_objects = 0;
735     all_functions = 0;
736     all_modules = 0;
737     some_modules = 0;
738     some_functions = 0;
739     waiting_for_resources = false;
740     signal_handler = 0;
741     execed_ = false;
742     mysteryTrap_ = false;
743
744 #ifdef SHM_SAMPLING
745 #ifdef sparc_sun_sunos4_1_3
746    kvmHandle = kvm_open(0, 0, 0, O_RDONLY, 0);
747    if (kvmHandle == NULL) {
748       perror("could not map child's uarea; kvm_open");
749       exit(5);
750    }
751
752 //   childUareaPtr = tryToMapChildUarea(iPid);
753    childUareaPtr = NULL;
754 #endif
755 #endif
756
757    initInferiorHeap(false);
758    splitHeaps = false;
759
760 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
761         // XXXX - move this to a machine dependant place.
762
763         // create a seperate text heap.
764         initInferiorHeap(true);
765         splitHeaps = true;
766 #endif
767
768    traceLink = iTraceLink;
769    ioLink = iIoLink;
770
771    // attach to the child process (machine-specific implementation)
772    attach();
773 }
774
775 // This is the "fork" constructor:
776 process::process(const process &parentProc, int iPid
777 #ifdef SHM_SAMPLING
778                  ,key_t theShmKey,
779                  void *applShmSegPtr,
780                  const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
781 #endif
782                  , bool childHasInstrumentation
783                  ) :
784                      baseMap(ipHash), 
785                      instInstanceMapping(instInstanceHash),
786 #ifdef SHM_SAMPLING
787                      inferiorHeapMgr(applShmSegPtr, theShmKey, iShmHeapStats, iPid),
788                      inferiorIntCounters(parentProc.inferiorIntCounters,
789                                          this,
790                                          inferiorHeapMgr.getSubHeapInParadynd(0),
791                                          inferiorHeapMgr.getSubHeapInApplic(0)),
792                      inferiorWallTimers(parentProc.inferiorWallTimers,
793                                         this,
794                                         inferiorHeapMgr.getSubHeapInParadynd(1),
795                                         inferiorHeapMgr.getSubHeapInApplic(1)),
796                      inferiorProcessTimers(parentProc.inferiorProcessTimers,
797                                            this,
798                                            inferiorHeapMgr.getSubHeapInParadynd(2),
799                                            inferiorHeapMgr.getSubHeapInApplic(2)),
800 #endif
801                      firstRecordTime(0)
802 {
803     hasBootstrapped = true;
804
805     // This is the "fork" ctor
806
807     symbols = parentProc.symbols;
808
809     /* initialize the traceLink to zero. The child process will get a 
810        connection later.  (But when does ioLink get set???) */
811     traceLink = -1;
812     ioLink = -1;
813
814     status_ = neonatal;
815     pid = iPid; 
816
817     struct utsname un;
818     P_uname(&un);
819     string buffer = string(pid) + string("_") + string(un.nodename);
820     rid = resource::newResource(processResource, // parent
821                                 (void*)this, // handle
822                                 nullString, // abstraction
823                                 parentProc.symbols->name(),
824                                 0.0, // creation time
825                                 buffer, // unique name (?)
826                                 MDL_T_STRING // mdl type (?)
827                                 );
828
829     parent = &parentProc;
830     bufStart = 0;
831     bufEnd = 0;
832
833     reachedFirstBreak = false; // process won't be paused until this is set
834
835     splitHeaps = parentProc.splitHeaps;
836     if (childHasInstrumentation) {
837       heaps[0] = inferiorHeap(parentProc.heaps[0]);
838       heaps[1] = inferiorHeap(parentProc.heaps[1]);
839     } else {
840       initInferiorHeap(false);
841       if (splitHeaps)
842         initInferiorHeap(true);
843     }
844
845     inExec = false;
846
847     cumObsCost = 0;
848     lastObsCostLow = 0;
849
850     proc_fd = -1;
851
852     trampTableItems = 0;
853     memset(trampTable, 0, sizeof(trampTable));
854     currentPC_ = 0;
855     hasNewPC = false;
856
857     inhandlestart = false;
858     dynamiclinking = parentProc.dynamiclinking;
859     dyn = new dynamic_linking;
860     *dyn = *parentProc.dyn;
861
862     shared_objects = 0;
863
864     // make copy of parent's shared_objects vector
865     if (parentProc.shared_objects) {
866       shared_objects = new vector<shared_object*>;
867       for (unsigned u1 = 0; u1 < parentProc.shared_objects->size(); u1++){
868         *shared_objects += 
869                 new shared_object(*(*parentProc.shared_objects)[u1]);
870       }
871     }
872
873     all_functions = 0;
874     if (parentProc.all_functions) {
875       all_functions = new vector<pdFunction *>;
876       for (unsigned u2 = 0; u2 < parentProc.all_functions->size(); u2++)
877         *all_functions += (*parentProc.all_functions)[u2];
878     }
879
880     all_modules = 0;
881     if (parentProc.all_modules) {
882       all_modules = new vector<module *>;
883       for (unsigned u3 = 0; u3 < parentProc.all_modules->size(); u3++)
884         *all_modules += (*parentProc.all_modules)[u3];
885     }
886
887     some_modules = 0;
888     if (parentProc.some_modules) {
889       some_modules = new vector<module *>;
890       for (unsigned u4 = 0; u4 < parentProc.some_modules->size(); u4++)
891         *some_modules += (*parentProc.some_modules)[u4];
892     }
893     
894     some_functions = 0;
895     if (parentProc.some_functions) {
896       some_functions = new vector<pdFunction *>;
897       for (unsigned u5 = 0; u5 < parentProc.some_functions->size(); u5++)
898         *some_functions += (*parentProc.some_functions)[u5];
899     }
900
901     waiting_for_resources = false;
902     signal_handler = parentProc.signal_handler;
903     execed_ = false;
904     mysteryTrap_ = false;
905
906 #ifdef SHM_SAMPLING
907 #ifdef sparc_sun_sunos4_1_3
908    childUareaPtr = NULL;
909 #endif
910 #endif
911
912 }
913
914 #ifdef SHM_SAMPLING
915 void process::registerInferiorAttachedSegs(void *inferiorAttachedAtPtr) {
916 #ifdef SHM_SAMPLING_DEBUG
917 cerr << "process pid " << getPid() << ": welcome to register with inferiorAttachedAtPtr=" << inferiorAttachedAtPtr << endl;
918 #endif
919
920    inferiorHeapMgr.registerInferiorAttachedAt(inferiorAttachedAtPtr);
921    inferiorIntCounters.setBaseAddrInApplic((intCounter*)
922                                            inferiorHeapMgr.getSubHeapInApplic(0));
923    inferiorWallTimers.setBaseAddrInApplic((tTimer*)
924                                           inferiorHeapMgr.getSubHeapInApplic(1));
925    inferiorProcessTimers.setBaseAddrInApplic((tTimer*)
926                                              inferiorHeapMgr.getSubHeapInApplic(2));
927 }
928 #endif
929
930 /*
931  * Create a new instance of the named process.  Read the symbols and start
932  *   the program
933  */
934 process *createProcess(const string File, vector<string> argv, vector<string> envp, const string dir = "")
935 {
936     int r;
937     unsigned i, j, k;
938     int tracePipe[2];
939     string inputFile, outputFile;
940     string file = File;
941
942     // prepend the directory (if any) to the file, unless the filename
943     // starts with a /
944     if (!file.prefixed_by("/") && dir.length() > 0)
945       file = dir + "/" + file;
946
947     // check for I/O redirection in arg list.
948     for (i=0; i<argv.size(); i++) {
949       if (argv[i] == "<") {
950         inputFile = argv[i+1];
951         for (j=i+2, k=i; j<argv.size(); j++, k++)
952           argv[k] = argv[j];
953         argv.resize(argv.size()-2);
954       }
955     }
956     // TODO -- this assumes no more than 1 of each "<", ">"
957     for (i=0; i<argv.size(); i++) {
958       if (argv[i] == ">") {
959         outputFile = argv[i+1];
960         for (j=i+2, k=i; j<argv.size(); j++, k++)
961           argv[k] = argv[j];
962         argv.resize(argv.size()-2);
963       }
964     }
965
966     // Strange, but using socketpair here doesn't seem to work OK on SunOS.
967     // Pipe works fine.
968     // r = P_socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, tracePipe);
969     r = P_pipe(tracePipe);
970     if (r) {
971         // P_perror("socketpair");
972         string msg = string("Unable to create trace pipe for program '") + File +
973                        string("': ") + string(sys_errlist[errno]);
974         showErrorCallback(68, msg);
975         return(NULL);
976     }
977
978     // ioPipe is used to redirect the child's stdout & stderr to a pipe which is in
979     // turn read by the parent via the process->ioLink socket.
980     int ioPipe[2];
981
982     // r = P_socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, ioPipe);
983     r = P_pipe(ioPipe);
984     if (r) {
985         // P_perror("socketpair");
986         string msg = string("Unable to create IO pipe for program '") + File +
987                        string("': ") + string(sys_errlist[errno]);
988         showErrorCallback(68, msg);
989         return(NULL);
990     }
991
992 //#ifdef SHM_SAMPLING
993 //    // Do this _before_ the fork so both the parent and child get the updated
994 //    // value of ::childShmKeyToUse
995 //    ::childShmKeyToUse = pickShmSegKey();
996 //#endif
997
998     //
999     // WARNING This code assumes that vfork is used, and a failed exec will
1000     //   corectly change failed in the parent process.
1001     //
1002     errno = 0;
1003 #ifdef PARADYND_PVM
1004 // must use fork, since pvmendtask will do some writing in the address space
1005     int pid = fork();
1006     // fprintf(stderr, "FORK: pid=%d\n", pid);
1007 #else
1008     int pid = vfork();
1009 #endif
1010     if (pid > 0) {
1011         if (errno) {
1012             sprintf(errorLine, "Unable to start %s: %s\n", file.string_of(), sys_errlist[errno]);
1013             logLine(errorLine);
1014             showErrorCallback(68, (const char *) errorLine);
1015             return(NULL);
1016         }
1017
1018 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
1019         extern bool establishBaseAddrs(int pid, int &status, bool waitForTrap);
1020         int status;
1021
1022         if (!establishBaseAddrs(pid, status, true)) {
1023             return(NULL);
1024         }
1025 #endif
1026
1027 // NEW: We bump up batch mode here; the matching bump-down occurs after shared objects
1028 //      are processed (after receiving the SIGSTOP indicating the end of running DYNINSTinit;
1029 //      more specifically, tryToReadAndProcessBootstrapInfo()).
1030 //      Prevents a diabolical w/w deadlock on solaris --ari
1031 tp->resourceBatchMode(true);
1032
1033         image *img = image::parseImage(file);
1034         if (!img) {
1035             string msg = string("Unable to parse image: ") + file;
1036             showErrorCallback(68, msg.string_of());
1037             // destroy child process
1038             P_kill(pid, 9);
1039
1040             return(NULL);
1041         }
1042
1043         /* parent */
1044         statusLine("initializing process data structures");
1045
1046 //      cerr << "welcome to new process, pid=" << getpid() << endl; cerr.flush();
1047 //      kill(getpid(), SIGSTOP);
1048 //      cerr << "doing new process " << endl; cerr.flush();
1049
1050 #ifdef SHM_SAMPLING
1051         vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
1052         theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
1053         theShmHeapStats[0].maxNumElems  = numIntCounters;
1054
1055         theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
1056         theShmHeapStats[1].maxNumElems  = numWallTimers;
1057
1058         theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
1059         theShmHeapStats[2].maxNumElems  = numProcTimers;
1060 #endif
1061
1062         process *ret = new process(pid, img,
1063                                    tracePipe[0], // trace link
1064                                    ioPipe[0] // io link
1065 #ifdef SHM_SAMPLING
1066                                    , 7000, // shm seg key to try first
1067                                    theShmHeapStats
1068 #endif
1069                                    );
1070            // change this to a ctor that takes in more args
1071
1072         assert(ret);
1073         processVec += ret;
1074         activeProcesses++;
1075         if (!costMetric::addProcessToAll(ret))
1076            assert(false);
1077         // find the signal handler function
1078         ret->findSignalHandler();
1079
1080         close(tracePipe[1]);
1081         close(ioPipe[1]);
1082            // parent closes write end of io pipe; child closes its read end.
1083            // pipe output goes to the parent's read fd (ret->ioLink); pipe input
1084            // comes from the child's write fd.  In short, when the child writes to
1085            // its stdout/stderr, it gets sent to the pipe which in turn sends it to
1086            // the parent's ret->ioLink fd for reading.
1087
1088 //      // attach to the child process
1089 //      ret->attach();
1090
1091 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
1092         // XXXX - this is a hack since establishBaseAddrs needed to wait for
1093         //    the TRAP signal.
1094         // We really need to move most of the above code (esp parse image)
1095         //    to the TRAP signal handler.  The problem is that we don't
1096         //    know the base addresses until we get the load info via ptrace.
1097         //    In general it is even harder, since dynamic libs can be loaded
1098         //    at any time.
1099         extern int handleSigChild(int pid, int status);
1100
1101         (void) handleSigChild(pid, status);
1102 #endif
1103         return(ret);
1104     } else if (pid == 0) {
1105 #ifdef PARADYND_PVM
1106         if (pvm_running)
1107           pvmendtask(); 
1108 #endif   
1109
1110         // handle stdio.
1111
1112         // The child doesn't care to read anything from the ioPipe; it only writes
1113         // to it.  Hence we close ioPipe[0], the read end.  Then we call dup2() twice
1114         // to assign our (the child's) stdout and stderr to the write end of the pipe.
1115         close(ioPipe[0]);
1116         dup2(ioPipe[1], 1);
1117            // assigns fd 1 (stdout) to be a copy of ioPipe[1].  (Since stdout is already
1118            // in use, dup2 will first close it then reopen it with the characteristics)
1119            // of ioPipe[1].
1120            // In short, stdout gets redirected towards the write end of the pipe.
1121            // The read end of the pipe is read by the parent (paradynd), not us.
1122
1123         dup2(ioPipe[1], 2); // redirect fd 2 (stderr) to the pipe, like above.
1124
1125         // We're not using ioPipe[1] anymore; close it.
1126         if (ioPipe[1] > 2) close (ioPipe[1]);
1127
1128         // Now that stdout is going to a pipe, it'll (unfortunately) be block buffered
1129         // instead of the usual line buffered (when it goes to a tty).  In effect the
1130         // stdio library is being a little too clever for our purposes.  We don't want
1131         // the "bufferedness" to change.  So we set it back to line-buffered.
1132         // The command to do this is setlinebuf(stdout) [stdio.h call]  But we don't
1133         // do it here, since the upcoming execve() would undo our work [execve keeps
1134         // fd's but resets higher-level stdio information, which is recreated before
1135         // execution of main()]  So when do we do it?  At the program's main(), via
1136         // rtinst's DYNINSTinit (RTposix.c et al.)
1137
1138         // setup stderr for rest of exec try.
1139         FILE *childError = P_fdopen(2, "w");
1140
1141         P_close(tracePipe[0]);
1142
1143         if (P_dup2(tracePipe[1], 3) != 3) {
1144             fprintf(childError, "dup2 failed\n");
1145             fflush(childError);
1146             P__exit(-1);
1147         }
1148
1149         /* close if higher */
1150         if (tracePipe[1] > 3) close(tracePipe[1]);
1151
1152         if ((dir.length() > 0) && (P_chdir(dir.string_of()) < 0)) {
1153           sprintf(errorLine, "cannot chdir to '%s': %s\n", dir.string_of(), sys_errlist[errno]);
1154           logLine(errorLine);
1155           P__exit(-1);
1156         }
1157
1158         /* see if I/O needs to be redirected */
1159         if (inputFile.length()) {
1160             int fd = P_open(inputFile.string_of(), O_RDONLY, 0);
1161             if (fd < 0) {
1162                 fprintf(childError, "stdin open of %s failed\n", inputFile.string_of());
1163                 fflush(childError);
1164                 P__exit(-1);
1165             } else {
1166                 dup2(fd, 0);
1167                 P_close(fd);
1168             }
1169         }
1170
1171         if (outputFile.length()) {
1172             int fd = P_open(outputFile.string_of(), O_WRONLY|O_CREAT, 0444);
1173             if (fd < 0) {
1174                 fprintf(childError, "stdout open of %s failed\n", outputFile.string_of());
1175                 fflush(childError);
1176                 P__exit(-1);
1177             } else {
1178                 dup2(fd, 1); // redirect fd 1 (stdout) to a copy of descriptor "fd"
1179                 P_close(fd); // not using descriptor fd any more; close it.
1180             }
1181         }
1182
1183         /* indicate our desire to be traced */
1184         errno = 0;
1185         OS::osTraceMe();
1186         if (errno != 0) {
1187           sprintf(errorLine, "ptrace error, exiting, errno=%d\n", errno);
1188           logLine(errorLine);
1189           logLine(sys_errlist[errno]);
1190           showErrorCallback(69, string("Internal error: ") + 
1191                                 string((const char *) errorLine)); 
1192           P__exit(-1);   // double underscores are correct
1193         }
1194 #ifdef PARADYND_PVM
1195         if (pvm_running && envp.size())
1196           for (int ep=envp.size()-1; ep>=0; ep--) {
1197             pvmputenv(envp[ep].string_of());
1198           }
1199 #endif
1200         // hand off info about how to start a paradynd to the application.
1201         //   used to catch rexec calls, and poe events.
1202         //
1203         char paradynInfo[1024];
1204         sprintf(paradynInfo, "PARADYN_MASTER_INFO= ");
1205         for (i=0; i < process::arg_list.size(); i++) {
1206             const char *str;
1207
1208             str = P_strdup(process::arg_list[i].string_of());
1209             if (!strcmp(str, "-l1")) {
1210                 strcat(paradynInfo, "-l0");
1211             } else {
1212                 strcat(paradynInfo, str);
1213             }
1214             strcat(paradynInfo, " ");
1215         }
1216         P_putenv(paradynInfo);
1217
1218         /* put the traceSocket address and host address in the environment. 
1219            This will be use by forked processes to get a connection with the daemon
1220         */
1221         extern int traceSocket;
1222         extern unsigned hostAddr;
1223         string paradyndSockInfo = string("PARADYND_TRACE_SOCKET=") + string(traceSocket)
1224                                   + string(" ") + string(hostAddr);
1225
1226         P_putenv(paradyndSockInfo.string_of());
1227
1228         char **args;
1229         args = new char*[argv.size()+1];
1230         for (unsigned ai=0; ai<argv.size(); ai++)
1231           args[ai] = P_strdup(argv[ai].string_of());
1232         args[argv.size()] = NULL;
1233         P_execvp(file.string_of(), args);
1234
1235         sprintf(errorLine, "paradynd: execv failed, errno=%d\n", errno);
1236         logLine(errorLine);
1237
1238         logLine(sys_errlist[errno]);
1239         int i=0;
1240         while (args[i]) {
1241           sprintf(errorLine, "argv %d = %s\n", i, args[i]);
1242           logLine(errorLine);
1243           i++;
1244         }
1245         P__exit(-1);
1246         return(NULL);
1247     } else {
1248         sprintf(errorLine, "vfork failed, errno=%d\n", errno);
1249         logLine(errorLine);
1250         showErrorCallback(71, (const char *) errorLine);
1251         return(NULL);
1252     }
1253 }
1254
1255
1256 // attachToProcess: attach to an already running process, this routine sets 
1257 // up the connection to the process, creates a shared memory segment, parses
1258 // the executable's image, creates a new process object, and processes
1259 // shared objects.  It returns 0 on error.
1260 process *process::attachToProcess(int pid,string file_name){
1261
1262 #ifdef ndef
1263     // open /proc/pid
1264     int proc_file = open
1265
1266     // set up socket stuff between process and paradynd
1267     int iTraceLink = 0;
1268     int iIoLink = 0;
1269
1270     // parse image file
1271     image *img = image::parseImage(file);
1272     if(!img){
1273         string msg = string("Unable to parse image: ") + file;
1274         showErrorCallback(68, msg.string_of());
1275         return 0;
1276     }
1277
1278 #ifdef SHM_SAMPLING
1279     // do shared memory stuff
1280     const vector<fastInferiorHeapMgr::oneHeapStats> iShmHeapStat;
1281     key_t theShmSegKey;
1282
1283 #endif
1284
1285     // create process
1286     process *p = new process(pid,img, iTraceLink,iIoLink,
1287 #ifdef SHM_SAMPLING
1288                              theShmSegKey,iShmHeapStat, 
1289 #endif  
1290                              );
1291
1292     // figure out if process has executed main yet or not, if it has then
1293     // call getAttachedSharedObjects() and DYNINSTinit(),  otherwise set
1294     // breakpoint at entry point of main and do this stuff there
1295     // get shared objects
1296     p->getAttachedSharedObjects();
1297
1298 #endif
1299
1300     return 0;
1301
1302 }
1303
1304
1305 #ifdef SHM_SAMPLING
1306 bool process::doMajorShmSample(unsigned long long theWallTime) {
1307    bool result = true; // will be set to false if any processAll() doesn't complete
1308                        // successfully.
1309
1310    if (!inferiorIntCounters.doMajorSample  (theWallTime, 0))
1311       result = false;
1312
1313    if (!inferiorWallTimers.doMajorSample   (theWallTime, 0))
1314       result = false;
1315
1316    if (!inferiorProcessTimers.doMajorSample(theWallTime, 0))
1317       // inferiorProcessTimers used to take in a non-dummy process time as the
1318       // 2d arg, but it looks like that we need to re-read the process time for
1319       // each proc timer, at the time of sampling the timer's value, to avoid
1320       // ugly jagged spikes in histogram (i.e. to avoid incorrect sampled values).
1321       //
1322       // Come to think of it: the same may have to be done for the wall time too!!!
1323       result = false;
1324
1325    const unsigned long long theProcTime = getInferiorProcessCPUtime();
1326
1327    // Now do the observed cost.
1328    // WARNING: shouldn't we be using a mutex?!
1329    unsigned *costAddr = this->getObsCostLowAddrInParadyndSpace();
1330    const unsigned theCost = *costAddr;
1331
1332    this->processCost(theCost, theWallTime, theProcTime);
1333
1334    return result;
1335 }
1336
1337 bool process::doMinorShmSample() {
1338    bool result = true; // so far...
1339
1340    if (!inferiorIntCounters.doMinorSample())
1341       result = false;
1342
1343    if (!inferiorWallTimers.doMinorSample())
1344       result = false;
1345
1346    if (!inferiorProcessTimers.doMinorSample())
1347       result = false;
1348
1349    return result;
1350 }
1351 #endif
1352
1353 extern void removeFromMetricInstances(process *);
1354 extern void disableAllInternalMetrics();
1355
1356 void handleProcessExit(process *proc, int exitStatus) {
1357   if (proc->status() == exited)
1358     return;
1359
1360   proc->Exited();
1361   if (proc->traceLink >= 0) {
1362     // We used to call processTraceStream(proc) here to soak up any last
1363     // messages but since it uses a blocking read, that doesn't seem like such
1364     // a good idea.
1365     //processTraceStream(proc);
1366
1367     P_close(proc->traceLink);
1368     proc->traceLink = -1;
1369   }
1370   if (proc->ioLink >= 0) {
1371     // We used to call processAppIO(proc) here to soak up any last
1372     // messages but since it uses a blocking read, that doesn't seem like such
1373     // a good idea.
1374     //processAppIO(proc);
1375
1376     P_close(proc->ioLink);
1377     proc->ioLink = -1;
1378   }
1379   removeFromMetricInstances(proc);
1380   --activeProcesses;
1381   if (activeProcesses == 0)
1382     disableAllInternalMetrics();
1383
1384   proc->detach(false);
1385
1386 #ifdef PARADYND_PVM
1387   if (pvm_running) {
1388     PDYN_reportSIGCHLD(proc->getPid(), exitStatus);
1389   }
1390 #endif
1391
1392   // Perhaps these lines can be un-commented out in the future, but since
1393   // cleanUpAndExit() does the same thing, and it always gets called
1394   // (when paradynd detects that paradyn died), it's not really necessary
1395   // here.  -ari
1396 //  for (unsigned lcv=0; lcv < processVec.size(); lcv++)
1397 //     if (processVec[lcv] == proc) {
1398 //        delete proc; // destructor removes shm segments...
1399 //      processVec[lcv] = NULL;
1400 //     }
1401 }
1402
1403
1404 /*
1405    process::forkProcess: called when a process forks, to initialize a new
1406    process object for the child.
1407
1408    the variable childHasInstrumentation is true if the child process has the 
1409    instrumentation of the parent. This is the common case.
1410    On some platforms (AIX) the child does not have any instrumentation because
1411    the text segment of the child is not a copy of the parent text segment at
1412    the time of the fork, but a copy of the original text segment of the parent,
1413    without any instrumentation.
1414 */
1415 process *process::forkProcess(const process *theParent, pid_t childPid
1416 #ifdef SHM_SAMPLING
1417                               ,key_t theKey,
1418                               void *applAttachedPtr
1419 #endif
1420                               , bool childHasInstrumentation
1421                               ) {
1422 #ifdef SHM_SAMPLING
1423     vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
1424     theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
1425     theShmHeapStats[0].maxNumElems  = numIntCounters;
1426     
1427     theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
1428     theShmHeapStats[1].maxNumElems  = numWallTimers;
1429
1430     theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
1431     theShmHeapStats[2].maxNumElems  = numProcTimers;
1432 #endif
1433
1434     process *ret = new process(*theParent, childPid
1435 #ifdef SHM_SAMPLING
1436                                , theKey,
1437                                applAttachedPtr,
1438                                theShmHeapStats
1439 #endif
1440                                , childHasInstrumentation
1441                                );
1442
1443        // change this to a "fork" ctor that takes in more args
1444     assert(ret);
1445     processVec += ret;
1446     activeProcesses++;
1447
1448     if (!costMetric::addProcessToAll(ret))
1449        assert(false);
1450
1451     /* attach to child */
1452     if (!ret->attach()) {
1453       showErrorCallback(69, "Error in forkprocess: cannot attach to child process");
1454       return 0;
1455     }
1456
1457     if (childHasInstrumentation) {
1458       /* all instrumentation on the parent is active on the child */
1459       /* TODO: what about instrumentation inserted near the fork time??? */
1460       ret->baseMap = theParent->baseMap;
1461
1462       /* copy all instrumentation instances of the parent to the child */
1463       /* this will update instMapping */
1464       copyInstInstances(theParent, ret, ret->instInstanceMapping);
1465     }
1466
1467     return ret;
1468 }
1469
1470 #ifdef SHM_SAMPLING
1471 void process::processCost(unsigned obsCostLow,
1472                           unsigned long long wallTime,
1473                           unsigned long long processTime) {
1474    // wallTime and processTime should compare to DYNINSTgetWallTime() and
1475    // DYNINSTgetCPUtime().
1476
1477    // check for overflow, add to running total, convert cycles to
1478    // seconds, and report.
1479    // Member vrbles of class process: lastObsCostLow and cumObsCost (the latter
1480    // a 64-bit value).
1481
1482    // code to handle overflow used to be in rtinst; we borrow it pretty much
1483    // verbatim. (see rtinst/RTposix.c)
1484    if (obsCostLow < lastObsCostLow) {
1485       // we have a wraparound
1486       cumObsCost += ((unsigned)0xffffffff - lastObsCostLow) + obsCostLow + 1;
1487    }
1488    else
1489       cumObsCost += (obsCostLow - lastObsCostLow);
1490
1491    lastObsCostLow = obsCostLow;
1492
1493    extern double cyclesPerSecond; // perfStream.C
1494
1495    double observedCostSecs = cumObsCost;
1496    observedCostSecs /= cyclesPerSecond;
1497 //   cerr << "processCost: cyclesPerSecond=" << cyclesPerSecond << "; cum obs cost=" << observedCostSecs << endl;
1498
1499    // Notice how most of the rest of this is copied from processCost() of metric.C
1500    // Be sure to keep the two "in sync"!
1501    timeStamp newSampleTime  = (double)wallTime / 1000000.0; // usec to seconds
1502    timeStamp newProcessTime = (double)processTime / 1000000.0; // usec to secs
1503
1504    extern costMetric *totalPredictedCost; // init.C
1505    extern costMetric *observed_cost; // init.C
1506    extern costMetric *smooth_obs_cost; // init.C
1507
1508    const timeStamp lastProcessTime =
1509                         totalPredictedCost->getLastSampleProcessTime(this);
1510
1511     // find the portion of uninstrumented time for this interval
1512     const double unInstTime = ((newProcessTime - lastProcessTime)
1513                          / (1+currentPredictedCost));
1514     // update predicted cost
1515     // note: currentPredictedCost is the same for all processes
1516     //       this should be changed to be computed on a per process basis
1517     sampleValue newPredCost = totalPredictedCost->getCumulativeValue(this);
1518     newPredCost += (float)(currentPredictedCost*unInstTime);
1519
1520     totalPredictedCost->updateValue(this,newPredCost,
1521                                     newSampleTime,newProcessTime);
1522     // update observed cost
1523     observed_cost->updateValue(this,observedCostSecs,
1524                                newSampleTime,newProcessTime);
1525
1526     // update smooth observed cost
1527     smooth_obs_cost->updateSmoothValue(this,observedCostSecs,
1528                                        newSampleTime,newProcessTime);
1529 }
1530 #endif
1531
1532 /*
1533  * Copy data from controller process to the named process.
1534  */
1535 bool process::writeDataSpace(void *inTracedProcess, int size,
1536                              const void *inSelf) {
1537   bool needToCont = false;
1538
1539   if (status_ == exited)
1540     return false;
1541
1542   if (status_ == running) {
1543     needToCont = true;
1544     if (! pause())
1545       return false;
1546   }
1547
1548   if (status_ != stopped && status_ != neonatal) {
1549     showErrorCallback(38, "Internal paradynd error in process::writeDataSpace");
1550     return false;
1551   }
1552
1553   bool res = writeDataSpace_(inTracedProcess, size, inSelf);
1554   if (!res) {
1555     string msg = string("System error: unable to write to process data space:")
1556                    + string(sys_errlist[errno]);
1557     showErrorCallback(38, msg);
1558     return false;
1559   }
1560
1561   if (needToCont)
1562     return this->continueProc();
1563   return true;
1564 }
1565
1566 bool process::readDataSpace(const void *inTracedProcess, int size,
1567                             void *inSelf, bool displayErrMsg) {
1568   bool needToCont = false;
1569
1570   if (status_ == exited)
1571     return false;
1572
1573   if (status_ == running) {
1574     needToCont = true;
1575     if (! pause())
1576       return false;
1577   }
1578
1579   if (status_ != stopped && status_ != neonatal) {
1580     showErrorCallback(38, "Internal paradynd error in process::readDataSpace");
1581     return false;
1582   }
1583
1584   bool res = readDataSpace_(inTracedProcess, size, inSelf);
1585   if (!res) {
1586     if (displayErrMsg) {
1587       string msg;
1588       msg=string("System error: unable to read from process data space:")
1589           + string(sys_errlist[errno]);
1590       showErrorCallback(38, msg);
1591     }
1592     return false;
1593   }
1594
1595   if (needToCont)
1596     return this->continueProc();
1597   return true;
1598
1599 }
1600
1601 bool process::writeTextWord(caddr_t inTracedProcess, int data) {
1602   bool needToCont = false;
1603
1604   if (status_ == exited)
1605     return false;
1606
1607   if (status_ == running) {
1608     needToCont = true;
1609     if (! pause())
1610       return false;
1611   }
1612
1613   if (status_ != stopped && status_ != neonatal) {
1614     string msg = string("Internal paradynd error in process::writeTextWord")
1615                + string((int)status_);
1616     showErrorCallback(38, msg);
1617     //showErrorCallback(38, "Internal paradynd error in process::writeTextWord");
1618     return false;
1619   }
1620
1621   bool res = writeTextWord_(inTracedProcess, data);
1622   if (!res) {
1623     string msg = string("System error: unable to write to process data space:")
1624                    + string(sys_errlist[errno]);
1625     showErrorCallback(38, msg);
1626     return false;
1627   }
1628
1629   if (needToCont)
1630     return this->continueProc();
1631   return true;
1632
1633 }
1634
1635 bool process::writeTextSpace(void *inTracedProcess, int amount, const void *inSelf) {
1636   bool needToCont = false;
1637
1638   if (status_ == exited)
1639     return false;
1640
1641   if (status_ == running) {
1642     needToCont = true;
1643     if (! pause())
1644       return false;
1645   }
1646
1647   if (status_ != stopped && status_ != neonatal) {
1648     string msg = string("Internal paradynd error in process::writeTextSpace")
1649                + string((int)status_);
1650     showErrorCallback(38, msg);
1651     //showErrorCallback(38, "Internal paradynd error in process::writeTextSpace");
1652     return false;
1653   }
1654
1655   bool res = writeTextSpace_(inTracedProcess, amount, inSelf);
1656   if (!res) {
1657     string msg = string("System error: unable to write to process data space:")
1658                    + string(sys_errlist[errno]);
1659     showErrorCallback(38, msg);
1660     return false;
1661   }
1662
1663   if (needToCont)
1664     return this->continueProc();
1665   return true;
1666 }
1667
1668 bool process::pause() {
1669   if (status_ == stopped || status_ == neonatal)
1670     return true;
1671
1672   if (status_ == exited)
1673     return false;
1674
1675   if (status_ == running && reachedFirstBreak) {
1676     bool res = pause_();
1677     if (!res)
1678       return false;
1679
1680     status_ = stopped;
1681   }
1682   else {
1683     // The only remaining combination is: status==running but haven't yet
1684     // reached first break.  We never want to pause before reaching the
1685     // first break.
1686   }
1687
1688   return true;
1689 }
1690
1691 //
1692 //  handler for a trace record of type TR_START
1693 //  this routines inserts initial instrumentation into the PLT
1694 //  so that function calls to dynamically linked objects that invoke
1695 //  the dynamic linker are caught 
1696 //
1697 //  TODO: This routine also traverses the link map and creates a list
1698 //        of (shared object file name,shared object base address, processed)
1699 //        structs for each element in the link map.  The daemon also 
1700 //        instruments the r_brk routine so that mapping and unmapping
1701 //        of shared objects by the runtime linker is detected
1702 //
1703 bool process::handleStartProcess(process *p){
1704
1705     if(!p){
1706         // cerr << "in process::handleStartProcess p is 0\n";
1707         return false;
1708     }
1709
1710     // cerr << " in handleStartProcess" << endl;
1711     // get shared objects, parse them, and define new resources 
1712     p->getSharedObjects();
1713
1714     if(resource::num_outstanding_creates)
1715        p->setWaitingForResources();
1716
1717     return true;
1718 }
1719
1720 //  Executes on the exit point of the exec: does any necessary initialization
1721 //  for the run time linker to export dynamic linking information
1722 //  returns true if the executable is dynamic
1723 //
1724 // bool process::findDynamicLinkingInfo(){
1725 //     dynamiclinking = true;
1726 //     return dynamiclinking;
1727 // }
1728
1729 // addASharedObject: This routine is called whenever a new shared object
1730 // has been loaded by the run-time linker
1731 // It processes the image, creates new resources
1732 bool process::addASharedObject(shared_object &new_obj){
1733
1734     image *img = image::parseImage(new_obj.getName(),new_obj.getBaseAddress());
1735     if(!img){
1736         logLine("error parsing image in addASharedObject\n");
1737     }
1738     new_obj.addImage(img);
1739
1740     // if the list of all functions and all modules have already been 
1741     // created for this process, then the functions and modules from this
1742     // shared object need to be added to those lists 
1743     if(all_modules){
1744         *all_modules += *(new_obj.getModules()); 
1745     }
1746     if(all_functions){
1747         *all_functions += *(new_obj.getAllFunctions()); 
1748     }
1749
1750     // if the signal handler function has not yet been found search for it
1751     if(!signal_handler){
1752         signal_handler = img->findOneFunction(SIGNAL_HANDLER);
1753     }
1754
1755     // clear the include_funcs flag if this shared object should not be
1756     // included in the some_functions and some_modules lists
1757     vector<string> lib_constraints;
1758     if(mdl_get_lib_constraints(lib_constraints)){
1759         for(u_int i=0; i < lib_constraints.size(); i++){
1760            if(new_obj.getName() == lib_constraints[i]){
1761               new_obj.changeIncludeFuncs(false); 
1762            }
1763         }
1764     }
1765
1766     if(new_obj.includeFunctions()){
1767         if(some_modules){
1768             *some_modules += *(new_obj.getModules()); 
1769         }
1770         if(some_functions){
1771             *some_functions += *(new_obj.getAllFunctions()); 
1772         }
1773     }
1774     return true;
1775 }
1776
1777 // getSharedObjects: This routine is called before main() to get and
1778 // process all shared objects that have been mapped into the process's
1779 // address space
1780 bool process::getSharedObjects() {
1781
1782     assert(!shared_objects);
1783     shared_objects = dyn->getSharedObjects(this); 
1784     if(shared_objects){
1785         statusLine("parsing shared object files");
1786
1787         tp->resourceBatchMode(true);
1788         // for each element in shared_objects list process the 
1789         // image file to find new instrumentaiton points
1790         for(u_int i=0; i < shared_objects->size(); i++){
1791             string temp2 = string(i);
1792             temp2 += string("th shared obj, addr: ");
1793             temp2 += string(((*shared_objects)[i])->getBaseAddress());
1794             temp2 += string(" name: ");
1795             temp2 += string(((*shared_objects)[i])->getName());
1796             temp2 += string("\n");
1797             // logLine(P_strdup(temp2.string_of()));
1798             if(!addASharedObject(*((*shared_objects)[i]))){
1799                 logLine("Error after call to addASharedObject\n");
1800             }
1801         }
1802
1803         tp->resourceBatchMode(false);
1804         return true;
1805     }
1806     // else this a.out does not have a .dynamic section
1807     dynamiclinking = false;
1808     return false;
1809 }
1810
1811 // findOneFunction: returns the function associated with func  
1812 // this routine checks both the a.out image and any shared object
1813 // images for this resource
1814 pdFunction *process::findOneFunction(resource *func,resource *mod){
1815     
1816     if((!func) || (!mod)) { return 0; }
1817     if(func->type() != MDL_T_PROCEDURE) { return 0; }
1818     if(mod->type() != MDL_T_MODULE) { return 0; }
1819
1820     const vector<string> &f_names = func->names();
1821     const vector<string> &m_names = mod->names();
1822     string func_name = f_names[f_names.size() -1]; 
1823     string mod_name = m_names[m_names.size() -1]; 
1824
1825     // KLUDGE: first search any shared libraries for the module name 
1826     //  (there is only one module in each shared library, and that 
1827     //  is the library name)
1828     if(dynamiclinking && shared_objects){
1829         for(u_int i=0; i < shared_objects->size(); i++){
1830             module *next = 0;
1831             next = ((*shared_objects)[i])->findModule(mod_name);
1832             if(next){
1833                 return(((*shared_objects)[i])->findOneFunction(func_name));
1834             }
1835         }
1836     }
1837
1838     // check a.out for function symbol
1839     return(symbols->findOneFunction(func_name));
1840 }
1841
1842 // findOneFunction: returns the function associated with func  
1843 // this routine checks both the a.out image and any shared object
1844 // images for this resource
1845 pdFunction *process::findOneFunction(const string &func_name){
1846     
1847     // first check a.out for function symbol
1848     pdFunction *pdf = symbols->findOneFunction(func_name);
1849     if(pdf) return pdf;
1850
1851     // search any shared libraries for the file name 
1852     if(dynamiclinking && shared_objects){
1853         for(u_int i=0; i < shared_objects->size(); i++){
1854             pdf = ((*shared_objects)[i])->findOneFunction(func_name);
1855             if(pdf){
1856                 return(pdf);
1857             }
1858     } }
1859     return(0);
1860 }
1861
1862 // findFunctionIn: returns the function containing the address "adr"
1863 // this routine checks both the a.out image and any shared object
1864 // images for this resource
1865 pdFunction *process::findFunctionIn(Address adr){
1866
1867     // first check a.out for function symbol
1868     pdFunction *pdf = symbols->findFunctionIn(adr,this);
1869     if(pdf) return pdf;
1870     // search any shared libraries for the function 
1871     if(dynamiclinking && shared_objects){
1872         for(u_int i=0; i < shared_objects->size(); i++){
1873             pdf = ((*shared_objects)[i])->findFunctionIn(adr,this);
1874             if(pdf){
1875                 return(pdf);
1876             }
1877     } }
1878
1879     if(!all_functions) getAllFunctions();
1880
1881
1882     // if the function was not found, then see if this addr corresponds
1883     // to  a function that was relocated in the heap
1884     if(all_functions){
1885         for(u_int i=0; i < all_functions->size(); i++){
1886             Address func_adr = ((*all_functions)[i])->getAddress(this);
1887             if((adr>=func_adr) && 
1888                 (adr<=(((*all_functions)[i])->size()+func_adr))){
1889                 return((*all_functions)[i]);
1890             }
1891         }
1892     }
1893     return(0);
1894 }
1895         
1896         
1897 // findModule: returns the module associated with mod_name 
1898 // this routine checks both the a.out image and any shared object
1899 // images for this resource
1900 module *process::findModule(const string &mod_name){
1901
1902     // KLUDGE: first search any shared libraries for the module name 
1903     //  (there is only one module in each shared library, and that 
1904     //  is the library name)
1905     if(dynamiclinking && shared_objects){
1906         for(u_int i=0; i < shared_objects->size(); i++){
1907             module *next = 0;
1908             next = ((*shared_objects)[i])->findModule(mod_name);
1909             if(next){
1910                 return(next);
1911             }
1912     } }
1913
1914     // check a.out for function symbol
1915     return(symbols->findModule(mod_name));
1916 }
1917
1918 // getSymbolInfo:  get symbol info of symbol associated with name n
1919 // this routine starts looking a.out for symbol and then in shared objects
1920 bool process::getSymbolInfo(string &name, Symbol &info){
1921     
1922     // first check a.out for symbol
1923     if(symbols->symbol_info(name,info)) return true;
1924
1925     // next check shared objects
1926     if(dynamiclinking && shared_objects){
1927         for(u_int i=0; i < shared_objects->size(); i++){
1928             if(((*shared_objects)[i])->getSymbolInfo(name,info)) { 
1929                 return true; 
1930     } } } 
1931     return false;
1932 }
1933
1934
1935 // getAllFunctions: returns a vector of all functions defined in the
1936 // a.out and in the shared objects
1937 // TODO: what to do about duplicate function names?
1938 vector<pdFunction *> *process::getAllFunctions(){
1939
1940     // if this list has already been created, return it
1941     if(all_functions) 
1942         return all_functions;
1943
1944     // else create the list of all functions
1945     all_functions = new vector<pdFunction *>;
1946     *all_functions += symbols->mdlNormal;
1947
1948     if(dynamiclinking && shared_objects){
1949         for(u_int i=0; i < shared_objects->size(); i++){
1950            vector<pdFunction *> *funcs = 
1951                         ((*shared_objects)[i])->getAllFunctions();
1952            if(funcs) { 
1953                *all_functions += *funcs; 
1954            }
1955     } } 
1956     return all_functions;
1957 }
1958       
1959 // getAllModules: returns a vector of all modules defined in the
1960 // a.out and in the shared objects
1961 vector<module *> *process::getAllModules(){
1962
1963     // if the list of all modules has already been created, the return it
1964     if(all_modules) return all_modules;
1965
1966     // else create the list of all modules
1967     all_modules = new vector<module *>;
1968     *all_modules += symbols->mods;
1969
1970     if(dynamiclinking && shared_objects){
1971         for(u_int i=0; i < shared_objects->size(); i++){
1972            vector<module *> *mods = ((*shared_objects)[i])->getModules();
1973            if(mods) {
1974                *all_modules += *mods; 
1975            }
1976     } } 
1977     return all_modules;
1978 }
1979
1980 // getIncludedFunctions: returns a vector of all functions defined in the
1981 // a.out and in the shared objects
1982 // TODO: what to do about duplicate function names?
1983 vector<pdFunction *> *process::getIncludedFunctions(){
1984
1985     // if this list has already been created, return it
1986     if(some_functions) 
1987         return some_functions;
1988
1989     // else create the list of all functions
1990     some_functions = new vector<pdFunction *>;
1991     *some_functions += symbols->mdlNormal;
1992
1993     if(dynamiclinking && shared_objects){
1994         for(u_int i=0; i < shared_objects->size(); i++){
1995             if(((*shared_objects)[i])->includeFunctions()){
1996                 vector<pdFunction *> *funcs = 
1997                         ((*shared_objects)[i])->getAllFunctions();
1998                 if(funcs) { 
1999                     *some_functions += *funcs; 
2000                 }
2001             } 
2002     } } 
2003     return some_functions;
2004 }
2005
2006 // getIncludedModules: returns a vector of all modules defined in the
2007 // a.out and in the shared objects that are included as specified in
2008 // the mdl
2009 vector<module *> *process::getIncludedModules(){
2010
2011     // if the list of all modules has already been created, the return it
2012     if(some_modules) return some_modules;
2013
2014     // else create the list of all modules
2015     some_modules = new vector<module *>;
2016     *some_modules += symbols->mods;
2017
2018     if(dynamiclinking && shared_objects){
2019         for(u_int i=0; i < shared_objects->size(); i++){
2020             if(((*shared_objects)[i])->includeFunctions()){
2021                vector<module *> *mods = ((*shared_objects)[i])->getModules();
2022                if(mods) {
2023                    *some_modules += *mods; 
2024                }
2025            }
2026     } } 
2027     return some_modules;
2028 }
2029       
2030
2031 // findSignalHandler: if signal_handler is 0, then it checks all images
2032 // associtated with this process for the signal handler function.
2033 // Otherwise, the signal handler function has already been found
2034 void process::findSignalHandler(){
2035
2036     if(SIGNAL_HANDLER == 0) return;
2037     if(!signal_handler) { 
2038         // first check a.out for signal handler function
2039         signal_handler = symbols->findOneFunction(SIGNAL_HANDLER);
2040
2041         // search any shared libraries for signal handler function
2042         if(!signal_handler && dynamiclinking && shared_objects) { 
2043             for(u_int i=0;(i < shared_objects->size()) && !signal_handler; i++){
2044                 signal_handler = 
2045                       ((*shared_objects)[i])->findOneFunction(SIGNAL_HANDLER);
2046         } }
2047     }
2048 }
2049
2050 bool process::continueProc() {
2051   if (status_ == exited) return false;
2052
2053   if (status_ != stopped && status_ != neonatal) {
2054     showErrorCallback(38, "Internal paradynd error in process::continueProc");
2055     return false;
2056   }
2057
2058   bool res = continueProc_();
2059
2060   if (!res) {
2061     showErrorCallback(38, "System error: can't continue process");
2062     return false;
2063   }
2064   status_ = running;
2065   return true;
2066 }
2067
2068 bool process::detach(const bool paused) {
2069   if (paused) {
2070     logLine("detach: pause not implemented\n");
2071   }
2072   bool res = detach_();
2073   if (!res) {
2074     // process may have exited
2075     return false;
2076   }
2077   return true;
2078 }
2079
2080 /* process::handleExec: called when a process exec.
2081    Parse the new image and disable metric instances on the old image.
2082 */
2083 void process::handleExec() {
2084
2085     // all instrumentation that was inserted in this process is gone.
2086     // set exited here so that the disables won't try to write to process
2087     status_ = exited; 
2088    
2089     removeFromMetricInstances(this);
2090
2091     // Clean up state from old exec: all dynamic linking stuff, all lists 
2092     // of functions and modules from old executable
2093
2094     // can't delete dynamic linking stuff here, because parent process
2095     // could still have pointers
2096     dynamiclinking = false;
2097     dyn = 0;
2098     dyn = new dynamic_linking;
2099     if(shared_objects){
2100         for(u_int i=0; i< shared_objects->size(); i++){
2101             delete (*shared_objects)[i];
2102         }
2103         delete shared_objects;
2104         shared_objects = 0;
2105     }
2106
2107     // TODO: when can pdFunction's be deleted???  definitely not here.
2108     delete some_modules;
2109     delete some_functions;
2110     delete all_functions;
2111     delete all_modules;
2112     some_modules = 0;
2113     some_functions = 0;
2114     all_functions = 0;
2115     all_modules = 0;
2116     signal_handler = 0;
2117     trampTableItems = 0;
2118     memset(trampTable, 0, sizeof(trampTable));
2119     baseMap.clear();
2120
2121 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
2122     // must call establishBaseAddrs before parsing the new image,
2123     // but doesn't need to wait for trap, since we already got the trap.
2124     bool establishBaseAddrs(int pid, int &status, bool waitForTrap);
2125     int status;
2126     establishBaseAddrs(getPid(), status, false);
2127 #endif
2128
2129     image *img = image::parseImage(execFilePath);
2130     if (!img) {
2131        string msg = string("Unable to parse image: ") + execFilePath;
2132        showErrorCallback(68, msg.string_of());
2133        P_kill(pid, 9);
2134        return;
2135     }
2136
2137     // delete proc->symbols ???  No, the image can be shared by more
2138     // than one process...images and instPoints can not be deleted...TODO
2139     // add some sort of reference count to these classes so that they can
2140     // be deleted
2141     symbols = img;
2142
2143     // see if new image contains the signal handler function
2144     this->findSignalHandler();
2145
2146     // initInferiorHeap can only be called after symbols is set!
2147     initInferiorHeap(false);
2148     if (splitHeaps) {
2149       initInferiorHeap(true);  // create separate text heap
2150     }
2151
2152     /* update process status */
2153     reachedFirstBreak = false;
2154     hasBootstrapped = false;
2155     status_ = stopped;
2156     execed_ = true;
2157     mysteryTrap_ = false;
2158 }
2159
2160 /* 
2161    process::cleanUpInstrumentation called when paradynd catch
2162    a SIGTRAP to find out if there's any previous unfinished instrumentation
2163    requests 
2164 */
2165 bool process::cleanUpInstrumentation(bool wasRunning) {
2166     // Try to process an item off of the waiting list 'instWlist'.
2167     // If something was found & processed, then true will be returned.
2168     // Additionally, if true is returned, the process will be continued
2169     // if 'wasRunning' is true.
2170     // But if false is returned, then there should be no side effects: noone
2171     // should be continued, nothing removed from 'instWList', no change
2172     // to this->status_, and so on (this is important to avoid bugs).
2173
2174     assert(status_ == stopped); // since we're always called after a SIGTRAP
2175     Frame frame(this);
2176     Address pc = frame.getPC();
2177
2178     // Go thru the instWList to find out the ones to be deleted 
2179     bool done = false;
2180     u_int i=0;
2181     bool found = false;
2182     while(!done){
2183         //process *p = (instWList[i])->which_proc;
2184         if(((instWList[i])->pc_ == pc) && ((instWList[i])->which_proc == this)){
2185             (instWList[i])->cleanUp(this,pc);
2186             u_int last = instWList.size()-1;
2187             delete (instWList[i]);
2188             instWList[i] = instWList[last];
2189             instWList.resize(last);
2190             found = true;
2191         }
2192         else {
2193             i++;
2194         }
2195         if(i >= instWList.size()) done = true;
2196     }
2197     if(found && wasRunning) continueProc();
2198     return found;
2199 }
2200
2201 void process::postRPCtoDo(AstNode *action, bool noCost,
2202                           void (*callbackFunc)(process *, void *),
2203                           void *userData) {
2204    // posts an RPC, but does NOT make any effort to launch it.
2205    inferiorRPCtoDo theStruct;
2206    theStruct.action = action;
2207    theStruct.noCost = noCost;
2208    theStruct.callbackFunc = callbackFunc;
2209    theStruct.userData = userData;
2210
2211    RPCsWaitingToStart += theStruct;
2212 }
2213
2214 bool process::existsRPCreadyToLaunch() const {
2215    if (currRunningRPCs.empty() && !RPCsWaitingToStart.empty())
2216       return true;
2217    return false;
2218 }
2219
2220 bool process::existsRPCinProgress() const {
2221    return (!currRunningRPCs.empty());
2222 }
2223
2224 bool process::launchRPCifAppropriate(bool wasRunning) {
2225    // asynchronously launches iff RPCsWaitingToStart.size() > 0 AND
2226    // if currRunningRPCs.size()==0 (the latter for safety)
2227
2228    if (!currRunningRPCs.empty())
2229       // an RPC is currently executing, so it's not safe to launch a new one.
2230       return false;
2231
2232    if (RPCsWaitingToStart.empty())
2233       // duh, no RPC is waiting to run, so there's nothing to do.
2234       return false;
2235
2236    /* ****************************************************** */
2237
2238    if (status_ == exited)
2239       return false;
2240          // I honestly don't know what the hell to do in this case, but we sure
2241          // can't expect the process to be able to execute any more code!
2242
2243    if (status_ == neonatal)
2244       // not sure if this should be some kind of error...is the inferior ready
2245       // to execute inferior RPCs??? For now, we'll allow it.
2246       ; 
2247
2248    // Steps to take (on sparc, at least)
2249    // 1) pause the process and wait for it to stop
2250    // 2) GETREGS (ptrace call) & store away
2251    // 3) create temp tramp: save, action, restore, trap, illegal
2252    //    (the illegal is just ot be sure that the trap never returns)
2253    // 4) set the PC and nPC regs to addr of temp tramp
2254    // 5) PTRACE_CONT; go back to main loop (SIGTRAP will eventually be delivered)
2255
2256    // When SIGTRAP is received,
2257    // 1) verify that PC is the location of the TRAP instr in the temp tramp
2258    // 2) free tramp
2259    // 3) SETREGS to restore all regs, including PC and nPC.
2260    // 4) continue inferior, if appropriate (THIS IS AN UNSETTLED ISSUE).
2261
2262    if (!pause()) {
2263       cerr << "launchRPCifAppropriate failed because pause failed" << endl;
2264       return false;
2265    }
2266
2267    bool syscall = false;
2268    void *theSavedRegs = getRegisters(syscall); // machine-specific implementation
2269       // result is allocated via new[]; we'll delete[] it later.
2270       // return value of NULL indicates total failure.
2271       // return value of (void *)-1 indicates that the state of the machine isn't quite
2272       //    ready for an inferiorRPC, and that we should try again 'later'.  In particular,
2273       //    we must handle the (void *)-1 case very gracefully (i.e., leave
2274       //    the vrble 'RPCsWaitingToStart' untouched).
2275
2276    if (theSavedRegs == (void *)-1) {
2277       // cerr << "launchRPCifAppropriate: deferring" << endl;
2278       if (wasRunning)
2279          (void)continueProc();
2280       return false;
2281    }
2282
2283    if (theSavedRegs == NULL) {
2284       cerr << "launchRPCifAppropriate failed because getRegisters() failed" << endl;
2285       if (wasRunning)
2286          (void)continueProc();
2287       return false;
2288    }
2289
2290    inferiorRPCtoDo todo = RPCsWaitingToStart.removeOne();
2291       // note: this line should always be below the test for (void*)-1, thus
2292       // leaving 'RPCsWaitingToStart' alone in that case.
2293
2294 // Code for the HPUX version of inferiorRPC exists, but crashes, so
2295 // for now, don't do inferiorRPC on HPUX!!!!
2296 /* #if defined(hppa1_1_hp_hpux)
2297 if (wasRunning)
2298   (void)continueProc();
2299 return false;
2300 #endif */
2301
2302    inferiorRPCinProgress inProgStruct;
2303    inProgStruct.callbackFunc = todo.callbackFunc;
2304    inProgStruct.userData = todo.userData;
2305    inProgStruct.savedRegs = theSavedRegs;
2306    inProgStruct.wasRunning = wasRunning;
2307    unsigned tempTrampBase = createRPCtempTramp(todo.action,
2308                                                todo.noCost,
2309                                                inProgStruct.firstPossibleBreakAddr,
2310                                                inProgStruct.lastPossibleBreakAddr);
2311       // the last 2 args are written to
2312
2313    if (tempTrampBase == NULL) {
2314       cerr << "launchRPCifAppropriate failed because createRPCtempTramp failed" << endl;
2315       if (wasRunning)
2316          (void)continueProc();
2317       return false;
2318    }
2319
2320    assert(tempTrampBase);
2321
2322    inProgStruct.firstInstrAddr = tempTrampBase;
2323
2324    assert(currRunningRPCs.empty()); // since it's unsafe to run > 1 at a time
2325    currRunningRPCs += inProgStruct;
2326
2327    // change the PC and nPC registers to the addr of the temp tramp
2328 #if defined(hppa1_1_hp_hpux)
2329    if (syscall) {
2330        // within system call, just directly change the PC
2331        if (!changePC(tempTrampBase, theSavedRegs)) {
2332            cerr << "launchRPCifAppropriate failed because changePC() failed" << endl;
2333            if (wasRunning)
2334                (void)continueProc();
2335            return false;
2336        }
2337    } else {
2338        pdFunction *f = symbols->findOneFunctionFromAll("$$dyncall");
2339        if (!f) {
2340            cerr << "$$dyncall was not found, inferior RPC won't work!" << endl;   
2341         
2342            //       if (wasRunning)
2343            //      (void)continueProc();
2344            //       return false;
2345        }
2346        
2347        int errno = 0;
2348        ptrace(PT_WUREGS, getPid(), 22 * 4, tempTrampBase, 0);
2349        if (errno != 0) {
2350            perror("process::changePC");
2351            cerr << "reg num was 22." << endl;
2352            return false;
2353        }
2354        
2355        int miniAddr = f -> getAddress(this);
2356        if (!changePC(miniAddr, theSavedRegs)) {
2357             cerr << "launchRPCifAppropriate failed because changePC() failed" << endl;
2358            if (wasRunning)
2359                (void)continueProc();
2360            return false;
2361         }
2362    }
2363 #else
2364        if (!changePC(tempTrampBase, theSavedRegs)) {
2365            cerr << "launchRPCifAppropriate failed because changePC() failed" << endl;
2366            if (wasRunning)
2367                (void)continueProc();
2368            return false;
2369        }
2370 #endif
2371
2372    if (!continueProc()) {
2373       cerr << "launchRPCifAppropriate: continueProc() failed" << endl;
2374       return false;
2375    }
2376
2377    return true; // success
2378 }
2379
2380 unsigned process::createRPCtempTramp(AstNode *action,
2381                                      bool noCost,
2382                                      unsigned &firstPossibBreakAddr,
2383                                      unsigned &lastPossibBreakAddr) {
2384
2385    // Returns addr of temp tramp, which was allocated in the inferoir heap.
2386    // You must free it yourself when done.
2387
2388    // Note how this is, in many ways, a greatly simplified version of
2389    // addInstFunc().
2390
2391    // Temp tramp structure: save; code; restore; trap; illegal
2392    // the illegal is just to make sure that the trap never returns
2393    // note that we may not need to save and restore anything, since we've
2394    // already done a GETREGS and we'll restore with a SETREGS, right?
2395
2396    unsigned char insnBuffer[4096];
2397    memset(insnBuffer, 0x00, sizeof(insnBuffer)); // aids debugging
2398
2399    initTramps(); // initializes "regSpace", but only the 1st time it gets called...
2400    extern registerSpace *regSpace;
2401    regSpace->resetSpace();
2402
2403    unsigned count = 0;
2404
2405    // The following is implemented in an arch-specific source file...
2406    if (!emitInferiorRPCheader(insnBuffer, count)) {
2407       // a fancy dialog box is probably called for here...
2408       cerr << "createRPCtempTramp failed because emitInferiorRPCheader failed." << endl;
2409       return NULL;
2410    }
2411
2412    reg resultReg = action->generateCode(this, regSpace,
2413                                         (char*)insnBuffer,
2414                                         count, noCost);
2415    // do we need to use the result register?
2416    regSpace->freeRegister(resultReg);
2417
2418    // Now, the trailer (restore, TRAP, illegal)
2419    // (the following is implemented in an arch-specific source file...)
2420
2421    unsigned firstPossibBreakOffset, lastPossibBreakOffset;
2422    if (!emitInferiorRPCtrailer(insnBuffer, count,
2423                                firstPossibBreakOffset, lastPossibBreakOffset)) {
2424       // last 3 args are modified by the call
2425       cerr << "createRPCtempTramp failed because emitInferiorRPCtrailer failed." << endl;
2426       return NULL;
2427    }
2428
2429    unsigned tempTrampBase = inferiorMalloc(this, count, textHeap);
2430    assert(tempTrampBase);
2431
2432    firstPossibBreakAddr = tempTrampBase + firstPossibBreakOffset;
2433    lastPossibBreakAddr = tempTrampBase + lastPossibBreakOffset;
2434
2435    /* Now, write to the tempTramp, in the inferior addr's data space
2436       (all tramps are allocated in data space) */
2437    if (!writeDataSpace((void*)tempTrampBase, count, insnBuffer)) {
2438       // should put up a nice error dialog window
2439       cerr << "createRPCtempTramp failed because writeDataSpace failed" << endl;
2440       return NULL;
2441    }
2442
2443    extern int trampBytes; // stats.h
2444    trampBytes += count;
2445
2446    return tempTrampBase;
2447 }
2448
2449 bool process::handleTrapIfDueToRPC() {
2450    // get curr PC register (can assume process is stopped), search for it in
2451    // 'currRunningRPCs'.  If found, restore regs, do callback, delete tramp, and
2452    // return true.  Returns false if not processed.
2453
2454    assert(status_ == stopped); // a TRAP should always stop a process (duh)
2455    
2456    if (currRunningRPCs.empty())
2457       return false; // no chance of a match
2458
2459    assert(currRunningRPCs.size() == 1);
2460       // it's unsafe to have > 1 RPCs going on at a time within a single process
2461
2462    // Okay, time to do a stack trace.
2463    // If we determine that the PC of a level of the back trace
2464    // falls within the bounds of [currRunningRPCs[0]'s address range],
2465    // then we assume success.  Note that we could probably narrow
2466    // it down to an EXACT address, to increase resistence to spurious
2467    // signals.
2468    Frame theFrame(this);
2469    while (true) {
2470       if (theFrame.isLastFrame())
2471          // well, we've gone as far as we can, with no match.
2472          return false;
2473
2474       // do we have a match?
2475       const int framePC = theFrame.getPC();
2476       if ((unsigned)framePC >= currRunningRPCs[0].firstPossibleBreakAddr &&
2477           (unsigned)framePC <= currRunningRPCs[0].lastPossibleBreakAddr) {
2478          // we've got a match!
2479          break;
2480       }
2481
2482       // else, backtrace 1 more level
2483       theFrame = theFrame.getPreviousStackFrameInfo(this);
2484    }
2485
2486    // Okay, we have a match.
2487    inferiorRPCinProgress theStruct = currRunningRPCs.removeByIndex(0);
2488 //   assert(theStruct.trapInstrAddr == currPCreg);
2489
2490    // step 1) restore registers:
2491    if (!restoreRegisters(theStruct.savedRegs)) {
2492       cerr << "handleTrapIfDueToRPC failed because restoreRegisters failed" << endl;
2493       assert(false);
2494    }
2495    delete [] theStruct.savedRegs;
2496
2497    // step 2) delete temp tramp
2498    vector< vector<unsigned> > pointsToCheck;
2499       // blank on purpose; deletion is safe to take place even right now
2500    inferiorFree(this, theStruct.firstInstrAddr, textHeap, pointsToCheck);
2501
2502    // step 3) invoke callback, if any
2503    if (theStruct.callbackFunc) {
2504       theStruct.callbackFunc(this, theStruct.userData);
2505    }
2506
2507    // step 4) continue process, if appropriate
2508    if (theStruct.wasRunning) {
2509       if (!continueProc())
2510          cerr << "RPC completion: continueProc failed" << endl;
2511    }
2512
2513    return true;
2514 }
2515
2516 bool process::tryToReadAndProcessBootstrapInfo() {
2517    // returns true iff we are now processing the bootstrap info.
2518    // if false is returned, there must be no side effects.
2519
2520    if (hasBootstrapped){
2521       // cerr << "hasBootstrapped is true\n";
2522       return false;
2523    }
2524
2525    string vrbleName = "DYNINST_bootstrap_info";
2526    
2527    internalSym *sym = findInternalSymbol(vrbleName, true);
2528    assert(sym);
2529
2530    Address symAddr = sym->getAddr();
2531
2532    // Read the structure; if pid 0 then not yet written!
2533    DYNINST_bootstrapStruct bs_record;
2534    if (!readDataSpace((const void*)symAddr, sizeof(bs_record), &bs_record, true)) {
2535       cerr << "tryToReadAndProcessBootstrapInfo failed because readDataSpace failed" << endl;
2536       return false;
2537    }
2538
2539    if (bs_record.pid == 0)
2540       return false;
2541
2542    string str=string("PID=") + string(bs_record.pid) + ", receiving bootstrap info...";
2543    statusLine(str.string_of());
2544
2545    process *checkProc = findProcess(bs_record.pid);
2546    assert(checkProc);
2547    assert(checkProc == this); // just to be sure
2548
2549 #ifdef SHM_SAMPLING
2550    registerInferiorAttachedSegs(bs_record.applicAttachedAt);
2551 #endif
2552    getObservedCostAddr();
2553
2554    str=string("PID=") + string(bs_record.pid) + ", calling handleStartProcess...";
2555    statusLine(str.string_of());
2556
2557    if (!handleStartProcess(this))
2558       logLine("warning: handleStartProcess failed\n");
2559
2560 // NEW: we decrement the batch mode here; the matching bump-up occurs in createProcess()
2561 tp->resourceBatchMode(false);
2562
2563
2564    str=string("PID=") + string(bs_record.pid) + ", installing default inst...";
2565    statusLine(str.string_of());
2566
2567    extern vector<instMapping*> initialRequests; // init.C
2568    installDefaultInst(this, initialRequests);
2569
2570    str=string("PID=") + string(bs_record.pid) + ", propagating mi's...";
2571    statusLine(str.string_of());
2572
2573    // propagate any metric that is already enabled to the new process.
2574    vector<metricDefinitionNode *> MIs = allMIs.values();
2575    for (unsigned j = 0; j < MIs.size(); j++) {
2576       MIs[j]->propagateMetricInstance(this);
2577    }
2578
2579 // The following is already done in createProcess, so it doesn't need to be
2580 // here, right?
2581 //   costMetric::addProcessToAll(this);
2582
2583    hasBootstrapped = true;
2584
2585    str=string("PID=") + string(bs_record.pid) + ", executing new-prog callback...";
2586    statusLine(str.string_of());
2587
2588    tp->newProgramCallbackFunc(bs_record.pid, this->arg_list, 
2589                               machineResource->part_name());
2590       // in paradyn, this will call paradynDaemon::addRunningProgram()
2591
2592    // The following call must be done before any samples are sent to
2593    // paradyn; otherwise, prepare for an assert fail.
2594
2595    const time64 currWallTime = getCurrWallTime();
2596
2597    if (!firstRecordTime) {
2598       //cerr << "process.C setting firstRecordTime to " << currWallTime << endl;
2599       firstRecordTime = currWallTime; // firstRecordTime may soon be obsolete; for now, it's used in metric.C and maybe perfStream.C
2600    }
2601    if (!::firstRecordTime) {
2602       //cerr << "process.C setting ::firstRecordTime to " << currWallTime << endl;
2603      ::firstRecordTime = currWallTime;
2604    }
2605
2606    tp->firstSampleCallback(getPid(), (double)currWallTime / 1000000.0);
2607                
2608    str=string("PID=") + string(bs_record.pid) + ", ready.";
2609    statusLine(str.string_of());
2610
2611    return true;
2612 }
2613
2614 void process::getObservedCostAddr() {
2615
2616 #ifndef SHM_SAMPLING
2617     bool err;
2618     costAddr_ = findInternalAddress("DYNINSTobsCostLow", true, err);
2619     if (err) {
2620         logLine("Internal error: unable to find addr of DYNINSTobsCostLow\n");
2621         showErrorCallback(79, "");
2622         P_abort();
2623     }
2624 #else
2625     costAddr_ = (int)getObsCostLowAddrInApplicSpace();
2626 #endif
2627 }