-
Notifications
You must be signed in to change notification settings - Fork 3
/
backtraced.d
215 lines (179 loc) · 6.32 KB
/
backtraced.d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
module backtraced;
version(Windows)
{
pragma(lib, "dbghelp.lib");
import core.sys.windows.windows;
import core.sys.windows.dbghelp;
import core.stdc.stdlib: free, calloc;
import core.stdc.stdio: fprintf, stderr;
import core.stdc.string: memcpy, strncmp, strlen;
struct SYMBOL_INFO {
ULONG SizeOfStruct;
ULONG TypeIndex;
ULONG64[2] Reserved;
ULONG Index;
ULONG Size;
ULONG64 ModBase;
ULONG Flags;
ULONG64 Value;
ULONG64 Address;
ULONG Register;
ULONG Scope;
ULONG Tag;
ULONG NameLen;
ULONG MaxNameLen;
CHAR[1] Name;
}
extern(Windows) USHORT RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID *BackTrace, PULONG BackTraceHash);
extern(Windows) BOOL SymFromAddr(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, SYMBOL_INFO* Symbol);
extern(Windows) BOOL SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, IMAGEHLP_LINEA64 *line);
extern(Windows)LONG TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{
fprintf(stderr, "-------------------------------------------------------------------+\r\n");
fprintf(stderr, "Received signal '%s' (%ull)\r\n", "exception".ptr, pExceptionInfo.ExceptionRecord.ExceptionCode);
fprintf(stderr, "-------------------------------------------------------------------+\r\n");
enum MAX_DEPTH = 32;
void*[MAX_DEPTH] stack;
HANDLE process = GetCurrentProcess();
SymInitialize(process, null, true);
SymSetOptions(SYMOPT_LOAD_LINES);
ushort frames = RtlCaptureStackBackTrace(0, MAX_DEPTH, stack.ptr, null);
SYMBOL_INFO* symbol = cast(SYMBOL_INFO*) calloc((SYMBOL_INFO.sizeof) + 256 * char.sizeof, 1);
symbol.MaxNameLen = 255;
symbol.SizeOfStruct = SYMBOL_INFO.sizeof;
IMAGEHLP_LINEA64 line = void;
line.SizeOfStruct = SYMBOL_INFO.sizeof;
DWORD dwDisplacement;
for (uint i = 0; i < frames; i++)
{
SymFromAddr(process, cast(DWORD64)(stack[i]), null, symbol);
SymGetLineFromAddr64(process, cast(DWORD64)(stack[i]), &dwDisplacement, &line);
// auto f = frames - i - 1;
auto funcName = symbol.Name.ptr;
auto fname = line.FileName;
auto lnum = line.LineNumber;
if (ends_with(fname, __FILE__)) continue; // skip trace from this module
fprintf(stderr, "%s:%i - %s\n", fname, lnum, funcName);
}
free(symbol);
return EXCEPTION_CONTINUE_SEARCH;
}
int ends_with(const(char)* str, const(char)* suffix)
{
if (!str || !suffix)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}
extern(C) export void register()
{
SetUnhandledExceptionFilter(&TopLevelExceptionHandler);
}
}
version(Posix)
{
import core.stdc.signal: SIGSEGV, SIGFPE, SIGILL, SIGABRT, signal;
import core.stdc.stdlib: free, exit;
import core.stdc.string: strlen, memcpy;
import core.stdc.stdio: fprintf, stderr, sprintf, fgets, fclose, FILE;
import core.sys.posix.unistd: STDERR_FILENO, readlink;
import core.sys.posix.signal: SIGUSR1;
import core.sys.posix.stdio: popen, pclose;
import core.sys.linux.execinfo: backtrace, backtrace_symbols;
import core.sys.linux.dlfcn: dladdr, dladdr1, Dl_info, RTLD_DL_LINKMAP;
import core.sys.linux.link: link_map;
import core.demangle: demangle;
extern(C) export void register()
{
signal(SIGSEGV, &handler);
signal(SIGUSR1, &handler);
}
// TODO: clean this mess
// TODO: use core.demangle instead
extern (C) void handler(int sig) nothrow @nogc
{
enum MAX_DEPTH = 32;
string signal_string;
switch (sig)
{
case SIGSEGV:
signal_string = "SIGSEGV";
break;
case SIGFPE:
signal_string = "SIGFPE";
break;
case SIGILL:
signal_string = "SIGILL";
break;
case SIGABRT:
signal_string = "SIGABRT";
break;
default:
signal_string = "unknown";
break;
}
fprintf(stderr, "-------------------------------------------------------------------+\r\n");
fprintf(stderr, "Received signal '%s' (%d)\r\n", signal_string.ptr, sig);
fprintf(stderr, "-------------------------------------------------------------------+\r\n");
void*[MAX_DEPTH] trace;
int stack_depth = backtrace(&trace[0], MAX_DEPTH);
char** strings = backtrace_symbols(&trace[0], stack_depth);
enum BUF_SIZE = 1024;
char[BUF_SIZE] syscom = 0;
char[BUF_SIZE] my_exe = 0;
char[BUF_SIZE] output = 0;
readlink("/proc/self/exe", &my_exe[0], BUF_SIZE);
fprintf(stderr, "executable: %s\n", &my_exe[0]);
fprintf(stderr, "backtrace: %i\n", stack_depth);
for (auto i = 2; i < stack_depth; ++i)
{
auto line = strings[i];
auto len = strlen(line);
bool insideParenthesis;
int startParenthesis;
int endParenthesis;
for (int j = 0; j < len; j++)
{
// ()
if (!insideParenthesis && line[j] == '(')
{
insideParenthesis = true;
startParenthesis = j + 1;
}
else if (insideParenthesis && line[j] == ')')
{
insideParenthesis = false;
endParenthesis = j;
}
}
auto addr = convert_to_vma(cast(size_t) trace[i]);
FILE* fp;
auto locLen = sprintf(&syscom[0], "addr2line -e %s %p | ddemangle", &my_exe[0], addr);
fp = popen(&syscom[0], "r");
auto loc = fgets(&output[0], output.length, fp);
fclose(fp);
// printf("loc: %s\n", loc);
auto getLen = strlen(output.ptr);
char[256] func = 0;
memcpy(func.ptr, &line[startParenthesis], (endParenthesis - startParenthesis));
sprintf(&syscom[0], "echo '%s' | ddemangle", func.ptr);
fp = popen(&syscom[0], "r");
output[getLen - 1] = ' '; // strip new line
auto locD = fgets(&output[getLen], cast(int)(output.length - getLen), fp);
fclose(fp);
fprintf(stderr, "%s", output.ptr);
}
exit(-1);
}
// https://stackoverflow.com/questions/56046062/linux-addr2line-command-returns-0/63856113#63856113
size_t convert_to_vma(size_t addr) nothrow @nogc
{
Dl_info info;
link_map* link_map;
dladdr1(cast(void*) addr, &info, cast(void**)&link_map, RTLD_DL_LINKMAP);
return addr - link_map.l_addr;
}
}