Skip to content

Commit aef5225

Browse files
committed
zend_call_stack_get implementation for NetBSD.
Despite being OpenBSD's predecessor, the approach is in fact a lot closer to Linux, at least in principle. We purposely avoid reading /proc/N/maps to be more future-proof. Close GH-11637
1 parent 880faa3 commit aef5225

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Core:
77
closures). (ilutov)
88
. Fixed bug GH-12102 (Incorrect compile error when using array access on TMP
99
value in function call). (ilutov)
10+
. Added zend_call_stack_get implementation for NetBSD. (David Carlier)
1011

1112
DOM:
1213
. Added DOMNode::compareDocumentPosition(). (nielsdos)

Zend/zend_call_stack.c

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
# include <sys/types.h>
3636
# endif
3737
#endif /* ZEND_WIN32 */
38-
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__)
38+
#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
3939
# include <pthread.h>
4040
#endif
4141
#ifdef __FreeBSD__
@@ -51,6 +51,10 @@ typedef int boolean_t;
5151
# include <sys/sysctl.h>
5252
# include <sys/user.h>
5353
#endif
54+
#ifdef __NetBSD__
55+
# include <sys/sysctl.h>
56+
# include <sys/syscall.h>
57+
#endif
5458
#ifdef __linux__
5559
#include <sys/syscall.h>
5660
#endif
@@ -504,6 +508,119 @@ static bool zend_call_stack_get_openbsd(zend_call_stack *stack)
504508
}
505509
#endif /* defined(__OpenBSD__) */
506510

511+
#if defined(__NetBSD__)
512+
# ifdef HAVE_PTHREAD_GETATTR_NP
513+
static bool zend_call_stack_get_netbsd_pthread(zend_call_stack *stack)
514+
{
515+
pthread_attr_t attr;
516+
int error;
517+
void *addr;
518+
size_t max_size, guard_size;
519+
520+
error = pthread_getattr_np(pthread_self(), &attr);
521+
if (error) {
522+
return false;
523+
}
524+
525+
error = pthread_attr_getstack(&attr, &addr, &max_size);
526+
if (error) {
527+
return false;
528+
}
529+
530+
error = pthread_attr_getguardsize(&attr, &guard_size);
531+
if (error) {
532+
return false;
533+
}
534+
535+
addr = (char *)addr + guard_size;
536+
max_size -= guard_size;
537+
538+
stack->base = (char *)addr + max_size;
539+
stack->max_size = max_size;
540+
541+
return true;
542+
}
543+
# else
544+
static bool zend_call_stack_get_netbsd_pthread(zend_call_stack *stack)
545+
{
546+
return false;
547+
}
548+
# endif /* HAVE_PTHREAD_GETATTR_NP */
549+
static bool zend_call_stack_get_netbsd_vm(zend_call_stack *stack, void **ptr)
550+
{
551+
/**
552+
* NetBSD supports procfs in a similar fashion as Linux
553+
* however NetBSD's mid/long term plan is to remove it completely.
554+
*/
555+
char *start, *end;
556+
struct kinfo_vmentry *entry;
557+
size_t len, max_size;
558+
char buffer[4096];
559+
uintptr_t addr_on_stack = (uintptr_t)&buffer;
560+
int mib[5] = { CTL_VM, VM_PROC, VM_PROC_MAP, getpid(), sizeof(struct kinfo_vmentry) };
561+
bool found = false;
562+
struct rlimit rlim;
563+
564+
if (sysctl(mib, 5, NULL, &len, NULL, 0) != 0) {
565+
return false;
566+
}
567+
568+
// kinfo_getvmmap uses the same formula, only we do not want to rely on libkvm
569+
len = len * 4 / 3 ;
570+
*ptr = malloc(len);
571+
572+
if (sysctl(mib, 5, *ptr, &len, NULL, 0) != 0) {
573+
return false;
574+
}
575+
576+
start = (char *)*ptr;
577+
end = start + len;
578+
579+
while (start < end) {
580+
entry = (struct kinfo_vmentry *)start;
581+
if (entry->kve_start <= addr_on_stack && entry->kve_end >= addr_on_stack) {
582+
found = true;
583+
break;
584+
}
585+
586+
start += sizeof(struct kinfo_vmentry);
587+
}
588+
589+
if (!found) {
590+
return false;
591+
}
592+
593+
if (getrlimit(RLIMIT_STACK, &rlim) || rlim.rlim_cur == RLIM_INFINITY) {
594+
return false;
595+
}
596+
597+
max_size = rlim.rlim_cur;
598+
599+
stack->base = (void *)entry->kve_end;
600+
stack->max_size = max_size;
601+
602+
return true;
603+
}
604+
605+
606+
static bool zend_call_stack_get_netbsd(zend_call_stack *stack)
607+
{
608+
if (syscall(SYS__lwp_self) == 1) {
609+
void *ptr = NULL;
610+
bool r = zend_call_stack_get_netbsd_vm(stack, &ptr);
611+
free(ptr);
612+
return r;
613+
}
614+
615+
return zend_call_stack_get_netbsd_pthread(stack);
616+
}
617+
#else
618+
static bool zend_call_stack_get_netbsd(zend_call_stack *stack)
619+
{
620+
return false;
621+
}
622+
#endif /* defined(__NetBSD__) */
623+
507624
/** Get the stack information for the calling thread */
508625
ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
509626
{
@@ -527,6 +644,10 @@ ZEND_API bool zend_call_stack_get(zend_call_stack *stack)
527644
return true;
528645
}
529646

647+
if (zend_call_stack_get_netbsd(stack)) {
648+
return true;
649+
}
650+
530651
return false;
531652
}
532653

0 commit comments

Comments
 (0)