PageRenderTime 27ms CodeModel.GetById 2ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/prelude/prelude.cpp

http://github.com/Eelis/geordi
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}