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); }
/* * 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; }