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