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