|
| 1 | +/** |
| 2 | + * DragonFlyBSD implementation of glibc's $(LINK2 http://www.gnu.org/software/libc/manual/html_node/Backtraces.html backtrace) facility. |
| 3 | + * |
| 4 | + * Copyright: Copyright Martin Nowak 2012. |
| 5 | + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) |
| 6 | + * Authors: Martin Nowak,Diederik de Groot(port:DragonFlyBSD) |
| 7 | + * Copied: From core/sys/freebsd/sys |
| 8 | + */ |
| 9 | +module core.sys.dragonflybsd.execinfo; |
| 10 | + |
| 11 | +version (DragonFlyBSD): |
| 12 | + |
| 13 | +extern (C) nothrow @system: |
| 14 | + |
| 15 | +import core.sys.dragonflybsd.dlfcn; |
| 16 | + |
| 17 | +// Use extern (D) so that these functions don't collide with libexecinfo. |
| 18 | + |
| 19 | +extern (D) int backtrace(void** buffer, int size) |
| 20 | +{ |
| 21 | + import core.thread : thread_stackBottom; |
| 22 | + |
| 23 | + void** p, pend=cast(void**)thread_stackBottom(); |
| 24 | + version (D_InlineAsm_X86) |
| 25 | + asm nothrow @trusted { mov p[EBP], EBP; } |
| 26 | + else version (D_InlineAsm_X86_64) |
| 27 | + asm nothrow @trusted { mov p[RBP], RBP; } |
| 28 | + else |
| 29 | + static assert(false, "Architecture not supported."); |
| 30 | + |
| 31 | + int i; |
| 32 | + for (; i < size && p < pend; ++i) |
| 33 | + { |
| 34 | + buffer[i] = *(p + 1); |
| 35 | + auto pnext = cast(void**)*p; |
| 36 | + if (pnext <= p) break; |
| 37 | + p = pnext; |
| 38 | + } |
| 39 | + return i; |
| 40 | +} |
| 41 | + |
| 42 | + |
| 43 | +extern (D) char** backtrace_symbols(const(void*)* buffer, int size) |
| 44 | +{ |
| 45 | + static void* realloc(void* p, size_t len) nothrow |
| 46 | + { |
| 47 | + static import cstdlib=core.stdc.stdlib; |
| 48 | + auto res = cstdlib.realloc(p, len); |
| 49 | + if (res is null) cstdlib.free(p); |
| 50 | + return res; |
| 51 | + } |
| 52 | + |
| 53 | + if (size <= 0) return null; |
| 54 | + |
| 55 | + size_t pos = size * (char*).sizeof; |
| 56 | + char** p = cast(char**)realloc(null, pos); |
| 57 | + if (p is null) return null; |
| 58 | + |
| 59 | + Dl_info info; |
| 60 | + foreach (i, addr; buffer[0 .. size]) |
| 61 | + { |
| 62 | + if (dladdr(addr, &info) == 0) |
| 63 | + (cast(ubyte*)&info)[0 .. info.sizeof] = 0; |
| 64 | + fixupDLInfo(addr, info); |
| 65 | + |
| 66 | + immutable len = formatStackFrame(null, 0, addr, info); |
| 67 | + assert(len > 0); |
| 68 | + |
| 69 | + p = cast(char**)realloc(p, pos + len); |
| 70 | + if (p is null) return null; |
| 71 | + |
| 72 | + formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0); |
| 73 | + |
| 74 | + p[i] = cast(char*)pos; |
| 75 | + pos += len; |
| 76 | + } |
| 77 | + foreach (i; 0 .. size) |
| 78 | + { |
| 79 | + pos = cast(size_t)p[i]; |
| 80 | + p[i] = cast(char*)p + pos; |
| 81 | + } |
| 82 | + return p; |
| 83 | +} |
| 84 | + |
| 85 | + |
| 86 | +extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd) |
| 87 | +{ |
| 88 | + import core.sys.posix.unistd : write; |
| 89 | + import core.stdc.stdlib : alloca; |
| 90 | + |
| 91 | + if (size <= 0) return; |
| 92 | + |
| 93 | + Dl_info info; |
| 94 | + foreach (i, addr; buffer[0 .. size]) |
| 95 | + { |
| 96 | + if (dladdr(addr, &info) == 0) |
| 97 | + (cast(ubyte*)&info)[0 .. info.sizeof] = 0; |
| 98 | + fixupDLInfo(addr, info); |
| 99 | + |
| 100 | + enum maxAlloca = 1024; |
| 101 | + enum min = (size_t a, size_t b) => a <= b ? a : b; |
| 102 | + immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca); |
| 103 | + assert(len > 0); |
| 104 | + |
| 105 | + auto p = cast(char*)alloca(len); |
| 106 | + if (p is null) return; |
| 107 | + |
| 108 | + formatStackFrame(p, len, addr, info) >= len || assert(0); |
| 109 | + p[len - 1] = '\n'; |
| 110 | + write(fd, p, len); |
| 111 | + } |
| 112 | +} |
| 113 | + |
| 114 | + |
| 115 | +private void fixupDLInfo(const(void)* addr, ref Dl_info info) |
| 116 | +{ |
| 117 | + if (info.dli_fname is null) info.dli_fname = "???"; |
| 118 | + if (info.dli_fbase is null) info.dli_fbase = null; |
| 119 | + if (info.dli_sname is null) info.dli_sname = "???"; |
| 120 | + if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr; |
| 121 | +} |
| 122 | + |
| 123 | + |
| 124 | +private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info) |
| 125 | +{ |
| 126 | + import core.stdc.stdio : snprintf; |
| 127 | + |
| 128 | + immutable off = addr - info.dli_saddr; |
| 129 | + immutable len = snprintf(p, plen, "%p <%s+%zd> at %s", |
| 130 | + addr, info.dli_sname, off, info.dli_fname); |
| 131 | + assert(len > 0); |
| 132 | + return cast(size_t)len + 1; // + '\0' |
| 133 | +} |
0 commit comments