diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-11-29 18:16:10 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2010-11-29 18:16:10 +0000 |
commit | 1f6efa3996dd1929fbc129203ce5009b620e6969 (patch) | |
tree | 6b782914982f90d3a983bcefef98b8ef68ab2961 /lib/Support | |
parent | 9363f739cdc3bd02e8516a25de0090f52ae12fbb (diff) | |
download | external_llvm-1f6efa3996dd1929fbc129203ce5009b620e6969.zip external_llvm-1f6efa3996dd1929fbc129203ce5009b620e6969.tar.gz external_llvm-1f6efa3996dd1929fbc129203ce5009b620e6969.tar.bz2 |
Merge System into Support.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120298 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Support')
69 files changed, 7414 insertions, 36 deletions
diff --git a/lib/Support/Alarm.cpp b/lib/Support/Alarm.cpp new file mode 100644 index 0000000..58ad609 --- /dev/null +++ b/lib/Support/Alarm.cpp @@ -0,0 +1,33 @@ +//===- Alarm.cpp - Alarm Generation Support ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Alarm functionality +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Alarm.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Alarm.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Alarm.inc" +#endif diff --git a/lib/Support/Allocator.cpp b/lib/Support/Allocator.cpp index 02b45d8..5e27df6 100644 --- a/lib/Support/Allocator.cpp +++ b/lib/Support/Allocator.cpp @@ -12,10 +12,10 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Allocator.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Recycler.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Memory.h" +#include "llvm/Support/Memory.h" #include <cstring> namespace llvm { diff --git a/lib/Support/Atomic.cpp b/lib/Support/Atomic.cpp new file mode 100644 index 0000000..c7b4bff --- /dev/null +++ b/lib/Support/Atomic.cpp @@ -0,0 +1,112 @@ +//===-- Atomic.cpp - Atomic Operations --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements atomic operations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Atomic.h" +#include "llvm/Config/config.h" + +using namespace llvm; + +#if defined(_MSC_VER) +#include <windows.h> +#undef MemoryFence +#endif + +void sys::MemoryFence() { +#if LLVM_MULTITHREADED==0 + return; +#else +# if defined(__GNUC__) + __sync_synchronize(); +# elif defined(_MSC_VER) + MemoryBarrier(); +# else +# error No memory fence implementation for your platform! +# endif +#endif +} + +sys::cas_flag sys::CompareAndSwap(volatile sys::cas_flag* ptr, + sys::cas_flag new_value, + sys::cas_flag old_value) { +#if LLVM_MULTITHREADED==0 + sys::cas_flag result = *ptr; + if (result == old_value) + *ptr = new_value; + return result; +#elif defined(__GNUC__) + return __sync_val_compare_and_swap(ptr, old_value, new_value); +#elif defined(_MSC_VER) + return InterlockedCompareExchange(ptr, new_value, old_value); +#else +# error No compare-and-swap implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicIncrement(volatile sys::cas_flag* ptr) { +#if LLVM_MULTITHREADED==0 + ++(*ptr); + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, 1); +#elif defined(_MSC_VER) + return InterlockedIncrement(ptr); +#else +# error No atomic increment implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicDecrement(volatile sys::cas_flag* ptr) { +#if LLVM_MULTITHREADED==0 + --(*ptr); + return *ptr; +#elif defined(__GNUC__) + return __sync_sub_and_fetch(ptr, 1); +#elif defined(_MSC_VER) + return InterlockedDecrement(ptr); +#else +# error No atomic decrement implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicAdd(volatile sys::cas_flag* ptr, sys::cas_flag val) { +#if LLVM_MULTITHREADED==0 + *ptr += val; + return *ptr; +#elif defined(__GNUC__) + return __sync_add_and_fetch(ptr, val); +#elif defined(_MSC_VER) + return InterlockedExchangeAdd(ptr, val) + val; +#else +# error No atomic add implementation for your platform! +#endif +} + +sys::cas_flag sys::AtomicMul(volatile sys::cas_flag* ptr, sys::cas_flag val) { + sys::cas_flag original, result; + do { + original = *ptr; + result = original * val; + } while (sys::CompareAndSwap(ptr, result, original) != original); + + return result; +} + +sys::cas_flag sys::AtomicDiv(volatile sys::cas_flag* ptr, sys::cas_flag val) { + sys::cas_flag original, result; + do { + original = *ptr; + result = original / val; + } while (sys::CompareAndSwap(ptr, result, original) != original); + + return result; +} diff --git a/lib/Support/CMakeLists.txt b/lib/Support/CMakeLists.txt index 8a6ed6f..105a507 100644 --- a/lib/Support/CMakeLists.txt +++ b/lib/Support/CMakeLists.txt @@ -1,5 +1,8 @@ ## FIXME: This only requires RTTI because tblgen uses it. Fix that. set(LLVM_REQUIRES_RTTI 1) +if( MINGW ) + set(LLVM_REQUIRES_EH 1) +endif() add_llvm_library(LLVMSupport APFloat.cpp @@ -49,4 +52,51 @@ add_llvm_library(LLVMSupport regexec.c regfree.c regstrlcpy.c + +# System + Alarm.cpp + Atomic.cpp + Disassembler.cpp + DynamicLibrary.cpp + Errno.cpp + Host.cpp + IncludeFile.cpp + Memory.cpp + Mutex.cpp + Path.cpp + Process.cpp + Program.cpp + RWMutex.cpp + SearchForAddressOfSpecialSymbol.cpp + Signals.cpp + system_error.cpp + ThreadLocal.cpp + Threading.cpp + TimeValue.cpp + Valgrind.cpp + Unix/Alarm.inc + Unix/Host.inc + Unix/Memory.inc + Unix/Mutex.inc + Unix/Path.inc + Unix/Process.inc + Unix/Program.inc + Unix/RWMutex.inc + Unix/Signals.inc + Unix/system_error.inc + Unix/ThreadLocal.inc + Unix/TimeValue.inc + Windows/Alarm.inc + Windows/DynamicLibrary.inc + Windows/Host.inc + Windows/Memory.inc + Windows/Mutex.inc + Windows/Path.inc + Windows/Process.inc + Windows/Program.inc + Windows/RWMutex.inc + Windows/Signals.inc + Windows/system_error.inc + Windows/ThreadLocal.inc + Windows/TimeValue.inc ) diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index 38ef084..a99e46d 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -23,8 +23,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetRegistry.h" -#include "llvm/System/Host.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/Support/CrashRecoveryContext.cpp b/lib/Support/CrashRecoveryContext.cpp index f24d6bd..bf8ca3f 100644 --- a/lib/Support/CrashRecoveryContext.cpp +++ b/lib/Support/CrashRecoveryContext.cpp @@ -10,8 +10,8 @@ #include "llvm/Support/CrashRecoveryContext.h" #include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/ThreadLocal.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/ThreadLocal.h" #include <setjmp.h> #include <cstdio> using namespace llvm; diff --git a/lib/Support/Debug.cpp b/lib/Support/Debug.cpp index 7f48f8a..9fdb12e 100644 --- a/lib/Support/Debug.cpp +++ b/lib/Support/Debug.cpp @@ -26,7 +26,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/circular_raw_ostream.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/Signals.h" using namespace llvm; diff --git a/lib/Support/Disassembler.cpp b/lib/Support/Disassembler.cpp new file mode 100644 index 0000000..6362aff --- /dev/null +++ b/lib/Support/Disassembler.cpp @@ -0,0 +1,75 @@ +//===- lib/System/Disassembler.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the necessary glue to call external disassembler +// libraries. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Disassembler.h" + +#include <cassert> +#include <iomanip> +#include <string> +#include <sstream> + +#if USE_UDIS86 +#include <udis86.h> +#endif + +using namespace llvm; + +bool llvm::sys::hasDisassembler() +{ +#if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) + // We have option to enable udis86 library. +# if USE_UDIS86 + return true; +#else + return false; +#endif +#else + return false; +#endif +} + +std::string llvm::sys::disassembleBuffer(uint8_t* start, size_t length, + uint64_t pc) { + std::stringstream res; + +#if (defined (__i386__) || defined (__amd64__) || defined (__x86_64__)) \ + && USE_UDIS86 + unsigned bits; +# if defined(__i386__) + bits = 32; +# else + bits = 64; +# endif + + ud_t ud_obj; + + ud_init(&ud_obj); + ud_set_input_buffer(&ud_obj, start, length); + ud_set_mode(&ud_obj, bits); + ud_set_pc(&ud_obj, pc); + ud_set_syntax(&ud_obj, UD_SYN_ATT); + + res << std::setbase(16) + << std::setw(bits/4); + + while (ud_disassemble(&ud_obj)) { + res << ud_insn_off(&ud_obj) << ":\t" << ud_insn_asm(&ud_obj) << "\n"; + } +#else + res << "No disassembler available. See configure help for options.\n"; +#endif + + return res.str(); +} diff --git a/lib/Support/DynamicLibrary.cpp b/lib/Support/DynamicLibrary.cpp new file mode 100644 index 0000000..cd9927a --- /dev/null +++ b/lib/Support/DynamicLibrary.cpp @@ -0,0 +1,177 @@ +//===-- DynamicLibrary.cpp - Runtime link/load libraries --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system DynamicLibrary concept. +// +// FIXME: This file leaks the ExplicitSymbols and OpenedHandles vector, and is +// not thread safe! +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Config/config.h" +#include <cstdio> +#include <cstring> +#include <map> +#include <vector> + +// Collection of symbol name/value pairs to be searched prior to any libraries. +static std::map<std::string, void*> *ExplicitSymbols = 0; + +namespace { + +struct ExplicitSymbolsDeleter { + ~ExplicitSymbolsDeleter() { + if (ExplicitSymbols) + delete ExplicitSymbols; + } +}; + +} + +static ExplicitSymbolsDeleter Dummy; + +void llvm::sys::DynamicLibrary::AddSymbol(const char* symbolName, + void *symbolValue) { + if (ExplicitSymbols == 0) + ExplicitSymbols = new std::map<std::string, void*>(); + (*ExplicitSymbols)[symbolName] = symbolValue; +} + +#ifdef LLVM_ON_WIN32 + +#include "Windows/DynamicLibrary.inc" + +#else + +#if HAVE_DLFCN_H +#include <dlfcn.h> +using namespace llvm; +using namespace llvm::sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +static SmartMutex<true>* HandlesMutex; +static std::vector<void *> *OpenedHandles = 0; + +static bool InitializeMutex() { + HandlesMutex = new SmartMutex<true>; + return HandlesMutex != 0; +} + +static bool EnsureMutexInitialized() { + static bool result = InitializeMutex(); + return result; +} + + +bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, + std::string *ErrMsg) { + void *H = dlopen(Filename, RTLD_LAZY|RTLD_GLOBAL); + if (H == 0) { + if (ErrMsg) *ErrMsg = dlerror(); + return true; + } +#ifdef __CYGWIN__ + // Cygwin searches symbols only in the main + // with the handle of dlopen(NULL, RTLD_GLOBAL). + if (Filename == NULL) + H = RTLD_DEFAULT; +#endif + EnsureMutexInitialized(); + SmartScopedLock<true> Lock(*HandlesMutex); + if (OpenedHandles == 0) + OpenedHandles = new std::vector<void *>(); + OpenedHandles->push_back(H); + return false; +} +#else + +using namespace llvm; +using namespace llvm::sys; + +bool DynamicLibrary::LoadLibraryPermanently(const char *Filename, + std::string *ErrMsg) { + if (ErrMsg) *ErrMsg = "dlopen() not supported on this platform"; + return true; +} +#endif + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName); +} + +void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { + // First check symbols added via AddSymbol(). + if (ExplicitSymbols) { + std::map<std::string, void *>::iterator I = + ExplicitSymbols->find(symbolName); + std::map<std::string, void *>::iterator E = ExplicitSymbols->end(); + + if (I != E) + return I->second; + } + +#if HAVE_DLFCN_H + // Now search the libraries. + EnsureMutexInitialized(); + SmartScopedLock<true> Lock(*HandlesMutex); + if (OpenedHandles) { + for (std::vector<void *>::iterator I = OpenedHandles->begin(), + E = OpenedHandles->end(); I != E; ++I) { + //lt_ptr ptr = lt_dlsym(*I, symbolName); + void *ptr = dlsym(*I, symbolName); + if (ptr) { + return ptr; + } + } + } +#endif + + if (void *Result = llvm::SearchForAddressOfSpecialSymbol(symbolName)) + return Result; + +// This macro returns the address of a well-known, explicit symbol +#define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(symbolName, #SYM)) return &SYM + +// On linux we have a weird situation. The stderr/out/in symbols are both +// macros and global variables because of standards requirements. So, we +// boldly use the EXPLICIT_SYMBOL macro without checking for a #define first. +#if defined(__linux__) + { + EXPLICIT_SYMBOL(stderr); + EXPLICIT_SYMBOL(stdout); + EXPLICIT_SYMBOL(stdin); + } +#else + // For everything else, we want to check to make sure the symbol isn't defined + // as a macro before using EXPLICIT_SYMBOL. + { +#ifndef stdin + EXPLICIT_SYMBOL(stdin); +#endif +#ifndef stdout + EXPLICIT_SYMBOL(stdout); +#endif +#ifndef stderr + EXPLICIT_SYMBOL(stderr); +#endif + } +#endif +#undef EXPLICIT_SYMBOL + + return 0; +} + +#endif // LLVM_ON_WIN32 diff --git a/lib/Support/Errno.cpp b/lib/Support/Errno.cpp new file mode 100644 index 0000000..312d91e --- /dev/null +++ b/lib/Support/Errno.cpp @@ -0,0 +1,74 @@ +//===- Errno.cpp - errno support --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the errno wrappers. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Errno.h" +#include "llvm/Config/config.h" // Get autoconf configuration settings + +#if HAVE_STRING_H +#include <string.h> + +#if HAVE_ERRNO_H +#include <errno.h> +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +namespace llvm { +namespace sys { + +#if HAVE_ERRNO_H +std::string StrError() { + return StrError(errno); +} +#endif // HAVE_ERRNO_H + +std::string StrError(int errnum) { + const int MaxErrStrLen = 2000; + char buffer[MaxErrStrLen]; + buffer[0] = '\0'; + char* str = buffer; +#ifdef HAVE_STRERROR_R + // strerror_r is thread-safe. + if (errnum) +# if defined(__GLIBC__) && defined(_GNU_SOURCE) + // glibc defines its own incompatible version of strerror_r + // which may not use the buffer supplied. + str = strerror_r(errnum,buffer,MaxErrStrLen-1); +# else + strerror_r(errnum,buffer,MaxErrStrLen-1); +# endif +#elif defined(HAVE_STRERROR_S) // Windows. + if (errnum) + strerror_s(buffer, errnum); +#elif defined(HAVE_STRERROR) + // Copy the thread un-safe result of strerror into + // the buffer as fast as possible to minimize impact + // of collision of strerror in multiple threads. + if (errnum) + strncpy(buffer,strerror(errnum),MaxErrStrLen-1); + buffer[MaxErrStrLen-1] = '\0'; +#else + // Strange that this system doesn't even have strerror + // but, oh well, just use a generic message + sprintf(buffer, "Error #%d", errnum); +#endif + return str; +} + +} // namespace sys +} // namespace llvm + +#endif // HAVE_STRING_H diff --git a/lib/Support/ErrorHandling.cpp b/lib/Support/ErrorHandling.cpp index 66b2c83..3579546 100644 --- a/lib/Support/ErrorHandling.cpp +++ b/lib/Support/ErrorHandling.cpp @@ -16,8 +16,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" -#include "llvm/System/Threading.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/Threading.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Config/config.h" #include <cassert> diff --git a/lib/Support/FileUtilities.cpp b/lib/Support/FileUtilities.cpp index 1bde2fe..7220085 100644 --- a/lib/Support/FileUtilities.cpp +++ b/lib/Support/FileUtilities.cpp @@ -15,7 +15,7 @@ #include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" #include <cstdlib> diff --git a/lib/Support/FoldingSet.cpp b/lib/Support/FoldingSet.cpp index 11a1de4..a4f80a9 100644 --- a/lib/Support/FoldingSet.cpp +++ b/lib/Support/FoldingSet.cpp @@ -18,7 +18,7 @@ #include "llvm/Support/Allocator.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/Host.h" +#include "llvm/Support/Host.h" #include <cassert> #include <cstring> using namespace llvm; diff --git a/lib/Support/GraphWriter.cpp b/lib/Support/GraphWriter.cpp index 79e978a..0dba28a 100644 --- a/lib/Support/GraphWriter.cpp +++ b/lib/Support/GraphWriter.cpp @@ -12,8 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/GraphWriter.h" -#include "llvm/System/Path.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Config/config.h" using namespace llvm; diff --git a/lib/Support/Host.cpp b/lib/Support/Host.cpp new file mode 100644 index 0000000..4dacf96 --- /dev/null +++ b/lib/Support/Host.cpp @@ -0,0 +1,307 @@ +//===-- Host.cpp - Implement OS Host Concept --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Host concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Host.h" +#include "llvm/Config/config.h" +#include <string.h> + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Host.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Host.inc" +#endif +#ifdef _MSC_VER +#include <intrin.h> +#endif + +//===----------------------------------------------------------------------===// +// +// Implementations of the CPU detection routines +// +//===----------------------------------------------------------------------===// + +using namespace llvm; + +#if defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86)\ + || defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + +/// GetX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in the +/// specified arguments. If we can't run cpuid on the host, return true. +static bool GetX86CpuIDAndInfo(unsigned value, unsigned *rEAX, + unsigned *rEBX, unsigned *rECX, unsigned *rEDX) { +#if defined(__x86_64__) || defined(_M_AMD64) || defined (_M_X64) + #if defined(__GNUC__) + // gcc doesn't know cpuid would clobber ebx/rbx. Preseve it manually. + asm ("movq\t%%rbx, %%rsi\n\t" + "cpuid\n\t" + "xchgq\t%%rbx, %%rsi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + int registers[4]; + __cpuid(registers, value); + *rEAX = registers[0]; + *rEBX = registers[1]; + *rECX = registers[2]; + *rEDX = registers[3]; + return false; + #endif +#elif defined(i386) || defined(__i386__) || defined(__x86__) || defined(_M_IX86) + #if defined(__GNUC__) + asm ("movl\t%%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl\t%%ebx, %%esi\n\t" + : "=a" (*rEAX), + "=S" (*rEBX), + "=c" (*rECX), + "=d" (*rEDX) + : "a" (value)); + return false; + #elif defined(_MSC_VER) + __asm { + mov eax,value + cpuid + mov esi,rEAX + mov dword ptr [esi],eax + mov esi,rEBX + mov dword ptr [esi],ebx + mov esi,rECX + mov dword ptr [esi],ecx + mov esi,rEDX + mov dword ptr [esi],edx + } + return false; + #endif +#endif + return true; +} + +static void DetectX86FamilyModel(unsigned EAX, unsigned &Family, + unsigned &Model) { + Family = (EAX >> 8) & 0xf; // Bits 8 - 11 + Model = (EAX >> 4) & 0xf; // Bits 4 - 7 + if (Family == 6 || Family == 0xf) { + if (Family == 0xf) + // Examine extended family ID if family ID is F. + Family += (EAX >> 20) & 0xff; // Bits 20 - 27 + // Examine extended model ID if family ID is 6 or F. + Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19 + } +} + +std::string sys::getHostCPUName() { + unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0; + if (GetX86CpuIDAndInfo(0x1, &EAX, &EBX, &ECX, &EDX)) + return "generic"; + unsigned Family = 0; + unsigned Model = 0; + DetectX86FamilyModel(EAX, Family, Model); + + bool HasSSE3 = (ECX & 0x1); + GetX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX); + bool Em64T = (EDX >> 29) & 0x1; + + union { + unsigned u[3]; + char c[12]; + } text; + + GetX86CpuIDAndInfo(0, &EAX, text.u+0, text.u+2, text.u+1); + if (memcmp(text.c, "GenuineIntel", 12) == 0) { + switch (Family) { + case 3: + return "i386"; + case 4: + switch (Model) { + case 0: // Intel486 DX processors + case 1: // Intel486 DX processors + case 2: // Intel486 SX processors + case 3: // Intel487 processors, IntelDX2 OverDrive processors, + // IntelDX2 processors + case 4: // Intel486 SL processor + case 5: // IntelSX2 processors + case 7: // Write-Back Enhanced IntelDX2 processors + case 8: // IntelDX4 OverDrive processors, IntelDX4 processors + default: return "i486"; + } + case 5: + switch (Model) { + case 1: // Pentium OverDrive processor for Pentium processor (60, 66), + // Pentium processors (60, 66) + case 2: // Pentium OverDrive processor for Pentium processor (75, 90, + // 100, 120, 133), Pentium processors (75, 90, 100, 120, 133, + // 150, 166, 200) + case 3: // Pentium OverDrive processors for Intel486 processor-based + // systems + return "pentium"; + + case 4: // Pentium OverDrive processor with MMX technology for Pentium + // processor (75, 90, 100, 120, 133), Pentium processor with + // MMX technology (166, 200) + return "pentium-mmx"; + + default: return "pentium"; + } + case 6: + switch (Model) { + case 1: // Pentium Pro processor + return "pentiumpro"; + + case 3: // Intel Pentium II OverDrive processor, Pentium II processor, + // model 03 + case 5: // Pentium II processor, model 05, Pentium II Xeon processor, + // model 05, and Intel Celeron processor, model 05 + case 6: // Celeron processor, model 06 + return "pentium2"; + + case 7: // Pentium III processor, model 07, and Pentium III Xeon + // processor, model 07 + case 8: // Pentium III processor, model 08, Pentium III Xeon processor, + // model 08, and Celeron processor, model 08 + case 10: // Pentium III Xeon processor, model 0Ah + case 11: // Pentium III processor, model 0Bh + return "pentium3"; + + case 9: // Intel Pentium M processor, Intel Celeron M processor model 09. + case 13: // Intel Pentium M processor, Intel Celeron M processor, model + // 0Dh. All processors are manufactured using the 90 nm process. + return "pentium-m"; + + case 14: // Intel Core Duo processor, Intel Core Solo processor, model + // 0Eh. All processors are manufactured using the 65 nm process. + return "yonah"; + + case 15: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile + // processor, Intel Core 2 Quad processor, Intel Core 2 Quad + // mobile processor, Intel Core 2 Extreme processor, Intel + // Pentium Dual-Core processor, Intel Xeon processor, model + // 0Fh. All processors are manufactured using the 65 nm process. + case 22: // Intel Celeron processor model 16h. All processors are + // manufactured using the 65 nm process + return "core2"; + + case 21: // Intel EP80579 Integrated Processor and Intel EP80579 + // Integrated Processor with Intel QuickAssist Technology + return "i686"; // FIXME: ??? + + case 23: // Intel Core 2 Extreme processor, Intel Xeon processor, model + // 17h. All processors are manufactured using the 45 nm process. + // + // 45nm: Penryn , Wolfdale, Yorkfield (XE) + return "penryn"; + + case 26: // Intel Core i7 processor and Intel Xeon processor. All + // processors are manufactured using the 45 nm process. + case 29: // Intel Xeon processor MP. All processors are manufactured using + // the 45 nm process. + case 30: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz. + // As found in a Summer 2010 model iMac. + case 37: // Intel Core i7, laptop version. + return "corei7"; + + case 28: // Intel Atom processor. All processors are manufactured using + // the 45 nm process + return "atom"; + + default: return "i686"; + } + case 15: { + switch (Model) { + case 0: // Pentium 4 processor, Intel Xeon processor. All processors are + // model 00h and manufactured using the 0.18 micron process. + case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon + // processor MP, and Intel Celeron processor. All processors are + // model 01h and manufactured using the 0.18 micron process. + case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M, + // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron + // processor, and Mobile Intel Celeron processor. All processors + // are model 02h and manufactured using the 0.13 micron process. + return (Em64T) ? "x86-64" : "pentium4"; + + case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D + // processor. All processors are model 03h and manufactured using + // the 90 nm process. + case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition, + // Pentium D processor, Intel Xeon processor, Intel Xeon + // processor MP, Intel Celeron D processor. All processors are + // model 04h and manufactured using the 90 nm process. + case 6: // Pentium 4 processor, Pentium D processor, Pentium processor + // Extreme Edition, Intel Xeon processor, Intel Xeon processor + // MP, Intel Celeron D processor. All processors are model 06h + // and manufactured using the 65 nm process. + return (Em64T) ? "nocona" : "prescott"; + + default: + return (Em64T) ? "x86-64" : "pentium4"; + } + } + + default: + return "generic"; + } + } else if (memcmp(text.c, "AuthenticAMD", 12) == 0) { + // FIXME: this poorly matches the generated SubtargetFeatureKV table. There + // appears to be no way to generate the wide variety of AMD-specific targets + // from the information returned from CPUID. + switch (Family) { + case 4: + return "i486"; + case 5: + switch (Model) { + case 6: + case 7: return "k6"; + case 8: return "k6-2"; + case 9: + case 13: return "k6-3"; + default: return "pentium"; + } + case 6: + switch (Model) { + case 4: return "athlon-tbird"; + case 6: + case 7: + case 8: return "athlon-mp"; + case 10: return "athlon-xp"; + default: return "athlon"; + } + case 15: + if (HasSSE3) + return "k8-sse3"; + switch (Model) { + case 1: return "opteron"; + case 5: return "athlon-fx"; // also opteron + default: return "athlon64"; + } + case 16: + return "amdfam10"; + default: + return "generic"; + } + } + return "generic"; +} +#else +std::string sys::getHostCPUName() { + return "generic"; +} +#endif + +bool sys::getHostCPUFeatures(StringMap<bool> &Features){ + return false; +} diff --git a/lib/Support/IncludeFile.cpp b/lib/Support/IncludeFile.cpp new file mode 100644 index 0000000..e41d1f0 --- /dev/null +++ b/lib/Support/IncludeFile.cpp @@ -0,0 +1,20 @@ +//===- lib/System/IncludeFile.cpp - Ensure Linking Of Implementation -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the IncludeFile constructor. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/IncludeFile.h" + +using namespace llvm; + +// This constructor is used to ensure linking of other modules. See the +// llvm/System/IncludeFile.h header for details. +IncludeFile::IncludeFile(const void*) {} diff --git a/lib/Support/Makefile b/lib/Support/Makefile index 48c21f4..d68e500 100644 --- a/lib/Support/Makefile +++ b/lib/Support/Makefile @@ -14,4 +14,9 @@ BUILD_ARCHIVE = 1 ## FIXME: This only requires RTTI because tblgen uses it. Fix that. REQUIRES_RTTI = 1 +EXTRA_DIST = Unix Win32 README.txt + include $(LEVEL)/Makefile.common + +CompileCommonOpts := $(filter-out -pedantic,$(CompileCommonOpts)) +CompileCommonOpts := $(filter-out -Wno-long-long,$(CompileCommonOpts)) diff --git a/lib/Support/ManagedStatic.cpp b/lib/Support/ManagedStatic.cpp index 4e655a0..c767c15 100644 --- a/lib/Support/ManagedStatic.cpp +++ b/lib/Support/ManagedStatic.cpp @@ -13,7 +13,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Config/config.h" -#include "llvm/System/Atomic.h" +#include "llvm/Support/Atomic.h" #include <cassert> using namespace llvm; diff --git a/lib/Support/Memory.cpp b/lib/Support/Memory.cpp new file mode 100644 index 0000000..a9689b2 --- /dev/null +++ b/lib/Support/Memory.cpp @@ -0,0 +1,74 @@ +//===- Memory.cpp - Memory Handling Support ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for allocating memory and dealing +// with memory mapped files +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Memory.h" +#include "llvm/Support/Valgrind.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Memory.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Memory.inc" +#endif + +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void llvm::sys::Memory::InvalidateInstructionCache(const void *Addr, + size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) + sys_icache_invalidate(Addr, Len); +# endif + +#else + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + const size_t LineSize = 32; + + const intptr_t Mask = ~(LineSize - 1); + const intptr_t StartLine = ((intptr_t) Addr) & Mask; + const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("dcbf 0, %0" : : "r"(Line)); + asm volatile("sync"); + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +# elif defined(__arm__) && defined(__GNUC__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + char *Start = (char*) Addr; + char *End = Start + Len; + __clear_cache(Start, End); +# endif + +#endif // end apple + + ValgrindDiscardTranslations(Addr, Len); +} diff --git a/lib/Support/MemoryBuffer.cpp b/lib/Support/MemoryBuffer.cpp index 5b701a5..07a5ed4 100644 --- a/lib/Support/MemoryBuffer.cpp +++ b/lib/Support/MemoryBuffer.cpp @@ -15,10 +15,10 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/MathExtras.h" -#include "llvm/System/Errno.h" -#include "llvm/System/Path.h" -#include "llvm/System/Process.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" #include <cassert> #include <cstdio> #include <cstring> @@ -203,14 +203,14 @@ MemoryBuffer *MemoryBuffer::getFile(const char *Filename, std::string *ErrStr, if (ErrStr) *ErrStr = sys::StrError(); return 0; } - + return getOpenFile(FD, Filename, ErrStr, FileSize); } - + MemoryBuffer *MemoryBuffer::getOpenFile(int FD, const char *Filename, std::string *ErrStr, int64_t FileSize) { FileCloser FC(FD); // Close FD on return. - + // If we don't know the file size, use fstat to find out. fstat on an open // file descriptor is cheaper than stat on a random path. if (FileSize == -1) { @@ -222,8 +222,8 @@ MemoryBuffer *MemoryBuffer::getOpenFile(int FD, const char *Filename, } FileSize = FileInfo.st_size; } - - + + // If the file is large, try to use mmap to read it in. We don't use mmap // for small files, because this can severely fragment our address space. Also // don't try to map files that are exactly a multiple of the system page size, diff --git a/lib/Support/Mutex.cpp b/lib/Support/Mutex.cpp new file mode 100644 index 0000000..488868f --- /dev/null +++ b/lib/Support/Mutex.cpp @@ -0,0 +1,156 @@ +//===- Mutex.cpp - Mutual Exclusion Lock ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::Mutex class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/Mutex.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +MutexImpl::MutexImpl( bool recursive) { } +MutexImpl::~MutexImpl() { } +bool MutexImpl::acquire() { return true; } +bool MutexImpl::release() { return true; } +bool MutexImpl::tryacquire() { return true; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_MUTEX_LOCK) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + + +// This variable is useful for situations where the pthread library has been +// compiled with weak linkage for its interface symbols. This allows the +// threading support to be turned off by simply not linking against -lpthread. +// In that situation, the value of pthread_mutex_init will be 0 and +// consequently pthread_enabled will be false. In such situations, all the +// pthread operations become no-ops and the functions all return false. If +// pthread_mutex_init does have an address, then mutex support is enabled. +// Note: all LLVM tools will link against -lpthread if its available since it +// is configured into the LIBS variable. +// Note: this line of code generates a warning if pthread_mutex_init is not +// declared with weak linkage. It's safe to ignore the warning. +static const bool pthread_enabled = true; + +// Construct a Mutex using pthread calls +MutexImpl::MutexImpl( bool recursive) + : data_(0) +{ + if (pthread_enabled) + { + // Declare the pthread_mutex data structures + pthread_mutex_t* mutex = + static_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t))); + pthread_mutexattr_t attr; + + // Initialize the mutex attributes + int errorcode = pthread_mutexattr_init(&attr); + assert(errorcode == 0); + + // Initialize the mutex as a recursive mutex, if requested, or normal + // otherwise. + int kind = ( recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL ); + errorcode = pthread_mutexattr_settype(&attr, kind); + assert(errorcode == 0); + +#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__) + // Make it a process local mutex + errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE); +#endif + + // Initialize the mutex + errorcode = pthread_mutex_init(mutex, &attr); + assert(errorcode == 0); + + // Destroy the attributes + errorcode = pthread_mutexattr_destroy(&attr); + assert(errorcode == 0); + + // Assign the data member + data_ = mutex; + } +} + +// Destruct a Mutex +MutexImpl::~MutexImpl() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + pthread_mutex_destroy(mutex); + free(mutex); + } +} + +bool +MutexImpl::acquire() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_lock(mutex); + return errorcode == 0; + } else return false; +} + +bool +MutexImpl::release() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_unlock(mutex); + return errorcode == 0; + } else return false; +} + +bool +MutexImpl::tryacquire() +{ + if (pthread_enabled) + { + pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data_); + assert(mutex != 0); + + int errorcode = pthread_mutex_trylock(mutex); + return errorcode == 0; + } else return false; +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/Mutex.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/Mutex.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp +#endif +#endif diff --git a/lib/Support/Path.cpp b/lib/Support/Path.cpp new file mode 100644 index 0000000..394e013 --- /dev/null +++ b/lib/Support/Path.cpp @@ -0,0 +1,296 @@ +//===-- Path.cpp - Implement OS Path Concept --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Path concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Path.h" +#include "llvm/Config/config.h" +#include <cassert> +#include <cstring> +#include <ostream> +using namespace llvm; +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +bool Path::operator==(const Path &that) const { + return path == that.path; +} + +bool Path::operator<(const Path& that) const { + return path < that.path; +} + +Path +Path::GetLLVMConfigDir() { + Path result; +#ifdef LLVM_ETCDIR + if (result.set(LLVM_ETCDIR)) + return result; +#endif + return GetLLVMDefaultConfigDir(); +} + +LLVMFileType +sys::IdentifyFileType(const char *magic, unsigned length) { + assert(magic && "Invalid magic number string"); + assert(length >=4 && "Invalid magic number length"); + switch ((unsigned char)magic[0]) { + case 0xDE: // 0x0B17C0DE = BC wraper + if (magic[1] == (char)0xC0 && magic[2] == (char)0x17 && + magic[3] == (char)0x0B) + return Bitcode_FileType; + break; + case 'B': + if (magic[1] == 'C' && magic[2] == (char)0xC0 && magic[3] == (char)0xDE) + return Bitcode_FileType; + break; + case '!': + if (length >= 8) + if (memcmp(magic,"!<arch>\n",8) == 0) + return Archive_FileType; + break; + + case '\177': + if (magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F') { + if (length >= 18 && magic[17] == 0) + switch (magic[16]) { + default: break; + case 1: return ELF_Relocatable_FileType; + case 2: return ELF_Executable_FileType; + case 3: return ELF_SharedObject_FileType; + case 4: return ELF_Core_FileType; + } + } + break; + + case 0xCA: + if (magic[1] == char(0xFE) && magic[2] == char(0xBA) && + magic[3] == char(0xBE)) { + // This is complicated by an overlap with Java class files. + // See the Mach-O section in /usr/share/file/magic for details. + if (length >= 8 && magic[7] < 43) + // FIXME: Universal Binary of any type. + return Mach_O_DynamicallyLinkedSharedLib_FileType; + } + break; + + case 0xFE: + case 0xCE: { + uint16_t type = 0; + if (magic[0] == char(0xFE) && magic[1] == char(0xED) && + magic[2] == char(0xFA) && magic[3] == char(0xCE)) { + /* Native endian */ + if (length >= 16) type = magic[14] << 8 | magic[15]; + } else if (magic[0] == char(0xCE) && magic[1] == char(0xFA) && + magic[2] == char(0xED) && magic[3] == char(0xFE)) { + /* Reverse endian */ + if (length >= 14) type = magic[13] << 8 | magic[12]; + } + switch (type) { + default: break; + case 1: return Mach_O_Object_FileType; + case 2: return Mach_O_Executable_FileType; + case 3: return Mach_O_FixedVirtualMemorySharedLib_FileType; + case 4: return Mach_O_Core_FileType; + case 5: return Mach_O_PreloadExecutable_FileType; + case 6: return Mach_O_DynamicallyLinkedSharedLib_FileType; + case 7: return Mach_O_DynamicLinker_FileType; + case 8: return Mach_O_Bundle_FileType; + case 9: return Mach_O_DynamicallyLinkedSharedLibStub_FileType; + case 10: break; // FIXME: MH_DSYM companion file with only debug. + } + break; + } + case 0xF0: // PowerPC Windows + case 0x83: // Alpha 32-bit + case 0x84: // Alpha 64-bit + case 0x66: // MPS R4000 Windows + case 0x50: // mc68K + case 0x4c: // 80386 Windows + if (magic[1] == 0x01) + return COFF_FileType; + + case 0x90: // PA-RISC Windows + case 0x68: // mc68K Windows + if (magic[1] == 0x02) + return COFF_FileType; + break; + case 0x64: // x86-64 Windows. + if (magic[1] == char(0x86)) + return COFF_FileType; + break; + + default: + break; + } + return Unknown_FileType; +} + +bool +Path::isArchive() const { + return hasMagicNumber("!<arch>\012"); +} + +bool +Path::isDynamicLibrary() const { + std::string Magic; + if (getMagicNumber(Magic, 64)) + switch (IdentifyFileType(Magic.c_str(), + static_cast<unsigned>(Magic.length()))) { + default: return false; + case Mach_O_FixedVirtualMemorySharedLib_FileType: + case Mach_O_DynamicallyLinkedSharedLib_FileType: + case Mach_O_DynamicallyLinkedSharedLibStub_FileType: + case ELF_SharedObject_FileType: + case COFF_FileType: return true; + } + + return false; +} + +bool +Path::isObjectFile() const { + std::string Magic; + if (getMagicNumber(Magic, 64)) + if (IdentifyFileType(Magic.c_str(), + static_cast<unsigned>(Magic.length())) + != Unknown_FileType) { + // Everything in LLVMFileType is currently an object file. + return true; + } + + return false; +} + +Path +Path::FindLibrary(std::string& name) { + std::vector<sys::Path> LibPaths; + GetSystemLibraryPaths(LibPaths); + for (unsigned i = 0; i < LibPaths.size(); ++i) { + sys::Path FullPath(LibPaths[i]); + FullPath.appendComponent("lib" + name + LTDL_SHLIB_EXT); + if (FullPath.isDynamicLibrary()) + return FullPath; + FullPath.eraseSuffix(); + FullPath.appendSuffix("a"); + if (FullPath.isArchive()) + return FullPath; + } + return sys::Path(); +} + +StringRef Path::GetDLLSuffix() { + return &(LTDL_SHLIB_EXT[1]); +} + +bool +Path::appendSuffix(StringRef suffix) { + if (!suffix.empty()) { + std::string save(path); + path.append("."); + path.append(suffix); + if (!isValid()) { + path = save; + return false; + } + } + + return true; +} + +bool +Path::isBitcodeFile() const { + std::string actualMagic; + if (!getMagicNumber(actualMagic, 4)) + return false; + LLVMFileType FT = + IdentifyFileType(actualMagic.c_str(), + static_cast<unsigned>(actualMagic.length())); + return FT == Bitcode_FileType; +} + +bool Path::hasMagicNumber(StringRef Magic) const { + std::string actualMagic; + if (getMagicNumber(actualMagic, static_cast<unsigned>(Magic.size()))) + return Magic == actualMagic; + return false; +} + +static void getPathList(const char*path, std::vector<Path>& Paths) { + const char* at = path; + const char* delim = strchr(at, PathSeparator); + Path tmpPath; + while (delim != 0) { + std::string tmp(at, size_t(delim-at)); + if (tmpPath.set(tmp)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + at = delim + 1; + delim = strchr(at, PathSeparator); + } + + if (*at != 0) + if (tmpPath.set(std::string(at))) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); +} + +static StringRef getDirnameCharSep(StringRef path, const char *Sep) { + assert(Sep[0] != '\0' && Sep[1] == '\0' && + "Sep must be a 1-character string literal."); + if (path.empty()) + return "."; + + // If the path is all slashes, return a single slash. + // Otherwise, remove all trailing slashes. + + signed pos = static_cast<signed>(path.size()) - 1; + + while (pos >= 0 && path[pos] == Sep[0]) + --pos; + + if (pos < 0) + return path[0] == Sep[0] ? Sep : "."; + + // Any slashes left? + signed i = 0; + + while (i < pos && path[i] != Sep[0]) + ++i; + + if (i == pos) // No slashes? Return "." + return "."; + + // There is at least one slash left. Remove all trailing non-slashes. + while (pos >= 0 && path[pos] != Sep[0]) + --pos; + + // Remove any trailing slashes. + while (pos >= 0 && path[pos] == Sep[0]) + --pos; + + if (pos < 0) + return path[0] == Sep[0] ? Sep : "."; + + return path.substr(0, pos+1); +} + +// Include the truly platform-specific parts of this class. +#if defined(LLVM_ON_UNIX) +#include "Unix/Path.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/Path.inc" +#endif diff --git a/lib/Support/PluginLoader.cpp b/lib/Support/PluginLoader.cpp index 36caecf..2924cfa 100644 --- a/lib/Support/PluginLoader.cpp +++ b/lib/Support/PluginLoader.cpp @@ -15,8 +15,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/DynamicLibrary.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Mutex.h" #include <vector> using namespace llvm; diff --git a/lib/Support/PrettyStackTrace.cpp b/lib/Support/PrettyStackTrace.cpp index 3c8a108..2f46b9e 100644 --- a/lib/Support/PrettyStackTrace.cpp +++ b/lib/Support/PrettyStackTrace.cpp @@ -15,8 +15,8 @@ #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Signals.h" -#include "llvm/System/ThreadLocal.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/ThreadLocal.h" #include "llvm/ADT/SmallString.h" #ifdef HAVE_CRASHREPORTERCLIENT_H diff --git a/lib/Support/Process.cpp b/lib/Support/Process.cpp new file mode 100644 index 0000000..88ca7c3 --- /dev/null +++ b/lib/Support/Process.cpp @@ -0,0 +1,33 @@ +//===-- Process.cpp - Implement OS Process Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Process concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Process.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Process.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Process.inc" +#endif diff --git a/lib/Support/Program.cpp b/lib/Support/Program.cpp new file mode 100644 index 0000000..01860b0 --- /dev/null +++ b/lib/Support/Program.cpp @@ -0,0 +1,56 @@ +//===-- Program.cpp - Implement OS Program Concept --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header file implements the operating system Program concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Program.h" +#include "llvm/Config/config.h" +using namespace llvm; +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +int +Program::ExecuteAndWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned secondsToWait, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + if (prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg)) + return prg.Wait(path, secondsToWait, ErrMsg); + else + return -1; +} + +void +Program::ExecuteNoWait(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + Program prg; + prg.Execute(path, args, envp, redirects, memoryLimit, ErrMsg); +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Program.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Program.inc" +#endif diff --git a/lib/Support/README.txt.system b/lib/Support/README.txt.system new file mode 100644 index 0000000..7a906b8 --- /dev/null +++ b/lib/Support/README.txt.system @@ -0,0 +1,43 @@ +Design Of lib/System +==================== + +The software in this directory is designed to completely shield LLVM from any +and all operating system specific functionality. It is not intended to be a +complete operating system wrapper (such as ACE), but only to provide the +functionality necessary to support LLVM. + +The software located here, of necessity, has very specific and stringent design +rules. Violation of these rules means that cracks in the shield could form and +the primary goal of the library is defeated. By consistently using this library, +LLVM becomes more easily ported to new platforms since the only thing requiring +porting is this library. + +Complete documentation for the library can be found in the file: + llvm/docs/SystemLibrary.html +or at this URL: + http://llvm.org/docs/SystemLibrary.html + +While we recommend that you read the more detailed documentation, for the +impatient, here's a high level summary of the library's requirements. + + 1. No system header files are to be exposed through the interface. + 2. Std C++ and Std C header files are okay to be exposed through the interface. + 3. No exposed system-specific functions. + 4. No exposed system-specific data. + 5. Data in lib/System classes must use only simple C++ intrinsic types. + 6. Errors are handled by returning "true" and setting an optional std::string + 7. Library must not throw any exceptions, period. + 8. Interface functions must not have throw() specifications. + 9. No duplicate function impementations are permitted within an operating + system class. + +To accomplish these requirements, the library has numerous design criteria that +must be satisfied. Here's a high level summary of the library's design criteria: + + 1. No unused functionality (only what LLVM needs) + 2. High-Level Interfaces + 3. Use Opaque Classes + 4. Common Implementations + 5. Multiple Implementations + 6. Minimize Memory Allocation + 7. No Virtual Methods diff --git a/lib/Support/RWMutex.cpp b/lib/Support/RWMutex.cpp new file mode 100644 index 0000000..fc02f9c --- /dev/null +++ b/lib/Support/RWMutex.cpp @@ -0,0 +1,157 @@ +//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::RWMutex class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/RWMutex.h" +#include <cstring> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +RWMutexImpl::RWMutexImpl() { } +RWMutexImpl::~RWMutexImpl() { } +bool RWMutexImpl::reader_acquire() { return true; } +bool RWMutexImpl::reader_release() { return true; } +bool RWMutexImpl::writer_acquire() { return true; } +bool RWMutexImpl::writer_release() { return true; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + + +// This variable is useful for situations where the pthread library has been +// compiled with weak linkage for its interface symbols. This allows the +// threading support to be turned off by simply not linking against -lpthread. +// In that situation, the value of pthread_mutex_init will be 0 and +// consequently pthread_enabled will be false. In such situations, all the +// pthread operations become no-ops and the functions all return false. If +// pthread_rwlock_init does have an address, then rwlock support is enabled. +// Note: all LLVM tools will link against -lpthread if its available since it +// is configured into the LIBS variable. +// Note: this line of code generates a warning if pthread_rwlock_init is not +// declared with weak linkage. It's safe to ignore the warning. +static const bool pthread_enabled = true; + +// Construct a RWMutex using pthread calls +RWMutexImpl::RWMutexImpl() + : data_(0) +{ + if (pthread_enabled) + { + // Declare the pthread_rwlock data structures + pthread_rwlock_t* rwlock = + static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t))); + +#ifdef __APPLE__ + // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init. + bzero(rwlock, sizeof(pthread_rwlock_t)); +#endif + + // Initialize the rwlock + int errorcode = pthread_rwlock_init(rwlock, NULL); + (void)errorcode; + assert(errorcode == 0); + + // Assign the data member + data_ = rwlock; + } +} + +// Destruct a RWMutex +RWMutexImpl::~RWMutexImpl() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + pthread_rwlock_destroy(rwlock); + free(rwlock); + } +} + +bool +RWMutexImpl::reader_acquire() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_rdlock(rwlock); + return errorcode == 0; + } else return false; +} + +bool +RWMutexImpl::reader_release() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; + } else return false; +} + +bool +RWMutexImpl::writer_acquire() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_wrlock(rwlock); + return errorcode == 0; + } else return false; +} + +bool +RWMutexImpl::writer_release() +{ + if (pthread_enabled) + { + pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_); + assert(rwlock != 0); + + int errorcode = pthread_rwlock_unlock(rwlock); + return errorcode == 0; + } else return false; +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/RWMutex.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/RWMutex.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp +#endif +#endif diff --git a/lib/Support/SearchForAddressOfSpecialSymbol.cpp b/lib/Support/SearchForAddressOfSpecialSymbol.cpp new file mode 100644 index 0000000..51ba417 --- /dev/null +++ b/lib/Support/SearchForAddressOfSpecialSymbol.cpp @@ -0,0 +1,68 @@ +//===- SearchForAddressOfSpecialSymbol.cpp - Function addresses -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file pulls the addresses of certain symbols out of the linker. It must +// include as few header files as possible because it declares the symbols as +// void*, which would conflict with the actual symbol type if any header +// declared it. +// +//===----------------------------------------------------------------------===// + +#include <string.h> + +// Must declare the symbols in the global namespace. +static void *DoSearch(const char* symbolName) { +#define EXPLICIT_SYMBOL(SYM) \ + extern void *SYM; if (!strcmp(symbolName, #SYM)) return &SYM + + // If this is darwin, it has some funky issues, try to solve them here. Some + // important symbols are marked 'private external' which doesn't allow + // SearchForAddressOfSymbol to find them. As such, we special case them here, + // there is only a small handful of them. + +#ifdef __APPLE__ + { + EXPLICIT_SYMBOL(__ashldi3); + EXPLICIT_SYMBOL(__ashrdi3); + EXPLICIT_SYMBOL(__cmpdi2); + EXPLICIT_SYMBOL(__divdi3); + EXPLICIT_SYMBOL(__fixdfdi); + EXPLICIT_SYMBOL(__fixsfdi); + EXPLICIT_SYMBOL(__fixunsdfdi); + EXPLICIT_SYMBOL(__fixunssfdi); + EXPLICIT_SYMBOL(__floatdidf); + EXPLICIT_SYMBOL(__floatdisf); + EXPLICIT_SYMBOL(__lshrdi3); + EXPLICIT_SYMBOL(__moddi3); + EXPLICIT_SYMBOL(__udivdi3); + EXPLICIT_SYMBOL(__umoddi3); + + // __eprintf is sometimes used for assert() handling on x86. +#ifdef __i386__ + EXPLICIT_SYMBOL(__eprintf); +#endif + } +#endif + +#ifdef __CYGWIN__ + { + EXPLICIT_SYMBOL(_alloca); + EXPLICIT_SYMBOL(__main); + } +#endif + +#undef EXPLICIT_SYMBOL + return 0; +} + +namespace llvm { +void *SearchForAddressOfSpecialSymbol(const char* symbolName) { + return DoSearch(symbolName); +} +} // namespace llvm diff --git a/lib/Support/Signals.cpp b/lib/Support/Signals.cpp new file mode 100644 index 0000000..a3af37d --- /dev/null +++ b/lib/Support/Signals.cpp @@ -0,0 +1,34 @@ +//===- Signals.cpp - Signal Handling support --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Signals.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +} + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Signals.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Signals.inc" +#endif diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index e32ab74..f0ed626 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -26,7 +26,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include "llvm/ADT/StringExtras.h" #include <algorithm> #include <cstring> diff --git a/lib/Support/SystemUtils.cpp b/lib/Support/SystemUtils.cpp index 9646d75..54b5e97 100644 --- a/lib/Support/SystemUtils.cpp +++ b/lib/Support/SystemUtils.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/SystemUtils.h" -#include "llvm/System/Process.h" -#include "llvm/System/Program.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/lib/Support/TargetRegistry.cpp b/lib/Support/TargetRegistry.cpp index 5896447..293a5d7 100644 --- a/lib/Support/TargetRegistry.cpp +++ b/lib/Support/TargetRegistry.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Target/TargetRegistry.h" -#include "llvm/System/Host.h" +#include "llvm/Support/Host.h" #include <cassert> using namespace llvm; diff --git a/lib/Support/ThreadLocal.cpp b/lib/Support/ThreadLocal.cpp new file mode 100644 index 0000000..6b43048 --- /dev/null +++ b/lib/Support/ThreadLocal.cpp @@ -0,0 +1,84 @@ +//===- ThreadLocal.cpp - Thread Local Data ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the llvm::sys::ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/Support/ThreadLocal.h" + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + +#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0 +// Define all methods as no-ops if threading is explicitly disabled +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} +const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { data = 0; } +} +#else + +#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_GETSPECIFIC) + +#include <cassert> +#include <pthread.h> +#include <stdlib.h> + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() : data(0) { + pthread_key_t* key = new pthread_key_t; + int errorcode = pthread_key_create(key, NULL); + assert(errorcode == 0); + (void) errorcode; + data = (void*)key; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + pthread_key_t* key = static_cast<pthread_key_t*>(data); + int errorcode = pthread_key_delete(*key); + assert(errorcode == 0); + (void) errorcode; + delete key; +} + +void ThreadLocalImpl::setInstance(const void* d) { + pthread_key_t* key = static_cast<pthread_key_t*>(data); + int errorcode = pthread_setspecific(*key, d); + assert(errorcode == 0); + (void) errorcode; +} + +const void* ThreadLocalImpl::getInstance() { + pthread_key_t* key = static_cast<pthread_key_t*>(data); + return pthread_getspecific(*key); +} + +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} + +#elif defined(LLVM_ON_UNIX) +#include "Unix/ThreadLocal.inc" +#elif defined( LLVM_ON_WIN32) +#include "Windows/ThreadLocal.inc" +#else +#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/ThreadLocal.cpp +#endif +#endif diff --git a/lib/Support/Threading.cpp b/lib/Support/Threading.cpp new file mode 100644 index 0000000..c2f8554 --- /dev/null +++ b/lib/Support/Threading.cpp @@ -0,0 +1,116 @@ +//===-- llvm/System/Threading.cpp- Control multithreading mode --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements llvm_start_multithreaded() and friends. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Threading.h" +#include "llvm/Support/Atomic.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Config/config.h" +#include <cassert> + +using namespace llvm; + +static bool multithreaded_mode = false; + +static sys::Mutex* global_lock = 0; + +bool llvm::llvm_start_multithreaded() { +#ifdef LLVM_MULTITHREADED + assert(!multithreaded_mode && "Already multithreaded!"); + multithreaded_mode = true; + global_lock = new sys::Mutex(true); + + // We fence here to ensure that all initialization is complete BEFORE we + // return from llvm_start_multithreaded(). + sys::MemoryFence(); + return true; +#else + return false; +#endif +} + +void llvm::llvm_stop_multithreaded() { +#ifdef LLVM_MULTITHREADED + assert(multithreaded_mode && "Not currently multithreaded!"); + + // We fence here to insure that all threaded operations are complete BEFORE we + // return from llvm_stop_multithreaded(). + sys::MemoryFence(); + + multithreaded_mode = false; + delete global_lock; +#endif +} + +bool llvm::llvm_is_multithreaded() { + return multithreaded_mode; +} + +void llvm::llvm_acquire_global_lock() { + if (multithreaded_mode) global_lock->acquire(); +} + +void llvm::llvm_release_global_lock() { + if (multithreaded_mode) global_lock->release(); +} + +#if defined(LLVM_MULTITHREADED) && defined(HAVE_PTHREAD_H) +#include <pthread.h> + +struct ThreadInfo { + void (*UserFn)(void *); + void *UserData; +}; +static void *ExecuteOnThread_Dispatch(void *Arg) { + ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); + TI->UserFn(TI->UserData); + return 0; +} + +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + ThreadInfo Info = { Fn, UserData }; + pthread_attr_t Attr; + pthread_t Thread; + + // Construct the attributes object. + if (::pthread_attr_init(&Attr) != 0) + return; + + // Set the requested stack size, if given. + if (RequestedStackSize != 0) { + if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) + goto error; + } + + // Construct and execute the thread. + if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) + goto error; + + // Wait for the thread and clean up. + ::pthread_join(Thread, 0); + + error: + ::pthread_attr_destroy(&Attr); +} + +#else + +// No non-pthread implementation, currently. + +void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + (void) RequestedStackSize; + Fn(UserData); +} + +#endif diff --git a/lib/Support/TimeValue.cpp b/lib/Support/TimeValue.cpp new file mode 100644 index 0000000..1a0f7bc --- /dev/null +++ b/lib/Support/TimeValue.cpp @@ -0,0 +1,57 @@ +//===-- TimeValue.cpp - Implement OS TimeValue Concept ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the operating system TimeValue concept. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/TimeValue.h" +#include "llvm/Config/config.h" + +namespace llvm { +using namespace sys; + +const TimeValue TimeValue::MinTime = TimeValue ( INT64_MIN,0 ); +const TimeValue TimeValue::MaxTime = TimeValue ( INT64_MAX,0 ); +const TimeValue TimeValue::ZeroTime = TimeValue ( 0,0 ); +const TimeValue TimeValue::PosixZeroTime = TimeValue ( -946684800,0 ); +const TimeValue TimeValue::Win32ZeroTime = TimeValue ( -12591158400ULL,0 ); + +void +TimeValue::normalize( void ) { + if ( nanos_ >= NANOSECONDS_PER_SECOND ) { + do { + seconds_++; + nanos_ -= NANOSECONDS_PER_SECOND; + } while ( nanos_ >= NANOSECONDS_PER_SECOND ); + } else if (nanos_ <= -NANOSECONDS_PER_SECOND ) { + do { + seconds_--; + nanos_ += NANOSECONDS_PER_SECOND; + } while (nanos_ <= -NANOSECONDS_PER_SECOND); + } + + if (seconds_ >= 1 && nanos_ < 0) { + seconds_--; + nanos_ += NANOSECONDS_PER_SECOND; + } else if (seconds_ < 0 && nanos_ > 0) { + seconds_++; + nanos_ -= NANOSECONDS_PER_SECOND; + } +} + +} + +/// Include the platform specific portion of TimeValue class +#ifdef LLVM_ON_UNIX +#include "Unix/TimeValue.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/TimeValue.inc" +#endif diff --git a/lib/Support/Timer.cpp b/lib/Support/Timer.cpp index 44ee177..a9ed5ee 100644 --- a/lib/Support/Timer.cpp +++ b/lib/Support/Timer.cpp @@ -17,8 +17,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Format.h" -#include "llvm/System/Mutex.h" -#include "llvm/System/Process.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Process.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" using namespace llvm; diff --git a/lib/Support/ToolOutputFile.cpp b/lib/Support/ToolOutputFile.cpp index 5b5ee66..e7ca927 100644 --- a/lib/Support/ToolOutputFile.cpp +++ b/lib/Support/ToolOutputFile.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ToolOutputFile.h" -#include "llvm/System/Signals.h" +#include "llvm/Support/Signals.h" using namespace llvm; tool_output_file::CleanupInstaller::CleanupInstaller(const char *filename) diff --git a/lib/Support/Unix/Alarm.inc b/lib/Support/Unix/Alarm.inc new file mode 100644 index 0000000..fb42b6c --- /dev/null +++ b/lib/Support/Unix/Alarm.inc @@ -0,0 +1,72 @@ +//===-- Alarm.inc - Implement Unix Alarm Support ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the UNIX Alarm support. +// +//===----------------------------------------------------------------------===// + +#include <signal.h> +#include <unistd.h> +#include <cassert> +using namespace llvm; + +/// AlarmCancelled - This flag is set by the SIGINT signal handler if the +/// user presses CTRL-C. +static volatile bool AlarmCancelled = false; + +/// AlarmTriggered - This flag is set by the SIGALRM signal handler if the +/// alarm was triggered. +static volatile bool AlarmTriggered = false; + +/// NestedSOI - Sanity check. Alarms cannot be nested or run in parallel. +/// This ensures that they never do. +static bool NestedSOI = false; + +static RETSIGTYPE SigIntHandler(int Sig) { + AlarmCancelled = true; + signal(SIGINT, SigIntHandler); +} + +static RETSIGTYPE SigAlarmHandler(int Sig) { + AlarmTriggered = true; +} + +static void (*OldSigIntHandler) (int); + +void sys::SetupAlarm(unsigned seconds) { + assert(!NestedSOI && "sys::SetupAlarm calls cannot be nested!"); + NestedSOI = true; + AlarmCancelled = false; + AlarmTriggered = false; + ::signal(SIGALRM, SigAlarmHandler); + OldSigIntHandler = ::signal(SIGINT, SigIntHandler); + ::alarm(seconds); +} + +void sys::TerminateAlarm() { + assert(NestedSOI && "sys::TerminateAlarm called without sys::SetupAlarm!"); + ::alarm(0); + ::signal(SIGALRM, SIG_DFL); + ::signal(SIGINT, OldSigIntHandler); + AlarmCancelled = false; + AlarmTriggered = false; + NestedSOI = false; +} + +int sys::AlarmStatus() { + if (AlarmCancelled) + return -1; + if (AlarmTriggered) + return 1; + return 0; +} + +void sys::Sleep(unsigned n) { + ::sleep(n); +} diff --git a/lib/Support/Unix/Host.inc b/lib/Support/Unix/Host.inc new file mode 100644 index 0000000..ca0de9c --- /dev/null +++ b/lib/Support/Unix/Host.inc @@ -0,0 +1,96 @@ + //===- llvm/System/Unix/Host.inc -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the UNIX Host support. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/ADT/StringRef.h" +#include "Unix.h" +#include <sys/utsname.h> +#include <string> + +using namespace llvm; + +static std::string getOSVersion() { + struct utsname info; + + if (uname(&info)) + return ""; + + return info.release; +} + +std::string sys::getHostTriple() { + // FIXME: Derive directly instead of relying on the autoconf generated + // variable. + + StringRef HostTripleString(LLVM_HOSTTRIPLE); + std::pair<StringRef, StringRef> ArchSplit = HostTripleString.split('-'); + + // Normalize the arch, since the host triple may not actually match the host. + std::string Arch = ArchSplit.first; + + // It would be nice to do this in terms of llvm::Triple, but that is in + // Support which is layered above us. +#if defined(__x86_64__) + Arch = "x86_64"; +#elif defined(__i386__) + Arch = "i386"; +#elif defined(__ppc64__) + Arch = "powerpc64"; +#elif defined(__ppc__) + Arch = "powerpc"; +#elif defined(__arm__) + + // FIXME: We need to pick the right ARM triple (which involves querying the + // chip). However, for now this is most important for LLVM arch selection, so + // we only need to make sure to distinguish ARM and Thumb. +# if defined(__thumb__) + Arch = "thumb"; +# else + Arch = "arm"; +# endif + +#else + + // FIXME: When enough auto-detection is in place, this should just + // #error. Then at least the arch selection is done, and we only need the OS + // etc selection to kill off the use of LLVM_HOSTTRIPLE. + +#endif + + std::string Triple(Arch); + Triple += '-'; + Triple += ArchSplit.second; + + // Force i<N>86 to i386. + if (Triple[0] == 'i' && isdigit(Triple[1]) && + Triple[2] == '8' && Triple[3] == '6') + Triple[1] = '3'; + + // On darwin, we want to update the version to match that of the + // host. + std::string::size_type DarwinDashIdx = Triple.find("-darwin"); + if (DarwinDashIdx != std::string::npos) { + Triple.resize(DarwinDashIdx + strlen("-darwin")); + + // Only add the major part of the os version. + std::string Version = getOSVersion(); + Triple += Version.substr(0, Version.find('.')); + } + + return Triple; +} diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc new file mode 100644 index 0000000..4312d67 --- /dev/null +++ b/lib/Support/Unix/Memory.inc @@ -0,0 +1,151 @@ +//===- Unix/Memory.cpp - Generic UNIX System Configuration ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some functions for various memory management utilities. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Process.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef __APPLE__ +#include <mach/mach.h> +#endif + +/// AllocateRWX - Allocate a slab of memory with read/write/execute +/// permissions. This is typically used for JIT applications where we want +/// to emit code to the memory then jump to it. Getting this type of memory +/// is very OS specific. +/// +llvm::sys::MemoryBlock +llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, + std::string *ErrMsg) { + if (NumBytes == 0) return MemoryBlock(); + + size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) { + MakeErrMsg(ErrMsg, "Can't open /dev/zero device"); + return MemoryBlock(); + } + fd = zero_fd; +#endif + + int flags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; + + void* start = NearBlock ? (unsigned char*)NearBlock->base() + + NearBlock->size() : 0; + +#if defined(__APPLE__) && defined(__arm__) + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, + flags, fd, 0); +#else + void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, + flags, fd, 0); +#endif + if (pa == MAP_FAILED) { + if (NearBlock) //Try again without a near hint + return AllocateRWX(NumBytes, 0); + + MakeErrMsg(ErrMsg, "Can't allocate RWX Memory"); + return MemoryBlock(); + } + +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)pa, + (vm_size_t)(pageSize*NumPages), 0, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + if (KERN_SUCCESS != kr) { + MakeErrMsg(ErrMsg, "vm_protect max RX failed"); + return sys::MemoryBlock(); + } + + kr = vm_protect(mach_task_self(), (vm_address_t)pa, + (vm_size_t)(pageSize*NumPages), 0, + VM_PROT_READ | VM_PROT_WRITE); + if (KERN_SUCCESS != kr) { + MakeErrMsg(ErrMsg, "vm_protect RW failed"); + return sys::MemoryBlock(); + } +#endif + + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + + return result; +} + +bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + if (M.Address == 0 || M.Size == 0) return false; + if (0 != ::munmap(M.Address, M.Size)) + return MakeErrMsg(ErrMsg, "Can't release RWX Memory"); + return false; +} + +bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { +#if defined(__APPLE__) && defined(__arm__) + if (M.Address == 0 || M.Size == 0) return false; + sys::Memory::InvalidateInstructionCache(M.Address, M.Size); + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)M.Address, + (vm_size_t)M.Size, 0, VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return false; +#endif +} + +bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, + (vm_size_t)Size, 0, + VM_PROT_READ | VM_PROT_WRITE); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} + +bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { +#if defined(__APPLE__) && defined(__arm__) + kern_return_t kr = vm_protect(mach_task_self(), (vm_address_t)Addr, + (vm_size_t)Size, 0, + VM_PROT_READ | VM_PROT_EXECUTE | VM_PROT_COPY); + return KERN_SUCCESS == kr; +#else + return true; +#endif +} diff --git a/lib/Support/Unix/Mutex.inc b/lib/Support/Unix/Mutex.inc new file mode 100644 index 0000000..5c50697 --- /dev/null +++ b/lib/Support/Unix/Mutex.inc @@ -0,0 +1,43 @@ +//===- llvm/System/Unix/Mutex.inc - Unix Mutex Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm +{ +using namespace sys; + +MutexImpl::MutexImpl( bool recursive) +{ +} + +MutexImpl::~MutexImpl() +{ +} + +bool +MutexImpl::release() +{ + return true; +} + +bool +MutexImpl::tryacquire( void ) +{ + return true; +} + +} diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc new file mode 100644 index 0000000..5ee3adc --- /dev/null +++ b/lib/Support/Unix/Path.inc @@ -0,0 +1,896 @@ +//===- llvm/System/Unix/Path.cpp - Unix Path Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_UTIME_H +#include <utime.h> +#endif +#if HAVE_TIME_H +#include <time.h> +#endif +#if HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#endif + +// Put in a hack for Cygwin which falsely reports that the mkdtemp function +// is available when it is not. +#ifdef __CYGWIN__ +# undef HAVE_MKDTEMP +#endif + +namespace { +inline bool lastIsSlash(const std::string& path) { + return !path.empty() && path[path.length() - 1] == '/'; +} + +} + +namespace llvm { +using namespace sys; + +const char sys::PathSeparator = ':'; + +StringRef Path::GetEXESuffix() { + return StringRef(); +} + +Path::Path(StringRef p) + : path(p) {} + +Path::Path(const char *StrStart, unsigned StrLen) + : path(StrStart, StrLen) {} + +Path& +Path::operator=(StringRef that) { + path.assign(that.data(), that.size()); + return *this; +} + +bool +Path::isValid() const { + // Empty paths are considered invalid here. + // This code doesn't check MAXPATHLEN because there's no need. Nothing in + // LLVM manipulates Paths with fixed-sizes arrays, and if the OS can't + // handle names longer than some limit, it'll report this on demand using + // ENAMETOLONG. + return !path.empty(); +} + +bool +Path::isAbsolute(const char *NameStart, unsigned NameLen) { + assert(NameStart); + if (NameLen == 0) + return false; + return NameStart[0] == '/'; +} + +bool +Path::isAbsolute() const { + if (path.empty()) + return false; + return path[0] == '/'; +} + +void Path::makeAbsolute() { + if (isAbsolute()) + return; + + Path CWD = Path::GetCurrentDirectory(); + assert(CWD.isAbsolute() && "GetCurrentDirectory returned relative path!"); + + CWD.appendComponent(path); + + path = CWD.str(); +} + +Path +Path::GetRootDirectory() { + Path result; + result.set("/"); + return result; +} + +Path +Path::GetTemporaryDirectory(std::string *ErrMsg) { +#if defined(HAVE_MKDTEMP) + // The best way is with mkdtemp but that's not available on many systems, + // Linux and FreeBSD have it. Others probably won't. + char pathname[] = "/tmp/llvm_XXXXXX"; + if (0 == mkdtemp(pathname)) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#elif defined(HAVE_MKSTEMP) + // If no mkdtemp is available, mkstemp can be used to create a temporary file + // which is then removed and created as a directory. We prefer this over + // mktemp because of mktemp's inherent security and threading risks. We still + // have a slight race condition from the time the temporary file is created to + // the time it is re-created as a directoy. + char pathname[] = "/tmp/llvm_XXXXXX"; + int fd = 0; + if (-1 == (fd = mkstemp(pathname))) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + ::close(fd); + ::unlink(pathname); // start race condition, ignore errors + if (-1 == ::mkdir(pathname, S_IRWXU)) { // end race condition + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#elif defined(HAVE_MKTEMP) + // If a system doesn't have mkdtemp(3) or mkstemp(3) but it does have + // mktemp(3) then we'll assume that system (e.g. AIX) has a reasonable + // implementation of mktemp(3) and doesn't follow BSD 4.3's lead of replacing + // the XXXXXX with the pid of the process and a letter. That leads to only + // twenty six temporary files that can be generated. + char pathname[] = "/tmp/llvm_XXXXXX"; + char *TmpName = ::mktemp(pathname); + if (TmpName == 0) { + MakeErrMsg(ErrMsg, + std::string(TmpName) + ": can't create unique directory name"); + return Path(); + } + if (-1 == ::mkdir(TmpName, S_IRWXU)) { + MakeErrMsg(ErrMsg, + std::string(TmpName) + ": can't create temporary directory"); + return Path(); + } + return Path(TmpName); +#else + // This is the worst case implementation. tempnam(3) leaks memory unless its + // on an SVID2 (or later) system. On BSD 4.3 it leaks. tmpnam(3) has thread + // issues. The mktemp(3) function doesn't have enough variability in the + // temporary name generated. So, we provide our own implementation that + // increments an integer from a random number seeded by the current time. This + // should be sufficiently unique that we don't have many collisions between + // processes. Generally LLVM processes don't run very long and don't use very + // many temporary files so this shouldn't be a big issue for LLVM. + static time_t num = ::time(0); + char pathname[MAXPATHLEN]; + do { + num++; + sprintf(pathname, "/tmp/llvm_%010u", unsigned(num)); + } while ( 0 == access(pathname, F_OK ) ); + if (-1 == ::mkdir(pathname, S_IRWXU)) { + MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create temporary directory"); + return Path(); + } + return Path(pathname); +#endif +} + +void +Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { +#ifdef LTDL_SHLIBPATH_VAR + char* env_var = getenv(LTDL_SHLIBPATH_VAR); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#endif + // FIXME: Should this look at LD_LIBRARY_PATH too? + Paths.push_back(sys::Path("/usr/local/lib/")); + Paths.push_back(sys::Path("/usr/X11R6/lib/")); + Paths.push_back(sys::Path("/usr/lib/")); + Paths.push_back(sys::Path("/lib/")); +} + +void +Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetLLVMDefaultConfigDir() { + return Path("/etc/llvm/"); +} + +Path +Path::GetUserHomeDirectory() { + const char* home = getenv("HOME"); + if (home) { + Path result; + if (result.set(home)) + return result; + } + return GetRootDirectory(); +} + +Path +Path::GetCurrentDirectory() { + char pathname[MAXPATHLEN]; + if (!getcwd(pathname,MAXPATHLEN)) { + assert (false && "Could not query current working directory."); + return Path(); + } + + return Path(pathname); +} + +#if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__minix) +static int +test_dir(char buf[PATH_MAX], char ret[PATH_MAX], + const char *dir, const char *bin) +{ + struct stat sb; + + snprintf(buf, PATH_MAX, "%s/%s", dir, bin); + if (realpath(buf, ret) == NULL) + return (1); + if (stat(buf, &sb) != 0) + return (1); + + return (0); +} + +static char * +getprogpath(char ret[PATH_MAX], const char *bin) +{ + char *pv, *s, *t, buf[PATH_MAX]; + + /* First approach: absolute path. */ + if (bin[0] == '/') { + if (test_dir(buf, ret, "/", bin) == 0) + return (ret); + return (NULL); + } + + /* Second approach: relative path. */ + if (strchr(bin, '/') != NULL) { + if (getcwd(buf, PATH_MAX) == NULL) + return (NULL); + if (test_dir(buf, ret, buf, bin) == 0) + return (ret); + return (NULL); + } + + /* Third approach: $PATH */ + if ((pv = getenv("PATH")) == NULL) + return (NULL); + s = pv = strdup(pv); + if (pv == NULL) + return (NULL); + while ((t = strsep(&s, ":")) != NULL) { + if (test_dir(buf, ret, t, bin) == 0) { + free(pv); + return (ret); + } + } + free(pv); + return (NULL); +} +#endif // __FreeBSD__ || __NetBSD__ + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { +#if defined(__APPLE__) + // On OS X the executable path is saved to the stack by dyld. Reading it + // from there is much faster than calling dladdr, especially for large + // binaries with symbols. + char exe_path[MAXPATHLEN]; + uint32_t size = sizeof(exe_path); + if (_NSGetExecutablePath(exe_path, &size) == 0) { + char link_path[MAXPATHLEN]; + if (realpath(exe_path, link_path)) + return Path(link_path); + } +#elif defined(__FreeBSD__) || defined (__NetBSD__) || defined(__minix) + char exe_path[PATH_MAX]; + + if (getprogpath(exe_path, argv0) != NULL) + return Path(exe_path); +#elif defined(__linux__) || defined(__CYGWIN__) + char exe_path[MAXPATHLEN]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); + if (len >= 0) + return Path(StringRef(exe_path, len)); +#elif defined(HAVE_DLFCN_H) + // Use dladdr to get executable path if available. + Dl_info DLInfo; + int err = dladdr(MainAddr, &DLInfo); + if (err == 0) + return Path(); + + // If the filename is a symlink, we need to resolve and return the location of + // the actual executable. + char link_path[MAXPATHLEN]; + if (realpath(DLInfo.dli_fname, link_path)) + return Path(link_path); +#else +#error GetMainExecutable is not implemented on this host yet. +#endif + return Path(); +} + + +StringRef Path::getDirname() const { + return getDirnameCharSep(path, "/"); +} + +StringRef +Path::getBasename() const { + // Find the last slash + std::string::size_type slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + std::string::size_type dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(path).substr(slash); + else + return StringRef(path).substr(slash, dot - slash); +} + +StringRef +Path::getSuffix() const { + // Find the last slash + std::string::size_type slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + std::string::size_type dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(); + else + return StringRef(path).substr(dot + 1); +} + +bool Path::getMagicNumber(std::string &Magic, unsigned len) const { + assert(len < 1024 && "Request for magic string too long"); + char Buf[1025]; + int fd = ::open(path.c_str(), O_RDONLY); + if (fd < 0) + return false; + ssize_t bytes_read = ::read(fd, Buf, len); + ::close(fd); + if (ssize_t(len) != bytes_read) + return false; + Magic.assign(Buf, len); + return true; +} + +bool +Path::exists() const { + return 0 == access(path.c_str(), F_OK ); +} + +bool +Path::isDirectory() const { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) + return false; + return ((buf.st_mode & S_IFMT) == S_IFDIR) ? true : false; +} + +bool +Path::isSymLink() const { + struct stat buf; + if (0 != lstat(path.c_str(), &buf)) + return false; + return S_ISLNK(buf.st_mode); +} + + +bool +Path::canRead() const { + return 0 == access(path.c_str(), R_OK); +} + +bool +Path::canWrite() const { + return 0 == access(path.c_str(), W_OK); +} + +bool +Path::isRegularFile() const { + // Get the status so we can determine if it's a file or directory + struct stat buf; + + if (0 != stat(path.c_str(), &buf)) + return false; + + if (S_ISREG(buf.st_mode)) + return true; + + return false; +} + +bool +Path::canExecute() const { + if (0 != access(path.c_str(), R_OK | X_OK )) + return false; + struct stat buf; + if (0 != stat(path.c_str(), &buf)) + return false; + if (!S_ISREG(buf.st_mode)) + return false; + return true; +} + +StringRef +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash + if (pos == path.length()-1) { + // Find the second to last slash + size_t pos2 = path.rfind('/', pos-1); + if (pos2 == std::string::npos) + return StringRef(path).substr(0,pos); + else + return StringRef(path).substr(pos2+1,pos-pos2-1); + } + // Return everything after the last slash + return StringRef(path).substr(pos+1); +} + +const FileStatus * +PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { + if (!fsIsValid || update) { + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + MakeErrMsg(ErrStr, path + ": can't get status of file"); + return 0; + } + status.fileSize = buf.st_size; + status.modTime.fromEpochTime(buf.st_mtime); + status.mode = buf.st_mode; + status.user = buf.st_uid; + status.group = buf.st_gid; + status.uniqueID = uint64_t(buf.st_ino); + status.isDir = S_ISDIR(buf.st_mode); + status.isFile = S_ISREG(buf.st_mode); + fsIsValid = true; + } + return &status; +} + +static bool AddPermissionBits(const Path &File, int bits) { + // Get the umask value from the operating system. We want to use it + // when changing the file's permissions. Since calling umask() sets + // the umask and returns its old value, we must call it a second + // time to reset it to the user's preference. + int mask = umask(0777); // The arg. to umask is arbitrary. + umask(mask); // Restore the umask. + + // Get the file's current mode. + struct stat buf; + if (0 != stat(File.c_str(), &buf)) + return false; + // Change the file to have whichever permissions bits from 'bits' + // that the umask would not disable. + if ((chmod(File.c_str(), (buf.st_mode | (bits & ~mask)))) == -1) + return false; + return true; +} + +bool Path::makeReadableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0444)) + return MakeErrMsg(ErrMsg, path + ": can't make file readable"); + return false; +} + +bool Path::makeWriteableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0222)) + return MakeErrMsg(ErrMsg, path + ": can't make file writable"); + return false; +} + +bool Path::makeExecutableOnDisk(std::string* ErrMsg) { + if (!AddPermissionBits(*this, 0111)) + return MakeErrMsg(ErrMsg, path + ": can't make file executable"); + return false; +} + +bool +Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { + DIR* direntries = ::opendir(path.c_str()); + if (direntries == 0) + return MakeErrMsg(ErrMsg, path + ": can't open directory"); + + std::string dirPath = path; + if (!lastIsSlash(dirPath)) + dirPath += '/'; + + result.clear(); + struct dirent* de = ::readdir(direntries); + for ( ; de != 0; de = ::readdir(direntries)) { + if (de->d_name[0] != '.') { + Path aPath(dirPath + (const char*)de->d_name); + struct stat st; + if (0 != lstat(aPath.path.c_str(), &st)) { + if (S_ISLNK(st.st_mode)) + continue; // dangling symlink -- ignore + return MakeErrMsg(ErrMsg, + aPath.path + ": can't determine file object type"); + } + result.insert(aPath); + } + } + + closedir(direntries); + return false; +} + +bool +Path::set(StringRef a_path) { + if (a_path.empty()) + return false; + path = a_path; + return true; +} + +bool +Path::appendComponent(StringRef name) { + if (name.empty()) + return false; + if (!lastIsSlash(path)) + path += '/'; + path += name; + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == 0 || slashpos == std::string::npos) { + path.erase(); + return true; + } + if (slashpos == path.size() - 1) + slashpos = path.rfind('/',slashpos-1); + if (slashpos == std::string::npos) { + path.erase(); + return true; + } + path.erase(slashpos); + return true; +} + +bool +Path::eraseSuffix() { + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + path.erase(dotpos, path.size()-dotpos); + return true; + } + } + return false; +} + +static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { + + if (access(beg, R_OK | W_OK) == 0) + return false; + + if (create_parents) { + + char* c = end; + + for (; c != beg; --c) + if (*c == '/') { + + // Recurse to handling the parent directory. + *c = '\0'; + bool x = createDirectoryHelper(beg, c, create_parents); + *c = '/'; + + // Return if we encountered an error. + if (x) + return true; + + break; + } + } + + return mkdir(beg, S_IRWXU | S_IRWXG) != 0; +} + +bool +Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { + // Get a writeable copy of the path name + std::string pathname(path); + + // Null-terminate the last component + size_t lastchar = path.length() - 1 ; + + if (pathname[lastchar] != '/') + ++lastchar; + + pathname[lastchar] = '\0'; + + if (createDirectoryHelper(&pathname[0], &pathname[lastchar], create_parents)) + return MakeErrMsg(ErrMsg, pathname + ": can't create directory"); + + return false; +} + +bool +Path::createFileOnDisk(std::string* ErrMsg) { + // Create the file + int fd = ::creat(path.c_str(), S_IRUSR | S_IWUSR); + if (fd < 0) + return MakeErrMsg(ErrMsg, path + ": can't create file"); + ::close(fd); + return false; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { + // Make this into a unique file name + if (makeUnique( reuse_current, ErrMsg )) + return true; + + // create the file + int fd = ::open(path.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) + return MakeErrMsg(ErrMsg, path + ": can't create temporary file"); + ::close(fd); + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { + // Get the status so we can determine if it's a file or directory. + struct stat buf; + if (0 != stat(path.c_str(), &buf)) { + MakeErrMsg(ErrStr, path + ": can't get status of file"); + return true; + } + + // Note: this check catches strange situations. In all cases, LLVM should + // only be involved in the creation and deletion of regular files. This + // check ensures that what we're trying to erase is a regular file. It + // effectively prevents LLVM from erasing things like /dev/null, any block + // special file, or other things that aren't "regular" files. + if (S_ISREG(buf.st_mode)) { + if (unlink(path.c_str()) != 0) + return MakeErrMsg(ErrStr, path + ": can't destroy file"); + return false; + } + + if (!S_ISDIR(buf.st_mode)) { + if (ErrStr) *ErrStr = "not a file or directory"; + return true; + } + + if (remove_contents) { + // Recursively descend the directory to remove its contents. + std::string cmd = "/bin/rm -rf " + path; + if (system(cmd.c_str()) != 0) { + MakeErrMsg(ErrStr, path + ": failed to recursively remove directory."); + return true; + } + return false; + } + + // Otherwise, try to just remove the one directory. + std::string pathname(path); + size_t lastchar = path.length() - 1; + if (pathname[lastchar] == '/') + pathname[lastchar] = '\0'; + else + pathname[lastchar+1] = '\0'; + + if (rmdir(pathname.c_str()) != 0) + return MakeErrMsg(ErrStr, pathname + ": can't erase directory"); + return false; +} + +bool +Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { + if (0 != ::rename(path.c_str(), newName.c_str())) + return MakeErrMsg(ErrMsg, std::string("can't rename '") + path + "' as '" + + newName.str() + "'"); + return false; +} + +bool +Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrStr) const { + struct utimbuf utb; + utb.actime = si.modTime.toPosixTime(); + utb.modtime = utb.actime; + if (0 != ::utime(path.c_str(),&utb)) + return MakeErrMsg(ErrStr, path + ": can't set file modification time"); + if (0 != ::chmod(path.c_str(),si.mode)) + return MakeErrMsg(ErrStr, path + ": can't set mode"); + return false; +} + +bool +sys::CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg){ + int inFile = -1; + int outFile = -1; + inFile = ::open(Src.c_str(), O_RDONLY); + if (inFile == -1) + return MakeErrMsg(ErrMsg, Src.str() + + ": can't open source file to copy"); + + outFile = ::open(Dest.c_str(), O_WRONLY|O_CREAT, 0666); + if (outFile == -1) { + ::close(inFile); + return MakeErrMsg(ErrMsg, Dest.str() + + ": can't create destination file for copy"); + } + + char Buffer[16*1024]; + while (ssize_t Amt = ::read(inFile, Buffer, 16*1024)) { + if (Amt == -1) { + if (errno != EINTR && errno != EAGAIN) { + ::close(inFile); + ::close(outFile); + return MakeErrMsg(ErrMsg, Src.str()+": can't read source file"); + } + } else { + char *BufPtr = Buffer; + while (Amt) { + ssize_t AmtWritten = ::write(outFile, BufPtr, Amt); + if (AmtWritten == -1) { + if (errno != EINTR && errno != EAGAIN) { + ::close(inFile); + ::close(outFile); + return MakeErrMsg(ErrMsg, Dest.str() + + ": can't write destination file"); + } + } else { + Amt -= AmtWritten; + BufPtr += AmtWritten; + } + } + } + } + ::close(inFile); + ::close(outFile); + return false; +} + +bool +Path::makeUnique(bool reuse_current, std::string* ErrMsg) { + if (reuse_current && !exists()) + return false; // File doesn't exist already, just use it! + + // Append an XXXXXX pattern to the end of the file for use with mkstemp, + // mktemp or our own implementation. + // This uses std::vector instead of SmallVector to avoid a dependence on + // libSupport. And performance isn't critical here. + std::vector<char> Buf; + Buf.resize(path.size()+8); + char *FNBuffer = &Buf[0]; + path.copy(FNBuffer,path.size()); + if (isDirectory()) + strcpy(FNBuffer+path.size(), "/XXXXXX"); + else + strcpy(FNBuffer+path.size(), "-XXXXXX"); + +#if defined(HAVE_MKSTEMP) + int TempFD; + if ((TempFD = mkstemp(FNBuffer)) == -1) + return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + + // We don't need to hold the temp file descriptor... we will trust that no one + // will overwrite/delete the file before we can open it again. + close(TempFD); + + // Save the name + path = FNBuffer; +#elif defined(HAVE_MKTEMP) + // If we don't have mkstemp, use the old and obsolete mktemp function. + if (mktemp(FNBuffer) == 0) + return MakeErrMsg(ErrMsg, path + ": can't make unique filename"); + + // Save the name + path = FNBuffer; +#else + // Okay, looks like we have to do it all by our lonesome. + static unsigned FCounter = 0; + // Try to initialize with unique value. + if (FCounter == 0) FCounter = ((unsigned)getpid() & 0xFFFF) << 8; + char* pos = strstr(FNBuffer, "XXXXXX"); + do { + if (++FCounter > 0xFFFFFF) { + return MakeErrMsg(ErrMsg, + path + ": can't make unique filename: too many files"); + } + sprintf(pos, "%06X", FCounter); + path = FNBuffer; + } while (exists()); + // POSSIBLE SECURITY BUG: An attacker can easily guess the name and exploit + // LLVM. +#endif + return false; +} + +const char *Path::MapInFilePages(int FD, uint64_t FileSize) { + int Flags = MAP_PRIVATE; +#ifdef MAP_FILE + Flags |= MAP_FILE; +#endif + void *BasePtr = ::mmap(0, FileSize, PROT_READ, Flags, FD, 0); + if (BasePtr == MAP_FAILED) + return 0; + return (const char*)BasePtr; +} + +void Path::UnMapFilePages(const char *BasePtr, uint64_t FileSize) { + ::munmap((void*)BasePtr, FileSize); +} + +} // end llvm namespace diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc new file mode 100644 index 0000000..5cdb11c --- /dev/null +++ b/lib/Support/Unix/Process.inc @@ -0,0 +1,295 @@ +//===- Unix/Process.cpp - Unix Process Implementation --------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the generic Unix implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +// DragonFly BSD has deprecated <malloc.h> for <stdlib.h> instead, +// Unix.h includes this for us already. +#if defined(HAVE_MALLOC_H) && !defined(__DragonFly__) +#include <malloc.h> +#endif +#ifdef HAVE_MALLOC_MALLOC_H +#include <malloc/malloc.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif +#ifdef HAVE_TERMIOS_H +# include <termios.h> +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; +using namespace sys; + +unsigned +Process::GetPageSize() +{ +#if defined(__CYGWIN__) + // On Cygwin, getpagesize() returns 64k but the page size for the purposes of + // memory protection and mmap() is 4k. + // See http://www.cygwin.com/ml/cygwin/2009-01/threads.html#00492 + const int page_size = 0x1000; +#elif defined(HAVE_GETPAGESIZE) + const int page_size = ::getpagesize(); +#elif defined(HAVE_SYSCONF) + long page_size = ::sysconf(_SC_PAGE_SIZE); +#else +#warning Cannot get the page size on this machine +#endif + return static_cast<unsigned>(page_size); +} + +size_t Process::GetMallocUsage() { +#if defined(HAVE_MALLINFO) + struct mallinfo mi; + mi = ::mallinfo(); + return mi.uordblks; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) + malloc_statistics_t Stats; + malloc_zone_statistics(malloc_default_zone(), &Stats); + return Stats.size_in_use; // darwin +#elif defined(HAVE_SBRK) + // Note this is only an approximation and more closely resembles + // the value returned by mallinfo in the arena field. + static char *StartOfMemory = reinterpret_cast<char*>(::sbrk(0)); + char *EndOfMemory = (char*)sbrk(0); + if (EndOfMemory != ((char*)-1) && StartOfMemory != ((char*)-1)) + return EndOfMemory - StartOfMemory; + else + return 0; +#else +#warning Cannot get malloc info on this platform + return 0; +#endif +} + +size_t +Process::GetTotalMemoryUsage() +{ +#if defined(HAVE_MALLINFO) + struct mallinfo mi = ::mallinfo(); + return mi.uordblks + mi.hblkhd; +#elif defined(HAVE_MALLOC_ZONE_STATISTICS) && defined(HAVE_MALLOC_MALLOC_H) + malloc_statistics_t Stats; + malloc_zone_statistics(malloc_default_zone(), &Stats); + return Stats.size_allocated; // darwin +#elif defined(HAVE_GETRUSAGE) && !defined(__HAIKU__) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + return usage.ru_maxrss; +#else +#warning Cannot get total memory size on this platform + return 0; +#endif +} + +void +Process::GetTimeUsage(TimeValue& elapsed, TimeValue& user_time, + TimeValue& sys_time) +{ + elapsed = TimeValue::now(); +#if defined(HAVE_GETRUSAGE) + struct rusage usage; + ::getrusage(RUSAGE_SELF, &usage); + user_time = TimeValue( + static_cast<TimeValue::SecondsType>( usage.ru_utime.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( usage.ru_utime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); + sys_time = TimeValue( + static_cast<TimeValue::SecondsType>( usage.ru_stime.tv_sec ), + static_cast<TimeValue::NanoSecondsType>( usage.ru_stime.tv_usec * + TimeValue::NANOSECONDS_PER_MICROSECOND ) ); +#else +#warning Cannot get usage times on this platform + user_time.seconds(0); + user_time.microseconds(0); + sys_time.seconds(0); + sys_time.microseconds(0); +#endif +} + +int Process::GetCurrentUserId() { + return getuid(); +} + +int Process::GetCurrentGroupId() { + return getgid(); +} + +#ifdef HAVE_MACH_MACH_H +#include <mach/mach.h> +#endif + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this function +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { +#if HAVE_SETRLIMIT + struct rlimit rlim; + rlim.rlim_cur = rlim.rlim_max = 0; + setrlimit(RLIMIT_CORE, &rlim); +#endif + +#ifdef HAVE_MACH_MACH_H + // Disable crash reporting on Mac OS X 10.0-10.4 + + // get information about the original set of exception ports for the task + mach_msg_type_number_t Count = 0; + exception_mask_t OriginalMasks[EXC_TYPES_COUNT]; + exception_port_t OriginalPorts[EXC_TYPES_COUNT]; + exception_behavior_t OriginalBehaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t OriginalFlavors[EXC_TYPES_COUNT]; + kern_return_t err = + task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, OriginalMasks, + &Count, OriginalPorts, OriginalBehaviors, + OriginalFlavors); + if (err == KERN_SUCCESS) { + // replace each with MACH_PORT_NULL. + for (unsigned i = 0; i != Count; ++i) + task_set_exception_ports(mach_task_self(), OriginalMasks[i], + MACH_PORT_NULL, OriginalBehaviors[i], + OriginalFlavors[i]); + } + + // Disable crash reporting on Mac OS X 10.5 + signal(SIGABRT, _exit); + signal(SIGILL, _exit); + signal(SIGFPE, _exit); + signal(SIGSEGV, _exit); + signal(SIGBUS, _exit); +#endif +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(STDIN_FILENO); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(STDOUT_FILENO); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(STDERR_FILENO); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { +#if HAVE_ISATTY + return isatty(fd); +#else + // If we don't have isatty, just return false. + return false; +#endif +} + +static unsigned getColumns(int FileID) { + // If COLUMNS is defined in the environment, wrap to that many columns. + if (const char *ColumnsStr = std::getenv("COLUMNS")) { + int Columns = std::atoi(ColumnsStr); + if (Columns > 0) + return Columns; + } + + unsigned Columns = 0; + +#if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_TERMIOS_H) + // Try to determine the width of the terminal. + struct winsize ws; + if (ioctl(FileID, TIOCGWINSZ, &ws) == 0) + Columns = ws.ws_col; +#endif + + return Columns; +} + +unsigned Process::StandardOutColumns() { + if (!StandardOutIsDisplayed()) + return 0; + + return getColumns(1); +} + +unsigned Process::StandardErrColumns() { + if (!StandardErrIsDisplayed()) + return 0; + + return getColumns(2); +} + +static bool terminalHasColors() { + if (const char *term = std::getenv("TERM")) { + // Most modern terminals support ANSI escape sequences for colors. + // We could check terminfo, or have a list of known terms that support + // colors, but that would be overkill. + // The user can always ask for no colors by setting TERM to dumb, or + // using a commandline flag. + return strcmp(term, "dumb") != 0; + } + return false; +} + +bool Process::StandardOutHasColors() { + if (!StandardOutIsDisplayed()) + return false; + return terminalHasColors(); +} + +bool Process::StandardErrHasColors() { + if (!StandardErrIsDisplayed()) + return false; + return terminalHasColors(); +} + +bool Process::ColorNeedsFlush() { + // No, we use ANSI escape sequences. + return false; +} + +#define COLOR(FGBG, CODE, BOLD) "\033[0;" BOLD FGBG CODE "m" + +#define ALLCOLORS(FGBG,BOLD) {\ + COLOR(FGBG, "0", BOLD),\ + COLOR(FGBG, "1", BOLD),\ + COLOR(FGBG, "2", BOLD),\ + COLOR(FGBG, "3", BOLD),\ + COLOR(FGBG, "4", BOLD),\ + COLOR(FGBG, "5", BOLD),\ + COLOR(FGBG, "6", BOLD),\ + COLOR(FGBG, "7", BOLD)\ + } + +static const char colorcodes[2][2][8][10] = { + { ALLCOLORS("3",""), ALLCOLORS("3","1;") }, + { ALLCOLORS("4",""), ALLCOLORS("4","1;") } +}; + +const char *Process::OutputColor(char code, bool bold, bool bg) { + return colorcodes[bg?1:0][bold?1:0][code&7]; +} + +const char *Process::OutputBold(bool bg) { + return "\033[1m"; +} + +const char *Process::ResetColor() { + return "\033[0m"; +} diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc new file mode 100644 index 0000000..e06f80b --- /dev/null +++ b/lib/Support/Unix/Program.inc @@ -0,0 +1,422 @@ +//===- llvm/System/Unix/Program.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the Program class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include <llvm/Config/config.h> +#include "Unix.h" +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_POSIX_SPAWN +#include <spawn.h> +#if !defined(__APPLE__) + extern char **environ; +#else +#include <crt_externs.h> // _NSGetEnviron +#endif +#endif + +namespace llvm { +using namespace sys; + +Program::Program() : Data_(0) {} + +Program::~Program() {} + +unsigned Program::GetPid() const { + uint64_t pid = reinterpret_cast<uint64_t>(Data_); + return static_cast<unsigned>(pid); +} + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // Use the given path verbatim if it contains any slashes; this matches + // the behavior of sh(1) and friends. + if (progName.find('/') != std::string::npos) + return temp; + + // At this point, the file name is valid and does not contain slashes. Search + // for it through the directories specified in the PATH environment variable. + + // Get the path. If its empty, we can't do anything to find it. + const char *PathStr = getenv("PATH"); + if (PathStr == 0) + return Path(); + + // Now we have a colon separated list of directories to search; try them. + size_t PathLen = strlen(PathStr); + while (PathLen) { + // Find the first colon... + const char *Colon = std::find(PathStr, PathStr+PathLen, ':'); + + // Check to see if this first directory contains the executable... + Path FilePath; + if (FilePath.set(std::string(PathStr,Colon))) { + FilePath.appendComponent(progName); + if (FilePath.canExecute()) + return FilePath; // Found the executable! + } + + // Nope it wasn't in this directory, check the next path in the list! + PathLen -= Colon-PathStr; + PathStr = Colon; + + // Advance past duplicate colons + while (*PathStr == ':') { + PathStr++; + PathLen--; + } + } + return Path(); +} + +static bool RedirectIO(const Path *Path, int FD, std::string* ErrMsg) { + if (Path == 0) // Noop + return false; + const char *File; + if (Path->isEmpty()) + // Redirect empty paths to /dev/null + File = "/dev/null"; + else + File = Path->c_str(); + + // Open the file + int InFD = open(File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666); + if (InFD == -1) { + MakeErrMsg(ErrMsg, "Cannot open file '" + std::string(File) + "' for " + + (FD == 0 ? "input" : "output")); + return true; + } + + // Install it as the requested FD + if (dup2(InFD, FD) == -1) { + MakeErrMsg(ErrMsg, "Cannot dup2"); + close(InFD); + return true; + } + close(InFD); // Close the original FD + return false; +} + +#ifdef HAVE_POSIX_SPAWN +static bool RedirectIO_PS(const Path *Path, int FD, std::string *ErrMsg, + posix_spawn_file_actions_t &FileActions) { + if (Path == 0) // Noop + return false; + const char *File; + if (Path->isEmpty()) + // Redirect empty paths to /dev/null + File = "/dev/null"; + else + File = Path->c_str(); + + if (int Err = posix_spawn_file_actions_addopen(&FileActions, FD, + File, FD == 0 ? O_RDONLY : O_WRONLY|O_CREAT, 0666)) + return MakeErrMsg(ErrMsg, "Cannot dup2", Err); + return false; +} +#endif + +static void TimeOutHandler(int Sig) { +} + +static void SetMemoryLimits (unsigned size) +{ +#if HAVE_SYS_RESOURCE_H && HAVE_GETRLIMIT && HAVE_SETRLIMIT + struct rlimit r; + __typeof__ (r.rlim_cur) limit = (__typeof__ (r.rlim_cur)) (size) * 1048576; + + // Heap size + getrlimit (RLIMIT_DATA, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_DATA, &r); +#ifdef RLIMIT_RSS + // Resident set size. + getrlimit (RLIMIT_RSS, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_RSS, &r); +#endif +#ifdef RLIMIT_AS // e.g. NetBSD doesn't have it. + // Virtual memory. + getrlimit (RLIMIT_AS, &r); + r.rlim_cur = limit; + setrlimit (RLIMIT_AS, &r); +#endif +#endif +} + +bool +Program::Execute(const Path &path, const char **args, const char **envp, + const Path **redirects, unsigned memoryLimit, + std::string *ErrMsg) { + // If this OS has posix_spawn and there is no memory limit being implied, use + // posix_spawn. It is more efficient than fork/exec. +#ifdef HAVE_POSIX_SPAWN + if (memoryLimit == 0) { + posix_spawn_file_actions_t FileActions; + posix_spawn_file_actions_init(&FileActions); + + if (redirects) { + // Redirect stdin/stdout. + if (RedirectIO_PS(redirects[0], 0, ErrMsg, FileActions) || + RedirectIO_PS(redirects[1], 1, ErrMsg, FileActions)) + return false; + if (redirects[1] == 0 || redirects[2] == 0 || + *redirects[1] != *redirects[2]) { + // Just redirect stderr + if (RedirectIO_PS(redirects[2], 2, ErrMsg, FileActions)) return false; + } else { + // If stdout and stderr should go to the same place, redirect stderr + // to the FD already open for stdout. + if (int Err = posix_spawn_file_actions_adddup2(&FileActions, 1, 2)) + return !MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout", Err); + } + } + + if (!envp) +#if !defined(__APPLE__) + envp = const_cast<const char **>(environ); +#else + // environ is missing in dylibs. + envp = const_cast<const char **>(*_NSGetEnviron()); +#endif + + // Explicitly initialized to prevent what appears to be a valgrind false + // positive. + pid_t PID = 0; + int Err = posix_spawn(&PID, path.c_str(), &FileActions, /*attrp*/0, + const_cast<char **>(args), const_cast<char **>(envp)); + + posix_spawn_file_actions_destroy(&FileActions); + + if (Err) + return !MakeErrMsg(ErrMsg, "posix_spawn failed", Err); + + Data_ = reinterpret_cast<void*>(PID); + return true; + } +#endif + + // Create a child process. + int child = fork(); + switch (child) { + // An error occured: Return to the caller. + case -1: + MakeErrMsg(ErrMsg, "Couldn't fork"); + return false; + + // Child process: Execute the program. + case 0: { + // Redirect file descriptors... + if (redirects) { + // Redirect stdin + if (RedirectIO(redirects[0], 0, ErrMsg)) { return false; } + // Redirect stdout + if (RedirectIO(redirects[1], 1, ErrMsg)) { return false; } + if (redirects[1] && redirects[2] && + *(redirects[1]) == *(redirects[2])) { + // If stdout and stderr should go to the same place, redirect stderr + // to the FD already open for stdout. + if (-1 == dup2(1,2)) { + MakeErrMsg(ErrMsg, "Can't redirect stderr to stdout"); + return false; + } + } else { + // Just redirect stderr + if (RedirectIO(redirects[2], 2, ErrMsg)) { return false; } + } + } + + // Set memory limits + if (memoryLimit!=0) { + SetMemoryLimits(memoryLimit); + } + + // Execute! + if (envp != 0) + execve(path.c_str(), + const_cast<char **>(args), + const_cast<char **>(envp)); + else + execv(path.c_str(), + const_cast<char **>(args)); + // If the execve() failed, we should exit. Follow Unix protocol and + // return 127 if the executable was not found, and 126 otherwise. + // Use _exit rather than exit so that atexit functions and static + // object destructors cloned from the parent process aren't + // redundantly run, and so that any data buffered in stdio buffers + // cloned from the parent aren't redundantly written out. + _exit(errno == ENOENT ? 127 : 126); + } + + // Parent process: Break out of the switch to do our processing. + default: + break; + } + + Data_ = reinterpret_cast<void*>(child); + + return true; +} + +int +Program::Wait(const sys::Path &path, + unsigned secondsToWait, + std::string* ErrMsg) +{ +#ifdef HAVE_SYS_WAIT_H + struct sigaction Act, Old; + + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + // Install a timeout handler. The handler itself does nothing, but the simple + // fact of having a handler at all causes the wait below to return with EINTR, + // unlike if we used SIG_IGN. + if (secondsToWait) { + memset(&Act, 0, sizeof(Act)); + Act.sa_handler = TimeOutHandler; + sigemptyset(&Act.sa_mask); + sigaction(SIGALRM, &Act, &Old); + alarm(secondsToWait); + } + + // Parent process: Wait for the child process to terminate. + int status; + uint64_t pid = reinterpret_cast<uint64_t>(Data_); + pid_t child = static_cast<pid_t>(pid); + while (waitpid(pid, &status, 0) != child) + if (secondsToWait && errno == EINTR) { + // Kill the child. + kill(child, SIGKILL); + + // Turn off the alarm and restore the signal handler + alarm(0); + sigaction(SIGALRM, &Old, 0); + + // Wait for child to die + if (wait(&status) != child) + MakeErrMsg(ErrMsg, "Child timed out but wouldn't die"); + else + MakeErrMsg(ErrMsg, "Child timed out", 0); + + return -1; // Timeout detected + } else if (errno != EINTR) { + MakeErrMsg(ErrMsg, "Error waiting for child process"); + return -1; + } + + // We exited normally without timeout, so turn off the timer. + if (secondsToWait) { + alarm(0); + sigaction(SIGALRM, &Old, 0); + } + + // Return the proper exit status. Detect error conditions + // so we can return -1 for them and set ErrMsg informatively. + int result = 0; + if (WIFEXITED(status)) { + result = WEXITSTATUS(status); +#ifdef HAVE_POSIX_SPAWN + // The posix_spawn child process returns 127 on any kind of error. + // Following the POSIX convention for command-line tools (which posix_spawn + // itself apparently does not), check to see if the failure was due to some + // reason other than the file not existing, and return 126 in this case. + if (result == 127 && path.exists()) + result = 126; +#endif + if (result == 127) { + if (ErrMsg) + *ErrMsg = llvm::sys::StrError(ENOENT); + return -1; + } + if (result == 126) { + if (ErrMsg) + *ErrMsg = "Program could not be executed"; + return -1; + } + } else if (WIFSIGNALED(status)) { + if (ErrMsg) { + *ErrMsg = strsignal(WTERMSIG(status)); +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + *ErrMsg += " (core dumped)"; +#endif + } + return -1; + } + return result; +#else + if (ErrMsg) + *ErrMsg = "Program::Wait is not implemented on this platform yet!"; + return -1; +#endif +} + +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + uint64_t pid64 = reinterpret_cast<uint64_t>(Data_); + pid_t pid = static_cast<pid_t>(pid64); + + if (kill(pid, SIGKILL) != 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + +bool Program::ChangeStdinToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return false; +} + +bool Program::ChangeStdoutToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return false; +} + +bool Program::ChangeStderrToBinary(){ + // Do nothing, as Unix doesn't differentiate between text and binary. + return false; +} + +} diff --git a/lib/Support/Unix/README.txt b/lib/Support/Unix/README.txt new file mode 100644 index 0000000..3d547c2 --- /dev/null +++ b/lib/Support/Unix/README.txt @@ -0,0 +1,16 @@ +llvm/lib/Support/Unix README +=========================== + +This directory provides implementations of the lib/System classes that +are common to two or more variants of UNIX. For example, the directory +structure underneath this directory could look like this: + +Unix - only code that is truly generic to all UNIX platforms + Posix - code that is specific to Posix variants of UNIX + SUS - code that is specific to the Single Unix Specification + SysV - code that is specific to System V variants of UNIX + +As a rule, only those directories actually needing to be created should be +created. Also, further subdirectories could be created to reflect versions of +the various standards. For example, under SUS there could be v1, v2, and v3 +subdirectories to reflect the three major versions of SUS. diff --git a/lib/Support/Unix/RWMutex.inc b/lib/Support/Unix/RWMutex.inc new file mode 100644 index 0000000..ee9853e --- /dev/null +++ b/lib/Support/Unix/RWMutex.inc @@ -0,0 +1,43 @@ +//= llvm/System/Unix/RWMutex.inc - Unix Reader/Writer Mutual Exclusion Lock =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) RWMutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { + +using namespace sys; + +RWMutexImpl::RWMutexImpl() { } + +RWMutexImpl::~RWMutexImpl() { } + +bool RWMutexImpl::reader_acquire() { + return true; +} + +bool RWMutexImpl::reader_release() { + return true; +} + +bool RWMutexImpl::writer_acquire() { + return true; +} + +bool RWMutexImpl::writer_release() { + return true; +} + +} diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc new file mode 100644 index 0000000..0a61759 --- /dev/null +++ b/lib/Support/Unix/Signals.inc @@ -0,0 +1,303 @@ +//===- Signals.cpp - Generic Unix Signals Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some helpful functions for dealing with the possibility of +// Unix signals occuring while your program is running. +// +//===----------------------------------------------------------------------===// + +#include "Unix.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Mutex.h" +#include <vector> +#include <algorithm> +#if HAVE_EXECINFO_H +# include <execinfo.h> // For backtrace(). +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_DLFCN_H && __GNUG__ +#include <dlfcn.h> +#include <cxxabi.h> +#endif +using namespace llvm; + +static RETSIGTYPE SignalHandler(int Sig); // defined below. + +static SmartMutex<true> SignalsMutex; + +/// InterruptFunction - The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector<sys::Path> FilesToRemove; +static std::vector<std::pair<void(*)(void*), void*> > CallBacksToRun; + +// IntSigs - Signals that may interrupt the program at any time. +static const int IntSigs[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2 +}; +static const int *const IntSigsEnd = + IntSigs + sizeof(IntSigs) / sizeof(IntSigs[0]); + +// KillSigs - Signals that are synchronous with the program that will cause it +// to die. +static const int KillSigs[] = { + SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGBUS, SIGSEGV +#ifdef SIGSYS + , SIGSYS +#endif +#ifdef SIGXCPU + , SIGXCPU +#endif +#ifdef SIGXFSZ + , SIGXFSZ +#endif +#ifdef SIGEMT + , SIGEMT +#endif +}; +static const int *const KillSigsEnd = + KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]); + +static unsigned NumRegisteredSignals = 0; +static struct { + struct sigaction SA; + int SigNo; +} RegisteredSignalInfo[(sizeof(IntSigs)+sizeof(KillSigs))/sizeof(KillSigs[0])]; + + +static void RegisterHandler(int Signal) { + assert(NumRegisteredSignals < + sizeof(RegisteredSignalInfo)/sizeof(RegisteredSignalInfo[0]) && + "Out of space for signal handlers!"); + + struct sigaction NewHandler; + + NewHandler.sa_handler = SignalHandler; + NewHandler.sa_flags = SA_NODEFER|SA_RESETHAND; + sigemptyset(&NewHandler.sa_mask); + + // Install the new handler, save the old one in RegisteredSignalInfo. + sigaction(Signal, &NewHandler, + &RegisteredSignalInfo[NumRegisteredSignals].SA); + RegisteredSignalInfo[NumRegisteredSignals].SigNo = Signal; + ++NumRegisteredSignals; +} + +static void RegisterHandlers() { + // If the handlers are already registered, we're done. + if (NumRegisteredSignals != 0) return; + + std::for_each(IntSigs, IntSigsEnd, RegisterHandler); + std::for_each(KillSigs, KillSigsEnd, RegisterHandler); +} + +static void UnregisterHandlers() { + // Restore all of the signal handlers to how they were before we showed up. + for (unsigned i = 0, e = NumRegisteredSignals; i != e; ++i) + sigaction(RegisteredSignalInfo[i].SigNo, + &RegisteredSignalInfo[i].SA, 0); + NumRegisteredSignals = 0; +} + + +/// RemoveFilesToRemove - Process the FilesToRemove list. This function +/// should be called with the SignalsMutex lock held. +static void RemoveFilesToRemove() { + while (!FilesToRemove.empty()) { + FilesToRemove.back().eraseFromDisk(true); + FilesToRemove.pop_back(); + } +} + +// SignalHandler - The signal handler that runs. +static RETSIGTYPE SignalHandler(int Sig) { + // Restore the signal behavior to default, so that the program actually + // crashes when we return and the signal reissues. This also ensures that if + // we crash in our signal handler that the program will terminate immediately + // instead of recursing in the signal handler. + UnregisterHandlers(); + + // Unmask all potentially blocked kill signals. + sigset_t SigMask; + sigfillset(&SigMask); + sigprocmask(SIG_UNBLOCK, &SigMask, 0); + + SignalsMutex.acquire(); + RemoveFilesToRemove(); + + if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) { + if (InterruptFunction) { + void (*IF)() = InterruptFunction; + SignalsMutex.release(); + InterruptFunction = 0; + IF(); // run the interrupt function. + return; + } + + SignalsMutex.release(); + raise(Sig); // Execute the default handler. + return; + } + + SignalsMutex.release(); + + // Otherwise if it is a fault (like SEGV) run any handler. + for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i) + CallBacksToRun[i].first(CallBacksToRun[i].second); +} + +void llvm::sys::RunInterruptHandlers() { + SignalsMutex.acquire(); + RemoveFilesToRemove(); + SignalsMutex.release(); +} + +void llvm::sys::SetInterruptFunction(void (*IF)()) { + SignalsMutex.acquire(); + InterruptFunction = IF; + SignalsMutex.release(); + RegisterHandlers(); +} + +// RemoveFileOnSignal - The public API +bool llvm::sys::RemoveFileOnSignal(const sys::Path &Filename, + std::string* ErrMsg) { + SignalsMutex.acquire(); + FilesToRemove.push_back(Filename); + + SignalsMutex.release(); + + RegisterHandlers(); + return false; +} + +// DontRemoveFileOnSignal - The public API +void llvm::sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + SignalsMutex.acquire(); + std::vector<sys::Path>::reverse_iterator I = + std::find(FilesToRemove.rbegin(), FilesToRemove.rend(), Filename); + if (I != FilesToRemove.rend()) + FilesToRemove.erase(I.base()-1); + SignalsMutex.release(); +} + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + CallBacksToRun.push_back(std::make_pair(FnPtr, Cookie)); + RegisterHandlers(); +} + + +// PrintStackTrace - In the case of a program crash or fault, print out a stack +// trace so that the user has an indication of why and where we died. +// +// On glibc systems we have the 'backtrace' function, which works nicely, but +// doesn't demangle symbols. +static void PrintStackTrace(void *) { +#ifdef HAVE_BACKTRACE + static void* StackTrace[256]; + // Use backtrace() to output a backtrace on Linux systems with glibc. + int depth = backtrace(StackTrace, + static_cast<int>(array_lengthof(StackTrace))); +#if HAVE_DLFCN_H && __GNUG__ + int width = 0; + for (int i = 0; i < depth; ++i) { + Dl_info dlinfo; + dladdr(StackTrace[i], &dlinfo); + const char* name = strrchr(dlinfo.dli_fname, '/'); + + int nwidth; + if (name == NULL) nwidth = strlen(dlinfo.dli_fname); + else nwidth = strlen(name) - 1; + + if (nwidth > width) width = nwidth; + } + + for (int i = 0; i < depth; ++i) { + Dl_info dlinfo; + dladdr(StackTrace[i], &dlinfo); + + fprintf(stderr, "%-2d", i); + + const char* name = strrchr(dlinfo.dli_fname, '/'); + if (name == NULL) fprintf(stderr, " %-*s", width, dlinfo.dli_fname); + else fprintf(stderr, " %-*s", width, name+1); + + fprintf(stderr, " %#0*lx", + (int)(sizeof(void*) * 2) + 2, (unsigned long)StackTrace[i]); + + if (dlinfo.dli_sname != NULL) { + int res; + fputc(' ', stderr); + char* d = abi::__cxa_demangle(dlinfo.dli_sname, NULL, NULL, &res); + if (d == NULL) fputs(dlinfo.dli_sname, stderr); + else fputs(d, stderr); + free(d); + + fprintf(stderr, " + %tu",(char*)StackTrace[i]-(char*)dlinfo.dli_saddr); + } + fputc('\n', stderr); + } +#else + backtrace_symbols_fd(StackTrace, depth, STDERR_FILENO); +#endif +#endif +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void llvm::sys::PrintStackTraceOnErrorSignal() { + AddSignalHandler(PrintStackTrace, 0); +} + + +/***/ + +// On Darwin, raise sends a signal to the main thread instead of the current +// thread. This has the unfortunate effect that assert() and abort() will end up +// bypassing our crash recovery attempts. We work around this for anything in +// the same linkage unit by just defining our own versions of the assert handler +// and abort. + +#ifdef __APPLE__ + +int raise(int sig) { + return pthread_kill(pthread_self(), sig); +} + +void __assert_rtn(const char *func, + const char *file, + int line, + const char *expr) { + if (func) + fprintf(stderr, "Assertion failed: (%s), function %s, file %s, line %d.\n", + expr, func, file, line); + else + fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", + expr, file, line); + abort(); +} + +#include <signal.h> +#include <pthread.h> + +void abort() { + raise(SIGABRT); + usleep(1000); + __builtin_trap(); +} + +#endif diff --git a/lib/Support/Unix/ThreadLocal.inc b/lib/Support/Unix/ThreadLocal.inc new file mode 100644 index 0000000..f009b72 --- /dev/null +++ b/lib/Support/Unix/ThreadLocal.inc @@ -0,0 +1,26 @@ +//=== llvm/System/Unix/ThreadLocal.inc - Unix Thread Local Data -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +namespace llvm { +using namespace sys; +ThreadLocalImpl::ThreadLocalImpl() { } +ThreadLocalImpl::~ThreadLocalImpl() { } +void ThreadLocalImpl::setInstance(const void* d) { data = const_cast<void*>(d);} +const void* ThreadLocalImpl::getInstance() { return data; } +void ThreadLocalImpl::removeInstance() { setInstance(0); } +} diff --git a/lib/Support/Unix/TimeValue.inc b/lib/Support/Unix/TimeValue.inc new file mode 100644 index 0000000..5cf5a9d --- /dev/null +++ b/lib/Support/Unix/TimeValue.inc @@ -0,0 +1,56 @@ +//===- Unix/TimeValue.cpp - Unix TimeValue Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Unix specific portion of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +#include "Unix.h" + +namespace llvm { + using namespace sys; + +std::string TimeValue::str() const { + char buffer[32]; + + time_t ourTime = time_t(this->toEpochTime()); +#ifdef __hpux +// note that the following line needs -D_REENTRANT on HP-UX to be picked up + asctime_r(localtime(&ourTime), buffer); +#else + ::asctime_r(::localtime(&ourTime), buffer); +#endif + + std::string result(buffer); + return result.substr(0,24); +} + +TimeValue TimeValue::now() { + struct timeval the_time; + timerclear(&the_time); + if (0 != ::gettimeofday(&the_time,0)) { + // This is *really* unlikely to occur because the only gettimeofday + // errors concern the timezone parameter which we're passing in as 0. + // In the unlikely case it does happen, just return MinTime, no error + // message needed. + return MinTime; + } + + return TimeValue( + static_cast<TimeValue::SecondsType>( the_time.tv_sec + PosixZeroTime.seconds_ ), + static_cast<TimeValue::NanoSecondsType>( the_time.tv_usec * + NANOSECONDS_PER_MICROSECOND ) ); +} + +} diff --git a/lib/Support/Unix/Unix.h b/lib/Support/Unix/Unix.h new file mode 100644 index 0000000..c15866f --- /dev/null +++ b/lib/Support/Unix/Unix.h @@ -0,0 +1,87 @@ +//===- llvm/System/Unix/Unix.h - Common Unix Include File -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Unix implementations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_UNIX_UNIX_H +#define LLVM_SYSTEM_UNIX_UNIX_H + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on all UNIX variants. +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" // Get autoconf configuration settings +#include "llvm/System/Errno.h" +#include <cstdlib> +#include <cstdio> +#include <cstring> +#include <cerrno> +#include <string> +#include <algorithm> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_ASSERT_H +#include <assert.h> +#endif + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif + +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif + +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +/// This function builds an error message into \p ErrMsg using the \p prefix +/// string and the Unix error number given by \p errnum. If errnum is -1, the +/// default then the value of errno is used. +/// @brief Make an error message +/// +/// If the error number can be converted to a string, it will be +/// separated from prefix by ": ". +static inline bool MakeErrMsg( + std::string* ErrMsg, const std::string& prefix, int errnum = -1) { + if (!ErrMsg) + return true; + if (errnum == -1) + errnum = errno; + *ErrMsg = prefix + ": " + llvm::sys::StrError(errnum); + return true; +} + +#endif diff --git a/lib/Support/Unix/system_error.inc b/lib/Support/Unix/system_error.inc new file mode 100644 index 0000000..a382214 --- /dev/null +++ b/lib/Support/Unix/system_error.inc @@ -0,0 +1,34 @@ +//===- llvm/System/Unix/system_error.inc - Unix error_code ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Unix specific implementation of the error_code +// and error_condition classes. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic UNIX code that +//=== is guaranteed to work on *all* UNIX variants. +//===----------------------------------------------------------------------===// + +using namespace llvm; + +std::string +_system_error_category::message(int ev) const { + return _do_message::message(ev); +} + +error_condition +_system_error_category::default_error_condition(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return error_condition(ev, system_category()); +#endif // ELAST + return error_condition(ev, generic_category()); +} diff --git a/lib/Support/Valgrind.cpp b/lib/Support/Valgrind.cpp new file mode 100644 index 0000000..7034485 --- /dev/null +++ b/lib/Support/Valgrind.cpp @@ -0,0 +1,54 @@ +//===-- Valgrind.cpp - Implement Valgrind communication ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines Valgrind communication methods, if HAVE_VALGRIND_VALGRIND_H is +// defined. If we have valgrind.h but valgrind isn't running, its macros are +// no-ops. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/Valgrind.h" +#include "llvm/Config/config.h" + +#if HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> + +static bool InitNotUnderValgrind() { + return !RUNNING_ON_VALGRIND; +} + +// This bool is negated from what we'd expect because code may run before it +// gets initialized. If that happens, it will appear to be 0 (false), and we +// want that to cause the rest of the code in this file to run the +// Valgrind-provided macros. +static const bool NotUnderValgrind = InitNotUnderValgrind(); + +bool llvm::sys::RunningOnValgrind() { + if (NotUnderValgrind) + return false; + return RUNNING_ON_VALGRIND; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { + if (NotUnderValgrind) + return; + + VALGRIND_DISCARD_TRANSLATIONS(Addr, Len); +} + +#else // !HAVE_VALGRIND_VALGRIND_H + +bool llvm::sys::RunningOnValgrind() { + return false; +} + +void llvm::sys::ValgrindDiscardTranslations(const void *Addr, size_t Len) { +} + +#endif // !HAVE_VALGRIND_VALGRIND_H diff --git a/lib/Support/Windows/Alarm.inc b/lib/Support/Windows/Alarm.inc new file mode 100644 index 0000000..e0d00a0 --- /dev/null +++ b/lib/Support/Windows/Alarm.inc @@ -0,0 +1,43 @@ +//===-- Alarm.inc - Implement Win32 Alarm Support ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 Alarm support. +// +//===----------------------------------------------------------------------===// + +#include <cassert> +using namespace llvm; + +/// NestedSOI - Sanity check. Alarms cannot be nested or run in parallel. +/// This ensures that they never do. +static bool NestedSOI = false; + +void sys::SetupAlarm(unsigned seconds) { + assert(!NestedSOI && "sys::SetupAlarm calls cannot be nested!"); + NestedSOI = true; + // FIXME: Implement for Win32 +} + +void sys::TerminateAlarm() { + assert(NestedSOI && "sys::TerminateAlarm called without sys::SetupAlarm!"); + // FIXME: Implement for Win32 + NestedSOI = false; +} + +int sys::AlarmStatus() { + // FIXME: Implement for Win32 + return 0; +} + +// Don't pull in all of the Windows headers. +extern "C" void __stdcall Sleep(unsigned long); + +void sys::Sleep(unsigned n) { + ::Sleep(n*1000); +} diff --git a/lib/Support/Windows/DynamicLibrary.inc b/lib/Support/Windows/DynamicLibrary.inc new file mode 100644 index 0000000..5fad37a --- /dev/null +++ b/lib/Support/Windows/DynamicLibrary.inc @@ -0,0 +1,199 @@ +//===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of DynamicLibrary. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" + +#ifdef __MINGW32__ + #include <imagehlp.h> +#else + #include <dbghelp.h> +#endif + +#ifdef _MSC_VER + #include <ntverp.h> +#endif + +#ifdef __MINGW32__ + #if (HAVE_LIBIMAGEHLP != 1) + #error "libimagehlp.a should be present" + #endif +#else + #pragma comment(lib, "dbghelp.lib") +#endif + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code. +//===----------------------------------------------------------------------===// + +static std::vector<HMODULE> OpenedHandles; + +#ifdef _WIN64 + typedef DWORD64 ModuleBaseType; +#else + typedef ULONG ModuleBaseType; +#endif + +extern "C" { +// Use old callback if: +// - Not using Visual Studio +// - Visual Studio 2005 or earlier but only if we are not using the Windows SDK +// or Windows SDK version is older than 6.0 +// Use new callback if: +// - Newer Visual Studio (comes with newer SDK). +// - Visual Studio 2005 with Windows SDK 6.0+ +#if !defined(_MSC_VER) || _MSC_VER < 1500 && (!defined(VER_PRODUCTBUILD) || VER_PRODUCTBUILD < 6000) + static BOOL CALLBACK ELM_Callback(PSTR ModuleName, + ModuleBaseType ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +#else + static BOOL CALLBACK ELM_Callback(PCSTR ModuleName, + ModuleBaseType ModuleBase, + ULONG ModuleSize, + PVOID UserContext) +#endif + { + // Ignore VC++ runtimes prior to 7.1. Somehow some of them get loaded + // into the process. + if (stricmp(ModuleName, "msvci70") != 0 && + stricmp(ModuleName, "msvcirt") != 0 && + stricmp(ModuleName, "msvcp50") != 0 && + stricmp(ModuleName, "msvcp60") != 0 && + stricmp(ModuleName, "msvcp70") != 0 && + stricmp(ModuleName, "msvcr70") != 0 && +#ifndef __MINGW32__ + // Mingw32 uses msvcrt.dll by default. Don't ignore it. + // Otherwise, user should be aware, what he's doing :) + stricmp(ModuleName, "msvcrt") != 0 && +#endif + stricmp(ModuleName, "msvcrt20") != 0 && + stricmp(ModuleName, "msvcrt40") != 0) { + OpenedHandles.push_back((HMODULE)ModuleBase); + } + return TRUE; + } +} + +bool DynamicLibrary::LoadLibraryPermanently(const char *filename, + std::string *ErrMsg) { + if (filename) { + HMODULE a_handle = LoadLibrary(filename); + + if (a_handle == 0) + return MakeErrMsg(ErrMsg, std::string(filename) + ": Can't open : "); + + OpenedHandles.push_back(a_handle); + } else { + // When no file is specified, enumerate all DLLs and EXEs in the + // process. + EnumerateLoadedModules(GetCurrentProcess(), ELM_Callback, 0); + } + + // Because we don't remember the handle, we will never free it; hence, + // it is loaded permanently. + return false; +} + +// Stack probing routines are in the support library (e.g. libgcc), but we don't +// have dynamic linking on windows. Provide a hook. +#if defined(__MINGW32__) || defined (_MSC_VER) + #define EXPLICIT_SYMBOL(SYM) \ + if (!strcmp(symbolName, #SYM)) return (void*)&SYM + #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) \ + if (!strcmp(symbolName, #SYMFROM)) return (void*)&SYMTO + #define EXPLICIT_SYMBOL_DEF(SYM) \ + extern "C" { extern void *SYM; } + + #if defined(__MINGW32__) + EXPLICIT_SYMBOL_DEF(_alloca) + EXPLICIT_SYMBOL_DEF(__main) + EXPLICIT_SYMBOL_DEF(__ashldi3) + EXPLICIT_SYMBOL_DEF(__ashrdi3) + EXPLICIT_SYMBOL_DEF(__cmpdi2) + EXPLICIT_SYMBOL_DEF(__divdi3) + EXPLICIT_SYMBOL_DEF(__fixdfdi) + EXPLICIT_SYMBOL_DEF(__fixsfdi) + EXPLICIT_SYMBOL_DEF(__fixunsdfdi) + EXPLICIT_SYMBOL_DEF(__fixunssfdi) + EXPLICIT_SYMBOL_DEF(__floatdidf) + EXPLICIT_SYMBOL_DEF(__floatdisf) + EXPLICIT_SYMBOL_DEF(__lshrdi3) + EXPLICIT_SYMBOL_DEF(__moddi3) + EXPLICIT_SYMBOL_DEF(__udivdi3) + EXPLICIT_SYMBOL_DEF(__umoddi3) + #elif defined(_MSC_VER) + EXPLICIT_SYMBOL_DEF(_alloca_probe) + #endif +#endif + +void* DynamicLibrary::SearchForAddressOfSymbol(const char* symbolName) { + // First check symbols added via AddSymbol(). + if (ExplicitSymbols) { + std::map<std::string, void *>::iterator I = + ExplicitSymbols->find(symbolName); + std::map<std::string, void *>::iterator E = ExplicitSymbols->end(); + if (I != E) + return I->second; + } + + // Now search the libraries. + for (std::vector<HMODULE>::iterator I = OpenedHandles.begin(), + E = OpenedHandles.end(); I != E; ++I) { + FARPROC ptr = GetProcAddress((HMODULE)*I, symbolName); + if (ptr) { + return (void *) ptr; + } + } + +#if defined(__MINGW32__) + { + EXPLICIT_SYMBOL(_alloca); + EXPLICIT_SYMBOL(__main); + EXPLICIT_SYMBOL(__ashldi3); + EXPLICIT_SYMBOL(__ashrdi3); + EXPLICIT_SYMBOL(__cmpdi2); + EXPLICIT_SYMBOL(__divdi3); + EXPLICIT_SYMBOL(__fixdfdi); + EXPLICIT_SYMBOL(__fixsfdi); + EXPLICIT_SYMBOL(__fixunsdfdi); + EXPLICIT_SYMBOL(__fixunssfdi); + EXPLICIT_SYMBOL(__floatdidf); + EXPLICIT_SYMBOL(__floatdisf); + EXPLICIT_SYMBOL(__lshrdi3); + EXPLICIT_SYMBOL(__moddi3); + EXPLICIT_SYMBOL(__udivdi3); + EXPLICIT_SYMBOL(__umoddi3); + + EXPLICIT_SYMBOL2(alloca, _alloca); +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 +#undef EXPLICIT_SYMBOL_DEF + } +#elif defined(_MSC_VER) + { + EXPLICIT_SYMBOL2(alloca, _alloca_probe); + EXPLICIT_SYMBOL2(_alloca, _alloca_probe); +#undef EXPLICIT_SYMBOL +#undef EXPLICIT_SYMBOL2 +#undef EXPLICIT_SYMBOL_DEF + } +#endif + + return 0; +} + +} diff --git a/lib/Support/Windows/Host.inc b/lib/Support/Windows/Host.inc new file mode 100644 index 0000000..5377c77 --- /dev/null +++ b/lib/Support/Windows/Host.inc @@ -0,0 +1,23 @@ +//===- llvm/System/Win32/Host.inc -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 Host support. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <cstdio> +#include <string> + +using namespace llvm; + +std::string sys::getHostTriple() { + // FIXME: Adapt to running version. + return LLVM_HOSTTRIPLE; +} diff --git a/lib/Support/Windows/Memory.inc b/lib/Support/Windows/Memory.inc new file mode 100644 index 0000000..9f69e73 --- /dev/null +++ b/lib/Support/Windows/Memory.inc @@ -0,0 +1,73 @@ +//===- Win32/Memory.cpp - Win32 Memory Implementation -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of various Memory +// management utilities +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Process.h" + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +MemoryBlock Memory::AllocateRWX(size_t NumBytes, + const MemoryBlock *NearBlock, + std::string *ErrMsg) { + if (NumBytes == 0) return MemoryBlock(); + + static const size_t pageSize = Process::GetPageSize(); + size_t NumPages = (NumBytes+pageSize-1)/pageSize; + + //FIXME: support NearBlock if ever needed on Win64. + + void *pa = VirtualAlloc(NULL, NumPages*pageSize, MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (pa == NULL) { + MakeErrMsg(ErrMsg, "Can't allocate RWX Memory: "); + return MemoryBlock(); + } + + MemoryBlock result; + result.Address = pa; + result.Size = NumPages*pageSize; + return result; +} + +bool Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { + if (M.Address == 0 || M.Size == 0) return false; + if (!VirtualFree(M.Address, 0, MEM_RELEASE)) + return MakeErrMsg(ErrMsg, "Can't release RWX Memory: "); + return false; +} + +bool Memory::setWritable(MemoryBlock &M, std::string *ErrMsg) { + return true; +} + +bool Memory::setExecutable(MemoryBlock &M, std::string *ErrMsg) { + return false; +} + +bool Memory::setRangeWritable(const void *Addr, size_t Size) { + return true; +} + +bool Memory::setRangeExecutable(const void *Addr, size_t Size) { + return false; +} + +} diff --git a/lib/Support/Windows/Mutex.inc b/lib/Support/Windows/Mutex.inc new file mode 100644 index 0000000..ff7d642 --- /dev/null +++ b/lib/Support/Windows/Mutex.inc @@ -0,0 +1,58 @@ +//===- llvm/System/Win32/Mutex.inc - Win32 Mutex Implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) Mutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/Mutex.h" + +namespace llvm { +using namespace sys; + +MutexImpl::MutexImpl(bool /*recursive*/) +{ + data_ = new CRITICAL_SECTION; + InitializeCriticalSection((LPCRITICAL_SECTION)data_); +} + +MutexImpl::~MutexImpl() +{ + DeleteCriticalSection((LPCRITICAL_SECTION)data_); + delete (LPCRITICAL_SECTION)data_; + data_ = 0; +} + +bool +MutexImpl::acquire() +{ + EnterCriticalSection((LPCRITICAL_SECTION)data_); + return true; +} + +bool +MutexImpl::release() +{ + LeaveCriticalSection((LPCRITICAL_SECTION)data_); + return true; +} + +bool +MutexImpl::tryacquire() +{ + return TryEnterCriticalSection((LPCRITICAL_SECTION)data_); +} + +} diff --git a/lib/Support/Windows/Path.inc b/lib/Support/Windows/Path.inc new file mode 100644 index 0000000..e517eec --- /dev/null +++ b/lib/Support/Windows/Path.inc @@ -0,0 +1,918 @@ +//===- llvm/System/Win32/Path.cpp - Win32 Path Implementation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Path class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <malloc.h> +#include <cstdio> + +// We need to undo a macro defined in Windows.h, otherwise we won't compile: +#undef CopyFile +#undef GetCurrentDirectory + +// Windows happily accepts either forward or backward slashes, though any path +// returned by a Win32 API will have backward slashes. As LLVM code basically +// assumes forward slashes are used, backward slashs are converted where they +// can be introduced into a path. +// +// Another invariant is that a path ends with a slash if and only if the path +// is a root directory. Any other use of a trailing slash is stripped. Unlike +// in Unix, Windows has a rather complicated notion of a root path and this +// invariant helps simply the code. + +static void FlipBackSlashes(std::string& s) { + for (size_t i = 0; i < s.size(); i++) + if (s[i] == '\\') + s[i] = '/'; +} + +namespace llvm { +namespace sys { + +const char PathSeparator = ';'; + +StringRef Path::GetEXESuffix() { + return "exe"; +} + +Path::Path(llvm::StringRef p) + : path(p) { + FlipBackSlashes(path); +} + +Path::Path(const char *StrStart, unsigned StrLen) + : path(StrStart, StrLen) { + FlipBackSlashes(path); +} + +Path& +Path::operator=(StringRef that) { + path.assign(that.data(), that.size()); + FlipBackSlashes(path); + return *this; +} + +// push_back 0 on create, and pop_back on delete. +struct ScopedNullTerminator { + std::string &str; + ScopedNullTerminator(std::string &s) : str(s) { str.push_back(0); } + ~ScopedNullTerminator() { + // str.pop_back(); But wait, C++03 doesn't have this... + assert(!str.empty() && str[str.size() - 1] == 0 + && "Null char not present!"); + str.resize(str.size() - 1); + } +}; + +bool +Path::isValid() const { + if (path.empty()) + return false; + + // If there is a colon, it must be the second character, preceded by a letter + // and followed by something. + size_t len = path.size(); + // This code assumes that path is null terminated, so make sure it is. + ScopedNullTerminator snt(path); + size_t pos = path.rfind(':',len); + size_t rootslash = 0; + if (pos != std::string::npos) { + if (pos != 1 || !isalpha(path[0]) || len < 3) + return false; + rootslash = 2; + } + + // Look for a UNC path, and if found adjust our notion of the root slash. + if (len > 3 && path[0] == '/' && path[1] == '/') { + rootslash = path.find('/', 2); + if (rootslash == std::string::npos) + rootslash = 0; + } + + // Check for illegal characters. + if (path.find_first_of("\\<>\"|\001\002\003\004\005\006\007\010\011\012" + "\013\014\015\016\017\020\021\022\023\024\025\026" + "\027\030\031\032\033\034\035\036\037") + != std::string::npos) + return false; + + // Remove trailing slash, unless it's a root slash. + if (len > rootslash+1 && path[len-1] == '/') + path.erase(--len); + + // Check each component for legality. + for (pos = 0; pos < len; ++pos) { + // A component may not end in a space. + if (path[pos] == ' ') { + if (path[pos+1] == '/' || path[pos+1] == '\0') + return false; + } + + // A component may not end in a period. + if (path[pos] == '.') { + if (path[pos+1] == '/' || path[pos+1] == '\0') { + // Unless it is the pseudo-directory "."... + if (pos == 0 || path[pos-1] == '/' || path[pos-1] == ':') + return true; + // or "..". + if (pos > 0 && path[pos-1] == '.') { + if (pos == 1 || path[pos-2] == '/' || path[pos-2] == ':') + return true; + } + return false; + } + } + } + + return true; +} + +void Path::makeAbsolute() { + TCHAR FullPath[MAX_PATH + 1] = {0}; + LPTSTR FilePart = NULL; + + DWORD RetLength = ::GetFullPathNameA(path.c_str(), + sizeof(FullPath)/sizeof(FullPath[0]), + FullPath, &FilePart); + + if (0 == RetLength) { + // FIXME: Report the error GetLastError() + assert(0 && "Unable to make absolute path!"); + } else if (RetLength > MAX_PATH) { + // FIXME: Report too small buffer (needed RetLength bytes). + assert(0 && "Unable to make absolute path!"); + } else { + path = FullPath; + } +} + +bool +Path::isAbsolute(const char *NameStart, unsigned NameLen) { + assert(NameStart); + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. + switch (NameLen) { + case 0: + return false; + case 1: + case 2: + return NameStart[0] == '/'; + default: + return + (NameStart[0] == '/' || (NameStart[1] == ':' && NameStart[2] == '/')) || + (NameStart[0] == '\\' || (NameStart[1] == ':' && NameStart[2] == '\\')); + } +} + +bool +Path::isAbsolute() const { + // FIXME: This does not handle correctly an absolute path starting from + // a drive letter or in UNC format. + switch (path.length()) { + case 0: + return false; + case 1: + case 2: + return path[0] == '/'; + default: + return path[0] == '/' || (path[1] == ':' && path[2] == '/'); + } +} + +static Path *TempDirectory; + +Path +Path::GetTemporaryDirectory(std::string* ErrMsg) { + if (TempDirectory) + return *TempDirectory; + + char pathname[MAX_PATH]; + if (!GetTempPath(MAX_PATH, pathname)) { + if (ErrMsg) + *ErrMsg = "Can't determine temporary directory"; + return Path(); + } + + Path result; + result.set(pathname); + + // Append a subdirectory passed on our process id so multiple LLVMs don't + // step on each other's toes. +#ifdef __MINGW32__ + // Mingw's Win32 header files are broken. + sprintf(pathname, "LLVM_%u", unsigned(GetCurrentProcessId())); +#else + sprintf(pathname, "LLVM_%u", GetCurrentProcessId()); +#endif + result.appendComponent(pathname); + + // If there's a directory left over from a previous LLVM execution that + // happened to have the same process id, get rid of it. + result.eraseFromDisk(true); + + // And finally (re-)create the empty directory. + result.createDirectoryOnDisk(false); + TempDirectory = new Path(result); + return *TempDirectory; +} + +// FIXME: the following set of functions don't map to Windows very well. +Path +Path::GetRootDirectory() { + // This is the only notion that that Windows has of a root directory. Nothing + // is here except for drives. + return Path("file:///"); +} + +void +Path::GetSystemLibraryPaths(std::vector<sys::Path>& Paths) { + char buff[MAX_PATH]; + // Generic form of C:\Windows\System32 + HRESULT res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_SYSTEM, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) { + assert(0 && "Failed to get system directory"); + return; + } + Paths.push_back(sys::Path(buff)); + + // Reset buff. + buff[0] = 0; + // Generic form of C:\Windows + res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_WINDOWS, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) { + assert(0 && "Failed to get windows directory"); + return; + } + Paths.push_back(sys::Path(buff)); +} + +void +Path::GetBitcodeLibraryPaths(std::vector<sys::Path>& Paths) { + char * env_var = getenv("LLVM_LIB_SEARCH_PATH"); + if (env_var != 0) { + getPathList(env_var,Paths); + } +#ifdef LLVM_LIBDIR + { + Path tmpPath; + if (tmpPath.set(LLVM_LIBDIR)) + if (tmpPath.canRead()) + Paths.push_back(tmpPath); + } +#endif + GetSystemLibraryPaths(Paths); +} + +Path +Path::GetLLVMDefaultConfigDir() { + Path ret = GetUserHomeDirectory(); + if (!ret.appendComponent(".llvm")) + assert(0 && "Failed to append .llvm"); + return ret; +} + +Path +Path::GetUserHomeDirectory() { + char buff[MAX_PATH]; + HRESULT res = SHGetFolderPathA(NULL, + CSIDL_FLAG_CREATE | CSIDL_APPDATA, + NULL, + SHGFP_TYPE_CURRENT, + buff); + if (res != S_OK) + assert(0 && "Failed to get user home directory"); + return Path(buff); +} + +Path +Path::GetCurrentDirectory() { + char pathname[MAX_PATH]; + ::GetCurrentDirectoryA(MAX_PATH,pathname); + return Path(pathname); +} + +/// GetMainExecutable - Return the path to the main executable, given the +/// value of argv[0] from program startup. +Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { + char pathname[MAX_PATH]; + DWORD ret = ::GetModuleFileNameA(NULL, pathname, MAX_PATH); + return ret != MAX_PATH ? Path(pathname) : Path(); +} + + +// FIXME: the above set of functions don't map to Windows very well. + + +StringRef Path::getDirname() const { + return getDirnameCharSep(path, "/"); +} + +StringRef +Path::getBasename() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(path).substr(slash); + else + return StringRef(path).substr(slash, dot - slash); +} + +StringRef +Path::getSuffix() const { + // Find the last slash + size_t slash = path.rfind('/'); + if (slash == std::string::npos) + slash = 0; + else + slash++; + + size_t dot = path.rfind('.'); + if (dot == std::string::npos || dot < slash) + return StringRef(""); + else + return StringRef(path).substr(dot + 1); +} + +bool +Path::exists() const { + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::isDirectory() const { + DWORD attr = GetFileAttributes(path.c_str()); + return (attr != INVALID_FILE_ATTRIBUTES) && + (attr & FILE_ATTRIBUTE_DIRECTORY); +} + +bool +Path::isSymLink() const { + DWORD attributes = GetFileAttributes(path.c_str()); + + if (attributes == INVALID_FILE_ATTRIBUTES) + // There's no sane way to report this :(. + assert(0 && "GetFileAttributes returned INVALID_FILE_ATTRIBUTES"); + + // This isn't exactly what defines a NTFS symlink, but it is only true for + // paths that act like a symlink. + return attributes & FILE_ATTRIBUTE_REPARSE_POINT; +} + +bool +Path::canRead() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::canWrite() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return (attr != INVALID_FILE_ATTRIBUTES) && !(attr & FILE_ATTRIBUTE_READONLY); +} + +bool +Path::canExecute() const { + // FIXME: take security attributes into account. + DWORD attr = GetFileAttributes(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES; +} + +bool +Path::isRegularFile() const { + if (isDirectory()) + return false; + return true; +} + +StringRef +Path::getLast() const { + // Find the last slash + size_t pos = path.rfind('/'); + + // Handle the corner cases + if (pos == std::string::npos) + return path; + + // If the last character is a slash, we have a root directory + if (pos == path.length()-1) + return path; + + // Return everything after the last slash + return StringRef(path).substr(pos+1); +} + +const FileStatus * +PathWithStatus::getFileStatus(bool update, std::string *ErrStr) const { + if (!fsIsValid || update) { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { + MakeErrMsg(ErrStr, "getStatusInfo():" + std::string(path) + + ": Can't get status: "); + return 0; + } + + status.fileSize = fi.nFileSizeHigh; + status.fileSize <<= sizeof(fi.nFileSizeHigh)*8; + status.fileSize += fi.nFileSizeLow; + + status.mode = fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY ? 0555 : 0777; + status.user = 9999; // Not applicable to Windows, so... + status.group = 9999; // Not applicable to Windows, so... + + // FIXME: this is only unique if the file is accessed by the same file path. + // How do we do this for C:\dir\file and ..\dir\file ? Unix has inode + // numbers, but the concept doesn't exist in Windows. + status.uniqueID = 0; + for (unsigned i = 0; i < path.length(); ++i) + status.uniqueID += path[i]; + + ULARGE_INTEGER ui; + ui.LowPart = fi.ftLastWriteTime.dwLowDateTime; + ui.HighPart = fi.ftLastWriteTime.dwHighDateTime; + status.modTime.fromWin32Time(ui.QuadPart); + + status.isDir = fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; + fsIsValid = true; + } + return &status; +} + +bool Path::makeReadableOnDisk(std::string* ErrMsg) { + // All files are readable on Windows (ignoring security attributes). + return false; +} + +bool Path::makeWriteableOnDisk(std::string* ErrMsg) { + DWORD attr = GetFileAttributes(path.c_str()); + + // If it doesn't exist, we're done. + if (attr == INVALID_FILE_ATTRIBUTES) + return false; + + if (attr & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), attr & ~FILE_ATTRIBUTE_READONLY)) { + MakeErrMsg(ErrMsg, std::string(path) + ": Can't make file writable: "); + return true; + } + } + return false; +} + +bool Path::makeExecutableOnDisk(std::string* ErrMsg) { + // All files are executable on Windows (ignoring security attributes). + return false; +} + +bool +Path::getDirectoryContents(std::set<Path>& result, std::string* ErrMsg) const { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { + MakeErrMsg(ErrMsg, path + ": can't get status of file"); + return true; + } + + if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + if (ErrMsg) + *ErrMsg = path + ": not a directory"; + return true; + } + + result.clear(); + WIN32_FIND_DATA fd; + std::string searchpath = path; + if (path.size() == 0 || searchpath[path.size()-1] == '/') + searchpath += "*"; + else + searchpath += "/*"; + + HANDLE h = FindFirstFile(searchpath.c_str(), &fd); + if (h == INVALID_HANDLE_VALUE) { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + return true; // not really an error, now is it? + MakeErrMsg(ErrMsg, path + ": Can't read directory: "); + return true; + } + + do { + if (fd.cFileName[0] == '.') + continue; + Path aPath(path); + aPath.appendComponent(&fd.cFileName[0]); + result.insert(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + MakeErrMsg(ErrMsg, path + ": Can't read directory: "); + return true; + } + return false; +} + +bool +Path::set(StringRef a_path) { + if (a_path.empty()) + return false; + std::string save(path); + path = a_path; + FlipBackSlashes(path); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::appendComponent(StringRef name) { + if (name.empty()) + return false; + std::string save(path); + if (!path.empty()) { + size_t last = path.size() - 1; + if (path[last] != '/') + path += '/'; + } + path += name; + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseComponent() { + size_t slashpos = path.rfind('/',path.size()); + if (slashpos == path.size() - 1 || slashpos == std::string::npos) + return false; + std::string save(path); + path.erase(slashpos); + if (!isValid()) { + path = save; + return false; + } + return true; +} + +bool +Path::eraseSuffix() { + size_t dotpos = path.rfind('.',path.size()); + size_t slashpos = path.rfind('/',path.size()); + if (dotpos != std::string::npos) { + if (slashpos == std::string::npos || dotpos > slashpos+1) { + std::string save(path); + path.erase(dotpos, path.size()-dotpos); + if (!isValid()) { + path = save; + return false; + } + return true; + } + } + return false; +} + +inline bool PathMsg(std::string* ErrMsg, const char* pathname, const char*msg) { + if (ErrMsg) + *ErrMsg = std::string(pathname) + ": " + std::string(msg); + return true; +} + +bool +Path::createDirectoryOnDisk(bool create_parents, std::string* ErrMsg) { + // Get a writeable copy of the path name + size_t len = path.length(); + char *pathname = reinterpret_cast<char *>(_alloca(len+2)); + path.copy(pathname, len); + pathname[len] = 0; + + // Make sure it ends with a slash. + if (len == 0 || pathname[len - 1] != '/') { + pathname[len] = '/'; + pathname[++len] = 0; + } + + // Determine starting point for initial / search. + char *next = pathname; + if (pathname[0] == '/' && pathname[1] == '/') { + // Skip host name. + next = strchr(pathname+2, '/'); + if (next == NULL) + return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + + // Skip share name. + next = strchr(next+1, '/'); + if (next == NULL) + return PathMsg(ErrMsg, pathname,"badly formed remote directory"); + + next++; + if (*next == 0) + return PathMsg(ErrMsg, pathname, "badly formed remote directory"); + + } else { + if (pathname[1] == ':') + next += 2; // skip drive letter + if (*next == '/') + next++; // skip root directory + } + + // If we're supposed to create intermediate directories + if (create_parents) { + // Loop through the directory components until we're done + while (*next) { + next = strchr(next, '/'); + *next = 0; + if (!CreateDirectory(pathname, NULL) && + GetLastError() != ERROR_ALREADY_EXISTS) + return MakeErrMsg(ErrMsg, + std::string(pathname) + ": Can't create directory: "); + *next++ = '/'; + } + } else { + // Drop trailing slash. + pathname[len-1] = 0; + if (!CreateDirectory(pathname, NULL) && + GetLastError() != ERROR_ALREADY_EXISTS) { + return MakeErrMsg(ErrMsg, std::string(pathname) + + ": Can't create directory: "); + } + } + return false; +} + +bool +Path::createFileOnDisk(std::string* ErrMsg) { + // Create the file + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return MakeErrMsg(ErrMsg, path + ": Can't create file: "); + + CloseHandle(h); + return false; +} + +bool +Path::eraseFromDisk(bool remove_contents, std::string *ErrStr) const { + WIN32_FILE_ATTRIBUTE_DATA fi; + if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) + return true; + + if (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + // If it doesn't exist, we're done. + if (!exists()) + return false; + + char *pathname = reinterpret_cast<char *>(_alloca(path.length()+3)); + int lastchar = path.length() - 1 ; + path.copy(pathname, lastchar+1); + + // Make path end with '/*'. + if (pathname[lastchar] != '/') + pathname[++lastchar] = '/'; + pathname[lastchar+1] = '*'; + pathname[lastchar+2] = 0; + + if (remove_contents) { + WIN32_FIND_DATA fd; + HANDLE h = FindFirstFile(pathname, &fd); + + // It's a bad idea to alter the contents of a directory while enumerating + // its contents. So build a list of its contents first, then destroy them. + + if (h != INVALID_HANDLE_VALUE) { + std::vector<Path> list; + + do { + if (strcmp(fd.cFileName, ".") == 0) + continue; + if (strcmp(fd.cFileName, "..") == 0) + continue; + + Path aPath(path); + aPath.appendComponent(&fd.cFileName[0]); + list.push_back(aPath); + } while (FindNextFile(h, &fd)); + + DWORD err = GetLastError(); + FindClose(h); + if (err != ERROR_NO_MORE_FILES) { + SetLastError(err); + return MakeErrMsg(ErrStr, path + ": Can't read directory: "); + } + + for (std::vector<Path>::iterator I = list.begin(); I != list.end(); + ++I) { + Path &aPath = *I; + aPath.eraseFromDisk(true); + } + } else { + if (GetLastError() != ERROR_FILE_NOT_FOUND) + return MakeErrMsg(ErrStr, path + ": Can't read directory: "); + } + } + + pathname[lastchar] = 0; + if (!RemoveDirectory(pathname)) + return MakeErrMsg(ErrStr, + std::string(pathname) + ": Can't destroy directory: "); + return false; + } else { + // Read-only files cannot be deleted on Windows. Must remove the read-only + // attribute first. + if (fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), + fi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); + } + + if (!DeleteFile(path.c_str())) + return MakeErrMsg(ErrStr, path + ": Can't destroy file: "); + return false; + } +} + +bool Path::getMagicNumber(std::string& Magic, unsigned len) const { + assert(len < 1024 && "Request for magic string too long"); + char* buf = reinterpret_cast<char*>(alloca(len)); + + HANDLE h = CreateFile(path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) + return false; + + DWORD nRead = 0; + BOOL ret = ReadFile(h, buf, len, &nRead, NULL); + CloseHandle(h); + + if (!ret || nRead != len) + return false; + + Magic = std::string(buf, len); + return true; +} + +bool +Path::renamePathOnDisk(const Path& newName, std::string* ErrMsg) { + if (!MoveFileEx(path.c_str(), newName.c_str(), MOVEFILE_REPLACE_EXISTING)) + return MakeErrMsg(ErrMsg, "Can't move '" + path + "' to '" + newName.path + + "': "); + return false; +} + +bool +Path::setStatusInfoOnDisk(const FileStatus &si, std::string *ErrMsg) const { + // FIXME: should work on directories also. + if (!si.isFile) { + return true; + } + + HANDLE h = CreateFile(path.c_str(), + FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (h == INVALID_HANDLE_VALUE) + return true; + + BY_HANDLE_FILE_INFORMATION bhfi; + if (!GetFileInformationByHandle(h, &bhfi)) { + DWORD err = GetLastError(); + CloseHandle(h); + SetLastError(err); + return MakeErrMsg(ErrMsg, path + ": GetFileInformationByHandle: "); + } + + ULARGE_INTEGER ui; + ui.QuadPart = si.modTime.toWin32Time(); + FILETIME ft; + ft.dwLowDateTime = ui.LowPart; + ft.dwHighDateTime = ui.HighPart; + BOOL ret = SetFileTime(h, NULL, &ft, &ft); + DWORD err = GetLastError(); + CloseHandle(h); + if (!ret) { + SetLastError(err); + return MakeErrMsg(ErrMsg, path + ": SetFileTime: "); + } + + // Best we can do with Unix permission bits is to interpret the owner + // writable bit. + if (si.mode & 0200) { + if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + if (!SetFileAttributes(path.c_str(), + bhfi.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); + } + } else { + if (!(bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) { + if (!SetFileAttributes(path.c_str(), + bhfi.dwFileAttributes | FILE_ATTRIBUTE_READONLY)) + return MakeErrMsg(ErrMsg, path + ": SetFileAttributes: "); + } + } + + return false; +} + +bool +CopyFile(const sys::Path &Dest, const sys::Path &Src, std::string* ErrMsg) { + // Can't use CopyFile macro defined in Windows.h because it would mess up the + // above line. We use the expansion it would have in a non-UNICODE build. + if (!::CopyFileA(Src.c_str(), Dest.c_str(), false)) + return MakeErrMsg(ErrMsg, "Can't copy '" + Src.str() + + "' to '" + Dest.str() + "': "); + return false; +} + +bool +Path::makeUnique(bool reuse_current, std::string* ErrMsg) { + if (reuse_current && !exists()) + return false; // File doesn't exist already, just use it! + + // Reserve space for -XXXXXX at the end. + char *FNBuffer = (char*) alloca(path.size()+8); + unsigned offset = path.size(); + path.copy(FNBuffer, offset); + + // Find a numeric suffix that isn't used by an existing file. Assume there + // won't be more than 1 million files with the same prefix. Probably a safe + // bet. + static unsigned FCounter = 0; + do { + sprintf(FNBuffer+offset, "-%06u", FCounter); + if (++FCounter > 999999) + FCounter = 0; + path = FNBuffer; + } while (exists()); + return false; +} + +bool +Path::createTemporaryFileOnDisk(bool reuse_current, std::string* ErrMsg) { + // Make this into a unique file name + makeUnique(reuse_current, ErrMsg); + + // Now go and create it + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) + return MakeErrMsg(ErrMsg, path + ": can't create file"); + + CloseHandle(h); + return false; +} + +/// MapInFilePages - Not yet implemented on win32. +const char *Path::MapInFilePages(int FD, uint64_t FileSize) { + return 0; +} + +/// MapInFilePages - Not yet implemented on win32. +void Path::UnMapFilePages(const char *Base, uint64_t FileSize) { + assert(0 && "NOT IMPLEMENTED"); +} + +} +} diff --git a/lib/Support/Windows/Process.inc b/lib/Support/Windows/Process.inc new file mode 100644 index 0000000..06a7f00 --- /dev/null +++ b/lib/Support/Windows/Process.inc @@ -0,0 +1,222 @@ +//===- Win32/Process.cpp - Win32 Process Implementation ------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Process class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <psapi.h> +#include <malloc.h> +#include <io.h> + +#ifdef __MINGW32__ + #if (HAVE_LIBPSAPI != 1) + #error "libpsapi.a should be present" + #endif +#else + #pragma comment(lib, "psapi.lib") +#endif + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef __MINGW32__ +// This ban should be lifted when MinGW 1.0+ has defined this value. +# define _HEAPOK (-2) +#endif + +namespace llvm { +using namespace sys; + +// This function retrieves the page size using GetSystemInfo and is present +// solely so it can be called once in Process::GetPageSize to initialize the +// static variable PageSize. +inline unsigned GetPageSizeOnce() { + // NOTE: A 32-bit application running under WOW64 is supposed to use + // GetNativeSystemInfo. However, this interface is not present prior + // to Windows XP so to use it requires dynamic linking. It is not clear + // how this affects the reported page size, if at all. One could argue + // that LLVM ought to run as 64-bits on a 64-bit system, anyway. + SYSTEM_INFO info; + GetSystemInfo(&info); + return static_cast<unsigned>(info.dwPageSize); +} + +unsigned +Process::GetPageSize() { + static const unsigned PageSize = GetPageSizeOnce(); + return PageSize; +} + +size_t +Process::GetMallocUsage() +{ + _HEAPINFO hinfo; + hinfo._pentry = NULL; + + size_t size = 0; + + while (_heapwalk(&hinfo) == _HEAPOK) + size += hinfo._size; + + return size; +} + +size_t +Process::GetTotalMemoryUsage() +{ + PROCESS_MEMORY_COUNTERS pmc; + GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + return pmc.PagefileUsage; +} + +void +Process::GetTimeUsage( + TimeValue& elapsed, TimeValue& user_time, TimeValue& sys_time) +{ + elapsed = TimeValue::now(); + + uint64_t ProcCreate, ProcExit, KernelTime, UserTime; + GetProcessTimes(GetCurrentProcess(), (FILETIME*)&ProcCreate, + (FILETIME*)&ProcExit, (FILETIME*)&KernelTime, + (FILETIME*)&UserTime); + + // FILETIME's are # of 100 nanosecond ticks (1/10th of a microsecond) + user_time.seconds( UserTime / 10000000 ); + user_time.nanoseconds( unsigned(UserTime % 10000000) * 100 ); + sys_time.seconds( KernelTime / 10000000 ); + sys_time.nanoseconds( unsigned(KernelTime % 10000000) * 100 ); +} + +int Process::GetCurrentUserId() +{ + return 65536; +} + +int Process::GetCurrentGroupId() +{ + return 65536; +} + +// Some LLVM programs such as bugpoint produce core files as a normal part of +// their operation. To prevent the disk from filling up, this configuration item +// does what's necessary to prevent their generation. +void Process::PreventCoreFiles() { + // Windows doesn't do core files, but it does do modal pop-up message + // boxes. As this method is used by bugpoint, preventing these pop-ups + // is the moral equivalent of suppressing core files. + SetErrorMode(SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); +} + +bool Process::StandardInIsUserInput() { + return FileDescriptorIsDisplayed(0); +} + +bool Process::StandardOutIsDisplayed() { + return FileDescriptorIsDisplayed(1); +} + +bool Process::StandardErrIsDisplayed() { + return FileDescriptorIsDisplayed(2); +} + +bool Process::FileDescriptorIsDisplayed(int fd) { + DWORD Mode; // Unused + return (GetConsoleMode((HANDLE)_get_osfhandle(fd), &Mode) != 0); +} + +unsigned Process::StandardOutColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +unsigned Process::StandardErrColumns() { + unsigned Columns = 0; + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_ERROR_HANDLE), &csbi)) + Columns = csbi.dwSize.X; + return Columns; +} + +// It always has colors. +bool Process::StandardErrHasColors() { + return StandardErrIsDisplayed(); +} + +bool Process::StandardOutHasColors() { + return StandardOutIsDisplayed(); +} + +namespace { +class DefaultColors +{ + private: + WORD defaultColor; + public: + DefaultColors() + :defaultColor(GetCurrentColor()) {} + static unsigned GetCurrentColor() { + CONSOLE_SCREEN_BUFFER_INFO csbi; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + return csbi.wAttributes; + return 0; + } + WORD operator()() const { return defaultColor; } +}; + +DefaultColors defaultColors; +} + +bool Process::ColorNeedsFlush() { + return true; +} + +const char *Process::OutputBold(bool bg) { + WORD colors = DefaultColors::GetCurrentColor(); + if (bg) + colors |= BACKGROUND_INTENSITY; + else + colors |= FOREGROUND_INTENSITY; + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::OutputColor(char code, bool bold, bool bg) { + WORD colors; + if (bg) { + colors = ((code&1) ? BACKGROUND_RED : 0) | + ((code&2) ? BACKGROUND_GREEN : 0 ) | + ((code&4) ? BACKGROUND_BLUE : 0); + if (bold) + colors |= BACKGROUND_INTENSITY; + } else { + colors = ((code&1) ? FOREGROUND_RED : 0) | + ((code&2) ? FOREGROUND_GREEN : 0 ) | + ((code&4) ? FOREGROUND_BLUE : 0); + if (bold) + colors |= FOREGROUND_INTENSITY; + } + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colors); + return 0; +} + +const char *Process::ResetColor() { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), defaultColors()); + return 0; +} + +} diff --git a/lib/Support/Windows/Program.inc b/lib/Support/Windows/Program.inc new file mode 100644 index 0000000..0b92c78 --- /dev/null +++ b/lib/Support/Windows/Program.inc @@ -0,0 +1,412 @@ +//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Program class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <cstdio> +#include <malloc.h> +#include <io.h> +#include <fcntl.h> + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef __MINGW32__ +// Ancient mingw32's w32api might not have this declaration. +extern "C" +BOOL WINAPI SetInformationJobObject(HANDLE hJob, + JOBOBJECTINFOCLASS JobObjectInfoClass, + LPVOID lpJobObjectInfo, + DWORD cbJobObjectInfoLength); +#endif + +namespace { + struct Win32ProcessInfo { + HANDLE hProcess; + DWORD dwProcessId; + }; +} + +namespace llvm { +using namespace sys; + +Program::Program() : Data_(0) {} + +Program::~Program() { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } +} + +unsigned Program::GetPid() const { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + return wpi->dwProcessId; +} + +// This function just uses the PATH environment variable to find the program. +Path +Program::FindProgramByName(const std::string& progName) { + + // Check some degenerate cases + if (progName.length() == 0) // no program + return Path(); + Path temp; + if (!temp.set(progName)) // invalid name + return Path(); + // Return paths with slashes verbatim. + if (progName.find('\\') != std::string::npos || + progName.find('/') != std::string::npos) + return temp; + + // At this point, the file name is valid and does not contain slashes. + // Let Windows search for it. + char buffer[MAX_PATH]; + char *dummy = NULL; + DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, + buffer, &dummy); + + // See if it wasn't found. + if (len == 0) + return Path(); + + // See if we got the entire path. + if (len < MAX_PATH) + return Path(buffer); + + // Buffer was too small; grow and retry. + while (true) { + char *b = reinterpret_cast<char *>(_alloca(len+1)); + DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); + + // It is unlikely the search failed, but it's always possible some file + // was added or removed since the last search, so be paranoid... + if (len2 == 0) + return Path(); + else if (len2 <= len) + return Path(b); + + len = len2; + } +} + +static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { + HANDLE h; + if (path == 0) { + DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), + GetCurrentProcess(), &h, + 0, TRUE, DUPLICATE_SAME_ACCESS); + return h; + } + + const char *fname; + if (path->isEmpty()) + fname = "NUL"; + else + fname = path->c_str(); + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = 0; + sa.bInheritHandle = TRUE; + + h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, + &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + + (fd ? "input: " : "output: ")); + } + + return h; +} + +/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess. +static bool ArgNeedsQuotes(const char *Str) { + return Str[0] == '\0' || strchr(Str, ' ') != 0; +} + + +/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling +/// CreateProcess and returns length of quoted arg with escaped quotes +static unsigned int ArgLenWithQuotes(const char *Str) { + unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; + + while (*Str != '\0') { + if (*Str == '\"') + ++len; + + ++len; + ++Str; + } + + return len; +} + + +bool +Program::Execute(const Path& path, + const char** args, + const char** envp, + const Path** redirects, + unsigned memoryLimit, + std::string* ErrMsg) { + if (Data_) { + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + CloseHandle(wpi->hProcess); + delete wpi; + Data_ = 0; + } + + if (!path.canExecute()) { + if (ErrMsg) + *ErrMsg = "program not executable"; + return false; + } + + // Windows wants a command line, not an array of args, to pass to the new + // process. We have to concatenate them all, while quoting the args that + // have embedded spaces (or are empty). + + // First, determine the length of the command line. + unsigned len = 0; + for (unsigned i = 0; args[i]; i++) { + len += ArgLenWithQuotes(args[i]) + 1; + } + + // Now build the command line. + char *command = reinterpret_cast<char *>(_alloca(len+1)); + char *p = command; + + for (unsigned i = 0; args[i]; i++) { + const char *arg = args[i]; + + bool needsQuoting = ArgNeedsQuotes(arg); + if (needsQuoting) + *p++ = '"'; + + while (*arg != '\0') { + if (*arg == '\"') + *p++ = '\\'; + + *p++ = *arg++; + } + + if (needsQuoting) + *p++ = '"'; + *p++ = ' '; + } + + *p = 0; + + // The pointer to the environment block for the new process. + char *envblock = 0; + + if (envp) { + // An environment block consists of a null-terminated block of + // null-terminated strings. Convert the array of environment variables to + // an environment block by concatenating them. + + // First, determine the length of the environment block. + len = 0; + for (unsigned i = 0; envp[i]; i++) + len += strlen(envp[i]) + 1; + + // Now build the environment block. + envblock = reinterpret_cast<char *>(_alloca(len+1)); + p = envblock; + + for (unsigned i = 0; envp[i]; i++) { + const char *ev = envp[i]; + size_t len = strlen(ev) + 1; + memcpy(p, ev, len); + p += len; + } + + *p = 0; + } + + // Create a child process. + STARTUPINFO si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.hStdInput = INVALID_HANDLE_VALUE; + si.hStdOutput = INVALID_HANDLE_VALUE; + si.hStdError = INVALID_HANDLE_VALUE; + + if (redirects) { + si.dwFlags = STARTF_USESTDHANDLES; + + si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); + if (si.hStdInput == INVALID_HANDLE_VALUE) { + MakeErrMsg(ErrMsg, "can't redirect stdin"); + return false; + } + si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); + if (si.hStdOutput == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + MakeErrMsg(ErrMsg, "can't redirect stdout"); + return false; + } + if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { + // If stdout and stderr should go to the same place, redirect stderr + // to the handle already open for stdout. + DuplicateHandle(GetCurrentProcess(), si.hStdOutput, + GetCurrentProcess(), &si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS); + } else { + // Just redirect stderr + si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); + if (si.hStdError == INVALID_HANDLE_VALUE) { + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + MakeErrMsg(ErrMsg, "can't redirect stderr"); + return false; + } + } + } + + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + + fflush(stdout); + fflush(stderr); + BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, + envblock, NULL, &si, &pi); + DWORD err = GetLastError(); + + // Regardless of whether the process got created or not, we are done with + // the handles we created for it to inherit. + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + // Now return an error if the process didn't get created. + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + + path.str() + "'"); + return false; + } + Win32ProcessInfo* wpi = new Win32ProcessInfo; + wpi->hProcess = pi.hProcess; + wpi->dwProcessId = pi.dwProcessId; + Data_ = wpi; + + // Make sure these get closed no matter what. + AutoHandle hThread(pi.hThread); + + // Assign the process to a job if a memory limit is defined. + AutoHandle hJob(0); + if (memoryLimit != 0) { + hJob = CreateJobObject(0, 0); + bool success = false; + if (hJob != 0) { + JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; + memset(&jeli, 0, sizeof(jeli)); + jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; + jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; + if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, + &jeli, sizeof(jeli))) { + if (AssignProcessToJobObject(hJob, pi.hProcess)) + success = true; + } + } + if (!success) { + SetLastError(GetLastError()); + MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); + TerminateProcess(pi.hProcess, 1); + WaitForSingleObject(pi.hProcess, INFINITE); + return false; + } + } + + return true; +} + +int +Program::Wait(const Path &path, + unsigned secondsToWait, + std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return -1; + } + + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + HANDLE hProcess = wpi->hProcess; + + // Wait for the process to terminate. + DWORD millisecondsToWait = INFINITE; + if (secondsToWait > 0) + millisecondsToWait = secondsToWait * 1000; + + if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { + if (!TerminateProcess(hProcess, 1)) { + MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); + return -1; + } + WaitForSingleObject(hProcess, INFINITE); + } + + // Get its exit status. + DWORD status; + BOOL rc = GetExitCodeProcess(hProcess, &status); + DWORD err = GetLastError(); + + if (!rc) { + SetLastError(err); + MakeErrMsg(ErrMsg, "Failed getting status for program."); + return -1; + } + + return status; +} + +bool +Program::Kill(std::string* ErrMsg) { + if (Data_ == 0) { + MakeErrMsg(ErrMsg, "Process not started!"); + return true; + } + + Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); + HANDLE hProcess = wpi->hProcess; + if (TerminateProcess(hProcess, 1) == 0) { + MakeErrMsg(ErrMsg, "The process couldn't be killed!"); + return true; + } + + return false; +} + +bool Program::ChangeStdinToBinary(){ + int result = _setmode( _fileno(stdin), _O_BINARY ); + return result == -1; +} + +bool Program::ChangeStdoutToBinary(){ + int result = _setmode( _fileno(stdout), _O_BINARY ); + return result == -1; +} + +bool Program::ChangeStderrToBinary(){ + int result = _setmode( _fileno(stderr), _O_BINARY ); + return result == -1; +} + +} diff --git a/lib/Support/Windows/RWMutex.inc b/lib/Support/Windows/RWMutex.inc new file mode 100644 index 0000000..82ae8af --- /dev/null +++ b/lib/Support/Windows/RWMutex.inc @@ -0,0 +1,58 @@ +//= llvm/System/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) RWMutex class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" + +// FIXME: Windows does not have reader-writer locks pre-Vista. If you want +// real reader-writer locks, you a threads implementation for Windows. + +namespace llvm { +using namespace sys; + +RWMutexImpl::RWMutexImpl() { + data_ = calloc(1, sizeof(CRITICAL_SECTION)); + InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); +} + +RWMutexImpl::~RWMutexImpl() { + DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + free(data_); +} + +bool RWMutexImpl::reader_acquire() { + EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + return true; +} + +bool RWMutexImpl::reader_release() { + LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + return true; +} + +bool RWMutexImpl::writer_acquire() { + EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + return true; +} + +bool RWMutexImpl::writer_release() { + LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_)); + return true; +} + + +} diff --git a/lib/Support/Windows/Signals.inc b/lib/Support/Windows/Signals.inc new file mode 100644 index 0000000..c0e3eca --- /dev/null +++ b/lib/Support/Windows/Signals.inc @@ -0,0 +1,325 @@ +//===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of the Signals class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <stdio.h> +#include <vector> +#include <algorithm> + +#ifdef __MINGW32__ + #include <imagehlp.h> +#else + #include <dbghelp.h> +#endif +#include <psapi.h> + +#ifdef __MINGW32__ + #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) + #error "libimagehlp.a & libpsapi.a should be present" + #endif +#else + #pragma comment(lib, "psapi.lib") + #pragma comment(lib, "dbghelp.lib") +#endif + +// Forward declare. +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); + +// InterruptFunction - The function to call if ctrl-c is pressed. +static void (*InterruptFunction)() = 0; + +static std::vector<llvm::sys::Path> *FilesToRemove = NULL; +static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; +static bool RegisteredUnhandledExceptionFilter = false; +static bool CleanupExecuted = false; +static bool ExitOnUnhandledExceptions = false; +static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; + +// Windows creates a new thread to execute the console handler when an event +// (such as CTRL/C) occurs. This causes concurrency issues with the above +// globals which this critical section addresses. +static CRITICAL_SECTION CriticalSection; + +namespace llvm { + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code +//=== and must not be UNIX code +//===----------------------------------------------------------------------===// + +#ifdef _MSC_VER +/// CRTReportHook - Function called on a CRT debugging event. +static int CRTReportHook(int ReportType, char *Message, int *Return) { + // Don't cause a DebugBreak() on return. + if (Return) + *Return = 0; + + switch (ReportType) { + default: + case _CRT_ASSERT: + fprintf(stderr, "CRT assert: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_ERROR: + fprintf(stderr, "CRT error: %s\n", Message); + // FIXME: Is there a way to just crash? Perhaps throw to the unhandled + // exception code? Perhaps SetErrorMode() handles this. + _exit(3); + break; + case _CRT_WARN: + fprintf(stderr, "CRT warn: %s\n", Message); + break; + } + + // Don't call _CrtDbgReport. + return TRUE; +} +#endif + +static void RegisterHandler() { + if (RegisteredUnhandledExceptionFilter) { + EnterCriticalSection(&CriticalSection); + return; + } + + // Now's the time to create the critical section. This is the first time + // through here, and there's only one thread. + InitializeCriticalSection(&CriticalSection); + + // Enter it immediately. Now if someone hits CTRL/C, the console handler + // can't proceed until the globals are updated. + EnterCriticalSection(&CriticalSection); + + RegisteredUnhandledExceptionFilter = true; + OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); + SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); + + // Environment variable to disable any kind of crash dialog. + if (getenv("LLVM_DISABLE_CRT_DEBUG")) { +#ifdef _MSC_VER + _CrtSetReportHook(CRTReportHook); +#endif + ExitOnUnhandledExceptions = true; + } + + // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or + // else multi-threading problems will ensue. +} + +// RemoveFileOnSignal - The public API +bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { + RegisterHandler(); + + if (CleanupExecuted) { + if (ErrMsg) + *ErrMsg = "Process terminating -- cannot register for removal"; + return true; + } + + if (FilesToRemove == NULL) + FilesToRemove = new std::vector<sys::Path>; + + FilesToRemove->push_back(Filename); + + LeaveCriticalSection(&CriticalSection); + return false; +} + +// DontRemoveFileOnSignal - The public API +void sys::DontRemoveFileOnSignal(const sys::Path &Filename) { + if (FilesToRemove == NULL) + return; + + RegisterHandler(); + + FilesToRemove->push_back(Filename); + std::vector<sys::Path>::reverse_iterator I = + std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); + if (I != FilesToRemove->rend()) + FilesToRemove->erase(I.base()-1); + + LeaveCriticalSection(&CriticalSection); +} + +/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or +/// SIGSEGV) is delivered to the process, print a stack trace and then exit. +void sys::PrintStackTraceOnErrorSignal() { + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} + + +void sys::SetInterruptFunction(void (*IF)()) { + RegisterHandler(); + InterruptFunction = IF; + LeaveCriticalSection(&CriticalSection); +} + + +/// AddSignalHandler - Add a function to be called when a signal is delivered +/// to the process. The handler can have a cookie passed to it to identify +/// what instance of the handler it is. +void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { + if (CallBacksToRun == 0) + CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >(); + CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); + RegisterHandler(); + LeaveCriticalSection(&CriticalSection); +} +} + +static void Cleanup() { + EnterCriticalSection(&CriticalSection); + + // Prevent other thread from registering new files and directories for + // removal, should we be executing because of the console handler callback. + CleanupExecuted = true; + + // FIXME: open files cannot be deleted. + + if (FilesToRemove != NULL) + while (!FilesToRemove->empty()) { + FilesToRemove->back().eraseFromDisk(); + FilesToRemove->pop_back(); + } + + if (CallBacksToRun) + for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) + (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); + + LeaveCriticalSection(&CriticalSection); +} + +void llvm::sys::RunInterruptHandlers() { + Cleanup(); +} + +static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { + Cleanup(); + +#ifdef _WIN64 + // TODO: provide a x64 friendly version of the following +#else + + // Initialize the STACKFRAME structure. + STACKFRAME StackFrame; + memset(&StackFrame, 0, sizeof(StackFrame)); + + StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; + StackFrame.AddrPC.Mode = AddrModeFlat; + StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; + StackFrame.AddrStack.Mode = AddrModeFlat; + StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; + StackFrame.AddrFrame.Mode = AddrModeFlat; + + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + // Initialize the symbol handler. + SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); + SymInitialize(hProcess, NULL, TRUE); + + while (true) { + if (!StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, + ep->ContextRecord, NULL, SymFunctionTableAccess, + SymGetModuleBase, NULL)) { + break; + } + + if (StackFrame.AddrFrame.Offset == 0) + break; + + // Print the PC in hexadecimal. + DWORD PC = StackFrame.AddrPC.Offset; + fprintf(stderr, "%08lX", PC); + + // Print the parameters. Assume there are four. + fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", + StackFrame.Params[0], + StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]); + + // Verify the PC belongs to a module in this process. + if (!SymGetModuleBase(hProcess, PC)) { + fputs(" <unknown module>\n", stderr); + continue; + } + + // Print the symbol name. + char buffer[512]; + IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL *>(buffer); + memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL)); + symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); + symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL); + + DWORD dwDisp; + if (!SymGetSymFromAddr(hProcess, PC, &dwDisp, symbol)) { + fputc('\n', stderr); + continue; + } + + buffer[511] = 0; + if (dwDisp > 0) + fprintf(stderr, ", %s()+%04lu bytes(s)", symbol->Name, dwDisp); + else + fprintf(stderr, ", %s", symbol->Name); + + // Print the source file and line number information. + IMAGEHLP_LINE line; + memset(&line, 0, sizeof(line)); + line.SizeOfStruct = sizeof(line); + if (SymGetLineFromAddr(hProcess, PC, &dwDisp, &line)) { + fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); + if (dwDisp > 0) + fprintf(stderr, "+%04lu byte(s)", dwDisp); + } + + fputc('\n', stderr); + } + +#endif + + if (ExitOnUnhandledExceptions) + _exit(-3); + + // Allow dialog box to pop up allowing choice to start debugger. + if (OldFilter) + return (*OldFilter)(ep); + else + return EXCEPTION_CONTINUE_SEARCH; +} + +static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { + // We are running in our very own thread, courtesy of Windows. + EnterCriticalSection(&CriticalSection); + Cleanup(); + + // If an interrupt function has been set, go and run one it; otherwise, + // the process dies. + void (*IF)() = InterruptFunction; + InterruptFunction = 0; // Don't run it on another CTRL-C. + + if (IF) { + // Note: if the interrupt function throws an exception, there is nothing + // to catch it in this thread so it will kill the process. + IF(); // Run it now. + LeaveCriticalSection(&CriticalSection); + return TRUE; // Don't kill the process. + } + + // Allow normal processing to take place; i.e., the process dies. + LeaveCriticalSection(&CriticalSection); + return FALSE; +} diff --git a/lib/Support/Windows/ThreadLocal.inc b/lib/Support/Windows/ThreadLocal.inc new file mode 100644 index 0000000..53070ea --- /dev/null +++ b/lib/Support/Windows/ThreadLocal.inc @@ -0,0 +1,54 @@ +//= llvm/System/Win32/ThreadLocal.inc - Win32 Thread Local Data -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Win32 specific (non-pthread) ThreadLocal class. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include "llvm/Support/ThreadLocal.h" + +namespace llvm { +using namespace sys; + +ThreadLocalImpl::ThreadLocalImpl() { + DWORD* tls = new DWORD; + *tls = TlsAlloc(); + assert(*tls != TLS_OUT_OF_INDEXES); + data = tls; +} + +ThreadLocalImpl::~ThreadLocalImpl() { + DWORD* tls = static_cast<DWORD*>(data); + TlsFree(*tls); + delete tls; +} + +const void* ThreadLocalImpl::getInstance() { + DWORD* tls = static_cast<DWORD*>(data); + return TlsGetValue(*tls); +} + +void ThreadLocalImpl::setInstance(const void* d){ + DWORD* tls = static_cast<DWORD*>(data); + int errorcode = TlsSetValue(*tls, const_cast<void*>(d)); + assert(errorcode != 0); + (void)errorcode; +} + +void ThreadLocalImpl::removeInstance() { + setInstance(0); +} + +} diff --git a/lib/Support/Windows/TimeValue.inc b/lib/Support/Windows/TimeValue.inc new file mode 100644 index 0000000..1227552 --- /dev/null +++ b/lib/Support/Windows/TimeValue.inc @@ -0,0 +1,51 @@ +//===- Win32/TimeValue.cpp - Win32 TimeValue Implementation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 implementation of the TimeValue class. +// +//===----------------------------------------------------------------------===// + +#include "Windows.h" +#include <time.h> + +namespace llvm { +using namespace sys; + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only Win32 specific code. +//===----------------------------------------------------------------------===// + +TimeValue TimeValue::now() { + uint64_t ft; + GetSystemTimeAsFileTime(reinterpret_cast<FILETIME *>(&ft)); + + TimeValue t(0, 0); + t.fromWin32Time(ft); + return t; +} + +std::string TimeValue::str() const { +#ifdef __MINGW32__ + // This ban may be lifted by either: + // (i) a future MinGW version other than 1.0 inherents the __time64_t type, or + // (ii) configure tests for either the time_t or __time64_t type. + time_t ourTime = time_t(this->toEpochTime()); + struct tm *lt = ::localtime(&ourTime); +#else + __time64_t ourTime = this->toEpochTime(); + struct tm *lt = ::_localtime64(&ourTime); +#endif + + char buffer[25]; + strftime(buffer, 25, "%a %b %d %H:%M:%S %Y", lt); + return std::string(buffer); +} + + +} diff --git a/lib/Support/Windows/Windows.h b/lib/Support/Windows/Windows.h new file mode 100644 index 0000000..00a7e75 --- /dev/null +++ b/lib/Support/Windows/Windows.h @@ -0,0 +1,60 @@ +//===- Win32/Win32.h - Common Win32 Include File ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines things specific to Win32 implementations. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Win32 code that +//=== is guaranteed to work on *all* Win32 variants. +//===----------------------------------------------------------------------===// + +// Require at least Windows 2000 API. +#define _WIN32_WINNT 0x0500 +#define _WIN32_IE 0x0500 // MinGW at it again. +#define WIN32_LEAN_AND_MEAN + +#include "llvm/Config/config.h" // Get build system configuration settings +#include <Windows.h> +#include <ShlObj.h> +#include <cassert> +#include <string> + +inline bool MakeErrMsg(std::string* ErrMsg, const std::string& prefix) { + if (!ErrMsg) + return true; + char *buffer = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), 0, (LPSTR)&buffer, 1, NULL); + *ErrMsg = prefix + buffer; + LocalFree(buffer); + return true; +} + +class AutoHandle { + HANDLE handle; + +public: + AutoHandle(HANDLE h) : handle(h) {} + + ~AutoHandle() { + if (handle) + CloseHandle(handle); + } + + operator HANDLE() { + return handle; + } + + AutoHandle &operator=(HANDLE h) { + handle = h; + return *this; + } +}; diff --git a/lib/Support/Windows/system_error.inc b/lib/Support/Windows/system_error.inc new file mode 100644 index 0000000..db02582 --- /dev/null +++ b/lib/Support/Windows/system_error.inc @@ -0,0 +1,140 @@ +//===- llvm/System/Win32/system_error.inc - Windows error_code --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Windows specific implementation of the error_code +// and error_condition classes. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only generic Windows code that +//=== is guaranteed to work on *all* Windows variants. +//===----------------------------------------------------------------------===// + +#include <Windows.h> +#include <WinError.h> + +using namespace llvm; + +std::string +_system_error_category::message(int ev) const { + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL); + if (retval == 0) { + ::LocalFree(lpMsgBuf); + return std::string("Unknown error"); + } + + std::string str( static_cast<LPCSTR>(lpMsgBuf) ); + ::LocalFree(lpMsgBuf); + + while (str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r')) + str.erase( str.size()-1 ); + if (str.size() && str[str.size()-1] == '.') + str.erase( str.size()-1 ); + return str; +} + +// I'd rather not double the line count of the following. +#define MAP_ERR_TO_COND(x, y) case x: return make_error_condition(errc::y) + +error_condition +_system_error_category::default_error_condition(int ev) const { + switch (ev) { + MAP_ERR_TO_COND(0, success); + // Windows system -> posix_errno decode table ---------------------------// + // see WinError.h comments for descriptions of errors + MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied); + MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device); + MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long); + MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_CANNOT_MAKE, permission_denied); + MAP_ERR_TO_COND(ERROR_CANTOPEN, io_error); + MAP_ERR_TO_COND(ERROR_CANTREAD, io_error); + MAP_ERR_TO_COND(ERROR_CANTWRITE, io_error); + MAP_ERR_TO_COND(ERROR_CURRENT_DIRECTORY, permission_denied); + MAP_ERR_TO_COND(ERROR_DEV_NOT_EXIST, no_such_device); + MAP_ERR_TO_COND(ERROR_DEVICE_IN_USE, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_DIR_NOT_EMPTY, directory_not_empty); + MAP_ERR_TO_COND(ERROR_DIRECTORY, invalid_argument); + MAP_ERR_TO_COND(ERROR_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_FILE_EXISTS, file_exists); + MAP_ERR_TO_COND(ERROR_FILE_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_HANDLE_DISK_FULL, no_space_on_device); + MAP_ERR_TO_COND(ERROR_INVALID_ACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_INVALID_DRIVE, no_such_device); + MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported); + MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument); + MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument); + MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available); + MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available); + MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument); + MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied); + MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_NOT_SAME_DEVICE, cross_device_link); + MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error); + MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy); + MAP_ERR_TO_COND(ERROR_OPERATION_ABORTED, operation_canceled); + MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory); + MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory); + MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again); + MAP_ERR_TO_COND(ERROR_SEEK, io_error); + MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied); + MAP_ERR_TO_COND(ERROR_TOO_MANY_OPEN_FILES, too_many_files_open); + MAP_ERR_TO_COND(ERROR_WRITE_FAULT, io_error); + MAP_ERR_TO_COND(ERROR_WRITE_PROTECT, permission_denied); + MAP_ERR_TO_COND(ERROR_SEM_TIMEOUT, timed_out); + MAP_ERR_TO_COND(WSAEACCES, permission_denied); + MAP_ERR_TO_COND(WSAEADDRINUSE, address_in_use); + MAP_ERR_TO_COND(WSAEADDRNOTAVAIL, address_not_available); + MAP_ERR_TO_COND(WSAEAFNOSUPPORT, address_family_not_supported); + MAP_ERR_TO_COND(WSAEALREADY, connection_already_in_progress); + MAP_ERR_TO_COND(WSAEBADF, bad_file_descriptor); + MAP_ERR_TO_COND(WSAECONNABORTED, connection_aborted); + MAP_ERR_TO_COND(WSAECONNREFUSED, connection_refused); + MAP_ERR_TO_COND(WSAECONNRESET, connection_reset); + MAP_ERR_TO_COND(WSAEDESTADDRREQ, destination_address_required); + MAP_ERR_TO_COND(WSAEFAULT, bad_address); + MAP_ERR_TO_COND(WSAEHOSTUNREACH, host_unreachable); + MAP_ERR_TO_COND(WSAEINPROGRESS, operation_in_progress); + MAP_ERR_TO_COND(WSAEINTR, interrupted); + MAP_ERR_TO_COND(WSAEINVAL, invalid_argument); + MAP_ERR_TO_COND(WSAEISCONN, already_connected); + MAP_ERR_TO_COND(WSAEMFILE, too_many_files_open); + MAP_ERR_TO_COND(WSAEMSGSIZE, message_size); + MAP_ERR_TO_COND(WSAENAMETOOLONG, filename_too_long); + MAP_ERR_TO_COND(WSAENETDOWN, network_down); + MAP_ERR_TO_COND(WSAENETRESET, network_reset); + MAP_ERR_TO_COND(WSAENETUNREACH, network_unreachable); + MAP_ERR_TO_COND(WSAENOBUFS, no_buffer_space); + MAP_ERR_TO_COND(WSAENOPROTOOPT, no_protocol_option); + MAP_ERR_TO_COND(WSAENOTCONN, not_connected); + MAP_ERR_TO_COND(WSAENOTSOCK, not_a_socket); + MAP_ERR_TO_COND(WSAEOPNOTSUPP, operation_not_supported); + MAP_ERR_TO_COND(WSAEPROTONOSUPPORT, protocol_not_supported); + MAP_ERR_TO_COND(WSAEPROTOTYPE, wrong_protocol_type); + MAP_ERR_TO_COND(WSAETIMEDOUT, timed_out); + MAP_ERR_TO_COND(WSAEWOULDBLOCK, operation_would_block); + default: return error_condition(ev, system_category()); + } +} diff --git a/lib/Support/raw_ostream.cpp b/lib/Support/raw_ostream.cpp index d3d6539..0279f40 100644 --- a/lib/Support/raw_ostream.cpp +++ b/lib/Support/raw_ostream.cpp @@ -13,8 +13,8 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Format.h" -#include "llvm/System/Program.h" -#include "llvm/System/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Process.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Config/config.h" diff --git a/lib/Support/system_error.cpp b/lib/Support/system_error.cpp new file mode 100644 index 0000000..cd18906 --- /dev/null +++ b/lib/Support/system_error.cpp @@ -0,0 +1,121 @@ +//===---------------------- system_error.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/system_error.h" +#include "llvm/Support/Errno.h" +#include <string> +#include <cstring> + +namespace llvm { + +// class error_category + +error_category::error_category() { +} + +error_category::~error_category() { +} + +error_condition +error_category::default_error_condition(int ev) const { + return error_condition(ev, *this); +} + +bool +error_category::equivalent(int code, const error_condition& condition) const { + return default_error_condition(code) == condition; +} + +bool +error_category::equivalent(const error_code& code, int condition) const { + return *this == code.category() && code.value() == condition; +} + +std::string +_do_message::message(int ev) const { + return std::string(sys::StrError(ev)); +} + +class _generic_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; +}; + +const char* +_generic_error_category::name() const { + return "generic"; +} + +std::string +_generic_error_category::message(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return std::string("unspecified generic_category error"); +#endif // ELAST + return _do_message::message(ev); +} + +const error_category& +generic_category() { + static _generic_error_category s; + return s; +} + +class _system_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; + +const char* +_system_error_category::name() const { + return "system"; +} + +// std::string _system_error_category::message(int ev) const { +// Is in Platform/system_error.inc + +// error_condition _system_error_category::default_error_condition(int ev) const +// Is in Platform/system_error.inc + +const error_category& +system_category() { + static _system_error_category s; + return s; +} + +// error_condition + +std::string +error_condition::message() const { + return _cat_->message(_val_); +} + +// error_code + +std::string +error_code::message() const { + return _cat_->message(_val_); +} + +} // end namespace llvm + +// Include the truly platform-specific parts of this class. +#if defined(LLVM_ON_UNIX) +#include "Unix/system_error.inc" +#endif +#if defined(LLVM_ON_WIN32) +#include "Windows/system_error.inc" +#endif |