summaryrefslogtreecommitdiff
path: root/fuzzylite/src/Exception.cpp
blob: 1c27e70a61a65cf8502f59ddb4e14fad4f49580b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
 fuzzylite (R), a fuzzy logic control library in C++.
 Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
 Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>

 This file is part of fuzzylite.

 fuzzylite is free software: you can redistribute it and/or modify it under
 the terms of the FuzzyLite License included with the software.

 You should have received a copy of the FuzzyLite License along with
 fuzzylite. If not, see <http://www.fuzzylite.com/license/>.

 fuzzylite is a registered trademark of FuzzyLite Limited.
 */

#include "fl/Exception.h"


#ifdef FL_BACKTRACE

#ifdef FL_UNIX
#include <execinfo.h>

#elif defined FL_WINDOWS
#include <windows.h>
#include <winbase.h>

#ifndef __MINGW32__
/*Disable warning 8.1\Include\um\dbghelp.h(1544):
warning C4091: 'typedef ': ignored on left of '' when no variable is declared*/
#pragma warning (push)
#pragma warning (disable:4091)
#include <dbghelp.h>
#pragma warning (pop)
#endif

#endif

#endif


#include <csignal>
#include <cstring>

namespace fl {

    Exception::Exception(const std::string& what)
    : std::exception(), _what(what) {
        FL_DBG(this->what());
    }

    Exception::Exception(const std::string& what, const std::string& file, int line,
            const std::string& function)
    : std::exception(), _what(what) {
        append(file, line, function);
        FL_DBG(this->what());
    }

    Exception::~Exception() FL_INOEXCEPT { }

    void Exception::setWhat(const std::string& what) {
        this->_what = what;
    }

    std::string Exception::getWhat() const {
        return this->_what;
    }

    const char* Exception::what() const FL_INOEXCEPT {
        return this->_what.c_str();
    }

    void Exception::append(const std::string& whatElse) {
        this->_what += whatElse + "\n";
    }

    void Exception::append(const std::string& file, int line, const std::string& function) {
        std::ostringstream ss;
        ss << "\n{at " << file << "::" << function << "() [line:" << line << "]}";
        _what += ss.str();
    }

    void Exception::append(const std::string& whatElse,
            const std::string& file, int line, const std::string& function) {
        append(whatElse);
        append(file, line, function);
    }

    std::string Exception::btCallStack() {
#ifndef FL_BACKTRACE
        return "[backtrace disabled] fuzzylite was built without -DFL_BACKTRACE";
#elif defined FL_UNIX
        std::ostringstream btStream;
        const int bufferSize = 30;
        void* buffer[bufferSize];
        int backtraceSize = ::backtrace(buffer, bufferSize);
        char **btSymbols = ::backtrace_symbols(buffer, backtraceSize);
        if (btSymbols == fl::null) {
            btStream << "[backtrace error] no symbols could be retrieved";
        } else {
            if (backtraceSize == 0) {
                btStream << "[backtrace is empty]";
            }
            for (int i = 0; i < backtraceSize; ++i) {
                btStream << btSymbols[i] << "\n";
            }
        }
        ::free(btSymbols);
        return btStream.str();


#elif defined FL_WINDOWS && ! defined __MINGW32__
        std::ostringstream btStream;
        const int bufferSize = 30;
        void* buffer[bufferSize];
        SymInitialize(GetCurrentProcess(), fl::null, TRUE);

        int backtraceSize = CaptureStackBackTrace(0, bufferSize, buffer, fl::null);
        SYMBOL_INFO* btSymbol = (SYMBOL_INFO *) calloc(sizeof ( SYMBOL_INFO) + 256 * sizeof ( char), 1);
        if (not btSymbol) {
            btStream << "[backtrace error] no symbols could be retrieved";
        } else {
            btSymbol->MaxNameLen = 255;
            btSymbol->SizeOfStruct = sizeof ( SYMBOL_INFO);
            if (backtraceSize == 0) {
                btStream << "[backtrace is empty]";
            }
            for (int i = 0; i < backtraceSize; ++i) {
                SymFromAddr(GetCurrentProcess(), (DWORD64) (buffer[ i ]), 0, btSymbol);
                btStream << (backtraceSize - i - 1) << ": " <<
                        btSymbol->Name << " at 0x" << btSymbol->Address << "\n";
            }
        }
        ::free(btSymbol);
        return btStream.str();
#else
        return "[backtrace missing] supported only in Unix and Windows platforms";
#endif
    }

    void Exception::signalHandler(int unixSignal) {
        std::ostringstream ex;
        ex << "[unexpected signal " << unixSignal << "] ";
#ifdef FL_UNIX
        ex << ::strsignal(unixSignal);
#endif
        ex << "\nBACKTRACE:\n" << btCallStack();
        Exception::catchException(Exception(ex.str(), FL_AT));
        ::exit(EXIT_FAILURE);
    }

    void Exception::convertToException(int unixSignal) {
        std::string signalDescription;
#ifdef FL_UNIX
        //Unblock the signal
        sigset_t empty;
        sigemptyset(&empty);
        sigaddset(&empty, unixSignal);
        sigprocmask(SIG_UNBLOCK, &empty, fl::null);
        signalDescription = ::strsignal(unixSignal);
#endif
        std::ostringstream ex;
        ex << "[signal " << unixSignal << "] " << signalDescription << "\n";
        ex << "BACKTRACE:\n" << btCallStack();
        throw Exception(ex.str(), FL_AT);
    }

    void Exception::terminate() {
        Exception::catchException(Exception("[unexpected exception] BACKTRACE:\n" + btCallStack(), FL_AT));
        ::exit(EXIT_FAILURE);
    }

    void Exception::catchException(const std::exception& exception) {
        std::ostringstream ss;
        ss << exception.what();
        std::string backtrace = btCallStack();
        if (not backtrace.empty()) {
            ss << "\n\nBACKTRACE:\n" << backtrace;
        }
        FL_LOG(ss.str());
    }

}