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