2 * NetBSD implementation of glibc's $(LINK2 http://www.gnu.org/software/libc/manual/html_node/Backtraces.html backtrace) facility.
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/netbsd/_execinfo.d)
9 module core
.sys
.netbsd
.execinfo
;
16 version = BacktraceExternal
;
18 version (BacktraceExternal
)
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*);
28 import core
.sys
.netbsd
.dlfcn
;
30 // Use extern (D) so that these functions don't collide with libexecinfo.
32 extern (D
) int backtrace(void** buffer
, int size
)
34 import core
.thread
: thread_stackBottom
;
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
; }
42 static assert(false, "Architecture not supported.");
45 for (; i
< size
&& p
< pend
; ++i
)
48 auto pnext
= cast(void**)*p
;
49 if (pnext
<= p
) break;
56 extern (D
) char** backtrace_symbols(const(void*)* buffer
, int size
)
58 static void* realloc(void* p
, size_t len
) nothrow
60 static import cstdlib
=core
.stdc
.stdlib
;
61 auto res
= cstdlib
.realloc(p
, len
);
62 if (res
is null) cstdlib
.free(p
);
66 if (size
<= 0) return null;
68 size_t pos
= size
* (char*).sizeof
;
69 char** p
= cast(char**)realloc(null, pos
);
70 if (p
is null) return null;
73 foreach (i
, addr
; buffer
[0 .. size
])
75 if (dladdr(addr
, &info
) == 0)
76 (cast(ubyte*)&info
)[0 .. info
.sizeof
] = 0;
77 fixupDLInfo(addr
, info
);
79 immutable len
= formatStackFrame(null, 0, addr
, info
);
82 p
= cast(char**)realloc(p
, pos
+ len
);
83 if (p
is null) return null;
85 formatStackFrame(cast(char*)p
+ pos
, len
, addr
, info
) == len ||
assert(0);
87 p
[i
] = cast(char*)pos
;
90 foreach (i
; 0 .. size
)
92 pos
= cast(size_t
)p
[i
];
93 p
[i
] = cast(char*)p
+ pos
;
99 extern (D
) void backtrace_symbols_fd(const(void*)* buffer
, int size
, int fd
)
101 import core
.sys
.posix
.unistd
: write
;
102 import core
.stdc
.stdlib
: alloca
;
104 if (size
<= 0) return;
107 foreach (i
, addr
; buffer
[0 .. size
])
109 if (dladdr(addr
, &info
) == 0)
110 (cast(ubyte*)&info
)[0 .. info
.sizeof
] = 0;
111 fixupDLInfo(addr
, info
);
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
);
118 auto p
= cast(char*)alloca(len
);
119 if (p
is null) return;
121 formatStackFrame(p
, len
, addr
, info
) >= len ||
assert(0);
128 private void fixupDLInfo(const(void)* addr
, ref Dl_info info
)
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
;
137 private size_t
formatStackFrame(char* p
, size_t plen
, const(void)* addr
, const ref Dl_info info
)
139 import core
.stdc
.stdio
: snprintf
;
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
);
145 return cast(size_t
)len
+ 1; // + '\0'