2 * Copyright (c) 1996 Barton P. Miller
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.
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.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
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.
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.
44 int pvmputenv (const char *);
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"
63 #include "dyninstAPI/h/BPatch.h"
65 #include "rtinst/h/rtinst.h"
66 #include "rtinst/h/trace.h"
67 #include "paradynd/src/perfStream.h"
68 #include "paradynd/src/costmetrics.h"
69 #include "paradynd/src/mdld.h"
70 #include "paradynd/src/main.h"
73 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
74 extern void generateMTpreamble(char *insn, unsigned &base, process *proc);
77 #include "util/h/debugOstream.h"
79 #ifdef ATTACH_DETACH_DEBUG
80 debug_ostream attach_cerr(cerr, true);
82 debug_ostream attach_cerr(cerr, false);
85 #ifdef INFERIOR_RPC_DEBUG
86 debug_ostream inferiorrpc_cerr(cerr, true);
88 debug_ostream inferiorrpc_cerr(cerr, false);
91 #ifdef SHM_SAMPLING_DEBUG
92 debug_ostream shmsample_cerr(cerr, true);
94 debug_ostream shmsample_cerr(cerr, false);
97 #ifdef FORK_EXEC_DEBUG
98 debug_ostream forkexec_cerr(cerr, true);
100 debug_ostream forkexec_cerr(cerr, false);
104 debug_ostream metric_cerr(cerr, true);
106 debug_ostream metric_cerr(cerr, false);
110 debug_ostream signal_cerr(cerr, true);
112 debug_ostream signal_cerr(cerr, false);
115 #ifdef SHAREDOBJ_DEBUG
116 debug_ostream sharedobj_cerr(cerr, true);
118 debug_ostream sharedobj_cerr(cerr, false);
121 #define FREE_WATERMARK (hp->totalFreeMemAvailable/2)
122 #define SIZE_WATERMARK 100
123 static const timeStamp MAX_WAITING_TIME=10.0;
124 static const timeStamp MAX_DELETING_TIME=2.0;
125 unsigned inferiorMemAvailable=0;
127 unsigned activeProcesses; // number of active processes
128 vector<process*> processVec;
129 string process::programName;
130 string process::pdFlavor;
131 vector<string> process::arg_list;
133 process *findProcess(int pid) { // make a public static member fn of class process
134 unsigned size=processVec.size();
135 for (unsigned u=0; u<size; u++)
136 if (processVec[u] && processVec[u]->getPid() == pid)
137 return processVec[u];
142 static unsigned numIntCounters=10000; // rather arbitrary; can we do better?
143 static unsigned numWallTimers =10000; // rather arbitrary; can we do better?
144 static unsigned numProcTimers =10000; // rather arbitrary; can we do better?
147 bool waitingPeriodIsOver()
149 static timeStamp previous=0;
154 previous=getCurrentTime(false);
158 current=getCurrentTime(false);
159 if ( (current-previous) > MAX_WAITING_TIME ) {
160 previous=getCurrentTime(false);
167 Frame::Frame(process *proc) {
170 proc->getActiveFrame(&frame_, &pc_);
172 uppermostFrame = true;
175 Frame Frame::getPreviousStackFrameInfo(process *proc) const {
177 // no prev frame exists; must return frame with 0 pc value otherwise
178 // will never break out of loop in walkStack()
179 Frame fake_frame(0,0,false);
186 Frame result(0, 0, false);
187 if (proc->readDataFromFrame(frame_, &fp, &rtn, uppermostFrame)) {
195 #if !defined(rs6000_ibm_aix4_1)
196 vector<int> process::getTOCoffsetInfo() const
200 return tmp; // this is to make the nt compiler happy! - naim
204 #if !defined(i386_unknown_nt4_0)
205 // Windows NT has its own version of the walkStack function in pdwinnt.C
206 // Note: it may not always be possible to do a correct stack walk.
207 // If it can't do a complete walk, the function should return an empty
208 // vector, which means that there was an error, and we can't walk the stack.
209 vector<Address> process::walkStack(bool noPause)
212 bool needToCont = noPause ? false : (status() == running);
214 if (!noPause && !pause()) {
215 // pause failed...give up
216 cerr << "walkStack: pause failed" << endl;
220 Address sig_addr = 0;
223 const image *sig_image = (signal_handler->file())->exec();
224 if(getBaseAddress(sig_image, sig_addr)){
225 sig_addr += signal_handler->getAddress(this);
227 sig_addr = signal_handler->getAddress(this);
229 sig_size = signal_handler->size();
230 // printf("signal_handler = %s size = %d addr = 0x%x\n",
231 // (signal_handler->prettyName()).string_of(),sig_size,sig_addr);
235 Frame currentFrame(this);
237 while (!currentFrame.isLastFrame()) {
238 Address fpNew = currentFrame.getFramePtr();
239 if (fpOld >= fpNew) { //Not moving up stack
240 if (!noPause && needToCont && !continueProc())
241 cerr << "walkStack: continueProc failed" << endl;
242 vector<Address> ev; //Empty vector
247 Address next_pc = currentFrame.getPC();
248 // printf("currentFrame pc = %d\n",next_pc);
250 // is this pc in the signal_handler function?
251 if(signal_handler && (next_pc >= sig_addr)
252 && (next_pc < (sig_addr+sig_size))){
253 // check to see if a leaf function was executing when the signal
254 // handler was called. If so, then an extra frame should be added
255 // for the leaf function...the call to getPreviousStackFrameInfo
256 // will get the function that called the leaf function
258 if(this->needToAddALeafFrame(currentFrame,leaf_pc)){
262 currentFrame = currentFrame.getPreviousStackFrameInfo(this);
264 pcs += currentFrame.getPC();
266 if (!noPause && needToCont) {
267 if (!continueProc()){
268 cerr << "walkStack: continueProc failed" << endl;
275 // disItem is generally unchanged and was previously declared const,
276 // however, the heap management occasionally deletes such items
277 // so it's now no longer const'd
278 bool isFreeOK(process *proc, disabledItem &disItem, vector<Address> &pcs) {
279 const unsigned disItemPointer = disItem.getPointer();
280 const inferiorHeapType disItemHeap = disItem.getHeapType();
282 #if defined(hppa1_1_hp_hpux)
283 if (proc->freeNotOK) return(false);
287 if (!proc->heaps[disItemHeap].heapActive.find(disItemPointer, ptr)) {
288 sprintf(errorLine,"Warning: attempt to free not defined heap entry "
289 "%x (pid=%d, heapActive.size()=%d)\n",
290 disItemPointer, proc->getPid(),
291 proc->heaps[disItemHeap].heapActive.size());
293 //showErrorCallback(67, (const char *)errorLine);
299 sprintf(errorLine, "isFreeOK called on 0x%x\n", ptr->addr);
303 // the following can't be const; we're sometimes gonna change it
304 vector<unsigVecType> &disItemPoints = disItem.getPointsToCheck();
306 const unsigned disItemNumPoints = disItemPoints.size();
308 for (unsigned int j=0;j<disItemNumPoints;j++) {
309 for (unsigned int k=0;k<disItemPoints[j].size();k++) {
310 unsigned pointer = disItemPoints[j][k];
312 if (disItemHeap == dataHeap)
313 sprintf(errorLine, "checking DATA pointer 0x%x\n", pointer);
315 sprintf(errorLine, "checking TEXT pointer 0x%x\n", pointer);
319 const dictionary_hash<unsigned, heapItem*> &heapActivePart =
320 proc->splitHeaps ? proc->heaps[textHeap].heapActive :
321 proc->heaps[dataHeap].heapActive;
324 if (!heapActivePart.find(pointer, np)) { // fills in "np" if found
326 sprintf(errorLine, "something freed addr 0x%x from us\n", pointer);
331 // This point was deleted already and we don't need it anymore in
334 const int size=disItemPoints[j].size();
335 disItemPoints[j][k] = disItemPoints[j][size-1];
336 disItemPoints[j].resize(size-1);
338 // need to make sure we check the next item too
343 if ( (ptr->addr >= np->addr) &&
344 (ptr->addr <= (np->addr + np->length)) )
348 sprintf(errorLine,"*** TEST *** IN isFreeOK: (1) we found 0x%x in our inst. range!\n",ptr->addr);
355 for (unsigned int l=0;l<pcs.size();l++) {
357 if ((pcs[l] >= ptr->addr) &&
358 (pcs[l] <= (ptr->addr + ptr->length)))
362 sprintf(errorLine,"*** TEST *** IN isFreeOK: (2) we found 0x%x in our inst. range!\n", ptr->addr);
369 if ( ((pcs[l] >= np->addr) && (pcs[l] <= (np->addr + np->length))) )
373 sprintf(errorLine,"*** TEST *** IN isFreeOK: (3) we found PC in our inst. range!\n");
387 // This procedure will try to compact the framented memory available in
388 // heapFree. This is an emergency procedure that will be called if we
389 // are running out of memory to insert instrumentation - naim
391 void inferiorFreeCompact(inferiorHeap *hp)
395 size = hp->heapFree.size();
399 logLine("***** Trying to compact freed memory...\n");
403 np = hp->heapFree[i];
405 sprintf(errorLine,"***** Checking address=%d\n",ALIGN_TO_WORDSIZE(np->addr+np->length));
408 for (j=0; j < size; j++) {
410 if ( (np->addr+np->length)==(hp->heapFree[j])->addr )
412 np->length += (hp->heapFree[j])->length;
413 hp->heapFree[j] = hp->heapFree[size-1];
414 hp->heapFree.resize(size-1);
415 size = hp->heapFree.size();
417 sprintf(errorLine,"***** Compacting free memory (%d bytes, i=%d, j=%d, heapFree.size=%d)\n",np->length,i,j,size);
428 for (i=0;i<hp->disabledList.size();i++) {
429 for (j=i+1;j<hp->disabledList.size();j++) {
430 if ( (hp->disabledList[i]).getPointer() ==
431 (hp->disabledList[j]).getPointer() ) {
432 sprintf(errorLine,"***** ERROR: address 0x%x appears more than once\n",(hp->disabledList[j]).getPointer());
440 logLine("***** Compact memory procedure END...\n");
444 void inferiorFreeDefered(process *proc, inferiorHeap *hp, bool runOutOfMem)
448 vector<disabledItem> *disList;
449 timeStamp initTime, maxDelTime;
451 pcs = proc->walkStack();
453 #if defined(i386_unknown_nt4_0)
454 // It may not always be possible to get a correct stack walk.
455 // If walkStack fails, it returns an empty vector. In this
456 // case, we assume that it is not safe to delete anything
461 // this is a while loop since we don't update i if an item is deleted.
462 disList = &hp->disabledList;
464 maxDelTime = MAX_DELETING_TIME*2.0;
465 sprintf(errorLine,"Emergency attempt to free memory (pid=%d). Please, wait...\n",proc->getPid());
468 sprintf(errorLine,"***** disList.size() = %d\n",disList->size());
473 maxDelTime = MAX_DELETING_TIME;
474 initTime=getCurrentTime(false);
475 while ( (i < disList->size()) &&
476 ((getCurrentTime(false)-initTime) < maxDelTime) )
478 disabledItem &item = (*disList)[i];
479 if (isFreeOK(proc,item,pcs)) {
481 unsigned pointer = item.getPointer();
482 if (!hp->heapActive.find(pointer,np)) {
483 showErrorCallback(96,"");
488 if (np->status != HEAPallocated) {
489 sprintf(errorLine,"Attempt to free already freed heap entry %x\n", pointer);
491 showErrorCallback(67, (const char *)errorLine);
494 np->status = HEAPfree;
496 // remove from active list.
497 hp->heapActive.undef(pointer);
500 sprintf(errorLine,"inferiorFreeDefered: deleting 0x%x from heap\n",pointer);
505 hp->freed += np->length;
507 // updating disabledList
508 hp->disabledList[i]=hp->disabledList[hp->disabledList.size()-1];
509 hp->disabledList.resize(hp->disabledList.size()-1);
510 hp->disabledListTotalMem -= np->length;
511 hp->totalFreeMemAvailable += np->length;
512 inferiorMemAvailable = hp->totalFreeMemAvailable;
519 void process::initInferiorHeap(bool initTextHeap)
521 assert(this->symbols);
525 hp = &this->heaps[textHeap];
527 hp = &this->heaps[dataHeap];
530 heapItem *np = new heapItem;
533 np->addr = findInternalAddress("DYNINSTtext", true,err);
538 np->addr = findInternalAddress(INFERIOR_HEAP_BASE, true, err);
542 np->length = SYN_INST_BUF_SIZE;
543 np->status = HEAPfree;
545 // make the heap double-word aligned
546 Address base = np->addr & ~0x1f;
547 Address diff = np->addr - base;
549 np->addr = base + 32;
550 np->length -= (32 - diff);
553 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
555 hp->size = np->length;
556 #endif /* BPATCH_SET_MUTATIONS_ACTIVE */
558 hp->totalFreeMemAvailable = np->length;
559 inferiorMemAvailable = hp->totalFreeMemAvailable;
561 // need to clear everything here, since this function may be called to
563 hp->heapActive.clear();
564 hp->heapFree.resize(0);
566 hp->disabledList.resize(0);
567 hp->disabledListTotalMem = 0;
571 // create a new inferior heap that is a copy of src. This is used when a process
572 // we are tracing forks.
573 inferiorHeap::inferiorHeap(const inferiorHeap &src):
574 heapActive(addrHash16)
576 for (unsigned u1 = 0; u1 < src.heapFree.size(); u1++) {
577 heapFree += new heapItem(src.heapFree[u1]);
580 vector<heapItem *> items = src.heapActive.values();
581 for (unsigned u2 = 0; u2 < items.size(); u2++) {
582 heapActive[items[u2]->addr] = new heapItem(items[u2]);
585 for (unsigned u3 = 0; u3 < src.disabledList.size(); u3++) {
586 disabledList += src.disabledList[u3];
588 disabledListTotalMem = src.disabledListTotalMem;
589 totalFreeMemAvailable = src.totalFreeMemAvailable;
590 inferiorMemAvailable = totalFreeMemAvailable;
595 void printHeapFree(process *proc, inferiorHeap *hp, int size)
597 for (unsigned i=0; i < hp->heapFree.size(); i++) {
598 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);
605 // This function will return the index corresponding to the next position
606 // available in heapFree.
608 bool findFreeIndex(inferiorHeap *hp, int size, unsigned *index)
610 bool foundFree=false;
613 for (unsigned i=0; i < hp->heapFree.size(); i++) {
614 length = (hp->heapFree[i])->length;
615 if (length >= size) {
628 unsigned inferiorMalloc(process *proc, int size, inferiorHeapType type)
631 heapItem *np=NULL, *newEntry = NULL;
634 /* round to next cache line size */
635 /* 32 bytes on a SPARC */
636 size = (size + 0x1f) & ~0x1f;
638 if ((type == textHeap) && (proc->splitHeaps)) {
639 hp = &proc->heaps[textHeap];
641 hp = &proc->heaps[dataHeap];
644 bool secondChance=false;
646 if (!findFreeIndex(hp,size,&foundIndex)) {
649 sprintf(errorLine,"==> TEST <== In inferiorMalloc: heap overflow, calling inferiorFreeDefered for a second chance...\n");
653 inferiorFreeDefered(proc, hp, true);
654 inferiorFreeCompact(hp);
658 if (secondChance && !findFreeIndex(hp,size,&foundIndex)) {
661 printHeapFree(proc,hp,size);
664 sprintf(errorLine, "***** Inferior heap overflow: %d bytes freed, %d bytes requested\n", hp->freed, size);
666 showErrorCallback(66, (const char *) errorLine);
672 // We must have found a free position in heapFree
675 np = hp->heapFree[foundIndex];
677 if (np->length != size) {
679 newEntry = new heapItem;
680 newEntry->length = np->length - size;
681 newEntry->addr = np->addr + size;
682 hp->totalFreeMemAvailable -= size;
683 inferiorMemAvailable = hp->totalFreeMemAvailable;
684 // overwrite the old entry
685 hp->heapFree[foundIndex] = newEntry;
690 unsigned i = hp->heapFree.size();
691 // copy the last element over this element
692 hp->heapFree[foundIndex] = hp->heapFree[i-1];
693 hp->heapFree.resize(i-1);
697 np->status = HEAPallocated;
700 hp->heapActive[np->addr] = np;
702 // make sure its a valid pointer.
708 void inferiorFree(process *proc, unsigned pointer, inferiorHeapType type,
709 const vector<unsigVecType> &pointsToCheck)
711 inferiorHeapType which = (type == textHeap && proc->splitHeaps) ? textHeap : dataHeap;
712 inferiorHeap *hp = &proc->heaps[which];
715 if (!hp->heapActive.find(pointer, np)) {
716 showErrorCallback(96,"");
721 disabledItem newItem(pointer, which, pointsToCheck);
724 for (unsigned i=0;i<hp->disabledList.size();i++) {
725 if (hp->disabledList[i].getPointer() == pointer) {
726 sprintf(errorLine,"***** ERROR, pointer 0x%x already defined in disabledList\n",pointer);
732 hp->disabledList += newItem;
733 hp->disabledListTotalMem += np->length;
736 sprintf(errorLine,"==> TEST <== In inferiorFree: disabledList has %d items, %d bytes, and FREE_WATERMARK is %d\n",hp->disabledList.size(),hp->disabledListTotalMem,FREE_WATERMARK);
738 for (unsigned i=0; i < hp->disabledList.size(); i++) {
739 sprintf(errorLine, " %x is on list\n", hp->disabledList[i].pointer);
745 // If the size of the disabled instrumentation list is greater than
746 // half of the size of the heapFree list, then we attempt to free
747 // all the defered requests. In my opinion, this seems to be a good
748 // time to proceed with the defered delete since this is an expensive
749 // procedure and should not be executed often - naim 03/19/96
751 if (((hp->disabledListTotalMem > FREE_WATERMARK) ||
752 (hp->disabledList.size() > SIZE_WATERMARK)) && waitingPeriodIsOver())
757 static timeStamp t3=0.0;
758 static timeStamp totalTime=0.0;
759 static timeStamp worst=0.0;
760 static int counter=0;
761 t1=getCurrentTime(false);
764 inferiorFreeDefered(proc, hp, false);
767 t2=getCurrentTime(false);
771 if ((t2-t1) > worst) worst=t2-t1;
772 if ((float)(t2-t1) > 1.0) {
773 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));
783 // initializes all DYNINST lib stuff: init the inferior heap and check for
785 // This is only called after we get the first breakpoint (SIGTRAP), because
786 // the DYNINST lib can be dynamically linked (currently it is only dynamically
787 // linked on Windows NT)
788 bool process::initDyninstLib() {
790 #if defined(i386_unknown_nt4_0)
792 Kludge for Windows NT: we need to call waitProcs here so that
793 we can load libdyninstRT when we attach to an already running
794 process. The solution to avoid this kludge is to divide
795 attachProcess in two parts: first we attach to a process,
796 and later, after libdyninstRT has been loaded,
797 we install the call to DYNINSTinit.
800 // libDyninstRT should already be loaded when we get here,
801 // except if the process was created via attach
802 if (createdViaAttach) {
803 // need to set reachedFirstBreak to false here, so that
804 // libdyninstRT gets loaded in waitProcs.
805 reachedFirstBreak = false;
806 while (!hasLoadedDyninstLib) {
811 assert(hasLoadedDyninstLib);
815 extern vector<sym_data> syms_to_find;
816 if (!heapIsOk(syms_to_find))
819 initInferiorHeap(false);
821 initInferiorHeap(true);
829 // Process "normal" (non-attach, non-fork) ctor, for when a new process
830 // is fired up by paradynd itself.
833 process::process(int iPid, image *iImage, int iTraceLink, int iIoLink
836 const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
840 pid(iPid) // needed in fastInferiorHeap ctors below
843 inferiorHeapMgr(theShmKey, iShmHeapStats, iPid),
845 iShmHeapStats[0].maxNumElems,
846 iShmHeapStats[1].maxNumElems,
847 iShmHeapStats[2].maxNumElems)
850 hasBootstrapped = false;
851 save_exitset_ptr = NULL;
853 // the next two variables are used only if libdyninstRT is dynamically linked
854 hasLoadedDyninstLib = false;
855 isLoadingDyninstLib = false;
857 reachedFirstBreak = false; // haven't yet seen first trap
858 reachedVeryFirstTrap = false;
859 createdViaAttach = false;
860 needToContinueAfterDYNINSTinit = false; //Wait for press of "RUN" button
863 mainFunction = NULL; // set in platform dependent function heapIsOk
866 continueAfterNextStop_ = false;
867 deferredContinueProc = false;
869 #ifndef BPATCH_LIBRARY
870 string buffer = string(pid) + string("_") + getHostName();
871 rid = resource::newResource(processResource, // parent
872 (void*)this, // handle
873 nullString, // abstraction
874 iImage->name(), // process name
875 0.0, // creation time
876 buffer, // unique name (?)
877 MDL_T_STRING, // mdl type (?)
893 memset(trampTable, 0, sizeof(trampTable));
897 dynamiclinking = false;
898 dyn = new dynamic_linking;
904 waiting_for_resources = false;
909 #ifdef sparc_sun_sunos4_1_3
910 kvmHandle = kvm_open(0, 0, 0, O_RDONLY, 0);
911 if (kvmHandle == NULL) {
912 perror("could not map child's uarea; kvm_open");
916 // childUareaPtr = tryToMapChildUarea(iPid);
917 childUareaPtr = NULL;
923 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
924 // XXXX - move this to a machine dependant place.
926 // create a seperate text heap.
927 //initInferiorHeap(true);
931 traceLink = iTraceLink;
934 RPCs_waiting_for_syscall_to_complete = false;
936 // attach to the child process (machine-specific implementation)
937 attach(); // error check?
941 // Process "attach" ctor, for when paradynd is attaching to an already-existing
945 process::process(int iPid, image *iSymbols,
946 int afterAttach, // 1 --> pause, 2 --> run, 0 --> leave as is
950 const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
957 inferiorHeapMgr(theShmKey, iShmHeapStats, iPid),
959 iShmHeapStats[0].maxNumElems,
960 iShmHeapStats[1].maxNumElems,
961 iShmHeapStats[2].maxNumElems)
964 RPCs_waiting_for_syscall_to_complete = false;
965 save_exitset_ptr = NULL;
967 hasBootstrapped = false;
968 reachedFirstBreak = true; // the initial trap of program entry was passed long ago...
969 reachedVeryFirstTrap = true;
970 createdViaAttach = true;
972 // the next two variables are used only if libdyninstRT is dynamically linked
973 hasLoadedDyninstLib = false;
974 isLoadingDyninstLib = false;
977 mainFunction = NULL; // set in platform dependent function heapIsOk
980 continueAfterNextStop_ = false;
981 deferredContinueProc = false;
983 #ifndef BPATCH_LIBRARY
984 string buffer = string(pid) + string("_") + getHostName();
985 rid = resource::newResource(processResource, // parent
986 (void*)this, // handle
987 nullString, // abstraction
989 0.0, // creation time
990 buffer, // unique name (?)
991 MDL_T_STRING, // mdl type (?)
1006 trampTableItems = 0;
1007 memset(trampTable, 0, sizeof(trampTable));
1011 dynamiclinking = false;
1012 dyn = new dynamic_linking;
1018 waiting_for_resources = false;
1024 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
1025 // XXXX - move this to a machine dependant place.
1027 // create a seperate text heap.
1028 //initInferiorHeap(true);
1032 traceLink = -1; // will be set later, when the appl runs DYNINSTinit
1034 ioLink = -1; // (ARGUABLY) NOT YET IMPLEMENTED...MAYBE WHEN WE ATTACH WE DON'T WANT
1035 // TO REDIRECT STDIO SO WE CAN LEAVE IT AT -1.
1037 // Now the actual attach...the moment we've all been waiting for
1039 attach_cerr << "process attach ctor: about to attach to pid " << getPid() << endl;
1041 // It is assumed that a call to attach() doesn't affect the running status
1042 // of the process. But, unfortunately, some platforms may barf if the
1043 // running status is anything except paused. (How to deal with this?)
1044 // Note that solaris in particular seems able to attach even if the process
1047 showErrorCallback(26, ""); // unable-to-attach
1052 #if defined(BPATCH_LIBRARY) && defined(rs6000_ibm_aix4_1)
1053 wasRunningWhenAttached = false; /* XXX Or should the default be true? */
1055 wasRunningWhenAttached = isRunning_();
1058 #if defined(BPATCH_LIBRARY) && defined(rs6000_ibm_aix4_1)
1059 // We use ptrace of AIX, which stops the process on attach.
1062 // Note: we used to pause the program here, but not anymore.
1066 #ifdef i386_unknown_nt4_0 // Except we still pause on NT.
1071 if (afterAttach == 0)
1072 needToContinueAfterDYNINSTinit = wasRunningWhenAttached;
1073 else if (afterAttach == 1)
1074 needToContinueAfterDYNINSTinit = false;
1075 else if (afterAttach == 2)
1076 needToContinueAfterDYNINSTinit = true;
1080 // Does attach() send a SIGTRAP, a la the initial SIGTRAP sent at the
1081 // end of exec? It seems that on some platforms it does; on others
1082 // it doesn't. Ick. On solaris, it doesn't.
1084 // note: we don't call getSharedObjects() yet; that happens once DYNINSTinit
1085 // finishes (handleStartProcess)
1087 // Everything worked
1092 // Process "fork" ctor, for when a process which is already being monitored by
1093 // paradynd executes the fork syscall.
1096 process::process(const process &parentProc, int iPid, int iTrace_fd
1099 void *applShmSegPtr,
1100 const vector<fastInferiorHeapMgr::oneHeapStats> &iShmHeapStats
1103 baseMap(ipHash) // could change to baseMap(parentProc.baseMap)
1106 inferiorHeapMgr(parentProc.inferiorHeapMgr,
1108 theShmKey, iShmHeapStats, iPid)
1109 ,theSuperTable(parentProc.getTable(),this)
1112 // This is the "fork" ctor
1114 RPCs_waiting_for_syscall_to_complete = false;
1115 save_exitset_ptr = NULL;
1117 hasBootstrapped = false;
1118 // The child of fork ("this") has yet to run DYNINSTinit.
1120 // the next two variables are used only if libdyninstRT is dynamically linked
1121 hasLoadedDyninstLib = false; // TODO: is this the right value?
1122 isLoadingDyninstLib = false;
1124 createdViaAttach = parentProc.createdViaAttach;
1125 wasRunningWhenAttached = true;
1126 needToContinueAfterDYNINSTinit = true;
1128 symbols = parentProc.symbols; // shouldn't a reference count also be bumped?
1129 mainFunction = parentProc.mainFunction;
1131 traceLink = iTrace_fd;
1133 ioLink = -1; // when does this get set?
1135 status_ = neonatal; // is neonatal right?
1136 continueAfterNextStop_ = false;
1137 deferredContinueProc = false;
1141 #ifndef BPATCH_LIBRARY
1142 string buffer = string(pid) + string("_") + getHostName();
1143 rid = resource::newResource(processResource, // parent
1144 (void*)this, // handle
1145 nullString, // abstraction
1146 parentProc.symbols->name(),
1147 0.0, // creation time
1148 buffer, // unique name (?)
1149 MDL_T_STRING, // mdl type (?)
1154 parent = &parentProc;
1159 reachedFirstBreak = true; // initial TRAP has (long since) been reached
1160 reachedVeryFirstTrap = true;
1162 splitHeaps = parentProc.splitHeaps;
1164 heaps[0] = inferiorHeap(parentProc.heaps[0]);
1165 heaps[1] = inferiorHeap(parentProc.heaps[1]);
1174 trampTableItems = 0;
1175 memset(trampTable, 0, sizeof(trampTable));
1179 dynamiclinking = parentProc.dynamiclinking;
1180 dyn = new dynamic_linking;
1181 *dyn = *parentProc.dyn;
1185 // make copy of parent's shared_objects vector
1186 if (parentProc.shared_objects) {
1187 shared_objects = new vector<shared_object*>;
1188 for (unsigned u1 = 0; u1 < parentProc.shared_objects->size(); u1++){
1190 new shared_object(*(*parentProc.shared_objects)[u1]);
1195 if (parentProc.all_functions) {
1196 all_functions = new vector<function_base *>;
1197 for (unsigned u2 = 0; u2 < parentProc.all_functions->size(); u2++)
1198 *all_functions += (*parentProc.all_functions)[u2];
1202 if (parentProc.all_modules) {
1203 all_modules = new vector<module *>;
1204 for (unsigned u3 = 0; u3 < parentProc.all_modules->size(); u3++)
1205 *all_modules += (*parentProc.all_modules)[u3];
1209 if (parentProc.some_modules) {
1210 some_modules = new vector<module *>;
1211 for (unsigned u4 = 0; u4 < parentProc.some_modules->size(); u4++)
1212 *some_modules += (*parentProc.some_modules)[u4];
1216 if (parentProc.some_functions) {
1217 some_functions = new vector<function_base *>;
1218 for (unsigned u5 = 0; u5 < parentProc.some_functions->size(); u5++)
1219 *some_functions += (*parentProc.some_functions)[u5];
1222 waiting_for_resources = false;
1223 signal_handler = parentProc.signal_handler;
1227 for (unsigned i=0; i<parentProc.threads.size(); i++) {
1228 threads += new pdThread(this,parentProc.threads[i]);
1231 #if defined(SHM_SAMPLING) && defined(sparc_sun_sunos4_1_3)
1232 childUareaPtr = NULL;
1235 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1236 // thread mapping table
1237 threadMap = new hashTable(parentProc.threadMap);
1240 if (!attach()) { // moved from ::forkProcess
1241 showErrorCallback(69, "Error in fork: cannot attach to child process");
1245 // would neonatal be more appropriate? Nah, we've reached the first trap
1249 void process::registerInferiorAttachedSegs(void *inferiorAttachedAtPtr) {
1250 shmsample_cerr << "process pid " << getPid() << ": welcome to register with inferiorAttachedAtPtr=" << inferiorAttachedAtPtr << endl;
1252 inferiorHeapMgr.registerInferiorAttachedAt(inferiorAttachedAtPtr);
1253 theSuperTable.setBaseAddrInApplic(0,(intCounter*) inferiorHeapMgr.getSubHeapInApplic(0));
1254 theSuperTable.setBaseAddrInApplic(1,(tTimer*) inferiorHeapMgr.getSubHeapInApplic(1));
1255 theSuperTable.setBaseAddrInApplic(2,(tTimer*) inferiorHeapMgr.getSubHeapInApplic(2));
1260 extern bool forkNewProcess(string file, string dir, vector<string> argv,
1261 vector<string>envp, string inputFile, string outputFile,
1262 int &traceLink, int &ioLink,
1264 int &procHandle, int &thrHandle);
1267 * Create a new instance of the named process. Read the symbols and start
1270 process *createProcess(const string File, vector<string> argv, vector<string> envp, const string dir = "")
1272 // prepend the directory (if any) to the file, unless the filename
1275 if (!file.prefixed_by("/") && dir.length() > 0)
1276 file = dir + "/" + file;
1278 #if defined(BPATCH_LIBRARY) && !defined(BPATCH_REDIRECT_IO)
1282 // check for I/O redirection in arg list.
1284 for (unsigned i1=0; i1<argv.size(); i1++) {
1285 if (argv[i1] == "<") {
1286 inputFile = argv[i1+1];
1287 for (unsigned j=i1+2, k=i1; j<argv.size(); j++, k++)
1289 argv.resize(argv.size()-2);
1292 // TODO -- this assumes no more than 1 of each "<", ">"
1294 for (unsigned i2=0; i2<argv.size(); i2++) {
1295 if (argv[i2] == ">") {
1296 outputFile = argv[i2+1];
1297 for (unsigned j=i2+2, k=i2; j<argv.size(); j++, k++)
1299 argv.resize(argv.size()-2);
1302 #endif /* BPATCH_LIBRARY */
1311 if (!forkNewProcess(file, dir, argv, envp, inputFile, outputFile,
1312 traceLink, ioLink, pid, tid, procHandle, thrHandle)) {
1313 // forkNewProcess is resposible for displaying error messages
1317 #ifdef BPATCH_LIBRARY
1318 // Register the pid with the BPatch library (not yet associated with a
1319 // BPatch_thread object).
1320 assert(BPatch::bpatch != NULL);
1321 BPatch::bpatch->registerProvisionalThread(pid);
1324 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
1325 extern bool establishBaseAddrs(int pid, int &status, bool waitForTrap);
1328 if (!establishBaseAddrs(pid, status, true)) {
1333 #ifndef BPATCH_LIBRARY
1334 // NEW: We bump up batch mode here; the matching bump-down occurs after shared objects
1335 // are processed (after receiving the SIGSTOP indicating the end of running
1336 // DYNINSTinit; more specifically, procStopFromDYNINSTinit().
1337 // Prevents a diabolical w/w deadlock on solaris --ari
1338 tp->resourceBatchMode(true);
1339 #endif /* BPATCH_LIBRARY */
1341 image *img = image::parseImage(file);
1343 // For better error reporting, two failure return values would be useful
1344 // One for simple error like because-file-not-because
1345 // Another for serious errors like found-but-parsing-failed (internal error;
1346 // please report to paradyn@cs.wisc.edu)
1348 string msg = string("Unable to parse image: ") + file;
1349 showErrorCallback(68, msg.string_of());
1350 // destroy child process
1357 statusLine("initializing process data structures");
1360 vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
1361 theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
1362 theShmHeapStats[0].maxNumElems = numIntCounters;
1364 theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
1365 theShmHeapStats[1].maxNumElems = numWallTimers;
1367 theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
1368 theShmHeapStats[2].maxNumElems = numProcTimers;
1371 process *ret = new process(pid, img, traceLink, ioLink
1373 , 7000, // shm seg key to try first
1377 // change this to a ctor that takes in more args
1384 #ifndef BPATCH_LIBRARY
1385 if (!costMetric::addProcessToAll(ret))
1388 // find the signal handler function
1389 ret->findSignalHandler(); // should this be in the ctor?
1391 // initializing vector of threads - thread[0] is really the
1394 #if defined(i386_unknown_nt4_0)
1395 ret->threads += new pdThread(ret, tid, (handleT)thrHandle);
1397 ret->threads += new pdThread(ret);
1400 // initializing hash table for threads. This table maps threads to
1401 // positions in the superTable - naim 4/14/97
1402 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
1403 ret->threadMap = new hashTable(MAX_NUMBER_OF_THREADS,1,0);
1406 // we use this flag to solve race condition between inferiorRPC and
1407 // continueProc message from paradyn - naim
1408 ret->deferredContinueProc = false;
1410 ret->numOfActCounters_is=0;
1411 ret->numOfActProcTimers_is=0;
1412 ret->numOfActWallTimers_is=0;
1414 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
1415 // XXXX - this is a hack since establishBaseAddrs needed to wait for
1417 // We really need to move most of the above code (esp parse image)
1418 // to the TRAP signal handler. The problem is that we don't
1419 // know the base addresses until we get the load info via ptrace.
1420 // In general it is even harder, since dynamic libs can be loaded
1422 extern int handleSigChild(int pid, int status);
1424 (void) handleSigChild(pid, status);
1431 void process::DYNINSTinitCompletionCallback(process *theProc,
1432 void *, // user data
1433 unsigned // return value from DYNINSTinit
1435 attach_cerr << "Welcome to DYNINSTinitCompletionCallback" << endl;
1436 theProc->handleCompletionOfDYNINSTinit(true);
1440 bool attachProcess(const string &progpath, int pid, int afterAttach
1441 #ifdef BPATCH_LIBRARY
1442 , process *&newProcess
1445 // implementation of dynRPC::attach() (the igen call)
1446 // This is meant to be "the other way" to start a process (competes w/ createProcess)
1448 // progpath gives the full path name of the executable, which we use ONLY to
1449 // read the symbol table.
1451 // We try to make progpath optional, since given pid, we should be able to
1452 // calculate it with a clever enough search of the process' PATH, examining
1453 // its argv[0], examining its current directory, etc. /proc gives us this
1454 // information on solaris...not sure about other platforms...
1456 // possible values for afterAttach: 1 --> pause, 2 --> run, 0 --> leave as is
1458 attach_cerr << "welcome to attachProcess for pid " << pid << endl;
1460 // QUESTION: When we attach to a process, do we want to redirect its stdout/stderr
1461 // (like we do when we fork off a new process the 'usual' way)?
1462 // My first guess would be no. -ari
1463 // But although we may ignore the io, we still need the trace stream.
1465 // When we attach to a process, we don't fork...so this routine is much simpler
1466 // than its "competitor", createProcess() (above).
1468 // TODO: What about AIX establishBaseAddrs??? Do that now?
1470 string fullPathToExecutable = process::tryToFindExecutable(progpath, pid);
1471 if (!fullPathToExecutable.length())
1474 #ifndef BPATCH_LIBRARY
1475 tp->resourceBatchMode(true);
1476 // matching bump-down occurs in procStopFromDYNINSTinit().
1479 image *theImage = image::parseImage(fullPathToExecutable);
1480 if (theImage == NULL) {
1481 // two failure return values would be useful here, to differentiate
1482 // file-not-found vs. catastrophic-parse-error.
1483 string msg = string("Unable to parse image: ") + fullPathToExecutable;
1484 showErrorCallback(68, msg.string_of());
1485 return false; // failure
1489 vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
1490 theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
1491 theShmHeapStats[0].maxNumElems = numIntCounters;
1493 theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
1494 theShmHeapStats[1].maxNumElems = numWallTimers;
1496 theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
1497 theShmHeapStats[2].maxNumElems = numProcTimers;
1500 // NOTE: the actual attach happens in the process "attach" constructor:
1502 process *theProc = new process(pid, theImage, afterAttach, success
1504 ,7000, // shm seg key to try first
1510 // XXX Do we need to do something to get rid of theImage, too?
1515 // Note: it used to be that the attach ctor called pause()...not anymore...so
1516 // the process is probably running even as we speak.
1518 processVec += theProc;
1521 theProc->threads += new pdThread(theProc);
1523 #if defined(USES_LIBDYNINSTRT_SO)
1524 // we now need to dynamically load libdyninstRT.so.1 - naim
1525 if (theProc->handleStartProcess()) {
1526 if (!theProc->pause()) {
1527 logLine("WARNING: pause failed\n");
1530 theProc->dlopenDYNINSTlib();
1531 // this will set isLoadingDyninstLib to true - naim
1532 if (!theProc->continueProc()) {
1533 logLine("WARNING: continueProc failed\n");
1537 while (!theProc->dyninstLibAlreadyLoaded()) {
1538 theProc->waitProcs(&status);
1543 theProc->initDyninstLib();
1545 #ifndef BPATCH_LIBRARY
1546 if (!costMetric::addProcessToAll(theProc))
1550 // find the signal handler function
1551 theProc->findSignalHandler(); // shouldn't this be in the ctor?
1553 // Now force DYNINSTinit() to be invoked, via inferiorRPC.
1554 string buffer = string("PID=") + string(pid) + ", running DYNINSTinit()...";
1555 statusLine(buffer.string_of());
1557 #ifdef BPATCH_LIBRARY
1558 newProcess = theProc;
1560 vector<AstNode*> the_args(2);
1562 the_args[0] = new AstNode(AstNode::Constant, (void*)3);
1563 the_args[1] = new AstNode(AstNode::Constant, (void*)getpid());
1564 #else /* BPATCH_LIBRARY */
1565 attach_cerr << "calling DYNINSTinit with args:" << endl;
1567 vector<AstNode*> the_args(3);
1570 the_args[0] = new AstNode(AstNode::Constant,
1571 (void*)(theProc->getShmKeyUsed()));
1572 attach_cerr << theProc->getShmKeyUsed() << endl;
1574 const unsigned shmHeapTotalNumBytes = theProc->getShmHeapTotalNumBytes();
1575 the_args[1] = new AstNode(AstNode::Constant,
1576 (void*)shmHeapTotalNumBytes);
1577 attach_cerr << shmHeapTotalNumBytes << endl;;
1579 // 2 dummy args when not shm sampling -- just make sure they're not both -1, which
1580 // would indicate that we're called from fork
1581 the_args[0] = new AstNode(AstNode::Constant, (void*)0);
1582 the_args[1] = new AstNode(AstNode::Constant, (void*)0);
1586 The third argument to DYNINSTinit is our (paradynd's) pid. It is used
1587 by DYNINSTinit to build the socket path to which it connects to in order
1588 to get the trace-stream connection. We make it negative to indicate
1589 to DYNINSTinit that it's being called from attach (sorry for that little
1590 kludge...if we didn't have it, we'd probably need to boost DYNINSTinit
1591 from 3 to 4 parameters).
1593 This socket is set up in controllerMainLoop (perfStream.C).
1595 the_args[2] = new AstNode(AstNode::Constant, (void*)(-1 * traceConnectInfo));
1596 attach_cerr << (-1* getpid()) << endl;
1597 #endif /* BPATCH_LIBRARY */
1599 AstNode *the_ast = new AstNode("DYNINSTinit", the_args);
1600 for (unsigned j=0;j<the_args.size();j++) removeAst(the_args[j]);
1602 theProc->postRPCtoDo(the_ast,
1603 true, // true --> don't try to update cost yet
1604 process::DYNINSTinitCompletionCallback, // callback routine
1606 -1); // we use -1 if this is not metric definition - naim
1607 // the rpc will be launched with a call to launchRPCifAppropriate()
1608 // in the main loop (perfStream.C).
1609 // DYNINSTinit() ends with a DYNINSTbreakPoint(), so we pick up
1610 // where we left off in the processing of the forwarded SIGSTOP signal.
1611 // In other words, there's lots more work to do, but since we can't do it until
1612 // DYNINSTinit has run, we wait until the SIGSTOP is forwarded.
1614 // Note: we used to pause() the process while attaching. Not anymore.
1615 // The attached process is running even as we speak. (Though we'll interrupt
1616 // it pretty soon when the inferior RPC of DYNINSTinit gets launched).
1618 return true; // successful
1622 bool process::doMajorShmSample(time64 theWallTime) {
1623 bool result = true; // will be set to false if any processAll() doesn't complete
1626 if (!theSuperTable.doMajorSample (theWallTime, 0))
1628 // inferiorProcessTimers used to take in a non-dummy process time as the
1629 // 2d arg, but it looks like that we need to re-read the process time for
1630 // each proc timer, at the time of sampling the timer's value, to avoid
1631 // ugly jagged spikes in histogram (i.e. to avoid incorrect sampled
1632 // values). Come to think of it: the same may have to be done for the
1635 const time64 theProcTime = getInferiorProcessCPUtime();
1637 // Now sample the observed cost.
1638 unsigned *costAddr = this->getObsCostLowAddrInParadyndSpace();
1639 const unsigned theCost = *costAddr; // WARNING: shouldn't we be using a mutex?!
1641 this->processCost(theCost, theWallTime, theProcTime);
1646 bool process::doMinorShmSample() {
1647 // Returns true if the minor sample has successfully completed all outstanding
1649 bool result = true; // so far...
1651 if (!theSuperTable.doMinorSample())
1658 extern void removeFromMetricInstances(process *);
1659 extern void disableAllInternalMetrics();
1661 void handleProcessExit(process *proc, int exitStatus) {
1662 if (proc->status() == exited)
1665 proc->Exited(); // updates status line
1669 #ifndef BPATCH_LIBRARY
1670 if (activeProcesses == 0)
1671 disableAllInternalMetrics();
1676 PDYN_reportSIGCHLD(proc->getPid(), exitStatus);
1680 // Perhaps these lines can be un-commented out in the future, but since
1681 // cleanUpAndExit() does the same thing, and it always gets called
1682 // (when paradynd detects that paradyn died), it's not really necessary
1684 // for (unsigned lcv=0; lcv < processVec.size(); lcv++)
1685 // if (processVec[lcv] == proc) {
1686 // delete proc; // destructor removes shm segments...
1687 // processVec[lcv] = NULL;
1693 process::forkProcess: called when a process forks, to initialize a new
1694 process object for the child.
1696 the variable childHasInstrumentation is true if the child process has the
1697 instrumentation of the parent. This is the common case.
1698 On some platforms (AIX) the child does not have any instrumentation because
1699 the text segment of the child is not a copy of the parent text segment at
1700 the time of the fork, but a copy of the original text segment of the parent,
1701 without any instrumentation.
1702 (actually, childHasInstr is obsoleted by aix's completeTheFork() routine)
1704 process *process::forkProcess(const process *theParent, pid_t childPid,
1705 dictionary_hash<instInstance*,instInstance*> &map, // gets filled in
1709 void *applAttachedPtr
1713 vector<fastInferiorHeapMgr::oneHeapStats> theShmHeapStats(3);
1714 theShmHeapStats[0].elemNumBytes = sizeof(intCounter);
1715 theShmHeapStats[0].maxNumElems = numIntCounters;
1717 theShmHeapStats[1].elemNumBytes = sizeof(tTimer);
1718 theShmHeapStats[1].maxNumElems = numWallTimers;
1720 theShmHeapStats[2].elemNumBytes = sizeof(tTimer);
1721 theShmHeapStats[2].maxNumElems = numProcTimers;
1724 forkexec_cerr << "paradynd welcome to process::forkProcess; parent pid=" << theParent->getPid() << "; calling fork ctor now" << endl;
1726 // Call the "fork" ctor:
1727 process *ret = new process(*theParent, (int)childPid, iTrace_fd
1736 forkexec_cerr << "paradynd fork ctor has completed ok...child pid is " << ret->getPid() << endl;
1741 #ifndef BPATCH_LIBRARY
1742 if (!costMetric::addProcessToAll(ret))
1746 // We used to do a ret->attach() here...it was moved to the fork ctor, so it's
1747 // been done already.
1749 /* all instrumentation on the parent is active on the child */
1750 /* TODO: what about instrumentation inserted near the fork time??? */
1751 ret->baseMap = theParent->baseMap; // WHY IS THIS HERE?
1753 // the following writes to "map", s.t. for each instInstance in the parent
1754 // process, we have a map to the corresponding one in the child process.
1755 // that's all this routine does -- it doesn't actually touch
1756 // any instrumentation (because it doesn't need to -- fork() syscall copied
1757 // all of the actual instrumentation [but what about AIX and its weird load
1759 copyInstInstances(theParent, ret, map);
1760 // doesn't copy anything; just writes to "map"
1766 void process::processCost(unsigned obsCostLow,
1768 time64 processTime) {
1769 // wallTime and processTime should compare to DYNINSTgetWallTime() and
1770 // DYNINSTgetCPUtime().
1772 // check for overflow, add to running total, convert cycles to
1773 // seconds, and report.
1774 // Member vrbles of class process: lastObsCostLow and cumObsCost (the latter
1777 // code to handle overflow used to be in rtinst; we borrow it pretty much
1778 // verbatim. (see rtinst/RTposix.c)
1779 if (obsCostLow < lastObsCostLow) {
1780 // we have a wraparound
1781 cumObsCost += ((unsigned)0xffffffff - lastObsCostLow) + obsCostLow + 1;
1784 cumObsCost += (obsCostLow - lastObsCostLow);
1786 lastObsCostLow = obsCostLow;
1788 extern double cyclesPerSecond; // perfStream.C
1790 double observedCostSecs = cumObsCost;
1791 observedCostSecs /= cyclesPerSecond;
1792 // cerr << "processCost: cyclesPerSecond=" << cyclesPerSecond << "; cum obs cost=" << observedCostSecs << endl;
1794 // Notice how most of the rest of this is copied from processCost() of metric.C
1795 // Be sure to keep the two "in sync"!
1796 timeStamp newSampleTime = (double)wallTime / 1000000.0; // usec to seconds
1797 timeStamp newProcessTime = (double)processTime / 1000000.0; // usec to secs
1799 extern costMetric *totalPredictedCost; // init.C
1800 extern costMetric *observed_cost; // init.C
1801 extern costMetric *smooth_obs_cost; // init.C
1803 const timeStamp lastProcessTime =
1804 totalPredictedCost->getLastSampleProcessTime(this);
1806 // find the portion of uninstrumented time for this interval
1807 const double unInstTime = ((newProcessTime - lastProcessTime)
1808 / (1+currentPredictedCost));
1809 // update predicted cost
1810 // note: currentPredictedCost is the same for all processes
1811 // this should be changed to be computed on a per process basis
1812 sampleValue newPredCost = totalPredictedCost->getCumulativeValue(this);
1813 newPredCost += (float)(currentPredictedCost*unInstTime);
1815 totalPredictedCost->updateValue(this,newPredCost,
1816 newSampleTime,newProcessTime);
1817 // update observed cost
1818 observed_cost->updateValue(this,observedCostSecs,
1819 newSampleTime,newProcessTime);
1821 // update smooth observed cost
1822 smooth_obs_cost->updateSmoothValue(this,observedCostSecs,
1823 newSampleTime,newProcessTime);
1828 * Copy data from controller process to the named process.
1830 bool process::writeDataSpace(void *inTracedProcess, int size,
1831 const void *inSelf) {
1832 bool needToCont = false;
1834 if (status_ == exited)
1837 if (status_ == running) {
1843 if (status_ != stopped && status_ != neonatal) {
1844 showErrorCallback(38, "Internal paradynd error in process::writeDataSpace");
1848 bool res = writeDataSpace_(inTracedProcess, size, inSelf);
1850 string msg = string("System error: unable to write to process data space:")
1851 + string(sys_errlist[errno]);
1852 showErrorCallback(38, msg);
1857 return this->continueProc();
1861 bool process::readDataSpace(const void *inTracedProcess, int size,
1862 void *inSelf, bool displayErrMsg) {
1863 bool needToCont = false;
1865 if (status_ == exited)
1868 if (status_ == running) {
1871 sprintf(errorLine, "in readDataSpace, status_ = running, but unable to pause()\n");
1877 if (status_ != stopped && status_ != neonatal) {
1878 showErrorCallback(38, "Internal paradynd error in process::readDataSpace");
1879 sprintf(errorLine, "Internal paradynd error in process::readDataSpace");
1884 bool res = readDataSpace_(inTracedProcess, size, inSelf);
1886 if (displayErrMsg) {
1888 msg=string("System error: unable to read from process data space:")
1889 + string(sys_errlist[errno]);
1890 sprintf(errorLine, msg.string_of());
1892 showErrorCallback(38, msg);
1898 needToCont = this->continueProc();
1900 sprintf(errorLine, "warning : readDataSpace, needToCont FALSE, returning FALSE\n");
1909 bool process::writeTextWord(caddr_t inTracedProcess, int data) {
1910 bool needToCont = false;
1912 if (status_ == exited)
1915 if (status_ == running) {
1921 if (status_ != stopped && status_ != neonatal) {
1922 string msg = string("Internal paradynd error in process::writeTextWord")
1923 + string((int)status_);
1924 showErrorCallback(38, msg);
1925 //showErrorCallback(38, "Internal paradynd error in process::writeTextWord");
1929 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
1930 if (!isAddrInHeap((Address)inTracedProcess)) {
1931 if (!saveOriginalInstructions((Address)inTracedProcess, sizeof(int)))
1933 afterMutationList.insertTail((Address)inTracedProcess, sizeof(int), &data);
1937 bool res = writeTextWord_(inTracedProcess, data);
1939 string msg = string("System error: unable to write to process text word:")
1940 + string(sys_errlist[errno]);
1941 showErrorCallback(38, msg);
1946 return this->continueProc();
1951 bool process::writeTextSpace(void *inTracedProcess, int amount, const void *inSelf) {
1952 bool needToCont = false;
1954 if (status_ == exited)
1957 if (status_ == running) {
1963 if (status_ != stopped && status_ != neonatal) {
1964 string msg = string("Internal paradynd error in process::writeTextSpace")
1965 + string((int)status_);
1966 showErrorCallback(38, msg);
1967 //showErrorCallback(38, "Internal paradynd error in process::writeTextSpace");
1971 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
1972 if (!isAddrInHeap((Address)inTracedProcess)) {
1973 if (!saveOriginalInstructions((Address)inTracedProcess, amount))
1975 afterMutationList.insertTail((Address)inTracedProcess, amount, inSelf);
1979 bool res = writeTextSpace_(inTracedProcess, amount, inSelf);
1981 string msg = string("System error: unable to write to process text space:")
1982 + string(sys_errlist[errno]);
1983 showErrorCallback(38, msg);
1988 return this->continueProc();
1992 #ifdef BPATCH_SET_MUTATIONS_ACTIVE
1993 bool process::readTextSpace(const void *inTracedProcess, int amount,
1996 bool needToCont = false;
1998 if (status_ == exited)
2001 if (status_ == running) {
2007 if (status_ != stopped && status_ != neonatal) {
2008 showErrorCallback(38, "Internal paradynd error in process::readTextSpace");
2012 bool res = readTextSpace_((void *)inTracedProcess, amount, inSelf);
2015 msg=string("System error: unable to read from process data space:")
2016 + string(sys_errlist[errno]);
2017 showErrorCallback(38, msg);
2022 return this->continueProc();
2026 #endif /* BPATCH_SET_MUTATIONS_ACTIVE */
2028 bool process::pause() {
2029 if (status_ == stopped || status_ == neonatal)
2032 if (status_ == exited) {
2033 sprintf(errorLine, "warn : in process::pause, trying to pause exited process, returning FALSE");
2038 if (status_ == running && reachedFirstBreak) {
2039 bool res = pause_();
2041 sprintf(errorLine, "warn : in process::pause, pause_ unable to pause process");
2049 // The only remaining combination is: status==running but haven't yet
2050 // reached first break. We never want to pause before reaching the
2051 // first break (trap, actually). But should we be returning true or false in this
2058 // handleIfDueToSharedObjectMapping: if a trap instruction was caused by
2059 // a dlopen or dlclose event then return true
2060 bool process::handleIfDueToSharedObjectMapping(){
2066 vector<shared_object *> *changed_objects = 0;
2067 u_int change_type = 0;
2068 bool error_occured = false;
2069 bool ok = dyn->handleIfDueToSharedObjectMapping(this,&changed_objects,
2070 change_type,error_occured);
2072 // if this trap was due to dlopen or dlclose, and if something changed
2073 // then figure out how it changed and either add or remove shared objects
2074 if(ok && !error_occured && (change_type != SHAREDOBJECT_NOCHANGE)) {
2076 // if something was added then call process::addASharedObject with
2077 // each element in the vector of changed_objects
2078 if((change_type == SHAREDOBJECT_ADDED) && changed_objects) {
2079 for(u_int i=0; i < changed_objects->size(); i++) {
2080 // TODO: currently we aren't handling dlopen because
2081 // we don't have the code in place to modify existing metrics
2082 // This is what we really want to do:
2083 #ifndef BPATCH_LIBRARY
2084 if (((*changed_objects)[i])->getName() == string(getenv("PARADYN_LIB")))
2087 if(addASharedObject(*((*changed_objects)[i]))){
2088 *shared_objects += (*changed_objects)[i];
2089 hasLoadedDyninstLib = true;
2090 isLoadingDyninstLib = false;
2092 logLine("Error after call to addASharedObject\n");
2093 delete (*changed_objects)[i];
2095 #ifndef BPATCH_LIBRARY
2097 // for now, just delete shared_objects to avoid memory leeks
2098 delete (*changed_objects)[i];
2102 delete changed_objects;
2104 else if((change_type == SHAREDOBJECT_REMOVED) && (changed_objects)) {
2105 // TODO: handle this case
2106 // if something was removed then call process::removeASharedObject
2107 // with each element in the vector of changed_objects
2109 // for now, just delete shared_objects to avoid memory leeks
2110 for(u_int i=0; i < changed_objects->size(); i++){
2111 delete (*changed_objects)[i];
2113 delete changed_objects;
2116 // TODO: add support for adding or removing new code resource once the
2117 // process has started running...this means that currently collected
2118 // metrics may have to have aggregate components added or deleted
2119 // this should be added to process::addASharedObject and
2120 // process::removeASharedObject
2130 // If this process is a dynamic executable, then get all its
2131 // shared objects, parse them, and define new instpoints and resources
2133 bool process::handleStartProcess(){
2135 // get shared objects, parse them, and define new resources
2136 // For WindowsNT we don't call getSharedObjects here, instead
2137 // addASharedObject will be called directly by pdwinnt.C
2138 #if !defined(i386_unknown_nt4_0)
2139 this->getSharedObjects();
2142 #ifndef BPATCH_LIBRARY
2143 if(resource::num_outstanding_creates)
2144 this->setWaitingForResources();
2150 // addASharedObject: This routine is called whenever a new shared object
2151 // has been loaded by the run-time linker
2152 // It processes the image, creates new resources
2153 bool process::addASharedObject(shared_object &new_obj){
2155 image *img = image::parseImage(new_obj.getName(),new_obj.getBaseAddress());
2157 logLine("error parsing image in addASharedObject\n");
2160 new_obj.addImage(img);
2162 // if the list of all functions and all modules have already been
2163 // created for this process, then the functions and modules from this
2164 // shared object need to be added to those lists
2166 *all_modules += *((vector<module *> *)(new_obj.getModules()));
2169 vector<function_base *> *normal_funcs = (vector<function_base *> *)
2170 (new_obj.getAllFunctions());
2171 *all_functions += *normal_funcs;
2175 // if the signal handler function has not yet been found search for it
2176 if(!signal_handler){
2177 signal_handler = img->findOneFunction(SIGNAL_HANDLER);
2180 // clear the include_funcs flag if this shared object should not be
2181 // included in the some_functions and some_modules lists
2182 #ifndef BPATCH_LIBRARY
2183 vector<string> lib_constraints;
2184 if(mdl_get_lib_constraints(lib_constraints)){
2185 for(u_int j=0; j < lib_constraints.size(); j++){
2187 // if the lib constraint is not of the form "module/function" and
2188 // if it is contained in the name of this object, then exclude
2189 // this shared object
2190 char *obj_name = P_strdup(new_obj.getName().string_of());
2191 char *lib_name = P_strdup(lib_constraints[j].string_of());
2192 if(obj_name && lib_name && (where=P_strstr(obj_name, lib_name))){
2193 new_obj.changeIncludeFuncs(false);
2195 if(lib_name) free(lib_name);
2196 if(obj_name) free(obj_name);
2200 // This looks a bit wierd at first glance, but apparently is ok -
2201 // A shared object has 1 module. If that module is excluded,
2202 // then new_obj.includeFunctions() should return FALSE. As such,
2203 // the some_modules += new_obj.getModules() is OK as long as
2204 // shared objects have ONLY 1 module.
2205 if(new_obj.includeFunctions()){
2207 *some_modules += *((vector<module *> *)(new_obj.getModules()));
2209 if(some_functions) {
2210 // gets only functions not excluded by mdl "exclude_node" option
2212 *((vector<function_base *> *)(new_obj.getSomeFunctions()));
2215 #endif /* BPATCH_LIBRARY */
2219 // getSharedObjects: This routine is called before main() or on attach
2220 // to an already running process. It gets and process all shared objects
2221 // that have been mapped into the process's address space
2222 bool process::getSharedObjects() {
2224 assert(!shared_objects);
2225 shared_objects = dyn->getSharedObjects(this);
2227 statusLine("parsing shared object files");
2229 #ifndef BPATCH_LIBRARY
2230 tp->resourceBatchMode(true);
2232 // for each element in shared_objects list process the
2233 // image file to find new instrumentaiton points
2234 for(u_int j=0; j < shared_objects->size(); j++){
2235 //string temp2 = string(i);
2236 //temp2 += string("th shared obj, addr: ");
2237 //temp2 += string(((*shared_objects)[i])->getBaseAddress());
2238 //temp2 += string(" name: ");
2239 //temp2 += string(((*shared_objects)[i])->getName());
2240 //temp2 += string("\n");
2241 // logLine(P_strdup(temp2.string_of()));
2243 if(!addASharedObject(*((*shared_objects)[j]))){
2244 logLine("Error after call to addASharedObject\n");
2248 #ifndef BPATCH_LIBRARY
2249 tp->resourceBatchMode(false);
2253 // else this a.out does not have a .dynamic section
2254 dynamiclinking = false;
2258 // findOneFunction: returns the function associated with func
2259 // this routine checks both the a.out image and any shared object
2260 // images for this resource.
2261 // Semantics of excluded functions - Once "exclude" works for both
2262 // static and dynamically linked objects, this should return NULL
2263 // if the function being sought is excluded....
2264 #ifndef BPATCH_LIBRARY
2265 function_base *process::findOneFunction(resource *func,resource *mod){
2267 if((!func) || (!mod)) { return 0; }
2268 if(func->type() != MDL_T_PROCEDURE) { return 0; }
2269 if(mod->type() != MDL_T_MODULE) { return 0; }
2271 const vector<string> &f_names = func->names();
2272 const vector<string> &m_names = mod->names();
2273 string func_name = f_names[f_names.size() -1];
2274 string mod_name = m_names[m_names.size() -1];
2276 //cerr << "process::findOneFunction called. function name = "
2277 // << func_name.string_of() << endl;
2279 // KLUDGE: first search any shared libraries for the module name
2280 // (there is only one module in each shared library, and that
2281 // is the library name)
2282 if(dynamiclinking && shared_objects){
2283 for(u_int j=0; j < shared_objects->size(); j++){
2285 next = ((*shared_objects)[j])->findModule(mod_name,true);
2287 if(((*shared_objects)[j])->includeFunctions()){
2288 //cerr << "function found in module " << mod_name.string_of() << endl;
2289 return(((*shared_objects)[j])->findOneFunction(func_name,
2293 //cerr << "function found in module " << mod_name.string()
2294 // << " that module excluded" << endl;
2301 return(symbols->findOneFunction(func_name));
2303 #endif /* BPATCH_LIBRARY */
2305 #ifndef BPATCH_LIBRARY
2306 // returns all the functions in the module "mod" that are not excluded by
2307 // exclude_lib or exclude_func
2308 // return 0 on error.
2309 vector<function_base *> *process::getIncludedFunctions(module *mod) {
2311 if((!mod)) { return 0; }
2313 //cerr << "process::getIncludedFunctions(" << mod->fileName() << ") called" << endl;
2315 // KLUDGE: first search any shared libraries for the module name
2316 // (there is only one module in each shared library, and that
2317 // is the library name)
2318 if(dynamiclinking && shared_objects){
2319 for(u_int j=0; j < shared_objects->size(); j++){
2321 next = ((*shared_objects)[j])->findModule(mod->fileName(), true);
2323 if(((*shared_objects)[j])->includeFunctions()){
2324 return((vector<function_base *> *)
2325 ((*shared_objects)[j])->getSomeFunctions());
2332 // this must be an a.out module so just return the list associated
2334 // Now that exclude should work for both static and dynamically
2335 // linked executables, probably need to either filter excluded
2336 // files here, or let the module do it and pass the information not
2337 // to include excluded functions along with this proc call....
2339 return(mod->getIncludedFunctions());
2341 #endif /* BPATCH_LIBRARY */
2344 // findOneFunction: returns the function associated with func
2345 // this routine checks both the a.out image and any shared object
2346 // images for this resource
2347 function_base *process::findOneFunction(const string &func_name){
2348 // first check a.out for function symbol
2349 function_base *pdf = symbols->findOneFunction(func_name);
2354 // search any shared libraries for the file name
2355 if(dynamiclinking && shared_objects){
2356 for(u_int j=0; j < shared_objects->size(); j++){
2357 pdf = ((*shared_objects)[j])->findOneFunction(func_name,false);
2365 // findOneFunctionFromAll: returns the function associated with func
2366 // this routine checks both the a.out image and any shared object
2367 // images for this resource
2368 function_base *process::findOneFunctionFromAll(const string &func_name){
2370 // first check a.out for function symbol
2371 function_base *pdf = symbols->findOneFunctionFromAll(func_name);
2374 // search any shared libraries for the file name
2375 if(dynamiclinking && shared_objects){
2376 for(u_int j=0; j < shared_objects->size(); j++){
2377 pdf=((*shared_objects)[j])->findOneFunctionFromAll(func_name,false);
2387 // findpdFunctionIn: returns the function which contains this address
2388 // This routine checks both the a.out image and any shared object images
2389 // for this function
2390 pd_Function *process::findpdFunctionIn(Address adr) {
2392 // first check a.out for function symbol
2393 // findFunctionInInstAndUnInst will search the instrumentable and
2394 // uninstrumentable functions. We are assuming that "adr" is the
2395 // entry point of the function, so we will use as the key to search
2396 // in the dictionary - naim
2397 pd_Function *pdf = symbols->findFunctionInInstAndUnInst(adr,this);
2399 // search any shared libraries for the function
2400 if(dynamiclinking && shared_objects){
2401 for(u_int j=0; j < shared_objects->size(); j++){
2402 pdf = ((*shared_objects)[j])->findFunctionInInstAndUnInst(adr,this);
2409 if(!all_functions) getAllFunctions();
2411 // if the function was not found, then see if this addr corresponds
2412 // to a function that was relocated in the heap
2414 for(u_int j=0; j < all_functions->size(); j++){
2415 Address func_adr = ((*all_functions)[j])->getAddress(this);
2416 if((adr>=func_adr) &&
2417 (adr<=(((*all_functions)[j])->size()+func_adr))){
2418 // yes, this is very bad, but too bad
2419 return((pd_Function*)((*all_functions)[j]));
2427 // findFunctionIn: returns the function containing the address "adr"
2428 // this routine checks both the a.out image and any shared object
2429 // images for this resource
2430 function_base *process::findFunctionIn(Address adr){
2432 // first check a.out for function symbol
2433 pd_Function *pdf = symbols->findFunctionIn(adr,this);
2435 // search any shared libraries for the function
2436 if(dynamiclinking && shared_objects){
2437 for(u_int j=0; j < shared_objects->size(); j++){
2438 pdf = ((*shared_objects)[j])->findFunctionIn(adr,this);
2444 if(!all_functions) getAllFunctions();
2446 // if the function was not found, then see if this addr corresponds
2447 // to a function that was relocated in the heap
2449 for(u_int j=0; j < all_functions->size(); j++){
2450 Address func_adr = ((*all_functions)[j])->getAddress(this);
2451 if((adr>=func_adr) &&
2452 (adr<=(((*all_functions)[j])->size()+func_adr))){
2453 return((*all_functions)[j]);
2462 // findModule: returns the module associated with mod_name
2463 // this routine checks both the a.out image and any shared object
2464 // images for this resource
2465 // if check_excluded is true it checks to see if the module is excluded
2466 // and if it is it returns 0. If check_excluded is false it doesn't check
2467 module *process::findModule(const string &mod_name,bool check_excluded){
2469 // KLUDGE: first search any shared libraries for the module name
2470 // (there is only one module in each shared library, and that
2471 // is the library name)
2472 if(dynamiclinking && shared_objects){
2473 for(u_int j=0; j < shared_objects->size(); j++){
2474 module *next = ((*shared_objects)[j])->findModule(mod_name,
2482 // check a.out for function symbol
2483 // Note that symbols is data member of type image* (comment says
2484 // "information related to the process"....
2485 return(symbols->findModule(mod_name));
2488 // getSymbolInfo: get symbol info of symbol associated with name n
2489 // this routine starts looking a.out for symbol and then in shared objects
2490 // baseAddr is set to the base address of the object containing the symbol.
2491 // This function appears to return symbol info even if module/function
2492 // is excluded. In extending excludes to statically linked executable,
2493 // we preserve these semantics....
2494 bool process::getSymbolInfo(const string &name, Symbol &info, Address &baseAddr) const {
2496 // first check a.out for symbol
2497 if(symbols->symbol_info(name,info))
2498 return getBaseAddress(symbols, baseAddr);
2500 // next check shared objects
2501 if(dynamiclinking && shared_objects) {
2502 for(u_int j=0; j < shared_objects->size(); j++) {
2503 if(((*shared_objects)[j])->getSymbolInfo(name,info))
2504 return getBaseAddress(((*shared_objects)[j])->getImage(), baseAddr);
2512 // getAllFunctions: returns a vector of all functions defined in the
2513 // a.out and in the shared objects
2514 // TODO: what to do about duplicate function names?
2515 vector<function_base *> *process::getAllFunctions(){
2517 // if this list has already been created, return it
2519 return all_functions;
2521 // else create the list of all functions
2522 all_functions = new vector<function_base *>;
2523 const vector<function_base *> &blah =
2524 (vector<function_base *> &)(symbols->getAllFunctions());
2525 *all_functions += blah;
2527 if(dynamiclinking && shared_objects){
2528 for(u_int j=0; j < shared_objects->size(); j++){
2529 vector<function_base *> *funcs = (vector<function_base *> *)
2530 (((*shared_objects)[j])->getAllFunctions());
2532 *all_functions += *funcs;
2536 return all_functions;
2539 // getAllModules: returns a vector of all modules defined in the
2540 // a.out and in the shared objects
2541 // Includes "excluded" modules....
2542 vector<module *> *process::getAllModules(){
2544 // if the list of all modules has already been created, the return it
2545 if(all_modules) return all_modules;
2547 // else create the list of all modules
2548 all_modules = new vector<module *>;
2549 *all_modules += *((vector<module *> *)(&(symbols->getAllModules())));
2551 if(dynamiclinking && shared_objects){
2552 for(u_int j=0; j < shared_objects->size(); j++){
2553 vector<module *> *mods =
2554 (vector<module *> *)(((*shared_objects)[j])->getModules());
2556 *all_modules += *mods;
2562 #ifndef BPATCH_LIBRARY
2563 // getIncludedFunctions: returns a vector of all functions defined in the
2564 // a.out and in the shared objects
2565 // TODO: what to do about duplicate function names?
2566 vector<function_base *> *process::getIncludedFunctions(){
2567 //cerr << "process " << programName << " :: getIncludedFunctions() called"
2569 // if this list has already been created, return it
2571 return some_functions;
2573 // else create the list of all functions
2574 some_functions = new vector<function_base *>;
2575 const vector<function_base *> &incl_funcs =
2576 (vector<function_base *> &)(symbols->getIncludedFunctions());
2577 *some_functions += incl_funcs;
2579 //cerr << " (process::getIncludedFunctions), about to add incl_funcs to some_functions, incl_funcs = " << endl;
2580 //print_func_vector_by_pretty_name(string(">>>"), &incl_funcs);
2582 if(dynamiclinking && shared_objects){
2583 for(u_int j=0; j < shared_objects->size(); j++){
2584 if(((*shared_objects)[j])->includeFunctions()){
2585 // kludge: can't assign a vector<derived_class *> to
2586 // a vector<base_class *> so recast
2587 vector<function_base *> *funcs = (vector<function_base *> *)
2588 (((*shared_objects)[j])->getSomeFunctions());
2590 *some_functions += (*funcs);
2595 //cerr << " (process::getIncludedFunctions()) about to return fucntion list : ";
2596 //print_func_vector_by_pretty_name(string(" "), some_functions);
2598 return some_functions;
2600 #endif /* BPATCH_LIBRARY */
2602 // getIncludedModules: returns a vector of all modules defined in the
2603 // a.out and in the shared objects that are included as specified in
2605 vector<module *> *process::getIncludedModules(){
2607 //cerr << "process::getIncludedModules called" << endl;
2609 // if the list of all modules has already been created, the return it
2611 //cerr << "some_modules already created, returning it:" << endl;
2612 //print_module_vector_by_short_name(string(" "), (vector<pdmodule*>*)some_modules);
2613 return some_modules;
2616 // else create the list of all modules
2617 some_modules = new vector<module *>;
2618 *some_modules += *((vector<module *> *)(&(symbols->getIncludedModules())));
2620 if(dynamiclinking && shared_objects){
2621 for(u_int j=0; j < shared_objects->size(); j++){
2622 if(((*shared_objects)[j])->includeFunctions()){
2623 vector<module *> *mods = (vector<module *> *)
2624 (((*shared_objects)[j])->getModules());
2626 *some_modules += *mods;
2631 //cerr << "some_modules newlyu created, returning it:" << endl;
2632 //print_module_vector_by_short_name(string(" "),
2633 // (vector<pdmodule*>*)some_modules);
2634 return some_modules;
2637 // getBaseAddress: sets baseAddress to the base address of the
2638 // image corresponding to which. It returns true if image is mapped
2639 // in processes address space, otherwise it returns 0
2640 bool process::getBaseAddress(const image *which,u_int &baseAddress) const {
2642 if((u_int)(symbols) == (u_int)(which)){
2646 else if (shared_objects) {
2647 // find shared object corr. to this image and compute correct address
2648 for(unsigned j=0; j < shared_objects->size(); j++){
2649 if(((*shared_objects)[j])->isMapped()){
2650 if(((*shared_objects)[j])->getImageId() == (u_int)which) {
2651 baseAddress = ((*shared_objects)[j])->getBaseAddress();
2659 // findSignalHandler: if signal_handler is 0, then it checks all images
2660 // associtated with this process for the signal handler function.
2661 // Otherwise, the signal handler function has already been found
2662 void process::findSignalHandler(){
2664 if(SIGNAL_HANDLER == 0) return;
2665 if(!signal_handler) {
2666 // first check a.out for signal handler function
2667 signal_handler = symbols->findOneFunction(SIGNAL_HANDLER);
2669 // search any shared libraries for signal handler function
2670 if(!signal_handler && dynamiclinking && shared_objects) {
2671 for(u_int j=0;(j < shared_objects->size()) && !signal_handler; j++){
2673 ((*shared_objects)[j])->findOneFunction(SIGNAL_HANDLER,false);
2679 bool process::findInternalSymbol(const string &name, bool warn, internalSym &ret_sym) const {
2680 // On some platforms, internal symbols may be dynamic linked
2681 // so we search both the a.out and the shared objects
2684 static const string underscore = "_";
2685 if (getSymbolInfo(name, sym, baseAddr)
2686 || getSymbolInfo(underscore+name, sym, baseAddr)) {
2687 ret_sym = internalSym(sym.addr()+baseAddr, name);
2692 msg = string("Unable to find symbol: ") + name;
2693 statusLine(msg.string_of());
2694 showErrorCallback(28, msg);
2699 Address process::findInternalAddress(const string &name, bool warn, bool &err) const {
2700 // On some platforms, internal symbols may be dynamic linked
2701 // so we search both the a.out and the shared objects
2704 static const string underscore = "_";
2705 #if defined(USES_LIBDYNINSTRT_SO)
2706 // we use "dlopen" because we took out the leading "_"'s from the name
2707 if (name==string("dlopen")) {
2708 // if the function is dlopen, we use the address in ld.so.1 directly
2709 baseAddr = get_dlopen_addr();
2710 if (baseAddr != NULL) {
2719 if (getSymbolInfo(name, sym, baseAddr)
2720 || getSymbolInfo(underscore+name, sym, baseAddr)) {
2722 return sym.addr()+baseAddr;
2726 msg = string("Unable to find symbol: ") + name;
2727 statusLine(msg.string_of());
2728 showErrorCallback(28, msg);
2736 bool process::continueProc() {
2737 if (status_ == exited) return false;
2739 if (status_ != stopped && status_ != neonatal) {
2740 showErrorCallback(38, "Internal paradynd error in process::continueProc");
2744 bool res = continueProc_();
2747 showErrorCallback(38, "System error: can't continue process");
2754 bool process::detach(const bool paused) {
2756 logLine("detach: pause not implemented\n"); // why not? --ari
2758 bool res = detach_();
2760 // process may have exited
2766 #ifdef BPATCH_LIBRARY
2767 // XXX Eventually detach() above should go away and this should be
2769 /* process::API_detach: detach from the application, leaving all
2770 instrumentation place. Returns true upon success and false upon failure.
2771 Fails if the application is not stopped when the call is made. The
2772 parameter "cont" indicates whether or not the application should be made
2773 running or not as a consquence of detaching (true indicates that it should
2776 bool process::API_detach(const bool cont)
2778 if (status() != neonatal && status() != stopped)
2781 return API_detach_(cont);
2785 /* process::handleExec: called when a process successfully exec's.
2786 Parse the new image, disable metric instances on the old image, create a
2787 new (and blank) shm segment. The process hasn't yet bootstrapped, so we
2788 mustn't try to enable anything...
2790 void process::handleExec() {
2791 // NOTE: for shm sampling, the shm segment has been removed, so we
2792 // mustn't try to disable any dataReqNodes in the standard way...
2794 // since the exec syscall has run, we're not ready to enable any m/f pairs or
2796 // So we set hasBootstrapped to false until we run DYNINSTinit again.
2797 hasBootstrapped = false;
2799 // all instrumentation that was inserted in this process is gone.
2800 // set exited here so that the disables won't try to write to process
2803 // Clean up state from old exec: all dynamic linking stuff, all lists
2804 // of functions and modules from old executable
2806 // can't delete dynamic linking stuff here, because parent process
2807 // could still have pointers
2808 dynamiclinking = false;
2809 dyn = 0; // AHEM. LEAKED MEMORY! not if the parent still has a pointer
2810 // to this dynamic_linking object.
2811 dyn = new dynamic_linking;
2813 for(u_int j=0; j< shared_objects->size(); j++){
2814 delete (*shared_objects)[j];
2816 delete shared_objects;
2820 // TODO: when can pdFunction's be deleted??? definitely not here.
2821 delete some_modules;
2822 delete some_functions;
2823 delete all_functions;
2830 trampTableItems = 0;
2831 memset(trampTable, 0, sizeof(trampTable));
2833 cleanInstFromActivePoints(this);
2835 #if defined(rs6000_ibm_aix3_2) || defined(rs6000_ibm_aix4_1)
2836 // must call establishBaseAddrs before parsing the new image,
2837 // but doesn't need to wait for trap, since we already got the trap.
2838 bool establishBaseAddrs(int pid, int &status, bool waitForTrap);
2840 establishBaseAddrs(getPid(), status, false);
2843 image *img = image::parseImage(execFilePath);
2846 // For better error reporting, two failure return values would be useful
2847 // One for simple error like because-file-not-found
2848 // Another for serious errors like found-but-parsing-failed (internal error;
2849 // please report to paradyn@cs.wisc.edu)
2851 string msg = string("Unable to parse image: ") + execFilePath;
2852 showErrorCallback(68, msg.string_of());
2854 // err..what if we had attached? Wouldn't a detach be appropriate in this case?
2858 // delete proc->symbols ??? No, the image can be shared by more
2859 // than one process...images and instPoints can not be deleted...TODO
2860 // add some sort of reference count to these classes so that they can
2862 symbols = img; // AHEM! LEAKED MEMORY!!! ...not if parent has ptr to
2865 // see if new image contains the signal handler function
2866 this->findSignalHandler();
2868 // initInferiorHeap can only be called after symbols is set!
2869 #if !defined(USES_LIBDYNINSTRT_SO)
2870 initInferiorHeap(false);
2872 initInferiorHeap(true); // create separate text heap
2876 /* update process status */
2877 reachedFirstBreak = false;
2878 // we haven't yet seen initial SIGTRAP for this proc (is this right?)
2879 reachedVeryFirstTrap = false;
2881 status_ = stopped; // was 'exited'
2883 // TODO: We should remove (code) items from the where axis, if the exec'd process
2884 // was the only one who had them.
2886 // the exec'd process has the same fd's as the pre-exec, so we don't need
2887 // to re-initialize traceLink or ioLink (is this right???)
2889 // we don't need to re-attach after an exec (is this right???)
2892 inferiorHeapMgr.handleExec();
2893 // reuses the shm seg (paradynd's already attached to it); resets applic-attached-
2894 // at to NULL. Quite similar to the (non-fork) ctor, really.
2896 theSuperTable.handleExec();
2904 process::cleanUpInstrumentation called when paradynd catch
2905 a SIGTRAP to find out if there's any previous unfinished instrumentation
2908 bool process::cleanUpInstrumentation(bool wasRunning) {
2909 // Try to process an item off of the waiting list 'instWlist'.
2910 // If something was found & processed, then true will be returned.
2911 // Additionally, if true is returned, the process will be continued
2912 // if 'wasRunning' is true.
2913 // But if false is returned, then there should be no side effects: noone
2914 // should be continued, nothing removed from 'instWList', no change
2915 // to this->status_, and so on (this is important to avoid bugs).
2917 assert(status_ == stopped); // since we're always called after a SIGTRAP
2919 Address pc = frame.getPC();
2921 // Go thru the instWList to find out the ones to be deleted
2926 //process *p = (instWList[i])->which_proc;
2927 if(((instWList[i])->pc_ == pc) && ((instWList[i])->which_proc == this)){
2928 (instWList[i])->cleanUp(this,pc);
2929 u_int last = instWList.size()-1;
2930 delete (instWList[i]);
2931 instWList[i] = instWList[last];
2932 instWList.resize(last);
2938 if(i >= instWList.size()) done = true;
2940 if(found && wasRunning) continueProc();
2944 void process::cleanRPCreadyToLaunch(int mid)
2946 vectorSet<inferiorRPCtoDo> tmpRPCsWaitingToStart;
2947 while (RPCsWaitingToStart.size() > 0) {
2948 inferiorRPCtoDo currElem = RPCsWaitingToStart.removeOne();
2949 if (currElem.mid == mid)
2952 tmpRPCsWaitingToStart += currElem;
2954 // reconstruct RPCsWaitingToStart
2955 while (tmpRPCsWaitingToStart.size() > 0) {
2956 RPCsWaitingToStart += tmpRPCsWaitingToStart.removeOne();
2960 void process::postRPCtoDo(AstNode *action, bool noCost,
2961 void (*callbackFunc)(process *, void *, unsigned),
2964 // posts an RPC, but does NOT make any effort to launch it.
2965 inferiorRPCtoDo theStruct;
2966 theStruct.action = action;
2967 theStruct.noCost = noCost;
2968 theStruct.callbackFunc = callbackFunc;
2969 theStruct.userData = userData;
2970 theStruct.mid = mid;
2972 RPCsWaitingToStart += theStruct;
2975 bool process::existsRPCreadyToLaunch() const {
2976 if (currRunningRPCs.empty() && !RPCsWaitingToStart.empty())
2981 bool process::existsRPCinProgress() const {
2982 return (!currRunningRPCs.empty());
2985 bool process::launchRPCifAppropriate(bool wasRunning, bool finishingSysCall) {
2986 // asynchronously launches an inferiorRPC iff RPCsWaitingToStart.size() > 0 AND
2987 // if currRunningRPCs.size()==0 (the latter for safety)
2989 if (!currRunningRPCs.empty())
2990 // an RPC is currently executing, so it's not safe to launch a new one.
2993 if (RPCsWaitingToStart.empty())
2994 // duh, no RPC is waiting to run, so there's nothing to do.
2997 if (status_ == exited)
3000 if (status_ == neonatal)
3001 // not sure if this should be some kind of error...is the inferior ready
3002 // to execute inferior RPCs??? For now, we'll allow it.
3005 /* ****************************************************** */
3007 // Steps to take (on sparc, at least)
3008 // 1) pause the process and wait for it to stop
3009 // 2) Get a copy of the registers...store them away
3010 // 3) create temp trampoline: save, action, restore, trap, illegal
3011 // (the illegal is just ot be sure that the trap never returns)
3012 // 4) set the PC and nPC regs to addr of temp tramp
3013 // 5) Continue the process...go back to the main loop (SIGTRAP will
3014 // eventually be delivered)
3016 // When SIGTRAP is received,
3017 // 5) verify that PC is the location of the TRAP instr in the temp tramp
3018 // 6) free temp trampoline
3019 // 7) SETREGS to restore all regs, including PC and nPC.
3020 // 8) continue inferior, if the inferior had been running when we had
3021 // paused it in step 1, above.
3023 if (!finishingSysCall && RPCs_waiting_for_syscall_to_complete) {
3024 assert(executingSystemCall());
3029 cerr << "launchRPCifAppropriate failed because pause failed" << endl;
3033 // If we're in the middle of a system call, then it's not safe to launch
3034 // an inferiorRPC on most platforms. On some platforms, it's safe, but the
3035 // actual launching won't take place until the system call finishes. In such
3036 // cases it's a good idea to set a breakpoint for when the sys call exits
3037 // (using /proc PIOCSEXIT), and launch the inferiorRPC then.
3038 if (!finishingSysCall && executingSystemCall()) {
3039 if (RPCs_waiting_for_syscall_to_complete) {
3040 inferiorrpc_cerr << "launchRPCifAppropriate: still waiting for syscall to "
3041 << "complete" << endl;
3043 inferiorrpc_cerr << "launchRPC: continuing so syscall may complete" << endl;
3044 (void)continueProc();
3047 inferiorrpc_cerr << "launchRPC: sorry not continuing (problem?)" << endl;
3051 // don't do the inferior rpc until the system call finishes. Determine
3052 // which system call is in the way, and set a breakpoint at its exit point
3053 // so we know when it's safe to launch the RPC. Platform-specific
3056 inferiorrpc_cerr << "launchRPCifAppropriate: within a system call" << endl;
3058 if (!set_breakpoint_for_syscall_completion()) {
3059 // sorry, this platform can't set a breakpoint at the system call
3060 // completion point. In such a case, we keep polling executingSystemCall()
3063 (void)continueProc();
3065 inferiorrpc_cerr << "launchRPCifAppropriate: couldn't set bkpt for "
3066 << "syscall completion; will just poll." << endl;
3070 inferiorrpc_cerr << "launchRPCifAppropriate: set bkpt for syscall completion"
3073 // a SIGTRAP will get delivered when the RPC is ready to go. Until then,
3074 // mark the rpc as deferred. Setting this flag prevents us from executing
3075 // this code too many times.
3077 RPCs_waiting_for_syscall_to_complete = true;
3080 (void)continueProc();
3085 // Okay, we're not in the middle of a system call, so we can fire off the rpc now!
3086 if (RPCs_waiting_for_syscall_to_complete)
3088 RPCs_waiting_for_syscall_to_complete = false;
3090 void *theSavedRegs = getRegisters(); // machine-specific implementation
3091 // result is allocated via new[]; we'll delete[] it later.
3092 // return value of NULL indicates total failure.
3093 // return value of (void *)-1 indicates that the state of the machine isn't quite
3094 // ready for an inferiorRPC, and that we should try again 'later'. In
3095 // particular, we must handle the (void *)-1 case very gracefully (i.e., leave
3096 // the vrble 'RPCsWaitingToStart' untouched).
3098 if (theSavedRegs == (void *)-1) {
3099 // cerr << "launchRPCifAppropriate: deferring" << endl;
3101 (void)continueProc();
3105 if (theSavedRegs == NULL) {
3106 cerr << "launchRPCifAppropriate failed because getRegisters() failed" << endl;
3108 (void)continueProc();
3113 inferiorrpc_cerr << "NOTE: launchIfAppropriate: wasRunning==false!!" << endl;
3115 inferiorRPCtoDo todo = RPCsWaitingToStart.removeOne();
3116 // note: this line should always be below the test for (void*)-1, thus
3117 // leaving 'RPCsWaitingToStart' alone in that case.
3119 inferiorRPCinProgress inProgStruct;
3120 inProgStruct.callbackFunc = todo.callbackFunc;
3121 inProgStruct.userData = todo.userData;
3122 inProgStruct.savedRegs = theSavedRegs;
3123 inProgStruct.wasRunning = wasRunning || finishingSysCall;
3124 // If finishing up a system call, current state is paused, but we want to
3125 // set wasRunning to true so that it'll continue when the inferiorRPC
3126 // completes. Sorry for the kludge.
3127 unsigned tempTrampBase = createRPCtempTramp(todo.action,
3129 inProgStruct.callbackFunc != NULL,
3130 inProgStruct.breakAddr,
3131 inProgStruct.stopForResultAddr,
3132 inProgStruct.justAfter_stopForResultAddr,
3133 inProgStruct.resultRegister);
3134 // the last 4 args are written to
3136 if (tempTrampBase == 0) {
3137 cerr << "launchRPCifAppropriate failed because createRPCtempTramp failed" << endl;
3139 (void)continueProc();
3143 assert(tempTrampBase);
3145 inProgStruct.firstInstrAddr = tempTrampBase;
3147 assert(currRunningRPCs.empty()); // since it's unsafe to run > 1 at a time
3148 currRunningRPCs += inProgStruct;
3150 inferiorrpc_cerr << "Changing pc and exec.." << endl;
3152 // change the PC and nPC registers to the addr of the temp tramp
3153 if (!changePC(tempTrampBase, theSavedRegs)) {
3154 cerr << "launchRPCifAppropriate failed because changePC() failed" << endl;
3156 (void)continueProc();
3160 if (!continueProc()) {
3161 cerr << "launchRPCifAppropriate: continueProc() failed" << endl;
3165 inferiorrpc_cerr << "inferiorRPC should be running now" << endl;
3167 return true; // success
3170 unsigned process::createRPCtempTramp(AstNode *action,
3172 bool shouldStopForResult,
3173 unsigned &breakAddr,
3174 unsigned &stopForResultAddr,
3175 unsigned &justAfter_stopForResultAddr,
3178 // Returns addr of temp tramp, which was allocated in the inferior heap.
3179 // You must free it yourself when done.
3181 // Note how this is, in many ways, a greatly simplified version of
3184 // Temp tramp structure: save; code; restore; trap; illegal
3185 // the illegal is just to make sure that the trap never returns
3186 // note that we may not need to save and restore anything, since we've
3187 // already done a GETREGS and we'll restore with a SETREGS, right?
3189 unsigned char insnBuffer[4096];
3191 initTramps(); // initializes "regSpace", but only the 1st time it gets called...
3192 extern registerSpace *regSpace;
3193 regSpace->resetSpace();
3197 // The following is implemented in an arch-specific source file...
3198 if (!emitInferiorRPCheader(insnBuffer, count)) {
3199 // a fancy dialog box is probably called for here...
3200 cerr << "createRPCtempTramp failed because emitInferiorRPCheader failed." << endl;
3204 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
3205 generateMTpreamble((char*)insnBuffer,count,this);
3208 resultReg = action->generateCode(this, regSpace,
3212 if (!shouldStopForResult) {
3213 regSpace->freeRegister(resultReg);
3216 ; // in this case, we'll call freeRegister() the inferior rpc completes
3218 // Now, the trailer (restore, TRAP, illegal)
3219 // (the following is implemented in an arch-specific source file...)
3221 unsigned breakOffset, stopForResultOffset, justAfter_stopForResultOffset;
3222 if (!emitInferiorRPCtrailer(insnBuffer, count,
3223 breakOffset, shouldStopForResult, stopForResultOffset,
3224 justAfter_stopForResultOffset)) {
3225 // last 4 args except shouldStopForResult are modified by the call
3226 cerr << "createRPCtempTramp failed because emitInferiorRPCtrailer failed." << endl;
3230 unsigned tempTrampBase = inferiorMalloc(this, count, textHeap);
3231 assert(tempTrampBase);
3234 breakAddr = tempTrampBase + breakOffset;
3235 if (shouldStopForResult) {
3236 stopForResultAddr = tempTrampBase + stopForResultOffset;
3237 justAfter_stopForResultAddr = tempTrampBase + justAfter_stopForResultOffset;
3240 stopForResultAddr = justAfter_stopForResultAddr = 0;
3243 inferiorrpc_cerr << "createRPCtempTramp: temp tramp base=" << (void*)tempTrampBase
3244 << ", stopForResultAddr=" << (void*)stopForResultAddr
3245 << ", justAfter_stopForResultAddr=" << (void*)justAfter_stopForResultAddr
3246 << ", breakAddr=" << (void*)breakAddr
3247 << ", count=" << count << " so end addr="
3248 << (void*)(tempTrampBase + count - 1) << endl;
3250 #if defined(MT_DEBUG)
3251 sprintf(errorLine,"********>>>>> tempTrampBase = 0x%x\n",tempTrampBase);
3255 /* Now, write to the tempTramp, in the inferior addr's data space
3256 (all tramps are allocated in data space) */
3257 if (!writeDataSpace((void*)tempTrampBase, count, insnBuffer)) {
3258 // should put up a nice error dialog window
3259 cerr << "createRPCtempTramp failed because writeDataSpace failed" << endl;
3263 extern int trampBytes; // stats.h
3264 trampBytes += count;
3266 return tempTrampBase;
3269 bool process::handleTrapIfDueToRPC() {
3270 // get curr PC register (can assume process is stopped), search for it in
3271 // 'currRunningRPCs'. If found, restore regs, do callback, delete tramp, and
3272 // return true. Returns false if not processed.
3274 assert(status_ == stopped); // a TRAP should always stop a process (duh)
3276 if (currRunningRPCs.empty())
3277 return false; // no chance of a match
3279 assert(currRunningRPCs.size() == 1);
3280 // it's unsafe to have > 1 RPCs going on at a time within a single process
3282 // Okay, time to do a stack trace.
3283 // If we determine that the PC of any level of the back trace
3284 // equals the current running RPC's stopForResultAddr or breakAddr,
3285 // then we have a match. Note: since all platforms currently
3286 // inline their trap/ill instruction instead of make a fn call e.g. to
3287 // DYNINSTbreakPoint(), we can probably get rid of the stack walk.
3289 int match_type = 0; // 1 --> stop for result, 2 --> really done
3290 Frame theFrame(this);
3292 // do we have a match?
3293 const int framePC = theFrame.getPC();
3294 if ((unsigned)framePC == currRunningRPCs[0].breakAddr) {
3295 // we've got a match!
3299 else if (currRunningRPCs[0].callbackFunc != NULL &&
3300 ((unsigned)framePC == currRunningRPCs[0].stopForResultAddr)) {
3305 if (theFrame.isLastFrame())
3306 // well, we've gone as far as we can, with no match.
3309 // else, backtrace 1 more level
3310 theFrame = theFrame.getPreviousStackFrameInfo(this);
3313 assert(match_type == 1 || match_type == 2);
3315 inferiorRPCinProgress &theStruct = currRunningRPCs[0];
3317 if (match_type == 1) {
3318 // We have stopped in order to grab the result. Grab it and write
3319 // to theStruct.resultValue, for use when we get match_type==2.
3321 inferiorrpc_cerr << "Welcome to handleTrapIfDueToRPC match type 1" << endl;
3323 assert(theStruct.callbackFunc != NULL);
3324 // must be a callback to ever see this match_type
3326 const unsigned returnValue = read_inferiorRPC_result_register(theStruct.resultRegister);
3328 extern registerSpace *regSpace;
3329 regSpace->freeRegister(theStruct.resultRegister);
3331 theStruct.resultValue = returnValue;
3333 // we don't remove the RPC from 'currRunningRPCs', since it's not yet done.
3334 // we continue the process...but not quite at the PC where we left off, since
3335 // that will just re-do the trap! Instead, we need to continue at the location
3336 // of the next instruction.
3337 if (!changePC(theStruct.justAfter_stopForResultAddr))
3340 if (!continueProc())
3341 cerr << "RPC getting result: continueProc failed" << endl;
3346 inferiorrpc_cerr << "Welcome to handleTrapIfDueToRPC match type 2" << endl;
3348 assert(match_type == 2);
3350 // step 1) restore registers:
3351 if (!restoreRegisters(theStruct.savedRegs)) {
3352 cerr << "handleTrapIfDueToRPC failed because restoreRegisters failed" << endl;
3355 currRunningRPCs.removeByIndex(0);
3357 if (currRunningRPCs.empty() && deferredContinueProc) {
3358 // We have a pending continueProc that we had to delay because
3359 // there was an inferior RPC in progress at that time, but now
3360 // we are ready to execute it - naim
3361 deferredContinueProc=false;
3362 if (continueProc()) statusLine("application running");
3365 delete [] theStruct.savedRegs;
3367 // step 2) delete temp tramp
3368 vector< vector<unsigned> > pointsToCheck;
3369 // blank on purpose; deletion is safe to take place even right now
3370 inferiorFree(this, theStruct.firstInstrAddr, textHeap, pointsToCheck);
3372 // step 3) continue process, if appropriate
3373 if (theStruct.wasRunning) {
3374 inferiorrpc_cerr << "end of rpc -- continuing process, since it had been running" << endl;
3376 if (!continueProc()) {
3377 cerr << "RPC completion: continueProc failed" << endl;
3381 inferiorrpc_cerr << "end of rpc -- leaving process paused, since it wasn't running before" << endl;
3383 // step 4) invoke user callback, if any
3384 // note: I feel it's important to do the user callback last, since it
3385 // may perform arbitrary actions (such as making igen calls) which can lead
3386 // to re-actions (such as receiving igen calls) that can alter the process
3387 // (e.g. continuing it). So clearly we need to restore registers, change the
3388 // PC, etc. BEFORE any such thing might happen. Hence we do the callback last.
3389 // I think the only potential controversy is whether we should do the callback
3390 // before step 3, above.
3392 inferiorrpc_cerr << "handleTrapIfDueToRPC match type 2 -- about to do callbackFunc, if any" << endl;
3394 if (theStruct.callbackFunc)
3395 theStruct.callbackFunc(this, theStruct.userData, theStruct.resultValue);
3397 inferiorrpc_cerr << "handleTrapIfDueToRPC match type 2 -- done with callbackFunc, if any" << endl;
3402 void process::installBootstrapInst() {
3403 // instrument main to call DYNINSTinit(). Don't use the shm seg for any
3404 // temp tramp space, since we can't assume that it's been intialized yet.
3405 // We build an ast saying: "call DYNINSTinit() with args
3406 // key_base, nbytes, paradynd_pid"
3408 #ifdef BPATCH_LIBRARY
3409 vector<AstNode *> the_args(2);
3411 the_args[0] = new AstNode(AstNode::Constant, (void*)1);
3412 the_args[1] = new AstNode(AstNode::Constant, (void*)getpid());
3414 AstNode *ast = new AstNode("DYNINSTinit", the_args);
3416 vector<AstNode *> the_args(3);
3418 // 2 dummy args when not shm sampling (just don't use -1, which is reserved
3420 unsigned numBytes = 0;
3423 key_t theKey = getShmKeyUsed();
3424 numBytes = getShmHeapTotalNumBytes();
3429 #ifdef SHM_SAMPLING_DEBUG
3430 cerr << "paradynd inst.C: about to call DYNINSTinit() with key=" << theKey
3431 << " and #bytes=" << numBytes << endl;
3434 the_args[0] = new AstNode(AstNode::Constant, (void*)theKey);
3435 the_args[1] = new AstNode(AstNode::Constant, (void*)numBytes);
3436 #ifdef BPATCH_LIBRARY
3437 // Unused by the dyninstAPI library
3438 the_args[2] = new AstNode(AstNode::Constant, (void *)0);
3440 the_args[2] = new AstNode(AstNode::Constant, (void*)traceConnectInfo);
3443 AstNode *ast = new AstNode("DYNINSTinit", the_args);
3444 for (unsigned j=0; j<the_args.size(); j++) {
3445 removeAst(the_args[j]);
3447 #endif /* BPATCH_LIBRARY */
3449 function_base *func = getMainFunction();
3452 instPoint *func_entry = (instPoint *)func->funcEntry(this);
3453 addInstFunc(this, func_entry, ast, callPreInsn,
3455 true // true --> don't try to have tramp code update the cost
3457 // returns an "instInstance", which we ignore (but should we?)
3461 void process::installInstrRequests(const vector<instMapping*> &requests) {
3462 for (unsigned lcv=0; lcv < requests.size(); lcv++) {
3463 instMapping *req = requests[lcv];
3465 function_base *func = findOneFunction(req->func);
3467 continue; // probably should have a flag telling us whether errors should
3468 // be silently handled or not
3471 if (req->where & FUNC_ARG) {
3472 // ast = new AstNode(req->inst, req->arg);
3473 ast = new AstNode(req->inst, req->args);
3475 AstNode *tmp = new AstNode(AstNode::Constant, (void*)0);
3476 ast = new AstNode(req->inst, tmp);
3480 if (req->where & FUNC_EXIT) {
3481 const vector<instPoint*> func_rets = func->funcExits(this);
3482 for (unsigned j=0; j < func_rets.size(); j++)
3483 (void)addInstFunc(this, func_rets[j], ast,
3484 callPreInsn, orderLastAtPoint, false);
3488 if (req->where & FUNC_ENTRY) {
3489 instPoint *func_entry = (instPoint *)func->funcEntry(this);
3490 (void)addInstFunc(this, func_entry, ast,
3491 callPreInsn, orderLastAtPoint, false);
3495 if (req->where & FUNC_CALL) {
3496 vector<instPoint*> func_calls = func->funcCalls(this);
3497 if (func_calls.size() == 0)
3500 for (unsigned j=0; j < func_calls.size(); j++)
3501 (void)addInstFunc(this, func_calls[j], ast,
3502 callPreInsn, orderLastAtPoint, false);
3510 bool process::extractBootstrapStruct(DYNINST_bootstrapStruct *bs_record) {
3511 const string vrbleName = "DYNINST_bootstrap_info";
3514 bool flag = findInternalSymbol(vrbleName, true, sym);
3517 Address symAddr = sym.getAddr();
3519 if (!readDataSpace((const void*)symAddr, sizeof(*bs_record), bs_record, true)) {
3520 cerr << "extractBootstrapStruct failed because readDataSpace failed" << endl;
3527 bool process::handleStopDueToExecEntry() {
3528 // returns true iff we are processing a stop due to the entry point of exec
3529 // The exec hasn't yet occurred.
3531 assert(status_ == stopped);
3533 DYNINST_bootstrapStruct bs_record;
3534 if (!extractBootstrapStruct(&bs_record))
3537 if (bs_record.event != 4)
3540 assert(getPid() == bs_record.pid);
3542 // for now, we just set aside the following information, to be used after the
3543 // exec actually happens (we'll get a SIGTRAP for that).
3546 execFilePath = string(bs_record.path);
3548 // the process was stopped...let's continue it so we can process the exec...
3549 assert(status_ == stopped);
3550 if (!continueProc())
3553 // should we set status_ to neonatal now? Nah, probably having the inExec flag
3554 // set is good enough...
3556 // shouldn't we be setting reachedFirstBreak to false???
3561 int process::procStopFromDYNINSTinit() {
3562 // possible return values:
3563 // 0 --> no, the stop wasn't the end of DYNINSTinit
3564 // 1 --> handled stop at end of DYNINSTinit, leaving program paused
3565 // 2 --> handled stop at end of DYNINSTinit...which had been invoked via
3566 // inferiorRPC...so we've continued the process in order to let the
3567 // inferiorRPC get its sigtrap.
3569 // Note that DYNINSTinit could have been run under several cases:
3570 // 1) the normal case (detect by bs_record.event==1 && execed_ == false)
3571 // 2) called after a fork (detect by bs_record.event==2)
3572 // 3) called after an exec (detect by bs_record.event==1 and execed_ == true)
3573 // 4) called for an attach (detect by bs_record.event==3)
3574 // note that bs_record.event == 4 is reserved for "sending" a tr_exec "record".
3576 // The exec case is tricky: we must loop thru all component mi's of this process
3577 // and decide now whether or not to carry them over to the new process.
3579 // if 0 is returned, there must be no side effects.
3581 assert(status_ == stopped);
3583 if (hasBootstrapped)
3586 DYNINST_bootstrapStruct bs_record;
3587 if (!extractBootstrapStruct(&bs_record))
3590 // Read the structure; if event 0 then it's undefined! (not yet written)
3591 if (bs_record.event == 0)
3594 forkexec_cerr << "procStopFromDYNINSTinit pid " << getPid() << "; got rec" << endl;
3596 assert(bs_record.event == 1 || bs_record.event == 2 || bs_record.event==3);
3597 assert(bs_record.pid == getPid());
3599 if (bs_record.event != 3) {
3600 // we don't want to do this stuff (yet) when DYNINSTinit was run via attach...we
3601 // want to wait until the inferiorRPC (thru which DYNINSTinit is being run)
3603 handleCompletionOfDYNINSTinit(false);
3607 if (!continueProc())
3613 void process::handleCompletionOfDYNINSTinit(bool fromAttach) {
3614 // 'event' values: (1) DYNINSTinit was started normally via paradynd
3615 // or via exec, (2) called from fork, (3) called from attach.
3617 DYNINST_bootstrapStruct bs_record;
3618 if (!extractBootstrapStruct(&bs_record))
3621 if (!fromAttach) // reset to 0 already if attaching, but other fields (attachedAtPtr) ok
3622 assert(bs_record.event == 1 || bs_record.event == 2 || bs_record.event==3);
3624 assert(bs_record.pid == getPid());
3626 // Note: the process isn't necessarily paused at this moment. In particular,
3627 // if we had attached to the process, then it will be running even as we speak.
3628 // While we're parsing the shared libraries, we should pause. So do that now.
3630 if (needToContinueAfterDYNINSTinit)
3633 wasRunning = status_ == running;
3636 const bool calledFromFork = (bs_record.event == 2);
3637 const bool calledFromExec = (bs_record.event == 1 && execed_);
3638 const bool calledFromAttach = fromAttach || bs_record.event == 3;
3639 if (calledFromAttach)
3640 assert(createdViaAttach);
3643 if (!calledFromFork)
3644 registerInferiorAttachedSegs(bs_record.appl_attachedAtPtr);
3647 if (!calledFromFork)
3648 getObservedCostAddr();
3650 // handleStartProcess gets shared objects, so no need to do it again after a fork.
3651 // (question: do we need to do this after an exec???)
3652 if (!calledFromFork) {
3653 string str=string("PID=") + string(bs_record.pid) + ", calling handleStartProcess...";
3654 statusLine(str.string_of());
3656 #if !defined(USES_LIBDYNINSTRT_SO)
3657 if (!handleStartProcess()) {
3658 // reads in shared libraries...can take a while
3659 logLine("WARNING: handleStartProcess failed\n");
3663 #ifndef BPATCH_LIBRARY
3664 // we decrement the batch mode here; it matches the bump-up in createProcess()
3665 tp->resourceBatchMode(false);
3668 str=string("PID=") + string(bs_record.pid) + ", installing default inst...";
3669 statusLine(str.string_of());
3671 extern vector<instMapping*> initialRequests; // init.C
3672 installInstrRequests(initialRequests);
3674 str=string("PID=") + string(bs_record.pid) + ", propagating mi's...";
3675 statusLine(str.string_of());
3677 forkexec_cerr << "procStopFromDYNINSTinit pid " << getPid() << "; about to propagate mi's" << endl;
3679 #ifndef BPATCH_LIBRARY
3680 if (!calledFromExec) {
3681 // propagate any metric that is already enabled to the new process.
3682 // For a forked process, this isn't needed because handleFork() has its own
3683 // special propagation algorithm (it propagates every aggregate mi having the
3684 // parent as a component, except for aggregate mi's whose focus is specifically
3685 // refined to the parent).
3686 vector<metricDefinitionNode *> MIs = allMIs.values();
3687 for (unsigned j = 0; j < MIs.size(); j++) {
3688 MIs[j]->propagateToNewProcess(this);
3689 // change to a process:: method which takes in the metricDefinitionNode