ETISS 0.11.2
ExtendableTranslatingInstructionSetSimulator(version0.11.2)
Loading...
Searching...
No Matches
LibraryInterface.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2//
3// This file is part of ETISS. It is licensed under the BSD 3-Clause License; you may not use this file except in
4// compliance with the License. You should have received a copy of the license along with this project. If not, see the
5// LICENSE file.
17#include "etiss/Misc.h"
18#if ETISS_USE_DLSYM
19#include <dlfcn.h>
20#elif ETISS_USE_GETPROC
21#include <windows.h>
22// defined by windows. clashed with etiss::ERROR
23#undef ERROR
24#endif
25
26using namespace etiss;
27
28LibraryInterface::LibraryInterface(std::string name) : name_(name) {}
30
32{
33 return "UNKNOWN";
34}
35
37{
38 return 0;
39}
41{
42 return 0;
43}
45{
46 return 0;
47}
48
49std::string LibraryInterface::nameJIT(unsigned index)
50{
51 return "";
52}
53std::string LibraryInterface::namePlugin(unsigned index)
54{
55 return "";
56}
57std::string LibraryInterface::nameCPUArch(unsigned index)
58{
59 return "";
60}
61
62etiss::JIT *LibraryInterface::createJIT(unsigned index, std::map<std::string, std::string> options)
63{
64 return 0;
65}
66etiss::CPUArch *LibraryInterface::createCPUArch(unsigned index, std::map<std::string, std::string> options)
67{
68 return 0;
69}
70etiss::Plugin *LibraryInterface::createPlugin(unsigned index, std::map<std::string, std::string> options)
71{
72 return 0;
73}
74
78
80{
81 return countPlugins() == 0 && countCPUArchs() == 0 && countJITs() == 0;
82}
83
84const std::string &LibraryInterface::getName()
85{
86 return name_;
87}
88
89#if ETISS_USE_DLSYM || ETISS_USE_GETPROC
90
91std::mutex ETISS_SharedLibraryInterface_mu_;
92std::set<void *> ETISS_SharedLibraryInterface_handles_;
93
94static std::string ETISS_sdlerror()
95{
96#if ETISS_USE_DLSYM
97 const char *e = dlerror();
98 if (e)
99 return std::string(e);
100#endif
101 return "";
102}
103static void *ETISS_dlsym(void *handle, std::string name, std::string symbol, bool printNotFoundWarning = false)
104{
105#if ETISS_USE_DLSYM
106 std::string fullsymbol = (name + "_" + symbol);
107 void *ret = dlsym(handle, fullsymbol.c_str()); // load function with libaray prefix
108 if (ret == 0 && handle != 0)
109 { // only fallback if not integrated library
110 std::string error = ETISS_sdlerror();
111 ret = dlsym(handle, symbol.c_str()); // fallback to unprefixed function.
112 if (ret != 0)
113 {
114 etiss::log(etiss::WARNING, "a library does not prefix its functions as recommended: declare as \"" + name +
115 "_" + symbol + "\" and not just as \"" + symbol + "\"");
116 }
117 else if (printNotFoundWarning)
118 {
119 etiss::log(etiss::WARNING, "failed to load symbol " + name + "_" + symbol + ": " + error +
120 "[secondary: " + ETISS_sdlerror() + "]");
121 }
122 }
123 return ret;
124#elif ETISS_USE_GETPROC
125 std::string fullsymbol = (name + "_" + symbol);
126 // Technically there is no guarnatee that a function pointer type in C++ can be
127 // Uniquely represented as a void *. Of course on any common general-purpose platform
128 // this is the case...
129 if (!handle)
130 {
131 HMODULE hmodule = NULL;
132 ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
133 reinterpret_cast<LPCTSTR>(&ETISS_dlsym), &hmodule);
134 if (!hmodule)
135 return nullptr;
136 return reinterpret_cast<void *>(reinterpret_cast<intptr_t>(GetProcAddress(hmodule, TEXT(fullsymbol.c_str()))));
137 }
138 else
139 {
140 return reinterpret_cast<void *>(
141 reinterpret_cast<intptr_t>(GetProcAddress((HMODULE)handle, TEXT(fullsymbol.c_str()))));
142 }
143#endif
144 return nullptr;
145}
146static void *ETISS_dlopen(const std::string &path, const std::string &name)
147{
148#if ETISS_USE_DLSYM
149 std::string fullname = path + "lib" + name +
150#ifdef __APPLE__
151 ".dylib";
152#else
153 ".so";
154#endif
155 void *ret = dlopen(fullname.c_str(), RTLD_GLOBAL | RTLD_NOW
157 //|RTLD_DEEPBIND
158#endif
159 );
160 if (!ret)
161 {
162 std::string err = ETISS_sdlerror();
163 ret = dlopen(name.c_str(), RTLD_GLOBAL | RTLD_NOW
165 //|RTLD_DEEPBIND
166#endif
167 );
168 if (ret)
169 etiss::log(etiss::WARNING, std::string("Using fallback library: ") + (name) + ": " + err);
170 else
171 {
172 // set error message right
173 ret = dlopen(fullname.c_str(), RTLD_GLOBAL | RTLD_NOW
175 //|RTLD_DEEPBIND
176#endif
177 );
178 }
179 }
180 return ret;
181#elif ETISS_USE_GETPROC
182 return LoadLibrary(TEXT((path + name).c_str()));
183#endif
184}
185static void ETISS_dlclose(void *handle)
186{
187#if ETISS_USE_DLSYM
188 dlclose(handle);
189#elif ETISS_USE_GETPROC
190 FreeLibrary((HMODULE)handle);
191#endif
192}
193
194class ETISS_SharedLibraryInterface : public LibraryInterface
195{
196 public:
197 ETISS_SharedLibraryInterface(std::string path, std::string name, void *handle)
198 : LibraryInterface(name)
199 , name_(name)
200 , path_(path)
201 , wd_(etiss::cfg().get<std::string>("etiss_wd", "~/.etiss"))
202 , handle_(handle)
203 , isvalid_(true)
204 {
205
206 // version check
207 {
208 typedef unsigned (*version)();
209 version vfunc = (version)ETISS_dlsym(handle_, name_, "etissversion");
210 if (vfunc == 0)
211 {
212 isvalid_ = false;
213 etiss::log(etiss::ERROR, std::string("the library ") + "lib" + name + ".so must implement unsigned " +
214 name + "_etissversion() to check for compability.");
215 }
216 else
217 {
218 unsigned v = vfunc();
219 if (v != getCurrentLibraryVersion())
220 {
221 isvalid_ = false;
223 std::string("the library ") + "lib" + name + ".so" +
224 " was compiled with an incompatible version of etiss. Loading aborted");
225 }
226 }
227 }
228 // try to communicate library location
229 if (isvalid_)
230 {
231 typedef void (*publicateLocation)(const char *path);
232 publicateLocation fnc = (publicateLocation)ETISS_dlsym(handle_, name_, "publicateLocation");
233 if (fnc == 0)
234 {
236 "lib" + name + ".so may implement \'void " + name +
237 "_publicateLocation(const char * path)\' to get the library location at runtime. The "
238 "passed string pointer remains valid as long as the library is loaded.");
239 }
240 else
241 {
242 (*fnc)(path_.c_str());
243 }
244 }
245 // try to communicate etiss workdir
246 if (isvalid_)
247 {
248 typedef void (*publicateWorkdir)(const char *path);
249 publicateWorkdir fnc = (publicateWorkdir)ETISS_dlsym(handle_, name_, "publicateWorkdir");
250 if (fnc == 0)
251 {
253 "lib" + name + ".so may implement \'void " + name +
254 "_publicateWorkdir(const char * path)\' to get the working directory at runtime (path "
255 "will be etiss::cfg().get<std::string>(\"etiss_wd\",\"~/.etiss\")). The passed string "
256 "pointer remains valid as long as the library is loaded.");
257 }
258 else
259 {
260 (*fnc)(wd_.c_str());
261 }
262 }
263
264 version_info_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "versionInfo");
265 if (isvalid_ && !version_info_)
266 {
267 etiss::log(etiss::VERBOSE, "lib" + name + ".so may implement \'const char * " + name +
268 "_versionInfo()\' to provide version/build information about the library");
269 }
270
271 count_plugin_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "countPlugin");
272 count_jit_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "countJIT");
273 count_cpuarch_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "countCPUArch");
274
275 name_jit_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "nameJIT", count_jit_ != 0);
276 name_plugin_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "namePlugin", count_plugin_ != 0);
277 name_cpuarch_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "nameCPUArch", count_cpuarch_ != 0);
278
279 create_plugin_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "createPlugin", count_plugin_ != 0);
280 create_jit_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "createJIT", count_jit_ != 0);
281 create_cpuarch_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "createCPUArch", count_cpuarch_ != 0);
282
283 delete_plugin_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "deletePlugin", count_plugin_ != 0);
284 delete_jit_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "deleteJIT", count_jit_ != 0);
285 delete_cpuarch_ = (!isvalid_) ? 0 : ETISS_dlsym(handle_, name_, "deleteCPUArch", count_cpuarch_ != 0);
286 }
287 virtual ~ETISS_SharedLibraryInterface()
288 {
289 {
290 std::lock_guard<std::mutex> lock(ETISS_SharedLibraryInterface_mu_);
291 ETISS_SharedLibraryInterface_handles_.erase(handle_);
292 }
293 if (handle_ != 0)
294 ETISS_dlclose(handle_);
295 }
296 virtual std::string versionInfo()
297 {
298 typedef const char *(*vi)();
299 if (version_info_)
300 {
301 return ((vi)version_info_)();
302 }
303 else
304 {
306 }
307 }
308 virtual unsigned countPlugins()
309 {
310 typedef unsigned (*count)();
311 if (count_plugin_ && name_plugin_ && create_plugin_)
312 {
313 return ((count)count_plugin_)();
314 }
315 else
316 {
317 return 0;
318 }
319 }
320 virtual unsigned countCPUArchs()
321 {
322 typedef unsigned (*count)();
323 if (count_cpuarch_ && name_cpuarch_ && create_cpuarch_)
324 {
325 return ((count)count_cpuarch_)();
326 }
327 else
328 {
329 return 0;
330 }
331 }
332 virtual unsigned countJITs()
333 {
334 typedef unsigned (*count)();
335 if (count_jit_ && name_jit_ && create_jit_)
336 {
337 return ((count)count_jit_)();
338 }
339 else
340 {
341 return 0;
342 }
343 }
344
345 virtual std::string nameJIT(unsigned index)
346 {
347 typedef const char *(*name)(unsigned index);
348 if (name_jit_)
349 {
350 return std::string(((name)name_jit_)(index));
351 }
352 else
353 {
354 return "";
355 }
356 }
357 virtual std::string namePlugin(unsigned index)
358 {
359 typedef const char *(*name)(unsigned index);
360 if (name_plugin_)
361 {
362 return std::string(((name)name_plugin_)(index));
363 }
364 else
365 {
366 return "";
367 }
368 }
369 virtual std::string nameCPUArch(unsigned index)
370 {
371 typedef const char *(*name)(unsigned index);
372 if (name_cpuarch_)
373 {
374 return std::string(((name)name_cpuarch_)(index));
375 }
376 else
377 {
378 return "";
379 }
380 }
381
382 virtual etiss::JIT *createJIT(unsigned index, std::map<std::string, std::string> options)
383 {
384 typedef etiss::JIT *(*create)(unsigned index, std::map<std::string, std::string> options);
385 if (create_jit_)
386 {
387 return ((create)create_jit_)(index, options);
388 }
389 else
390 {
391 return nullptr;
392 }
393 }
394 virtual etiss::CPUArch *createCPUArch(unsigned index, std::map<std::string, std::string> options)
395 {
396 typedef etiss::CPUArch *(*create)(unsigned index, std::map<std::string, std::string> options);
397 if (create_cpuarch_)
398 {
399 return ((create)create_cpuarch_)(index, options);
400 }
401 else
402 {
403 return nullptr;
404 }
405 }
406 virtual etiss::Plugin *createPlugin(unsigned index, std::map<std::string, std::string> options)
407 {
408 typedef etiss::Plugin *(*create)(unsigned index, std::map<std::string, std::string> options);
409 if (create_plugin_)
410 {
411 return ((create)create_plugin_)(index, options);
412 }
413 else
414 {
415 return nullptr;
416 }
417 }
418
419 virtual void deleteJIT(etiss::JIT *o)
420 {
421 typedef void (*del)(etiss::JIT *);
422 if (delete_jit_)
423 {
424 ((del)delete_jit_)(o);
425 }
426 else
427 {
428 std::cout << "Warning: " << ("lib" + name_ + ".so") << " does not implement void " << name_
429 << "_deleteJIT(etiss::JIT*). Memory leaked." << std::endl;
430 }
431 }
432 virtual void deleteCPUArch(etiss::CPUArch *o)
433 {
434 typedef void (*del)(etiss::CPUArch *);
435 if (delete_cpuarch_)
436 {
437 ((del)delete_cpuarch_)(o);
438 }
439 else
440 {
441 std::cout << "Warning: " << ("lib" + name_ + ".so") << " does not implement void " << name_
442 << "_deleteCPUArch(etiss::CPUArch *). Memory leaked." << std::endl;
443 }
444 }
445 virtual void deletePlugin(etiss::Plugin *o)
446 {
447 typedef void (*del)(etiss::Plugin *);
448 if (delete_plugin_)
449 {
450 ((del)delete_plugin_)(o);
451 }
452 else
453 {
454 std::cout << "Warning: " << ("lib" + name_ + ".so") << " does not implement void " << name_
455 << "_deletePlugin(etiss::Plugin*). Memory leaked." << std::endl;
456 }
457 }
458
459 virtual bool isValid() { return isvalid_; }
460
461 private:
462 const std::string name_;
463 const std::string path_;
464 const std::string wd_;
465 void *handle_;
466 bool isvalid_;
467
468 void *version_info_;
469
470 void *count_plugin_;
471 void *count_jit_;
472 void *count_cpuarch_;
473
474 void *name_jit_;
475 void *name_plugin_;
476 void *name_cpuarch_;
477
478 void *create_plugin_;
479 void *create_jit_;
480 void *create_cpuarch_;
481
482 void *delete_plugin_;
483 void *delete_jit_;
484 void *delete_cpuarch_;
485};
486
487#endif
488
489std::shared_ptr<LibraryInterface> LibraryInterface::openSharedLibrary(std::string path, std::string name)
490{
491#if ETISS_USE_DLSYM || ETISS_USE_GETPROC
492 void *handle;
493 {
494 // check name collision
495 {
496 if (ETISS_dlsym(0, name, "_etissversion"))
497 {
499 std::string("Failed to load library because the name ") + name + " is already in use.");
500 return 0;
501 }
502 }
503
504 if (path.size() > 0)
505 {
506 if (path[path.size() - 1] != '/')
507 path = path + std::string("/");
508 }
509 handle = ETISS_dlopen(path, name);
510 if (handle == 0)
511 {
512 std::string err = ETISS_sdlerror();
513 if (ETISS_dlsym(0, name, "etissversion"))
514 {
516 std::string("Failed to load library: ") + (path + "lib" + name + ".so") + ": " + err);
517 etiss::log(etiss::VERBOSE, std::string("using integrated library: ") + name);
518 }
519 else
520 {
522 std::string("Failed to load library: ") + (path + "lib" + name + ".so") + ": " + err);
523 etiss::log(etiss::ERROR, std::string("Failed to use integrated library: ") + name);
524 return std::shared_ptr<LibraryInterface>(0);
525 }
526 }
527
528 if (handle != 0)
529 {
530 if (ETISS_SharedLibraryInterface_handles_.find(handle) != ETISS_SharedLibraryInterface_handles_.end())
531 {
532 etiss::log(etiss::VERBOSE, "Failed to load library: already loaded.", name);
533 ETISS_dlclose(handle);
534 return 0;
535 }
536 else
537 {
538 ETISS_SharedLibraryInterface_handles_.insert(handle);
539 }
540 }
541 }
542
543 ETISS_SharedLibraryInterface *retptr = new ETISS_SharedLibraryInterface(
544 path, name, handle); // from here on ETISS_SharedLibraryInterface is responsible for the handle
545
546 std::shared_ptr<LibraryInterface> ret(retptr);
547
548 if (!(retptr->isValid()))
549 {
550 if (handle != 0)
551 {
552 std::lock_guard<std::mutex> lock(ETISS_SharedLibraryInterface_mu_);
553 ETISS_SharedLibraryInterface_handles_.erase(handle);
554 }
555 ret.reset();
556 }
557
558 return ret;
559#else
561 "etiss::loadLibrary was compiled without any library loading support. library cannot be loaded.",
563 return nullptr;
564#endif
565}
566
567void LibraryInterface::addSearchPath(const std::string &path)
568{
569#if ETISS_USE_GETPROC
570 int len = (int)path.length() + 1;
571 int newlen = MultiByteToWideChar(CP_ACP, 0, path.c_str(), len, 0, 0);
572 std::vector<wchar_t> buf(newlen);
573 MultiByteToWideChar(CP_ACP, 0, path.c_str(), len, buf.data(), newlen);
574
575 SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
576 AddDllDirectory(buf.data());
577#endif
578}
ETISS_PLUGIN_EXPORT etiss::CPUArch std::map< std::string, std::string > options
create new instance of the CPUArch type at index
class for simple library access.
general configuration and logging
#define ETISS_VARVAL(VAR)
Definition Misc.h:203
#define ETISS_SRCLOC
Definition Misc.h:202
do v
Definition arm_acle.h:76
the interface to translate instructions of and processor architecture
Definition CPUArch.h:116
compiler interface for just in time compilation of generated C code
Definition JIT.h:29
interface class for libraries.
virtual void deletePlugin(etiss::Plugin *)
virtual bool isEmpty()
returns true if this library provides nothing
virtual etiss::CPUArch * createCPUArch(unsigned index, std::map< std::string, std::string > options=std::map< std::string, std::string >())
virtual unsigned countPlugins()
virtual etiss::Plugin * createPlugin(unsigned index, std::map< std::string, std::string > options=std::map< std::string, std::string >())
LibraryInterface(std::string name)
virtual void deleteCPUArch(etiss::CPUArch *)
virtual std::string versionInfo()
simple version info string. intended to present information in a human readable way.
static void addSearchPath(const std::string &path)
virtual void deleteJIT(etiss::JIT *)
virtual unsigned countJITs()
static std::shared_ptr< LibraryInterface > openSharedLibrary(std::string path, std::string name)
virtual std::string nameCPUArch(unsigned index)
virtual unsigned countCPUArchs()
virtual std::string namePlugin(unsigned index)
virtual std::string nameJIT(unsigned index)
virtual const std::string & getName()
virtual etiss::JIT * createJIT(unsigned index, std::map< std::string, std::string > options=std::map< std::string, std::string >())
base plugin class that provides access to different plugin functions if present
Definition Plugin.h:38
#define ETISS_USE_DLSYM_DEEPBIND
Definition config.h:44
forwards: include/jit/*
Definition Benchmark.h:17
@ INFO
Definition Misc.h:87
@ VERBOSE
Definition Misc.h:88
@ WARNING
Definition Misc.h:86
@ ERROR
Definition Misc.h:85
Configuration & cfg()
Definition Misc.cpp:548
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition Misc.cpp:94
STL namespace.
#define NULL
__INTPTR_TYPE__ intptr_t
A signed integer type with the property that any valid pointer to void can be converted to this type,...
#define true
Definition stdbool.h:16