diff options
Diffstat (limited to 'lib/Support/Unix')
| -rw-r--r-- | lib/Support/Unix/Memory.inc | 220 | ||||
| -rw-r--r-- | lib/Support/Unix/Path.inc | 17 | ||||
| -rw-r--r-- | lib/Support/Unix/PathV2.inc | 11 | ||||
| -rw-r--r-- | lib/Support/Unix/Process.inc | 99 | ||||
| -rw-r--r-- | lib/Support/Unix/Program.inc | 27 | ||||
| -rw-r--r-- | lib/Support/Unix/Signals.inc | 34 | ||||
| -rw-r--r-- | lib/Support/Unix/Unix.h | 6 |
7 files changed, 301 insertions, 113 deletions
diff --git a/lib/Support/Unix/Memory.inc b/lib/Support/Unix/Memory.inc index 5a57a28..40d6b3f 100644 --- a/lib/Support/Unix/Memory.inc +++ b/lib/Support/Unix/Memory.inc @@ -13,6 +13,7 @@ #include "Unix.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Process.h" #ifdef HAVE_SYS_MMAN_H @@ -23,18 +24,150 @@ #include <mach/mach.h> #endif +#if defined(__mips__) +# if defined(__OpenBSD__) +# include <mips64/sysarch.h> +# else +# include <sys/cachectl.h> +# endif +#endif + +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); + +namespace { + +int getPosixProtectionFlags(unsigned Flags) { + switch (Flags) { + case llvm::sys::Memory::MF_READ: + return PROT_READ; + case llvm::sys::Memory::MF_WRITE: + return PROT_WRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_WRITE: + return PROT_READ | PROT_WRITE; + case llvm::sys::Memory::MF_READ|llvm::sys::Memory::MF_EXEC: + return PROT_READ | PROT_EXEC; + case llvm::sys::Memory::MF_READ | + llvm::sys::Memory::MF_WRITE | + llvm::sys::Memory::MF_EXEC: + return PROT_READ | PROT_WRITE | PROT_EXEC; + case llvm::sys::Memory::MF_EXEC: + return PROT_EXEC; + default: + llvm_unreachable("Illegal memory protection flag specified!"); + } + // Provide a default return value as required by some compilers. + return PROT_NONE; +} + +} // namespace + +namespace llvm { +namespace sys { + +MemoryBlock +Memory::allocateMappedMemory(size_t NumBytes, + const MemoryBlock *const NearBlock, + unsigned PFlags, + error_code &EC) { + EC = error_code::success(); + if (NumBytes == 0) + return MemoryBlock(); + + static const size_t PageSize = process::get_self()->page_size(); + const 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) { + EC = error_code(errno, system_category()); + return MemoryBlock(); + } + fd = zero_fd; +#endif + + int MMFlags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; // Ends statement above + + int Protect = getPosixProtectionFlags(PFlags); + + // Use any near hint and the page size to set a page-aligned starting address + uintptr_t Start = NearBlock ? reinterpret_cast<uintptr_t>(NearBlock->base()) + + NearBlock->size() : 0; + if (Start && Start % PageSize) + Start += PageSize - Start % PageSize; + + void *Addr = ::mmap(reinterpret_cast<void*>(Start), PageSize*NumPages, + Protect, MMFlags, fd, 0); + if (Addr == MAP_FAILED) { + if (NearBlock) //Try again without a near hint + return allocateMappedMemory(NumBytes, 0, PFlags, EC); + + EC = error_code(errno, system_category()); + return MemoryBlock(); + } + + MemoryBlock Result; + Result.Address = Addr; + Result.Size = NumPages*PageSize; + + if (PFlags & MF_EXEC) + Memory::InvalidateInstructionCache(Result.Address, Result.Size); + + return Result; +} + +error_code +Memory::releaseMappedMemory(MemoryBlock &M) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + + if (0 != ::munmap(M.Address, M.Size)) + return error_code(errno, system_category()); + + M.Address = 0; + M.Size = 0; + + return error_code::success(); +} + +error_code +Memory::protectMappedMemory(const MemoryBlock &M, unsigned Flags) { + if (M.Address == 0 || M.Size == 0) + return error_code::success(); + + if (!Flags) + return error_code(EINVAL, generic_category()); + + int Protect = getPosixProtectionFlags(Flags); + + int Result = ::mprotect(M.Address, M.Size, Protect); + if (Result != 0) + return error_code(errno, system_category()); + + if (Flags & MF_EXEC) + Memory::InvalidateInstructionCache(M.Address, M.Size); + + return error_code::success(); +} + /// 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) { +MemoryBlock +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; + size_t PageSize = process::get_self()->page_size(); + size_t NumPages = (NumBytes+PageSize-1)/PageSize; int fd = -1; #ifdef NEED_DEV_ZERO_FOR_MMAP @@ -58,10 +191,10 @@ llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, NearBlock->size() : 0; #if defined(__APPLE__) && defined(__arm__) - void *pa = ::mmap(start, pageSize*NumPages, PROT_READ|PROT_EXEC, + 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, + void *pa = ::mmap(start, PageSize*NumPages, PROT_READ|PROT_WRITE|PROT_EXEC, flags, fd, 0); #endif if (pa == MAP_FAILED) { @@ -74,40 +207,40 @@ llvm::sys::Memory::AllocateRWX(size_t NumBytes, const MemoryBlock* NearBlock, #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_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(); + return MemoryBlock(); } kr = vm_protect(mach_task_self(), (vm_address_t)pa, - (vm_size_t)(pageSize*NumPages), 0, + (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(); + return MemoryBlock(); } #endif MemoryBlock result; result.Address = pa; - result.Size = NumPages*pageSize; + result.Size = NumPages*PageSize; return result; } -bool llvm::sys::Memory::ReleaseRWX(MemoryBlock &M, std::string *ErrMsg) { +bool 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) { +bool 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); + 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; @@ -116,10 +249,10 @@ bool llvm::sys::Memory::setWritable (MemoryBlock &M, std::string *ErrMsg) { #endif } -bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { +bool 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); + 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; @@ -128,7 +261,7 @@ bool llvm::sys::Memory::setExecutable (MemoryBlock &M, std::string *ErrMsg) { #endif } -bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { +bool 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, @@ -139,7 +272,7 @@ bool llvm::sys::Memory::setRangeWritable(const void *Addr, size_t Size) { #endif } -bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { +bool 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, @@ -149,3 +282,52 @@ bool llvm::sys::Memory::setRangeExecutable(const void *Addr, size_t Size) { return true; #endif } + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void 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(const_cast<void *>(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? + const char *Start = static_cast<const char *>(Addr); + const char *End = Start + Len; + __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); +# elif defined(__mips__) + const char *Start = static_cast<const char *>(Addr); + cacheflush(const_cast<char *>(Start), Len, BCACHE); +# endif + +#endif // end apple + + ValgrindDiscardTranslations(Addr, Len); +} + +} // namespace sys +} // namespace llvm diff --git a/lib/Support/Unix/Path.inc b/lib/Support/Unix/Path.inc index 6bddbdf..6a5ebb8 100644 --- a/lib/Support/Unix/Path.inc +++ b/lib/Support/Unix/Path.inc @@ -261,7 +261,8 @@ Path::GetCurrentDirectory() { } #if defined(__FreeBSD__) || defined (__NetBSD__) || defined(__Bitrig__) || \ - defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) + defined(__OpenBSD__) || defined(__minix) || defined(__FreeBSD_kernel__) || \ + defined(__linux__) || defined(__CYGWIN__) static int test_dir(char buf[PATH_MAX], char ret[PATH_MAX], const char *dir, const char *bin) @@ -337,9 +338,17 @@ Path Path::GetMainExecutable(const char *argv0, void *MainAddr) { 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)); + StringRef aPath("/proc/self/exe"); + if (sys::fs::exists(aPath)) { + // /proc is not always mounted under Linux (chroot for example). + ssize_t len = readlink(aPath.str().c_str(), exe_path, sizeof(exe_path)); + if (len >= 0) + return Path(StringRef(exe_path, len)); + } else { + // Fall back to the classical detection. + if (getprogpath(exe_path, argv0) != NULL) + return Path(exe_path); + } #elif defined(HAVE_DLFCN_H) // Use dladdr to get executable path if available. Dl_info DLInfo; diff --git a/lib/Support/Unix/PathV2.inc b/lib/Support/Unix/PathV2.inc index f59551e..dc43b59 100644 --- a/lib/Support/Unix/PathV2.inc +++ b/lib/Support/Unix/PathV2.inc @@ -426,9 +426,10 @@ rety_open_create: // If the file existed, try again, otherwise, error. if (errno == errc::file_exists) goto retry_random_path; - // The path prefix doesn't exist. - if (errno == errc::no_such_file_or_directory) { - StringRef p(RandomPath.begin(), RandomPath.size()); + // If path prefix doesn't exist, try to create it. + if (errno == errc::no_such_file_or_directory && + !exists(path::parent_path(RandomPath))) { + StringRef p(RandomPath); SmallString<64> dir_to_create; for (path::const_iterator i = path::begin(p), e = --path::end(p); i != e; ++i) { @@ -547,7 +548,7 @@ mapped_file_region::~mapped_file_region() { ::munmap(Mapping, Size); } -#if LLVM_USE_RVALUE_REFERENCES +#if LLVM_HAS_RVALUE_REFERENCES mapped_file_region::mapped_file_region(mapped_file_region &&other) : Mode(other.Mode), Size(other.Size), Mapping(other.Mapping) { other.Mapping = 0; @@ -576,7 +577,7 @@ const char *mapped_file_region::const_data() const { } int mapped_file_region::alignment() { - return Process::GetPageSize(); + return process::get_self()->page_size(); } error_code detail::directory_iterator_construct(detail::DirIterState &it, diff --git a/lib/Support/Unix/Process.inc b/lib/Support/Unix/Process.inc index 5204147..1335b78 100644 --- a/lib/Support/Unix/Process.inc +++ b/lib/Support/Unix/Process.inc @@ -44,9 +44,49 @@ using namespace llvm; using namespace sys; -unsigned -Process::GetPageSize() -{ + +process::id_type self_process::get_id() { + return getpid(); +} + +static std::pair<TimeValue, TimeValue> getRUsageTimes() { +#if defined(HAVE_GETRUSAGE) + struct rusage RU; + ::getrusage(RUSAGE_SELF, &RU); + return std::make_pair( + TimeValue( + static_cast<TimeValue::SecondsType>(RU.ru_utime.tv_sec), + static_cast<TimeValue::NanoSecondsType>( + RU.ru_utime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND)), + TimeValue( + static_cast<TimeValue::SecondsType>(RU.ru_stime.tv_sec), + static_cast<TimeValue::NanoSecondsType>( + RU.ru_stime.tv_usec * TimeValue::NANOSECONDS_PER_MICROSECOND))); +#else +#warning Cannot get usage times on this platform + return std::make_pair(TimeValue(), TimeValue()); +#endif +} + +TimeValue self_process::get_user_time() const { +#if _POSIX_TIMERS > 0 && _POSIX_CPUTIME > 0 + // Try to get a high resolution CPU timer. + struct timespec TS; + if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &TS) == 0) + return TimeValue(static_cast<TimeValue::SecondsType>(TS.tv_sec), + static_cast<TimeValue::NanoSecondsType>(TS.tv_nsec)); +#endif + + // Otherwise fall back to rusage based timing. + return getRUsageTimes().first; +} + +TimeValue self_process::get_system_time() const { + // We can only collect system time by inspecting the results of getrusage. + return getRUsageTimes().second; +} + +static unsigned getPageSize() { #if defined(__CYGWIN__) // On Cygwin, getpagesize() returns 64k but the page size for the purposes of // memory protection and mmap() is 4k. @@ -62,6 +102,12 @@ Process::GetPageSize() return static_cast<unsigned>(page_size); } +// This constructor guaranteed to be run exactly once on a single thread, and +// sets up various process invariants that can be queried cheaply from then on. +self_process::self_process() : PageSize(getPageSize()) { +} + + size_t Process::GetMallocUsage() { #if defined(HAVE_MALLINFO) struct mallinfo mi; @@ -86,49 +132,10 @@ size_t Process::GetMallocUsage() { #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) -{ +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 + llvm::tie(user_time, sys_time) = getRUsageTimes(); } int Process::GetCurrentUserId() { @@ -318,7 +325,7 @@ static unsigned GetRandomNumberSeed() { // Otherwise, swizzle the current time and the process ID to form a reasonable // seed. - TimeValue Now = llvm::TimeValue::now(); + TimeValue Now = TimeValue::now(); return hash_combine(Now.seconds(), Now.nanoseconds(), ::getpid()); } #endif diff --git a/lib/Support/Unix/Program.inc b/lib/Support/Unix/Program.inc index e5990d0..c384316 100644 --- a/lib/Support/Unix/Program.inc +++ b/lib/Support/Unix/Program.inc @@ -16,9 +16,9 @@ //=== is guaranteed to work on *all* UNIX variants. //===----------------------------------------------------------------------===// -#include <llvm/Config/config.h> -#include "llvm/Support/FileSystem.h" #include "Unix.h" +#include "llvm/Support/FileSystem.h" +#include <llvm/Config/config.h> #if HAVE_SYS_STAT_H #include <sys/stat.h> #endif @@ -47,11 +47,6 @@ 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) { @@ -394,24 +389,6 @@ Program::Wait(const sys::Path &path, #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; -} - error_code Program::ChangeStdinToBinary(){ // Do nothing, as Unix doesn't differentiate between text and binary. return make_error_code(errc::success); diff --git a/lib/Support/Unix/Signals.inc b/lib/Support/Unix/Signals.inc index 2f1e382..4a2496f 100644 --- a/lib/Support/Unix/Signals.inc +++ b/lib/Support/Unix/Signals.inc @@ -15,9 +15,9 @@ #include "Unix.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Mutex.h" +#include <algorithm> #include <string> #include <vector> -#include <algorithm> #if HAVE_EXECINFO_H # include <execinfo.h> // For backtrace(). #endif @@ -121,17 +121,29 @@ static void UnregisterHandlers() { /// NB: This must be an async signal safe function. It cannot allocate or free /// memory, even in debug builds. static void RemoveFilesToRemove() { - // Note: avoid iterators in case of debug iterators that allocate or release + // We avoid iterators in case of debug iterators that allocate or release // memory. for (unsigned i = 0, e = FilesToRemove.size(); i != e; ++i) { - // Note that we don't want to use any external code here, and we don't care - // about errors. We're going to try as hard as we can as often as we need - // to to make these files go away. If these aren't files, too bad. - // - // We do however rely on a std::string implementation for which repeated - // calls to 'c_str()' don't allocate memory. We pre-call 'c_str()' on all - // of these strings to try to ensure this is safe. - unlink(FilesToRemove[i].c_str()); + // We rely on a std::string implementation for which repeated calls to + // 'c_str()' don't allocate memory. We pre-call 'c_str()' on all of these + // strings to try to ensure this is safe. + const char *path = FilesToRemove[i].c_str(); + + // Get the status so we can determine if it's a file or directory. If we + // can't stat the file, ignore it. + struct stat buf; + if (stat(path, &buf) != 0) + continue; + + // If this is not a regular file, ignore it. We want to prevent removal of + // special files like /dev/null, even if the compiler is being run with the + // super-user permissions. + if (!S_ISREG(buf.st_mode)) + continue; + + // Otherwise, remove the file. We ignore any errors here as there is nothing + // else we can do. + unlink(path); } } @@ -243,7 +255,7 @@ void llvm::sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { // On glibc systems we have the 'backtrace' function, which works nicely, but // doesn't demangle symbols. static void PrintStackTrace(void *) { -#ifdef HAVE_BACKTRACE +#if defined(HAVE_BACKTRACE) && defined(ENABLE_BACKTRACES) static void* StackTrace[256]; // Use backtrace() to output a backtrace on Linux systems with glibc. int depth = backtrace(StackTrace, diff --git a/lib/Support/Unix/Unix.h b/lib/Support/Unix/Unix.h index 361f297..051f56f 100644 --- a/lib/Support/Unix/Unix.h +++ b/lib/Support/Unix/Unix.h @@ -21,12 +21,12 @@ #include "llvm/Config/config.h" // Get autoconf configuration settings #include "llvm/Support/Errno.h" -#include <cstdlib> +#include <algorithm> +#include <cerrno> #include <cstdio> +#include <cstdlib> #include <cstring> -#include <cerrno> #include <string> -#include <algorithm> #ifdef HAVE_UNISTD_H #include <unistd.h> |
