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