Adding new platform:ppc32_bgp
[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    int i;
609    for (i = 0; argv[i] != NULL; i++) ;
610
611    bool bgp_test = false;
612    int BGP_MAX_ARGS=13;
613         char **attach_argv;
614    char *platform = getenv("PLATFORM");
615    if(strcmp(platform, "ppc32_bgp") == 0)
616         bgp_test = true;
617    if (bgp_test) {
618    attach_argv = (char**)malloc(sizeof(char *) * BGP_MAX_ARGS);
619    for (int i = 0; i < 12; i++){
620          attach_argv[i] = (char *) malloc (1024);
621    }
622    attach_argv[12] = (char *) malloc (4*1024);
623    char *binedit_dir = BINEDIT_DIRNAME;
624    char cwd[1024]; 
625    getcwd(cwd, 1024);
626    strcat(cwd, binedit_dir);
627    strcpy(attach_argv[0], "-nofree");
628    strcpy(attach_argv[1], "-partition");
629    char *partition = getenv("DYNINST_BGP_PARTITION");
630    if(partition == NULL) partition = "BGB1";
631    strcpy(attach_argv[2], partition);
632    strcpy(attach_argv[3], "-np");
633    strcpy(attach_argv[4], "1");
634    strcpy(attach_argv[5], "-env");
635    char *dyninst_base = getenv("DYNINST_ROOT");
636         if (dyninst_base == NULL)
637                 fprintf(stderr, " DYNINST_ROOT is not set!! ");
638         sprintf(attach_argv[6], "LD_LIBRARY_PATH=.:%s/%s/binaries:%s/%s:${LD_LIBRARY_PATH}", dyninst_base, platform, dyninst_base, platform);
639 //   strcpy(attach_argv[6], "LD_LIBRARY_PATH=.:/gpfs/fs2/frontend-3/ppc32_linux:${LD_LIBRARY_PATH}");
640    strcpy(attach_argv[7], "-cwd");
641    strcpy(attach_argv[8], cwd);
642    strcpy(attach_argv[9], "-exe");
643    strcpy(attach_argv[10], (char *) pathname);
644    strcpy(attach_argv[11], "-args");
645    strcpy(attach_argv[12], "\"");
646
647    for (int j = 0; argv[j] != NULL; j++){
648         strcat(attach_argv[12], argv[j]);
649         strcat(attach_argv[12], " ");
650    }
651    strcat(attach_argv[12], "\"");
652
653    attach_argv[BGP_MAX_ARGS] = NULL;
654
655 } else{
656
657    // i now contains the count of elements in argv
658    const char **attach_argv = (const char**)malloc(sizeof(char *) * (i + 3));
659    // attach_argv is length i + 3 (including space for NULL)
660
661    for (i = 0; argv[i] != NULL; i++)
662       attach_argv[i] = argv[i];
663    if (attach)
664    {
665       attach_argv[i++] = const_cast<char*>("-attach");
666       attach_argv[i++] = fdstr;
667    }
668    attach_argv[i++] = NULL;
669 }
670
671    int pid;
672    if (attach)
673       pid = fork_mutatee();
674    else 
675       pid = fork();
676    if (pid == 0) {
677       // child
678       if (attach) 
679          close(fds[0]); // We don't need the read side
680       if (outlog != NULL) {
681          int outlog_fd = fileno(outlog);
682          if (dup2(outlog_fd, 1) == -1) {
683             fprintf(stderr, "Error duplicating log fd(1)\n");
684          }
685       }
686       if (errlog != NULL) {
687          int errlog_fd = fileno(errlog);
688          if (dup2(errlog_fd, 2) == -1) {
689             fprintf(stderr, "Error duplicating log fd(2)\n");
690          }
691       }
692       char *ld_path = getenv("LD_LIBRARY_PATH");
693       char *new_ld_path = NULL;
694       if (ld_path) {
695          new_ld_path = (char *) malloc(strlen(ld_path) + strlen(binedit_dir) + 4);
696          strcpy(new_ld_path, "./");
697          strcat(new_ld_path, binedit_dir);
698          strcat(new_ld_path, ":");
699          strcat(new_ld_path, ld_path);
700       }
701       else {
702          new_ld_path = (char *) malloc(strlen(binedit_dir) + 4);
703          strcpy(new_ld_path, "./");
704          strcat(new_ld_path, binedit_dir);
705          strcat(new_ld_path, ":");
706       }
707       setenv("LD_LIBRARY_PATH", new_ld_path, 1);
708
709           //fprintf(stderr, "%s[%d]:  before exec '%s':  LD_LIBRARY_PATH='%s'\n", 
710           //FILE__, __LINE__, pathname, getenv("LD_LIBRARY_PATH"));
711
712 if(bgp_test) {
713       printf(" running mpirun ");
714       for (int i = 0 ; i < BGP_MAX_ARGS ; i++)
715           printf(" %s", attach_argv[i]);
716       printf(" \n");
717       execvp("mpirun", (char * const *)attach_argv);
718       logerror("%s[%d]:  Exec failed!\n", FILE__, __LINE__);
719       exit(-1);
720 }else{
721       execvp(pathname, (char * const *)attach_argv);
722       char *newname = (char *) malloc(strlen(pathname) + 3);
723       strcpy(newname, "./");
724       strcat(newname, pathname);
725       execvp(newname, (char * const *)attach_argv);
726       logerror("%s[%d]:  Exec failed!\n", FILE__, __LINE__);
727       exit(-1);
728 }
729
730    } else if (pid < 0) {
731       return -1;
732    }
733
734    registerPID(pid);
735
736    // parent
737    if (attach) {
738       close(fds[1]);  // We don't need the write side
739       
740       // Wait for the child to write to the pipe
741       char ch;
742       if (read(fds[0], &ch, sizeof(char)) != sizeof(char)) {
743          perror("read");
744          fprintf(stderr, "*ERROR*: Error reading from pipe\n");
745          return -1;
746       }
747
748       if (ch != 'T') {
749          fprintf(stderr, "*ERROR*: Child didn't write expected value to pipe.\n");
750          return -1;
751       }
752        
753 #if defined( os_linux_test )
754       /* Random Linux-ism: it's possible to close the pipe before the 
755          mutatee returns from the write() system call matching the above
756          read().  In this case, rather than ignore the close() because the
757          write() is on its way out the kernel, Linux sends a SIGPIPE
758          to the mutatee, which causes us no end of trouble.  read()ing
759          an EOF from the pipe seems to alleviate this problem, and seems
760          more reliable than a sleep(1).  The condition test if we somehow
761          got any /extra/ bytes on the pipe. */
762       if( read( fds[0], & ch, sizeof( char ) ) != 0 ) {
763          fprintf(stderr, "*ERROR*: Shouldn't have read anything here.\n");
764          return -1;
765       }
766 #endif /* defined( os_linux_test ) */
767       
768       close( fds[0] ); // We're done with the pipe
769    }
770    return pid;
771 #endif
772 }
773
774
775 // control debug printf statements
776 void dprintf(const char *fmt, ...) {
777    va_list args;
778    va_start(args, fmt);
779
780    if(debugPrint)
781       vfprintf(stderr, fmt, args);
782
783    va_end(args);
784
785    fflush(stderr);
786 }
787
788 // Build Architecture specific libname
789 // FIXME Is this used any more?  Is it necessary?
790 void addLibArchExt(char *dest, unsigned int dest_max_len, int psize, bool isStatic)
791 {
792    int dest_len;
793
794    dest_len = strlen(dest);
795
796    // Patch up alternate ABI filenames
797 #if defined(rs6000_ibm_aix64_test)
798    if(psize == 4) {
799      strncat(dest, "_32", dest_max_len - dest_len);
800      dest_len += 3;
801    }
802 #endif
803
804 #if defined(arch_x86_64_test)
805    if (psize == 4) {
806       strncat(dest,"_m32", dest_max_len - dest_len);
807       dest_len += 4;   
808    }
809 #endif
810
811 #if defined(mips_sgi_irix6_4_test)
812    strncat(dest,"_n32", dest_max_len - dest_len);
813    dest_len += 4;
814 #endif
815
816 #if defined(os_windows_test)
817    strncat(dest, ".dll", dest_max_len - dest_len);
818    dest_len += 4;
819 #else
820    if( isStatic ) {
821        strncat(dest, ".a", dest_max_len - dest_len);
822        dest_len += 2;
823    }else{
824        strncat(dest, ".so", dest_max_len - dest_len);
825        dest_len += 3;
826    }
827 #endif
828 }
829
830 #define TOLOWER(c) ((c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c)
831 int strcmpcase(char *s1, char *s2) {
832     unsigned i;
833     unsigned char s1_c, s2_c;
834     for (i=0; s1[i] || s2[i]; i++) {
835         s1_c = TOLOWER(s1[i]);
836         s2_c = TOLOWER(s2[i]);
837         if (s1_c < s2_c)
838             return -1;
839         if (s1_c > s2_c)
840             return 1;
841     }
842     return 0;
843 }
844
845
846 #if !defined(os_windows_test)
847 char *searchPath(const char *path, const char *file) {
848    assert(path);
849    assert(file);
850
851    char *pathcopy = strdup(path);
852    char *fullpath;
853    char *ptr = NULL; // Purify complained that this was read uninitialized
854    char *token = strtok_r(pathcopy, ":", &ptr);
855
856    while (token) {
857       fullpath = (char *) ::malloc(strlen(token) + strlen(file) + 2);
858       strcpy(fullpath, token);
859       strcat(fullpath, "/");
860       strcat(fullpath, file);
861
862       struct stat statbuf;
863       if (!stat(fullpath, &statbuf))
864          break;
865
866       ::free(fullpath);
867       token = strtok_r(NULL, ":", &ptr);
868    }
869    ::free(pathcopy);
870    if (token)
871       return fullpath;
872    return NULL;
873 }
874 #else
875 char *searchPath(const char *path, const char *file) {
876   char *fullpath = (char *) ::malloc(strlen(path) + strlen(file) + 2);
877   strcpy(fullpath, path);
878   strcat(fullpath, "\\");
879   strcat(fullpath, file);
880   return fullpath;
881 }
882 #endif
883
884 /**
885  * A test should be run if:
886  *   1) It isn't disabled
887  *   2) It hasn't reported a failure/crash/skip
888  *   3) It hasn't reported final results already
889  **/
890 bool shouldRunTest(RunGroup *group, TestInfo *test)
891 {
892    if (group->disabled || test->disabled)
893       return false;
894    
895    if (test->result_reported)
896       return false;
897
898    for (unsigned i=0; i<NUM_RUNSTATES; i++)
899    {
900       if (i == program_teardown_rs)
901          continue;
902       if (test->results[i] == FAILED ||
903           test->results[i] == SKIPPED ||
904           test->results[i] == CRASHED)
905       {
906          reportTestResult(group, test);
907          return false;
908       }
909       assert(test->results[i] == UNKNOWN ||
910              test->results[i] == PASSED);
911    }
912    return true;
913 }
914
915 void reportTestResult(RunGroup *group, TestInfo *test)
916 {
917    if (test->result_reported || test->disabled)
918       return;
919
920    test_results_t result = UNKNOWN;
921    bool has_unknown = false;
922    int failed_state = -1;
923
924    for (unsigned i=0; i<NUM_RUNSTATES; i++)
925    {
926       if (i == program_teardown_rs)
927          continue;
928       if (test->results[i] == FAILED ||
929           test->results[i] == CRASHED || 
930           test->results[i] == SKIPPED) {
931          result = test->results[i];
932          failed_state = i;
933          break;
934       }
935       else if (test->results[i] == PASSED) {
936          result = test->results[i];
937       }
938       else if (test->results[i] == UNKNOWN) {
939          has_unknown = true;
940       }
941       else {
942          assert(0 && "Unknown run state");
943       }
944    }
945
946    if (result == PASSED && has_unknown)
947       return;
948
949    std::map<std::string, std::string> attrs;
950    TestOutputDriver::getAttributesMap(test, group, attrs);
951    getOutput()->startNewTest(attrs, test, group);
952    getOutput()->logResult(result, failed_state);
953    getOutput()->finalizeOutput();
954
955    log_testreported(group->index, test->index);
956    test->result_reported = true;
957 }
958
959 #if defined(os_solaris_test) || defined(os_linux_test)
960 #if !defined(cap_gnu_demangler_test)
961 /**
962  * Many linkers don't want to link the static libiberty.a unless
963  * we have a reference to it.  It's really needed by libtestdyninst.so
964  * and libtestsymtab.so, but we can't link into them because 
965  * most systems only provide a static version of this library.
966  * 
967  * Thus we need libiberty.a linked in with test_driver.  We put a reference
968  * to libiberty in libtestSuite.so here, which causes cplus_demangle to 
969  * be exported for use by libraries in in test_driver.
970  *
971  * This is intentionally unreachable code
972  **/
973 extern "C" char *cplus_demangle(char *, int);
974
975 void use_liberty()
976 {
977    cplus_demangle("a", 0);
978 }
979 #endif
980 #endif
981
982 #if defined (os_solaris_test) || defined (os_windows_test)
983 //  solaris does not provide setenv, so we provide an ersatz replacement.
984 // yes it's leaky, but we don't plan on using it too much, so who cares?
985 int setenv(const char *envname, const char *envval, int)
986 {
987         std::string *alloc_env = new std::string(std::string(envname) 
988                         + std::string("=") + std::string(envval));
989         return putenv((char *)alloc_env->c_str());
990
991 }
992 #endif