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