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