Added several calls to API (waitForStatusChange, BPatch_variableExpr
[dyninst.git] / dyninstAPI / src / unix.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42
43 #include "util/h/headers.h"
44 #include "util/h/String.h"
45 #include "util/h/Vector.h"
46 #include "paradynd/src/showerror.h"
47 #include "dyninstAPI/src/os.h"
48 #include "dyninstAPI/src/util.h"
49
50 #ifndef BPATCH_LIBRARY
51 #include "paradynd/src/perfStream.h"
52 #include "paradynd/src/main.h"
53 #endif
54
55 // the following are needed for handleSigChild
56 #include "dyninstAPI/src/process.h"
57 #include "dyninstAPI/src/instP.h"
58 #include "dyninstAPI/src/stats.h"
59 extern process *findProcess(int);
60
61 // The following were all defined in process.C (for no particular reason)
62 extern debug_ostream attach_cerr;
63 extern debug_ostream inferiorrpc_cerr;
64 extern debug_ostream shmsample_cerr;
65 extern debug_ostream forkexec_cerr;
66 extern debug_ostream metric_cerr;
67 extern debug_ostream signal_cerr;
68 extern debug_ostream sharedobj_cerr;
69
70
71 extern "C" {
72 #ifdef PARADYND_PVM
73 int pvmputenv (const char *);
74 int pvmendtask();
75 #endif
76 }
77
78 /*****************************************************************************
79  * forkNewProcess: starts a new process, setting up trace and io links between
80  *                the new process and the daemon
81  * Returns true if succesfull.
82  * 
83  * Arguments:
84  *   file: file to execute
85  *   dir: working directory for the new process
86  *   argv: arguments to new process
87  *   envp: environment **** not in use
88  *   inputFile: where to redirect standard input
89  *   outputFile: where to redirect standard output
90  *   traceLink: handle or file descriptor of trace link (read only)
91  *   ioLink: handle or file descriptor of io link (read only)
92  *   pid: process id of new process
93  *   tid: thread id for main thread (needed by WindowsNT)
94  *   procHandle: handle for new process (needed by WindowsNT)
95  *   thrHandle: handle for main thread (needed by WindowsNT)
96  ****************************************************************************/
97 bool forkNewProcess(string file, string dir, vector<string> argv, 
98                     vector<string>envp, string inputFile, string outputFile,
99                     int &traceLink, int &ioLink, 
100                     int &pid, int & /*tid*/, 
101                     int & /*procHandle*/, int & /*thrHandle*/) {
102
103 #ifndef BPATCH_LIBRARY
104     // Strange, but using socketpair here doesn't seem to work OK on SunOS.
105     // Pipe works fine.
106     // r = P_socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, tracePipe);
107     int tracePipe[2];
108     int r = P_pipe(tracePipe);
109     if (r) {
110         // P_perror("socketpair");
111         string msg = string("Unable to create trace pipe for program '") + file +
112                        string("': ") + string(sys_errlist[errno]);
113         showErrorCallback(68, msg);
114         return false;
115     }
116
117     // ioPipe is used to redirect the child's stdout & stderr to a pipe which is in
118     // turn read by the parent via the process->ioLink socket.
119     int ioPipe[2];
120
121     // r = P_socketpair(AF_UNIX, SOCK_STREAM, (int) NULL, ioPipe);
122     r = P_pipe(ioPipe);
123     if (r) {
124         // P_perror("socketpair");
125         string msg = string("Unable to create IO pipe for program '") + file +
126                        string("': ") + string(sys_errlist[errno]);
127         showErrorCallback(68, msg);
128         return false;
129     }
130 #endif
131
132     //
133     // WARNING This code assumes that vfork is used, and a failed exec will
134     //   corectly change failed in the parent process.
135     //
136     
137     errno = 0;
138 #if defined(PARADYND_PVM) || defined(BPATCH_LIBRARY)
139 // must use fork, since pvmendtask will do some writing in the address space
140     pid = fork();
141     // fprintf(stderr, "FORK: pid=%d\n", pid);
142 #else
143     pid = vfork();
144 #endif
145
146     if (pid > 0) {
147
148         //*** parent
149
150         if (errno) {
151             sprintf(errorLine, "Unable to start %s: %s\n", file.string_of(), 
152                     sys_errlist[errno]);
153             logLine(errorLine);
154             showErrorCallback(68, (const char *) errorLine);
155             return false;
156         }
157
158 #ifndef BPATCH_LIBRARY
159         close(tracePipe[1]);
160            // parent never writes trace records; it only receives them.
161
162         close(ioPipe[1]);
163            // parent closes write end of io pipe; child closes its read end.
164            // pipe output goes to the parent's read fd (ret->ioLink); pipe input
165            // comes from the child's write fd.  In short, when the child writes to
166            // its stdout/stderr, it gets sent to the pipe which in turn sends it to
167            // the parent's ret->ioLink fd for reading.
168
169         traceLink = tracePipe[0];
170         ioLink = ioPipe[0];
171 #endif
172         return true;
173
174     } else if (pid == 0) {
175         //*** child
176
177 #ifdef PARADYND_PVM
178         if (pvm_running)
179           pvmendtask(); 
180 #endif   
181
182 #ifndef BPATCH_LIBRARY
183         // handle stdio.
184
185         // We only write to ioPipe.  Hence we close ioPipe[0], the read end.  Then we
186         // call dup2() twice to assign our stdout and stderr to the write end of the
187         // pipe.
188         close(ioPipe[0]);
189         dup2(ioPipe[1], 1);
190            // assigns fd 1 (stdout) to be a copy of ioPipe[1].  (Since stdout is already
191            // in use, dup2 will first close it then reopen it with the characteristics
192            // of ioPipe[1].)
193            // In short, stdout gets redirected towards the write end of the pipe.
194            // The read end of the pipe is read by the parent (paradynd), not by us.
195
196         dup2(ioPipe[1], 2); // redirect fd 2 (stderr) to the pipe, like above.
197
198         // We're not using ioPipe[1] anymore; close it.
199         if (ioPipe[1] > 2) close (ioPipe[1]);
200
201         // Now that stdout is going to a pipe, it'll (unfortunately) be block buffered
202         // instead of the usual line buffered (when it goes to a tty).  In effect the
203         // stdio library is being a little too clever for our purposes.  We don't want
204         // the "bufferedness" to change.  So we set it back to line-buffered.
205         // The command to do this is setlinebuf(stdout) [stdio.h call]  But we don't
206         // do it here, since the upcoming execve() would undo our work [execve keeps
207         // fd's but resets higher-level stdio information, which is recreated before
208         // execution of main()]  So when do we do it?  In rtinst's DYNINSTinit
209         // (RTposix.c et al.)
210
211         // setup stderr for rest of exec try.
212         FILE *childError = P_fdopen(2, "w");
213
214         P_close(tracePipe[0]);
215
216         if (P_dup2(tracePipe[1], 3) != 3) {
217             fprintf(childError, "dup2 failed\n");
218             fflush(childError);
219             P__exit(-1);
220         }
221
222         /* close if higher */
223         if (tracePipe[1] > 3) close(tracePipe[1]);
224
225         if ((dir.length() > 0) && (P_chdir(dir.string_of()) < 0)) {
226           sprintf(errorLine, "cannot chdir to '%s': %s\n", dir.string_of(), 
227                   sys_errlist[errno]);
228           logLine(errorLine);
229           P__exit(-1);
230         }
231 #endif
232 #if !defined(BPATCH_LIBRARY) || defined(BPATCH_REDIRECT_IO)
233 #if defined(BPATCH_LIBRARY) /* For BPATCH_REDIRECT_IO */
234         FILE *childError = stderr;
235 #endif
236         /* see if I/O needs to be redirected */
237         if (inputFile.length()) {
238             int fd = P_open(inputFile.string_of(), O_RDONLY, 0);
239             if (fd < 0) {
240                 fprintf(childError, "stdin open of %s failed\n", inputFile.string_of());
241                 fflush(childError);
242                 P__exit(-1);
243             } else {
244                 dup2(fd, 0);
245                 P_close(fd);
246             }
247         }
248
249         if (outputFile.length()) {
250             int fd = P_open(outputFile.string_of(), O_WRONLY|O_CREAT, 0444);
251             if (fd < 0) {
252                 fprintf(childError, "stdout open of %s failed\n", outputFile.string_of());
253                 fflush(childError);
254                 P__exit(-1);
255             } else {
256                 dup2(fd, 1); // redirect fd 1 (stdout) to a copy of descriptor "fd"
257                 P_close(fd); // not using descriptor fd any more; close it.
258             }
259         }
260 #endif
261
262         /* indicate our desire to be traced */
263         errno = 0;
264         OS::osTraceMe();
265         if (errno != 0) {
266           sprintf(errorLine, "ptrace error, exiting, errno=%d\n", errno);
267           logLine(errorLine);
268           logLine(sys_errlist[errno]);
269           showErrorCallback(69, string("Internal error: ") + 
270                                 string((const char *) errorLine)); 
271           P__exit(-1);   // double underscores are correct
272         }
273 #ifdef PARADYND_PVM
274         if (pvm_running && envp.size())
275           for (int ep=envp.size()-1; ep>=0; ep--) {
276             pvmputenv(envp[ep].string_of());
277           }
278 #endif
279 #ifndef BPATCH_LIBRARY
280         // hand off info about how to start a paradynd to the application.
281         //   used to catch rexec calls, and poe events.
282         //
283         char paradynInfo[1024];
284         sprintf(paradynInfo, "PARADYN_MASTER_INFO= ");
285         for (unsigned i=0; i < process::arg_list.size(); i++) {
286             const char *str;
287
288             str = P_strdup(process::arg_list[i].string_of());
289             if (!strcmp(str, "-l1")) {
290                 strcat(paradynInfo, "-l0");
291             } else {
292                 strcat(paradynInfo, str);
293             }
294             strcat(paradynInfo, " ");
295         }
296         P_putenv(paradynInfo);
297 #endif
298
299         char **args;
300         args = new char*[argv.size()+1];
301         for (unsigned ai=0; ai<argv.size(); ai++)
302           args[ai] = P_strdup(argv[ai].string_of());
303         args[argv.size()] = NULL;
304         P_execvp(file.string_of(), args);
305
306         sprintf(errorLine, "paradynd: execv failed, errno=%d\n", errno);
307         logLine(errorLine);
308
309         logLine(sys_errlist[errno]);
310 {
311         int i=0;
312         while (args[i]) {
313           sprintf(errorLine, "argv %d = %s\n", i, args[i]);
314           logLine(errorLine);
315           i++;
316         }
317 }
318         P__exit(-1);
319         // not reached
320
321         return false;
322
323     } else { // pid == 0 --- error
324         sprintf(errorLine, "vfork failed, errno=%d\n", errno);
325         logLine(errorLine);
326         showErrorCallback(71, (const char *) errorLine);
327         return false;
328     }
329
330 }
331
332
333
334 /* 
335    TODO: cleanup handleSigChild. This function has a lot of code that
336    should be moved to a machine independent place (a lot of what is
337    going on here will probably have to be moved anyway once we move to
338    the dyninstAPI).
339
340    There is a different version of this function for WindowsNT. If any changes
341    are made here, they will probably also be needed in the NT version.
342
343    --mjrg
344 */
345
346 // TODO -- make this a process method
347 int handleSigChild(int pid, int status)
348 {
349 #ifdef rs6000_ibm_aix4_1
350     // On AIX, we get sigtraps on fork and load, and must handle
351     // these cases specially
352     extern bool handleAIXsigTraps(int, int);
353     if (handleAIXsigTraps(pid, status)) {
354       return 0;
355     }
356     /* else check for regular traps and signals */
357 #endif
358
359     // ignore signals from unknown processes
360     process *curr = findProcess(pid);
361     if (!curr) {
362        forkexec_cerr << "handleSigChild pid " << pid << " is an unknown process." << endl;
363        forkexec_cerr << "WIFSTOPPED=" << (WIFSTOPPED(status) ? "true" : "false");
364        if (WIFSTOPPED(status)) {
365           forkexec_cerr << "WSTOPSIG=" << WSTOPSIG(status);
366        }
367        forkexec_cerr << endl << flush;
368 #ifdef rs6000_ibm_aix4_1
369        cerr << "handleSigChild:  Detaching process " << pid 
370             << " and continuing." << endl;
371        return ptrace(PT_DETACH, pid, (int *)0, SIGCONT, 0);   //Set process free
372 #endif
373        return -1;
374     }
375
376     if (WIFSTOPPED(status)) {
377         int sig = WSTOPSIG(status);
378         switch (sig) {
379
380             case SIGTSTP:
381                 sprintf(errorLine, "process %d got SIGTSTP", pid);
382                 statusLine(errorLine);
383                 curr->Stopped();
384                 break;
385
386             case SIGTRAP: {
387                 // Note that there are now several uses for SIGTRAPs in paradynd.
388                 // The original use was to detect when a ptraced process had
389                 // started up.  Several have been added.  We must be careful
390                 // to make sure that uses of SIGTRAPs do not conflict.
391
392                 signal_cerr << "welcome to SIGTRAP for pid " << curr->getPid() << " status=" << curr->getStatusAsString() << endl;
393                 const bool wasRunning = (curr->status() == running);
394                 curr->status_ = stopped;
395
396                 // Check to see if the TRAP is due to a system call exit which
397                 // we were waiting for, in order to launch an inferior rpc safely.
398                 if (curr->isRPCwaitingForSysCallToComplete()) {
399                    inferiorrpc_cerr << "got SIGTRAP indicating syscall completion!"
400                                     << endl;
401                    curr->setRPCwaitingForSysCallToComplete(false);
402
403                    if (curr->launchRPCifAppropriate(false, // not running
404                                                     true   // finishing a syscall
405                                                     )) {
406                       inferiorrpc_cerr << "syscall completion: rpc launched ok, as expected " << endl;
407                    }
408                    else {
409                      inferiorrpc_cerr << "syscall completion: failed to launch rpc" << endl;
410                      if (!curr->continueProc()) {
411                        sprintf(errorLine,"WARNING: failed to continue process with pid=%d\n",curr->getPid());
412                        logLine(errorLine);
413                      }
414                    }
415                    break;
416                 }
417
418                 // check to see if trap is due to dlopen or dlcose event
419                 if(curr->isDynamicallyLinked()){
420                     if(curr->handleIfDueToSharedObjectMapping()){
421                       if (wasRunning && !curr->continueProc()) {
422                         assert(0);
423                       }
424                       break;
425                     }
426                 }
427
428 #if defined(USES_LIBDYNINSTRT_SO)
429                 // this code has to go after we have handle the trap
430                 // due to the call to dlopen - naim
431                 if (curr->trapDueToDyninstLib()) {
432                   curr->handleIfDueToDyninstLib();
433                   // fall through...
434                 }
435 #endif
436
437                 //If the list is not empty, it means some previous
438                 //instrumentation has yet need to be finished.
439                 if (instWList.size() != 0) {
440                     // cerr << "instWList is full" << endl;
441                     if(curr -> cleanUpInstrumentation(wasRunning)){
442                         break; // successfully processed the SIGTRAP
443                     }
444                 }
445
446                 if (curr->handleTrapIfDueToRPC()) {
447                    inferiorrpc_cerr << "processed RPC response in SIGTRAP" << endl;
448                    break;
449                 }
450
451                 if (curr->inExec) {
452                    // the process has executed a succesful exec, and is now
453                    // stopped at the exit of the exec call.
454
455                    forkexec_cerr << "SIGTRAP: inExec is true, so doing process::handleExec()!" << endl;
456                    string buffer = string("process ") + string(curr->getPid()) +
457                                    " has performed exec() syscall";
458                    statusLine(buffer.string_of());
459
460                    // call handleExec to clean our internal data structures, reparse
461                    // symbol table.  handleExec does not insert instrumentation or do
462                    // any propagation.  Why not?  Because it wouldn't be safe -- the
463                    // process hasn't yet been bootstrapped (run DYNINST, etc.)  Only
464                    // when we get the breakpoint at the end of DYNINSTinit() is it safe
465                    // to insert instrumentation and allocate timers & counters...
466                    curr->handleExec();
467
468 #ifndef BPATCH_LIBRARY
469                    // need to start resourceBatchMode here because we will call
470                    //  tryToReadAndProcessBootstrapInfo which
471                    // calls tp->resourceBatchMode(false)
472                    tp->resourceBatchMode(true);
473 #endif
474
475                    // set reachedFirstBreak to false here, so we execute
476                    // the code below, and insert the initial instrumentation
477                    // in the new image. (Actually, this is already done by handleExec())
478                    curr->reachedFirstBreak = false;
479
480                    // fall through...
481                 }
482
483                 // Now we expect that this TRAP is the initial trap sent when a ptrace'd
484                 // process completes startup via exec (or when an exec syscall was
485                 // executed in an already-running process).
486                 // But we must query 'reachedFirstBreak' because on machines where we
487                 // attach/detach on pause/continue, a TRAP is generated on each pause!
488
489 #if defined(USES_LIBDYNINSTRT_SO)
490                 if (!curr->reachedVeryFirstTrap) {
491                   // we haven't executed main yet, so we can insert a trap
492                   // at the entry point of main - naim
493                   curr->reachedVeryFirstTrap = true;
494                   curr->insertTrapAtEntryPointOfMain();
495                   if (!curr->continueProc()) {
496                     assert(0);
497                   }
498                   break;
499                 } else {
500                   if (curr->trapAtEntryPointOfMain() &&
501                       !curr->dyninstLibAlreadyLoaded() &&
502                       !curr->dyninstLibIsBeingLoaded()) {
503                      curr->handleTrapAtEntryPointOfMain();
504                      if (curr->handleStartProcess()) {
505                        curr->dlopenDYNINSTlib();
506                        // this will set isLoadingDyninstLib to true - naim
507                      } else {
508                        logLine("WARNING: handleStartProcess failed\n");
509                        assert(0);
510                      }
511                      if (!curr->continueProc()) {
512                        assert(0);
513                      }
514                      break;
515                   }
516                   // fall through...
517                 }
518                 if (curr->dyninstLibAlreadyLoaded() &&
519                     !curr->dyninstLibIsBeingLoaded()) {
520                   // we are ready to handle reachedFirstBreak. The first
521                   // condition means that dyninstRT.so.1 has been loaded
522                   // already. The second condition makes sure that we have
523                   // handle the trap after loading dyninstRT.so.1 and we
524                   // have restored the original instructions in the place
525                   // we use to call dlopen - naim
526                   // process the code below yet - naim
527                 } else {
528                   // if this is not the case, then we are not ready to
529                   // process the code below yet - naim
530                   string msg = string("Process") + string(curr->getPid()) +
531                                string(" was unable to load file ") + 
532 #ifdef BPATCH_LIBRARY
533                                string(getenv("DYNINSTAPI_RT_LIB"));
534 #else
535                                string(getenv("PARADYN_LIB"));
536 #endif
537                   showErrorCallback(101, msg);
538                   break;
539                 }
540 #endif
541
542                 if (!curr->reachedFirstBreak) { // vrble should be renamed 'reachedFirstTrap'
543                    string buffer = string("PID=") + string(pid);
544                    buffer += string(", passed trap at start of program");
545                    statusLine(buffer.string_of());
546
547                    // check for DYNINST symbols and initializes the inferiorHeap
548                    // If libdyninst is dynamically linked, this can only be
549                    // called after libdyninst is loaded
550                    curr->initDyninstLib();
551
552                    curr->reachedFirstBreak = true;
553
554                    buffer=string("PID=") + string(pid) + ", installing call to DYNINSTinit()";
555                    statusLine(buffer.string_of());
556
557                    curr->installBootstrapInst();
558
559                    // now, let main() and then DYNINSTinit() get invoked.  As it
560                    // completes, DYNINSTinit() does a DYNINSTbreakPoint, at which time
561                    // we read bootstrap information "sent back" (in a global vrble),
562                    // propagate metric instances, do tp->newProgramCallbackFunc(), etc.
563                    if (!curr->continueProc()) {
564                       cerr << "continueProc after installBootstrapInst() failed, so DYNINSTinit() isn't being invoked yet, which it should!" << endl;
565                    }
566                    else {
567                       buffer=string("PID=") + string(pid) + ", running DYNINSTinit()...";
568                       statusLine(buffer.string_of());
569                    }
570                 }
571                 else {
572                    signal_cerr << "SIGTRAP not handled for pid " << pid << " so just leaving process in stopped state" << endl << flush;
573                 }
574
575                 break;
576             }
577
578             case SIGSTOP:
579             case SIGINT: {
580                 signal_cerr << "welcome to SIGSTOP/SIGINT for proc pid " << curr->getPid() << endl;
581
582                 const processState prevStatus = curr->status_;
583                 // assert(prevStatus != stopped); (bombs on sunos and AIX, when lots of spurious sigstops are delivered)
584
585                 curr->status_ = stopped;
586                    // the following routines expect (and assert) this status.
587
588                 int result = curr->procStopFromDYNINSTinit();
589                 assert(result >=0 && result <= 2);
590                 if (result != 0) {
591                    forkexec_cerr << "processed SIGSTOP from DYNINSTinit for pid " << curr->getPid() << endl << flush;
592
593                    if (result == 1) {
594                       assert(curr->status_ == stopped);
595                       // DYNINSTinit() after normal startup, after fork, or after exec
596                       // syscall was made by a running program; leave paused
597                       // (tp->newProgramCallback() to paradyn will result in the process
598                       // being continued soon enough, assuming the applic was running,
599                       // which is true in all cases except when an applic is just being
600                       // started up).  Fall through (we want the status line to change)
601                    } else {
602                       assert(result == 2);
603                       break; // don't fall through...prog is finishing the inferiorRPC
604                    }
605                 }
606                 else if (curr->handleTrapIfDueToRPC()) {
607                    inferiorrpc_cerr << "processed RPC response in SIGSTOP" << endl;
608                    break; // don't want to execute ->Stopped() which changes status line
609                 }
610 #ifndef BPATCH_LIBRARY
611                 else if (curr->handleStopDueToExecEntry()) {
612                    // grabs data from DYNINST_bootstrap_info
613                    forkexec_cerr << "fork/exec -- handled stop before exec" << endl;
614                    string buffer = string("process ") + string(curr->getPid()) +
615                                    " performing exec() syscall...";
616                    statusLine(buffer.string_of());
617
618                    // note: status will now be 'running', since handleStopDueToExec()
619                    // did a continueProc() to let the exec() syscall go forward.
620                    assert(curr->status_ == running);
621                       // would neonatal be better? or exited?
622
623                    break; // don't want to change status line in conventional way
624                 }
625 #endif /* BPATCH_LIBRARY */
626                 else {
627                    forkexec_cerr << "unhandled SIGSTOP for pid " << curr->getPid() << " so just leaving process in paused state." << endl << flush;
628                 }
629                 curr->status_ = prevStatus; // so Stopped() below won't be a nop
630                 curr->Stopped();
631
632                 break;
633             }
634
635             case SIGILL:
636                signal_cerr << "welcome to SIGILL" << endl << flush;
637                curr->status_ = stopped;
638
639                if (curr->handleTrapIfDueToRPC()) {
640                   inferiorrpc_cerr << "processed RPC response in SIGILL" << endl; cerr.flush();
641
642                   break; // we don't forward the signal -- on purpose
643                }
644                else
645                   // fall through, on purpose
646                   ;
647
648             case SIGIOT:
649             case SIGBUS:
650 #if (defined(POWER_DEBUG) || defined(HP_DEBUG)) && (defined(rs6000_ibm_aix4_1) || defined(hppa1_1_hp_hpux))
651                 // In this way, we will detach from the application and we
652                 // will be able to attach again using gdb. We need to send
653                 // a kill -ILL pid signal to the application in order to
654                 // get here - naim
655 #if defined(rs6000_ibm_aix4_1)
656                 {
657                   string hostName = getHostName();
658                   sprintf(errorLine, "***** Detaching from process %d "
659                                      "on host %s, ready for debugging...\n",
660                                      pid, hostName.string_of());
661                   logLine(errorLine);
662                 }
663                 if (ptrace(PT_DETACH,pid,(int *) 1, SIGSTOP, NULL) == -1) {
664 #else
665                 if (ptrace(PT_DETACH, pid, 1, SIGSTOP, NULL) == -1) { 
666 #endif
667                   logLine("ptrace error\n");
668                 }
669 #else
670                 signal_cerr << "caught signal, dying...  (sig="
671                             << WSTOPSIG(status) << ")" << endl << flush;
672
673                 curr->status_ = stopped;
674 #ifdef BPATCH_LIBRARY
675                 curr->dumpImage("imagefile");
676 #else
677                 curr->dumpImage();
678 #endif
679                 curr->continueWithForwardSignal(WSTOPSIG(status));
680 #endif
681                 break;
682
683             case SIGALRM:
684 #ifndef SHM_SAMPLING
685                 // Due to the DYNINSTin_sample variable, it's safest to launch
686                 // inferior-RPCs only when we know that the inferior is not in the
687                 // middle of processing an alarm-expire.  Otherwise, code that does
688                 // stuff like call DYNINSTstartWallTimer will appear to do nothing
689                 // (DYNINSTstartWallTimer will be invoked but will see that
690                 //  DYNINSTin_sample is set and so bails out!!!)
691                 // Ick.
692                 if (curr->existsRPCreadyToLaunch()) {
693                    curr -> status_ = stopped;
694                    (void)curr->launchRPCifAppropriate(true, false);
695                    break; // sure, we lose the SIGALARM, but so what.
696                 }
697                 else
698                    ; // no break, on purpose
699 #endif
700
701             case SIGCHLD:
702             case SIGUSR1:
703             case SIGUSR2:
704             case SIGVTALRM:
705             case SIGCONT:
706             case SIGSEGV:       // treadmarks needs this signal
707 #if (defined(POWER_DEBUG) || defined(HP_DEBUG)) && (defined(rs6000_ibm_aix4_1) || defined(hppa1_1_hp_hpux))
708                 // In this way, we will detach from the application and we
709                 // will be able to attach again using gdb - naim
710                 if (sig==SIGSEGV)
711                 {
712 #if defined(rs6000_ibm_aix4_1)
713                   if (ptrace(PT_DETACH,pid,(int *) 1, SIGSTOP, NULL) == -1)
714 #else
715                   if (ptrace(PT_DETACH,pid, 1, SIGSTOP, NULL) == -1)
716 #endif
717                     logLine("ptrace error\n");
718                   break;
719                 }
720 #endif
721                 if (!curr->continueWithForwardSignal(WSTOPSIG(status))) {
722                      logLine("error  in forwarding  signal\n");
723                      showErrorCallback(38, "Error  in forwarding  signal");
724                      //P_abort();
725                 }
726
727                 break;
728
729 #ifdef notdef
730             // XXXX for debugging
731             case SIGSEGV:       // treadmarks needs this signal
732                 sprintf(errorLine, "DEBUG: forwarding signal (sig=%d, pid=%d)\n"
733                         , WSTOPSIG(status), pid);
734                 logLine(errorLine);
735 #endif
736             default:
737                 if (!curr->continueWithForwardSignal(WSTOPSIG(status))) {
738                      logLine("error  in forwarding  signal\n");
739                      P_abort();
740                 }
741                 break;
742
743         }
744     } else if (WIFEXITED(status)) {
745 #if defined(PARADYND_PVM)
746 //        if (pvm_running) {
747 //            PDYN_reportSIGCHLD (pid, WEXITSTATUS(status));
748 //      }
749 #endif
750         sprintf(errorLine, "Process %d has terminated\n", curr->getPid());
751         statusLine(errorLine);
752         logLine(errorLine);
753
754         printDyninstStats();
755         handleProcessExit(curr, WEXITSTATUS(status));
756     } else if (WIFSIGNALED(status)) {
757         sprintf(errorLine, "process %d has terminated on signal %d\n", curr->getPid(), WTERMSIG(status));
758         logLine(errorLine);
759         statusLine(errorLine);
760         handleProcessExit(curr, WTERMSIG(status));
761     } else {
762         sprintf(errorLine, "Unknown state %d from process %d\n", status, curr->getPid());
763         logLine(errorLine);
764         showErrorCallback(39,(const char *) errorLine);
765     }
766     return(0);
767 }
768
769
770 void checkProcStatus() {
771    /* check for status change on inferior processes, or the arrival of
772       a signal. */
773
774    int wait_status;
775    int wait_pid = process::waitProcs(&wait_status);
776    if (wait_pid > 0) {
777       if (handleSigChild(wait_pid, wait_status) < 0) {
778          cerr << "handleSigChild failed for pid " << wait_pid << endl;
779       }
780    }
781 }
782
783
784 bool  OS::osKill(int pid) {
785   return (P_kill(pid,9)==0);
786 }