/prelude/prelude.cpp

http://github.com/Eelis/geordi · C++ · 259 lines · 200 code · 55 blank · 4 comment · 43 complexity · ae8dea57b05bf1bf4ab768447b5f27d7 MD5 · raw file

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <iterator>
  4. #include <string>
  5. #include <fstream>
  6. #include <stdexcept>
  7. #include <vector>
  8. #include <cerrno>
  9. #include <cstring>
  10. #include <cstdlib>
  11. #include <cstdio>
  12. #include <ctime>
  13. #include <cassert>
  14. #include <ios>
  15. #include <set>
  16. #include <functional>
  17. #include <clocale>
  18. #include <climits>
  19. #include <stdlib.h>
  20. #include <cxxabi.h>
  21. #include <dlfcn.h>
  22. #include <execinfo.h>
  23. #include <ext/malloc_allocator.h>
  24. #include "geordi.hpp"
  25. #if __cplusplus >= 201103
  26. #include "bin_iomanip.hpp"
  27. #include <regex>
  28. template class std::basic_regex<char>;
  29. template std::string std::regex_replace<std::regex_traits<char>, char>(
  30. char const *, std::regex const &, char const *, std::regex_constants::match_flag_type);
  31. #endif
  32. namespace tracked { void atexit(); }
  33. namespace geordi
  34. {
  35. namespace
  36. {
  37. bool is_prefix_of(char const * a, char const * b) { while(*a && *b == *a) { ++a; ++b; } return !*a; }
  38. void terminate_handler(bool const unexp)
  39. {
  40. // We use printf because cout/cerr may be dead.
  41. std::printf("%sterminated", parsep);
  42. if(std::type_info const * const t = abi::__cxa_current_exception_type())
  43. {
  44. int status = 0;
  45. char const * const name = abi::__cxa_demangle(t->name(), 0, 0, &status);
  46. // In OOM conditions, the above call to __cxa_demangle will fail (and name will be 0). Supplying a preallocated buffer using __cxa_demangle's second and third parameters does not help, because it performs additional internal allocations.
  47. std::printf(" by ");
  48. if(unexp) std::printf("unexpected ");
  49. try { throw; }
  50. catch(std::exception const & e)
  51. {
  52. char const * const what = e.what();
  53. if(!name) std::printf("exception: ");
  54. else if(!is_prefix_of(name, what)) std::printf("%s: ", name);
  55. std::printf("%s", what);
  56. }
  57. catch(char const * const s) { std::printf("exception: %s", s); }
  58. catch(int const i) { std::printf("exception: %d", i); }
  59. catch(...)
  60. {
  61. std::printf("exception");
  62. if(name) std::printf(" of type %s", name);
  63. }
  64. }
  65. std::fclose(stdout);
  66. std::abort();
  67. }
  68. void terminate_handler() { terminate_handler(false); }
  69. void unexpected_handler() { terminate_handler(true); }
  70. void maybe_show_asm()
  71. {
  72. std::ifstream f("0.s");
  73. std::string line;
  74. while (std::getline(f, line) && line.find("unassembled") == std::string::npos);
  75. if (!f) return;
  76. while (std::getline(f, line) && line != "\t.cfi_startproc");
  77. bool first = true;
  78. while (std::getline(f, line) && line != "\t.cfi_endproc")
  79. {
  80. if (line.find("\t.cfi") == 0) continue;
  81. std::replace(line.begin(), line.end(), '\t', ' ');
  82. if (line.substr(0, 1) == " ") line = line.substr(1);
  83. if (first) first = false; else std::cout << "; ";
  84. std::cout << line;
  85. }
  86. }
  87. struct initializer
  88. {
  89. initializer()
  90. {
  91. std::ios_base::Init const i;
  92. std::boolalpha(std::cout);
  93. std::boolalpha(std::wcout);
  94. std::boolalpha(std::cerr);
  95. std::boolalpha(std::wcerr);
  96. std::boolalpha(std::clog);
  97. std::boolalpha(std::wclog);
  98. std::unitbuf(std::cout);
  99. std::unitbuf(std::wcout);
  100. std::unitbuf(std::cerr);
  101. std::unitbuf(std::wcerr);
  102. std::unitbuf(std::clog);
  103. std::unitbuf(std::wclog);
  104. #if __cplusplus >= 201103
  105. static bin_num_put<> bnp(1);
  106. static bin_num_put<wchar_t> wbnp(1);
  107. std::cout.imbue(std::locale(std::cout.getloc(), &bnp));
  108. std::wcout.imbue(std::locale(std::wcout.getloc(), &wbnp));
  109. std::cerr.imbue(std::locale(std::cerr.getloc(), &bnp));
  110. std::wcerr.imbue(std::locale(std::wcerr.getloc(), &wbnp));
  111. std::clog.imbue(std::locale(std::clog.getloc(), &bnp));
  112. std::wclog.imbue(std::locale(std::wclog.getloc(), &wbnp));
  113. // Having this compiled separately saves more than a full second per request.
  114. #endif
  115. std::set_terminate(terminate_handler);
  116. std::set_unexpected(unexpected_handler);
  117. std::setlocale(LC_ALL, "");
  118. std::atexit(tracked::atexit);
  119. maybe_show_asm();
  120. }
  121. };
  122. }
  123. utsname uname()
  124. {
  125. utsname r;
  126. if (uname(&r)) throw std::runtime_error(std::strerror(errno));
  127. return r;
  128. }
  129. char const * demangle(char const * const name)
  130. {
  131. int st;
  132. char * const p = abi::__cxa_demangle(name, 0, 0, &st);
  133. switch (st)
  134. {
  135. case 0: return p;
  136. case -1: throw std::runtime_error("A memory allocation failure occurred.");
  137. case -2: throw std::runtime_error("Not a valid name under the GCC C++ ABI mangling rules.");
  138. case -3: throw std::runtime_error("One of the arguments is invalid.");
  139. default: assert(!"unexpected demangle status");
  140. }
  141. // We could return a std::string and free p, but since deallocation is not a concern (and is even a no-op) in geordi anyway, we don't bother.
  142. }
  143. #if __cplusplus >= 201103
  144. std::map<std::string, std::string> depersist()
  145. {
  146. std::ifstream f("data");
  147. std::map<std::string, std::string> r;
  148. std::string k, v;
  149. while (getline(f, k) && getline(f, v)) r[k] = v;
  150. return r;
  151. }
  152. void persist(std::string const k, std::string const v)
  153. {
  154. auto m = depersist();
  155. m[k] = v;
  156. std::ofstream f("data");
  157. for (auto && p : m) f << p.first << '\n' << p.second << '\n';
  158. }
  159. #endif
  160. } // namespace geordi
  161. extern "C"
  162. {
  163. geordi::initializer geordi_init __attribute__((init_priority(102)));
  164. }
  165. std::ostream & operator<<(std::ostream & o, wchar_t const c)
  166. {
  167. char buf[MB_LEN_MAX];
  168. int const i = wctomb(buf, c);
  169. if(i < 0) o << '?';
  170. else std::copy(buf, buf + i, std::ostreambuf_iterator<char>(o));
  171. return o;
  172. }
  173. std::ostream & operator<<(std::ostream & o, wchar_t const * s)
  174. { for(; *s; ++s) o << *s; return o; }
  175. std::ostream & operator<<(std::ostream & o, std::wstring const & s)
  176. { for(std::wstring::const_iterator i = s.begin(); i != s.end(); ++i) o << *i; return o; }
  177. static char const * lookup_name(void * func)
  178. {
  179. static void * handle = dlopen(NULL, RTLD_NOW);
  180. if (!handle) return NULL;
  181. Dl_info info;
  182. dladdr(func, &info);
  183. if (!info.dli_sname) return NULL;
  184. char const * name = info.dli_sname;
  185. if (*name == '_')
  186. {
  187. int st;
  188. if (char const * s = abi::__cxa_demangle(name, 0, 0, &st))
  189. name = s;
  190. }
  191. return name;
  192. }
  193. extern "C"
  194. {
  195. void __cyg_profile_func_enter(void * func, void * /*caller*/)
  196. {
  197. if (char const * name = lookup_name(func))
  198. std::cout << name << '{';
  199. }
  200. void __cyg_profile_func_exit(void * func, void * /*caller*/)
  201. {
  202. if (lookup_name(func)) std::cout << '}';
  203. }
  204. }