Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / mutatee_driver.c
1 /*
2  * Copyright (c) 1996-2009 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  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31
32 /* Test application (Mutatee) */
33
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <ctype.h>
40 #include <assert.h>
41 #include <errno.h>
42
43 #if defined(os_windows_test)
44 #define WIN32_LEAN_AND_MEAN
45 #include <Windows.h>
46 #define snprintf _snprintf
47 #else
48 #include <unistd.h>
49 #include <sys/time.h>
50 #endif
51
52 #ifdef __cplusplus
53 int mutateeCplusplus = 1;
54 #else
55 int mutateeCplusplus = 0;
56 #endif
57
58 #ifndef COMPILER
59 #define COMPILER ""
60 #endif
61 const char *Builder_id=COMPILER; /* defined on compile line */
62
63 #ifdef __cplusplus
64 extern "C" {
65 #endif
66 #include "mutatee_util.h"
67 #ifdef __cplusplus
68 }
69 #endif
70
71 volatile int isAttached = 0;
72
73 #include "mutatee_call_info.h"
74 /* #include "mutatee_glue.h" */
75
76 #if defined(USE_GROUP_MUTATEE)
77 #include "group_driver.gen.h"
78 #else
79 #include "solo_driver.h"
80 #endif
81
82 #ifdef SOLO_MUTATEE
83 #include "solo_driver.h"
84 #endif
85
86 /* Pointer size variable, for multiple-ABI platforms */
87 int pointerSize = sizeof (void *);
88
89 /* Global copies of argc and argv, for tests that require them */
90 int gargc;
91 char **gargv;
92
93 int debugPrint = 0;
94
95 #define USAGE "Usage: mutatee [-attach <fd>] [-verbose] -run <num> .."
96
97 void setRunTest(const char *testname) {
98   unsigned int i;
99   if (NULL == testname) { /* Sanity check */
100     return;
101   }
102
103   for (i = 0; i < max_tests; i++) {
104     if (!strcmp(testname, mutatee_funcs[i].testname)) {
105       runTest[i] = TRUE;
106       break;
107     }
108   }
109   if (i >= max_tests) 
110   {
111     output->log(STDERR, "%s is not a valid test for this mutatee: %s, max_tests = %d\n", testname, gargv[0], max_tests);
112   }
113 } /* setRunTest() */
114
115 /*
116  * Check to see if the mutator has attached to us.
117  */
118 int checkIfAttached()
119 {
120   return isAttached;
121 }
122
123 /* Note which test we're running so we can detect crashes */
124 void updateResumeLog(const char *resumelogname, const char *testname) {
125   FILE *resumelog;
126
127   resumelog = fopen(resumelogname, "w");
128   if (resumelog != NULL) {
129     fprintf(resumelog, "%s\n", testname);
130     fclose(resumelog);
131   } else {
132     output->log(STDERR, "Error opening mutatee resumelog: %s\n",
133             strerror(errno));
134   }
135 }
136
137 void updateResumeLogCompleted(const char *resumelogname) {
138   FILE *resumelog;
139   resumelog = fopen(resumelogname, "a");
140   if (resumelog != NULL) {
141     fprintf(resumelog, "+\n");
142     fclose(resumelog);
143   } else {
144     output->log(STDERR, "Error opening mutatee resumelog: %s\n",
145             strerror(errno));
146   }
147 }
148
149 void setLabel(unsigned int label_ndx, char *label) {
150   /* TODO Fix me so group mutatees work */
151   if (max_tests > 1) {
152     output->log(STDERR, "Group mutatees not enabled yet\n");
153     return;
154   }
155
156   mutatee_funcs[0].testlabel = label;
157 }
158
159 int main(int iargc, char *argv[])
160 {                                       /* despite different conventions */
161    unsigned argc = (unsigned) iargc;   /* make argc consistently unsigned */
162    unsigned int i, j;
163 #if !defined(i386_unknown_nt4_0_test)
164    int pfd;
165 #endif
166    int useAttach = FALSE;
167    char *logfilename = NULL;
168    int allTestsPassed = TRUE;
169    int retval;
170    char *mutatee_name = NULL;
171    unsigned int label_count = 0;
172    int print_labels = FALSE;
173    int has_pidfile = 0;
174 #if !defined(os_windows_test)
175    struct timeval start_time;
176 #endif
177
178    gargc = argc;
179    gargv = argv;
180
181    initOutputDriver();
182
183    /* Extract the name of the mutatee binary from argv[0] */
184    /* Find the last '/' in argv[0]; we want everything after that */
185    mutatee_name = strrchr(argv[0], '/');
186    if (!mutatee_name) {
187       /* argv[0] contains just the filename for the executable */
188       mutatee_name = argv[0];
189       setExecutableName(argv[0]);
190    } else {
191       mutatee_name += 1; /* Skip past the '/' */
192       setExecutableName(mutatee_name);
193    }
194
195    for (j=0; j < max_tests; j++) {
196       runTest[j] = FALSE;
197    }
198
199    /* Parse command line arguments */
200    for (i=1; i < argc; i++) {
201       if (!strcmp(argv[i], "-verbose")) {
202          debugPrint = 1;
203       } else if (!strcmp(argv[i], "-log")) {
204          /* Read the log file name so we can set it up later */
205          if ((i + 1) >= argc) {
206             output->log(STDERR, "Missing log file name\n");
207             exit(-1);
208          }
209          i += 1;
210          logfilename = argv[i];
211       } else if (!strcmp(argv[i], "-attach")) {
212          useAttach = TRUE;
213 #if !defined(os_windows_test)
214          if (++i >= argc) {
215             output->log(STDERR, "attach usage\n");
216             output->log(STDERR, "%s\n", USAGE);
217             exit(-1);
218          }
219          pfd = atoi(argv[i]);
220 #endif
221       } else if (!strcmp(argv[i], "-run")) {
222          char *tests;
223          char *name;
224
225          if (i + 1 >= argc) {
226             output->log(STDERR, "-run must be followed by a test name\n");
227             exit(-1);
228          }
229          i += 1;
230          tests = strdup(argv[i]);
231          /* FIXME I think strtok is frowned on */
232          name = strtok(tests, ",");
233          setRunTest(name); /* Enables the named test to run */
234          while (name != NULL) {
235             name = strtok(NULL, ",");
236             if (name != NULL) {
237                setRunTest(name);
238             }
239          }
240          free(tests);
241       } else if (!strcmp(argv[i], "-label")) {
242          if (i + 1 >= argc) {
243             output->log(STDERR, "-label must be followed by a label string\n");
244             exit(-1);
245          }
246          i += 1;
247          setLabel(label_count, argv[i]);
248          label_count += 1;
249       } else if (!strcmp(argv[i], "-print-labels")) {
250          print_labels = TRUE;
251       } else if (!strcmp(argv[i], "-humanlog")) {
252          if (i + 1 >= argc) {
253             output->log(STDERR, "-humanlog must be followed by a file name or '-'\n");
254             exit(-1);
255          }
256          i += 1;
257          setHumanLog(argv[i]);
258       } else if (strcmp(argv[i], "-pidfile") == 0) {
259          if (i + 1 >= argc) {
260             output->log(STDERR, "-pidfile must be followed by a file name\n");
261             exit(-1);
262          }
263          has_pidfile = 1;
264          i += 1;
265          setPIDFilename(argv[i]);
266       } else if (!strcmp(argv[i], "-runall")) {
267          for (j = 0; j < max_tests; j++) {
268             runTest[j] = TRUE;
269          }
270       } else if (!strcmp(argv[i], "-dboutput")) {
271          /* Set up database output */
272          initDatabaseOutputDriver();
273       } else {
274          /* Let's just ignore unrecognized parameters.  They might be
275           * important to a specific test.
276           */
277       }
278    }
279
280    if ((logfilename != NULL) && (strcmp(logfilename, "-") != 0)) {
281       /* Set up the log file */
282       redirectStream(LOGINFO, logfilename);
283       redirectStream(LOGERR, logfilename);
284       outlog = fopen(logfilename, "a");
285       if (NULL == outlog) {
286          output->log(STDERR, "Error opening log file %s\n", logfilename);
287          exit(-1);
288       }
289       errlog = outlog;
290    } else {
291       outlog = stdout;
292       errlog = stderr;
293    }
294
295    if ((argc==1) || debugPrint)
296       logstatus("Mutatee %s [%s]:\"%s\"\n", argv[0],
297                 mutateeCplusplus ? "C++" : "C", Builder_id);
298    if (argc==1) exit(0);
299
300    /* see if we should wait for the attach */
301    if (useAttach) {
302 #ifndef i386_unknown_nt4_0_test
303       char ch = 'T';
304       if (write(pfd, &ch, sizeof(char)) != sizeof(char)) {
305          output->log(STDERR, "*ERROR*: Writing to pipe\n");
306          exit(-1);
307       }
308       close(pfd);
309 #else
310            char ch = 'T';
311            LPCTSTR pipeName = "\\\\.\\pipe\\mutatee_signal_pipe";
312            DWORD bytes_written = 0;
313            BOOL wrote_ok = FALSE;
314            HANDLE signalPipe = CreateFile(pipeName,
315                    GENERIC_WRITE,
316                    0,
317                    NULL,
318                    OPEN_EXISTING,
319                    0,
320                    NULL);
321            if(signalPipe == INVALID_HANDLE) 
322            {
323                    if(GetLastError() != ERROR_PIPE_BUSY)
324                    {
325                            output->log(STDERR, "*ERROR*: Couldn't open pipe\n");
326                            exit(-1);
327                    }
328                    if(!WaitNamedPipe(pipeName, 2000))
329                    {
330                            output->log(STDERR, "*ERROR*: Couldn't open pipe\n");
331                            exit(-1);
332                    }
333            }
334            wrote_ok = WriteFile(signalPipe,
335                    &ch,
336                    1,
337                    &bytes_written,
338                    NULL);
339            if(!wrote_ok ||(bytes_written != 1))
340            {
341                    output->log(STDERR, "*ERROR*: Couldn't write to pipe\n");
342                    exit(-1);
343            }
344            CloseHandle(signalPipe);
345 #endif
346       setUseAttach(TRUE);
347 #if defined (os_windows_test)
348       logstatus("mutatee: Waiting for mutator to attach...\n");
349 #else
350       logstatus("mutatee %d: Waiting for mutator to attach...\n", getpid());
351           gettimeofday(&start_time, NULL);
352 #endif
353       flushOutputLog();
354
355       while (!checkIfAttached()) {
356 #if !defined(os_windows_test)
357                   struct timeval present_time;
358                   gettimeofday(&present_time, NULL);
359                   if (present_time.tv_sec > (start_time.tv_sec + 30))
360                   {
361            if (checkIfAttached())
362               break;
363                           logstatus("mutatee: mutator attach problem, failing...\n");
364                           exit(-1);
365                   }
366 #endif
367 #if 0
368                   struct timeval slp;
369                   slp.tv_sec = 1;
370                   slp.tv_usec = 0;
371                   select(0, NULL, NULL, NULL, &slp);
372
373                   elapsed++;
374                   if (elapsed > 60) {
375                           logstatus("mutatee %d: mutator attach problem, failing...\n", getpid());
376                           exit(-1);
377                   }
378 #endif
379          /* Do nothing */
380       }
381       fflush(stderr);
382       logstatus("Mutator attached.  Mutatee continuing.\n");
383    } else {
384       setUseAttach(FALSE);
385    }
386
387    /* 
388     * Run the tests and keep track of return values in case of test failure
389     */
390    for (i = 0; i < max_tests; i++) {
391       if (runTest[i]) {
392
393          log_testrun(mutatee_funcs[i].testname);
394
395          if (print_labels && (mutatee_funcs[i].testlabel != NULL)) {
396             logstatus("%s\n", mutatee_funcs[i].testlabel);
397          }
398
399          output->setTestName(mutatee_funcs[i].testname);
400          mutatee_funcs[i].func();
401          log_testresult(passedTest[i]);
402     
403          if (!passedTest[i]) {
404             allTestsPassed = FALSE;
405          }
406       }
407
408       flushOutputLog();
409       flushErrorLog();
410    }
411
412    if (allTestsPassed) {
413       logstatus("All tests passed.\n");
414       retval = 0;
415    } else {
416 #if 0
417            unsigned int i;
418            for (i = 0; i < max_tests; ++i)
419            {
420                    if (runTest[i])
421                            logstatus("%s[%d]: %s: %s \n", passedTest[i] ? "PASSED" : "FAILED", __FILE__, __LINE__, 
422                                            mutatee_funcs[i].testlabel == NULL ? "bad_label" : mutatee_funcs[i].testlabel);
423            }
424            logstatus("\n");
425 #endif
426       retval = -1;
427    }
428
429    /* Clean up after ourselves */
430    if ((outlog != NULL) && (outlog != stdout)) {
431       fclose(outlog);
432    }
433
434    exit( retval);
435 }