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
version(BacktraceExternal)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
backtrace(void ** buffer,int size)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
backtrace_symbols(const (void *)* buffer,int size)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
backtrace_symbols_fd(const (void *)* buffer,int size,int fd)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
fixupDLInfo(const (void)* addr,ref Dl_info info)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
formatStackFrame(char * p,size_t plen,const (void)* addr,const ref Dl_info info)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 }
152