diff options
author | Bernard Normier <bernard@zeroc.com> | 2016-05-09 19:30:54 -0400 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2016-05-09 19:30:54 -0400 |
commit | db4206bee14d8cd4e53e82e2848ae8cbc1cb47a2 (patch) | |
tree | 2c534974d2fa0c302c8fada7f55c1c92cc5414e0 /cpp/src/IceUtil/UtilException.cpp | |
parent | Conflict fixes from previous commit (diff) | |
download | ice-db4206bee14d8cd4e53e82e2848ae8cbc1cb47a2.tar.bz2 ice-db4206bee14d8cd4e53e82e2848ae8cbc1cb47a2.tar.xz ice-db4206bee14d8cd4e53e82e2848ae8cbc1cb47a2.zip |
Removed libIceUtil and libSlice
Diffstat (limited to 'cpp/src/IceUtil/UtilException.cpp')
-rw-r--r-- | cpp/src/IceUtil/UtilException.cpp | 979 |
1 files changed, 979 insertions, 0 deletions
diff --git a/cpp/src/IceUtil/UtilException.cpp b/cpp/src/IceUtil/UtilException.cpp new file mode 100644 index 00000000000..b0c25c75324 --- /dev/null +++ b/cpp/src/IceUtil/UtilException.cpp @@ -0,0 +1,979 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#if defined(_MSC_VER) && _MSC_VER >= 1700 +// +// DbgHelp.dll on Windows XP does not contain Unicode functions, so we +// "switch on" Unicode only with VS2012 and up +// +# ifndef UNICODE +# define UNICODE +# endif +# ifndef _UNICODE +# define _UNICODE +# endif +#endif + +// +// For UINTPTR_MAX on Ubuntu Precise +// +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif + +#include <IceUtil/Exception.h> +#include <IceUtil/MutexPtrLock.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/StringUtil.h> +#include <ostream> +#include <iomanip> +#include <cstdlib> + +#ifdef __GNUC__ +# if defined(ICE_LIBBACKTRACE) +# include <backtrace.h> +# include <backtrace-supported.h> +# if BACKTRACE_SUPPORTED && BACKTRACE_SUPPORTS_THREADS +# include <algorithm> +# include <cxxabi.h> +# else + // It's available but we cant' use it - shouldn't happen +# undef ICE_LIBBACKTRACE +# endif +# endif + +# if !defined(__sun) && !defined(__FreeBSD__) && !defined(__MINGW32__) && !defined(ICE_STATIC_LIBS) +# include <execinfo.h> +# include <cxxabi.h> +# include <stdint.h> +# define ICE_BACKTRACE +# endif +#endif + +#if defined(_WIN32) && !defined(ICE_OS_WINRT) && !defined(__MINGW32__) +# define ICE_DBGHELP +# if defined(_MSC_VER) && (_MSC_VER >= 1700) +# define DBGHELP_TRANSLATE_TCHAR +# include <IceUtil/StringConverter.h> +# if _MSC_VER >= 1900 +# pragma warning(disable:4091) // VS 2015 RC issues this warning for code in DbgHelp.h +# endif +# endif +# include <DbgHelp.h> +# include <tchar.h> +#endif + +using namespace std; + +namespace IceUtilInternal +{ + +bool ICE_UTIL_API printStackTraces = false; +bool ICE_UTIL_API nullHandleAbort = false; + +StackTraceImpl +stackTraceImpl() +{ +#if defined(ICE_DBGHELP) + return STDbghelp; +#elif defined(ICE_LIBBACKTRACE) +# if defined(ICE_BACKTRACE) + return STLibbacktracePlus; +# else + return STLibbacktrace; +# endif +#elif defined(ICE_BACKTRACE) + return STBacktrace; +#else + return STNone; +#endif +} +} + +namespace +{ + +IceUtil::Mutex* globalMutex = 0; + +#ifdef ICE_DBGHELP +HANDLE process = 0; +#endif + +#ifdef ICE_LIBBACKTRACE +backtrace_state* bstate = 0; + +void +ignoreErrorCallback(void*, const char* msg, int errnum) +{ + // cerr << "Error callback: " << msg << ", errnum = " << errnum << endl; +} + +#endif + +class Init +{ +public: + + Init() + { + globalMutex = new IceUtil::Mutex; +#ifdef ICE_LIBBACKTRACE + // Leaked, as libbacktrace does not provide an API to free + // this state + bstate = backtrace_create_state(0, 1, ignoreErrorCallback, 0); +#endif + } + + ~Init() + { + delete globalMutex; + globalMutex = 0; +#ifdef ICE_DBGHELP + if(process != 0) + { + SymCleanup(process); + process = 0; + } +#endif + } +}; + +Init init; + +#if defined(ICE_LIBBACKTRACE) || defined (ICE_BACKTRACE) + +struct FrameInfo +{ + FrameInfo(int i, uintptr_t p) : + index(i), + pc(p), + fallback(0), + setByErrorCb(false) + { + } + + int index; + uintptr_t pc; + const char* fallback; + bool setByErrorCb; + string output; +}; + +void +decode(const string& line, string& function, string& filename) +{ + string::size_type openParen = line.find_first_of('('); + if(openParen != string::npos) + { + // + // Format: "/opt/Ice/lib/libIceUtil.so.33(_ZN7IceUtil9ExceptionC2EPKci+0x51) [0x73b267]" + // + string::size_type closeParen = line.find_first_of(')', openParen); + if(closeParen != string::npos) + { + string tmp = line.substr(openParen + 1, closeParen - openParen - 1); + string::size_type plus = tmp.find_last_of('+'); + if(plus != string::npos) + { + function = tmp.substr(0 , plus); + filename = line.substr(0, openParen); + } + } + } + else + { + // + // Format: "1 libIce.3.3.1.dylib 0x000933a1 _ZN7IceUtil9ExceptionC2EPKci + 71" + // + string::size_type plus = line.find_last_of('+'); + if(plus != string::npos) + { + string tmp = line.substr(0, plus - 1); + string::size_type space = tmp.find_last_of(" \t"); + if(space != string::npos) + { + tmp = tmp.substr(space + 1, tmp.size() - space); + + string::size_type start = line.find_first_not_of(" \t", 3); + if(start != string::npos) + { + string::size_type finish = line.find_first_of(" \t", start); + if(finish != string::npos) + { + function = tmp; + filename = line.substr(start, finish - start); + } + } + } + } + } +} + +int +printFrame(void* data, uintptr_t pc, const char* filename, int lineno, const char* function) +{ + FrameInfo& frameInfo = *reinterpret_cast<FrameInfo*>(data); + + ostringstream os; + os << setw(3) << frameInfo.index << " "; + + string functionHolder, filenameHolder; + + if(!function && frameInfo.fallback) + { + // Extract function and filename from fallback + decode(frameInfo.fallback, functionHolder, filenameHolder); + if(!functionHolder.empty()) + { + function = functionHolder.c_str(); + } + if(!filename && !filenameHolder.empty()) + { + filename = filenameHolder.c_str(); + } + } + + int ret = 0; + + if(function) + { + char* demangledFunction = abi::__cxa_demangle(function, 0, 0, 0); + if(demangledFunction) + { + os << demangledFunction; + free(demangledFunction); + } + else + { + os << function; + } + + if(filename && lineno > 0) + { + os << " at " << filename << ":" << lineno; + } + else if(filename) + { + os << " in " << filename; + } + } + else if(frameInfo.fallback) + { + // decode was not able to parse this string + os << frameInfo.fallback; + ret = 1; + } + else + { + os << hex << setw(sizeof(uintptr_t) * 2) << setfill('0') << pc; + ret = 2; + } + os << "\n"; + frameInfo.output = os.str(); + return ret; +} +#endif + +#ifdef ICE_LIBBACKTRACE + +void +handlePcInfoError(void* data, const char* msg, int errnum) +{ + // cerr << "pcinfo error callback: " << msg << ", " << errnum << endl; + + FrameInfo& frameInfo = *reinterpret_cast<FrameInfo*>(data); + printFrame(&frameInfo, frameInfo.pc, 0, 0, 0); + frameInfo.setByErrorCb = true; +} + + +int +addFrame(void* sf, uintptr_t pc) +{ + if(pc != UINTPTR_MAX) + { + vector<void*>* stackFrames = reinterpret_cast<vector<void*>*>(sf); + stackFrames->push_back(reinterpret_cast<void*>(pc)); + return 0; + } + else + { + return 1; + } +} +#endif + +vector<void*> +getStackFrames() +{ + vector<void*> stackFrames; + + if(!IceUtilInternal::printStackTraces) + { + return stackFrames; + } + +#if defined(ICE_DBGHELP) + + stackFrames.resize(61); + // + // 1: skip the first frame (the call to getStackFrames) + // 1 + stackSize < 63 on Windows XP according to the documentation for CaptureStackBackTrace + // + USHORT frameCount = CaptureStackBackTrace(1, static_cast<DWORD>(stackFrames.size()), &stackFrames.front(), 0); + + stackFrames.resize(frameCount); + +#elif defined(ICE_LIBBACKTRACE) + + backtrace_simple(bstate, 1, addFrame, ignoreErrorCallback, &stackFrames); + +#elif defined(ICE_BACKTRACE) + + stackFrames.resize(100); + size_t stackDepth = backtrace(&stackFrames.front(), stackFrames.size()); + stackFrames.resize(stackDepth); + if(!stackFrames.empty()) + { + stackFrames.erase(stackFrames.begin()); // drop the first frame + } +#endif + + return stackFrames; +} + + +string +getStackTrace(const vector<void*>& stackFrames) +{ + if(stackFrames.empty()) + { + return ""; + } + + string stackTrace; + +#if defined(ICE_DBGHELP) + + // + // Note: the Sym functions are not thread-safe + // + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(globalMutex); + if(process == 0) + { + // + // Compute Search path (best effort) + // consists of the current working directory, this DLL (or exe) directory and %_NT_SYMBOL_PATH% + // + basic_string<TCHAR> searchPath; + const TCHAR pathSeparator = _T('\\'); + const TCHAR searchPathSeparator = _T(';'); + + TCHAR cwd[MAX_PATH]; + if(GetCurrentDirectory(MAX_PATH, cwd) != 0) + { + searchPath = cwd; + } + + HMODULE myModule = 0; + GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + "startHook", + &myModule); + // + // If GetModuleHandleEx fails, myModule is NULL, i.e. we'll locate the current exe's directory. + // + + TCHAR myFilename[MAX_PATH]; + DWORD len = GetModuleFileName(myModule, myFilename, MAX_PATH); + if(len != 0 && len < MAX_PATH) + { + assert(myFilename[len] == 0); + + basic_string<TCHAR> myPath = myFilename; + size_t pos = myPath.find_last_of(pathSeparator); + if(pos != basic_string<TCHAR>::npos) + { + myPath = myPath.substr(0, pos); + + if(!searchPath.empty()) + { + searchPath += searchPathSeparator; + } + searchPath += myPath; + } + } + + const DWORD size = 1024; + TCHAR symbolPath[size]; + len = GetEnvironmentVariable(_T("_NT_SYMBOL_PATH"), symbolPath, size); + if(len > 0 && len < size) + { + if(!searchPath.empty()) + { + searchPath += searchPathSeparator; + } + searchPath += symbolPath; + } + + process = GetCurrentProcess(); + + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS | SYMOPT_UNDNAME); + if(SymInitialize(process, searchPath.c_str(), TRUE) == 0) + { + process = 0; + return "No stack trace: SymInitialize failed with " + IceUtilInternal::errorToString(GetLastError()); + } + } + lock.release(); + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# if defined(DBGHELP_TRANSLATE_TCHAR) + static_assert(sizeof(TCHAR) == sizeof(wchar_t), "Bad TCHAR - should be wchar_t"); +# else + static_assert(sizeof(TCHAR) == sizeof(char), "Bad TCHAR - should be char"); +# endif +#endif + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + + SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buffer); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + + IMAGEHLP_LINE64 line = {}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + DWORD displacement = 0; + + lock.acquire(); + + // TODO: call SymRefreshModuleList here? (not available on XP) + +#ifdef DBGHELP_TRANSLATE_TCHAR + const IceUtil::StringConverterPtr converter = IceUtil::getProcessStringConverter(); +#endif + for(size_t i = 0; i < stackFrames.size(); i++) + { + ostringstream s; + s << setw(3) << i << " "; + + DWORD64 address = reinterpret_cast<DWORD64>(stackFrames[i]); + + BOOL ok = SymFromAddr(process, address, 0, symbol); + if(ok) + { +#ifdef DBGHELP_TRANSLATE_TCHAR + s << IceUtil::wstringToString(symbol->Name, converter); +#else + s << symbol->Name; +#endif + ok = SymGetLineFromAddr64(process, address, &displacement, &line); + if(ok) + { + s << " at " +#ifdef DBGHELP_TRANSLATE_TCHAR + << IceUtil::wstringToString(line.FileName, converter) +#else + << line.FileName +#endif + << ":" << line.LineNumber; + } + } + else + { + s << hex << setw(sizeof(DWORD64) * 2) << setfill('0') << address; + } + s << "\n"; + stackTrace += s.str(); + } + lock.release(); + +#elif defined(ICE_LIBBACKTRACE) || defined (ICE_BACKTRACE) + + vector<void*>::const_iterator p = stackFrames.begin(); + int frameIndex = 0; + int offset = 0; + char** backtraceStrings = 0; + +# if defined(ICE_LIBBACKTRACE) && defined(ICE_BACKTRACE) + bool backtraceStringsInitialized = false; +# endif +# if !defined(ICE_LIBBACKTRACE) + // Initialize backtraceStrings immediately + if(p != stackFrames.end()) + { + backtraceStrings = backtrace_symbols(&*p, stackFrames.size()); + } +# endif + + do + { + FrameInfo frameInfo(frameIndex, reinterpret_cast<uintptr_t>(*p)); + bool retry = false; + + if(backtraceStrings) + { + frameInfo.fallback = backtraceStrings[frameIndex - offset]; + } + +# if defined(ICE_LIBBACKTRACE) + bool ok = backtrace_pcinfo(bstate, frameInfo.pc, printFrame, handlePcInfoError, &frameInfo) == 0; + + // When error callback is called, pcinfo returns 0 + if(!ok || frameInfo.setByErrorCb) + { +# if defined(ICE_BACKTRACE) + if(!backtraceStringsInitialized) + { + offset = frameIndex; + // Initialize backtraceStrings as fallback + backtraceStrings = backtrace_symbols(&*p, stackFrames.size() - offset); + backtraceStringsInitialized = true; + retry = true; + } +# endif + } +# else // not using libbacktrace: + printFrame(&frameInfo, frameInfo.pc, 0, 0, 0); +# endif + if(!retry) + { + stackTrace += frameInfo.output; + ++p; + ++frameIndex; + } + } while(p != stackFrames.end()); + + if(backtraceStrings) + { + free(backtraceStrings); + } + +#endif + return stackTrace; +} +} + +IceUtil::Exception::Exception() : + _file(0), + _line(0), + _stackFrames(getStackFrames()) +{ +} + +IceUtil::Exception::Exception(const char* file, int line) : + _file(file), + _line(line), + _stackFrames(getStackFrames()) +{ +} + +IceUtil::Exception::~Exception() ICE_NOEXCEPT +{ +} + +void +IceUtil::Exception::ice_print(ostream& out) const +{ + if(_file && _line > 0) + { + out << _file << ':' << _line << ": "; + } + out << ice_id(); +} + +const char* +IceUtil::Exception::what() const ICE_NOEXCEPT +{ + try + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(globalMutex); + { + if(_str.empty()) + { + stringstream s; + ice_print(s); + _str = s.str(); // Lazy initialization. + } + } + return _str.c_str(); + } + catch(...) + { + } + return ""; +} + +string +IceUtil::Exception::ice_id() const +{ + return "::IceUtil::Exception"; +} + +#ifdef ICE_CPP11_MAPPING +exception_ptr +IceUtil::Exception::ice_clone() const +{ + try + { + ice_throw(); + } + catch(...) + { + return current_exception(); + } + assert(false); + return nullptr; // Make compilers happy +} +#else + +string +IceUtil::Exception::ice_name() const +{ + return ice_id().substr(2); +} + +IceUtil::Exception* +IceUtil::Exception::ice_clone() const +{ + return new Exception(*this); +} +#endif + +void +IceUtil::Exception::ice_throw() const +{ + throw *this; +} + +const char* +IceUtil::Exception::ice_file() const +{ + return _file; +} + +int +IceUtil::Exception::ice_line() const +{ + return _line; +} + +string +IceUtil::Exception::ice_stackTrace() const +{ + return getStackTrace(_stackFrames); +} + +ostream& +IceUtil::operator<<(ostream& out, const IceUtil::Exception& ex) +{ + ex.ice_print(out); + return out; +} + +IceUtil::NullHandleException::NullHandleException(const char* file, int line) : + Exception(file, line) +{ + if(IceUtilInternal::nullHandleAbort) + { + abort(); + } +} + +IceUtil::NullHandleException::~NullHandleException() ICE_NOEXCEPT +{ +} + +string +IceUtil::NullHandleException::ice_id() const +{ + return "::IceUtil::NullHandleException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::NullHandleException* +IceUtil::NullHandleException::ice_clone() const +{ + return new NullHandleException(*this); +} +#endif + +void +IceUtil::NullHandleException::ice_throw() const +{ + throw *this; +} + +IceUtil::IllegalArgumentException::IllegalArgumentException(const char* file, int line) : + Exception(file, line) +{ +} + +IceUtil::IllegalArgumentException::IllegalArgumentException(const char* file, int line, const string& r) : + Exception(file, line), + _reason(r) +{ +} + +IceUtil::IllegalArgumentException::~IllegalArgumentException() ICE_NOEXCEPT +{ +} + +void +IceUtil::IllegalArgumentException::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ": " << _reason; +} + +string +IceUtil::IllegalArgumentException::ice_id() const +{ + return "::IceUtil::IllegalArgumentException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::IllegalArgumentException* +IceUtil::IllegalArgumentException::ice_clone() const +{ + return new IllegalArgumentException(*this); +} +#endif + +void +IceUtil::IllegalArgumentException::ice_throw() const +{ + throw *this; +} + +string +IceUtil::IllegalArgumentException::reason() const +{ + return _reason; +} + +// +// IllegalConversionException +// +IceUtil::IllegalConversionException::IllegalConversionException(const char* file, int line): + Exception(file, line) +{} + +IceUtil::IllegalConversionException::IllegalConversionException(const char* file, int line, + const string& reason): + Exception(file, line), + _reason(reason) +{} + +IceUtil::IllegalConversionException::~IllegalConversionException() ICE_NOEXCEPT +{} + +void +IceUtil::IllegalConversionException::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ": " << _reason; + +} + +string +IceUtil::IllegalConversionException::ice_id() const +{ + return "::IceUtil::IllegalConversionException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::IllegalConversionException* +IceUtil::IllegalConversionException::ice_clone() const +{ + return new IllegalConversionException(*this); +} +#endif + +void +IceUtil::IllegalConversionException::ice_throw() const +{ + throw *this; +} + +string +IceUtil::IllegalConversionException::reason() const +{ + return _reason; +} + + + +IceUtil::SyscallException::SyscallException(const char* file, int line, int err ): + Exception(file, line), + _error(err) +{ +} + +void +IceUtil::SyscallException::ice_print(ostream& os) const +{ + Exception::ice_print(os); + if(_error != 0) + { + os << ":\nsyscall exception: " << IceUtilInternal::errorToString(_error); + } +} + +string +IceUtil::SyscallException::ice_id() const +{ + return "::IceUtil::SyscallException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::SyscallException* +IceUtil::SyscallException::ice_clone() const +{ + return new SyscallException(*this); +} +#endif + +void +IceUtil::SyscallException::ice_throw() const +{ + throw *this; +} + +int +IceUtil::SyscallException::error() const +{ + return _error; +} + + +IceUtil::FileLockException::FileLockException(const char* file, int line, int err, const string& path): + Exception(file, line), + _error(err), + _path(path) +{ +} + +IceUtil::FileLockException::~FileLockException() ICE_NOEXCEPT +{ +} + +void +IceUtil::FileLockException::ice_print(ostream& os) const +{ + Exception::ice_print(os); + os << ":\ncould not lock file: `" << _path << "'"; + if(_error != 0) + { + os << "\nsyscall exception: " << IceUtilInternal::errorToString(_error); + } +} + +string +IceUtil::FileLockException::ice_id() const +{ + return "::IceUtil::FileLockException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::FileLockException* +IceUtil::FileLockException::ice_clone() const +{ + return new FileLockException(*this); +} +#endif + +void +IceUtil::FileLockException::ice_throw() const +{ + throw *this; +} + +int +IceUtil::FileLockException::error() const +{ + return _error; +} + +IceUtil::OptionalNotSetException::OptionalNotSetException(const char* file, int line) : + Exception(file, line) +{ + if(IceUtilInternal::nullHandleAbort) + { + abort(); + } +} + +IceUtil::OptionalNotSetException::~OptionalNotSetException() ICE_NOEXCEPT +{ +} + +string +IceUtil::OptionalNotSetException::ice_id() const +{ + return "::IceUtil::OptionalNotSetException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::OptionalNotSetException* +IceUtil::OptionalNotSetException::ice_clone() const +{ + return new OptionalNotSetException(*this); +} +#endif + +void +IceUtil::OptionalNotSetException::ice_throw() const +{ + throw *this; +} + +#ifndef _WIN32 +IceUtil::IconvInitializationException::IconvInitializationException(const char* file, int line, const string& reason) : + Exception(file, line), + _reason(reason) +{ +} + +IceUtil::IconvInitializationException::~IconvInitializationException() ICE_NOEXCEPT +{ +} + +void +IceUtil::IconvInitializationException::ice_print(ostream& out) const +{ + Exception::ice_print(out); + out << ": " << _reason; +} + +string +IceUtil::IconvInitializationException::ice_id() const +{ + return "::IceUtil::IconvInitializationException"; +} + +#ifndef ICE_CPP11_MAPPING +IceUtil::IconvInitializationException* +IceUtil::IconvInitializationException::ice_clone() const +{ + return new IconvInitializationException(*this); +} +#endif + +void +IceUtil::IconvInitializationException::ice_throw() const +{ + throw *this; +} + +string +IceUtil::IconvInitializationException::reason() const +{ + return _reason; +} +#endif |