240044516eb61bb045ad18accf6e55d6f7ee8c2b
[oota-llvm.git] / lib / Support / SystemUtils.cpp
1 //===- SystemUtils.h - Utilities to do low-level system stuff --*- C++ -*--===//
2 // 
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file was developed by the LLVM research group and is distributed under
6 // the University of Illinois Open Source License. See LICENSE.TXT for details.
7 // 
8 //===----------------------------------------------------------------------===//
9 //
10 // This file contains functions used to do a variety of low-level, often
11 // system-specific, tasks.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #define _POSIX_MAPPED_FILES
16 #include "Support/SystemUtils.h"
17 #include "Config/sys/types.h"
18 #include "Config/sys/stat.h"
19 #include "Config/fcntl.h"
20 #include "Config/sys/wait.h"
21 #include "Config/sys/mman.h"
22 #include "Config/unistd.h"
23 #include <algorithm>
24 #include <fstream>
25 #include <iostream>
26 #include <cstdlib>
27 #include <cerrno>
28 using namespace llvm;
29
30 /// isExecutableFile - This function returns true if the filename specified
31 /// exists and is executable.
32 ///
33 bool llvm::isExecutableFile(const std::string &ExeFileName) {
34   struct stat Buf;
35   if (stat(ExeFileName.c_str(), &Buf))
36     return false;  // Must not be executable!
37
38   if (!(Buf.st_mode & S_IFREG))
39     return false;                    // Not a regular file?
40
41   if (Buf.st_uid == getuid())        // Owner of file?
42     return Buf.st_mode & S_IXUSR;
43   else if (Buf.st_gid == getgid())   // In group of file?
44     return Buf.st_mode & S_IXGRP;
45   else                               // Unrelated to file?
46     return Buf.st_mode & S_IXOTH;
47 }
48
49 /// isStandardOutAConsole - Return true if we can tell that the standard output
50 /// stream goes to a terminal window or console.
51 bool llvm::isStandardOutAConsole() {
52 #if HAVE_ISATTY
53   return isatty(1);
54 #endif
55   // If we don't have isatty, just return false.
56   return false;
57 }
58
59
60 /// FindExecutable - Find a named executable, giving the argv[0] of program
61 /// being executed. This allows us to find another LLVM tool if it is built
62 /// into the same directory, but that directory is neither the current
63 /// directory, nor in the PATH.  If the executable cannot be found, return an
64 /// empty string.
65 /// 
66 std::string llvm::FindExecutable(const std::string &ExeName,
67                                  const std::string &ProgramPath) {
68   // First check the directory that bugpoint is in.  We can do this if
69   // BugPointPath contains at least one / character, indicating that it is a
70   // relative path to bugpoint itself.
71   //
72   std::string Result = ProgramPath;
73   while (!Result.empty() && Result[Result.size()-1] != '/')
74     Result.erase(Result.size()-1, 1);
75
76   if (!Result.empty()) {
77     Result += ExeName;
78     if (isExecutableFile(Result)) return Result; // Found it?
79   }
80
81   // Okay, if the path to the program didn't tell us anything, try using the
82   // PATH environment variable.
83   const char *PathStr = getenv("PATH");
84   if (PathStr == 0) return "";
85
86   // Now we have a colon separated list of directories to search... try them...
87   unsigned PathLen = strlen(PathStr);
88   while (PathLen) {
89     // Find the first colon...
90     const char *Colon = std::find(PathStr, PathStr+PathLen, ':');
91     
92     // Check to see if this first directory contains the executable...
93     std::string FilePath = std::string(PathStr, Colon) + '/' + ExeName;
94     if (isExecutableFile(FilePath))
95       return FilePath;                    // Found the executable!
96    
97     // Nope it wasn't in this directory, check the next range!
98     PathLen -= Colon-PathStr;
99     PathStr = Colon;
100     while (*PathStr == ':') {   // Advance past colons
101       PathStr++;
102       PathLen--;
103     }
104   }
105
106   // If we fell out, we ran out of directories in PATH to search, return failure
107   return "";
108 }
109
110 static void RedirectFD(const std::string &File, int FD) {
111   if (File.empty()) return;  // Noop
112
113   // Open the file
114   int InFD = open(File.c_str(), FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666);
115   if (InFD == -1) {
116     std::cerr << "Error opening file '" << File << "' for "
117               << (FD == 0 ? "input" : "output") << "!\n";
118     exit(1);
119   }
120
121   dup2(InFD, FD);   // Install it as the requested FD
122   close(InFD);      // Close the original FD
123 }
124
125 /// RunProgramWithTimeout - This function executes the specified program, with
126 /// the specified null-terminated argument array, with the stdin/out/err fd's
127 /// redirected, with a timeout specified on the command line.  This terminates
128 /// the calling program if there is an error executing the specified program.
129 /// It returns the return value of the program, or -1 if a timeout is detected.
130 ///
131 int llvm::RunProgramWithTimeout(const std::string &ProgramPath,
132                                 const char **Args,
133                                 const std::string &StdInFile,
134                                 const std::string &StdOutFile,
135                                 const std::string &StdErrFile) {
136   // FIXME: install sigalarm handler here for timeout...
137
138 #ifdef HAVE_SYS_WAIT_H
139   int Child = fork();
140   switch (Child) {
141   case -1:
142     std::cerr << "ERROR forking!\n";
143     exit(1);
144   case 0:               // Child
145     RedirectFD(StdInFile, 0);      // Redirect file descriptors...
146     RedirectFD(StdOutFile, 1);
147     if (StdOutFile != StdErrFile)
148       RedirectFD(StdErrFile, 2);
149     else
150       dup2(1, 2);
151
152     execv(ProgramPath.c_str(), (char *const *)Args);
153     std::cerr << "Error executing program: '" << ProgramPath;
154     for (; *Args; ++Args)
155       std::cerr << " " << *Args;
156     std::cerr << "'\n";
157     exit(1);
158
159   default: break;
160   }
161
162   // Make sure all output has been written while waiting
163   std::cout << std::flush;
164
165   int Status;
166   if (wait(&Status) != Child) {
167     if (errno == EINTR) {
168       static bool FirstTimeout = true;
169       if (FirstTimeout) {
170         std::cout <<
171  "*** Program execution timed out!  This mechanism is designed to handle\n"
172  "    programs stuck in infinite loops gracefully.  The -timeout option\n"
173  "    can be used to change the timeout threshold or disable it completely\n"
174  "    (with -timeout=0).  This message is only displayed once.\n";
175         FirstTimeout = false;
176       }
177       return -1;   // Timeout detected
178     }
179
180     std::cerr << "Error waiting for child process!\n";
181     exit(1);
182   }
183   return Status;
184
185 #else
186   std::cerr << "RunProgramWithTimeout not implemented on this platform!\n";
187   return -1;
188 #endif
189 }
190
191
192 //
193 // Function: ExecWait ()
194 //
195 // Description:
196 //  This function executes a program with the specified arguments and
197 //  environment.  It then waits for the progarm to termiante and then returns
198 //  to the caller.
199 //
200 // Inputs:
201 //  argv - The arguments to the program as an array of C strings.  The first
202 //         argument should be the name of the program to execute, and the
203 //         last argument should be a pointer to NULL.
204 //
205 //  envp - The environment passes to the program as an array of C strings in
206 //         the form of "name=value" pairs.  The last element should be a
207 //         pointer to NULL.
208 //
209 // Outputs:
210 //  None.
211 //
212 // Return value:
213 //  0 - No errors.
214 //  1 - The program could not be executed.
215 //  1 - The program returned a non-zero exit status.
216 //  1 - The program terminated abnormally.
217 //
218 // Notes:
219 //  The program will inherit the stdin, stdout, and stderr file descriptors
220 //  as well as other various configuration settings (umask).
221 //
222 //  This function should not print anything to stdout/stderr on its own.  It is
223 //  a generic library function.  The caller or executed program should report
224 //  errors in the way it sees fit.
225 //
226 //  This function does not use $PATH to find programs.
227 //
228 int llvm::ExecWait(const char * const old_argv[],
229                    const char * const old_envp[]) {
230 #ifdef HAVE_SYS_WAIT_H
231   //
232   // Create local versions of the parameters that can be passed into execve()
233   // without creating const problems.
234   //
235   char ** const argv = (char ** const) old_argv;
236   char ** const envp = (char ** const) old_envp;
237
238   // Create a child process.
239   switch (fork()) {
240     // An error occured:  Return to the caller.
241     case -1:
242       return 1;
243       break;
244
245     // Child process: Execute the program.
246     case 0:
247       execve (argv[0], argv, envp);
248       // If the execve() failed, we should exit and let the parent pick up
249       // our non-zero exit status.
250       exit (1);
251
252     // Parent process: Break out of the switch to do our processing.
253     default:
254       break;
255   }
256
257   // Parent process: Wait for the child process to termiante.
258   int status;
259   if ((wait (&status)) == -1)
260     return 1;
261
262   // If the program exited normally with a zero exit status, return success!
263   if (WIFEXITED (status) && (WEXITSTATUS(status) == 0))
264     return 0;
265 #else
266   std::cerr << "llvm::ExecWait not implemented on this platform!\n";
267 #endif
268
269   // Otherwise, return failure.
270   return 1;
271 }
272
273 /// AllocateRWXMemory - Allocate a slab of memory with read/write/execute
274 /// permissions.  This is typically used for JIT applications where we want
275 /// to emit code to the memory then jump to it.  Getting this type of memory
276 /// is very OS specific.
277 ///
278 void *llvm::AllocateRWXMemory(unsigned NumBytes) {
279   if (NumBytes == 0) return 0;
280   static const long pageSize = sysconf(_SC_PAGESIZE);
281   unsigned NumPages = (NumBytes+pageSize-1)/pageSize;
282
283 /* FIXME: This should use the proper autoconf flags */
284 #if defined(i386) || defined(__i386__) || defined(__x86__)
285   /* Linux and *BSD tend to have these flags named differently. */
286 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
287 # define MAP_ANONYMOUS MAP_ANON
288 #endif /* defined(MAP_ANON) && !defined(MAP_ANONYMOUS) */
289 #elif defined(sparc) || defined(__sparc__) || defined(__sparcv9)
290 /* nothing */
291 #else
292   std::cerr << "This architecture is not supported by the JIT!\n";
293   abort();
294   return 0;
295 #endif
296
297 #ifdef HAVE_MMAP
298   int fd = -1;
299 #if defined(__linux__)
300   fd = 0;
301 #endif
302
303   unsigned mmapFlags = MAP_PRIVATE|MAP_ANONYMOUS;
304 #ifdef MAP_NORESERVE
305   mmapFlags |= MAP_NORESERVE;
306 #endif
307
308   void *pa = mmap(0, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC,
309                   mmapFlags, fd, 0);
310   if (pa == MAP_FAILED) {
311     perror("mmap");
312     abort();
313   }
314   return pa;
315 #else
316   std::cerr << "Do not know how to allocate mem for the JIT without mmap!\n";
317   abort();
318   return 0;
319 #endif
320 }
321
322