Bluegene testsuite fixes.
[dyninst.git] / testsuite / src / test_lib.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 //
33 // $Id: test_lib.C,v 1.6 2008/10/30 19:16:54 legendre Exp $
34 // Utility functions for use by the dyninst API test programs.
35 //
36
37 #include <stdio.h>
38 #include <signal.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <assert.h>
44 #include <stdlib.h>
45
46 #if !defined(i386_unknown_nt4_0_test)
47 #include <fnmatch.h>
48 #endif
49
50 #if defined(i386_unknown_nt4_0_test) || defined(mips_unknown_ce2_11_test) //ccw 10 apr 2001 
51 #ifndef mips_unknown_ce2_11_test //ccw 10 apr 2001
52 #define WIN32_LEAN_AND_MEAN
53 #endif
54 #include <Windows.h>
55 #else
56 #include <unistd.h>
57 #include <sys/wait.h>
58 #include <sys/types.h>
59 #include <sys/stat.h>
60 #endif
61 #include <stdarg.h>
62
63 // Blind inclusion from test9.C
64 #if defined(i386_unknown_linux2_0_test) \
65  || defined(x86_64_unknown_linux2_4) /* Blind duplication - Ray */ \
66  || defined(sparc_sun_solaris2_4)
67 #include <sys/types.h>
68 #include <sys/wait.h>
69 #endif
70
71 #if defined(i386_unknown_linux2_0_test) \
72  || defined(x86_64_unknown_linux2_4)
73 #include <unistd.h>
74 #endif
75 // end inclusion from test9.C
76
77 #if defined(i386_unknown_nt4_0_test)
78 #define snprintf _snprintf
79 #endif
80
81 #include "test_lib.h"
82 #include "ResumeLog.h"
83 #define BINEDIT_DIRNAME "" 
84
85
86 /* Control Debug printf statements */
87 int debugPrint = 0;
88
89 // output logging
90 FILE *outlog = NULL;
91 FILE *errlog = NULL;
92 const char *outlogname = "-";
93 const char *errlogname = "-";
94
95 static char *binedit_dir = BINEDIT_BASENAME;
96
97 char *get_binedit_dir()
98 {
99         return binedit_dir;
100 }
101
102 void set_binedit_dir(char *d)
103 {
104         binedit_dir = d;
105 }
106
107 static char *resumelog_name = "resumelog";
108 char *get_resumelog_name() {
109         return resumelog_name;
110 }
111
112 void set_resumelog_name(char *s) {
113         resumelog_name = s;
114 }
115
116
117 LocErr::LocErr(const char *__file__, const int __line__, const std::string msg) :
118         msg__(msg),
119         file__(std::string(__file__)),
120         line__(__line__)
121 {}
122
123 LocErr::~LocErr() THROW
124 {}
125
126 std::string LocErr::file() const
127 {
128         return file__;
129 }
130
131 std::string LocErr::msg() const
132 {
133         return msg__;
134 }
135 const char * LocErr::what() const
136 {
137         return msg__.c_str();
138 }
139 int LocErr::line() const
140 {
141         return line__;
142 }
143
144 void LocErr::print(FILE * /*stream*/) const
145 {
146         logerror( "Error thrown from %s[%d]:\n\t\"%s\"\n",
147                         file__.c_str(), line__, what());
148 }
149
150 std::vector<std::string> Tempfile::all_open_files;
151
152 Tempfile::Tempfile()
153 {
154 #if defined (os_windows_test)
155         fname = new char[1024];
156         assert(fname);
157         const char *dyninst_root = getenv("DYNINST_ROOT");
158         char tmp_dir[1024];
159         struct stat statbuf;
160
161         if (!dyninst_root)
162         {
163       dyninst_root = "../..";
164         }
165
166         snprintf(tmp_dir, 1024, "%s\temp", dyninst_root);
167
168         if (0 != stat(tmp_dir, &statbuf))
169         {
170                 if (ENOENT == errno)
171                 {
172                         //  doesn't exist, make it
173                         if (0 != _mkdir(tmp_dir))
174                         {
175                                 fprintf(stderr, "%s[%d]:  mkdir(%s): %s\n", __FILE__, __LINE__, tmp_dir, strerror(errno));
176                                 abort();
177                         }
178                 }
179                 else
180                 {
181                         fprintf(stderr, "%s[%d]:  FIXME:  unexpected stat result: %s\n",
182                                         __FILE__, __LINE__, strerror(errno));
183                         abort();
184                 }
185         }
186
187         if (0 != GetTempFileName(tmp_dir, "tempfile", 0, fname))
188         {
189                 fprintf(stderr, "%s[%d]:  failed to create temp file name\n", __FILE__, __LINE__);
190                 assert(0);
191         }
192
193         fd = CreateFile(fname,
194                         GENERIC_READ | GENERIC_WRITE, // open r-w 
195                         0,                    // do not share 
196                         NULL,                 // default security 
197                         CREATE_ALWAYS,        // overwrite existing
198                         FILE_ATTRIBUTE_NORMAL,// normal file 
199                         NULL);                // no template 
200
201         if (fd == INVALID_HANDLE_VALUE)
202         {
203                 fprintf(stderr, "%s[%d]:  failed to create temp file\n", __FILE__, __LINE__);
204                 assert(0);
205         }
206 #else
207         fname = strdup("/tmp/tmpfileXXXXXX");
208         fd = mkstemp(fname);
209
210         if (-1 == fd)
211         {
212                 fprintf(stderr, "%s[%d]:  failed to make temp file\n", __FILE__, __LINE__);
213                 abort();
214         }
215 #endif
216         all_open_files.push_back(std::string(fname));
217 }
218
219 Tempfile::~Tempfile()
220 {
221 #if defined (os_windows_test)
222         if (0 == DeleteFile(fname))
223         {
224                 fprintf(stderr, "%s[%d]:  DeleteFile failed: %s\n",
225                                 __FILE__, __LINE__, strerror(errno));
226         }
227         delete [] fname;
228 #else
229         logerror( "%s[%d]:  unlinking %s\n", FILE__, __LINE__, fname);
230         if (0 != unlink (fname))
231         {
232                 fprintf(stderr, "%s[%d]:  unlink failed: %s\n",
233                                 __FILE__, __LINE__, strerror(errno));
234         }
235         free (fname);
236 #endif
237 }
238
239 const char *Tempfile::getName()
240 {
241         return fname;
242 }
243
244 void Tempfile::deleteAll()
245 {
246         for (unsigned int i = (all_open_files.size() - 1); i > 0; --i)
247         {
248                 const char *fn = all_open_files[i].c_str();
249                 assert(fn);
250 #if defined (os_windows_test)
251                 if (0 == DeleteFile(fn))
252                 {
253                         fprintf(stderr, "%s[%d]:  DeleteFile failed: %s\n",
254                                         __FILE__, __LINE__, strerror(errno));
255                 }
256 #else
257                 fprintf(stderr, "%s[%d]:  unlinking %s\n", FILE__, __LINE__, fn);
258                 if (0 != unlink (fn))
259                 {
260                         fprintf(stderr, "%s[%d]:  unlink failed: %s\n",
261                                         __FILE__, __LINE__, strerror(errno));
262                 }
263 #endif
264         }
265         all_open_files.clear();
266 }
267
268 TestOutputDriver * output = NULL;
269
270 // windows has strange support for sharing variables across
271 // a dll and a program, so here is a simple utility function to do that, since
272 // FUNCTION definitions are easily shared.
273 TestOutputDriver * getOutput() {
274         return output;
275 }
276
277         void setOutput(TestOutputDriver * new_output) {
278                 if (output != NULL)
279                         delete output;
280                 output = new_output;
281         }
282
283 void setOutputLog(FILE *log_fp) {
284         if (log_fp != NULL) {
285                 outlog = log_fp;
286         } else {
287                 outlog = stdout;
288         }
289 }
290
291 FILE *getOutputLog() {
292         return outlog;
293 }
294
295 void setErrorLog(FILE *log_fp) {
296         if (log_fp != NULL) {
297                 errlog = log_fp;
298         } else {
299                 errlog = stderr;
300         }
301 }
302
303 FILE *getErrorLog() {
304         return errlog;
305 }
306
307 void setOutputLogFilename(char *log_fn) {
308         if (log_fn != NULL) {
309                 outlogname = log_fn;
310         }
311 }
312
313 void setErrorLogFilename(char *log_fn) {
314         if (log_fn != NULL) {
315                 errlogname = log_fn;
316         }
317 }
318
319 const char *getOutputLogFilename() {
320         return outlogname;
321 }
322
323 const char *getErrorLogFilename() {
324         return errlogname;
325 }
326
327 void logstatus(const char *fmt, ...) {
328         va_list args;
329         va_start(args, fmt);
330         getOutput()->vlog(LOGINFO, fmt, args);
331         va_end(args);
332 }
333
334 void logerror(const char *fmt, ...) {
335         va_list args;
336         va_start(args, fmt);
337         getOutput()->vlog(LOGERR, fmt, args);
338         va_end(args);
339 }
340
341 void flushOutputLog() {
342         if (outlog != NULL) {
343                 fflush(outlog);
344         }
345 }
346 void flushErrorLog() {
347         if (errlog != NULL) {
348                 fflush(errlog);
349         }
350 }
351
352 // PID registration for mutatee cleanup
353 // TODO Check if these make any sense on Windows.  I suspect I'll need to
354 // change them.
355 char *pidFilename = NULL;
356 void setPIDFilename(char *pfn) {
357         pidFilename = pfn;
358 }
359 char *getPIDFilename() {
360         return pidFilename;
361 }
362 void registerPID(int pid) {
363         if (NULL == pidFilename) {
364                 return;
365         }
366         FILE *pidFile = fopen(pidFilename, "a");
367         if (NULL == pidFile) {
368                 //fprintf(stderr, "[%s:%u] - Error registering mutatee PID: unable to open PID file\n", __FILE__, __LINE__);
369         } else {
370      fprintf(pidFile, "%d\n", pid);
371      fclose(pidFile);
372   }
373 }
374
375 void cleanPIDFile()
376 {
377         if(!pidFilename)
378                 return;
379    FILE *f = fopen(pidFilename, "r");
380    if (!f)
381       return;
382    for (;;)
383    {
384       int pid;
385       int res = fscanf(f, "%d\n", &pid);
386       if (res != 1)
387          break;
388 #if !defined(os_windows_test)
389       kill(pid, SIGKILL);
390 #else
391       HANDLE h = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
392       if (h == NULL) {
393          return;
394       }
395       bool dummy = TerminateProcess(h,0);
396       CloseHandle(h);
397 #endif
398    }
399    fclose(f);
400    f = fopen(pidFilename, "w");
401    fclose(f);
402 }
403
404 void setDebugPrint(int debug) {
405    debugPrint = debug;
406 }
407
408 #if !defined(os_windows_test)
409 #if !defined(os_linux_test)
410 pid_t fork_mutatee() {
411   return fork();
412 }
413 #else
414 pid_t fork_mutatee() {
415    /**
416     * Perform a granchild fork.  This code forks off a child, that child
417     * then forks off a granchild.  The original child then exits, making
418     * the granchild's new parent init.  Both the original process and the
419     * granchild then exit from this function.
420     *
421     * This works around a linux kernel bug in kernel version 2.6.9 to
422     * 2.6.11, see https://www.dyninst.org/emails/2006/5676.html for
423     * details.
424     **/
425    int status, result;
426    pid_t gchild_pid, child_pid;
427    int filedes[2];
428
429    pipe(filedes);
430
431    child_pid = fork();
432    if (child_pid < 0) { // This is an error
433       close(filedes[0]);
434       close(filedes[1]);
435       return child_pid;
436    }
437
438    if (child_pid) {
439       //Read the grandchild pid from the child.
440       do {
441          result = read(filedes[0], &gchild_pid, sizeof(pid_t));
442       } while (result == -1 && errno == EINTR);
443       if (result == -1) {
444          perror("Couldn't read from pipe");
445       }
446
447       int options = 0;
448       do {
449          result = waitpid(child_pid, &status, options);
450          if (result != child_pid) {
451             perror("Couldn't join child");
452             break;
453          }
454       } while (!WIFEXITED(status));
455       close(filedes[0]);
456       close(filedes[1]);
457       return gchild_pid;
458    }
459    //Child
460    
461    gchild_pid = fork();
462    if (gchild_pid) {
463       //Child pid, send grand child pid to parent then terminate
464       result = write(filedes[1], &gchild_pid, sizeof(pid_t));
465       if (result == -1) {
466          perror("Couldn't write to parent");
467       }         
468       close(filedes[0]);
469       close(filedes[1]);
470       exit(0);
471    }   
472
473    //Granchild
474    close(filedes[0]);
475    close(filedes[1]);
476    return 0;
477 }
478 #endif
479 #endif
480
481 bool inTestList(test_data_t &test, std::vector<char *> &test_list)
482 {
483    for (unsigned int i = 0; i < test_list.size(); i++ )
484    {
485 #if defined(i386_unknown_nt4_0_test)
486       if ( strcmp(test_list[i], test.name) == 0 )
487 #else
488       if ( fnmatch(test_list[i], test.name, 0) == 0 )
489 #endif
490       {
491          return true;
492       }
493    }
494
495    return false;
496 }
497
498 //
499 // Create a new process and return its process id.  If process creation 
500 // fails, this function returns -1.
501 //
502 int startNewProcessForAttach(const char *pathname, const char *argv[],
503                              FILE *outlog, FILE *errlog, bool attach) {
504 #if defined(os_windows_test)
505    // TODO Fix Windows code to work with log file
506         LPCTSTR pipeName = "\\\\.\\pipe\\mutatee_signal_pipe";
507         HANDLE mutatee_signal_pipe = CreateNamedPipe(pipeName,
508                 PIPE_ACCESS_INBOUND,
509                 PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
510                 1, // num instances
511                 1024, // read buffer
512                 1024, // write buffer
513                 5000, //timeout
514                 NULL); // security descriptor
515         if(mutatee_signal_pipe == INVALID_HANDLE_VALUE)
516         {
517       fprintf(stderr, "*ERROR*: Unable to create pipe.\n");
518       return -1;
519         }
520         char child_args[1024];
521    strcpy(child_args, "");
522    if (argv[0] != NULL) {
523       strcpy(child_args, pathname);
524       for (int i = 1; argv[i] != NULL; i++) {
525          strcat(child_args, " ");
526          strcat(child_args, argv[i]);
527       }
528       strcat(child_args, " -attach");
529    }
530
531    STARTUPINFO si;
532    memset(&si, 0, sizeof(STARTUPINFO));
533    si.cb = sizeof(STARTUPINFO);
534    PROCESS_INFORMATION pi;
535    if (!CreateProcess(pathname, // application name
536                       child_args,       // command line
537                       NULL,             // security attributes
538                       NULL,             // thread security attributes
539                       FALSE,            // inherit handles
540                       0,                // creation flags
541                       NULL,             // environment,
542                       NULL,             // current directory
543                       &si,
544                       &pi)) {
545                                                   LPTSTR lastErrorMsg;
546                                                   DWORD lastError = GetLastError();
547                                                   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
548                                                           FORMAT_MESSAGE_FROM_SYSTEM |
549                                                           FORMAT_MESSAGE_IGNORE_INSERTS,
550                                                           NULL,
551                                                           lastError,
552                                                           MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
553                                                           (LPTSTR)&lastErrorMsg,
554                                                           0, NULL );
555                                                   fprintf(stderr, "CreateProcess failed: (%d) %s\n",
556                                                           lastError, lastErrorMsg);
557                                                   LocalFree(lastErrorMsg);
558
559       return -1;
560    }
561
562    registerPID(pi.dwProcessId);
563         // Keep synchronization pattern the same as on Unix...
564         BOOL conn_ok = ConnectNamedPipe(mutatee_signal_pipe, NULL) ?
565                 TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
566         if(!conn_ok)
567         {
568                 CloseHandle(mutatee_signal_pipe);
569                 return -1;
570         }
571         char mutatee_ready = 0x0;
572         DWORD bytes_read;
573         BOOL read_ok = ReadFile(mutatee_signal_pipe,
574                 &mutatee_ready, // buffer
575                 1,      // size
576                 &bytes_read,
577                 NULL); // not overlapped I/O
578         if (!read_ok || (bytes_read != 1))
579         {
580                 fprintf(stderr, "Couldn't read from mutatee pipe\n");
581                 DisconnectNamedPipe(mutatee_signal_pipe);
582                 CloseHandle(mutatee_signal_pipe);
583                 return -1;
584         }
585         if(mutatee_ready != 'T')
586         {
587                 fprintf(stderr, "Got unexpected message from mutatee, aborting\n");
588                 DisconnectNamedPipe(mutatee_signal_pipe);
589                 CloseHandle(mutatee_signal_pipe);
590                 return -1;
591         }
592         DisconnectNamedPipe(mutatee_signal_pipe);
593         CloseHandle(mutatee_signal_pipe);
594    return pi.dwProcessId;
595 #else
596    /* Make a pipe that we will use to signal that the mutatee has started. */
597    int fds[2];
598    char fdstr[32];
599    if (attach) {
600       if (pipe(fds) != 0) {
601          fprintf(stderr, "*ERROR*: Unable to create pipe.\n");
602          return -1;
603       }
604       /* Create the argv string for the child process. */
605       sprintf(fdstr, "%d", fds[1]);
606    }
607
608
609    const char **attach_argv;
610
611    bool bgp_test = false;
612    int BGP_MAX_ARGS=13;
613    char *platform = getenv("PLATFORM");
614    if(strcmp(platform, "ppc32_bgp") == 0)
615                 bgp_test = true;
616
617    if (bgp_test) {
618           attach_argv = (const char**)malloc(sizeof(char *) * BGP_MAX_ARGS);
619           attach_argv[0] = const_cast<char *>("-nofree");
620           attach_argv[1] = const_cast<char *>("-partition");
621           char *partition = getenv("DYNINST_BGP_PARTITION");
622           if(partition == NULL) partition = "BGB1";
623           attach_argv[2] = const_cast<char *>( partition);
624           attach_argv[3] = const_cast<char *>("-np");
625           attach_argv[4] = const_cast<char *>("1");
626           attach_argv[5] = const_cast<char *>("-env");
627
628           char *dyninst_base = getenv("DYNINST_ROOT");
629           if (dyninst_base == NULL)
630                 fprintf(stderr, " DYNINST_ROOT is not set!! ");
631           char *ldpath = (char *) malloc (1024);
632           sprintf(ldpath, "LD_LIBRARY_PATH=%s/dyninst/testsuite/%s/binaries:.:%s/%s/lib:${LD_LIBRARY_PATH}", dyninst_base, platform, dyninst_base, platform);
633           attach_argv[6] = const_cast<char *>(ldpath);
634
635           char *binedit_dir = BINEDIT_DIRNAME;
636           char cwd[1024]; 
637           getcwd(cwd, 1024);
638           strcat(cwd, binedit_dir);
639           attach_argv[7] = const_cast<char *>("-cwd");
640           attach_argv[8] = const_cast<char *>(cwd);
641
642           attach_argv[9] = const_cast<char *>("-exe");
643           attach_argv[10] = const_cast<char *>(pathname);
644           attach_argv[11] = const_cast<char *>("-args");
645           char *args = (char*) malloc (2048);
646           strcpy(args ,"\"");
647
648           for (int j = 0; argv[j] != NULL; j++){
649                 strcat(args, argv[j]);
650                 strcat(args, " ");
651           }
652           strcat(args, "\"");
653           attach_argv[12] =  const_cast<char *>(args);
654
655           attach_argv[BGP_MAX_ARGS] = NULL;
656
657         } else {
658
659           int i;
660           for (i = 0; argv[i] != NULL; i++) ;
661           // i now contains the count of elements in argv
662           attach_argv = (const char**)malloc(sizeof(char *) * (i + 3));
663           // attach_argv is length i + 3 (including space for NULL)
664
665           for (i = 0; argv[i] != NULL; i++)
666              attach_argv[i] = argv[i];
667           if (attach)
668           {
669              attach_argv[i++] = const_cast<char*>("-attach");
670              attach_argv[i++] = fdstr;
671           }
672           attach_argv[i++] = NULL;
673         }
674
675    int pid;
676    if (attach)
677       pid = fork_mutatee();
678    else  
679       pid = fork();
680    if (pid == 0) {
681       // child
682       if (attach) 
683          close(fds[0]); // We don't need the read side
684       if (outlog != NULL) {
685          int outlog_fd = fileno(outlog);
686          if (dup2(outlog_fd, 1) == -1) {
687             fprintf(stderr, "Error duplicating log fd(1)\n");
688          }
689       }
690       if (errlog != NULL) {
691          int errlog_fd = fileno(errlog);
692          if (dup2(errlog_fd, 2) == -1) {
693             fprintf(stderr, "Error duplicating log fd(2)\n");
694          }
695       }
696       char *ld_path = getenv("LD_LIBRARY_PATH");
697       char *new_ld_path = NULL;
698       if (ld_path) {
699          new_ld_path = (char *) malloc(strlen(ld_path) + strlen(binedit_dir) + 4);
700          strcpy(new_ld_path, "./");
701          strcat(new_ld_path, binedit_dir);
702          strcat(new_ld_path, ":");
703          strcat(new_ld_path, ld_path);
704       }
705       else {
706          new_ld_path = (char *) malloc(strlen(binedit_dir) + 4);
707          strcpy(new_ld_path, "./");
708          strcat(new_ld_path, binedit_dir);
709          strcat(new_ld_path, ":");
710       }
711       setenv("LD_LIBRARY_PATH", new_ld_path, 1);
712
713           //fprintf(stderr, "%s[%d]:  before exec '%s':  LD_LIBRARY_PATH='%s'\n", 
714           //FILE__, __LINE__, pathname, getenv("LD_LIBRARY_PATH"));
715
716 if(bgp_test) {
717
718       dprintf(" running mpirun ");
719       for (int i = 0 ; i < BGP_MAX_ARGS ; i++)
720           dprintf(" %s", attach_argv[i]);
721       dprintf(" \n");
722
723       execvp("mpirun", (char * const *)attach_argv);
724       logerror("%s[%d]:  Exec failed!\n", FILE__, __LINE__);
725       exit(-1);
726 }else{
727       execvp(pathname, (char * const *)attach_argv);
728       char *newname = (char *) malloc(strlen(pathname) + 3);
729       strcpy(newname, "./");
730       strcat(newname, pathname);
731       execvp(newname, (char * const *)attach_argv);
732       logerror("%s[%d]:  Exec failed!\n", FILE__, __LINE__);
733       exit(-1);
734 }
735
736    } else if (pid < 0) {
737       return -1;
738    }
739
740    registerPID(pid);
741
742    // parent
743    if (attach) {
744       close(fds[1]);  // We don't need the write side
745       
746       // Wait for the child to write to the pipe
747       char ch;
748       if (read(fds[0], &ch, sizeof(char)) != sizeof(char)) {
749          perror("read");
750          fprintf(stderr, "*ERROR*: Error reading from pipe\n");
751          return -1;
752       }
753
754       if (ch != 'T') {
755          fprintf(stderr, "*ERROR*: Child didn't write expected value to pipe.\n");
756          return -1;
757       }
758        
759 #if defined( os_linux_test )
760       /* Random Linux-ism: it's possible to close the pipe before the 
761          mutatee returns from the write() system call matching the above
762          read().  In this case, rather than ignore the close() because the
763          write() is on its way out the kernel, Linux sends a SIGPIPE
764          to the mutatee, which causes us no end of trouble.  read()ing
765          an EOF from the pipe seems to alleviate this problem, and seems
766          more reliable than a sleep(1).  The condition test if we somehow
767          got any /extra/ bytes on the pipe. */
768       if( read( fds[0], & ch, sizeof( char ) ) != 0 ) {
769          fprintf(stderr, "*ERROR*: Shouldn't have read anything here.\n");
770          return -1;
771       }
772 #endif /* defined( os_linux_test ) */
773       
774       close( fds[0] ); // We're done with the pipe
775    }
776    return pid;
777 #endif
778 }
779
780
781 // control debug printf statements
782 void dprintf(const char *fmt, ...) {
783    va_list args;
784    va_start(args, fmt);
785
786    if(debugPrint)
787       vfprintf(stderr, fmt, args);
788
789    va_end(args);
790
791    fflush(stderr);
792 }
793
794 // Build Architecture specific libname
795 // FIXME Is this used any more?  Is it necessary?
796 void addLibArchExt(char *dest, unsigned int dest_max_len, int psize, bool isStatic)
797 {
798    int dest_len;
799
800    dest_len = strlen(dest);
801
802    // Patch up alternate ABI filenames
803 #if defined(rs6000_ibm_aix64_test)
804    if(psize == 4) {
805      strncat(dest, "_32", dest_max_len - dest_len);
806      dest_len += 3;
807    }
808 #endif
809
810 #if defined(arch_x86_64_test)
811    if (psize == 4) {
812       strncat(dest,"_m32", dest_max_len - dest_len);
813       dest_len += 4;   
814    }
815 #endif
816
817 #if defined(mips_sgi_irix6_4_test)
818    strncat(dest,"_n32", dest_max_len - dest_len);
819    dest_len += 4;
820 #endif
821
822 #if defined(os_windows_test)
823    strncat(dest, ".dll", dest_max_len - dest_len);
824    dest_len += 4;
825 #else
826    if( isStatic ) {
827        strncat(dest, ".a", dest_max_len - dest_len);
828        dest_len += 2;
829    }else{
830        strncat(dest, ".so", dest_max_len - dest_len);
831        dest_len += 3;
832    }
833 #endif
834 }
835
836 #define TOLOWER(c) ((c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c)
837 int strcmpcase(char *s1, char *s2) {
838     unsigned i;
839     unsigned char s1_c, s2_c;
840     for (i=0; s1[i] || s2[i]; i++) {
841         s1_c = TOLOWER(s1[i]);
842         s2_c = TOLOWER(s2[i]);
843         if (s1_c < s2_c)
844             return -1;
845         if (s1_c > s2_c)
846             return 1;
847     }
848     return 0;
849 }
850
851
852 #if !defined(os_windows_test)
853 char *searchPath(const char *path, const char *file) {
854    assert(path);
855    assert(file);
856
857    char *pathcopy = strdup(path);
858    char *fullpath;
859    char *ptr = NULL; // Purify complained that this was read uninitialized
860    char *token = strtok_r(pathcopy, ":", &ptr);
861
862    while (token) {
863       fullpath = (char *) ::malloc(strlen(token) + strlen(file) + 2);
864       strcpy(fullpath, token);
865       strcat(fullpath, "/");
866       strcat(fullpath, file);
867
868       struct stat statbuf;
869       if (!stat(fullpath, &statbuf))
870          break;
871
872       ::free(fullpath);
873       token = strtok_r(NULL, ":", &ptr);
874    }
875    ::free(pathcopy);
876    if (token)
877       return fullpath;
878    return NULL;
879 }
880 #else
881 char *searchPath(const char *path, const char *file) {
882   char *fullpath = (char *) ::malloc(strlen(path) + strlen(file) + 2);
883   strcpy(fullpath, path);
884   strcat(fullpath, "\\");
885   strcat(fullpath, file);
886   return fullpath;
887 }
888 #endif
889
890 /**
891  * A test should be run if:
892  *   1) It isn't disabled
893  *   2) It hasn't reported a failure/crash/skip
894  *   3) It hasn't reported final results already
895  **/
896 bool shouldRunTest(RunGroup *group, TestInfo *test)
897 {
898    if (group->disabled || test->disabled)
899       return false;
900    
901    if (test->result_reported)
902       return false;
903
904    for (unsigned i=0; i<NUM_RUNSTATES; i++)
905    {
906       if (i == program_teardown_rs)
907          continue;
908       if (test->results[i] == FAILED ||
909           test->results[i] == SKIPPED ||
910           test->results[i] == CRASHED)
911       {
912          reportTestResult(group, test);
913          return false;
914       }
915       assert(test->results[i] == UNKNOWN ||
916              test->results[i] == PASSED);
917    }
918    return true;
919 }
920
921 void reportTestResult(RunGroup *group, TestInfo *test)
922 {
923    if (test->result_reported || test->disabled)
924       return;
925
926    test_results_t result = UNKNOWN;
927    bool has_unknown = false;
928    int failed_state = -1;
929
930    for (unsigned i=0; i<NUM_RUNSTATES; i++)
931    {
932       if (i == program_teardown_rs)
933          continue;
934       if (test->results[i] == FAILED ||
935           test->results[i] == CRASHED || 
936           test->results[i] == SKIPPED) {
937          result = test->results[i];
938          failed_state = i;
939          break;
940       }
941       else if (test->results[i] == PASSED) {
942          result = test->results[i];
943       }
944       else if (test->results[i] == UNKNOWN) {
945          has_unknown = true;
946       }
947       else {
948          assert(0 && "Unknown run state");
949       }
950    }
951
952    if (result == PASSED && has_unknown)
953       return;
954
955    std::map<std::string, std::string> attrs;
956    TestOutputDriver::getAttributesMap(test, group, attrs);
957    getOutput()->startNewTest(attrs, test, group);
958    getOutput()->logResult(result, failed_state);
959    getOutput()->finalizeOutput();
960
961    log_testreported(group->index, test->index);
962    test->result_reported = true;
963 }
964
965 #if defined(os_solaris_test) || defined(os_linux_test)
966 #if !defined(cap_gnu_demangler_test)
967 /**
968  * Many linkers don't want to link the static libiberty.a unless
969  * we have a reference to it.  It's really needed by libtestdyninst.so
970  * and libtestsymtab.so, but we can't link into them because 
971  * most systems only provide a static version of this library.
972  * 
973  * Thus we need libiberty.a linked in with test_driver.  We put a reference
974  * to libiberty in libtestSuite.so here, which causes cplus_demangle to 
975  * be exported for use by libraries in in test_driver.
976  *
977  * This is intentionally unreachable code
978  **/
979 extern "C" char *cplus_demangle(char *, int);
980
981 void use_liberty()
982 {
983    cplus_demangle("a", 0);
984 }
985 #endif
986 #endif
987
988 #if defined (os_solaris_test) || defined (os_windows_test)
989 //  solaris does not provide setenv, so we provide an ersatz replacement.
990 // yes it's leaky, but we don't plan on using it too much, so who cares?
991 int setenv(const char *envname, const char *envval, int)
992 {
993         std::string *alloc_env = new std::string(std::string(envname) 
994                         + std::string("=") + std::string(envval));
995         return putenv((char *)alloc_env->c_str());
996
997 }
998 #endif