Author: eliot Date: 2011-03-18 16:10:49 -0700 (Fri, 18 Mar 2011) New Revision: 2370 Modified: branches/Cog/platforms/Cross/vm/sqVirtualMachine.c branches/Cog/platforms/Mac OS/vm/sqMacMain.c branches/Cog/platforms/unix/plugins/UUIDPlugin/Makefile.inc branches/Cog/platforms/unix/plugins/UUIDPlugin/sqUnixUUID.c branches/Cog/platforms/unix/vm/sqUnixMain.c branches/Cog/platforms/win32/vm/sqWin32Intel.c Log: Add improved stack trace facilities (store native stack & frame pointers to framePointer and stackPointer if the natve pointers are in the stack zone). Fix sqUnixUUID.c for CentOS/RedHat (uuid/uuid.h, not sys/uuid.h or plain uuid.h) Provide push/pop output file for better tracing when debugging. Modified: branches/Cog/platforms/Cross/vm/sqVirtualMachine.c =================================================================== --- branches/Cog/platforms/Cross/vm/sqVirtualMachine.c 2011-03-18 21:25:53 UTC (rev 2369) +++ branches/Cog/platforms/Cross/vm/sqVirtualMachine.c 2011-03-18 23:10:49 UTC (rev 2370) @@ -469,3 +469,83 @@ return VM; } + + +/* This lives here for now but belongs somewhere else. + * platforms/Cross/vm/sqStuff.c?? + */ +#define STDOUT_STACK_SZ 5 +static int stdoutStackIdx = -1; +static FILE stdoutStack[STDOUT_STACK_SZ]; + +/* N.B. As of cygwin 1.5.25 fopen("crash.dmp","a") DOES NOT WORK! crash.dmp + * contains garbled output as if the file pointer gets set to the start of the + * file, not the end. So we synthesize our own append mode. + */ +#if __MINGW32__ +# include <io.h> +static FILE * +fopen_for_append(char *filename) +{ + FILE *f = !access(filename, F_OK) /* access is bass ackwards */ + ? fopen(filename,"r+") + : fopen(filename,"w+"); + if (f) + fseek(f,0,SEEK_END); + return f; +} +#elif defined(WIN32) +# define fopen_for_append(filename) fopen(filename,"a+t") +#else +# define fopen_for_append(filename) fopen(filename,"a+") +#endif + +void +pushOutputFile(char *filenameOrStdioIndex) +{ +#ifndef STDOUT_FILENO +# define STDOUT_FILENO 1 +# define STDERR_FILENO 2 +#endif + + FILE *output; + + if (stdoutStackIdx + 2 >= STDOUT_STACK_SZ) { + fprintf(stderr,"output file stack is full.\n"); + return; + } + switch ((unsigned)filenameOrStdioIndex) { + case STDOUT_FILENO: output = stdout; break; + case STDERR_FILENO: output = stderr; break; + default: + if (!(output = fopen_for_append(filenameOrStdioIndex))) { + fprintf(stderr, + "could not open \"%s\" for writing.\n", + filenameOrStdioIndex); + return; + } + } + stdoutStack[++stdoutStackIdx] = *stdout; + *stdout = *output; +} + +void +popOutputFile() +{ + if (stdoutStackIdx < 0) { + fprintf(stderr,"output file stack is empty.\n"); + return; + } + fflush(stdout); + if (fileno(stdout) > STDERR_FILENO) { + /* as of Feb 2011 with fclose@@GLIBC_2.1 under e.g. CentOS 5.3, fclose + * hangs in _IO_un_link_internal. This hack avoids that. + */ +#if __linux__ + close(fileno(stdout)); +#else + fclose(stdout); +#endif + } + *stdout = stdoutStack[stdoutStackIdx--]; +} Modified: branches/Cog/platforms/Mac OS/vm/sqMacMain.c =================================================================== --- branches/Cog/platforms/Mac OS/vm/sqMacMain.c 2011-03-18 21:25:53 UTC (rev 2369) +++ branches/Cog/platforms/Mac OS/vm/sqMacMain.c 2011-03-18 23:10:49 UTC (rev 2370) @@ -102,6 +102,11 @@ #if !defined(PATH_MAX) # include <sys/syslimits.h> #endif +#if !defined(NOEXECINFO) +# include <execinfo.h> +# define BACKTRACE_DEPTH 64 +#endif +#include <sys/ucontext.h> extern pthread_mutex_t gEventQueueLock,gSleepLock; extern pthread_cond_t gSleepLockCondition; @@ -134,41 +139,145 @@ sqInt printCallStack(void); extern void dumpPrimTraceLog(void); extern BOOL NSApplicationLoad(void); +static void fetchPrefrences(void); -/* Print an error message, possibly a stack trace, and exit. */ -/* Disable Intel compiler inlining of error which is used for breakpoints */ -#pragma auto_inline off -void -error(char *msg) + +/*** errors ***/ + +/* Print an error message, possibly a stack trace, do /not/ exit. + * Allows e.g. writing to a log file and stderr. + */ +static void +reportStackState(char *msg, char *date, int printAll, ucontext_t *uap) { +#if !defined(NOEXECINFO) + void *addrs[BACKTRACE_DEPTH]; + int depth; +#endif /* flag prevents recursive error when trying to print a broken stack */ static sqInt printingStack = false; - printf("\n%s\n\n", msg); + printf("\n%s%s%s\n\n", msg, date ? " " : "", date ? date : ""); - printf("\nMost recent primitives\n"); - dumpPrimTraceLog(); +#if !defined(NOEXECINFO) + printf("C stack backtrace:\n"); + fflush(stdout); /* backtrace_symbols_fd uses unbuffered i/o */ + depth = backtrace(addrs, BACKTRACE_DEPTH); + backtrace_symbols_fd(addrs, depth, fileno(stdout)); +#endif + if (ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) { if (!printingStack) { +#if COGVM + /* If we're in generated machine code then the only way the stack + * dump machinery has of giving us an accurate report is if we set + * stackPointer & framePointer to the native stack & frame pointers. + */ +# if __APPLE__ && __MACH__ && __i386__ +# if __GNUC__ /* see sys/ucontext.h; two different namings */ + void *fp = (void *)(uap ? uap->uc_mcontext->__ss.__ebp: 0); + void *sp = (void *)(uap ? uap->uc_mcontext->__ss.__esp: 0); +# else + void *fp = (void *)(uap ? uap->uc_mcontext->ss.ebp: 0); + void *sp = (void *)(uap ? uap->uc_mcontext->ss.esp: 0); +# endif +# elif __linux__ && __i386__ + void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_EBP]: 0); + void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_ESP]: 0); +# else +# error need to implement extracting pc from a ucontext_t on this system +# endif + char *savedSP, *savedFP; + + ifValidWriteBackStackPointersSaveTo(fp,sp,&savedFP,&savedSP); +#endif + printingStack = true; - printf("\n\nSmalltalk stack dump:\n"); - printCallStack(); + if (printAll) { + printf("\n\nAll Smalltalk process stacks (active first):\n"); + printAllStacks(); + } + else { + printf("\n\nSmalltalk stack dump:\n"); + printCallStack(); + } + printingStack = false; +#if COGVM + /* Now restore framePointer and stackPointer via same function */ + ifValidWriteBackStackPointersSaveTo(savedFP,savedSP,0,0); +#endif } } else - printf("\nCan't dump Smalltalk stack. Not in VM thread\n"); + printf("\nCan't dump Smalltalk stack(s). Not in VM thread\n"); + printf("\nMost recent primitives\n"); + dumpPrimTraceLog(); + fflush(stdout); +} + +/* Print an error message, possibly a stack trace, and exit. */ +/* Disable Intel compiler inlining of error which is used for breakpoints */ +#pragma auto_inline off +void +error(char *msg) +{ + reportStackState(msg,0,0,0); abort(); } #pragma auto_inline on -static void sigsegv(int ignore) +/* construct /dir/for/image/crash.dmp if a / in imageName else crash.dmp */ +static void +getCrashDumpFilenameInto(char *buf) { -#pragma unused(ignore) + char *slash; - error("Segmentation fault"); + strcpy(buf,imageName); + slash = strrchr(buf,'/'); + strcpy(slash ? slash + 1 : buf, "crash.dmp"); } +static void +sigusr1(int sig, siginfo_t *info, ucontext_t *uap) +{ + int saved_errno = errno; + time_t now = time(NULL); + char ctimebuf[32]; + char crashdump[IMAGE_NAME_SIZE+1]; + unsigned long pc; + if (!ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) { + pthread_kill(getVMOSThread(),sig); + errno = saved_errno; + return; + } + + getCrashDumpFilenameInto(crashdump); + ctime_r(&now,ctimebuf); + pushOutputFile(crashdump); + reportStackState("SIGUSR1", ctimebuf, 1, uap); + popOutputFile(); + reportStackState("SIGUSR1", ctimebuf, 1, uap); + + errno = saved_errno; +} + +static void +sigsegv(int sig, siginfo_t *info, ucontext_t *uap) +{ + time_t now = time(NULL); + char ctimebuf[32]; + char crashdump[IMAGE_NAME_SIZE+1]; + + getCrashDumpFilenameInto(crashdump); + ctime_r(&now,ctimebuf); + pushOutputFile(crashdump); + reportStackState("Segmentation fault", ctimebuf, 0, uap); + popOutputFile(); + reportStackState("Segmentation fault", ctimebuf, 0, uap); + abort(); +} + int main(int argc, char **argv, char **envp); #if defined(__GNUC__) && ( defined(i386) || defined(__i386) || defined(__i386__) \ @@ -194,12 +303,16 @@ # define mtfsfi(fpscr) #endif -int main(int argc, char **argv, char **envp) { +int +main(int argc, char **argv, char **envp) +{ EventRecord theEvent; sqImageFile f; OSErr err; char shortImageName[SHORTIMAGE_NAME_SIZE+1]; + struct sigaction sigusr1_handler_action, sigsegv_handler_action; + #if 0 /* Useful debugging stub? Dump args to file ~/argvPID. */ { char fname[PATH_MAX]; FILE *f; @@ -224,16 +337,24 @@ error("This C compiler's time_t's are not 32 bits."); } - /* Make parameters global for access from pluggable primitives */ - argCnt= argc; - argVec= argv; - envVec= envp; + /* Make parameters global for access from pluggable primitives */ + argCnt= argc; + argVec= argv; + envVec= envp; - signal(SIGSEGV, sigsegv); + sigsegv_handler_action.sa_sigaction = sigsegv; + sigsegv_handler_action.sa_flags = SA_NODEFER | SA_SIGINFO; + sigemptyset(&sigsegv_handler_action.sa_mask); + (void)sigaction(SIGSEGV, &sigsegv_handler_action, 0); - fldcw(0x12bf); /* signed infinity, round to nearest, REAL8, disable intrs, disable signals */ - mtfsfi(0); /* disable signals, IEEE mode, round to nearest */ + sigusr1_handler_action.sa_sigaction = sigusr1; + sigusr1_handler_action.sa_flags = SA_NODEFER | SA_SIGINFO; + sigemptyset(&sigusr1_handler_action.sa_mask); + (void)sigaction(SIGUSR1, &sigusr1_handler_action, 0); + fldcw(0x12bf); /* signed infinity, round to nearest, REAL8, disable intrs, disable signals */ + mtfsfi(0); /* disable signals, IEEE mode, round to nearest */ + LoadScrap(); SetUpClipboard(); fetchPrefrences(); @@ -541,7 +662,8 @@ } -void fetchPrefrences() { +static void +fetchPrefrences() { CFBundleRef myBundle; CFDictionaryRef myDictionary; CFNumberRef SqueakWindowType,SqueakMaxHeapSizeType,SqueakUIFlushPrimaryDeferNMilliseconds,SqueakUIFlushSecondaryCleanupDelayMilliseconds,SqueakUIFlushSecondaryCheckForPossibleNeedEveryNMilliseconds,SqueakDebug; Modified: branches/Cog/platforms/unix/plugins/UUIDPlugin/Makefile.inc =================================================================== --- branches/Cog/platforms/unix/plugins/UUIDPlugin/Makefile.inc 2011-03-18 21:25:53 UTC (rev 2369) +++ branches/Cog/platforms/unix/plugins/UUIDPlugin/Makefile.inc 2011-03-18 23:10:49 UTC (rev 2370) @@ -1 +1,2 @@ +XCFLAGS=-DHAVE_UUID_UUID_H=1 XLDFLAGS = $(LIB_UUID) Modified: branches/Cog/platforms/unix/plugins/UUIDPlugin/sqUnixUUID.c =================================================================== --- branches/Cog/platforms/unix/plugins/UUIDPlugin/sqUnixUUID.c 2011-03-18 21:25:53 UTC (rev 2369) +++ branches/Cog/platforms/unix/plugins/UUIDPlugin/sqUnixUUID.c 2011-03-18 23:10:49 UTC (rev 2370) @@ -4,8 +4,11 @@ # include <sys/types.h> # include <sys/uuid.h> #endif +#if defined(HAVE_UUID_UUID_H) +# include <uuid/uuid.h> +#endif #if defined(HAVE_UUID_H) - #include <uuid.h> +# include <uuid.h> #endif #include "sq.h" Modified: branches/Cog/platforms/unix/vm/sqUnixMain.c =================================================================== --- branches/Cog/platforms/unix/vm/sqUnixMain.c 2011-03-18 21:25:53 UTC (rev 2369) +++ branches/Cog/platforms/unix/vm/sqUnixMain.c 2011-03-18 23:10:49 UTC (rev 2370) @@ -735,88 +735,150 @@ /*** errors ***/ - static void outOfMemory(void) { - fprintf(stderr, "out of memory\n"); - exit(1); + /* pushing stderr outputs the error report on stderr instead of stdout */ + pushOutputFile((char *)STDERR_FILENO); + error("out of memory\n"); } -static void sigusr1(int ignore) +/* Print an error message, possibly a stack trace, do /not/ exit. + * Allows e.g. writing to a log file and stderr. + */ +static void +reportStackState(char *msg, char *date, int printAll, ucontext_t *uap) { #if !defined(NOEXECINFO) void *addrs[BACKTRACE_DEPTH]; int depth; - time_t now = time(NULL); - /* ctime includes newline */ - printf("\nReceived user signal, printing active C stack at %s:", ctime(&now)); - depth = backtrace(addrs, BACKTRACE_DEPTH); - backtrace_symbols_fd(addrs, depth, fileno(stdout)); #endif - printf("\nReceived user signal, printing active Smalltalk stack:\n\n"); - printCallStack(); - printf("\nReceived user signal, printing all Smalltalk processes:\n\n"); - printAllStacks(); - fflush(stdout); - fflush(stderr); -} - -/* Print an error message, possibly a stack trace, and exit. */ -/* Disable Intel compiler inlining of error which is used for breakpoints */ -#pragma auto_inline off -void -error(char *msg) -{ -#if !defined(NOEXECINFO) - void *addrs[BACKTRACE_DEPTH]; - int depth; -#endif /* flag prevents recursive error when trying to print a broken stack */ static sqInt printingStack = false; - printf("\n%s\n\n", msg); + printf("\n%s%s%s\n\n", msg, date ? " " : "", date ? date : ""); #if !defined(NOEXECINFO) printf("C stack backtrace:\n"); + fflush(stdout); /* backtrace_symbols_fd uses unbuffered i/o */ depth = backtrace(addrs, BACKTRACE_DEPTH); backtrace_symbols_fd(addrs, depth, fileno(stdout)); #endif if (ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) { if (!printingStack) { +#if COGVM + /* If we're in generated machine code then the only way the stack + * dump machinery has of giving us an accurate report is if we set + * stackPointer & framePointer to the native stack & frame pointers. + */ +# if __APPLE__ && __MACH__ && __i386__ + void *fp = (void *)(uap ? uap->uc_mcontext->ss.ebp: 0); + void *sp = (void *)(uap ? uap->uc_mcontext->ss.esp: 0); +# elif __linux__ && __i386__ + void *fp = (void *)(uap ? uap->uc_mcontext.gregs[REG_EBP]: 0); + void *sp = (void *)(uap ? uap->uc_mcontext.gregs[REG_ESP]: 0); +# else +# error need to implement extracting pc from a ucontext_t on this system +# endif + char *savedSP, *savedFP; + + ifValidWriteBackStackPointersSaveTo(fp,sp,&savedFP,&savedSP); +#endif + printingStack = true; - printf("\n\nSmalltalk stack dump:\n"); - printCallStack(); + if (printAll) { + printf("\n\nAll Smalltalk process stacks (active first):\n"); + printAllStacks(); + } + else { + printf("\n\nSmalltalk stack dump:\n"); + printCallStack(); + } + printingStack = false; +#if COGVM + /* Now restore framePointer and stackPointer via same function */ + ifValidWriteBackStackPointersSaveTo(savedFP,savedSP,0,0); +#endif } } else - printf("\nCan't dump Smalltalk stack. Not in VM thread\n"); + printf("\nCan't dump Smalltalk stack(s). Not in VM thread\n"); printf("\nMost recent primitives\n"); dumpPrimTraceLog(); + fflush(stdout); +} + +/* Print an error message, possibly a stack trace, and exit. */ +/* Disable Intel compiler inlining of error which is used for breakpoints */ +#pragma auto_inline off +void +error(char *msg) +{ + reportStackState(msg,0,0,0); abort(); } #pragma auto_inline on -static void sigsegv(int ignore) +/* construct /dir/for/image/crash.dmp if a / in imageName else crash.dmp */ +static void +getCrashDumpFilenameInto(char *buf) { -#pragma unused(ignore) + char *slash; - error("Segmentation fault"); + strcpy(buf,imageName); + slash = strrchr(buf,'/'); + strcpy(slash ? slash + 1 : buf, "crash.dmp"); } +static void +sigusr1(int sig, siginfo_t *info, ucontext_t *uap) +{ + int saved_errno = errno; + time_t now = time(NULL); + char ctimebuf[32]; + char crashdump[IMAGE_NAME_SIZE+1]; + unsigned long pc; -#if defined(IMAGE_DUMP) + if (!ioOSThreadsEqual(ioCurrentOSThread(),getVMOSThread())) { + pthread_kill(getVMOSThread(),sig); + errno = saved_errno; + return; + } -static void sighup(int ignore) -{ - dumpImageFile= 1; + getCrashDumpFilenameInto(crashdump); + ctime_r(&now,ctimebuf); + pushOutputFile(crashdump); + reportStackState("SIGUSR1", ctimebuf, 1, uap); + popOutputFile(); + reportStackState("SIGUSR1", ctimebuf, 1, uap); + + errno = saved_errno; } -static void sigquit(int ignore) +static void +sigsegv(int sig, siginfo_t *info, ucontext_t *uap) { - emergencyDump(1); + time_t now = time(NULL); + char ctimebuf[32]; + char crashdump[IMAGE_NAME_SIZE+1]; + + getCrashDumpFilenameInto(crashdump); + ctime_r(&now,ctimebuf); + pushOutputFile(crashdump); + reportStackState("Segmentation fault", ctimebuf, 0, uap); + popOutputFile(); + reportStackState("Segmentation fault", ctimebuf, 0, uap); + abort(); } + + +#if defined(IMAGE_DUMP) +static void +sighup(int ignore) { dumpImageFile= 1; } + +static void +sigquit(int ignore) { emergencyDump(1); } #endif @@ -1645,8 +1707,17 @@ #endif /* defined(HAVE_LIBDL) && !(STACKVM || COGVM) */ if (installHandlers) { - signal(SIGSEGV, sigsegv); - signal(SIGUSR1, sigusr1); + struct sigaction sigusr1_handler_action, sigsegv_handler_action; + + sigsegv_handler_action.sa_sigaction = sigsegv; + sigsegv_handler_action.sa_flags = SA_NODEFER | SA_SIGINFO; + sigemptyset(&sigsegv_handler_action.sa_mask); + (void)sigaction(SIGSEGV, &sigsegv_handler_action, 0); + + sigusr1_handler_action.sa_sigaction = sigusr1; + sigusr1_handler_action.sa_flags = SA_NODEFER | SA_SIGINFO; + sigemptyset(&sigusr1_handler_action.sa_mask); + (void)sigaction(SIGUSR1, &sigusr1_handler_action, 0); } #if defined(IMAGE_DUMP) Modified: branches/Cog/platforms/win32/vm/sqWin32Intel.c =================================================================== --- branches/Cog/platforms/win32/vm/sqWin32Intel.c 2011-03-18 21:25:53 UTC (rev 2369) +++ branches/Cog/platforms/win32/vm/sqWin32Intel.c 2011-03-18 23:10:49 UTC (rev 2370) @@ -955,8 +955,10 @@ TRY { if (inVMThread) - ifValidWriteBackStackPointers((void *)exp->ContextRecord->Ebp, - (void *)exp->ContextRecord->Esp); + ifValidWriteBackStackPointersSaveTo((void *)exp->ContextRecord->Ebp, + (void *)exp->ContextRecord->Esp, + 0, + 0); callstack[0] = (void *)exp->ContextRecord->Eip; nframes = backtrace_from_fp((void*)exp->ContextRecord->Ebp, callstack+1, |
Free forum by Nabble | Edit this page |