Extra debugging information in main.C
[dyninst.git] / paradynd / src / main.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  * Main loop for the default paradynd.
44  *
45  * $Log: main.C,v $
46  * Revision 1.67  1997/11/26 21:50:18  mcheyney
47  * Extra debugging information in main.C
48  * Changed exclude syntax in mdl:
49  * Old:
50  *   exclude "module";  or
51  *   exclude "module/function";
52  *
53  * New:
54  *   exclude "/Code/module"; or
55  *   exclude "/Code/module/function";
56  *
57  * Also added some better error messages for identifying cases where
58  *  underlying process falls over.
59  *
60  * Revision 1.66  1997/06/06 22:01:38  mjrg
61  * added option for manual daemon start-up
62  *
63  * Revision 1.65  1997/05/23 23:02:17  mjrg
64  * Windows NT port
65  *
66  * Revision 1.64  1997/05/17 19:58:51  lzheng
67  * Changes made for nonblocking write
68  *
69  * Revision 1.63  1997/05/13 14:26:04  sec
70  * Removed a simple assert
71  *
72  * Revision 1.62  1997/05/07 19:01:15  naim
73  * Getting rid of old support for threads and turning it off until the new
74  * version is finished. Additionally, new superTable, baseTable and superVector
75  * classes for future support of multiple threads. The fastInferiorHeap class has
76  * also changed - naim
77  *
78  * Revision 1.61  1997/03/29 02:08:53  sec
79  * Changed the daemon poe to mpi
80  *
81  * Revision 1.60  1997/03/23 16:57:48  zhichen
82  * added code to set process:pdFlavor
83  *
84  * Revision 1.59  1997/03/14 18:50:57  zhichen
85  * Added reportSelf in the case when the daemons were started by
86  * COW DJM. Search for 'Tempest' for the change
87  *
88  * Revision 1.58  1997/02/26 23:46:35  mjrg
89  * First part of WindowsNT port: changes for compiling with Visual C++;
90  * moved unix specific code to unix.C file
91  *
92  * Revision 1.57  1997/02/21 20:15:50  naim
93  * Moving files from paradynd to dyninstAPI + eliminating references to
94  * dataReqNode from the ast class. This is the first pre-dyninstAPI commit! - naim
95  *
96  * Revision 1.56  1997/02/18 21:25:15  sec
97  * Added poe support
98  *
99  * Revision 1.55  1997/01/21 20:07:47  mjrg
100  * Changed to unix domain socket for trace stream
101  * Replaced calls to uname by calls to libutil function getHostName
102  *
103  * Revision 1.54  1997/01/16 22:07:15  tamches
104  * moved RPC_undo_arg_list here from util lib
105  *
106  * Revision 1.53  1997/01/15 00:28:09  tamches
107  * added some debug msgs
108  *
109  * Revision 1.52  1996/12/16 23:10:16  mjrg
110  * bug fixes to fork/exec on all platforms, partial fix to fork on AIX
111  *
112  * Revision 1.51  1996/12/06 09:37:55  tamches
113  * cleanUpAndExit() moved here (from .h file); it now also
114  * calls destructors for all processes, which should clean up
115  * process state like shm segments.
116  *
117  * Revision 1.50  1996/11/29 19:41:08  newhall
118  * Cleaned up some code.  Moved code that was duplicated in inst-sparc-solaris.C
119  * and inst-sparc-sunos.C to inst-sparc.C.  Bug fix to process::findFunctionIn.
120  *
121  * Revision 1.49  1996/11/26 16:08:09  naim
122  * Fixing asserts - naim
123  *
124  * Revision 1.48  1996/09/26 18:58:44  newhall
125  * added support for instrumenting dynamic executables on sparc-solaris
126  * platform
127  *
128  * Revision 1.47  1996/08/16 21:19:13  tamches
129  * updated copyright for release 1.1
130  *
131  * Revision 1.46  1996/08/12 16:27:08  mjrg
132  * Code cleanup: removed cm5 kludges and some unused code
133  *
134  * Revision 1.45  1996/07/18 19:39:14  naim
135  * Minor fix to give proper error message when the pvm daemon runs out of
136  * virtual memory - naim
137  *
138  * Revision 1.44  1996/05/31  23:57:48  tamches
139  * code to change send socket buffer size moved to comm.h
140  * removed handshaking code w/paradyn (where we sent "PARADYND" plus
141  * the pid) [wasn't being used and contributed to freeze in paradyn UI]
142  *
143  * Revision 1.43  1996/05/09 21:27:42  newhall
144  * increased the socket send buffer size from 4K to 32K on sunos and hpux
145  *
146  * Revision 1.42  1996/05/08  23:54:50  mjrg
147  * added support for handling fork and exec by an application
148  * use /proc instead of ptrace on solaris
149  * removed warnings
150  *
151  * Revision 1.41  1996/02/09 22:13:43  mjrg
152  * metric inheritance now works in all cases
153  * paradynd now always reports to paradyn when a process is ready to run
154  * fixed aggregation to handle first samples and addition of new components
155  *
156  * Revision 1.40  1996/01/29 22:09:23  mjrg
157  * Added metric propagation when new processes start
158  * Adjust time to account for clock differences between machines
159  * Daemons don't enable internal metrics when they are not running any processes
160  * Changed CM5 start (paradynd doesn't stop application at first breakpoint;
161  * the application stops only after it starts the CM5 daemon)
162  *
163  */
164
165 #include "util/h/headers.h"
166 #include "util/h/makenan.h"
167
168 #include "rtinst/h/rtinst.h"
169
170 #include "dyninstAPI/src/symtab.h"
171 #include "dyninstAPI/src/process.h"
172 #include "dyninstAPI/src/inst.h"
173 #include "dyninstAPI/src/instP.h"
174 #include "dyninstAPI/src/ast.h"
175 #include "dyninstAPI/src/util.h"
176 #include "dyninstAPI/src/dyninstP.h"
177 #include "paradynd/src/metric.h"
178 #include "paradynd/src/comm.h"
179 #include "paradynd/src/internalMetrics.h"
180 #include "util/h/machineType.h"
181 #include "paradynd/src/init.h"
182 #include "paradynd/src/perfStream.h"
183 #include "dyninstAPI/src/clock.h"
184 #include "paradynd/src/mdld.h"
185
186 pdRPC *tp;
187
188 #ifdef PARADYND_PVM
189 #include "pvm_support.h"
190 extern "C" {
191 #include <pvm3.h>
192 }
193 #endif     
194
195
196 bool pvm_running = false;
197
198 static string machine_name;
199
200 int ready;
201
202 /*
203  * These variables are global so that we can easily find out what
204  * machine/socket/etc we're connected to paradyn on; we may need to
205  * start up other paradynds (such as on the CM5), and need this later.
206  */
207 static string pd_machine;
208 static int pd_known_socket_portnum;
209 static int pd_flag;
210 static string pd_flavor;
211
212 void configStdIO(bool closeStdIn)
213 {
214     int nullfd;
215
216     /* now make stdin, out and error things that we can't hurt us */
217     if ((nullfd = open("/dev/null", O_RDWR, 0)) < 0) {
218         abort();
219     }
220
221     if (closeStdIn) (void) dup2(nullfd, 0);
222     (void) dup2(nullfd, 1);
223     (void) dup2(nullfd, 2);
224
225     if (nullfd > 2) close(nullfd);
226 }
227
228 void sigtermHandler()
229 {
230   showErrorCallback(98,"paradynd has been terminated");
231 }
232
233 // Cleanup for pvm and exit.
234 // This function must be called when we exit, to clean up and exit from pvm.
235 // Now also cleans up shm segs by deleting all processes  -ari
236 void cleanUpAndExit(int status) {
237 #ifdef PARADYND_PVM
238   if (pvm_running)
239     PDYN_exit_pvm();
240 #endif
241
242   // delete the trace socket file
243   unlink(traceSocketPath.string_of());
244
245 #ifdef SHM_SAMPLING_DEBUG
246    cerr << "paradynd cleanUpAndExit: deleting all process structures now" << endl;
247 #endif
248
249   // Fry all processes
250   extern vector<process*> processVec;
251
252   for (unsigned lcv=0; lcv < processVec.size(); lcv++) {
253      process *theProc = processVec[lcv];
254      if (theProc == NULL)
255         continue; // process has already been cleaned up
256
257      delete theProc; // calls process::~process, which fries the shm seg
258
259      processVec[lcv] = NULL; // probably not needed here.
260   }
261
262   P_exit(status);
263 }
264
265 // TODO
266 // mdc - I need to clean this up
267 bool
268 RPC_undo_arg_list (string& flavor, int argc, char **arg_list, string &machine,
269                    int &well_known_socket, int &flag,
270                    int &firstPVM)
271 {
272   char *ptr;
273   bool b_well_known=false; // found well-known socket port num
274   bool b_first=false;
275   bool b_machine = false, b_flag = false, b_flavor=false;
276
277   for (int loop=0; loop < argc; ++loop) {
278       // stop at the -runme argument since the rest are for the application
279       //   process we are about to spawn
280       if (!strcmp(arg_list[loop], "-runme")) break;
281       if (!P_strncmp(arg_list[loop], "-p", 2)) {
282           well_known_socket = P_strtol (arg_list[loop] + 2, &ptr, 10);
283           if (ptr == (arg_list[loop] + 2))
284             return(false);
285           b_well_known = true;
286       }
287       else if (!P_strncmp(arg_list[loop], "-v", 2)) {
288           firstPVM = P_strtol (arg_list[loop] + 2, &ptr, 10);
289           if (ptr == (arg_list[loop] + 2))
290             return(false);
291           b_first = true;
292       }
293       else if (!P_strncmp(arg_list[loop], "-m", 2)) {
294           machine = (arg_list[loop] + 2);
295           if (!machine.length()) return false;
296           b_machine = true;
297       }
298       else if (!P_strncmp(arg_list[loop], "-l", 2)) {
299           flag = P_strtol (arg_list[loop] + 2, &ptr, 10);
300           if (ptr == (arg_list[loop] + 2))
301             return(false);
302           b_flag = true;
303       }
304       else if (!P_strncmp(arg_list[loop], "-z", 2)) {
305           flavor = (arg_list[loop]+2);
306           if (!flavor.length()) return false;
307           b_flavor = true;
308       }
309   }
310
311   return (b_flag && b_first && b_machine && b_well_known && b_flavor);
312 }
313
314 int main(int argc, char *argv[]) {
315     cerr << "welcome to paradynd, args are:" << endl;
316     for (unsigned lcv=0; lcv < argc; lcv++) {
317        cerr << argv[lcv] << endl;
318     }
319
320 #if !defined(i386_unknown_nt4_0)
321     struct sigaction act;
322
323     // int i = 1;
324     // while (i) {};
325
326
327 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
328     act.sa_handler = (void (*)(...)) sigtermHandler;
329 #else
330     act.sa_handler = (void (*)(int)) sigtermHandler;
331 #endif
332     act.sa_flags   = 0;
333
334     /* for AIX - default (non BSD) library does not restart - jkh 7/26/95 */
335 #if defined(SA_RESTART)
336     act.sa_flags  |= SA_RESTART;
337 #endif
338
339     sigfillset(&act.sa_mask);
340
341     if (sigaction(SIGTERM, &act, 0) == -1) {
342         perror("sigaction(SIGTERM)");
343         abort();
344     }
345 #endif
346
347 #if defined(i386_unknown_nt4_0)
348     // Windows NT needs to initialize winsock library
349     WORD wsversion = MAKEWORD(2,0);
350     WSADATA wsadata;
351     WSAStartup(wsversion, &wsadata);
352 #endif
353
354     process::programName = argv[0];
355     // process command line args passed in
356     // pd_flag == 1 --> started by paradyn
357     int pvm_first;
358     bool aflag;
359     aflag = RPC_undo_arg_list (pd_flavor, argc, argv, pd_machine,
360                                pd_known_socket_portnum, pd_flag, 
361                                pvm_first);
362     assert(aflag);
363     aflag = RPC_make_arg_list(process::arg_list,
364                               pd_known_socket_portnum, pd_flag, 0,
365                               pd_machine, true);
366     assert(aflag);
367     string flav_arg(string("-z")+ pd_flavor);
368     process::arg_list += flav_arg;
369     machine_name = getHostName();
370
371     // kill(getpid(),SIGSTOP);
372
373     //
374     // See if we should fork an app process now.
375     //
376     vector<string> cmdLine;
377     for (int i=0; argv[i]; i++) {
378         if (!strcmp(argv[i], "-runme")) {
379              // next arg is the command to run.
380              int j;
381              for (j=0,i++; argv[i]; i++,j++) {
382                  cmdLine += argv[i];
383              }
384         }
385     }
386 #ifdef PARADYND_PVM
387     // There are 3 ways to get here
388     //     started by pvm_spawn from first paradynd -- must report back
389     //     started by rsh, rexec, ugly code --> connect via socket
390     //     started by exec --> use pipe
391     
392     // int pvm_id = pvm_mytid();
393     int pvmParent = PvmSysErr;
394
395     cerr << "pd_flavor: " << pd_flavor.string_of() << endl ;
396     process::pdFlavor = pd_flavor ;
397     if (pd_flavor == string("pvm")) {
398        pvmParent = pvm_parent();
399
400        if (pvmParent == PvmSysErr) {
401           fprintf(stdout, "Unable to connect to PVM daemon, is PVM running?\n");
402           fflush(stdout);
403           cleanUpAndExit(-1);
404         }
405        else
406           pvm_running = true;
407     }
408
409     if (pvm_running && pvmParent != PvmNoParent) {
410       // started by pvm_spawn
411       // TODO -- report error here
412       if (!PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 0)) {
413         cleanUpAndExit(-1);
414       }
415       tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
416                      NULL, NULL, 2);
417       assert(tp);
418
419       tp->reportSelf (machine_name, argv[0], getpid(), "pvm");
420     } else if(pd_flavor == string("mpi")) {
421       // the executables which are started by poe (for mpi daemon) must report to paradyn
422       // the pdRPC is allocated and reportSelf is called
423       tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, 
424                      pd_machine, NULL, NULL, 2);
425       assert(tp);
426
427       tp->reportSelf(machine_name, argv[0], getpid(), "mpi");
428     } else if (pd_flag == 2) {
429        // manual startup
430         tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine, 
431                        NULL, NULL, 2);
432         assert(tp);
433         tp->reportSelf(machine_name, argv[0], getpid(), pd_flavor);
434
435         if (pvm_running
436             && !PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 1))
437             cleanUpAndExit(-1);
438
439     } else if (!pd_flag) {
440       // not started by pvm_spawn; rather, started via rsh/rexec --> use socket
441       int pid = fork();
442       if (pid == 0) {
443         // configStdIO(true);
444         // setup socket
445         // TODO -- report error here
446         
447         // We must get a connection with paradyn before starting any other daemons,
448         // or else one of the daemons we start (in PDYN_initForPVM), may get our
449         // connection.
450         tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
451                        NULL, NULL, 2);
452         assert(tp);
453         //Tempest, in the case of blizzard_cow, all daemons should report themselves
454         if (pd_flavor == string("cow")) {
455                 cerr << "rsh, rexec, reportSelf " 
456                      << machine_name.string_of() 
457                      << argv[0] << endl ;
458                 tp->reportSelf (machine_name, argv[0], getpid(), "cow");
459         }
460       
461
462         if (pvm_running && !PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 1)) {
463             cleanUpAndExit(-1);
464         }
465
466       } else if (pid > 0) {
467         P__exit(-1);
468       } else {
469         cerr << "Fatal error on paradyn daemon: fork failed." << endl;
470         cerr.flush();
471         cleanUpAndExit(-1);
472       }
473     } else {
474        // started via exec   --> use pipe
475        // TODO -- report error here
476       if (pvm_running && !PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 1)) {
477           cleanUpAndExit(-1);
478       }
479       // already setup on this FD.
480       // disconnect from controlling terminal 
481       OS::osDisconnect();
482       tp = new pdRPC(0, NULL, NULL, 2);
483       assert(tp);
484     }
485     assert(tp);
486 #else
487
488     if(pd_flavor == string("mpi")) {
489       // not put here, only up above since PARADYND_PVM is always set
490       assert(0);
491     } else if (pd_flag == 2) {
492        // manual startup
493         tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine, 
494                        NULL, NULL, 2);
495         assert(tp);
496         tp->reportSelf(machine_name, argv[0], getpid(), pd_flavor);
497
498     } else if (!pd_flag) {
499 #if !defined(i386_unknown_nt4_0)
500       int pid = fork();
501 #else
502       int pid = 0;
503 #endif
504       if (pid == 0) {
505         // configStdIO(true);
506         // setup socket
507
508         tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine, 
509                        NULL, NULL, 2);
510         assert(tp);
511
512         if (cmdLine.size()) {
513             tp->reportSelf(machine_name, argv[0], getpid(), pd_flavor);
514         }
515     } else if (!pd_flag) {
516       } else if (pid > 0) {
517         P__exit(-1);
518       } else {
519         cerr << "Fatal error on paradyn daemon: fork failed." << endl;
520         cerr.flush();
521         cleanUpAndExit(-1);
522       }
523     } else {
524       OS::osDisconnect();
525       tp = new pdRPC(0, NULL, NULL, 2);
526       assert(tp);
527
528       // configStdIO(false);
529     }
530 #endif
531
532     cyclesPerSecond = timing_loop() * 1000000;
533
534     // Note -- it is important that this daemon receives all mdl info
535     // before starting a process
536     aflag = mdl_get_initial(pd_flavor, tp);
537     assert(aflag);
538
539     initLibraryFunctions();
540     if (!init()) 
541       abort();
542
543     if (cmdLine.size()) {
544          //logLine("paradynd: cmdLine is non-empty so we'll be calling addProcess now!\n") ; 
545          //cerr << "cmdLine is:" << endl;
546          //for (unsigned lcv=0; lcv < cmdLine.size(); lcv++)
547          //   cerr << cmdLine[lcv] << endl;
548
549          vector<string> envp;
550          addProcess(cmdLine, envp, string("")); // ignore return val (is this right?)
551     }
552
553     controllerMainLoop(true);
554 }