Debug multithreading-related errors
[lsnes.git] / src / core / misc.cpp
blobd306beb1b053156ce92f8b62bd47e1fb9b23e3fc
1 #include "lsnes.hpp"
3 #include "core/memorymanip.hpp"
4 #include "core/misc.hpp"
5 #include "core/rom.hpp"
6 #include "core/threaddebug.hpp"
7 #include "core/window.hpp"
9 #include <sstream>
10 #include <iostream>
11 #include <iomanip>
12 #include <fstream>
13 #include <string>
14 #include <vector>
15 #include <algorithm>
16 #include <ctime>
17 #include <cstdlib>
18 #include <cstring>
19 #include <boost/filesystem.hpp>
21 namespace
23 std::string rseed;
24 uint64_t rcounter = 0;
25 bool reached_main_flag;
27 std::string get_random_hexstring_64(size_t index)
29 std::ostringstream str;
30 str << rseed << " " << time(NULL) << " " << (rcounter++) << " " << index;
31 std::string s = str.str();
32 std::vector<char> x;
33 x.resize(s.length());
34 std::copy(s.begin(), s.end(), x.begin());
35 return sha256::hash(reinterpret_cast<uint8_t*>(&x[0]), x.size());
38 std::string collect_identifying_information()
40 //TODO: Collect as much identifying information as possible.
41 std::ostringstream str;
42 time_t told = time(NULL);
43 time_t tnew;
44 uint64_t loops = 0;
45 uint64_t base = 0;
46 int cnt = 0;
47 while(cnt < 3) {
48 tnew = time(NULL);
49 if(tnew > told) {
50 told = tnew;
51 cnt++;
52 str << (loops - base) << " ";
53 base = loops;
55 loops++;
57 return str.str();
61 std::string get_random_hexstring(size_t length) throw(std::bad_alloc)
63 std::string out;
64 for(size_t i = 0; i < length; i += 64)
65 out = out + get_random_hexstring_64(i);
66 return out.substr(0, length);
69 void set_random_seed(const std::string& seed) throw(std::bad_alloc)
71 std::ostringstream str;
72 str << seed.length() << " " << seed;
73 rseed = str.str();
76 void set_random_seed() throw(std::bad_alloc)
78 //Try /dev/urandom first.
80 std::ifstream r("/dev/urandom", std::ios::binary);
81 if(r.is_open()) {
82 char buf[64];
83 r.read(buf, 64);
84 std::string s(buf, 64);
85 set_random_seed(s);
86 return;
89 //Fall back to time.
90 std::ostringstream str;
91 str << collect_identifying_information() << " " << time(NULL);
92 set_random_seed(str.str());
95 //VERY dirty hack.
96 namespace foobar
98 #include <nall/sha256.hpp>
100 using foobar::nall::sha256_ctx;
101 using foobar::nall::sha256_init;
102 using foobar::nall::sha256_final;
103 using foobar::nall::sha256_hash;
104 using foobar::nall::sha256_chunk;
107 * \brief Opaque internal state of SHA256
109 struct sha256_opaque
112 * \brief Opaque internal state structure of SHA256
114 sha256_ctx shactx;
117 sha256::sha256() throw(std::bad_alloc)
119 opaque = new sha256_opaque();
120 finished = false;
121 sha256_init(&opaque->shactx);
124 sha256::~sha256() throw()
126 delete opaque;
129 void sha256::write(const uint8_t* data, size_t datalen) throw()
131 sha256_chunk(&opaque->shactx, data, datalen);
134 void sha256::read(uint8_t* hashout) throw()
136 if(!finished)
137 sha256_final(&opaque->shactx);
138 finished = true;
139 sha256_hash(&opaque->shactx, hashout);
142 std::string sha256::read() throw(std::bad_alloc)
144 uint8_t b[32];
145 read(b);
146 return sha256::tostring(b);
149 void sha256::hash(uint8_t* hashout, const uint8_t* data, size_t datalen) throw()
151 sha256 s;
152 s.write(data, datalen);
153 s.read(hashout);
156 std::string sha256::tostring(const uint8_t* hashout) throw(std::bad_alloc)
158 std::ostringstream str;
159 for(unsigned i = 0; i < 32; i++)
160 str << std::hex << std::setw(2) << std::setfill('0') << (unsigned)hashout[i];
161 return str.str();
164 struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) throw(std::bad_alloc,
165 std::runtime_error)
167 struct rom_files f;
168 try {
169 f = rom_files(cmdline);
170 f.resolve_relative();
171 } catch(std::bad_alloc& e) {
172 OOM_panic();
173 } catch(std::exception& e) {
174 throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what());
176 messages << "ROM type: " << gtype::tostring(f.rtype, f.region) << std::endl;
177 if(f.rom != "") messages << name_subrom(f.rtype, 0) << " file: '" << f.rom << "'" << std::endl;
178 if(f.rom_xml != "") messages << name_subrom(f.rtype, 1) << " file: '" << f.rom_xml << "'"
179 << std::endl;
180 if(f.slota != "") messages << name_subrom(f.rtype, 2) << " file: '" << f.slota << "'" << std::endl;
181 if(f.slota_xml != "") messages << name_subrom(f.rtype, 3) << " file: '" << f.slota_xml << "'"
182 << std::endl;
183 if(f.slotb != "") messages << name_subrom(f.rtype, 4) << " file: '" << f.slotb << "'" << std::endl;
184 if(f.slotb_xml != "") messages << name_subrom(f.rtype, 5) << " file: '" << f.slotb_xml << "'"
185 << std::endl;
187 struct loaded_rom r;
188 try {
189 r = loaded_rom(f);
190 r.do_patch(cmdline);
191 } catch(std::bad_alloc& e) {
192 OOM_panic();
193 } catch(std::exception& e) {
194 throw std::runtime_error(std::string("Can't load ROM: ") + e.what());
197 std::string not_present = "N/A";
198 if(r.rom.valid) messages << name_subrom(f.rtype, 0) << " hash: " << r.rom.sha256 << std::endl;
199 if(r.rom_xml.valid) messages << name_subrom(f.rtype, 1) << " hash: " << r.rom_xml.sha256 << std::endl;
200 if(r.slota.valid) messages << name_subrom(f.rtype, 2) << " hash: " << r.slota.sha256 << std::endl;
201 if(r.slota_xml.valid) messages << name_subrom(f.rtype, 3) << " hash: " << r.slota_xml.sha256
202 << std::endl;
203 if(r.slotb.valid) messages << name_subrom(f.rtype, 4) << " hash: " << r.slotb.sha256 << std::endl;
204 if(r.slotb_xml.valid) messages << name_subrom(f.rtype, 5) << " hash: " << r.slotb_xml.sha256
205 << std::endl;
206 return r;
209 void dump_region_map() throw(std::bad_alloc)
211 std::vector<struct memory_region> regions = get_regions();
212 for(auto i : regions) {
213 char buf[256];
214 sprintf(buf, "Region: %08X-%08X %08X %s%c %s", i.baseaddr, i.lastaddr, i.size,
215 i.readonly ? "R-" : "RW", i.native_endian ? 'N' : 'L', i.region_name.c_str());
216 messages << buf << std::endl;
220 void fatal_error() throw()
222 platform::fatal_error();
223 std::cout << "PANIC: Fatal error, can't continue." << std::endl;
224 exit(1);
227 std::string get_config_path() throw(std::bad_alloc)
229 const char* tmp;
230 std::string basedir;
231 if((tmp = getenv("APPDATA"))) {
232 //If $APPDATA exists, it is the base directory
233 basedir = tmp;
234 } else if((tmp = getenv("XDG_CONFIG_HOME"))) {
235 //If $XDG_CONFIG_HOME exists, it is the base directory
236 basedir = tmp;
237 } else if((tmp = getenv("HOME"))) {
238 //If $HOME exists, the base directory is '.config' there.
239 basedir = std::string(tmp) + "/.config";
240 } else {
241 //Last chance: Return current directory.
242 return ".";
244 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
245 std::string lsnes_path = basedir + "/lsnes";
246 boost::filesystem::path p(lsnes_path);
247 if(!boost::filesystem::create_directories(p) && !boost::filesystem::is_directory(p)) {
248 messages << "FATAL: Can't create configuration directory '" << lsnes_path << "'" << std::endl;
249 fatal_error();
251 //Yes, this is racy, but portability is more important than being absolutely correct...
252 std::string tfile = lsnes_path + "/test";
253 remove(tfile.c_str());
254 FILE* x;
255 if(!(x = fopen(tfile.c_str(), "w+"))) {
256 messages << "FATAL: Configuration directory '" << lsnes_path << "' is not writable" << std::endl;
257 fatal_error();
259 fclose(x);
260 remove(tfile.c_str());
261 return lsnes_path;
264 extern const char* lsnesrc_file;
266 void create_lsnesrc()
268 std::string rcfile = get_config_path() + "/lsnes.rc";
269 std::ifstream x(rcfile.c_str());
270 if(x) {
271 x.close();
272 return;
274 std::ofstream y(rcfile.c_str());
275 if(!y) {
276 messages << "FATAL: lsnes.rc (" << rcfile << ") doesn't exist nor it can be created" << std::endl;
277 fatal_error();
279 y.write(lsnesrc_file, strlen(lsnesrc_file));
280 y.close();
284 void OOM_panic()
286 messages << "FATAL: Out of memory!" << std::endl;
287 fatal_error();
290 std::ostream& _messages()
292 return platform::out();
295 uint32_t gcd(uint32_t a, uint32_t b) throw()
297 if(b == 0)
298 return a;
299 else
300 return gcd(b, a % b);
303 std::string format_address(void* addr)
305 unsigned long x = (unsigned long)addr;
306 std::ostringstream y;
307 y << "0x" << std::hex << std::setfill('0') << std::setw(2 * sizeof(unsigned long)) << x;
308 return y.str();
311 bool in_global_ctors()
313 return !reached_main_flag;
316 void reached_main()
318 reached_main_flag = true;
319 init_threaded_malloc();
322 std::string bsnes_core_version;