diff mbox series

[libphobos] Committed merge with upstream druntime 4b2674b3

Message ID CABOHX+cx-0ts82xzXZU_oR9DQHQE2aWLQwAwyrsXe2EMvM_GQQ@mail.gmail.com
State New
Headers show
Series [libphobos] Committed merge with upstream druntime 4b2674b3 | expand

Commit Message

Iain Buclaw April 21, 2019, 10:07 a.m. UTC
Hi,

This patch merges the libdruntime sub-library with upstream druntime 4b2674b3.

Adds version (BacktraceExternal) for using libexecinfo instead of
internal implementation on FreeBSD, NetBSD, and DragonFly.

Bootstrapped and regression tested on x86_64-linux-gnu, with
preliminary build testing done on x86_64-freebsd11.2,
x86_64-dragonfly5.4, and x86_64-netbsd8.0.

Committed to trunk as r270482.
diff mbox series

Patch

diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index dd5f621082f..405be921eb3 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-70b9fea60246e63d936ad6826b1b48b6e0f1de8f
+4b2674b36b1f6aac75db2a5aa38d67d4be55a987
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d
index 0ead04752e4..1fd54407aa5 100644
--- a/libphobos/libdruntime/core/runtime.d
+++ b/libphobos/libdruntime/core/runtime.d
@@ -519,9 +519,8 @@  extern (C) bool runModuleUnitTests()
         {
             static enum MAXFRAMES = 128;
             void*[MAXFRAMES]  callstack;
-            int               numframes;
 
-            numframes = backtrace( callstack.ptr, MAXFRAMES );
+            auto numframes = backtrace( callstack.ptr, MAXFRAMES );
             backtrace_symbols_fd( callstack.ptr, numframes, 2 );
         }
 
diff --git a/libphobos/libdruntime/core/sys/dragonflybsd/execinfo.d b/libphobos/libdruntime/core/sys/dragonflybsd/execinfo.d
index 9d2d615f786..9f91a0be6ca 100644
--- a/libphobos/libdruntime/core/sys/dragonflybsd/execinfo.d
+++ b/libphobos/libdruntime/core/sys/dragonflybsd/execinfo.d
@@ -9,125 +9,139 @@ 
 module core.sys.dragonflybsd.execinfo;
 
 version (DragonFlyBSD):
+extern (C):
+nothrow:
 
-extern (C) nothrow @system:
+version (GNU)
+    version = BacktraceExternal;
 
-import core.sys.dragonflybsd.dlfcn;
-
-// Use extern (D) so that these functions don't collide with libexecinfo.
-
-extern (D) int backtrace(void** buffer, int size)
+version (BacktraceExternal)
 {
-    import core.thread : thread_stackBottom;
-
-    void** p, pend=cast(void**)thread_stackBottom();
-    version (D_InlineAsm_X86)
-        asm nothrow @trusted { mov p[EBP], EBP; }
-    else version (D_InlineAsm_X86_64)
-        asm nothrow @trusted { mov p[RBP], RBP; }
-    else
-        static assert(false, "Architecture not supported.");
-
-    int i;
-    for (; i < size && p < pend; ++i)
-    {
-        buffer[i] = *(p + 1);
-        auto pnext = cast(void**)*p;
-        if (pnext <= p) break;
-        p = pnext;
-    }
-    return i;
+    size_t backtrace(void**, size_t);
+    char** backtrace_symbols(const(void*)*, size_t);
+    void backtrace_symbols_fd(const(void*)*, size_t, int);
+    char** backtrace_symbols_fmt(const(void*)*, size_t, const char*);
+    int backtrace_symbols_fd_fmt(const(void*)*, size_t, int, const char*);
 }
+else
+{
+    import core.sys.dragonflybsd.dlfcn;
 
+    // Use extern (D) so that these functions don't collide with libexecinfo.
 
-extern (D) char** backtrace_symbols(const(void*)* buffer, int size)
-{
-    static void* realloc(void* p, size_t len) nothrow
+    extern (D) int backtrace(void** buffer, int size)
     {
-        static import cstdlib=core.stdc.stdlib;
-        auto res = cstdlib.realloc(p, len);
-        if (res is null) cstdlib.free(p);
-        return res;
+        import core.thread : thread_stackBottom;
+
+        void** p, pend=cast(void**)thread_stackBottom();
+        version (D_InlineAsm_X86)
+            asm nothrow @trusted { mov p[EBP], EBP; }
+        else version (D_InlineAsm_X86_64)
+            asm nothrow @trusted { mov p[RBP], RBP; }
+        else
+            static assert(false, "Architecture not supported.");
+
+        int i;
+        for (; i < size && p < pend; ++i)
+        {
+            buffer[i] = *(p + 1);
+            auto pnext = cast(void**)*p;
+            if (pnext <= p) break;
+            p = pnext;
+        }
+        return i;
     }
 
-    if (size <= 0) return null;
-
-    size_t pos = size * (char*).sizeof;
-    char** p = cast(char**)realloc(null, pos);
-    if (p is null) return null;
 
-    Dl_info info;
-    foreach (i, addr; buffer[0 .. size])
+    extern (D) char** backtrace_symbols(const(void*)* buffer, int size)
     {
-        if (dladdr(addr, &info) == 0)
-            (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
-        fixupDLInfo(addr, info);
-
-        immutable len = formatStackFrame(null, 0, addr, info);
-        assert(len > 0);
-
-        p = cast(char**)realloc(p, pos + len);
+        static void* realloc(void* p, size_t len) nothrow
+        {
+            static import cstdlib=core.stdc.stdlib;
+            auto res = cstdlib.realloc(p, len);
+            if (res is null) cstdlib.free(p);
+            return res;
+        }
+
+        if (size <= 0) return null;
+
+        size_t pos = size * (char*).sizeof;
+        char** p = cast(char**)realloc(null, pos);
         if (p is null) return null;
 
-        formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0);
-
-        p[i] = cast(char*)pos;
-        pos += len;
+        Dl_info info;
+        foreach (i, addr; buffer[0 .. size])
+        {
+            if (dladdr(addr, &info) == 0)
+                (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
+            fixupDLInfo(addr, info);
+
+            immutable len = formatStackFrame(null, 0, addr, info);
+            assert(len > 0);
+
+            p = cast(char**)realloc(p, pos + len);
+            if (p is null) return null;
+
+            formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0);
+
+            p[i] = cast(char*)pos;
+            pos += len;
+        }
+        foreach (i; 0 .. size)
+        {
+            pos = cast(size_t)p[i];
+            p[i] = cast(char*)p + pos;
+        }
+        return p;
     }
-    foreach (i; 0 .. size)
+
+
+    extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd)
     {
-        pos = cast(size_t)p[i];
-        p[i] = cast(char*)p + pos;
+        import core.sys.posix.unistd : write;
+        import core.stdc.stdlib : alloca;
+
+        if (size <= 0) return;
+
+        Dl_info info;
+        foreach (i, addr; buffer[0 .. size])
+        {
+            if (dladdr(addr, &info) == 0)
+                (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
+            fixupDLInfo(addr, info);
+
+            enum maxAlloca = 1024;
+            enum min = (size_t a, size_t b) => a <= b ? a : b;
+            immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca);
+            assert(len > 0);
+
+            auto p = cast(char*)alloca(len);
+            if (p is null) return;
+
+            formatStackFrame(p, len, addr, info) >= len || assert(0);
+            p[len - 1] = '\n';
+            write(fd, p, len);
+        }
     }
-    return p;
-}
 
 
-extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd)
-{
-    import core.sys.posix.unistd : write;
-    import core.stdc.stdlib : alloca;
+    private void fixupDLInfo(const(void)* addr, ref Dl_info info)
+    {
+        if (info.dli_fname is null) info.dli_fname = "???";
+        if (info.dli_fbase is null) info.dli_fbase = null;
+        if (info.dli_sname is null) info.dli_sname = "???";
+        if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr;
+    }
 
-    if (size <= 0) return;
 
-    Dl_info info;
-    foreach (i, addr; buffer[0 .. size])
+    private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info)
     {
-        if (dladdr(addr, &info) == 0)
-            (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
-        fixupDLInfo(addr, info);
+        import core.stdc.stdio : snprintf;
 
-        enum maxAlloca = 1024;
-        enum min = (size_t a, size_t b) => a <= b ? a : b;
-        immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca);
+        immutable off = addr - info.dli_saddr;
+        immutable len = snprintf(p, plen, "%p <%s+%zd> at %s",
+                                 addr, info.dli_sname, off, info.dli_fname);
         assert(len > 0);
-
-        auto p = cast(char*)alloca(len);
-        if (p is null) return;
-
-        formatStackFrame(p, len, addr, info) >= len || assert(0);
-        p[len - 1] = '\n';
-        write(fd, p, len);
+        return cast(size_t)len + 1; // + '\0'
     }
 }
-
-
-private void fixupDLInfo(const(void)* addr, ref Dl_info info)
-{
-    if (info.dli_fname is null) info.dli_fname = "???";
-    if (info.dli_fbase is null) info.dli_fbase = null;
-    if (info.dli_sname is null) info.dli_sname = "???";
-    if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr;
-}
-
-
-private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info)
-{
-    import core.stdc.stdio : snprintf;
-
-    immutable off = addr - info.dli_saddr;
-    immutable len = snprintf(p, plen, "%p <%s+%zd> at %s",
-                             addr, info.dli_sname, off, info.dli_fname);
-    assert(len > 0);
-    return cast(size_t)len + 1; // + '\0'
-}
diff --git a/libphobos/libdruntime/core/sys/freebsd/execinfo.d b/libphobos/libdruntime/core/sys/freebsd/execinfo.d
index 7b4ad6c03c4..cbdf70219dc 100644
--- a/libphobos/libdruntime/core/sys/freebsd/execinfo.d
+++ b/libphobos/libdruntime/core/sys/freebsd/execinfo.d
@@ -12,122 +12,136 @@  version (FreeBSD):
 extern (C):
 nothrow:
 
-import core.sys.freebsd.dlfcn;
+version (GNU)
+    version = BacktraceExternal;
 
-// Use extern (D) so that these functions don't collide with libexecinfo.
-
-extern (D) int backtrace(void** buffer, int size)
+version (BacktraceExternal)
 {
-    import core.thread : thread_stackBottom;
-
-    void** p, pend=cast(void**)thread_stackBottom();
-    version (D_InlineAsm_X86)
-        asm nothrow @trusted { mov p[EBP], EBP; }
-    else version (D_InlineAsm_X86_64)
-        asm nothrow @trusted { mov p[RBP], RBP; }
-    else
-        static assert(false, "Architecture not supported.");
-
-    int i;
-    for (; i < size && p < pend; ++i)
-    {
-        buffer[i] = *(p + 1);
-        auto pnext = cast(void**)*p;
-        if (pnext <= p) break;
-        p = pnext;
-    }
-    return i;
+    size_t backtrace(void**, size_t);
+    char** backtrace_symbols(const(void*)*, size_t);
+    void backtrace_symbols_fd(const(void*)*, size_t, int);
+    char** backtrace_symbols_fmt(const(void*)*, size_t, const char*);
+    int backtrace_symbols_fd_fmt(const(void*)*, size_t, int, const char*);
 }
+else
+{
+    import core.sys.freebsd.dlfcn;
 
+    // Use extern (D) so that these functions don't collide with libexecinfo.
 
-extern (D) char** backtrace_symbols(const(void*)* buffer, int size)
-{
-    static void* realloc(void* p, size_t len) nothrow
+    extern (D) int backtrace(void** buffer, int size)
     {
-        static import cstdlib=core.stdc.stdlib;
-        auto res = cstdlib.realloc(p, len);
-        if (res is null) cstdlib.free(p);
-        return res;
+        import core.thread : thread_stackBottom;
+
+        void** p, pend=cast(void**)thread_stackBottom();
+        version (D_InlineAsm_X86)
+            asm nothrow @trusted { mov p[EBP], EBP; }
+        else version (D_InlineAsm_X86_64)
+            asm nothrow @trusted { mov p[RBP], RBP; }
+        else
+            static assert(false, "Architecture not supported.");
+
+        int i;
+        for (; i < size && p < pend; ++i)
+        {
+            buffer[i] = *(p + 1);
+            auto pnext = cast(void**)*p;
+            if (pnext <= p) break;
+            p = pnext;
+        }
+        return i;
     }
 
-    if (size <= 0) return null;
-
-    size_t pos = size * (char*).sizeof;
-    char** p = cast(char**)realloc(null, pos);
-    if (p is null) return null;
 
-    Dl_info info;
-    foreach (i, addr; buffer[0 .. size])
+    extern (D) char** backtrace_symbols(const(void*)* buffer, int size)
     {
-        if (dladdr(addr, &info) == 0)
-            (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
-        fixupDLInfo(addr, info);
-
-        immutable len = formatStackFrame(null, 0, addr, info);
-        assert(len > 0);
-
-        p = cast(char**)realloc(p, pos + len);
+        static void* realloc(void* p, size_t len) nothrow
+        {
+            static import cstdlib=core.stdc.stdlib;
+            auto res = cstdlib.realloc(p, len);
+            if (res is null) cstdlib.free(p);
+            return res;
+        }
+
+        if (size <= 0) return null;
+
+        size_t pos = size * (char*).sizeof;
+        char** p = cast(char**)realloc(null, pos);
         if (p is null) return null;
 
-        formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0);
-
-        p[i] = cast(char*)pos;
-        pos += len;
+        Dl_info info;
+        foreach (i, addr; buffer[0 .. size])
+        {
+            if (dladdr(addr, &info) == 0)
+                (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
+            fixupDLInfo(addr, info);
+
+            immutable len = formatStackFrame(null, 0, addr, info);
+            assert(len > 0);
+
+            p = cast(char**)realloc(p, pos + len);
+            if (p is null) return null;
+
+            formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0);
+
+            p[i] = cast(char*)pos;
+            pos += len;
+        }
+        foreach (i; 0 .. size)
+        {
+            pos = cast(size_t)p[i];
+            p[i] = cast(char*)p + pos;
+        }
+        return p;
     }
-    foreach (i; 0 .. size)
+
+
+    extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd)
     {
-        pos = cast(size_t)p[i];
-        p[i] = cast(char*)p + pos;
+        import core.sys.posix.unistd : write;
+        import core.stdc.stdlib : alloca;
+
+        if (size <= 0) return;
+
+        Dl_info info;
+        foreach (i, addr; buffer[0 .. size])
+        {
+            if (dladdr(addr, &info) == 0)
+                (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
+            fixupDLInfo(addr, info);
+
+            enum maxAlloca = 1024;
+            enum min = (size_t a, size_t b) => a <= b ? a : b;
+            immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca);
+            assert(len > 0);
+
+            auto p = cast(char*)alloca(len);
+            if (p is null) return;
+
+            formatStackFrame(p, len, addr, info) >= len || assert(0);
+            p[len - 1] = '\n';
+            write(fd, p, len);
+        }
     }
-    return p;
-}
 
 
-extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd)
-{
-    import core.sys.posix.unistd : write;
-    import core.stdc.stdlib : alloca;
+    private void fixupDLInfo(const(void)* addr, ref Dl_info info)
+    {
+        if (info.dli_fname is null) info.dli_fname = "???";
+        if (info.dli_fbase is null) info.dli_fbase = null;
+        if (info.dli_sname is null) info.dli_sname = "???";
+        if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr;
+    }
 
-    if (size <= 0) return;
 
-    Dl_info info;
-    foreach (i, addr; buffer[0 .. size])
+    private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info)
     {
-        if (dladdr(addr, &info) == 0)
-            (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
-        fixupDLInfo(addr, info);
+        import core.stdc.stdio : snprintf;
 
-        enum maxAlloca = 1024;
-        enum min = (size_t a, size_t b) => a <= b ? a : b;
-        immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca);
+        immutable off = addr - info.dli_saddr;
+        immutable len = snprintf(p, plen, "%p <%s+%zd> at %s",
+                                 addr, info.dli_sname, off, info.dli_fname);
         assert(len > 0);
-
-        auto p = cast(char*)alloca(len);
-        if (p is null) return;
-
-        formatStackFrame(p, len, addr, info) >= len || assert(0);
-        p[len - 1] = '\n';
-        write(fd, p, len);
+        return cast(size_t)len + 1; // + '\0'
     }
 }
-
-
-private void fixupDLInfo(const(void)* addr, ref Dl_info info)
-{
-    if (info.dli_fname is null) info.dli_fname = "???";
-    if (info.dli_fbase is null) info.dli_fbase = null;
-    if (info.dli_sname is null) info.dli_sname = "???";
-    if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr;
-}
-
-
-private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info)
-{
-    import core.stdc.stdio : snprintf;
-
-    immutable off = addr - info.dli_saddr;
-    immutable len = snprintf(p, plen, "%p <%s+%zd> at %s",
-                             addr, info.dli_sname, off, info.dli_fname);
-    assert(len > 0);
-    return cast(size_t)len + 1; // + '\0'
-}
diff --git a/libphobos/libdruntime/core/sys/netbsd/execinfo.d b/libphobos/libdruntime/core/sys/netbsd/execinfo.d
index 6287557a7e3..97b2a45d365 100644
--- a/libphobos/libdruntime/core/sys/netbsd/execinfo.d
+++ b/libphobos/libdruntime/core/sys/netbsd/execinfo.d
@@ -12,122 +12,136 @@  version (NetBSD):
 extern (C):
 nothrow:
 
-import core.sys.netbsd.dlfcn;
+version (GNU)
+    version = BacktraceExternal;
 
-// Use extern (D) so that these functions don't collide with libexecinfo.
-
-extern (D) int backtrace(void** buffer, int size)
+version (BacktraceExternal)
 {
-    import core.thread : thread_stackBottom;
-
-    void** p, pend=cast(void**)thread_stackBottom();
-    version (D_InlineAsm_X86)
-        asm nothrow @trusted { mov p[EBP], EBP; }
-    else version (D_InlineAsm_X86_64)
-        asm nothrow @trusted { mov p[RBP], RBP; }
-    else
-        static assert(false, "Architecture not supported.");
-
-    int i;
-    for (; i < size && p < pend; ++i)
-    {
-        buffer[i] = *(p + 1);
-        auto pnext = cast(void**)*p;
-        if (pnext <= p) break;
-        p = pnext;
-    }
-    return i;
+    size_t backtrace(void**, size_t);
+    char** backtrace_symbols(const(void*)*, size_t);
+    void backtrace_symbols_fd(const(void*)*, size_t, int);
+    char** backtrace_symbols_fmt(const(void*)*, size_t, const char*);
+    int backtrace_symbols_fd_fmt(const(void*)*, size_t, int, const char*);
 }
+else
+{
+    import core.sys.netbsd.dlfcn;
 
+    // Use extern (D) so that these functions don't collide with libexecinfo.
 
-extern (D) char** backtrace_symbols(const(void*)* buffer, int size)
-{
-    static void* realloc(void* p, size_t len) nothrow
+    extern (D) int backtrace(void** buffer, int size)
     {
-        static import cstdlib=core.stdc.stdlib;
-        auto res = cstdlib.realloc(p, len);
-        if (res is null) cstdlib.free(p);
-        return res;
+        import core.thread : thread_stackBottom;
+
+        void** p, pend=cast(void**)thread_stackBottom();
+        version (D_InlineAsm_X86)
+            asm nothrow @trusted { mov p[EBP], EBP; }
+        else version (D_InlineAsm_X86_64)
+            asm nothrow @trusted { mov p[RBP], RBP; }
+        else
+            static assert(false, "Architecture not supported.");
+
+        int i;
+        for (; i < size && p < pend; ++i)
+        {
+            buffer[i] = *(p + 1);
+            auto pnext = cast(void**)*p;
+            if (pnext <= p) break;
+            p = pnext;
+        }
+        return i;
     }
 
-    if (size <= 0) return null;
-
-    size_t pos = size * (char*).sizeof;
-    char** p = cast(char**)realloc(null, pos);
-    if (p is null) return null;
 
-    Dl_info info;
-    foreach (i, addr; buffer[0 .. size])
+    extern (D) char** backtrace_symbols(const(void*)* buffer, int size)
     {
-        if (dladdr(addr, &info) == 0)
-            (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
-        fixupDLInfo(addr, info);
-
-        immutable len = formatStackFrame(null, 0, addr, info);
-        assert(len > 0);
-
-        p = cast(char**)realloc(p, pos + len);
+        static void* realloc(void* p, size_t len) nothrow
+        {
+            static import cstdlib=core.stdc.stdlib;
+            auto res = cstdlib.realloc(p, len);
+            if (res is null) cstdlib.free(p);
+            return res;
+        }
+
+        if (size <= 0) return null;
+
+        size_t pos = size * (char*).sizeof;
+        char** p = cast(char**)realloc(null, pos);
         if (p is null) return null;
 
-        formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0);
-
-        p[i] = cast(char*)pos;
-        pos += len;
+        Dl_info info;
+        foreach (i, addr; buffer[0 .. size])
+        {
+            if (dladdr(addr, &info) == 0)
+                (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
+            fixupDLInfo(addr, info);
+
+            immutable len = formatStackFrame(null, 0, addr, info);
+            assert(len > 0);
+
+            p = cast(char**)realloc(p, pos + len);
+            if (p is null) return null;
+
+            formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0);
+
+            p[i] = cast(char*)pos;
+            pos += len;
+        }
+        foreach (i; 0 .. size)
+        {
+            pos = cast(size_t)p[i];
+            p[i] = cast(char*)p + pos;
+        }
+        return p;
     }
-    foreach (i; 0 .. size)
+
+
+    extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd)
     {
-        pos = cast(size_t)p[i];
-        p[i] = cast(char*)p + pos;
+        import core.sys.posix.unistd : write;
+        import core.stdc.stdlib : alloca;
+
+        if (size <= 0) return;
+
+        Dl_info info;
+        foreach (i, addr; buffer[0 .. size])
+        {
+            if (dladdr(addr, &info) == 0)
+                (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
+            fixupDLInfo(addr, info);
+
+            enum maxAlloca = 1024;
+            enum min = (size_t a, size_t b) => a <= b ? a : b;
+            immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca);
+            assert(len > 0);
+
+            auto p = cast(char*)alloca(len);
+            if (p is null) return;
+
+            formatStackFrame(p, len, addr, info) >= len || assert(0);
+            p[len - 1] = '\n';
+            write(fd, p, len);
+        }
     }
-    return p;
-}
 
 
-extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd)
-{
-    import core.sys.posix.unistd : write;
-    import core.stdc.stdlib : alloca;
+    private void fixupDLInfo(const(void)* addr, ref Dl_info info)
+    {
+        if (info.dli_fname is null) info.dli_fname = "???";
+        if (info.dli_fbase is null) info.dli_fbase = null;
+        if (info.dli_sname is null) info.dli_sname = "???";
+        if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr;
+    }
 
-    if (size <= 0) return;
 
-    Dl_info info;
-    foreach (i, addr; buffer[0 .. size])
+    private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info)
     {
-        if (dladdr(addr, &info) == 0)
-            (cast(ubyte*)&info)[0 .. info.sizeof] = 0;
-        fixupDLInfo(addr, info);
+        import core.stdc.stdio : snprintf;
 
-        enum maxAlloca = 1024;
-        enum min = (size_t a, size_t b) => a <= b ? a : b;
-        immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca);
+        immutable off = addr - info.dli_saddr;
+        immutable len = snprintf(p, plen, "%p <%s+%zd> at %s",
+                                 addr, info.dli_sname, off, info.dli_fname);
         assert(len > 0);
-
-        auto p = cast(char*)alloca(len);
-        if (p is null) return;
-
-        formatStackFrame(p, len, addr, info) >= len || assert(0);
-        p[len - 1] = '\n';
-        write(fd, p, len);
+        return cast(size_t)len + 1; // + '\0'
     }
 }
-
-
-private void fixupDLInfo(const(void)* addr, ref Dl_info info)
-{
-    if (info.dli_fname is null) info.dli_fname = "???";
-    if (info.dli_fbase is null) info.dli_fbase = null;
-    if (info.dli_sname is null) info.dli_sname = "???";
-    if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr;
-}
-
-
-private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info)
-{
-    import core.stdc.stdio : snprintf;
-
-    immutable off = addr - info.dli_saddr;
-    immutable len = snprintf(p, plen, "%p <%s+%zd> at %s",
-                             addr, info.dli_sname, off, info.dli_fname);
-    assert(len > 0);
-    return cast(size_t)len + 1; // + '\0'
-}