void PrintBacktrace(void) {
    int                         err;
    QCrashReportRef             crRef = NULL;

    char                        nameBuf[256], pathToThisProcess[1024];
    const NXArchInfo            *localArch;
    char                        OSMinorVersion = '?';
    time_t                      t;
    char                        atosPipeBuf[1024], cppfiltPipeBuf[1024];
    char                        outBuf[1024], offsetBuf[32];
    char                        *sourceSymbol, *symbolEnd;
    char                        **symbols = NULL;
    void                        *callstack[CALL_STACK_SIZE];
    int                         frames, i;
    void                        *systemlib = NULL;
    FILE                        *atosPipe = NULL;
    FILE                        *cppfiltPipe = NULL;
    backtraceProc               myBacktraceProc = NULL;
    backtrace_symbolsProc       myBacktrace_symbolsProc = NULL;
    char                        saved_env[128], *env = NULL;
    bool                        atosExists = false, cppfiltExists = false;

#if 0
// To debug backtrace logic:
//  * Enable this block of code.
//  * Set a breakpoint at sleep(1) call, and wherever else you wish.
//  * Launch built development application from Finder.
//  * Get this application's pid from Activity Monitor.
//  * Attach Debugger to this application.
//  * Continue until you reach this breakpoint.
//  * Change wait variable to 0 (false).
// This is necessary because GDB intercepts signals even if you tell it 
// not to, so you must attach GDB after the signal handler is invoked.

    bool wait = true;
    
    while (wait) {
        fprintf(stderr, "waiting\n");
        sleep(1);
    }
#endif

    GetNameOfAndPathToThisProcess(nameBuf, sizeof(nameBuf), pathToThisProcess, sizeof(pathToThisProcess));
    
    if (nameBuf[0]) {
        fprintf(stderr, "\nCrashed executable name: %s\n", nameBuf);
    }
    
#ifdef BOINC_VERSION_STRING
    fprintf(stderr, "built using BOINC library version %s\n", BOINC_VERSION_STRING);
#endif

    localArch = NXGetLocalArchInfo();
    fprintf(stderr, "Machine type %s", localArch->description);
#ifdef __LP64__
    fprintf(stderr, " (64-bit executable)\n");
#else
    fprintf(stderr, " (32-bit executable)\n");
#endif

    PrintOSVersion(&OSMinorVersion);

    time(&t);
    fputs(asctime(localtime(&t)), stderr);
    fputc('\n', stderr);
    
    err = QCRCreateFromSelf(&crRef);

    if (OSMinorVersion == '5') {
#ifdef __ppc__
        fputs("BOINC backtrace under OS 10.5.x only shows exported (global) symbols\n", stderr);
        fputs("and may work poorly on a PowerPC Mac after a crash.  For a better\n", stderr);
        fputs("backtrace, run under OS 10.4.x.\n\n", stderr);
#else
        fputs("BOINC backtrace under OS 10.5.x only shows exported (global) symbols\n", stderr);
        fputs("and may not show the final location which caused a crash.  For a better\n", stderr);
        fputs("backtrace, either run under OS 10.4.x or run under OS 10.6.x or later.\n\n", stderr);
#endif
    }
    
    if (OSMinorVersion >= '5') {
        // Use new backtrace functions if available (only in OS 10.5 and later)
        systemlib = dlopen ("/usr/lib/libSystem.dylib", RTLD_NOW );
        if (systemlib) {
            myBacktraceProc = (backtraceProc)dlsym(systemlib, "backtrace");
         }
        if (! myBacktraceProc) {
            goto skipBackTrace;     // Should never happen
        }
        frames = myBacktraceProc(callstack, CALL_STACK_SIZE);
        myBacktrace_symbolsProc = (backtrace_symbolsProc)dlsym(systemlib, "backtrace_symbols");
        if (myBacktrace_symbolsProc) {
            symbols = myBacktrace_symbolsProc(callstack, frames);
        } else {
            goto skipBackTrace;     // Should never happen
        }
        
        atosExists = boinc_file_exists("/usr/bin/atos");
        cppfiltExists = boinc_file_exists("/usr/bin/atos");
        if (atosExists || cppfiltExists) {
            // The bidirectional popen only works if the NSUnbufferedIO environment 
            // variable is set, so we save and restore its current value.
            env = getenv("NSUnbufferedIO");
            if (env) {
                strlcpy(saved_env, env, sizeof(saved_env));
            }
            setenv("NSUnbufferedIO", "YES", 1);
        }
        
        if (atosExists) {
            // The backtrace_symbols() and backtrace_symbols() APIs are limited to 
            // external symbols only, so we also use the atos command-line utility  
            // which gives us debugging symbols when available.
            //
            // For some reason, using the -p option with the value from getpid() 
            // fails here but the -o option with a path does work.
#ifdef __x86_64__
            snprintf(atosPipeBuf, sizeof(atosPipeBuf), "/usr/bin/atos -o \"%s\" -arch x86_64", pathToThisProcess);
#elif defined (__i386__)
            snprintf(atosPipeBuf, sizeof(atosPipeBuf), "/usr/bin/atos -o \"%s\" -arch i386", pathToThisProcess);
#else
            snprintf(atosPipeBuf, sizeof(atosPipeBuf), "/usr/bin/atos -o \"%s\" -arch ppc", pathToThisProcess);
#endif

            atosPipe = popen(atosPipeBuf, "r+");
            if (atosPipe) {
                setbuf(atosPipe, 0);
            }
        }

        if (cppfiltExists) {
            cppfiltPipe = popen("/usr/bin/c++filt -s gnu-v3 -n", "r+");
            if (cppfiltPipe) {
                setbuf(cppfiltPipe, 0);
            }
        }
        
        for (i=0; i<frames; i++) {
            strlcpy(outBuf, symbols[i], sizeof(outBuf));
            if (cppfiltPipe) {
                sourceSymbol = strstr(outBuf, "0x");
                if (sourceSymbol) {
                    sourceSymbol = strchr(sourceSymbol, (int)'_');
                    if (sourceSymbol) {
                        strlcpy(cppfiltPipeBuf, sourceSymbol, sizeof(cppfiltPipeBuf)-1);
                        *sourceSymbol = '\0';
                        symbolEnd = strchr(cppfiltPipeBuf, (int)' ');
                        if (symbolEnd) {
                            strlcpy(offsetBuf, symbolEnd, sizeof(offsetBuf));
                            *symbolEnd = '\0';
                        }
                        fprintf(cppfiltPipe, "%s\n", cppfiltPipeBuf);
                        BT_PersistentFGets(cppfiltPipeBuf, sizeof(cppfiltPipeBuf), cppfiltPipe);
                        symbolEnd = strchr(cppfiltPipeBuf, (int)'\n');
                        if (symbolEnd) {
                            *symbolEnd = '\0';
                        }
                        strlcat(outBuf, cppfiltPipeBuf, sizeof(outBuf));
                        strlcat(outBuf, offsetBuf, sizeof(outBuf));
                    }
                }
            }
            
            if (atosPipe) {
                fprintf(atosPipe, "%#llx\n", (QTMAddr)callstack[i]);
                BT_PersistentFGets(atosPipeBuf, sizeof(atosPipeBuf), atosPipe);
                sourceSymbol = strstr(atosPipeBuf, "0x");
                if (!sourceSymbol) {        // If atos returned a symbol (not just a hex value)
                    sourceSymbol = strstr(outBuf, "0x");
                    if (sourceSymbol) sourceSymbol = strstr(sourceSymbol, " ");
                    if (sourceSymbol) *++sourceSymbol = '\0'; // Remove questionable symbol from backtrace_symbols()
                    strlcat(outBuf, " ", sizeof(outBuf));
                    strlcat(outBuf, atosPipeBuf, sizeof(outBuf));
                    symbolEnd = strchr(outBuf, (int)'\n');
                    if (symbolEnd) {
                        *symbolEnd = '\0';
                    }
                }
            }
            fprintf(stderr, "%s\n", outBuf);
        }

        if (atosPipe) {
            pclose(atosPipe);
        }
        
        if (cppfiltPipe) {
            pclose(cppfiltPipe);
        }

        if (atosExists || cppfiltExists) {
            if (env) {
                setenv("NSUnbufferedIO", saved_env, 1);
            } else {
                unsetenv("NSUnbufferedIO");
            }
        }
        
skipBackTrace:
        fprintf(stderr, "\n");
    } else {
    // Not OS 10.5.x
        QCRPrintBacktraces(crRef, stderr);
    }

    // make sure this much gets written to file in case future 
    // versions of OS break our crash dump code beyond this point.
    fflush(stderr);
    
    QCRPrintThreadState(crRef, stderr);
    QCRPrintImages(crRef, stderr);
}
Exemple #2
0
/*
 * display shell version info internal command.
 */
INT cmd_ver (LPTSTR param)
{
    INT i;

    nErrorLevel = 0;

    if (_tcsstr(param, _T("/?")) != NULL)
    {
        ConOutResPaging(TRUE,STRING_VERSION_HELP1);
        return 0;
    }

    ConOutResPrintf(STRING_CMD_SHELLINFO, _T(KERNEL_RELEASE_STR), _T(KERNEL_VERSION_BUILD_STR));
    ConOutChar(_T('\n'));
    ConOutResPuts(STRING_VERSION_RUNNING_ON);
    PrintOSVersion();

    /* Basic copyright notice */
    if (param[0] != _T('\0'))
    {
        ConOutPuts(_T("\n\n"));
        ConOutPuts(_T("Copyright (C) 1994-1998 Tim Norman and others.\n"));
        ConOutPuts(_T("Copyright (C) 1998-") _T(COPYRIGHT_YEAR) _T(" ReactOS Team\n"));

        for (i = 0; param[i]; i++)
        {
            /* Skip spaces */
            if (param[i] == _T(' '))
                continue;

            if (param[i] == _T('/'))
            {
                /* Is this a lone '/' ? */
                if (param[i + 1] == 0)
                {
                    error_invalid_switch(_T(' '));
                    return 1;
                }
                continue;
            }

            if (_totupper(param[i]) == _T('W'))
            {
                /* Warranty notice */
                ConOutResPuts(STRING_VERSION_HELP3);
            }
            else if (_totupper(param[i]) == _T('R'))
            {
                /* Redistribution notice */
                ConOutResPuts(STRING_VERSION_HELP4);
            }
            else if (_totupper(param[i]) == _T('C'))
            {
                /* Developer listing */
                ConOutResPuts(STRING_VERSION_HELP6);
                ConOutResPuts(STRING_FREEDOS_DEV);
                ConOutResPuts(STRING_VERSION_HELP7);
                ConOutResPuts(STRING_REACTOS_DEV);
            }
            else
            {
                error_invalid_switch(_totupper(param[i]));
                return 1;
            }
        }

        /* Bug report notice */
        ConOutResPuts(STRING_VERSION_HELP5);
    }

    ConOutChar(_T('\n'));

    return 0;
}