Bus fixes: Reading of CPU MMIO registers does not update MDR
[lsnes.git] / src / library / loadlib.cpp
blob40c2a1abbf9be3b99b65438675ad72dae0f91d53
1 #include "loadlib.hpp"
2 #include <sstream>
3 #include <list>
4 #include <set>
6 #if defined(_WIN32) || defined(_WIN64)
7 #include <windows.h>
8 #endif
10 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
11 #include <dlfcn.h>
12 #include <unistd.h>
13 #endif
15 namespace loadlib
17 threads::lock& global_mutex()
19 static threads::lock m;
20 return m;
23 namespace
25 thread_local library* currently_loading;
26 #if defined(_WIN32) || defined(_WIN64)
27 std::string callsign = "dynamic link library";
28 std::string callsign_ext = "dll";
29 #elif !defined(NO_DLFCN)
30 #if defined(__APPLE__)
31 std::string callsign = "dynamic library";
32 std::string callsign_ext = "bundle";
33 #else
34 std::string callsign = "shared object";
35 std::string callsign_ext = "so";
36 #endif
37 #else
38 std::string callsign = "";
39 std::string callsign_ext = "";
40 #endif
43 library::internal::internal(const std::string& filename) throw(std::bad_alloc, std::runtime_error)
45 libname = filename;
46 refs = 1;
47 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
48 char buffer[16384];
49 getcwd(buffer, 16383);
50 std::string _filename = filename;
51 if(filename.find_first_of("/") >= filename.length())
52 _filename = buffer + std::string("/") + filename;
53 handle = dlopen(_filename.c_str(), RTLD_LOCAL | RTLD_NOW);
54 if(!handle)
55 throw std::runtime_error(dlerror());
56 #elif defined(_WIN32) || defined(_WIN64)
57 char buffer[16384];
58 GetCurrentDirectory(16383, buffer);
59 std::string _filename = filename;
60 if(filename.find_first_of("/\\") >= filename.length())
61 _filename = buffer + std::string("/") + filename;
62 handle = LoadLibraryA(_filename.c_str());
63 if(!handle) {
64 int errcode = GetLastError();
65 char errorbuffer[1024];
66 if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0,
67 errorbuffer, sizeof(errorbuffer), NULL))
68 throw std::runtime_error(errorbuffer);
69 else {
70 std::ostringstream str;
71 str << "Unknown system error (code " << errcode << ")";
72 throw std::runtime_error(str.str());
75 #else
76 throw std::runtime_error("Loading libraries is not supported");
77 #endif
80 library::internal::~internal() throw()
82 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
83 dlclose(handle);
84 #elif defined(_WIN32) || defined(_WIN64)
85 FreeLibrary((HMODULE)handle);
86 #endif
89 void* library::internal::operator[](const std::string& symbol) const throw(std::bad_alloc, std::runtime_error)
91 #if !defined(NO_DLFCN) && !defined(_WIN32) && !defined(_WIN64)
92 dlerror();
93 void* s = dlsym(handle, symbol.c_str());
94 if(s)
95 return s;
96 char* e = dlerror();
97 if(e)
98 throw std::runtime_error(e);
99 return NULL; //Yes, real NULL symbol.
100 #elif defined(_WIN32) || defined(_WIN64)
101 void* s = (void*)GetProcAddress((HMODULE)handle, symbol.c_str());
102 if(s)
103 return s;
104 int errcode = GetLastError();
105 char errorbuffer[1024];
106 if(FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, errcode, 0,
107 errorbuffer, sizeof(errorbuffer), NULL))
108 throw std::runtime_error(errorbuffer);
109 else {
110 std::ostringstream str;
111 str << "Unknown system error (code " << errcode << ")";
112 throw std::runtime_error(str.str());
114 #else
115 throw std::runtime_error("Library loading not supported");
116 #endif
119 const std::string& library::name() throw()
121 return callsign;
124 const std::string& library::extension() throw()
126 return callsign_ext;
129 library* library::loading() throw() { return currently_loading; }
130 void library::set_loading(library* lib) throw(std::bad_alloc) { currently_loading = lib; }
132 namespace
134 std::list<loadlib::module*>& module_queue()
136 static std::list<module*> x;
137 return x;
141 module::module(std::initializer_list<symbol> _symbols, std::function<void(const module&)> init_fn)
143 dynamic = false;
144 for(auto i : _symbols)
145 symbols[i.name] = i.address;
146 init = init_fn;
147 if(init) {
148 threads::alock h(global_mutex());
149 module_queue().push_back(this);
151 libname = "<anonymous module inside executable>";
154 module::module(library _lib)
156 dynamic = true;
157 lib = _lib;
158 libname = _lib.get_libname();
161 module::~module()
163 threads::alock h(global_mutex());
164 for(auto i = module_queue().begin(); i != module_queue().end(); i++) {
165 if(*i == this) {
166 module_queue().erase(i);
167 break;
172 module::module(const module& mod)
174 dynamic = mod.dynamic;
175 lib = mod.lib;
176 symbols = mod.symbols;
177 init = mod.init;
178 libname = mod.libname;
179 if(init) {
180 threads::alock h(global_mutex());
181 module_queue().push_back(this);
185 void* module::operator[](const std::string& symbol) const throw(std::bad_alloc, std::runtime_error)
187 if(dynamic)
188 return lib[symbol];
189 else if(symbols.count(symbol))
190 return symbols.find(symbol)->second;
191 else
192 throw std::runtime_error("Symbol '" + symbol + "' not found");
195 void module::run_initializers()
197 for(auto i : module_queue())
198 if(i->init) {
199 i->init(*i);
200 i->init = std::function<void(const module&)>();
202 module_queue().clear();