PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/mordor/exception.cpp

http://github.com/mozy/mordor
C++ | 375 lines | 341 code | 29 blank | 5 comment | 24 complexity | c903ccbc975cbac7d424dd8d03855912 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2009 - Mozy, Inc.
  2. #include "exception.h"
  3. #ifdef WINDOWS
  4. #include <dbghelp.h>
  5. #include "runtime_linking.h"
  6. #pragma comment(lib, "dbghelp")
  7. #else
  8. #include <errno.h>
  9. #include <execinfo.h>
  10. #include <netdb.h>
  11. #include <string.h>
  12. #endif
  13. #include <boost/thread/mutex.hpp>
  14. #include "socket.h"
  15. namespace Mordor {
  16. #ifdef WINDOWS
  17. static BOOL g_useSymbols;
  18. namespace {
  19. static struct Initializer {
  20. Initializer()
  21. {
  22. SymSetOptions(SYMOPT_DEFERRED_LOADS |
  23. SYMOPT_FAIL_CRITICAL_ERRORS |
  24. SYMOPT_LOAD_LINES |
  25. SYMOPT_NO_PROMPTS);
  26. g_useSymbols = SymInitialize(GetCurrentProcess(), NULL, TRUE);
  27. }
  28. ~Initializer()
  29. {
  30. if (g_useSymbols)
  31. SymCleanup(GetCurrentProcess());
  32. }
  33. } g_init;
  34. }
  35. #endif
  36. std::string to_string(const std::vector<void *> backtrace)
  37. {
  38. #ifdef WINDOWS
  39. static boost::mutex s_mutex;
  40. boost::mutex::scoped_lock lock(s_mutex);
  41. #endif
  42. std::ostringstream os;
  43. #ifdef POSIX
  44. boost::shared_ptr<char *> symbols(backtrace_symbols(&backtrace[0],
  45. backtrace.size()), &free);
  46. #endif
  47. for (size_t i = 0; i < backtrace.size(); ++i) {
  48. if (i != 0)
  49. os << std::endl;
  50. #ifdef WINDOWS
  51. os << backtrace[i];
  52. if (g_useSymbols) {
  53. char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME - 1];
  54. SYMBOL_INFO *symbol = (SYMBOL_INFO*)buf;
  55. symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  56. symbol->MaxNameLen = MAX_SYM_NAME;
  57. DWORD64 displacement64 = 0;
  58. if (pSymFromAddr(GetCurrentProcess(), (DWORD64)backtrace[i],
  59. &displacement64, symbol)) {
  60. os << ": " << symbol->Name << "+" << displacement64;
  61. }
  62. IMAGEHLP_LINE64 line;
  63. line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
  64. DWORD displacement = 0;
  65. if (pSymGetLineFromAddr64(GetCurrentProcess(),
  66. (DWORD64)backtrace[i], &displacement, &line)) {
  67. os << ": " << line.FileName << "(" << line.LineNumber << ")+"
  68. << displacement;
  69. }
  70. }
  71. #else
  72. if (symbols)
  73. os << symbols.get()[i];
  74. else
  75. os << backtrace[i];
  76. #endif
  77. }
  78. return os.str();
  79. }
  80. std::string to_string( errinfo_backtrace const &bt )
  81. {
  82. return to_string(bt.value());
  83. }
  84. #ifdef WINDOWS
  85. std::string to_string( errinfo_lasterror const &e)
  86. {
  87. return boost::lexical_cast<std::string>(e.value());
  88. }
  89. #else
  90. std::string to_string( errinfo_gaierror const &e)
  91. {
  92. std::ostringstream os;
  93. os << e.value() << ", \"" << gai_strerror(e.value()) << "\"";
  94. return os.str();
  95. }
  96. #endif
  97. std::vector<void *> backtrace(int framesToSkip)
  98. {
  99. std::vector<void *> result;
  100. #ifdef WINDOWS
  101. result.resize(64);
  102. WORD count = pRtlCaptureStackBackTrace(1 + framesToSkip, 61 - framesToSkip, &result[0], NULL);
  103. result.resize(count);
  104. #else
  105. result.resize(64);
  106. int count = ::backtrace(&result[0], 64);
  107. result.resize(count);
  108. framesToSkip = std::min(count, framesToSkip + 1);
  109. result.erase(result.begin(), result.begin() + framesToSkip);
  110. #endif
  111. return result;
  112. }
  113. void removeTopFrames(boost::exception &ex, int framesToSkip)
  114. {
  115. const std::vector<void *> *oldbt = boost::get_error_info<errinfo_backtrace>(ex);
  116. if (oldbt && !oldbt->empty()) {
  117. std::vector<void *> newbt(*oldbt);
  118. std::vector<void *> bt = backtrace();
  119. size_t count = 0;
  120. ++framesToSkip;
  121. for (; count + framesToSkip < newbt.size() &&
  122. count + framesToSkip < bt.size(); ++count) {
  123. if (bt[bt.size() - count - 1] != newbt[newbt.size() - count - 1])
  124. break;
  125. }
  126. count -= framesToSkip;
  127. newbt.resize(newbt.size() > count ? newbt.size() - count : 0);
  128. ex << errinfo_backtrace(newbt);
  129. }
  130. }
  131. void rethrow_exception(boost::exception_ptr const & ep)
  132. {
  133. // Take the backtrace from here, to avoid additional frames from the
  134. // exception handler
  135. std::vector<void *> bt = backtrace(1);
  136. try {
  137. boost::rethrow_exception(ep);
  138. } catch (boost::exception &e) {
  139. const std::vector<void *> *oldbt =
  140. boost::get_error_info<errinfo_backtrace>(e);
  141. if (oldbt)
  142. bt.insert(bt.begin(), oldbt->begin(), oldbt->end());
  143. e << errinfo_backtrace(bt);
  144. throw;
  145. }
  146. }
  147. #ifdef WINDOWS
  148. #define WSA(error) WSA ## error
  149. #else
  150. #define WSA(error) error
  151. #endif
  152. static void throwSocketException(error_t error)
  153. {
  154. switch (error) {
  155. case WSA(EAFNOSUPPORT):
  156. throw boost::enable_current_exception(OperationNotSupportedException())
  157. << errinfo_nativeerror(error);
  158. case WSA(EADDRINUSE):
  159. #ifdef WINDOWS
  160. // WSAEACESS is returned from bind when you set SO_REUSEADDR, and
  161. // another socket has set SO_EXCLUSIVEADDRUSE
  162. case WSAEACCES:
  163. case ERROR_ADDRESS_ALREADY_ASSOCIATED:
  164. #endif
  165. throw boost::enable_current_exception(AddressInUseException())
  166. << errinfo_nativeerror(error);
  167. case WSA(ECONNABORTED):
  168. #ifdef WINDOWS
  169. case ERROR_CONNECTION_ABORTED:
  170. #endif
  171. throw boost::enable_current_exception(ConnectionAbortedException())
  172. << errinfo_nativeerror(error);
  173. case WSA(ECONNRESET):
  174. throw boost::enable_current_exception(ConnectionResetException())
  175. << errinfo_nativeerror(error);
  176. case WSA(ECONNREFUSED):
  177. #ifdef WINDOWS
  178. case ERROR_CONNECTION_REFUSED:
  179. #endif
  180. throw boost::enable_current_exception(ConnectionRefusedException())
  181. << errinfo_nativeerror(error);
  182. case WSA(EHOSTDOWN):
  183. throw boost::enable_current_exception(HostDownException())
  184. << errinfo_nativeerror(error);
  185. case WSA(EHOSTUNREACH):
  186. #ifdef WINDOWS
  187. case ERROR_HOST_UNREACHABLE:
  188. #endif
  189. throw boost::enable_current_exception(HostUnreachableException())
  190. << errinfo_nativeerror(error);
  191. case WSA(ENETDOWN):
  192. throw boost::enable_current_exception(NetworkDownException())
  193. << errinfo_nativeerror(error);
  194. case WSA(ENETRESET):
  195. #ifdef WINDOWS
  196. case ERROR_NETNAME_DELETED:
  197. #endif
  198. throw boost::enable_current_exception(NetworkResetException())
  199. << errinfo_nativeerror(error);
  200. case WSA(ENETUNREACH):
  201. #ifdef WINDOWS
  202. case ERROR_NETWORK_UNREACHABLE:
  203. #endif
  204. throw boost::enable_current_exception(NetworkUnreachableException())
  205. << errinfo_nativeerror(error);
  206. case WSA(EPROTOTYPE):
  207. throw boost::enable_current_exception(WrongProtocolTypeException())
  208. << errinfo_nativeerror(error);
  209. case WSA(ETIMEDOUT):
  210. throw boost::enable_current_exception(TimedOutException())
  211. << errinfo_nativeerror(error);
  212. default:
  213. break;
  214. }
  215. }
  216. #ifdef WINDOWS
  217. error_t lastError()
  218. {
  219. return GetLastError();
  220. }
  221. void lastError(error_t error)
  222. {
  223. SetLastError(error);
  224. }
  225. std::ostream &operator <<(std::ostream &os, error_t error)
  226. {
  227. if (error == ERROR_SUCCESS)
  228. return os << "0, \"The operation completed successfully.\"";
  229. os << (DWORD)error;
  230. std::string result;
  231. char *desc;
  232. DWORD numChars = FormatMessageA(
  233. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  234. FORMAT_MESSAGE_FROM_SYSTEM |
  235. FORMAT_MESSAGE_IGNORE_INSERTS,
  236. NULL,
  237. error, 0,
  238. (char*)&desc, 0, NULL);
  239. if (numChars > 0) {
  240. if (desc[numChars - 1] == '\n') {
  241. desc[numChars - 1] = '\0';
  242. if (desc[numChars - 2] == '\r')
  243. desc[numChars - 2] = '\0';
  244. }
  245. try {
  246. os << ", \"" << desc << "\"";
  247. } catch (...) {
  248. LocalFree((HANDLE)desc);
  249. throw;
  250. }
  251. LocalFree((HANDLE)desc);
  252. }
  253. return os;
  254. }
  255. void throwExceptionFromLastError(error_t error)
  256. {
  257. switch (error) {
  258. case ERROR_INVALID_HANDLE:
  259. case WSAENOTSOCK:
  260. throw boost::enable_current_exception(BadHandleException())
  261. << errinfo_nativeerror(error);
  262. case ERROR_FILE_NOT_FOUND:
  263. throw boost::enable_current_exception(FileNotFoundException())
  264. << errinfo_nativeerror(error);
  265. case ERROR_ACCESS_DENIED:
  266. throw boost::enable_current_exception(AccessDeniedException())
  267. << errinfo_nativeerror(error);
  268. case ERROR_OPERATION_ABORTED:
  269. throw boost::enable_current_exception(OperationAbortedException())
  270. << errinfo_nativeerror(error);
  271. case ERROR_BROKEN_PIPE:
  272. throw boost::enable_current_exception(UnexpectedEofException())
  273. << errinfo_nativeerror(error);
  274. case WSAESHUTDOWN:
  275. throw boost::enable_current_exception(BrokenPipeException())
  276. << errinfo_nativeerror(error);
  277. case ERROR_SHARING_VIOLATION:
  278. case ERROR_LOCK_VIOLATION:
  279. throw boost::enable_current_exception(SharingViolation())
  280. << errinfo_nativeerror(error);
  281. case ERROR_CANT_RESOLVE_FILENAME:
  282. throw boost::enable_current_exception(UnresolvablePathException())
  283. << errinfo_nativeerror(error);
  284. case ERROR_DISK_FULL:
  285. throw boost::enable_current_exception(OutOfDiskSpaceException())
  286. << errinfo_nativeerror(error);
  287. case ERROR_NO_UNICODE_TRANSLATION:
  288. throw boost::enable_current_exception(InvalidUnicodeException())
  289. << errinfo_nativeerror(error);
  290. default:
  291. throwSocketException(error);
  292. throw boost::enable_current_exception(NativeException())
  293. << errinfo_nativeerror(error);
  294. }
  295. }
  296. #else
  297. error_t lastError()
  298. {
  299. return errno;
  300. }
  301. void lastError(error_t error)
  302. {
  303. errno = error;
  304. }
  305. std::ostream &operator <<(std::ostream &os, error_t error)
  306. {
  307. return os << (int)error << ", \"" << strerror(error) << "\"";
  308. }
  309. void throwExceptionFromLastError(error_t error)
  310. {
  311. switch (error) {
  312. case EBADF:
  313. throw boost::enable_current_exception(BadHandleException())
  314. << errinfo_nativeerror(error);
  315. case ENOENT:
  316. throw boost::enable_current_exception(FileNotFoundException())
  317. << errinfo_nativeerror(error);
  318. case EACCES:
  319. throw boost::enable_current_exception(AccessDeniedException())
  320. << errinfo_nativeerror(error);
  321. case ECANCELED:
  322. throw boost::enable_current_exception(OperationAbortedException())
  323. << errinfo_nativeerror(error);
  324. case EPIPE:
  325. throw boost::enable_current_exception(BrokenPipeException())
  326. << errinfo_nativeerror(error);
  327. case EISDIR:
  328. throw boost::enable_current_exception(IsDirectoryException())
  329. << errinfo_nativeerror(error);
  330. case ENOTDIR:
  331. throw boost::enable_current_exception(IsNotDirectoryException())
  332. << errinfo_nativeerror(error);
  333. case ELOOP:
  334. throw boost::enable_current_exception(TooManySymbolicLinksException())
  335. << errinfo_nativeerror(error);
  336. case ENOSPC:
  337. throw boost::enable_current_exception(OutOfDiskSpaceException())
  338. << errinfo_nativeerror(error);
  339. default:
  340. throwSocketException(error);
  341. throw boost::enable_current_exception(NativeException())
  342. << errinfo_nativeerror(error);
  343. }
  344. }
  345. #endif
  346. }