summaryrefslogtreecommitdiff
path: root/src/Exceptions.cc
blob: 44743fe78c593bc7e2c43c6ce57699c96ec588d0 (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
#include "Exceptions.h"

#define MAXTRACE 128

#ifdef _WIN32

#include <windows.h>
#include <dbghelp.h>

void Balau::GeneralException::genTrace() {
    // taken from http://stackoverflow.com/questions/5693192/win32-backtrace-from-c-code
    unsigned int   i;
    void         * stack[MAXTRACE];
    unsigned short frames;
    SYMBOL_INFO  * symbol;
    HANDLE         process;

    process = GetCurrentProcess();

    SymInitialize(process, NULL, TRUE);

    frames               = CaptureStackBackTrace(0, MAXTRACE, stack, NULL);
    symbol               = (SYMBOL_INFO *) calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
    symbol->MaxNameLen   = 255;
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);

    for (i = 0; i < frames; i++) {
        SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);

        int status = 0;
        String line;
#ifndef _MSC_VER
        char * demangled = abi::__cxa_demangle(symbol->Name, 0, 0, &status);
#else
        char * demangled = NULL;
#endif
        line.set("%i: 0x%08x (%s)", i, symbol->Address, status == 0 && demangled ? demangled : symbol->Name);
        if (demangled)
            free(demangled);
        m_trace.push_back(line);
    }

    free(symbol);
}

#else

#include <execinfo.h>
#include <dlfcn.h>

void Balau::GeneralException::genTrace() {
    void * trace[MAXTRACE];
    int n = backtrace(trace, MAXTRACE);
    char ** symbols = backtrace_symbols(trace, MAXTRACE);

    if (!symbols)
        return;

    String line;
    for (int i = 0; i < n; i++)
        line += String().set("%08zx ", (uintptr_t) trace[i]);

    m_trace.push_back(line);
    Dl_info info;

    for (int i = 0; i < n; i++) {
        int status;
        String line;
        dladdr(trace[i], &info);
        long dist = ((char *) trace[i]) - ((char *) info.dli_saddr);
        char * demangled;
        if (info.dli_sname) {
            demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, &status);
        } else {
            demangled = NULL;
        }
        line.set("%i: %s(%s%c0x%lx) [0x%08zx]", i, info.dli_fname, info.dli_sname ? (demangled ? (status == 0 ? demangled : info.dli_sname) : info.dli_sname) : "??", dist < 0 ? '-' : '+', dist < 0 ? -dist : dist, (uintptr_t) trace[i]);
        m_trace.push_back(line);
        if (demangled)
            free(demangled);
    }

    free(symbols);
}


#endif

static void ExitHelperInner(const Balau::String & msg, const char * details) throw (Balau::RessourceException) {
    throw Balau::RessourceException(msg, details);
}

void Balau::ExitHelper(const String & msg, const char * fmt, ...) {
    if (fmt) {
        String details;
        va_list ap;
        va_start(ap, fmt);
        details.set(fmt, ap);
        va_end(ap);
        ExitHelperInner(msg, details.to_charp());
    } else {
        ExitHelperInner(msg, NULL);
    }
}

void Balau::AssertHelperInner(const Balau::String & msg, const char * details) throw (Balau::GeneralException) {
#if defined(_MSC_VER) && defined(_DEBUG)
    if (IsDebuggerPresent())
        __debugbreak();
    else
#endif
        throw Balau::GeneralException(msg, details);
}