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 extern (C): 13 nothrow: 14 15 version (GNU) 16 version = BacktraceExternal; 17 18 version (BacktraceExternal) 19 { 20 size_t backtrace(void**, size_t); 21 char** backtrace_symbols(const(void*)*, size_t); 22 void backtrace_symbols_fd(const(void*)*, size_t, int); 23 char** backtrace_symbols_fmt(const(void*)*, size_t, const char*); 24 int backtrace_symbols_fd_fmt(const(void*)*, size_t, int, const char*); 25 } 26 else 27 { 28 import core.sys.dragonflybsd.dlfcn; 29 30 // Use extern (D) so that these functions don't collide with libexecinfo. 31 32 extern (D) int backtrace(void** buffer, int size) 33 { 34 import core.thread : thread_stackBottom; 35 36 void** p, pend=cast(void**)thread_stackBottom(); 37 version (D_InlineAsm_X86) 38 asm nothrow @trusted { mov p[EBP], EBP; } 39 else version (D_InlineAsm_X86_64) 40 asm nothrow @trusted { mov p[RBP], RBP; } 41 else 42 static assert(false, "Architecture not supported."); 43 44 int i; 45 for (; i < size && p < pend; ++i) 46 { 47 buffer[i] = *(p + 1); 48 auto pnext = cast(void**)*p; 49 if (pnext <= p) break; 50 p = pnext; 51 } 52 return i; 53 } 54 55 56 extern (D) char** backtrace_symbols(const(void*)* buffer, int size) 57 { 58 static void* realloc(void* p, size_t len) nothrow 59 { 60 static import cstdlib=core.stdc.stdlib; 61 auto res = cstdlib.realloc(p, len); 62 if (res is null) cstdlib.free(p); 63 return res; 64 } 65 66 if (size <= 0) return null; 67 68 size_t pos = size * (char*).sizeof; 69 char** p = cast(char**)realloc(null, pos); 70 if (p is null) return null; 71 72 Dl_info info; 73 foreach (i, addr; buffer[0 .. size]) 74 { 75 if (dladdr(addr, &info) == 0) 76 (cast(ubyte*)&info)[0 .. info.sizeof] = 0; 77 fixupDLInfo(addr, info); 78 79 immutable len = formatStackFrame(null, 0, addr, info); 80 assert(len > 0); 81 82 p = cast(char**)realloc(p, pos + len); 83 if (p is null) return null; 84 85 formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0); 86 87 p[i] = cast(char*)pos; 88 pos += len; 89 } 90 foreach (i; 0 .. size) 91 { 92 pos = cast(size_t)p[i]; 93 p[i] = cast(char*)p + pos; 94 } 95 return p; 96 } 97 98 99 extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd) 100 { 101 import core.sys.posix.unistd : write; 102 import core.stdc.stdlib : alloca; 103 104 if (size <= 0) return; 105 106 Dl_info info; 107 foreach (i, addr; buffer[0 .. size]) 108 { 109 if (dladdr(addr, &info) == 0) 110 (cast(ubyte*)&info)[0 .. info.sizeof] = 0; 111 fixupDLInfo(addr, info); 112 113 enum maxAlloca = 1024; 114 enum min = (size_t a, size_t b) => a <= b ? a : b; 115 immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca); 116 assert(len > 0); 117 118 auto p = cast(char*)alloca(len); 119 if (p is null) return; 120 121 formatStackFrame(p, len, addr, info) >= len || assert(0); 122 p[len - 1] = '\n'; 123 write(fd, p, len); 124 } 125 } 126 127 128 private void fixupDLInfo(const(void)* addr, ref Dl_info info) 129 { 130 if (info.dli_fname is null) info.dli_fname = "???"; 131 if (info.dli_fbase is null) info.dli_fbase = null; 132 if (info.dli_sname is null) info.dli_sname = "???"; 133 if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr; 134 } 135 136 137 private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info) 138 { 139 import core.stdc.stdio : snprintf; 140 141 immutable off = addr - info.dli_saddr; 142 immutable len = snprintf(p, plen, "%p <%s+%zd> at %s", 143 addr, info.dli_sname, off, info.dli_fname); 144 assert(len > 0); 145 return cast(size_t)len + 1; // + '\0' 146 } 147 }