int addr2line_all(std::vector<void*> addrsVector, std::string& output) {
    int length = (int) addrsVector.size();
    void* addrs[length];
    for (int i = 0; i < length; i++) {
        addrs[i] = addrsVector[i];
    }
    return addr2line_all(addrs, length, output);
}
/*
 * Resolve symbol name and source location given the path to the executable
 * and an address
 */
int addr2line(void* addr, std::string& line) {
    void* addrs[1] = {addr};
    return addr2line_all(addrs, 1, line);
}
call_stack::call_stack(const size_t /*num_discard = 0*/) {
    // getting a stack trace on Windows / MinGW is loads of fun (not)
    std::vector<void*> traceVector;
    HANDLE process = GetCurrentProcess();
    HANDLE thread = GetCurrentThread();

    void* fakeStackPtr = stacktrace::getFakeCallStackPointer();
    if (fakeStackPtr) {
        // set up fake stack for partial trace
        LPEXCEPTION_POINTERS exceptionInfo = (LPEXCEPTION_POINTERS) fakeStackPtr;
        if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
            // can't do stack walking in Windows when a stack overflow happens :-/
            traceVector.push_back((void*) exceptionInfo->ContextRecord->Eip);
        } else {
            SymInitialize(GetCurrentProcess(), 0, TRUE);
            STACKFRAME frame = {0};
            frame.AddrPC.Offset    = exceptionInfo->ContextRecord->Eip;
            frame.AddrPC.Mode      = AddrModeFlat;
            frame.AddrStack.Offset = exceptionInfo->ContextRecord->Esp;
            frame.AddrStack.Mode   = AddrModeFlat;
            frame.AddrFrame.Offset = exceptionInfo->ContextRecord->Ebp;
            frame.AddrFrame.Mode   = AddrModeFlat;
            while ((int) traceVector.size() < WIN_STACK_FRAMES_MAX &&
                   StackWalk(IMAGE_FILE_MACHINE_I386,
                             process,
                             thread,
                             &frame,
                             exceptionInfo->ContextRecord,
                             0,
                             SymFunctionTableAccess,
                             SymGetModuleBase,
                             0)) {
                traceVector.push_back((void*) frame.AddrPC.Offset);
            }
        }
    } else {
        if (!::SymSetOptions(
                             // ::SymGetOptions()
                               SYMOPT_DEBUG
                             | SYMOPT_DEFERRED_LOADS
                             | SYMOPT_INCLUDE_32BIT_MODULES
                             // | SYMOPT_UNDNAME
                             | SYMOPT_CASE_INSENSITIVE
                             | SYMOPT_LOAD_LINES)) {
            // std::cout << "SymSetOptions failed!" << std::endl;
            // return;
        }
        if (!::SymInitialize(
                /* process */ process,
                /* user-defined search path */ NULL,
                /* include current process */ TRUE)) {
            // std::cout << "SymInitialize failed!" << std::endl;
            // return;
        }

        void* trace[WIN_STACK_FRAMES_MAX];
        USHORT frameCount = ::CaptureStackBackTrace(
                    /* framesToSkip */ WIN_STACK_FRAMES_TO_SKIP,
                    /* framesToCapture; must be < 63 */ WIN_STACK_FRAMES_MAX,
                    trace,
                    /* hash */ NULL
                    );
        for (int i = 0; i < frameCount; i++) {
            traceVector.push_back(trace[i]);
        }

        // try to load module symbol information; this always fails for me  :-/
        DWORD64 BaseAddr = 0;
        DWORD   FileSize = 0;
        const char* progFileC = exceptions::getProgramNameForStackTrace().c_str();
        char* progFile = (char*) progFileC;
        if (!::SymLoadModule(
                process,      // Process handle of the current process
                NULL,         // Handle to the module's image file (not needed)
                progFile,     // Path/name of the file
                NULL,         // User-defined short name of the module (it can be NULL)
                BaseAddr,     // Base address of the module (cannot be NULL if .PDB file is used, otherwise it can be NULL)
                FileSize)) {      // Size of the file (cannot be NULL if .PDB file is used, otherwise it can be NULL)
            // std::cout << "Error: SymLoadModule() failed: " << pp->os_getLastError() << std::endl;
            // return;
        }
    }

    // let's also try to get the line numbers via an external command-line process 'addr2line'
    // (ought to be able to get this information through C function 'backtrace', but for some
    // reason, Qt Creator's shipped version of MinGW does not include this functionality, argh)
    std::string addr2lineOutput;
    std::vector<std::string> addr2lineLines;
    if (!traceVector.empty()) {
        int result = addr2line_all(traceVector, addr2lineOutput);
        if (result == 0) {
            addr2lineLines = stringSplit(addr2lineOutput, "\n");
        }
    }

    SYMBOL_INFO* symbol = (SYMBOL_INFO*) calloc(sizeof(SYMBOL_INFO) + 1024 * sizeof(char), 1);
    symbol->MaxNameLen   = 1020;
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    for (int i = 0; i < (int) traceVector.size(); ++i) {
        entry ent;
        ent.address = traceVector[i];
        if (process && ::SymFromAddr(process, (DWORD64) traceVector[i], 0, symbol)) {
            ent.function = symbol->Name;
        }
        // internal stuff failed, so load from external process
        if (i < addr2lineLines.size()) {
            injectAddr2lineInfo(ent, addr2line_clean(addr2lineLines[i]));
        } else {
            injectAddr2lineInfo(ent, "");
        }

        if (!ent.function.empty() || ent.line > 0) {
            stack.push_back(ent);
        }
    }
    free(symbol);
}