diff --git a/Zend/zend_call_stack.c b/Zend/zend_call_stack.c index cad6f7330e3..dd3a48533af 100644 --- a/Zend/zend_call_stack.c +++ b/Zend/zend_call_stack.c @@ -35,7 +35,9 @@ # include # endif #endif /* ZEND_WIN32 */ -#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) +#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ + defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__sun) # include #endif #if defined(__FreeBSD__) || defined(__DragonFly__) @@ -61,6 +63,12 @@ typedef int boolean_t; #ifdef __linux__ #include #endif +#ifdef __sun +#define _STRUCTURED_PROC 1 +#include +#include +#include +#endif #ifdef ZEND_CHECK_STACK_LIMIT @@ -650,6 +658,125 @@ static bool zend_call_stack_get_netbsd(zend_call_stack *stack) } #endif /* defined(__NetBSD__) */ +#if defined(__sun) +static bool zend_call_stack_get_solaris_pthread(zend_call_stack *stack) +{ + pthread_attr_t attr; + int error; + void *addr; + size_t max_size, guard_size; + + error = pthread_attr_get_np(pthread_self(), &attr); + if (error) { + return false; + } + + error = pthread_attr_getstack(&attr, &addr, &max_size); + if (error) { + return false; + } + + error = pthread_attr_getguardsize(&attr, &guard_size); + if (error) { + return false; + } + + addr = (char *)addr + guard_size; + max_size -= guard_size; + + stack->base = (char *)addr + max_size; + stack->max_size = max_size; + + return true; +} + +static bool zend_call_stack_get_solaris_proc_maps(zend_call_stack *stack) +{ + char buffer[4096]; + uintptr_t addr_on_stack = (uintptr_t)&buffer; + bool found = false, r = false; + struct ps_prochandle *proc; + prmap_t *map, *orig; + struct rlimit rlim; + char path[PATH_MAX]; + size_t size; + ssize_t len; + pid_t pid; + int error, fd; + + pid = getpid(); + proc = Pgrab(pid, PGRAB_RDONLY, &error); + if (!proc) { + return false; + } + + size = (1 << 20); + snprintf(path, sizeof(path), "/proc/%d/map", pid); + + if ((fd = open(path, O_RDONLY)) == -1) { + Prelease(proc, 0); + return false; + } + + orig = malloc(size); + if (!orig) { + Prelease(proc, 0); + close(fd); + return false; + } + + while (size > 0 && (len = pread(fd, orig, size, 0)) == size) { + prmap_t *tmp; + size <<= 1; + tmp = realloc(orig, size); + if (!tmp) { + goto end; + } + orig = tmp; + } + + for (map = orig; len > 0; ++map) { + if ((uintptr_t)map->pr_vaddr <= addr_on_stack && (uintptr_t)map->pr_vaddr + map->pr_size >= addr_on_stack) { + found = true; + break; + } + len -= sizeof(*map); + } + + if (!found) { + goto end; + } + + error = getrlimit(RLIMIT_STACK, &rlim); + if (error || rlim.rlim_cur == RLIM_INFINITY) { + goto end; + } + + stack->base = (void *)map->pr_vaddr + map->pr_size; + stack->max_size = rlim.rlim_cur; + r = true; + +end: + free(orig); + Prelease(proc, 0); + close(fd); + return r; +} + +static bool zend_call_stack_get_solaris(zend_call_stack *stack) +{ + if (_lwp_self() == 1) { + return zend_call_stack_get_solaris_proc_maps(stack); + } + return zend_call_stack_get_solaris_pthread(stack); +} +#else +static bool zend_call_stack_get_solaris(zend_call_stack *stack) +{ + return false; +} +#endif /* defined(__sun) */ + /** Get the stack information for the calling thread */ ZEND_API bool zend_call_stack_get(zend_call_stack *stack) { @@ -681,6 +808,10 @@ ZEND_API bool zend_call_stack_get(zend_call_stack *stack) return true; } + if (zend_call_stack_get_solaris(stack)) { + return true; + } + return false; } diff --git a/Zend/zend_call_stack.h b/Zend/zend_call_stack.h index 79b93920003..d3bc26418ec 100644 --- a/Zend/zend_call_stack.h +++ b/Zend/zend_call_stack.h @@ -92,6 +92,9 @@ static inline size_t zend_call_stack_default_size(void) #ifdef __HAIKU__ return 64 * 4096; #endif +#ifdef __sun + return 8 * 4096; +#endif return 2 * 1024 * 1024; } diff --git a/configure.ac b/configure.ac index 927761ecd0b..983bbe5c596 100644 --- a/configure.ac +++ b/configure.ac @@ -656,6 +656,9 @@ PHP_CHECK_FUNC_LIB(nanosleep, rt) dnl Haiku does not have network api in libc. PHP_CHECK_FUNC_LIB(setsockopt, network) +dnl Solaris/Illumos for process mapping. +PHP_CHECK_FUNC_LIB(Pgrab, proc) + dnl Check for getaddrinfo, should be a better way, but... Also check for working dnl getaddrinfo. AC_CACHE_CHECK([for getaddrinfo], ac_cv_func_getaddrinfo,