1 //
2 // Copyright (C) 2011-2018 Nick Gasson
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 //
17
18 #include "util.h"
19 #include "rt.h"
20 #include "lib.h"
21 #include "tree.h"
22 #include "common.h"
23 #include "array.h"
24
25 #include <assert.h>
26 #include <limits.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <math.h>
35
36 #ifdef HAVE_EXECINFO_H
37 #include <execinfo.h>
38 #endif
39
40 #ifdef __MINGW32__
41 #define WIN32_LEAN_AND_MEAN
42 #include <windows.h>
43 #else
44 #include <dlfcn.h>
45 #endif
46
47 #define TRACE_MAX 10
48
49 #ifdef __MINGW32__
50 #ifdef _WIN64
51 extern void ___chkstk_ms(void);
52 #else
53 #undef _alloca
54 extern void _alloca(void);
55 #endif
56
57 static HMODULE *search_modules;
58 static size_t nmodules = 0, max_modules = 0;
59
60 #endif
61
jit_find_symbol(const char * name,bool required)62 void *jit_find_symbol(const char *name, bool required)
63 {
64 #if (defined __MINGW32__ || defined __CYGWIN__) && !defined _WIN64
65 if (*name == '_')
66 name++; // Remove leading underscore on 32-bit Windows
67 #endif
68
69 name = safe_symbol(name);
70
71 #ifdef __MINGW32__
72
73 #ifdef _WIN64
74 if (strcmp(name, "___chkstk_ms") == 0)
75 return (void *)(uintptr_t)___chkstk_ms;
76 #else
77 if (strcmp(name, "_alloca") == 0)
78 return (void *)(uintptr_t)_alloca;
79 #endif
80
81 if (strcmp(name, "exp2") == 0)
82 return (void *)(uintptr_t)exp2;
83
84 for (size_t i = 0; i < nmodules; i++) {
85 void *ptr = (void *)(uintptr_t)GetProcAddress(search_modules[i], name);
86 if (ptr != NULL)
87 return ptr;
88 }
89
90 if (required)
91 fatal("cannot find symbol %s", name);
92
93 return NULL;
94
95 #else // __MINGW32__
96
97 dlerror(); // Clear any previous error
98
99 void *sym = dlsym(NULL, name);
100 const char *error = dlerror();
101 if (error != NULL) {
102 sym = dlsym(RTLD_DEFAULT, name);
103 error = dlerror();
104 if ((error != NULL) && required)
105 fatal("%s: %s", name, error);
106 }
107 return sym;
108 #endif
109 }
110
jit_load_module(ident_t name)111 static void jit_load_module(ident_t name)
112 {
113 lib_t lib = lib_find(ident_until(name, '.'), true);
114
115 tree_kind_t kind = lib_index_kind(lib, name);
116 if (kind == T_LAST_TREE_KIND)
117 fatal("Cannot find %s in library %s", istr(name), istr(lib_name(lib)));
118
119 if (kind == T_ENTITY || kind == T_ARCH)
120 return;
121
122 const bool optional = (kind == T_PACKAGE || kind == T_PACK_BODY);
123
124 char *so_fname LOCAL = xasprintf("_%s." DLL_EXT, istr(name));
125
126 char so_path[PATH_MAX];
127 lib_realpath(lib, so_fname, so_path, sizeof(so_path));
128
129 if (access(so_path, F_OK) != 0 && optional)
130 return;
131
132 if (opt_get_int("rt_trace_en"))
133 fprintf(stderr, "TRACE (init): load %s from %s\n", istr(name), so_path);
134
135 #ifdef __MINGW32__
136 HMODULE hModule = LoadLibrary(so_path);
137 if (hModule == NULL)
138 fatal("failed to load %s", so_path);
139
140 ARRAY_APPEND(search_modules, hModule, nmodules, max_modules);
141 #else
142 if (dlopen(so_path, RTLD_LAZY | RTLD_GLOBAL) == NULL)
143 fatal("%s: %s", so_path, dlerror());
144 #endif
145 }
146
jit_init(tree_t top)147 void jit_init(tree_t top)
148 {
149 #ifdef __MINGW32__
150 max_modules = 16;
151 nmodules = 0;
152 search_modules = xmalloc(sizeof(HMODULE) * max_modules);
153 ARRAY_APPEND(search_modules, GetModuleHandle(NULL), nmodules, max_modules);
154 ARRAY_APPEND(search_modules, GetModuleHandle("MSVCRT.DLL"),
155 nmodules, max_modules);
156 #endif
157
158 const int ncontext = tree_contexts(top);
159 for (int i = 0; i < ncontext; i++) {
160 tree_t c = tree_context(top, i);
161 if (tree_kind(c) == T_USE)
162 jit_load_module(tree_ident(c));
163 }
164
165 jit_load_module(tree_ident(top));
166 }
167
jit_shutdown(void)168 void jit_shutdown(void)
169 {
170
171 }
172
jit_trace(jit_trace_t ** trace,size_t * count)173 void jit_trace(jit_trace_t **trace, size_t *count)
174 {
175 #if defined HAVE_EXECINFO_H && defined __linux__
176
177 void *frames[TRACE_MAX];
178 char **messages = NULL;
179 int trace_size = 0;
180
181 trace_size = backtrace(frames, TRACE_MAX);
182 messages = backtrace_symbols(frames, trace_size);
183
184 *count = 0;
185 *trace = xcalloc(sizeof(jit_trace_t) * trace_size);
186
187 for (int i = 0; i < trace_size; i++) {
188 // This hack only works for native compiled code
189 char *begin = strchr(messages[i], '(');
190 char *end = strchr(messages[i], '+');
191
192 if (begin == NULL || end == NULL)
193 continue;
194
195 *end = '\0';
196
197 bool maybe_vhdl = false;
198 for (const char *p = begin + 1; *p != '\0'; p++) {
199 if (isupper((int)*p) || isdigit((int)*p) || *p == '_') {
200 maybe_vhdl = true;
201 continue;
202 }
203 else if (*p == '.') {
204 maybe_vhdl = p > begin + 1;
205 break;
206 }
207 else {
208 maybe_vhdl = false;
209 break;
210 }
211 }
212
213 if (!maybe_vhdl)
214 continue;
215
216 ident_t mangled = ident_new(begin + 1);
217 ident_t lib_name = ident_until(mangled, '.');
218
219 lib_t lib = lib_find(lib_name, false);
220 if (lib == NULL)
221 continue;
222
223 ident_t decl_name = ident_until(mangled, '$');
224
225 ident_t unit_name = ident_runtil(decl_name, '.');
226 tree_t unit = lib_get(lib, unit_name);
227 if (unit == NULL)
228 continue;
229
230 if (tree_kind(unit) == T_PACKAGE) {
231 unit = lib_get(lib, ident_prefix(unit_name, ident_new("body"), '-'));
232 if (unit == NULL)
233 continue;
234 }
235
236 tree_t best = NULL;
237 const int ndecls = tree_decls(unit);
238 for (int i = 0; i < ndecls; i++) {
239 tree_t d = tree_decl(unit, i);
240 if (tree_attr_str(d, mangled_i) == mangled)
241 best = d;
242 else if (tree_ident(d) == decl_name && best == NULL)
243 best = d;
244 }
245
246 if (best == NULL)
247 continue;
248
249 (*trace)[*count].loc = *tree_loc(best);
250 (*trace)[*count].tree = best;
251 (*count)++;
252 }
253
254 free(messages);
255
256 #else
257 *count = 0;
258 *trace = NULL;
259 #endif
260 }
261